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