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

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:47:56 +0000 (8 days ago)

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