root/main/streams/xp_socket.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_sockop_write
  2. php_sock_stream_wait_for_data
  3. php_sockop_read
  4. php_sockop_close
  5. php_sockop_flush
  6. php_sockop_stat
  7. sock_sendto
  8. sock_recvfrom
  9. php_sockop_set_option
  10. php_sockop_cast
  11. parse_unix_address
  12. parse_ip_address_ex
  13. parse_ip_address
  14. php_tcp_sockop_bind
  15. php_tcp_sockop_connect
  16. php_tcp_sockop_accept
  17. php_tcp_sockop_set_option
  18. php_stream_generic_socket_factory

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

/* [<][>][^][v][top][bottom][index][help] */