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

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_2/main/streams - xp_socket.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 289
Code covered: 69.6 % Executed lines: 201
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:29 +0000 (5 days ago)

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