Return to sockets.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / sockets |
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: */