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