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