PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/sockets - sockets.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 821 1055 77.8 %
Date: 2016-09-27 Functions: 46 47 97.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2016 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Chris Vandomelen <chrisv@b0rked.dhs.org>                    |
      16             :    |          Sterling Hughes  <sterling@php.net>                         |
      17             :    |          Jason Greene     <jason@php.net>                            |
      18             :    |          Gustavo Lopes    <cataphract@php.net>                       |
      19             :    | WinSock: Daniel Beulshausen <daniel@php4win.de>                      |
      20             :    +----------------------------------------------------------------------+
      21             :  */
      22             : 
      23             : /* $Id$ */
      24             : 
      25             : #ifdef HAVE_CONFIG_H
      26             : #include "config.h"
      27             : #endif
      28             : 
      29             : #include "php.h"
      30             : 
      31             : #include "php_network.h"
      32             : #include "ext/standard/file.h"
      33             : #include "ext/standard/info.h"
      34             : #include "php_ini.h"
      35             : #ifdef PHP_WIN32
      36             : # include "windows_common.h"
      37             : # include <win32/inet.h>
      38             : # include <windows.h>
      39             : # include <Ws2tcpip.h>
      40             : # include "php_sockets.h"
      41             : # include <win32/sockets.h>
      42             : #else
      43             : # include <sys/types.h>
      44             : # include <sys/socket.h>
      45             : # include <netdb.h>
      46             : # include <netinet/in.h>
      47             : # include <netinet/tcp.h>
      48             : # include <sys/un.h>
      49             : # include <arpa/inet.h>
      50             : # include <sys/time.h>
      51             : # include <unistd.h>
      52             : # include <errno.h>
      53             : # include <fcntl.h>
      54             : # include <signal.h>
      55             : # include <sys/uio.h>
      56             : # define IS_INVALID_SOCKET(a)   (a->bsd_socket < 0)
      57             : # define set_errno(a) (errno = a)
      58             : # include "php_sockets.h"
      59             : # if HAVE_IF_NAMETOINDEX
      60             : #  include <net/if.h>
      61             : # endif
      62             : #endif
      63             : 
      64             : #include <stddef.h>
      65             : 
      66             : #include "sockaddr_conv.h"
      67             : #include "multicast.h"
      68             : #include "sendrecvmsg.h"
      69             : 
      70             : ZEND_DECLARE_MODULE_GLOBALS(sockets)
      71             : 
      72             : #ifndef MSG_WAITALL
      73             : #ifdef LINUX
      74             : #define MSG_WAITALL 0x00000100
      75             : #else
      76             : #define MSG_WAITALL 0x00000000
      77             : #endif
      78             : #endif
      79             : 
      80             : #ifndef MSG_EOF
      81             : #ifdef MSG_FIN
      82             : #define MSG_EOF MSG_FIN
      83             : #endif
      84             : #endif
      85             : 
      86             : #ifndef SUN_LEN
      87             : #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
      88             : #endif
      89             : 
      90             : #ifndef PF_INET
      91             : #define PF_INET AF_INET
      92             : #endif
      93             : 
      94             : #define PHP_NORMAL_READ 0x0001
      95             : #define PHP_BINARY_READ 0x0002
      96             : 
      97             : static int le_socket;
      98             : #define le_socket_name php_sockets_le_socket_name
      99             : 
     100             : static int le_addrinfo;
     101             : #define le_addrinfo_name php_sockets_le_addrinfo_name
     102             : 
     103             : /* {{{ arginfo */
     104             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_select, 0, 0, 4)
     105             :         ZEND_ARG_INFO(1, read_fds)
     106             :         ZEND_ARG_INFO(1, write_fds)
     107             :         ZEND_ARG_INFO(1, except_fds)
     108             :         ZEND_ARG_INFO(0, tv_sec)
     109             :         ZEND_ARG_INFO(0, tv_usec)
     110             : ZEND_END_ARG_INFO()
     111             : 
     112             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_listen, 0, 0, 1)
     113             :         ZEND_ARG_INFO(0, port)
     114             :         ZEND_ARG_INFO(0, backlog)
     115             : ZEND_END_ARG_INFO()
     116             : 
     117             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_accept, 0, 0, 1)
     118             :         ZEND_ARG_INFO(0, socket)
     119             : ZEND_END_ARG_INFO()
     120             : 
     121             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_nonblock, 0, 0, 1)
     122             :         ZEND_ARG_INFO(0, socket)
     123             : ZEND_END_ARG_INFO()
     124             : 
     125             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_block, 0, 0, 1)
     126             :         ZEND_ARG_INFO(0, socket)
     127             : ZEND_END_ARG_INFO()
     128             : 
     129             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_listen, 0, 0, 1)
     130             :         ZEND_ARG_INFO(0, socket)
     131             :         ZEND_ARG_INFO(0, backlog)
     132             : ZEND_END_ARG_INFO()
     133             : 
     134             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_close, 0, 0, 1)
     135             :         ZEND_ARG_INFO(0, socket)
     136             : ZEND_END_ARG_INFO()
     137             : 
     138             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_write, 0, 0, 2)
     139             :         ZEND_ARG_INFO(0, socket)
     140             :         ZEND_ARG_INFO(0, buf)
     141             :         ZEND_ARG_INFO(0, length)
     142             : ZEND_END_ARG_INFO()
     143             : 
     144             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_read, 0, 0, 2)
     145             :         ZEND_ARG_INFO(0, socket)
     146             :         ZEND_ARG_INFO(0, length)
     147             :         ZEND_ARG_INFO(0, type)
     148             : ZEND_END_ARG_INFO()
     149             : 
     150             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getsockname, 0, 0, 2)
     151             :         ZEND_ARG_INFO(0, socket)
     152             :         ZEND_ARG_INFO(1, addr)
     153             :         ZEND_ARG_INFO(1, port)
     154             : ZEND_END_ARG_INFO()
     155             : 
     156             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getpeername, 0, 0, 2)
     157             :         ZEND_ARG_INFO(0, socket)
     158             :         ZEND_ARG_INFO(1, addr)
     159             :         ZEND_ARG_INFO(1, port)
     160             : ZEND_END_ARG_INFO()
     161             : 
     162             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create, 0, 0, 3)
     163             :         ZEND_ARG_INFO(0, domain)
     164             :         ZEND_ARG_INFO(0, type)
     165             :         ZEND_ARG_INFO(0, protocol)
     166             : ZEND_END_ARG_INFO()
     167             : 
     168             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_connect, 0, 0, 2)
     169             :         ZEND_ARG_INFO(0, socket)
     170             :         ZEND_ARG_INFO(0, addr)
     171             :         ZEND_ARG_INFO(0, port)
     172             : ZEND_END_ARG_INFO()
     173             : 
     174             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_strerror, 0, 0, 1)
     175             :         ZEND_ARG_INFO(0, errno)
     176             : ZEND_END_ARG_INFO()
     177             : 
     178             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_bind, 0, 0, 2)
     179             :         ZEND_ARG_INFO(0, socket)
     180             :         ZEND_ARG_INFO(0, addr)
     181             :         ZEND_ARG_INFO(0, port)
     182             : ZEND_END_ARG_INFO()
     183             : 
     184             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recv, 0, 0, 4)
     185             :         ZEND_ARG_INFO(0, socket)
     186             :         ZEND_ARG_INFO(1, buf)
     187             :         ZEND_ARG_INFO(0, len)
     188             :         ZEND_ARG_INFO(0, flags)
     189             : ZEND_END_ARG_INFO()
     190             : 
     191             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_send, 0, 0, 4)
     192             :         ZEND_ARG_INFO(0, socket)
     193             :         ZEND_ARG_INFO(0, buf)
     194             :         ZEND_ARG_INFO(0, len)
     195             :         ZEND_ARG_INFO(0, flags)
     196             : ZEND_END_ARG_INFO()
     197             : 
     198             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvfrom, 0, 0, 5)
     199             :         ZEND_ARG_INFO(0, socket)
     200             :         ZEND_ARG_INFO(1, buf)
     201             :         ZEND_ARG_INFO(0, len)
     202             :         ZEND_ARG_INFO(0, flags)
     203             :         ZEND_ARG_INFO(1, name)
     204             :         ZEND_ARG_INFO(1, port)
     205             : ZEND_END_ARG_INFO()
     206             : 
     207             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendto, 0, 0, 5)
     208             :         ZEND_ARG_INFO(0, socket)
     209             :         ZEND_ARG_INFO(0, buf)
     210             :         ZEND_ARG_INFO(0, len)
     211             :         ZEND_ARG_INFO(0, flags)
     212             :         ZEND_ARG_INFO(0, addr)
     213             :         ZEND_ARG_INFO(0, port)
     214             : ZEND_END_ARG_INFO()
     215             : 
     216             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_get_option, 0, 0, 3)
     217             :         ZEND_ARG_INFO(0, socket)
     218             :         ZEND_ARG_INFO(0, level)
     219             :         ZEND_ARG_INFO(0, optname)
     220             : ZEND_END_ARG_INFO()
     221             : 
     222             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_option, 0, 0, 4)
     223             :         ZEND_ARG_INFO(0, socket)
     224             :         ZEND_ARG_INFO(0, level)
     225             :         ZEND_ARG_INFO(0, optname)
     226             :         ZEND_ARG_INFO(0, optval)
     227             : ZEND_END_ARG_INFO()
     228             : 
     229             : #ifdef HAVE_SOCKETPAIR
     230             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_pair, 0, 0, 4)
     231             :         ZEND_ARG_INFO(0, domain)
     232             :         ZEND_ARG_INFO(0, type)
     233             :         ZEND_ARG_INFO(0, protocol)
     234             :         ZEND_ARG_INFO(1, fd)
     235             : ZEND_END_ARG_INFO()
     236             : #endif
     237             : 
     238             : #ifdef HAVE_SHUTDOWN
     239             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_shutdown, 0, 0, 1)
     240             :         ZEND_ARG_INFO(0, socket)
     241             :         ZEND_ARG_INFO(0, how)
     242             : ZEND_END_ARG_INFO()
     243             : #endif
     244             : 
     245             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_last_error, 0, 0, 0)
     246             :         ZEND_ARG_INFO(0, socket)
     247             : ZEND_END_ARG_INFO()
     248             : 
     249             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
     250             :         ZEND_ARG_INFO(0, socket)
     251             : ZEND_END_ARG_INFO()
     252             : 
     253             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1)
     254             :         ZEND_ARG_INFO(0, stream)
     255             : ZEND_END_ARG_INFO()
     256             : 
     257             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_export_stream, 0, 0, 1)
     258             :         ZEND_ARG_INFO(0, socket)
     259             : ZEND_END_ARG_INFO()
     260             : 
     261             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendmsg, 0, 0, 3)
     262             :         ZEND_ARG_INFO(0, socket)
     263             :         ZEND_ARG_INFO(0, msghdr)
     264             :         ZEND_ARG_INFO(0, flags)
     265             : ZEND_END_ARG_INFO()
     266             : 
     267             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvmsg, 0, 0, 3)
     268             :         ZEND_ARG_INFO(0, socket)
     269             :         ZEND_ARG_INFO(1, msghdr)
     270             :         ZEND_ARG_INFO(0, flags)
     271             : ZEND_END_ARG_INFO()
     272             : 
     273             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_cmsg_space, 0, 0, 2)
     274             :         ZEND_ARG_INFO(0, level)
     275             :         ZEND_ARG_INFO(0, type)
     276             : ZEND_END_ARG_INFO()
     277             : 
     278             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_lookup, 0, 0, 1)
     279             :         ZEND_ARG_INFO(0, host)
     280             :         ZEND_ARG_INFO(0, service)
     281             :         ZEND_ARG_INFO(0, hints)
     282             : ZEND_END_ARG_INFO()
     283             : 
     284             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_connect, 0, 0, 1)
     285             :         ZEND_ARG_INFO(0, addr)
     286             : ZEND_END_ARG_INFO()
     287             : 
     288             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_bind, 0, 0, 1)
     289             :         ZEND_ARG_INFO(0, addr)
     290             : ZEND_END_ARG_INFO()
     291             : 
     292             : ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_explain, 0, 0, 1)
     293             :         ZEND_ARG_INFO(0, addr)
     294             : ZEND_END_ARG_INFO()
     295             : 
     296             : /* }}} */
     297             : 
     298             : static PHP_GINIT_FUNCTION(sockets);
     299             : static PHP_MINIT_FUNCTION(sockets);
     300             : static PHP_MSHUTDOWN_FUNCTION(sockets);
     301             : static PHP_MINFO_FUNCTION(sockets);
     302             : static PHP_RSHUTDOWN_FUNCTION(sockets);
     303             : 
     304             : PHP_FUNCTION(socket_select);
     305             : PHP_FUNCTION(socket_create_listen);
     306             : #ifdef HAVE_SOCKETPAIR
     307             : PHP_FUNCTION(socket_create_pair);
     308             : #endif
     309             : PHP_FUNCTION(socket_accept);
     310             : PHP_FUNCTION(socket_set_nonblock);
     311             : PHP_FUNCTION(socket_set_block);
     312             : PHP_FUNCTION(socket_listen);
     313             : PHP_FUNCTION(socket_close);
     314             : PHP_FUNCTION(socket_write);
     315             : PHP_FUNCTION(socket_read);
     316             : PHP_FUNCTION(socket_getsockname);
     317             : PHP_FUNCTION(socket_getpeername);
     318             : PHP_FUNCTION(socket_create);
     319             : PHP_FUNCTION(socket_connect);
     320             : PHP_FUNCTION(socket_strerror);
     321             : PHP_FUNCTION(socket_bind);
     322             : PHP_FUNCTION(socket_recv);
     323             : PHP_FUNCTION(socket_send);
     324             : PHP_FUNCTION(socket_recvfrom);
     325             : PHP_FUNCTION(socket_sendto);
     326             : PHP_FUNCTION(socket_get_option);
     327             : PHP_FUNCTION(socket_set_option);
     328             : #ifdef HAVE_SHUTDOWN
     329             : PHP_FUNCTION(socket_shutdown);
     330             : #endif
     331             : PHP_FUNCTION(socket_last_error);
     332             : PHP_FUNCTION(socket_clear_error);
     333             : PHP_FUNCTION(socket_import_stream);
     334             : PHP_FUNCTION(socket_export_stream);
     335             : PHP_FUNCTION(socket_addrinfo_lookup);
     336             : PHP_FUNCTION(socket_addrinfo_connect);
     337             : PHP_FUNCTION(socket_addrinfo_bind);
     338             : PHP_FUNCTION(socket_addrinfo_explain);
     339             : 
     340             : /* {{{ sockets_functions[]
     341             :  */
     342             : const zend_function_entry sockets_functions[] = {
     343             :         PHP_FE(socket_select,                   arginfo_socket_select)
     344             :         PHP_FE(socket_create,                   arginfo_socket_create)
     345             :         PHP_FE(socket_create_listen,    arginfo_socket_create_listen)
     346             : #ifdef HAVE_SOCKETPAIR
     347             :         PHP_FE(socket_create_pair,              arginfo_socket_create_pair)
     348             : #endif
     349             :         PHP_FE(socket_accept,                   arginfo_socket_accept)
     350             :         PHP_FE(socket_set_nonblock,             arginfo_socket_set_nonblock)
     351             :         PHP_FE(socket_set_block,                arginfo_socket_set_block)
     352             :         PHP_FE(socket_listen,                   arginfo_socket_listen)
     353             :         PHP_FE(socket_close,                    arginfo_socket_close)
     354             :         PHP_FE(socket_write,                    arginfo_socket_write)
     355             :         PHP_FE(socket_read,                             arginfo_socket_read)
     356             :         PHP_FE(socket_getsockname,              arginfo_socket_getsockname)
     357             :         PHP_FE(socket_getpeername,              arginfo_socket_getpeername)
     358             :         PHP_FE(socket_connect,                  arginfo_socket_connect)
     359             :         PHP_FE(socket_strerror,                 arginfo_socket_strerror)
     360             :         PHP_FE(socket_bind,                             arginfo_socket_bind)
     361             :         PHP_FE(socket_recv,                             arginfo_socket_recv)
     362             :         PHP_FE(socket_send,                             arginfo_socket_send)
     363             :         PHP_FE(socket_recvfrom,                 arginfo_socket_recvfrom)
     364             :         PHP_FE(socket_sendto,                   arginfo_socket_sendto)
     365             :         PHP_FE(socket_get_option,               arginfo_socket_get_option)
     366             :         PHP_FE(socket_set_option,               arginfo_socket_set_option)
     367             : #ifdef HAVE_SHUTDOWN
     368             :         PHP_FE(socket_shutdown,                 arginfo_socket_shutdown)
     369             : #endif
     370             :         PHP_FE(socket_last_error,               arginfo_socket_last_error)
     371             :         PHP_FE(socket_clear_error,              arginfo_socket_clear_error)
     372             :         PHP_FE(socket_import_stream,    arginfo_socket_import_stream)
     373             :         PHP_FE(socket_export_stream,    arginfo_socket_export_stream)
     374             :         PHP_FE(socket_sendmsg,                  arginfo_socket_sendmsg)
     375             :         PHP_FE(socket_recvmsg,                  arginfo_socket_recvmsg)
     376             :         PHP_FE(socket_cmsg_space,               arginfo_socket_cmsg_space)
     377             :         PHP_FE(socket_addrinfo_lookup,  arginfo_socket_addrinfo_lookup)
     378             :         PHP_FE(socket_addrinfo_connect, arginfo_socket_addrinfo_connect)
     379             :         PHP_FE(socket_addrinfo_bind,    arginfo_socket_addrinfo_bind)
     380             :         PHP_FE(socket_addrinfo_explain, arginfo_socket_addrinfo_explain)
     381             : 
     382             :         /* for downwards compatibility */
     383             :         PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)
     384             :         PHP_FALIAS(socket_setopt, socket_set_option, arginfo_socket_set_option)
     385             : 
     386             :         PHP_FE_END
     387             : };
     388             : /* }}} */
     389             : 
     390             : zend_module_entry sockets_module_entry = {
     391             :         STANDARD_MODULE_HEADER,
     392             :         "sockets",
     393             :         sockets_functions,
     394             :         PHP_MINIT(sockets),
     395             :         PHP_MSHUTDOWN(sockets),
     396             :         NULL,
     397             :         PHP_RSHUTDOWN(sockets),
     398             :         PHP_MINFO(sockets),
     399             :         PHP_SOCKETS_VERSION,
     400             :         PHP_MODULE_GLOBALS(sockets),
     401             :         PHP_GINIT(sockets),
     402             :         NULL,
     403             :         NULL,
     404             :         STANDARD_MODULE_PROPERTIES_EX
     405             : };
     406             : 
     407             : 
     408             : #ifdef COMPILE_DL_SOCKETS
     409             : #ifdef ZTS
     410             :         ZEND_TSRMLS_CACHE_DEFINE()
     411             : #endif
     412             : ZEND_GET_MODULE(sockets)
     413             : #endif
     414             : 
     415             : /* inet_ntop should be used instead of inet_ntoa */
     416             : int inet_ntoa_lock = 0;
     417             : 
     418          12 : PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{ */
     419             : {
     420          12 :         return le_socket;
     421             : }
     422             : /* }}} */
     423             : 
     424             : /* allocating function to make programming errors due to uninitialized fields
     425             :  * less likely */
     426         124 : PHP_SOCKETS_API php_socket *php_create_socket(void) /* {{{ */
     427             : {
     428         124 :         php_socket *php_sock = emalloc(sizeof(php_socket));
     429             : 
     430         124 :         php_sock->bsd_socket = -1; /* invalid socket */
     431         124 :         php_sock->type                = PF_UNSPEC;
     432         124 :         php_sock->error               = 0;
     433         124 :         php_sock->blocking    = 1;
     434         124 :         ZVAL_UNDEF(&php_sock->zstream);
     435             : 
     436         124 :         return php_sock;
     437             : }
     438             : /* }}} */
     439             : 
     440         109 : PHP_SOCKETS_API void php_destroy_socket(zend_resource *rsrc) /* {{{ */
     441             : {
     442         109 :         php_socket *php_sock = rsrc->ptr;
     443             : 
     444         218 :         if (Z_ISUNDEF(php_sock->zstream)) {
     445          91 :                 if (!IS_INVALID_SOCKET(php_sock)) {
     446          91 :                         close(php_sock->bsd_socket);
     447             :                 }
     448             :         } else {
     449          18 :                 zval_ptr_dtor(&php_sock->zstream);
     450             :         }
     451         109 :         efree(php_sock);
     452         109 : }
     453             : /* }}} */
     454             : 
     455           4 : PHP_SOCKETS_API void php_destroy_addrinfo(zend_resource *rsrc) /* {{{ */
     456             : {
     457           4 :         struct addrinfo *addr = rsrc->ptr;
     458           4 :         efree(addr->ai_addr);
     459           4 :         if (addr->ai_canonname != NULL) {
     460           0 :                 efree(addr->ai_canonname);
     461             :         }
     462           4 :         efree(addr);
     463           4 : }
     464             : /* }}} */
     465             : 
     466          13 : static int php_open_listen_sock(php_socket **php_sock, int port, int backlog) /* {{{ */
     467             : {
     468             :         struct sockaddr_in  la;
     469             :         struct hostent          *hp;
     470          13 :         php_socket                      *sock = php_create_socket();
     471             : 
     472          13 :         *php_sock = sock;
     473             : 
     474             : #ifndef PHP_WIN32
     475          13 :         if ((hp = php_network_gethostbyname("0.0.0.0")) == NULL) {
     476             : #else
     477             :         if ((hp = php_network_gethostbyname("localhost")) == NULL) {
     478             : #endif
     479           0 :                 efree(sock);
     480           0 :                 return 0;
     481             :         }
     482             : 
     483          13 :         memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length);
     484          13 :         la.sin_family = hp->h_addrtype;
     485          13 :         la.sin_port = htons((unsigned short) port);
     486             : 
     487          13 :         sock->bsd_socket = socket(PF_INET, SOCK_STREAM, 0);
     488          13 :         sock->blocking = 1;
     489             : 
     490          13 :         if (IS_INVALID_SOCKET(sock)) {
     491           0 :                 PHP_SOCKET_ERROR(sock, "unable to create listening socket", errno);
     492           0 :                 efree(sock);
     493           0 :                 return 0;
     494             :         }
     495             : 
     496          13 :         sock->type = PF_INET;
     497             : 
     498          13 :         if (bind(sock->bsd_socket, (struct sockaddr *)&la, sizeof(la)) != 0) {
     499           2 :                 PHP_SOCKET_ERROR(sock, "unable to bind to given address", errno);
     500           2 :                 close(sock->bsd_socket);
     501           2 :                 efree(sock);
     502           2 :                 return 0;
     503             :         }
     504             : 
     505          11 :         if (listen(sock->bsd_socket, backlog) != 0) {
     506           0 :                 PHP_SOCKET_ERROR(sock, "unable to listen on socket", errno);
     507           0 :                 close(sock->bsd_socket);
     508           0 :                 efree(sock);
     509           0 :                 return 0;
     510             :         }
     511             : 
     512          11 :         return 1;
     513             : }
     514             : /* }}} */
     515             : 
     516           6 : static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la, socklen_t *la_len) /* {{{ */
     517             : {
     518           6 :         php_socket      *out_sock = php_create_socket();
     519             : 
     520           6 :         *new_sock = out_sock;
     521             : 
     522           6 :         out_sock->bsd_socket = accept(in_sock->bsd_socket, la, la_len);
     523             : 
     524           6 :         if (IS_INVALID_SOCKET(out_sock)) {
     525           0 :                 PHP_SOCKET_ERROR(out_sock, "unable to accept incoming connection", errno);
     526           0 :                 efree(out_sock);
     527           0 :                 return 0;
     528             :         }
     529             : 
     530           6 :         out_sock->error = 0;
     531           6 :         out_sock->blocking = 1;
     532           6 :         out_sock->type = la->sa_family;
     533             : 
     534           6 :         return 1;
     535             : }
     536             : /* }}} */
     537             : 
     538             : /* {{{ php_read -- wrapper around read() so that it only reads to a \r or \n. */
     539           0 : static int php_read(php_socket *sock, void *buf, size_t maxlen, int flags)
     540             : {
     541           0 :         int m = 0;
     542           0 :         size_t n = 0;
     543           0 :         int no_read = 0;
     544           0 :         int nonblock = 0;
     545           0 :         char *t = (char *) buf;
     546             : 
     547             : #ifndef PHP_WIN32
     548           0 :         m = fcntl(sock->bsd_socket, F_GETFL);
     549           0 :         if (m < 0) {
     550           0 :                 return m;
     551             :         }
     552           0 :         nonblock = (m & O_NONBLOCK);
     553           0 :         m = 0;
     554             : #else
     555             :         nonblock = !sock->blocking;
     556             : #endif
     557           0 :         set_errno(0);
     558             : 
     559           0 :         *t = '\0';
     560           0 :         while (*t != '\n' && *t != '\r' && n < maxlen) {
     561           0 :                 if (m > 0) {
     562           0 :                         t++;
     563           0 :                         n++;
     564           0 :                 } else if (m == 0) {
     565           0 :                         no_read++;
     566           0 :                         if (nonblock && no_read >= 2) {
     567           0 :                                 return n;
     568             :                                 /* The first pass, m always is 0, so no_read becomes 1
     569             :                                  * in the first pass. no_read becomes 2 in the second pass,
     570             :                                  * and if this is nonblocking, we should return.. */
     571             :                         }
     572             : 
     573           0 :                         if (no_read > 200) {
     574           0 :                                 set_errno(ECONNRESET);
     575           0 :                                 return -1;
     576             :                         }
     577             :                 }
     578             : 
     579           0 :                 if (n < maxlen) {
     580           0 :                         m = recv(sock->bsd_socket, (void *) t, 1, flags);
     581             :                 }
     582             : 
     583           0 :                 if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
     584           0 :                         return -1;
     585             :                 }
     586             : 
     587           0 :                 set_errno(0);
     588             :         }
     589             : 
     590           0 :         if (n < maxlen) {
     591           0 :                 n++;
     592             :                 /* The only reasons it makes it to here is
     593             :                  * if '\n' or '\r' are encountered. So, increase
     594             :                  * the return by 1 to make up for the lack of the
     595             :                  * '\n' or '\r' in the count (since read() takes
     596             :                  * place at the end of the loop..) */
     597             :         }
     598             : 
     599           0 :         return n;
     600             : }
     601             : /* }}} */
     602             : 
     603         153 : char *sockets_strerror(int error) /* {{{ */
     604             : {
     605             :         const char *buf;
     606             : 
     607             : #ifndef PHP_WIN32
     608         153 :         if (error < -10000) {
     609           0 :                 error = -error - 10000;
     610             : 
     611             : #ifdef HAVE_HSTRERROR
     612           0 :                 buf = hstrerror(error);
     613             : #else
     614             :                 {
     615             :                         if (SOCKETS_G(strerror_buf)) {
     616             :                                 efree(SOCKETS_G(strerror_buf));
     617             :                         }
     618             : 
     619             :                         spprintf(&(SOCKETS_G(strerror_buf)), 0, "Host lookup error %d", error);
     620             :                         buf = SOCKETS_G(strerror_buf);
     621             :                 }
     622             : #endif
     623             :         } else {
     624         153 :                 buf = strerror(error);
     625             :         }
     626             : #else
     627             :         {
     628             :                 LPTSTR tmp = NULL;
     629             :                 buf = NULL;
     630             : 
     631             :                 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
     632             :                         NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &tmp, 0, NULL)
     633             :                 ) {
     634             :                         if (SOCKETS_G(strerror_buf)) {
     635             :                                 efree(SOCKETS_G(strerror_buf));
     636             :                         }
     637             : 
     638             :                         SOCKETS_G(strerror_buf) = estrdup(tmp);
     639             :                         LocalFree(tmp);
     640             : 
     641             :                         buf = SOCKETS_G(strerror_buf);
     642             :                 }
     643             :         }
     644             : #endif
     645             : 
     646         153 :         return (buf ? (char *) buf : "");
     647             : }
     648             : /* }}} */
     649             : 
     650             : /* {{{ PHP_GINIT_FUNCTION */
     651       23950 : static PHP_GINIT_FUNCTION(sockets)
     652             : {
     653             : #if defined(COMPILE_DL_SOCKETS) && defined(ZTS)
     654             :         ZEND_TSRMLS_CACHE_UPDATE();
     655             : #endif
     656       23950 :         sockets_globals->last_error = 0;
     657       23950 :         sockets_globals->strerror_buf = NULL;
     658       23950 : }
     659             : /* }}} */
     660             : 
     661             : /* {{{ PHP_MINIT_FUNCTION
     662             :  */
     663       23950 : static PHP_MINIT_FUNCTION(sockets)
     664             : {
     665             : #if defined(COMPILE_DL_SOCKETS) && defined(ZTS)
     666             :         ZEND_TSRMLS_CACHE_UPDATE();
     667             : #endif
     668       23950 :         le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);
     669       23950 :         le_addrinfo = zend_register_list_destructors_ex(php_destroy_addrinfo, NULL, le_addrinfo_name, module_number);
     670             : 
     671       23950 :         REGISTER_LONG_CONSTANT("AF_UNIX",             AF_UNIX,                CONST_CS | CONST_PERSISTENT);
     672       23950 :         REGISTER_LONG_CONSTANT("AF_INET",             AF_INET,                CONST_CS | CONST_PERSISTENT);
     673             : #if HAVE_IPV6
     674       23950 :         REGISTER_LONG_CONSTANT("AF_INET6",            AF_INET6,               CONST_CS | CONST_PERSISTENT);
     675             : #endif
     676       23950 :         REGISTER_LONG_CONSTANT("SOCK_STREAM", SOCK_STREAM,    CONST_CS | CONST_PERSISTENT);
     677       23950 :         REGISTER_LONG_CONSTANT("SOCK_DGRAM",  SOCK_DGRAM,             CONST_CS | CONST_PERSISTENT);
     678       23950 :         REGISTER_LONG_CONSTANT("SOCK_RAW",            SOCK_RAW,               CONST_CS | CONST_PERSISTENT);
     679       23950 :         REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT);
     680       23950 :         REGISTER_LONG_CONSTANT("SOCK_RDM",            SOCK_RDM,               CONST_CS | CONST_PERSISTENT);
     681             : 
     682       23950 :         REGISTER_LONG_CONSTANT("MSG_OOB",             MSG_OOB,                CONST_CS | CONST_PERSISTENT);
     683       23950 :         REGISTER_LONG_CONSTANT("MSG_WAITALL", MSG_WAITALL,    CONST_CS | CONST_PERSISTENT);
     684       23950 :         REGISTER_LONG_CONSTANT("MSG_CTRUNC",  MSG_CTRUNC,             CONST_CS | CONST_PERSISTENT);
     685       23950 :         REGISTER_LONG_CONSTANT("MSG_TRUNC",           MSG_TRUNC,              CONST_CS | CONST_PERSISTENT);
     686       23950 :         REGISTER_LONG_CONSTANT("MSG_PEEK",            MSG_PEEK,               CONST_CS | CONST_PERSISTENT);
     687       23950 :         REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE,        CONST_CS | CONST_PERSISTENT);
     688             : #ifdef MSG_EOR
     689       23950 :         REGISTER_LONG_CONSTANT("MSG_EOR",             MSG_EOR,                CONST_CS | CONST_PERSISTENT);
     690             : #endif
     691             : #ifdef MSG_EOF
     692       23950 :         REGISTER_LONG_CONSTANT("MSG_EOF",             MSG_EOF,                CONST_CS | CONST_PERSISTENT);
     693             : #endif
     694             : 
     695             : #ifdef MSG_CONFIRM
     696       23950 :         REGISTER_LONG_CONSTANT("MSG_CONFIRM", MSG_CONFIRM,    CONST_CS | CONST_PERSISTENT);
     697             : #endif
     698             : #ifdef MSG_ERRQUEUE
     699       23950 :         REGISTER_LONG_CONSTANT("MSG_ERRQUEUE",        MSG_ERRQUEUE,   CONST_CS | CONST_PERSISTENT);
     700             : #endif
     701             : #ifdef MSG_NOSIGNAL
     702       23950 :         REGISTER_LONG_CONSTANT("MSG_NOSIGNAL",        MSG_NOSIGNAL,   CONST_CS | CONST_PERSISTENT);
     703             : #endif
     704             : #ifdef MSG_DONTWAIT
     705       23950 :         REGISTER_LONG_CONSTANT("MSG_DONTWAIT",        MSG_DONTWAIT,   CONST_CS | CONST_PERSISTENT);
     706             : #endif
     707             : #ifdef MSG_MORE
     708       23950 :         REGISTER_LONG_CONSTANT("MSG_MORE",            MSG_MORE,               CONST_CS | CONST_PERSISTENT);
     709             : #endif
     710             : #ifdef MSG_WAITFORONE
     711       23950 :         REGISTER_LONG_CONSTANT("MSG_WAITFORONE",MSG_WAITFORONE,       CONST_CS | CONST_PERSISTENT);
     712             : #endif
     713             : #ifdef MSG_CMSG_CLOEXEC
     714       23950 :         REGISTER_LONG_CONSTANT("MSG_CMSG_CLOEXEC",MSG_CMSG_CLOEXEC,CONST_CS | CONST_PERSISTENT);
     715             : #endif
     716             : 
     717       23950 :         REGISTER_LONG_CONSTANT("SO_DEBUG",            SO_DEBUG,               CONST_CS | CONST_PERSISTENT);
     718       23950 :         REGISTER_LONG_CONSTANT("SO_REUSEADDR",        SO_REUSEADDR,   CONST_CS | CONST_PERSISTENT);
     719             : #ifdef SO_REUSEPORT
     720       23950 :         REGISTER_LONG_CONSTANT("SO_REUSEPORT",        SO_REUSEPORT,   CONST_CS | CONST_PERSISTENT);
     721             : #endif
     722       23950 :         REGISTER_LONG_CONSTANT("SO_KEEPALIVE",        SO_KEEPALIVE,   CONST_CS | CONST_PERSISTENT);
     723       23950 :         REGISTER_LONG_CONSTANT("SO_DONTROUTE",        SO_DONTROUTE,   CONST_CS | CONST_PERSISTENT);
     724       23950 :         REGISTER_LONG_CONSTANT("SO_LINGER",           SO_LINGER,              CONST_CS | CONST_PERSISTENT);
     725       23950 :         REGISTER_LONG_CONSTANT("SO_BROADCAST",        SO_BROADCAST,   CONST_CS | CONST_PERSISTENT);
     726       23950 :         REGISTER_LONG_CONSTANT("SO_OOBINLINE",        SO_OOBINLINE,   CONST_CS | CONST_PERSISTENT);
     727       23950 :         REGISTER_LONG_CONSTANT("SO_SNDBUF",           SO_SNDBUF,              CONST_CS | CONST_PERSISTENT);
     728       23950 :         REGISTER_LONG_CONSTANT("SO_RCVBUF",           SO_RCVBUF,              CONST_CS | CONST_PERSISTENT);
     729       23950 :         REGISTER_LONG_CONSTANT("SO_SNDLOWAT", SO_SNDLOWAT,    CONST_CS | CONST_PERSISTENT);
     730       23950 :         REGISTER_LONG_CONSTANT("SO_RCVLOWAT", SO_RCVLOWAT,    CONST_CS | CONST_PERSISTENT);
     731       23950 :         REGISTER_LONG_CONSTANT("SO_SNDTIMEO", SO_SNDTIMEO,    CONST_CS | CONST_PERSISTENT);
     732       23950 :         REGISTER_LONG_CONSTANT("SO_RCVTIMEO", SO_RCVTIMEO,    CONST_CS | CONST_PERSISTENT);
     733       23950 :         REGISTER_LONG_CONSTANT("SO_TYPE",             SO_TYPE,                CONST_CS | CONST_PERSISTENT);
     734             : #ifdef SO_FAMILY
     735             :         REGISTER_LONG_CONSTANT("SO_FAMILY",           SO_FAMILY,              CONST_CS | CONST_PERSISTENT);
     736             : #endif
     737       23950 :         REGISTER_LONG_CONSTANT("SO_ERROR",            SO_ERROR,               CONST_CS | CONST_PERSISTENT);
     738             : #ifdef SO_BINDTODEVICE
     739       23950 :         REGISTER_LONG_CONSTANT("SO_BINDTODEVICE",       SO_BINDTODEVICE,        CONST_CS | CONST_PERSISTENT);
     740             : #endif
     741       23950 :         REGISTER_LONG_CONSTANT("SOL_SOCKET",  SOL_SOCKET,             CONST_CS | CONST_PERSISTENT);
     742       23950 :         REGISTER_LONG_CONSTANT("SOMAXCONN",           SOMAXCONN,              CONST_CS | CONST_PERSISTENT);
     743             : #ifdef TCP_NODELAY
     744       23950 :         REGISTER_LONG_CONSTANT("TCP_NODELAY",   TCP_NODELAY,    CONST_CS | CONST_PERSISTENT);
     745             : #endif
     746       23950 :         REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
     747       23950 :         REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
     748             : 
     749       23950 :         REGISTER_LONG_CONSTANT("MCAST_JOIN_GROUP",                    PHP_MCAST_JOIN_GROUP,                   CONST_CS | CONST_PERSISTENT);
     750       23950 :         REGISTER_LONG_CONSTANT("MCAST_LEAVE_GROUP",                   PHP_MCAST_LEAVE_GROUP,                  CONST_CS | CONST_PERSISTENT);
     751             : #ifdef HAS_MCAST_EXT
     752       23950 :         REGISTER_LONG_CONSTANT("MCAST_BLOCK_SOURCE",          PHP_MCAST_BLOCK_SOURCE,                 CONST_CS | CONST_PERSISTENT);
     753       23950 :         REGISTER_LONG_CONSTANT("MCAST_UNBLOCK_SOURCE",                PHP_MCAST_UNBLOCK_SOURCE,               CONST_CS | CONST_PERSISTENT);
     754       23950 :         REGISTER_LONG_CONSTANT("MCAST_JOIN_SOURCE_GROUP",     PHP_MCAST_JOIN_SOURCE_GROUP,    CONST_CS | CONST_PERSISTENT);
     755       23950 :         REGISTER_LONG_CONSTANT("MCAST_LEAVE_SOURCE_GROUP",    PHP_MCAST_LEAVE_SOURCE_GROUP,   CONST_CS | CONST_PERSISTENT);
     756             : #endif
     757             : 
     758       23950 :         REGISTER_LONG_CONSTANT("IP_MULTICAST_IF",                     IP_MULTICAST_IF,                CONST_CS | CONST_PERSISTENT);
     759       23950 :         REGISTER_LONG_CONSTANT("IP_MULTICAST_TTL",                    IP_MULTICAST_TTL,               CONST_CS | CONST_PERSISTENT);
     760       23950 :         REGISTER_LONG_CONSTANT("IP_MULTICAST_LOOP",                   IP_MULTICAST_LOOP,              CONST_CS | CONST_PERSISTENT);
     761             : #if HAVE_IPV6
     762       23950 :         REGISTER_LONG_CONSTANT("IPV6_MULTICAST_IF",                   IPV6_MULTICAST_IF,              CONST_CS | CONST_PERSISTENT);
     763       23950 :         REGISTER_LONG_CONSTANT("IPV6_MULTICAST_HOPS",         IPV6_MULTICAST_HOPS,    CONST_CS | CONST_PERSISTENT);
     764       23950 :         REGISTER_LONG_CONSTANT("IPV6_MULTICAST_LOOP",         IPV6_MULTICAST_LOOP,    CONST_CS | CONST_PERSISTENT);
     765             : #endif
     766             : 
     767             : #ifdef IPV6_V6ONLY
     768       23950 :         REGISTER_LONG_CONSTANT("IPV6_V6ONLY",                 IPV6_V6ONLY,            CONST_CS | CONST_PERSISTENT);
     769             : #endif
     770             : 
     771             : #ifndef WIN32
     772             : # include "unix_socket_constants.h"
     773             : #else
     774             : # include "win32_socket_constants.h"
     775             : #endif
     776             : 
     777       23950 :         REGISTER_LONG_CONSTANT("IPPROTO_IP",  IPPROTO_IP,             CONST_CS | CONST_PERSISTENT);
     778             : #if HAVE_IPV6
     779       23950 :         REGISTER_LONG_CONSTANT("IPPROTO_IPV6",        IPPROTO_IPV6,   CONST_CS | CONST_PERSISTENT);
     780             : #endif
     781             : 
     782       23950 :         REGISTER_LONG_CONSTANT("SOL_TCP",             IPPROTO_TCP,    CONST_CS | CONST_PERSISTENT);
     783       23950 :         REGISTER_LONG_CONSTANT("SOL_UDP",             IPPROTO_UDP,    CONST_CS | CONST_PERSISTENT);
     784             : 
     785             : #if HAVE_IPV6
     786       23950 :         REGISTER_LONG_CONSTANT("IPV6_UNICAST_HOPS",                   IPV6_UNICAST_HOPS,      CONST_CS | CONST_PERSISTENT);
     787             : #endif
     788             : 
     789       23950 :         REGISTER_LONG_CONSTANT("AI_PASSIVE",          AI_PASSIVE,                     CONST_CS | CONST_PERSISTENT);
     790       23950 :         REGISTER_LONG_CONSTANT("AI_CANONNAME",                AI_CANONNAME,           CONST_CS | CONST_PERSISTENT);
     791       23950 :         REGISTER_LONG_CONSTANT("AI_NUMERICHOST",      AI_NUMERICHOST,         CONST_CS | CONST_PERSISTENT);
     792       23950 :         REGISTER_LONG_CONSTANT("AI_V4MAPPED",         AI_V4MAPPED,            CONST_CS | CONST_PERSISTENT);
     793       23950 :         REGISTER_LONG_CONSTANT("AI_ALL",                      AI_ALL,                         CONST_CS | CONST_PERSISTENT);
     794       23950 :         REGISTER_LONG_CONSTANT("AI_ADDRCONFIG",               AI_ADDRCONFIG,          CONST_CS | CONST_PERSISTENT);
     795             : #ifdef __USE_GNU
     796       23950 :         REGISTER_LONG_CONSTANT("AI_IDN",                      AI_IDN,                         CONST_CS | CONST_PERSISTENT);
     797       23950 :         REGISTER_LONG_CONSTANT("AI_CANONIDN",         AI_CANONIDN,            CONST_CS | CONST_PERSISTENT);
     798       23950 :         REGISTER_LONG_CONSTANT("AI_IDN_ALLOW_UNASSIGNED",             AI_IDN_ALLOW_UNASSIGNED, CONST_CS | CONST_PERSISTENT);
     799       23950 :         REGISTER_LONG_CONSTANT("AI_IDN_USE_STD3_ASCII_RULES", AI_IDN_USE_STD3_ASCII_RULES, CONST_CS | CONST_PERSISTENT);
     800             : #endif
     801       23950 :         REGISTER_LONG_CONSTANT("AI_NUMERICSERV",      AI_NUMERICSERV,         CONST_CS | CONST_PERSISTENT);
     802             : 
     803       23950 :         php_socket_sendrecvmsg_init(INIT_FUNC_ARGS_PASSTHRU);
     804             : 
     805       23950 :         return SUCCESS;
     806             : }
     807             : /* }}} */
     808             : 
     809             : /* {{{ PHP_MSHUTDOWN_FUNCTION
     810             :  */
     811       23969 : static PHP_MSHUTDOWN_FUNCTION(sockets)
     812             : {
     813       23969 :         php_socket_sendrecvmsg_shutdown(SHUTDOWN_FUNC_ARGS_PASSTHRU);
     814             : 
     815       23969 :         return SUCCESS;
     816             : }
     817             : /* }}} */
     818             : 
     819             : /* {{{ PHP_MINFO_FUNCTION
     820             :  */
     821         143 : static PHP_MINFO_FUNCTION(sockets)
     822             : {
     823         143 :         php_info_print_table_start();
     824         143 :         php_info_print_table_row(2, "Sockets Support", "enabled");
     825         143 :         php_info_print_table_end();
     826         143 : }
     827             : /* }}} */
     828             : 
     829             : /* {{{ PHP_RSHUTDOWN_FUNCTION */
     830       23925 : static PHP_RSHUTDOWN_FUNCTION(sockets)
     831             : {
     832       23925 :         if (SOCKETS_G(strerror_buf)) {
     833           0 :                 efree(SOCKETS_G(strerror_buf));
     834           0 :                 SOCKETS_G(strerror_buf) = NULL;
     835             :         }
     836             : 
     837       23925 :         return SUCCESS;
     838             : }
     839             : /* }}} */
     840             : 
     841          28 : static int php_sock_array_to_fd_set(zval *sock_array, fd_set *fds, PHP_SOCKET *max_fd) /* {{{ */
     842             : {
     843             :         zval            *element;
     844             :         php_socket      *php_sock;
     845          28 :         int                     num = 0;
     846             : 
     847          28 :         if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
     848             : 
     849          60 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(sock_array), element) {
     850          16 :                 php_sock = (php_socket*) zend_fetch_resource_ex(element, le_socket_name, le_socket);
     851          16 :                 if (!php_sock) continue; /* If element is not a resource, skip it */
     852             : 
     853          16 :                 PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
     854          16 :                 if (php_sock->bsd_socket > *max_fd) {
     855          16 :                         *max_fd = php_sock->bsd_socket;
     856             :                 }
     857          16 :                 num++;
     858             :         } ZEND_HASH_FOREACH_END();
     859             : 
     860          28 :         return num ? 1 : 0;
     861             : }
     862             : /* }}} */
     863             : 
     864          27 : static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds) /* {{{ */
     865             : {
     866             :         zval            *element;
     867             :         zval            *dest_element;
     868             :         php_socket      *php_sock;
     869             :         zval            new_hash;
     870          27 :         int                     num = 0;
     871             :         zend_ulong       num_key;
     872             :         zend_string *key;
     873             : 
     874          27 :         if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
     875             : 
     876          27 :         array_init(&new_hash);
     877          55 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(sock_array), num_key, key, element) {
     878          14 :                 php_sock = (php_socket*) zend_fetch_resource_ex(element, le_socket_name, le_socket);
     879          14 :                 if (!php_sock) continue; /* If element is not a resource, skip it */
     880             : 
     881          14 :                 if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
     882             :                         /* Add fd to new array */
     883           7 :                         if (key) {
     884           0 :                                 dest_element = zend_hash_add(Z_ARRVAL(new_hash), key, element);
     885             :                         } else {
     886           7 :                                 dest_element = zend_hash_index_update(Z_ARRVAL(new_hash), num_key, element);
     887             :                         }
     888           7 :                         if (dest_element) {
     889             :                                 Z_ADDREF_P(dest_element);
     890             :                         }
     891             :                 }
     892          14 :                 num++;
     893             :         } ZEND_HASH_FOREACH_END();
     894             : 
     895             :         /* Destroy old array, add new one */
     896          27 :         zval_ptr_dtor(sock_array);
     897             : 
     898          27 :         ZVAL_COPY_VALUE(sock_array, &new_hash);
     899             : 
     900          27 :         return num ? 1 : 0;
     901             : }
     902             : /* }}} */
     903             : 
     904             : /* {{{ proto int socket_select(array &read_fds, array &write_fds, array &except_fds, int tv_sec[, int tv_usec])
     905             :    Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec */
     906          14 : PHP_FUNCTION(socket_select)
     907             : {
     908             :         zval                    *r_array, *w_array, *e_array, *sec;
     909             :         struct timeval  tv;
     910          14 :         struct timeval *tv_p = NULL;
     911             :         fd_set                  rfds, wfds, efds;
     912          14 :         PHP_SOCKET              max_fd = 0;
     913          14 :         int                             retval, sets = 0;
     914          14 :         zend_long                       usec = 0;
     915             : 
     916          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/!a/!a/!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE) {
     917           1 :                 return;
     918             :         }
     919             : 
     920          13 :         FD_ZERO(&rfds);
     921          13 :         FD_ZERO(&wfds);
     922          13 :         FD_ZERO(&efds);
     923             : 
     924          13 :         if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd);
     925          13 :         if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd);
     926          13 :         if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd);
     927             : 
     928          13 :         if (!sets) {
     929           1 :                 php_error_docref(NULL, E_WARNING, "no resource arrays were passed to select");
     930           1 :                 RETURN_FALSE;
     931             :         }
     932             : 
     933          12 :         PHP_SAFE_MAX_FD(max_fd, 0); /* someone needs to make this look more like stream_socket_select */
     934             : 
     935             :         /* If seconds is not set to null, build the timeval, else we wait indefinitely */
     936          12 :         if (sec != NULL) {
     937             :                 zval tmp;
     938             : 
     939          24 :                 if (Z_TYPE_P(sec) != IS_LONG) {
     940           1 :                         tmp = *sec;
     941             :                         zval_copy_ctor(&tmp);
     942           1 :                         convert_to_long(&tmp);
     943           1 :                         sec = &tmp;
     944             :                 }
     945             : 
     946             :                 /* Solaris + BSD do not like microsecond values which are >= 1 sec */
     947          12 :                 if (usec > 999999) {
     948           1 :                         tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000);
     949           1 :                         tv.tv_usec = usec % 1000000;
     950             :                 } else {
     951          11 :                         tv.tv_sec = Z_LVAL_P(sec);
     952          11 :                         tv.tv_usec = usec;
     953             :                 }
     954             : 
     955          12 :                 tv_p = &tv;
     956             : 
     957          12 :                 if (sec == &tmp) {
     958             :                         zval_dtor(&tmp);
     959             :                 }
     960             :         }
     961             : 
     962          12 :         retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p);
     963             : 
     964          12 :         if (retval == -1) {
     965           1 :                 SOCKETS_G(last_error) = errno;
     966           1 :                 php_error_docref(NULL, E_WARNING, "unable to select [%d]: %s", errno, sockets_strerror(errno));
     967           1 :                 RETURN_FALSE;
     968             :         }
     969             : 
     970          11 :         if (r_array != NULL) php_sock_array_from_fd_set(r_array, &rfds);
     971          11 :         if (w_array != NULL) php_sock_array_from_fd_set(w_array, &wfds);
     972          11 :         if (e_array != NULL) php_sock_array_from_fd_set(e_array, &efds);
     973             : 
     974          11 :         RETURN_LONG(retval);
     975             : }
     976             : /* }}} */
     977             : 
     978             : /* {{{ proto resource socket_create_listen(int port[, int backlog])
     979             :    Opens a socket on port to accept connections */
     980          16 : PHP_FUNCTION(socket_create_listen)
     981             : {
     982             :         php_socket      *php_sock;
     983          16 :         zend_long               port, backlog = 128;
     984             : 
     985          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &port, &backlog) == FAILURE) {
     986           3 :                 return;
     987             :         }
     988             : 
     989          13 :         if (!php_open_listen_sock(&php_sock, port, backlog)) {
     990           2 :                 RETURN_FALSE;
     991             :         }
     992             : 
     993          11 :         php_sock->error = 0;
     994          11 :         php_sock->blocking = 1;
     995             : 
     996          11 :         RETURN_RES(zend_register_resource(php_sock, le_socket));
     997             : }
     998             : /* }}} */
     999             : 
    1000             : /* {{{ proto resource socket_accept(resource socket)
    1001             :    Accepts a connection on the listening socket fd */
    1002           7 : PHP_FUNCTION(socket_accept)
    1003             : {
    1004             :         zval                             *arg1;
    1005             :         php_socket                       *php_sock, *new_sock;
    1006             :         php_sockaddr_storage sa;
    1007           7 :         socklen_t                        php_sa_len = sizeof(sa);
    1008             : 
    1009           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
    1010           1 :                 return;
    1011             :         }
    1012             : 
    1013           6 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1014           0 :                 RETURN_FALSE;
    1015             :         }
    1016             : 
    1017           6 :         if (!php_accept_connect(php_sock, &new_sock, (struct sockaddr*)&sa, &php_sa_len)) {
    1018           0 :                 RETURN_FALSE;
    1019             :         }
    1020             : 
    1021           6 :         RETURN_RES(zend_register_resource(new_sock, le_socket));
    1022             : }
    1023             : /* }}} */
    1024             : 
    1025             : /* {{{ proto bool socket_set_nonblock(resource socket)
    1026             :    Sets nonblocking mode on a socket resource */
    1027          15 : PHP_FUNCTION(socket_set_nonblock)
    1028             : {
    1029             :         zval            *arg1;
    1030             :         php_socket      *php_sock;
    1031             : 
    1032          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
    1033           1 :                 return;
    1034             :         }
    1035             : 
    1036          14 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1037           1 :                 RETURN_FALSE;
    1038             :         }
    1039             : 
    1040          26 :         if (!Z_ISUNDEF(php_sock->zstream)) {
    1041             :                 php_stream *stream;
    1042             :                 /* omit notice if resource doesn't exist anymore */
    1043           0 :                 stream = zend_fetch_resource2_ex(&php_sock->zstream, NULL, php_file_le_stream(), php_file_le_pstream());
    1044           0 :                 if (stream != NULL) {
    1045           0 :                         if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 0,
    1046             :                                         NULL) != -1) {
    1047           0 :                                 php_sock->blocking = 0;
    1048           0 :                                 RETURN_TRUE;
    1049             :                         }
    1050             :                 }
    1051             :         }
    1052             : 
    1053          13 :         if (php_set_sock_blocking(php_sock->bsd_socket, 0) == SUCCESS) {
    1054          13 :                 php_sock->blocking = 0;
    1055          13 :                 RETURN_TRUE;
    1056             :         } else {
    1057           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to set nonblocking mode", errno);
    1058           0 :                 RETURN_FALSE;
    1059             :         }
    1060             : }
    1061             : /* }}} */
    1062             : 
    1063             : /* {{{ proto bool socket_set_block(resource socket)
    1064             :    Sets blocking mode on a socket resource */
    1065          13 : PHP_FUNCTION(socket_set_block)
    1066             : {
    1067             :         zval            *arg1;
    1068             :         php_socket      *php_sock;
    1069             : 
    1070          13 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
    1071           1 :                 return;
    1072             :         }
    1073             : 
    1074          12 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1075           3 :                 RETURN_FALSE;
    1076             :         }
    1077             : 
    1078             :         /* if socket was created from a stream, give the stream a chance to take
    1079             :          * care of the operation itself, thereby allowing it to update its internal
    1080             :          * state */
    1081          18 :         if (!Z_ISUNDEF(php_sock->zstream)) {
    1082             :                 php_stream *stream;
    1083           6 :                 stream = zend_fetch_resource2_ex(&php_sock->zstream, NULL, php_file_le_stream(), php_file_le_pstream());
    1084           6 :                 if (stream != NULL) {
    1085           4 :                         if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 1,
    1086             :                                         NULL) != -1) {
    1087           4 :                                 php_sock->blocking = 1;
    1088           4 :                                 RETURN_TRUE;
    1089             :                         }
    1090             :                 }
    1091             :         }
    1092             : 
    1093           5 :         if (php_set_sock_blocking(php_sock->bsd_socket, 1) == SUCCESS) {
    1094           3 :                 php_sock->blocking = 1;
    1095           3 :                 RETURN_TRUE;
    1096             :         } else {
    1097           2 :                 PHP_SOCKET_ERROR(php_sock, "unable to set blocking mode", errno);
    1098           2 :                 RETURN_FALSE;
    1099             :         }
    1100             : }
    1101             : /* }}} */
    1102             : 
    1103             : /* {{{ proto bool socket_listen(resource socket[, int backlog])
    1104             :    Sets the maximum number of connections allowed to be waited for on the socket specified by fd */
    1105           9 : PHP_FUNCTION(socket_listen)
    1106             : {
    1107             :         zval            *arg1;
    1108             :         php_socket      *php_sock;
    1109           9 :         zend_long               backlog = 0;
    1110             : 
    1111           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &arg1, &backlog) == FAILURE) {
    1112           2 :                 return;
    1113             :         }
    1114             : 
    1115           7 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1116           0 :                 RETURN_FALSE;
    1117             :         }
    1118             : 
    1119           7 :         if (listen(php_sock->bsd_socket, backlog) != 0) {
    1120           1 :                 PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno);
    1121           1 :                 RETURN_FALSE;
    1122             :         }
    1123           6 :         RETURN_TRUE;
    1124             : }
    1125             : /* }}} */
    1126             : 
    1127             : /* {{{ proto void socket_close(resource socket)
    1128             :    Closes a file descriptor */
    1129          49 : PHP_FUNCTION(socket_close)
    1130             : {
    1131             :         zval            *arg1;
    1132             :         php_socket      *php_sock;
    1133             : 
    1134          49 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
    1135           4 :                 return;
    1136             :         }
    1137             : 
    1138          45 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1139           0 :                 RETURN_FALSE;
    1140             :         }
    1141             : 
    1142          90 :         if (!Z_ISUNDEF(php_sock->zstream)) {
    1143           3 :                 php_stream *stream = NULL;
    1144           3 :                 php_stream_from_zval_no_verify(stream, &php_sock->zstream);
    1145           3 :                 if (stream != NULL) {
    1146             :                         /* close & destroy stream, incl. removing it from the rsrc list;
    1147             :                          * resource stored in php_sock->zstream will become invalid */
    1148           3 :                         php_stream_free(stream,
    1149             :                                         PHP_STREAM_FREE_KEEP_RSRC | PHP_STREAM_FREE_CLOSE |
    1150             :                                         (stream->is_persistent?PHP_STREAM_FREE_CLOSE_PERSISTENT:0));
    1151             :                 }
    1152             :         }
    1153          45 :         zend_list_close(Z_RES_P(arg1));
    1154             : }
    1155             : /* }}} */
    1156             : 
    1157             : /* {{{ proto int socket_write(resource socket, string buf[, int length])
    1158             :    Writes the buffer to the socket resource, length is optional */
    1159           9 : PHP_FUNCTION(socket_write)
    1160             : {
    1161             :         zval            *arg1;
    1162             :         php_socket      *php_sock;
    1163             :         int                     retval;
    1164             :         size_t      str_len;
    1165           9 :         zend_long       length = 0;
    1166             :         char            *str;
    1167             : 
    1168           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &arg1, &str, &str_len, &length) == FAILURE) {
    1169           2 :                 return;
    1170             :         }
    1171             : 
    1172           7 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1173           0 :                 RETURN_FALSE;
    1174             :         }
    1175             : 
    1176           7 :         if (ZEND_NUM_ARGS() < 3) {
    1177           7 :                 length = str_len;
    1178             :         }
    1179             : 
    1180             : #ifndef PHP_WIN32
    1181           7 :         retval = write(php_sock->bsd_socket, str, MIN(length, str_len));
    1182             : #else
    1183             :         retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);
    1184             : #endif
    1185             : 
    1186           7 :         if (retval < 0) {
    1187           1 :                 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
    1188           1 :                 RETURN_FALSE;
    1189             :         }
    1190             : 
    1191           6 :         RETURN_LONG(retval);
    1192             : }
    1193             : /* }}} */
    1194             : 
    1195             : /* {{{ proto string socket_read(resource socket, int length [, int type])
    1196             :    Reads a maximum of length bytes from socket */
    1197          14 : PHP_FUNCTION(socket_read)
    1198             : {
    1199             :         zval            *arg1;
    1200             :         php_socket      *php_sock;
    1201             :         zend_string     *tmpbuf;
    1202             :         int                     retval;
    1203          14 :         zend_long               length, type = PHP_BINARY_READ;
    1204             : 
    1205          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|l", &arg1, &length, &type) == FAILURE) {
    1206           2 :                 return;
    1207             :         }
    1208             : 
    1209             :         /* overflow check */
    1210          12 :         if ((length + 1) < 2) {
    1211           0 :                 RETURN_FALSE;
    1212             :         }
    1213             : 
    1214          24 :         tmpbuf = zend_string_alloc(length, 0);
    1215             : 
    1216          12 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1217           0 :                 RETURN_FALSE;
    1218             :         }
    1219             : 
    1220          12 :         if (type == PHP_NORMAL_READ) {
    1221           0 :                 retval = php_read(php_sock, ZSTR_VAL(tmpbuf), length, 0);
    1222             :         } else {
    1223          12 :                 retval = recv(php_sock->bsd_socket, ZSTR_VAL(tmpbuf), length, 0);
    1224             :         }
    1225             : 
    1226          12 :         if (retval == -1) {
    1227             :                 /* if the socket is in non-blocking mode and there's no data to read,
    1228             :                 don't output any error, as this is a normal situation, and not an error */
    1229           2 :                 if (errno == EAGAIN
    1230             : #ifdef EWOULDBLOCK
    1231           1 :                 || errno == EWOULDBLOCK
    1232             : #endif
    1233             :                 ) {
    1234           0 :                         php_sock->error = errno;
    1235           0 :                         SOCKETS_G(last_error) = errno;
    1236             :                 } else {
    1237           1 :                         PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
    1238             :                 }
    1239             : 
    1240             :                 zend_string_free(tmpbuf);
    1241           1 :                 RETURN_FALSE;
    1242          11 :         } else if (!retval) {
    1243             :                 zend_string_free(tmpbuf);
    1244           0 :                 RETURN_EMPTY_STRING();
    1245             :         }
    1246             : 
    1247          22 :         tmpbuf = zend_string_truncate(tmpbuf, retval, 0);
    1248          11 :         ZSTR_LEN(tmpbuf) = retval;
    1249          11 :         ZSTR_VAL(tmpbuf)[ZSTR_LEN(tmpbuf)] = '\0' ;
    1250             : 
    1251          11 :         RETURN_NEW_STR(tmpbuf);
    1252             : }
    1253             : /* }}} */
    1254             : 
    1255             : /* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port])
    1256             :    Queries the remote side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type. */
    1257           2 : PHP_FUNCTION(socket_getsockname)
    1258             : {
    1259           2 :         zval                                    *arg1, *addr, *port = NULL;
    1260             :         php_sockaddr_storage    sa_storage;
    1261             :         php_socket                              *php_sock;
    1262             :         struct sockaddr                 *sa;
    1263             :         struct sockaddr_in              *sin;
    1264             : #if HAVE_IPV6
    1265             :         struct sockaddr_in6             *sin6;
    1266             :         char                                    addr6[INET6_ADDRSTRLEN+1];
    1267             : #endif
    1268             :         struct sockaddr_un              *s_un;
    1269             :         char                                    *addr_string;
    1270           2 :         socklen_t                               salen = sizeof(php_sockaddr_storage);
    1271             : 
    1272           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &addr, &port) == FAILURE) {
    1273           0 :                 return;
    1274             :         }
    1275             : 
    1276           2 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1277           0 :                 RETURN_FALSE;
    1278             :         }
    1279             : 
    1280           2 :         sa = (struct sockaddr *) &sa_storage;
    1281             : 
    1282           2 :         if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
    1283           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
    1284           0 :                 RETURN_FALSE;
    1285             :         }
    1286             : 
    1287           2 :         if (port != NULL) {
    1288           4 :                 ZVAL_DEREF(port);
    1289             :         }
    1290             : 
    1291           2 :         switch (sa->sa_family) {
    1292             : #if HAVE_IPV6
    1293             :                 case AF_INET6:
    1294           0 :                         sin6 = (struct sockaddr_in6 *) sa;
    1295           0 :                         inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
    1296           0 :                         zval_dtor(addr);
    1297           0 :                         ZVAL_STRING(addr, addr6);
    1298             : 
    1299           0 :                         if (port != NULL) {
    1300           0 :                                 zval_dtor(port);
    1301           0 :                                 ZVAL_LONG(port, htons(sin6->sin6_port));
    1302             :                         }
    1303           0 :                         RETURN_TRUE;
    1304             :                         break;
    1305             : #endif
    1306             :                 case AF_INET:
    1307           2 :                         sin = (struct sockaddr_in *) sa;
    1308           2 :                         while (inet_ntoa_lock == 1);
    1309           2 :                         inet_ntoa_lock = 1;
    1310           2 :                         addr_string = inet_ntoa(sin->sin_addr);
    1311           2 :                         inet_ntoa_lock = 0;
    1312             : 
    1313           2 :                         zval_dtor(addr);
    1314           4 :                         ZVAL_STRING(addr, addr_string);
    1315             : 
    1316           2 :                         if (port != NULL) {
    1317           2 :                                 zval_dtor(port);
    1318           2 :                                 ZVAL_LONG(port, htons(sin->sin_port));
    1319             :                         }
    1320           2 :                         RETURN_TRUE;
    1321             :                         break;
    1322             : 
    1323             :                 case AF_UNIX:
    1324           0 :                         s_un = (struct sockaddr_un *) sa;
    1325             : 
    1326           0 :                         zval_dtor(addr);
    1327           0 :                         ZVAL_STRING(addr, s_un->sun_path);
    1328           0 :                         RETURN_TRUE;
    1329             :                         break;
    1330             : 
    1331             :                 default:
    1332           0 :                         php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
    1333           0 :                         RETURN_FALSE;
    1334             :         }
    1335             : }
    1336             : /* }}} */
    1337             : 
    1338             : /* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port])
    1339             :    Queries the remote side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type. */
    1340           3 : PHP_FUNCTION(socket_getpeername)
    1341             : {
    1342           3 :         zval                                    *arg1, *arg2, *arg3 = NULL;
    1343             :         php_sockaddr_storage    sa_storage;
    1344             :         php_socket                              *php_sock;
    1345             :         struct sockaddr                 *sa;
    1346             :         struct sockaddr_in              *sin;
    1347             : #if HAVE_IPV6
    1348             :         struct sockaddr_in6             *sin6;
    1349             :         char                                    addr6[INET6_ADDRSTRLEN+1];
    1350             : #endif
    1351             :         struct sockaddr_un              *s_un;
    1352             :         char                                    *addr_string;
    1353           3 :         socklen_t                               salen = sizeof(php_sockaddr_storage);
    1354             : 
    1355           3 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &arg2, &arg3) == FAILURE) {
    1356           0 :                 return;
    1357             :         }
    1358             : 
    1359           3 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1360           0 :                 RETURN_FALSE;
    1361             :         }
    1362             : 
    1363           3 :         sa = (struct sockaddr *) &sa_storage;
    1364             : 
    1365           3 :         if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
    1366           1 :                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
    1367           1 :                 RETURN_FALSE;
    1368             :         }
    1369             : 
    1370           2 :         switch (sa->sa_family) {
    1371             : #if HAVE_IPV6
    1372             :                 case AF_INET6:
    1373           1 :                         sin6 = (struct sockaddr_in6 *) sa;
    1374           1 :                         inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
    1375           1 :                         zval_dtor(arg2);
    1376           2 :                         ZVAL_STRING(arg2, addr6);
    1377             : 
    1378           1 :                         if (arg3 != NULL) {
    1379           1 :                                 zval_dtor(arg3);
    1380           1 :                                 ZVAL_LONG(arg3, htons(sin6->sin6_port));
    1381             :                         }
    1382             : 
    1383           1 :                         RETURN_TRUE;
    1384             :                         break;
    1385             : #endif
    1386             :                 case AF_INET:
    1387           1 :                         sin = (struct sockaddr_in *) sa;
    1388           1 :                         while (inet_ntoa_lock == 1);
    1389           1 :                         inet_ntoa_lock = 1;
    1390           1 :                         addr_string = inet_ntoa(sin->sin_addr);
    1391           1 :                         inet_ntoa_lock = 0;
    1392             : 
    1393           1 :                         zval_dtor(arg2);
    1394           2 :                         ZVAL_STRING(arg2, addr_string);
    1395             : 
    1396           1 :                         if (arg3 != NULL) {
    1397           1 :                                 zval_dtor(arg3);
    1398           1 :                                 ZVAL_LONG(arg3, htons(sin->sin_port));
    1399             :                         }
    1400             : 
    1401           1 :                         RETURN_TRUE;
    1402             :                         break;
    1403             : 
    1404             :                 case AF_UNIX:
    1405           0 :                         s_un = (struct sockaddr_un *) sa;
    1406             : 
    1407           0 :                         zval_dtor(arg2);
    1408           0 :                         ZVAL_STRING(arg2, s_un->sun_path);
    1409           0 :                         RETURN_TRUE;
    1410             :                         break;
    1411             : 
    1412             :                 default:
    1413           0 :                         php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
    1414           0 :                         RETURN_FALSE;
    1415             :         }
    1416             : }
    1417             : /* }}} */
    1418             : 
    1419             : /* {{{ proto resource socket_create(int domain, int type, int protocol)
    1420             :    Creates an endpoint for communication in the domain specified by domain, of type specified by type */
    1421          74 : PHP_FUNCTION(socket_create)
    1422             : {
    1423             :         zend_long               arg1, arg2, arg3;
    1424          74 :         php_socket      *php_sock = php_create_socket();
    1425             : 
    1426          74 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &arg1, &arg2, &arg3) == FAILURE) {
    1427           6 :                 efree(php_sock);
    1428           6 :                 return;
    1429             :         }
    1430             : 
    1431         162 :         if (arg1 != AF_UNIX
    1432             : #if HAVE_IPV6
    1433          68 :                 && arg1 != AF_INET6
    1434             : #endif
    1435          94 :                 && arg1 != AF_INET) {
    1436           0 :                 php_error_docref(NULL, E_WARNING, "invalid socket domain [" ZEND_LONG_FMT "] specified for argument 1, assuming AF_INET", arg1);
    1437           0 :                 arg1 = AF_INET;
    1438             :         }
    1439             : 
    1440          68 :         if (arg2 > 10) {
    1441           0 :                 php_error_docref(NULL, E_WARNING, "invalid socket type [" ZEND_LONG_FMT "] specified for argument 2, assuming SOCK_STREAM", arg2);
    1442           0 :                 arg2 = SOCK_STREAM;
    1443             :         }
    1444             : 
    1445          68 :         php_sock->bsd_socket = socket(arg1, arg2, arg3);
    1446          68 :         php_sock->type = arg1;
    1447             : 
    1448          68 :         if (IS_INVALID_SOCKET(php_sock)) {
    1449           1 :                 SOCKETS_G(last_error) = errno;
    1450           1 :                 php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
    1451           1 :                 efree(php_sock);
    1452           1 :                 RETURN_FALSE;
    1453             :         }
    1454             : 
    1455          67 :         php_sock->error = 0;
    1456          67 :         php_sock->blocking = 1;
    1457             : 
    1458          67 :         RETURN_RES(zend_register_resource(php_sock, le_socket));
    1459             : }
    1460             : /* }}} */
    1461             : 
    1462             : /* {{{ proto bool socket_connect(resource socket, string addr [, int port])
    1463             :    Opens a connection to addr:port on the socket specified by socket */
    1464          17 : PHP_FUNCTION(socket_connect)
    1465             : {
    1466             :         zval                            *arg1;
    1467             :         php_socket                      *php_sock;
    1468             :         char                            *addr;
    1469             :         int                                     retval;
    1470             :         size_t              addr_len;
    1471          17 :         zend_long                               port = 0;
    1472          17 :         int                                     argc = ZEND_NUM_ARGS();
    1473             : 
    1474          17 :         if (zend_parse_parameters(argc, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
    1475           2 :                 return;
    1476             :         }
    1477             : 
    1478          15 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1479           0 :                 RETURN_FALSE;
    1480             :         }
    1481             : 
    1482          15 :         switch(php_sock->type) {
    1483             : #if HAVE_IPV6
    1484             :                 case AF_INET6: {
    1485           2 :                         struct sockaddr_in6 sin6 = {0};
    1486             : 
    1487           2 :                         if (argc != 3) {
    1488           0 :                                 php_error_docref(NULL, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
    1489           0 :                                 RETURN_FALSE;
    1490             :                         }
    1491             : 
    1492           2 :                         memset(&sin6, 0, sizeof(struct sockaddr_in6));
    1493             : 
    1494           2 :                         sin6.sin6_family = AF_INET6;
    1495           2 :                         sin6.sin6_port   = htons((unsigned short int)port);
    1496             : 
    1497           2 :                         if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
    1498           0 :                                 RETURN_FALSE;
    1499             :                         }
    1500             : 
    1501           2 :                         retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
    1502           2 :                         break;
    1503             :                 }
    1504             : #endif
    1505             :                 case AF_INET: {
    1506          11 :                         struct sockaddr_in sin = {0};
    1507             : 
    1508          11 :                         if (argc != 3) {
    1509           1 :                                 php_error_docref(NULL, E_WARNING, "Socket of type AF_INET requires 3 arguments");
    1510           1 :                                 RETURN_FALSE;
    1511             :                         }
    1512             : 
    1513          10 :                         sin.sin_family = AF_INET;
    1514          10 :                         sin.sin_port   = htons((unsigned short int)port);
    1515             : 
    1516          10 :                         if (! php_set_inet_addr(&sin, addr, php_sock)) {
    1517           0 :                                 RETURN_FALSE;
    1518             :                         }
    1519             : 
    1520          10 :                         retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
    1521          10 :                         break;
    1522             :                 }
    1523             : 
    1524             :                 case AF_UNIX: {
    1525           2 :                         struct sockaddr_un s_un = {0};
    1526             : 
    1527           2 :                         if (addr_len >= sizeof(s_un.sun_path)) {
    1528           0 :                                 php_error_docref(NULL, E_WARNING, "Path too long");
    1529           0 :                                 RETURN_FALSE;
    1530             :                         }
    1531             : 
    1532           2 :                         s_un.sun_family = AF_UNIX;
    1533           2 :                         memcpy(&s_un.sun_path, addr, addr_len);
    1534           2 :                         retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
    1535             :                                 (socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
    1536           2 :                         break;
    1537             :                 }
    1538             : 
    1539             :                 default:
    1540           0 :                         php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
    1541           0 :                         RETURN_FALSE;
    1542             :                 }
    1543             : 
    1544          14 :         if (retval != 0) {
    1545           2 :                 PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
    1546           2 :                 RETURN_FALSE;
    1547             :         }
    1548             : 
    1549          12 :         RETURN_TRUE;
    1550             : }
    1551             : /* }}} */
    1552             : 
    1553             : /* {{{ proto string socket_strerror(int errno)
    1554             :    Returns a string describing an error */
    1555         134 : PHP_FUNCTION(socket_strerror)
    1556             : {
    1557             :         zend_long       arg1;
    1558             : 
    1559         134 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &arg1) == FAILURE) {
    1560           1 :                 return;
    1561             :         }
    1562             : 
    1563         266 :         RETURN_STRING(sockets_strerror(arg1));
    1564             : }
    1565             : /* }}} */
    1566             : 
    1567             : /* {{{ proto bool socket_bind(resource socket, string addr [, int port])
    1568             :    Binds an open socket to a listening port, port is only specified in AF_INET family. */
    1569          38 : PHP_FUNCTION(socket_bind)
    1570             : {
    1571             :         zval                                    *arg1;
    1572          38 :         php_sockaddr_storage    sa_storage = {0};
    1573          38 :         struct sockaddr                 *sock_type = (struct sockaddr*) &sa_storage;
    1574             :         php_socket                              *php_sock;
    1575             :         char                                    *addr;
    1576             :         size_t                                          addr_len;
    1577          38 :         zend_long                                       port = 0;
    1578          38 :         zend_long                                       retval = 0;
    1579             : 
    1580          38 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
    1581           2 :                 return;
    1582             :         }
    1583             : 
    1584          36 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1585           0 :                 RETURN_FALSE;
    1586             :         }
    1587             : 
    1588          36 :         switch(php_sock->type) {
    1589             :                 case AF_UNIX:
    1590             :                         {
    1591           6 :                                 struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
    1592             : 
    1593           6 :                                 sa->sun_family = AF_UNIX;
    1594             : 
    1595           6 :                                 if (addr_len >= sizeof(sa->sun_path)) {
    1596           0 :                                         php_error_docref(NULL, E_WARNING,
    1597             :                                                         "Invalid path: too long (maximum size is %d)",
    1598             :                                                         (int)sizeof(sa->sun_path) - 1);
    1599           0 :                                         RETURN_FALSE;
    1600             :                                 }
    1601           6 :                                 memcpy(&sa->sun_path, addr, addr_len);
    1602             : 
    1603           6 :                                 retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa,
    1604             :                                                 offsetof(struct sockaddr_un, sun_path) + addr_len);
    1605           6 :                                 break;
    1606             :                         }
    1607             : 
    1608             :                 case AF_INET:
    1609             :                         {
    1610          20 :                                 struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
    1611             : 
    1612          20 :                                 sa->sin_family = AF_INET;
    1613          20 :                                 sa->sin_port = htons((unsigned short) port);
    1614             : 
    1615          20 :                                 if (! php_set_inet_addr(sa, addr, php_sock)) {
    1616           0 :                                         RETURN_FALSE;
    1617             :                                 }
    1618             : 
    1619          20 :                                 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
    1620          20 :                                 break;
    1621             :                         }
    1622             : #if HAVE_IPV6
    1623             :                 case AF_INET6:
    1624             :                         {
    1625          10 :                                 struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
    1626             : 
    1627          10 :                                 sa->sin6_family = AF_INET6;
    1628          10 :                                 sa->sin6_port = htons((unsigned short) port);
    1629             : 
    1630          10 :                                 if (! php_set_inet6_addr(sa, addr, php_sock)) {
    1631           0 :                                         RETURN_FALSE;
    1632             :                                 }
    1633             : 
    1634          10 :                                 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
    1635          10 :                                 break;
    1636             :                         }
    1637             : #endif
    1638             :                 default:
    1639           0 :                         php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
    1640           0 :                         RETURN_FALSE;
    1641             :         }
    1642             : 
    1643          36 :         if (retval != 0) {
    1644           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
    1645           0 :                 RETURN_FALSE;
    1646             :         }
    1647             : 
    1648          36 :         RETURN_TRUE;
    1649             : }
    1650             : /* }}} */
    1651             : 
    1652             : /* {{{ proto int socket_recv(resource socket, string &buf, int len, int flags)
    1653             :    Receives data from a connected socket */
    1654           2 : PHP_FUNCTION(socket_recv)
    1655             : {
    1656             :         zval            *php_sock_res, *buf;
    1657             :         zend_string     *recv_buf;
    1658             :         php_socket      *php_sock;
    1659             :         int                     retval;
    1660             :         zend_long               len, flags;
    1661             : 
    1662           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/ll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
    1663           0 :                 return;
    1664             :         }
    1665             : 
    1666           2 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(php_sock_res), le_socket_name, le_socket)) == NULL) {
    1667           0 :                 RETURN_FALSE;
    1668             :         }
    1669             : 
    1670             :         /* overflow check */
    1671           2 :         if ((len + 1) < 2) {
    1672           0 :                 RETURN_FALSE;
    1673             :         }
    1674             : 
    1675           4 :         recv_buf = zend_string_alloc(len, 0);
    1676             : 
    1677           2 :         if ((retval = recv(php_sock->bsd_socket, ZSTR_VAL(recv_buf), len, flags)) < 1) {
    1678           0 :                 efree(recv_buf);
    1679             : 
    1680           0 :                 zval_dtor(buf);
    1681           0 :                 ZVAL_NULL(buf);
    1682             :         } else {
    1683           2 :                 ZSTR_LEN(recv_buf) = retval;
    1684           2 :                 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
    1685             : 
    1686             :                 /* Rebuild buffer zval */
    1687           2 :                 zval_dtor(buf);
    1688           2 :                 ZVAL_NEW_STR(buf, recv_buf);
    1689             :         }
    1690             : 
    1691           2 :         if (retval == -1) {
    1692           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
    1693           0 :                 RETURN_FALSE;
    1694             :         }
    1695             : 
    1696           2 :         RETURN_LONG(retval);
    1697             : }
    1698             : /* }}} */
    1699             : 
    1700             : /* {{{ proto int socket_send(resource socket, string buf, int len, int flags)
    1701             :    Sends data to a connected socket */
    1702           4 : PHP_FUNCTION(socket_send)
    1703             : {
    1704             :         zval            *arg1;
    1705             :         php_socket      *php_sock;
    1706             :         size_t                  buf_len, retval;
    1707             :         zend_long               len, flags;
    1708             :         char            *buf;
    1709             : 
    1710           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
    1711           0 :                 return;
    1712             :         }
    1713             : 
    1714           4 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1715           0 :                 RETURN_FALSE;
    1716             :         }
    1717             : 
    1718           4 :         retval = send(php_sock->bsd_socket, buf, (buf_len < (size_t)len ? buf_len : (size_t)len), flags);
    1719             : 
    1720           4 :         if (retval == (size_t)-1) {
    1721           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
    1722           0 :                 RETURN_FALSE;
    1723             :         }
    1724             : 
    1725           4 :         RETURN_LONG(retval);
    1726             : }
    1727             : /* }}} */
    1728             : 
    1729             : /* {{{ proto int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port])
    1730             :    Receives data from a socket, connected or not */
    1731          11 : PHP_FUNCTION(socket_recvfrom)
    1732             : {
    1733          11 :         zval                            *arg1, *arg2, *arg5, *arg6 = NULL;
    1734             :         php_socket                      *php_sock;
    1735             :         struct sockaddr_un      s_un;
    1736             :         struct sockaddr_in      sin;
    1737             : #if HAVE_IPV6
    1738             :         struct sockaddr_in6     sin6;
    1739             :         char                            addr6[INET6_ADDRSTRLEN];
    1740             : #endif
    1741             :         socklen_t                       slen;
    1742             :         int                                     retval;
    1743             :         zend_long                               arg3, arg4;
    1744             :         char                            *address;
    1745             :         zend_string                     *recv_buf;
    1746             : 
    1747          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/llz/|z/", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
    1748           2 :                 return;
    1749             :         }
    1750             : 
    1751           9 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1752           0 :                 RETURN_FALSE;
    1753             :         }
    1754             : 
    1755             :         /* overflow check */
    1756           9 :         if ((arg3 + 2) < 3) {
    1757           1 :                 RETURN_FALSE;
    1758             :         }
    1759             : 
    1760          16 :         recv_buf = zend_string_alloc(arg3 + 1, 0);
    1761             : 
    1762           8 :         switch (php_sock->type) {
    1763             :                 case AF_UNIX:
    1764           2 :                         slen = sizeof(s_un);
    1765           2 :                         s_un.sun_family = AF_UNIX;
    1766           2 :                         retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
    1767             : 
    1768           2 :                         if (retval < 0) {
    1769           1 :                                 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
    1770             :                                 zend_string_free(recv_buf);
    1771           1 :                                 RETURN_FALSE;
    1772             :                         }
    1773           1 :                         ZSTR_LEN(recv_buf) = retval;
    1774           1 :                         ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
    1775             : 
    1776           1 :                         zval_dtor(arg2);
    1777           1 :                         zval_dtor(arg5);
    1778             : 
    1779           1 :                         ZVAL_NEW_STR(arg2, recv_buf);
    1780           2 :                         ZVAL_STRING(arg5, s_un.sun_path);
    1781           1 :                         break;
    1782             : 
    1783             :                 case AF_INET:
    1784           3 :                         slen = sizeof(sin);
    1785           3 :                         memset(&sin, 0, slen);
    1786           3 :                         sin.sin_family = AF_INET;
    1787             : 
    1788           3 :                         if (arg6 == NULL) {
    1789             :                                 zend_string_free(recv_buf);
    1790           1 :                                 WRONG_PARAM_COUNT;
    1791             :                         }
    1792             : 
    1793           2 :                         retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
    1794             : 
    1795           2 :                         if (retval < 0) {
    1796           1 :                                 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
    1797             :                                 zend_string_free(recv_buf);
    1798           1 :                                 RETURN_FALSE;
    1799             :                         }
    1800           1 :                         ZSTR_LEN(recv_buf) = retval;
    1801           1 :                         ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
    1802             : 
    1803           1 :                         zval_dtor(arg2);
    1804           1 :                         zval_dtor(arg5);
    1805           1 :                         zval_dtor(arg6);
    1806             : 
    1807           1 :                         address = inet_ntoa(sin.sin_addr);
    1808             : 
    1809           1 :                         ZVAL_NEW_STR(arg2, recv_buf);
    1810           2 :                         ZVAL_STRING(arg5, address ? address : "0.0.0.0");
    1811           1 :                         ZVAL_LONG(arg6, ntohs(sin.sin_port));
    1812           1 :                         break;
    1813             : #if HAVE_IPV6
    1814             :                 case AF_INET6:
    1815           3 :                         slen = sizeof(sin6);
    1816           3 :                         memset(&sin6, 0, slen);
    1817           3 :                         sin6.sin6_family = AF_INET6;
    1818             : 
    1819           3 :                         if (arg6 == NULL) {
    1820           1 :                                 efree(recv_buf);
    1821           1 :                                 WRONG_PARAM_COUNT;
    1822             :                         }
    1823             : 
    1824           2 :                         retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
    1825             : 
    1826           2 :                         if (retval < 0) {
    1827           1 :                                 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
    1828             :                                 zend_string_free(recv_buf);
    1829           1 :                                 RETURN_FALSE;
    1830             :                         }
    1831           1 :                         ZSTR_LEN(recv_buf) = retval;
    1832           1 :                         ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
    1833             : 
    1834           1 :                         zval_dtor(arg2);
    1835           1 :                         zval_dtor(arg5);
    1836           1 :                         zval_dtor(arg6);
    1837             : 
    1838           1 :                         memset(addr6, 0, INET6_ADDRSTRLEN);
    1839           1 :                         inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
    1840             : 
    1841           1 :                         ZVAL_NEW_STR(arg2, recv_buf);
    1842           2 :                         ZVAL_STRING(arg5, addr6[0] ? addr6 : "::");
    1843           1 :                         ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
    1844           1 :                         break;
    1845             : #endif
    1846             :                 default:
    1847           0 :                         php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
    1848           0 :                         RETURN_FALSE;
    1849             :         }
    1850             : 
    1851           3 :         RETURN_LONG(retval);
    1852             : }
    1853             : /* }}} */
    1854             : 
    1855             : /* {{{ proto int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port])
    1856             :    Sends a message to a socket, whether it is connected or not */
    1857          26 : PHP_FUNCTION(socket_sendto)
    1858             : {
    1859             :         zval                            *arg1;
    1860             :         php_socket                      *php_sock;
    1861             :         struct sockaddr_un      s_un;
    1862             :         struct sockaddr_in      sin;
    1863             : #if HAVE_IPV6
    1864             :         struct sockaddr_in6     sin6;
    1865             : #endif
    1866             :         int                                     retval;
    1867             :         size_t              buf_len, addr_len;
    1868          26 :         zend_long                       len, flags, port = 0;
    1869             :         char                            *buf, *addr;
    1870          26 :         int                                     argc = ZEND_NUM_ARGS();
    1871             : 
    1872          26 :         if (zend_parse_parameters(argc, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
    1873           1 :                 return;
    1874             :         }
    1875             : 
    1876          25 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1877           0 :                 RETURN_FALSE;
    1878             :         }
    1879             : 
    1880          25 :         switch (php_sock->type) {
    1881             :                 case AF_UNIX:
    1882           2 :                         memset(&s_un, 0, sizeof(s_un));
    1883           2 :                         s_un.sun_family = AF_UNIX;
    1884           2 :                         snprintf(s_un.sun_path, 108, "%s", addr);
    1885             : 
    1886           2 :                         retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len,       flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
    1887           2 :                         break;
    1888             : 
    1889             :                 case AF_INET:
    1890          17 :                         if (argc != 6) {
    1891           1 :                                 WRONG_PARAM_COUNT;
    1892             :                         }
    1893             : 
    1894          16 :                         memset(&sin, 0, sizeof(sin));
    1895          16 :                         sin.sin_family = AF_INET;
    1896          16 :                         sin.sin_port = htons((unsigned short) port);
    1897             : 
    1898          16 :                         if (! php_set_inet_addr(&sin, addr, php_sock)) {
    1899           0 :                                 RETURN_FALSE;
    1900             :                         }
    1901             : 
    1902          16 :                         retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin, sizeof(sin));
    1903          16 :                         break;
    1904             : #if HAVE_IPV6
    1905             :                 case AF_INET6:
    1906           6 :                         if (argc != 6) {
    1907           1 :                                 WRONG_PARAM_COUNT;
    1908             :                         }
    1909             : 
    1910           5 :                         memset(&sin6, 0, sizeof(sin6));
    1911           5 :                         sin6.sin6_family = AF_INET6;
    1912           5 :                         sin6.sin6_port = htons((unsigned short) port);
    1913             : 
    1914           5 :                         if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
    1915           0 :                                 RETURN_FALSE;
    1916             :                         }
    1917             : 
    1918           5 :                         retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
    1919           5 :                         break;
    1920             : #endif
    1921             :                 default:
    1922           0 :                         php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
    1923           0 :                         RETURN_FALSE;
    1924             :         }
    1925             : 
    1926          23 :         if (retval == -1) {
    1927           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
    1928           0 :                 RETURN_FALSE;
    1929             :         }
    1930             : 
    1931          23 :         RETURN_LONG(retval);
    1932             : }
    1933             : /* }}} */
    1934             : 
    1935             : /* {{{ proto mixed socket_get_option(resource socket, int level, int optname)
    1936             :    Gets socket options for the socket */
    1937          35 : PHP_FUNCTION(socket_get_option)
    1938             : {
    1939             :         zval                    *arg1;
    1940             :         struct linger   linger_val;
    1941             :         struct timeval  tv;
    1942             : #ifdef PHP_WIN32
    1943             :         int                             timeout = 0;
    1944             : #endif
    1945             :         socklen_t               optlen;
    1946             :         php_socket              *php_sock;
    1947             :         int                             other_val;
    1948             :         zend_long                       level, optname;
    1949             : 
    1950          35 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rll", &arg1, &level, &optname) == FAILURE) {
    1951           0 :                 return;
    1952             :         }
    1953             : 
    1954          35 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    1955           2 :                 RETURN_FALSE;
    1956             :         }
    1957             : 
    1958          33 :         if (level == IPPROTO_IP) {
    1959          15 :                 switch (optname) {
    1960             :                 case IP_MULTICAST_IF: {
    1961             :                         struct in_addr if_addr;
    1962             :                         unsigned int if_index;
    1963           4 :                         optlen = sizeof(if_addr);
    1964           4 :                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&if_addr, &optlen) != 0) {
    1965           0 :                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
    1966           0 :                                 RETURN_FALSE;
    1967             :                         }
    1968           4 :                         if (php_add4_to_if_index(&if_addr, php_sock, &if_index) == SUCCESS) {
    1969           4 :                                 RETURN_LONG((zend_long) if_index);
    1970             :                         } else {
    1971           0 :                                 RETURN_FALSE;
    1972             :                         }
    1973             :                 }
    1974             :                 }
    1975             :         }
    1976             : #if HAVE_IPV6
    1977          18 :         else if (level == IPPROTO_IPV6) {
    1978           5 :                 int ret = php_do_getsockopt_ipv6_rfc3542(php_sock, level, optname, return_value);
    1979           5 :                 if (ret == SUCCESS) {
    1980           0 :                         return;
    1981           5 :                 } else if (ret == FAILURE) {
    1982           0 :                         RETURN_FALSE;
    1983             :                 } /* else continue */
    1984             :         }
    1985             : #endif
    1986             : 
    1987             :         /* sol_socket options and general case */
    1988          29 :         switch(optname) {
    1989             :                 case SO_LINGER:
    1990           1 :                         optlen = sizeof(linger_val);
    1991             : 
    1992           1 :                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
    1993           0 :                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
    1994           0 :                                 RETURN_FALSE;
    1995             :                         }
    1996             : 
    1997           1 :                         array_init(return_value);
    1998           1 :                         add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
    1999           1 :                         add_assoc_long(return_value, "l_linger", linger_val.l_linger);
    2000           1 :                         break;
    2001             : 
    2002             :                 case SO_RCVTIMEO:
    2003             :                 case SO_SNDTIMEO:
    2004             : #ifndef PHP_WIN32
    2005           2 :                         optlen = sizeof(tv);
    2006             : 
    2007           2 :                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
    2008           0 :                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
    2009           0 :                                 RETURN_FALSE;
    2010             :                         }
    2011             : #else
    2012             :                         optlen = sizeof(int);
    2013             : 
    2014             :                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
    2015             :                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
    2016             :                                 RETURN_FALSE;
    2017             :                         }
    2018             : 
    2019             :                         tv.tv_sec = timeout ? timeout / 1000 : 0;
    2020             :                         tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;
    2021             : #endif
    2022             : 
    2023           2 :                         array_init(return_value);
    2024             : 
    2025           2 :                         add_assoc_long(return_value, "sec", tv.tv_sec);
    2026           2 :                         add_assoc_long(return_value, "usec", tv.tv_usec);
    2027           2 :                         break;
    2028             : 
    2029             :                 default:
    2030          26 :                         optlen = sizeof(other_val);
    2031             : 
    2032          26 :                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
    2033           2 :                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
    2034           2 :                                 RETURN_FALSE;
    2035             :                         }
    2036          24 :                         if (optlen == 1)
    2037           0 :                                 other_val = *((unsigned char *)&other_val);
    2038             : 
    2039          24 :                         RETURN_LONG(other_val);
    2040             :                         break;
    2041             :         }
    2042             : }
    2043             : /* }}} */
    2044             : 
    2045             : /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
    2046             :    Sets socket options for the socket */
    2047          58 : PHP_FUNCTION(socket_set_option)
    2048             : {
    2049             :         zval                                    *arg1, *arg4;
    2050             :         struct linger                   lv;
    2051             :         php_socket                              *php_sock;
    2052             :         int                                             ov, optlen, retval;
    2053             : #ifdef PHP_WIN32
    2054             :         int                                             timeout;
    2055             : #else
    2056             :         struct                                  timeval tv;
    2057             : #endif
    2058             :         zend_long                                       level, optname;
    2059             :         void                                    *opt_ptr;
    2060             :         HashTable                               *opt_ht;
    2061             :         zval                                    *l_onoff, *l_linger;
    2062             :         zval                                    *sec, *usec;
    2063             : 
    2064             : 
    2065          58 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rllz", &arg1, &level, &optname, &arg4) == FAILURE) {
    2066           1 :                 return;
    2067             :         }
    2068             : 
    2069          57 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    2070           0 :                 RETURN_FALSE;
    2071             :         }
    2072             : 
    2073          57 :         set_errno(0);
    2074             : 
    2075             : #define HANDLE_SUBCALL(res) \
    2076             :         do { \
    2077             :                 if (res == 1) { goto default_case; } \
    2078             :                 else if (res == SUCCESS) { RETURN_TRUE; } \
    2079             :                 else { RETURN_FALSE; } \
    2080             :         } while (0)
    2081             : 
    2082             : 
    2083          57 :         if (level == IPPROTO_IP) {
    2084          30 :                 int res = php_do_setsockopt_ip_mcast(php_sock, level, optname, arg4);
    2085          30 :                 HANDLE_SUBCALL(res);
    2086             :         }
    2087             : 
    2088             : #if HAVE_IPV6
    2089          27 :         else if (level == IPPROTO_IPV6) {
    2090          18 :                 int res = php_do_setsockopt_ipv6_mcast(php_sock, level, optname, arg4);
    2091          18 :                 if (res == 1) {
    2092           5 :                         res = php_do_setsockopt_ipv6_rfc3542(php_sock, level, optname, arg4);
    2093             :                 }
    2094          18 :                 HANDLE_SUBCALL(res);
    2095             :         }
    2096             : #endif
    2097             : 
    2098           9 :         switch (optname) {
    2099             :                 case SO_LINGER: {
    2100           3 :                         const char l_onoff_key[] = "l_onoff";
    2101           3 :                         const char l_linger_key[] = "l_linger";
    2102             : 
    2103           6 :                         convert_to_array_ex(arg4);
    2104           3 :                         opt_ht = Z_ARRVAL_P(arg4);
    2105             : 
    2106           3 :                         if ((l_onoff = zend_hash_str_find(opt_ht, l_onoff_key, sizeof(l_onoff_key) - 1)) == NULL) {
    2107           1 :                                 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
    2108           1 :                                 RETURN_FALSE;
    2109             :                         }
    2110           2 :                         if ((l_linger = zend_hash_str_find(opt_ht, l_linger_key, sizeof(l_linger_key) - 1)) == NULL) {
    2111           1 :                                 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
    2112           1 :                                 RETURN_FALSE;
    2113             :                         }
    2114             : 
    2115           1 :                         convert_to_long_ex(l_onoff);
    2116           1 :                         convert_to_long_ex(l_linger);
    2117             : 
    2118           1 :                         lv.l_onoff = (unsigned short)Z_LVAL_P(l_onoff);
    2119           1 :                         lv.l_linger = (unsigned short)Z_LVAL_P(l_linger);
    2120             : 
    2121           1 :                         optlen = sizeof(lv);
    2122           1 :                         opt_ptr = &lv;
    2123           1 :                         break;
    2124             :                 }
    2125             : 
    2126             :                 case SO_RCVTIMEO:
    2127             :                 case SO_SNDTIMEO: {
    2128           4 :                         const char sec_key[] = "sec";
    2129           4 :                         const char usec_key[] = "usec";
    2130             : 
    2131           8 :                         convert_to_array_ex(arg4);
    2132           4 :                         opt_ht = Z_ARRVAL_P(arg4);
    2133             : 
    2134           4 :                         if ((sec = zend_hash_str_find(opt_ht, sec_key, sizeof(sec_key) - 1)) == NULL) {
    2135           2 :                                 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", sec_key);
    2136           2 :                                 RETURN_FALSE;
    2137             :                         }
    2138           2 :                         if ((usec = zend_hash_str_find(opt_ht, usec_key, sizeof(usec_key) - 1)) == NULL) {
    2139           0 :                                 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", usec_key);
    2140           0 :                                 RETURN_FALSE;
    2141             :                         }
    2142             : 
    2143           2 :                         convert_to_long_ex(sec);
    2144           2 :                         convert_to_long_ex(usec);
    2145             : #ifndef PHP_WIN32
    2146           2 :                         tv.tv_sec = Z_LVAL_P(sec);
    2147           2 :                         tv.tv_usec = Z_LVAL_P(usec);
    2148           2 :                         optlen = sizeof(tv);
    2149           2 :                         opt_ptr = &tv;
    2150             : #else
    2151             :                         timeout = Z_LVAL_P(sec) * 1000 + Z_LVAL_P(usec) / 1000;
    2152             :                         optlen = sizeof(int);
    2153             :                         opt_ptr = &timeout;
    2154             : #endif
    2155           2 :                         break;
    2156             :                 }
    2157             : #ifdef SO_BINDTODEVICE
    2158             :                 case SO_BINDTODEVICE: {
    2159           0 :                         if (Z_TYPE_P(arg4) == IS_STRING) {
    2160           0 :                                 opt_ptr = Z_STRVAL_P(arg4);
    2161           0 :                                 optlen = Z_STRLEN_P(arg4);
    2162             :                         } else {
    2163           0 :                                 opt_ptr = "";
    2164           0 :                                 optlen = 0;
    2165             :                         }
    2166           0 :                         break;
    2167             :                 }
    2168             : #endif
    2169             : 
    2170             :                 default:
    2171             : default_case:
    2172          10 :                         convert_to_long_ex(arg4);
    2173           5 :                         ov = Z_LVAL_P(arg4);
    2174             : 
    2175           5 :                         optlen = sizeof(ov);
    2176           5 :                         opt_ptr = &ov;
    2177             :                         break;
    2178             :         }
    2179             : 
    2180           8 :         retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
    2181           8 :         if (retval != 0) {
    2182           1 :                 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
    2183           1 :                 RETURN_FALSE;
    2184             :         }
    2185             : 
    2186           7 :         RETURN_TRUE;
    2187             : }
    2188             : /* }}} */
    2189             : 
    2190             : #ifdef HAVE_SOCKETPAIR
    2191             : /* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd)
    2192             :    Creates a pair of indistinguishable sockets and stores them in fds. */
    2193          11 : PHP_FUNCTION(socket_create_pair)
    2194             : {
    2195             :         zval            retval[2], *fds_array_zval;
    2196             :         php_socket      *php_sock[2];
    2197             :         PHP_SOCKET      fds_array[2];
    2198             :         zend_long               domain, type, protocol;
    2199             : 
    2200          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "lllz/", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
    2201           2 :                 return;
    2202             :         }
    2203             : 
    2204           9 :         php_sock[0] = php_create_socket();
    2205           9 :         php_sock[1] = php_create_socket();
    2206             : 
    2207          23 :         if (domain != AF_INET
    2208             : #if HAVE_IPV6
    2209           9 :                 && domain != AF_INET6
    2210             : #endif
    2211          14 :                 && domain != AF_UNIX) {
    2212           1 :                 php_error_docref(NULL, E_WARNING, "invalid socket domain [" ZEND_LONG_FMT "] specified for argument 1, assuming AF_INET", domain);
    2213           1 :                 domain = AF_INET;
    2214             :         }
    2215             : 
    2216           9 :         if (type > 10) {
    2217           1 :                 php_error_docref(NULL, E_WARNING, "invalid socket type [" ZEND_LONG_FMT "] specified for argument 2, assuming SOCK_STREAM", type);
    2218           1 :                 type = SOCK_STREAM;
    2219             :         }
    2220             : 
    2221           9 :         if (socketpair(domain, type, protocol, fds_array) != 0) {
    2222           3 :                 SOCKETS_G(last_error) = errno;
    2223           3 :                 php_error_docref(NULL, E_WARNING, "unable to create socket pair [%d]: %s", errno, sockets_strerror(errno));
    2224           3 :                 efree(php_sock[0]);
    2225           3 :                 efree(php_sock[1]);
    2226           3 :                 RETURN_FALSE;
    2227             :         }
    2228             : 
    2229           6 :         zval_dtor(fds_array_zval);
    2230           6 :         array_init(fds_array_zval);
    2231             : 
    2232           6 :         php_sock[0]->bsd_socket = fds_array[0];
    2233           6 :         php_sock[1]->bsd_socket = fds_array[1];
    2234           6 :         php_sock[0]->type            = domain;
    2235           6 :         php_sock[1]->type            = domain;
    2236           6 :         php_sock[0]->error           = 0;
    2237           6 :         php_sock[1]->error           = 0;
    2238           6 :         php_sock[0]->blocking        = 1;
    2239           6 :         php_sock[1]->blocking        = 1;
    2240             : 
    2241           6 :         ZVAL_RES(&retval[0], zend_register_resource(php_sock[0], le_socket));
    2242           6 :         ZVAL_RES(&retval[1], zend_register_resource(php_sock[1], le_socket));
    2243             : 
    2244           6 :         add_index_zval(fds_array_zval, 0, &retval[0]);
    2245           6 :         add_index_zval(fds_array_zval, 1, &retval[1]);
    2246             : 
    2247           6 :         RETURN_TRUE;
    2248             : }
    2249             : /* }}} */
    2250             : #endif
    2251             : 
    2252             : #ifdef HAVE_SHUTDOWN
    2253             : /* {{{ proto bool socket_shutdown(resource socket[, int how])
    2254             :    Shuts down a socket for receiving, sending, or both. */
    2255           5 : PHP_FUNCTION(socket_shutdown)
    2256             : {
    2257             :         zval            *arg1;
    2258           5 :         zend_long               how_shutdown = 2;
    2259             :         php_socket      *php_sock;
    2260             : 
    2261           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &arg1, &how_shutdown) == FAILURE) {
    2262           0 :                 return;
    2263             :         }
    2264             : 
    2265           5 :         if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    2266           0 :                 RETURN_FALSE;
    2267             :         }
    2268             : 
    2269           5 :         if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
    2270           2 :                 PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
    2271           2 :                 RETURN_FALSE;
    2272             :         }
    2273             : 
    2274           3 :         RETURN_TRUE;
    2275             : }
    2276             : /* }}} */
    2277             : #endif
    2278             : 
    2279             : /* {{{ proto int socket_last_error([resource socket])
    2280             :    Returns the last socket error (either the last used or the provided socket resource) */
    2281           2 : PHP_FUNCTION(socket_last_error)
    2282             : {
    2283           2 :         zval            *arg1 = NULL;
    2284             :         php_socket      *php_sock;
    2285             : 
    2286           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
    2287           0 :                 return;
    2288             :         }
    2289             : 
    2290           2 :         if (arg1) {
    2291           2 :                 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    2292           0 :                         RETURN_FALSE;
    2293             :                 }
    2294           2 :                 RETVAL_LONG(php_sock->error);
    2295             :         } else {
    2296           0 :                 RETVAL_LONG(SOCKETS_G(last_error));
    2297             :         }
    2298             : }
    2299             : /* }}} */
    2300             : 
    2301             : /* {{{ proto void socket_clear_error([resource socket])
    2302             :    Clears the error on the socket or the last error code. */
    2303           1 : PHP_FUNCTION(socket_clear_error)
    2304             : {
    2305           1 :         zval            *arg1 = NULL;
    2306             :         php_socket      *php_sock;
    2307             : 
    2308           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
    2309           0 :                 return;
    2310             :         }
    2311             : 
    2312           1 :         if (arg1) {
    2313           1 :                 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
    2314           0 :                         RETURN_FALSE;
    2315             :                 }
    2316           1 :                 php_sock->error = 0;
    2317             :         } else {
    2318           0 :                 SOCKETS_G(last_error) = 0;
    2319             :         }
    2320             : 
    2321           1 :         return;
    2322             : }
    2323             : /* }}} */
    2324             : 
    2325          11 : php_socket *socket_import_file_descriptor(PHP_SOCKET socket)
    2326             : {
    2327             : #ifdef SO_DOMAIN
    2328             :         int                                             type;
    2329          11 :         socklen_t                               type_len = sizeof(type);
    2330             : #endif
    2331             :         php_socket                              *retsock;
    2332             :         php_sockaddr_storage    addr;
    2333          11 :         socklen_t                               addr_len = sizeof(addr);
    2334             : #ifndef PHP_WIN32
    2335             :         int                                      t;
    2336             : #endif
    2337             : 
    2338          11 :     retsock = php_create_socket();
    2339          11 :     retsock->bsd_socket = socket;
    2340             : 
    2341             :     /* determine family */
    2342             : #ifdef SO_DOMAIN
    2343          11 :     if (getsockopt(socket, SOL_SOCKET, SO_DOMAIN, &type, &type_len) == 0) {
    2344          11 :                 retsock->type = type;
    2345             :         } else
    2346             : #endif
    2347           0 :         if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
    2348           0 :                 retsock->type = addr.ss_family;
    2349             :         } else {
    2350           0 :                 PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
    2351           0 :                 goto error;
    2352             :         }
    2353             : 
    2354             :     /* determine blocking mode */
    2355             : #ifndef PHP_WIN32
    2356          11 :     t = fcntl(socket, F_GETFL);
    2357          11 :     if (t == -1) {
    2358           0 :                 PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
    2359           0 :                 goto error;
    2360             :     } else {
    2361          11 :         retsock->blocking = !(t & O_NONBLOCK);
    2362             :     }
    2363             : #endif
    2364             : 
    2365          11 :     return retsock;
    2366             : 
    2367             : error:
    2368           0 :         efree(retsock);
    2369           0 :         return NULL;
    2370             : }
    2371             : 
    2372             : /* {{{ proto resource socket_import_stream(resource stream)
    2373             :    Imports a stream that encapsulates a socket into a socket extension resource. */
    2374          18 : PHP_FUNCTION(socket_import_stream)
    2375             : {
    2376             :         zval                             *zstream;
    2377             :         php_stream                       *stream;
    2378          18 :         php_socket                       *retsock = NULL;
    2379             :         PHP_SOCKET                       socket; /* fd */
    2380             : 
    2381          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream) == FAILURE) {
    2382           4 :                 return;
    2383             :         }
    2384          14 :         php_stream_from_zval(stream, zstream);
    2385             : 
    2386          12 :         if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
    2387             :                 /* error supposedly already shown */
    2388           1 :                 RETURN_FALSE;
    2389             :         }
    2390             : 
    2391          11 :         retsock = socket_import_file_descriptor(socket);
    2392          11 :         if (retsock == NULL) {
    2393           0 :                 RETURN_FALSE;
    2394             :         }
    2395             : 
    2396             : #ifdef PHP_WIN32
    2397             :         /* on windows, check if the stream is a socket stream and read its
    2398             :          * private data; otherwise assume it's in non-blocking mode */
    2399             :         if (php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
    2400             :                 retsock->blocking =
    2401             :                                 ((php_netstream_data_t *)stream->abstract)->is_blocked;
    2402             :         } else {
    2403             :                 retsock->blocking = 1;
    2404             :         }
    2405             : #endif
    2406             : 
    2407             :         /* hold a zval reference to the stream (holding a php_stream* directly could
    2408             :          * also be done, but this makes socket_export_stream a bit simpler) */
    2409          11 :         ZVAL_COPY(&retsock->zstream, zstream);
    2410             : 
    2411          11 :         php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
    2412             :                 PHP_STREAM_BUFFER_NONE, NULL);
    2413             : 
    2414          11 :         RETURN_RES(zend_register_resource(retsock, le_socket));
    2415             : }
    2416             : /* }}} */
    2417             : 
    2418             : /* {{{ proto resource socket_export_stream(resource socket)
    2419             :    Exports a socket extension resource into a stream that encapsulates a socket. */
    2420          14 : PHP_FUNCTION(socket_export_stream)
    2421             : {
    2422             :         zval *zsocket;
    2423             :         php_socket *socket;
    2424          14 :         php_stream *stream = NULL;
    2425             :         php_netstream_data_t *stream_data;
    2426          14 :         char *protocol = NULL;
    2427          14 :         size_t protocollen = 0;
    2428             : 
    2429          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsocket) == FAILURE) {
    2430           4 :                 return;
    2431             :         }
    2432          10 :         if ((socket = (php_socket *) zend_fetch_resource(Z_RES_P(zsocket), le_socket_name, le_socket)) == NULL) {
    2433           3 :                 RETURN_FALSE;
    2434             :         }
    2435             : 
    2436             :         /* Either we already exported a stream or the socket came from an import,
    2437             :          * just return the existing stream */
    2438          14 :         if (!Z_ISUNDEF(socket->zstream)) {
    2439           0 :                 RETURN_ZVAL(&socket->zstream, 1, 0);
    2440             :         }
    2441             : 
    2442             :         /* Determine if socket is using a protocol with one of the default registered
    2443             :          * socket stream wrappers */
    2444          14 :         if (socket->type == PF_INET
    2445             : #if HAVE_IPV6
    2446           8 :                  || socket->type == PF_INET6
    2447             : #endif
    2448             :         ) {
    2449             :                 int protoid;
    2450           6 :                 socklen_t protoidlen = sizeof(protoid);
    2451             : 
    2452           6 :                 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &protoid, &protoidlen);
    2453             : 
    2454           6 :                 if (protoid == SOCK_STREAM) {
    2455             :                         /* SO_PROTOCOL is not (yet?) supported on OS X, so lets assume it's TCP there */
    2456             : #ifdef SO_PROTOCOL
    2457           0 :                         protoidlen = sizeof(protoid);
    2458           0 :                         getsockopt(socket->bsd_socket, SOL_SOCKET, SO_PROTOCOL, (char *) &protoid, &protoidlen);
    2459           0 :                         if (protoid == IPPROTO_TCP)
    2460             : #endif
    2461             :                         {
    2462           0 :                                 protocol = "tcp";
    2463           0 :                                 protocollen = 3;
    2464             :                         }
    2465           6 :                 } else if (protoid == SOCK_DGRAM) {
    2466           6 :                         protocol = "udp";
    2467           6 :                         protocollen = 3;
    2468             :                 }
    2469             : #ifdef PF_UNIX
    2470           1 :         } else if (socket->type == PF_UNIX) {
    2471             :                 int type;
    2472           1 :                 socklen_t typelen = sizeof(type);
    2473             : 
    2474           1 :                 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen);
    2475             : 
    2476           1 :                 if (type == SOCK_STREAM) {
    2477           1 :                         protocol = "unix";
    2478           1 :                         protocollen = 4;
    2479           0 :                 } else if (type == SOCK_DGRAM) {
    2480           0 :                         protocol = "udg";
    2481           0 :                         protocollen = 3;
    2482             :                 }
    2483             : #endif
    2484             :         }
    2485             : 
    2486             :         /* Try to get a stream with the registered sockops for the protocol in use
    2487             :          * We don't want streams to actually *do* anything though, so don't give it
    2488             :          * anything apart from the protocol */
    2489           7 :         if (protocol != NULL) {
    2490           7 :                 stream = php_stream_xport_create(protocol, protocollen, 0, 0, NULL, NULL, NULL, NULL, NULL);
    2491             :         }
    2492             : 
    2493             :         /* Fall back to creating a generic socket stream */
    2494           7 :         if (stream == NULL) {
    2495           0 :                 stream = php_stream_sock_open_from_socket(socket->bsd_socket, 0);
    2496             : 
    2497           0 :                 if (stream == NULL) {
    2498           0 :                         php_error_docref(NULL, E_WARNING, "failed to create stream");
    2499           0 :                         RETURN_FALSE;
    2500             :                 }
    2501             :         }
    2502             : 
    2503           7 :         stream_data = (php_netstream_data_t *) stream->abstract;
    2504           7 :         stream_data->socket = socket->bsd_socket;
    2505           7 :         stream_data->is_blocked = socket->blocking;
    2506           7 :         stream_data->timeout.tv_sec = FG(default_socket_timeout);
    2507           7 :         stream_data->timeout.tv_usec = 0;
    2508             : 
    2509           7 :         php_stream_to_zval(stream, &socket->zstream);
    2510             : 
    2511          14 :         RETURN_ZVAL(&socket->zstream, 1, 0);
    2512             : }
    2513             : /* }}} */
    2514             : 
    2515             : /* {{{ proto resource addrinfo socket_addrinfo_lookup(string hostname[, mixed service, array hints])
    2516             :    Gets array with contents of getaddrinfo about the given hostname. */
    2517           4 : PHP_FUNCTION(socket_addrinfo_lookup)
    2518             : {
    2519           4 :         char *service = NULL;
    2520             :         size_t service_len;
    2521             :         zend_string *hostname, *key;
    2522           4 :         zval *hint, *zhints = NULL;
    2523             : 
    2524             :         struct addrinfo hints, *result, *rp, *res;
    2525             : 
    2526           4 :         memset(&hints, 0, sizeof(hints));
    2527             : 
    2528           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|sa", &hostname, &service, &service_len, &zhints) == FAILURE) {
    2529           0 :                 RETURN_NULL();
    2530             :         }
    2531             : 
    2532           4 :         if (zhints) {
    2533          22 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zhints), key, hint) {
    2534           9 :                         if (key) {
    2535           9 :                                 if (zend_string_equals_literal(key, "ai_flags")) {
    2536           0 :                                         hints.ai_flags = zval_get_long(hint);
    2537          13 :                                 } else if (zend_string_equals_literal(key, "ai_socktype")) {
    2538           4 :                                         hints.ai_socktype = zval_get_long(hint);
    2539           5 :                                 } else if (zend_string_equals_literal(key, "ai_protocol")) {
    2540           0 :                                         hints.ai_protocol = zval_get_long(hint);
    2541           9 :                                 } else if (zend_string_equals_literal(key, "ai_family")) {
    2542           4 :                                         hints.ai_family = zval_get_long(hint);
    2543             :                                 } else {
    2544           1 :                                         php_error_docref(NULL, E_NOTICE, "Unknown hint %s", ZSTR_VAL(key));
    2545             :                                 }
    2546             :                         }
    2547             :                 } ZEND_HASH_FOREACH_END();
    2548             :         }
    2549             : 
    2550           4 :         if (getaddrinfo(ZSTR_VAL(hostname), service, &hints, &result) != 0) {
    2551           0 :                 RETURN_FALSE;
    2552             :         }
    2553             : 
    2554           4 :         array_init(return_value);
    2555             : 
    2556           8 :         for (rp = result; rp != NULL; rp = rp->ai_next) {
    2557           4 :                 if (rp->ai_family != AF_UNSPEC) {
    2558           4 :                         res = emalloc(sizeof(struct addrinfo));
    2559           4 :                         memcpy(res, rp, sizeof(struct addrinfo));
    2560             : 
    2561           4 :                         res->ai_addr = emalloc(rp->ai_addrlen);
    2562           4 :                         memcpy(res->ai_addr, rp->ai_addr, rp->ai_addrlen);
    2563             : 
    2564           4 :                         if (rp->ai_canonname != NULL) {
    2565           0 :                                 res->ai_canonname = estrdup(rp->ai_canonname);
    2566             :                         }
    2567             : 
    2568           4 :                         add_next_index_resource(return_value, zend_register_resource(res, le_addrinfo));
    2569             :                 }
    2570             :         }
    2571             : 
    2572           4 :         freeaddrinfo(result);
    2573             : }
    2574             : /* }}} */
    2575             : 
    2576             : /* {{{ proto resource socket_addrinfo_bind(resource addrinfo)
    2577             :    Creates and binds to a socket from a given addrinfo resource */
    2578           1 : PHP_FUNCTION(socket_addrinfo_bind)
    2579             : {
    2580             :         zval                    *arg1;
    2581             :         int                             retval;
    2582             :         struct addrinfo *ai;
    2583             :         php_socket              *php_sock;
    2584             : 
    2585           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
    2586           0 :                 return;
    2587             :         }
    2588             : 
    2589           1 :         if ((ai = (struct addrinfo *) zend_fetch_resource(Z_RES_P(arg1), le_addrinfo_name, le_addrinfo)) == NULL) {
    2590           0 :                 RETURN_FALSE;
    2591             :         }
    2592             : 
    2593           1 :         php_sock = php_create_socket();
    2594           1 :         php_sock->bsd_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    2595           1 :         php_sock->type = ai->ai_family;
    2596             : 
    2597           1 :         if (IS_INVALID_SOCKET(php_sock)) {
    2598           0 :                 SOCKETS_G(last_error) = errno;
    2599           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
    2600           0 :                 efree(php_sock);
    2601           0 :                 RETURN_FALSE;
    2602             :         }
    2603             : 
    2604           1 :         php_sock->error = 0;
    2605           1 :         php_sock->blocking = 1;
    2606             : 
    2607           1 :         switch(php_sock->type) {
    2608             :                 case AF_UNIX:
    2609             :                         {
    2610             :                                 // AF_UNIX sockets via getaddrino are not implemented due to security problems
    2611           0 :                                 close(php_sock->bsd_socket);
    2612           0 :                                 efree(php_sock);
    2613           0 :                                 RETURN_FALSE;
    2614             :                         }
    2615             : 
    2616             :                 case AF_INET:
    2617             : #if HAVE_IPV6
    2618             :                 case AF_INET6:
    2619             : #endif
    2620             :                         {
    2621           1 :                                 retval = bind(php_sock->bsd_socket, ai->ai_addr, ai->ai_addrlen);
    2622           1 :                                 break;
    2623             :                         }
    2624             :                 default:
    2625           0 :                         php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
    2626           0 :                         close(php_sock->bsd_socket);
    2627           0 :                         efree(php_sock);
    2628           0 :                         RETURN_FALSE;
    2629             :         }
    2630             : 
    2631           1 :         if (retval != 0) {
    2632           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
    2633           0 :                 close(php_sock->bsd_socket);
    2634           0 :                 efree(php_sock);
    2635           0 :                 RETURN_FALSE;
    2636             :         }
    2637             : 
    2638           1 :         RETURN_RES(zend_register_resource(php_sock, le_socket));
    2639             : }
    2640             : /* }}} */
    2641             : 
    2642             : /* {{{ proto resource socket_addrinfo_connect(resource addrinfo)
    2643             :    Creates and connects to a socket from a given addrinfo resource */
    2644           1 : PHP_FUNCTION(socket_addrinfo_connect)
    2645             : {
    2646             :         zval                    *arg1;
    2647             :         int                             retval;
    2648             :         struct addrinfo *ai;
    2649             :         php_socket              *php_sock;
    2650             : 
    2651           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
    2652           0 :                 return;
    2653             :         }
    2654             : 
    2655           1 :         if ((ai = (struct addrinfo *) zend_fetch_resource(Z_RES_P(arg1), le_addrinfo_name, le_addrinfo)) == NULL) {
    2656           0 :                 RETURN_FALSE;
    2657             :         }
    2658             : 
    2659           1 :         php_sock = php_create_socket();
    2660           1 :         php_sock->bsd_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    2661           1 :         php_sock->type = ai->ai_family;
    2662             : 
    2663           1 :         if (IS_INVALID_SOCKET(php_sock)) {
    2664           0 :                 SOCKETS_G(last_error) = errno;
    2665           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
    2666           0 :                 efree(php_sock);
    2667           0 :                 RETURN_FALSE;
    2668             :         }
    2669             : 
    2670           1 :         php_sock->error = 0;
    2671           1 :         php_sock->blocking = 1;
    2672             : 
    2673           1 :         switch(php_sock->type) {
    2674             :                 case AF_UNIX:
    2675             :                         {
    2676             :                                 // AF_UNIX sockets via getaddrino are not implemented due to security problems
    2677           0 :                                 close(php_sock->bsd_socket);
    2678           0 :                                 efree(php_sock);
    2679           0 :                                 RETURN_FALSE;
    2680             :                         }
    2681             : 
    2682             :                 case AF_INET:
    2683             : #if HAVE_IPV6
    2684             :                 case AF_INET6:
    2685             : #endif
    2686             :                         {
    2687           1 :                                 retval = connect(php_sock->bsd_socket, ai->ai_addr, ai->ai_addrlen);
    2688           1 :                                 break;
    2689             :                         }
    2690             :                 default:
    2691           0 :                         php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
    2692           0 :                         close(php_sock->bsd_socket);
    2693           0 :                         efree(php_sock);
    2694           0 :                         RETURN_FALSE;
    2695             :         }
    2696             : 
    2697           1 :         if (retval != 0) {
    2698           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to connect address", errno);
    2699           0 :                 close(php_sock->bsd_socket);
    2700           0 :                 efree(php_sock);
    2701           0 :                 RETURN_FALSE;
    2702             :         }
    2703             : 
    2704           1 :         RETURN_RES(zend_register_resource(php_sock, le_socket));
    2705             : }
    2706             : /* }}} */
    2707             : 
    2708             : /* {{{ proto resource socket_addrinfo_explain(resource addrinfo)
    2709             :    Creates and connects to a socket from a given addrinfo resource */
    2710           1 : PHP_FUNCTION(socket_addrinfo_explain)
    2711             : {
    2712             :         zval                    *arg1, sockaddr;
    2713             :         struct addrinfo *ai;
    2714             : 
    2715           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
    2716           0 :                 return;
    2717             :         }
    2718             : 
    2719           1 :         if ((ai = (struct addrinfo *) zend_fetch_resource(Z_RES_P(arg1), le_addrinfo_name, le_addrinfo)) == NULL) {
    2720           0 :                 RETURN_FALSE;
    2721             :         }
    2722             : 
    2723           1 :         array_init(return_value);
    2724             : 
    2725           1 :         add_assoc_long(return_value, "ai_flags", ai->ai_flags);
    2726           1 :         add_assoc_long(return_value, "ai_family", ai->ai_family);
    2727           1 :         add_assoc_long(return_value, "ai_socktype", ai->ai_socktype);
    2728           1 :         add_assoc_long(return_value, "ai_protocol", ai->ai_protocol);
    2729           1 :         if (ai->ai_canonname != NULL) {
    2730           0 :                 add_assoc_string(return_value, "ai_canonname", ai->ai_canonname);
    2731             :         }
    2732             : 
    2733           1 :         array_init(&sockaddr);
    2734           1 :         switch(ai->ai_family) {
    2735             :                 case AF_INET:
    2736             :                         {
    2737           1 :                                 struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
    2738             :                                 char addr[INET_ADDRSTRLEN];
    2739             : 
    2740           1 :                                 add_assoc_long(&sockaddr, "sin_port", ntohs((unsigned short) sa->sin_port));
    2741           1 :                                 inet_ntop(ai->ai_family, &sa->sin_addr, addr, sizeof(addr));
    2742           1 :                                 add_assoc_string(&sockaddr, "sin_addr", addr);
    2743           1 :                                 break;
    2744             :                         }
    2745             : #if HAVE_IPV6
    2746             :                 case AF_INET6:
    2747             :                         {
    2748           0 :                                 struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
    2749             :                                 char addr[INET6_ADDRSTRLEN];
    2750             : 
    2751           0 :                                 add_assoc_long(&sockaddr, "sin6_port", ntohs((unsigned short) sa->sin6_port));
    2752           0 :                                 inet_ntop(ai->ai_family, &sa->sin6_addr, addr, sizeof(addr));
    2753           0 :                                 add_assoc_string(&sockaddr, "sin6_addr", addr);
    2754             :                                 break;
    2755             :                         }
    2756             : #endif
    2757             :         }
    2758             : 
    2759           1 :         add_assoc_zval(return_value, "ai_addr", &sockaddr);
    2760             : }
    2761             : /* }}} */
    2762             : 
    2763             : /*
    2764             :  * Local variables:
    2765             :  * tab-width: 4
    2766             :  * c-basic-offset: 4
    2767             :  * End:
    2768             :  * vim600: fdm=marker
    2769             :  * vim: noet sw=4 ts=4
    2770             :  */

Generated by: LCOV version 1.10

Generated at Tue, 27 Sep 2016 10:26:06 +0000 (2 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.