PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/release/src/router/php/main/streams/xp_socket.c

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