xref: /PHP-5.4/ext/sockets/sockets.c (revision c0d060f5)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2014 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 #if HAVE_SOCKETS
32 
33 #include "php_network.h"
34 #include "ext/standard/file.h"
35 #include "ext/standard/info.h"
36 #include "php_ini.h"
37 #ifdef PHP_WIN32
38 # include "win32/inet.h"
39 # include <winsock2.h>
40 # include <windows.h>
41 # include <Ws2tcpip.h>
42 # include "php_sockets.h"
43 # include "win32/sockets.h"
44 # define IS_INVALID_SOCKET(a)	(a->bsd_socket == INVALID_SOCKET)
45 # ifdef EPROTONOSUPPORT
46 #  undef EPROTONOSUPPORT
47 # endif
48 # ifdef ECONNRESET
49 #  undef ECONNRESET
50 # endif
51 # define EPROTONOSUPPORT	WSAEPROTONOSUPPORT
52 # define ECONNRESET		WSAECONNRESET
53 # ifdef errno
54 #  undef errno
55 # endif
56 # define errno			WSAGetLastError()
57 # define h_errno		WSAGetLastError()
58 # define set_errno(a)		WSASetLastError(a)
59 # define close(a)		closesocket(a)
60 # if _WIN32_WINNT >= 0x0600 && SOCKETS_ENABLE_VISTA_API
61 #  define HAVE_IF_NAMETOINDEX 1
62 # endif
63 #else
64 # include <sys/types.h>
65 # include <sys/socket.h>
66 # include <netdb.h>
67 # include <netinet/in.h>
68 # include <netinet/tcp.h>
69 # include <sys/un.h>
70 # include <arpa/inet.h>
71 # include <sys/time.h>
72 # include <unistd.h>
73 # include <errno.h>
74 # include <fcntl.h>
75 # include <signal.h>
76 # include <sys/uio.h>
77 # define IS_INVALID_SOCKET(a)	(a->bsd_socket < 0)
78 # define set_errno(a) (errno = a)
79 # include "php_sockets.h"
80 # if defined(_AIX) && !defined(HAVE_SA_SS_FAMILY)
81 # define ss_family __ss_family
82 # endif
83 # if HAVE_IF_NAMETOINDEX
84 #  include <net/if.h>
85 # endif
86 #endif
87 
88 #include "multicast.h"
89 
90 ZEND_DECLARE_MODULE_GLOBALS(sockets)
91 static PHP_GINIT_FUNCTION(sockets);
92 
93 #ifndef MSG_WAITALL
94 #ifdef LINUX
95 #define MSG_WAITALL 0x00000100
96 #else
97 #define MSG_WAITALL 0x00000000
98 #endif
99 #endif
100 
101 #ifndef MSG_EOF
102 #ifdef MSG_FIN
103 #define MSG_EOF MSG_FIN
104 #endif
105 #endif
106 
107 #ifndef SUN_LEN
108 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
109 #endif
110 
111 #ifndef PF_INET
112 #define PF_INET AF_INET
113 #endif
114 
115 static char *php_strerror(int error TSRMLS_DC);
116 
117 #define PHP_SOCKET_ERROR(socket, msg, errn) \
118 		do { \
119 			int _err = (errn); /* save value to avoid repeated calls to WSAGetLastError() on Windows */ \
120 			(socket)->error = _err; \
121 			SOCKETS_G(last_error) = _err; \
122 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s [%d]: %s", msg, _err, php_strerror(_err TSRMLS_CC)); \
123 		} while (0)
124 
125 #define PHP_NORMAL_READ 0x0001
126 #define PHP_BINARY_READ 0x0002
127 
128 static int le_socket;
129 #define le_socket_name php_sockets_le_socket_name
130 
131 /* {{{ arginfo */
132 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_select, 0, 0, 4)
133 	ZEND_ARG_INFO(1, read_fds)
134 	ZEND_ARG_INFO(1, write_fds)
135 	ZEND_ARG_INFO(1, except_fds)
136 	ZEND_ARG_INFO(0, tv_sec)
137 	ZEND_ARG_INFO(0, tv_usec)
138 ZEND_END_ARG_INFO()
139 
140 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_listen, 0, 0, 1)
141 	ZEND_ARG_INFO(0, port)
142 	ZEND_ARG_INFO(0, backlog)
143 ZEND_END_ARG_INFO()
144 
145 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_accept, 0, 0, 1)
146 	ZEND_ARG_INFO(0, socket)
147 ZEND_END_ARG_INFO()
148 
149 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_nonblock, 0, 0, 1)
150 	ZEND_ARG_INFO(0, socket)
151 ZEND_END_ARG_INFO()
152 
153 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_block, 0, 0, 1)
154 	ZEND_ARG_INFO(0, socket)
155 ZEND_END_ARG_INFO()
156 
157 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_listen, 0, 0, 1)
158 	ZEND_ARG_INFO(0, socket)
159 	ZEND_ARG_INFO(0, backlog)
160 ZEND_END_ARG_INFO()
161 
162 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_close, 0, 0, 1)
163 	ZEND_ARG_INFO(0, socket)
164 ZEND_END_ARG_INFO()
165 
166 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_write, 0, 0, 2)
167 	ZEND_ARG_INFO(0, socket)
168 	ZEND_ARG_INFO(0, buf)
169 	ZEND_ARG_INFO(0, length)
170 ZEND_END_ARG_INFO()
171 
172 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_read, 0, 0, 2)
173 	ZEND_ARG_INFO(0, socket)
174 	ZEND_ARG_INFO(0, length)
175 	ZEND_ARG_INFO(0, type)
176 ZEND_END_ARG_INFO()
177 
178 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getsockname, 0, 0, 2)
179 	ZEND_ARG_INFO(0, socket)
180 	ZEND_ARG_INFO(1, addr)
181 	ZEND_ARG_INFO(1, port)
182 ZEND_END_ARG_INFO()
183 
184 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getpeername, 0, 0, 2)
185 	ZEND_ARG_INFO(0, socket)
186 	ZEND_ARG_INFO(1, addr)
187 	ZEND_ARG_INFO(1, port)
188 ZEND_END_ARG_INFO()
189 
190 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create, 0, 0, 3)
191 	ZEND_ARG_INFO(0, domain)
192 	ZEND_ARG_INFO(0, type)
193 	ZEND_ARG_INFO(0, protocol)
194 ZEND_END_ARG_INFO()
195 
196 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_connect, 0, 0, 2)
197 	ZEND_ARG_INFO(0, socket)
198 	ZEND_ARG_INFO(0, addr)
199 	ZEND_ARG_INFO(0, port)
200 ZEND_END_ARG_INFO()
201 
202 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_strerror, 0, 0, 1)
203 	ZEND_ARG_INFO(0, errno)
204 ZEND_END_ARG_INFO()
205 
206 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_bind, 0, 0, 2)
207 	ZEND_ARG_INFO(0, socket)
208 	ZEND_ARG_INFO(0, addr)
209 	ZEND_ARG_INFO(0, port)
210 ZEND_END_ARG_INFO()
211 
212 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recv, 0, 0, 4)
213 	ZEND_ARG_INFO(0, socket)
214 	ZEND_ARG_INFO(1, buf)
215 	ZEND_ARG_INFO(0, len)
216 	ZEND_ARG_INFO(0, flags)
217 ZEND_END_ARG_INFO()
218 
219 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_send, 0, 0, 4)
220 	ZEND_ARG_INFO(0, socket)
221 	ZEND_ARG_INFO(0, buf)
222 	ZEND_ARG_INFO(0, len)
223 	ZEND_ARG_INFO(0, flags)
224 ZEND_END_ARG_INFO()
225 
226 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvfrom, 0, 0, 5)
227 	ZEND_ARG_INFO(0, socket)
228 	ZEND_ARG_INFO(1, buf)
229 	ZEND_ARG_INFO(0, len)
230 	ZEND_ARG_INFO(0, flags)
231 	ZEND_ARG_INFO(1, name)
232 	ZEND_ARG_INFO(1, port)
233 ZEND_END_ARG_INFO()
234 
235 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendto, 0, 0, 5)
236 	ZEND_ARG_INFO(0, socket)
237 	ZEND_ARG_INFO(0, buf)
238 	ZEND_ARG_INFO(0, len)
239 	ZEND_ARG_INFO(0, flags)
240 	ZEND_ARG_INFO(0, addr)
241 	ZEND_ARG_INFO(0, port)
242 ZEND_END_ARG_INFO()
243 
244 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_get_option, 0, 0, 3)
245 	ZEND_ARG_INFO(0, socket)
246 	ZEND_ARG_INFO(0, level)
247 	ZEND_ARG_INFO(0, optname)
248 ZEND_END_ARG_INFO()
249 
250 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_option, 0, 0, 4)
251 	ZEND_ARG_INFO(0, socket)
252 	ZEND_ARG_INFO(0, level)
253 	ZEND_ARG_INFO(0, optname)
254 	ZEND_ARG_INFO(0, optval)
255 ZEND_END_ARG_INFO()
256 
257 #ifdef HAVE_SOCKETPAIR
258 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_pair, 0, 0, 4)
259 	ZEND_ARG_INFO(0, domain)
260 	ZEND_ARG_INFO(0, type)
261 	ZEND_ARG_INFO(0, protocol)
262 	ZEND_ARG_INFO(1, fd)
263 ZEND_END_ARG_INFO()
264 #endif
265 
266 #ifdef HAVE_SHUTDOWN
267 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_shutdown, 0, 0, 1)
268 	ZEND_ARG_INFO(0, socket)
269 	ZEND_ARG_INFO(0, how)
270 ZEND_END_ARG_INFO()
271 #endif
272 
273 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_last_error, 0, 0, 0)
274 	ZEND_ARG_INFO(0, socket)
275 ZEND_END_ARG_INFO()
276 
277 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
278 	ZEND_ARG_INFO(0, socket)
279 ZEND_END_ARG_INFO()
280 
281 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1)
282 	ZEND_ARG_INFO(0, stream)
283 ZEND_END_ARG_INFO()
284 /* }}} */
285 
286 PHP_MINIT_FUNCTION(sockets);
287 PHP_MINFO_FUNCTION(sockets);
288 PHP_RSHUTDOWN_FUNCTION(sockets);
289 
290 PHP_FUNCTION(socket_select);
291 PHP_FUNCTION(socket_create_listen);
292 #ifdef HAVE_SOCKETPAIR
293 PHP_FUNCTION(socket_create_pair);
294 #endif
295 PHP_FUNCTION(socket_accept);
296 PHP_FUNCTION(socket_set_nonblock);
297 PHP_FUNCTION(socket_set_block);
298 PHP_FUNCTION(socket_listen);
299 PHP_FUNCTION(socket_close);
300 PHP_FUNCTION(socket_write);
301 PHP_FUNCTION(socket_read);
302 PHP_FUNCTION(socket_getsockname);
303 PHP_FUNCTION(socket_getpeername);
304 PHP_FUNCTION(socket_create);
305 PHP_FUNCTION(socket_connect);
306 PHP_FUNCTION(socket_strerror);
307 PHP_FUNCTION(socket_bind);
308 PHP_FUNCTION(socket_recv);
309 PHP_FUNCTION(socket_send);
310 PHP_FUNCTION(socket_recvfrom);
311 PHP_FUNCTION(socket_sendto);
312 PHP_FUNCTION(socket_get_option);
313 PHP_FUNCTION(socket_set_option);
314 #ifdef HAVE_SHUTDOWN
315 PHP_FUNCTION(socket_shutdown);
316 #endif
317 PHP_FUNCTION(socket_last_error);
318 PHP_FUNCTION(socket_clear_error);
319 PHP_FUNCTION(socket_import_stream);
320 
321 /* {{{ sockets_functions[]
322  */
323 const zend_function_entry sockets_functions[] = {
324 	PHP_FE(socket_select,			arginfo_socket_select)
325 	PHP_FE(socket_create,			arginfo_socket_create)
326 	PHP_FE(socket_create_listen,	arginfo_socket_create_listen)
327 #ifdef HAVE_SOCKETPAIR
328 	PHP_FE(socket_create_pair,		arginfo_socket_create_pair)
329 #endif
330 	PHP_FE(socket_accept,			arginfo_socket_accept)
331 	PHP_FE(socket_set_nonblock,		arginfo_socket_set_nonblock)
332 	PHP_FE(socket_set_block,		arginfo_socket_set_block)
333 	PHP_FE(socket_listen,			arginfo_socket_listen)
334 	PHP_FE(socket_close,			arginfo_socket_close)
335 	PHP_FE(socket_write,			arginfo_socket_write)
336 	PHP_FE(socket_read,				arginfo_socket_read)
337 	PHP_FE(socket_getsockname, 		arginfo_socket_getsockname)
338 	PHP_FE(socket_getpeername, 		arginfo_socket_getpeername)
339 	PHP_FE(socket_connect,			arginfo_socket_connect)
340 	PHP_FE(socket_strerror,			arginfo_socket_strerror)
341 	PHP_FE(socket_bind,				arginfo_socket_bind)
342 	PHP_FE(socket_recv,				arginfo_socket_recv)
343 	PHP_FE(socket_send,				arginfo_socket_send)
344 	PHP_FE(socket_recvfrom,			arginfo_socket_recvfrom)
345 	PHP_FE(socket_sendto,			arginfo_socket_sendto)
346 	PHP_FE(socket_get_option,		arginfo_socket_get_option)
347 	PHP_FE(socket_set_option,		arginfo_socket_set_option)
348 #ifdef HAVE_SHUTDOWN
349 	PHP_FE(socket_shutdown,			arginfo_socket_shutdown)
350 #endif
351 	PHP_FE(socket_last_error,		arginfo_socket_last_error)
352 	PHP_FE(socket_clear_error,		arginfo_socket_clear_error)
353 	PHP_FE(socket_import_stream,	arginfo_socket_import_stream)
354 
355 	/* for downwards compatibility */
356 	PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)
357 	PHP_FALIAS(socket_setopt, socket_set_option, arginfo_socket_set_option)
358 
359 	PHP_FE_END
360 };
361 /* }}} */
362 
363 zend_module_entry sockets_module_entry = {
364 	STANDARD_MODULE_HEADER,
365 	"sockets",
366 	sockets_functions,
367 	PHP_MINIT(sockets),
368 	NULL,
369 	NULL,
370 	PHP_RSHUTDOWN(sockets),
371 	PHP_MINFO(sockets),
372 	NO_VERSION_YET,
373 	PHP_MODULE_GLOBALS(sockets),
374 	PHP_GINIT(sockets),
375 	NULL,
376 	NULL,
377 	STANDARD_MODULE_PROPERTIES_EX
378 };
379 
380 
381 #ifdef COMPILE_DL_SOCKETS
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 static php_socket *php_create_socket(void) /* {{{ */
397 {
398 	php_socket *php_sock = emalloc(sizeof *php_sock);
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 	php_sock->zstream	 = NULL;
405 
406 	return php_sock;
407 }
408 /* }}} */
409 
php_destroy_socket(zend_rsrc_list_entry * rsrc TSRMLS_DC)410 static void php_destroy_socket(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
411 {
412 	php_socket *php_sock = rsrc->ptr;
413 
414 	if (php_sock->zstream == NULL) {
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 TSRMLS_DC)425 static int php_open_listen_sock(php_socket **php_sock, int port, int backlog TSRMLS_DC) /* {{{ */
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 = gethostbyname("0.0.0.0")) == NULL) {
435 #else
436 	if ((hp = 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 TSRMLS_DC) /* {{{ */
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 static char *php_strerror(int error TSRMLS_DC) /* {{{ */
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 #if HAVE_IPV6
610 static int php_get_if_index_from_string(const char *val, unsigned *out TSRMLS_DC);
611 
612 /* Sets addr by hostname, or by ip in string form (AF_INET6) */
613 static int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
614 {
615 	struct in6_addr tmp;
616 #if HAVE_GETADDRINFO
617 	struct addrinfo hints;
618 	struct addrinfo *addrinfo = NULL;
619 #endif
620 	char *scope = strchr(string, '%');
621 
622 	if (inet_pton(AF_INET6, string, &tmp)) {
623 		memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
624 	} else {
625 #if HAVE_GETADDRINFO
626 
627 		memset(&hints, 0, sizeof(struct addrinfo));
628 		hints.ai_family = PF_INET6;
629 		getaddrinfo(string, NULL, &hints, &addrinfo);
630 		if (!addrinfo) {
631 #ifdef PHP_WIN32
632 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
633 #else
634 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
635 #endif
636 			return 0;
637 		}
638 		if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
639 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
640 			freeaddrinfo(addrinfo);
641 			return 0;
642 		}
643 
644 		memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
645 		freeaddrinfo(addrinfo);
646 
647 #else
648 		/* No IPv6 specific hostname resolution is available on this system? */
649 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system");
650 		return 0;
651 #endif
652 
653 	}
654 
655 	if (scope++) {
656 		long lval = 0;
657 		double dval = 0;
658 		unsigned scope_id = 0;
659 
660 		if (IS_LONG == is_numeric_string(scope, strlen(scope), &lval, &dval, 0)) {
661 			if (lval > 0 && lval <= UINT_MAX) {
662 				scope_id = lval;
663 			}
664 		} else {
665 			php_get_if_index_from_string(scope, &scope_id TSRMLS_CC);
666 		}
667 
668 		sin6->sin6_scope_id = scope_id;
669 	}
670 
671 	return 1;
672 }
673 /* }}} */
674 #endif
675 
676 /* Sets addr by hostname, or by ip in string form (AF_INET)  */
677 static int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
678 {
679 	struct in_addr tmp;
680 	struct hostent *host_entry;
681 
682 	if (inet_aton(string, &tmp)) {
683 		sin->sin_addr.s_addr = tmp.s_addr;
684 	} else {
685 		if (! (host_entry = gethostbyname(string))) {
686 			/* Note: < -10000 indicates a host lookup error */
687 #ifdef PHP_WIN32
688 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
689 #else
690 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
691 #endif
692 			return 0;
693 		}
694 		if (host_entry->h_addrtype != AF_INET) {
695 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket");
696 			return 0;
697 		}
698 		memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
699 	}
700 
701 	return 1;
702 }
703 /* }}} */
704 
705 /* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6,
706  * depending on the socket) */
707 static int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
708 {
709 	if (php_sock->type == AF_INET) {
710 		struct sockaddr_in t = {0};
711 		if (php_set_inet_addr(&t, string, php_sock TSRMLS_CC)) {
712 			memcpy(ss, &t, sizeof t);
713 			ss->ss_family = AF_INET;
714 			*ss_len = sizeof(t);
715 			return 1;
716 		}
717 	}
718 #if HAVE_IPV6
719 	else if (php_sock->type == AF_INET6) {
720 		struct sockaddr_in6 t = {0};
721 		if (php_set_inet6_addr(&t, string, php_sock TSRMLS_CC)) {
722 			memcpy(ss, &t, sizeof t);
723 			ss->ss_family = AF_INET6;
724 			*ss_len = sizeof(t);
725 			return 1;
726 		}
727 	}
728 #endif
729 	else {
730 		php_error_docref(NULL TSRMLS_CC, E_WARNING,
731 			"IP address used in the context of an unexpected type of socket");
732 	}
733 	return 0;
734 }
735 
736 static int php_get_if_index_from_string(const char *val, unsigned *out TSRMLS_DC)
737 {
738 #if HAVE_IF_NAMETOINDEX
739 	unsigned int ind;
740 
741 	ind = if_nametoindex(val);
742 	if (ind == 0) {
743 		php_error_docref(NULL TSRMLS_CC, E_WARNING,
744 			"no interface with name \"%s\" could be found", val);
745 		return FAILURE;
746 	} else {
747 		*out = ind;
748 		return SUCCESS;
749 	}
750 #else
751 	php_error_docref(NULL TSRMLS_CC, E_WARNING,
752 			"this platform does not support looking up an interface by "
753 			"name, an integer interface index must be supplied instead");
754 	return FAILURE;
755 #endif
756 }
757 
758 static int php_get_if_index_from_zval(zval *val, unsigned *out TSRMLS_DC)
759 {
760 	int ret;
761 
762 	if (Z_TYPE_P(val) == IS_LONG) {
763 		if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > UINT_MAX) {
764 			php_error_docref(NULL TSRMLS_CC, E_WARNING,
765 				"the interface index cannot be negative or larger than %u;"
766 				" given %ld", UINT_MAX, Z_LVAL_P(val));
767 			ret = FAILURE;
768 		} else {
769 			*out = Z_LVAL_P(val);
770 			ret = SUCCESS;
771 		}
772 	} else {
773 		zval_add_ref(&val);
774 		convert_to_string_ex(&val);
775 		ret = php_get_if_index_from_string(Z_STRVAL_P(val), out TSRMLS_CC);
776 		zval_ptr_dtor(&val);
777 	}
778 
779 	return ret;
780 }
781 
782 static int php_get_if_index_from_array(const HashTable *ht, const char *key,
783 	php_socket *sock, unsigned int *if_index TSRMLS_DC)
784 {
785 	zval **val;
786 
787 	if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
788 		*if_index = 0; /* default: 0 */
789 		return SUCCESS;
790 	}
791 
792 	return php_get_if_index_from_zval(*val, if_index TSRMLS_CC);
793 }
794 
795 static int php_get_address_from_array(const HashTable *ht, const char *key,
796 	php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len TSRMLS_DC)
797 {
798 	zval **val,
799 		 *valcp;
800 
801 	if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
802 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", key);
803 		return FAILURE;
804 	}
805 	valcp = *val;
806 	zval_add_ref(&valcp);
807 	convert_to_string_ex(val);
808 	if (!php_set_inet46_addr(ss, ss_len, Z_STRVAL_P(valcp), sock TSRMLS_CC)) {
809 		zval_ptr_dtor(&valcp);
810 		return FAILURE;
811 	}
812 	zval_ptr_dtor(&valcp);
813 	return SUCCESS;
814 }
815 
816 /* {{{ PHP_GINIT_FUNCTION */
817 static PHP_GINIT_FUNCTION(sockets)
818 {
819 	sockets_globals->last_error = 0;
820 	sockets_globals->strerror_buf = NULL;
821 }
822 /* }}} */
823 
824 /* {{{ PHP_MINIT_FUNCTION
825  */
826 PHP_MINIT_FUNCTION(sockets)
827 {
828 	le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);
829 
830 	REGISTER_LONG_CONSTANT("AF_UNIX",		AF_UNIX,		CONST_CS | CONST_PERSISTENT);
831 	REGISTER_LONG_CONSTANT("AF_INET",		AF_INET,		CONST_CS | CONST_PERSISTENT);
832 #if HAVE_IPV6
833 	REGISTER_LONG_CONSTANT("AF_INET6",		AF_INET6,		CONST_CS | CONST_PERSISTENT);
834 #endif
835 	REGISTER_LONG_CONSTANT("SOCK_STREAM",	SOCK_STREAM,	CONST_CS | CONST_PERSISTENT);
836 	REGISTER_LONG_CONSTANT("SOCK_DGRAM",	SOCK_DGRAM,		CONST_CS | CONST_PERSISTENT);
837 	REGISTER_LONG_CONSTANT("SOCK_RAW",		SOCK_RAW,		CONST_CS | CONST_PERSISTENT);
838 	REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT);
839 	REGISTER_LONG_CONSTANT("SOCK_RDM",		SOCK_RDM,		CONST_CS | CONST_PERSISTENT);
840 	REGISTER_LONG_CONSTANT("MSG_OOB",		MSG_OOB,		CONST_CS | CONST_PERSISTENT);
841 	REGISTER_LONG_CONSTANT("MSG_WAITALL",	MSG_WAITALL,	CONST_CS | CONST_PERSISTENT);
842 #ifdef MSG_DONTWAIT
843 	REGISTER_LONG_CONSTANT("MSG_DONTWAIT",	MSG_DONTWAIT,	CONST_CS | CONST_PERSISTENT);
844 #endif
845 	REGISTER_LONG_CONSTANT("MSG_PEEK",		MSG_PEEK,		CONST_CS | CONST_PERSISTENT);
846 	REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE,	CONST_CS | CONST_PERSISTENT);
847 #ifdef MSG_EOR
848 	REGISTER_LONG_CONSTANT("MSG_EOR",		MSG_EOR,		CONST_CS | CONST_PERSISTENT);
849 #endif
850 #ifdef MSG_EOF
851 	REGISTER_LONG_CONSTANT("MSG_EOF",		MSG_EOF,		CONST_CS | CONST_PERSISTENT);
852 #endif
853 	REGISTER_LONG_CONSTANT("SO_DEBUG",		SO_DEBUG,		CONST_CS | CONST_PERSISTENT);
854 	REGISTER_LONG_CONSTANT("SO_REUSEADDR",	SO_REUSEADDR,	CONST_CS | CONST_PERSISTENT);
855 #ifdef SO_REUSEPORT
856 	REGISTER_LONG_CONSTANT("SO_REUSEPORT",	SO_REUSEPORT,	CONST_CS | CONST_PERSISTENT);
857 #endif
858 	REGISTER_LONG_CONSTANT("SO_KEEPALIVE",	SO_KEEPALIVE,	CONST_CS | CONST_PERSISTENT);
859 	REGISTER_LONG_CONSTANT("SO_DONTROUTE",	SO_DONTROUTE,	CONST_CS | CONST_PERSISTENT);
860 	REGISTER_LONG_CONSTANT("SO_LINGER",		SO_LINGER,		CONST_CS | CONST_PERSISTENT);
861 	REGISTER_LONG_CONSTANT("SO_BROADCAST",	SO_BROADCAST,	CONST_CS | CONST_PERSISTENT);
862 	REGISTER_LONG_CONSTANT("SO_OOBINLINE",	SO_OOBINLINE,	CONST_CS | CONST_PERSISTENT);
863 	REGISTER_LONG_CONSTANT("SO_SNDBUF",		SO_SNDBUF,		CONST_CS | CONST_PERSISTENT);
864 	REGISTER_LONG_CONSTANT("SO_RCVBUF",		SO_RCVBUF,		CONST_CS | CONST_PERSISTENT);
865 	REGISTER_LONG_CONSTANT("SO_SNDLOWAT",	SO_SNDLOWAT,	CONST_CS | CONST_PERSISTENT);
866 	REGISTER_LONG_CONSTANT("SO_RCVLOWAT",	SO_RCVLOWAT,	CONST_CS | CONST_PERSISTENT);
867 	REGISTER_LONG_CONSTANT("SO_SNDTIMEO",	SO_SNDTIMEO,	CONST_CS | CONST_PERSISTENT);
868 	REGISTER_LONG_CONSTANT("SO_RCVTIMEO",	SO_RCVTIMEO,	CONST_CS | CONST_PERSISTENT);
869 	REGISTER_LONG_CONSTANT("SO_TYPE",		SO_TYPE,		CONST_CS | CONST_PERSISTENT);
870 	REGISTER_LONG_CONSTANT("SO_ERROR",		SO_ERROR,		CONST_CS | CONST_PERSISTENT);
871 #ifdef SO_BINDTODEVICE
872 	REGISTER_LONG_CONSTANT("SO_BINDTODEVICE",       SO_BINDTODEVICE,        CONST_CS | CONST_PERSISTENT);
873 #endif
874 	REGISTER_LONG_CONSTANT("SOL_SOCKET",	SOL_SOCKET,		CONST_CS | CONST_PERSISTENT);
875 	REGISTER_LONG_CONSTANT("SOMAXCONN",		SOMAXCONN,		CONST_CS | CONST_PERSISTENT);
876 #ifdef TCP_NODELAY
877 	REGISTER_LONG_CONSTANT("TCP_NODELAY",   TCP_NODELAY,    CONST_CS | CONST_PERSISTENT);
878 #endif
879 	REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
880 	REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
881 
882 #ifndef RFC3678_API
883 #define MCAST_JOIN_GROUP			IP_ADD_MEMBERSHIP
884 #define MCAST_LEAVE_GROUP			IP_DROP_MEMBERSHIP
885 #ifdef HAS_MCAST_EXT
886 #define MCAST_BLOCK_SOURCE			IP_BLOCK_SOURCE
887 #define MCAST_UNBLOCK_SOURCE		IP_UNBLOCK_SOURCE
888 #define MCAST_JOIN_SOURCE_GROUP		IP_ADD_SOURCE_MEMBERSHIP
889 #define MCAST_LEAVE_SOURCE_GROUP	IP_DROP_SOURCE_MEMBERSHIP
890 #endif
891 #endif
892 
893 	REGISTER_LONG_CONSTANT("MCAST_JOIN_GROUP",			MCAST_JOIN_GROUP,			CONST_CS | CONST_PERSISTENT);
894 	REGISTER_LONG_CONSTANT("MCAST_LEAVE_GROUP",			MCAST_LEAVE_GROUP,			CONST_CS | CONST_PERSISTENT);
895 #ifdef HAS_MCAST_EXT
896 	REGISTER_LONG_CONSTANT("MCAST_BLOCK_SOURCE",		MCAST_BLOCK_SOURCE,			CONST_CS | CONST_PERSISTENT);
897 	REGISTER_LONG_CONSTANT("MCAST_UNBLOCK_SOURCE",		MCAST_UNBLOCK_SOURCE,		CONST_CS | CONST_PERSISTENT);
898 	REGISTER_LONG_CONSTANT("MCAST_JOIN_SOURCE_GROUP",	MCAST_JOIN_SOURCE_GROUP,	CONST_CS | CONST_PERSISTENT);
899 	REGISTER_LONG_CONSTANT("MCAST_LEAVE_SOURCE_GROUP",	MCAST_LEAVE_SOURCE_GROUP,	CONST_CS | CONST_PERSISTENT);
900 #endif
901 
902 	REGISTER_LONG_CONSTANT("IP_MULTICAST_IF",			IP_MULTICAST_IF,		CONST_CS | CONST_PERSISTENT);
903 	REGISTER_LONG_CONSTANT("IP_MULTICAST_TTL",			IP_MULTICAST_TTL,		CONST_CS | CONST_PERSISTENT);
904 	REGISTER_LONG_CONSTANT("IP_MULTICAST_LOOP",			IP_MULTICAST_LOOP,		CONST_CS | CONST_PERSISTENT);
905 #if HAVE_IPV6
906 	REGISTER_LONG_CONSTANT("IPV6_MULTICAST_IF",			IPV6_MULTICAST_IF,		CONST_CS | CONST_PERSISTENT);
907 	REGISTER_LONG_CONSTANT("IPV6_MULTICAST_HOPS",		IPV6_MULTICAST_HOPS,	CONST_CS | CONST_PERSISTENT);
908 	REGISTER_LONG_CONSTANT("IPV6_MULTICAST_LOOP",		IPV6_MULTICAST_LOOP,	CONST_CS | CONST_PERSISTENT);
909 #endif
910 
911 #ifndef WIN32
912 # include "unix_socket_constants.h"
913 #else
914 # include "win32_socket_constants.h"
915 #endif
916 
917 	REGISTER_LONG_CONSTANT("IPPROTO_IP",	IPPROTO_IP,		CONST_CS | CONST_PERSISTENT);
918 #if HAVE_IPV6
919 	REGISTER_LONG_CONSTANT("IPPROTO_IPV6",	IPPROTO_IPV6,	CONST_CS | CONST_PERSISTENT);
920 #endif
921 
922 	REGISTER_LONG_CONSTANT("SOL_TCP",		IPPROTO_TCP,	CONST_CS | CONST_PERSISTENT);
923 	REGISTER_LONG_CONSTANT("SOL_UDP",		IPPROTO_UDP,	CONST_CS | CONST_PERSISTENT);
924 
925 	return SUCCESS;
926 }
927 /* }}} */
928 
929 /* {{{ PHP_MINFO_FUNCTION
930  */
931 PHP_MINFO_FUNCTION(sockets)
932 {
933 	php_info_print_table_start();
934 	php_info_print_table_row(2, "Sockets Support", "enabled");
935 	php_info_print_table_end();
936 }
937 /* }}} */
938 
939 /* {{{ PHP_RSHUTDOWN_FUNCTION */
940 PHP_RSHUTDOWN_FUNCTION(sockets)
941 {
942 	if (SOCKETS_G(strerror_buf)) {
943 		efree(SOCKETS_G(strerror_buf));
944 		SOCKETS_G(strerror_buf) = NULL;
945 	}
946 
947 	return SUCCESS;
948 }
949 /* }}} */
950 
951 static int php_sock_array_to_fd_set(zval *sock_array, fd_set *fds, PHP_SOCKET *max_fd TSRMLS_DC) /* {{{ */
952 {
953 	zval		**element;
954 	php_socket	*php_sock;
955 	int			num = 0;
956 
957 	if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
958 
959 	for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
960 		 zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
961 		 zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
962 
963 		php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
964 		if (!php_sock) continue; /* If element is not a resource, skip it */
965 
966 		PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
967 		if (php_sock->bsd_socket > *max_fd) {
968 			*max_fd = php_sock->bsd_socket;
969 		}
970 		num++;
971 	}
972 
973 	return num ? 1 : 0;
974 }
975 /* }}} */
976 
977 static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds TSRMLS_DC) /* {{{ */
978 {
979 	zval		**element;
980 	zval		**dest_element;
981 	php_socket	*php_sock;
982 	HashTable	*new_hash;
983 	char 		*key;
984 	int			num = 0;
985 	ulong       num_key;
986 	uint 		key_len;
987 
988 	if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
989 
990 	ALLOC_HASHTABLE(new_hash);
991 	zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(sock_array)), NULL, ZVAL_PTR_DTOR, 0);
992 	for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
993 		 zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
994 		 zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
995 
996 		php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
997 		if (!php_sock) continue; /* If element is not a resource, skip it */
998 
999 		if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
1000 			/* Add fd to new array */
1001 			switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(sock_array), &key, &key_len, &num_key, 0, NULL)) {
1002 				case HASH_KEY_IS_STRING:
1003 					zend_hash_add(new_hash, key, key_len, (void *)element, sizeof(zval *), (void **)&dest_element);
1004 					break;
1005 				case HASH_KEY_IS_LONG:
1006 					zend_hash_index_update(new_hash, num_key, (void *)element, sizeof(zval *), (void **)&dest_element);
1007 					break;
1008 			}
1009 			if (dest_element) zval_add_ref(dest_element);
1010 		}
1011 		num++;
1012 	}
1013 
1014 	/* Destroy old array, add new one */
1015 	zend_hash_destroy(Z_ARRVAL_P(sock_array));
1016 	efree(Z_ARRVAL_P(sock_array));
1017 
1018 	zend_hash_internal_pointer_reset(new_hash);
1019 	Z_ARRVAL_P(sock_array) = new_hash;
1020 
1021 	return num ? 1 : 0;
1022 }
1023 /* }}} */
1024 
1025 /* {{{ proto int socket_select(array &read_fds, array &write_fds, array &except_fds, int tv_sec[, int tv_usec]) U
1026    Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec */
1027 PHP_FUNCTION(socket_select)
1028 {
1029 	zval			*r_array, *w_array, *e_array, *sec;
1030 	struct timeval	tv;
1031 	struct timeval *tv_p = NULL;
1032 	fd_set			rfds, wfds, efds;
1033 	PHP_SOCKET		max_fd = 0;
1034 	int				retval, sets = 0;
1035 	long			usec = 0;
1036 
1037 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE) {
1038 		return;
1039 	}
1040 
1041 	FD_ZERO(&rfds);
1042 	FD_ZERO(&wfds);
1043 	FD_ZERO(&efds);
1044 
1045 	if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
1046 	if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
1047 	if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
1048 
1049 	if (!sets) {
1050 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "no resource arrays were passed to select");
1051 		RETURN_FALSE;
1052 	}
1053 
1054 	PHP_SAFE_MAX_FD(max_fd, 0); /* someone needs to make this look more like stream_socket_select */
1055 
1056 	/* If seconds is not set to null, build the timeval, else we wait indefinitely */
1057 	if (sec != NULL) {
1058 		zval tmp;
1059 
1060 		if (Z_TYPE_P(sec) != IS_LONG) {
1061 			tmp = *sec;
1062 			zval_copy_ctor(&tmp);
1063 			convert_to_long(&tmp);
1064 			sec = &tmp;
1065 		}
1066 
1067 		/* Solaris + BSD do not like microsecond values which are >= 1 sec */
1068 		if (usec > 999999) {
1069 			tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000);
1070 			tv.tv_usec = usec % 1000000;
1071 		} else {
1072 			tv.tv_sec = Z_LVAL_P(sec);
1073 			tv.tv_usec = usec;
1074 		}
1075 
1076 		tv_p = &tv;
1077 
1078 		if (sec == &tmp) {
1079 			zval_dtor(&tmp);
1080 		}
1081 	}
1082 
1083 	retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p);
1084 
1085 	if (retval == -1) {
1086 		SOCKETS_G(last_error) = errno;
1087 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
1088 		RETURN_FALSE;
1089 	}
1090 
1091 	if (r_array != NULL) php_sock_array_from_fd_set(r_array, &rfds TSRMLS_CC);
1092 	if (w_array != NULL) php_sock_array_from_fd_set(w_array, &wfds TSRMLS_CC);
1093 	if (e_array != NULL) php_sock_array_from_fd_set(e_array, &efds TSRMLS_CC);
1094 
1095 	RETURN_LONG(retval);
1096 }
1097 /* }}} */
1098 
1099 /* {{{ proto resource socket_create_listen(int port[, int backlog]) U
1100    Opens a socket on port to accept connections */
1101 PHP_FUNCTION(socket_create_listen)
1102 {
1103 	php_socket	*php_sock;
1104 	long		port, backlog = 128;
1105 
1106 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &port, &backlog) == FAILURE) {
1107 		return;
1108 	}
1109 
1110 	if (!php_open_listen_sock(&php_sock, port, backlog TSRMLS_CC)) {
1111 		RETURN_FALSE;
1112 	}
1113 
1114 	php_sock->error = 0;
1115 	php_sock->blocking = 1;
1116 
1117 	ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);
1118 }
1119 /* }}} */
1120 
1121 /* {{{ proto resource socket_accept(resource socket) U
1122    Accepts a connection on the listening socket fd */
1123 PHP_FUNCTION(socket_accept)
1124 {
1125 	zval				 *arg1;
1126 	php_socket			 *php_sock, *new_sock;
1127 	php_sockaddr_storage sa;
1128 	socklen_t			 php_sa_len = sizeof(sa);
1129 
1130 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
1131 		return;
1132 	}
1133 
1134 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1135 
1136 	if (!php_accept_connect(php_sock, &new_sock, (struct sockaddr*)&sa, &php_sa_len TSRMLS_CC)) {
1137 		RETURN_FALSE;
1138 	}
1139 
1140 	ZEND_REGISTER_RESOURCE(return_value, new_sock, le_socket);
1141 }
1142 /* }}} */
1143 
1144 /* {{{ proto bool socket_set_nonblock(resource socket) U
1145    Sets nonblocking mode on a socket resource */
1146 PHP_FUNCTION(socket_set_nonblock)
1147 {
1148 	zval		*arg1;
1149 	php_socket	*php_sock;
1150 
1151 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
1152 		return;
1153 	}
1154 
1155 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1156 
1157 	if (php_sock->zstream != NULL) {
1158 		php_stream *stream;
1159 		/* omit notice if resource doesn't exist anymore */
1160 		stream = zend_fetch_resource(&php_sock->zstream TSRMLS_CC, -1,
1161 			NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
1162 		if (stream != NULL) {
1163 			if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 0,
1164 					NULL) != -1) {
1165 				php_sock->blocking = 0;
1166 				RETURN_TRUE;
1167 			}
1168 		}
1169 	}
1170 
1171 	if (php_set_sock_blocking(php_sock->bsd_socket, 0 TSRMLS_CC) == SUCCESS) {
1172 		php_sock->blocking = 0;
1173 		RETURN_TRUE;
1174 	} else {
1175 		PHP_SOCKET_ERROR(php_sock, "unable to set nonblocking mode", errno);
1176 		RETURN_FALSE;
1177 	}
1178 }
1179 /* }}} */
1180 
1181 /* {{{ proto bool socket_set_block(resource socket) U
1182    Sets blocking mode on a socket resource */
1183 PHP_FUNCTION(socket_set_block)
1184 {
1185 	zval		*arg1;
1186 	php_socket	*php_sock;
1187 
1188 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
1189 		return;
1190 	}
1191 
1192 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1193 
1194 	/* if socket was created from a stream, give the stream a chance to take
1195 	 * care of the operation itself, thereby allowing it to update its internal
1196 	 * state */
1197 	if (php_sock->zstream != NULL) {
1198 		php_stream *stream;
1199 		stream = zend_fetch_resource(&php_sock->zstream TSRMLS_CC, -1,
1200 			NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream());
1201 		if (stream != NULL) {
1202 			if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 1,
1203 					NULL) != -1) {
1204 				php_sock->blocking = 1;
1205 				RETURN_TRUE;
1206 			}
1207 		}
1208 	}
1209 
1210 	if (php_set_sock_blocking(php_sock->bsd_socket, 1 TSRMLS_CC) == SUCCESS) {
1211 		php_sock->blocking = 1;
1212 		RETURN_TRUE;
1213 	} else {
1214 		PHP_SOCKET_ERROR(php_sock, "unable to set blocking mode", errno);
1215 		RETURN_FALSE;
1216 	}
1217 }
1218 /* }}} */
1219 
1220 /* {{{ proto bool socket_listen(resource socket[, int backlog]) U
1221    Sets the maximum number of connections allowed to be waited for on the socket specified by fd */
1222 PHP_FUNCTION(socket_listen)
1223 {
1224 	zval		*arg1;
1225 	php_socket	*php_sock;
1226 	long		backlog = 0;
1227 
1228 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &backlog) == FAILURE) {
1229 		return;
1230 	}
1231 
1232 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1233 
1234 	if (listen(php_sock->bsd_socket, backlog) != 0) {
1235 		PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno);
1236 		RETURN_FALSE;
1237 	}
1238 	RETURN_TRUE;
1239 }
1240 /* }}} */
1241 
1242 /* {{{ proto void socket_close(resource socket) U
1243    Closes a file descriptor */
1244 PHP_FUNCTION(socket_close)
1245 {
1246 	zval		*arg1;
1247 	php_socket	*php_sock;
1248 
1249 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
1250 		return;
1251 	}
1252 
1253 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1254 	if (php_sock->zstream != NULL) {
1255 		php_stream *stream = NULL;
1256 		php_stream_from_zval_no_verify(stream, &php_sock->zstream);
1257 		if (stream != NULL) {
1258 			/* close & destroy stream, incl. removing it from the rsrc list;
1259 			 * resource stored in php_sock->zstream will become invalid */
1260 			php_stream_free(stream, PHP_STREAM_FREE_CLOSE |
1261 					(stream->is_persistent?PHP_STREAM_FREE_CLOSE_PERSISTENT:0));
1262 		}
1263 	}
1264 	zend_list_delete(Z_RESVAL_P(arg1));
1265 }
1266 /* }}} */
1267 
1268 /* {{{ proto int socket_write(resource socket, string buf[, int length])
1269    Writes the buffer to the socket resource, length is optional */
1270 PHP_FUNCTION(socket_write)
1271 {
1272 	zval		*arg1;
1273 	php_socket	*php_sock;
1274 	int			retval, str_len;
1275 	long		length = 0;
1276 	char		*str;
1277 
1278 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &str, &str_len, &length) == FAILURE) {
1279 		return;
1280 	}
1281 
1282 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1283 
1284 	if (ZEND_NUM_ARGS() < 3) {
1285 		length = str_len;
1286 	}
1287 
1288 #ifndef PHP_WIN32
1289 	retval = write(php_sock->bsd_socket, str, MIN(length, str_len));
1290 #else
1291 	retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);
1292 #endif
1293 
1294 	if (retval < 0) {
1295 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1296 		RETURN_FALSE;
1297 	}
1298 
1299 	RETURN_LONG(retval);
1300 }
1301 /* }}} */
1302 
1303 /* {{{ proto string socket_read(resource socket, int length [, int type]) U
1304    Reads a maximum of length bytes from socket */
1305 PHP_FUNCTION(socket_read)
1306 {
1307 	zval		*arg1;
1308 	php_socket	*php_sock;
1309 	char		*tmpbuf;
1310 	int			retval;
1311 	long		length, type = PHP_BINARY_READ;
1312 
1313 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|l", &arg1, &length, &type) == FAILURE) {
1314 		return;
1315 	}
1316 
1317 	/* overflow check */
1318 	if ((length + 1) < 2) {
1319 		RETURN_FALSE;
1320 	}
1321 
1322 	tmpbuf = emalloc(length + 1);
1323 
1324 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1325 
1326 	if (type == PHP_NORMAL_READ) {
1327 		retval = php_read(php_sock, tmpbuf, length, 0);
1328 	} else {
1329 		retval = recv(php_sock->bsd_socket, tmpbuf, length, 0);
1330 	}
1331 
1332 	if (retval == -1) {
1333 		/* if the socket is in non-blocking mode and there's no data to read,
1334 		don't output any error, as this is a normal situation, and not an error */
1335 		if (errno == EAGAIN
1336 #ifdef EWOULDBLOCK
1337 		|| errno == EWOULDBLOCK
1338 #endif
1339 		) {
1340 			php_sock->error = errno;
1341 			SOCKETS_G(last_error) = errno;
1342 		} else {
1343 			PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1344 		}
1345 
1346 		efree(tmpbuf);
1347 		RETURN_FALSE;
1348 	} else if (!retval) {
1349 		efree(tmpbuf);
1350 		RETURN_EMPTY_STRING();
1351 	}
1352 
1353 	tmpbuf = erealloc(tmpbuf, retval + 1);
1354 	tmpbuf[retval] = '\0' ;
1355 
1356 	RETURN_STRINGL(tmpbuf, retval, 0);
1357 }
1358 /* }}} */
1359 
1360 /* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port])
1361    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. */
1362 PHP_FUNCTION(socket_getsockname)
1363 {
1364 	zval					*arg1, *addr, *port = NULL;
1365 	php_sockaddr_storage	sa_storage;
1366 	php_socket				*php_sock;
1367 	struct sockaddr			*sa;
1368 	struct sockaddr_in		*sin;
1369 #if HAVE_IPV6
1370 	struct sockaddr_in6		*sin6;
1371 	char					addr6[INET6_ADDRSTRLEN+1];
1372 #endif
1373 	struct sockaddr_un		*s_un;
1374 	char					*addr_string;
1375 	socklen_t				salen = sizeof(php_sockaddr_storage);
1376 
1377 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &addr, &port) == FAILURE) {
1378 		return;
1379 	}
1380 
1381 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1382 
1383 	sa = (struct sockaddr *) &sa_storage;
1384 
1385 	if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
1386 		PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
1387 		RETURN_FALSE;
1388 	}
1389 
1390 	switch (sa->sa_family) {
1391 #if HAVE_IPV6
1392 		case AF_INET6:
1393 			sin6 = (struct sockaddr_in6 *) sa;
1394 			inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1395 			zval_dtor(addr);
1396 			ZVAL_STRING(addr, addr6, 1);
1397 
1398 			if (port != NULL) {
1399 				zval_dtor(port);
1400 				ZVAL_LONG(port, htons(sin6->sin6_port));
1401 			}
1402 			RETURN_TRUE;
1403 			break;
1404 #endif
1405 		case AF_INET:
1406 			sin = (struct sockaddr_in *) sa;
1407 			while (inet_ntoa_lock == 1);
1408 			inet_ntoa_lock = 1;
1409 			addr_string = inet_ntoa(sin->sin_addr);
1410 			inet_ntoa_lock = 0;
1411 
1412 			zval_dtor(addr);
1413 			ZVAL_STRING(addr, addr_string, 1);
1414 
1415 			if (port != NULL) {
1416 				zval_dtor(port);
1417 				ZVAL_LONG(port, htons(sin->sin_port));
1418 			}
1419 			RETURN_TRUE;
1420 			break;
1421 
1422 		case AF_UNIX:
1423 			s_un = (struct sockaddr_un *) sa;
1424 
1425 			zval_dtor(addr);
1426 			ZVAL_STRING(addr, s_un->sun_path, 1);
1427 			RETURN_TRUE;
1428 			break;
1429 
1430 		default:
1431 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
1432 			RETURN_FALSE;
1433 	}
1434 }
1435 /* }}} */
1436 
1437 /* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port])
1438    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. */
1439 PHP_FUNCTION(socket_getpeername)
1440 {
1441 	zval					*arg1, *arg2, *arg3 = NULL;
1442 	php_sockaddr_storage	sa_storage;
1443 	php_socket				*php_sock;
1444 	struct sockaddr			*sa;
1445 	struct sockaddr_in		*sin;
1446 #if HAVE_IPV6
1447 	struct sockaddr_in6		*sin6;
1448 	char					addr6[INET6_ADDRSTRLEN+1];
1449 #endif
1450 	struct sockaddr_un		*s_un;
1451 	char					*addr_string;
1452 	socklen_t				salen = sizeof(php_sockaddr_storage);
1453 
1454 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &arg2, &arg3) == FAILURE) {
1455 		return;
1456 	}
1457 
1458 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1459 
1460 	sa = (struct sockaddr *) &sa_storage;
1461 
1462 	if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
1463 		PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
1464 		RETURN_FALSE;
1465 	}
1466 
1467 	switch (sa->sa_family) {
1468 #if HAVE_IPV6
1469 		case AF_INET6:
1470 			sin6 = (struct sockaddr_in6 *) sa;
1471 			inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1472 			zval_dtor(arg2);
1473 			ZVAL_STRING(arg2, addr6, 1);
1474 
1475 			if (arg3 != NULL) {
1476 				zval_dtor(arg3);
1477 				ZVAL_LONG(arg3, htons(sin6->sin6_port));
1478 			}
1479 
1480 			RETURN_TRUE;
1481 			break;
1482 #endif
1483 		case AF_INET:
1484 			sin = (struct sockaddr_in *) sa;
1485 			while (inet_ntoa_lock == 1);
1486 			inet_ntoa_lock = 1;
1487 			addr_string = inet_ntoa(sin->sin_addr);
1488 			inet_ntoa_lock = 0;
1489 
1490 			zval_dtor(arg2);
1491 			ZVAL_STRING(arg2, addr_string, 1);
1492 
1493 			if (arg3 != NULL) {
1494 				zval_dtor(arg3);
1495 				ZVAL_LONG(arg3, htons(sin->sin_port));
1496 			}
1497 
1498 			RETURN_TRUE;
1499 			break;
1500 
1501 		case AF_UNIX:
1502 			s_un = (struct sockaddr_un *) sa;
1503 
1504 			zval_dtor(arg2);
1505 			ZVAL_STRING(arg2, s_un->sun_path, 1);
1506 			RETURN_TRUE;
1507 			break;
1508 
1509 		default:
1510 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
1511 			RETURN_FALSE;
1512 	}
1513 }
1514 /* }}} */
1515 
1516 /* {{{ proto resource socket_create(int domain, int type, int protocol) U
1517    Creates an endpoint for communication in the domain specified by domain, of type specified by type */
1518 PHP_FUNCTION(socket_create)
1519 {
1520 	long		arg1, arg2, arg3;
1521 	php_socket	*php_sock = php_create_socket();
1522 
1523 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {
1524 		efree(php_sock);
1525 		return;
1526 	}
1527 
1528 	if (arg1 != AF_UNIX
1529 #if HAVE_IPV6
1530 		&& arg1 != AF_INET6
1531 #endif
1532 		&& arg1 != AF_INET) {
1533 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", arg1);
1534 		arg1 = AF_INET;
1535 	}
1536 
1537 	if (arg2 > 10) {
1538 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", arg2);
1539 		arg2 = SOCK_STREAM;
1540 	}
1541 
1542 	php_sock->bsd_socket = socket(arg1, arg2, arg3);
1543 	php_sock->type = arg1;
1544 
1545 	if (IS_INVALID_SOCKET(php_sock)) {
1546 		SOCKETS_G(last_error) = errno;
1547 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
1548 		efree(php_sock);
1549 		RETURN_FALSE;
1550 	}
1551 
1552 	php_sock->error = 0;
1553 	php_sock->blocking = 1;
1554 
1555 	ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);
1556 }
1557 /* }}} */
1558 
1559 /* {{{ proto bool socket_connect(resource socket, string addr [, int port])
1560    Opens a connection to addr:port on the socket specified by socket */
1561 PHP_FUNCTION(socket_connect)
1562 {
1563 	zval				*arg1;
1564 	php_socket			*php_sock;
1565 	char				*addr;
1566 	int					retval, addr_len;
1567 	long				port = 0;
1568 	int					argc = ZEND_NUM_ARGS();
1569 
1570 	if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1571 		return;
1572 	}
1573 
1574 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1575 
1576 	switch(php_sock->type) {
1577 #if HAVE_IPV6
1578 		case AF_INET6: {
1579 			struct sockaddr_in6 sin6 = {0};
1580 
1581 			if (argc != 3) {
1582 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
1583 				RETURN_FALSE;
1584 			}
1585 
1586 			memset(&sin6, 0, sizeof(struct sockaddr_in6));
1587 
1588 			sin6.sin6_family = AF_INET6;
1589 			sin6.sin6_port   = htons((unsigned short int)port);
1590 
1591 			if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
1592 				RETURN_FALSE;
1593 			}
1594 
1595 			retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
1596 			break;
1597 		}
1598 #endif
1599 		case AF_INET: {
1600 			struct sockaddr_in sin = {0};
1601 
1602 			if (argc != 3) {
1603 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");
1604 				RETURN_FALSE;
1605 			}
1606 
1607 			sin.sin_family = AF_INET;
1608 			sin.sin_port   = htons((unsigned short int)port);
1609 
1610 			if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
1611 				RETURN_FALSE;
1612 			}
1613 
1614 			retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
1615 			break;
1616 		}
1617 
1618 		case AF_UNIX: {
1619 			struct sockaddr_un s_un = {0};
1620 
1621 			if (addr_len >= sizeof(s_un.sun_path)) {
1622 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long");
1623 				RETURN_FALSE;
1624 			}
1625 
1626 			s_un.sun_family = AF_UNIX;
1627 			memcpy(&s_un.sun_path, addr, addr_len);
1628 			retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
1629 				(socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
1630 			break;
1631 		}
1632 
1633 		default:
1634 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1635 			RETURN_FALSE;
1636 		}
1637 
1638 	if (retval != 0) {
1639 		PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
1640 		RETURN_FALSE;
1641 	}
1642 
1643 	RETURN_TRUE;
1644 }
1645 /* }}} */
1646 
1647 /* {{{ proto string socket_strerror(int errno)
1648    Returns a string describing an error */
1649 PHP_FUNCTION(socket_strerror)
1650 {
1651 	long	arg1;
1652 
1653 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg1) == FAILURE) {
1654 		return;
1655 	}
1656 
1657 	RETURN_STRING(php_strerror(arg1 TSRMLS_CC), 1);
1658 }
1659 /* }}} */
1660 
1661 /* {{{ proto bool socket_bind(resource socket, string addr [, int port])
1662    Binds an open socket to a listening port, port is only specified in AF_INET family. */
1663 PHP_FUNCTION(socket_bind)
1664 {
1665 	zval					*arg1;
1666 	php_sockaddr_storage	sa_storage;
1667 	struct sockaddr			*sock_type = (struct sockaddr*) &sa_storage;
1668 	php_socket				*php_sock;
1669 	char					*addr;
1670 	int						addr_len;
1671 	long					port = 0;
1672 	long					retval = 0;
1673 
1674 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1675 		return;
1676 	}
1677 
1678 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1679 
1680 	switch(php_sock->type) {
1681 		case AF_UNIX:
1682 			{
1683 				struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
1684 				memset(sa, 0, sizeof(sa_storage));
1685 				sa->sun_family = AF_UNIX;
1686 				snprintf(sa->sun_path, 108, "%s", addr);
1687 				retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa, SUN_LEN(sa));
1688 				break;
1689 			}
1690 
1691 		case AF_INET:
1692 			{
1693 				struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
1694 
1695 				memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
1696 
1697 				sa->sin_family = AF_INET;
1698 				sa->sin_port = htons((unsigned short) port);
1699 
1700 				if (! php_set_inet_addr(sa, addr, php_sock TSRMLS_CC)) {
1701 					RETURN_FALSE;
1702 				}
1703 
1704 				retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
1705 				break;
1706 			}
1707 #if HAVE_IPV6
1708 		case AF_INET6:
1709 			{
1710 				struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
1711 
1712 				memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
1713 
1714 				sa->sin6_family = AF_INET6;
1715 				sa->sin6_port = htons((unsigned short) port);
1716 
1717 				if (! php_set_inet6_addr(sa, addr, php_sock TSRMLS_CC)) {
1718 					RETURN_FALSE;
1719 				}
1720 
1721 				retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
1722 				break;
1723 			}
1724 #endif
1725 		default:
1726 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
1727 			RETURN_FALSE;
1728 	}
1729 
1730 	if (retval != 0) {
1731 		PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
1732 		RETURN_FALSE;
1733 	}
1734 
1735 	RETURN_TRUE;
1736 }
1737 /* }}} */
1738 
1739 /* {{{ proto int socket_recv(resource socket, string &buf, int len, int flags)
1740    Receives data from a connected socket */
1741 PHP_FUNCTION(socket_recv)
1742 {
1743 	zval		*php_sock_res, *buf;
1744 	char		*recv_buf;
1745 	php_socket	*php_sock;
1746 	int			retval;
1747 	long		len, flags;
1748 
1749 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
1750 		return;
1751 	}
1752 
1753 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &php_sock_res, -1, le_socket_name, le_socket);
1754 
1755 	/* overflow check */
1756 	if ((len + 1) < 2) {
1757 		RETURN_FALSE;
1758 	}
1759 
1760 	recv_buf = emalloc(len + 1);
1761 	memset(recv_buf, 0, len + 1);
1762 
1763 	if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {
1764 		efree(recv_buf);
1765 
1766 		zval_dtor(buf);
1767 		Z_TYPE_P(buf) = IS_NULL;
1768 	} else {
1769 		recv_buf[retval] = '\0';
1770 
1771 		/* Rebuild buffer zval */
1772 		zval_dtor(buf);
1773 
1774 		Z_STRVAL_P(buf) = recv_buf;
1775 		Z_STRLEN_P(buf) = retval;
1776 		Z_TYPE_P(buf) = IS_STRING;
1777 	}
1778 
1779 	if (retval == -1) {
1780 		PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1781 		RETURN_FALSE;
1782 	}
1783 
1784 	RETURN_LONG(retval);
1785 }
1786 /* }}} */
1787 
1788 /* {{{ proto int socket_send(resource socket, string buf, int len, int flags)
1789    Sends data to a connected socket */
1790 PHP_FUNCTION(socket_send)
1791 {
1792 	zval		*arg1;
1793 	php_socket	*php_sock;
1794 	int			buf_len, retval;
1795 	long		len, flags;
1796 	char		*buf;
1797 
1798 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
1799 		return;
1800 	}
1801 
1802 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1803 
1804 	retval = send(php_sock->bsd_socket, buf, (buf_len < len ? buf_len : len), flags);
1805 
1806 	if (retval == -1) {
1807 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1808 		RETURN_FALSE;
1809 	}
1810 
1811 	RETURN_LONG(retval);
1812 }
1813 /* }}} */
1814 
1815 /* {{{ proto int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port])
1816    Receives data from a socket, connected or not */
1817 PHP_FUNCTION(socket_recvfrom)
1818 {
1819 	zval				*arg1, *arg2, *arg5, *arg6 = NULL;
1820 	php_socket			*php_sock;
1821 	struct sockaddr_un	s_un;
1822 	struct sockaddr_in	sin;
1823 #if HAVE_IPV6
1824 	struct sockaddr_in6	sin6;
1825 	char				addr6[INET6_ADDRSTRLEN];
1826 #endif
1827 	socklen_t			slen;
1828 	int					retval;
1829 	long				arg3, arg4;
1830 	char				*recv_buf, *address;
1831 
1832 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzllz|z", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
1833 		return;
1834 	}
1835 
1836 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1837 
1838 	/* overflow check */
1839 	if ((arg3 + 2) < 3) {
1840 		RETURN_FALSE;
1841 	}
1842 
1843 	recv_buf = emalloc(arg3 + 2);
1844 	memset(recv_buf, 0, arg3 + 2);
1845 
1846 	switch (php_sock->type) {
1847 		case AF_UNIX:
1848 			slen = sizeof(s_un);
1849 			s_un.sun_family = AF_UNIX;
1850 			retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
1851 
1852 			if (retval < 0) {
1853 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1854 				efree(recv_buf);
1855 				RETURN_FALSE;
1856 			}
1857 
1858 			zval_dtor(arg2);
1859 			zval_dtor(arg5);
1860 
1861 			ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1862 			ZVAL_STRING(arg5, s_un.sun_path, 1);
1863 			break;
1864 
1865 		case AF_INET:
1866 			slen = sizeof(sin);
1867 			memset(&sin, 0, slen);
1868 			sin.sin_family = AF_INET;
1869 
1870 			if (arg6 == NULL) {
1871 				efree(recv_buf);
1872 				WRONG_PARAM_COUNT;
1873 			}
1874 
1875 			retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
1876 
1877 			if (retval < 0) {
1878 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1879 				efree(recv_buf);
1880 				RETURN_FALSE;
1881 			}
1882 
1883 			zval_dtor(arg2);
1884 			zval_dtor(arg5);
1885 			zval_dtor(arg6);
1886 
1887 			address = inet_ntoa(sin.sin_addr);
1888 
1889 			ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1890 			ZVAL_STRING(arg5, address ? address : "0.0.0.0", 1);
1891 			ZVAL_LONG(arg6, ntohs(sin.sin_port));
1892 			break;
1893 #if HAVE_IPV6
1894 		case AF_INET6:
1895 			slen = sizeof(sin6);
1896 			memset(&sin6, 0, slen);
1897 			sin6.sin6_family = AF_INET6;
1898 
1899 			if (arg6 == NULL) {
1900 				efree(recv_buf);
1901 				WRONG_PARAM_COUNT;
1902 			}
1903 
1904 			retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
1905 
1906 			if (retval < 0) {
1907 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1908 				efree(recv_buf);
1909 				RETURN_FALSE;
1910 			}
1911 
1912 			zval_dtor(arg2);
1913 			zval_dtor(arg5);
1914 			zval_dtor(arg6);
1915 
1916 			memset(addr6, 0, INET6_ADDRSTRLEN);
1917 			inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
1918 
1919 			ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1920 			ZVAL_STRING(arg5, addr6[0] ? addr6 : "::", 1);
1921 			ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
1922 			break;
1923 #endif
1924 		default:
1925 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1926 			RETURN_FALSE;
1927 	}
1928 
1929 	RETURN_LONG(retval);
1930 }
1931 /* }}} */
1932 
1933 /* {{{ proto int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port])
1934    Sends a message to a socket, whether it is connected or not */
1935 PHP_FUNCTION(socket_sendto)
1936 {
1937 	zval				*arg1;
1938 	php_socket			*php_sock;
1939 	struct sockaddr_un	s_un;
1940 	struct sockaddr_in	sin;
1941 #if HAVE_IPV6
1942 	struct sockaddr_in6	sin6;
1943 #endif
1944 	int					retval, buf_len, addr_len;
1945 	long				len, flags, port = 0;
1946 	char				*buf, *addr;
1947 	int					argc = ZEND_NUM_ARGS();
1948 
1949 	if (zend_parse_parameters(argc TSRMLS_CC, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
1950 		return;
1951 	}
1952 
1953 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1954 
1955 	switch (php_sock->type) {
1956 		case AF_UNIX:
1957 			memset(&s_un, 0, sizeof(s_un));
1958 			s_un.sun_family = AF_UNIX;
1959 			snprintf(s_un.sun_path, 108, "%s", addr);
1960 
1961 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len,	flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
1962 			break;
1963 
1964 		case AF_INET:
1965 			if (argc != 6) {
1966 				WRONG_PARAM_COUNT;
1967 			}
1968 
1969 			memset(&sin, 0, sizeof(sin));
1970 			sin.sin_family = AF_INET;
1971 			sin.sin_port = htons((unsigned short) port);
1972 
1973 			if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
1974 				RETURN_FALSE;
1975 			}
1976 
1977 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin, sizeof(sin));
1978 			break;
1979 #if HAVE_IPV6
1980 		case AF_INET6:
1981 			if (argc != 6) {
1982 				WRONG_PARAM_COUNT;
1983 			}
1984 
1985 			memset(&sin6, 0, sizeof(sin6));
1986 			sin6.sin6_family = AF_INET6;
1987 			sin6.sin6_port = htons((unsigned short) port);
1988 
1989 			if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
1990 				RETURN_FALSE;
1991 			}
1992 
1993 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
1994 			break;
1995 #endif
1996 		default:
1997 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1998 			RETURN_FALSE;
1999 	}
2000 
2001 	if (retval == -1) {
2002 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
2003 		RETURN_FALSE;
2004 	}
2005 
2006 	RETURN_LONG(retval);
2007 }
2008 /* }}} */
2009 
2010 /* {{{ proto mixed socket_get_option(resource socket, int level, int optname) U
2011    Gets socket options for the socket */
2012 PHP_FUNCTION(socket_get_option)
2013 {
2014 	zval			*arg1;
2015 	struct linger	linger_val;
2016 	struct timeval	tv;
2017 #ifdef PHP_WIN32
2018 	int				timeout = 0;
2019 #endif
2020 	socklen_t		optlen;
2021 	php_socket		*php_sock;
2022 	int				other_val;
2023 	long			level, optname;
2024 
2025 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &arg1, &level, &optname) == FAILURE) {
2026 		return;
2027 	}
2028 
2029 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
2030 
2031 	if (level == IPPROTO_IP) {
2032 		switch (optname) {
2033 		case IP_MULTICAST_IF: {
2034 			struct in_addr if_addr;
2035 			unsigned int if_index;
2036 			optlen = sizeof(if_addr);
2037 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&if_addr, &optlen) != 0) {
2038 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2039 				RETURN_FALSE;
2040 			}
2041 			if (php_add4_to_if_index(&if_addr, php_sock, &if_index TSRMLS_CC) == SUCCESS) {
2042 				RETURN_LONG((long) if_index);
2043 			} else {
2044 				RETURN_FALSE;
2045 			}
2046 		}
2047 		}
2048 	}
2049 
2050 	/* sol_socket options and general case */
2051 	switch(optname) {
2052 		case SO_LINGER:
2053 			optlen = sizeof(linger_val);
2054 
2055 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
2056 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2057 				RETURN_FALSE;
2058 			}
2059 
2060 			array_init(return_value);
2061 			add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
2062 			add_assoc_long(return_value, "l_linger", linger_val.l_linger);
2063 			break;
2064 
2065 		case SO_RCVTIMEO:
2066 		case SO_SNDTIMEO:
2067 #ifndef PHP_WIN32
2068 			optlen = sizeof(tv);
2069 
2070 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
2071 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2072 				RETURN_FALSE;
2073 			}
2074 #else
2075 			optlen = sizeof(int);
2076 
2077 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
2078 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2079 				RETURN_FALSE;
2080 			}
2081 
2082 			tv.tv_sec = timeout ? timeout / 1000 : 0;
2083 			tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;
2084 #endif
2085 
2086 			array_init(return_value);
2087 
2088 			add_assoc_long(return_value, "sec", tv.tv_sec);
2089 			add_assoc_long(return_value, "usec", tv.tv_usec);
2090 			break;
2091 
2092 		default:
2093 			optlen = sizeof(other_val);
2094 
2095 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
2096 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2097 				RETURN_FALSE;
2098 			}
2099 			if (optlen == 1)
2100 				other_val = *((unsigned char *)&other_val);
2101 
2102 			RETURN_LONG(other_val);
2103 			break;
2104 	}
2105 }
2106 /* }}} */
2107 
2108 static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval **arg4 TSRMLS_DC)
2109 {
2110 	HashTable		 		*opt_ht;
2111 	unsigned int			if_index;
2112 	int						retval;
2113 	int (*mcast_req_fun)(php_socket *, int, struct sockaddr *, socklen_t,
2114 		unsigned TSRMLS_DC);
2115 #ifdef HAS_MCAST_EXT
2116 	int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t,
2117 		struct sockaddr *, socklen_t, unsigned TSRMLS_DC);
2118 #endif
2119 
2120 	switch (optname) {
2121 	case MCAST_JOIN_GROUP:
2122 		mcast_req_fun = &php_mcast_join;
2123 		goto mcast_req_fun;
2124 	case MCAST_LEAVE_GROUP:
2125 		{
2126 			php_sockaddr_storage	group = {0};
2127 			socklen_t				glen;
2128 
2129 			mcast_req_fun = &php_mcast_leave;
2130 mcast_req_fun:
2131 			convert_to_array_ex(arg4);
2132 			opt_ht = HASH_OF(*arg4);
2133 
2134 			if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
2135 				&glen TSRMLS_CC) == FAILURE) {
2136 					return FAILURE;
2137 			}
2138 			if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
2139 				&if_index TSRMLS_CC) == FAILURE) {
2140 					return FAILURE;
2141 			}
2142 
2143 			retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group,
2144 				glen, if_index TSRMLS_CC);
2145 			break;
2146 		}
2147 
2148 #ifdef HAS_MCAST_EXT
2149 	case MCAST_BLOCK_SOURCE:
2150 		mcast_sreq_fun = &php_mcast_block_source;
2151 		goto mcast_sreq_fun;
2152 	case MCAST_UNBLOCK_SOURCE:
2153 		mcast_sreq_fun = &php_mcast_unblock_source;
2154 		goto mcast_sreq_fun;
2155 	case MCAST_JOIN_SOURCE_GROUP:
2156 		mcast_sreq_fun = &php_mcast_join_source;
2157 		goto mcast_sreq_fun;
2158 	case MCAST_LEAVE_SOURCE_GROUP:
2159 		{
2160 			php_sockaddr_storage	group = {0},
2161 									source = {0};
2162 			socklen_t				glen,
2163 									slen;
2164 
2165 			mcast_sreq_fun = &php_mcast_leave_source;
2166 		mcast_sreq_fun:
2167 			convert_to_array_ex(arg4);
2168 			opt_ht = HASH_OF(*arg4);
2169 
2170 			if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
2171 					&glen TSRMLS_CC) == FAILURE) {
2172 				return FAILURE;
2173 			}
2174 			if (php_get_address_from_array(opt_ht, "source", php_sock, &source,
2175 					&slen TSRMLS_CC) == FAILURE) {
2176 				return FAILURE;
2177 			}
2178 			if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
2179 					&if_index TSRMLS_CC) == FAILURE) {
2180 				return FAILURE;
2181 			}
2182 
2183 			retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group,
2184 					glen, (struct sockaddr*)&source, slen, if_index TSRMLS_CC);
2185 			break;
2186 		}
2187 #endif
2188 	default:
2189 		php_error_docref(NULL TSRMLS_CC, E_WARNING,
2190 			"unexpected option in php_do_mcast_opt (level %d, option %d). "
2191 			"This is a bug.", level, optname);
2192 		return FAILURE;
2193 	}
2194 
2195 	if (retval != 0) {
2196 		if (retval != -2) { /* error, but message already emitted */
2197 			PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
2198 		}
2199 		return FAILURE;
2200 	}
2201 	return SUCCESS;
2202 }
2203 
2204 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
2205    Sets socket options for the socket */
2206 PHP_FUNCTION(socket_set_option)
2207 {
2208 	zval					*arg1, **arg4;
2209 	struct linger			lv;
2210 	php_socket				*php_sock;
2211 	int						ov, optlen, retval;
2212 #ifdef PHP_WIN32
2213 	int						timeout;
2214 #else
2215 	struct					timeval tv;
2216 #endif
2217 	long					level, optname;
2218 	void 					*opt_ptr;
2219 	HashTable		 		*opt_ht;
2220 	zval 					**l_onoff, **l_linger;
2221 	zval		 			**sec, **usec;
2222 
2223 	/* Multicast */
2224 	unsigned int			if_index;
2225 	struct in_addr			if_addr;
2226 	unsigned char			ipv4_mcast_ttl_lback;
2227 
2228 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, &level, &optname, &arg4) == FAILURE) {
2229 		return;
2230 	}
2231 
2232 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
2233 
2234 	set_errno(0);
2235 
2236 	if (level == IPPROTO_IP) {
2237 		switch (optname) {
2238 		case MCAST_JOIN_GROUP:
2239 		case MCAST_LEAVE_GROUP:
2240 #ifdef HAS_MCAST_EXT
2241 		case MCAST_BLOCK_SOURCE:
2242 		case MCAST_UNBLOCK_SOURCE:
2243 		case MCAST_JOIN_SOURCE_GROUP:
2244 		case MCAST_LEAVE_SOURCE_GROUP:
2245 #endif
2246 			if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC) == FAILURE) {
2247 				RETURN_FALSE;
2248 			} else {
2249 				RETURN_TRUE;
2250 			}
2251 
2252 		case IP_MULTICAST_IF:
2253 			if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
2254 				RETURN_FALSE;
2255 			}
2256 
2257 			if (php_if_index_to_addr4(if_index, php_sock, &if_addr TSRMLS_CC) == FAILURE) {
2258 				RETURN_FALSE;
2259 			}
2260 			opt_ptr = &if_addr;
2261 			optlen	= sizeof(if_addr);
2262 			goto dosockopt;
2263 
2264 		case IP_MULTICAST_LOOP:
2265 			convert_to_boolean_ex(arg4);
2266 			goto ipv4_loop_ttl;
2267 		case IP_MULTICAST_TTL:
2268 			convert_to_long_ex(arg4);
2269 			if (Z_LVAL_PP(arg4) < 0L || Z_LVAL_PP(arg4) > 255L) {
2270 				php_error_docref(NULL TSRMLS_CC, E_WARNING,
2271 						"Expected a value between 0 and 255");
2272 				RETURN_FALSE;
2273 			}
2274 ipv4_loop_ttl:
2275 			ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_PP(arg4);
2276 			opt_ptr = &ipv4_mcast_ttl_lback;
2277 			optlen	= sizeof(ipv4_mcast_ttl_lback);
2278 			goto dosockopt;
2279 		}
2280 	}
2281 
2282 #if HAVE_IPV6
2283 	else if (level == IPPROTO_IPV6) {
2284 		switch (optname) {
2285 		case MCAST_JOIN_GROUP:
2286 		case MCAST_LEAVE_GROUP:
2287 #ifdef HAS_MCAST_EXT
2288 		case MCAST_BLOCK_SOURCE:
2289 		case MCAST_UNBLOCK_SOURCE:
2290 		case MCAST_JOIN_SOURCE_GROUP:
2291 		case MCAST_LEAVE_SOURCE_GROUP:
2292 #endif
2293 			if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC) == FAILURE) {
2294 				RETURN_FALSE;
2295 			} else {
2296 				RETURN_TRUE;
2297 			}
2298 
2299 		case IPV6_MULTICAST_IF:
2300 			if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
2301 				RETURN_FALSE;
2302 			}
2303 
2304 			opt_ptr = &if_index;
2305 			optlen	= sizeof(if_index);
2306 			goto dosockopt;
2307 
2308 		case IPV6_MULTICAST_LOOP:
2309 			convert_to_boolean_ex(arg4);
2310 			goto ipv6_loop_hops;
2311 		case IPV6_MULTICAST_HOPS:
2312 			convert_to_long_ex(arg4);
2313 			if (Z_LVAL_PP(arg4) < -1L || Z_LVAL_PP(arg4) > 255L) {
2314 				php_error_docref(NULL TSRMLS_CC, E_WARNING,
2315 						"Expected a value between -1 and 255");
2316 				RETURN_FALSE;
2317 			}
2318 ipv6_loop_hops:
2319 			ov = (int) Z_LVAL_PP(arg4);
2320 			opt_ptr = &ov;
2321 			optlen	= sizeof(ov);
2322 			goto dosockopt;
2323 		}
2324 	}
2325 #endif
2326 
2327 	switch (optname) {
2328 		case SO_LINGER: {
2329 			const char l_onoff_key[] = "l_onoff";
2330 			const char l_linger_key[] = "l_linger";
2331 
2332 			convert_to_array_ex(arg4);
2333 			opt_ht = HASH_OF(*arg4);
2334 
2335 			if (zend_hash_find(opt_ht, l_onoff_key, sizeof(l_onoff_key), (void **)&l_onoff) == FAILURE) {
2336 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
2337 				RETURN_FALSE;
2338 			}
2339 			if (zend_hash_find(opt_ht, l_linger_key, sizeof(l_linger_key), (void **)&l_linger) == FAILURE) {
2340 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
2341 				RETURN_FALSE;
2342 			}
2343 
2344 			convert_to_long_ex(l_onoff);
2345 			convert_to_long_ex(l_linger);
2346 
2347 			lv.l_onoff = (unsigned short)Z_LVAL_PP(l_onoff);
2348 			lv.l_linger = (unsigned short)Z_LVAL_PP(l_linger);
2349 
2350 			optlen = sizeof(lv);
2351 			opt_ptr = &lv;
2352 			break;
2353 		}
2354 
2355 		case SO_RCVTIMEO:
2356 		case SO_SNDTIMEO: {
2357 			const char sec_key[] = "sec";
2358 			const char usec_key[] = "usec";
2359 
2360 			convert_to_array_ex(arg4);
2361 			opt_ht = HASH_OF(*arg4);
2362 
2363 			if (zend_hash_find(opt_ht, sec_key, sizeof(sec_key), (void **)&sec) == FAILURE) {
2364 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", sec_key);
2365 				RETURN_FALSE;
2366 			}
2367 			if (zend_hash_find(opt_ht, usec_key, sizeof(usec_key), (void **)&usec) == FAILURE) {
2368 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", usec_key);
2369 				RETURN_FALSE;
2370 			}
2371 
2372 			convert_to_long_ex(sec);
2373 			convert_to_long_ex(usec);
2374 #ifndef PHP_WIN32
2375 			tv.tv_sec = Z_LVAL_PP(sec);
2376 			tv.tv_usec = Z_LVAL_PP(usec);
2377 			optlen = sizeof(tv);
2378 			opt_ptr = &tv;
2379 #else
2380 			timeout = Z_LVAL_PP(sec) * 1000 + Z_LVAL_PP(usec) / 1000;
2381 			optlen = sizeof(int);
2382 			opt_ptr = &timeout;
2383 #endif
2384 			break;
2385 		}
2386 #ifdef SO_BINDTODEVICE
2387 		case SO_BINDTODEVICE: {
2388 			if (Z_TYPE_PP(arg4) == IS_STRING) {
2389 				opt_ptr = Z_STRVAL_PP(arg4);
2390 				optlen = Z_STRLEN_PP(arg4);
2391 			} else {
2392 				opt_ptr = "";
2393 				optlen = 0;
2394 			}
2395 			break;
2396 		}
2397 #endif
2398 
2399 		default:
2400 			convert_to_long_ex(arg4);
2401 			ov = Z_LVAL_PP(arg4);
2402 
2403 			optlen = sizeof(ov);
2404 			opt_ptr = &ov;
2405 			break;
2406 	}
2407 
2408 dosockopt:
2409 	retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
2410 	if (retval != 0) {
2411 		if (retval != -2) { /* error, but message already emitted */
2412 			PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
2413 		}
2414 		RETURN_FALSE;
2415 	}
2416 
2417 	RETURN_TRUE;
2418 }
2419 /* }}} */
2420 
2421 #ifdef HAVE_SOCKETPAIR
2422 /* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd) U
2423    Creates a pair of indistinguishable sockets and stores them in fds. */
2424 PHP_FUNCTION(socket_create_pair)
2425 {
2426 	zval		*retval[2], *fds_array_zval;
2427 	php_socket	*php_sock[2];
2428 	PHP_SOCKET	fds_array[2];
2429 	long		domain, type, protocol;
2430 
2431 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lllz", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
2432 		return;
2433 	}
2434 
2435 	php_sock[0] = php_create_socket();
2436 	php_sock[1] = php_create_socket();
2437 
2438 	if (domain != AF_INET
2439 #if HAVE_IPV6
2440 		&& domain != AF_INET6
2441 #endif
2442 		&& domain != AF_UNIX) {
2443 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", domain);
2444 		domain = AF_INET;
2445 	}
2446 
2447 	if (type > 10) {
2448 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", type);
2449 		type = SOCK_STREAM;
2450 	}
2451 
2452 	if (socketpair(domain, type, protocol, fds_array) != 0) {
2453 		SOCKETS_G(last_error) = errno;
2454 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create socket pair [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
2455 		efree(php_sock[0]);
2456 		efree(php_sock[1]);
2457 		RETURN_FALSE;
2458 	}
2459 
2460 	zval_dtor(fds_array_zval);
2461 	array_init(fds_array_zval);
2462 
2463 	MAKE_STD_ZVAL(retval[0]);
2464 	MAKE_STD_ZVAL(retval[1]);
2465 
2466 	php_sock[0]->bsd_socket = fds_array[0];
2467 	php_sock[1]->bsd_socket = fds_array[1];
2468 	php_sock[0]->type		= domain;
2469 	php_sock[1]->type		= domain;
2470 	php_sock[0]->error		= 0;
2471 	php_sock[1]->error		= 0;
2472 	php_sock[0]->blocking	= 1;
2473 	php_sock[1]->blocking	= 1;
2474 
2475 	ZEND_REGISTER_RESOURCE(retval[0], php_sock[0], le_socket);
2476 	ZEND_REGISTER_RESOURCE(retval[1], php_sock[1], le_socket);
2477 
2478 	add_index_zval(fds_array_zval, 0, retval[0]);
2479 	add_index_zval(fds_array_zval, 1, retval[1]);
2480 
2481 	RETURN_TRUE;
2482 }
2483 /* }}} */
2484 #endif
2485 
2486 #ifdef HAVE_SHUTDOWN
2487 /* {{{ proto bool socket_shutdown(resource socket[, int how]) U
2488    Shuts down a socket for receiving, sending, or both. */
2489 PHP_FUNCTION(socket_shutdown)
2490 {
2491 	zval		*arg1;
2492 	long		how_shutdown = 2;
2493 	php_socket	*php_sock;
2494 
2495 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &how_shutdown) == FAILURE) {
2496 		return;
2497 	}
2498 
2499 	ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2500 
2501 	if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
2502 		PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
2503 		RETURN_FALSE;
2504 	}
2505 
2506 	RETURN_TRUE;
2507 }
2508 /* }}} */
2509 #endif
2510 
2511 /* {{{ proto int socket_last_error([resource socket]) U
2512    Returns the last socket error (either the last used or the provided socket resource) */
2513 PHP_FUNCTION(socket_last_error)
2514 {
2515 	zval		*arg1 = NULL;
2516 	php_socket	*php_sock;
2517 
2518 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
2519 		return;
2520 	}
2521 
2522 	if (arg1) {
2523 		ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2524 		RETVAL_LONG(php_sock->error);
2525 	} else {
2526 		RETVAL_LONG(SOCKETS_G(last_error));
2527 	}
2528 }
2529 /* }}} */
2530 
2531 /* {{{ proto void socket_clear_error([resource socket]) U
2532    Clears the error on the socket or the last error code. */
2533 PHP_FUNCTION(socket_clear_error)
2534 {
2535 	zval		*arg1 = NULL;
2536 	php_socket	*php_sock;
2537 
2538 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
2539 		return;
2540 	}
2541 
2542 	if (arg1) {
2543 		ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2544 		php_sock->error = 0;
2545 	} else {
2546 		SOCKETS_G(last_error) = 0;
2547 	}
2548 
2549 	return;
2550 }
2551 /* }}} */
2552 
2553 /* {{{ proto void socket_import_stream(resource stream)
2554    Imports a stream that encapsulates a socket into a socket extension resource. */
2555 PHP_FUNCTION(socket_import_stream)
2556 {
2557 	zval				 *zstream;
2558 	php_stream			 *stream;
2559 	php_socket			 *retsock = NULL;
2560 	PHP_SOCKET			 socket; /* fd */
2561 	php_sockaddr_storage addr;
2562 	socklen_t			 addr_len = sizeof(addr);
2563 #ifndef PHP_WIN32
2564 	int					 t;
2565 #endif
2566 
2567 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) == FAILURE) {
2568 		return;
2569 	}
2570 	php_stream_from_zval(stream, &zstream);
2571 
2572 	if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
2573 		/* error supposedly already shown */
2574 		RETURN_FALSE;
2575 	}
2576 
2577 	retsock = php_create_socket();
2578 
2579 	retsock->bsd_socket = socket;
2580 
2581 	/* determine family */
2582 	if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
2583 		retsock->type = addr.ss_family;
2584 	} else {
2585 		PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
2586 		goto error;
2587 	}
2588 
2589 	/* determine blocking mode */
2590 #ifndef PHP_WIN32
2591 	t = fcntl(socket, F_GETFL);
2592 	if(t == -1) {
2593 		PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
2594 		goto error;
2595 	} else {
2596 		retsock->blocking = !(t & O_NONBLOCK);
2597 	}
2598 #else
2599 	/* on windows, check if the stream is a socket stream and read its
2600 	 * private data; otherwise assume it's in non-blocking mode */
2601 	if (php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
2602 		retsock->blocking =
2603 				((php_netstream_data_t *)stream->abstract)->is_blocked;
2604 	} else {
2605 		retsock->blocking = 1;
2606 	}
2607 #endif
2608 
2609 	/* hold a zval reference to the stream (holding a php_stream* directly could
2610 	 * also be done, but this might be slightly better if in the future we want
2611 	 * to provide a socket_export_stream) */
2612 	MAKE_STD_ZVAL(retsock->zstream);
2613 	*retsock->zstream = *zstream;
2614 	zval_copy_ctor(retsock->zstream);
2615 	Z_UNSET_ISREF_P(retsock->zstream);
2616 	Z_SET_REFCOUNT_P(retsock->zstream, 1);
2617 
2618 	php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
2619 		PHP_STREAM_BUFFER_NONE, NULL);
2620 
2621 	ZEND_REGISTER_RESOURCE(return_value, retsock, le_socket);
2622 	return;
2623 error:
2624 	if (retsock != NULL)
2625 		efree(retsock);
2626 	RETURN_FALSE;
2627 }
2628 /* }}} */
2629 
2630 #endif
2631 
2632 /*
2633  * Local variables:
2634  * tab-width: 4
2635  * c-basic-offset: 4
2636  * End:
2637  * vim600: fdm=marker
2638  * vim: noet sw=4 ts=4
2639  */
2640