Diff for /embedaddon/php/ext/sockets/sockets.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2012/02/21 23:48:01 version 1.1.1.2, 2012/05/29 12:34:42
Line 15 Line 15
    | Authors: Chris Vandomelen <chrisv@b0rked.dhs.org>                    |     | Authors: Chris Vandomelen <chrisv@b0rked.dhs.org>                    |
    |          Sterling Hughes  <sterling@php.net>                         |     |          Sterling Hughes  <sterling@php.net>                         |
    |          Jason Greene     <jason@php.net>                            |     |          Jason Greene     <jason@php.net>                            |
      |          Gustavo Lopes    <cataphract@php.net>                       |
    | WinSock: Daniel Beulshausen <daniel@php4win.de>                      |     | WinSock: Daniel Beulshausen <daniel@php4win.de>                      |
    +----------------------------------------------------------------------+     +----------------------------------------------------------------------+
  */   */
Line 56 Line 57
 # define h_errno                WSAGetLastError()  # define h_errno                WSAGetLastError()
 # define set_errno(a)           WSASetLastError(a)  # define set_errno(a)           WSASetLastError(a)
 # define close(a)               closesocket(a)  # define close(a)               closesocket(a)
   # if _WIN32_WINNT >= 0x0600 && SOCKETS_ENABLE_VISTA_API
   #  define HAVE_IF_NAMETOINDEX 1
   # endif
 #else  #else
 # include <sys/types.h>  # include <sys/types.h>
 # include <sys/socket.h>  # include <sys/socket.h>
Line 73 Line 77
 # define IS_INVALID_SOCKET(a)   (a->bsd_socket < 0)  # define IS_INVALID_SOCKET(a)   (a->bsd_socket < 0)
 # define set_errno(a) (errno = a)  # define set_errno(a) (errno = a)
 # include "php_sockets.h"  # include "php_sockets.h"
   # if HAVE_IF_NAMETOINDEX
   #  include <net/if.h>
   # endif
 #endif  #endif
   
   #include "multicast.h"
   
 ZEND_DECLARE_MODULE_GLOBALS(sockets)  ZEND_DECLARE_MODULE_GLOBALS(sockets)
 static PHP_GINIT_FUNCTION(sockets);  static PHP_GINIT_FUNCTION(sockets);
   
Line 261  ZEND_END_ARG_INFO() Line 270  ZEND_END_ARG_INFO()
 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)  ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
         ZEND_ARG_INFO(0, socket)          ZEND_ARG_INFO(0, socket)
 ZEND_END_ARG_INFO()  ZEND_END_ARG_INFO()
                   
   ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1)
           ZEND_ARG_INFO(0, stream)
   ZEND_END_ARG_INFO()
 /* }}} */  /* }}} */
   
 /* {{{ sockets_functions[]  /* {{{ sockets_functions[]
Line 295  const zend_function_entry sockets_functions[] = { Line 308  const zend_function_entry sockets_functions[] = {
 #endif  #endif
         PHP_FE(socket_last_error,               arginfo_socket_last_error)          PHP_FE(socket_last_error,               arginfo_socket_last_error)
         PHP_FE(socket_clear_error,              arginfo_socket_clear_error)          PHP_FE(socket_clear_error,              arginfo_socket_clear_error)
           PHP_FE(socket_import_stream,    arginfo_socket_import_stream)
   
         /* for downwards compatability */          /* for downwards compatability */
         PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)          PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)
Line 335  PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{ Line 349  PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{
 }  }
 /* }}} */  /* }}} */
   
   /* allocating function to make programming errors due to uninitialized fields
    * less likely */
   static php_socket *php_create_socket(void) /* {{{ */
   {
           php_socket *php_sock = emalloc(sizeof *php_sock);
           
           php_sock->bsd_socket = -1; /* invalid socket */
           php_sock->type           = PF_UNSPEC;
           php_sock->error          = 0;
           php_sock->blocking       = 1;
           php_sock->zstream        = NULL;
           
           return php_sock;
   }
   /* }}} */
   
 static void php_destroy_socket(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */  static void php_destroy_socket(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
 {  {
        php_socket *php_sock = (php_socket *) rsrc->ptr;        php_socket *php_sock = rsrc->ptr;
   
        close(php_sock->bsd_socket);        if (php_sock->zstream == NULL) {
                 if (!IS_INVALID_SOCKET(php_sock)) {
                         close(php_sock->bsd_socket);
                 }
         } else {
                 zval_ptr_dtor(&php_sock->zstream);
         }
         efree(php_sock);          efree(php_sock);
 }  }
 /* }}} */  /* }}} */
Line 348  static int php_open_listen_sock(php_socket **php_sock, Line 384  static int php_open_listen_sock(php_socket **php_sock,
 {  {
         struct sockaddr_in  la;          struct sockaddr_in  la;
         struct hostent          *hp;          struct hostent          *hp;
        php_socket                      *sock = (php_socket*)emalloc(sizeof(php_socket));        php_socket                      *sock = php_create_socket();
   
         *php_sock = sock;          *php_sock = sock;
   
Line 396  static int php_open_listen_sock(php_socket **php_sock, Line 432  static int php_open_listen_sock(php_socket **php_sock,
   
 static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la, socklen_t *la_len TSRMLS_DC) /* {{{ */  static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la, socklen_t *la_len TSRMLS_DC) /* {{{ */
 {  {
        php_socket      *out_sock = (php_socket*)emalloc(sizeof(php_socket));        php_socket      *out_sock = php_create_socket();
   
         *new_sock = out_sock;          *new_sock = out_sock;
   
Line 605  static int php_set_inet_addr(struct sockaddr_in *sin,  Line 641  static int php_set_inet_addr(struct sockaddr_in *sin, 
 }  }
 /* }}} */  /* }}} */
   
   /* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6,
    * depending on the socket) */
   static int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
   {
           if (php_sock->type == AF_INET) {
                   struct sockaddr_in t = {0};
                   if (php_set_inet_addr(&t, string, php_sock TSRMLS_CC)) {
                           memcpy(ss, &t, sizeof t);
                           ss->ss_family = AF_INET;
                           *ss_len = sizeof(t);
                           return 1;
                   }
           }
   #if HAVE_IPV6
           else if (php_sock->type == AF_INET6) {
                   struct sockaddr_in6 t = {0};
                   if (php_set_inet6_addr(&t, string, php_sock TSRMLS_CC)) {
                           memcpy(ss, &t, sizeof t);
                           ss->ss_family = AF_INET6;
                           *ss_len = sizeof(t);
                           return 1;
                   }
           }
   #endif
           else {
                   php_error_docref(NULL TSRMLS_CC, E_WARNING,
                           "IP address used in the context of an unexpected type of socket");
           }
           return 0;
   }
   
   static int php_get_if_index_from_zval(zval *val, unsigned *out TSRMLS_DC)
   {
           int ret;
   
           if (Z_TYPE_P(val) == IS_LONG) {
                   if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > UINT_MAX) {
                           php_error_docref(NULL TSRMLS_CC, E_WARNING,
                                   "the interface index cannot be negative or larger than %u;"
                                   " given %ld", UINT_MAX, Z_LVAL_P(val));
                           ret = FAILURE;
                   } else {
                           *out = Z_LVAL_P(val);
                           ret = SUCCESS;
                   }
           } else {
   #if HAVE_IF_NAMETOINDEX
                   unsigned int ind;
                   zval_add_ref(&val);
                   convert_to_string_ex(&val);
                   ind = if_nametoindex(Z_STRVAL_P(val));
                   if (ind == 0) {
                           php_error_docref(NULL TSRMLS_CC, E_WARNING,
                                   "no interface with name \"%s\" could be found", Z_STRVAL_P(val));
                           ret = FAILURE;
                   } else {
                           *out = ind;
                           ret = SUCCESS;
                   }
                   zval_ptr_dtor(&val);
   #else
                   php_error_docref(NULL TSRMLS_CC, E_WARNING,
                                   "this platform does not support looking up an interface by "
                                   "name, an integer interface index must be supplied instead");
                   ret = FAILURE;
   #endif
           }
   
           return ret;
   }
   
   static int php_get_if_index_from_array(const HashTable *ht, const char *key,
           php_socket *sock, unsigned int *if_index TSRMLS_DC)
   {
           zval **val;
           
           if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
                   *if_index = 0; /* default: 0 */
                   return SUCCESS;
           }
           
           return php_get_if_index_from_zval(*val, if_index TSRMLS_CC);
   }
   
   static int php_get_address_from_array(const HashTable *ht, const char *key,
           php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len TSRMLS_DC)
   {
           zval **val,
                    *valcp;
           
           if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
                   php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", key);
                   return FAILURE;
           }
           valcp = *val;
           zval_add_ref(&valcp);
           convert_to_string_ex(val);      
           if (!php_set_inet46_addr(ss, ss_len, Z_STRVAL_P(valcp), sock TSRMLS_CC)) {
                   zval_ptr_dtor(&valcp);
                   return FAILURE;
           }
           zval_ptr_dtor(&valcp);
           return SUCCESS;
   }
   
 /* {{{ PHP_GINIT_FUNCTION */  /* {{{ PHP_GINIT_FUNCTION */
 static PHP_GINIT_FUNCTION(sockets)  static PHP_GINIT_FUNCTION(sockets)
 {  {
Line 617  static PHP_GINIT_FUNCTION(sockets) Line 758  static PHP_GINIT_FUNCTION(sockets)
  */   */
 PHP_MINIT_FUNCTION(sockets)  PHP_MINIT_FUNCTION(sockets)
 {  {
         struct protoent *pe;  
   
         le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);          le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);
   
         REGISTER_LONG_CONSTANT("AF_UNIX",               AF_UNIX,                CONST_CS | CONST_PERSISTENT);          REGISTER_LONG_CONSTANT("AF_UNIX",               AF_UNIX,                CONST_CS | CONST_PERSISTENT);
Line 667  PHP_MINIT_FUNCTION(sockets) Line 806  PHP_MINIT_FUNCTION(sockets)
         REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);          REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
         REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);          REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
   
   #ifndef RFC3678_API
   #define MCAST_JOIN_GROUP                        IP_ADD_MEMBERSHIP
   #define MCAST_LEAVE_GROUP                       IP_DROP_MEMBERSHIP
   #ifdef HAS_MCAST_EXT
   #define MCAST_BLOCK_SOURCE                      IP_BLOCK_SOURCE
   #define MCAST_UNBLOCK_SOURCE            IP_UNBLOCK_SOURCE
   #define MCAST_JOIN_SOURCE_GROUP         IP_ADD_SOURCE_MEMBERSHIP
   #define MCAST_LEAVE_SOURCE_GROUP        IP_DROP_SOURCE_MEMBERSHIP
   #endif
   #endif
           
           REGISTER_LONG_CONSTANT("MCAST_JOIN_GROUP",                      MCAST_JOIN_GROUP,                       CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("MCAST_LEAVE_GROUP",                     MCAST_LEAVE_GROUP,                      CONST_CS | CONST_PERSISTENT);
   #ifdef HAS_MCAST_EXT
           REGISTER_LONG_CONSTANT("MCAST_BLOCK_SOURCE",            MCAST_BLOCK_SOURCE,                     CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("MCAST_UNBLOCK_SOURCE",          MCAST_UNBLOCK_SOURCE,           CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("MCAST_JOIN_SOURCE_GROUP",       MCAST_JOIN_SOURCE_GROUP,        CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("MCAST_LEAVE_SOURCE_GROUP",      MCAST_LEAVE_SOURCE_GROUP,       CONST_CS | CONST_PERSISTENT);
   #endif
   
           REGISTER_LONG_CONSTANT("IP_MULTICAST_IF",                       IP_MULTICAST_IF,                CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("IP_MULTICAST_TTL",                      IP_MULTICAST_TTL,               CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("IP_MULTICAST_LOOP",                     IP_MULTICAST_LOOP,              CONST_CS | CONST_PERSISTENT);
   #if HAVE_IPV6
           REGISTER_LONG_CONSTANT("IPV6_MULTICAST_IF",                     IPV6_MULTICAST_IF,              CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("IPV6_MULTICAST_HOPS",           IPV6_MULTICAST_HOPS,    CONST_CS | CONST_PERSISTENT);
           REGISTER_LONG_CONSTANT("IPV6_MULTICAST_LOOP",           IPV6_MULTICAST_LOOP,    CONST_CS | CONST_PERSISTENT);
   #endif
   
 #ifndef WIN32  #ifndef WIN32
 # include "unix_socket_constants.h"  # include "unix_socket_constants.h"
 #else  #else
 # include "win32_socket_constants.h"  # include "win32_socket_constants.h"
 #endif  #endif
   
        if ((pe = getprotobyname("tcp"))) {        REGISTER_LONG_CONSTANT("IPPROTO_IP",    IPPROTO_IP,                CONST_CS | CONST_PERSISTENT);
                REGISTER_LONG_CONSTANT("SOL_TCP", pe->p_proto, CONST_CS | CONST_PERSISTENT);#if HAVE_IPV6
        }        REGISTER_LONG_CONSTANT("IPPROTO_IPV6",  IPPROTO_IPV6,   CONST_CS | CONST_PERSISTENT);
 #endif
   
        if ((pe = getprotobyname("udp"))) {        REGISTER_LONG_CONSTANT("SOL_TCP",               IPPROTO_TCP,    CONST_CS | CONST_PERSISTENT);
                REGISTER_LONG_CONSTANT("SOL_UDP", pe->p_proto, CONST_CS | CONST_PERSISTENT);        REGISTER_LONG_CONSTANT("SOL_UDP",               IPPROTO_UDP,        CONST_CS | CONST_PERSISTENT);
        } 
   
         return SUCCESS;          return SUCCESS;
 }  }
Line 912  PHP_FUNCTION(socket_set_nonblock) Line 1080  PHP_FUNCTION(socket_set_nonblock)
         }          }
   
         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);          ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
           
           if (php_sock->zstream != NULL) {
                   php_stream *stream;
                   /* omit notice if resource doesn't exist anymore */
                   stream = zend_fetch_resource(&php_sock->zstream TSRMLS_CC, -1,
                           NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
                   if (stream != NULL) {
                           if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 0,
                                           NULL) != -1) {
                                   php_sock->blocking = 1;
                                   RETURN_TRUE;
                           }
                   }
           }
   
         if (php_set_sock_blocking(php_sock->bsd_socket, 0 TSRMLS_CC) == SUCCESS) {          if (php_set_sock_blocking(php_sock->bsd_socket, 0 TSRMLS_CC) == SUCCESS) {
                 php_sock->blocking = 0;                  php_sock->blocking = 0;
Line 935  PHP_FUNCTION(socket_set_block) Line 1117  PHP_FUNCTION(socket_set_block)
         }          }
   
         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);          ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
           
           /* if socket was created from a stream, give the stream a chance to take
            * care of the operation itself, thereby allowing it to update its internal
            * state */
           if (php_sock->zstream != NULL) {
                   php_stream *stream;
                   stream = zend_fetch_resource(&php_sock->zstream TSRMLS_CC, -1,
                           NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
                   if (stream != NULL) {
                           if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 1,
                                           NULL) != -1) {
                                   php_sock->blocking = 1;
                                   RETURN_TRUE;
                           }
                   }
           }
   
         if (php_set_sock_blocking(php_sock->bsd_socket, 1 TSRMLS_CC) == SUCCESS) {          if (php_set_sock_blocking(php_sock->bsd_socket, 1 TSRMLS_CC) == SUCCESS) {
                 php_sock->blocking = 1;                  php_sock->blocking = 1;
Line 980  PHP_FUNCTION(socket_close) Line 1178  PHP_FUNCTION(socket_close)
         }          }
   
         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);          ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
           if (php_sock->zstream != NULL) {
                   php_stream *stream = NULL;
                   php_stream_from_zval_no_verify(stream, &php_sock->zstream);
                   if (stream != NULL) {
                           /* close & destroy stream, incl. removing it from the rsrc list;
                            * resource stored in php_sock->zstream will become invalid */
                           php_stream_free(stream, PHP_STREAM_FREE_CLOSE |
                                           (stream->is_persistent?PHP_STREAM_FREE_CLOSE_PERSISTENT:0));
                   }
           }
         zend_list_delete(Z_RESVAL_P(arg1));          zend_list_delete(Z_RESVAL_P(arg1));
 }  }
 /* }}} */  /* }}} */
Line 1237  PHP_FUNCTION(socket_getpeername) Line 1445  PHP_FUNCTION(socket_getpeername)
 PHP_FUNCTION(socket_create)  PHP_FUNCTION(socket_create)
 {  {
         long            arg1, arg2, arg3;          long            arg1, arg2, arg3;
        php_socket      *php_sock = (php_socket*)emalloc(sizeof(php_socket));        php_socket      *php_sock = php_create_socket();
   
         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {          if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {
                 efree(php_sock);                  efree(php_sock);
Line 1281  PHP_FUNCTION(socket_connect) Line 1489  PHP_FUNCTION(socket_connect)
 {  {
         zval                            *arg1;          zval                            *arg1;
         php_socket                      *php_sock;          php_socket                      *php_sock;
         struct sockaddr_in      sin;  
 #if HAVE_IPV6  
         struct sockaddr_in6     sin6;  
 #endif  
         struct sockaddr_un      s_un;  
         char                            *addr;          char                            *addr;
         int                                     retval, addr_len;          int                                     retval, addr_len;
         long                            port = 0;          long                            port = 0;
Line 1299  PHP_FUNCTION(socket_connect) Line 1502  PHP_FUNCTION(socket_connect)
   
         switch(php_sock->type) {          switch(php_sock->type) {
 #if HAVE_IPV6  #if HAVE_IPV6
                case AF_INET6:                case AF_INET6: {
                         struct sockaddr_in6 sin6 = {0};
                         
                         if (argc != 3) {                          if (argc != 3) {
                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
                                 RETURN_FALSE;                                  RETURN_FALSE;
Line 1316  PHP_FUNCTION(socket_connect) Line 1521  PHP_FUNCTION(socket_connect)
   
                         retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));                          retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
                         break;                          break;
                   }
 #endif  #endif
                case AF_INET:                case AF_INET: {
                         struct sockaddr_in sin = {0};
                         
                         if (argc != 3) {                          if (argc != 3) {
                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");
                                 RETURN_FALSE;                                  RETURN_FALSE;
                         }                          }
   
                         memset(&sin, 0, sizeof(struct sockaddr_in));  
   
                         sin.sin_family = AF_INET;                          sin.sin_family = AF_INET;
                         sin.sin_port   = htons((unsigned short int)port);                          sin.sin_port   = htons((unsigned short int)port);
   
Line 1334  PHP_FUNCTION(socket_connect) Line 1540  PHP_FUNCTION(socket_connect)
   
                         retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));                          retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
                         break;                          break;
                   }
   
                case AF_UNIX:                case AF_UNIX: {
                         struct sockaddr_un s_un = {0};
                         
                         if (addr_len >= sizeof(s_un.sun_path)) {                          if (addr_len >= sizeof(s_un.sun_path)) {
                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long");                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long");
                                 RETURN_FALSE;                                  RETURN_FALSE;
                         }                          }
                                   
                         memset(&s_un, 0, sizeof(struct sockaddr_un));  
   
                         s_un.sun_family = AF_UNIX;                          s_un.sun_family = AF_UNIX;
                         memcpy(&s_un.sun_path, addr, addr_len);                          memcpy(&s_un.sun_path, addr, addr_len);
                        retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + addr_len);                        retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
                                 (socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
                         break;                          break;
                   }
   
                 default:                  default:
                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);                          php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
Line 1746  PHP_FUNCTION(socket_get_option) Line 1955  PHP_FUNCTION(socket_get_option)
   
         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);          ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
   
           if (level == IPPROTO_IP) {
                   switch (optname) {
                   case IP_MULTICAST_IF: {
                           struct in_addr if_addr;
                           unsigned int if_index;
                           optlen = sizeof(if_addr);
                           if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&if_addr, &optlen) != 0) {
                                   PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
                                   RETURN_FALSE;
                           }
                           if (php_add4_to_if_index(&if_addr, php_sock, &if_index TSRMLS_CC) == SUCCESS) {
                                   RETURN_LONG((long) if_index);
                           } else {
                                   RETURN_FALSE;
                           }
                   }
                   }
           }
           
           /* sol_socket options and general case */
         switch(optname) {          switch(optname) {
                 case SO_LINGER:                  case SO_LINGER:
                         optlen = sizeof(linger_val);                          optlen = sizeof(linger_val);
Line 1786  PHP_FUNCTION(socket_get_option) Line 2015  PHP_FUNCTION(socket_get_option)
                         add_assoc_long(return_value, "sec", tv.tv_sec);                          add_assoc_long(return_value, "sec", tv.tv_sec);
                         add_assoc_long(return_value, "usec", tv.tv_usec);                          add_assoc_long(return_value, "usec", tv.tv_usec);
                         break;                          break;
                
                 default:                  default:
                         optlen = sizeof(other_val);                          optlen = sizeof(other_val);
   
Line 1794  PHP_FUNCTION(socket_get_option) Line 2023  PHP_FUNCTION(socket_get_option)
                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);                                  PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
                                 RETURN_FALSE;                                  RETURN_FALSE;
                         }                          }
                           if (optlen == 1)
                                   other_val = *((unsigned char *)&other_val);
   
                         RETURN_LONG(other_val);                          RETURN_LONG(other_val);
                         break;                          break;
Line 1801  PHP_FUNCTION(socket_get_option) Line 2032  PHP_FUNCTION(socket_get_option)
 }  }
 /* }}} */  /* }}} */
   
   static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval **arg4 TSRMLS_DC)
   {
           HashTable                               *opt_ht;
           unsigned int                    if_index;
           int                                             retval;
           int (*mcast_req_fun)(php_socket *, int, struct sockaddr *, socklen_t,
                   unsigned TSRMLS_DC);
   #ifdef HAS_MCAST_EXT
           int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t,
                   struct sockaddr *, socklen_t, unsigned TSRMLS_DC);
   #endif
   
           switch (optname) {
           case MCAST_JOIN_GROUP:
                   mcast_req_fun = &php_mcast_join;
                   goto mcast_req_fun;
           case MCAST_LEAVE_GROUP:
                   {
                           php_sockaddr_storage    group = {0};
                           socklen_t                               glen;
   
                           mcast_req_fun = &php_mcast_leave;
   mcast_req_fun:
                           convert_to_array_ex(arg4);
                           opt_ht = HASH_OF(*arg4);
   
                           if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
                                   &glen TSRMLS_CC) == FAILURE) {
                                           return FAILURE;
                           }
                           if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
                                   &if_index TSRMLS_CC) == FAILURE) {
                                           return FAILURE;
                           }
   
                           retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group,
                                   glen, if_index TSRMLS_CC);
                           break;
                   }
   
   #ifdef HAS_MCAST_EXT
           case MCAST_BLOCK_SOURCE:
                   mcast_sreq_fun = &php_mcast_block_source;
                   goto mcast_sreq_fun;
           case MCAST_UNBLOCK_SOURCE:
                   mcast_sreq_fun = &php_mcast_unblock_source;
                   goto mcast_sreq_fun;
           case MCAST_JOIN_SOURCE_GROUP:
                   mcast_sreq_fun = &php_mcast_join_source;
                   goto mcast_sreq_fun;
           case MCAST_LEAVE_SOURCE_GROUP:
                   {
                           php_sockaddr_storage    group = {0},
                                                                           source = {0};
                           socklen_t                               glen,
                                                                           slen;
                           
                           mcast_sreq_fun = &php_mcast_leave_source;
                   mcast_sreq_fun:
                           convert_to_array_ex(arg4);
                           opt_ht = HASH_OF(*arg4);
                           
                           if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
                                           &glen TSRMLS_CC) == FAILURE) {
                                   return FAILURE;
                           }
                           if (php_get_address_from_array(opt_ht, "source", php_sock, &source,
                                           &slen TSRMLS_CC) == FAILURE) {
                                   return FAILURE;
                           }
                           if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
                                           &if_index TSRMLS_CC) == FAILURE) {
                                   return FAILURE;
                           }
                           
                           retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group,
                                           glen, (struct sockaddr*)&source, slen, if_index TSRMLS_CC);
                           break;
                   }
   #endif
           default:
                   php_error_docref(NULL TSRMLS_CC, E_WARNING,
                           "unexpected option in php_do_mcast_opt (level %d, option %d). "
                           "This is a bug.", level, optname);
                   return FAILURE;
           }
   
           if (retval != 0) {
                   if (retval != -2) { /* error, but message already emitted */
                           PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
                   }
                   return FAILURE;
           }
           return SUCCESS;
   }
   
 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)  /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
    Sets socket options for the socket */     Sets socket options for the socket */
 PHP_FUNCTION(socket_set_option)  PHP_FUNCTION(socket_set_option)
 {  {
        zval                    *arg1, **arg4;        zval                                    *arg1, **arg4;
        struct linger   lv;        struct linger                   lv;
        php_socket              *php_sock;        php_socket                              *php_sock;
        int                             ov, optlen, retval;        int                                             ov, optlen, retval;
 #ifdef PHP_WIN32  #ifdef PHP_WIN32
        int                                timeout;        int                                                timeout;
 #else  #else
        struct                  timeval tv;        struct                                  timeval tv;
 #endif  #endif
        long                    level, optname;        long                                    level, optname;
        void                    *opt_ptr;        void                                    *opt_ptr;
        HashTable               *opt_ht;        HashTable                               *opt_ht;
        zval                    **l_onoff, **l_linger;        zval                                    **l_onoff, **l_linger;
        zval                    **sec, **usec;        zval                                    **sec, **usec;
        /* key name constants */        
        char                    *l_onoff_key = "l_onoff";        /* Multicast */
        char                    *l_linger_key = "l_linger";        unsigned int                    if_index;
        char                    *sec_key = "sec";        struct in_addr                  if_addr;
        char                    *usec_key = "usec";        unsigned char                   ipv4_mcast_ttl_lback;
        
         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, &level, &optname, &arg4) == FAILURE) {          if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, &level, &optname, &arg4) == FAILURE) {
                 return;                  return;
         }          }
Line 1833  PHP_FUNCTION(socket_set_option) Line 2160  PHP_FUNCTION(socket_set_option)
   
         set_errno(0);          set_errno(0);
   
           if (level == IPPROTO_IP) {
                   switch (optname) {
                   case MCAST_JOIN_GROUP:
                   case MCAST_LEAVE_GROUP:
   #ifdef HAS_MCAST_EXT
                   case MCAST_BLOCK_SOURCE:
                   case MCAST_UNBLOCK_SOURCE:
                   case MCAST_JOIN_SOURCE_GROUP:
                   case MCAST_LEAVE_SOURCE_GROUP:
   #endif
                           if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC) == FAILURE) {
                                   RETURN_FALSE;
                           } else {
                                   RETURN_TRUE;
                           }
   
                   case IP_MULTICAST_IF:
                           if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
                                   RETURN_FALSE;
                           }
   
                           if (php_if_index_to_addr4(if_index, php_sock, &if_addr TSRMLS_CC) == FAILURE) {
                                   RETURN_FALSE;
                           }
                           opt_ptr = &if_addr;
                           optlen  = sizeof(if_addr);
                           goto dosockopt;
   
                   case IP_MULTICAST_LOOP:
                           convert_to_boolean_ex(arg4);
                           goto ipv4_loop_ttl;
                   case IP_MULTICAST_TTL:
                           convert_to_long_ex(arg4);
                           if (Z_LVAL_PP(arg4) < 0L || Z_LVAL_PP(arg4) > 255L) {
                                   php_error_docref(NULL TSRMLS_CC, E_WARNING,
                                                   "Expected a value between 0 and 255");
                                   RETURN_FALSE;
                           }
   ipv4_loop_ttl:
                           ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_PP(arg4);
                           opt_ptr = &ipv4_mcast_ttl_lback;
                           optlen  = sizeof(ipv4_mcast_ttl_lback);
                           goto dosockopt;
                   }
           }
   
   #if HAVE_IPV6
           else if (level == IPPROTO_IPV6) {
                   switch (optname) {
                   case MCAST_JOIN_GROUP:
                   case MCAST_LEAVE_GROUP:
   #ifdef HAS_MCAST_EXT
                   case MCAST_BLOCK_SOURCE:
                   case MCAST_UNBLOCK_SOURCE:
                   case MCAST_JOIN_SOURCE_GROUP:
                   case MCAST_LEAVE_SOURCE_GROUP:
   #endif
                           if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC) == FAILURE) {
                                   RETURN_FALSE;
                           } else {
                                   RETURN_TRUE;
                           }
   
                   case IPV6_MULTICAST_IF:
                           if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
                                   RETURN_FALSE;
                           }
                           
                           opt_ptr = &if_index;
                           optlen  = sizeof(if_index);
                           goto dosockopt;
   
                   case IPV6_MULTICAST_LOOP:
                           convert_to_boolean_ex(arg4);
                           goto ipv6_loop_hops;
                   case IPV6_MULTICAST_HOPS:
                           convert_to_long_ex(arg4);
                           if (Z_LVAL_PP(arg4) < -1L || Z_LVAL_PP(arg4) > 255L) {
                                   php_error_docref(NULL TSRMLS_CC, E_WARNING,
                                                   "Expected a value between -1 and 255");
                                   RETURN_FALSE;
                           }
   ipv6_loop_hops:
                           ov = (int) Z_LVAL_PP(arg4);
                           opt_ptr = &ov;
                           optlen  = sizeof(ov);
                           goto dosockopt;
                   }
           }
   #endif
   
         switch (optname) {          switch (optname) {
                case SO_LINGER:                case SO_LINGER: {
                         const char l_onoff_key[] = "l_onoff";
                         const char l_linger_key[] = "l_linger";
 
                         convert_to_array_ex(arg4);                          convert_to_array_ex(arg4);
                         opt_ht = HASH_OF(*arg4);                          opt_ht = HASH_OF(*arg4);
   
                        if (zend_hash_find(opt_ht, l_onoff_key, strlen(l_onoff_key) + 1, (void **)&l_onoff) == FAILURE) {                        if (zend_hash_find(opt_ht, l_onoff_key, sizeof(l_onoff_key), (void **)&l_onoff) == FAILURE) {
                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
                                 RETURN_FALSE;                                  RETURN_FALSE;
                         }                          }
                        if (zend_hash_find(opt_ht, l_linger_key, strlen(l_linger_key) + 1, (void **)&l_linger) == FAILURE) {                        if (zend_hash_find(opt_ht, l_linger_key, sizeof(l_linger_key), (void **)&l_linger) == FAILURE) {
                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
                                 RETURN_FALSE;                                  RETURN_FALSE;
                         }                          }
Line 1856  PHP_FUNCTION(socket_set_option) Line 2277  PHP_FUNCTION(socket_set_option)
                         optlen = sizeof(lv);                          optlen = sizeof(lv);
                         opt_ptr = &lv;                          opt_ptr = &lv;
                         break;                          break;
                   }
   
                 case SO_RCVTIMEO:                  case SO_RCVTIMEO:
                case SO_SNDTIMEO:                case SO_SNDTIMEO: {
                         const char sec_key[] = "sec";
                         const char usec_key[] = "usec";
 
                         convert_to_array_ex(arg4);                          convert_to_array_ex(arg4);
                         opt_ht = HASH_OF(*arg4);                          opt_ht = HASH_OF(*arg4);
   
                        if (zend_hash_find(opt_ht, sec_key, strlen(sec_key) + 1, (void **)&sec) == FAILURE) {                        if (zend_hash_find(opt_ht, sec_key, sizeof(sec_key), (void **)&sec) == FAILURE) {
                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", sec_key);                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", sec_key);
                                 RETURN_FALSE;                                  RETURN_FALSE;
                         }                          }
                        if (zend_hash_find(opt_ht, usec_key, strlen(usec_key) + 1, (void **)&usec) == FAILURE) {                        if (zend_hash_find(opt_ht, usec_key, sizeof(usec_key), (void **)&usec) == FAILURE) {
                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", usec_key);                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", usec_key);
                                 RETURN_FALSE;                                  RETURN_FALSE;
                         }                          }
Line 1884  PHP_FUNCTION(socket_set_option) Line 2309  PHP_FUNCTION(socket_set_option)
                         opt_ptr = &timeout;                          opt_ptr = &timeout;
 #endif  #endif
                         break;                          break;
                }
                 
                 default:                  default:
                         convert_to_long_ex(arg4);                          convert_to_long_ex(arg4);
                         ov = Z_LVAL_PP(arg4);                          ov = Z_LVAL_PP(arg4);
Line 1894  PHP_FUNCTION(socket_set_option) Line 2320  PHP_FUNCTION(socket_set_option)
                         break;                          break;
         }          }
   
   dosockopt:
         retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);          retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
   
         if (retval != 0) {          if (retval != 0) {
                PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);                if (retval != -2) { /* error, but message already emitted */
                         PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
                 }
                 RETURN_FALSE;                  RETURN_FALSE;
         }          }
   
Line 1919  PHP_FUNCTION(socket_create_pair) Line 2347  PHP_FUNCTION(socket_create_pair)
                 return;                  return;
         }          }
   
        php_sock[0] = (php_socket*)emalloc(sizeof(php_socket));        php_sock[0] = php_create_socket();
        php_sock[1] = (php_socket*)emalloc(sizeof(php_socket));        php_sock[1] = php_create_socket();
   
         if (domain != AF_INET          if (domain != AF_INET
 #if HAVE_IPV6  #if HAVE_IPV6
Line 2034  PHP_FUNCTION(socket_clear_error) Line 2462  PHP_FUNCTION(socket_clear_error)
         }          }
   
         return;          return;
   }
   /* }}} */
   
   /* {{{ proto void socket_import_stream(resource stream)
      Imports a stream that encapsulates a socket into a socket extension resource. */
   PHP_FUNCTION(socket_import_stream)
   {
           zval                             *zstream;
           php_stream                       *stream;
           php_socket                       *retsock = NULL;
           PHP_SOCKET                       socket; /* fd */
           php_sockaddr_storage addr;
           socklen_t                        addr_len = sizeof(addr);
   #ifndef PHP_WIN32
           int                                      t;
   #endif
   
           if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) == FAILURE) {
                   return;
           }
           php_stream_from_zval(stream, &zstream);
           
           if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
                   /* error supposedly already shown */
                   RETURN_FALSE;
           }
           
           retsock = php_create_socket();
           
           retsock->bsd_socket = socket;
           
           /* determine family */
           if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
                   retsock->type = addr.ss_family;
           } else {
                   PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
                   goto error;
           }
           
           /* determine blocking mode */
   #ifndef PHP_WIN32
           t = fcntl(socket, F_GETFL);
           if(t == -1) {
                   PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
                   goto error;
           } else {
                   retsock->blocking = !(t & O_NONBLOCK);
           }
   #else
           /* on windows, check if the stream is a socket stream and read its
            * private data; otherwise assume it's in non-blocking mode */
           if (php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
                   retsock->blocking =
                                   ((php_netstream_data_t *)stream->abstract)->is_blocked;
           } else {
                   retsock->blocking = 1;
           }
   #endif
           
           /* hold a zval reference to the stream (holding a php_stream* directly could
            * also be done, but this might be slightly better if in the future we want
            * to provide a socket_export_stream) */
           MAKE_STD_ZVAL(retsock->zstream);
           *retsock->zstream = *zstream;
           zval_copy_ctor(retsock->zstream);
           Z_UNSET_ISREF_P(retsock->zstream);
           Z_SET_REFCOUNT_P(retsock->zstream, 1);
           
           php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
                   PHP_STREAM_BUFFER_NONE, NULL);
           
           ZEND_REGISTER_RESOURCE(return_value, retsock, le_socket);
           return;
   error:
           if (retsock != NULL)
                   efree(retsock);
           RETURN_FALSE;
 }  }
 /* }}} */  /* }}} */
   

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>