xref: /PHP-5.3/ext/sockets/sockets.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 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    | WinSock: Daniel Beulshausen <daniel@php4win.de>                      |
19    +----------------------------------------------------------------------+
20  */
21 
22 /* $Id$ */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "php.h"
29 
30 #if HAVE_SOCKETS
31 
32 #include "php_network.h"
33 #include "ext/standard/file.h"
34 #include "ext/standard/info.h"
35 #include "php_ini.h"
36 #ifdef PHP_WIN32
37 # include "win32/inet.h"
38 # include <winsock2.h>
39 # include <windows.h>
40 # include <Ws2tcpip.h>
41 # include "php_sockets.h"
42 # include "win32/sockets.h"
43 # define IS_INVALID_SOCKET(a)	(a->bsd_socket == INVALID_SOCKET)
44 # ifdef EPROTONOSUPPORT
45 #  undef EPROTONOSUPPORT
46 # endif
47 # ifdef ECONNRESET
48 #  undef ECONNRESET
49 # endif
50 # define EPROTONOSUPPORT	WSAEPROTONOSUPPORT
51 # define ECONNRESET		WSAECONNRESET
52 # ifdef errno
53 #  undef errno
54 # endif
55 # define errno			WSAGetLastError()
56 # define h_errno		WSAGetLastError()
57 # define set_errno(a)		WSASetLastError(a)
58 # define close(a)		closesocket(a)
59 #else
60 # include <sys/types.h>
61 # include <sys/socket.h>
62 # include <netdb.h>
63 # include <netinet/in.h>
64 # include <netinet/tcp.h>
65 # include <sys/un.h>
66 # include <arpa/inet.h>
67 # include <sys/time.h>
68 # include <unistd.h>
69 # include <errno.h>
70 # include <fcntl.h>
71 # include <signal.h>
72 # include <sys/uio.h>
73 # define IS_INVALID_SOCKET(a)	(a->bsd_socket < 0)
74 # define set_errno(a) (errno = a)
75 # include "php_sockets.h"
76 #endif
77 
78 ZEND_DECLARE_MODULE_GLOBALS(sockets)
79 static PHP_GINIT_FUNCTION(sockets);
80 
81 #ifndef MSG_WAITALL
82 #ifdef LINUX
83 #define MSG_WAITALL 0x00000100
84 #else
85 #define MSG_WAITALL 0x00000000
86 #endif
87 #endif
88 
89 #ifndef MSG_EOF
90 #ifdef MSG_FIN
91 #define MSG_EOF MSG_FIN
92 #endif
93 #endif
94 
95 #ifndef SUN_LEN
96 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
97 #endif
98 
99 #ifndef PF_INET
100 #define PF_INET AF_INET
101 #endif
102 
103 static char *php_strerror(int error TSRMLS_DC);
104 
105 #define PHP_NORMAL_READ 0x0001
106 #define PHP_BINARY_READ 0x0002
107 
108 #define PHP_SOCKET_ERROR(socket,msg,errn)	socket->error = errn;	\
109 						SOCKETS_G(last_error) = errn; \
110 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s [%d]: %s", msg, errn, php_strerror(errn TSRMLS_CC))
111 
112 static int le_socket;
113 #define le_socket_name php_sockets_le_socket_name
114 
115 /* {{{ arginfo */
116 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_select, 0, 0, 4)
117 	ZEND_ARG_INFO(1, read_fds)
118 	ZEND_ARG_INFO(1, write_fds)
119 	ZEND_ARG_INFO(1, except_fds)
120 	ZEND_ARG_INFO(0, tv_sec)
121 	ZEND_ARG_INFO(0, tv_usec)
122 ZEND_END_ARG_INFO()
123 
124 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_listen, 0, 0, 1)
125 	ZEND_ARG_INFO(0, port)
126 	ZEND_ARG_INFO(0, backlog)
127 ZEND_END_ARG_INFO()
128 
129 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_accept, 0, 0, 1)
130 	ZEND_ARG_INFO(0, socket)
131 ZEND_END_ARG_INFO()
132 
133 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_nonblock, 0, 0, 1)
134 	ZEND_ARG_INFO(0, socket)
135 ZEND_END_ARG_INFO()
136 
137 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_block, 0, 0, 1)
138 	ZEND_ARG_INFO(0, socket)
139 ZEND_END_ARG_INFO()
140 
141 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_listen, 0, 0, 1)
142 	ZEND_ARG_INFO(0, socket)
143 	ZEND_ARG_INFO(0, backlog)
144 ZEND_END_ARG_INFO()
145 
146 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_close, 0, 0, 1)
147 	ZEND_ARG_INFO(0, socket)
148 ZEND_END_ARG_INFO()
149 
150 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_write, 0, 0, 2)
151 	ZEND_ARG_INFO(0, socket)
152 	ZEND_ARG_INFO(0, buf)
153 	ZEND_ARG_INFO(0, length)
154 ZEND_END_ARG_INFO()
155 
156 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_read, 0, 0, 2)
157 	ZEND_ARG_INFO(0, socket)
158 	ZEND_ARG_INFO(0, length)
159 	ZEND_ARG_INFO(0, type)
160 ZEND_END_ARG_INFO()
161 
162 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getsockname, 0, 0, 2)
163 	ZEND_ARG_INFO(0, socket)
164 	ZEND_ARG_INFO(1, addr)
165 	ZEND_ARG_INFO(1, port)
166 ZEND_END_ARG_INFO()
167 
168 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getpeername, 0, 0, 2)
169 	ZEND_ARG_INFO(0, socket)
170 	ZEND_ARG_INFO(1, addr)
171 	ZEND_ARG_INFO(1, port)
172 ZEND_END_ARG_INFO()
173 
174 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create, 0, 0, 3)
175 	ZEND_ARG_INFO(0, domain)
176 	ZEND_ARG_INFO(0, type)
177 	ZEND_ARG_INFO(0, protocol)
178 ZEND_END_ARG_INFO()
179 
180 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_connect, 0, 0, 2)
181 	ZEND_ARG_INFO(0, socket)
182 	ZEND_ARG_INFO(0, addr)
183 	ZEND_ARG_INFO(0, port)
184 ZEND_END_ARG_INFO()
185 
186 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_strerror, 0, 0, 1)
187 	ZEND_ARG_INFO(0, errno)
188 ZEND_END_ARG_INFO()
189 
190 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_bind, 0, 0, 2)
191 	ZEND_ARG_INFO(0, socket)
192 	ZEND_ARG_INFO(0, addr)
193 	ZEND_ARG_INFO(0, port)
194 ZEND_END_ARG_INFO()
195 
196 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recv, 0, 0, 4)
197 	ZEND_ARG_INFO(0, socket)
198 	ZEND_ARG_INFO(1, buf)
199 	ZEND_ARG_INFO(0, len)
200 	ZEND_ARG_INFO(0, flags)
201 ZEND_END_ARG_INFO()
202 
203 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_send, 0, 0, 4)
204 	ZEND_ARG_INFO(0, socket)
205 	ZEND_ARG_INFO(0, buf)
206 	ZEND_ARG_INFO(0, len)
207 	ZEND_ARG_INFO(0, flags)
208 ZEND_END_ARG_INFO()
209 
210 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvfrom, 0, 0, 5)
211 	ZEND_ARG_INFO(0, socket)
212 	ZEND_ARG_INFO(1, buf)
213 	ZEND_ARG_INFO(0, len)
214 	ZEND_ARG_INFO(0, flags)
215 	ZEND_ARG_INFO(1, name)
216 	ZEND_ARG_INFO(1, port)
217 ZEND_END_ARG_INFO()
218 
219 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendto, 0, 0, 5)
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_ARG_INFO(0, addr)
225 	ZEND_ARG_INFO(0, port)
226 ZEND_END_ARG_INFO()
227 
228 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_get_option, 0, 0, 3)
229 	ZEND_ARG_INFO(0, socket)
230 	ZEND_ARG_INFO(0, level)
231 	ZEND_ARG_INFO(0, optname)
232 ZEND_END_ARG_INFO()
233 
234 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_option, 0, 0, 4)
235 	ZEND_ARG_INFO(0, socket)
236 	ZEND_ARG_INFO(0, level)
237 	ZEND_ARG_INFO(0, optname)
238 	ZEND_ARG_INFO(0, optval)
239 ZEND_END_ARG_INFO()
240 
241 #ifdef HAVE_SOCKETPAIR
242 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_pair, 0, 0, 4)
243 	ZEND_ARG_INFO(0, domain)
244 	ZEND_ARG_INFO(0, type)
245 	ZEND_ARG_INFO(0, protocol)
246 	ZEND_ARG_INFO(1, fd)
247 ZEND_END_ARG_INFO()
248 #endif
249 
250 #ifdef HAVE_SHUTDOWN
251 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_shutdown, 0, 0, 1)
252 	ZEND_ARG_INFO(0, socket)
253 	ZEND_ARG_INFO(0, how)
254 ZEND_END_ARG_INFO()
255 #endif
256 
257 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_last_error, 0, 0, 0)
258 	ZEND_ARG_INFO(0, socket)
259 ZEND_END_ARG_INFO()
260 
261 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
262 	ZEND_ARG_INFO(0, socket)
263 ZEND_END_ARG_INFO()
264 /* }}} */
265 
266 /* {{{ sockets_functions[]
267  */
268 const zend_function_entry sockets_functions[] = {
269 	PHP_FE(socket_select,			arginfo_socket_select)
270 	PHP_FE(socket_create,			arginfo_socket_create)
271 	PHP_FE(socket_create_listen,	arginfo_socket_create_listen)
272 #ifdef HAVE_SOCKETPAIR
273 	PHP_FE(socket_create_pair,		arginfo_socket_create_pair)
274 #endif
275 	PHP_FE(socket_accept,			arginfo_socket_accept)
276 	PHP_FE(socket_set_nonblock,		arginfo_socket_set_nonblock)
277 	PHP_FE(socket_set_block,		arginfo_socket_set_block)
278 	PHP_FE(socket_listen,			arginfo_socket_listen)
279 	PHP_FE(socket_close,			arginfo_socket_close)
280 	PHP_FE(socket_write,			arginfo_socket_write)
281 	PHP_FE(socket_read,				arginfo_socket_read)
282 	PHP_FE(socket_getsockname, 		arginfo_socket_getsockname)
283 	PHP_FE(socket_getpeername, 		arginfo_socket_getpeername)
284 	PHP_FE(socket_connect,			arginfo_socket_connect)
285 	PHP_FE(socket_strerror,			arginfo_socket_strerror)
286 	PHP_FE(socket_bind,				arginfo_socket_bind)
287 	PHP_FE(socket_recv,				arginfo_socket_recv)
288 	PHP_FE(socket_send,				arginfo_socket_send)
289 	PHP_FE(socket_recvfrom,			arginfo_socket_recvfrom)
290 	PHP_FE(socket_sendto,			arginfo_socket_sendto)
291 	PHP_FE(socket_get_option,		arginfo_socket_get_option)
292 	PHP_FE(socket_set_option,		arginfo_socket_set_option)
293 #ifdef HAVE_SHUTDOWN
294 	PHP_FE(socket_shutdown,			arginfo_socket_shutdown)
295 #endif
296 	PHP_FE(socket_last_error,		arginfo_socket_last_error)
297 	PHP_FE(socket_clear_error,		arginfo_socket_clear_error)
298 
299 	/* for downwards compatability */
300 	PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)
301 	PHP_FALIAS(socket_setopt, socket_set_option, arginfo_socket_set_option)
302 
303 	PHP_FE_END
304 };
305 /* }}} */
306 
307 zend_module_entry sockets_module_entry = {
308 	STANDARD_MODULE_HEADER,
309 	"sockets",
310 	sockets_functions,
311 	PHP_MINIT(sockets),
312 	NULL,
313 	NULL,
314 	PHP_RSHUTDOWN(sockets),
315 	PHP_MINFO(sockets),
316 	NO_VERSION_YET,
317 	PHP_MODULE_GLOBALS(sockets),
318 	PHP_GINIT(sockets),
319 	NULL,
320 	NULL,
321 	STANDARD_MODULE_PROPERTIES_EX
322 };
323 
324 
325 #ifdef COMPILE_DL_SOCKETS
326 ZEND_GET_MODULE(sockets)
327 #endif
328 
329 /* inet_ntop should be used instead of inet_ntoa */
330 int inet_ntoa_lock = 0;
331 
php_sockets_le_socket(void)332 PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{ */
333 {
334 	return le_socket;
335 }
336 /* }}} */
337 
php_destroy_socket(zend_rsrc_list_entry * rsrc TSRMLS_DC)338 static void php_destroy_socket(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
339 {
340 	php_socket *php_sock = (php_socket *) rsrc->ptr;
341 
342 	close(php_sock->bsd_socket);
343 	efree(php_sock);
344 }
345 /* }}} */
346 
php_open_listen_sock(php_socket ** php_sock,int port,int backlog TSRMLS_DC)347 static int php_open_listen_sock(php_socket **php_sock, int port, int backlog TSRMLS_DC) /* {{{ */
348 {
349 	struct sockaddr_in  la;
350 	struct hostent		*hp;
351 	php_socket			*sock = (php_socket*)emalloc(sizeof(php_socket));
352 
353 	*php_sock = sock;
354 
355 #ifndef PHP_WIN32
356 	if ((hp = gethostbyname("0.0.0.0")) == NULL) {
357 #else
358 	if ((hp = gethostbyname("localhost")) == NULL) {
359 #endif
360 		efree(sock);
361 		return 0;
362 	}
363 
364 	memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length);
365 	la.sin_family = hp->h_addrtype;
366 	la.sin_port = htons((unsigned short) port);
367 
368 	sock->bsd_socket = socket(PF_INET, SOCK_STREAM, 0);
369 	sock->blocking = 1;
370 
371 	if (IS_INVALID_SOCKET(sock)) {
372 		PHP_SOCKET_ERROR(sock, "unable to create listening socket", errno);
373 		efree(sock);
374 		return 0;
375 	}
376 
377 	sock->type = PF_INET;
378 
379 	if (bind(sock->bsd_socket, (struct sockaddr *)&la, sizeof(la)) != 0) {
380 		PHP_SOCKET_ERROR(sock, "unable to bind to given address", errno);
381 		close(sock->bsd_socket);
382 		efree(sock);
383 		return 0;
384 	}
385 
386 	if (listen(sock->bsd_socket, backlog) != 0) {
387 		PHP_SOCKET_ERROR(sock, "unable to listen on socket", errno);
388 		close(sock->bsd_socket);
389 		efree(sock);
390 		return 0;
391 	}
392 
393 	return 1;
394 }
395 /* }}} */
396 
397 static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la, socklen_t *la_len TSRMLS_DC) /* {{{ */
398 {
399 	php_socket	*out_sock = (php_socket*)emalloc(sizeof(php_socket));
400 
401 	*new_sock = out_sock;
402 
403 	out_sock->bsd_socket = accept(in_sock->bsd_socket, la, la_len);
404 
405 	if (IS_INVALID_SOCKET(out_sock)) {
406 		PHP_SOCKET_ERROR(out_sock, "unable to accept incoming connection", errno);
407 		efree(out_sock);
408 		return 0;
409 	}
410 
411 	out_sock->error = 0;
412 	out_sock->blocking = 1;
413 	out_sock->type = la->sa_family;
414 
415 	return 1;
416 }
417 /* }}} */
418 
419 /* {{{ php_read -- wrapper around read() so that it only reads to a \r or \n. */
420 static int php_read(php_socket *sock, void *buf, size_t maxlen, int flags)
421 {
422 	int m = 0;
423 	size_t n = 0;
424 	int no_read = 0;
425 	int nonblock = 0;
426 	char *t = (char *) buf;
427 
428 #ifndef PHP_WIN32
429 	m = fcntl(sock->bsd_socket, F_GETFL);
430 	if (m < 0) {
431 		return m;
432 	}
433 	nonblock = (m & O_NONBLOCK);
434 	m = 0;
435 #else
436 	nonblock = !sock->blocking;
437 #endif
438 	set_errno(0);
439 
440 	*t = '\0';
441 	while (*t != '\n' && *t != '\r' && n < maxlen) {
442 		if (m > 0) {
443 			t++;
444 			n++;
445 		} else if (m == 0) {
446 			no_read++;
447 			if (nonblock && no_read >= 2) {
448 				return n;
449 				/* The first pass, m always is 0, so no_read becomes 1
450 				 * in the first pass. no_read becomes 2 in the second pass,
451 				 * and if this is nonblocking, we should return.. */
452 			}
453 
454 			if (no_read > 200) {
455 				set_errno(ECONNRESET);
456 				return -1;
457 			}
458 		}
459 
460 		if (n < maxlen) {
461 			m = recv(sock->bsd_socket, (void *) t, 1, flags);
462 		}
463 
464 		if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
465 			return -1;
466 		}
467 
468 		set_errno(0);
469 	}
470 
471 	if (n < maxlen) {
472 		n++;
473 		/* The only reasons it makes it to here is
474 		 * if '\n' or '\r' are encountered. So, increase
475 		 * the return by 1 to make up for the lack of the
476 		 * '\n' or '\r' in the count (since read() takes
477 		 * place at the end of the loop..) */
478 	}
479 
480 	return n;
481 }
482 /* }}} */
483 
484 static char *php_strerror(int error TSRMLS_DC) /* {{{ */
485 {
486 	const char *buf;
487 
488 #ifndef PHP_WIN32
489 	if (error < -10000) {
490 		error = -error - 10000;
491 
492 #ifdef HAVE_HSTRERROR
493 		buf = hstrerror(error);
494 #else
495 		{
496 			if (SOCKETS_G(strerror_buf)) {
497 				efree(SOCKETS_G(strerror_buf));
498 			}
499 
500 			spprintf(&(SOCKETS_G(strerror_buf)), 0, "Host lookup error %d", error);
501 			buf = SOCKETS_G(strerror_buf);
502 		}
503 #endif
504 	} else {
505 		buf = strerror(error);
506 	}
507 #else
508 	{
509 		LPTSTR tmp = NULL;
510 		buf = NULL;
511 
512 		if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |	FORMAT_MESSAGE_IGNORE_INSERTS,
513 			NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &tmp, 0, NULL)
514 		) {
515 			if (SOCKETS_G(strerror_buf)) {
516 				efree(SOCKETS_G(strerror_buf));
517 			}
518 
519 			SOCKETS_G(strerror_buf) = estrdup(tmp);
520 			LocalFree(tmp);
521 
522 			buf = SOCKETS_G(strerror_buf);
523 		}
524 	}
525 #endif
526 
527 	return (buf ? (char *) buf : "");
528 }
529 /* }}} */
530 
531 #if HAVE_IPV6
532 /* Sets addr by hostname, or by ip in string form (AF_INET6) */
533 static int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
534 {
535 	struct in6_addr tmp;
536 #if HAVE_GETADDRINFO
537 	struct addrinfo hints;
538 	struct addrinfo *addrinfo = NULL;
539 #endif
540 
541 	if (inet_pton(AF_INET6, string, &tmp)) {
542 		memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
543 	} else {
544 #if HAVE_GETADDRINFO
545 
546 		memset(&hints, 0, sizeof(struct addrinfo));
547 		hints.ai_family = PF_INET6;
548 		getaddrinfo(string, NULL, &hints, &addrinfo);
549 		if (!addrinfo) {
550 #ifdef PHP_WIN32
551 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
552 #else
553 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
554 #endif
555 			return 0;
556 		}
557 		if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
558 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
559 			freeaddrinfo(addrinfo);
560 			return 0;
561 		}
562 
563 		memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
564 		freeaddrinfo(addrinfo);
565 
566 #else
567 		/* No IPv6 specific hostname resolution is available on this system? */
568 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system");
569 		return 0;
570 #endif
571 
572 	}
573 
574 	return 1;
575 }
576 /* }}} */
577 #endif
578 
579 /* Sets addr by hostname, or by ip in string form (AF_INET)  */
580 static int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
581 {
582 	struct in_addr tmp;
583 	struct hostent *host_entry;
584 
585 	if (inet_aton(string, &tmp)) {
586 		sin->sin_addr.s_addr = tmp.s_addr;
587 	} else {
588 		if (! (host_entry = gethostbyname(string))) {
589 			/* Note: < -10000 indicates a host lookup error */
590 #ifdef PHP_WIN32
591 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
592 #else
593 			PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
594 #endif
595 			return 0;
596 		}
597 		if (host_entry->h_addrtype != AF_INET) {
598 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket");
599 			return 0;
600 		}
601 		memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
602 	}
603 
604 	return 1;
605 }
606 /* }}} */
607 
608 /* {{{ PHP_GINIT_FUNCTION */
609 static PHP_GINIT_FUNCTION(sockets)
610 {
611 	sockets_globals->last_error = 0;
612 	sockets_globals->strerror_buf = NULL;
613 }
614 /* }}} */
615 
616 /* {{{ PHP_MINIT_FUNCTION
617  */
618 PHP_MINIT_FUNCTION(sockets)
619 {
620 	struct protoent *pe;
621 
622 	le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);
623 
624 	REGISTER_LONG_CONSTANT("AF_UNIX",		AF_UNIX,		CONST_CS | CONST_PERSISTENT);
625 	REGISTER_LONG_CONSTANT("AF_INET",		AF_INET,		CONST_CS | CONST_PERSISTENT);
626 #if HAVE_IPV6
627 	REGISTER_LONG_CONSTANT("AF_INET6",		AF_INET6,		CONST_CS | CONST_PERSISTENT);
628 #endif
629 	REGISTER_LONG_CONSTANT("SOCK_STREAM",	SOCK_STREAM,	CONST_CS | CONST_PERSISTENT);
630 	REGISTER_LONG_CONSTANT("SOCK_DGRAM",	SOCK_DGRAM,		CONST_CS | CONST_PERSISTENT);
631 	REGISTER_LONG_CONSTANT("SOCK_RAW",		SOCK_RAW,		CONST_CS | CONST_PERSISTENT);
632 	REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT);
633 	REGISTER_LONG_CONSTANT("SOCK_RDM",		SOCK_RDM,		CONST_CS | CONST_PERSISTENT);
634 	REGISTER_LONG_CONSTANT("MSG_OOB",		MSG_OOB,		CONST_CS | CONST_PERSISTENT);
635 	REGISTER_LONG_CONSTANT("MSG_WAITALL",	MSG_WAITALL,	CONST_CS | CONST_PERSISTENT);
636 #ifdef MSG_DONTWAIT
637 	REGISTER_LONG_CONSTANT("MSG_DONTWAIT",	MSG_DONTWAIT,	CONST_CS | CONST_PERSISTENT);
638 #endif
639 	REGISTER_LONG_CONSTANT("MSG_PEEK",		MSG_PEEK,		CONST_CS | CONST_PERSISTENT);
640 	REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE,	CONST_CS | CONST_PERSISTENT);
641 #ifdef MSG_EOR
642 	REGISTER_LONG_CONSTANT("MSG_EOR",		MSG_EOR,		CONST_CS | CONST_PERSISTENT);
643 #endif
644 #ifdef MSG_EOF
645 	REGISTER_LONG_CONSTANT("MSG_EOF",		MSG_EOF,		CONST_CS | CONST_PERSISTENT);
646 #endif
647 	REGISTER_LONG_CONSTANT("SO_DEBUG",		SO_DEBUG,		CONST_CS | CONST_PERSISTENT);
648 	REGISTER_LONG_CONSTANT("SO_REUSEADDR",	SO_REUSEADDR,	CONST_CS | CONST_PERSISTENT);
649 	REGISTER_LONG_CONSTANT("SO_KEEPALIVE",	SO_KEEPALIVE,	CONST_CS | CONST_PERSISTENT);
650 	REGISTER_LONG_CONSTANT("SO_DONTROUTE",	SO_DONTROUTE,	CONST_CS | CONST_PERSISTENT);
651 	REGISTER_LONG_CONSTANT("SO_LINGER",		SO_LINGER,		CONST_CS | CONST_PERSISTENT);
652 	REGISTER_LONG_CONSTANT("SO_BROADCAST",	SO_BROADCAST,	CONST_CS | CONST_PERSISTENT);
653 	REGISTER_LONG_CONSTANT("SO_OOBINLINE",	SO_OOBINLINE,	CONST_CS | CONST_PERSISTENT);
654 	REGISTER_LONG_CONSTANT("SO_SNDBUF",		SO_SNDBUF,		CONST_CS | CONST_PERSISTENT);
655 	REGISTER_LONG_CONSTANT("SO_RCVBUF",		SO_RCVBUF,		CONST_CS | CONST_PERSISTENT);
656 	REGISTER_LONG_CONSTANT("SO_SNDLOWAT",	SO_SNDLOWAT,	CONST_CS | CONST_PERSISTENT);
657 	REGISTER_LONG_CONSTANT("SO_RCVLOWAT",	SO_RCVLOWAT,	CONST_CS | CONST_PERSISTENT);
658 	REGISTER_LONG_CONSTANT("SO_SNDTIMEO",	SO_SNDTIMEO,	CONST_CS | CONST_PERSISTENT);
659 	REGISTER_LONG_CONSTANT("SO_RCVTIMEO",	SO_RCVTIMEO,	CONST_CS | CONST_PERSISTENT);
660 	REGISTER_LONG_CONSTANT("SO_TYPE",		SO_TYPE,		CONST_CS | CONST_PERSISTENT);
661 	REGISTER_LONG_CONSTANT("SO_ERROR",		SO_ERROR,		CONST_CS | CONST_PERSISTENT);
662 	REGISTER_LONG_CONSTANT("SOL_SOCKET",	SOL_SOCKET,		CONST_CS | CONST_PERSISTENT);
663 	REGISTER_LONG_CONSTANT("SOMAXCONN",		SOMAXCONN,		CONST_CS | CONST_PERSISTENT);
664 #ifdef TCP_NODELAY
665 	REGISTER_LONG_CONSTANT("TCP_NODELAY",   TCP_NODELAY,    CONST_CS | CONST_PERSISTENT);
666 #endif
667 	REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
668 	REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
669 
670 #ifndef WIN32
671 # include "unix_socket_constants.h"
672 #else
673 # include "win32_socket_constants.h"
674 #endif
675 
676 	if ((pe = getprotobyname("tcp"))) {
677 		REGISTER_LONG_CONSTANT("SOL_TCP", pe->p_proto, CONST_CS | CONST_PERSISTENT);
678 	}
679 
680 	if ((pe = getprotobyname("udp"))) {
681 		REGISTER_LONG_CONSTANT("SOL_UDP", pe->p_proto, CONST_CS | CONST_PERSISTENT);
682 	}
683 
684 	return SUCCESS;
685 }
686 /* }}} */
687 
688 /* {{{ PHP_MINFO_FUNCTION
689  */
690 PHP_MINFO_FUNCTION(sockets)
691 {
692 	php_info_print_table_start();
693 	php_info_print_table_row(2, "Sockets Support", "enabled");
694 	php_info_print_table_end();
695 }
696 /* }}} */
697 
698 /* {{{ PHP_RSHUTDOWN_FUNCTION */
699 PHP_RSHUTDOWN_FUNCTION(sockets)
700 {
701 	if (SOCKETS_G(strerror_buf)) {
702 		efree(SOCKETS_G(strerror_buf));
703 		SOCKETS_G(strerror_buf) = NULL;
704 	}
705 
706 	return SUCCESS;
707 }
708 /* }}} */
709 
710 static int php_sock_array_to_fd_set(zval *sock_array, fd_set *fds, PHP_SOCKET *max_fd TSRMLS_DC) /* {{{ */
711 {
712 	zval		**element;
713 	php_socket	*php_sock;
714 	int			num = 0;
715 
716 	if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
717 
718 	for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
719 		 zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
720 		 zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
721 
722 		php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
723 		if (!php_sock) continue; /* If element is not a resource, skip it */
724 
725 		PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
726 		if (php_sock->bsd_socket > *max_fd) {
727 			*max_fd = php_sock->bsd_socket;
728 		}
729 		num++;
730 	}
731 
732 	return num ? 1 : 0;
733 }
734 /* }}} */
735 
736 static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds TSRMLS_DC) /* {{{ */
737 {
738 	zval		**element;
739 	zval		**dest_element;
740 	php_socket	*php_sock;
741 	HashTable	*new_hash;
742 	char 		*key;
743 	int			num = 0;
744 	ulong       num_key;
745 	uint 		key_len;
746 
747 	if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
748 
749 	ALLOC_HASHTABLE(new_hash);
750 	zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(sock_array)), NULL, ZVAL_PTR_DTOR, 0);
751 	for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array));
752 		 zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS;
753 		 zend_hash_move_forward(Z_ARRVAL_P(sock_array))) {
754 
755 		php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket);
756 		if (!php_sock) continue; /* If element is not a resource, skip it */
757 
758 		if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
759 			/* Add fd to new array */
760 			switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(sock_array), &key, &key_len, &num_key, 0, NULL)) {
761 				case HASH_KEY_IS_STRING:
762 					zend_hash_add(new_hash, key, key_len, (void *)element, sizeof(zval *), (void **)&dest_element);
763 					break;
764 				case HASH_KEY_IS_LONG:
765 					zend_hash_index_update(new_hash, num_key, (void *)element, sizeof(zval *), (void **)&dest_element);
766 					break;
767 			}
768 			if (dest_element) zval_add_ref(dest_element);
769 		}
770 		num++;
771 	}
772 
773 	/* Destroy old array, add new one */
774 	zend_hash_destroy(Z_ARRVAL_P(sock_array));
775 	efree(Z_ARRVAL_P(sock_array));
776 
777 	zend_hash_internal_pointer_reset(new_hash);
778 	Z_ARRVAL_P(sock_array) = new_hash;
779 
780 	return num ? 1 : 0;
781 }
782 /* }}} */
783 
784 /* {{{ proto int socket_select(array &read_fds, array &write_fds, array &except_fds, int tv_sec[, int tv_usec]) U
785    Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec */
786 PHP_FUNCTION(socket_select)
787 {
788 	zval			*r_array, *w_array, *e_array, *sec;
789 	struct timeval	tv;
790 	struct timeval *tv_p = NULL;
791 	fd_set			rfds, wfds, efds;
792 	PHP_SOCKET		max_fd = 0;
793 	int				retval, sets = 0;
794 	long			usec = 0;
795 
796 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE) {
797 		return;
798 	}
799 
800 	FD_ZERO(&rfds);
801 	FD_ZERO(&wfds);
802 	FD_ZERO(&efds);
803 
804 	if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
805 	if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
806 	if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
807 
808 	if (!sets) {
809 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "no resource arrays were passed to select");
810 		RETURN_FALSE;
811 	}
812 
813 	PHP_SAFE_MAX_FD(max_fd, 0); /* someone needs to make this look more like stream_socket_select */
814 
815 	/* If seconds is not set to null, build the timeval, else we wait indefinitely */
816 	if (sec != NULL) {
817 		zval tmp;
818 
819 		if (Z_TYPE_P(sec) != IS_LONG) {
820 			tmp = *sec;
821 			zval_copy_ctor(&tmp);
822 			convert_to_long(&tmp);
823 			sec = &tmp;
824 		}
825 
826 		/* Solaris + BSD do not like microsecond values which are >= 1 sec */
827 		if (usec > 999999) {
828 			tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000);
829 			tv.tv_usec = usec % 1000000;
830 		} else {
831 			tv.tv_sec = Z_LVAL_P(sec);
832 			tv.tv_usec = usec;
833 		}
834 
835 		tv_p = &tv;
836 
837 		if (sec == &tmp) {
838 			zval_dtor(&tmp);
839 		}
840 	}
841 
842 	retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p);
843 
844 	if (retval == -1) {
845 		SOCKETS_G(last_error) = errno;
846 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
847 		RETURN_FALSE;
848 	}
849 
850 	if (r_array != NULL) php_sock_array_from_fd_set(r_array, &rfds TSRMLS_CC);
851 	if (w_array != NULL) php_sock_array_from_fd_set(w_array, &wfds TSRMLS_CC);
852 	if (e_array != NULL) php_sock_array_from_fd_set(e_array, &efds TSRMLS_CC);
853 
854 	RETURN_LONG(retval);
855 }
856 /* }}} */
857 
858 /* {{{ proto resource socket_create_listen(int port[, int backlog]) U
859    Opens a socket on port to accept connections */
860 PHP_FUNCTION(socket_create_listen)
861 {
862 	php_socket	*php_sock;
863 	long		port, backlog = 128;
864 
865 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &port, &backlog) == FAILURE) {
866 		return;
867 	}
868 
869 	if (!php_open_listen_sock(&php_sock, port, backlog TSRMLS_CC)) {
870 		RETURN_FALSE;
871 	}
872 
873 	php_sock->error = 0;
874 	php_sock->blocking = 1;
875 
876 	ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);
877 }
878 /* }}} */
879 
880 /* {{{ proto resource socket_accept(resource socket) U
881    Accepts a connection on the listening socket fd */
882 PHP_FUNCTION(socket_accept)
883 {
884 	zval				 *arg1;
885 	php_socket			 *php_sock, *new_sock;
886 	php_sockaddr_storage sa;
887 	socklen_t			 php_sa_len = sizeof(sa);
888 
889 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
890 		return;
891 	}
892 
893 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
894 
895 	if (!php_accept_connect(php_sock, &new_sock, (struct sockaddr*)&sa, &php_sa_len TSRMLS_CC)) {
896 		RETURN_FALSE;
897 	}
898 
899 	ZEND_REGISTER_RESOURCE(return_value, new_sock, le_socket);
900 }
901 /* }}} */
902 
903 /* {{{ proto bool socket_set_nonblock(resource socket) U
904    Sets nonblocking mode on a socket resource */
905 PHP_FUNCTION(socket_set_nonblock)
906 {
907 	zval		*arg1;
908 	php_socket	*php_sock;
909 
910 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
911 		return;
912 	}
913 
914 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
915 
916 	if (php_set_sock_blocking(php_sock->bsd_socket, 0 TSRMLS_CC) == SUCCESS) {
917 		php_sock->blocking = 0;
918 		RETURN_TRUE;
919 	} else {
920 		PHP_SOCKET_ERROR(php_sock, "unable to set nonblocking mode", errno);
921 		RETURN_FALSE;
922 	}
923 }
924 /* }}} */
925 
926 /* {{{ proto bool socket_set_block(resource socket) U
927    Sets blocking mode on a socket resource */
928 PHP_FUNCTION(socket_set_block)
929 {
930 	zval		*arg1;
931 	php_socket	*php_sock;
932 
933 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
934 		return;
935 	}
936 
937 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
938 
939 	if (php_set_sock_blocking(php_sock->bsd_socket, 1 TSRMLS_CC) == SUCCESS) {
940 		php_sock->blocking = 1;
941 		RETURN_TRUE;
942 	} else {
943 		PHP_SOCKET_ERROR(php_sock, "unable to set blocking mode", errno);
944 		RETURN_FALSE;
945 	}
946 }
947 /* }}} */
948 
949 /* {{{ proto bool socket_listen(resource socket[, int backlog]) U
950    Sets the maximum number of connections allowed to be waited for on the socket specified by fd */
951 PHP_FUNCTION(socket_listen)
952 {
953 	zval		*arg1;
954 	php_socket	*php_sock;
955 	long		backlog = 0;
956 
957 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &backlog) == FAILURE) {
958 		return;
959 	}
960 
961 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
962 
963 	if (listen(php_sock->bsd_socket, backlog) != 0) {
964 		PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno);
965 		RETURN_FALSE;
966 	}
967 	RETURN_TRUE;
968 }
969 /* }}} */
970 
971 /* {{{ proto void socket_close(resource socket) U
972    Closes a file descriptor */
973 PHP_FUNCTION(socket_close)
974 {
975 	zval		*arg1;
976 	php_socket	*php_sock;
977 
978 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
979 		return;
980 	}
981 
982 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
983 	zend_list_delete(Z_RESVAL_P(arg1));
984 }
985 /* }}} */
986 
987 /* {{{ proto int socket_write(resource socket, string buf[, int length])
988    Writes the buffer to the socket resource, length is optional */
989 PHP_FUNCTION(socket_write)
990 {
991 	zval		*arg1;
992 	php_socket	*php_sock;
993 	int			retval, str_len;
994 	long		length = 0;
995 	char		*str;
996 
997 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &str, &str_len, &length) == FAILURE) {
998 		return;
999 	}
1000 
1001 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1002 
1003 	if (ZEND_NUM_ARGS() < 3) {
1004 		length = str_len;
1005 	}
1006 
1007 #ifndef PHP_WIN32
1008 	retval = write(php_sock->bsd_socket, str, MIN(length, str_len));
1009 #else
1010 	retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);
1011 #endif
1012 
1013 	if (retval < 0) {
1014 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1015 		RETURN_FALSE;
1016 	}
1017 
1018 	RETURN_LONG(retval);
1019 }
1020 /* }}} */
1021 
1022 /* {{{ proto string socket_read(resource socket, int length [, int type]) U
1023    Reads a maximum of length bytes from socket */
1024 PHP_FUNCTION(socket_read)
1025 {
1026 	zval		*arg1;
1027 	php_socket	*php_sock;
1028 	char		*tmpbuf;
1029 	int			retval;
1030 	long		length, type = PHP_BINARY_READ;
1031 
1032 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|l", &arg1, &length, &type) == FAILURE) {
1033 		return;
1034 	}
1035 
1036 	/* overflow check */
1037 	if ((length + 1) < 2) {
1038 		RETURN_FALSE;
1039 	}
1040 
1041 	tmpbuf = emalloc(length + 1);
1042 
1043 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1044 
1045 	if (type == PHP_NORMAL_READ) {
1046 		retval = php_read(php_sock, tmpbuf, length, 0);
1047 	} else {
1048 		retval = recv(php_sock->bsd_socket, tmpbuf, length, 0);
1049 	}
1050 
1051 	if (retval == -1) {
1052 		/* if the socket is in non-blocking mode and there's no data to read,
1053 		don't output any error, as this is a normal situation, and not an error */
1054 		if (errno == EAGAIN
1055 #ifdef EWOULDBLOCK
1056 		|| errno == EWOULDBLOCK
1057 #endif
1058 		) {
1059 			php_sock->error = errno;
1060 			SOCKETS_G(last_error) = errno;
1061 		} else {
1062 			PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1063 		}
1064 
1065 		efree(tmpbuf);
1066 		RETURN_FALSE;
1067 	} else if (!retval) {
1068 		efree(tmpbuf);
1069 		RETURN_EMPTY_STRING();
1070 	}
1071 
1072 	tmpbuf = erealloc(tmpbuf, retval + 1);
1073 	tmpbuf[retval] = '\0' ;
1074 
1075 	RETURN_STRINGL(tmpbuf, retval, 0);
1076 }
1077 /* }}} */
1078 
1079 /* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port])
1080    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. */
1081 PHP_FUNCTION(socket_getsockname)
1082 {
1083 	zval					*arg1, *addr, *port = NULL;
1084 	php_sockaddr_storage	sa_storage;
1085 	php_socket				*php_sock;
1086 	struct sockaddr			*sa;
1087 	struct sockaddr_in		*sin;
1088 #if HAVE_IPV6
1089 	struct sockaddr_in6		*sin6;
1090 	char					addr6[INET6_ADDRSTRLEN+1];
1091 #endif
1092 	struct sockaddr_un		*s_un;
1093 	char					*addr_string;
1094 	socklen_t				salen = sizeof(php_sockaddr_storage);
1095 
1096 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &addr, &port) == FAILURE) {
1097 		return;
1098 	}
1099 
1100 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1101 
1102 	sa = (struct sockaddr *) &sa_storage;
1103 
1104 	if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
1105 		PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
1106 		RETURN_FALSE;
1107 	}
1108 
1109 	switch (sa->sa_family) {
1110 #if HAVE_IPV6
1111 		case AF_INET6:
1112 			sin6 = (struct sockaddr_in6 *) sa;
1113 			inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1114 			zval_dtor(addr);
1115 			ZVAL_STRING(addr, addr6, 1);
1116 
1117 			if (port != NULL) {
1118 				zval_dtor(port);
1119 				ZVAL_LONG(port, htons(sin6->sin6_port));
1120 			}
1121 			RETURN_TRUE;
1122 			break;
1123 #endif
1124 		case AF_INET:
1125 			sin = (struct sockaddr_in *) sa;
1126 			while (inet_ntoa_lock == 1);
1127 			inet_ntoa_lock = 1;
1128 			addr_string = inet_ntoa(sin->sin_addr);
1129 			inet_ntoa_lock = 0;
1130 
1131 			zval_dtor(addr);
1132 			ZVAL_STRING(addr, addr_string, 1);
1133 
1134 			if (port != NULL) {
1135 				zval_dtor(port);
1136 				ZVAL_LONG(port, htons(sin->sin_port));
1137 			}
1138 			RETURN_TRUE;
1139 			break;
1140 
1141 		case AF_UNIX:
1142 			s_un = (struct sockaddr_un *) sa;
1143 
1144 			zval_dtor(addr);
1145 			ZVAL_STRING(addr, s_un->sun_path, 1);
1146 			RETURN_TRUE;
1147 			break;
1148 
1149 		default:
1150 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
1151 			RETURN_FALSE;
1152 	}
1153 }
1154 /* }}} */
1155 
1156 /* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port])
1157    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. */
1158 PHP_FUNCTION(socket_getpeername)
1159 {
1160 	zval					*arg1, *arg2, *arg3 = NULL;
1161 	php_sockaddr_storage	sa_storage;
1162 	php_socket				*php_sock;
1163 	struct sockaddr			*sa;
1164 	struct sockaddr_in		*sin;
1165 #if HAVE_IPV6
1166 	struct sockaddr_in6		*sin6;
1167 	char					addr6[INET6_ADDRSTRLEN+1];
1168 #endif
1169 	struct sockaddr_un		*s_un;
1170 	char					*addr_string;
1171 	socklen_t				salen = sizeof(php_sockaddr_storage);
1172 
1173 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &arg2, &arg3) == FAILURE) {
1174 		return;
1175 	}
1176 
1177 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1178 
1179 	sa = (struct sockaddr *) &sa_storage;
1180 
1181 	if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
1182 		PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
1183 		RETURN_FALSE;
1184 	}
1185 
1186 	switch (sa->sa_family) {
1187 #if HAVE_IPV6
1188 		case AF_INET6:
1189 			sin6 = (struct sockaddr_in6 *) sa;
1190 			inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1191 			zval_dtor(arg2);
1192 			ZVAL_STRING(arg2, addr6, 1);
1193 
1194 			if (arg3 != NULL) {
1195 				zval_dtor(arg3);
1196 				ZVAL_LONG(arg3, htons(sin6->sin6_port));
1197 			}
1198 
1199 			RETURN_TRUE;
1200 			break;
1201 #endif
1202 		case AF_INET:
1203 			sin = (struct sockaddr_in *) sa;
1204 			while (inet_ntoa_lock == 1);
1205 			inet_ntoa_lock = 1;
1206 			addr_string = inet_ntoa(sin->sin_addr);
1207 			inet_ntoa_lock = 0;
1208 
1209 			zval_dtor(arg2);
1210 			ZVAL_STRING(arg2, addr_string, 1);
1211 
1212 			if (arg3 != NULL) {
1213 				zval_dtor(arg3);
1214 				ZVAL_LONG(arg3, htons(sin->sin_port));
1215 			}
1216 
1217 			RETURN_TRUE;
1218 			break;
1219 
1220 		case AF_UNIX:
1221 			s_un = (struct sockaddr_un *) sa;
1222 
1223 			zval_dtor(arg2);
1224 			ZVAL_STRING(arg2, s_un->sun_path, 1);
1225 			RETURN_TRUE;
1226 			break;
1227 
1228 		default:
1229 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
1230 			RETURN_FALSE;
1231 	}
1232 }
1233 /* }}} */
1234 
1235 /* {{{ proto resource socket_create(int domain, int type, int protocol) U
1236    Creates an endpoint for communication in the domain specified by domain, of type specified by type */
1237 PHP_FUNCTION(socket_create)
1238 {
1239 	long		arg1, arg2, arg3;
1240 	php_socket	*php_sock = (php_socket*)emalloc(sizeof(php_socket));
1241 
1242 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {
1243 		efree(php_sock);
1244 		return;
1245 	}
1246 
1247 	if (arg1 != AF_UNIX
1248 #if HAVE_IPV6
1249 		&& arg1 != AF_INET6
1250 #endif
1251 		&& arg1 != AF_INET) {
1252 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", arg1);
1253 		arg1 = AF_INET;
1254 	}
1255 
1256 	if (arg2 > 10) {
1257 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", arg2);
1258 		arg2 = SOCK_STREAM;
1259 	}
1260 
1261 	php_sock->bsd_socket = socket(arg1, arg2, arg3);
1262 	php_sock->type = arg1;
1263 
1264 	if (IS_INVALID_SOCKET(php_sock)) {
1265 		SOCKETS_G(last_error) = errno;
1266 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
1267 		efree(php_sock);
1268 		RETURN_FALSE;
1269 	}
1270 
1271 	php_sock->error = 0;
1272 	php_sock->blocking = 1;
1273 
1274 	ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);
1275 }
1276 /* }}} */
1277 
1278 /* {{{ proto bool socket_connect(resource socket, string addr [, int port])
1279    Opens a connection to addr:port on the socket specified by socket */
1280 PHP_FUNCTION(socket_connect)
1281 {
1282 	zval				*arg1;
1283 	php_socket			*php_sock;
1284 	struct sockaddr_in	sin;
1285 #if HAVE_IPV6
1286 	struct sockaddr_in6	sin6;
1287 #endif
1288 	struct sockaddr_un	s_un;
1289 	char				*addr;
1290 	int					retval, addr_len;
1291 	long				port = 0;
1292 	int					argc = ZEND_NUM_ARGS();
1293 
1294 	if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1295 		return;
1296 	}
1297 
1298 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1299 
1300 	switch(php_sock->type) {
1301 #if HAVE_IPV6
1302 		case AF_INET6:
1303 			if (argc != 3) {
1304 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
1305 				RETURN_FALSE;
1306 			}
1307 
1308 			memset(&sin6, 0, sizeof(struct sockaddr_in6));
1309 
1310 			sin6.sin6_family = AF_INET6;
1311 			sin6.sin6_port   = htons((unsigned short int)port);
1312 
1313 			if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
1314 				RETURN_FALSE;
1315 			}
1316 
1317 			retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
1318 			break;
1319 #endif
1320 		case AF_INET:
1321 			if (argc != 3) {
1322 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");
1323 				RETURN_FALSE;
1324 			}
1325 
1326 			memset(&sin, 0, sizeof(struct sockaddr_in));
1327 
1328 			sin.sin_family = AF_INET;
1329 			sin.sin_port   = htons((unsigned short int)port);
1330 
1331 			if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
1332 				RETURN_FALSE;
1333 			}
1334 
1335 			retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
1336 			break;
1337 
1338 		case AF_UNIX:
1339 			if (addr_len >= sizeof(s_un.sun_path)) {
1340 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long");
1341 				RETURN_FALSE;
1342 			}
1343 
1344 			memset(&s_un, 0, sizeof(struct sockaddr_un));
1345 
1346 			s_un.sun_family = AF_UNIX;
1347 			memcpy(&s_un.sun_path, addr, addr_len);
1348 			retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + addr_len);
1349 			break;
1350 
1351 		default:
1352 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1353 			RETURN_FALSE;
1354 		}
1355 
1356 	if (retval != 0) {
1357 		PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
1358 		RETURN_FALSE;
1359 	}
1360 
1361 	RETURN_TRUE;
1362 }
1363 /* }}} */
1364 
1365 /* {{{ proto string socket_strerror(int errno)
1366    Returns a string describing an error */
1367 PHP_FUNCTION(socket_strerror)
1368 {
1369 	long	arg1;
1370 
1371 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg1) == FAILURE) {
1372 		return;
1373 	}
1374 
1375 	RETURN_STRING(php_strerror(arg1 TSRMLS_CC), 1);
1376 }
1377 /* }}} */
1378 
1379 /* {{{ proto bool socket_bind(resource socket, string addr [, int port])
1380    Binds an open socket to a listening port, port is only specified in AF_INET family. */
1381 PHP_FUNCTION(socket_bind)
1382 {
1383 	zval					*arg1;
1384 	php_sockaddr_storage	sa_storage;
1385 	struct sockaddr			*sock_type = (struct sockaddr*) &sa_storage;
1386 	php_socket				*php_sock;
1387 	char					*addr;
1388 	int						addr_len;
1389 	long					port = 0;
1390 	long					retval = 0;
1391 
1392 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1393 		return;
1394 	}
1395 
1396 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1397 
1398 	switch(php_sock->type) {
1399 		case AF_UNIX:
1400 			{
1401 				struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
1402 				memset(sa, 0, sizeof(sa_storage));
1403 				sa->sun_family = AF_UNIX;
1404 				snprintf(sa->sun_path, 108, "%s", addr);
1405 				retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa, SUN_LEN(sa));
1406 				break;
1407 			}
1408 
1409 		case AF_INET:
1410 			{
1411 				struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
1412 
1413 				memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
1414 
1415 				sa->sin_family = AF_INET;
1416 				sa->sin_port = htons((unsigned short) port);
1417 
1418 				if (! php_set_inet_addr(sa, addr, php_sock TSRMLS_CC)) {
1419 					RETURN_FALSE;
1420 				}
1421 
1422 				retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
1423 				break;
1424 			}
1425 #if HAVE_IPV6
1426 		case AF_INET6:
1427 			{
1428 				struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
1429 
1430 				memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
1431 
1432 				sa->sin6_family = AF_INET6;
1433 				sa->sin6_port = htons((unsigned short) port);
1434 
1435 				if (! php_set_inet6_addr(sa, addr, php_sock TSRMLS_CC)) {
1436 					RETURN_FALSE;
1437 				}
1438 
1439 				retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
1440 				break;
1441 			}
1442 #endif
1443 		default:
1444 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
1445 			RETURN_FALSE;
1446 	}
1447 
1448 	if (retval != 0) {
1449 		PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
1450 		RETURN_FALSE;
1451 	}
1452 
1453 	RETURN_TRUE;
1454 }
1455 /* }}} */
1456 
1457 /* {{{ proto int socket_recv(resource socket, string &buf, int len, int flags)
1458    Receives data from a connected socket */
1459 PHP_FUNCTION(socket_recv)
1460 {
1461 	zval		*php_sock_res, *buf;
1462 	char		*recv_buf;
1463 	php_socket	*php_sock;
1464 	int			retval;
1465 	long		len, flags;
1466 
1467 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
1468 		return;
1469 	}
1470 
1471 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &php_sock_res, -1, le_socket_name, le_socket);
1472 
1473 	/* overflow check */
1474 	if ((len + 1) < 2) {
1475 		RETURN_FALSE;
1476 	}
1477 
1478 	recv_buf = emalloc(len + 1);
1479 	memset(recv_buf, 0, len + 1);
1480 
1481 	if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {
1482 		efree(recv_buf);
1483 
1484 		zval_dtor(buf);
1485 		Z_TYPE_P(buf) = IS_NULL;
1486 	} else {
1487 		recv_buf[retval] = '\0';
1488 
1489 		/* Rebuild buffer zval */
1490 		zval_dtor(buf);
1491 
1492 		Z_STRVAL_P(buf) = recv_buf;
1493 		Z_STRLEN_P(buf) = retval;
1494 		Z_TYPE_P(buf) = IS_STRING;
1495 	}
1496 
1497 	if (retval == -1) {
1498 		PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1499 		RETURN_FALSE;
1500 	}
1501 
1502 	RETURN_LONG(retval);
1503 }
1504 /* }}} */
1505 
1506 /* {{{ proto int socket_send(resource socket, string buf, int len, int flags)
1507    Sends data to a connected socket */
1508 PHP_FUNCTION(socket_send)
1509 {
1510 	zval		*arg1;
1511 	php_socket	*php_sock;
1512 	int			buf_len, retval;
1513 	long		len, flags;
1514 	char		*buf;
1515 
1516 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
1517 		return;
1518 	}
1519 
1520 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1521 
1522 	retval = send(php_sock->bsd_socket, buf, (buf_len < len ? buf_len : len), flags);
1523 
1524 	if (retval == -1) {
1525 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1526 		RETURN_FALSE;
1527 	}
1528 
1529 	RETURN_LONG(retval);
1530 }
1531 /* }}} */
1532 
1533 /* {{{ proto int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port])
1534    Receives data from a socket, connected or not */
1535 PHP_FUNCTION(socket_recvfrom)
1536 {
1537 	zval				*arg1, *arg2, *arg5, *arg6 = NULL;
1538 	php_socket			*php_sock;
1539 	struct sockaddr_un	s_un;
1540 	struct sockaddr_in	sin;
1541 #if HAVE_IPV6
1542 	struct sockaddr_in6	sin6;
1543 	char				addr6[INET6_ADDRSTRLEN];
1544 #endif
1545 	socklen_t			slen;
1546 	int					retval;
1547 	long				arg3, arg4;
1548 	char				*recv_buf, *address;
1549 
1550 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzllz|z", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
1551 		return;
1552 	}
1553 
1554 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1555 
1556 	/* overflow check */
1557 	if ((arg3 + 2) < 3) {
1558 		RETURN_FALSE;
1559 	}
1560 
1561 	recv_buf = emalloc(arg3 + 2);
1562 	memset(recv_buf, 0, arg3 + 2);
1563 
1564 	switch (php_sock->type) {
1565 		case AF_UNIX:
1566 			slen = sizeof(s_un);
1567 			s_un.sun_family = AF_UNIX;
1568 			retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
1569 
1570 			if (retval < 0) {
1571 				efree(recv_buf);
1572 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1573 				RETURN_FALSE;
1574 			}
1575 
1576 			zval_dtor(arg2);
1577 			zval_dtor(arg5);
1578 
1579 			ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1580 			ZVAL_STRING(arg5, s_un.sun_path, 1);
1581 			break;
1582 
1583 		case AF_INET:
1584 			slen = sizeof(sin);
1585 			memset(&sin, 0, slen);
1586 			sin.sin_family = AF_INET;
1587 
1588 			if (arg6 == NULL) {
1589 				efree(recv_buf);
1590 				WRONG_PARAM_COUNT;
1591 			}
1592 
1593 			retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
1594 
1595 			if (retval < 0) {
1596 				efree(recv_buf);
1597 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1598 				RETURN_FALSE;
1599 			}
1600 
1601 			zval_dtor(arg2);
1602 			zval_dtor(arg5);
1603 			zval_dtor(arg6);
1604 
1605 			address = inet_ntoa(sin.sin_addr);
1606 
1607 			ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1608 			ZVAL_STRING(arg5, address ? address : "0.0.0.0", 1);
1609 			ZVAL_LONG(arg6, ntohs(sin.sin_port));
1610 			break;
1611 #if HAVE_IPV6
1612 		case AF_INET6:
1613 			slen = sizeof(sin6);
1614 			memset(&sin6, 0, slen);
1615 			sin6.sin6_family = AF_INET6;
1616 
1617 			if (arg6 == NULL) {
1618 				efree(recv_buf);
1619 				WRONG_PARAM_COUNT;
1620 			}
1621 
1622 			retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
1623 
1624 			if (retval < 0) {
1625 				efree(recv_buf);
1626 				PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1627 				RETURN_FALSE;
1628 			}
1629 
1630 			zval_dtor(arg2);
1631 			zval_dtor(arg5);
1632 			zval_dtor(arg6);
1633 
1634 			memset(addr6, 0, INET6_ADDRSTRLEN);
1635 			inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
1636 
1637 			ZVAL_STRINGL(arg2, recv_buf, retval, 0);
1638 			ZVAL_STRING(arg5, addr6[0] ? addr6 : "::", 1);
1639 			ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
1640 			break;
1641 #endif
1642 		default:
1643 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1644 			RETURN_FALSE;
1645 	}
1646 
1647 	RETURN_LONG(retval);
1648 }
1649 /* }}} */
1650 
1651 /* {{{ proto int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port])
1652    Sends a message to a socket, whether it is connected or not */
1653 PHP_FUNCTION(socket_sendto)
1654 {
1655 	zval				*arg1;
1656 	php_socket			*php_sock;
1657 	struct sockaddr_un	s_un;
1658 	struct sockaddr_in	sin;
1659 #if HAVE_IPV6
1660 	struct sockaddr_in6	sin6;
1661 #endif
1662 	int					retval, buf_len, addr_len;
1663 	long				len, flags, port = 0;
1664 	char				*buf, *addr;
1665 	int					argc = ZEND_NUM_ARGS();
1666 
1667 	if (zend_parse_parameters(argc TSRMLS_CC, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
1668 		return;
1669 	}
1670 
1671 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1672 
1673 	switch (php_sock->type) {
1674 		case AF_UNIX:
1675 			memset(&s_un, 0, sizeof(s_un));
1676 			s_un.sun_family = AF_UNIX;
1677 			snprintf(s_un.sun_path, 108, "%s", addr);
1678 
1679 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len,	flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
1680 			break;
1681 
1682 		case AF_INET:
1683 			if (argc != 6) {
1684 				WRONG_PARAM_COUNT;
1685 			}
1686 
1687 			memset(&sin, 0, sizeof(sin));
1688 			sin.sin_family = AF_INET;
1689 			sin.sin_port = htons((unsigned short) port);
1690 
1691 			if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
1692 				RETURN_FALSE;
1693 			}
1694 
1695 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin, sizeof(sin));
1696 			break;
1697 #if HAVE_IPV6
1698 		case AF_INET6:
1699 			if (argc != 6) {
1700 				WRONG_PARAM_COUNT;
1701 			}
1702 
1703 			memset(&sin6, 0, sizeof(sin6));
1704 			sin6.sin6_family = AF_INET6;
1705 			sin6.sin6_port = htons((unsigned short) port);
1706 
1707 			if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
1708 				RETURN_FALSE;
1709 			}
1710 
1711 			retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
1712 			break;
1713 #endif
1714 		default:
1715 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
1716 			RETURN_FALSE;
1717 	}
1718 
1719 	if (retval == -1) {
1720 		PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1721 		RETURN_FALSE;
1722 	}
1723 
1724 	RETURN_LONG(retval);
1725 }
1726 /* }}} */
1727 
1728 /* {{{ proto mixed socket_get_option(resource socket, int level, int optname) U
1729    Gets socket options for the socket */
1730 PHP_FUNCTION(socket_get_option)
1731 {
1732 	zval			*arg1;
1733 	struct linger	linger_val;
1734 	struct timeval	tv;
1735 #ifdef PHP_WIN32
1736 	int				timeout = 0;
1737 #endif
1738 	socklen_t		optlen;
1739 	php_socket		*php_sock;
1740 	int				other_val;
1741 	long			level, optname;
1742 
1743 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &arg1, &level, &optname) == FAILURE) {
1744 		return;
1745 	}
1746 
1747 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1748 
1749 	switch(optname) {
1750 		case SO_LINGER:
1751 			optlen = sizeof(linger_val);
1752 
1753 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
1754 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1755 				RETURN_FALSE;
1756 			}
1757 
1758 			array_init(return_value);
1759 			add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
1760 			add_assoc_long(return_value, "l_linger", linger_val.l_linger);
1761 			break;
1762 
1763 		case SO_RCVTIMEO:
1764 		case SO_SNDTIMEO:
1765 #ifndef PHP_WIN32
1766 			optlen = sizeof(tv);
1767 
1768 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
1769 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1770 				RETURN_FALSE;
1771 			}
1772 #else
1773 			optlen = sizeof(int);
1774 
1775 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
1776 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1777 				RETURN_FALSE;
1778 			}
1779 
1780 			tv.tv_sec = timeout ? timeout / 1000 : 0;
1781 			tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;
1782 #endif
1783 
1784 			array_init(return_value);
1785 
1786 			add_assoc_long(return_value, "sec", tv.tv_sec);
1787 			add_assoc_long(return_value, "usec", tv.tv_usec);
1788 			break;
1789 
1790 		default:
1791 			optlen = sizeof(other_val);
1792 
1793 			if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
1794 				PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
1795 				RETURN_FALSE;
1796 			}
1797 
1798 			RETURN_LONG(other_val);
1799 			break;
1800 	}
1801 }
1802 /* }}} */
1803 
1804 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
1805    Sets socket options for the socket */
1806 PHP_FUNCTION(socket_set_option)
1807 {
1808 	zval			*arg1, **arg4;
1809 	struct linger	lv;
1810 	php_socket		*php_sock;
1811 	int				ov, optlen, retval;
1812 #ifdef PHP_WIN32
1813 	int				timeout;
1814 #else
1815 	struct			timeval tv;
1816 #endif
1817 	long			level, optname;
1818 	void 			*opt_ptr;
1819 	HashTable 		*opt_ht;
1820 	zval 			**l_onoff, **l_linger;
1821 	zval 			**sec, **usec;
1822 	/* key name constants */
1823 	char			*l_onoff_key = "l_onoff";
1824 	char			*l_linger_key = "l_linger";
1825 	char			*sec_key = "sec";
1826 	char			*usec_key = "usec";
1827 
1828 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, &level, &optname, &arg4) == FAILURE) {
1829 		return;
1830 	}
1831 
1832 	ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
1833 
1834 	set_errno(0);
1835 
1836 	switch (optname) {
1837 		case SO_LINGER:
1838 			convert_to_array_ex(arg4);
1839 			opt_ht = HASH_OF(*arg4);
1840 
1841 			if (zend_hash_find(opt_ht, l_onoff_key, strlen(l_onoff_key) + 1, (void **)&l_onoff) == FAILURE) {
1842 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
1843 				RETURN_FALSE;
1844 			}
1845 			if (zend_hash_find(opt_ht, l_linger_key, strlen(l_linger_key) + 1, (void **)&l_linger) == FAILURE) {
1846 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
1847 				RETURN_FALSE;
1848 			}
1849 
1850 			convert_to_long_ex(l_onoff);
1851 			convert_to_long_ex(l_linger);
1852 
1853 			lv.l_onoff = (unsigned short)Z_LVAL_PP(l_onoff);
1854 			lv.l_linger = (unsigned short)Z_LVAL_PP(l_linger);
1855 
1856 			optlen = sizeof(lv);
1857 			opt_ptr = &lv;
1858 			break;
1859 
1860 		case SO_RCVTIMEO:
1861 		case SO_SNDTIMEO:
1862 			convert_to_array_ex(arg4);
1863 			opt_ht = HASH_OF(*arg4);
1864 
1865 			if (zend_hash_find(opt_ht, sec_key, strlen(sec_key) + 1, (void **)&sec) == FAILURE) {
1866 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", sec_key);
1867 				RETURN_FALSE;
1868 			}
1869 			if (zend_hash_find(opt_ht, usec_key, strlen(usec_key) + 1, (void **)&usec) == FAILURE) {
1870 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", usec_key);
1871 				RETURN_FALSE;
1872 			}
1873 
1874 			convert_to_long_ex(sec);
1875 			convert_to_long_ex(usec);
1876 #ifndef PHP_WIN32
1877 			tv.tv_sec = Z_LVAL_PP(sec);
1878 			tv.tv_usec = Z_LVAL_PP(usec);
1879 			optlen = sizeof(tv);
1880 			opt_ptr = &tv;
1881 #else
1882 			timeout = Z_LVAL_PP(sec) * 1000 + Z_LVAL_PP(usec) / 1000;
1883 			optlen = sizeof(int);
1884 			opt_ptr = &timeout;
1885 #endif
1886 			break;
1887 
1888 		default:
1889 			convert_to_long_ex(arg4);
1890 			ov = Z_LVAL_PP(arg4);
1891 
1892 			optlen = sizeof(ov);
1893 			opt_ptr = &ov;
1894 			break;
1895 	}
1896 
1897 	retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
1898 
1899 	if (retval != 0) {
1900 		PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
1901 		RETURN_FALSE;
1902 	}
1903 
1904 	RETURN_TRUE;
1905 }
1906 /* }}} */
1907 
1908 #ifdef HAVE_SOCKETPAIR
1909 /* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd) U
1910    Creates a pair of indistinguishable sockets and stores them in fds. */
1911 PHP_FUNCTION(socket_create_pair)
1912 {
1913 	zval		*retval[2], *fds_array_zval;
1914 	php_socket	*php_sock[2];
1915 	PHP_SOCKET	fds_array[2];
1916 	long		domain, type, protocol;
1917 
1918 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lllz", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
1919 		return;
1920 	}
1921 
1922 	php_sock[0] = (php_socket*)emalloc(sizeof(php_socket));
1923 	php_sock[1] = (php_socket*)emalloc(sizeof(php_socket));
1924 
1925 	if (domain != AF_INET
1926 #if HAVE_IPV6
1927 		&& domain != AF_INET6
1928 #endif
1929 		&& domain != AF_UNIX) {
1930 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", domain);
1931 		domain = AF_INET;
1932 	}
1933 
1934 	if (type > 10) {
1935 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", type);
1936 		type = SOCK_STREAM;
1937 	}
1938 
1939 	if (socketpair(domain, type, protocol, fds_array) != 0) {
1940 		SOCKETS_G(last_error) = errno;
1941 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create socket pair [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
1942 		efree(php_sock[0]);
1943 		efree(php_sock[1]);
1944 		RETURN_FALSE;
1945 	}
1946 
1947 	zval_dtor(fds_array_zval);
1948 	array_init(fds_array_zval);
1949 
1950 	MAKE_STD_ZVAL(retval[0]);
1951 	MAKE_STD_ZVAL(retval[1]);
1952 
1953 	php_sock[0]->bsd_socket = fds_array[0];
1954 	php_sock[1]->bsd_socket = fds_array[1];
1955 	php_sock[0]->type		= domain;
1956 	php_sock[1]->type		= domain;
1957 	php_sock[0]->error		= 0;
1958 	php_sock[1]->error		= 0;
1959 	php_sock[0]->blocking	= 1;
1960 	php_sock[1]->blocking	= 1;
1961 
1962 	ZEND_REGISTER_RESOURCE(retval[0], php_sock[0], le_socket);
1963 	ZEND_REGISTER_RESOURCE(retval[1], php_sock[1], le_socket);
1964 
1965 	add_index_zval(fds_array_zval, 0, retval[0]);
1966 	add_index_zval(fds_array_zval, 1, retval[1]);
1967 
1968 	RETURN_TRUE;
1969 }
1970 /* }}} */
1971 #endif
1972 
1973 #ifdef HAVE_SHUTDOWN
1974 /* {{{ proto bool socket_shutdown(resource socket[, int how]) U
1975    Shuts down a socket for receiving, sending, or both. */
1976 PHP_FUNCTION(socket_shutdown)
1977 {
1978 	zval		*arg1;
1979 	long		how_shutdown = 2;
1980 	php_socket	*php_sock;
1981 
1982 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &how_shutdown) == FAILURE) {
1983 		return;
1984 	}
1985 
1986 	ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
1987 
1988 	if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
1989 		PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
1990 		RETURN_FALSE;
1991 	}
1992 
1993 	RETURN_TRUE;
1994 }
1995 /* }}} */
1996 #endif
1997 
1998 /* {{{ proto int socket_last_error([resource socket]) U
1999    Returns the last socket error (either the last used or the provided socket resource) */
2000 PHP_FUNCTION(socket_last_error)
2001 {
2002 	zval		*arg1 = NULL;
2003 	php_socket	*php_sock;
2004 
2005 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
2006 		return;
2007 	}
2008 
2009 	if (arg1) {
2010 		ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2011 		RETVAL_LONG(php_sock->error);
2012 	} else {
2013 		RETVAL_LONG(SOCKETS_G(last_error));
2014 	}
2015 }
2016 /* }}} */
2017 
2018 /* {{{ proto void socket_clear_error([resource socket]) U
2019    Clears the error on the socket or the last error code. */
2020 PHP_FUNCTION(socket_clear_error)
2021 {
2022 	zval		*arg1 = NULL;
2023 	php_socket	*php_sock;
2024 
2025 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) {
2026 		return;
2027 	}
2028 
2029 	if (arg1) {
2030 		ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket);
2031 		php_sock->error = 0;
2032 	} else {
2033 		SOCKETS_G(last_error) = 0;
2034 	}
2035 
2036 	return;
2037 }
2038 /* }}} */
2039 
2040 #endif
2041 
2042 /*
2043  * Local variables:
2044  * tab-width: 4
2045  * c-basic-offset: 4
2046  * End:
2047  * vim600: fdm=marker
2048  * vim: noet sw=4 ts=4
2049  */
2050