This source file includes following definitions.
- php_sockop_write
- php_sock_stream_wait_for_data
- php_sockop_read
- php_sockop_close
- php_sockop_flush
- php_sockop_stat
- sock_sendto
- sock_recvfrom
- php_sockop_set_option
- php_sockop_cast
- parse_unix_address
- parse_ip_address_ex
- parse_ip_address
- php_tcp_sockop_bind
- php_tcp_sockop_connect
- php_tcp_sockop_accept
- php_tcp_sockop_set_option
- php_stream_generic_socket_factory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include "php.h"
22 #include "ext/standard/file.h"
23 #include "streams/php_streams_int.h"
24 #include "php_network.h"
25
26 #if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
27 # undef AF_UNIX
28 #endif
29
30 #if defined(AF_UNIX)
31 #include <sys/un.h>
32 #endif
33
34 #ifndef MSG_DONTWAIT
35 # define MSG_DONTWAIT 0
36 #endif
37
38 #ifndef MSG_PEEK
39 # define MSG_PEEK 0
40 #endif
41
42 #ifdef PHP_WIN32
43
44 # define XP_SOCK_BUF_SIZE(sz) (((sz) > INT_MAX) ? INT_MAX : (int)(sz))
45 #else
46 # define XP_SOCK_BUF_SIZE(sz) (sz)
47 #endif
48
49 php_stream_ops php_stream_generic_socket_ops;
50 PHPAPI php_stream_ops php_stream_socket_ops;
51 php_stream_ops php_stream_udp_socket_ops;
52 #ifdef AF_UNIX
53 php_stream_ops php_stream_unix_socket_ops;
54 php_stream_ops php_stream_unixdg_socket_ops;
55 #endif
56
57
58 static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam);
59
60
61 static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count)
62 {
63 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
64 int didwrite;
65 struct timeval *ptimeout;
66
67 if (!sock || sock->socket == -1) {
68 return 0;
69 }
70
71 if (sock->timeout.tv_sec == -1)
72 ptimeout = NULL;
73 else
74 ptimeout = &sock->timeout;
75
76 retry:
77 didwrite = send(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0);
78
79 if (didwrite <= 0) {
80 int err = php_socket_errno();
81 char *estr;
82
83 if (sock->is_blocked && (err == EWOULDBLOCK || err == EAGAIN)) {
84 int retval;
85
86 sock->timeout_event = 0;
87
88 do {
89 retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout);
90
91 if (retval == 0) {
92 sock->timeout_event = 1;
93 break;
94 }
95
96 if (retval > 0) {
97
98 goto retry;
99 }
100
101 err = php_socket_errno();
102 } while (err == EINTR);
103 }
104 estr = php_socket_strerror(err, NULL, 0);
105 php_error_docref(NULL, E_NOTICE, "send of " ZEND_LONG_FMT " bytes failed with errno=%ld %s",
106 (zend_long)count, err, estr);
107 efree(estr);
108 }
109
110 if (didwrite > 0) {
111 php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0);
112 }
113
114 if (didwrite < 0) {
115 didwrite = 0;
116 }
117
118 return didwrite;
119 }
120
121 static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock)
122 {
123 int retval;
124 struct timeval *ptimeout;
125
126 if (!sock || sock->socket == -1) {
127 return;
128 }
129
130 sock->timeout_event = 0;
131
132 if (sock->timeout.tv_sec == -1)
133 ptimeout = NULL;
134 else
135 ptimeout = &sock->timeout;
136
137 while(1) {
138 retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
139
140 if (retval == 0)
141 sock->timeout_event = 1;
142
143 if (retval >= 0)
144 break;
145
146 if (php_socket_errno() != EINTR)
147 break;
148 }
149 }
150
151 static size_t php_sockop_read(php_stream *stream, char *buf, size_t count)
152 {
153 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
154 ssize_t nr_bytes = 0;
155 int err;
156
157 if (!sock || sock->socket == -1) {
158 return 0;
159 }
160
161 if (sock->is_blocked) {
162 php_sock_stream_wait_for_data(stream, sock);
163 if (sock->timeout_event)
164 return 0;
165 }
166
167 nr_bytes = recv(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && sock->timeout.tv_sec != -1) ? MSG_DONTWAIT : 0);
168 err = php_socket_errno();
169
170 stream->eof = (nr_bytes == 0 || (nr_bytes == -1 && err != EWOULDBLOCK && err != EAGAIN));
171
172 if (nr_bytes > 0) {
173 php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0);
174 }
175
176 if (nr_bytes < 0) {
177 nr_bytes = 0;
178 }
179
180 return nr_bytes;
181 }
182
183
184 static int php_sockop_close(php_stream *stream, int close_handle)
185 {
186 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
187 #ifdef PHP_WIN32
188 int n;
189 #endif
190
191 if (!sock) {
192 return 0;
193 }
194
195 if (close_handle) {
196
197 #ifdef PHP_WIN32
198 if (sock->socket == -1)
199 sock->socket = SOCK_ERR;
200 #endif
201 if (sock->socket != SOCK_ERR) {
202 #ifdef PHP_WIN32
203
204 shutdown(sock->socket, SHUT_RD);
205
206
207
208
209
210
211
212 do {
213 n = php_pollfd_for_ms(sock->socket, POLLOUT, 500);
214 } while (n == -1 && php_socket_errno() == EINTR);
215 #endif
216 closesocket(sock->socket);
217 sock->socket = SOCK_ERR;
218 }
219
220 }
221
222 pefree(sock, php_stream_is_persistent(stream));
223
224 return 0;
225 }
226
227 static int php_sockop_flush(php_stream *stream)
228 {
229 #if 0
230 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
231 return fsync(sock->socket);
232 #endif
233 return 0;
234 }
235
236 static int php_sockop_stat(php_stream *stream, php_stream_statbuf *ssb)
237 {
238 #if ZEND_WIN32
239 return 0;
240 #else
241 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
242
243 return zend_fstat(sock->socket, &ssb->sb);
244 #endif
245 }
246
247 static inline int sock_sendto(php_netstream_data_t *sock, const char *buf, size_t buflen, int flags,
248 struct sockaddr *addr, socklen_t addrlen
249 )
250 {
251 int ret;
252 if (addr) {
253 ret = sendto(sock->socket, buf, XP_SOCK_BUF_SIZE(buflen), flags, addr, XP_SOCK_BUF_SIZE(addrlen));
254
255 return (ret == SOCK_CONN_ERR) ? -1 : ret;
256 }
257 #ifdef PHP_WIN32
258 return ((ret = send(sock->socket, buf, buflen > INT_MAX ? INT_MAX : (int)buflen, flags)) == SOCK_CONN_ERR) ? -1 : ret;
259 #else
260 return ((ret = send(sock->socket, buf, buflen, flags)) == SOCK_CONN_ERR) ? -1 : ret;
261 #endif
262 }
263
264 static inline int sock_recvfrom(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
265 zend_string **textaddr,
266 struct sockaddr **addr, socklen_t *addrlen
267 )
268 {
269 php_sockaddr_storage sa;
270 socklen_t sl = sizeof(sa);
271 int ret;
272 int want_addr = textaddr || addr;
273
274 if (want_addr) {
275 ret = recvfrom(sock->socket, buf, XP_SOCK_BUF_SIZE(buflen), flags, (struct sockaddr*)&sa, &sl);
276 ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
277 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
278 textaddr, addr, addrlen);
279 } else {
280 ret = recv(sock->socket, buf, XP_SOCK_BUF_SIZE(buflen), flags);
281 ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
282 }
283
284 return ret;
285 }
286
287 static int php_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam)
288 {
289 int oldmode, flags;
290 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
291 php_stream_xport_param *xparam;
292
293 if (!sock) {
294 return PHP_STREAM_OPTION_RETURN_NOTIMPL;
295 }
296
297 switch(option) {
298 case PHP_STREAM_OPTION_CHECK_LIVENESS:
299 {
300 struct timeval tv;
301 char buf;
302 int alive = 1;
303
304 if (value == -1) {
305 if (sock->timeout.tv_sec == -1) {
306 tv.tv_sec = FG(default_socket_timeout);
307 tv.tv_usec = 0;
308 } else {
309 tv = sock->timeout;
310 }
311 } else {
312 tv.tv_sec = value;
313 tv.tv_usec = 0;
314 }
315
316 if (sock->socket == -1) {
317 alive = 0;
318 } else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
319 #ifdef PHP_WIN32
320 int ret;
321 #else
322 ssize_t ret;
323 #endif
324 int err;
325
326 ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK);
327 err = php_socket_errno();
328 if (0 == ret ||
329 (0 > ret && err != EWOULDBLOCK && err != EAGAIN)) {
330 alive = 0;
331 }
332 }
333 return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
334 }
335
336 case PHP_STREAM_OPTION_BLOCKING:
337 oldmode = sock->is_blocked;
338 if (SUCCESS == php_set_sock_blocking(sock->socket, value)) {
339 sock->is_blocked = value;
340 return oldmode;
341 }
342 return PHP_STREAM_OPTION_RETURN_ERR;
343
344 case PHP_STREAM_OPTION_READ_TIMEOUT:
345 sock->timeout = *(struct timeval*)ptrparam;
346 sock->timeout_event = 0;
347 return PHP_STREAM_OPTION_RETURN_OK;
348
349 case PHP_STREAM_OPTION_META_DATA_API:
350 add_assoc_bool((zval *)ptrparam, "timed_out", sock->timeout_event);
351 add_assoc_bool((zval *)ptrparam, "blocked", sock->is_blocked);
352 add_assoc_bool((zval *)ptrparam, "eof", stream->eof);
353 return PHP_STREAM_OPTION_RETURN_OK;
354
355 case PHP_STREAM_OPTION_XPORT_API:
356 xparam = (php_stream_xport_param *)ptrparam;
357
358 switch (xparam->op) {
359 case STREAM_XPORT_OP_LISTEN:
360 xparam->outputs.returncode = (listen(sock->socket, xparam->inputs.backlog) == 0) ? 0: -1;
361 return PHP_STREAM_OPTION_RETURN_OK;
362
363 case STREAM_XPORT_OP_GET_NAME:
364 xparam->outputs.returncode = php_network_get_sock_name(sock->socket,
365 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
366 xparam->want_addr ? &xparam->outputs.addr : NULL,
367 xparam->want_addr ? &xparam->outputs.addrlen : NULL
368 );
369 return PHP_STREAM_OPTION_RETURN_OK;
370
371 case STREAM_XPORT_OP_GET_PEER_NAME:
372 xparam->outputs.returncode = php_network_get_peer_name(sock->socket,
373 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
374 xparam->want_addr ? &xparam->outputs.addr : NULL,
375 xparam->want_addr ? &xparam->outputs.addrlen : NULL
376 );
377 return PHP_STREAM_OPTION_RETURN_OK;
378
379 case STREAM_XPORT_OP_SEND:
380 flags = 0;
381 if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
382 flags |= MSG_OOB;
383 }
384 xparam->outputs.returncode = sock_sendto(sock,
385 xparam->inputs.buf, xparam->inputs.buflen,
386 flags,
387 xparam->inputs.addr,
388 xparam->inputs.addrlen);
389 if (xparam->outputs.returncode == -1) {
390 char *err = php_socket_strerror(php_socket_errno(), NULL, 0);
391 php_error_docref(NULL, E_WARNING,
392 "%s\n", err);
393 efree(err);
394 }
395 return PHP_STREAM_OPTION_RETURN_OK;
396
397 case STREAM_XPORT_OP_RECV:
398 flags = 0;
399 if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
400 flags |= MSG_OOB;
401 }
402 if ((xparam->inputs.flags & STREAM_PEEK) == STREAM_PEEK) {
403 flags |= MSG_PEEK;
404 }
405 xparam->outputs.returncode = sock_recvfrom(sock,
406 xparam->inputs.buf, xparam->inputs.buflen,
407 flags,
408 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
409 xparam->want_addr ? &xparam->outputs.addr : NULL,
410 xparam->want_addr ? &xparam->outputs.addrlen : NULL
411 );
412 return PHP_STREAM_OPTION_RETURN_OK;
413
414
415 #ifdef HAVE_SHUTDOWN
416 # ifndef SHUT_RD
417 # define SHUT_RD 0
418 # endif
419 # ifndef SHUT_WR
420 # define SHUT_WR 1
421 # endif
422 # ifndef SHUT_RDWR
423 # define SHUT_RDWR 2
424 # endif
425 case STREAM_XPORT_OP_SHUTDOWN: {
426 static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR};
427
428 xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]);
429 return PHP_STREAM_OPTION_RETURN_OK;
430 }
431 #endif
432
433 default:
434 return PHP_STREAM_OPTION_RETURN_NOTIMPL;
435 }
436
437 default:
438 return PHP_STREAM_OPTION_RETURN_NOTIMPL;
439 }
440 }
441
442 static int php_sockop_cast(php_stream *stream, int castas, void **ret)
443 {
444 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
445
446 if (!sock) {
447 return FAILURE;
448 }
449
450 switch(castas) {
451 case PHP_STREAM_AS_STDIO:
452 if (ret) {
453 *(FILE**)ret = fdopen(sock->socket, stream->mode);
454 if (*ret)
455 return SUCCESS;
456 return FAILURE;
457 }
458 return SUCCESS;
459 case PHP_STREAM_AS_FD_FOR_SELECT:
460 case PHP_STREAM_AS_FD:
461 case PHP_STREAM_AS_SOCKETD:
462 if (ret)
463 *(php_socket_t *)ret = sock->socket;
464 return SUCCESS;
465 default:
466 return FAILURE;
467 }
468 }
469
470
471
472
473
474
475
476
477 php_stream_ops php_stream_generic_socket_ops = {
478 php_sockop_write, php_sockop_read,
479 php_sockop_close, php_sockop_flush,
480 "generic_socket",
481 NULL,
482 php_sockop_cast,
483 php_sockop_stat,
484 php_sockop_set_option,
485 };
486
487
488 php_stream_ops php_stream_socket_ops = {
489 php_sockop_write, php_sockop_read,
490 php_sockop_close, php_sockop_flush,
491 "tcp_socket",
492 NULL,
493 php_sockop_cast,
494 php_sockop_stat,
495 php_tcp_sockop_set_option,
496 };
497
498 php_stream_ops php_stream_udp_socket_ops = {
499 php_sockop_write, php_sockop_read,
500 php_sockop_close, php_sockop_flush,
501 "udp_socket",
502 NULL,
503 php_sockop_cast,
504 php_sockop_stat,
505 php_tcp_sockop_set_option,
506 };
507
508 #ifdef AF_UNIX
509 php_stream_ops php_stream_unix_socket_ops = {
510 php_sockop_write, php_sockop_read,
511 php_sockop_close, php_sockop_flush,
512 "unix_socket",
513 NULL,
514 php_sockop_cast,
515 php_sockop_stat,
516 php_tcp_sockop_set_option,
517 };
518 php_stream_ops php_stream_unixdg_socket_ops = {
519 php_sockop_write, php_sockop_read,
520 php_sockop_close, php_sockop_flush,
521 "udg_socket",
522 NULL,
523 php_sockop_cast,
524 php_sockop_stat,
525 php_tcp_sockop_set_option,
526 };
527 #endif
528
529
530
531
532 #ifdef AF_UNIX
533 static inline int parse_unix_address(php_stream_xport_param *xparam, struct sockaddr_un *unix_addr)
534 {
535 memset(unix_addr, 0, sizeof(*unix_addr));
536 unix_addr->sun_family = AF_UNIX;
537
538
539
540 if (xparam->inputs.namelen >= sizeof(unix_addr->sun_path)) {
541
542
543
544
545
546 xparam->inputs.namelen = sizeof(unix_addr->sun_path) - 1;
547 php_error_docref(NULL, E_NOTICE,
548 "socket path exceeded the maximum allowed length of %lu bytes "
549 "and was truncated", (unsigned long)sizeof(unix_addr->sun_path));
550 }
551
552 memcpy(unix_addr->sun_path, xparam->inputs.name, xparam->inputs.namelen);
553
554 return 1;
555 }
556 #endif
557
558 static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *portno, int get_err, zend_string **err)
559 {
560 char *colon;
561 char *host = NULL;
562
563 #ifdef HAVE_IPV6
564 char *p;
565
566 if (*(str) == '[' && str_len > 1) {
567
568 p = memchr(str + 1, ']', str_len - 2);
569 if (!p || *(p + 1) != ':') {
570 if (get_err) {
571 *err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
572 }
573 return NULL;
574 }
575 *portno = atoi(p + 2);
576 return estrndup(str + 1, p - str - 1);
577 }
578 #endif
579 if (str_len) {
580 colon = memchr(str, ':', str_len - 1);
581 } else {
582 colon = NULL;
583 }
584 if (colon) {
585 *portno = atoi(colon + 1);
586 host = estrndup(str, colon - str);
587 } else {
588 if (get_err) {
589 *err = strpprintf(0, "Failed to parse address \"%s\"", str);
590 }
591 return NULL;
592 }
593
594 return host;
595 }
596
597 static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno)
598 {
599 return parse_ip_address_ex(xparam->inputs.name, xparam->inputs.namelen, portno, xparam->want_errortext, &xparam->outputs.error_text);
600 }
601
602 static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
603 php_stream_xport_param *xparam)
604 {
605 char *host = NULL;
606 int portno, err;
607 long sockopts = STREAM_SOCKOP_NONE;
608 zval *tmpzval = NULL;
609
610 #ifdef AF_UNIX
611 if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
612 struct sockaddr_un unix_addr;
613
614 sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
615
616 if (sock->socket == SOCK_ERR) {
617 if (xparam->want_errortext) {
618 xparam->outputs.error_text = strpprintf(0, "Failed to create unix%s socket %s",
619 stream->ops == &php_stream_unix_socket_ops ? "" : "datagram",
620 strerror(errno));
621 }
622 return -1;
623 }
624
625 parse_unix_address(xparam, &unix_addr);
626
627 return bind(sock->socket, (const struct sockaddr *)&unix_addr,
628 (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen);
629 }
630 #endif
631
632 host = parse_ip_address(xparam, &portno);
633
634 if (host == NULL) {
635 return -1;
636 }
637
638 #ifdef IPV6_V6ONLY
639 if (PHP_STREAM_CONTEXT(stream)
640 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "ipv6_v6only")) != NULL
641 && Z_TYPE_P(tmpzval) != IS_NULL
642 ) {
643 sockopts |= STREAM_SOCKOP_IPV6_V6ONLY;
644 sockopts |= STREAM_SOCKOP_IPV6_V6ONLY_ENABLED * zend_is_true(tmpzval);
645 }
646 #endif
647
648 #ifdef SO_REUSEPORT
649 if (PHP_STREAM_CONTEXT(stream)
650 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_reuseport")) != NULL
651 && zend_is_true(tmpzval)
652 ) {
653 sockopts |= STREAM_SOCKOP_SO_REUSEPORT;
654 }
655 #endif
656
657 #ifdef SO_BROADCAST
658 if (stream->ops == &php_stream_udp_socket_ops
659 && PHP_STREAM_CONTEXT(stream)
660 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL
661 && zend_is_true(tmpzval)
662 ) {
663 sockopts |= STREAM_SOCKOP_SO_BROADCAST;
664 }
665 #endif
666
667 sock->socket = php_network_bind_socket_to_local_addr(host, portno,
668 stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
669 sockopts,
670 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
671 &err
672 );
673
674 if (host) {
675 efree(host);
676 }
677
678 return sock->socket == -1 ? -1 : 0;
679 }
680
681 static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
682 php_stream_xport_param *xparam)
683 {
684 char *host = NULL, *bindto = NULL;
685 int portno, bindport = 0;
686 int err = 0;
687 int ret;
688 zval *tmpzval = NULL;
689 long sockopts = STREAM_SOCKOP_NONE;
690
691 #ifdef AF_UNIX
692 if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
693 struct sockaddr_un unix_addr;
694
695 sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
696
697 if (sock->socket == SOCK_ERR) {
698 if (xparam->want_errortext) {
699 xparam->outputs.error_text = strpprintf(0, "Failed to create unix socket");
700 }
701 return -1;
702 }
703
704 parse_unix_address(xparam, &unix_addr);
705
706 ret = php_network_connect_socket(sock->socket,
707 (const struct sockaddr *)&unix_addr, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen,
708 xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC, xparam->inputs.timeout,
709 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
710 &err);
711
712 xparam->outputs.error_code = err;
713
714 goto out;
715 }
716 #endif
717
718 host = parse_ip_address(xparam, &portno);
719
720 if (host == NULL) {
721 return -1;
722 }
723
724 if (PHP_STREAM_CONTEXT(stream) && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "bindto")) != NULL) {
725 if (Z_TYPE_P(tmpzval) != IS_STRING) {
726 if (xparam->want_errortext) {
727 xparam->outputs.error_text = strpprintf(0, "local_addr context option is not a string.");
728 }
729 efree(host);
730 return -1;
731 }
732 bindto = parse_ip_address_ex(Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval), &bindport, xparam->want_errortext, &xparam->outputs.error_text);
733 }
734
735 #ifdef SO_BROADCAST
736 if (stream->ops == &php_stream_udp_socket_ops
737 && PHP_STREAM_CONTEXT(stream)
738 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL
739 && zend_is_true(tmpzval)
740 ) {
741 sockopts |= STREAM_SOCKOP_SO_BROADCAST;
742 }
743 #endif
744
745
746
747
748
749 sock->socket = php_network_connect_socket_to_host(host, portno,
750 stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
751 xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC,
752 xparam->inputs.timeout,
753 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
754 &err,
755 bindto,
756 bindport,
757 sockopts
758 );
759
760 ret = sock->socket == -1 ? -1 : 0;
761 xparam->outputs.error_code = err;
762
763 if (host) {
764 efree(host);
765 }
766 if (bindto) {
767 efree(bindto);
768 }
769
770 #ifdef AF_UNIX
771 out:
772 #endif
773
774 if (ret >= 0 && xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && err == EINPROGRESS) {
775
776 return 1;
777 }
778
779 return ret;
780 }
781
782 static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
783 php_stream_xport_param *xparam STREAMS_DC)
784 {
785 int clisock;
786
787 xparam->outputs.client = NULL;
788
789 clisock = php_network_accept_incoming(sock->socket,
790 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
791 xparam->want_addr ? &xparam->outputs.addr : NULL,
792 xparam->want_addr ? &xparam->outputs.addrlen : NULL,
793 xparam->inputs.timeout,
794 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
795 &xparam->outputs.error_code
796 );
797
798 if (clisock >= 0) {
799 php_netstream_data_t *clisockdata;
800
801 clisockdata = emalloc(sizeof(*clisockdata));
802
803 if (clisockdata == NULL) {
804 close(clisock);
805
806 } else {
807 memcpy(clisockdata, sock, sizeof(*clisockdata));
808 clisockdata->socket = clisock;
809
810 xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
811 if (xparam->outputs.client) {
812 xparam->outputs.client->ctx = stream->ctx;
813 if (stream->ctx) {
814 GC_REFCOUNT(stream->ctx)++;
815 }
816 }
817 }
818 }
819
820 return xparam->outputs.client == NULL ? -1 : 0;
821 }
822
823 static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam)
824 {
825 php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
826 php_stream_xport_param *xparam;
827
828 switch(option) {
829 case PHP_STREAM_OPTION_XPORT_API:
830 xparam = (php_stream_xport_param *)ptrparam;
831
832 switch(xparam->op) {
833 case STREAM_XPORT_OP_CONNECT:
834 case STREAM_XPORT_OP_CONNECT_ASYNC:
835 xparam->outputs.returncode = php_tcp_sockop_connect(stream, sock, xparam);
836 return PHP_STREAM_OPTION_RETURN_OK;
837
838 case STREAM_XPORT_OP_BIND:
839 xparam->outputs.returncode = php_tcp_sockop_bind(stream, sock, xparam);
840 return PHP_STREAM_OPTION_RETURN_OK;
841
842
843 case STREAM_XPORT_OP_ACCEPT:
844 xparam->outputs.returncode = php_tcp_sockop_accept(stream, sock, xparam STREAMS_CC);
845 return PHP_STREAM_OPTION_RETURN_OK;
846 default:
847
848 ;
849 }
850 }
851 return php_sockop_set_option(stream, option, value, ptrparam);
852 }
853
854
855 PHPAPI php_stream *php_stream_generic_socket_factory(const char *proto, size_t protolen,
856 const char *resourcename, size_t resourcenamelen,
857 const char *persistent_id, int options, int flags,
858 struct timeval *timeout,
859 php_stream_context *context STREAMS_DC)
860 {
861 php_stream *stream = NULL;
862 php_netstream_data_t *sock;
863 php_stream_ops *ops;
864
865
866 if (strncmp(proto, "tcp", protolen) == 0) {
867 ops = &php_stream_socket_ops;
868 } else if (strncmp(proto, "udp", protolen) == 0) {
869 ops = &php_stream_udp_socket_ops;
870 }
871 #ifdef AF_UNIX
872 else if (strncmp(proto, "unix", protolen) == 0) {
873 ops = &php_stream_unix_socket_ops;
874 } else if (strncmp(proto, "udg", protolen) == 0) {
875 ops = &php_stream_unixdg_socket_ops;
876 }
877 #endif
878 else {
879
880 return NULL;
881 }
882
883 sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
884 memset(sock, 0, sizeof(php_netstream_data_t));
885
886 sock->is_blocked = 1;
887 sock->timeout.tv_sec = FG(default_socket_timeout);
888 sock->timeout.tv_usec = 0;
889
890
891
892 sock->socket = -1;
893
894 stream = php_stream_alloc_rel(ops, sock, persistent_id, "r+");
895
896 if (stream == NULL) {
897 pefree(sock, persistent_id ? 1 : 0);
898 return NULL;
899 }
900
901 if (flags == 0) {
902 return stream;
903 }
904
905 return stream;
906 }
907
908
909
910
911
912
913
914
915
916