1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Chris Vandomelen <chrisv@b0rked.dhs.org> |
16 | Sterling Hughes <sterling@php.net> |
17 | Jason Greene <jason@php.net> |
18 | Gustavo Lopes <cataphract@php.net> |
19 | WinSock: Daniel Beulshausen <daniel@php4win.de> |
20 +----------------------------------------------------------------------+
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "php.h"
28
29 #include "php_network.h"
30 #include "ext/standard/file.h"
31 #include "ext/standard/info.h"
32 #include "php_ini.h"
33 #ifdef PHP_WIN32
34 # include "windows_common.h"
35 # include <win32/inet.h>
36 # include <windows.h>
37 # include <Ws2tcpip.h>
38 # include "php_sockets.h"
39 # include <win32/sockets.h>
40 #else
41 # include <sys/types.h>
42 # include <sys/socket.h>
43 # include <netdb.h>
44 # include <netinet/in.h>
45 # include <netinet/tcp.h>
46 # include <sys/un.h>
47 # include <arpa/inet.h>
48 # include <sys/time.h>
49 # include <unistd.h>
50 # include <errno.h>
51 # include <fcntl.h>
52 # include <signal.h>
53 # include <sys/uio.h>
54 # define IS_INVALID_SOCKET(a) (a->bsd_socket < 0)
55 # define set_errno(a) (errno = a)
56 # include "php_sockets.h"
57 # if HAVE_IF_NAMETOINDEX
58 # include <net/if.h>
59 # endif
60 #endif
61
62 #include <stddef.h>
63
64 #include "sockaddr_conv.h"
65 #include "multicast.h"
66 #include "sendrecvmsg.h"
67
68 ZEND_DECLARE_MODULE_GLOBALS(sockets)
69
70 #ifndef MSG_WAITALL
71 #ifdef LINUX
72 #define MSG_WAITALL 0x00000100
73 #else
74 #define MSG_WAITALL 0x00000000
75 #endif
76 #endif
77
78 #ifndef MSG_EOF
79 #ifdef MSG_FIN
80 #define MSG_EOF MSG_FIN
81 #endif
82 #endif
83
84 #ifndef SUN_LEN
85 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
86 #endif
87
88 #ifndef PF_INET
89 #define PF_INET AF_INET
90 #endif
91
92 #define PHP_NORMAL_READ 0x0001
93 #define PHP_BINARY_READ 0x0002
94
95 static int le_socket;
96 #define le_socket_name php_sockets_le_socket_name
97
98 static int le_addrinfo;
99 #define le_addrinfo_name php_sockets_le_addrinfo_name
100
101 /* {{{ arginfo */
102 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_select, 0, 0, 4)
103 ZEND_ARG_INFO(1, read_fds)
104 ZEND_ARG_INFO(1, write_fds)
105 ZEND_ARG_INFO(1, except_fds)
106 ZEND_ARG_INFO(0, tv_sec)
107 ZEND_ARG_INFO(0, tv_usec)
108 ZEND_END_ARG_INFO()
109
110 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_listen, 0, 0, 1)
111 ZEND_ARG_INFO(0, port)
112 ZEND_ARG_INFO(0, backlog)
113 ZEND_END_ARG_INFO()
114
115 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_accept, 0, 0, 1)
116 ZEND_ARG_INFO(0, socket)
117 ZEND_END_ARG_INFO()
118
119 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_nonblock, 0, 0, 1)
120 ZEND_ARG_INFO(0, socket)
121 ZEND_END_ARG_INFO()
122
123 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_block, 0, 0, 1)
124 ZEND_ARG_INFO(0, socket)
125 ZEND_END_ARG_INFO()
126
127 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_listen, 0, 0, 1)
128 ZEND_ARG_INFO(0, socket)
129 ZEND_ARG_INFO(0, backlog)
130 ZEND_END_ARG_INFO()
131
132 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_close, 0, 0, 1)
133 ZEND_ARG_INFO(0, socket)
134 ZEND_END_ARG_INFO()
135
136 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_write, 0, 0, 2)
137 ZEND_ARG_INFO(0, socket)
138 ZEND_ARG_INFO(0, buf)
139 ZEND_ARG_INFO(0, length)
140 ZEND_END_ARG_INFO()
141
142 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_read, 0, 0, 2)
143 ZEND_ARG_INFO(0, socket)
144 ZEND_ARG_INFO(0, length)
145 ZEND_ARG_INFO(0, type)
146 ZEND_END_ARG_INFO()
147
148 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getsockname, 0, 0, 2)
149 ZEND_ARG_INFO(0, socket)
150 ZEND_ARG_INFO(1, addr)
151 ZEND_ARG_INFO(1, port)
152 ZEND_END_ARG_INFO()
153
154 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_getpeername, 0, 0, 2)
155 ZEND_ARG_INFO(0, socket)
156 ZEND_ARG_INFO(1, addr)
157 ZEND_ARG_INFO(1, port)
158 ZEND_END_ARG_INFO()
159
160 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create, 0, 0, 3)
161 ZEND_ARG_INFO(0, domain)
162 ZEND_ARG_INFO(0, type)
163 ZEND_ARG_INFO(0, protocol)
164 ZEND_END_ARG_INFO()
165
166 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_connect, 0, 0, 2)
167 ZEND_ARG_INFO(0, socket)
168 ZEND_ARG_INFO(0, addr)
169 ZEND_ARG_INFO(0, port)
170 ZEND_END_ARG_INFO()
171
172 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_strerror, 0, 0, 1)
173 ZEND_ARG_INFO(0, errno)
174 ZEND_END_ARG_INFO()
175
176 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_bind, 0, 0, 2)
177 ZEND_ARG_INFO(0, socket)
178 ZEND_ARG_INFO(0, addr)
179 ZEND_ARG_INFO(0, port)
180 ZEND_END_ARG_INFO()
181
182 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recv, 0, 0, 4)
183 ZEND_ARG_INFO(0, socket)
184 ZEND_ARG_INFO(1, buf)
185 ZEND_ARG_INFO(0, len)
186 ZEND_ARG_INFO(0, flags)
187 ZEND_END_ARG_INFO()
188
189 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_send, 0, 0, 4)
190 ZEND_ARG_INFO(0, socket)
191 ZEND_ARG_INFO(0, buf)
192 ZEND_ARG_INFO(0, len)
193 ZEND_ARG_INFO(0, flags)
194 ZEND_END_ARG_INFO()
195
196 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvfrom, 0, 0, 5)
197 ZEND_ARG_INFO(0, socket)
198 ZEND_ARG_INFO(1, buf)
199 ZEND_ARG_INFO(0, len)
200 ZEND_ARG_INFO(0, flags)
201 ZEND_ARG_INFO(1, name)
202 ZEND_ARG_INFO(1, port)
203 ZEND_END_ARG_INFO()
204
205 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendto, 0, 0, 5)
206 ZEND_ARG_INFO(0, socket)
207 ZEND_ARG_INFO(0, buf)
208 ZEND_ARG_INFO(0, len)
209 ZEND_ARG_INFO(0, flags)
210 ZEND_ARG_INFO(0, addr)
211 ZEND_ARG_INFO(0, port)
212 ZEND_END_ARG_INFO()
213
214 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_get_option, 0, 0, 3)
215 ZEND_ARG_INFO(0, socket)
216 ZEND_ARG_INFO(0, level)
217 ZEND_ARG_INFO(0, optname)
218 ZEND_END_ARG_INFO()
219
220 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_set_option, 0, 0, 4)
221 ZEND_ARG_INFO(0, socket)
222 ZEND_ARG_INFO(0, level)
223 ZEND_ARG_INFO(0, optname)
224 ZEND_ARG_INFO(0, optval)
225 ZEND_END_ARG_INFO()
226
227 #ifdef HAVE_SOCKETPAIR
228 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_create_pair, 0, 0, 4)
229 ZEND_ARG_INFO(0, domain)
230 ZEND_ARG_INFO(0, type)
231 ZEND_ARG_INFO(0, protocol)
232 ZEND_ARG_INFO(1, fd)
233 ZEND_END_ARG_INFO()
234 #endif
235
236 #ifdef HAVE_SHUTDOWN
237 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_shutdown, 0, 0, 1)
238 ZEND_ARG_INFO(0, socket)
239 ZEND_ARG_INFO(0, how)
240 ZEND_END_ARG_INFO()
241 #endif
242
243 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_last_error, 0, 0, 0)
244 ZEND_ARG_INFO(0, socket)
245 ZEND_END_ARG_INFO()
246
247 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
248 ZEND_ARG_INFO(0, socket)
249 ZEND_END_ARG_INFO()
250
251 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1)
252 ZEND_ARG_INFO(0, stream)
253 ZEND_END_ARG_INFO()
254
255 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_export_stream, 0, 0, 1)
256 ZEND_ARG_INFO(0, socket)
257 ZEND_END_ARG_INFO()
258
259 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendmsg, 0, 0, 3)
260 ZEND_ARG_INFO(0, socket)
261 ZEND_ARG_INFO(0, msghdr)
262 ZEND_ARG_INFO(0, flags)
263 ZEND_END_ARG_INFO()
264
265 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvmsg, 0, 0, 3)
266 ZEND_ARG_INFO(0, socket)
267 ZEND_ARG_INFO(1, msghdr)
268 ZEND_ARG_INFO(0, flags)
269 ZEND_END_ARG_INFO()
270
271 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_cmsg_space, 0, 0, 2)
272 ZEND_ARG_INFO(0, level)
273 ZEND_ARG_INFO(0, type)
274 ZEND_END_ARG_INFO()
275
276 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_lookup, 0, 0, 1)
277 ZEND_ARG_INFO(0, host)
278 ZEND_ARG_INFO(0, service)
279 ZEND_ARG_INFO(0, hints)
280 ZEND_END_ARG_INFO()
281
282 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_connect, 0, 0, 1)
283 ZEND_ARG_INFO(0, addr)
284 ZEND_END_ARG_INFO()
285
286 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_bind, 0, 0, 1)
287 ZEND_ARG_INFO(0, addr)
288 ZEND_END_ARG_INFO()
289
290 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_addrinfo_explain, 0, 0, 1)
291 ZEND_ARG_INFO(0, addr)
292 ZEND_END_ARG_INFO()
293
294 #ifdef PHP_WIN32
295 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_wsaprotocol_info_export, 0, 0, 2)
296 ZEND_ARG_INFO(0, socket)
297 ZEND_ARG_INFO(0, target_pid)
298 ZEND_END_ARG_INFO()
299
300 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_wsaprotocol_info_import, 0, 0, 1)
301 ZEND_ARG_INFO(0, info_id)
302 ZEND_END_ARG_INFO()
303
304 ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_wsaprotocol_info_release, 0, 0, 1)
305 ZEND_ARG_INFO(0, info_id)
306 ZEND_END_ARG_INFO()
307 #endif
308 /* }}} */
309
310 static PHP_GINIT_FUNCTION(sockets);
311 static PHP_GSHUTDOWN_FUNCTION(sockets);
312 static PHP_MINIT_FUNCTION(sockets);
313 static PHP_MSHUTDOWN_FUNCTION(sockets);
314 static PHP_MINFO_FUNCTION(sockets);
315 static PHP_RSHUTDOWN_FUNCTION(sockets);
316
317 PHP_FUNCTION(socket_select);
318 PHP_FUNCTION(socket_create_listen);
319 #ifdef HAVE_SOCKETPAIR
320 PHP_FUNCTION(socket_create_pair);
321 #endif
322 PHP_FUNCTION(socket_accept);
323 PHP_FUNCTION(socket_set_nonblock);
324 PHP_FUNCTION(socket_set_block);
325 PHP_FUNCTION(socket_listen);
326 PHP_FUNCTION(socket_close);
327 PHP_FUNCTION(socket_write);
328 PHP_FUNCTION(socket_read);
329 PHP_FUNCTION(socket_getsockname);
330 PHP_FUNCTION(socket_getpeername);
331 PHP_FUNCTION(socket_create);
332 PHP_FUNCTION(socket_connect);
333 PHP_FUNCTION(socket_strerror);
334 PHP_FUNCTION(socket_bind);
335 PHP_FUNCTION(socket_recv);
336 PHP_FUNCTION(socket_send);
337 PHP_FUNCTION(socket_recvfrom);
338 PHP_FUNCTION(socket_sendto);
339 PHP_FUNCTION(socket_get_option);
340 PHP_FUNCTION(socket_set_option);
341 #ifdef HAVE_SHUTDOWN
342 PHP_FUNCTION(socket_shutdown);
343 #endif
344 PHP_FUNCTION(socket_last_error);
345 PHP_FUNCTION(socket_clear_error);
346 PHP_FUNCTION(socket_import_stream);
347 PHP_FUNCTION(socket_export_stream);
348 PHP_FUNCTION(socket_addrinfo_lookup);
349 PHP_FUNCTION(socket_addrinfo_connect);
350 PHP_FUNCTION(socket_addrinfo_bind);
351 PHP_FUNCTION(socket_addrinfo_explain);
352 #ifdef PHP_WIN32
353 PHP_FUNCTION(socket_wsaprotocol_info_export);
354 PHP_FUNCTION(socket_wsaprotocol_info_import);
355 PHP_FUNCTION(socket_wsaprotocol_info_release);
356 #endif
357
358 /* {{{ sockets_functions[]
359 */
360 static const zend_function_entry sockets_functions[] = {
361 PHP_FE(socket_select, arginfo_socket_select)
362 PHP_FE(socket_create, arginfo_socket_create)
363 PHP_FE(socket_create_listen, arginfo_socket_create_listen)
364 #ifdef HAVE_SOCKETPAIR
365 PHP_FE(socket_create_pair, arginfo_socket_create_pair)
366 #endif
367 PHP_FE(socket_accept, arginfo_socket_accept)
368 PHP_FE(socket_set_nonblock, arginfo_socket_set_nonblock)
369 PHP_FE(socket_set_block, arginfo_socket_set_block)
370 PHP_FE(socket_listen, arginfo_socket_listen)
371 PHP_FE(socket_close, arginfo_socket_close)
372 PHP_FE(socket_write, arginfo_socket_write)
373 PHP_FE(socket_read, arginfo_socket_read)
374 PHP_FE(socket_getsockname, arginfo_socket_getsockname)
375 PHP_FE(socket_getpeername, arginfo_socket_getpeername)
376 PHP_FE(socket_connect, arginfo_socket_connect)
377 PHP_FE(socket_strerror, arginfo_socket_strerror)
378 PHP_FE(socket_bind, arginfo_socket_bind)
379 PHP_FE(socket_recv, arginfo_socket_recv)
380 PHP_FE(socket_send, arginfo_socket_send)
381 PHP_FE(socket_recvfrom, arginfo_socket_recvfrom)
382 PHP_FE(socket_sendto, arginfo_socket_sendto)
383 PHP_FE(socket_get_option, arginfo_socket_get_option)
384 PHP_FE(socket_set_option, arginfo_socket_set_option)
385 #ifdef HAVE_SHUTDOWN
386 PHP_FE(socket_shutdown, arginfo_socket_shutdown)
387 #endif
388 PHP_FE(socket_last_error, arginfo_socket_last_error)
389 PHP_FE(socket_clear_error, arginfo_socket_clear_error)
390 PHP_FE(socket_import_stream, arginfo_socket_import_stream)
391 PHP_FE(socket_export_stream, arginfo_socket_export_stream)
392 PHP_FE(socket_sendmsg, arginfo_socket_sendmsg)
393 PHP_FE(socket_recvmsg, arginfo_socket_recvmsg)
394 PHP_FE(socket_cmsg_space, arginfo_socket_cmsg_space)
395 PHP_FE(socket_addrinfo_lookup, arginfo_socket_addrinfo_lookup)
396 PHP_FE(socket_addrinfo_connect, arginfo_socket_addrinfo_connect)
397 PHP_FE(socket_addrinfo_bind, arginfo_socket_addrinfo_bind)
398 PHP_FE(socket_addrinfo_explain, arginfo_socket_addrinfo_explain)
399
400 /* for downwards compatibility */
401 PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)
402 PHP_FALIAS(socket_setopt, socket_set_option, arginfo_socket_set_option)
403
404 #ifdef PHP_WIN32
405 PHP_FE(socket_wsaprotocol_info_export, arginfo_socket_wsaprotocol_info_export)
406 PHP_FE(socket_wsaprotocol_info_import, arginfo_socket_wsaprotocol_info_import)
407 PHP_FE(socket_wsaprotocol_info_release, arginfo_socket_wsaprotocol_info_release)
408 #endif
409
410 PHP_FE_END
411 };
412 /* }}} */
413
414 zend_module_entry sockets_module_entry = {
415 STANDARD_MODULE_HEADER,
416 "sockets",
417 sockets_functions,
418 PHP_MINIT(sockets),
419 PHP_MSHUTDOWN(sockets),
420 NULL,
421 PHP_RSHUTDOWN(sockets),
422 PHP_MINFO(sockets),
423 PHP_SOCKETS_VERSION,
424 PHP_MODULE_GLOBALS(sockets),
425 PHP_GINIT(sockets),
426 PHP_GSHUTDOWN(sockets),
427 NULL,
428 STANDARD_MODULE_PROPERTIES_EX
429 };
430
431
432 #ifdef COMPILE_DL_SOCKETS
433 #ifdef ZTS
434 ZEND_TSRMLS_CACHE_DEFINE()
435 #endif
436 ZEND_GET_MODULE(sockets)
437 #endif
438
439 /* inet_ntop should be used instead of inet_ntoa */
440 int inet_ntoa_lock = 0;
441
php_sockets_le_socket(void)442 PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{ */
443 {
444 return le_socket;
445 }
446 /* }}} */
447
448 /* allocating function to make programming errors due to uninitialized fields
449 * less likely */
php_create_socket(void)450 PHP_SOCKETS_API php_socket *php_create_socket(void) /* {{{ */
451 {
452 php_socket *php_sock = emalloc(sizeof(php_socket));
453
454 php_sock->bsd_socket = -1; /* invalid socket */
455 php_sock->type = PF_UNSPEC;
456 php_sock->error = 0;
457 php_sock->blocking = 1;
458 ZVAL_UNDEF(&php_sock->zstream);
459
460 return php_sock;
461 }
462 /* }}} */
463
php_destroy_socket(zend_resource * rsrc)464 PHP_SOCKETS_API void php_destroy_socket(zend_resource *rsrc) /* {{{ */
465 {
466 php_socket *php_sock = rsrc->ptr;
467
468 if (Z_ISUNDEF(php_sock->zstream)) {
469 if (!IS_INVALID_SOCKET(php_sock)) {
470 close(php_sock->bsd_socket);
471 }
472 } else {
473 zval_ptr_dtor(&php_sock->zstream);
474 }
475 efree(php_sock);
476 }
477 /* }}} */
478
php_destroy_addrinfo(zend_resource * rsrc)479 PHP_SOCKETS_API void php_destroy_addrinfo(zend_resource *rsrc) /* {{{ */
480 {
481 struct addrinfo *addr = rsrc->ptr;
482 efree(addr->ai_addr);
483 if (addr->ai_canonname != NULL) {
484 efree(addr->ai_canonname);
485 }
486 efree(addr);
487 }
488 /* }}} */
489
php_open_listen_sock(php_socket ** php_sock,int port,int backlog)490 static int php_open_listen_sock(php_socket **php_sock, int port, int backlog) /* {{{ */
491 {
492 struct sockaddr_in la;
493 struct hostent *hp;
494 php_socket *sock = php_create_socket();
495
496 *php_sock = sock;
497
498 #ifndef PHP_WIN32
499 if ((hp = php_network_gethostbyname("0.0.0.0")) == NULL) {
500 #else
501 if ((hp = php_network_gethostbyname("localhost")) == NULL) {
502 #endif
503 efree(sock);
504 return 0;
505 }
506
507 memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length);
508 la.sin_family = hp->h_addrtype;
509 la.sin_port = htons((unsigned short) port);
510
511 sock->bsd_socket = socket(PF_INET, SOCK_STREAM, 0);
512 sock->blocking = 1;
513
514 if (IS_INVALID_SOCKET(sock)) {
515 PHP_SOCKET_ERROR(sock, "unable to create listening socket", errno);
516 efree(sock);
517 return 0;
518 }
519
520 sock->type = PF_INET;
521
522 if (bind(sock->bsd_socket, (struct sockaddr *)&la, sizeof(la)) != 0) {
523 PHP_SOCKET_ERROR(sock, "unable to bind to given address", errno);
524 close(sock->bsd_socket);
525 efree(sock);
526 return 0;
527 }
528
529 if (listen(sock->bsd_socket, backlog) != 0) {
530 PHP_SOCKET_ERROR(sock, "unable to listen on socket", errno);
531 close(sock->bsd_socket);
532 efree(sock);
533 return 0;
534 }
535
536 return 1;
537 }
538 /* }}} */
539
540 static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la, socklen_t *la_len) /* {{{ */
541 {
542 php_socket *out_sock = php_create_socket();
543
544 *new_sock = out_sock;
545
546 out_sock->bsd_socket = accept(in_sock->bsd_socket, la, la_len);
547
548 if (IS_INVALID_SOCKET(out_sock)) {
549 PHP_SOCKET_ERROR(out_sock, "unable to accept incoming connection", errno);
550 efree(out_sock);
551 return 0;
552 }
553
554 out_sock->error = 0;
555 out_sock->blocking = 1;
556 out_sock->type = la->sa_family;
557
558 return 1;
559 }
560 /* }}} */
561
562 /* {{{ php_read -- wrapper around read() so that it only reads to a \r or \n. */
563 static int php_read(php_socket *sock, void *buf, size_t maxlen, int flags)
564 {
565 int m = 0;
566 size_t n = 0;
567 int no_read = 0;
568 int nonblock = 0;
569 char *t = (char *) buf;
570
571 #ifndef PHP_WIN32
572 m = fcntl(sock->bsd_socket, F_GETFL);
573 if (m < 0) {
574 return m;
575 }
576 nonblock = (m & O_NONBLOCK);
577 m = 0;
578 #else
579 nonblock = !sock->blocking;
580 #endif
581 set_errno(0);
582
583 *t = '\0';
584 while (*t != '\n' && *t != '\r' && n < maxlen) {
585 if (m > 0) {
586 t++;
587 n++;
588 } else if (m == 0) {
589 no_read++;
590 if (nonblock && no_read >= 2) {
591 return n;
592 /* The first pass, m always is 0, so no_read becomes 1
593 * in the first pass. no_read becomes 2 in the second pass,
594 * and if this is nonblocking, we should return.. */
595 }
596
597 if (no_read > 200) {
598 set_errno(ECONNRESET);
599 return -1;
600 }
601 }
602
603 if (n < maxlen) {
604 m = recv(sock->bsd_socket, (void *) t, 1, flags);
605 }
606
607 if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
608 return -1;
609 }
610
611 set_errno(0);
612 }
613
614 if (n < maxlen) {
615 n++;
616 /* The only reasons it makes it to here is
617 * if '\n' or '\r' are encountered. So, increase
618 * the return by 1 to make up for the lack of the
619 * '\n' or '\r' in the count (since read() takes
620 * place at the end of the loop..) */
621 }
622
623 return n;
624 }
625 /* }}} */
626
627 char *sockets_strerror(int error) /* {{{ */
628 {
629 const char *buf;
630
631 #ifndef PHP_WIN32
632 if (error < -10000) {
633 error = -error - 10000;
634
635 #ifdef HAVE_HSTRERROR
636 buf = hstrerror(error);
637 #else
638 {
639 if (SOCKETS_G(strerror_buf)) {
640 efree(SOCKETS_G(strerror_buf));
641 }
642
643 spprintf(&(SOCKETS_G(strerror_buf)), 0, "Host lookup error %d", error);
644 buf = SOCKETS_G(strerror_buf);
645 }
646 #endif
647 } else {
648 buf = strerror(error);
649 }
650 #else
651 {
652 LPTSTR tmp = NULL;
653 buf = NULL;
654
655 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
656 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &tmp, 0, NULL)
657 ) {
658 if (SOCKETS_G(strerror_buf)) {
659 efree(SOCKETS_G(strerror_buf));
660 }
661
662 SOCKETS_G(strerror_buf) = estrdup(tmp);
663 LocalFree(tmp);
664
665 buf = SOCKETS_G(strerror_buf);
666 }
667 }
668 #endif
669
670 return (buf ? (char *) buf : "");
671 }
672 /* }}} */
673
674 #ifdef PHP_WIN32
675 static void sockets_destroy_wsa_info(zval *data)
676 {/*{{{*/
677 HANDLE h = (HANDLE)Z_PTR_P(data);
678 CloseHandle(h);
679 }/*}}}*/
680 #endif
681
682 /* {{{ PHP_GINIT_FUNCTION */
683 static PHP_GINIT_FUNCTION(sockets)
684 {
685 #if defined(COMPILE_DL_SOCKETS) && defined(ZTS)
686 ZEND_TSRMLS_CACHE_UPDATE();
687 #endif
688 sockets_globals->last_error = 0;
689 sockets_globals->strerror_buf = NULL;
690 #ifdef PHP_WIN32
691 sockets_globals->wsa_child_count = 0;
692 zend_hash_init(&sockets_globals->wsa_info, 0, NULL, sockets_destroy_wsa_info, 1);
693 #endif
694 }
695 /* }}} */
696
697 /* {{{ PHP_GSHUTDOWN_FUNCTION */
698 static PHP_GSHUTDOWN_FUNCTION(sockets)
699 {
700 #ifdef PHP_WIN32
701 zend_hash_destroy(&sockets_globals->wsa_info);
702 #endif
703 }
704 /* }}} */
705
706 /* {{{ PHP_MINIT_FUNCTION
707 */
708 static PHP_MINIT_FUNCTION(sockets)
709 {
710 #if defined(COMPILE_DL_SOCKETS) && defined(ZTS)
711 ZEND_TSRMLS_CACHE_UPDATE();
712 #endif
713 le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number);
714 le_addrinfo = zend_register_list_destructors_ex(php_destroy_addrinfo, NULL, le_addrinfo_name, module_number);
715
716 REGISTER_LONG_CONSTANT("AF_UNIX", AF_UNIX, CONST_CS | CONST_PERSISTENT);
717 REGISTER_LONG_CONSTANT("AF_INET", AF_INET, CONST_CS | CONST_PERSISTENT);
718 #if HAVE_IPV6
719 REGISTER_LONG_CONSTANT("AF_INET6", AF_INET6, CONST_CS | CONST_PERSISTENT);
720 #endif
721 REGISTER_LONG_CONSTANT("SOCK_STREAM", SOCK_STREAM, CONST_CS | CONST_PERSISTENT);
722 REGISTER_LONG_CONSTANT("SOCK_DGRAM", SOCK_DGRAM, CONST_CS | CONST_PERSISTENT);
723 REGISTER_LONG_CONSTANT("SOCK_RAW", SOCK_RAW, CONST_CS | CONST_PERSISTENT);
724 REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT);
725 REGISTER_LONG_CONSTANT("SOCK_RDM", SOCK_RDM, CONST_CS | CONST_PERSISTENT);
726
727 REGISTER_LONG_CONSTANT("MSG_OOB", MSG_OOB, CONST_CS | CONST_PERSISTENT);
728 REGISTER_LONG_CONSTANT("MSG_WAITALL", MSG_WAITALL, CONST_CS | CONST_PERSISTENT);
729 REGISTER_LONG_CONSTANT("MSG_CTRUNC", MSG_CTRUNC, CONST_CS | CONST_PERSISTENT);
730 REGISTER_LONG_CONSTANT("MSG_TRUNC", MSG_TRUNC, CONST_CS | CONST_PERSISTENT);
731 REGISTER_LONG_CONSTANT("MSG_PEEK", MSG_PEEK, CONST_CS | CONST_PERSISTENT);
732 REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE, CONST_CS | CONST_PERSISTENT);
733 #ifdef MSG_EOR
734 REGISTER_LONG_CONSTANT("MSG_EOR", MSG_EOR, CONST_CS | CONST_PERSISTENT);
735 #endif
736 #ifdef MSG_EOF
737 REGISTER_LONG_CONSTANT("MSG_EOF", MSG_EOF, CONST_CS | CONST_PERSISTENT);
738 #endif
739
740 #ifdef MSG_CONFIRM
741 REGISTER_LONG_CONSTANT("MSG_CONFIRM", MSG_CONFIRM, CONST_CS | CONST_PERSISTENT);
742 #endif
743 #ifdef MSG_ERRQUEUE
744 REGISTER_LONG_CONSTANT("MSG_ERRQUEUE", MSG_ERRQUEUE, CONST_CS | CONST_PERSISTENT);
745 #endif
746 #ifdef MSG_NOSIGNAL
747 REGISTER_LONG_CONSTANT("MSG_NOSIGNAL", MSG_NOSIGNAL, CONST_CS | CONST_PERSISTENT);
748 #endif
749 #ifdef MSG_DONTWAIT
750 REGISTER_LONG_CONSTANT("MSG_DONTWAIT", MSG_DONTWAIT, CONST_CS | CONST_PERSISTENT);
751 #endif
752 #ifdef MSG_MORE
753 REGISTER_LONG_CONSTANT("MSG_MORE", MSG_MORE, CONST_CS | CONST_PERSISTENT);
754 #endif
755 #ifdef MSG_WAITFORONE
756 REGISTER_LONG_CONSTANT("MSG_WAITFORONE",MSG_WAITFORONE, CONST_CS | CONST_PERSISTENT);
757 #endif
758 #ifdef MSG_CMSG_CLOEXEC
759 REGISTER_LONG_CONSTANT("MSG_CMSG_CLOEXEC",MSG_CMSG_CLOEXEC,CONST_CS | CONST_PERSISTENT);
760 #endif
761
762 REGISTER_LONG_CONSTANT("SO_DEBUG", SO_DEBUG, CONST_CS | CONST_PERSISTENT);
763 REGISTER_LONG_CONSTANT("SO_REUSEADDR", SO_REUSEADDR, CONST_CS | CONST_PERSISTENT);
764 #ifdef SO_REUSEPORT
765 REGISTER_LONG_CONSTANT("SO_REUSEPORT", SO_REUSEPORT, CONST_CS | CONST_PERSISTENT);
766 #endif
767 REGISTER_LONG_CONSTANT("SO_KEEPALIVE", SO_KEEPALIVE, CONST_CS | CONST_PERSISTENT);
768 REGISTER_LONG_CONSTANT("SO_DONTROUTE", SO_DONTROUTE, CONST_CS | CONST_PERSISTENT);
769 REGISTER_LONG_CONSTANT("SO_LINGER", SO_LINGER, CONST_CS | CONST_PERSISTENT);
770 REGISTER_LONG_CONSTANT("SO_BROADCAST", SO_BROADCAST, CONST_CS | CONST_PERSISTENT);
771 REGISTER_LONG_CONSTANT("SO_OOBINLINE", SO_OOBINLINE, CONST_CS | CONST_PERSISTENT);
772 REGISTER_LONG_CONSTANT("SO_SNDBUF", SO_SNDBUF, CONST_CS | CONST_PERSISTENT);
773 REGISTER_LONG_CONSTANT("SO_RCVBUF", SO_RCVBUF, CONST_CS | CONST_PERSISTENT);
774 REGISTER_LONG_CONSTANT("SO_SNDLOWAT", SO_SNDLOWAT, CONST_CS | CONST_PERSISTENT);
775 REGISTER_LONG_CONSTANT("SO_RCVLOWAT", SO_RCVLOWAT, CONST_CS | CONST_PERSISTENT);
776 REGISTER_LONG_CONSTANT("SO_SNDTIMEO", SO_SNDTIMEO, CONST_CS | CONST_PERSISTENT);
777 REGISTER_LONG_CONSTANT("SO_RCVTIMEO", SO_RCVTIMEO, CONST_CS | CONST_PERSISTENT);
778 REGISTER_LONG_CONSTANT("SO_TYPE", SO_TYPE, CONST_CS | CONST_PERSISTENT);
779 #ifdef SO_FAMILY
780 REGISTER_LONG_CONSTANT("SO_FAMILY", SO_FAMILY, CONST_CS | CONST_PERSISTENT);
781 #endif
782 REGISTER_LONG_CONSTANT("SO_ERROR", SO_ERROR, CONST_CS | CONST_PERSISTENT);
783 #ifdef SO_BINDTODEVICE
784 REGISTER_LONG_CONSTANT("SO_BINDTODEVICE", SO_BINDTODEVICE, CONST_CS | CONST_PERSISTENT);
785 #endif
786 REGISTER_LONG_CONSTANT("SOL_SOCKET", SOL_SOCKET, CONST_CS | CONST_PERSISTENT);
787 REGISTER_LONG_CONSTANT("SOMAXCONN", SOMAXCONN, CONST_CS | CONST_PERSISTENT);
788 #ifdef TCP_NODELAY
789 REGISTER_LONG_CONSTANT("TCP_NODELAY", TCP_NODELAY, CONST_CS | CONST_PERSISTENT);
790 #endif
791 REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
792 REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
793
794 REGISTER_LONG_CONSTANT("MCAST_JOIN_GROUP", PHP_MCAST_JOIN_GROUP, CONST_CS | CONST_PERSISTENT);
795 REGISTER_LONG_CONSTANT("MCAST_LEAVE_GROUP", PHP_MCAST_LEAVE_GROUP, CONST_CS | CONST_PERSISTENT);
796 #ifdef HAS_MCAST_EXT
797 REGISTER_LONG_CONSTANT("MCAST_BLOCK_SOURCE", PHP_MCAST_BLOCK_SOURCE, CONST_CS | CONST_PERSISTENT);
798 REGISTER_LONG_CONSTANT("MCAST_UNBLOCK_SOURCE", PHP_MCAST_UNBLOCK_SOURCE, CONST_CS | CONST_PERSISTENT);
799 REGISTER_LONG_CONSTANT("MCAST_JOIN_SOURCE_GROUP", PHP_MCAST_JOIN_SOURCE_GROUP, CONST_CS | CONST_PERSISTENT);
800 REGISTER_LONG_CONSTANT("MCAST_LEAVE_SOURCE_GROUP", PHP_MCAST_LEAVE_SOURCE_GROUP, CONST_CS | CONST_PERSISTENT);
801 #endif
802
803 REGISTER_LONG_CONSTANT("IP_MULTICAST_IF", IP_MULTICAST_IF, CONST_CS | CONST_PERSISTENT);
804 REGISTER_LONG_CONSTANT("IP_MULTICAST_TTL", IP_MULTICAST_TTL, CONST_CS | CONST_PERSISTENT);
805 REGISTER_LONG_CONSTANT("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP, CONST_CS | CONST_PERSISTENT);
806 #if HAVE_IPV6
807 REGISTER_LONG_CONSTANT("IPV6_MULTICAST_IF", IPV6_MULTICAST_IF, CONST_CS | CONST_PERSISTENT);
808 REGISTER_LONG_CONSTANT("IPV6_MULTICAST_HOPS", IPV6_MULTICAST_HOPS, CONST_CS | CONST_PERSISTENT);
809 REGISTER_LONG_CONSTANT("IPV6_MULTICAST_LOOP", IPV6_MULTICAST_LOOP, CONST_CS | CONST_PERSISTENT);
810 #endif
811
812 #ifdef IPV6_V6ONLY
813 REGISTER_LONG_CONSTANT("IPV6_V6ONLY", IPV6_V6ONLY, CONST_CS | CONST_PERSISTENT);
814 #endif
815
816 #ifndef WIN32
817 # include "unix_socket_constants.h"
818 #else
819 # include "win32_socket_constants.h"
820 #endif
821
822 REGISTER_LONG_CONSTANT("IPPROTO_IP", IPPROTO_IP, CONST_CS | CONST_PERSISTENT);
823 #if HAVE_IPV6
824 REGISTER_LONG_CONSTANT("IPPROTO_IPV6", IPPROTO_IPV6, CONST_CS | CONST_PERSISTENT);
825 #endif
826
827 REGISTER_LONG_CONSTANT("SOL_TCP", IPPROTO_TCP, CONST_CS | CONST_PERSISTENT);
828 REGISTER_LONG_CONSTANT("SOL_UDP", IPPROTO_UDP, CONST_CS | CONST_PERSISTENT);
829
830 #if HAVE_IPV6
831 REGISTER_LONG_CONSTANT("IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS, CONST_CS | CONST_PERSISTENT);
832 #endif
833
834 REGISTER_LONG_CONSTANT("AI_PASSIVE", AI_PASSIVE, CONST_CS | CONST_PERSISTENT);
835 REGISTER_LONG_CONSTANT("AI_CANONNAME", AI_CANONNAME, CONST_CS | CONST_PERSISTENT);
836 REGISTER_LONG_CONSTANT("AI_NUMERICHOST", AI_NUMERICHOST, CONST_CS | CONST_PERSISTENT);
837 #if HAVE_AI_V4MAPPED
838 REGISTER_LONG_CONSTANT("AI_V4MAPPED", AI_V4MAPPED, CONST_CS | CONST_PERSISTENT);
839 #endif
840 #if HAVE_AI_ALL
841 REGISTER_LONG_CONSTANT("AI_ALL", AI_ALL, CONST_CS | CONST_PERSISTENT);
842 #endif
843 REGISTER_LONG_CONSTANT("AI_ADDRCONFIG", AI_ADDRCONFIG, CONST_CS | CONST_PERSISTENT);
844 #if HAVE_AI_IDN
845 REGISTER_LONG_CONSTANT("AI_IDN", AI_IDN, CONST_CS | CONST_PERSISTENT);
846 REGISTER_LONG_CONSTANT("AI_CANONIDN", AI_CANONIDN, CONST_CS | CONST_PERSISTENT);
847 REGISTER_LONG_CONSTANT("AI_IDN_ALLOW_UNASSIGNED", AI_IDN_ALLOW_UNASSIGNED, CONST_CS | CONST_PERSISTENT);
848 REGISTER_LONG_CONSTANT("AI_IDN_USE_STD3_ASCII_RULES", AI_IDN_USE_STD3_ASCII_RULES, CONST_CS | CONST_PERSISTENT);
849 #endif
850 #ifdef AI_NUMERICSERV
851 REGISTER_LONG_CONSTANT("AI_NUMERICSERV", AI_NUMERICSERV, CONST_CS | CONST_PERSISTENT);
852 #endif
853
854 php_socket_sendrecvmsg_init(INIT_FUNC_ARGS_PASSTHRU);
855
856 return SUCCESS;
857 }
858 /* }}} */
859
860 /* {{{ PHP_MSHUTDOWN_FUNCTION
861 */
862 static PHP_MSHUTDOWN_FUNCTION(sockets)
863 {
864 php_socket_sendrecvmsg_shutdown(SHUTDOWN_FUNC_ARGS_PASSTHRU);
865
866 return SUCCESS;
867 }
868 /* }}} */
869
870 /* {{{ PHP_MINFO_FUNCTION
871 */
872 static PHP_MINFO_FUNCTION(sockets)
873 {
874 php_info_print_table_start();
875 php_info_print_table_row(2, "Sockets Support", "enabled");
876 php_info_print_table_end();
877 }
878 /* }}} */
879
880 /* {{{ PHP_RSHUTDOWN_FUNCTION */
881 static PHP_RSHUTDOWN_FUNCTION(sockets)
882 {
883 if (SOCKETS_G(strerror_buf)) {
884 efree(SOCKETS_G(strerror_buf));
885 SOCKETS_G(strerror_buf) = NULL;
886 }
887
888 return SUCCESS;
889 }
890 /* }}} */
891
892 static int php_sock_array_to_fd_set(zval *sock_array, fd_set *fds, PHP_SOCKET *max_fd) /* {{{ */
893 {
894 zval *element;
895 php_socket *php_sock;
896 int num = 0;
897
898 if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
899
900 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(sock_array), element) {
901 ZVAL_DEREF(element);
902 php_sock = (php_socket*) zend_fetch_resource_ex(element, le_socket_name, le_socket);
903 if (!php_sock) continue; /* If element is not a resource, skip it */
904
905 PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
906 if (php_sock->bsd_socket > *max_fd) {
907 *max_fd = php_sock->bsd_socket;
908 }
909 num++;
910 } ZEND_HASH_FOREACH_END();
911
912 return num ? 1 : 0;
913 }
914 /* }}} */
915
916 static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds) /* {{{ */
917 {
918 zval *element;
919 zval *dest_element;
920 php_socket *php_sock;
921 zval new_hash;
922 int num = 0;
923 zend_ulong num_key;
924 zend_string *key;
925
926 if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0;
927
928 array_init(&new_hash);
929 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(sock_array), num_key, key, element) {
930 ZVAL_DEREF(element);
931 php_sock = (php_socket*) zend_fetch_resource_ex(element, le_socket_name, le_socket);
932 if (!php_sock) continue; /* If element is not a resource, skip it */
933
934 if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
935 /* Add fd to new array */
936 if (key) {
937 dest_element = zend_hash_add(Z_ARRVAL(new_hash), key, element);
938 } else {
939 dest_element = zend_hash_index_update(Z_ARRVAL(new_hash), num_key, element);
940 }
941 if (dest_element) {
942 Z_ADDREF_P(dest_element);
943 }
944 }
945 num++;
946 } ZEND_HASH_FOREACH_END();
947
948 /* Destroy old array, add new one */
949 zval_ptr_dtor(sock_array);
950
951 ZVAL_COPY_VALUE(sock_array, &new_hash);
952
953 return num ? 1 : 0;
954 }
955 /* }}} */
956
957 /* {{{ proto int socket_select(array &read_fds, array &write_fds, array &except_fds, int tv_sec[, int tv_usec])
958 Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec */
959 PHP_FUNCTION(socket_select)
960 {
961 zval *r_array, *w_array, *e_array, *sec;
962 struct timeval tv;
963 struct timeval *tv_p = NULL;
964 fd_set rfds, wfds, efds;
965 PHP_SOCKET max_fd = 0;
966 int retval, sets = 0;
967 zend_long usec = 0;
968
969 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a!a!a!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE) {
970 return;
971 }
972
973 FD_ZERO(&rfds);
974 FD_ZERO(&wfds);
975 FD_ZERO(&efds);
976
977 if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd);
978 if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd);
979 if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd);
980
981 if (!sets) {
982 php_error_docref(NULL, E_WARNING, "no resource arrays were passed to select");
983 RETURN_FALSE;
984 }
985
986 PHP_SAFE_MAX_FD(max_fd, 0); /* someone needs to make this look more like stream_socket_select */
987
988 /* If seconds is not set to null, build the timeval, else we wait indefinitely */
989 if (sec != NULL) {
990 zend_long s = zval_get_long(sec);
991
992 /* Solaris + BSD do not like microsecond values which are >= 1 sec */
993 if (usec > 999999) {
994 tv.tv_sec = s + (usec / 1000000);
995 tv.tv_usec = usec % 1000000;
996 } else {
997 tv.tv_sec = s;
998 tv.tv_usec = usec;
999 }
1000
1001 tv_p = &tv;
1002 }
1003
1004 retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p);
1005
1006 if (retval == -1) {
1007 SOCKETS_G(last_error) = errno;
1008 php_error_docref(NULL, E_WARNING, "unable to select [%d]: %s", errno, sockets_strerror(errno));
1009 RETURN_FALSE;
1010 }
1011
1012 if (r_array != NULL) php_sock_array_from_fd_set(r_array, &rfds);
1013 if (w_array != NULL) php_sock_array_from_fd_set(w_array, &wfds);
1014 if (e_array != NULL) php_sock_array_from_fd_set(e_array, &efds);
1015
1016 RETURN_LONG(retval);
1017 }
1018 /* }}} */
1019
1020 /* {{{ proto resource socket_create_listen(int port[, int backlog])
1021 Opens a socket on port to accept connections */
1022 PHP_FUNCTION(socket_create_listen)
1023 {
1024 php_socket *php_sock;
1025 zend_long port, backlog = 128;
1026
1027 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &port, &backlog) == FAILURE) {
1028 return;
1029 }
1030
1031 if (!php_open_listen_sock(&php_sock, port, backlog)) {
1032 RETURN_FALSE;
1033 }
1034
1035 php_sock->error = 0;
1036 php_sock->blocking = 1;
1037
1038 RETURN_RES(zend_register_resource(php_sock, le_socket));
1039 }
1040 /* }}} */
1041
1042 /* {{{ proto resource socket_accept(resource socket)
1043 Accepts a connection on the listening socket fd */
1044 PHP_FUNCTION(socket_accept)
1045 {
1046 zval *arg1;
1047 php_socket *php_sock, *new_sock;
1048 php_sockaddr_storage sa;
1049 socklen_t php_sa_len = sizeof(sa);
1050
1051 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
1052 return;
1053 }
1054
1055 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1056 RETURN_FALSE;
1057 }
1058
1059 if (!php_accept_connect(php_sock, &new_sock, (struct sockaddr*)&sa, &php_sa_len)) {
1060 RETURN_FALSE;
1061 }
1062
1063 RETURN_RES(zend_register_resource(new_sock, le_socket));
1064 }
1065 /* }}} */
1066
1067 /* {{{ proto bool socket_set_nonblock(resource socket)
1068 Sets nonblocking mode on a socket resource */
1069 PHP_FUNCTION(socket_set_nonblock)
1070 {
1071 zval *arg1;
1072 php_socket *php_sock;
1073
1074 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
1075 return;
1076 }
1077
1078 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1079 RETURN_FALSE;
1080 }
1081
1082 if (!Z_ISUNDEF(php_sock->zstream)) {
1083 php_stream *stream;
1084 /* omit notice if resource doesn't exist anymore */
1085 stream = zend_fetch_resource2_ex(&php_sock->zstream, NULL, php_file_le_stream(), php_file_le_pstream());
1086 if (stream != NULL) {
1087 if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 0,
1088 NULL) != -1) {
1089 php_sock->blocking = 0;
1090 RETURN_TRUE;
1091 }
1092 }
1093 }
1094
1095 if (php_set_sock_blocking(php_sock->bsd_socket, 0) == SUCCESS) {
1096 php_sock->blocking = 0;
1097 RETURN_TRUE;
1098 } else {
1099 PHP_SOCKET_ERROR(php_sock, "unable to set nonblocking mode", errno);
1100 RETURN_FALSE;
1101 }
1102 }
1103 /* }}} */
1104
1105 /* {{{ proto bool socket_set_block(resource socket)
1106 Sets blocking mode on a socket resource */
1107 PHP_FUNCTION(socket_set_block)
1108 {
1109 zval *arg1;
1110 php_socket *php_sock;
1111
1112 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
1113 return;
1114 }
1115
1116 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1117 RETURN_FALSE;
1118 }
1119
1120 /* if socket was created from a stream, give the stream a chance to take
1121 * care of the operation itself, thereby allowing it to update its internal
1122 * state */
1123 if (!Z_ISUNDEF(php_sock->zstream)) {
1124 php_stream *stream;
1125 stream = zend_fetch_resource2_ex(&php_sock->zstream, NULL, php_file_le_stream(), php_file_le_pstream());
1126 if (stream != NULL) {
1127 if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 1,
1128 NULL) != -1) {
1129 php_sock->blocking = 1;
1130 RETURN_TRUE;
1131 }
1132 }
1133 }
1134
1135 if (php_set_sock_blocking(php_sock->bsd_socket, 1) == SUCCESS) {
1136 php_sock->blocking = 1;
1137 RETURN_TRUE;
1138 } else {
1139 PHP_SOCKET_ERROR(php_sock, "unable to set blocking mode", errno);
1140 RETURN_FALSE;
1141 }
1142 }
1143 /* }}} */
1144
1145 /* {{{ proto bool socket_listen(resource socket[, int backlog])
1146 Sets the maximum number of connections allowed to be waited for on the socket specified by fd */
1147 PHP_FUNCTION(socket_listen)
1148 {
1149 zval *arg1;
1150 php_socket *php_sock;
1151 zend_long backlog = 0;
1152
1153 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &arg1, &backlog) == FAILURE) {
1154 return;
1155 }
1156
1157 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1158 RETURN_FALSE;
1159 }
1160
1161 if (listen(php_sock->bsd_socket, backlog) != 0) {
1162 PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno);
1163 RETURN_FALSE;
1164 }
1165 RETURN_TRUE;
1166 }
1167 /* }}} */
1168
1169 /* {{{ proto void socket_close(resource socket)
1170 Closes a file descriptor */
1171 PHP_FUNCTION(socket_close)
1172 {
1173 zval *arg1;
1174 php_socket *php_sock;
1175
1176 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
1177 return;
1178 }
1179
1180 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1181 RETURN_FALSE;
1182 }
1183
1184 if (!Z_ISUNDEF(php_sock->zstream)) {
1185 php_stream *stream = NULL;
1186 php_stream_from_zval_no_verify(stream, &php_sock->zstream);
1187 if (stream != NULL) {
1188 /* close & destroy stream, incl. removing it from the rsrc list;
1189 * resource stored in php_sock->zstream will become invalid */
1190 php_stream_free(stream,
1191 PHP_STREAM_FREE_KEEP_RSRC | PHP_STREAM_FREE_CLOSE |
1192 (stream->is_persistent?PHP_STREAM_FREE_CLOSE_PERSISTENT:0));
1193 }
1194 }
1195 zend_list_close(Z_RES_P(arg1));
1196 }
1197 /* }}} */
1198
1199 /* {{{ proto int socket_write(resource socket, string buf[, int length])
1200 Writes the buffer to the socket resource, length is optional */
1201 PHP_FUNCTION(socket_write)
1202 {
1203 zval *arg1;
1204 php_socket *php_sock;
1205 int retval;
1206 size_t str_len;
1207 zend_long length = 0;
1208 char *str;
1209
1210 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &arg1, &str, &str_len, &length) == FAILURE) {
1211 return;
1212 }
1213
1214 if (length < 0) {
1215 php_error_docref(NULL, E_WARNING, "Length cannot be negative");
1216 RETURN_FALSE;
1217 }
1218
1219 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1220 RETURN_FALSE;
1221 }
1222
1223 if (ZEND_NUM_ARGS() < 3) {
1224 length = str_len;
1225 }
1226
1227 #ifndef PHP_WIN32
1228 retval = write(php_sock->bsd_socket, str, MIN(length, str_len));
1229 #else
1230 retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);
1231 #endif
1232
1233 if (retval < 0) {
1234 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1235 RETURN_FALSE;
1236 }
1237
1238 RETURN_LONG(retval);
1239 }
1240 /* }}} */
1241
1242 /* {{{ proto string socket_read(resource socket, int length [, int type])
1243 Reads a maximum of length bytes from socket */
1244 PHP_FUNCTION(socket_read)
1245 {
1246 zval *arg1;
1247 php_socket *php_sock;
1248 zend_string *tmpbuf;
1249 int retval;
1250 zend_long length, type = PHP_BINARY_READ;
1251
1252 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|l", &arg1, &length, &type) == FAILURE) {
1253 return;
1254 }
1255
1256 /* overflow check */
1257 if ((length + 1) < 2) {
1258 RETURN_FALSE;
1259 }
1260
1261 tmpbuf = zend_string_alloc(length, 0);
1262
1263 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1264 RETURN_FALSE;
1265 }
1266
1267 if (type == PHP_NORMAL_READ) {
1268 retval = php_read(php_sock, ZSTR_VAL(tmpbuf), length, 0);
1269 } else {
1270 retval = recv(php_sock->bsd_socket, ZSTR_VAL(tmpbuf), length, 0);
1271 }
1272
1273 if (retval == -1) {
1274 /* if the socket is in non-blocking mode and there's no data to read,
1275 don't output any error, as this is a normal situation, and not an error */
1276 if (errno == EAGAIN
1277 #ifdef EWOULDBLOCK
1278 || errno == EWOULDBLOCK
1279 #endif
1280 ) {
1281 php_sock->error = errno;
1282 SOCKETS_G(last_error) = errno;
1283 } else {
1284 PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1285 }
1286
1287 zend_string_efree(tmpbuf);
1288 RETURN_FALSE;
1289 } else if (!retval) {
1290 zend_string_efree(tmpbuf);
1291 RETURN_EMPTY_STRING();
1292 }
1293
1294 tmpbuf = zend_string_truncate(tmpbuf, retval, 0);
1295 ZSTR_LEN(tmpbuf) = retval;
1296 ZSTR_VAL(tmpbuf)[ZSTR_LEN(tmpbuf)] = '\0' ;
1297
1298 RETURN_NEW_STR(tmpbuf);
1299 }
1300 /* }}} */
1301
1302 /* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port])
1303 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. */
1304 PHP_FUNCTION(socket_getsockname)
1305 {
1306 zval *arg1, *addr, *port = NULL;
1307 php_sockaddr_storage sa_storage;
1308 php_socket *php_sock;
1309 struct sockaddr *sa;
1310 struct sockaddr_in *sin;
1311 #if HAVE_IPV6
1312 struct sockaddr_in6 *sin6;
1313 char addr6[INET6_ADDRSTRLEN+1];
1314 #endif
1315 struct sockaddr_un *s_un;
1316 char *addr_string;
1317 socklen_t salen = sizeof(php_sockaddr_storage);
1318
1319 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &addr, &port) == FAILURE) {
1320 return;
1321 }
1322
1323 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1324 RETURN_FALSE;
1325 }
1326
1327 sa = (struct sockaddr *) &sa_storage;
1328
1329 if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) {
1330 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno);
1331 RETURN_FALSE;
1332 }
1333
1334 if (port != NULL) {
1335 ZVAL_DEREF(port);
1336 }
1337
1338 switch (sa->sa_family) {
1339 #if HAVE_IPV6
1340 case AF_INET6:
1341 sin6 = (struct sockaddr_in6 *) sa;
1342 inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1343 zval_ptr_dtor(addr);
1344 ZVAL_STRING(addr, addr6);
1345
1346 if (port != NULL) {
1347 zval_ptr_dtor(port);
1348 ZVAL_LONG(port, htons(sin6->sin6_port));
1349 }
1350 RETURN_TRUE;
1351 break;
1352 #endif
1353 case AF_INET:
1354 sin = (struct sockaddr_in *) sa;
1355 while (inet_ntoa_lock == 1);
1356 inet_ntoa_lock = 1;
1357 addr_string = inet_ntoa(sin->sin_addr);
1358 inet_ntoa_lock = 0;
1359
1360 zval_ptr_dtor(addr);
1361 ZVAL_STRING(addr, addr_string);
1362
1363 if (port != NULL) {
1364 zval_ptr_dtor(port);
1365 ZVAL_LONG(port, htons(sin->sin_port));
1366 }
1367 RETURN_TRUE;
1368 break;
1369
1370 case AF_UNIX:
1371 s_un = (struct sockaddr_un *) sa;
1372
1373 zval_ptr_dtor(addr);
1374 ZVAL_STRING(addr, s_un->sun_path);
1375 RETURN_TRUE;
1376 break;
1377
1378 default:
1379 php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
1380 RETURN_FALSE;
1381 }
1382 }
1383 /* }}} */
1384
1385 /* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port])
1386 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. */
1387 PHP_FUNCTION(socket_getpeername)
1388 {
1389 zval *arg1, *arg2, *arg3 = NULL;
1390 php_sockaddr_storage sa_storage;
1391 php_socket *php_sock;
1392 struct sockaddr *sa;
1393 struct sockaddr_in *sin;
1394 #if HAVE_IPV6
1395 struct sockaddr_in6 *sin6;
1396 char addr6[INET6_ADDRSTRLEN+1];
1397 #endif
1398 struct sockaddr_un *s_un;
1399 char *addr_string;
1400 socklen_t salen = sizeof(php_sockaddr_storage);
1401
1402 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &arg2, &arg3) == FAILURE) {
1403 return;
1404 }
1405
1406 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1407 RETURN_FALSE;
1408 }
1409
1410 sa = (struct sockaddr *) &sa_storage;
1411
1412 if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) {
1413 PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno);
1414 RETURN_FALSE;
1415 }
1416
1417 switch (sa->sa_family) {
1418 #if HAVE_IPV6
1419 case AF_INET6:
1420 sin6 = (struct sockaddr_in6 *) sa;
1421 inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
1422 zval_ptr_dtor(arg2);
1423 ZVAL_STRING(arg2, addr6);
1424
1425 if (arg3 != NULL) {
1426 zval_ptr_dtor(arg3);
1427 ZVAL_LONG(arg3, htons(sin6->sin6_port));
1428 }
1429
1430 RETURN_TRUE;
1431 break;
1432 #endif
1433 case AF_INET:
1434 sin = (struct sockaddr_in *) sa;
1435 while (inet_ntoa_lock == 1);
1436 inet_ntoa_lock = 1;
1437 addr_string = inet_ntoa(sin->sin_addr);
1438 inet_ntoa_lock = 0;
1439
1440 zval_ptr_dtor(arg2);
1441 ZVAL_STRING(arg2, addr_string);
1442
1443 if (arg3 != NULL) {
1444 zval_ptr_dtor(arg3);
1445 ZVAL_LONG(arg3, htons(sin->sin_port));
1446 }
1447
1448 RETURN_TRUE;
1449 break;
1450
1451 case AF_UNIX:
1452 s_un = (struct sockaddr_un *) sa;
1453
1454 zval_ptr_dtor(arg2);
1455 ZVAL_STRING(arg2, s_un->sun_path);
1456 RETURN_TRUE;
1457 break;
1458
1459 default:
1460 php_error_docref(NULL, E_WARNING, "Unsupported address family %d", sa->sa_family);
1461 RETURN_FALSE;
1462 }
1463 }
1464 /* }}} */
1465
1466 /* {{{ proto resource socket_create(int domain, int type, int protocol)
1467 Creates an endpoint for communication in the domain specified by domain, of type specified by type */
1468 PHP_FUNCTION(socket_create)
1469 {
1470 zend_long arg1, arg2, arg3;
1471 php_socket *php_sock = php_create_socket();
1472
1473 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &arg1, &arg2, &arg3) == FAILURE) {
1474 efree(php_sock);
1475 return;
1476 }
1477
1478 if (arg1 != AF_UNIX
1479 #if HAVE_IPV6
1480 && arg1 != AF_INET6
1481 #endif
1482 && arg1 != AF_INET) {
1483 php_error_docref(NULL, E_WARNING, "invalid socket domain [" ZEND_LONG_FMT "] specified for argument 1, assuming AF_INET", arg1);
1484 arg1 = AF_INET;
1485 }
1486
1487 if (arg2 > 10) {
1488 php_error_docref(NULL, E_WARNING, "invalid socket type [" ZEND_LONG_FMT "] specified for argument 2, assuming SOCK_STREAM", arg2);
1489 arg2 = SOCK_STREAM;
1490 }
1491
1492 php_sock->bsd_socket = socket(arg1, arg2, arg3);
1493 php_sock->type = arg1;
1494
1495 if (IS_INVALID_SOCKET(php_sock)) {
1496 SOCKETS_G(last_error) = errno;
1497 php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
1498 efree(php_sock);
1499 RETURN_FALSE;
1500 }
1501
1502 php_sock->error = 0;
1503 php_sock->blocking = 1;
1504
1505 RETURN_RES(zend_register_resource(php_sock, le_socket));
1506 }
1507 /* }}} */
1508
1509 /* {{{ proto bool socket_connect(resource socket, string addr [, int port])
1510 Opens a connection to addr:port on the socket specified by socket */
1511 PHP_FUNCTION(socket_connect)
1512 {
1513 zval *arg1;
1514 php_socket *php_sock;
1515 char *addr;
1516 int retval;
1517 size_t addr_len;
1518 zend_long port = 0;
1519 int argc = ZEND_NUM_ARGS();
1520
1521 if (zend_parse_parameters(argc, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1522 return;
1523 }
1524
1525 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1526 RETURN_FALSE;
1527 }
1528
1529 switch(php_sock->type) {
1530 #if HAVE_IPV6
1531 case AF_INET6: {
1532 struct sockaddr_in6 sin6 = {0};
1533
1534 if (argc != 3) {
1535 php_error_docref(NULL, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
1536 RETURN_FALSE;
1537 }
1538
1539 memset(&sin6, 0, sizeof(struct sockaddr_in6));
1540
1541 sin6.sin6_family = AF_INET6;
1542 sin6.sin6_port = htons((unsigned short int)port);
1543
1544 if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
1545 RETURN_FALSE;
1546 }
1547
1548 retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
1549 break;
1550 }
1551 #endif
1552 case AF_INET: {
1553 struct sockaddr_in sin = {0};
1554
1555 if (argc != 3) {
1556 php_error_docref(NULL, E_WARNING, "Socket of type AF_INET requires 3 arguments");
1557 RETURN_FALSE;
1558 }
1559
1560 sin.sin_family = AF_INET;
1561 sin.sin_port = htons((unsigned short int)port);
1562
1563 if (! php_set_inet_addr(&sin, addr, php_sock)) {
1564 RETURN_FALSE;
1565 }
1566
1567 retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
1568 break;
1569 }
1570
1571 case AF_UNIX: {
1572 struct sockaddr_un s_un = {0};
1573
1574 if (addr_len >= sizeof(s_un.sun_path)) {
1575 php_error_docref(NULL, E_WARNING, "Path too long");
1576 RETURN_FALSE;
1577 }
1578
1579 s_un.sun_family = AF_UNIX;
1580 memcpy(&s_un.sun_path, addr, addr_len);
1581 retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
1582 (socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
1583 break;
1584 }
1585
1586 default:
1587 php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1588 RETURN_FALSE;
1589 }
1590
1591 if (retval != 0) {
1592 PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
1593 RETURN_FALSE;
1594 }
1595
1596 RETURN_TRUE;
1597 }
1598 /* }}} */
1599
1600 /* {{{ proto string socket_strerror(int errno)
1601 Returns a string describing an error */
1602 PHP_FUNCTION(socket_strerror)
1603 {
1604 zend_long arg1;
1605
1606 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &arg1) == FAILURE) {
1607 return;
1608 }
1609
1610 RETURN_STRING(sockets_strerror(arg1));
1611 }
1612 /* }}} */
1613
1614 /* {{{ proto bool socket_bind(resource socket, string addr [, int port])
1615 Binds an open socket to a listening port, port is only specified in AF_INET family. */
1616 PHP_FUNCTION(socket_bind)
1617 {
1618 zval *arg1;
1619 php_sockaddr_storage sa_storage = {0};
1620 struct sockaddr *sock_type = (struct sockaddr*) &sa_storage;
1621 php_socket *php_sock;
1622 char *addr;
1623 size_t addr_len;
1624 zend_long port = 0;
1625 zend_long retval = 0;
1626
1627 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) {
1628 return;
1629 }
1630
1631 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1632 RETURN_FALSE;
1633 }
1634
1635 switch(php_sock->type) {
1636 case AF_UNIX:
1637 {
1638 struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
1639
1640 sa->sun_family = AF_UNIX;
1641
1642 if (addr_len >= sizeof(sa->sun_path)) {
1643 php_error_docref(NULL, E_WARNING,
1644 "Invalid path: too long (maximum size is %d)",
1645 (int)sizeof(sa->sun_path) - 1);
1646 RETURN_FALSE;
1647 }
1648 memcpy(&sa->sun_path, addr, addr_len);
1649
1650 retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa,
1651 offsetof(struct sockaddr_un, sun_path) + addr_len);
1652 break;
1653 }
1654
1655 case AF_INET:
1656 {
1657 struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
1658
1659 sa->sin_family = AF_INET;
1660 sa->sin_port = htons((unsigned short) port);
1661
1662 if (! php_set_inet_addr(sa, addr, php_sock)) {
1663 RETURN_FALSE;
1664 }
1665
1666 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
1667 break;
1668 }
1669 #if HAVE_IPV6
1670 case AF_INET6:
1671 {
1672 struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
1673
1674 sa->sin6_family = AF_INET6;
1675 sa->sin6_port = htons((unsigned short) port);
1676
1677 if (! php_set_inet6_addr(sa, addr, php_sock)) {
1678 RETURN_FALSE;
1679 }
1680
1681 retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
1682 break;
1683 }
1684 #endif
1685 default:
1686 php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
1687 RETURN_FALSE;
1688 }
1689
1690 if (retval != 0) {
1691 PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
1692 RETURN_FALSE;
1693 }
1694
1695 RETURN_TRUE;
1696 }
1697 /* }}} */
1698
1699 /* {{{ proto int socket_recv(resource socket, string &buf, int len, int flags)
1700 Receives data from a connected socket */
1701 PHP_FUNCTION(socket_recv)
1702 {
1703 zval *php_sock_res, *buf;
1704 zend_string *recv_buf;
1705 php_socket *php_sock;
1706 int retval;
1707 zend_long len, flags;
1708
1709 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/ll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
1710 return;
1711 }
1712
1713 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(php_sock_res), le_socket_name, le_socket)) == NULL) {
1714 RETURN_FALSE;
1715 }
1716
1717 /* overflow check */
1718 if ((len + 1) < 2) {
1719 RETURN_FALSE;
1720 }
1721
1722 recv_buf = zend_string_alloc(len, 0);
1723
1724 if ((retval = recv(php_sock->bsd_socket, ZSTR_VAL(recv_buf), len, flags)) < 1) {
1725 zend_string_efree(recv_buf);
1726
1727 zval_ptr_dtor(buf);
1728 ZVAL_NULL(buf);
1729 } else {
1730 ZSTR_LEN(recv_buf) = retval;
1731 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1732
1733 /* Rebuild buffer zval */
1734 zval_ptr_dtor(buf);
1735 ZVAL_NEW_STR(buf, recv_buf);
1736 }
1737
1738 if (retval == -1) {
1739 PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
1740 RETURN_FALSE;
1741 }
1742
1743 RETURN_LONG(retval);
1744 }
1745 /* }}} */
1746
1747 /* {{{ proto int socket_send(resource socket, string buf, int len, int flags)
1748 Sends data to a connected socket */
1749 PHP_FUNCTION(socket_send)
1750 {
1751 zval *arg1;
1752 php_socket *php_sock;
1753 size_t buf_len, retval;
1754 zend_long len, flags;
1755 char *buf;
1756
1757 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsll", &arg1, &buf, &buf_len, &len, &flags) == FAILURE) {
1758 return;
1759 }
1760
1761 if (len < 0) {
1762 php_error_docref(NULL, E_WARNING, "Length cannot be negative");
1763 RETURN_FALSE;
1764 }
1765
1766 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1767 RETURN_FALSE;
1768 }
1769
1770 retval = send(php_sock->bsd_socket, buf, (buf_len < (size_t)len ? buf_len : (size_t)len), flags);
1771
1772 if (retval == (size_t)-1) {
1773 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1774 RETURN_FALSE;
1775 }
1776
1777 RETURN_LONG(retval);
1778 }
1779 /* }}} */
1780
1781 /* {{{ proto int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port])
1782 Receives data from a socket, connected or not */
1783 PHP_FUNCTION(socket_recvfrom)
1784 {
1785 zval *arg1, *arg2, *arg5, *arg6 = NULL;
1786 php_socket *php_sock;
1787 struct sockaddr_un s_un;
1788 struct sockaddr_in sin;
1789 #if HAVE_IPV6
1790 struct sockaddr_in6 sin6;
1791 char addr6[INET6_ADDRSTRLEN];
1792 #endif
1793 socklen_t slen;
1794 int retval;
1795 zend_long arg3, arg4;
1796 char *address;
1797 zend_string *recv_buf;
1798
1799 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/llz/|z/", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) {
1800 return;
1801 }
1802
1803 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1804 RETURN_FALSE;
1805 }
1806
1807 /* overflow check */
1808 if ((arg3 + 2) < 3) {
1809 RETURN_FALSE;
1810 }
1811
1812 recv_buf = zend_string_alloc(arg3 + 1, 0);
1813
1814 switch (php_sock->type) {
1815 case AF_UNIX:
1816 slen = sizeof(s_un);
1817 memset(&s_un, 0, slen);
1818 s_un.sun_family = AF_UNIX;
1819
1820 retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
1821
1822 if (retval < 0) {
1823 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1824 zend_string_efree(recv_buf);
1825 RETURN_FALSE;
1826 }
1827 ZSTR_LEN(recv_buf) = retval;
1828 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1829
1830 zval_ptr_dtor(arg2);
1831 zval_ptr_dtor(arg5);
1832
1833 ZVAL_NEW_STR(arg2, recv_buf);
1834 ZVAL_STRING(arg5, s_un.sun_path);
1835 break;
1836
1837 case AF_INET:
1838 slen = sizeof(sin);
1839 memset(&sin, 0, slen);
1840 sin.sin_family = AF_INET;
1841
1842 if (arg6 == NULL) {
1843 zend_string_efree(recv_buf);
1844 WRONG_PARAM_COUNT;
1845 }
1846
1847 retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
1848
1849 if (retval < 0) {
1850 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1851 zend_string_efree(recv_buf);
1852 RETURN_FALSE;
1853 }
1854 ZSTR_LEN(recv_buf) = retval;
1855 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1856
1857 zval_ptr_dtor(arg2);
1858 zval_ptr_dtor(arg5);
1859 zval_ptr_dtor(arg6);
1860
1861 address = inet_ntoa(sin.sin_addr);
1862
1863 ZVAL_NEW_STR(arg2, recv_buf);
1864 ZVAL_STRING(arg5, address ? address : "0.0.0.0");
1865 ZVAL_LONG(arg6, ntohs(sin.sin_port));
1866 break;
1867 #if HAVE_IPV6
1868 case AF_INET6:
1869 slen = sizeof(sin6);
1870 memset(&sin6, 0, slen);
1871 sin6.sin6_family = AF_INET6;
1872
1873 if (arg6 == NULL) {
1874 zend_string_efree(recv_buf);
1875 WRONG_PARAM_COUNT;
1876 }
1877
1878 retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
1879
1880 if (retval < 0) {
1881 PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1882 zend_string_efree(recv_buf);
1883 RETURN_FALSE;
1884 }
1885 ZSTR_LEN(recv_buf) = retval;
1886 ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1887
1888 zval_ptr_dtor(arg2);
1889 zval_ptr_dtor(arg5);
1890 zval_ptr_dtor(arg6);
1891
1892 memset(addr6, 0, INET6_ADDRSTRLEN);
1893 inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
1894
1895 ZVAL_NEW_STR(arg2, recv_buf);
1896 ZVAL_STRING(arg5, addr6[0] ? addr6 : "::");
1897 ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
1898 break;
1899 #endif
1900 default:
1901 php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1902 RETURN_FALSE;
1903 }
1904
1905 RETURN_LONG(retval);
1906 }
1907 /* }}} */
1908
1909 /* {{{ proto int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port])
1910 Sends a message to a socket, whether it is connected or not */
1911 PHP_FUNCTION(socket_sendto)
1912 {
1913 zval *arg1;
1914 php_socket *php_sock;
1915 struct sockaddr_un s_un;
1916 struct sockaddr_in sin;
1917 #if HAVE_IPV6
1918 struct sockaddr_in6 sin6;
1919 #endif
1920 int retval;
1921 size_t buf_len, addr_len;
1922 zend_long len, flags, port = 0;
1923 char *buf, *addr;
1924 int argc = ZEND_NUM_ARGS();
1925
1926 if (zend_parse_parameters(argc, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
1927 return;
1928 }
1929
1930 if (len < 0) {
1931 php_error_docref(NULL, E_WARNING, "Length cannot be negative");
1932 RETURN_FALSE;
1933 }
1934
1935 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
1936 RETURN_FALSE;
1937 }
1938
1939 switch (php_sock->type) {
1940 case AF_UNIX:
1941 memset(&s_un, 0, sizeof(s_un));
1942 s_un.sun_family = AF_UNIX;
1943 snprintf(s_un.sun_path, 108, "%s", addr);
1944
1945 retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
1946 break;
1947
1948 case AF_INET:
1949 if (argc != 6) {
1950 WRONG_PARAM_COUNT;
1951 }
1952
1953 memset(&sin, 0, sizeof(sin));
1954 sin.sin_family = AF_INET;
1955 sin.sin_port = htons((unsigned short) port);
1956
1957 if (! php_set_inet_addr(&sin, addr, php_sock)) {
1958 RETURN_FALSE;
1959 }
1960
1961 retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin, sizeof(sin));
1962 break;
1963 #if HAVE_IPV6
1964 case AF_INET6:
1965 if (argc != 6) {
1966 WRONG_PARAM_COUNT;
1967 }
1968
1969 memset(&sin6, 0, sizeof(sin6));
1970 sin6.sin6_family = AF_INET6;
1971 sin6.sin6_port = htons((unsigned short) port);
1972
1973 if (! php_set_inet6_addr(&sin6, addr, php_sock)) {
1974 RETURN_FALSE;
1975 }
1976
1977 retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
1978 break;
1979 #endif
1980 default:
1981 php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", php_sock->type);
1982 RETURN_FALSE;
1983 }
1984
1985 if (retval == -1) {
1986 PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno);
1987 RETURN_FALSE;
1988 }
1989
1990 RETURN_LONG(retval);
1991 }
1992 /* }}} */
1993
1994 /* {{{ proto mixed socket_get_option(resource socket, int level, int optname)
1995 Gets socket options for the socket */
1996 PHP_FUNCTION(socket_get_option)
1997 {
1998 zval *arg1;
1999 struct linger linger_val;
2000 struct timeval tv;
2001 #ifdef PHP_WIN32
2002 int timeout = 0;
2003 #endif
2004 socklen_t optlen;
2005 php_socket *php_sock;
2006 int other_val;
2007 zend_long level, optname;
2008
2009 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rll", &arg1, &level, &optname) == FAILURE) {
2010 return;
2011 }
2012
2013 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2014 RETURN_FALSE;
2015 }
2016
2017 if (level == IPPROTO_IP) {
2018 switch (optname) {
2019 case IP_MULTICAST_IF: {
2020 struct in_addr if_addr;
2021 unsigned int if_index;
2022 optlen = sizeof(if_addr);
2023 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&if_addr, &optlen) != 0) {
2024 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2025 RETURN_FALSE;
2026 }
2027 if (php_add4_to_if_index(&if_addr, php_sock, &if_index) == SUCCESS) {
2028 RETURN_LONG((zend_long) if_index);
2029 } else {
2030 RETURN_FALSE;
2031 }
2032 }
2033 }
2034 }
2035 #if HAVE_IPV6
2036 else if (level == IPPROTO_IPV6) {
2037 int ret = php_do_getsockopt_ipv6_rfc3542(php_sock, level, optname, return_value);
2038 if (ret == SUCCESS) {
2039 return;
2040 } else if (ret == FAILURE) {
2041 RETURN_FALSE;
2042 } /* else continue */
2043 }
2044 #endif
2045
2046 /* sol_socket options and general case */
2047 switch(optname) {
2048 case SO_LINGER:
2049 optlen = sizeof(linger_val);
2050
2051 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) {
2052 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2053 RETURN_FALSE;
2054 }
2055
2056 array_init(return_value);
2057 add_assoc_long(return_value, "l_onoff", linger_val.l_onoff);
2058 add_assoc_long(return_value, "l_linger", linger_val.l_linger);
2059 break;
2060
2061 case SO_RCVTIMEO:
2062 case SO_SNDTIMEO:
2063 #ifndef PHP_WIN32
2064 optlen = sizeof(tv);
2065
2066 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
2067 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2068 RETURN_FALSE;
2069 }
2070 #else
2071 optlen = sizeof(int);
2072
2073 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
2074 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2075 RETURN_FALSE;
2076 }
2077
2078 tv.tv_sec = timeout ? timeout / 1000 : 0;
2079 tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;
2080 #endif
2081
2082 array_init(return_value);
2083
2084 add_assoc_long(return_value, "sec", tv.tv_sec);
2085 add_assoc_long(return_value, "usec", tv.tv_usec);
2086 break;
2087
2088 default:
2089 optlen = sizeof(other_val);
2090
2091 if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) {
2092 PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno);
2093 RETURN_FALSE;
2094 }
2095 if (optlen == 1)
2096 other_val = *((unsigned char *)&other_val);
2097
2098 RETURN_LONG(other_val);
2099 break;
2100 }
2101 }
2102 /* }}} */
2103
2104 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
2105 Sets socket options for the socket */
2106 PHP_FUNCTION(socket_set_option)
2107 {
2108 zval *arg1, *arg4;
2109 struct linger lv;
2110 php_socket *php_sock;
2111 int ov, optlen, retval;
2112 #ifdef PHP_WIN32
2113 int timeout;
2114 #else
2115 struct timeval tv;
2116 #endif
2117 zend_long level, optname;
2118 void *opt_ptr;
2119 HashTable *opt_ht;
2120 zval *l_onoff, *l_linger;
2121 zval *sec, *usec;
2122
2123
2124 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rllz", &arg1, &level, &optname, &arg4) == FAILURE) {
2125 return;
2126 }
2127
2128 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2129 RETURN_FALSE;
2130 }
2131
2132 set_errno(0);
2133
2134 #define HANDLE_SUBCALL(res) \
2135 do { \
2136 if (res == 1) { goto default_case; } \
2137 else if (res == SUCCESS) { RETURN_TRUE; } \
2138 else { RETURN_FALSE; } \
2139 } while (0)
2140
2141
2142 if (level == IPPROTO_IP) {
2143 int res = php_do_setsockopt_ip_mcast(php_sock, level, optname, arg4);
2144 HANDLE_SUBCALL(res);
2145 }
2146
2147 #if HAVE_IPV6
2148 else if (level == IPPROTO_IPV6) {
2149 int res = php_do_setsockopt_ipv6_mcast(php_sock, level, optname, arg4);
2150 if (res == 1) {
2151 res = php_do_setsockopt_ipv6_rfc3542(php_sock, level, optname, arg4);
2152 }
2153 HANDLE_SUBCALL(res);
2154 }
2155 #endif
2156
2157 switch (optname) {
2158 case SO_LINGER: {
2159 const char l_onoff_key[] = "l_onoff";
2160 const char l_linger_key[] = "l_linger";
2161
2162 convert_to_array_ex(arg4);
2163 opt_ht = Z_ARRVAL_P(arg4);
2164
2165 if ((l_onoff = zend_hash_str_find(opt_ht, l_onoff_key, sizeof(l_onoff_key) - 1)) == NULL) {
2166 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
2167 RETURN_FALSE;
2168 }
2169 if ((l_linger = zend_hash_str_find(opt_ht, l_linger_key, sizeof(l_linger_key) - 1)) == NULL) {
2170 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
2171 RETURN_FALSE;
2172 }
2173
2174 convert_to_long_ex(l_onoff);
2175 convert_to_long_ex(l_linger);
2176
2177 lv.l_onoff = (unsigned short)Z_LVAL_P(l_onoff);
2178 lv.l_linger = (unsigned short)Z_LVAL_P(l_linger);
2179
2180 optlen = sizeof(lv);
2181 opt_ptr = &lv;
2182 break;
2183 }
2184
2185 case SO_RCVTIMEO:
2186 case SO_SNDTIMEO: {
2187 const char sec_key[] = "sec";
2188 const char usec_key[] = "usec";
2189
2190 convert_to_array_ex(arg4);
2191 opt_ht = Z_ARRVAL_P(arg4);
2192
2193 if ((sec = zend_hash_str_find(opt_ht, sec_key, sizeof(sec_key) - 1)) == NULL) {
2194 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", sec_key);
2195 RETURN_FALSE;
2196 }
2197 if ((usec = zend_hash_str_find(opt_ht, usec_key, sizeof(usec_key) - 1)) == NULL) {
2198 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", usec_key);
2199 RETURN_FALSE;
2200 }
2201
2202 convert_to_long_ex(sec);
2203 convert_to_long_ex(usec);
2204 #ifndef PHP_WIN32
2205 tv.tv_sec = Z_LVAL_P(sec);
2206 tv.tv_usec = Z_LVAL_P(usec);
2207 optlen = sizeof(tv);
2208 opt_ptr = &tv;
2209 #else
2210 timeout = Z_LVAL_P(sec) * 1000 + Z_LVAL_P(usec) / 1000;
2211 optlen = sizeof(int);
2212 opt_ptr = &timeout;
2213 #endif
2214 break;
2215 }
2216 #ifdef SO_BINDTODEVICE
2217 case SO_BINDTODEVICE: {
2218 if (Z_TYPE_P(arg4) == IS_STRING) {
2219 opt_ptr = Z_STRVAL_P(arg4);
2220 optlen = Z_STRLEN_P(arg4);
2221 } else {
2222 opt_ptr = "";
2223 optlen = 0;
2224 }
2225 break;
2226 }
2227 #endif
2228
2229 default:
2230 default_case:
2231 convert_to_long_ex(arg4);
2232 ov = Z_LVAL_P(arg4);
2233
2234 optlen = sizeof(ov);
2235 opt_ptr = &ov;
2236 break;
2237 }
2238
2239 retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
2240 if (retval != 0) {
2241 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
2242 RETURN_FALSE;
2243 }
2244
2245 RETURN_TRUE;
2246 }
2247 /* }}} */
2248
2249 #ifdef HAVE_SOCKETPAIR
2250 /* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd)
2251 Creates a pair of indistinguishable sockets and stores them in fds. */
2252 PHP_FUNCTION(socket_create_pair)
2253 {
2254 zval retval[2], *fds_array_zval;
2255 php_socket *php_sock[2];
2256 PHP_SOCKET fds_array[2];
2257 zend_long domain, type, protocol;
2258
2259 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lllz/", &domain, &type, &protocol, &fds_array_zval) == FAILURE) {
2260 return;
2261 }
2262
2263 php_sock[0] = php_create_socket();
2264 php_sock[1] = php_create_socket();
2265
2266 if (domain != AF_INET
2267 #if HAVE_IPV6
2268 && domain != AF_INET6
2269 #endif
2270 && domain != AF_UNIX) {
2271 php_error_docref(NULL, E_WARNING, "invalid socket domain [" ZEND_LONG_FMT "] specified for argument 1, assuming AF_INET", domain);
2272 domain = AF_INET;
2273 }
2274
2275 if (type > 10) {
2276 php_error_docref(NULL, E_WARNING, "invalid socket type [" ZEND_LONG_FMT "] specified for argument 2, assuming SOCK_STREAM", type);
2277 type = SOCK_STREAM;
2278 }
2279
2280 if (socketpair(domain, type, protocol, fds_array) != 0) {
2281 SOCKETS_G(last_error) = errno;
2282 php_error_docref(NULL, E_WARNING, "unable to create socket pair [%d]: %s", errno, sockets_strerror(errno));
2283 efree(php_sock[0]);
2284 efree(php_sock[1]);
2285 RETURN_FALSE;
2286 }
2287
2288 zval_ptr_dtor(fds_array_zval);
2289 array_init(fds_array_zval);
2290
2291 php_sock[0]->bsd_socket = fds_array[0];
2292 php_sock[1]->bsd_socket = fds_array[1];
2293 php_sock[0]->type = domain;
2294 php_sock[1]->type = domain;
2295 php_sock[0]->error = 0;
2296 php_sock[1]->error = 0;
2297 php_sock[0]->blocking = 1;
2298 php_sock[1]->blocking = 1;
2299
2300 ZVAL_RES(&retval[0], zend_register_resource(php_sock[0], le_socket));
2301 ZVAL_RES(&retval[1], zend_register_resource(php_sock[1], le_socket));
2302
2303 add_index_zval(fds_array_zval, 0, &retval[0]);
2304 add_index_zval(fds_array_zval, 1, &retval[1]);
2305
2306 RETURN_TRUE;
2307 }
2308 /* }}} */
2309 #endif
2310
2311 #ifdef HAVE_SHUTDOWN
2312 /* {{{ proto bool socket_shutdown(resource socket[, int how])
2313 Shuts down a socket for receiving, sending, or both. */
2314 PHP_FUNCTION(socket_shutdown)
2315 {
2316 zval *arg1;
2317 zend_long how_shutdown = 2;
2318 php_socket *php_sock;
2319
2320 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &arg1, &how_shutdown) == FAILURE) {
2321 return;
2322 }
2323
2324 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2325 RETURN_FALSE;
2326 }
2327
2328 if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
2329 PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno);
2330 RETURN_FALSE;
2331 }
2332
2333 RETURN_TRUE;
2334 }
2335 /* }}} */
2336 #endif
2337
2338 /* {{{ proto int socket_last_error([resource socket])
2339 Returns the last socket error (either the last used or the provided socket resource) */
2340 PHP_FUNCTION(socket_last_error)
2341 {
2342 zval *arg1 = NULL;
2343 php_socket *php_sock;
2344
2345 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
2346 return;
2347 }
2348
2349 if (arg1) {
2350 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2351 RETURN_FALSE;
2352 }
2353 RETVAL_LONG(php_sock->error);
2354 } else {
2355 RETVAL_LONG(SOCKETS_G(last_error));
2356 }
2357 }
2358 /* }}} */
2359
2360 /* {{{ proto void socket_clear_error([resource socket])
2361 Clears the error on the socket or the last error code. */
2362 PHP_FUNCTION(socket_clear_error)
2363 {
2364 zval *arg1 = NULL;
2365 php_socket *php_sock;
2366
2367 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg1) == FAILURE) {
2368 return;
2369 }
2370
2371 if (arg1) {
2372 if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
2373 RETURN_FALSE;
2374 }
2375 php_sock->error = 0;
2376 } else {
2377 SOCKETS_G(last_error) = 0;
2378 }
2379
2380 return;
2381 }
2382 /* }}} */
2383
2384 php_socket *socket_import_file_descriptor(PHP_SOCKET socket)
2385 {
2386 #ifdef SO_DOMAIN
2387 int type;
2388 socklen_t type_len = sizeof(type);
2389 #endif
2390 php_socket *retsock;
2391 php_sockaddr_storage addr;
2392 socklen_t addr_len = sizeof(addr);
2393 #ifndef PHP_WIN32
2394 int t;
2395 #endif
2396
2397 retsock = php_create_socket();
2398 retsock->bsd_socket = socket;
2399
2400 /* determine family */
2401 #ifdef SO_DOMAIN
2402 if (getsockopt(socket, SOL_SOCKET, SO_DOMAIN, &type, &type_len) == 0) {
2403 retsock->type = type;
2404 } else
2405 #endif
2406 if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
2407 retsock->type = addr.ss_family;
2408 } else {
2409 PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
2410 goto error;
2411 }
2412
2413 /* determine blocking mode */
2414 #ifndef PHP_WIN32
2415 t = fcntl(socket, F_GETFL);
2416 if (t == -1) {
2417 PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
2418 goto error;
2419 } else {
2420 retsock->blocking = !(t & O_NONBLOCK);
2421 }
2422 #endif
2423
2424 return retsock;
2425
2426 error:
2427 efree(retsock);
2428 return NULL;
2429 }
2430
2431 /* {{{ proto resource socket_import_stream(resource stream)
2432 Imports a stream that encapsulates a socket into a socket extension resource. */
2433 PHP_FUNCTION(socket_import_stream)
2434 {
2435 zval *zstream;
2436 php_stream *stream;
2437 php_socket *retsock = NULL;
2438 PHP_SOCKET socket; /* fd */
2439
2440 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream) == FAILURE) {
2441 return;
2442 }
2443 php_stream_from_zval(stream, zstream);
2444
2445 if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
2446 /* error supposedly already shown */
2447 RETURN_FALSE;
2448 }
2449
2450 retsock = socket_import_file_descriptor(socket);
2451 if (retsock == NULL) {
2452 RETURN_FALSE;
2453 }
2454
2455 #ifdef PHP_WIN32
2456 /* on windows, check if the stream is a socket stream and read its
2457 * private data; otherwise assume it's in non-blocking mode */
2458 if (php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
2459 retsock->blocking =
2460 ((php_netstream_data_t *)stream->abstract)->is_blocked;
2461 } else {
2462 retsock->blocking = 1;
2463 }
2464 #endif
2465
2466 /* hold a zval reference to the stream (holding a php_stream* directly could
2467 * also be done, but this makes socket_export_stream a bit simpler) */
2468 ZVAL_COPY(&retsock->zstream, zstream);
2469
2470 php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
2471 PHP_STREAM_BUFFER_NONE, NULL);
2472
2473 RETURN_RES(zend_register_resource(retsock, le_socket));
2474 }
2475 /* }}} */
2476
2477 /* {{{ proto resource socket_export_stream(resource socket)
2478 Exports a socket extension resource into a stream that encapsulates a socket. */
2479 PHP_FUNCTION(socket_export_stream)
2480 {
2481 zval *zsocket;
2482 php_socket *socket;
2483 php_stream *stream = NULL;
2484 php_netstream_data_t *stream_data;
2485 char *protocol = NULL;
2486 size_t protocollen = 0;
2487
2488 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsocket) == FAILURE) {
2489 return;
2490 }
2491 if ((socket = (php_socket *) zend_fetch_resource(Z_RES_P(zsocket), le_socket_name, le_socket)) == NULL) {
2492 RETURN_FALSE;
2493 }
2494
2495 /* Either we already exported a stream or the socket came from an import,
2496 * just return the existing stream */
2497 if (!Z_ISUNDEF(socket->zstream)) {
2498 RETURN_ZVAL(&socket->zstream, 1, 0);
2499 }
2500
2501 /* Determine if socket is using a protocol with one of the default registered
2502 * socket stream wrappers */
2503 if (socket->type == PF_INET
2504 #if HAVE_IPV6
2505 || socket->type == PF_INET6
2506 #endif
2507 ) {
2508 int protoid;
2509 socklen_t protoidlen = sizeof(protoid);
2510
2511 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &protoid, &protoidlen);
2512
2513 if (protoid == SOCK_STREAM) {
2514 /* SO_PROTOCOL is not (yet?) supported on OS X, so lets assume it's TCP there */
2515 #ifdef SO_PROTOCOL
2516 protoidlen = sizeof(protoid);
2517 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_PROTOCOL, (char *) &protoid, &protoidlen);
2518 if (protoid == IPPROTO_TCP)
2519 #endif
2520 {
2521 protocol = "tcp";
2522 protocollen = 3;
2523 }
2524 } else if (protoid == SOCK_DGRAM) {
2525 protocol = "udp";
2526 protocollen = 3;
2527 }
2528 #ifdef PF_UNIX
2529 } else if (socket->type == PF_UNIX) {
2530 int type;
2531 socklen_t typelen = sizeof(type);
2532
2533 getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen);
2534
2535 if (type == SOCK_STREAM) {
2536 protocol = "unix";
2537 protocollen = 4;
2538 } else if (type == SOCK_DGRAM) {
2539 protocol = "udg";
2540 protocollen = 3;
2541 }
2542 #endif
2543 }
2544
2545 /* Try to get a stream with the registered sockops for the protocol in use
2546 * We don't want streams to actually *do* anything though, so don't give it
2547 * anything apart from the protocol */
2548 if (protocol != NULL) {
2549 stream = php_stream_xport_create(protocol, protocollen, 0, 0, NULL, NULL, NULL, NULL, NULL);
2550 }
2551
2552 /* Fall back to creating a generic socket stream */
2553 if (stream == NULL) {
2554 stream = php_stream_sock_open_from_socket(socket->bsd_socket, 0);
2555
2556 if (stream == NULL) {
2557 php_error_docref(NULL, E_WARNING, "failed to create stream");
2558 RETURN_FALSE;
2559 }
2560 }
2561
2562 stream_data = (php_netstream_data_t *) stream->abstract;
2563 stream_data->socket = socket->bsd_socket;
2564 stream_data->is_blocked = socket->blocking;
2565 stream_data->timeout.tv_sec = FG(default_socket_timeout);
2566 stream_data->timeout.tv_usec = 0;
2567
2568 php_stream_to_zval(stream, &socket->zstream);
2569
2570 RETURN_ZVAL(&socket->zstream, 1, 0);
2571 }
2572 /* }}} */
2573
2574 /* {{{ proto resource addrinfo socket_addrinfo_lookup(string hostname[, mixed service, array hints])
2575 Gets array with contents of getaddrinfo about the given hostname. */
2576 PHP_FUNCTION(socket_addrinfo_lookup)
2577 {
2578 char *service = NULL;
2579 size_t service_len;
2580 zend_string *hostname, *key;
2581 zval *hint, *zhints = NULL;
2582
2583 struct addrinfo hints, *result, *rp, *res;
2584
2585 memset(&hints, 0, sizeof(hints));
2586
2587 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|sa", &hostname, &service, &service_len, &zhints) == FAILURE) {
2588 RETURN_NULL();
2589 }
2590
2591 if (zhints) {
2592 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zhints), key, hint) {
2593 if (key) {
2594 if (zend_string_equals_literal(key, "ai_flags")) {
2595 hints.ai_flags = zval_get_long(hint);
2596 } else if (zend_string_equals_literal(key, "ai_socktype")) {
2597 hints.ai_socktype = zval_get_long(hint);
2598 } else if (zend_string_equals_literal(key, "ai_protocol")) {
2599 hints.ai_protocol = zval_get_long(hint);
2600 } else if (zend_string_equals_literal(key, "ai_family")) {
2601 hints.ai_family = zval_get_long(hint);
2602 } else {
2603 php_error_docref(NULL, E_NOTICE, "Unknown hint %s", ZSTR_VAL(key));
2604 }
2605 }
2606 } ZEND_HASH_FOREACH_END();
2607 }
2608
2609 if (getaddrinfo(ZSTR_VAL(hostname), service, &hints, &result) != 0) {
2610 RETURN_FALSE;
2611 }
2612
2613 array_init(return_value);
2614
2615 for (rp = result; rp != NULL; rp = rp->ai_next) {
2616 if (rp->ai_family != AF_UNSPEC) {
2617 res = emalloc(sizeof(struct addrinfo));
2618 memcpy(res, rp, sizeof(struct addrinfo));
2619
2620 res->ai_addr = emalloc(rp->ai_addrlen);
2621 memcpy(res->ai_addr, rp->ai_addr, rp->ai_addrlen);
2622
2623 if (rp->ai_canonname != NULL) {
2624 res->ai_canonname = estrdup(rp->ai_canonname);
2625 }
2626
2627 add_next_index_resource(return_value, zend_register_resource(res, le_addrinfo));
2628 }
2629 }
2630
2631 freeaddrinfo(result);
2632 }
2633 /* }}} */
2634
2635 /* {{{ proto resource socket_addrinfo_bind(resource addrinfo)
2636 Creates and binds to a socket from a given addrinfo resource */
2637 PHP_FUNCTION(socket_addrinfo_bind)
2638 {
2639 zval *arg1;
2640 int retval;
2641 struct addrinfo *ai;
2642 php_socket *php_sock;
2643
2644 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
2645 return;
2646 }
2647
2648 if ((ai = (struct addrinfo *) zend_fetch_resource(Z_RES_P(arg1), le_addrinfo_name, le_addrinfo)) == NULL) {
2649 RETURN_FALSE;
2650 }
2651
2652 php_sock = php_create_socket();
2653 php_sock->bsd_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
2654 php_sock->type = ai->ai_family;
2655
2656 if (IS_INVALID_SOCKET(php_sock)) {
2657 SOCKETS_G(last_error) = errno;
2658 php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
2659 efree(php_sock);
2660 RETURN_FALSE;
2661 }
2662
2663 php_sock->error = 0;
2664 php_sock->blocking = 1;
2665
2666 switch(php_sock->type) {
2667 case AF_UNIX:
2668 {
2669 // AF_UNIX sockets via getaddrino are not implemented due to security problems
2670 close(php_sock->bsd_socket);
2671 efree(php_sock);
2672 RETURN_FALSE;
2673 }
2674
2675 case AF_INET:
2676 #if HAVE_IPV6
2677 case AF_INET6:
2678 #endif
2679 {
2680 retval = bind(php_sock->bsd_socket, ai->ai_addr, ai->ai_addrlen);
2681 break;
2682 }
2683 default:
2684 php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
2685 close(php_sock->bsd_socket);
2686 efree(php_sock);
2687 RETURN_FALSE;
2688 }
2689
2690 if (retval != 0) {
2691 PHP_SOCKET_ERROR(php_sock, "unable to bind address", errno);
2692 close(php_sock->bsd_socket);
2693 efree(php_sock);
2694 RETURN_FALSE;
2695 }
2696
2697 RETURN_RES(zend_register_resource(php_sock, le_socket));
2698 }
2699 /* }}} */
2700
2701 /* {{{ proto resource socket_addrinfo_connect(resource addrinfo)
2702 Creates and connects to a socket from a given addrinfo resource */
2703 PHP_FUNCTION(socket_addrinfo_connect)
2704 {
2705 zval *arg1;
2706 int retval;
2707 struct addrinfo *ai;
2708 php_socket *php_sock;
2709
2710 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
2711 return;
2712 }
2713
2714 if ((ai = (struct addrinfo *) zend_fetch_resource(Z_RES_P(arg1), le_addrinfo_name, le_addrinfo)) == NULL) {
2715 RETURN_FALSE;
2716 }
2717
2718 php_sock = php_create_socket();
2719 php_sock->bsd_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
2720 php_sock->type = ai->ai_family;
2721
2722 if (IS_INVALID_SOCKET(php_sock)) {
2723 SOCKETS_G(last_error) = errno;
2724 php_error_docref(NULL, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno));
2725 efree(php_sock);
2726 RETURN_FALSE;
2727 }
2728
2729 php_sock->error = 0;
2730 php_sock->blocking = 1;
2731
2732 switch(php_sock->type) {
2733 case AF_UNIX:
2734 {
2735 // AF_UNIX sockets via getaddrino are not implemented due to security problems
2736 close(php_sock->bsd_socket);
2737 efree(php_sock);
2738 RETURN_FALSE;
2739 }
2740
2741 case AF_INET:
2742 #if HAVE_IPV6
2743 case AF_INET6:
2744 #endif
2745 {
2746 retval = connect(php_sock->bsd_socket, ai->ai_addr, ai->ai_addrlen);
2747 break;
2748 }
2749 default:
2750 php_error_docref(NULL, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
2751 close(php_sock->bsd_socket);
2752 efree(php_sock);
2753 RETURN_FALSE;
2754 }
2755
2756 if (retval != 0) {
2757 PHP_SOCKET_ERROR(php_sock, "unable to connect address", errno);
2758 close(php_sock->bsd_socket);
2759 efree(php_sock);
2760 RETURN_FALSE;
2761 }
2762
2763 RETURN_RES(zend_register_resource(php_sock, le_socket));
2764 }
2765 /* }}} */
2766
2767 /* {{{ proto resource socket_addrinfo_explain(resource addrinfo)
2768 Creates and connects to a socket from a given addrinfo resource */
2769 PHP_FUNCTION(socket_addrinfo_explain)
2770 {
2771 zval *arg1, sockaddr;
2772 struct addrinfo *ai;
2773
2774 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) {
2775 return;
2776 }
2777
2778 if ((ai = (struct addrinfo *) zend_fetch_resource(Z_RES_P(arg1), le_addrinfo_name, le_addrinfo)) == NULL) {
2779 RETURN_FALSE;
2780 }
2781
2782 array_init(return_value);
2783
2784 add_assoc_long(return_value, "ai_flags", ai->ai_flags);
2785 add_assoc_long(return_value, "ai_family", ai->ai_family);
2786 add_assoc_long(return_value, "ai_socktype", ai->ai_socktype);
2787 add_assoc_long(return_value, "ai_protocol", ai->ai_protocol);
2788 if (ai->ai_canonname != NULL) {
2789 add_assoc_string(return_value, "ai_canonname", ai->ai_canonname);
2790 }
2791
2792 array_init(&sockaddr);
2793 switch(ai->ai_family) {
2794 case AF_INET:
2795 {
2796 struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
2797 char addr[INET_ADDRSTRLEN];
2798
2799 add_assoc_long(&sockaddr, "sin_port", ntohs((unsigned short) sa->sin_port));
2800 inet_ntop(ai->ai_family, &sa->sin_addr, addr, sizeof(addr));
2801 add_assoc_string(&sockaddr, "sin_addr", addr);
2802 break;
2803 }
2804 #if HAVE_IPV6
2805 case AF_INET6:
2806 {
2807 struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
2808 char addr[INET6_ADDRSTRLEN];
2809
2810 add_assoc_long(&sockaddr, "sin6_port", ntohs((unsigned short) sa->sin6_port));
2811 inet_ntop(ai->ai_family, &sa->sin6_addr, addr, sizeof(addr));
2812 add_assoc_string(&sockaddr, "sin6_addr", addr);
2813 break;
2814 }
2815 #endif
2816 }
2817
2818 add_assoc_zval(return_value, "ai_addr", &sockaddr);
2819 }
2820 /* }}} */
2821
2822 #ifdef PHP_WIN32
2823
2824 /* {{{ proto string socket_wsaprotocol_info_export(resource stream, int target_pid)
2825 Exports the network socket information suitable to be used in another process and returns the info id. */
2826 PHP_FUNCTION(socket_wsaprotocol_info_export)
2827 {
2828 WSAPROTOCOL_INFO wi;
2829 zval *zsocket;
2830 php_socket *socket;
2831 zend_long target_pid;
2832 zend_string *seg_name;
2833 HANDLE map;
2834
2835 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &zsocket, &target_pid) == FAILURE) {
2836 return;
2837 }
2838 if ((socket = (php_socket *) zend_fetch_resource(Z_RES_P(zsocket), le_socket_name, le_socket)) == NULL) {
2839 RETURN_FALSE;
2840 }
2841
2842 if (SOCKET_ERROR == WSADuplicateSocket(socket->bsd_socket, (DWORD)target_pid, &wi)) {
2843 DWORD err = WSAGetLastError();
2844 LPSTR buf = NULL;
2845
2846 if (!FormatMessage(
2847 FORMAT_MESSAGE_ALLOCATE_BUFFER |
2848 FORMAT_MESSAGE_FROM_SYSTEM |
2849 FORMAT_MESSAGE_IGNORE_INSERTS,
2850 NULL,
2851 err,
2852 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2853 (LPSTR)&buf,
2854 0, NULL)) {
2855 php_error_docref(NULL, E_WARNING, "Unable to export WSA protocol info [0x%08lx]", err);
2856 } else {
2857 php_error_docref(NULL, E_WARNING, "Unable to export WSA protocol info [0x%08lx]: %s", err, buf);
2858 }
2859
2860 RETURN_FALSE;
2861 }
2862
2863 seg_name = zend_strpprintf(0, "php_wsa_for_%u", SOCKETS_G(wsa_child_count)++);
2864 map = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(WSAPROTOCOL_INFO), ZSTR_VAL(seg_name));
2865 if (NULL != map) {
2866 LPVOID view = MapViewOfFile(map, FILE_MAP_WRITE, 0, 0, 0);
2867 if (view) {
2868 memcpy(view, &wi, sizeof(wi));
2869 UnmapViewOfFile(view);
2870 zend_hash_add_ptr(&(SOCKETS_G(wsa_info)), seg_name, map);
2871 RETURN_STR(seg_name);
2872 } else {
2873 DWORD err = GetLastError();
2874 php_error_docref(NULL, E_WARNING, "Unable to map file view [0x%08lx]", err);
2875 }
2876 } else {
2877 DWORD err = GetLastError();
2878 php_error_docref(NULL, E_WARNING, "Unable to create file mapping [0x%08lx]", err);
2879 }
2880 zend_string_release_ex(seg_name, 0);
2881
2882 RETURN_FALSE;
2883 }
2884 /* }}} */
2885
2886 /* {{{ proto resource socket_wsaprotocol_info_import(string id)
2887 Imports the network socket information using the supplied id and creates a new socket on its base. */
2888 PHP_FUNCTION(socket_wsaprotocol_info_import)
2889 {
2890 char *id;
2891 size_t id_len;
2892 WSAPROTOCOL_INFO wi;
2893 PHP_SOCKET sock;
2894 php_socket *php_sock;
2895 HANDLE map;
2896
2897 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &id, &id_len) == FAILURE) {
2898 return;
2899 }
2900
2901 map = OpenFileMapping(FILE_MAP_READ, FALSE, id);
2902 if (map) {
2903 LPVOID view = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
2904 if (view) {
2905 memcpy(&wi, view, sizeof(WSAPROTOCOL_INFO));
2906 UnmapViewOfFile(view);
2907 } else {
2908 DWORD err = GetLastError();
2909 php_error_docref(NULL, E_WARNING, "Unable to map file view [0x%08lx]", err);
2910 RETURN_FALSE;
2911 }
2912 CloseHandle(map);
2913 } else {
2914 DWORD err = GetLastError();
2915 php_error_docref(NULL, E_WARNING, "Unable to open file mapping [0x%08lx]", err);
2916 RETURN_FALSE;
2917 }
2918
2919 sock = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &wi, 0, 0);
2920 if (INVALID_SOCKET == sock) {
2921 DWORD err = WSAGetLastError();
2922 LPSTR buf = NULL;
2923
2924 if (!FormatMessage(
2925 FORMAT_MESSAGE_ALLOCATE_BUFFER |
2926 FORMAT_MESSAGE_FROM_SYSTEM |
2927 FORMAT_MESSAGE_IGNORE_INSERTS,
2928 NULL,
2929 err,
2930 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2931 (LPSTR)&buf,
2932 0, NULL)) {
2933 php_error_docref(NULL, E_WARNING, "Unable to import WSA protocol info [0x%08lx]", err);
2934 } else {
2935 php_error_docref(NULL, E_WARNING, "Unable to import WSA protocol info [0x%08lx]: %s", err, buf);
2936 }
2937
2938 RETURN_FALSE;
2939 }
2940
2941 php_sock = php_create_socket();
2942 php_sock->bsd_socket = sock;
2943 php_sock->type = wi.iAddressFamily;
2944 php_sock->error = 0;
2945 php_sock->blocking = 1;
2946
2947 RETURN_RES(zend_register_resource(php_sock, le_socket));
2948 }
2949 /* }}} */
2950
2951 /* {{{ proto bool socket_wsaprotocol_info_release(string id)
2952 Frees the exported info and corresponding resources using the supplied id. */
2953 PHP_FUNCTION(socket_wsaprotocol_info_release)
2954 {
2955 char *id;
2956 size_t id_len;
2957
2958 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &id, &id_len) == FAILURE) {
2959 return;
2960 }
2961
2962 RETURN_BOOL(SUCCESS == zend_hash_str_del(&(SOCKETS_G(wsa_info)), id, id_len));
2963 }
2964 /* }}} */
2965 #endif
2966
2967 /*
2968 * Local variables:
2969 * tab-width: 4
2970 * c-basic-offset: 4
2971 * End:
2972 * vim600: fdm=marker
2973 * vim: noet sw=4 ts=4
2974 */
2975