1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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 (length < 0) {
1117 php_error_docref(NULL, E_WARNING, "Length cannot be negative");
1118 RETURN_FALSE;
1119 }
1120
1121 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1122 RETURN_FALSE;
1123 }
1124
1125 if (ZEND_NUM_ARGS() < 3) {
1126 length = str_len;
1127 }
1128
1129 #ifndef PHP_WIN32
1130 retval = write(php_sock->bsd_socket, str, MIN(length, str_len));
1131 #else
1132 retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);
1133 #endif
1134
1135 if (retval < 0) {
1136 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1137 RETURN_FALSE;
1138 }
1139
1140 RETURN_LONG(retval);
1141 }
1142 /* }}} */
1143
1144 /* {{{ proto string socket_read(resource socket, int length [, int type])
1145 Reads a maximum of length bytes from socket */
1146 PHP_FUNCTION(socket_read)
1147 {
1148 zval *arg1;
1149 php_socket *php_sock;
1150 zend_string *tmpbuf;
1151 int retval;
1152 zend_long length, type = PHP_BINARY_READ;
1153
1154 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|l", &arg1, &length, &type) == FAILURE) {
1155 return;
1156 }
1157
1158 /* overflow check */
1159 if ((length + 1) < 2) {
1160 RETURN_FALSE;
1161 }
1162
1163 tmpbuf = zend_string_alloc(length, 0);
1164
1165 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1166 RETURN_FALSE;
1167 }
1168
1169 if (type == PHP_NORMAL_READ) {
1170 retval = php_read(php_sock, ZSTR_VAL(tmpbuf), length, 0);
1171 } else {
1172 retval = recv(php_sock->bsd_socket, ZSTR_VAL(tmpbuf), length, 0);
1173 }
1174
1175 if (retval == -1) {
1176 /* if the socket is in non-blocking mode and there's no data to read,
1177 don't output any error, as this is a normal situation, and not an error */
1178 if (errno == EAGAIN
1179 #ifdef EWOULDBLOCK
1180 || errno == EWOULDBLOCK
1181 #endif
1182 ) {
1183 php_sock->error = errno;
1184 SOCKETS_G(last_error) = errno;
1185 } else {
1186 PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1187 }
1188
1189 zend_string_free(tmpbuf);
1190 RETURN_FALSE;
1191 } else if (!retval) {
1192 zend_string_free(tmpbuf);
1193 RETURN_EMPTY_STRING();
1194 }
1195
1196 tmpbuf = zend_string_truncate(tmpbuf, retval, 0);
1197 ZSTR_LEN(tmpbuf) = retval;
1198 ZSTR_VAL(tmpbuf)[ZSTR_LEN(tmpbuf)] = '\0' ;
1199
1200 RETURN_NEW_STR(tmpbuf);
1201 }
1202 /* }}} */
1203
1204 /* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port])
1205 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. */
1206 PHP_FUNCTION(socket_getsockname)
1207 {
1208 zval *arg1, *addr, *port = NULL;
1209 php_sockaddr_storage sa_storage;
1210 php_socket *php_sock;
1211 struct sockaddr *sa;
1212 struct sockaddr_in *sin;
1213 #if HAVE_IPV6
1214 struct sockaddr_in6 *sin6;
1215 char addr6[INET6_ADDRSTRLEN+1];
1216 #endif
1217 struct sockaddr_un *s_un;
1218 char *addr_string;
1219 socklen_t salen = sizeof(php_sockaddr_storage);
1220
1221 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &addr, &port) == FAILURE) {
1222 return;
1223 }
1224
1225 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1226 RETURN_FALSE;
1227 }
1228
1229 sa = (struct sockaddr *) &sa_storage;
1230
1231 if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
1232 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
1233 RETURN_FALSE;
1234 }
1235
1236 if (port != NULL) {
1237 ZVAL_DEREF(port);
1238 }
1239
1240 switch (sa->sa_family) {
1241 #if HAVE_IPV6
1242 case AF_INET6:
1243 sin6 = (struct sockaddr_in6 *) sa;
1244 inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1245 zval_ptr_dtor(addr);
1246 ZVAL_STRING(addr, addr6);
1247
1248 if (port != NULL) {
1249 zval_ptr_dtor(port);
1250 ZVAL_LONG(port, htons(sin6->sin6_port));
1251 }
1252 RETURN_TRUE;
1253 break;
1254 #endif
1255 case AF_INET:
1256 sin = (struct sockaddr_in *) sa;
1257 while (inet_ntoa_lock == 1);
1258 inet_ntoa_lock = 1;
1259 addr_string = inet_ntoa(sin->sin_addr);
1260 inet_ntoa_lock = 0;
1261
1262 zval_ptr_dtor(addr);
1263 ZVAL_STRING(addr, addr_string);
1264
1265 if (port != NULL) {
1266 zval_ptr_dtor(port);
1267 ZVAL_LONG(port, htons(sin->sin_port));
1268 }
1269 RETURN_TRUE;
1270 break;
1271
1272 case AF_UNIX:
1273 s_un = (struct sockaddr_un *) sa;
1274
1275 zval_ptr_dtor(addr);
1276 ZVAL_STRING(addr, s_un->sun_path);
1277 RETURN_TRUE;
1278 break;
1279
1280 default:
1281 php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
1282 RETURN_FALSE;
1283 }
1284 }
1285 /* }}} */
1286
1287 /* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port])
1288 Queries the remote side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type. */
1289 PHP_FUNCTION(socket_getpeername)
1290 {
1291 zval *arg1, *arg2, *arg3 = NULL;
1292 php_sockaddr_storage sa_storage;
1293 php_socket *php_sock;
1294 struct sockaddr *sa;
1295 struct sockaddr_in *sin;
1296 #if HAVE_IPV6
1297 struct sockaddr_in6 *sin6;
1298 char addr6[INET6_ADDRSTRLEN+1];
1299 #endif
1300 struct sockaddr_un *s_un;
1301 char *addr_string;
1302 socklen_t salen = sizeof(php_sockaddr_storage);
1303
1304 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &arg2, &arg3) == FAILURE) {
1305 return;
1306 }
1307
1308 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1309 RETURN_FALSE;
1310 }
1311
1312 sa = (struct sockaddr *) &sa_storage;
1313
1314 if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
1315 PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
1316 RETURN_FALSE;
1317 }
1318
1319 switch (sa->sa_family) {
1320 #if HAVE_IPV6
1321 case AF_INET6:
1322 sin6 = (struct sockaddr_in6 *) sa;
1323 inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1324 zval_ptr_dtor(arg2);
1325 ZVAL_STRING(arg2, addr6);
1326
1327 if (arg3 != NULL) {
1328 zval_ptr_dtor(arg3);
1329 ZVAL_LONG(arg3, htons(sin6->sin6_port));
1330 }
1331
1332 RETURN_TRUE;
1333 break;
1334 #endif
1335 case AF_INET:
1336 sin = (struct sockaddr_in *) sa;
1337 while (inet_ntoa_lock == 1);
1338 inet_ntoa_lock = 1;
1339 addr_string = inet_ntoa(sin->sin_addr);
1340 inet_ntoa_lock = 0;
1341
1342 zval_ptr_dtor(arg2);
1343 ZVAL_STRING(arg2, addr_string);
1344
1345 if (arg3 != NULL) {
1346 zval_ptr_dtor(arg3);
1347 ZVAL_LONG(arg3, htons(sin->sin_port));
1348 }
1349
1350 RETURN_TRUE;
1351 break;
1352
1353 case AF_UNIX:
1354 s_un = (struct sockaddr_un *) sa;
1355
1356 zval_ptr_dtor(arg2);
1357 ZVAL_STRING(arg2, s_un->sun_path);
1358 RETURN_TRUE;
1359 break;
1360
1361 default:
1362 php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
1363 RETURN_FALSE;
1364 }
1365 }
1366 /* }}} */
1367
1368 /* {{{ proto resource socket_create(int domain, int type, int protocol)
1369 Creates an endpoint for communication in the domain specified by domain, of type specified by type */
1370 PHP_FUNCTION(socket_create)
1371 {
1372 zend_long arg1, arg2, arg3;
1373 php_socket *php_sock = php_create_socket();
1374
1375 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &arg1, &arg2, &arg3) == FAILURE) {
1376 efree(php_sock);
1377 return;
1378 }
1379
1380 if (arg1 != AF_UNIX
1381 #if HAVE_IPV6
1382 && arg1 != AF_INET6
1383 #endif
1384 && arg1 != AF_INET) {
1385 php_error_docref(NULL, E_WARNING, "invalid socket domain [" ZEND_LONG_FMT "] specified for argument 1, assuming AF_INET", arg1);
1386 arg1 = AF_INET;
1387 }
1388
1389 if (arg2 > 10) {
1390 php_error_docref(NULL, E_WARNING, "invalid socket type [" ZEND_LONG_FMT "] specified for argument 2, assuming SOCK_STREAM", arg2);
1391 arg2 = SOCK_STREAM;
1392 }
1393
1394 php_sock->bsd_socket = socket(arg1, arg2, arg3);
1395 php_sock->type = arg1;
1396
1397 if (IS_INVALID_SOCKET(php_sock)) {
1398 SOCKETS_G(last_error) = errno;
1399 php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
1400 efree(php_sock);
1401 RETURN_FALSE;
1402 }
1403
1404 php_sock->error = 0;
1405 php_sock->blocking = 1;
1406
1407 RETURN_RES(zend_register_resource(php_sock, le_socket));
1408 }
1409 /* }}} */
1410
1411 /* {{{ proto bool socket_connect(resource socket, string addr [, int port])
1412 Opens a connection to addr:port on the socket specified by socket */
1413 PHP_FUNCTION(socket_connect)
1414 {
1415 zval *arg1;
1416 php_socket *php_sock;
1417 char *addr;
1418 int retval;
1419 size_t addr_len;
1420 zend_long port = 0;
1421 int argc = ZEND_NUM_ARGS();
1422
1423 if (zend_parse_parameters(argc, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1424 return;
1425 }
1426
1427 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1428 RETURN_FALSE;
1429 }
1430
1431 switch(php_sock->type) {
1432 #if HAVE_IPV6
1433 case AF_INET6: {
1434 struct sockaddr_in6 sin6 = {0};
1435
1436 if (argc != 3) {
1437 php_error_docref(NULL, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
1438 RETURN_FALSE;
1439 }
1440
1441 memset(&sin6, 0, sizeof(struct sockaddr_in6));
1442
1443 sin6.sin6_family = AF_INET6;
1444 sin6.sin6_port = htons((unsigned short int)port);
1445
1446 if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
1447 RETURN_FALSE;
1448 }
1449
1450 retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
1451 break;
1452 }
1453 #endif
1454 case AF_INET: {
1455 struct sockaddr_in sin = {0};
1456
1457 if (argc != 3) {
1458 php_error_docref(NULL, E_WARNING, "Socket of type AF_INET requires 3 arguments");
1459 RETURN_FALSE;
1460 }
1461
1462 sin.sin_family = AF_INET;
1463 sin.sin_port = htons((unsigned short int)port);
1464
1465 if (! php_set_inet_addr(&sin, addr, php_sock)) {
1466 RETURN_FALSE;
1467 }
1468
1469 retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
1470 break;
1471 }
1472
1473 case AF_UNIX: {
1474 struct sockaddr_un s_un = {0};
1475
1476 if (addr_len >= sizeof(s_un.sun_path)) {
1477 php_error_docref(NULL, E_WARNING, "Path too long");
1478 RETURN_FALSE;
1479 }
1480
1481 s_un.sun_family = AF_UNIX;
1482 memcpy(&s_un.sun_path, addr, addr_len);
1483 retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
1484 (socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
1485 break;
1486 }
1487
1488 default:
1489 php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1490 RETURN_FALSE;
1491 }
1492
1493 if (retval != 0) {
1494 PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
1495 RETURN_FALSE;
1496 }
1497
1498 RETURN_TRUE;
1499 }
1500 /* }}} */
1501
1502 /* {{{ proto string socket_strerror(int errno)
1503 Returns a string describing an error */
1504 PHP_FUNCTION(socket_strerror)
1505 {
1506 zend_long arg1;
1507
1508 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &arg1) == FAILURE) {
1509 return;
1510 }
1511
1512 RETURN_STRING(sockets_strerror(arg1));
1513 }
1514 /* }}} */
1515
1516 /* {{{ proto bool socket_bind(resource socket, string addr [, int port])
1517 Binds an open socket to a listening port, port is only specified in AF_INET family. */
1518 PHP_FUNCTION(socket_bind)
1519 {
1520 zval *arg1;
1521 php_sockaddr_storage sa_storage = {0};
1522 struct sockaddr *sock_type = (struct sockaddr*) &sa_storage;
1523 php_socket *php_sock;
1524 char *addr;
1525 size_t addr_len;
1526 zend_long port = 0;
1527 zend_long retval = 0;
1528
1529 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1530 return;
1531 }
1532
1533 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1534 RETURN_FALSE;
1535 }
1536
1537 switch(php_sock->type) {
1538 case AF_UNIX:
1539 {
1540 struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
1541
1542 sa->sun_family = AF_UNIX;
1543
1544 if (addr_len >= sizeof(sa->sun_path)) {
1545 php_error_docref(NULL, E_WARNING,
1546 "Invalid path: too long (maximum size is %d)",
1547 (int)sizeof(sa->sun_path) - 1);
1548 RETURN_FALSE;
1549 }
1550 memcpy(&sa->sun_path, addr, addr_len);
1551
1552 retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa,
1553 offsetof(struct sockaddr_un, sun_path) + addr_len);
1554 break;
1555 }
1556
1557 case AF_INET:
1558 {
1559 struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
1560
1561 sa->sin_family = AF_INET;
1562 sa->sin_port = htons((unsigned short) port);
1563
1564 if (! php_set_inet_addr(sa, addr, php_sock)) {
1565 RETURN_FALSE;
1566 }
1567
1568 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
1569 break;
1570 }
1571 #if HAVE_IPV6
1572 case AF_INET6:
1573 {
1574 struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
1575
1576 sa->sin6_family = AF_INET6;
1577 sa->sin6_port = htons((unsigned short) port);
1578
1579 if (! php_set_inet6_addr(sa, addr, php_sock)) {
1580 RETURN_FALSE;
1581 }
1582
1583 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
1584 break;
1585 }
1586 #endif
1587 default:
1588 php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
1589 RETURN_FALSE;
1590 }
1591
1592 if (retval != 0) {
1593 PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
1594 RETURN_FALSE;
1595 }
1596
1597 RETURN_TRUE;
1598 }
1599 /* }}} */
1600
1601 /* {{{ proto int socket_recv(resource socket, string &buf, int len, int flags)
1602 Receives data from a connected socket */
1603 PHP_FUNCTION(socket_recv)
1604 {
1605 zval *php_sock_res, *buf;
1606 zend_string *recv_buf;
1607 php_socket *php_sock;
1608 int retval;
1609 zend_long len, flags;
1610
1611 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/ll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
1612 return;
1613 }
1614
1615 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(php_sock_res), le_socket_name, le_socket)) == NULL) {
1616 RETURN_FALSE;
1617 }
1618
1619 /* overflow check */
1620 if ((len + 1) < 2) {
1621 RETURN_FALSE;
1622 }
1623
1624 recv_buf = zend_string_alloc(len, 0);
1625
1626 if ((retval = recv(php_sock->bsd_socket, ZSTR_VAL(recv_buf), len, flags)) < 1) {
1627 zend_string_free(recv_buf);
1628
1629 zval_ptr_dtor(buf);
1630 ZVAL_NULL(buf);
1631 } else {
1632 ZSTR_LEN(recv_buf) = retval;
1633 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1634
1635 /* Rebuild buffer zval */
1636 zval_ptr_dtor(buf);
1637 ZVAL_NEW_STR(buf, recv_buf);
1638 }
1639
1640 if (retval == -1) {
1641 PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1642 RETURN_FALSE;
1643 }
1644
1645 RETURN_LONG(retval);
1646 }
1647 /* }}} */
1648
1649 /* {{{ proto int socket_send(resource socket, string buf, int len, int flags)
1650 Sends data to a connected socket */
1651 PHP_FUNCTION(socket_send)
1652 {
1653 zval *arg1;
1654 php_socket *php_sock;
1655 size_t buf_len, retval;
1656 zend_long len, flags;
1657 char *buf;
1658
1659 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
1660 return;
1661 }
1662
1663 if (len < 0) {
1664 php_error_docref(NULL, E_WARNING, "Length cannot be negative");
1665 RETURN_FALSE;
1666 }
1667
1668 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1669 RETURN_FALSE;
1670 }
1671
1672 retval = send(php_sock->bsd_socket, buf, (buf_len < (size_t)len ? buf_len : (size_t)len), flags);
1673
1674 if (retval == (size_t)-1) {
1675 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1676 RETURN_FALSE;
1677 }
1678
1679 RETURN_LONG(retval);
1680 }
1681 /* }}} */
1682
1683 /* {{{ proto int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port])
1684 Receives data from a socket, connected or not */
1685 PHP_FUNCTION(socket_recvfrom)
1686 {
1687 zval *arg1, *arg2, *arg5, *arg6 = NULL;
1688 php_socket *php_sock;
1689 struct sockaddr_un s_un;
1690 struct sockaddr_in sin;
1691 #if HAVE_IPV6
1692 struct sockaddr_in6 sin6;
1693 char addr6[INET6_ADDRSTRLEN];
1694 #endif
1695 socklen_t slen;
1696 int retval;
1697 zend_long arg3, arg4;
1698 char *address;
1699 zend_string *recv_buf;
1700
1701 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/llz/|z/", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
1702 return;
1703 }
1704
1705 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1706 RETURN_FALSE;
1707 }
1708
1709 /* overflow check */
1710 if ((arg3 + 2) < 3) {
1711 RETURN_FALSE;
1712 }
1713
1714 recv_buf = zend_string_alloc(arg3 + 1, 0);
1715
1716 switch (php_sock->type) {
1717 case AF_UNIX:
1718 slen = sizeof(s_un);
1719 s_un.sun_family = AF_UNIX;
1720 retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
1721
1722 if (retval < 0) {
1723 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1724 zend_string_free(recv_buf);
1725 RETURN_FALSE;
1726 }
1727 ZSTR_LEN(recv_buf) = retval;
1728 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1729
1730 zval_ptr_dtor(arg2);
1731 zval_ptr_dtor(arg5);
1732
1733 ZVAL_NEW_STR(arg2, recv_buf);
1734 ZVAL_STRING(arg5, s_un.sun_path);
1735 break;
1736
1737 case AF_INET:
1738 slen = sizeof(sin);
1739 memset(&sin, 0, slen);
1740 sin.sin_family = AF_INET;
1741
1742 if (arg6 == NULL) {
1743 zend_string_free(recv_buf);
1744 WRONG_PARAM_COUNT;
1745 }
1746
1747 retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
1748
1749 if (retval < 0) {
1750 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1751 zend_string_free(recv_buf);
1752 RETURN_FALSE;
1753 }
1754 ZSTR_LEN(recv_buf) = retval;
1755 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1756
1757 zval_ptr_dtor(arg2);
1758 zval_ptr_dtor(arg5);
1759 zval_ptr_dtor(arg6);
1760
1761 address = inet_ntoa(sin.sin_addr);
1762
1763 ZVAL_NEW_STR(arg2, recv_buf);
1764 ZVAL_STRING(arg5, address ? address : "0.0.0.0");
1765 ZVAL_LONG(arg6, ntohs(sin.sin_port));
1766 break;
1767 #if HAVE_IPV6
1768 case AF_INET6:
1769 slen = sizeof(sin6);
1770 memset(&sin6, 0, slen);
1771 sin6.sin6_family = AF_INET6;
1772
1773 if (arg6 == NULL) {
1774 zend_string_free(recv_buf);
1775 WRONG_PARAM_COUNT;
1776 }
1777
1778 retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
1779
1780 if (retval < 0) {
1781 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1782 zend_string_free(recv_buf);
1783 RETURN_FALSE;
1784 }
1785 ZSTR_LEN(recv_buf) = retval;
1786 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1787
1788 zval_ptr_dtor(arg2);
1789 zval_ptr_dtor(arg5);
1790 zval_ptr_dtor(arg6);
1791
1792 memset(addr6, 0, INET6_ADDRSTRLEN);
1793 inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
1794
1795 ZVAL_NEW_STR(arg2, recv_buf);
1796 ZVAL_STRING(arg5, addr6[0] ? addr6 : "::");
1797 ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
1798 break;
1799 #endif
1800 default:
1801 php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1802 RETURN_FALSE;
1803 }
1804
1805 RETURN_LONG(retval);
1806 }
1807 /* }}} */
1808
1809 /* {{{ proto int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port])
1810 Sends a message to a socket, whether it is connected or not */
1811 PHP_FUNCTION(socket_sendto)
1812 {
1813 zval *arg1;
1814 php_socket *php_sock;
1815 struct sockaddr_un s_un;
1816 struct sockaddr_in sin;
1817 #if HAVE_IPV6
1818 struct sockaddr_in6 sin6;
1819 #endif
1820 int retval;
1821 size_t buf_len, addr_len;
1822 zend_long len, flags, port = 0;
1823 char *buf, *addr;
1824 int argc = ZEND_NUM_ARGS();
1825
1826 if (zend_parse_parameters(argc, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
1827 return;
1828 }
1829
1830 if (len < 0) {
1831 php_error_docref(NULL, E_WARNING, "Length cannot be negative");
1832 RETURN_FALSE;
1833 }
1834
1835 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1836 RETURN_FALSE;
1837 }
1838
1839 switch (php_sock->type) {
1840 case AF_UNIX:
1841 memset(&s_un, 0, sizeof(s_un));
1842 s_un.sun_family = AF_UNIX;
1843 snprintf(s_un.sun_path, 108, "%s", addr);
1844
1845 retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
1846 break;
1847
1848 case AF_INET:
1849 if (argc != 6) {
1850 WRONG_PARAM_COUNT;
1851 }
1852
1853 memset(&sin, 0, sizeof(sin));
1854 sin.sin_family = AF_INET;
1855 sin.sin_port = htons((unsigned short) port);
1856
1857 if (! php_set_inet_addr(&sin, addr, php_sock)) {
1858 RETURN_FALSE;
1859 }
1860
1861 retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin, sizeof(sin));
1862 break;
1863 #if HAVE_IPV6
1864 case AF_INET6:
1865 if (argc != 6) {
1866 WRONG_PARAM_COUNT;
1867 }
1868
1869 memset(&sin6, 0, sizeof(sin6));
1870 sin6.sin6_family = AF_INET6;
1871 sin6.sin6_port = htons((unsigned short) port);
1872
1873 if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
1874 RETURN_FALSE;
1875 }
1876
1877 retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
1878 break;
1879 #endif
1880 default:
1881 php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1882 RETURN_FALSE;
1883 }
1884
1885 if (retval == -1) {
1886 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1887 RETURN_FALSE;
1888 }
1889
1890 RETURN_LONG(retval);
1891 }
1892 /* }}} */
1893
1894 /* {{{ proto mixed socket_get_option(resource socket, int level, int optname)
1895 Gets socket options for the socket */
1896 PHP_FUNCTION(socket_get_option)
1897 {
1898 zval *arg1;
1899 struct linger linger_val;
1900 struct timeval tv;
1901 #ifdef PHP_WIN32
1902 int timeout = 0;
1903 #endif
1904 socklen_t optlen;
1905 php_socket *php_sock;
1906 int other_val;
1907 zend_long level, optname;
1908
1909 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rll", &arg1, &level, &optname) == FAILURE) {
1910 return;
1911 }
1912
1913 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1914 RETURN_FALSE;
1915 }
1916
1917 if (level == IPPROTO_IP) {
1918 switch (optname) {
1919 case IP_MULTICAST_IF: {
1920 struct in_addr if_addr;
1921 unsigned int if_index;
1922 optlen = sizeof(if_addr);
1923 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&if_addr, &optlen) != 0) {
1924 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1925 RETURN_FALSE;
1926 }
1927 if (php_add4_to_if_index(&if_addr, php_sock, &if_index) == SUCCESS) {
1928 RETURN_LONG((zend_long) if_index);
1929 } else {
1930 RETURN_FALSE;
1931 }
1932 }
1933 }
1934 }
1935 #if HAVE_IPV6
1936 else if (level == IPPROTO_IPV6) {
1937 int ret = php_do_getsockopt_ipv6_rfc3542(php_sock, level, optname, return_value);
1938 if (ret == SUCCESS) {
1939 return;
1940 } else if (ret == FAILURE) {
1941 RETURN_FALSE;
1942 } /* else continue */
1943 }
1944 #endif
1945
1946 /* sol_socket options and general case */
1947 switch(optname) {
1948 case SO_LINGER:
1949 optlen = sizeof(linger_val);
1950
1951 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
1952 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1953 RETURN_FALSE;
1954 }
1955
1956 array_init(return_value);
1957 add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
1958 add_assoc_long(return_value, "l_linger", linger_val.l_linger);
1959 break;
1960
1961 case SO_RCVTIMEO:
1962 case SO_SNDTIMEO:
1963 #ifndef PHP_WIN32
1964 optlen = sizeof(tv);
1965
1966 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
1967 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1968 RETURN_FALSE;
1969 }
1970 #else
1971 optlen = sizeof(int);
1972
1973 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
1974 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1975 RETURN_FALSE;
1976 }
1977
1978 tv.tv_sec = timeout ? timeout / 1000 : 0;
1979 tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;
1980 #endif
1981
1982 array_init(return_value);
1983
1984 add_assoc_long(return_value, "sec", tv.tv_sec);
1985 add_assoc_long(return_value, "usec", tv.tv_usec);
1986 break;
1987
1988 default:
1989 optlen = sizeof(other_val);
1990
1991 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
1992 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1993 RETURN_FALSE;
1994 }
1995 if (optlen == 1)
1996 other_val = *((unsigned char *)&other_val);
1997
1998 RETURN_LONG(other_val);
1999 break;
2000 }
2001 }
2002 /* }}} */
2003
2004 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
2005 Sets socket options for the socket */
2006 PHP_FUNCTION(socket_set_option)
2007 {
2008 zval *arg1, *arg4;
2009 struct linger lv;
2010 php_socket *php_sock;
2011 int ov, optlen, retval;
2012 #ifdef PHP_WIN32
2013 int timeout;
2014 #else
2015 struct timeval tv;
2016 #endif
2017 zend_long level, optname;
2018 void *opt_ptr;
2019 HashTable *opt_ht;
2020 zval *l_onoff, *l_linger;
2021 zval *sec, *usec;
2022
2023
2024 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rllz", &arg1, &level, &optname, &arg4) == FAILURE) {
2025 return;
2026 }
2027
2028 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2029 RETURN_FALSE;
2030 }
2031
2032 set_errno(0);
2033
2034 #define HANDLE_SUBCALL(res) \
2035 do { \
2036 if (res == 1) { goto default_case; } \
2037 else if (res == SUCCESS) { RETURN_TRUE; } \
2038 else { RETURN_FALSE; } \
2039 } while (0)
2040
2041
2042 if (level == IPPROTO_IP) {
2043 int res = php_do_setsockopt_ip_mcast(php_sock, level, optname, arg4);
2044 HANDLE_SUBCALL(res);
2045 }
2046
2047 #if HAVE_IPV6
2048 else if (level == IPPROTO_IPV6) {
2049 int res = php_do_setsockopt_ipv6_mcast(php_sock, level, optname, arg4);
2050 if (res == 1) {
2051 res = php_do_setsockopt_ipv6_rfc3542(php_sock, level, optname, arg4);
2052 }
2053 HANDLE_SUBCALL(res);
2054 }
2055 #endif
2056
2057 switch (optname) {
2058 case SO_LINGER: {
2059 const char l_onoff_key[] = "l_onoff";
2060 const char l_linger_key[] = "l_linger";
2061
2062 convert_to_array_ex(arg4);
2063 opt_ht = Z_ARRVAL_P(arg4);
2064
2065 if ((l_onoff = zend_hash_str_find(opt_ht, l_onoff_key, sizeof(l_onoff_key) - 1)) == NULL) {
2066 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
2067 RETURN_FALSE;
2068 }
2069 if ((l_linger = zend_hash_str_find(opt_ht, l_linger_key, sizeof(l_linger_key) - 1)) == NULL) {
2070 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
2071 RETURN_FALSE;
2072 }
2073
2074 convert_to_long_ex(l_onoff);
2075 convert_to_long_ex(l_linger);
2076
2077 lv.l_onoff = (unsigned short)Z_LVAL_P(l_onoff);
2078 lv.l_linger = (unsigned short)Z_LVAL_P(l_linger);
2079
2080 optlen = sizeof(lv);
2081 opt_ptr = &lv;
2082 break;
2083 }
2084
2085 case SO_RCVTIMEO:
2086 case SO_SNDTIMEO: {
2087 const char sec_key[] = "sec";
2088 const char usec_key[] = "usec";
2089
2090 convert_to_array_ex(arg4);
2091 opt_ht = Z_ARRVAL_P(arg4);
2092
2093 if ((sec = zend_hash_str_find(opt_ht, sec_key, sizeof(sec_key) - 1)) == NULL) {
2094 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", sec_key);
2095 RETURN_FALSE;
2096 }
2097 if ((usec = zend_hash_str_find(opt_ht, usec_key, sizeof(usec_key) - 1)) == NULL) {
2098 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", usec_key);
2099 RETURN_FALSE;
2100 }
2101
2102 convert_to_long_ex(sec);
2103 convert_to_long_ex(usec);
2104 #ifndef PHP_WIN32
2105 tv.tv_sec = Z_LVAL_P(sec);
2106 tv.tv_usec = Z_LVAL_P(usec);
2107 optlen = sizeof(tv);
2108 opt_ptr = &tv;
2109 #else
2110 timeout = Z_LVAL_P(sec) * 1000 + Z_LVAL_P(usec) / 1000;
2111 optlen = sizeof(int);
2112 opt_ptr = &timeout;
2113 #endif
2114 break;
2115 }
2116 #ifdef SO_BINDTODEVICE
2117 case SO_BINDTODEVICE: {
2118 if (Z_TYPE_P(arg4) == IS_STRING) {
2119 opt_ptr = Z_STRVAL_P(arg4);
2120 optlen = Z_STRLEN_P(arg4);
2121 } else {
2122 opt_ptr = "";
2123 optlen = 0;
2124 }
2125 break;
2126 }
2127 #endif
2128
2129 default:
2130 default_case:
2131 convert_to_long_ex(arg4);
2132 ov = Z_LVAL_P(arg4);
2133
2134 optlen = sizeof(ov);
2135 opt_ptr = &ov;
2136 break;
2137 }
2138
2139 retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
2140 if (retval != 0) {
2141 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
2142 RETURN_FALSE;
2143 }
2144
2145 RETURN_TRUE;
2146 }
2147 /* }}} */
2148
2149 #ifdef HAVE_SOCKETPAIR
2150 /* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd)
2151 Creates a pair of indistinguishable sockets and stores them in fds. */
2152 PHP_FUNCTION(socket_create_pair)
2153 {
2154 zval retval[2], *fds_array_zval;
2155 php_socket *php_sock[2];
2156 PHP_SOCKET fds_array[2];
2157 zend_long domain, type, protocol;
2158
2159 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lllz/", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
2160 return;
2161 }
2162
2163 php_sock[0] = php_create_socket();
2164 php_sock[1] = php_create_socket();
2165
2166 if (domain != AF_INET
2167 #if HAVE_IPV6
2168 && domain != AF_INET6
2169 #endif
2170 && domain != AF_UNIX) {
2171 php_error_docref(NULL, E_WARNING, "invalid socket domain [" ZEND_LONG_FMT "] specified for argument 1, assuming AF_INET", domain);
2172 domain = AF_INET;
2173 }
2174
2175 if (type > 10) {
2176 php_error_docref(NULL, E_WARNING, "invalid socket type [" ZEND_LONG_FMT "] specified for argument 2, assuming SOCK_STREAM", type);
2177 type = SOCK_STREAM;
2178 }
2179
2180 if (socketpair(domain, type, protocol, fds_array) != 0) {
2181 SOCKETS_G(last_error) = errno;
2182 php_error_docref(NULL, E_WARNING, "unable to create socket pair [%d]: %s", errno, sockets_strerror(errno));
2183 efree(php_sock[0]);
2184 efree(php_sock[1]);
2185 RETURN_FALSE;
2186 }
2187
2188 zval_ptr_dtor(fds_array_zval);
2189 array_init(fds_array_zval);
2190
2191 php_sock[0]->bsd_socket = fds_array[0];
2192 php_sock[1]->bsd_socket = fds_array[1];
2193 php_sock[0]->type = domain;
2194 php_sock[1]->type = domain;
2195 php_sock[0]->error = 0;
2196 php_sock[1]->error = 0;
2197 php_sock[0]->blocking = 1;
2198 php_sock[1]->blocking = 1;
2199
2200 ZVAL_RES(&retval[0], zend_register_resource(php_sock[0], le_socket));
2201 ZVAL_RES(&retval[1], zend_register_resource(php_sock[1], le_socket));
2202
2203 add_index_zval(fds_array_zval, 0, &retval[0]);
2204 add_index_zval(fds_array_zval, 1, &retval[1]);
2205
2206 RETURN_TRUE;
2207 }
2208 /* }}} */
2209 #endif
2210
2211 #ifdef HAVE_SHUTDOWN
2212 /* {{{ proto bool socket_shutdown(resource socket[, int how])
2213 Shuts down a socket for receiving, sending, or both. */
2214 PHP_FUNCTION(socket_shutdown)
2215 {
2216 zval *arg1;
2217 zend_long how_shutdown = 2;
2218 php_socket *php_sock;
2219
2220 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &arg1, &how_shutdown) == FAILURE) {
2221 return;
2222 }
2223
2224 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2225 RETURN_FALSE;
2226 }
2227
2228 if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
2229 PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
2230 RETURN_FALSE;
2231 }
2232
2233 RETURN_TRUE;
2234 }
2235 /* }}} */
2236 #endif
2237
2238 /* {{{ proto int socket_last_error([resource socket])
2239 Returns the last socket error (either the last used or the provided socket resource) */
2240 PHP_FUNCTION(socket_last_error)
2241 {
2242 zval *arg1 = NULL;
2243 php_socket *php_sock;
2244
2245 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
2246 return;
2247 }
2248
2249 if (arg1) {
2250 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2251 RETURN_FALSE;
2252 }
2253 RETVAL_LONG(php_sock->error);
2254 } else {
2255 RETVAL_LONG(SOCKETS_G(last_error));
2256 }
2257 }
2258 /* }}} */
2259
2260 /* {{{ proto void socket_clear_error([resource socket])
2261 Clears the error on the socket or the last error code. */
2262 PHP_FUNCTION(socket_clear_error)
2263 {
2264 zval *arg1 = NULL;
2265 php_socket *php_sock;
2266
2267 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
2268 return;
2269 }
2270
2271 if (arg1) {
2272 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2273 RETURN_FALSE;
2274 }
2275 php_sock->error = 0;
2276 } else {
2277 SOCKETS_G(last_error) = 0;
2278 }
2279
2280 return;
2281 }
2282 /* }}} */
2283
2284 php_socket *socket_import_file_descriptor(PHP_SOCKET socket)
2285 {
2286 #ifdef SO_DOMAIN
2287 int type;
2288 socklen_t type_len = sizeof(type);
2289 #endif
2290 php_socket *retsock;
2291 php_sockaddr_storage addr;
2292 socklen_t addr_len = sizeof(addr);
2293 #ifndef PHP_WIN32
2294 int t;
2295 #endif
2296
2297 retsock = php_create_socket();
2298 retsock->bsd_socket = socket;
2299
2300 /* determine family */
2301 #ifdef SO_DOMAIN
2302 if (getsockopt(socket, SOL_SOCKET, SO_DOMAIN, &type, &type_len) == 0) {
2303 retsock->type = type;
2304 } else
2305 #endif
2306 if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
2307 retsock->type = addr.ss_family;
2308 } else {
2309 PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
2310 goto error;
2311 }
2312
2313 /* determine blocking mode */
2314 #ifndef PHP_WIN32
2315 t = fcntl(socket, F_GETFL);
2316 if (t == -1) {
2317 PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
2318 goto error;
2319 } else {
2320 retsock->blocking = !(t & O_NONBLOCK);
2321 }
2322 #endif
2323
2324 return retsock;
2325
2326 error:
2327 efree(retsock);
2328 return NULL;
2329 }
2330
2331 /* {{{ proto resource socket_import_stream(resource stream)
2332 Imports a stream that encapsulates a socket into a socket extension resource. */
2333 PHP_FUNCTION(socket_import_stream)
2334 {
2335 zval *zstream;
2336 php_stream *stream;
2337 php_socket *retsock = NULL;
2338 PHP_SOCKET socket; /* fd */
2339
2340 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream) == FAILURE) {
2341 return;
2342 }
2343 php_stream_from_zval(stream, zstream);
2344
2345 if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
2346 /* error supposedly already shown */
2347 RETURN_FALSE;
2348 }
2349
2350 retsock = socket_import_file_descriptor(socket);
2351 if (retsock == NULL) {
2352 RETURN_FALSE;
2353 }
2354
2355 #ifdef PHP_WIN32
2356 /* on windows, check if the stream is a socket stream and read its
2357 * private data; otherwise assume it's in non-blocking mode */
2358 if (php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
2359 retsock->blocking =
2360 ((php_netstream_data_t *)stream->abstract)->is_blocked;
2361 } else {
2362 retsock->blocking = 1;
2363 }
2364 #endif
2365
2366 /* hold a zval reference to the stream (holding a php_stream* directly could
2367 * also be done, but this makes socket_export_stream a bit simpler) */
2368 ZVAL_COPY(&retsock->zstream, zstream);
2369
2370 php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
2371 PHP_STREAM_BUFFER_NONE, NULL);
2372
2373 RETURN_RES(zend_register_resource(retsock, le_socket));
2374 }
2375 /* }}} */
2376
2377 /* {{{ proto resource socket_export_stream(resource socket)
2378 Exports a socket extension resource into a stream that encapsulates a socket. */
2379 PHP_FUNCTION(socket_export_stream)
2380 {
2381 zval *zsocket;
2382 php_socket *socket;
2383 php_stream *stream = NULL;
2384 php_netstream_data_t *stream_data;
2385 char *protocol = NULL;
2386 size_t protocollen = 0;
2387
2388 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsocket) == FAILURE) {
2389 return;
2390 }
2391 if ((socket = (php_socket *) zend_fetch_resource(Z_RES_P(zsocket), le_socket_name, le_socket)) == NULL) {
2392 RETURN_FALSE;
2393 }
2394
2395 /* Either we already exported a stream or the socket came from an import,
2396 * just return the existing stream */
2397 if (!Z_ISUNDEF(socket->zstream)) {
2398 RETURN_ZVAL(&socket->zstream, 1, 0);
2399 }
2400
2401 /* Determine if socket is using a protocol with one of the default registered
2402 * socket stream wrappers */
2403 if (socket->type == PF_INET
2404 #if HAVE_IPV6
2405 || socket->type == PF_INET6
2406 #endif
2407 ) {
2408 int protoid;
2409 socklen_t protoidlen = sizeof(protoid);
2410
2411 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &protoid, &protoidlen);
2412
2413 if (protoid == SOCK_STREAM) {
2414 /* SO_PROTOCOL is not (yet?) supported on OS X, so lets assume it's TCP there */
2415 #ifdef SO_PROTOCOL
2416 protoidlen = sizeof(protoid);
2417 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_PROTOCOL, (char *) &protoid, &protoidlen);
2418 if (protoid == IPPROTO_TCP)
2419 #endif
2420 {
2421 protocol = "tcp";
2422 protocollen = 3;
2423 }
2424 } else if (protoid == SOCK_DGRAM) {
2425 protocol = "udp";
2426 protocollen = 3;
2427 }
2428 #ifdef PF_UNIX
2429 } else if (socket->type == PF_UNIX) {
2430 int type;
2431 socklen_t typelen = sizeof(type);
2432
2433 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen);
2434
2435 if (type == SOCK_STREAM) {
2436 protocol = "unix";
2437 protocollen = 4;
2438 } else if (type == SOCK_DGRAM) {
2439 protocol = "udg";
2440 protocollen = 3;
2441 }
2442 #endif
2443 }
2444
2445 /* Try to get a stream with the registered sockops for the protocol in use
2446 * We don't want streams to actually *do* anything though, so don't give it
2447 * anything apart from the protocol */
2448 if (protocol != NULL) {
2449 stream = php_stream_xport_create(protocol, protocollen, 0, 0, NULL, NULL, NULL, NULL, NULL);
2450 }
2451
2452 /* Fall back to creating a generic socket stream */
2453 if (stream == NULL) {
2454 stream = php_stream_sock_open_from_socket(socket->bsd_socket, 0);
2455
2456 if (stream == NULL) {
2457 php_error_docref(NULL, E_WARNING, "failed to create stream");
2458 RETURN_FALSE;
2459 }
2460 }
2461
2462 stream_data = (php_netstream_data_t *) stream->abstract;
2463 stream_data->socket = socket->bsd_socket;
2464 stream_data->is_blocked = socket->blocking;
2465 stream_data->timeout.tv_sec = FG(default_socket_timeout);
2466 stream_data->timeout.tv_usec = 0;
2467
2468 php_stream_to_zval(stream, &socket->zstream);
2469
2470 RETURN_ZVAL(&socket->zstream, 1, 0);
2471 }
2472 /* }}} */
2473
2474 /*
2475 * Local variables:
2476 * tab-width: 4
2477 * c-basic-offset: 4
2478 * End:
2479 * vim600: fdm=marker
2480 * vim: noet sw=4 ts=4
2481 */
2482