From 9f855c60674f5d1929a79d891cf435db3f4f4b42 Mon Sep 17 00:00:00 2001 From: Julius Michaelis Date: Thu, 5 Jan 2012 23:30:11 +0100 Subject: [PATCH] Add a way to test hosts for their hosting capabilities to the masterserver. --- .../web/server/include/C4HostTest.php | 124 ++++++++++++++++++ masterserver/web/server/include/config.ini | 12 ++ masterserver/web/server/index.php | 8 +- 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 masterserver/web/server/include/C4HostTest.php diff --git a/masterserver/web/server/include/C4HostTest.php b/masterserver/web/server/include/C4HostTest.php new file mode 100644 index 000000000..5c960d923 --- /dev/null +++ b/masterserver/web/server/include/C4HostTest.php @@ -0,0 +1,124 @@ + (microtime(true)-$remote_start)); + if(!preg_match('#^HTTP/1.[01] 200#', $reply)) { + trigger_error('Unable to process response from C4HostTest. Wrong address in hosttest_url? No redirects allowed!', E_USER_WARNING); + return true; + } + if(!preg_match('/\r\n\r\n(.*\n)?Reached=[Yy]es\r?\n/s', $reply)) + return false; + return true; + } +} +/** + * Perform host test on $host with $tcpport and $udpport, maximally take $timeout time. + * + */ +function performHostTest ($host,$tcpport,$udpport,$timeout) { + global $C4HostTestIncludeMode; + if($tcpport < 1024) + $tcpport = false; + if($udpport < 1024) + $udpport = false; + if($timeout < 0.001) // 0 check + return false; + if($timeout > 60) + $timeout = 60; // Actually, something larger than 30 seconds doesn't make much sense + $udpreqhex = array( // Magic UDP data stolen from a capture. + 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x2b, 0x73, 0x3e, 0xb4, 0x6c, + 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 ); + $udpreq = ''; + for($i=0; $i $timeout/5) // Send 5 Paks a max, usually because tcp waits for half timeout. + fwrite($udp, $udpreq); + $lastudppack = microtime(true); + $udpreply = fread($udp,1500); + } + if(!$tcp && $tcpport) + $tcp = @fsockopen($host, $tcpport, $tcperrno, $tcperrstr, min($timeout/2 - 0.1, $timeend-microtime(true))); + usleep(max(0,min($timeout*1000000/20,microtime(true)-$cylcestart))); // That means 20 cycles limit, even if $stuff goes wrong + if ($tcp || $udpreply) + break; + } + if(!$C4HostTestIncludeMode) + if($tcperrno && !$tcp) + echo "TCP=Error $tcperrno - $tcperrstr\n"; + else if($tcp) + echo "TCP=Reached\n"; + else + echo "TCP=Unknown\n"; //Somewhat unbeliegable that UDP replied that quick. + if(!$C4HostTestIncludeMode) + if($udperrno && !$udp) + echo "UDP=Error $udperrno - $udperrstr\n"; + if(!$udpreply && $udp) + $udpreply = fread($udp,1500); // Last chance udp! + if(!$C4HostTestIncludeMode) + if(!$tcp && !$udpreply) // we can't say if tcp was just faster, so: ignore + echo "UDP=Timeout\n"; + else if($tcp && !$udpreply) + echo "UDP=Unknown\n"; + else if($udpreply) + echo "UDP=Reached\n"; + return ($tcp || $udpreply); // Reachable if a tcp connection could be made, udp replied +} +?> diff --git a/masterserver/web/server/include/config.ini b/masterserver/web/server/include/config.ini index 3b0e76e7a..ff8da07aa 100644 --- a/masterserver/web/server/include/config.ini +++ b/masterserver/web/server/include/config.ini @@ -46,3 +46,15 @@ oc_update_url=http://www.example.com/ ;secret key for the HAMC-updating system (using sha256) to verify files oc_update_secret= + +;host port testing: 0 - off (default), 1 - perfrom from local host, 2 - perform from from hosttest_url +hosttest_mode=0 + +;time for the client to reply - keep in mind that if that test fails, a client will have to wait at least that long. +hosttest_timeout=6 + +;remote address of host testing script, supply in format of masterserver address in oc config +hosttest_url= + +;hosttest provider answer time. Additional time that may be consumed by establishing the http connection, etc. +hosttest_remote_timeout=1.5 diff --git a/masterserver/web/server/index.php b/masterserver/web/server/index.php index bab834a7e..a3cd250f8 100644 --- a/masterserver/web/server/index.php +++ b/masterserver/web/server/index.php @@ -14,6 +14,8 @@ require_once('include/C4Masterserver.php'); require_once('include/C4Network.php'); require_once('include/FloodProtection.php'); require_once('include/ParseINI.php'); +$C4HostTestIncludeMode = true; +require_once('include/C4HostTest.php'); $config = file_get_contents('include/config.ini'); $link = mysql_connect( @@ -85,7 +87,11 @@ if ($link && $db) { } else { $csid = $server->addReference($reference); if ($csid) { - C4Network::sendAnswer(C4Network::createAnswer(array('Status' => 'Success', 'CSID' => $csid))); + $answer = array('Status' => 'Success', 'CSID' => $csid); + if(!testHostConn($input)) + $answer['Message'] = 'Your network failed to pass certain tests. It is unlikely that are you able to host for the public.|To fix that, you need port forwarding in your router.'; + C4Network::sendAnswer(C4Network::createAnswer($answer)); + unset($answer); } else { C4Network::sendAnswer(C4Network::createError('Round signup failed. (To many tries?)')); }