==== Programming guide for Smart Subdomains ==== I'll just assume you already created a [[Smart Subdomains|smart subdomain]] called www.example.com and you want to write code for it. Smart subdomains can only return A, AAAA and CNAME records (for now). **Note**: If you want to redirect visitors based on their country of origin, network name, uptime information, or extra information, please don't forget to select the "share" checkboxes in the Edit smart subdomain page. === Simple Script === The simplest script that you can write is: $output[] = array("A", "127.0.0.1"); As I said in the Overview, smart subdomains run limited [[http://www.php.net/|PHP]] scripts. This code returns 127.0.0.1 to anybody that requests the IP address of the www.example.com subdomain. The $output array represents the only output that your script can send to the DNS server. Once the script has finished running, GeoScaling searches for the $output variable, and if it is well formatted, it generated the reply to the user. If the scrpt fails to run or it has invalid output, DNS2 uses the IP address which you put in the **"Failover IP"** section when you defined the smart subdomain. === Country Redirection === This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/. Next, let's add redirection based on the country. Let's say I want to return 127.0.0.1 for everybody from inside Romania, and 127.0.0.2 for anybody else: if($country == "ro") $output[] = array("A", "127.0.0.1"); else $output[] = array("A", "127.0.0.2"); All country names are **lower-case**. You can find a list of possible countries, including codes for Satellite Providers and Anonymous Proxies, [[http://www.maxmind.com/app/iso3166|here]]. **Please note**: You need to select "Share country name" in the smart subdomains form for the country information to be available to the script! === Return serveral IPs === As the $output variable is an array, you can return more than one IP address: $output[] = array("A", "127.0.0.3"); $output[] = array("A", "127.0.0.4"); This would return both ip addresses. === Set the TTL === The default [[http://en.wikipedia.org/wiki/Time_to_live#Time_to_live_of_DNS_records|TTL]] (time-to-live) in GeoScaling is 300 (5 minutes). You cannot define a record with a TTL lower than 300 (well, unless you contact to us). If you want to output an IP address with a custom TTL in a smart subdomain, you can do it like this: $output[] = array("A", "127.0.0.5", "400"); This returns a ttl of 400 seconds for 127.0.0.5. === Fail without returning failure ip === If you don't want to return any ip address, you can just define $output like this: $output[] = array("fail"); === Returning CNAMEs === You can return a CNAME is a similar way you return an IP address: $output[] = array("CNAME", "ghs.google.com"); This returns the CNAME of ghs.google.com (pleasae note the **lack of an ending dot** after ghs.google.com). === Redirecting based on the Network Name (AS/ASN) === GeoScaling DNS2 can redirect based on the AS number of the network the visitor comes from. If it is defined, the $as variable contains the AS/ASN network id in **lower case**. You can make a simple redirect: if( $as == "as6128" ) $output[] = array("A", "127.0.0.1"); else $output[] = array("A", "127.0.0.2"); Or you can check for lists of network names, like this: if( in_array ( $as, array("as30890", "as24745", "as6128") ) ) $output[] = array("A", "127.0.0.1"); else $output[] = array("A", "127.0.0.2"); **Please note**: You need to select "Share network name / AS number" in the smart subdomains form for the network information to be available to the script! === Redirecting on uptime information === Redirecting based on uptime is also easy. All the results of your uptime checks are made available in the $uptime array. Let's say you set up an uptime check named "simpliq". If simpliq is down, you can redirect visitors to another mirror like this: if($uptime['simpliq']==1) $output[] = array("A", "127.0.0.1"); else $output[] = array("A", "127.0.0.2"); Here's another real-life example that you can base your code on: if($uptime['fisierulmeu-teentelecom']==1) $output[] = array("A", "193.138.195.114"); if($uptime['fisierulmeu-evolva']==1) $output[] = array("A", "86.55.16.126"); if(!isset($output) || !sizeof($output)) $output[] = array("A", "96.9.130.197"); // backup mirror **Please note**: You need to select "Share uptime info" in the smart subdomains form for the uptime information to be available to the script! === Redirecting based on extra information === As described [[Sending extra information to DNS2 with the XML-RPC API|here]], you can send extra information in the form of a string that can be accessed by your scripts. The following script returns reuturns 4.4.4.4 when the variable datacenter3 is smaller than 80. This could be useful to redirect users to mirrors based on the load of your servers. if(isset($extra_info) && $extra_info!=false ) { $extra_info = unserialize($extra_info); if($extra_info['datacenter3']<80) $output[] = array("A", "4.4.4.4"); else $output[] = array("A", "5.5.5.5"); } else { $output[] = array("A", "3.3.3.3"); } This particular example uses data sent by the script given as example in the [[Sending extra information to DNS2 with the XML-RPC API]] page: $payload['datacenter1'] = "43"; $payload['datacenter2'] = "22"; $payload['datacenter3'] = "87"; **Please note**: You need to select "Share extra info (like server load)" in the smart subdomains form for the extra information to be available to the script! === Other useful variables sent to the script === * **$subdomain** - the complete name of the subdomain + domain (in our case, www.example.com) * **$remote_ip** - the IP of the user === Real-life example that combines two types of redirects === /* as30890 - Evolva as8708 - RDS as34304 - Teen Telecom as24745 - Romtelecom */ if($country=="ro") // if our user comes from Romania { if( in_array( $as, array("as30890", "as24745") ) ) // if the network of the visitor is either evolva or romtelecom, { $output[] = array("A", "86.55.16.126"); // give them this ip } else if( in_array( $as, array("as34304", "as8708") ) ) // else if their network is teen telecom or rds { $output[] = array("A", "193.138.195.114"); // give them this ip } else // if he/she comes from another network, just send both ips { $output[] = array("A", "86.55.16.126"); $output[] = array("A", "193.138.195.114"); } } else // if our user comes from outside Romania { $output[] = array("A", "91.121.158.100", "400"); // return IP 91.121.158.100 with a TTL of 400 } === Return the closest server to the user === $new_server['lat'] = 41.0186111; $new_server['lon'] = 28.9647222; $new_server['loc'] = "Istanbul TR"; $new_server['ip'] = "1.2.3.4"; // IP1 $servers[] = $new_server; $new_server['lat'] = 47.6063889; $new_server['lon'] = -122.3308333; $new_server['loc'] = "Seattle, Wa"; $new_server['ip'] = "1.2.3.5"; // IP2 $servers[] = $new_server; $new_server['lat'] = 32.7833333; $new_server['lon'] = -96.8; $new_server['loc'] = "Dallas, TX"; $new_server['ip'] = "1.2.3.6"; // IP3 $servers[] = $new_server; $new_server['lat'] = 38.895; $new_server['lon'] = -77.0366667; $new_server['loc'] = "Washington D.C."; $new_server['ip'] = "1.2.3.7"; // IP4 $servers[] = $new_server; $current_lat = $city_info['latitude']; $current_lon = $city_info['longitude']; $minimum_distance = PHP_INT_MAX; $minimum_distance_server_id = 0; for($i=0 ; $i"; //echo distance(32.9697, -96.80322, 29.46786, -98.53506, "k") . " kilometers
"; //echo distance(32.9697, -96.80322, 29.46786, -98.53506, "n") . " nautical miles
"; function distance($lat1, $lon1, $lat2, $lon2, $unit) { $theta = $lon1 - $lon2; $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); $dist = acos($dist); $dist = rad2deg($dist); $miles = $dist * 60 * 1.1515; $unit = strtoupper($unit); if ($unit == "K") { return ($miles * 1.609344); } else if ($unit == "N") { return ($miles * 0.8684); } else { return $miles; } }
=== Output debug information in TXT records === This simple script generates TXT records with the information GeoScaling sends to your script: $output[] = array("TXT", "City Info: ".var_export($city_info, true)); $output[] = array("TXT", "Network info: ".var_export($as, true)); $output[] = array("TXT", "Country: ".$country); $output[] = array("TXT", "Subdomain: ".$subdomain); $output[] = array("TXT", "Remote IP: ".$remote_ip); Now, if you make a DNS request for the TXT records of your subdomain: dig -t TXT geo.nyuu.org @ns1.geoscaling.com you will get something like this: ... ;; ANSWER SECTION: geo.nyuu.org. 300 IN TXT "Remote IP: 67.82.29.100" geo.nyuu.org. 300 IN TXT "Network info: 'as6128'" geo.nyuu.org. 300 IN TXT "City Info: array ( 'city' => 'newark', 'country' => 'us', 'region' => 'nj', 'latitude' => 40.734, 'longitude' => -74.1868, )" geo.nyuu.org. 300 IN TXT "Country: us" geo.nyuu.org. 300 IN TXT "Subdomain: geo.nyuu.org" ... User contribution that combines, Closest, plus uptime / take server offline, plus send extra info to take server offline during a deployment See send extra_info wiki part, to see the php code that sends the associated extra_info via a URL /* GeoScaling "smart subdomain script" PURPOSE: 1/ associate url/IP with the physically closest server, monitoring with www.monitis.com reveals minimum of 2x improvement in latency if we do this 2/ take a server out of the list of possible servers if GeoScaling monitoring shows it as down 3/ take a sever out of the list (immediate effect) if we are about to deploy an upgrade of the app software by sending "extra_info" Contributed BY: keitht@sasimedia.net AVAILABLE INFRASTRUCTURE CONSULTING ON 1/ automated build and deploy the N servers in the cloud 2/ Unix or Windows cloud server setup (linode / Rackspace / other) 3/ Techniques for achieving fastest initial page load 4/ No SQL keystore for database replication across cloud servers (Hazelcast + Voldemort + Oracle BDB) 5/ HA / 100 % uptime 6/ Smart browser clients (Flex / GWT), with service calls automatically tied to the fastest responding server (not necessarily the closest) */ $info = unserialize($extra_info); if($uptime['Linode-s1.info']==1 && strcmp($info['linode-s1-offline'],'true') != 0){ $new_server['lat'] = 37.4919627; $new_server['lon'] = -121.93811; $new_server['loc'] = "Fremont, California"; $new_server['ip'] = "1.1.1.1"; //linode-s1 CA $servers[] = $new_server; } if($uptime['rackspace-s1.info']==1 && strcmp($info['rackspace-s1-offline'],'true') != 0){ $new_server['lat'] = 32.7833333; $new_server['lon'] = -96.8; $new_server['loc'] = "Dallas, TX"; $new_server['ip'] = "1.1.1.1"; //rackspace-s1 DALLAS $servers[] = $new_server; } if($uptime['rackspace-s1.info']==1 && strcmp($info['rackspace-s2-offline'],'true') != 0){ $new_server['lat'] = 41.85; $new_server['lon'] = -87.65; $new_server['loc'] = "Chicago, IL"; $new_server['ip'] = "1.1.1.1"; // rackspace-s2 CHICAGO $servers[] = $new_server; } if($uptime['Linode-s2.info']==1 && strcmp($info['linode-s2-offline'],'true') != 0){ $new_server['lat'] = 33.73; $new_server['lon'] = -84.38; $new_server['loc'] = "Atlanta, GA."; $new_server['ip'] = "11.1.1.1"; // linode-s2 ATLANTA $servers[] = $new_server; } $current_lat = $city_info['latitude']; $current_lon = $city_info['longitude']; $minimum_distance = PHP_INT_MAX; $minimum_distance_server_id = 0; for($i=0 ; $i"; //echo distance(32.9697, -96.80322, 29.46786, -98.53506, "k") . " kilometers
"; //echo distance(32.9697, -96.80322, 29.46786, -98.53506, "n") . " nautical miles
"; function distance($lat1, $lon1, $lat2, $lon2, $unit) { $theta = $lon1 - $lon2; $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); $dist = acos($dist); $dist = rad2deg($dist); $miles = $dist * 60 * 1.1515; $unit = strtoupper($unit); if ($unit == "K") { return ($miles * 1.609344); } else if ($unit == "N") { return ($miles * 0.8684); } else { return $miles; } }