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 - xp_socket.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 214 315 67.9 %
Date: 2014-04-18 Functions: 16 18 88.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 5                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 1997-2013 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 "ext/standard/file.h"
      23             : #include "streams/php_streams_int.h"
      24             : #include "php_network.h"
      25             : 
      26             : #if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
      27             : # undef AF_UNIX
      28             : #endif
      29             : 
      30             : #if defined(AF_UNIX)
      31             : #include <sys/un.h>
      32             : #endif
      33             : 
      34             : #ifndef MSG_DONTWAIT
      35             : # define MSG_DONTWAIT 0
      36             : #endif
      37             : 
      38             : #ifndef MSG_PEEK
      39             : # define MSG_PEEK 0
      40             : #endif
      41             : 
      42             : php_stream_ops php_stream_generic_socket_ops;
      43             : PHPAPI php_stream_ops php_stream_socket_ops;
      44             : php_stream_ops php_stream_udp_socket_ops;
      45             : #ifdef AF_UNIX
      46             : php_stream_ops php_stream_unix_socket_ops;
      47             : php_stream_ops php_stream_unixdg_socket_ops;
      48             : #endif
      49             : 
      50             : 
      51             : static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC);
      52             : 
      53             : /* {{{ Generic socket stream operations */
      54       38246 : static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
      55             : {
      56       38246 :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
      57             :         int didwrite;
      58             :         struct timeval *ptimeout;
      59             : 
      60       38246 :         if (sock->socket == -1) {
      61           0 :                 return 0;
      62             :         }
      63             : 
      64       38246 :         if (sock->timeout.tv_sec == -1)
      65           0 :                 ptimeout = NULL;
      66             :         else
      67       38246 :                 ptimeout = &sock->timeout;
      68             : 
      69             : retry:
      70       38246 :         didwrite = send(sock->socket, buf, count, (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0);
      71             : 
      72       38246 :         if (didwrite <= 0) {
      73          14 :                 long err = php_socket_errno();
      74             :                 char *estr;
      75             : 
      76          14 :                 if (sock->is_blocked && err == EWOULDBLOCK) {
      77             :                         int retval;
      78             : 
      79           0 :                         sock->timeout_event = 0;
      80             : 
      81             :                         do {
      82           0 :                                 retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout);
      83             : 
      84           0 :                                 if (retval == 0) {
      85           0 :                                         sock->timeout_event = 1;
      86           0 :                                         break;
      87             :                                 }
      88             : 
      89           0 :                                 if (retval > 0) {
      90             :                                         /* writable now; retry */
      91           0 :                                         goto retry;
      92             :                                 }
      93             : 
      94           0 :                                 err = php_socket_errno();
      95           0 :                         } while (err == EINTR);
      96             :                 }
      97          14 :                 estr = php_socket_strerror(err, NULL, 0);
      98          14 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "send of %ld bytes failed with errno=%ld %s",
      99             :                                 (long)count, err, estr);
     100          14 :                 efree(estr);
     101             :         }
     102             : 
     103       38246 :         if (didwrite > 0) {
     104       38232 :                 php_stream_notify_progress_increment(stream->context, didwrite, 0);
     105             :         }
     106             : 
     107       38246 :         if (didwrite < 0) {
     108          14 :                 didwrite = 0;
     109             :         }
     110             : 
     111       38246 :         return didwrite;
     112             : }
     113             : 
     114      114211 : static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock TSRMLS_DC)
     115             : {
     116             :         int retval;
     117             :         struct timeval *ptimeout;
     118             : 
     119      114211 :         if (sock->socket == -1) {
     120           0 :                 return;
     121             :         }
     122             :         
     123      114211 :         sock->timeout_event = 0;
     124             : 
     125      114211 :         if (sock->timeout.tv_sec == -1)
     126           0 :                 ptimeout = NULL;
     127             :         else
     128      114211 :                 ptimeout = &sock->timeout;
     129             : 
     130             :         while(1) {
     131      114211 :                 retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
     132             : 
     133      114211 :                 if (retval == 0)
     134           3 :                         sock->timeout_event = 1;
     135             : 
     136      114211 :                 if (retval >= 0)
     137      114211 :                         break;
     138             : 
     139           0 :                 if (php_socket_errno() != EINTR)
     140           0 :                         break;
     141           0 :         }
     142             : }
     143             : 
     144      114223 : static size_t php_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
     145             : {
     146      114223 :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
     147      114223 :         int nr_bytes = 0;
     148             : 
     149      114223 :         if (sock->socket == -1) {
     150           0 :                 return 0;
     151             :         }
     152             : 
     153      114223 :         if (sock->is_blocked) {
     154      114211 :                 php_sock_stream_wait_for_data(stream, sock TSRMLS_CC);
     155      114211 :                 if (sock->timeout_event)
     156           3 :                         return 0;
     157             :         }
     158             : 
     159      114220 :         nr_bytes = recv(sock->socket, buf, count, (sock->is_blocked && sock->timeout.tv_sec != -1) ? MSG_DONTWAIT : 0);
     160             : 
     161      114220 :         stream->eof = (nr_bytes == 0 || (nr_bytes == -1 && php_socket_errno() != EWOULDBLOCK));
     162             : 
     163      114220 :         if (nr_bytes > 0) {
     164      114180 :                 php_stream_notify_progress_increment(stream->context, nr_bytes, 0);
     165             :         }
     166             : 
     167      114220 :         if (nr_bytes < 0) {
     168          10 :                 nr_bytes = 0;
     169             :         }
     170             : 
     171      114220 :         return nr_bytes;
     172             : }
     173             : 
     174             : 
     175        2455 : static int php_sockop_close(php_stream *stream, int close_handle TSRMLS_DC)
     176             : {
     177        2455 :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
     178             : #ifdef PHP_WIN32
     179             :         int n;
     180             : #endif
     181             : 
     182        2455 :         if (close_handle) {
     183             : 
     184             : #ifdef PHP_WIN32
     185             :                 if (sock->socket == -1)
     186             :                         sock->socket = SOCK_ERR;
     187             : #endif
     188        2455 :                 if (sock->socket != SOCK_ERR) {
     189             : #ifdef PHP_WIN32
     190             :                         /* prevent more data from coming in */
     191             :                         shutdown(sock->socket, SHUT_RD);
     192             : 
     193             :                         /* try to make sure that the OS sends all data before we close the connection.
     194             :                          * Essentially, we are waiting for the socket to become writeable, which means
     195             :                          * that all pending data has been sent.
     196             :                          * We use a small timeout which should encourage the OS to send the data,
     197             :                          * but at the same time avoid hanging indefintely.
     198             :                          * */
     199             :                         do {
     200             :                                 n = php_pollfd_for_ms(sock->socket, POLLOUT, 500);
     201             :                         } while (n == -1 && php_socket_errno() == EINTR);
     202             : #endif
     203        2455 :                         closesocket(sock->socket);
     204        2455 :                         sock->socket = SOCK_ERR;
     205             :                 }
     206             : 
     207             :         }
     208             : 
     209        2455 :         pefree(sock, php_stream_is_persistent(stream));
     210             :         
     211        2455 :         return 0;
     212             : }
     213             : 
     214        2665 : static int php_sockop_flush(php_stream *stream TSRMLS_DC)
     215             : {
     216             : #if 0
     217             :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
     218             :         return fsync(sock->socket);
     219             : #endif
     220        2665 :         return 0;
     221             : }
     222             : 
     223           5 : static int php_sockop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
     224             : {
     225           5 :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
     226             : #if ZEND_WIN32
     227             :         return 0;
     228             : #else
     229           5 :         return fstat(sock->socket, &ssb->sb);
     230             : #endif
     231             : }
     232             : 
     233           0 : static inline int sock_sendto(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
     234             :                 struct sockaddr *addr, socklen_t addrlen
     235             :                 TSRMLS_DC)
     236             : {
     237             :         int ret;
     238           0 :         if (addr) {
     239           0 :                 ret = sendto(sock->socket, buf, buflen, flags, addr, addrlen);
     240           0 :                 return (ret == SOCK_CONN_ERR) ? -1 : ret;
     241             :         }
     242           0 :         return ((ret = send(sock->socket, buf, buflen, flags)) == SOCK_CONN_ERR) ? -1 : ret;
     243             : }
     244             : 
     245           0 : static inline int sock_recvfrom(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
     246             :                 char **textaddr, long *textaddrlen,
     247             :                 struct sockaddr **addr, socklen_t *addrlen
     248             :                 TSRMLS_DC)
     249             : {
     250             :         php_sockaddr_storage sa;
     251           0 :         socklen_t sl = sizeof(sa);
     252             :         int ret;
     253           0 :         int want_addr = textaddr || addr;
     254             : 
     255           0 :         if (want_addr) {
     256           0 :                 ret = recvfrom(sock->socket, buf, buflen, flags, (struct sockaddr*)&sa, &sl);
     257           0 :                 ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
     258           0 :                 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
     259             :                         textaddr, textaddrlen, addr, addrlen TSRMLS_CC);
     260             :         } else {
     261           0 :                 ret = recv(sock->socket, buf, buflen, flags);
     262           0 :                 ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
     263             :         }
     264             : 
     265           0 :         return ret;
     266             : }
     267             : 
     268        1918 : static int php_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
     269             : {
     270             :         int oldmode, flags;
     271        1918 :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
     272             :         php_stream_xport_param *xparam;
     273             :         
     274        1918 :         switch(option) {
     275             :                 case PHP_STREAM_OPTION_CHECK_LIVENESS:
     276             :                         {
     277             :                                 struct timeval tv;
     278             :                                 char buf;
     279           3 :                                 int alive = 1;
     280             : 
     281           3 :                                 if (value == -1) {
     282           0 :                                         if (sock->timeout.tv_sec == -1) {
     283           0 :                                                 tv.tv_sec = FG(default_socket_timeout);
     284           0 :                                                 tv.tv_usec = 0;
     285             :                                         } else {
     286           0 :                                                 tv = sock->timeout;
     287             :                                         }
     288             :                                 } else {
     289           3 :                                         tv.tv_sec = value;
     290           3 :                                         tv.tv_usec = 0;
     291             :                                 }
     292             : 
     293           3 :                                 if (sock->socket == -1) {
     294           0 :                                         alive = 0;
     295           3 :                                 } else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
     296           3 :                                         if (0 >= recv(sock->socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EWOULDBLOCK) {
     297           1 :                                                 alive = 0;
     298             :                                         }
     299             :                                 }
     300           3 :                                 return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
     301             :                         }
     302             :                         
     303             :                 case PHP_STREAM_OPTION_BLOCKING:
     304           4 :                         oldmode = sock->is_blocked;
     305           4 :                         if (SUCCESS == php_set_sock_blocking(sock->socket, value TSRMLS_CC)) {
     306           4 :                                 sock->is_blocked = value;
     307           4 :                                 return oldmode;
     308             :                         }
     309           0 :                         return PHP_STREAM_OPTION_RETURN_ERR;
     310             : 
     311             :                 case PHP_STREAM_OPTION_READ_TIMEOUT:
     312        1815 :                         sock->timeout = *(struct timeval*)ptrparam;
     313        1815 :                         sock->timeout_event = 0;
     314        1815 :                         return PHP_STREAM_OPTION_RETURN_OK;
     315             : 
     316             :                 case PHP_STREAM_OPTION_META_DATA_API:
     317          16 :                         add_assoc_bool((zval *)ptrparam, "timed_out", sock->timeout_event);
     318          16 :                         add_assoc_bool((zval *)ptrparam, "blocked", sock->is_blocked);
     319          16 :                         add_assoc_bool((zval *)ptrparam, "eof", stream->eof);
     320          16 :                         return PHP_STREAM_OPTION_RETURN_OK;
     321             :                 
     322             :                 case PHP_STREAM_OPTION_XPORT_API:
     323          75 :                         xparam = (php_stream_xport_param *)ptrparam;
     324             : 
     325          75 :                         switch (xparam->op) {
     326             :                                 case STREAM_XPORT_OP_LISTEN:
     327          71 :                                         xparam->outputs.returncode = (listen(sock->socket, xparam->inputs.backlog) == 0) ?  0: -1;
     328          71 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     329             : 
     330             :                                 case STREAM_XPORT_OP_GET_NAME:
     331           0 :                                         xparam->outputs.returncode = php_network_get_sock_name(sock->socket,
     332           0 :                                                         xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
     333           0 :                                                         xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
     334           0 :                                                         xparam->want_addr ? &xparam->outputs.addr : NULL,
     335           0 :                                                         xparam->want_addr ? &xparam->outputs.addrlen : NULL
     336             :                                                         TSRMLS_CC);
     337           0 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     338             : 
     339             :                                 case STREAM_XPORT_OP_GET_PEER_NAME:
     340           0 :                                         xparam->outputs.returncode = php_network_get_peer_name(sock->socket,
     341           0 :                                                         xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
     342           0 :                                                         xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
     343           0 :                                                         xparam->want_addr ? &xparam->outputs.addr : NULL,
     344           0 :                                                         xparam->want_addr ? &xparam->outputs.addrlen : NULL
     345             :                                                         TSRMLS_CC);
     346           0 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     347             : 
     348             :                                 case STREAM_XPORT_OP_SEND:
     349           0 :                                         flags = 0;
     350           0 :                                         if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
     351           0 :                                                 flags |= MSG_OOB;
     352             :                                         }
     353           0 :                                         xparam->outputs.returncode = sock_sendto(sock,
     354             :                                                         xparam->inputs.buf, xparam->inputs.buflen,
     355             :                                                         flags,
     356             :                                                         xparam->inputs.addr,
     357             :                                                         xparam->inputs.addrlen TSRMLS_CC);
     358           0 :                                         if (xparam->outputs.returncode == -1) {
     359           0 :                                                 char *err = php_socket_strerror(php_socket_errno(), NULL, 0);
     360           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     361             :                                                         "%s\n", err);
     362           0 :                                                 efree(err);
     363             :                                         }
     364           0 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     365             : 
     366             :                                 case STREAM_XPORT_OP_RECV:
     367           0 :                                         flags = 0;
     368           0 :                                         if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
     369           0 :                                                 flags |= MSG_OOB;
     370             :                                         }
     371           0 :                                         if ((xparam->inputs.flags & STREAM_PEEK) == STREAM_PEEK) {
     372           0 :                                                 flags |= MSG_PEEK;
     373             :                                         }
     374           0 :                                         xparam->outputs.returncode = sock_recvfrom(sock,
     375             :                                                         xparam->inputs.buf, xparam->inputs.buflen,
     376             :                                                         flags,
     377           0 :                                                         xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
     378           0 :                                                         xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
     379           0 :                                                         xparam->want_addr ? &xparam->outputs.addr : NULL,
     380           0 :                                                         xparam->want_addr ? &xparam->outputs.addrlen : NULL
     381             :                                                         TSRMLS_CC);
     382           0 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     383             : 
     384             : 
     385             : #ifdef HAVE_SHUTDOWN
     386             : # ifndef SHUT_RD
     387             : #  define SHUT_RD 0
     388             : # endif
     389             : # ifndef SHUT_WR
     390             : #  define SHUT_WR 1
     391             : # endif
     392             : # ifndef SHUT_RDWR
     393             : #  define SHUT_RDWR 2
     394             : # endif
     395             :                                 case STREAM_XPORT_OP_SHUTDOWN: {
     396             :                                         static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR};
     397             : 
     398           4 :                                         xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]);
     399           4 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     400             :                                 }
     401             : #endif
     402             :                                 
     403             :                                 case PHP_STREAM_OPTION_WRITE_BUFFER:
     404           0 :                                         php_stream_set_chunk_size(stream, (ptrparam ? *(size_t *)ptrparam : PHP_SOCK_CHUNK_SIZE));
     405           0 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     406             : 
     407             :                                 default:
     408           0 :                                         return PHP_STREAM_OPTION_RETURN_NOTIMPL;
     409             :                         }
     410             : 
     411             :                 default:
     412           5 :                         return PHP_STREAM_OPTION_RETURN_NOTIMPL;
     413             :         }
     414             : }
     415             : 
     416         209 : static int php_sockop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
     417             : {
     418         209 :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
     419             : 
     420         209 :         switch(castas)  {
     421             :                 case PHP_STREAM_AS_STDIO:
     422           0 :                         if (ret)        {
     423           0 :                                 *(FILE**)ret = fdopen(sock->socket, stream->mode);
     424           0 :                                 if (*ret)
     425           0 :                                         return SUCCESS;
     426           0 :                                 return FAILURE;
     427             :                         }
     428           0 :                         return SUCCESS;
     429             :                 case PHP_STREAM_AS_FD_FOR_SELECT:
     430             :                 case PHP_STREAM_AS_FD:
     431             :                 case PHP_STREAM_AS_SOCKETD:
     432         209 :                         if (ret)
     433         209 :                                 *(int*)ret = sock->socket;
     434         209 :                         return SUCCESS;
     435             :                 default:
     436           0 :                         return FAILURE;
     437             :         }
     438             : }
     439             : /* }}} */
     440             : 
     441             : /* These may look identical, but we need them this way so that
     442             :  * we can determine which type of socket we are dealing with
     443             :  * by inspecting stream->ops.
     444             :  * A "useful" side-effect is that the user's scripts can then
     445             :  * make similar decisions using stream_get_meta_data.
     446             :  * */
     447             : php_stream_ops php_stream_generic_socket_ops = {
     448             :         php_sockop_write, php_sockop_read,
     449             :         php_sockop_close, php_sockop_flush,
     450             :         "generic_socket",
     451             :         NULL, /* seek */
     452             :         php_sockop_cast,
     453             :         php_sockop_stat,
     454             :         php_sockop_set_option,
     455             : };
     456             : 
     457             : 
     458             : php_stream_ops php_stream_socket_ops = {
     459             :         php_sockop_write, php_sockop_read,
     460             :         php_sockop_close, php_sockop_flush,
     461             :         "tcp_socket",
     462             :         NULL, /* seek */
     463             :         php_sockop_cast,
     464             :         php_sockop_stat,
     465             :         php_tcp_sockop_set_option,
     466             : };
     467             : 
     468             : php_stream_ops php_stream_udp_socket_ops = {
     469             :         php_sockop_write, php_sockop_read,
     470             :         php_sockop_close, php_sockop_flush,
     471             :         "udp_socket",
     472             :         NULL, /* seek */
     473             :         php_sockop_cast,
     474             :         php_sockop_stat,
     475             :         php_tcp_sockop_set_option,
     476             : };
     477             : 
     478             : #ifdef AF_UNIX
     479             : php_stream_ops php_stream_unix_socket_ops = {
     480             :         php_sockop_write, php_sockop_read,
     481             :         php_sockop_close, php_sockop_flush,
     482             :         "unix_socket",
     483             :         NULL, /* seek */
     484             :         php_sockop_cast,
     485             :         php_sockop_stat,
     486             :         php_tcp_sockop_set_option,
     487             : };
     488             : php_stream_ops php_stream_unixdg_socket_ops = {
     489             :         php_sockop_write, php_sockop_read,
     490             :         php_sockop_close, php_sockop_flush,
     491             :         "udg_socket",
     492             :         NULL, /* seek */
     493             :         php_sockop_cast,
     494             :         php_sockop_stat,
     495             :         php_tcp_sockop_set_option,
     496             : };
     497             : #endif
     498             : 
     499             : 
     500             : /* network socket operations */
     501             : 
     502             : #ifdef AF_UNIX
     503        1825 : static inline int parse_unix_address(php_stream_xport_param *xparam, struct sockaddr_un *unix_addr TSRMLS_DC)
     504             : {
     505        1825 :         memset(unix_addr, 0, sizeof(*unix_addr));
     506        1825 :         unix_addr->sun_family = AF_UNIX;
     507             : 
     508             :         /* we need to be binary safe on systems that support an abstract
     509             :          * namespace */
     510        1825 :         if (xparam->inputs.namelen >= sizeof(unix_addr->sun_path)) {
     511             :                 /* On linux, when the path begins with a NUL byte we are
     512             :                  * referring to an abstract namespace.  In theory we should
     513             :                  * allow an extra byte below, since we don't need the NULL.
     514             :                  * BUT, to get into this branch of code, the name is too long,
     515             :                  * so we don't care. */
     516           1 :                 xparam->inputs.namelen = sizeof(unix_addr->sun_path) - 1;
     517           1 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE,
     518             :                         "socket path exceeded the maximum allowed length of %lu bytes "
     519             :                         "and was truncated", (unsigned long)sizeof(unix_addr->sun_path));
     520             :         }
     521             : 
     522        1825 :         memcpy(unix_addr->sun_path, xparam->inputs.name, xparam->inputs.namelen);
     523             : 
     524        1825 :         return 1;
     525             : }
     526             : #endif
     527             : 
     528         754 : static inline char *parse_ip_address_ex(const char *str, int str_len, int *portno, int get_err, char **err TSRMLS_DC)
     529             : {
     530             :         char *colon;
     531         754 :         char *host = NULL;
     532             : 
     533             : #ifdef HAVE_IPV6
     534             :         char *p;
     535             : 
     536         754 :         if (*(str) == '[' && str_len > 1) {
     537             :                 /* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
     538          10 :                 p = memchr(str + 1, ']', str_len - 2);
     539          10 :                 if (!p || *(p + 1) != ':') {
     540           1 :                         if (get_err) {
     541           1 :                                 spprintf(err, 0, "Failed to parse IPv6 address \"%s\"", str);
     542             :                         }
     543           1 :                         return NULL;
     544             :                 }
     545           9 :                 *portno = atoi(p + 2);
     546           9 :                 return estrndup(str + 1, p - str - 1);
     547             :         }
     548             : #endif
     549         744 :         if (str_len) {
     550         743 :                 colon = memchr(str, ':', str_len - 1);
     551             :         } else {
     552           1 :                 colon = NULL;
     553             :         }
     554         744 :         if (colon) {
     555         740 :                 *portno = atoi(colon + 1);
     556         740 :                 host = estrndup(str, colon - str);
     557             :         } else {
     558           4 :                 if (get_err) {
     559           4 :                         spprintf(err, 0, "Failed to parse address \"%s\"", str);
     560             :                 }
     561           4 :                 return NULL;
     562             :         }
     563             : 
     564         740 :         return host;
     565             : }
     566             : 
     567         754 : static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno TSRMLS_DC)
     568             : {
     569         754 :         return parse_ip_address_ex(xparam->inputs.name, xparam->inputs.namelen, portno, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC);
     570             : }
     571             : 
     572          75 : static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
     573             :                 php_stream_xport_param *xparam TSRMLS_DC)
     574             : {
     575          75 :         char *host = NULL;
     576             :         int portno, err;
     577             : 
     578             : #ifdef AF_UNIX
     579          75 :         if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
     580             :                 struct sockaddr_un unix_addr;
     581             : 
     582           4 :                 sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
     583             : 
     584           4 :                 if (sock->socket == SOCK_ERR) {
     585           0 :                         if (xparam->want_errortext) {
     586           0 :                                 spprintf(&xparam->outputs.error_text, 0, "Failed to create unix%s socket %s",
     587           0 :                                                 stream->ops == &php_stream_unix_socket_ops ? "" : "datagram",
     588             :                                                 strerror(errno));
     589             :                         }
     590           0 :                         return -1;
     591             :                 }
     592             : 
     593           4 :                 parse_unix_address(xparam, &unix_addr TSRMLS_CC);
     594             : 
     595           4 :                 return bind(sock->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
     596             :         }
     597             : #endif
     598             : 
     599          71 :         host = parse_ip_address(xparam, &portno TSRMLS_CC);
     600             : 
     601          71 :         if (host == NULL) {
     602           0 :                 return -1;
     603             :         }
     604             : 
     605         142 :         sock->socket = php_network_bind_socket_to_local_addr(host, portno,
     606          71 :                         stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
     607          71 :                         xparam->want_errortext ? &xparam->outputs.error_text : NULL,
     608             :                         &err
     609             :                         TSRMLS_CC);
     610             :         
     611          71 :         if (host) {
     612          71 :                 efree(host);
     613             :         }
     614             : 
     615          71 :         return sock->socket == -1 ? -1 : 0;
     616             : }
     617             : 
     618        2504 : static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
     619             :                 php_stream_xport_param *xparam TSRMLS_DC)
     620             : {
     621        2504 :         char *host = NULL, *bindto = NULL;
     622        2504 :         int portno, bindport = 0;
     623        2504 :         int err = 0;
     624             :         int ret;
     625        2504 :         zval **tmpzval = NULL;
     626             : 
     627             : #ifdef AF_UNIX
     628        2504 :         if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
     629             :                 struct sockaddr_un unix_addr;
     630             : 
     631        1821 :                 sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
     632             : 
     633        1821 :                 if (sock->socket == SOCK_ERR) {
     634           0 :                         if (xparam->want_errortext) {
     635           0 :                                 spprintf(&xparam->outputs.error_text, 0, "Failed to create unix socket");
     636             :                         }
     637           0 :                         return -1;
     638             :                 }
     639             : 
     640        1821 :                 parse_unix_address(xparam, &unix_addr TSRMLS_CC);
     641             : 
     642        1821 :                 ret = php_network_connect_socket(sock->socket,
     643             :                                 (const struct sockaddr *)&unix_addr, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen,
     644             :                                 xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC, xparam->inputs.timeout,
     645        1821 :                                 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
     646             :                                 &err);
     647             : 
     648        1821 :                 xparam->outputs.error_code = err;
     649             : 
     650        1821 :                 goto out;
     651             :         }
     652             : #endif
     653             : 
     654         683 :         host = parse_ip_address(xparam, &portno TSRMLS_CC);
     655             : 
     656         683 :         if (host == NULL) {
     657           5 :                 return -1;
     658             :         }
     659             : 
     660         678 :         if (stream->context && php_stream_context_get_option(stream->context, "socket", "bindto", &tmpzval) == SUCCESS) {
     661           0 :                 if (Z_TYPE_PP(tmpzval) != IS_STRING) {
     662           0 :                         if (xparam->want_errortext) {
     663           0 :                                 spprintf(&xparam->outputs.error_text, 0, "local_addr context option is not a string.");
     664             :                         }
     665           0 :                         efree(host);
     666           0 :                         return -1;
     667             :                 }
     668           0 :                 bindto = parse_ip_address_ex(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), &bindport, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC);
     669             :         }
     670             : 
     671             :         /* Note: the test here for php_stream_udp_socket_ops is important, because we
     672             :          * want the default to be TCP sockets so that the openssl extension can
     673             :          * re-use this code. */
     674             :         
     675        2034 :         sock->socket = php_network_connect_socket_to_host(host, portno,
     676         678 :                         stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
     677             :                         xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC,
     678             :                         xparam->inputs.timeout,
     679         678 :                         xparam->want_errortext ? &xparam->outputs.error_text : NULL,
     680             :                         &err,
     681             :                         bindto,
     682             :                         bindport
     683             :                         TSRMLS_CC);
     684             :         
     685         678 :         ret = sock->socket == -1 ? -1 : 0;
     686         678 :         xparam->outputs.error_code = err;
     687             : 
     688         678 :         if (host) {
     689         678 :                 efree(host);
     690             :         }
     691         678 :         if (bindto) {
     692           0 :                 efree(bindto);
     693             :         }
     694             : 
     695             : #ifdef AF_UNIX
     696             : out:
     697             : #endif
     698             : 
     699        2499 :         if (ret >= 0 && xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && err == EINPROGRESS) {
     700             :                 /* indicates pending connection */
     701           1 :                 return 1;
     702             :         }
     703             :         
     704        2498 :         return ret;
     705             : }
     706             : 
     707           1 : static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
     708             :                 php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC)
     709             : {
     710             :         int clisock;
     711             : 
     712           1 :         xparam->outputs.client = NULL;
     713             : 
     714           6 :         clisock = php_network_accept_incoming(sock->socket,
     715           1 :                         xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
     716           1 :                         xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
     717           1 :                         xparam->want_addr ? &xparam->outputs.addr : NULL,
     718           1 :                         xparam->want_addr ? &xparam->outputs.addrlen : NULL,
     719             :                         xparam->inputs.timeout,
     720           1 :                         xparam->want_errortext ? &xparam->outputs.error_text : NULL,
     721             :                         &xparam->outputs.error_code
     722             :                         TSRMLS_CC);
     723             : 
     724           1 :         if (clisock >= 0) {
     725             :                 php_netstream_data_t *clisockdata;
     726             : 
     727           1 :                 clisockdata = emalloc(sizeof(*clisockdata));
     728             : 
     729           1 :                 if (clisockdata == NULL) {
     730           0 :                         close(clisock);
     731             :                         /* technically a fatal error */
     732             :                 } else {
     733           1 :                         memcpy(clisockdata, sock, sizeof(*clisockdata));
     734           1 :                         clisockdata->socket = clisock;
     735             : 
     736           1 :                         xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
     737           1 :                         if (xparam->outputs.client) {
     738           1 :                                 xparam->outputs.client->context = stream->context;
     739           1 :                                 if (stream->context) {
     740           1 :                                         zend_list_addref(stream->context->rsrc_id);
     741             :                                 }
     742             :                         }
     743             :                 }
     744             :         }
     745             :         
     746           1 :         return xparam->outputs.client == NULL ? -1 : 0;
     747             : }
     748             : 
     749        4490 : static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
     750             : {
     751        4490 :         php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
     752             :         php_stream_xport_param *xparam;
     753             : 
     754        4490 :         switch(option) {
     755             :                 case PHP_STREAM_OPTION_XPORT_API:
     756        2653 :                         xparam = (php_stream_xport_param *)ptrparam;
     757             : 
     758        2653 :                         switch(xparam->op) {
     759             :                                 case STREAM_XPORT_OP_CONNECT:
     760             :                                 case STREAM_XPORT_OP_CONNECT_ASYNC:
     761        2504 :                                         xparam->outputs.returncode = php_tcp_sockop_connect(stream, sock, xparam TSRMLS_CC);
     762        2504 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     763             : 
     764             :                                 case STREAM_XPORT_OP_BIND:
     765          75 :                                         xparam->outputs.returncode = php_tcp_sockop_bind(stream, sock, xparam TSRMLS_CC);
     766          75 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     767             : 
     768             : 
     769             :                                 case STREAM_XPORT_OP_ACCEPT:
     770           1 :                                         xparam->outputs.returncode = php_tcp_sockop_accept(stream, sock, xparam STREAMS_CC TSRMLS_CC);
     771           1 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     772             :                                 default:
     773             :                                         /* fall through */
     774             :                                         ;
     775             :                         }
     776             :         }
     777        1910 :         return php_sockop_set_option(stream, option, value, ptrparam TSRMLS_CC);
     778             : }
     779             : 
     780             : 
     781        2441 : PHPAPI php_stream *php_stream_generic_socket_factory(const char *proto, long protolen,
     782             :                 char *resourcename, long resourcenamelen,
     783             :                 const char *persistent_id, int options, int flags,
     784             :                 struct timeval *timeout,
     785             :                 php_stream_context *context STREAMS_DC TSRMLS_DC)
     786             : {
     787        2441 :         php_stream *stream = NULL;
     788             :         php_netstream_data_t *sock;
     789             :         php_stream_ops *ops;
     790             : 
     791             :         /* which type of socket ? */
     792        2441 :         if (strncmp(proto, "tcp", protolen) == 0) {
     793           0 :                 ops = &php_stream_socket_ops;
     794        2441 :         } else if (strncmp(proto, "udp", protolen) == 0) {
     795         616 :                 ops = &php_stream_udp_socket_ops;
     796             :         }
     797             : #ifdef AF_UNIX
     798        1825 :         else if (strncmp(proto, "unix", protolen) == 0) {
     799        1823 :                 ops = &php_stream_unix_socket_ops;
     800           2 :         } else if (strncmp(proto, "udg", protolen) == 0) {
     801           2 :                 ops = &php_stream_unixdg_socket_ops;
     802             :         }
     803             : #endif
     804             :         else {
     805             :                 /* should never happen */
     806           0 :                 return NULL;
     807             :         }
     808             :         
     809        2441 :         sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
     810        2441 :         memset(sock, 0, sizeof(php_netstream_data_t));
     811             : 
     812        2441 :         sock->is_blocked = 1;
     813        2441 :         sock->timeout.tv_sec = FG(default_socket_timeout);
     814        2441 :         sock->timeout.tv_usec = 0;
     815             : 
     816             :         /* we don't know the socket until we have determined if we are binding or
     817             :          * connecting */
     818        2441 :         sock->socket = -1;
     819             :         
     820        2441 :         stream = php_stream_alloc_rel(ops, sock, persistent_id, "r+");
     821             : 
     822        2441 :         if (stream == NULL)     {
     823           0 :                 pefree(sock, persistent_id ? 1 : 0);
     824           0 :                 return NULL;
     825             :         }
     826             : 
     827        2441 :         if (flags == 0) {
     828           0 :                 return stream;
     829             :         }
     830             : 
     831        2441 :         return stream;
     832             : }
     833             : 
     834             : 
     835             : /*
     836             :  * Local variables:
     837             :  * tab-width: 4
     838             :  * c-basic-offset: 4
     839             :  * End:
     840             :  * vim600: noet sw=4 ts=4 fdm=marker
     841             :  * vim<600: noet sw=4 ts=4
     842             :  */

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:41 +0000 (6 hours ago)

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