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

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

https://gitlab.com/envieidoc/advancedtomato2
C | 532 lines | 381 code | 100 blank | 51 comment | 102 complexity | f9371728c2e9c5ea16ff16cf008257f1 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 "php_streams_int.h"
  21. #include "ext/standard/file.h"
  22. static HashTable xport_hash;
  23. PHPAPI HashTable *php_stream_xport_get_hash(void)
  24. {
  25. return &xport_hash;
  26. }
  27. PHPAPI int php_stream_xport_register(char *protocol, php_stream_transport_factory factory TSRMLS_DC)
  28. {
  29. return zend_hash_update(&xport_hash, protocol, strlen(protocol) + 1, &factory, sizeof(factory), NULL);
  30. }
  31. PHPAPI int php_stream_xport_unregister(char *protocol TSRMLS_DC)
  32. {
  33. return zend_hash_del(&xport_hash, protocol, strlen(protocol) + 1);
  34. }
  35. #define ERR_REPORT(out_err, fmt, arg) \
  36. if (out_err) { spprintf(out_err, 0, fmt, arg); } \
  37. else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, arg); }
  38. #define ERR_RETURN(out_err, local_err, fmt) \
  39. if (out_err) { *out_err = local_err; } \
  40. else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, local_err ? local_err : "Unspecified error"); \
  41. if (local_err) { efree(local_err); local_err = NULL; } \
  42. }
  43. PHPAPI php_stream *_php_stream_xport_create(const char *name, long namelen, int options,
  44. int flags, const char *persistent_id,
  45. struct timeval *timeout,
  46. php_stream_context *context,
  47. char **error_string,
  48. int *error_code
  49. STREAMS_DC TSRMLS_DC)
  50. {
  51. php_stream *stream = NULL;
  52. php_stream_transport_factory *factory = NULL;
  53. const char *p, *protocol = NULL;
  54. int n = 0, failed = 0;
  55. char *error_text = NULL;
  56. struct timeval default_timeout = { 0, 0 };
  57. default_timeout.tv_sec = FG(default_socket_timeout);
  58. if (timeout == NULL) {
  59. timeout = &default_timeout;
  60. }
  61. /* check for a cached persistent socket */
  62. if (persistent_id) {
  63. switch(php_stream_from_persistent_id(persistent_id, &stream TSRMLS_CC)) {
  64. case PHP_STREAM_PERSISTENT_SUCCESS:
  65. /* use a 0 second timeout when checking if the socket
  66. * has already died */
  67. if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL)) {
  68. return stream;
  69. }
  70. /* dead - kill it */
  71. php_stream_pclose(stream);
  72. stream = NULL;
  73. /* fall through */
  74. case PHP_STREAM_PERSISTENT_FAILURE:
  75. default:
  76. /* failed; get a new one */
  77. ;
  78. }
  79. }
  80. for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
  81. n++;
  82. }
  83. if ((*p == ':') && (n > 1) && !strncmp("://", p, 3)) {
  84. protocol = name;
  85. name = p + 3;
  86. namelen -= n + 3;
  87. } else {
  88. protocol = "tcp";
  89. n = 3;
  90. }
  91. if (protocol) {
  92. char *tmp = estrndup(protocol, n);
  93. if (FAILURE == zend_hash_find(&xport_hash, (char*)tmp, n + 1, (void**)&factory)) {
  94. char wrapper_name[32];
  95. if (n >= sizeof(wrapper_name))
  96. n = sizeof(wrapper_name) - 1;
  97. PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
  98. ERR_REPORT(error_string, "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?",
  99. wrapper_name);
  100. efree(tmp);
  101. return NULL;
  102. }
  103. efree(tmp);
  104. }
  105. if (factory == NULL) {
  106. /* should never happen */
  107. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find a factory !?");
  108. return NULL;
  109. }
  110. stream = (*factory)(protocol, n,
  111. (char*)name, namelen, persistent_id, options, flags, timeout,
  112. context STREAMS_REL_CC TSRMLS_CC);
  113. if (stream) {
  114. php_stream_context_set(stream, context);
  115. if ((flags & STREAM_XPORT_SERVER) == 0) {
  116. /* client */
  117. if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
  118. if (-1 == php_stream_xport_connect(stream, name, namelen,
  119. flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
  120. timeout, &error_text, error_code TSRMLS_CC)) {
  121. ERR_RETURN(error_string, error_text, "connect() failed: %s");
  122. failed = 1;
  123. }
  124. }
  125. } else {
  126. /* server */
  127. if (flags & STREAM_XPORT_BIND) {
  128. if (0 != php_stream_xport_bind(stream, name, namelen, &error_text TSRMLS_CC)) {
  129. ERR_RETURN(error_string, error_text, "bind() failed: %s");
  130. failed = 1;
  131. } else if (flags & STREAM_XPORT_LISTEN) {
  132. zval **zbacklog = NULL;
  133. int backlog = 32;
  134. if (stream->context && php_stream_context_get_option(stream->context, "socket", "backlog", &zbacklog) == SUCCESS) {
  135. zval *ztmp = *zbacklog;
  136. convert_to_long_ex(&ztmp);
  137. backlog = Z_LVAL_P(ztmp);
  138. if (ztmp != *zbacklog) {
  139. zval_ptr_dtor(&ztmp);
  140. }
  141. }
  142. if (0 != php_stream_xport_listen(stream, backlog, &error_text TSRMLS_CC)) {
  143. ERR_RETURN(error_string, error_text, "listen() failed: %s");
  144. failed = 1;
  145. }
  146. }
  147. }
  148. }
  149. }
  150. if (failed) {
  151. /* failure means that they don't get a stream to play with */
  152. if (persistent_id) {
  153. php_stream_pclose(stream);
  154. } else {
  155. php_stream_close(stream);
  156. }
  157. stream = NULL;
  158. }
  159. return stream;
  160. }
  161. /* Bind the stream to a local address */
  162. PHPAPI int php_stream_xport_bind(php_stream *stream,
  163. const char *name, long namelen,
  164. char **error_text
  165. TSRMLS_DC)
  166. {
  167. php_stream_xport_param param;
  168. int ret;
  169. memset(&param, 0, sizeof(param));
  170. param.op = STREAM_XPORT_OP_BIND;
  171. param.inputs.name = (char*)name;
  172. param.inputs.namelen = namelen;
  173. param.want_errortext = error_text ? 1 : 0;
  174. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  175. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  176. if (error_text) {
  177. *error_text = param.outputs.error_text;
  178. }
  179. return param.outputs.returncode;
  180. }
  181. return ret;
  182. }
  183. /* Connect to a remote address */
  184. PHPAPI int php_stream_xport_connect(php_stream *stream,
  185. const char *name, long namelen,
  186. int asynchronous,
  187. struct timeval *timeout,
  188. char **error_text,
  189. int *error_code
  190. TSRMLS_DC)
  191. {
  192. php_stream_xport_param param;
  193. int ret;
  194. memset(&param, 0, sizeof(param));
  195. param.op = asynchronous ? STREAM_XPORT_OP_CONNECT_ASYNC: STREAM_XPORT_OP_CONNECT;
  196. param.inputs.name = (char*)name;
  197. param.inputs.namelen = namelen;
  198. param.inputs.timeout = timeout;
  199. param.want_errortext = error_text ? 1 : 0;
  200. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  201. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  202. if (error_text) {
  203. *error_text = param.outputs.error_text;
  204. }
  205. if (error_code) {
  206. *error_code = param.outputs.error_code;
  207. }
  208. return param.outputs.returncode;
  209. }
  210. return ret;
  211. }
  212. /* Prepare to listen */
  213. PHPAPI int php_stream_xport_listen(php_stream *stream, int backlog, char **error_text TSRMLS_DC)
  214. {
  215. php_stream_xport_param param;
  216. int ret;
  217. memset(&param, 0, sizeof(param));
  218. param.op = STREAM_XPORT_OP_LISTEN;
  219. param.inputs.backlog = backlog;
  220. param.want_errortext = error_text ? 1 : 0;
  221. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  222. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  223. if (error_text) {
  224. *error_text = param.outputs.error_text;
  225. }
  226. return param.outputs.returncode;
  227. }
  228. return ret;
  229. }
  230. /* Get the next client and their address (as a string) */
  231. PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
  232. char **textaddr, int *textaddrlen,
  233. void **addr, socklen_t *addrlen,
  234. struct timeval *timeout,
  235. char **error_text
  236. TSRMLS_DC)
  237. {
  238. php_stream_xport_param param;
  239. int ret;
  240. memset(&param, 0, sizeof(param));
  241. param.op = STREAM_XPORT_OP_ACCEPT;
  242. param.inputs.timeout = timeout;
  243. param.want_addr = addr ? 1 : 0;
  244. param.want_textaddr = textaddr ? 1 : 0;
  245. param.want_errortext = error_text ? 1 : 0;
  246. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  247. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  248. *client = param.outputs.client;
  249. if (addr) {
  250. *addr = param.outputs.addr;
  251. *addrlen = param.outputs.addrlen;
  252. }
  253. if (textaddr) {
  254. *textaddr = param.outputs.textaddr;
  255. *textaddrlen = param.outputs.textaddrlen;
  256. }
  257. if (error_text) {
  258. *error_text = param.outputs.error_text;
  259. }
  260. return param.outputs.returncode;
  261. }
  262. return ret;
  263. }
  264. PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
  265. char **textaddr, int *textaddrlen,
  266. void **addr, socklen_t *addrlen
  267. TSRMLS_DC)
  268. {
  269. php_stream_xport_param param;
  270. int ret;
  271. memset(&param, 0, sizeof(param));
  272. param.op = want_peer ? STREAM_XPORT_OP_GET_PEER_NAME : STREAM_XPORT_OP_GET_NAME;
  273. param.want_addr = addr ? 1 : 0;
  274. param.want_textaddr = textaddr ? 1 : 0;
  275. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  276. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  277. if (addr) {
  278. *addr = param.outputs.addr;
  279. *addrlen = param.outputs.addrlen;
  280. }
  281. if (textaddr) {
  282. *textaddr = param.outputs.textaddr;
  283. *textaddrlen = param.outputs.textaddrlen;
  284. }
  285. return param.outputs.returncode;
  286. }
  287. return ret;
  288. }
  289. PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC)
  290. {
  291. php_stream_xport_crypto_param param;
  292. int ret;
  293. memset(&param, 0, sizeof(param));
  294. param.op = STREAM_XPORT_CRYPTO_OP_SETUP;
  295. param.inputs.method = crypto_method;
  296. param.inputs.session = session_stream;
  297. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, &param);
  298. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  299. return param.outputs.returncode;
  300. }
  301. php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
  302. return ret;
  303. }
  304. PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate TSRMLS_DC)
  305. {
  306. php_stream_xport_crypto_param param;
  307. int ret;
  308. memset(&param, 0, sizeof(param));
  309. param.op = STREAM_XPORT_CRYPTO_OP_ENABLE;
  310. param.inputs.activate = activate;
  311. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, &param);
  312. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  313. return param.outputs.returncode;
  314. }
  315. php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
  316. return ret;
  317. }
  318. /* Similar to recv() system call; read data from the stream, optionally
  319. * peeking, optionally retrieving OOB data */
  320. PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen,
  321. long flags, void **addr, socklen_t *addrlen, char **textaddr, int *textaddrlen
  322. TSRMLS_DC)
  323. {
  324. php_stream_xport_param param;
  325. int ret = 0;
  326. int recvd_len = 0;
  327. #if 0
  328. int oob;
  329. if (flags == 0 && addr == NULL) {
  330. return php_stream_read(stream, buf, buflen);
  331. }
  332. if (stream->readfilters.head) {
  333. php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot peek or fetch OOB data from a filtered stream");
  334. return -1;
  335. }
  336. oob = (flags & STREAM_OOB) == STREAM_OOB;
  337. if (!oob && addr == NULL) {
  338. /* must be peeking at regular data; copy content from the buffer
  339. * first, then adjust the pointer/len before handing off to the
  340. * stream */
  341. recvd_len = stream->writepos - stream->readpos;
  342. if (recvd_len > buflen) {
  343. recvd_len = buflen;
  344. }
  345. if (recvd_len) {
  346. memcpy(buf, stream->readbuf, recvd_len);
  347. buf += recvd_len;
  348. buflen -= recvd_len;
  349. }
  350. /* if we filled their buffer, return */
  351. if (buflen == 0) {
  352. return recvd_len;
  353. }
  354. }
  355. #endif
  356. /* otherwise, we are going to bypass the buffer */
  357. memset(&param, 0, sizeof(param));
  358. param.op = STREAM_XPORT_OP_RECV;
  359. param.want_addr = addr ? 1 : 0;
  360. param.want_textaddr = textaddr ? 1 : 0;
  361. param.inputs.buf = buf;
  362. param.inputs.buflen = buflen;
  363. param.inputs.flags = flags;
  364. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  365. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  366. if (addr) {
  367. *addr = param.outputs.addr;
  368. *addrlen = param.outputs.addrlen;
  369. }
  370. if (textaddr) {
  371. *textaddr = param.outputs.textaddr;
  372. *textaddrlen = param.outputs.textaddrlen;
  373. }
  374. return recvd_len + param.outputs.returncode;
  375. }
  376. return recvd_len ? recvd_len : -1;
  377. }
  378. /* Similar to send() system call; send data to the stream, optionally
  379. * sending it as OOB data */
  380. PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen,
  381. long flags, void *addr, socklen_t addrlen TSRMLS_DC)
  382. {
  383. php_stream_xport_param param;
  384. int ret = 0;
  385. int oob;
  386. #if 0
  387. if (flags == 0 && addr == NULL) {
  388. return php_stream_write(stream, buf, buflen);
  389. }
  390. #endif
  391. oob = (flags & STREAM_OOB) == STREAM_OOB;
  392. if ((oob || addr) && stream->writefilters.head) {
  393. php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot write OOB data, or data to a targeted address on a filtered stream");
  394. return -1;
  395. }
  396. memset(&param, 0, sizeof(param));
  397. param.op = STREAM_XPORT_OP_SEND;
  398. param.want_addr = addr ? 1 : 0;
  399. param.inputs.buf = (char*)buf;
  400. param.inputs.buflen = buflen;
  401. param.inputs.flags = flags;
  402. param.inputs.addr = addr;
  403. param.inputs.addrlen = addrlen;
  404. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  405. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  406. return param.outputs.returncode;
  407. }
  408. return -1;
  409. }
  410. /* Similar to shutdown() system call; shut down part of a full-duplex
  411. * connection */
  412. PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how TSRMLS_DC)
  413. {
  414. php_stream_xport_param param;
  415. int ret = 0;
  416. memset(&param, 0, sizeof(param));
  417. param.op = STREAM_XPORT_OP_SHUTDOWN;
  418. param.how = how;
  419. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
  420. if (ret == PHP_STREAM_OPTION_RETURN_OK) {
  421. return param.outputs.returncode;
  422. }
  423. return -1;
  424. }
  425. /*
  426. * Local variables:
  427. * tab-width: 4
  428. * c-basic-offset: 4
  429. * End:
  430. * vim600: noet sw=4 ts=4 fdm=marker
  431. * vim<600: noet sw=4 ts=4
  432. */