LTP GCOV extension - code coverage report
Current view: directory - main/streams - transports.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 204
Code covered: 22.5 % Executed lines: 46
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5