root/ext/sockets/sockets.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_sockets_le_socket
  2. php_create_socket
  3. php_destroy_socket
  4. php_open_listen_sock
  5. php_accept_connect
  6. php_read
  7. sockets_strerror
  8. PHP_GINIT_FUNCTION
  9. PHP_MINIT_FUNCTION
  10. PHP_MSHUTDOWN_FUNCTION
  11. PHP_MINFO_FUNCTION
  12. PHP_RSHUTDOWN_FUNCTION
  13. php_sock_array_to_fd_set
  14. php_sock_array_from_fd_set
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. PHP_FUNCTION
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. socket_import_file_descriptor
  41. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Chris Vandomelen <chrisv@b0rked.dhs.org>                    |
  16    |          Sterling Hughes  <sterling@php.net>                         |
  17    |          Jason Greene     <jason@php.net>                            |
  18    |          Gustavo Lopes    <cataphract@php.net>                       |
  19    | WinSock: Daniel Beulshausen <daniel@php4win.de>                      |
  20    +----------------------------------------------------------------------+
  21  */
  22 
  23 /* $Id$ */
  24 
  25 #ifdef HAVE_CONFIG_H
  26 #include "config.h"
  27 #endif
  28 
  29 #include "php.h"
  30 
  31 #include "php_network.h"
  32 #include "ext/standard/file.h"
  33 #include "ext/standard/info.h"
  34 #include "php_ini.h"
  35 #ifdef PHP_WIN32
  36 # include "windows_common.h"
  37 # include <win32/inet.h>
  38 # include <windows.h>
  39 # include <Ws2tcpip.h>
  40 # include "php_sockets.h"
  41 # include <win32/sockets.h>
  42 #else
  43 # include <sys/types.h>
  44 # include <sys/socket.h>
  45 # include <netdb.h>
  46 # include <netinet/in.h>
  47 # include <netinet/tcp.h>
  48 # include <sys/un.h>
  49 # include <arpa/inet.h>
  50 # include <sys/time.h>
  51 # include <unistd.h>
  52 # include <errno.h>
  53 # include <fcntl.h>
  54 # include <signal.h>
  55 # include <sys/uio.h>
  56 # define IS_INVALID_SOCKET(a)   (a->bsd_socket < 0)
  57 # define set_errno(a) (errno = a)
  58 # include "php_sockets.h"
  59 # if HAVE_IF_NAMETOINDEX
  60 #  include <net/if.h>
  61 # endif
  62 #endif
  63 
  64 #include <stddef.h>
  65 
  66 #include "sockaddr_conv.h"
  67 #include "multicast.h"
  68 #include "sendrecvmsg.h"
  69 
  70 ZEND_DECLARE_MODULE_GLOBALS(sockets)
  71 
  72 #ifndef MSG_WAITALL
  73 #ifdef LINUX
  74 #define MSG_WAITALL 0x00000100
  75 #else
  76 #define MSG_WAITALL 0x00000000
  77 #endif
  78 #endif
  79 
  80 #ifndef MSG_EOF
  81 #ifdef MSG_FIN
  82 #define MSG_EOF MSG_FIN
  83 #endif
  84 #endif
  85 
  86 #ifndef SUN_LEN
  87 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
  88 #endif
  89 
  90 #ifndef PF_INET
  91 #define PF_INET AF_INET
  92 #endif
  93 
  94 #define PHP_NORMAL_READ 0x0001
  95 #define PHP_BINARY_READ 0x0002
  96 
  97 static int le_socket;
  98 #define le_socket_name php_sockets_le_socket_name
  99 
 100 /* {{{ arginfo */
 101 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_select, 0, 0, 4)
 102         ZEND_ARG_INFO(1, read_fds)
 103         ZEND_ARG_INFO(1, write_fds)
 104         ZEND_ARG_INFO(1, except_fds)
 105         ZEND_ARG_INFO(0, tv_sec)
 106         ZEND_ARG_INFO(0, tv_usec)
 107 ZEND_END_ARG_INFO()
 108 
 109 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_listen, 0, 0, 1)
 110         ZEND_ARG_INFO(0, port)
 111         ZEND_ARG_INFO(0, backlog)
 112 ZEND_END_ARG_INFO()
 113 
 114 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_accept, 0, 0, 1)
 115         ZEND_ARG_INFO(0, socket)
 116 ZEND_END_ARG_INFO()
 117 
 118 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_nonblock, 0, 0, 1)
 119         ZEND_ARG_INFO(0, socket)
 120 ZEND_END_ARG_INFO()
 121 
 122 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_block, 0, 0, 1)
 123         ZEND_ARG_INFO(0, socket)
 124 ZEND_END_ARG_INFO()
 125 
 126 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_listen, 0, 0, 1)
 127         ZEND_ARG_INFO(0, socket)
 128         ZEND_ARG_INFO(0, backlog)
 129 ZEND_END_ARG_INFO()
 130 
 131 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_close, 0, 0, 1)
 132         ZEND_ARG_INFO(0, socket)
 133 ZEND_END_ARG_INFO()
 134 
 135 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_write, 0, 0, 2)
 136         ZEND_ARG_INFO(0, socket)
 137         ZEND_ARG_INFO(0, buf)
 138         ZEND_ARG_INFO(0, length)
 139 ZEND_END_ARG_INFO()
 140 
 141 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_read, 0, 0, 2)
 142         ZEND_ARG_INFO(0, socket)
 143         ZEND_ARG_INFO(0, length)
 144         ZEND_ARG_INFO(0, type)
 145 ZEND_END_ARG_INFO()
 146 
 147 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getsockname, 0, 0, 2)
 148         ZEND_ARG_INFO(0, socket)
 149         ZEND_ARG_INFO(1, addr)
 150         ZEND_ARG_INFO(1, port)
 151 ZEND_END_ARG_INFO()
 152 
 153 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getpeername, 0, 0, 2)
 154         ZEND_ARG_INFO(0, socket)
 155         ZEND_ARG_INFO(1, addr)
 156         ZEND_ARG_INFO(1, port)
 157 ZEND_END_ARG_INFO()
 158 
 159 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create, 0, 0, 3)
 160         ZEND_ARG_INFO(0, domain)
 161         ZEND_ARG_INFO(0, type)
 162         ZEND_ARG_INFO(0, protocol)
 163 ZEND_END_ARG_INFO()
 164 
 165 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_connect, 0, 0, 2)
 166         ZEND_ARG_INFO(0, socket)
 167         ZEND_ARG_INFO(0, addr)
 168         ZEND_ARG_INFO(0, port)
 169 ZEND_END_ARG_INFO()
 170 
 171 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_strerror, 0, 0, 1)
 172         ZEND_ARG_INFO(0, errno)
 173 ZEND_END_ARG_INFO()
 174 
 175 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_bind, 0, 0, 2)
 176         ZEND_ARG_INFO(0, socket)
 177         ZEND_ARG_INFO(0, addr)
 178         ZEND_ARG_INFO(0, port)
 179 ZEND_END_ARG_INFO()
 180 
 181 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recv, 0, 0, 4)
 182         ZEND_ARG_INFO(0, socket)
 183         ZEND_ARG_INFO(1, buf)
 184         ZEND_ARG_INFO(0, len)
 185         ZEND_ARG_INFO(0, flags)
 186 ZEND_END_ARG_INFO()
 187 
 188 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_send, 0, 0, 4)
 189         ZEND_ARG_INFO(0, socket)
 190         ZEND_ARG_INFO(0, buf)
 191         ZEND_ARG_INFO(0, len)
 192         ZEND_ARG_INFO(0, flags)
 193 ZEND_END_ARG_INFO()
 194 
 195 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvfrom, 0, 0, 5)
 196         ZEND_ARG_INFO(0, socket)
 197         ZEND_ARG_INFO(1, buf)
 198         ZEND_ARG_INFO(0, len)
 199         ZEND_ARG_INFO(0, flags)
 200         ZEND_ARG_INFO(1, name)
 201         ZEND_ARG_INFO(1, port)
 202 ZEND_END_ARG_INFO()
 203 
 204 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendto, 0, 0, 5)
 205         ZEND_ARG_INFO(0, socket)
 206         ZEND_ARG_INFO(0, buf)
 207         ZEND_ARG_INFO(0, len)
 208         ZEND_ARG_INFO(0, flags)
 209         ZEND_ARG_INFO(0, addr)
 210         ZEND_ARG_INFO(0, port)
 211 ZEND_END_ARG_INFO()
 212 
 213 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_get_option, 0, 0, 3)
 214         ZEND_ARG_INFO(0, socket)
 215         ZEND_ARG_INFO(0, level)
 216         ZEND_ARG_INFO(0, optname)
 217 ZEND_END_ARG_INFO()
 218 
 219 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_option, 0, 0, 4)
 220         ZEND_ARG_INFO(0, socket)
 221         ZEND_ARG_INFO(0, level)
 222         ZEND_ARG_INFO(0, optname)
 223         ZEND_ARG_INFO(0, optval)
 224 ZEND_END_ARG_INFO()
 225 
 226 #ifdef HAVE_SOCKETPAIR
 227 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_pair, 0, 0, 4)
 228         ZEND_ARG_INFO(0, domain)
 229         ZEND_ARG_INFO(0, type)
 230         ZEND_ARG_INFO(0, protocol)
 231         ZEND_ARG_INFO(1, fd)
 232 ZEND_END_ARG_INFO()
 233 #endif
 234 
 235 #ifdef HAVE_SHUTDOWN
 236 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_shutdown, 0, 0, 1)
 237         ZEND_ARG_INFO(0, socket)
 238         ZEND_ARG_INFO(0, how)
 239 ZEND_END_ARG_INFO()
 240 #endif
 241 
 242 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_last_error, 0, 0, 0)
 243         ZEND_ARG_INFO(0, socket)
 244 ZEND_END_ARG_INFO()
 245 
 246 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
 247         ZEND_ARG_INFO(0, socket)
 248 ZEND_END_ARG_INFO()
 249 
 250 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1)
 251         ZEND_ARG_INFO(0, stream)
 252 ZEND_END_ARG_INFO()
 253 
 254 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_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 PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{ */
 380 {
 381         return le_socket;
 382 }
 383 /* }}} */
 384 
 385 /* allocating function to make programming errors due to uninitialized fields
 386  * less likely */
 387 static php_socket *php_create_socket(void) /* {{{ */
 388 {
 389         php_socket *php_sock = emalloc(sizeof *php_sock);
 390 
 391         php_sock->bsd_socket = -1; /* invalid socket */
 392         php_sock->type           = PF_UNSPEC;
 393         php_sock->error          = 0;
 394         php_sock->blocking       = 1;
 395         php_sock->zstream        = NULL;
 396 
 397         return php_sock;
 398 }
 399 /* }}} */
 400 
 401 static void php_destroy_socket(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
 402 {
 403         php_socket *php_sock = rsrc->ptr;
 404 
 405         if (php_sock->zstream == NULL) {
 406                 if (!IS_INVALID_SOCKET(php_sock)) {
 407                         close(php_sock->bsd_socket);
 408                 }
 409         } else {
 410                 zval_ptr_dtor(&php_sock->zstream);
 411         }
 412         efree(php_sock);
 413 }
 414 /* }}} */
 415 
 416 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         php_socket                      *sock = php_create_socket();
 421 
 422         *php_sock = sock;
 423 
 424 #ifndef PHP_WIN32
 425         if ((hp = gethostbyname("0.0.0.0")) == NULL) {
 426 #else
 427         if ((hp = gethostbyname("localhost")) == NULL) {
 428 #endif
 429                 efree(sock);
 430                 return 0;
 431         }
 432 
 433         memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length);
 434         la.sin_family = hp->h_addrtype;
 435         la.sin_port = htons((unsigned short) port);
 436 
 437         sock->bsd_socket = socket(PF_INET, SOCK_STREAM, 0);
 438         sock->blocking = 1;
 439 
 440         if (IS_INVALID_SOCKET(sock)) {
 441                 PHP_SOCKET_ERROR(sock, "unable to create listening socket", errno);
 442                 efree(sock);
 443                 return 0;
 444         }
 445 
 446         sock->type = PF_INET;
 447 
 448         if (bind(sock->bsd_socket, (struct sockaddr *)&la, sizeof(la)) != 0) {
 449                 PHP_SOCKET_ERROR(sock, "unable to bind to given address", errno);
 450                 close(sock->bsd_socket);
 451                 efree(sock);
 452                 return 0;
 453         }
 454 
 455         if (listen(sock->bsd_socket, backlog) != 0) {
 456                 PHP_SOCKET_ERROR(sock, "unable to listen on socket", errno);
 457                 close(sock->bsd_socket);
 458                 efree(sock);
 459                 return 0;
 460         }
 461 
 462         return 1;
 463 }
 464 /* }}} */
 465 
 466 static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la, socklen_t *la_len TSRMLS_DC) /* {{{ */
 467 {
 468         php_socket      *out_sock = php_create_socket();
 469 
 470         *new_sock = out_sock;
 471 
 472         out_sock->bsd_socket = accept(in_sock->bsd_socket, la, la_len);
 473 
 474         if (IS_INVALID_SOCKET(out_sock)) {
 475                 PHP_SOCKET_ERROR(out_sock, "unable to accept incoming connection", errno);
 476                 efree(out_sock);
 477                 return 0;
 478         }
 479 
 480         out_sock->error = 0;
 481         out_sock->blocking = 1;
 482         out_sock->type = la->sa_family;
 483 
 484         return 1;
 485 }
 486 /* }}} */
 487 
 488 /* {{{ php_read -- wrapper around read() so that it only reads to a \r or \n. */
 489 static int php_read(php_socket *sock, void *buf, size_t maxlen, int flags)
 490 {
 491         int m = 0;
 492         size_t n = 0;
 493         int no_read = 0;
 494         int nonblock = 0;
 495         char *t = (char *) buf;
 496 
 497 #ifndef PHP_WIN32
 498         m = fcntl(sock->bsd_socket, F_GETFL);
 499         if (m < 0) {
 500                 return m;
 501         }
 502         nonblock = (m & O_NONBLOCK);
 503         m = 0;
 504 #else
 505         nonblock = !sock->blocking;
 506 #endif
 507         set_errno(0);
 508 
 509         *t = '\0';
 510         while (*t != '\n' && *t != '\r' && n < maxlen) {
 511                 if (m > 0) {
 512                         t++;
 513                         n++;
 514                 } else if (m == 0) {
 515                         no_read++;
 516                         if (nonblock && no_read >= 2) {
 517                                 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                         if (no_read > 200) {
 524                                 set_errno(ECONNRESET);
 525                                 return -1;
 526                         }
 527                 }
 528 
 529                 if (n < maxlen) {
 530                         m = recv(sock->bsd_socket, (void *) t, 1, flags);
 531                 }
 532 
 533                 if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
 534                         return -1;
 535                 }
 536 
 537                 set_errno(0);
 538         }
 539 
 540         if (n < maxlen) {
 541                 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         return n;
 550 }
 551 /* }}} */
 552 
 553 char *sockets_strerror(int error TSRMLS_DC) /* {{{ */
 554 {
 555         const char *buf;
 556 
 557 #ifndef PHP_WIN32
 558         if (error < -10000) {
 559                 error = -error - 10000;
 560 
 561 #ifdef HAVE_HSTRERROR
 562                 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                 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         return (buf ? (char *) buf : "");
 597 }
 598 /* }}} */
 599 
 600 /* {{{ PHP_GINIT_FUNCTION */
 601 static PHP_GINIT_FUNCTION(sockets)
 602 {
 603         sockets_globals->last_error = 0;
 604         sockets_globals->strerror_buf = NULL;
 605 }
 606 /* }}} */
 607 
 608 /* {{{ PHP_MINIT_FUNCTION
 609  */
 610 static PHP_MINIT_FUNCTION(sockets)
 611 {
 612         le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);
 613 
 614         REGISTER_LONG_CONSTANT("AF_UNIX",               AF_UNIX,                CONST_CS | CONST_PERSISTENT);
 615         REGISTER_LONG_CONSTANT("AF_INET",               AF_INET,                CONST_CS | CONST_PERSISTENT);
 616 #if HAVE_IPV6
 617         REGISTER_LONG_CONSTANT("AF_INET6",              AF_INET6,               CONST_CS | CONST_PERSISTENT);
 618 #endif
 619         REGISTER_LONG_CONSTANT("SOCK_STREAM",   SOCK_STREAM,    CONST_CS | CONST_PERSISTENT);
 620         REGISTER_LONG_CONSTANT("SOCK_DGRAM",    SOCK_DGRAM,             CONST_CS | CONST_PERSISTENT);
 621         REGISTER_LONG_CONSTANT("SOCK_RAW",              SOCK_RAW,               CONST_CS | CONST_PERSISTENT);
 622         REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT);
 623         REGISTER_LONG_CONSTANT("SOCK_RDM",              SOCK_RDM,               CONST_CS | CONST_PERSISTENT);
 624 
 625         REGISTER_LONG_CONSTANT("MSG_OOB",               MSG_OOB,                CONST_CS | CONST_PERSISTENT);
 626         REGISTER_LONG_CONSTANT("MSG_WAITALL",   MSG_WAITALL,    CONST_CS | CONST_PERSISTENT);
 627         REGISTER_LONG_CONSTANT("MSG_CTRUNC",    MSG_CTRUNC,             CONST_CS | CONST_PERSISTENT);
 628         REGISTER_LONG_CONSTANT("MSG_TRUNC",             MSG_TRUNC,              CONST_CS | CONST_PERSISTENT);
 629         REGISTER_LONG_CONSTANT("MSG_PEEK",              MSG_PEEK,               CONST_CS | CONST_PERSISTENT);
 630         REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE,  CONST_CS | CONST_PERSISTENT);
 631 #ifdef MSG_EOR
 632         REGISTER_LONG_CONSTANT("MSG_EOR",               MSG_EOR,                CONST_CS | CONST_PERSISTENT);
 633 #endif
 634 #ifdef MSG_EOF
 635         REGISTER_LONG_CONSTANT("MSG_EOF",               MSG_EOF,                CONST_CS | CONST_PERSISTENT);
 636 #endif
 637 
 638 #ifdef MSG_CONFIRM
 639         REGISTER_LONG_CONSTANT("MSG_CONFIRM",   MSG_CONFIRM,    CONST_CS | CONST_PERSISTENT);
 640 #endif
 641 #ifdef MSG_ERRQUEUE
 642         REGISTER_LONG_CONSTANT("MSG_ERRQUEUE",  MSG_ERRQUEUE,   CONST_CS | CONST_PERSISTENT);
 643 #endif
 644 #ifdef MSG_NOSIGNAL
 645         REGISTER_LONG_CONSTANT("MSG_NOSIGNAL",  MSG_NOSIGNAL,   CONST_CS | CONST_PERSISTENT);
 646 #endif
 647 #ifdef MSG_DONTWAIT
 648         REGISTER_LONG_CONSTANT("MSG_DONTWAIT",  MSG_DONTWAIT,   CONST_CS | CONST_PERSISTENT);
 649 #endif
 650 #ifdef MSG_MORE
 651         REGISTER_LONG_CONSTANT("MSG_MORE",              MSG_MORE,               CONST_CS | CONST_PERSISTENT);
 652 #endif
 653 #ifdef MSG_WAITFORONE
 654         REGISTER_LONG_CONSTANT("MSG_WAITFORONE",MSG_WAITFORONE, CONST_CS | CONST_PERSISTENT);
 655 #endif
 656 #ifdef MSG_CMSG_CLOEXEC
 657         REGISTER_LONG_CONSTANT("MSG_CMSG_CLOEXEC",MSG_CMSG_CLOEXEC,CONST_CS | CONST_PERSISTENT);
 658 #endif
 659 
 660         REGISTER_LONG_CONSTANT("SO_DEBUG",              SO_DEBUG,               CONST_CS | CONST_PERSISTENT);
 661         REGISTER_LONG_CONSTANT("SO_REUSEADDR",  SO_REUSEADDR,   CONST_CS | CONST_PERSISTENT);
 662 #ifdef SO_REUSEPORT
 663         REGISTER_LONG_CONSTANT("SO_REUSEPORT",  SO_REUSEPORT,   CONST_CS | CONST_PERSISTENT);
 664 #endif
 665         REGISTER_LONG_CONSTANT("SO_KEEPALIVE",  SO_KEEPALIVE,   CONST_CS | CONST_PERSISTENT);
 666         REGISTER_LONG_CONSTANT("SO_DONTROUTE",  SO_DONTROUTE,   CONST_CS | CONST_PERSISTENT);
 667         REGISTER_LONG_CONSTANT("SO_LINGER",             SO_LINGER,              CONST_CS | CONST_PERSISTENT);
 668         REGISTER_LONG_CONSTANT("SO_BROADCAST",  SO_BROADCAST,   CONST_CS | CONST_PERSISTENT);
 669         REGISTER_LONG_CONSTANT("SO_OOBINLINE",  SO_OOBINLINE,   CONST_CS | CONST_PERSISTENT);
 670         REGISTER_LONG_CONSTANT("SO_SNDBUF",             SO_SNDBUF,              CONST_CS | CONST_PERSISTENT);
 671         REGISTER_LONG_CONSTANT("SO_RCVBUF",             SO_RCVBUF,              CONST_CS | CONST_PERSISTENT);
 672         REGISTER_LONG_CONSTANT("SO_SNDLOWAT",   SO_SNDLOWAT,    CONST_CS | CONST_PERSISTENT);
 673         REGISTER_LONG_CONSTANT("SO_RCVLOWAT",   SO_RCVLOWAT,    CONST_CS | CONST_PERSISTENT);
 674         REGISTER_LONG_CONSTANT("SO_SNDTIMEO",   SO_SNDTIMEO,    CONST_CS | CONST_PERSISTENT);
 675         REGISTER_LONG_CONSTANT("SO_RCVTIMEO",   SO_RCVTIMEO,    CONST_CS | CONST_PERSISTENT);
 676         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         REGISTER_LONG_CONSTANT("SO_ERROR",              SO_ERROR,               CONST_CS | CONST_PERSISTENT);
 681 #ifdef SO_BINDTODEVICE
 682         REGISTER_LONG_CONSTANT("SO_BINDTODEVICE",       SO_BINDTODEVICE,        CONST_CS | CONST_PERSISTENT);
 683 #endif
 684         REGISTER_LONG_CONSTANT("SOL_SOCKET",    SOL_SOCKET,             CONST_CS | CONST_PERSISTENT);
 685         REGISTER_LONG_CONSTANT("SOMAXCONN",             SOMAXCONN,              CONST_CS | CONST_PERSISTENT);
 686 #ifdef TCP_NODELAY
 687         REGISTER_LONG_CONSTANT("TCP_NODELAY",   TCP_NODELAY,    CONST_CS | CONST_PERSISTENT);
 688 #endif
 689         REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
 690         REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
 691 
 692         REGISTER_LONG_CONSTANT("MCAST_JOIN_GROUP",                      PHP_MCAST_JOIN_GROUP,                   CONST_CS | CONST_PERSISTENT);
 693         REGISTER_LONG_CONSTANT("MCAST_LEAVE_GROUP",                     PHP_MCAST_LEAVE_GROUP,                  CONST_CS | CONST_PERSISTENT);
 694 #ifdef HAS_MCAST_EXT
 695         REGISTER_LONG_CONSTANT("MCAST_BLOCK_SOURCE",            PHP_MCAST_BLOCK_SOURCE,                 CONST_CS | CONST_PERSISTENT);
 696         REGISTER_LONG_CONSTANT("MCAST_UNBLOCK_SOURCE",          PHP_MCAST_UNBLOCK_SOURCE,               CONST_CS | CONST_PERSISTENT);
 697         REGISTER_LONG_CONSTANT("MCAST_JOIN_SOURCE_GROUP",       PHP_MCAST_JOIN_SOURCE_GROUP,    CONST_CS | CONST_PERSISTENT);
 698         REGISTER_LONG_CONSTANT("MCAST_LEAVE_SOURCE_GROUP",      PHP_MCAST_LEAVE_SOURCE_GROUP,   CONST_CS | CONST_PERSISTENT);
 699 #endif
 700 
 701         REGISTER_LONG_CONSTANT("IP_MULTICAST_IF",                       IP_MULTICAST_IF,                CONST_CS | CONST_PERSISTENT);
 702         REGISTER_LONG_CONSTANT("IP_MULTICAST_TTL",                      IP_MULTICAST_TTL,               CONST_CS | CONST_PERSISTENT);
 703         REGISTER_LONG_CONSTANT("IP_MULTICAST_LOOP",                     IP_MULTICAST_LOOP,              CONST_CS | CONST_PERSISTENT);
 704 #if HAVE_IPV6
 705         REGISTER_LONG_CONSTANT("IPV6_MULTICAST_IF",                     IPV6_MULTICAST_IF,              CONST_CS | CONST_PERSISTENT);
 706         REGISTER_LONG_CONSTANT("IPV6_MULTICAST_HOPS",           IPV6_MULTICAST_HOPS,    CONST_CS | CONST_PERSISTENT);
 707         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         REGISTER_LONG_CONSTANT("IPPROTO_IP",    IPPROTO_IP,             CONST_CS | CONST_PERSISTENT);
 717 #if HAVE_IPV6
 718         REGISTER_LONG_CONSTANT("IPPROTO_IPV6",  IPPROTO_IPV6,   CONST_CS | CONST_PERSISTENT);
 719 #endif
 720 
 721         REGISTER_LONG_CONSTANT("SOL_TCP",               IPPROTO_TCP,    CONST_CS | CONST_PERSISTENT);
 722         REGISTER_LONG_CONSTANT("SOL_UDP",               IPPROTO_UDP,    CONST_CS | CONST_PERSISTENT);
 723 
 724 #if HAVE_IPV6
 725         REGISTER_LONG_CONSTANT("IPV6_UNICAST_HOPS",                     IPV6_UNICAST_HOPS,      CONST_CS | CONST_PERSISTENT);
 726 #endif
 727 
 728         php_socket_sendrecvmsg_init(INIT_FUNC_ARGS_PASSTHRU);
 729 
 730         return SUCCESS;
 731 }
 732 /* }}} */
 733 
 734 /* {{{ PHP_MSHUTDOWN_FUNCTION
 735  */
 736 static PHP_MSHUTDOWN_FUNCTION(sockets)
 737 {
 738         php_socket_sendrecvmsg_shutdown(SHUTDOWN_FUNC_ARGS_PASSTHRU);
 739 
 740         return SUCCESS;
 741 }
 742 /* }}} */
 743 
 744 /* {{{ PHP_MINFO_FUNCTION
 745  */
 746 static PHP_MINFO_FUNCTION(sockets)
 747 {
 748         php_info_print_table_start();
 749         php_info_print_table_row(2, "Sockets Support", "enabled");
 750         php_info_print_table_end();
 751 }
 752 /* }}} */
 753 
 754 /* {{{ PHP_RSHUTDOWN_FUNCTION */
 755 static PHP_RSHUTDOWN_FUNCTION(sockets)
 756 {
 757         if (SOCKETS_G(strerror_buf)) {
 758                 efree(SOCKETS_G(strerror_buf));
 759                 SOCKETS_G(strerror_buf) = NULL;
 760         }
 761 
 762         return SUCCESS;
 763 }
 764 /* }}} */
 765 
 766 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         int                     num = 0;
 771 
 772         if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
 773 
 774         for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
 775                  zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
 776                  zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
 777 
 778                 php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
 779                 if (!php_sock) continue; /* If element is not a resource, skip it */
 780 
 781                 PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
 782                 if (php_sock->bsd_socket > *max_fd) {
 783                         *max_fd = php_sock->bsd_socket;
 784                 }
 785                 num++;
 786         }
 787 
 788         return num ? 1 : 0;
 789 }
 790 /* }}} */
 791 
 792 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         int                     num = 0;
 800         ulong       num_key;
 801         uint            key_len;
 802 
 803         if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
 804 
 805         ALLOC_HASHTABLE(new_hash);
 806         zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(sock_array)), NULL, ZVAL_PTR_DTOR, 0);
 807         for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
 808                  zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
 809                  zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
 810 
 811                 php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
 812                 if (!php_sock) continue; /* If element is not a resource, skip it */
 813 
 814                 if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
 815                         /* Add fd to new array */
 816                         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                                         zend_hash_add(new_hash, key, key_len, (void *)element, sizeof(zval *), (void **)&dest_element);
 819                                         break;
 820                                 case HASH_KEY_IS_LONG:
 821                                         zend_hash_index_update(new_hash, num_key, (void *)element, sizeof(zval *), (void **)&dest_element);
 822                                         break;
 823                         }
 824                         if (dest_element) zval_add_ref(dest_element);
 825                 }
 826                 num++;
 827         }
 828 
 829         /* Destroy old array, add new one */
 830         zend_hash_destroy(Z_ARRVAL_P(sock_array));
 831         efree(Z_ARRVAL_P(sock_array));
 832 
 833         zend_hash_internal_pointer_reset(new_hash);
 834         Z_ARRVAL_P(sock_array) = new_hash;
 835 
 836         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 PHP_FUNCTION(socket_select)
 843 {
 844         zval                    *r_array, *w_array, *e_array, *sec;
 845         struct timeval  tv;
 846         struct timeval *tv_p = NULL;
 847         fd_set                  rfds, wfds, efds;
 848         PHP_SOCKET              max_fd = 0;
 849         int                             retval, sets = 0;
 850         long                    usec = 0;
 851 
 852         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE) {
 853                 return;
 854         }
 855 
 856         FD_ZERO(&rfds);
 857         FD_ZERO(&wfds);
 858         FD_ZERO(&efds);
 859 
 860         if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
 861         if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
 862         if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
 863 
 864         if (!sets) {
 865                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no resource arrays were passed to select");
 866                 RETURN_FALSE;
 867         }
 868 
 869         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         if (sec != NULL) {
 873                 zval tmp;
 874 
 875                 if (Z_TYPE_P(sec) != IS_LONG) {
 876                         tmp = *sec;
 877                         zval_copy_ctor(&tmp);
 878                         convert_to_long(&tmp);
 879                         sec = &tmp;
 880                 }
 881 
 882                 /* Solaris + BSD do not like microsecond values which are >= 1 sec */
 883                 if (usec > 999999) {
 884                         tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000);
 885                         tv.tv_usec = usec % 1000000;
 886                 } else {
 887                         tv.tv_sec = Z_LVAL_P(sec);
 888                         tv.tv_usec = usec;
 889                 }
 890 
 891                 tv_p = &tv;
 892 
 893                 if (sec == &tmp) {
 894                         zval_dtor(&tmp);
 895                 }
 896         }
 897 
 898         retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p);
 899 
 900         if (retval == -1) {
 901                 SOCKETS_G(last_error) = errno;
 902                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s", errno, sockets_strerror(errno TSRMLS_CC));
 903                 RETURN_FALSE;
 904         }
 905 
 906         if (r_array != NULL) php_sock_array_from_fd_set(r_array, &rfds TSRMLS_CC);
 907         if (w_array != NULL) php_sock_array_from_fd_set(w_array, &wfds TSRMLS_CC);
 908         if (e_array != NULL) php_sock_array_from_fd_set(e_array, &efds TSRMLS_CC);
 909 
 910         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 PHP_FUNCTION(socket_create_listen)
 917 {
 918         php_socket      *php_sock;
 919         long            port, backlog = 128;
 920 
 921         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &port, &backlog) == FAILURE) {
 922                 return;
 923         }
 924 
 925         if (!php_open_listen_sock(&php_sock, port, backlog TSRMLS_CC)) {
 926                 RETURN_FALSE;
 927         }
 928 
 929         php_sock->error = 0;
 930         php_sock->blocking = 1;
 931 
 932         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 PHP_FUNCTION(socket_accept)
 939 {
 940         zval                             *arg1;
 941         php_socket                       *php_sock, *new_sock;
 942         php_sockaddr_storage sa;
 943         socklen_t                        php_sa_len = sizeof(sa);
 944 
 945         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
 946                 return;
 947         }
 948 
 949         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
 950 
 951         if (!php_accept_connect(php_sock, &new_sock, (struct sockaddr*)&sa, &php_sa_len TSRMLS_CC)) {
 952                 RETURN_FALSE;
 953         }
 954 
 955         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 PHP_FUNCTION(socket_set_nonblock)
 962 {
 963         zval            *arg1;
 964         php_socket      *php_sock;
 965 
 966         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
 967                 return;
 968         }
 969 
 970         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
 971 
 972         if (php_sock->zstream != NULL) {
 973                 php_stream *stream;
 974                 /* omit notice if resource doesn't exist anymore */
 975                 stream = zend_fetch_resource(&php_sock->zstream TSRMLS_CC, -1,
 976                         NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
 977                 if (stream != NULL) {
 978                         if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 0,
 979                                         NULL) != -1) {
 980                                 php_sock->blocking = 0;
 981                                 RETURN_TRUE;
 982                         }
 983                 }
 984         }
 985 
 986         if (php_set_sock_blocking(php_sock->bsd_socket, 0 TSRMLS_CC) == SUCCESS) {
 987                 php_sock->blocking = 0;
 988                 RETURN_TRUE;
 989         } else {
 990                 PHP_SOCKET_ERROR(php_sock, "unable to set nonblocking mode", errno);
 991                 RETURN_FALSE;
 992         }
 993 }
 994 /* }}} */
 995 
 996 /* {{{ proto bool socket_set_block(resource socket) U
 997    Sets blocking mode on a socket resource */
 998 PHP_FUNCTION(socket_set_block)
 999 {
1000         zval            *arg1;
1001         php_socket      *php_sock;
1002 
1003         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
1004                 return;
1005         }
1006 
1007         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         if (php_sock->zstream != NULL) {
1013                 php_stream *stream;
1014                 stream = zend_fetch_resource(&php_sock->zstream TSRMLS_CC, -1,
1015                         NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
1016                 if (stream != NULL) {
1017                         if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 1,
1018                                         NULL) != -1) {
1019                                 php_sock->blocking = 1;
1020                                 RETURN_TRUE;
1021                         }
1022                 }
1023         }
1024 
1025         if (php_set_sock_blocking(php_sock->bsd_socket, 1 TSRMLS_CC) == SUCCESS) {
1026                 php_sock->blocking = 1;
1027                 RETURN_TRUE;
1028         } else {
1029                 PHP_SOCKET_ERROR(php_sock, "unable to set blocking mode", errno);
1030                 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 PHP_FUNCTION(socket_listen)
1038 {
1039         zval            *arg1;
1040         php_socket      *php_sock;
1041         long            backlog = 0;
1042 
1043         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &backlog) == FAILURE) {
1044                 return;
1045         }
1046 
1047         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1048 
1049         if (listen(php_sock->bsd_socket, backlog) != 0) {
1050                 PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno);
1051                 RETURN_FALSE;
1052         }
1053         RETURN_TRUE;
1054 }
1055 /* }}} */
1056 
1057 /* {{{ proto void socket_close(resource socket) U
1058    Closes a file descriptor */
1059 PHP_FUNCTION(socket_close)
1060 {
1061         zval            *arg1;
1062         php_socket      *php_sock;
1063 
1064         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
1065                 return;
1066         }
1067 
1068         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1069         if (php_sock->zstream != NULL) {
1070                 php_stream *stream = NULL;
1071                 php_stream_from_zval_no_verify(stream, &php_sock->zstream);
1072                 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                         php_stream_free(stream, PHP_STREAM_FREE_CLOSE |
1076                                         (stream->is_persistent?PHP_STREAM_FREE_CLOSE_PERSISTENT:0));
1077                 }
1078         }
1079         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 PHP_FUNCTION(socket_write)
1086 {
1087         zval            *arg1;
1088         php_socket      *php_sock;
1089         int                     retval, str_len;
1090         long            length = 0;
1091         char            *str;
1092 
1093         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &str, &str_len, &length) == FAILURE) {
1094                 return;
1095         }
1096 
1097         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1098 
1099         if (ZEND_NUM_ARGS() < 3) {
1100                 length = str_len;
1101         }
1102 
1103 #ifndef PHP_WIN32
1104         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         if (retval < 0) {
1110                 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1111                 RETURN_FALSE;
1112         }
1113 
1114         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 PHP_FUNCTION(socket_read)
1121 {
1122         zval            *arg1;
1123         php_socket      *php_sock;
1124         char            *tmpbuf;
1125         int                     retval;
1126         long            length, type = PHP_BINARY_READ;
1127 
1128         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|l", &arg1, &length, &type) == FAILURE) {
1129                 return;
1130         }
1131 
1132         /* overflow check */
1133         if ((length + 1) < 2) {
1134                 RETURN_FALSE;
1135         }
1136 
1137         tmpbuf = emalloc(length + 1);
1138 
1139         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1140 
1141         if (type == PHP_NORMAL_READ) {
1142                 retval = php_read(php_sock, tmpbuf, length, 0);
1143         } else {
1144                 retval = recv(php_sock->bsd_socket, tmpbuf, length, 0);
1145         }
1146 
1147         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                 if (errno == EAGAIN
1151 #ifdef EWOULDBLOCK
1152                 || errno == EWOULDBLOCK
1153 #endif
1154                 ) {
1155                         php_sock->error = errno;
1156                         SOCKETS_G(last_error) = errno;
1157                 } else {
1158                         PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1159                 }
1160 
1161                 efree(tmpbuf);
1162                 RETURN_FALSE;
1163         } else if (!retval) {
1164                 efree(tmpbuf);
1165                 RETURN_EMPTY_STRING();
1166         }
1167 
1168         tmpbuf = erealloc(tmpbuf, retval + 1);
1169         tmpbuf[retval] = '\0' ;
1170 
1171         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 PHP_FUNCTION(socket_getsockname)
1178 {
1179         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         socklen_t                               salen = sizeof(php_sockaddr_storage);
1191 
1192         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &addr, &port) == FAILURE) {
1193                 return;
1194         }
1195 
1196         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1197 
1198         sa = (struct sockaddr *) &sa_storage;
1199 
1200         if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
1201                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
1202                 RETURN_FALSE;
1203         }
1204 
1205         switch (sa->sa_family) {
1206 #if HAVE_IPV6
1207                 case AF_INET6:
1208                         sin6 = (struct sockaddr_in6 *) sa;
1209                         inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1210                         zval_dtor(addr);
1211                         ZVAL_STRING(addr, addr6, 1);
1212 
1213                         if (port != NULL) {
1214                                 zval_dtor(port);
1215                                 ZVAL_LONG(port, htons(sin6->sin6_port));
1216                         }
1217                         RETURN_TRUE;
1218                         break;
1219 #endif
1220                 case AF_INET:
1221                         sin = (struct sockaddr_in *) sa;
1222                         while (inet_ntoa_lock == 1);
1223                         inet_ntoa_lock = 1;
1224                         addr_string = inet_ntoa(sin->sin_addr);
1225                         inet_ntoa_lock = 0;
1226 
1227                         zval_dtor(addr);
1228                         ZVAL_STRING(addr, addr_string, 1);
1229 
1230                         if (port != NULL) {
1231                                 zval_dtor(port);
1232                                 ZVAL_LONG(port, htons(sin->sin_port));
1233                         }
1234                         RETURN_TRUE;
1235                         break;
1236 
1237                 case AF_UNIX:
1238                         s_un = (struct sockaddr_un *) sa;
1239 
1240                         zval_dtor(addr);
1241                         ZVAL_STRING(addr, s_un->sun_path, 1);
1242                         RETURN_TRUE;
1243                         break;
1244 
1245                 default:
1246                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
1247                         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 PHP_FUNCTION(socket_getpeername)
1255 {
1256         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         socklen_t                               salen = sizeof(php_sockaddr_storage);
1268 
1269         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &arg2, &arg3) == FAILURE) {
1270                 return;
1271         }
1272 
1273         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1274 
1275         sa = (struct sockaddr *) &sa_storage;
1276 
1277         if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
1278                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
1279                 RETURN_FALSE;
1280         }
1281 
1282         switch (sa->sa_family) {
1283 #if HAVE_IPV6
1284                 case AF_INET6:
1285                         sin6 = (struct sockaddr_in6 *) sa;
1286                         inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1287                         zval_dtor(arg2);
1288                         ZVAL_STRING(arg2, addr6, 1);
1289 
1290                         if (arg3 != NULL) {
1291                                 zval_dtor(arg3);
1292                                 ZVAL_LONG(arg3, htons(sin6->sin6_port));
1293                         }
1294 
1295                         RETURN_TRUE;
1296                         break;
1297 #endif
1298                 case AF_INET:
1299                         sin = (struct sockaddr_in *) sa;
1300                         while (inet_ntoa_lock == 1);
1301                         inet_ntoa_lock = 1;
1302                         addr_string = inet_ntoa(sin->sin_addr);
1303                         inet_ntoa_lock = 0;
1304 
1305                         zval_dtor(arg2);
1306                         ZVAL_STRING(arg2, addr_string, 1);
1307 
1308                         if (arg3 != NULL) {
1309                                 zval_dtor(arg3);
1310                                 ZVAL_LONG(arg3, htons(sin->sin_port));
1311                         }
1312 
1313                         RETURN_TRUE;
1314                         break;
1315 
1316                 case AF_UNIX:
1317                         s_un = (struct sockaddr_un *) sa;
1318 
1319                         zval_dtor(arg2);
1320                         ZVAL_STRING(arg2, s_un->sun_path, 1);
1321                         RETURN_TRUE;
1322                         break;
1323 
1324                 default:
1325                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
1326                         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 PHP_FUNCTION(socket_create)
1334 {
1335         long            arg1, arg2, arg3;
1336         php_socket      *php_sock = php_create_socket();
1337 
1338         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {
1339                 efree(php_sock);
1340                 return;
1341         }
1342 
1343         if (arg1 != AF_UNIX
1344 #if HAVE_IPV6
1345                 && arg1 != AF_INET6
1346 #endif
1347                 && arg1 != AF_INET) {
1348                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", arg1);
1349                 arg1 = AF_INET;
1350         }
1351 
1352         if (arg2 > 10) {
1353                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", arg2);
1354                 arg2 = SOCK_STREAM;
1355         }
1356 
1357         php_sock->bsd_socket = socket(arg1, arg2, arg3);
1358         php_sock->type = arg1;
1359 
1360         if (IS_INVALID_SOCKET(php_sock)) {
1361                 SOCKETS_G(last_error) = errno;
1362                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno TSRMLS_CC));
1363                 efree(php_sock);
1364                 RETURN_FALSE;
1365         }
1366 
1367         php_sock->error = 0;
1368         php_sock->blocking = 1;
1369 
1370         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 PHP_FUNCTION(socket_connect)
1377 {
1378         zval                            *arg1;
1379         php_socket                      *php_sock;
1380         char                            *addr;
1381         int                                     retval, addr_len;
1382         long                            port = 0;
1383         int                                     argc = ZEND_NUM_ARGS();
1384 
1385         if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1386                 return;
1387         }
1388 
1389         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1390 
1391         switch(php_sock->type) {
1392 #if HAVE_IPV6
1393                 case AF_INET6: {
1394                         struct sockaddr_in6 sin6 = {0};
1395 
1396                         if (argc != 3) {
1397                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
1398                                 RETURN_FALSE;
1399                         }
1400 
1401                         memset(&sin6, 0, sizeof(struct sockaddr_in6));
1402 
1403                         sin6.sin6_family = AF_INET6;
1404                         sin6.sin6_port   = htons((unsigned short int)port);
1405 
1406                         if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
1407                                 RETURN_FALSE;
1408                         }
1409 
1410                         retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
1411                         break;
1412                 }
1413 #endif
1414                 case AF_INET: {
1415                         struct sockaddr_in sin = {0};
1416 
1417                         if (argc != 3) {
1418                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");
1419                                 RETURN_FALSE;
1420                         }
1421 
1422                         sin.sin_family = AF_INET;
1423                         sin.sin_port   = htons((unsigned short int)port);
1424 
1425                         if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
1426                                 RETURN_FALSE;
1427                         }
1428 
1429                         retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
1430                         break;
1431                 }
1432 
1433                 case AF_UNIX: {
1434                         struct sockaddr_un s_un = {0};
1435 
1436                         if (addr_len >= sizeof(s_un.sun_path)) {
1437                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long");
1438                                 RETURN_FALSE;
1439                         }
1440 
1441                         s_un.sun_family = AF_UNIX;
1442                         memcpy(&s_un.sun_path, addr, addr_len);
1443                         retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
1444                                 (socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
1445                         break;
1446                 }
1447 
1448                 default:
1449                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1450                         RETURN_FALSE;
1451                 }
1452 
1453         if (retval != 0) {
1454                 PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
1455                 RETURN_FALSE;
1456         }
1457 
1458         RETURN_TRUE;
1459 }
1460 /* }}} */
1461 
1462 /* {{{ proto string socket_strerror(int errno)
1463    Returns a string describing an error */
1464 PHP_FUNCTION(socket_strerror)
1465 {
1466         long    arg1;
1467 
1468         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg1) == FAILURE) {
1469                 return;
1470         }
1471 
1472         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 PHP_FUNCTION(socket_bind)
1479 {
1480         zval                                    *arg1;
1481         php_sockaddr_storage    sa_storage = {0};
1482         struct sockaddr                 *sock_type = (struct sockaddr*) &sa_storage;
1483         php_socket                              *php_sock;
1484         char                                    *addr;
1485         int                                             addr_len;
1486         long                                    port = 0;
1487         long                                    retval = 0;
1488 
1489         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1490                 return;
1491         }
1492 
1493         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1494 
1495         switch(php_sock->type) {
1496                 case AF_UNIX:
1497                         {
1498                                 struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
1499 
1500                                 sa->sun_family = AF_UNIX;
1501 
1502                                 if (addr_len >= sizeof(sa->sun_path)) {
1503                                         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                                         RETURN_FALSE;
1507                                 }
1508                                 memcpy(&sa->sun_path, addr, addr_len);
1509 
1510                                 retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa,
1511                                                 offsetof(struct sockaddr_un, sun_path) + addr_len);
1512                                 break;
1513                         }
1514 
1515                 case AF_INET:
1516                         {
1517                                 struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
1518 
1519                                 sa->sin_family = AF_INET;
1520                                 sa->sin_port = htons((unsigned short) port);
1521 
1522                                 if (! php_set_inet_addr(sa, addr, php_sock TSRMLS_CC)) {
1523                                         RETURN_FALSE;
1524                                 }
1525 
1526                                 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
1527                                 break;
1528                         }
1529 #if HAVE_IPV6
1530                 case AF_INET6:
1531                         {
1532                                 struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
1533 
1534                                 sa->sin6_family = AF_INET6;
1535                                 sa->sin6_port = htons((unsigned short) port);
1536 
1537                                 if (! php_set_inet6_addr(sa, addr, php_sock TSRMLS_CC)) {
1538                                         RETURN_FALSE;
1539                                 }
1540 
1541                                 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
1542                                 break;
1543                         }
1544 #endif
1545                 default:
1546                         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                         RETURN_FALSE;
1548         }
1549 
1550         if (retval != 0) {
1551                 PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
1552                 RETURN_FALSE;
1553         }
1554 
1555         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 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         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
1570                 return;
1571         }
1572 
1573         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &php_sock_res, -1, le_socket_name, le_socket);
1574 
1575         /* overflow check */
1576         if ((len + 1) < 2) {
1577                 RETURN_FALSE;
1578         }
1579 
1580         recv_buf = emalloc(len + 1);
1581         memset(recv_buf, 0, len + 1);
1582 
1583         if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {
1584                 efree(recv_buf);
1585 
1586                 zval_dtor(buf);
1587                 Z_TYPE_P(buf) = IS_NULL;
1588         } else {
1589                 recv_buf[retval] = '\0';
1590 
1591                 /* Rebuild buffer zval */
1592                 zval_dtor(buf);
1593 
1594                 Z_STRVAL_P(buf) = recv_buf;
1595                 Z_STRLEN_P(buf) = retval;
1596                 Z_TYPE_P(buf) = IS_STRING;
1597         }
1598 
1599         if (retval == -1) {
1600                 PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1601                 RETURN_FALSE;
1602         }
1603 
1604         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 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         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
1619                 return;
1620         }
1621 
1622         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1623 
1624         retval = send(php_sock->bsd_socket, buf, (buf_len < len ? buf_len : len), flags);
1625 
1626         if (retval == -1) {
1627                 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1628                 RETURN_FALSE;
1629         }
1630 
1631         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 PHP_FUNCTION(socket_recvfrom)
1638 {
1639         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         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzllz|z", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
1653                 return;
1654         }
1655 
1656         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1657 
1658         /* overflow check */
1659         if ((arg3 + 2) < 3) {
1660                 RETURN_FALSE;
1661         }
1662 
1663         recv_buf = emalloc(arg3 + 2);
1664         memset(recv_buf, 0, arg3 + 2);
1665 
1666         switch (php_sock->type) {
1667                 case AF_UNIX:
1668                         slen = sizeof(s_un);
1669                         s_un.sun_family = AF_UNIX;
1670                         retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
1671 
1672                         if (retval < 0) {
1673                                 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1674                                 efree(recv_buf);
1675                                 RETURN_FALSE;
1676                         }
1677 
1678                         zval_dtor(arg2);
1679                         zval_dtor(arg5);
1680 
1681                         ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1682                         ZVAL_STRING(arg5, s_un.sun_path, 1);
1683                         break;
1684 
1685                 case AF_INET:
1686                         slen = sizeof(sin);
1687                         memset(&sin, 0, slen);
1688                         sin.sin_family = AF_INET;
1689 
1690                         if (arg6 == NULL) {
1691                                 efree(recv_buf);
1692                                 WRONG_PARAM_COUNT;
1693                         }
1694 
1695                         retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
1696 
1697                         if (retval < 0) {
1698                                 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1699                                 efree(recv_buf);
1700                                 RETURN_FALSE;
1701                         }
1702 
1703                         zval_dtor(arg2);
1704                         zval_dtor(arg5);
1705                         zval_dtor(arg6);
1706 
1707                         address = inet_ntoa(sin.sin_addr);
1708 
1709                         ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1710                         ZVAL_STRING(arg5, address ? address : "0.0.0.0", 1);
1711                         ZVAL_LONG(arg6, ntohs(sin.sin_port));
1712                         break;
1713 #if HAVE_IPV6
1714                 case AF_INET6:
1715                         slen = sizeof(sin6);
1716                         memset(&sin6, 0, slen);
1717                         sin6.sin6_family = AF_INET6;
1718 
1719                         if (arg6 == NULL) {
1720                                 efree(recv_buf);
1721                                 WRONG_PARAM_COUNT;
1722                         }
1723 
1724                         retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
1725 
1726                         if (retval < 0) {
1727                                 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1728                                 efree(recv_buf);
1729                                 RETURN_FALSE;
1730                         }
1731 
1732                         zval_dtor(arg2);
1733                         zval_dtor(arg5);
1734                         zval_dtor(arg6);
1735 
1736                         memset(addr6, 0, INET6_ADDRSTRLEN);
1737                         inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
1738 
1739                         ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1740                         ZVAL_STRING(arg5, addr6[0] ? addr6 : "::", 1);
1741                         ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
1742                         break;
1743 #endif
1744                 default:
1745                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1746                         RETURN_FALSE;
1747         }
1748 
1749         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 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         long                            len, flags, port = 0;
1766         char                            *buf, *addr;
1767         int                                     argc = ZEND_NUM_ARGS();
1768 
1769         if (zend_parse_parameters(argc TSRMLS_CC, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
1770                 return;
1771         }
1772 
1773         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1774 
1775         switch (php_sock->type) {
1776                 case AF_UNIX:
1777                         memset(&s_un, 0, sizeof(s_un));
1778                         s_un.sun_family = AF_UNIX;
1779                         snprintf(s_un.sun_path, 108, "%s", addr);
1780 
1781                         retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len,     flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
1782                         break;
1783 
1784                 case AF_INET:
1785                         if (argc != 6) {
1786                                 WRONG_PARAM_COUNT;
1787                         }
1788 
1789                         memset(&sin, 0, sizeof(sin));
1790                         sin.sin_family = AF_INET;
1791                         sin.sin_port = htons((unsigned short) port);
1792 
1793                         if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
1794                                 RETURN_FALSE;
1795                         }
1796 
1797                         retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin, sizeof(sin));
1798                         break;
1799 #if HAVE_IPV6
1800                 case AF_INET6:
1801                         if (argc != 6) {
1802                                 WRONG_PARAM_COUNT;
1803                         }
1804 
1805                         memset(&sin6, 0, sizeof(sin6));
1806                         sin6.sin6_family = AF_INET6;
1807                         sin6.sin6_port = htons((unsigned short) port);
1808 
1809                         if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
1810                                 RETURN_FALSE;
1811                         }
1812 
1813                         retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
1814                         break;
1815 #endif
1816                 default:
1817                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1818                         RETURN_FALSE;
1819         }
1820 
1821         if (retval == -1) {
1822                 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1823                 RETURN_FALSE;
1824         }
1825 
1826         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 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         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &arg1, &level, &optname) == FAILURE) {
1846                 return;
1847         }
1848 
1849         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1850 
1851         if (level == IPPROTO_IP) {
1852                 switch (optname) {
1853                 case IP_MULTICAST_IF: {
1854                         struct in_addr if_addr;
1855                         unsigned int if_index;
1856                         optlen = sizeof(if_addr);
1857                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&if_addr, &optlen) != 0) {
1858                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1859                                 RETURN_FALSE;
1860                         }
1861                         if (php_add4_to_if_index(&if_addr, php_sock, &if_index TSRMLS_CC) == SUCCESS) {
1862                                 RETURN_LONG((long) if_index);
1863                         } else {
1864                                 RETURN_FALSE;
1865                         }
1866                 }
1867                 }
1868         }
1869 #if HAVE_IPV6
1870         else if (level == IPPROTO_IPV6) {
1871                 int ret = php_do_getsockopt_ipv6_rfc3542(php_sock, level, optname, return_value TSRMLS_CC);
1872                 if (ret == SUCCESS) {
1873                         return;
1874                 } else if (ret == FAILURE) {
1875                         RETURN_FALSE;
1876                 } /* else continue */
1877         }
1878 #endif
1879 
1880         /* sol_socket options and general case */
1881         switch(optname) {
1882                 case SO_LINGER:
1883                         optlen = sizeof(linger_val);
1884 
1885                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
1886                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1887                                 RETURN_FALSE;
1888                         }
1889 
1890                         array_init(return_value);
1891                         add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
1892                         add_assoc_long(return_value, "l_linger", linger_val.l_linger);
1893                         break;
1894 
1895                 case SO_RCVTIMEO:
1896                 case SO_SNDTIMEO:
1897 #ifndef PHP_WIN32
1898                         optlen = sizeof(tv);
1899 
1900                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
1901                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1902                                 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                         array_init(return_value);
1917 
1918                         add_assoc_long(return_value, "sec", tv.tv_sec);
1919                         add_assoc_long(return_value, "usec", tv.tv_usec);
1920                         break;
1921 
1922                 default:
1923                         optlen = sizeof(other_val);
1924 
1925                         if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
1926                                 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1927                                 RETURN_FALSE;
1928                         }
1929                         if (optlen == 1)
1930                                 other_val = *((unsigned char *)&other_val);
1931 
1932                         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 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         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, &level, &optname, &arg4) == FAILURE) {
1959                 return;
1960         }
1961 
1962         ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1963 
1964         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         if (level == IPPROTO_IP) {
1975                 int res = php_do_setsockopt_ip_mcast(php_sock, level, optname, arg4 TSRMLS_CC);
1976                 HANDLE_SUBCALL(res);
1977         }
1978 
1979 #if HAVE_IPV6
1980         else if (level == IPPROTO_IPV6) {
1981                 int res = php_do_setsockopt_ipv6_mcast(php_sock, level, optname, arg4 TSRMLS_CC);
1982                 if (res == 1) {
1983                         res = php_do_setsockopt_ipv6_rfc3542(php_sock, level, optname, arg4 TSRMLS_CC);
1984                 }
1985                 HANDLE_SUBCALL(res);
1986         }
1987 #endif
1988 
1989         switch (optname) {
1990                 case SO_LINGER: {
1991                         const char l_onoff_key[] = "l_onoff";
1992                         const char l_linger_key[] = "l_linger";
1993 
1994                         convert_to_array_ex(arg4);
1995                         opt_ht = HASH_OF(*arg4);
1996 
1997                         if (zend_hash_find(opt_ht, l_onoff_key, sizeof(l_onoff_key), (void **)&l_onoff) == FAILURE) {
1998                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
1999                                 RETURN_FALSE;
2000                         }
2001                         if (zend_hash_find(opt_ht, l_linger_key, sizeof(l_linger_key), (void **)&l_linger) == FAILURE) {
2002                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
2003                                 RETURN_FALSE;
2004                         }
2005 
2006                         convert_to_long_ex(l_onoff);
2007                         convert_to_long_ex(l_linger);
2008 
2009                         lv.l_onoff = (unsigned short)Z_LVAL_PP(l_onoff);
2010                         lv.l_linger = (unsigned short)Z_LVAL_PP(l_linger);
2011 
2012                         optlen = sizeof(lv);
2013                         opt_ptr = &lv;
2014                         break;
2015                 }
2016 
2017                 case SO_RCVTIMEO:
2018                 case SO_SNDTIMEO: {
2019                         const char sec_key[] = "sec";
2020                         const char usec_key[] = "usec";
2021 
2022                         convert_to_array_ex(arg4);
2023                         opt_ht = HASH_OF(*arg4);
2024 
2025                         if (zend_hash_find(opt_ht, sec_key, sizeof(sec_key), (void **)&sec) == FAILURE) {
2026                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", sec_key);
2027                                 RETURN_FALSE;
2028                         }
2029                         if (zend_hash_find(opt_ht, usec_key, sizeof(usec_key), (void **)&usec) == FAILURE) {
2030                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", usec_key);
2031                                 RETURN_FALSE;
2032                         }
2033 
2034                         convert_to_long_ex(sec);
2035                         convert_to_long_ex(usec);
2036 #ifndef PHP_WIN32
2037                         tv.tv_sec = Z_LVAL_PP(sec);
2038                         tv.tv_usec = Z_LVAL_PP(usec);
2039                         optlen = sizeof(tv);
2040                         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                         break;
2047                 }
2048 #ifdef SO_BINDTODEVICE
2049                 case SO_BINDTODEVICE: {
2050                         if (Z_TYPE_PP(arg4) == IS_STRING) {
2051                                 opt_ptr = Z_STRVAL_PP(arg4);
2052                                 optlen = Z_STRLEN_PP(arg4);
2053                         } else {
2054                                 opt_ptr = "";
2055                                 optlen = 0;
2056                         }
2057                         break;
2058                 }
2059 #endif
2060 
2061                 default:
2062 default_case:
2063                         convert_to_long_ex(arg4);
2064                         ov = Z_LVAL_PP(arg4);
2065 
2066                         optlen = sizeof(ov);
2067                         opt_ptr = &ov;
2068                         break;
2069         }
2070 
2071         retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
2072         if (retval != 0) {
2073                 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
2074                 RETURN_FALSE;
2075         }
2076 
2077         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 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         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lllz", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
2092                 return;
2093         }
2094 
2095         php_sock[0] = php_create_socket();
2096         php_sock[1] = php_create_socket();
2097 
2098         if (domain != AF_INET
2099 #if HAVE_IPV6
2100                 && domain != AF_INET6
2101 #endif
2102                 && domain != AF_UNIX) {
2103                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", domain);
2104                 domain = AF_INET;
2105         }
2106 
2107         if (type > 10) {
2108                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", type);
2109                 type = SOCK_STREAM;
2110         }
2111 
2112         if (socketpair(domain, type, protocol, fds_array) != 0) {
2113                 SOCKETS_G(last_error) = errno;
2114                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create socket pair [%d]: %s", errno, sockets_strerror(errno TSRMLS_CC));
2115                 efree(php_sock[0]);
2116                 efree(php_sock[1]);
2117                 RETURN_FALSE;
2118         }
2119 
2120         zval_dtor(fds_array_zval);
2121         array_init(fds_array_zval);
2122 
2123         MAKE_STD_ZVAL(retval[0]);
2124         MAKE_STD_ZVAL(retval[1]);
2125 
2126         php_sock[0]->bsd_socket = fds_array[0];
2127         php_sock[1]->bsd_socket = fds_array[1];
2128         php_sock[0]->type               = domain;
2129         php_sock[1]->type               = domain;
2130         php_sock[0]->error              = 0;
2131         php_sock[1]->error              = 0;
2132         php_sock[0]->blocking   = 1;
2133         php_sock[1]->blocking   = 1;
2134 
2135         ZEND_REGISTER_RESOURCE(retval[0], php_sock[0], le_socket);
2136         ZEND_REGISTER_RESOURCE(retval[1], php_sock[1], le_socket);
2137 
2138         add_index_zval(fds_array_zval, 0, retval[0]);
2139         add_index_zval(fds_array_zval, 1, retval[1]);
2140 
2141         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 PHP_FUNCTION(socket_shutdown)
2150 {
2151         zval            *arg1;
2152         long            how_shutdown = 2;
2153         php_socket      *php_sock;
2154 
2155         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &how_shutdown) == FAILURE) {
2156                 return;
2157         }
2158 
2159         ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2160 
2161         if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
2162                 PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
2163                 RETURN_FALSE;
2164         }
2165 
2166         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 PHP_FUNCTION(socket_last_error)
2174 {
2175         zval            *arg1 = NULL;
2176         php_socket      *php_sock;
2177 
2178         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
2179                 return;
2180         }
2181 
2182         if (arg1) {
2183                 ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2184                 RETVAL_LONG(php_sock->error);
2185         } else {
2186                 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 PHP_FUNCTION(socket_clear_error)
2194 {
2195         zval            *arg1 = NULL;
2196         php_socket      *php_sock;
2197 
2198         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
2199                 return;
2200         }
2201 
2202         if (arg1) {
2203                 ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2204                 php_sock->error = 0;
2205         } else {
2206                 SOCKETS_G(last_error) = 0;
2207         }
2208 
2209         return;
2210 }
2211 /* }}} */
2212 
2213 php_socket *socket_import_file_descriptor(PHP_SOCKET socket TSRMLS_DC)
2214 {
2215 #ifdef SO_DOMAIN
2216         int                                             type;
2217         socklen_t                               type_len = sizeof(type);
2218 #endif
2219         php_socket                              *retsock;
2220         php_sockaddr_storage    addr;
2221         socklen_t                               addr_len = sizeof(addr);
2222 #ifndef PHP_WIN32
2223         int                                      t;
2224 #endif
2225 
2226     retsock = php_create_socket();
2227     retsock->bsd_socket = socket;
2228 
2229     /* determine family */
2230 #ifdef SO_DOMAIN
2231     if (getsockopt(socket, SOL_SOCKET, SO_DOMAIN, &type, &type_len) == 0) {
2232                 retsock->type = type;
2233         } else
2234 #endif
2235         if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
2236                 retsock->type = addr.ss_family;
2237         } else {
2238                 PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
2239                 goto error;
2240         }
2241 
2242     /* determine blocking mode */
2243 #ifndef PHP_WIN32
2244     t = fcntl(socket, F_GETFL);
2245     if (t == -1) {
2246                 PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
2247                 goto error;
2248     } else {
2249         retsock->blocking = !(t & O_NONBLOCK);
2250     }
2251 #endif
2252 
2253     return retsock;
2254 
2255 error:
2256         efree(retsock);
2257         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 PHP_FUNCTION(socket_import_stream)
2263 {
2264         zval                             *zstream;
2265         php_stream                       *stream;
2266         php_socket                       *retsock = NULL;
2267         PHP_SOCKET                       socket; /* fd */
2268 
2269         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) == FAILURE) {
2270                 return;
2271         }
2272         php_stream_from_zval(stream, &zstream);
2273 
2274         if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
2275                 /* error supposedly already shown */
2276                 RETURN_FALSE;
2277         }
2278 
2279         retsock = socket_import_file_descriptor(socket TSRMLS_CC);
2280         if (retsock == NULL) {
2281                 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         MAKE_STD_ZVAL(retsock->zstream);
2299         *retsock->zstream = *zstream;
2300         zval_copy_ctor(retsock->zstream);
2301         Z_UNSET_ISREF_P(retsock->zstream);
2302         Z_SET_REFCOUNT_P(retsock->zstream, 1);
2303 
2304         php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
2305                 PHP_STREAM_BUFFER_NONE, NULL);
2306 
2307         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  */

/* [<][>][^][v][top][bottom][index][help] */