You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

823 lines
22 KiB

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