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