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