Annotation of embedaddon/php/main/streams/xp_socket.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.4 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 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: | Author: Wez Furlong <wez@thebrainroom.com> |
16: +----------------------------------------------------------------------+
17: */
18:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 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: php_stream_ops php_stream_generic_socket_ops;
43: PHPAPI php_stream_ops php_stream_socket_ops;
44: php_stream_ops php_stream_udp_socket_ops;
45: #ifdef AF_UNIX
46: php_stream_ops php_stream_unix_socket_ops;
47: php_stream_ops php_stream_unixdg_socket_ops;
48: #endif
49:
50:
51: static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC);
52:
53: /* {{{ Generic socket stream operations */
54: static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
55: {
56: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
57: int didwrite;
58: struct timeval *ptimeout;
59:
60: if (sock->socket == -1) {
61: return 0;
62: }
63:
64: if (sock->timeout.tv_sec == -1)
65: ptimeout = NULL;
66: else
67: ptimeout = &sock->timeout;
68:
69: retry:
70: didwrite = send(sock->socket, buf, count, (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0);
71:
72: if (didwrite <= 0) {
73: long err = php_socket_errno();
74: char *estr;
75:
76: if (sock->is_blocked && err == EWOULDBLOCK) {
77: int retval;
78:
79: sock->timeout_event = 0;
80:
81: do {
82: retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout);
83:
84: if (retval == 0) {
85: sock->timeout_event = 1;
86: break;
87: }
88:
89: if (retval > 0) {
90: /* writable now; retry */
91: goto retry;
92: }
93:
94: err = php_socket_errno();
95: } while (err == EINTR);
96: }
97: estr = php_socket_strerror(err, NULL, 0);
98: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "send of %ld bytes failed with errno=%ld %s",
99: (long)count, err, estr);
100: efree(estr);
101: }
102:
103: if (didwrite > 0) {
104: php_stream_notify_progress_increment(stream->context, didwrite, 0);
105: }
106:
107: if (didwrite < 0) {
108: didwrite = 0;
109: }
110:
111: return didwrite;
112: }
113:
114: static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock TSRMLS_DC)
115: {
116: int retval;
117: struct timeval *ptimeout;
118:
119: if (sock->socket == -1) {
120: return;
121: }
122:
123: sock->timeout_event = 0;
124:
125: if (sock->timeout.tv_sec == -1)
126: ptimeout = NULL;
127: else
128: ptimeout = &sock->timeout;
129:
130: while(1) {
131: retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
132:
133: if (retval == 0)
134: sock->timeout_event = 1;
135:
136: if (retval >= 0)
137: break;
138:
139: if (php_socket_errno() != EINTR)
140: break;
141: }
142: }
143:
144: static size_t php_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
145: {
146: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
147: int nr_bytes = 0;
148:
149: if (sock->socket == -1) {
150: return 0;
151: }
152:
153: if (sock->is_blocked) {
154: php_sock_stream_wait_for_data(stream, sock TSRMLS_CC);
155: if (sock->timeout_event)
156: return 0;
157: }
158:
159: nr_bytes = recv(sock->socket, buf, count, (sock->is_blocked && sock->timeout.tv_sec != -1) ? MSG_DONTWAIT : 0);
160:
161: stream->eof = (nr_bytes == 0 || (nr_bytes == -1 && php_socket_errno() != EWOULDBLOCK));
162:
163: if (nr_bytes > 0) {
164: php_stream_notify_progress_increment(stream->context, nr_bytes, 0);
165: }
166:
167: if (nr_bytes < 0) {
168: nr_bytes = 0;
169: }
170:
171: return nr_bytes;
172: }
173:
174:
175: static int php_sockop_close(php_stream *stream, int close_handle TSRMLS_DC)
176: {
177: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
178: #ifdef PHP_WIN32
179: int n;
180: #endif
181:
182: if (close_handle) {
183:
184: #ifdef PHP_WIN32
185: if (sock->socket == -1)
186: sock->socket = SOCK_ERR;
187: #endif
188: if (sock->socket != SOCK_ERR) {
189: #ifdef PHP_WIN32
190: /* prevent more data from coming in */
191: shutdown(sock->socket, SHUT_RD);
192:
193: /* try to make sure that the OS sends all data before we close the connection.
194: * Essentially, we are waiting for the socket to become writeable, which means
195: * that all pending data has been sent.
196: * We use a small timeout which should encourage the OS to send the data,
1.1.1.3 misho 197: * but at the same time avoid hanging indefinitely.
1.1 misho 198: * */
199: do {
200: n = php_pollfd_for_ms(sock->socket, POLLOUT, 500);
201: } while (n == -1 && php_socket_errno() == EINTR);
202: #endif
203: closesocket(sock->socket);
204: sock->socket = SOCK_ERR;
205: }
206:
207: }
208:
209: pefree(sock, php_stream_is_persistent(stream));
210:
211: return 0;
212: }
213:
214: static int php_sockop_flush(php_stream *stream TSRMLS_DC)
215: {
216: #if 0
217: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
218: return fsync(sock->socket);
219: #endif
220: return 0;
221: }
222:
223: static int php_sockop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
224: {
225: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
226: #if ZEND_WIN32
227: return 0;
228: #else
229: return fstat(sock->socket, &ssb->sb);
230: #endif
231: }
232:
233: static inline int sock_sendto(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
234: struct sockaddr *addr, socklen_t addrlen
235: TSRMLS_DC)
236: {
237: int ret;
238: if (addr) {
239: ret = sendto(sock->socket, buf, buflen, flags, addr, addrlen);
240: return (ret == SOCK_CONN_ERR) ? -1 : ret;
241: }
242: return ((ret = send(sock->socket, buf, buflen, flags)) == SOCK_CONN_ERR) ? -1 : ret;
243: }
244:
245: static inline int sock_recvfrom(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
246: char **textaddr, long *textaddrlen,
247: struct sockaddr **addr, socklen_t *addrlen
248: TSRMLS_DC)
249: {
250: php_sockaddr_storage sa;
251: socklen_t sl = sizeof(sa);
252: int ret;
253: int want_addr = textaddr || addr;
254:
255: if (want_addr) {
256: ret = recvfrom(sock->socket, buf, buflen, flags, (struct sockaddr*)&sa, &sl);
257: ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
258: php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
259: textaddr, textaddrlen, addr, addrlen TSRMLS_CC);
260: } else {
261: ret = recv(sock->socket, buf, buflen, flags);
262: ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
263: }
264:
265: return ret;
266: }
267:
268: static int php_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
269: {
270: int oldmode, flags;
271: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
272: php_stream_xport_param *xparam;
273:
274: switch(option) {
275: case PHP_STREAM_OPTION_CHECK_LIVENESS:
276: {
277: struct timeval tv;
278: char buf;
279: int alive = 1;
280:
281: if (value == -1) {
282: if (sock->timeout.tv_sec == -1) {
283: tv.tv_sec = FG(default_socket_timeout);
284: tv.tv_usec = 0;
285: } else {
286: tv = sock->timeout;
287: }
288: } else {
289: tv.tv_sec = value;
290: tv.tv_usec = 0;
291: }
292:
293: if (sock->socket == -1) {
294: alive = 0;
295: } else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
296: if (0 >= recv(sock->socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EWOULDBLOCK) {
297: alive = 0;
298: }
299: }
300: return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
301: }
302:
303: case PHP_STREAM_OPTION_BLOCKING:
304: oldmode = sock->is_blocked;
305: if (SUCCESS == php_set_sock_blocking(sock->socket, value TSRMLS_CC)) {
306: sock->is_blocked = value;
307: return oldmode;
308: }
309: return PHP_STREAM_OPTION_RETURN_ERR;
310:
311: case PHP_STREAM_OPTION_READ_TIMEOUT:
312: sock->timeout = *(struct timeval*)ptrparam;
313: sock->timeout_event = 0;
314: return PHP_STREAM_OPTION_RETURN_OK;
315:
316: case PHP_STREAM_OPTION_META_DATA_API:
317: add_assoc_bool((zval *)ptrparam, "timed_out", sock->timeout_event);
318: add_assoc_bool((zval *)ptrparam, "blocked", sock->is_blocked);
319: add_assoc_bool((zval *)ptrparam, "eof", stream->eof);
320: return PHP_STREAM_OPTION_RETURN_OK;
321:
322: case PHP_STREAM_OPTION_XPORT_API:
323: xparam = (php_stream_xport_param *)ptrparam;
324:
325: switch (xparam->op) {
326: case STREAM_XPORT_OP_LISTEN:
327: xparam->outputs.returncode = (listen(sock->socket, xparam->inputs.backlog) == 0) ? 0: -1;
328: return PHP_STREAM_OPTION_RETURN_OK;
329:
330: case STREAM_XPORT_OP_GET_NAME:
331: xparam->outputs.returncode = php_network_get_sock_name(sock->socket,
332: xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
333: xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
334: xparam->want_addr ? &xparam->outputs.addr : NULL,
335: xparam->want_addr ? &xparam->outputs.addrlen : NULL
336: TSRMLS_CC);
337: return PHP_STREAM_OPTION_RETURN_OK;
338:
339: case STREAM_XPORT_OP_GET_PEER_NAME:
340: xparam->outputs.returncode = php_network_get_peer_name(sock->socket,
341: xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
342: xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
343: xparam->want_addr ? &xparam->outputs.addr : NULL,
344: xparam->want_addr ? &xparam->outputs.addrlen : NULL
345: TSRMLS_CC);
346: return PHP_STREAM_OPTION_RETURN_OK;
347:
348: case STREAM_XPORT_OP_SEND:
349: flags = 0;
350: if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
351: flags |= MSG_OOB;
352: }
353: xparam->outputs.returncode = sock_sendto(sock,
354: xparam->inputs.buf, xparam->inputs.buflen,
355: flags,
356: xparam->inputs.addr,
357: xparam->inputs.addrlen TSRMLS_CC);
358: if (xparam->outputs.returncode == -1) {
359: char *err = php_socket_strerror(php_socket_errno(), NULL, 0);
360: php_error_docref(NULL TSRMLS_CC, E_WARNING,
361: "%s\n", err);
362: efree(err);
363: }
364: return PHP_STREAM_OPTION_RETURN_OK;
365:
366: case STREAM_XPORT_OP_RECV:
367: flags = 0;
368: if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
369: flags |= MSG_OOB;
370: }
371: if ((xparam->inputs.flags & STREAM_PEEK) == STREAM_PEEK) {
372: flags |= MSG_PEEK;
373: }
374: xparam->outputs.returncode = sock_recvfrom(sock,
375: xparam->inputs.buf, xparam->inputs.buflen,
376: flags,
377: xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
378: xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
379: xparam->want_addr ? &xparam->outputs.addr : NULL,
380: xparam->want_addr ? &xparam->outputs.addrlen : NULL
381: TSRMLS_CC);
382: return PHP_STREAM_OPTION_RETURN_OK;
383:
384:
385: #ifdef HAVE_SHUTDOWN
386: # ifndef SHUT_RD
387: # define SHUT_RD 0
388: # endif
389: # ifndef SHUT_WR
390: # define SHUT_WR 1
391: # endif
392: # ifndef SHUT_RDWR
393: # define SHUT_RDWR 2
394: # endif
395: case STREAM_XPORT_OP_SHUTDOWN: {
396: static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR};
397:
398: xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]);
399: return PHP_STREAM_OPTION_RETURN_OK;
400: }
401: #endif
402:
403: default:
404: return PHP_STREAM_OPTION_RETURN_NOTIMPL;
405: }
406:
407: default:
408: return PHP_STREAM_OPTION_RETURN_NOTIMPL;
409: }
410: }
411:
412: static int php_sockop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
413: {
414: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
415:
416: switch(castas) {
417: case PHP_STREAM_AS_STDIO:
418: if (ret) {
419: *(FILE**)ret = fdopen(sock->socket, stream->mode);
420: if (*ret)
421: return SUCCESS;
422: return FAILURE;
423: }
424: return SUCCESS;
425: case PHP_STREAM_AS_FD_FOR_SELECT:
426: case PHP_STREAM_AS_FD:
427: case PHP_STREAM_AS_SOCKETD:
428: if (ret)
429: *(int*)ret = sock->socket;
430: return SUCCESS;
431: default:
432: return FAILURE;
433: }
434: }
435: /* }}} */
436:
437: /* These may look identical, but we need them this way so that
438: * we can determine which type of socket we are dealing with
439: * by inspecting stream->ops.
440: * A "useful" side-effect is that the user's scripts can then
441: * make similar decisions using stream_get_meta_data.
442: * */
443: php_stream_ops php_stream_generic_socket_ops = {
444: php_sockop_write, php_sockop_read,
445: php_sockop_close, php_sockop_flush,
446: "generic_socket",
447: NULL, /* seek */
448: php_sockop_cast,
449: php_sockop_stat,
450: php_sockop_set_option,
451: };
452:
453:
454: php_stream_ops php_stream_socket_ops = {
455: php_sockop_write, php_sockop_read,
456: php_sockop_close, php_sockop_flush,
457: "tcp_socket",
458: NULL, /* seek */
459: php_sockop_cast,
460: php_sockop_stat,
461: php_tcp_sockop_set_option,
462: };
463:
464: php_stream_ops php_stream_udp_socket_ops = {
465: php_sockop_write, php_sockop_read,
466: php_sockop_close, php_sockop_flush,
467: "udp_socket",
468: NULL, /* seek */
469: php_sockop_cast,
470: php_sockop_stat,
471: php_tcp_sockop_set_option,
472: };
473:
474: #ifdef AF_UNIX
475: php_stream_ops php_stream_unix_socket_ops = {
476: php_sockop_write, php_sockop_read,
477: php_sockop_close, php_sockop_flush,
478: "unix_socket",
479: NULL, /* seek */
480: php_sockop_cast,
481: php_sockop_stat,
482: php_tcp_sockop_set_option,
483: };
484: php_stream_ops php_stream_unixdg_socket_ops = {
485: php_sockop_write, php_sockop_read,
486: php_sockop_close, php_sockop_flush,
487: "udg_socket",
488: NULL, /* seek */
489: php_sockop_cast,
490: php_sockop_stat,
491: php_tcp_sockop_set_option,
492: };
493: #endif
494:
495:
496: /* network socket operations */
497:
498: #ifdef AF_UNIX
499: static inline int parse_unix_address(php_stream_xport_param *xparam, struct sockaddr_un *unix_addr TSRMLS_DC)
500: {
501: memset(unix_addr, 0, sizeof(*unix_addr));
502: unix_addr->sun_family = AF_UNIX;
503:
504: /* we need to be binary safe on systems that support an abstract
505: * namespace */
506: if (xparam->inputs.namelen >= sizeof(unix_addr->sun_path)) {
507: /* On linux, when the path begins with a NUL byte we are
508: * referring to an abstract namespace. In theory we should
509: * allow an extra byte below, since we don't need the NULL.
510: * BUT, to get into this branch of code, the name is too long,
511: * so we don't care. */
512: xparam->inputs.namelen = sizeof(unix_addr->sun_path) - 1;
1.1.1.2 misho 513: php_error_docref(NULL TSRMLS_CC, E_NOTICE,
514: "socket path exceeded the maximum allowed length of %lu bytes "
515: "and was truncated", (unsigned long)sizeof(unix_addr->sun_path));
1.1 misho 516: }
517:
518: memcpy(unix_addr->sun_path, xparam->inputs.name, xparam->inputs.namelen);
519:
520: return 1;
521: }
522: #endif
523:
524: static inline char *parse_ip_address_ex(const char *str, int str_len, int *portno, int get_err, char **err TSRMLS_DC)
525: {
526: char *colon;
527: char *host = NULL;
528:
529: #ifdef HAVE_IPV6
530: char *p;
531:
532: if (*(str) == '[' && str_len > 1) {
533: /* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
534: p = memchr(str + 1, ']', str_len - 2);
535: if (!p || *(p + 1) != ':') {
536: if (get_err) {
537: spprintf(err, 0, "Failed to parse IPv6 address \"%s\"", str);
538: }
539: return NULL;
540: }
541: *portno = atoi(p + 2);
542: return estrndup(str + 1, p - str - 1);
543: }
544: #endif
545: if (str_len) {
546: colon = memchr(str, ':', str_len - 1);
547: } else {
548: colon = NULL;
549: }
550: if (colon) {
551: *portno = atoi(colon + 1);
552: host = estrndup(str, colon - str);
553: } else {
554: if (get_err) {
555: spprintf(err, 0, "Failed to parse address \"%s\"", str);
556: }
557: return NULL;
558: }
559:
560: return host;
561: }
562:
563: static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno TSRMLS_DC)
564: {
565: return parse_ip_address_ex(xparam->inputs.name, xparam->inputs.namelen, portno, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC);
566: }
567:
568: static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
569: php_stream_xport_param *xparam TSRMLS_DC)
570: {
571: char *host = NULL;
572: int portno, err;
573:
574: #ifdef AF_UNIX
575: if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
576: struct sockaddr_un unix_addr;
577:
578: sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
579:
580: if (sock->socket == SOCK_ERR) {
581: if (xparam->want_errortext) {
582: spprintf(&xparam->outputs.error_text, 0, "Failed to create unix%s socket %s",
583: stream->ops == &php_stream_unix_socket_ops ? "" : "datagram",
584: strerror(errno));
585: }
586: return -1;
587: }
588:
589: parse_unix_address(xparam, &unix_addr TSRMLS_CC);
590:
1.1.1.4 ! misho 591: return bind(sock->socket, (const struct sockaddr *)&unix_addr,
! 592: (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen);
1.1 misho 593: }
594: #endif
595:
596: host = parse_ip_address(xparam, &portno TSRMLS_CC);
597:
598: if (host == NULL) {
599: return -1;
600: }
601:
602: sock->socket = php_network_bind_socket_to_local_addr(host, portno,
603: stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
604: xparam->want_errortext ? &xparam->outputs.error_text : NULL,
605: &err
606: TSRMLS_CC);
607:
608: if (host) {
609: efree(host);
610: }
611:
612: return sock->socket == -1 ? -1 : 0;
613: }
614:
615: static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
616: php_stream_xport_param *xparam TSRMLS_DC)
617: {
618: char *host = NULL, *bindto = NULL;
619: int portno, bindport = 0;
620: int err = 0;
621: int ret;
622: zval **tmpzval = NULL;
623:
624: #ifdef AF_UNIX
625: if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
626: struct sockaddr_un unix_addr;
627:
628: sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
629:
630: if (sock->socket == SOCK_ERR) {
631: if (xparam->want_errortext) {
632: spprintf(&xparam->outputs.error_text, 0, "Failed to create unix socket");
633: }
634: return -1;
635: }
636:
637: parse_unix_address(xparam, &unix_addr TSRMLS_CC);
638:
639: ret = php_network_connect_socket(sock->socket,
640: (const struct sockaddr *)&unix_addr, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen,
641: xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC, xparam->inputs.timeout,
642: xparam->want_errortext ? &xparam->outputs.error_text : NULL,
643: &err);
644:
645: xparam->outputs.error_code = err;
646:
647: goto out;
648: }
649: #endif
650:
651: host = parse_ip_address(xparam, &portno TSRMLS_CC);
652:
653: if (host == NULL) {
654: return -1;
655: }
656:
657: if (stream->context && php_stream_context_get_option(stream->context, "socket", "bindto", &tmpzval) == SUCCESS) {
658: if (Z_TYPE_PP(tmpzval) != IS_STRING) {
659: if (xparam->want_errortext) {
660: spprintf(&xparam->outputs.error_text, 0, "local_addr context option is not a string.");
661: }
662: efree(host);
663: return -1;
664: }
665: bindto = parse_ip_address_ex(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), &bindport, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC);
666: }
667:
668: /* Note: the test here for php_stream_udp_socket_ops is important, because we
669: * want the default to be TCP sockets so that the openssl extension can
670: * re-use this code. */
671:
672: sock->socket = php_network_connect_socket_to_host(host, portno,
673: stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
674: xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC,
675: xparam->inputs.timeout,
676: xparam->want_errortext ? &xparam->outputs.error_text : NULL,
677: &err,
678: bindto,
679: bindport
680: TSRMLS_CC);
681:
682: ret = sock->socket == -1 ? -1 : 0;
683: xparam->outputs.error_code = err;
684:
685: if (host) {
686: efree(host);
687: }
688: if (bindto) {
689: efree(bindto);
690: }
691:
692: #ifdef AF_UNIX
693: out:
694: #endif
695:
696: if (ret >= 0 && xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && err == EINPROGRESS) {
697: /* indicates pending connection */
698: return 1;
699: }
700:
701: return ret;
702: }
703:
704: static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
705: php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC)
706: {
707: int clisock;
708:
709: xparam->outputs.client = NULL;
710:
711: clisock = php_network_accept_incoming(sock->socket,
712: xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
713: xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
714: xparam->want_addr ? &xparam->outputs.addr : NULL,
715: xparam->want_addr ? &xparam->outputs.addrlen : NULL,
716: xparam->inputs.timeout,
717: xparam->want_errortext ? &xparam->outputs.error_text : NULL,
718: &xparam->outputs.error_code
719: TSRMLS_CC);
720:
721: if (clisock >= 0) {
722: php_netstream_data_t *clisockdata;
723:
724: clisockdata = emalloc(sizeof(*clisockdata));
725:
726: if (clisockdata == NULL) {
727: close(clisock);
728: /* technically a fatal error */
729: } else {
730: memcpy(clisockdata, sock, sizeof(*clisockdata));
731: clisockdata->socket = clisock;
732:
733: xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
734: if (xparam->outputs.client) {
735: xparam->outputs.client->context = stream->context;
736: if (stream->context) {
737: zend_list_addref(stream->context->rsrc_id);
738: }
739: }
740: }
741: }
742:
743: return xparam->outputs.client == NULL ? -1 : 0;
744: }
745:
746: static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
747: {
748: php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
749: php_stream_xport_param *xparam;
750:
751: switch(option) {
752: case PHP_STREAM_OPTION_XPORT_API:
753: xparam = (php_stream_xport_param *)ptrparam;
754:
755: switch(xparam->op) {
756: case STREAM_XPORT_OP_CONNECT:
757: case STREAM_XPORT_OP_CONNECT_ASYNC:
758: xparam->outputs.returncode = php_tcp_sockop_connect(stream, sock, xparam TSRMLS_CC);
759: return PHP_STREAM_OPTION_RETURN_OK;
760:
761: case STREAM_XPORT_OP_BIND:
762: xparam->outputs.returncode = php_tcp_sockop_bind(stream, sock, xparam TSRMLS_CC);
763: return PHP_STREAM_OPTION_RETURN_OK;
764:
765:
766: case STREAM_XPORT_OP_ACCEPT:
767: xparam->outputs.returncode = php_tcp_sockop_accept(stream, sock, xparam STREAMS_CC TSRMLS_CC);
768: return PHP_STREAM_OPTION_RETURN_OK;
769: default:
770: /* fall through */
771: ;
772: }
773: }
774: return php_sockop_set_option(stream, option, value, ptrparam TSRMLS_CC);
775: }
776:
777:
778: PHPAPI php_stream *php_stream_generic_socket_factory(const char *proto, long protolen,
779: char *resourcename, long resourcenamelen,
780: const char *persistent_id, int options, int flags,
781: struct timeval *timeout,
782: php_stream_context *context STREAMS_DC TSRMLS_DC)
783: {
784: php_stream *stream = NULL;
785: php_netstream_data_t *sock;
786: php_stream_ops *ops;
787:
788: /* which type of socket ? */
789: if (strncmp(proto, "tcp", protolen) == 0) {
790: ops = &php_stream_socket_ops;
791: } else if (strncmp(proto, "udp", protolen) == 0) {
792: ops = &php_stream_udp_socket_ops;
793: }
794: #ifdef AF_UNIX
795: else if (strncmp(proto, "unix", protolen) == 0) {
796: ops = &php_stream_unix_socket_ops;
797: } else if (strncmp(proto, "udg", protolen) == 0) {
798: ops = &php_stream_unixdg_socket_ops;
799: }
800: #endif
801: else {
802: /* should never happen */
803: return NULL;
804: }
805:
806: sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
807: memset(sock, 0, sizeof(php_netstream_data_t));
808:
809: sock->is_blocked = 1;
810: sock->timeout.tv_sec = FG(default_socket_timeout);
811: sock->timeout.tv_usec = 0;
812:
813: /* we don't know the socket until we have determined if we are binding or
814: * connecting */
815: sock->socket = -1;
816:
817: stream = php_stream_alloc_rel(ops, sock, persistent_id, "r+");
818:
819: if (stream == NULL) {
820: pefree(sock, persistent_id ? 1 : 0);
821: return NULL;
822: }
823:
824: if (flags == 0) {
825: return stream;
826: }
827:
828: return stream;
829: }
830:
831:
832: /*
833: * Local variables:
834: * tab-width: 4
835: * c-basic-offset: 4
836: * End:
837: * vim600: noet sw=4 ts=4 fdm=marker
838: * vim<600: noet sw=4 ts=4
839: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>