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