284 } |
284 } |
285 $socket_do_root = ( $allow_root ) ? function_exists('posix_geteuid') : false; |
285 $socket_do_root = ( $allow_root ) ? function_exists('posix_geteuid') : false; |
286 |
286 |
287 $class = 'Socket_' . HTTPD_SOCKET_LAYER; |
287 $class = 'Socket_' . HTTPD_SOCKET_LAYER; |
288 $this->server = new $class(); |
288 $this->server = new $class(); |
289 $this->server->tcp_listen($address, $port); |
289 if ( is_array($address) ) |
|
290 { |
|
291 foreach ( $address as $a ) |
|
292 { |
|
293 if ( is_array($port) ) |
|
294 { |
|
295 foreach ( $port as $p ) |
|
296 { |
|
297 $this->server->tcp_listen($a, $p); |
|
298 } |
|
299 } |
|
300 else |
|
301 { |
|
302 $this->server->tcp_listen($a, $port); |
|
303 } |
|
304 } |
|
305 } |
|
306 else |
|
307 { |
|
308 if ( is_array($port) ) |
|
309 { |
|
310 foreach ( $port as $p ) |
|
311 { |
|
312 $this->server->tcp_listen($address, $p); |
|
313 } |
|
314 } |
|
315 else |
|
316 { |
|
317 $this->server->tcp_listen($address, $port); |
|
318 } |
|
319 } |
290 |
320 |
291 // if running as root and we made it here, switch credentials |
321 // if running as root and we made it here, switch credentials |
292 if ( $socket_do_root ) |
322 if ( $socket_do_root ) |
293 { |
323 { |
294 posix_setuid($targetuser); |
324 posix_setuid($targetuser); |
1847 * Socket abstraction layer - low-level socket functions (socket_*) |
1877 * Socket abstraction layer - low-level socket functions (socket_*) |
1848 */ |
1878 */ |
1849 |
1879 |
1850 class Socket_Raw |
1880 class Socket_Raw |
1851 { |
1881 { |
1852 var $sock; |
1882 var $sock = array(); |
1853 var $socket_initted = false; |
1883 var $socket_initted = false; |
1854 |
1884 |
1855 function tcp_listen($address, $port) |
1885 function tcp_listen($address, $port) |
1856 { |
1886 { |
1857 // do we have socket functions? |
1887 // do we have socket functions? |
1858 if ( !function_exists('socket_create') ) |
1888 if ( !function_exists('socket_create') ) |
1859 { |
1889 { |
1860 burnout('System does not support socket functions. Please rebuild your PHP or install an appropriate extension.'); |
1890 burnout('System does not support socket functions. Please rebuild your PHP or install an appropriate extension.'); |
1861 } |
1891 } |
1862 |
1892 |
1863 $this->sock = @socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp')); |
1893 $sockid = count($this->sock); |
1864 if ( !$this->sock ) |
1894 |
|
1895 $socktype = ( strstr($address, ':') ) ? AF_INET6 : AF_INET; |
|
1896 $this->sock[$sockid] = @socket_create($socktype, SOCK_STREAM, getprotobyname('tcp')); |
|
1897 if ( !$this->sock[$sockid] ) |
1865 throw new Exception('Could not create socket'); |
1898 throw new Exception('Could not create socket'); |
1866 $result = @socket_bind($this->sock, $address, $port); |
1899 $result = @socket_bind($this->sock[$sockid], $address, $port); |
1867 if ( !$result ) |
1900 if ( !$result ) |
1868 throw new Exception("Could not bind to $address:$port"); |
1901 throw new Exception("Could not bind to $address:$port"); |
1869 $this->socket_initted = true; |
1902 $this->socket_initted = true; |
1870 $result = @socket_listen($this->sock, SOMAXCONN); |
1903 $result = @socket_listen($this->sock[$sockid], SOMAXCONN); |
1871 if ( !$result ) |
1904 if ( !$result ) |
1872 throw new Exception("Could not listen for connections $address:$port"); |
1905 throw new Exception("Could not listen for connections $address:$port"); |
1873 |
1906 |
1874 $this->socket_initted = true; |
1907 $this->socket_initted = true; |
1875 } |
1908 } |
1877 function destroy() |
1910 function destroy() |
1878 { |
1911 { |
1879 if ( $this->socket_initted ) |
1912 if ( $this->socket_initted ) |
1880 { |
1913 { |
1881 // http://us3.php.net/manual/en/function.socket-bind.php |
1914 // http://us3.php.net/manual/en/function.socket-bind.php |
1882 if ( !@socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 1) ) |
1915 if ( is_array($this->sock) ) |
1883 { |
1916 { |
1884 echo socket_strerror(socket_last_error($this->sock)) . "\n"; |
1917 foreach ( $this->sock as $sock ) |
1885 } |
1918 { |
1886 @socket_shutdown($this->sock, 2); |
1919 if ( !@socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1) ) |
1887 @socket_close($this->sock); |
1920 { |
|
1921 echo socket_strerror(socket_last_error($sock)) . "\n"; |
|
1922 } |
|
1923 @socket_shutdown($sock, 2); |
|
1924 @socket_close($sock); |
|
1925 } |
|
1926 } |
|
1927 else |
|
1928 { |
|
1929 if ( !@socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 1) ) |
|
1930 { |
|
1931 echo socket_strerror(socket_last_error($this->sock)) . "\n"; |
|
1932 } |
|
1933 @socket_shutdown($this->sock, 2); |
|
1934 @socket_close($this->sock); |
|
1935 } |
1888 } |
1936 } |
1889 } |
1937 } |
1890 |
1938 |
1891 function accept() |
1939 function accept() |
1892 { |
1940 { |
1893 $remote = false; |
1941 $remote = false; |
1894 $timeout = 5; |
1942 foreach ( $this->sock as $sock ) |
1895 switch(@socket_select($r = array($this->sock), $w = array($this->sock), $e = array($this->sock), $timeout)) { |
1943 { |
1896 case 2: |
1944 $timeout = 200000; |
1897 return false; |
1945 switch(@socket_select($r = array($sock), $w = array($sock), $e = array($sock), 0, $timeout)) { |
1898 case 1: |
1946 case 2: |
1899 $remote = @socket_accept($this->sock); |
1947 return false; |
1900 $return = new Socket_Raw(); |
1948 case 1: |
1901 $return->sock = $remote; |
1949 $remote = @socket_accept($sock); |
1902 $return->socket_initted = true; |
1950 $return = new Socket_Raw(); |
1903 return $return; |
1951 $return->sock = $remote; |
1904 break; |
1952 $return->socket_initted = true; |
1905 case 0: |
1953 return $return; |
1906 return false; |
1954 break; |
|
1955 case 0: |
|
1956 continue; |
|
1957 } |
1907 } |
1958 } |
1908 } |
1959 } |
1909 |
1960 |
1910 /** |
1961 /** |
1911 * Closes the socket but doesn't destroy it. |
1962 * Closes the socket but doesn't destroy it. |
1959 * Socket abstraction layer - PHP stream support |
2010 * Socket abstraction layer - PHP stream support |
1960 */ |
2011 */ |
1961 |
2012 |
1962 class Socket_Stream |
2013 class Socket_Stream |
1963 { |
2014 { |
1964 var $sock; |
2015 var $sock = array(); |
1965 var $socket_initted = false; |
2016 var $socket_initted = false; |
1966 |
2017 |
1967 function tcp_listen($address, $port) |
2018 function tcp_listen($address, $port) |
1968 { |
2019 { |
1969 // does PHP support this? |
2020 // does PHP support this? |
1970 if ( !function_exists('stream_socket_server') ) |
2021 if ( !function_exists('stream_socket_server') ) |
1971 { |
2022 { |
1972 burnout('System does not support stream functions. Please rebuild your PHP or install an appropriate extension.'); |
2023 burnout('System does not support stream functions. Please rebuild your PHP or install an appropriate extension.'); |
1973 } |
2024 } |
1974 |
2025 |
1975 $this->sock = @stream_socket_server("tcp://$address:$port", $errno, $errstr); |
2026 if ( strstr($address, ':') ) |
1976 if ( !$this->sock ) |
2027 { |
|
2028 // ipv6 address (probably) |
|
2029 $address = "[$address]"; |
|
2030 } |
|
2031 |
|
2032 $sockid = count($this->sock); |
|
2033 |
|
2034 $this->sock[$sockid] = @stream_socket_server("tcp://$address:$port", $errno, $errstr); |
|
2035 if ( !$this->sock[$sockid] ) |
|
2036 { |
1977 throw new Exception("Could not create the socket: error $errno: $errstr"); |
2037 throw new Exception("Could not create the socket: error $errno: $errstr"); |
|
2038 } |
1978 } |
2039 } |
1979 |
2040 |
1980 function destroy() |
2041 function destroy() |
1981 { |
2042 { |
1982 if ( $this->socket_initted ) |
2043 if ( $this->socket_initted ) |
1983 { |
2044 { |
1984 // PHP >= 5.2.1 |
2045 // PHP >= 5.2.1 |
1985 if ( function_exists('stream_socket_shutdown') ) |
2046 if ( is_array($this->sock) ) |
1986 { |
2047 { |
1987 @stream_socket_shutdown($this->sock, STREAM_SHUT_RDWR); |
2048 foreach ( $this->sock as $sock ) |
1988 } |
2049 { |
1989 while ( !@fclose($this->sock) ) |
2050 if ( function_exists('stream_socket_shutdown') ) |
1990 { |
2051 { |
1991 usleep(100000); |
2052 @stream_socket_shutdown($sock, STREAM_SHUT_RDWR); |
|
2053 } |
|
2054 while ( !@fclose($sock) ) |
|
2055 { |
|
2056 usleep(100000); |
|
2057 } |
|
2058 } |
|
2059 } |
|
2060 else |
|
2061 { |
|
2062 if ( function_exists('stream_socket_shutdown') ) |
|
2063 { |
|
2064 @stream_socket_shutdown($this->sock, STREAM_SHUT_RDWR); |
|
2065 } |
|
2066 while ( !@fclose($this->sock) ) |
|
2067 { |
|
2068 usleep(100000); |
|
2069 } |
1992 } |
2070 } |
1993 } |
2071 } |
1994 } |
2072 } |
1995 |
2073 |
1996 function accept() |
2074 function accept() |
1997 { |
2075 { |
1998 // the goal of a custom accept() with *_select() is to tick every 200ms to allow signals. |
2076 // the goal of a custom accept() with *_select() is to tick every 200ms to allow signals. |
1999 stream_set_blocking($this->sock, 1); |
2077 foreach ( $this->sock as $sock ) |
2000 $timeout = 5; |
2078 { |
2001 $selection = @stream_select($r = array($this->sock), $w = array($this->sock), $e = array($this->sock), $timeout); |
2079 stream_set_blocking($sock, 1); |
2002 if ( !$selection ) |
2080 $timeout = 200000; |
2003 { |
2081 $selection = @stream_select($r = array($sock), $w = array($sock), $e = array($sock), 0, $timeout); |
2004 return false; |
2082 if ( !$selection ) |
2005 } |
2083 { |
2006 $remote = stream_socket_accept($this->sock); |
2084 return false; |
2007 $return = new Socket_Stream(); |
2085 } |
2008 $return->sock = $remote; |
2086 $remote = stream_socket_accept($sock); |
2009 $return->socket_initted = true; |
2087 $return = new Socket_Stream(); |
2010 return $return; |
2088 $return->sock = $remote; |
|
2089 $return->socket_initted = true; |
|
2090 return $return; |
|
2091 } |
2011 } |
2092 } |
2012 |
2093 |
2013 function soft_shutdown() |
2094 function soft_shutdown() |
2014 { |
2095 { |
2015 fclose($this->sock); |
2096 fclose($this->sock); |