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