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