webserver.php
changeset 57 31ce64a3ff6c
parent 56 53b0f0d7ff6f
child 62 1b73be5346df
--- a/webserver.php	Wed Oct 08 21:56:21 2008 -0400
+++ b/webserver.php	Sun Nov 23 23:43:52 2008 -0500
@@ -286,7 +286,37 @@
     
     $class = 'Socket_' . HTTPD_SOCKET_LAYER;
     $this->server = new $class();
-    $this->server->tcp_listen($address, $port);
+    if ( is_array($address) )
+    {
+      foreach ( $address as $a )
+      {
+        if ( is_array($port) )
+        {
+          foreach ( $port as $p )
+          {
+            $this->server->tcp_listen($a, $p);
+          }
+        }
+        else
+        {
+          $this->server->tcp_listen($a, $port);
+        }
+      }
+    }
+    else
+    {
+      if ( is_array($port) )
+      {
+        foreach ( $port as $p )
+        {
+          $this->server->tcp_listen($address, $p);
+        }
+      }
+      else
+      {
+        $this->server->tcp_listen($address, $port);
+      }
+    }
     
     // if running as root and we made it here, switch credentials
     if ( $socket_do_root )
@@ -1849,7 +1879,7 @@
 
 class Socket_Raw
 {
-  var $sock;
+  var $sock = array();
   var $socket_initted = false;
   
   function tcp_listen($address, $port)
@@ -1860,14 +1890,17 @@
       burnout('System does not support socket functions. Please rebuild your PHP or install an appropriate extension.');
     }
     
-    $this->sock = @socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
-    if ( !$this->sock )
+    $sockid = count($this->sock);
+    
+    $socktype = ( strstr($address, ':') ) ? AF_INET6 : AF_INET;
+    $this->sock[$sockid] = @socket_create($socktype, SOCK_STREAM, getprotobyname('tcp'));
+    if ( !$this->sock[$sockid] )
       throw new Exception('Could not create socket');
-    $result = @socket_bind($this->sock, $address, $port);
+    $result = @socket_bind($this->sock[$sockid], $address, $port);
     if ( !$result )
       throw new Exception("Could not bind to $address:$port");
     $this->socket_initted = true;
-    $result = @socket_listen($this->sock, SOMAXCONN);
+    $result = @socket_listen($this->sock[$sockid], SOMAXCONN);
     if ( !$result )
       throw new Exception("Could not listen for connections $address:$port");
     
@@ -1879,31 +1912,49 @@
     if ( $this->socket_initted )
     {
       // http://us3.php.net/manual/en/function.socket-bind.php
-      if ( !@socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 1) )
+      if ( is_array($this->sock) )
       {
-        echo socket_strerror(socket_last_error($this->sock)) . "\n";
+        foreach ( $this->sock as $sock )
+        {
+          if ( !@socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1) )
+          {
+            echo socket_strerror(socket_last_error($sock)) . "\n";
+          }
+          @socket_shutdown($sock, 2);
+          @socket_close($sock);
+        }
       }
-      @socket_shutdown($this->sock, 2);
-      @socket_close($this->sock);
+      else
+      {
+        if ( !@socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 1) )
+        {
+          echo socket_strerror(socket_last_error($this->sock)) . "\n";
+        }
+        @socket_shutdown($this->sock, 2);
+        @socket_close($this->sock);
+      }
     }
   }
   
   function accept()
   {
     $remote = false;
-    $timeout = 5;
-    switch(@socket_select($r = array($this->sock), $w = array($this->sock), $e = array($this->sock), $timeout)) {
-      case 2:
-        return false;
-      case 1:
-        $remote = @socket_accept($this->sock);
-        $return = new Socket_Raw();
-        $return->sock = $remote;
-        $return->socket_initted = true;
-        return $return;
-        break;
-      case 0:
-        return false;
+    foreach ( $this->sock as $sock )
+    {
+      $timeout = 200000;
+      switch(@socket_select($r = array($sock), $w = array($sock), $e = array($sock), 0, $timeout)) {
+        case 2:
+          return false;
+        case 1:
+          $remote = @socket_accept($sock);
+          $return = new Socket_Raw();
+          $return->sock = $remote;
+          $return->socket_initted = true;
+          return $return;
+          break;
+        case 0:
+          continue;
+      }
     }
   }
   
@@ -1961,7 +2012,7 @@
 
 class Socket_Stream
 {
-  var $sock;
+  var $sock = array();
   var $socket_initted = false;
   
   function tcp_listen($address, $port)
@@ -1972,9 +2023,19 @@
       burnout('System does not support stream functions. Please rebuild your PHP or install an appropriate extension.');
     }
     
-    $this->sock = @stream_socket_server("tcp://$address:$port", $errno, $errstr);
-    if ( !$this->sock )
+    if ( strstr($address, ':') )
+    {
+      // ipv6 address (probably)
+      $address = "[$address]";
+    }
+    
+    $sockid = count($this->sock);
+    
+    $this->sock[$sockid] = @stream_socket_server("tcp://$address:$port", $errno, $errstr);
+    if ( !$this->sock[$sockid] )
+    {
       throw new Exception("Could not create the socket: error $errno: $errstr");
+    }
   }
   
   function destroy()
@@ -1982,13 +2043,30 @@
     if ( $this->socket_initted )
     {
       // PHP >= 5.2.1
-      if ( function_exists('stream_socket_shutdown') )
+      if ( is_array($this->sock) )
       {
-        @stream_socket_shutdown($this->sock, STREAM_SHUT_RDWR);
+        foreach ( $this->sock as $sock )
+        {
+          if ( function_exists('stream_socket_shutdown') )
+          {
+            @stream_socket_shutdown($sock, STREAM_SHUT_RDWR);
+          }
+          while ( !@fclose($sock) )
+          {
+            usleep(100000);
+          }
+        }
       }
-      while ( !@fclose($this->sock) )
+      else
       {
-        usleep(100000);
+        if ( function_exists('stream_socket_shutdown') )
+        {
+          @stream_socket_shutdown($this->sock, STREAM_SHUT_RDWR);
+        }
+        while ( !@fclose($this->sock) )
+        {
+          usleep(100000);
+        }
       }
     }
   }
@@ -1996,18 +2074,21 @@
   function accept()
   {
     // the goal of a custom accept() with *_select() is to tick every 200ms to allow signals.
-    stream_set_blocking($this->sock, 1);
-    $timeout = 5;
-    $selection = @stream_select($r = array($this->sock), $w = array($this->sock), $e = array($this->sock), $timeout);
-    if ( !$selection )
+    foreach ( $this->sock as $sock )
     {
-      return false;
+      stream_set_blocking($sock, 1);
+      $timeout = 200000;
+      $selection = @stream_select($r = array($sock), $w = array($sock), $e = array($sock), 0, $timeout);
+      if ( !$selection )
+      {
+        return false;
+      }
+      $remote = stream_socket_accept($sock);
+      $return = new Socket_Stream();
+      $return->sock = $remote;
+      $return->socket_initted = true;
+      return $return;
     }
-    $remote = stream_socket_accept($this->sock);
-    $return = new Socket_Stream();
-    $return->sock = $remote;
-    $return->socket_initted = true;
-    return $return;
   }
   
   function soft_shutdown()