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