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