Back to index

php5  5.3.10
sockets.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Chris Vandomelen <chrisv@b0rked.dhs.org>                    |
00016    |          Sterling Hughes  <sterling@php.net>                         |
00017    |          Jason Greene     <jason@php.net>                            |
00018    | WinSock: Daniel Beulshausen <daniel@php4win.de>                      |
00019    +----------------------------------------------------------------------+
00020  */
00021 
00022 /* $Id: sockets.c 321634 2012-01-01 13:15:04Z felipe $ */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include "php.h"
00029 
00030 #if HAVE_SOCKETS
00031 
00032 #include "php_network.h"
00033 #include "ext/standard/file.h"
00034 #include "ext/standard/info.h"
00035 #include "php_ini.h"
00036 #ifdef PHP_WIN32
00037 # include "win32/inet.h"
00038 # include <winsock2.h>
00039 # include <windows.h>
00040 # include <Ws2tcpip.h>
00041 # include "php_sockets.h"
00042 # include "win32/sockets.h"
00043 # define IS_INVALID_SOCKET(a)      (a->bsd_socket == INVALID_SOCKET)
00044 # ifdef EPROTONOSUPPORT
00045 #  undef EPROTONOSUPPORT
00046 # endif
00047 # ifdef ECONNRESET
00048 #  undef ECONNRESET
00049 # endif
00050 # define EPROTONOSUPPORT    WSAEPROTONOSUPPORT
00051 # define ECONNRESET         WSAECONNRESET
00052 # ifdef errno
00053 #  undef errno
00054 # endif
00055 # define errno                     WSAGetLastError()
00056 # define h_errno            WSAGetLastError()
00057 # define set_errno(a)              WSASetLastError(a)
00058 # define close(a)           closesocket(a)
00059 #else
00060 # include <sys/types.h>
00061 # include <sys/socket.h>
00062 # include <netdb.h>
00063 # include <netinet/in.h>
00064 # include <netinet/tcp.h>
00065 # include <sys/un.h>
00066 # include <arpa/inet.h>
00067 # include <sys/time.h>
00068 # include <unistd.h>
00069 # include <errno.h>
00070 # include <fcntl.h>
00071 # include <signal.h>
00072 # include <sys/uio.h>
00073 # define IS_INVALID_SOCKET(a)      (a->bsd_socket < 0)
00074 # define set_errno(a) (errno = a)
00075 # include "php_sockets.h"
00076 #endif
00077 
00078 ZEND_DECLARE_MODULE_GLOBALS(sockets)
00079 static PHP_GINIT_FUNCTION(sockets);
00080 
00081 #ifndef MSG_WAITALL
00082 #ifdef LINUX
00083 #define MSG_WAITALL 0x00000100
00084 #else
00085 #define MSG_WAITALL 0x00000000
00086 #endif
00087 #endif
00088 
00089 #ifndef MSG_EOF
00090 #ifdef MSG_FIN
00091 #define MSG_EOF MSG_FIN
00092 #endif
00093 #endif
00094 
00095 #ifndef SUN_LEN
00096 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
00097 #endif
00098 
00099 #ifndef PF_INET
00100 #define PF_INET AF_INET
00101 #endif
00102 
00103 static char *php_strerror(int error TSRMLS_DC);
00104 
00105 #define PHP_NORMAL_READ 0x0001
00106 #define PHP_BINARY_READ 0x0002
00107 
00108 #define PHP_SOCKET_ERROR(socket,msg,errn) socket->error = errn;       \
00109                                           SOCKETS_G(last_error) = errn; \
00110                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s [%d]: %s", msg, errn, php_strerror(errn TSRMLS_CC))
00111 
00112 static int le_socket;
00113 #define le_socket_name php_sockets_le_socket_name
00114 
00115 /* {{{ arginfo */
00116 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_select, 0, 0, 4)
00117        ZEND_ARG_INFO(1, read_fds)
00118        ZEND_ARG_INFO(1, write_fds)
00119        ZEND_ARG_INFO(1, except_fds)
00120        ZEND_ARG_INFO(0, tv_sec)
00121        ZEND_ARG_INFO(0, tv_usec)
00122 ZEND_END_ARG_INFO()
00123 
00124 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_listen, 0, 0, 1)
00125        ZEND_ARG_INFO(0, port)
00126        ZEND_ARG_INFO(0, backlog)
00127 ZEND_END_ARG_INFO()
00128 
00129 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_accept, 0, 0, 1)
00130        ZEND_ARG_INFO(0, socket)
00131 ZEND_END_ARG_INFO()
00132 
00133 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_nonblock, 0, 0, 1)
00134        ZEND_ARG_INFO(0, socket)
00135 ZEND_END_ARG_INFO()
00136 
00137 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_block, 0, 0, 1)
00138        ZEND_ARG_INFO(0, socket)
00139 ZEND_END_ARG_INFO()
00140 
00141 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_listen, 0, 0, 1)
00142        ZEND_ARG_INFO(0, socket)
00143        ZEND_ARG_INFO(0, backlog)
00144 ZEND_END_ARG_INFO()
00145 
00146 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_close, 0, 0, 1)
00147        ZEND_ARG_INFO(0, socket)
00148 ZEND_END_ARG_INFO()
00149 
00150 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_write, 0, 0, 2)
00151        ZEND_ARG_INFO(0, socket)
00152        ZEND_ARG_INFO(0, buf)
00153        ZEND_ARG_INFO(0, length)
00154 ZEND_END_ARG_INFO()
00155 
00156 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_read, 0, 0, 2)
00157        ZEND_ARG_INFO(0, socket)
00158        ZEND_ARG_INFO(0, length)
00159        ZEND_ARG_INFO(0, type)
00160 ZEND_END_ARG_INFO()
00161 
00162 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getsockname, 0, 0, 2)
00163        ZEND_ARG_INFO(0, socket)
00164        ZEND_ARG_INFO(1, addr)
00165        ZEND_ARG_INFO(1, port)
00166 ZEND_END_ARG_INFO()
00167 
00168 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getpeername, 0, 0, 2)
00169        ZEND_ARG_INFO(0, socket)
00170        ZEND_ARG_INFO(1, addr)
00171        ZEND_ARG_INFO(1, port)
00172 ZEND_END_ARG_INFO()
00173 
00174 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create, 0, 0, 3)
00175        ZEND_ARG_INFO(0, domain)
00176        ZEND_ARG_INFO(0, type)
00177        ZEND_ARG_INFO(0, protocol)
00178 ZEND_END_ARG_INFO()
00179 
00180 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_connect, 0, 0, 2)
00181        ZEND_ARG_INFO(0, socket)
00182        ZEND_ARG_INFO(0, addr)
00183        ZEND_ARG_INFO(0, port)
00184 ZEND_END_ARG_INFO()
00185 
00186 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_strerror, 0, 0, 1)
00187        ZEND_ARG_INFO(0, errno)
00188 ZEND_END_ARG_INFO()
00189 
00190 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_bind, 0, 0, 2)
00191        ZEND_ARG_INFO(0, socket)
00192        ZEND_ARG_INFO(0, addr)
00193        ZEND_ARG_INFO(0, port)
00194 ZEND_END_ARG_INFO()
00195 
00196 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recv, 0, 0, 4)
00197        ZEND_ARG_INFO(0, socket)
00198        ZEND_ARG_INFO(1, buf)
00199        ZEND_ARG_INFO(0, len)
00200        ZEND_ARG_INFO(0, flags)
00201 ZEND_END_ARG_INFO()
00202 
00203 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_send, 0, 0, 4)
00204        ZEND_ARG_INFO(0, socket)
00205        ZEND_ARG_INFO(0, buf)
00206        ZEND_ARG_INFO(0, len)
00207        ZEND_ARG_INFO(0, flags)
00208 ZEND_END_ARG_INFO()
00209 
00210 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvfrom, 0, 0, 5)
00211        ZEND_ARG_INFO(0, socket)
00212        ZEND_ARG_INFO(1, buf)
00213        ZEND_ARG_INFO(0, len)
00214        ZEND_ARG_INFO(0, flags)
00215        ZEND_ARG_INFO(1, name)
00216        ZEND_ARG_INFO(1, port)
00217 ZEND_END_ARG_INFO()
00218 
00219 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendto, 0, 0, 5)
00220        ZEND_ARG_INFO(0, socket)
00221        ZEND_ARG_INFO(0, buf)
00222        ZEND_ARG_INFO(0, len)
00223        ZEND_ARG_INFO(0, flags)
00224        ZEND_ARG_INFO(0, addr)
00225        ZEND_ARG_INFO(0, port)
00226 ZEND_END_ARG_INFO()
00227 
00228 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_get_option, 0, 0, 3)
00229        ZEND_ARG_INFO(0, socket)
00230        ZEND_ARG_INFO(0, level)
00231        ZEND_ARG_INFO(0, optname)
00232 ZEND_END_ARG_INFO()
00233 
00234 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_option, 0, 0, 4)
00235        ZEND_ARG_INFO(0, socket)
00236        ZEND_ARG_INFO(0, level)
00237        ZEND_ARG_INFO(0, optname)
00238        ZEND_ARG_INFO(0, optval)
00239 ZEND_END_ARG_INFO()
00240 
00241 #ifdef HAVE_SOCKETPAIR
00242 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_pair, 0, 0, 4)
00243        ZEND_ARG_INFO(0, domain)
00244        ZEND_ARG_INFO(0, type)
00245        ZEND_ARG_INFO(0, protocol)
00246        ZEND_ARG_INFO(1, fd)
00247 ZEND_END_ARG_INFO()
00248 #endif
00249 
00250 #ifdef HAVE_SHUTDOWN
00251 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_shutdown, 0, 0, 1)
00252        ZEND_ARG_INFO(0, socket)
00253        ZEND_ARG_INFO(0, how)
00254 ZEND_END_ARG_INFO()
00255 #endif
00256 
00257 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_last_error, 0, 0, 0)
00258        ZEND_ARG_INFO(0, socket)
00259 ZEND_END_ARG_INFO()
00260 
00261 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
00262        ZEND_ARG_INFO(0, socket)
00263 ZEND_END_ARG_INFO()
00264 /* }}} */
00265 
00266 /* {{{ sockets_functions[]
00267  */
00268 const zend_function_entry sockets_functions[] = {
00269        PHP_FE(socket_select,                     arginfo_socket_select)
00270        PHP_FE(socket_create,                     arginfo_socket_create)
00271        PHP_FE(socket_create_listen,       arginfo_socket_create_listen)
00272 #ifdef HAVE_SOCKETPAIR
00273        PHP_FE(socket_create_pair,         arginfo_socket_create_pair)
00274 #endif
00275        PHP_FE(socket_accept,                     arginfo_socket_accept)
00276        PHP_FE(socket_set_nonblock,        arginfo_socket_set_nonblock)
00277        PHP_FE(socket_set_block,           arginfo_socket_set_block)
00278        PHP_FE(socket_listen,                     arginfo_socket_listen)
00279        PHP_FE(socket_close,               arginfo_socket_close)
00280        PHP_FE(socket_write,               arginfo_socket_write)
00281        PHP_FE(socket_read,                       arginfo_socket_read)
00282        PHP_FE(socket_getsockname,         arginfo_socket_getsockname)
00283        PHP_FE(socket_getpeername,         arginfo_socket_getpeername)
00284        PHP_FE(socket_connect,                    arginfo_socket_connect)
00285        PHP_FE(socket_strerror,                   arginfo_socket_strerror)
00286        PHP_FE(socket_bind,                       arginfo_socket_bind)
00287        PHP_FE(socket_recv,                       arginfo_socket_recv)
00288        PHP_FE(socket_send,                       arginfo_socket_send)
00289        PHP_FE(socket_recvfrom,                   arginfo_socket_recvfrom)
00290        PHP_FE(socket_sendto,                     arginfo_socket_sendto)
00291        PHP_FE(socket_get_option,          arginfo_socket_get_option)
00292        PHP_FE(socket_set_option,          arginfo_socket_set_option)
00293 #ifdef HAVE_SHUTDOWN
00294        PHP_FE(socket_shutdown,                   arginfo_socket_shutdown)
00295 #endif
00296        PHP_FE(socket_last_error,          arginfo_socket_last_error)
00297        PHP_FE(socket_clear_error,         arginfo_socket_clear_error)
00298 
00299        /* for downwards compatability */
00300        PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)
00301        PHP_FALIAS(socket_setopt, socket_set_option, arginfo_socket_set_option)
00302 
00303        PHP_FE_END
00304 };
00305 /* }}} */
00306 
00307 zend_module_entry sockets_module_entry = {
00308        STANDARD_MODULE_HEADER,
00309        "sockets",
00310        sockets_functions,
00311        PHP_MINIT(sockets),
00312        NULL,
00313        NULL,
00314        PHP_RSHUTDOWN(sockets),
00315        PHP_MINFO(sockets),
00316        NO_VERSION_YET,
00317        PHP_MODULE_GLOBALS(sockets),
00318        PHP_GINIT(sockets),
00319        NULL,
00320        NULL,
00321        STANDARD_MODULE_PROPERTIES_EX
00322 };
00323 
00324 
00325 #ifdef COMPILE_DL_SOCKETS
00326 ZEND_GET_MODULE(sockets)
00327 #endif
00328 
00329 /* inet_ntop should be used instead of inet_ntoa */
00330 int inet_ntoa_lock = 0;
00331 
00332 PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{ */
00333 {
00334        return le_socket;
00335 }
00336 /* }}} */
00337 
00338 static void php_destroy_socket(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00339 {
00340        php_socket *php_sock = (php_socket *) rsrc->ptr;
00341 
00342        close(php_sock->bsd_socket);
00343        efree(php_sock);
00344 }
00345 /* }}} */
00346 
00347 static int php_open_listen_sock(php_socket **php_sock, int port, int backlog TSRMLS_DC) /* {{{ */
00348 {
00349        struct sockaddr_in  la;
00350        struct hostent              *hp;
00351        php_socket                  *sock = (php_socket*)emalloc(sizeof(php_socket));
00352 
00353        *php_sock = sock;
00354 
00355 #ifndef PHP_WIN32
00356        if ((hp = gethostbyname("0.0.0.0")) == NULL) {
00357 #else
00358        if ((hp = gethostbyname("localhost")) == NULL) {
00359 #endif
00360               efree(sock);
00361               return 0;
00362        }
00363 
00364        memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length);
00365        la.sin_family = hp->h_addrtype;
00366        la.sin_port = htons((unsigned short) port);
00367 
00368        sock->bsd_socket = socket(PF_INET, SOCK_STREAM, 0);
00369        sock->blocking = 1;
00370 
00371        if (IS_INVALID_SOCKET(sock)) {
00372               PHP_SOCKET_ERROR(sock, "unable to create listening socket", errno);
00373               efree(sock);
00374               return 0;
00375        }
00376 
00377        sock->type = PF_INET;
00378 
00379        if (bind(sock->bsd_socket, (struct sockaddr *)&la, sizeof(la)) != 0) {
00380               PHP_SOCKET_ERROR(sock, "unable to bind to given address", errno);
00381               close(sock->bsd_socket);
00382               efree(sock);
00383               return 0;
00384        }
00385 
00386        if (listen(sock->bsd_socket, backlog) != 0) {
00387               PHP_SOCKET_ERROR(sock, "unable to listen on socket", errno);
00388               close(sock->bsd_socket);
00389               efree(sock);
00390               return 0;
00391        }
00392 
00393        return 1;
00394 }
00395 /* }}} */
00396 
00397 static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la, socklen_t *la_len TSRMLS_DC) /* {{{ */
00398 {
00399        php_socket    *out_sock = (php_socket*)emalloc(sizeof(php_socket));
00400 
00401        *new_sock = out_sock;
00402 
00403        out_sock->bsd_socket = accept(in_sock->bsd_socket, la, la_len);
00404 
00405        if (IS_INVALID_SOCKET(out_sock)) {
00406               PHP_SOCKET_ERROR(out_sock, "unable to accept incoming connection", errno);
00407               efree(out_sock);
00408               return 0;
00409        }
00410 
00411        out_sock->error = 0;
00412        out_sock->blocking = 1;
00413        out_sock->type = la->sa_family;
00414 
00415        return 1;
00416 }
00417 /* }}} */
00418 
00419 /* {{{ php_read -- wrapper around read() so that it only reads to a \r or \n. */
00420 static int php_read(php_socket *sock, void *buf, size_t maxlen, int flags)
00421 {
00422        int m = 0;
00423        size_t n = 0;
00424        int no_read = 0;
00425        int nonblock = 0;
00426        char *t = (char *) buf;
00427 
00428 #ifndef PHP_WIN32
00429        m = fcntl(sock->bsd_socket, F_GETFL);
00430        if (m < 0) {
00431               return m;
00432        }
00433        nonblock = (m & O_NONBLOCK);
00434        m = 0;
00435 #else
00436        nonblock = !sock->blocking;
00437 #endif
00438        set_errno(0);
00439 
00440        *t = '\0';
00441        while (*t != '\n' && *t != '\r' && n < maxlen) {
00442               if (m > 0) {
00443                      t++;
00444                      n++;
00445               } else if (m == 0) {
00446                      no_read++;
00447                      if (nonblock && no_read >= 2) {
00448                             return n;
00449                             /* The first pass, m always is 0, so no_read becomes 1
00450                              * in the first pass. no_read becomes 2 in the second pass,
00451                              * and if this is nonblocking, we should return.. */
00452                      }
00453 
00454                      if (no_read > 200) {
00455                             set_errno(ECONNRESET);
00456                             return -1;
00457                      }
00458               }
00459 
00460               if (n < maxlen) {
00461                      m = recv(sock->bsd_socket, (void *) t, 1, flags);
00462               }
00463 
00464               if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
00465                      return -1;
00466               }
00467 
00468               set_errno(0);
00469        }
00470 
00471        if (n < maxlen) {
00472               n++;
00473               /* The only reasons it makes it to here is
00474                * if '\n' or '\r' are encountered. So, increase
00475                * the return by 1 to make up for the lack of the
00476                * '\n' or '\r' in the count (since read() takes
00477                * place at the end of the loop..) */
00478        }
00479 
00480        return n;
00481 }
00482 /* }}} */
00483 
00484 static char *php_strerror(int error TSRMLS_DC) /* {{{ */
00485 {
00486        const char *buf;
00487 
00488 #ifndef PHP_WIN32
00489        if (error < -10000) {
00490               error = -error - 10000;
00491 
00492 #ifdef HAVE_HSTRERROR
00493               buf = hstrerror(error);
00494 #else
00495               {
00496                      if (SOCKETS_G(strerror_buf)) {
00497                             efree(SOCKETS_G(strerror_buf));
00498                      }
00499 
00500                      spprintf(&(SOCKETS_G(strerror_buf)), 0, "Host lookup error %d", error);
00501                      buf = SOCKETS_G(strerror_buf);
00502               }
00503 #endif
00504        } else {
00505               buf = strerror(error);
00506        }
00507 #else
00508        {
00509               LPTSTR tmp = NULL;
00510               buf = NULL;
00511 
00512               if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |     FORMAT_MESSAGE_IGNORE_INSERTS,
00513                      NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &tmp, 0, NULL)
00514               ) {
00515                      if (SOCKETS_G(strerror_buf)) {
00516                             efree(SOCKETS_G(strerror_buf));
00517                      }
00518 
00519                      SOCKETS_G(strerror_buf) = estrdup(tmp);
00520                      LocalFree(tmp);
00521 
00522                      buf = SOCKETS_G(strerror_buf);
00523               }
00524        }
00525 #endif
00526 
00527        return (buf ? (char *) buf : "");
00528 }
00529 /* }}} */
00530 
00531 #if HAVE_IPV6
00532 /* Sets addr by hostname, or by ip in string form (AF_INET6) */
00533 static int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
00534 {
00535        struct in6_addr tmp;
00536 #if HAVE_GETADDRINFO
00537        struct addrinfo hints;
00538        struct addrinfo *addrinfo = NULL;
00539 #endif
00540 
00541        if (inet_pton(AF_INET6, string, &tmp)) {
00542               memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
00543        } else {
00544 #if HAVE_GETADDRINFO
00545 
00546               memset(&hints, 0, sizeof(struct addrinfo));
00547               hints.ai_family = PF_INET6;
00548               getaddrinfo(string, NULL, &hints, &addrinfo);
00549               if (!addrinfo) {
00550 #ifdef PHP_WIN32
00551                      PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
00552 #else
00553                      PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
00554 #endif
00555                      return 0;
00556               }
00557               if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
00558                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
00559                      freeaddrinfo(addrinfo);
00560                      return 0;
00561               }
00562 
00563               memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
00564               freeaddrinfo(addrinfo);
00565 
00566 #else
00567               /* No IPv6 specific hostname resolution is available on this system? */
00568               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system");
00569               return 0;
00570 #endif
00571 
00572        }
00573 
00574        return 1;
00575 }
00576 /* }}} */
00577 #endif
00578 
00579 /* Sets addr by hostname, or by ip in string form (AF_INET)  */
00580 static int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
00581 {
00582        struct in_addr tmp;
00583        struct hostent *host_entry;
00584 
00585        if (inet_aton(string, &tmp)) {
00586               sin->sin_addr.s_addr = tmp.s_addr;
00587        } else {
00588               if (! (host_entry = gethostbyname(string))) {
00589                      /* Note: < -10000 indicates a host lookup error */
00590 #ifdef PHP_WIN32
00591                      PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
00592 #else
00593                      PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
00594 #endif
00595                      return 0;
00596               }
00597               if (host_entry->h_addrtype != AF_INET) {
00598                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket");
00599                      return 0;
00600               }
00601               memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
00602        }
00603 
00604        return 1;
00605 }
00606 /* }}} */
00607 
00608 /* {{{ PHP_GINIT_FUNCTION */
00609 static PHP_GINIT_FUNCTION(sockets)
00610 {
00611        sockets_globals->last_error = 0;
00612        sockets_globals->strerror_buf = NULL;
00613 }
00614 /* }}} */
00615 
00616 /* {{{ PHP_MINIT_FUNCTION
00617  */
00618 PHP_MINIT_FUNCTION(sockets)
00619 {
00620        struct protoent *pe;
00621 
00622        le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);
00623 
00624        REGISTER_LONG_CONSTANT("AF_UNIX",         AF_UNIX,             CONST_CS | CONST_PERSISTENT);
00625        REGISTER_LONG_CONSTANT("AF_INET",         AF_INET,             CONST_CS | CONST_PERSISTENT);
00626 #if HAVE_IPV6
00627        REGISTER_LONG_CONSTANT("AF_INET6",        AF_INET6,            CONST_CS | CONST_PERSISTENT);
00628 #endif
00629        REGISTER_LONG_CONSTANT("SOCK_STREAM",     SOCK_STREAM,  CONST_CS | CONST_PERSISTENT);
00630        REGISTER_LONG_CONSTANT("SOCK_DGRAM",      SOCK_DGRAM,          CONST_CS | CONST_PERSISTENT);
00631        REGISTER_LONG_CONSTANT("SOCK_RAW",        SOCK_RAW,            CONST_CS | CONST_PERSISTENT);
00632        REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT);
00633        REGISTER_LONG_CONSTANT("SOCK_RDM",        SOCK_RDM,            CONST_CS | CONST_PERSISTENT);
00634        REGISTER_LONG_CONSTANT("MSG_OOB",         MSG_OOB,             CONST_CS | CONST_PERSISTENT);
00635        REGISTER_LONG_CONSTANT("MSG_WAITALL",     MSG_WAITALL,  CONST_CS | CONST_PERSISTENT);
00636 #ifdef MSG_DONTWAIT
00637        REGISTER_LONG_CONSTANT("MSG_DONTWAIT",    MSG_DONTWAIT, CONST_CS | CONST_PERSISTENT);
00638 #endif
00639        REGISTER_LONG_CONSTANT("MSG_PEEK",        MSG_PEEK,            CONST_CS | CONST_PERSISTENT);
00640        REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE,  CONST_CS | CONST_PERSISTENT);
00641 #ifdef MSG_EOR
00642        REGISTER_LONG_CONSTANT("MSG_EOR",         MSG_EOR,             CONST_CS | CONST_PERSISTENT);
00643 #endif
00644 #ifdef MSG_EOF
00645        REGISTER_LONG_CONSTANT("MSG_EOF",         MSG_EOF,             CONST_CS | CONST_PERSISTENT);
00646 #endif
00647        REGISTER_LONG_CONSTANT("SO_DEBUG",        SO_DEBUG,            CONST_CS | CONST_PERSISTENT);
00648        REGISTER_LONG_CONSTANT("SO_REUSEADDR",    SO_REUSEADDR, CONST_CS | CONST_PERSISTENT);
00649        REGISTER_LONG_CONSTANT("SO_KEEPALIVE",    SO_KEEPALIVE, CONST_CS | CONST_PERSISTENT);
00650        REGISTER_LONG_CONSTANT("SO_DONTROUTE",    SO_DONTROUTE, CONST_CS | CONST_PERSISTENT);
00651        REGISTER_LONG_CONSTANT("SO_LINGER",              SO_LINGER,           CONST_CS | CONST_PERSISTENT);
00652        REGISTER_LONG_CONSTANT("SO_BROADCAST",    SO_BROADCAST, CONST_CS | CONST_PERSISTENT);
00653        REGISTER_LONG_CONSTANT("SO_OOBINLINE",    SO_OOBINLINE, CONST_CS | CONST_PERSISTENT);
00654        REGISTER_LONG_CONSTANT("SO_SNDBUF",              SO_SNDBUF,           CONST_CS | CONST_PERSISTENT);
00655        REGISTER_LONG_CONSTANT("SO_RCVBUF",              SO_RCVBUF,           CONST_CS | CONST_PERSISTENT);
00656        REGISTER_LONG_CONSTANT("SO_SNDLOWAT",     SO_SNDLOWAT,  CONST_CS | CONST_PERSISTENT);
00657        REGISTER_LONG_CONSTANT("SO_RCVLOWAT",     SO_RCVLOWAT,  CONST_CS | CONST_PERSISTENT);
00658        REGISTER_LONG_CONSTANT("SO_SNDTIMEO",     SO_SNDTIMEO,  CONST_CS | CONST_PERSISTENT);
00659        REGISTER_LONG_CONSTANT("SO_RCVTIMEO",     SO_RCVTIMEO,  CONST_CS | CONST_PERSISTENT);
00660        REGISTER_LONG_CONSTANT("SO_TYPE",         SO_TYPE,             CONST_CS | CONST_PERSISTENT);
00661        REGISTER_LONG_CONSTANT("SO_ERROR",        SO_ERROR,            CONST_CS | CONST_PERSISTENT);
00662        REGISTER_LONG_CONSTANT("SOL_SOCKET",      SOL_SOCKET,          CONST_CS | CONST_PERSISTENT);
00663        REGISTER_LONG_CONSTANT("SOMAXCONN",              SOMAXCONN,           CONST_CS | CONST_PERSISTENT);
00664 #ifdef TCP_NODELAY
00665        REGISTER_LONG_CONSTANT("TCP_NODELAY",   TCP_NODELAY,    CONST_CS | CONST_PERSISTENT);
00666 #endif
00667        REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
00668        REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
00669 
00670 #ifndef WIN32
00671 # include "unix_socket_constants.h"
00672 #else
00673 # include "win32_socket_constants.h"
00674 #endif
00675 
00676        if ((pe = getprotobyname("tcp"))) {
00677               REGISTER_LONG_CONSTANT("SOL_TCP", pe->p_proto, CONST_CS | CONST_PERSISTENT);
00678        }
00679 
00680        if ((pe = getprotobyname("udp"))) {
00681               REGISTER_LONG_CONSTANT("SOL_UDP", pe->p_proto, CONST_CS | CONST_PERSISTENT);
00682        }
00683 
00684        return SUCCESS;
00685 }
00686 /* }}} */
00687 
00688 /* {{{ PHP_MINFO_FUNCTION
00689  */
00690 PHP_MINFO_FUNCTION(sockets)
00691 {
00692        php_info_print_table_start();
00693        php_info_print_table_row(2, "Sockets Support", "enabled");
00694        php_info_print_table_end();
00695 }
00696 /* }}} */
00697 
00698 /* {{{ PHP_RSHUTDOWN_FUNCTION */
00699 PHP_RSHUTDOWN_FUNCTION(sockets)
00700 {
00701        if (SOCKETS_G(strerror_buf)) {
00702               efree(SOCKETS_G(strerror_buf));
00703               SOCKETS_G(strerror_buf) = NULL;
00704        }
00705 
00706        return SUCCESS;
00707 }
00708 /* }}} */
00709 
00710 static int php_sock_array_to_fd_set(zval *sock_array, fd_set *fds, PHP_SOCKET *max_fd TSRMLS_DC) /* {{{ */
00711 {
00712        zval          **element;
00713        php_socket    *php_sock;
00714        int                  num = 0;
00715 
00716        if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
00717 
00718        for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
00719                zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
00720                zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
00721 
00722               php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
00723               if (!php_sock) continue; /* If element is not a resource, skip it */
00724 
00725               PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
00726               if (php_sock->bsd_socket > *max_fd) {
00727                      *max_fd = php_sock->bsd_socket;
00728               }
00729               num++;
00730        }
00731 
00732        return num ? 1 : 0;
00733 }
00734 /* }}} */
00735 
00736 static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds TSRMLS_DC) /* {{{ */
00737 {
00738        zval          **element;
00739        zval          **dest_element;
00740        php_socket    *php_sock;
00741        HashTable     *new_hash;
00742        char          *key;
00743        int                  num = 0;
00744        ulong       num_key;
00745        uint          key_len;
00746 
00747        if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
00748 
00749        ALLOC_HASHTABLE(new_hash);
00750        zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(sock_array)), NULL, ZVAL_PTR_DTOR, 0);
00751        for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
00752                zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
00753                zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
00754 
00755               php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
00756               if (!php_sock) continue; /* If element is not a resource, skip it */
00757 
00758               if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
00759                      /* Add fd to new array */
00760                      switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(sock_array), &key, &key_len, &num_key, 0, NULL)) {
00761                             case HASH_KEY_IS_STRING:
00762                                    zend_hash_add(new_hash, key, key_len, (void *)element, sizeof(zval *), (void **)&dest_element);
00763                                    break;
00764                             case HASH_KEY_IS_LONG:
00765                                    zend_hash_index_update(new_hash, num_key, (void *)element, sizeof(zval *), (void **)&dest_element);
00766                                    break;
00767                      }
00768                      if (dest_element) zval_add_ref(dest_element);
00769               }
00770               num++;
00771        }
00772 
00773        /* Destroy old array, add new one */
00774        zend_hash_destroy(Z_ARRVAL_P(sock_array));
00775        efree(Z_ARRVAL_P(sock_array));
00776 
00777        zend_hash_internal_pointer_reset(new_hash);
00778        Z_ARRVAL_P(sock_array) = new_hash;
00779 
00780        return num ? 1 : 0;
00781 }
00782 /* }}} */
00783 
00784 /* {{{ proto int socket_select(array &read_fds, array &write_fds, array &except_fds, int tv_sec[, int tv_usec]) U
00785    Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec */
00786 PHP_FUNCTION(socket_select)
00787 {
00788        zval                 *r_array, *w_array, *e_array, *sec;
00789        struct timeval       tv;
00790        struct timeval *tv_p = NULL;
00791        fd_set               rfds, wfds, efds;
00792        PHP_SOCKET           max_fd = 0;
00793        int                         retval, sets = 0;
00794        long                 usec = 0;
00795 
00796        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE) {
00797               return;
00798        }
00799 
00800        FD_ZERO(&rfds);
00801        FD_ZERO(&wfds);
00802        FD_ZERO(&efds);
00803 
00804        if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
00805        if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
00806        if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
00807 
00808        if (!sets) {
00809               php_error_docref(NULL TSRMLS_CC, E_WARNING, "no resource arrays were passed to select");
00810               RETURN_FALSE;
00811        }
00812 
00813        PHP_SAFE_MAX_FD(max_fd, 0); /* someone needs to make this look more like stream_socket_select */
00814 
00815        /* If seconds is not set to null, build the timeval, else we wait indefinitely */
00816        if (sec != NULL) {
00817               zval tmp;
00818 
00819               if (Z_TYPE_P(sec) != IS_LONG) {
00820                      tmp = *sec;
00821                      zval_copy_ctor(&tmp);
00822                      convert_to_long(&tmp);
00823                      sec = &tmp;
00824               }
00825 
00826               /* Solaris + BSD do not like microsecond values which are >= 1 sec */
00827               if (usec > 999999) {
00828                      tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000);
00829                      tv.tv_usec = usec % 1000000;
00830               } else {
00831                      tv.tv_sec = Z_LVAL_P(sec);
00832                      tv.tv_usec = usec;
00833               }
00834 
00835               tv_p = &tv;
00836 
00837               if (sec == &tmp) {
00838                      zval_dtor(&tmp);
00839               }
00840        }
00841 
00842        retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p);
00843 
00844        if (retval == -1) {
00845               SOCKETS_G(last_error) = errno;
00846               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
00847               RETURN_FALSE;
00848        }
00849 
00850        if (r_array != NULL) php_sock_array_from_fd_set(r_array, &rfds TSRMLS_CC);
00851        if (w_array != NULL) php_sock_array_from_fd_set(w_array, &wfds TSRMLS_CC);
00852        if (e_array != NULL) php_sock_array_from_fd_set(e_array, &efds TSRMLS_CC);
00853 
00854        RETURN_LONG(retval);
00855 }
00856 /* }}} */
00857 
00858 /* {{{ proto resource socket_create_listen(int port[, int backlog]) U
00859    Opens a socket on port to accept connections */
00860 PHP_FUNCTION(socket_create_listen)
00861 {
00862        php_socket    *php_sock;
00863        long          port, backlog = 128;
00864 
00865        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &port, &backlog) == FAILURE) {
00866               return;
00867        }
00868 
00869        if (!php_open_listen_sock(&php_sock, port, backlog TSRMLS_CC)) {
00870               RETURN_FALSE;
00871        }
00872 
00873        php_sock->error = 0;
00874        php_sock->blocking = 1;
00875 
00876        ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);
00877 }
00878 /* }}} */
00879 
00880 /* {{{ proto resource socket_accept(resource socket) U
00881    Accepts a connection on the listening socket fd */
00882 PHP_FUNCTION(socket_accept)
00883 {
00884        zval                         *arg1;
00885        php_socket                   *php_sock, *new_sock;
00886        php_sockaddr_storage sa;
00887        socklen_t                    php_sa_len = sizeof(sa);
00888 
00889        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
00890               return;
00891        }
00892 
00893        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
00894 
00895        if (!php_accept_connect(php_sock, &new_sock, (struct sockaddr*)&sa, &php_sa_len TSRMLS_CC)) {
00896               RETURN_FALSE;
00897        }
00898 
00899        ZEND_REGISTER_RESOURCE(return_value, new_sock, le_socket);
00900 }
00901 /* }}} */
00902 
00903 /* {{{ proto bool socket_set_nonblock(resource socket) U
00904    Sets nonblocking mode on a socket resource */
00905 PHP_FUNCTION(socket_set_nonblock)
00906 {
00907        zval          *arg1;
00908        php_socket    *php_sock;
00909 
00910        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
00911               return;
00912        }
00913 
00914        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
00915 
00916        if (php_set_sock_blocking(php_sock->bsd_socket, 0 TSRMLS_CC) == SUCCESS) {
00917               php_sock->blocking = 0;
00918               RETURN_TRUE;
00919        } else {
00920               PHP_SOCKET_ERROR(php_sock, "unable to set nonblocking mode", errno);
00921               RETURN_FALSE;
00922        }
00923 }
00924 /* }}} */
00925 
00926 /* {{{ proto bool socket_set_block(resource socket) U
00927    Sets blocking mode on a socket resource */
00928 PHP_FUNCTION(socket_set_block)
00929 {
00930        zval          *arg1;
00931        php_socket    *php_sock;
00932 
00933        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
00934               return;
00935        }
00936 
00937        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
00938 
00939        if (php_set_sock_blocking(php_sock->bsd_socket, 1 TSRMLS_CC) == SUCCESS) {
00940               php_sock->blocking = 1;
00941               RETURN_TRUE;
00942        } else {
00943               PHP_SOCKET_ERROR(php_sock, "unable to set blocking mode", errno);
00944               RETURN_FALSE;
00945        }
00946 }
00947 /* }}} */
00948 
00949 /* {{{ proto bool socket_listen(resource socket[, int backlog]) U
00950    Sets the maximum number of connections allowed to be waited for on the socket specified by fd */
00951 PHP_FUNCTION(socket_listen)
00952 {
00953        zval          *arg1;
00954        php_socket    *php_sock;
00955        long          backlog = 0;
00956 
00957        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &backlog) == FAILURE) {
00958               return;
00959        }
00960 
00961        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
00962 
00963        if (listen(php_sock->bsd_socket, backlog) != 0) {
00964               PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno);
00965               RETURN_FALSE;
00966        }
00967        RETURN_TRUE;
00968 }
00969 /* }}} */
00970 
00971 /* {{{ proto void socket_close(resource socket) U
00972    Closes a file descriptor */
00973 PHP_FUNCTION(socket_close)
00974 {
00975        zval          *arg1;
00976        php_socket    *php_sock;
00977 
00978        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
00979               return;
00980        }
00981 
00982        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
00983        zend_list_delete(Z_RESVAL_P(arg1));
00984 }
00985 /* }}} */
00986 
00987 /* {{{ proto int socket_write(resource socket, string buf[, int length])
00988    Writes the buffer to the socket resource, length is optional */
00989 PHP_FUNCTION(socket_write)
00990 {
00991        zval          *arg1;
00992        php_socket    *php_sock;
00993        int                  retval, str_len;
00994        long          length = 0;
00995        char          *str;
00996 
00997        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &str, &str_len, &length) == FAILURE) {
00998               return;
00999        }
01000 
01001        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01002 
01003        if (ZEND_NUM_ARGS() < 3) {
01004               length = str_len;
01005        }
01006 
01007 #ifndef PHP_WIN32
01008        retval = write(php_sock->bsd_socket, str, MIN(length, str_len));
01009 #else
01010        retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);
01011 #endif
01012 
01013        if (retval < 0) {
01014               PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
01015               RETURN_FALSE;
01016        }
01017 
01018        RETURN_LONG(retval);
01019 }
01020 /* }}} */
01021 
01022 /* {{{ proto string socket_read(resource socket, int length [, int type]) U
01023    Reads a maximum of length bytes from socket */
01024 PHP_FUNCTION(socket_read)
01025 {
01026        zval          *arg1;
01027        php_socket    *php_sock;
01028        char          *tmpbuf;
01029        int                  retval;
01030        long          length, type = PHP_BINARY_READ;
01031 
01032        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|l", &arg1, &length, &type) == FAILURE) {
01033               return;
01034        }
01035 
01036        /* overflow check */
01037        if ((length + 1) < 2) {
01038               RETURN_FALSE;
01039        }
01040 
01041        tmpbuf = emalloc(length + 1);
01042 
01043        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01044 
01045        if (type == PHP_NORMAL_READ) {
01046               retval = php_read(php_sock, tmpbuf, length, 0);
01047        } else {
01048               retval = recv(php_sock->bsd_socket, tmpbuf, length, 0);
01049        }
01050 
01051        if (retval == -1) {
01052               /* if the socket is in non-blocking mode and there's no data to read,
01053               don't output any error, as this is a normal situation, and not an error */
01054               if (errno == EAGAIN
01055 #ifdef EWOULDBLOCK
01056               || errno == EWOULDBLOCK
01057 #endif
01058               ) {
01059                      php_sock->error = errno;
01060                      SOCKETS_G(last_error) = errno;
01061               } else {
01062                      PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
01063               }
01064 
01065               efree(tmpbuf);
01066               RETURN_FALSE;
01067        } else if (!retval) {
01068               efree(tmpbuf);
01069               RETURN_EMPTY_STRING();
01070        }
01071 
01072        tmpbuf = erealloc(tmpbuf, retval + 1);
01073        tmpbuf[retval] = '\0' ;
01074 
01075        RETURN_STRINGL(tmpbuf, retval, 0);
01076 }
01077 /* }}} */
01078 
01079 /* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port])
01080    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. */
01081 PHP_FUNCTION(socket_getsockname)
01082 {
01083        zval                               *arg1, *addr, *port = NULL;
01084        php_sockaddr_storage sa_storage;
01085        php_socket                         *php_sock;
01086        struct sockaddr                    *sa;
01087        struct sockaddr_in          *sin;
01088 #if HAVE_IPV6
01089        struct sockaddr_in6         *sin6;
01090        char                               addr6[INET6_ADDRSTRLEN+1];
01091 #endif
01092        struct sockaddr_un          *s_un;
01093        char                               *addr_string;
01094        socklen_t                          salen = sizeof(php_sockaddr_storage);
01095 
01096        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &addr, &port) == FAILURE) {
01097               return;
01098        }
01099 
01100        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01101 
01102        sa = (struct sockaddr *) &sa_storage;
01103 
01104        if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
01105               PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
01106               RETURN_FALSE;
01107        }
01108 
01109        switch (sa->sa_family) {
01110 #if HAVE_IPV6
01111               case AF_INET6:
01112                      sin6 = (struct sockaddr_in6 *) sa;
01113                      inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
01114                      zval_dtor(addr);
01115                      ZVAL_STRING(addr, addr6, 1);
01116 
01117                      if (port != NULL) {
01118                             zval_dtor(port);
01119                             ZVAL_LONG(port, htons(sin6->sin6_port));
01120                      }
01121                      RETURN_TRUE;
01122                      break;
01123 #endif
01124               case AF_INET:
01125                      sin = (struct sockaddr_in *) sa;
01126                      while (inet_ntoa_lock == 1);
01127                      inet_ntoa_lock = 1;
01128                      addr_string = inet_ntoa(sin->sin_addr);
01129                      inet_ntoa_lock = 0;
01130 
01131                      zval_dtor(addr);
01132                      ZVAL_STRING(addr, addr_string, 1);
01133 
01134                      if (port != NULL) {
01135                             zval_dtor(port);
01136                             ZVAL_LONG(port, htons(sin->sin_port));
01137                      }
01138                      RETURN_TRUE;
01139                      break;
01140 
01141               case AF_UNIX:
01142                      s_un = (struct sockaddr_un *) sa;
01143 
01144                      zval_dtor(addr);
01145                      ZVAL_STRING(addr, s_un->sun_path, 1);
01146                      RETURN_TRUE;
01147                      break;
01148 
01149               default:
01150                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
01151                      RETURN_FALSE;
01152        }
01153 }
01154 /* }}} */
01155 
01156 /* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port])
01157    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. */
01158 PHP_FUNCTION(socket_getpeername)
01159 {
01160        zval                               *arg1, *arg2, *arg3 = NULL;
01161        php_sockaddr_storage sa_storage;
01162        php_socket                         *php_sock;
01163        struct sockaddr                    *sa;
01164        struct sockaddr_in          *sin;
01165 #if HAVE_IPV6
01166        struct sockaddr_in6         *sin6;
01167        char                               addr6[INET6_ADDRSTRLEN+1];
01168 #endif
01169        struct sockaddr_un          *s_un;
01170        char                               *addr_string;
01171        socklen_t                          salen = sizeof(php_sockaddr_storage);
01172 
01173        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &arg2, &arg3) == FAILURE) {
01174               return;
01175        }
01176 
01177        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01178 
01179        sa = (struct sockaddr *) &sa_storage;
01180 
01181        if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
01182               PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
01183               RETURN_FALSE;
01184        }
01185 
01186        switch (sa->sa_family) {
01187 #if HAVE_IPV6
01188               case AF_INET6:
01189                      sin6 = (struct sockaddr_in6 *) sa;
01190                      inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
01191                      zval_dtor(arg2);
01192                      ZVAL_STRING(arg2, addr6, 1);
01193 
01194                      if (arg3 != NULL) {
01195                             zval_dtor(arg3);
01196                             ZVAL_LONG(arg3, htons(sin6->sin6_port));
01197                      }
01198 
01199                      RETURN_TRUE;
01200                      break;
01201 #endif
01202               case AF_INET:
01203                      sin = (struct sockaddr_in *) sa;
01204                      while (inet_ntoa_lock == 1);
01205                      inet_ntoa_lock = 1;
01206                      addr_string = inet_ntoa(sin->sin_addr);
01207                      inet_ntoa_lock = 0;
01208 
01209                      zval_dtor(arg2);
01210                      ZVAL_STRING(arg2, addr_string, 1);
01211 
01212                      if (arg3 != NULL) {
01213                             zval_dtor(arg3);
01214                             ZVAL_LONG(arg3, htons(sin->sin_port));
01215                      }
01216 
01217                      RETURN_TRUE;
01218                      break;
01219 
01220               case AF_UNIX:
01221                      s_un = (struct sockaddr_un *) sa;
01222 
01223                      zval_dtor(arg2);
01224                      ZVAL_STRING(arg2, s_un->sun_path, 1);
01225                      RETURN_TRUE;
01226                      break;
01227 
01228               default:
01229                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
01230                      RETURN_FALSE;
01231        }
01232 }
01233 /* }}} */
01234 
01235 /* {{{ proto resource socket_create(int domain, int type, int protocol) U
01236    Creates an endpoint for communication in the domain specified by domain, of type specified by type */
01237 PHP_FUNCTION(socket_create)
01238 {
01239        long          arg1, arg2, arg3;
01240        php_socket    *php_sock = (php_socket*)emalloc(sizeof(php_socket));
01241 
01242        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {
01243               efree(php_sock);
01244               return;
01245        }
01246 
01247        if (arg1 != AF_UNIX
01248 #if HAVE_IPV6
01249               && arg1 != AF_INET6
01250 #endif
01251               && arg1 != AF_INET) {
01252               php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", arg1);
01253               arg1 = AF_INET;
01254        }
01255 
01256        if (arg2 > 10) {
01257               php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", arg2);
01258               arg2 = SOCK_STREAM;
01259        }
01260 
01261        php_sock->bsd_socket = socket(arg1, arg2, arg3);
01262        php_sock->type = arg1;
01263 
01264        if (IS_INVALID_SOCKET(php_sock)) {
01265               SOCKETS_G(last_error) = errno;
01266               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
01267               efree(php_sock);
01268               RETURN_FALSE;
01269        }
01270 
01271        php_sock->error = 0;
01272        php_sock->blocking = 1;
01273 
01274        ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);
01275 }
01276 /* }}} */
01277 
01278 /* {{{ proto bool socket_connect(resource socket, string addr [, int port])
01279    Opens a connection to addr:port on the socket specified by socket */
01280 PHP_FUNCTION(socket_connect)
01281 {
01282        zval                        *arg1;
01283        php_socket                  *php_sock;
01284        struct sockaddr_in   sin;
01285 #if HAVE_IPV6
01286        struct sockaddr_in6  sin6;
01287 #endif
01288        struct sockaddr_un   s_un;
01289        char                        *addr;
01290        int                                retval, addr_len;
01291        long                        port = 0;
01292        int                                argc = ZEND_NUM_ARGS();
01293 
01294        if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
01295               return;
01296        }
01297 
01298        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01299 
01300        switch(php_sock->type) {
01301 #if HAVE_IPV6
01302               case AF_INET6:
01303                      if (argc != 3) {
01304                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
01305                             RETURN_FALSE;
01306                      }
01307 
01308                      memset(&sin6, 0, sizeof(struct sockaddr_in6));
01309 
01310                      sin6.sin6_family = AF_INET6;
01311                      sin6.sin6_port   = htons((unsigned short int)port);
01312 
01313                      if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
01314                             RETURN_FALSE;
01315                      }
01316 
01317                      retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
01318                      break;
01319 #endif
01320               case AF_INET:
01321                      if (argc != 3) {
01322                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");
01323                             RETURN_FALSE;
01324                      }
01325 
01326                      memset(&sin, 0, sizeof(struct sockaddr_in));
01327 
01328                      sin.sin_family = AF_INET;
01329                      sin.sin_port   = htons((unsigned short int)port);
01330 
01331                      if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
01332                             RETURN_FALSE;
01333                      }
01334 
01335                      retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
01336                      break;
01337 
01338               case AF_UNIX:
01339                      if (addr_len >= sizeof(s_un.sun_path)) {
01340                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long");
01341                             RETURN_FALSE;
01342                      }
01343                             
01344                      memset(&s_un, 0, sizeof(struct sockaddr_un));
01345 
01346                      s_un.sun_family = AF_UNIX;
01347                      memcpy(&s_un.sun_path, addr, addr_len);
01348                      retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + addr_len);
01349                      break;
01350 
01351               default:
01352                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
01353                      RETURN_FALSE;
01354               }
01355 
01356        if (retval != 0) {
01357               PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
01358               RETURN_FALSE;
01359        }
01360 
01361        RETURN_TRUE;
01362 }
01363 /* }}} */
01364 
01365 /* {{{ proto string socket_strerror(int errno)
01366    Returns a string describing an error */
01367 PHP_FUNCTION(socket_strerror)
01368 {
01369        long   arg1;
01370 
01371        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg1) == FAILURE) {
01372               return;
01373        }
01374 
01375        RETURN_STRING(php_strerror(arg1 TSRMLS_CC), 1);
01376 }
01377 /* }}} */
01378 
01379 /* {{{ proto bool socket_bind(resource socket, string addr [, int port])
01380    Binds an open socket to a listening port, port is only specified in AF_INET family. */
01381 PHP_FUNCTION(socket_bind)
01382 {
01383        zval                               *arg1;
01384        php_sockaddr_storage sa_storage;
01385        struct sockaddr                    *sock_type = (struct sockaddr*) &sa_storage;
01386        php_socket                         *php_sock;
01387        char                               *addr;
01388        int                                       addr_len;
01389        long                               port = 0;
01390        long                               retval = 0;
01391 
01392        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
01393               return;
01394        }
01395 
01396        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01397 
01398        switch(php_sock->type) {
01399               case AF_UNIX:
01400                      {
01401                             struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
01402                             memset(sa, 0, sizeof(sa_storage));
01403                             sa->sun_family = AF_UNIX;
01404                             snprintf(sa->sun_path, 108, "%s", addr);
01405                             retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa, SUN_LEN(sa));
01406                             break;
01407                      }
01408 
01409               case AF_INET:
01410                      {
01411                             struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
01412 
01413                             memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
01414 
01415                             sa->sin_family = AF_INET;
01416                             sa->sin_port = htons((unsigned short) port);
01417 
01418                             if (! php_set_inet_addr(sa, addr, php_sock TSRMLS_CC)) {
01419                                    RETURN_FALSE;
01420                             }
01421 
01422                             retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
01423                             break;
01424                      }
01425 #if HAVE_IPV6
01426               case AF_INET6:
01427                      {
01428                             struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
01429 
01430                             memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
01431 
01432                             sa->sin6_family = AF_INET6;
01433                             sa->sin6_port = htons((unsigned short) port);
01434 
01435                             if (! php_set_inet6_addr(sa, addr, php_sock TSRMLS_CC)) {
01436                                    RETURN_FALSE;
01437                             }
01438 
01439                             retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
01440                             break;
01441                      }
01442 #endif
01443               default:
01444                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
01445                      RETURN_FALSE;
01446        }
01447 
01448        if (retval != 0) {
01449               PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
01450               RETURN_FALSE;
01451        }
01452 
01453        RETURN_TRUE;
01454 }
01455 /* }}} */
01456 
01457 /* {{{ proto int socket_recv(resource socket, string &buf, int len, int flags)
01458    Receives data from a connected socket */
01459 PHP_FUNCTION(socket_recv)
01460 {
01461        zval          *php_sock_res, *buf;
01462        char          *recv_buf;
01463        php_socket    *php_sock;
01464        int                  retval;
01465        long          len, flags;
01466 
01467        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
01468               return;
01469        }
01470 
01471        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &php_sock_res, -1, le_socket_name, le_socket);
01472 
01473        /* overflow check */
01474        if ((len + 1) < 2) {
01475               RETURN_FALSE;
01476        }
01477 
01478        recv_buf = emalloc(len + 1);
01479        memset(recv_buf, 0, len + 1);
01480 
01481        if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {
01482               efree(recv_buf);
01483 
01484               zval_dtor(buf);
01485               Z_TYPE_P(buf) = IS_NULL;
01486        } else {
01487               recv_buf[retval] = '\0';
01488 
01489               /* Rebuild buffer zval */
01490               zval_dtor(buf);
01491 
01492               Z_STRVAL_P(buf) = recv_buf;
01493               Z_STRLEN_P(buf) = retval;
01494               Z_TYPE_P(buf) = IS_STRING;
01495        }
01496 
01497        if (retval == -1) {
01498               PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
01499               RETURN_FALSE;
01500        }
01501 
01502        RETURN_LONG(retval);
01503 }
01504 /* }}} */
01505 
01506 /* {{{ proto int socket_send(resource socket, string buf, int len, int flags)
01507    Sends data to a connected socket */
01508 PHP_FUNCTION(socket_send)
01509 {
01510        zval          *arg1;
01511        php_socket    *php_sock;
01512        int                  buf_len, retval;
01513        long          len, flags;
01514        char          *buf;
01515 
01516        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
01517               return;
01518        }
01519 
01520        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01521 
01522        retval = send(php_sock->bsd_socket, buf, (buf_len < len ? buf_len : len), flags);
01523 
01524        if (retval == -1) {
01525               PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
01526               RETURN_FALSE;
01527        }
01528 
01529        RETURN_LONG(retval);
01530 }
01531 /* }}} */
01532 
01533 /* {{{ proto int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port])
01534    Receives data from a socket, connected or not */
01535 PHP_FUNCTION(socket_recvfrom)
01536 {
01537        zval                        *arg1, *arg2, *arg5, *arg6 = NULL;
01538        php_socket                  *php_sock;
01539        struct sockaddr_un   s_un;
01540        struct sockaddr_in   sin;
01541 #if HAVE_IPV6
01542        struct sockaddr_in6  sin6;
01543        char                        addr6[INET6_ADDRSTRLEN];
01544 #endif
01545        socklen_t                   slen;
01546        int                                retval;
01547        long                        arg3, arg4;
01548        char                        *recv_buf, *address;
01549 
01550        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzllz|z", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
01551               return;
01552        }
01553 
01554        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01555 
01556        /* overflow check */
01557        if ((arg3 + 2) < 3) {
01558               RETURN_FALSE;
01559        }
01560 
01561        recv_buf = emalloc(arg3 + 2);
01562        memset(recv_buf, 0, arg3 + 2);
01563 
01564        switch (php_sock->type) {
01565               case AF_UNIX:
01566                      slen = sizeof(s_un);
01567                      s_un.sun_family = AF_UNIX;
01568                      retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
01569 
01570                      if (retval < 0) {
01571                             efree(recv_buf);
01572                             PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
01573                             RETURN_FALSE;
01574                      }
01575 
01576                      zval_dtor(arg2);
01577                      zval_dtor(arg5);
01578 
01579                      ZVAL_STRINGL(arg2, recv_buf, retval, 0);
01580                      ZVAL_STRING(arg5, s_un.sun_path, 1);
01581                      break;
01582 
01583               case AF_INET:
01584                      slen = sizeof(sin);
01585                      memset(&sin, 0, slen);
01586                      sin.sin_family = AF_INET;
01587 
01588                      if (arg6 == NULL) {
01589                             efree(recv_buf);
01590                             WRONG_PARAM_COUNT;
01591                      }
01592 
01593                      retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
01594 
01595                      if (retval < 0) {
01596                             efree(recv_buf);
01597                             PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
01598                             RETURN_FALSE;
01599                      }
01600 
01601                      zval_dtor(arg2);
01602                      zval_dtor(arg5);
01603                      zval_dtor(arg6);
01604 
01605                      address = inet_ntoa(sin.sin_addr);
01606 
01607                      ZVAL_STRINGL(arg2, recv_buf, retval, 0);
01608                      ZVAL_STRING(arg5, address ? address : "0.0.0.0", 1);
01609                      ZVAL_LONG(arg6, ntohs(sin.sin_port));
01610                      break;
01611 #if HAVE_IPV6
01612               case AF_INET6:
01613                      slen = sizeof(sin6);
01614                      memset(&sin6, 0, slen);
01615                      sin6.sin6_family = AF_INET6;
01616 
01617                      if (arg6 == NULL) {
01618                             efree(recv_buf);
01619                             WRONG_PARAM_COUNT;
01620                      }
01621 
01622                      retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
01623 
01624                      if (retval < 0) {
01625                             efree(recv_buf);
01626                             PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
01627                             RETURN_FALSE;
01628                      }
01629 
01630                      zval_dtor(arg2);
01631                      zval_dtor(arg5);
01632                      zval_dtor(arg6);
01633 
01634                      memset(addr6, 0, INET6_ADDRSTRLEN);
01635                      inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
01636 
01637                      ZVAL_STRINGL(arg2, recv_buf, retval, 0);
01638                      ZVAL_STRING(arg5, addr6[0] ? addr6 : "::", 1);
01639                      ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
01640                      break;
01641 #endif
01642               default:
01643                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
01644                      RETURN_FALSE;
01645        }
01646 
01647        RETURN_LONG(retval);
01648 }
01649 /* }}} */
01650 
01651 /* {{{ proto int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port])
01652    Sends a message to a socket, whether it is connected or not */
01653 PHP_FUNCTION(socket_sendto)
01654 {
01655        zval                        *arg1;
01656        php_socket                  *php_sock;
01657        struct sockaddr_un   s_un;
01658        struct sockaddr_in   sin;
01659 #if HAVE_IPV6
01660        struct sockaddr_in6  sin6;
01661 #endif
01662        int                                retval, buf_len, addr_len;
01663        long                        len, flags, port = 0;
01664        char                        *buf, *addr;
01665        int                                argc = ZEND_NUM_ARGS();
01666 
01667        if (zend_parse_parameters(argc TSRMLS_CC, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
01668               return;
01669        }
01670 
01671        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01672 
01673        switch (php_sock->type) {
01674               case AF_UNIX:
01675                      memset(&s_un, 0, sizeof(s_un));
01676                      s_un.sun_family = AF_UNIX;
01677                      snprintf(s_un.sun_path, 108, "%s", addr);
01678 
01679                      retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len,  flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
01680                      break;
01681 
01682               case AF_INET:
01683                      if (argc != 6) {
01684                             WRONG_PARAM_COUNT;
01685                      }
01686 
01687                      memset(&sin, 0, sizeof(sin));
01688                      sin.sin_family = AF_INET;
01689                      sin.sin_port = htons((unsigned short) port);
01690 
01691                      if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
01692                             RETURN_FALSE;
01693                      }
01694 
01695                      retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin, sizeof(sin));
01696                      break;
01697 #if HAVE_IPV6
01698               case AF_INET6:
01699                      if (argc != 6) {
01700                             WRONG_PARAM_COUNT;
01701                      }
01702 
01703                      memset(&sin6, 0, sizeof(sin6));
01704                      sin6.sin6_family = AF_INET6;
01705                      sin6.sin6_port = htons((unsigned short) port);
01706 
01707                      if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
01708                             RETURN_FALSE;
01709                      }
01710 
01711                      retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
01712                      break;
01713 #endif
01714               default:
01715                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
01716                      RETURN_FALSE;
01717        }
01718 
01719        if (retval == -1) {
01720               PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
01721               RETURN_FALSE;
01722        }
01723 
01724        RETURN_LONG(retval);
01725 }
01726 /* }}} */
01727 
01728 /* {{{ proto mixed socket_get_option(resource socket, int level, int optname) U
01729    Gets socket options for the socket */
01730 PHP_FUNCTION(socket_get_option)
01731 {
01732        zval                 *arg1;
01733        struct linger linger_val;
01734        struct timeval       tv;
01735 #ifdef PHP_WIN32
01736        int                         timeout = 0;
01737 #endif
01738        socklen_t            optlen;
01739        php_socket           *php_sock;
01740        int                         other_val;
01741        long                 level, optname;
01742 
01743        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &arg1, &level, &optname) == FAILURE) {
01744               return;
01745        }
01746 
01747        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01748 
01749        switch(optname) {
01750               case SO_LINGER:
01751                      optlen = sizeof(linger_val);
01752 
01753                      if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
01754                             PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
01755                             RETURN_FALSE;
01756                      }
01757 
01758                      array_init(return_value);
01759                      add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
01760                      add_assoc_long(return_value, "l_linger", linger_val.l_linger);
01761                      break;
01762 
01763               case SO_RCVTIMEO:
01764               case SO_SNDTIMEO:
01765 #ifndef PHP_WIN32
01766                      optlen = sizeof(tv);
01767 
01768                      if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
01769                             PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
01770                             RETURN_FALSE;
01771                      }
01772 #else
01773                      optlen = sizeof(int);
01774 
01775                      if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
01776                             PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
01777                             RETURN_FALSE;
01778                      }
01779 
01780                      tv.tv_sec = timeout ? timeout / 1000 : 0;
01781                      tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;
01782 #endif
01783 
01784                      array_init(return_value);
01785 
01786                      add_assoc_long(return_value, "sec", tv.tv_sec);
01787                      add_assoc_long(return_value, "usec", tv.tv_usec);
01788                      break;
01789 
01790               default:
01791                      optlen = sizeof(other_val);
01792 
01793                      if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
01794                             PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
01795                             RETURN_FALSE;
01796                      }
01797 
01798                      RETURN_LONG(other_val);
01799                      break;
01800        }
01801 }
01802 /* }}} */
01803 
01804 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
01805    Sets socket options for the socket */
01806 PHP_FUNCTION(socket_set_option)
01807 {
01808        zval                 *arg1, **arg4;
01809        struct linger lv;
01810        php_socket           *php_sock;
01811        int                         ov, optlen, retval;
01812 #ifdef PHP_WIN32
01813        int                         timeout;
01814 #else
01815        struct               timeval tv;
01816 #endif
01817        long                 level, optname;
01818        void                 *opt_ptr;
01819        HashTable            *opt_ht;
01820        zval                 **l_onoff, **l_linger;
01821        zval                 **sec, **usec;
01822        /* key name constants */
01823        char                 *l_onoff_key = "l_onoff";
01824        char                 *l_linger_key = "l_linger";
01825        char                 *sec_key = "sec";
01826        char                 *usec_key = "usec";
01827 
01828        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, &level, &optname, &arg4) == FAILURE) {
01829               return;
01830        }
01831 
01832        ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
01833 
01834        set_errno(0);
01835 
01836        switch (optname) {
01837               case SO_LINGER:
01838                      convert_to_array_ex(arg4);
01839                      opt_ht = HASH_OF(*arg4);
01840 
01841                      if (zend_hash_find(opt_ht, l_onoff_key, strlen(l_onoff_key) + 1, (void **)&l_onoff) == FAILURE) {
01842                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
01843                             RETURN_FALSE;
01844                      }
01845                      if (zend_hash_find(opt_ht, l_linger_key, strlen(l_linger_key) + 1, (void **)&l_linger) == FAILURE) {
01846                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
01847                             RETURN_FALSE;
01848                      }
01849 
01850                      convert_to_long_ex(l_onoff);
01851                      convert_to_long_ex(l_linger);
01852 
01853                      lv.l_onoff = (unsigned short)Z_LVAL_PP(l_onoff);
01854                      lv.l_linger = (unsigned short)Z_LVAL_PP(l_linger);
01855 
01856                      optlen = sizeof(lv);
01857                      opt_ptr = &lv;
01858                      break;
01859 
01860               case SO_RCVTIMEO:
01861               case SO_SNDTIMEO:
01862                      convert_to_array_ex(arg4);
01863                      opt_ht = HASH_OF(*arg4);
01864 
01865                      if (zend_hash_find(opt_ht, sec_key, strlen(sec_key) + 1, (void **)&sec) == FAILURE) {
01866                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", sec_key);
01867                             RETURN_FALSE;
01868                      }
01869                      if (zend_hash_find(opt_ht, usec_key, strlen(usec_key) + 1, (void **)&usec) == FAILURE) {
01870                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", usec_key);
01871                             RETURN_FALSE;
01872                      }
01873 
01874                      convert_to_long_ex(sec);
01875                      convert_to_long_ex(usec);
01876 #ifndef PHP_WIN32
01877                      tv.tv_sec = Z_LVAL_PP(sec);
01878                      tv.tv_usec = Z_LVAL_PP(usec);
01879                      optlen = sizeof(tv);
01880                      opt_ptr = &tv;
01881 #else
01882                      timeout = Z_LVAL_PP(sec) * 1000 + Z_LVAL_PP(usec) / 1000;
01883                      optlen = sizeof(int);
01884                      opt_ptr = &timeout;
01885 #endif
01886                      break;
01887 
01888               default:
01889                      convert_to_long_ex(arg4);
01890                      ov = Z_LVAL_PP(arg4);
01891 
01892                      optlen = sizeof(ov);
01893                      opt_ptr = &ov;
01894                      break;
01895        }
01896 
01897        retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
01898 
01899        if (retval != 0) {
01900               PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
01901               RETURN_FALSE;
01902        }
01903 
01904        RETURN_TRUE;
01905 }
01906 /* }}} */
01907 
01908 #ifdef HAVE_SOCKETPAIR
01909 /* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd) U
01910    Creates a pair of indistinguishable sockets and stores them in fds. */
01911 PHP_FUNCTION(socket_create_pair)
01912 {
01913        zval          *retval[2], *fds_array_zval;
01914        php_socket    *php_sock[2];
01915        PHP_SOCKET    fds_array[2];
01916        long          domain, type, protocol;
01917 
01918        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lllz", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
01919               return;
01920        }
01921 
01922        php_sock[0] = (php_socket*)emalloc(sizeof(php_socket));
01923        php_sock[1] = (php_socket*)emalloc(sizeof(php_socket));
01924 
01925        if (domain != AF_INET
01926 #if HAVE_IPV6
01927               && domain != AF_INET6
01928 #endif
01929               && domain != AF_UNIX) {
01930               php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", domain);
01931               domain = AF_INET;
01932        }
01933 
01934        if (type > 10) {
01935               php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", type);
01936               type = SOCK_STREAM;
01937        }
01938 
01939        if (socketpair(domain, type, protocol, fds_array) != 0) {
01940               SOCKETS_G(last_error) = errno;
01941               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create socket pair [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
01942               efree(php_sock[0]);
01943               efree(php_sock[1]);
01944               RETURN_FALSE;
01945        }
01946 
01947        zval_dtor(fds_array_zval);
01948        array_init(fds_array_zval);
01949 
01950        MAKE_STD_ZVAL(retval[0]);
01951        MAKE_STD_ZVAL(retval[1]);
01952 
01953        php_sock[0]->bsd_socket = fds_array[0];
01954        php_sock[1]->bsd_socket = fds_array[1];
01955        php_sock[0]->type           = domain;
01956        php_sock[1]->type           = domain;
01957        php_sock[0]->error          = 0;
01958        php_sock[1]->error          = 0;
01959        php_sock[0]->blocking       = 1;
01960        php_sock[1]->blocking       = 1;
01961 
01962        ZEND_REGISTER_RESOURCE(retval[0], php_sock[0], le_socket);
01963        ZEND_REGISTER_RESOURCE(retval[1], php_sock[1], le_socket);
01964 
01965        add_index_zval(fds_array_zval, 0, retval[0]);
01966        add_index_zval(fds_array_zval, 1, retval[1]);
01967 
01968        RETURN_TRUE;
01969 }
01970 /* }}} */
01971 #endif
01972 
01973 #ifdef HAVE_SHUTDOWN
01974 /* {{{ proto bool socket_shutdown(resource socket[, int how]) U
01975    Shuts down a socket for receiving, sending, or both. */
01976 PHP_FUNCTION(socket_shutdown)
01977 {
01978        zval          *arg1;
01979        long          how_shutdown = 2;
01980        php_socket    *php_sock;
01981 
01982        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &how_shutdown) == FAILURE) {
01983               return;
01984        }
01985 
01986        ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
01987 
01988        if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
01989               PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
01990               RETURN_FALSE;
01991        }
01992 
01993        RETURN_TRUE;
01994 }
01995 /* }}} */
01996 #endif
01997 
01998 /* {{{ proto int socket_last_error([resource socket]) U
01999    Returns the last socket error (either the last used or the provided socket resource) */
02000 PHP_FUNCTION(socket_last_error)
02001 {
02002        zval          *arg1 = NULL;
02003        php_socket    *php_sock;
02004 
02005        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
02006               return;
02007        }
02008 
02009        if (arg1) {
02010               ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
02011               RETVAL_LONG(php_sock->error);
02012        } else {
02013               RETVAL_LONG(SOCKETS_G(last_error));
02014        }
02015 }
02016 /* }}} */
02017 
02018 /* {{{ proto void socket_clear_error([resource socket]) U
02019    Clears the error on the socket or the last error code. */
02020 PHP_FUNCTION(socket_clear_error)
02021 {
02022        zval          *arg1 = NULL;
02023        php_socket    *php_sock;
02024 
02025        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
02026               return;
02027        }
02028 
02029        if (arg1) {
02030               ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
02031               php_sock->error = 0;
02032        } else {
02033               SOCKETS_G(last_error) = 0;
02034        }
02035 
02036        return;
02037 }
02038 /* }}} */
02039 
02040 #endif
02041 
02042 /*
02043  * Local variables:
02044  * tab-width: 4
02045  * c-basic-offset: 4
02046  * End:
02047  * vim600: fdm=marker
02048  * vim: noet sw=4 ts=4
02049  */