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

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

Generated by: LTP GCOV extension version 1.5