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