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