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

Generated by: LCOV version 1.10

Generated at Tue, 26 Jul 2016 17:07:44 +0000 (14 hours ago)

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