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