xp_socket.c 23 KB

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