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