PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - main/streams - transports.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 164 211 77.7 %
Date: 2016-07-26 Functions: 13 14 92.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 26 Jul 2016 17:07:50 +0000 (2 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.