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: 747 1007 74.2 %
Date: 2014-09-29 Functions: 40 47 85.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 29 Sep 2014 14:26:29 +0000 (2 days ago)

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