PageRenderTime 65ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/main/streams/xp_socket.c

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