xref: /PHP-7.0/ext/sockets/sockets.c (revision 478f119a)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2017 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 ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1117 		RETURN_FALSE;
1118 	}
1119 
1120 	if (ZEND_NUM_ARGS() < 3) {
1121 		length = str_len;
1122 	}
1123 
1124 #ifndef PHP_WIN32
1125 	retval = write(php_sock->bsd_socket, str, MIN(length, str_len));
1126 #else
1127 	retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);
1128 #endif
1129 
1130 	if (retval < 0) {
1131 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1132 		RETURN_FALSE;
1133 	}
1134 
1135 	RETURN_LONG(retval);
1136 }
1137 /* }}} */
1138 
1139 /* {{{ proto string socket_read(resource socket, int length [, int type])
1140    Reads a maximum of length bytes from socket */
1141 PHP_FUNCTION(socket_read)
1142 {
1143 	zval		*arg1;
1144 	php_socket	*php_sock;
1145 	zend_string	*tmpbuf;
1146 	int			retval;
1147 	zend_long		length, type = PHP_BINARY_READ;
1148 
1149 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|l", &arg1, &length, &type) == FAILURE) {
1150 		return;
1151 	}
1152 
1153 	/* overflow check */
1154 	if ((length + 1) < 2) {
1155 		RETURN_FALSE;
1156 	}
1157 
1158 	tmpbuf = zend_string_alloc(length, 0);
1159 
1160 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1161 		RETURN_FALSE;
1162 	}
1163 
1164 	if (type == PHP_NORMAL_READ) {
1165 		retval = php_read(php_sock, ZSTR_VAL(tmpbuf), length, 0);
1166 	} else {
1167 		retval = recv(php_sock->bsd_socket, ZSTR_VAL(tmpbuf), length, 0);
1168 	}
1169 
1170 	if (retval == -1) {
1171 		/* if the socket is in non-blocking mode and there's no data to read,
1172 		don't output any error, as this is a normal situation, and not an error */
1173 		if (errno == EAGAIN
1174 #ifdef EWOULDBLOCK
1175 		|| errno == EWOULDBLOCK
1176 #endif
1177 		) {
1178 			php_sock->error = errno;
1179 			SOCKETS_G(last_error) = errno;
1180 		} else {
1181 			PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1182 		}
1183 
1184 		zend_string_free(tmpbuf);
1185 		RETURN_FALSE;
1186 	} else if (!retval) {
1187 		zend_string_free(tmpbuf);
1188 		RETURN_EMPTY_STRING();
1189 	}
1190 
1191 	tmpbuf = zend_string_truncate(tmpbuf, retval, 0);
1192 	ZSTR_LEN(tmpbuf) = retval;
1193 	ZSTR_VAL(tmpbuf)[ZSTR_LEN(tmpbuf)] = '\0' ;
1194 
1195 	RETURN_NEW_STR(tmpbuf);
1196 }
1197 /* }}} */
1198 
1199 /* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port])
1200    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. */
1201 PHP_FUNCTION(socket_getsockname)
1202 {
1203 	zval					*arg1, *addr, *port = NULL;
1204 	php_sockaddr_storage	sa_storage;
1205 	php_socket				*php_sock;
1206 	struct sockaddr			*sa;
1207 	struct sockaddr_in		*sin;
1208 #if HAVE_IPV6
1209 	struct sockaddr_in6		*sin6;
1210 	char					addr6[INET6_ADDRSTRLEN+1];
1211 #endif
1212 	struct sockaddr_un		*s_un;
1213 	char					*addr_string;
1214 	socklen_t				salen = sizeof(php_sockaddr_storage);
1215 
1216 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &addr, &port) == FAILURE) {
1217 		return;
1218 	}
1219 
1220 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1221 		RETURN_FALSE;
1222 	}
1223 
1224 	sa = (struct sockaddr *) &sa_storage;
1225 
1226 	if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
1227 		PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
1228 		RETURN_FALSE;
1229 	}
1230 
1231 	if (port != NULL) {
1232 		ZVAL_DEREF(port);
1233 	}
1234 
1235 	switch (sa->sa_family) {
1236 #if HAVE_IPV6
1237 		case AF_INET6:
1238 			sin6 = (struct sockaddr_in6 *) sa;
1239 			inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1240 			zval_dtor(addr);
1241 			ZVAL_STRING(addr, addr6);
1242 
1243 			if (port != NULL) {
1244 				zval_dtor(port);
1245 				ZVAL_LONG(port, htons(sin6->sin6_port));
1246 			}
1247 			RETURN_TRUE;
1248 			break;
1249 #endif
1250 		case AF_INET:
1251 			sin = (struct sockaddr_in *) sa;
1252 			while (inet_ntoa_lock == 1);
1253 			inet_ntoa_lock = 1;
1254 			addr_string = inet_ntoa(sin->sin_addr);
1255 			inet_ntoa_lock = 0;
1256 
1257 			zval_dtor(addr);
1258 			ZVAL_STRING(addr, addr_string);
1259 
1260 			if (port != NULL) {
1261 				zval_dtor(port);
1262 				ZVAL_LONG(port, htons(sin->sin_port));
1263 			}
1264 			RETURN_TRUE;
1265 			break;
1266 
1267 		case AF_UNIX:
1268 			s_un = (struct sockaddr_un *) sa;
1269 
1270 			zval_dtor(addr);
1271 			ZVAL_STRING(addr, s_un->sun_path);
1272 			RETURN_TRUE;
1273 			break;
1274 
1275 		default:
1276 			php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
1277 			RETURN_FALSE;
1278 	}
1279 }
1280 /* }}} */
1281 
1282 /* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port])
1283    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. */
1284 PHP_FUNCTION(socket_getpeername)
1285 {
1286 	zval					*arg1, *arg2, *arg3 = NULL;
1287 	php_sockaddr_storage	sa_storage;
1288 	php_socket				*php_sock;
1289 	struct sockaddr			*sa;
1290 	struct sockaddr_in		*sin;
1291 #if HAVE_IPV6
1292 	struct sockaddr_in6		*sin6;
1293 	char					addr6[INET6_ADDRSTRLEN+1];
1294 #endif
1295 	struct sockaddr_un		*s_un;
1296 	char					*addr_string;
1297 	socklen_t				salen = sizeof(php_sockaddr_storage);
1298 
1299 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &arg2, &arg3) == FAILURE) {
1300 		return;
1301 	}
1302 
1303 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1304 		RETURN_FALSE;
1305 	}
1306 
1307 	sa = (struct sockaddr *) &sa_storage;
1308 
1309 	if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
1310 		PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
1311 		RETURN_FALSE;
1312 	}
1313 
1314 	switch (sa->sa_family) {
1315 #if HAVE_IPV6
1316 		case AF_INET6:
1317 			sin6 = (struct sockaddr_in6 *) sa;
1318 			inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1319 			zval_dtor(arg2);
1320 			ZVAL_STRING(arg2, addr6);
1321 
1322 			if (arg3 != NULL) {
1323 				zval_dtor(arg3);
1324 				ZVAL_LONG(arg3, htons(sin6->sin6_port));
1325 			}
1326 
1327 			RETURN_TRUE;
1328 			break;
1329 #endif
1330 		case AF_INET:
1331 			sin = (struct sockaddr_in *) sa;
1332 			while (inet_ntoa_lock == 1);
1333 			inet_ntoa_lock = 1;
1334 			addr_string = inet_ntoa(sin->sin_addr);
1335 			inet_ntoa_lock = 0;
1336 
1337 			zval_dtor(arg2);
1338 			ZVAL_STRING(arg2, addr_string);
1339 
1340 			if (arg3 != NULL) {
1341 				zval_dtor(arg3);
1342 				ZVAL_LONG(arg3, htons(sin->sin_port));
1343 			}
1344 
1345 			RETURN_TRUE;
1346 			break;
1347 
1348 		case AF_UNIX:
1349 			s_un = (struct sockaddr_un *) sa;
1350 
1351 			zval_dtor(arg2);
1352 			ZVAL_STRING(arg2, s_un->sun_path);
1353 			RETURN_TRUE;
1354 			break;
1355 
1356 		default:
1357 			php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
1358 			RETURN_FALSE;
1359 	}
1360 }
1361 /* }}} */
1362 
1363 /* {{{ proto resource socket_create(int domain, int type, int protocol)
1364    Creates an endpoint for communication in the domain specified by domain, of type specified by type */
1365 PHP_FUNCTION(socket_create)
1366 {
1367 	zend_long		arg1, arg2, arg3;
1368 	php_socket	*php_sock = php_create_socket();
1369 
1370 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &arg1, &arg2, &arg3) == FAILURE) {
1371 		efree(php_sock);
1372 		return;
1373 	}
1374 
1375 	if (arg1 != AF_UNIX
1376 #if HAVE_IPV6
1377 		&& arg1 != AF_INET6
1378 #endif
1379 		&& arg1 != AF_INET) {
1380 		php_error_docref(NULL, E_WARNING, "invalid socket domain [%pd] specified for argument 1, assuming AF_INET", arg1);
1381 		arg1 = AF_INET;
1382 	}
1383 
1384 	if (arg2 > 10) {
1385 		php_error_docref(NULL, E_WARNING, "invalid socket type [%pd] specified for argument 2, assuming SOCK_STREAM", arg2);
1386 		arg2 = SOCK_STREAM;
1387 	}
1388 
1389 	php_sock->bsd_socket = socket(arg1, arg2, arg3);
1390 	php_sock->type = arg1;
1391 
1392 	if (IS_INVALID_SOCKET(php_sock)) {
1393 		SOCKETS_G(last_error) = errno;
1394 		php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
1395 		efree(php_sock);
1396 		RETURN_FALSE;
1397 	}
1398 
1399 	php_sock->error = 0;
1400 	php_sock->blocking = 1;
1401 
1402 	RETURN_RES(zend_register_resource(php_sock, le_socket));
1403 }
1404 /* }}} */
1405 
1406 /* {{{ proto bool socket_connect(resource socket, string addr [, int port])
1407    Opens a connection to addr:port on the socket specified by socket */
1408 PHP_FUNCTION(socket_connect)
1409 {
1410 	zval				*arg1;
1411 	php_socket			*php_sock;
1412 	char				*addr;
1413 	int					retval;
1414 	size_t              addr_len;
1415 	zend_long				port = 0;
1416 	int					argc = ZEND_NUM_ARGS();
1417 
1418 	if (zend_parse_parameters(argc, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1419 		return;
1420 	}
1421 
1422 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1423 		RETURN_FALSE;
1424 	}
1425 
1426 	switch(php_sock->type) {
1427 #if HAVE_IPV6
1428 		case AF_INET6: {
1429 			struct sockaddr_in6 sin6 = {0};
1430 
1431 			if (argc != 3) {
1432 				php_error_docref(NULL, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
1433 				RETURN_FALSE;
1434 			}
1435 
1436 			memset(&sin6, 0, sizeof(struct sockaddr_in6));
1437 
1438 			sin6.sin6_family = AF_INET6;
1439 			sin6.sin6_port   = htons((unsigned short int)port);
1440 
1441 			if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
1442 				RETURN_FALSE;
1443 			}
1444 
1445 			retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
1446 			break;
1447 		}
1448 #endif
1449 		case AF_INET: {
1450 			struct sockaddr_in sin = {0};
1451 
1452 			if (argc != 3) {
1453 				php_error_docref(NULL, E_WARNING, "Socket of type AF_INET requires 3 arguments");
1454 				RETURN_FALSE;
1455 			}
1456 
1457 			sin.sin_family = AF_INET;
1458 			sin.sin_port   = htons((unsigned short int)port);
1459 
1460 			if (! php_set_inet_addr(&sin, addr, php_sock)) {
1461 				RETURN_FALSE;
1462 			}
1463 
1464 			retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
1465 			break;
1466 		}
1467 
1468 		case AF_UNIX: {
1469 			struct sockaddr_un s_un = {0};
1470 
1471 			if (addr_len >= sizeof(s_un.sun_path)) {
1472 				php_error_docref(NULL, E_WARNING, "Path too long");
1473 				RETURN_FALSE;
1474 			}
1475 
1476 			s_un.sun_family = AF_UNIX;
1477 			memcpy(&s_un.sun_path, addr, addr_len);
1478 			retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
1479 				(socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
1480 			break;
1481 		}
1482 
1483 		default:
1484 			php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1485 			RETURN_FALSE;
1486 		}
1487 
1488 	if (retval != 0) {
1489 		PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
1490 		RETURN_FALSE;
1491 	}
1492 
1493 	RETURN_TRUE;
1494 }
1495 /* }}} */
1496 
1497 /* {{{ proto string socket_strerror(int errno)
1498    Returns a string describing an error */
1499 PHP_FUNCTION(socket_strerror)
1500 {
1501 	zend_long	arg1;
1502 
1503 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &arg1) == FAILURE) {
1504 		return;
1505 	}
1506 
1507 	RETURN_STRING(sockets_strerror(arg1));
1508 }
1509 /* }}} */
1510 
1511 /* {{{ proto bool socket_bind(resource socket, string addr [, int port])
1512    Binds an open socket to a listening port, port is only specified in AF_INET family. */
1513 PHP_FUNCTION(socket_bind)
1514 {
1515 	zval					*arg1;
1516 	php_sockaddr_storage	sa_storage = {0};
1517 	struct sockaddr			*sock_type = (struct sockaddr*) &sa_storage;
1518 	php_socket				*php_sock;
1519 	char					*addr;
1520 	size_t						addr_len;
1521 	zend_long					port = 0;
1522 	zend_long					retval = 0;
1523 
1524 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1525 		return;
1526 	}
1527 
1528 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1529 		RETURN_FALSE;
1530 	}
1531 
1532 	switch(php_sock->type) {
1533 		case AF_UNIX:
1534 			{
1535 				struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
1536 
1537 				sa->sun_family = AF_UNIX;
1538 
1539 				if (addr_len >= sizeof(sa->sun_path)) {
1540 					php_error_docref(NULL, E_WARNING,
1541 							"Invalid path: too long (maximum size is %d)",
1542 							(int)sizeof(sa->sun_path) - 1);
1543 					RETURN_FALSE;
1544 				}
1545 				memcpy(&sa->sun_path, addr, addr_len);
1546 
1547 				retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa,
1548 						offsetof(struct sockaddr_un, sun_path) + addr_len);
1549 				break;
1550 			}
1551 
1552 		case AF_INET:
1553 			{
1554 				struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
1555 
1556 				sa->sin_family = AF_INET;
1557 				sa->sin_port = htons((unsigned short) port);
1558 
1559 				if (! php_set_inet_addr(sa, addr, php_sock)) {
1560 					RETURN_FALSE;
1561 				}
1562 
1563 				retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
1564 				break;
1565 			}
1566 #if HAVE_IPV6
1567 		case AF_INET6:
1568 			{
1569 				struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
1570 
1571 				sa->sin6_family = AF_INET6;
1572 				sa->sin6_port = htons((unsigned short) port);
1573 
1574 				if (! php_set_inet6_addr(sa, addr, php_sock)) {
1575 					RETURN_FALSE;
1576 				}
1577 
1578 				retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
1579 				break;
1580 			}
1581 #endif
1582 		default:
1583 			php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
1584 			RETURN_FALSE;
1585 	}
1586 
1587 	if (retval != 0) {
1588 		PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
1589 		RETURN_FALSE;
1590 	}
1591 
1592 	RETURN_TRUE;
1593 }
1594 /* }}} */
1595 
1596 /* {{{ proto int socket_recv(resource socket, string &buf, int len, int flags)
1597    Receives data from a connected socket */
1598 PHP_FUNCTION(socket_recv)
1599 {
1600 	zval		*php_sock_res, *buf;
1601 	zend_string	*recv_buf;
1602 	php_socket	*php_sock;
1603 	int			retval;
1604 	zend_long		len, flags;
1605 
1606 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/ll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
1607 		return;
1608 	}
1609 
1610 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(php_sock_res), le_socket_name, le_socket)) == NULL) {
1611 		RETURN_FALSE;
1612 	}
1613 
1614 	/* overflow check */
1615 	if ((len + 1) < 2) {
1616 		RETURN_FALSE;
1617 	}
1618 
1619 	recv_buf = zend_string_alloc(len, 0);
1620 
1621 	if ((retval = recv(php_sock->bsd_socket, ZSTR_VAL(recv_buf), len, flags)) < 1) {
1622 		efree(recv_buf);
1623 
1624 		zval_dtor(buf);
1625 		ZVAL_NULL(buf);
1626 	} else {
1627 		ZSTR_LEN(recv_buf) = retval;
1628 		ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1629 
1630 		/* Rebuild buffer zval */
1631 		zval_dtor(buf);
1632 		ZVAL_NEW_STR(buf, recv_buf);
1633 	}
1634 
1635 	if (retval == -1) {
1636 		PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1637 		RETURN_FALSE;
1638 	}
1639 
1640 	RETURN_LONG(retval);
1641 }
1642 /* }}} */
1643 
1644 /* {{{ proto int socket_send(resource socket, string buf, int len, int flags)
1645    Sends data to a connected socket */
1646 PHP_FUNCTION(socket_send)
1647 {
1648 	zval		*arg1;
1649 	php_socket	*php_sock;
1650 	size_t			buf_len, retval;
1651 	zend_long		len, flags;
1652 	char		*buf;
1653 
1654 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
1655 		return;
1656 	}
1657 
1658 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1659 		RETURN_FALSE;
1660 	}
1661 
1662 	retval = send(php_sock->bsd_socket, buf, (buf_len < len ? buf_len : len), flags);
1663 
1664 	if (retval == -1) {
1665 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1666 		RETURN_FALSE;
1667 	}
1668 
1669 	RETURN_LONG(retval);
1670 }
1671 /* }}} */
1672 
1673 /* {{{ proto int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port])
1674    Receives data from a socket, connected or not */
1675 PHP_FUNCTION(socket_recvfrom)
1676 {
1677 	zval				*arg1, *arg2, *arg5, *arg6 = NULL;
1678 	php_socket			*php_sock;
1679 	struct sockaddr_un	s_un;
1680 	struct sockaddr_in	sin;
1681 #if HAVE_IPV6
1682 	struct sockaddr_in6	sin6;
1683 	char				addr6[INET6_ADDRSTRLEN];
1684 #endif
1685 	socklen_t			slen;
1686 	int					retval;
1687 	zend_long				arg3, arg4;
1688 	char				*address;
1689 	zend_string			*recv_buf;
1690 
1691 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/llz/|z/", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
1692 		return;
1693 	}
1694 
1695 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1696 		RETURN_FALSE;
1697 	}
1698 
1699 	/* overflow check */
1700 	if ((arg3 + 2) < 3) {
1701 		RETURN_FALSE;
1702 	}
1703 
1704 	recv_buf = zend_string_alloc(arg3 + 1, 0);
1705 
1706 	switch (php_sock->type) {
1707 		case AF_UNIX:
1708 			slen = sizeof(s_un);
1709 			s_un.sun_family = AF_UNIX;
1710 			retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
1711 
1712 			if (retval < 0) {
1713 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1714 				zend_string_free(recv_buf);
1715 				RETURN_FALSE;
1716 			}
1717 			ZSTR_LEN(recv_buf) = retval;
1718 			ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1719 
1720 			zval_dtor(arg2);
1721 			zval_dtor(arg5);
1722 
1723 			ZVAL_NEW_STR(arg2, recv_buf);
1724 			ZVAL_STRING(arg5, s_un.sun_path);
1725 			break;
1726 
1727 		case AF_INET:
1728 			slen = sizeof(sin);
1729 			memset(&sin, 0, slen);
1730 			sin.sin_family = AF_INET;
1731 
1732 			if (arg6 == NULL) {
1733 				zend_string_free(recv_buf);
1734 				WRONG_PARAM_COUNT;
1735 			}
1736 
1737 			retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
1738 
1739 			if (retval < 0) {
1740 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1741 				zend_string_free(recv_buf);
1742 				RETURN_FALSE;
1743 			}
1744 			ZSTR_LEN(recv_buf) = retval;
1745 			ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1746 
1747 			zval_dtor(arg2);
1748 			zval_dtor(arg5);
1749 			zval_dtor(arg6);
1750 
1751 			address = inet_ntoa(sin.sin_addr);
1752 
1753 			ZVAL_NEW_STR(arg2, recv_buf);
1754 			ZVAL_STRING(arg5, address ? address : "0.0.0.0");
1755 			ZVAL_LONG(arg6, ntohs(sin.sin_port));
1756 			break;
1757 #if HAVE_IPV6
1758 		case AF_INET6:
1759 			slen = sizeof(sin6);
1760 			memset(&sin6, 0, slen);
1761 			sin6.sin6_family = AF_INET6;
1762 
1763 			if (arg6 == NULL) {
1764 				efree(recv_buf);
1765 				WRONG_PARAM_COUNT;
1766 			}
1767 
1768 			retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
1769 
1770 			if (retval < 0) {
1771 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1772 				zend_string_free(recv_buf);
1773 				RETURN_FALSE;
1774 			}
1775 			ZSTR_LEN(recv_buf) = retval;
1776 			ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1777 
1778 			zval_dtor(arg2);
1779 			zval_dtor(arg5);
1780 			zval_dtor(arg6);
1781 
1782 			memset(addr6, 0, INET6_ADDRSTRLEN);
1783 			inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
1784 
1785 			ZVAL_NEW_STR(arg2, recv_buf);
1786 			ZVAL_STRING(arg5, addr6[0] ? addr6 : "::");
1787 			ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
1788 			break;
1789 #endif
1790 		default:
1791 			php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1792 			RETURN_FALSE;
1793 	}
1794 
1795 	RETURN_LONG(retval);
1796 }
1797 /* }}} */
1798 
1799 /* {{{ proto int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port])
1800    Sends a message to a socket, whether it is connected or not */
1801 PHP_FUNCTION(socket_sendto)
1802 {
1803 	zval				*arg1;
1804 	php_socket			*php_sock;
1805 	struct sockaddr_un	s_un;
1806 	struct sockaddr_in	sin;
1807 #if HAVE_IPV6
1808 	struct sockaddr_in6	sin6;
1809 #endif
1810 	int					retval;
1811 	size_t              buf_len, addr_len;
1812 	zend_long			len, flags, port = 0;
1813 	char				*buf, *addr;
1814 	int					argc = ZEND_NUM_ARGS();
1815 
1816 	if (zend_parse_parameters(argc, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
1817 		return;
1818 	}
1819 
1820 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1821 		RETURN_FALSE;
1822 	}
1823 
1824 	switch (php_sock->type) {
1825 		case AF_UNIX:
1826 			memset(&s_un, 0, sizeof(s_un));
1827 			s_un.sun_family = AF_UNIX;
1828 			snprintf(s_un.sun_path, 108, "%s", addr);
1829 
1830 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len,	flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
1831 			break;
1832 
1833 		case AF_INET:
1834 			if (argc != 6) {
1835 				WRONG_PARAM_COUNT;
1836 			}
1837 
1838 			memset(&sin, 0, sizeof(sin));
1839 			sin.sin_family = AF_INET;
1840 			sin.sin_port = htons((unsigned short) port);
1841 
1842 			if (! php_set_inet_addr(&sin, addr, php_sock)) {
1843 				RETURN_FALSE;
1844 			}
1845 
1846 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin, sizeof(sin));
1847 			break;
1848 #if HAVE_IPV6
1849 		case AF_INET6:
1850 			if (argc != 6) {
1851 				WRONG_PARAM_COUNT;
1852 			}
1853 
1854 			memset(&sin6, 0, sizeof(sin6));
1855 			sin6.sin6_family = AF_INET6;
1856 			sin6.sin6_port = htons((unsigned short) port);
1857 
1858 			if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
1859 				RETURN_FALSE;
1860 			}
1861 
1862 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
1863 			break;
1864 #endif
1865 		default:
1866 			php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1867 			RETURN_FALSE;
1868 	}
1869 
1870 	if (retval == -1) {
1871 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1872 		RETURN_FALSE;
1873 	}
1874 
1875 	RETURN_LONG(retval);
1876 }
1877 /* }}} */
1878 
1879 /* {{{ proto mixed socket_get_option(resource socket, int level, int optname)
1880    Gets socket options for the socket */
1881 PHP_FUNCTION(socket_get_option)
1882 {
1883 	zval			*arg1;
1884 	struct linger	linger_val;
1885 	struct timeval	tv;
1886 #ifdef PHP_WIN32
1887 	int				timeout = 0;
1888 #endif
1889 	socklen_t		optlen;
1890 	php_socket		*php_sock;
1891 	int				other_val;
1892 	zend_long			level, optname;
1893 
1894 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rll", &arg1, &level, &optname) == FAILURE) {
1895 		return;
1896 	}
1897 
1898 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1899 		RETURN_FALSE;
1900 	}
1901 
1902 	if (level == IPPROTO_IP) {
1903 		switch (optname) {
1904 		case IP_MULTICAST_IF: {
1905 			struct in_addr if_addr;
1906 			unsigned int if_index;
1907 			optlen = sizeof(if_addr);
1908 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&if_addr, &optlen) != 0) {
1909 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1910 				RETURN_FALSE;
1911 			}
1912 			if (php_add4_to_if_index(&if_addr, php_sock, &if_index) == SUCCESS) {
1913 				RETURN_LONG((zend_long) if_index);
1914 			} else {
1915 				RETURN_FALSE;
1916 			}
1917 		}
1918 		}
1919 	}
1920 #if HAVE_IPV6
1921 	else if (level == IPPROTO_IPV6) {
1922 		int ret = php_do_getsockopt_ipv6_rfc3542(php_sock, level, optname, return_value);
1923 		if (ret == SUCCESS) {
1924 			return;
1925 		} else if (ret == FAILURE) {
1926 			RETURN_FALSE;
1927 		} /* else continue */
1928 	}
1929 #endif
1930 
1931 	/* sol_socket options and general case */
1932 	switch(optname) {
1933 		case SO_LINGER:
1934 			optlen = sizeof(linger_val);
1935 
1936 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
1937 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1938 				RETURN_FALSE;
1939 			}
1940 
1941 			array_init(return_value);
1942 			add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
1943 			add_assoc_long(return_value, "l_linger", linger_val.l_linger);
1944 			break;
1945 
1946 		case SO_RCVTIMEO:
1947 		case SO_SNDTIMEO:
1948 #ifndef PHP_WIN32
1949 			optlen = sizeof(tv);
1950 
1951 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
1952 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1953 				RETURN_FALSE;
1954 			}
1955 #else
1956 			optlen = sizeof(int);
1957 
1958 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
1959 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1960 				RETURN_FALSE;
1961 			}
1962 
1963 			tv.tv_sec = timeout ? timeout / 1000 : 0;
1964 			tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;
1965 #endif
1966 
1967 			array_init(return_value);
1968 
1969 			add_assoc_long(return_value, "sec", tv.tv_sec);
1970 			add_assoc_long(return_value, "usec", tv.tv_usec);
1971 			break;
1972 
1973 		default:
1974 			optlen = sizeof(other_val);
1975 
1976 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
1977 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1978 				RETURN_FALSE;
1979 			}
1980 			if (optlen == 1)
1981 				other_val = *((unsigned char *)&other_val);
1982 
1983 			RETURN_LONG(other_val);
1984 			break;
1985 	}
1986 }
1987 /* }}} */
1988 
1989 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
1990    Sets socket options for the socket */
1991 PHP_FUNCTION(socket_set_option)
1992 {
1993 	zval					*arg1, *arg4;
1994 	struct linger			lv;
1995 	php_socket				*php_sock;
1996 	int						ov, optlen, retval;
1997 #ifdef PHP_WIN32
1998 	int						timeout;
1999 #else
2000 	struct					timeval tv;
2001 #endif
2002 	zend_long					level, optname;
2003 	void 					*opt_ptr;
2004 	HashTable		 		*opt_ht;
2005 	zval 					*l_onoff, *l_linger;
2006 	zval		 			*sec, *usec;
2007 
2008 
2009 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rllz", &arg1, &level, &optname, &arg4) == 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 	set_errno(0);
2018 
2019 #define HANDLE_SUBCALL(res) \
2020 	do { \
2021 		if (res == 1) { goto default_case; } \
2022 		else if (res == SUCCESS) { RETURN_TRUE; } \
2023 		else { RETURN_FALSE; } \
2024 	} while (0)
2025 
2026 
2027 	if (level == IPPROTO_IP) {
2028 		int res = php_do_setsockopt_ip_mcast(php_sock, level, optname, arg4);
2029 		HANDLE_SUBCALL(res);
2030 	}
2031 
2032 #if HAVE_IPV6
2033 	else if (level == IPPROTO_IPV6) {
2034 		int res = php_do_setsockopt_ipv6_mcast(php_sock, level, optname, arg4);
2035 		if (res == 1) {
2036 			res = php_do_setsockopt_ipv6_rfc3542(php_sock, level, optname, arg4);
2037 		}
2038 		HANDLE_SUBCALL(res);
2039 	}
2040 #endif
2041 
2042 	switch (optname) {
2043 		case SO_LINGER: {
2044 			const char l_onoff_key[] = "l_onoff";
2045 			const char l_linger_key[] = "l_linger";
2046 
2047 			convert_to_array_ex(arg4);
2048 			opt_ht = Z_ARRVAL_P(arg4);
2049 
2050 			if ((l_onoff = zend_hash_str_find(opt_ht, l_onoff_key, sizeof(l_onoff_key) - 1)) == NULL) {
2051 				php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
2052 				RETURN_FALSE;
2053 			}
2054 			if ((l_linger = zend_hash_str_find(opt_ht, l_linger_key, sizeof(l_linger_key) - 1)) == NULL) {
2055 				php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
2056 				RETURN_FALSE;
2057 			}
2058 
2059 			convert_to_long_ex(l_onoff);
2060 			convert_to_long_ex(l_linger);
2061 
2062 			lv.l_onoff = (unsigned short)Z_LVAL_P(l_onoff);
2063 			lv.l_linger = (unsigned short)Z_LVAL_P(l_linger);
2064 
2065 			optlen = sizeof(lv);
2066 			opt_ptr = &lv;
2067 			break;
2068 		}
2069 
2070 		case SO_RCVTIMEO:
2071 		case SO_SNDTIMEO: {
2072 			const char sec_key[] = "sec";
2073 			const char usec_key[] = "usec";
2074 
2075 			convert_to_array_ex(arg4);
2076 			opt_ht = Z_ARRVAL_P(arg4);
2077 
2078 			if ((sec = zend_hash_str_find(opt_ht, sec_key, sizeof(sec_key) - 1)) == NULL) {
2079 				php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", sec_key);
2080 				RETURN_FALSE;
2081 			}
2082 			if ((usec = zend_hash_str_find(opt_ht, usec_key, sizeof(usec_key) - 1)) == NULL) {
2083 				php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", usec_key);
2084 				RETURN_FALSE;
2085 			}
2086 
2087 			convert_to_long_ex(sec);
2088 			convert_to_long_ex(usec);
2089 #ifndef PHP_WIN32
2090 			tv.tv_sec = Z_LVAL_P(sec);
2091 			tv.tv_usec = Z_LVAL_P(usec);
2092 			optlen = sizeof(tv);
2093 			opt_ptr = &tv;
2094 #else
2095 			timeout = Z_LVAL_P(sec) * 1000 + Z_LVAL_P(usec) / 1000;
2096 			optlen = sizeof(int);
2097 			opt_ptr = &timeout;
2098 #endif
2099 			break;
2100 		}
2101 #ifdef SO_BINDTODEVICE
2102 		case SO_BINDTODEVICE: {
2103 			if (Z_TYPE_P(arg4) == IS_STRING) {
2104 				opt_ptr = Z_STRVAL_P(arg4);
2105 				optlen = Z_STRLEN_P(arg4);
2106 			} else {
2107 				opt_ptr = "";
2108 				optlen = 0;
2109 			}
2110 			break;
2111 		}
2112 #endif
2113 
2114 		default:
2115 default_case:
2116 			convert_to_long_ex(arg4);
2117 			ov = Z_LVAL_P(arg4);
2118 
2119 			optlen = sizeof(ov);
2120 			opt_ptr = &ov;
2121 			break;
2122 	}
2123 
2124 	retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
2125 	if (retval != 0) {
2126 		PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
2127 		RETURN_FALSE;
2128 	}
2129 
2130 	RETURN_TRUE;
2131 }
2132 /* }}} */
2133 
2134 #ifdef HAVE_SOCKETPAIR
2135 /* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd)
2136    Creates a pair of indistinguishable sockets and stores them in fds. */
2137 PHP_FUNCTION(socket_create_pair)
2138 {
2139 	zval		retval[2], *fds_array_zval;
2140 	php_socket	*php_sock[2];
2141 	PHP_SOCKET	fds_array[2];
2142 	zend_long		domain, type, protocol;
2143 
2144 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lllz/", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
2145 		return;
2146 	}
2147 
2148 	php_sock[0] = php_create_socket();
2149 	php_sock[1] = php_create_socket();
2150 
2151 	if (domain != AF_INET
2152 #if HAVE_IPV6
2153 		&& domain != AF_INET6
2154 #endif
2155 		&& domain != AF_UNIX) {
2156 		php_error_docref(NULL, E_WARNING, "invalid socket domain [%pd] specified for argument 1, assuming AF_INET", domain);
2157 		domain = AF_INET;
2158 	}
2159 
2160 	if (type > 10) {
2161 		php_error_docref(NULL, E_WARNING, "invalid socket type [%pd] specified for argument 2, assuming SOCK_STREAM", type);
2162 		type = SOCK_STREAM;
2163 	}
2164 
2165 	if (socketpair(domain, type, protocol, fds_array) != 0) {
2166 		SOCKETS_G(last_error) = errno;
2167 		php_error_docref(NULL, E_WARNING, "unable to create socket pair [%d]: %s", errno, sockets_strerror(errno));
2168 		efree(php_sock[0]);
2169 		efree(php_sock[1]);
2170 		RETURN_FALSE;
2171 	}
2172 
2173 	zval_dtor(fds_array_zval);
2174 	array_init(fds_array_zval);
2175 
2176 	php_sock[0]->bsd_socket = fds_array[0];
2177 	php_sock[1]->bsd_socket = fds_array[1];
2178 	php_sock[0]->type		= domain;
2179 	php_sock[1]->type		= domain;
2180 	php_sock[0]->error		= 0;
2181 	php_sock[1]->error		= 0;
2182 	php_sock[0]->blocking	= 1;
2183 	php_sock[1]->blocking	= 1;
2184 
2185 	ZVAL_RES(&retval[0], zend_register_resource(php_sock[0], le_socket));
2186 	ZVAL_RES(&retval[1], zend_register_resource(php_sock[1], le_socket));
2187 
2188 	add_index_zval(fds_array_zval, 0, &retval[0]);
2189 	add_index_zval(fds_array_zval, 1, &retval[1]);
2190 
2191 	RETURN_TRUE;
2192 }
2193 /* }}} */
2194 #endif
2195 
2196 #ifdef HAVE_SHUTDOWN
2197 /* {{{ proto bool socket_shutdown(resource socket[, int how])
2198    Shuts down a socket for receiving, sending, or both. */
2199 PHP_FUNCTION(socket_shutdown)
2200 {
2201 	zval		*arg1;
2202 	zend_long		how_shutdown = 2;
2203 	php_socket	*php_sock;
2204 
2205 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &arg1, &how_shutdown) == FAILURE) {
2206 		return;
2207 	}
2208 
2209 	if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2210 		RETURN_FALSE;
2211 	}
2212 
2213 	if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
2214 		PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
2215 		RETURN_FALSE;
2216 	}
2217 
2218 	RETURN_TRUE;
2219 }
2220 /* }}} */
2221 #endif
2222 
2223 /* {{{ proto int socket_last_error([resource socket])
2224    Returns the last socket error (either the last used or the provided socket resource) */
2225 PHP_FUNCTION(socket_last_error)
2226 {
2227 	zval		*arg1 = NULL;
2228 	php_socket	*php_sock;
2229 
2230 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
2231 		return;
2232 	}
2233 
2234 	if (arg1) {
2235 		if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2236 			RETURN_FALSE;
2237 		}
2238 		RETVAL_LONG(php_sock->error);
2239 	} else {
2240 		RETVAL_LONG(SOCKETS_G(last_error));
2241 	}
2242 }
2243 /* }}} */
2244 
2245 /* {{{ proto void socket_clear_error([resource socket])
2246    Clears the error on the socket or the last error code. */
2247 PHP_FUNCTION(socket_clear_error)
2248 {
2249 	zval		*arg1 = NULL;
2250 	php_socket	*php_sock;
2251 
2252 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
2253 		return;
2254 	}
2255 
2256 	if (arg1) {
2257 		if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2258 			RETURN_FALSE;
2259 		}
2260 		php_sock->error = 0;
2261 	} else {
2262 		SOCKETS_G(last_error) = 0;
2263 	}
2264 
2265 	return;
2266 }
2267 /* }}} */
2268 
2269 php_socket *socket_import_file_descriptor(PHP_SOCKET socket)
2270 {
2271 #ifdef SO_DOMAIN
2272 	int						type;
2273 	socklen_t				type_len = sizeof(type);
2274 #endif
2275 	php_socket 				*retsock;
2276 	php_sockaddr_storage	addr;
2277 	socklen_t				addr_len = sizeof(addr);
2278 #ifndef PHP_WIN32
2279 	int					 t;
2280 #endif
2281 
2282     retsock = php_create_socket();
2283     retsock->bsd_socket = socket;
2284 
2285     /* determine family */
2286 #ifdef SO_DOMAIN
2287     if (getsockopt(socket, SOL_SOCKET, SO_DOMAIN, &type, &type_len) == 0) {
2288 		retsock->type = type;
2289 	} else
2290 #endif
2291 	if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
2292 		retsock->type = addr.ss_family;
2293 	} else {
2294 		PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
2295 		goto error;
2296 	}
2297 
2298     /* determine blocking mode */
2299 #ifndef PHP_WIN32
2300     t = fcntl(socket, F_GETFL);
2301     if (t == -1) {
2302 		PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
2303 		goto error;
2304     } else {
2305     	retsock->blocking = !(t & O_NONBLOCK);
2306     }
2307 #endif
2308 
2309     return retsock;
2310 
2311 error:
2312 	efree(retsock);
2313 	return NULL;
2314 }
2315 
2316 /* {{{ proto resource socket_import_stream(resource stream)
2317    Imports a stream that encapsulates a socket into a socket extension resource. */
2318 PHP_FUNCTION(socket_import_stream)
2319 {
2320 	zval				 *zstream;
2321 	php_stream			 *stream;
2322 	php_socket			 *retsock = NULL;
2323 	PHP_SOCKET			 socket; /* fd */
2324 
2325 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream) == FAILURE) {
2326 		return;
2327 	}
2328 	php_stream_from_zval(stream, zstream);
2329 
2330 	if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
2331 		/* error supposedly already shown */
2332 		RETURN_FALSE;
2333 	}
2334 
2335 	retsock = socket_import_file_descriptor(socket);
2336 	if (retsock == NULL) {
2337 		RETURN_FALSE;
2338 	}
2339 
2340 #ifdef PHP_WIN32
2341 	/* on windows, check if the stream is a socket stream and read its
2342 	 * private data; otherwise assume it's in non-blocking mode */
2343 	if (php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
2344 		retsock->blocking =
2345 				((php_netstream_data_t *)stream->abstract)->is_blocked;
2346 	} else {
2347 		retsock->blocking = 1;
2348 	}
2349 #endif
2350 
2351 	/* hold a zval reference to the stream (holding a php_stream* directly could
2352 	 * also be done, but this makes socket_export_stream a bit simpler) */
2353 	ZVAL_COPY(&retsock->zstream, zstream);
2354 
2355 	php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
2356 		PHP_STREAM_BUFFER_NONE, NULL);
2357 
2358 	RETURN_RES(zend_register_resource(retsock, le_socket));
2359 }
2360 /* }}} */
2361 
2362 /* {{{ proto resource socket_export_stream(resource socket)
2363    Exports a socket extension resource into a stream that encapsulates a socket. */
2364 PHP_FUNCTION(socket_export_stream)
2365 {
2366 	zval *zsocket;
2367 	php_socket *socket;
2368 	php_stream *stream = NULL;
2369 	php_netstream_data_t *stream_data;
2370 	char *protocol = NULL;
2371 	size_t protocollen = 0;
2372 
2373 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsocket) == FAILURE) {
2374 		return;
2375 	}
2376 	if ((socket = (php_socket *) zend_fetch_resource(Z_RES_P(zsocket), le_socket_name, le_socket)) == NULL) {
2377 		RETURN_FALSE;
2378 	}
2379 
2380 	/* Either we already exported a stream or the socket came from an import,
2381 	 * just return the existing stream */
2382 	if (!Z_ISUNDEF(socket->zstream)) {
2383 		RETURN_ZVAL(&socket->zstream, 1, 0);
2384 	}
2385 
2386 	/* Determine if socket is using a protocol with one of the default registered
2387 	 * socket stream wrappers */
2388 	if (socket->type == PF_INET
2389 #if HAVE_IPV6
2390 		 || socket->type == PF_INET6
2391 #endif
2392 	) {
2393 		int protoid;
2394 		socklen_t protoidlen = sizeof(protoid);
2395 
2396 		getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &protoid, &protoidlen);
2397 
2398 		if (protoid == SOCK_STREAM) {
2399 			/* SO_PROTOCOL is not (yet?) supported on OS X, so lets assume it's TCP there */
2400 #ifdef SO_PROTOCOL
2401 			protoidlen = sizeof(protoid);
2402 			getsockopt(socket->bsd_socket, SOL_SOCKET, SO_PROTOCOL, (char *) &protoid, &protoidlen);
2403 			if (protoid == IPPROTO_TCP)
2404 #endif
2405 			{
2406 				protocol = "tcp";
2407 				protocollen = 3;
2408 			}
2409 		} else if (protoid == SOCK_DGRAM) {
2410 			protocol = "udp";
2411 			protocollen = 3;
2412 		}
2413 #ifdef PF_UNIX
2414 	} else if (socket->type == PF_UNIX) {
2415 		int type;
2416 		socklen_t typelen = sizeof(type);
2417 
2418 		getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen);
2419 
2420 		if (type == SOCK_STREAM) {
2421 			protocol = "unix";
2422 			protocollen = 4;
2423 		} else if (type == SOCK_DGRAM) {
2424 			protocol = "udg";
2425 			protocollen = 3;
2426 		}
2427 #endif
2428 	}
2429 
2430 	/* Try to get a stream with the registered sockops for the protocol in use
2431 	 * We don't want streams to actually *do* anything though, so don't give it
2432 	 * anything apart from the protocol */
2433 	if (protocol != NULL) {
2434 		stream = php_stream_xport_create(protocol, protocollen, 0, 0, NULL, NULL, NULL, NULL, NULL);
2435 	}
2436 
2437 	/* Fall back to creating a generic socket stream */
2438 	if (stream == NULL) {
2439 		stream = php_stream_sock_open_from_socket(socket->bsd_socket, 0);
2440 
2441 		if (stream == NULL) {
2442 			php_error_docref(NULL, E_WARNING, "failed to create stream");
2443 			RETURN_FALSE;
2444 		}
2445 	}
2446 
2447 	stream_data = (php_netstream_data_t *) stream->abstract;
2448 	stream_data->socket = socket->bsd_socket;
2449 	stream_data->is_blocked = socket->blocking;
2450 	stream_data->timeout.tv_sec = FG(default_socket_timeout);
2451 	stream_data->timeout.tv_usec = 0;
2452 
2453 	php_stream_to_zval(stream, &socket->zstream);
2454 
2455 	RETURN_ZVAL(&socket->zstream, 1, 0);
2456 }
2457 /* }}} */
2458 
2459 /*
2460  * Local variables:
2461  * tab-width: 4
2462  * c-basic-offset: 4
2463  * End:
2464  * vim600: fdm=marker
2465  * vim: noet sw=4 ts=4
2466  */
2467