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

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