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