PageRenderTime 132ms CodeModel.GetById 3ms app.highlight 120ms RepoModel.GetById 1ms app.codeStats 1ms

/hphp/runtime/ext/ext_socket.cpp

http://github.com/facebook/hiphop-php
C++ | 1267 lines | 1070 code | 152 blank | 45 comment | 203 complexity | 6001964cd246e6c05a1cf89e59d5ea30 MD5 | raw file
   1/*
   2   +----------------------------------------------------------------------+
   3   | HipHop for PHP                                                       |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com)     |
   6   | Copyright (c) 1997-2010 The PHP Group                                |
   7   +----------------------------------------------------------------------+
   8   | This source file is subject to version 3.01 of the PHP license,      |
   9   | that is bundled with this package in the file LICENSE, and is        |
  10   | available through the world-wide-web at the following url:           |
  11   | http://www.php.net/license/3_01.txt                                  |
  12   | If you did not receive a copy of the PHP license and are unable to   |
  13   | obtain it through the world-wide-web, please send a note to          |
  14   | license@php.net so we can mail you a copy immediately.               |
  15   +----------------------------------------------------------------------+
  16*/
  17
  18#include "hphp/runtime/ext/ext_socket.h"
  19#include "hphp/runtime/base/socket.h"
  20#include "hphp/runtime/base/ssl-socket.h"
  21#include "hphp/runtime/server/server-stats.h"
  22#include "hphp/util/logger.h"
  23#include "folly/String.h"
  24
  25#include <sys/types.h>
  26#include <sys/socket.h>
  27#include <netdb.h>
  28#include <netinet/in.h>
  29#include <netinet/tcp.h>
  30#include <sys/un.h>
  31#include <arpa/inet.h>
  32#include <sys/time.h>
  33#include <unistd.h>
  34#include <errno.h>
  35#include <fcntl.h>
  36#include <signal.h>
  37#include <sys/uio.h>
  38#include "hphp/util/network.h"
  39#include <poll.h>
  40
  41#define PHP_NORMAL_READ 0x0001
  42#define PHP_BINARY_READ 0x0002
  43
  44namespace HPHP {
  45IMPLEMENT_DEFAULT_EXTENSION(sockets);
  46///////////////////////////////////////////////////////////////////////////////
  47// helpers
  48
  49static void check_socket_parameters(int &domain, int &type) {
  50  if (domain != AF_UNIX && domain != AF_INET6 && domain != AF_INET) {
  51    raise_warning("invalid socket domain [%d] specified for argument 1, "
  52                    "assuming AF_INET", domain);
  53    domain = AF_INET;
  54  }
  55
  56  if (type > 10) {
  57    raise_warning("invalid socket type [%d] specified for argument 2, "
  58                    "assuming SOCK_STREAM", type);
  59    type = SOCK_STREAM;
  60  }
  61}
  62
  63static bool get_sockaddr(sockaddr *sa, socklen_t salen,
  64                         Variant &address, Variant &port) {
  65  switch (sa->sa_family) {
  66  case AF_INET6:
  67    {
  68      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
  69      char addr6[INET6_ADDRSTRLEN+1];
  70      inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
  71      address = String(addr6, CopyString);
  72      port = htons(sin6->sin6_port);
  73    }
  74    return true;
  75  case AF_INET:
  76    {
  77      struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  78      address = String(Util::safe_inet_ntoa(sin->sin_addr));
  79      port = htons(sin->sin_port);
  80    }
  81    return true;
  82  case AF_UNIX:
  83    {
  84      // NB: an unnamed socket has no path, and sun_path should not be
  85      // inspected. In that case the length is just the size of the
  86      // struct without sun_path.
  87      struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
  88      if (salen > offsetof(sockaddr_un, sun_path)) {
  89        address = String(s_un->sun_path, CopyString);
  90      }
  91    }
  92    return true;
  93
  94  default:
  95    break;
  96  }
  97
  98  raise_warning("Unsupported address family %d", sa->sa_family);
  99  return false;
 100}
 101
 102static bool php_set_inet6_addr(struct sockaddr_in6 *sin6, const char *address,
 103                               Socket *sock) {
 104  struct in6_addr tmp;
 105  struct addrinfo hints;
 106  struct addrinfo *addrinfo = NULL;
 107
 108  if (inet_pton(AF_INET6, address, &tmp)) {
 109    memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr),
 110           sizeof(struct in6_addr));
 111  } else {
 112    memset(&hints, 0, sizeof(struct addrinfo));
 113    hints.ai_family = PF_INET6;
 114    getaddrinfo(address, NULL, &hints, &addrinfo);
 115    if (!addrinfo) {
 116      SOCKET_ERROR(sock, "Host lookup failed", (-10000 - h_errno));
 117      return false;
 118    }
 119    if (addrinfo->ai_family != PF_INET6 ||
 120        addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
 121      raise_warning("Host lookup failed: Non AF_INET6 domain "
 122                      "returned on AF_INET6 socket");
 123      freeaddrinfo(addrinfo);
 124      return false;
 125    }
 126
 127    memcpy(&(sin6->sin6_addr.s6_addr),
 128           ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr,
 129           sizeof(struct in6_addr));
 130    freeaddrinfo(addrinfo);
 131  }
 132
 133  return true;
 134}
 135
 136static bool php_set_inet_addr(struct sockaddr_in *sin, const char *address,
 137                              Socket *sock) {
 138  struct in_addr tmp;
 139
 140  if (inet_aton(address, &tmp)) {
 141    sin->sin_addr.s_addr = tmp.s_addr;
 142  } else {
 143    Util::HostEnt result;
 144    if (!Util::safe_gethostbyname(address, result)) {
 145      /* Note: < -10000 indicates a host lookup error */
 146      SOCKET_ERROR(sock, "Host lookup failed", (-10000 - result.herr));
 147      return false;
 148    }
 149    if (result.hostbuf.h_addrtype != AF_INET) {
 150      raise_warning("Host lookup failed: Non AF_INET domain "
 151                      "returned on AF_INET socket");
 152      return false;
 153    }
 154    memcpy(&(sin->sin_addr.s_addr), result.hostbuf.h_addr_list[0],
 155           result.hostbuf.h_length);
 156  }
 157
 158  return true;
 159}
 160
 161static bool set_sockaddr(sockaddr_storage &sa_storage, Socket *sock,
 162                         const char *addr, int port,
 163                         struct sockaddr *&sa_ptr, size_t &sa_size) {
 164  struct sockaddr *sock_type = (struct sockaddr*) &sa_storage;
 165  switch (sock->getType()) {
 166  case AF_UNIX:
 167    {
 168      struct sockaddr_un *sa = (struct sockaddr_un *)sock_type;
 169      memset(sa, 0, sizeof(sa_storage));
 170      sa->sun_family = AF_UNIX;
 171      snprintf(sa->sun_path, 108, "%s", addr);
 172      sa_ptr = (struct sockaddr *)sa;
 173      sa_size = SUN_LEN(sa);
 174    }
 175    break;
 176  case AF_INET:
 177    {
 178      struct sockaddr_in *sa = (struct sockaddr_in *)sock_type;
 179      memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
 180      sa->sin_family = AF_INET;
 181      sa->sin_port = htons((unsigned short) port);
 182      if (!php_set_inet_addr(sa, addr, sock)) {
 183        return false;
 184      }
 185      sa_ptr = (struct sockaddr *)sa;
 186      sa_size = sizeof(struct sockaddr_in);
 187    }
 188    break;
 189  case AF_INET6:
 190    {
 191      struct sockaddr_in6 *sa = (struct sockaddr_in6 *)sock_type;
 192      memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
 193      sa->sin6_family = AF_INET6;
 194      sa->sin6_port = htons((unsigned short) port);
 195      if (!php_set_inet6_addr(sa, addr, sock)) {
 196        return false;
 197      }
 198      sa_ptr = (struct sockaddr *)sa;
 199      sa_size = sizeof(struct sockaddr_in6);
 200    }
 201    break;
 202  default:
 203    raise_warning("unsupported socket type '%d', must be "
 204                    "AF_UNIX, AF_INET, or AF_INET6", sock->getType());
 205    return false;
 206  }
 207  return true;
 208}
 209
 210static void sock_array_to_fd_set(CArrRef sockets, pollfd *fds, int &nfds,
 211                                 short flag) {
 212  assert(fds);
 213  for (ArrayIter iter(sockets); iter; ++iter) {
 214    File *sock = iter.second().toResource().getTyped<File>();
 215    pollfd &fd = fds[nfds++];
 216    fd.fd = sock->fd();
 217    fd.events = flag;
 218    fd.revents = 0;
 219  }
 220}
 221
 222static void sock_array_from_fd_set(Variant &sockets, pollfd *fds, int &nfds,
 223                                   int &count, short flag) {
 224  assert(sockets.is(KindOfArray));
 225  Array sock_array = sockets.toArray();
 226  Array ret;
 227  for (ArrayIter iter(sock_array); iter; ++iter) {
 228    pollfd &fd = fds[nfds++];
 229    assert(fd.fd == iter.second().toResource().getTyped<File>()->fd());
 230    if (fd.revents & flag) {
 231      ret.append(iter.second());
 232      count++;
 233    }
 234  }
 235  sockets = ret;
 236}
 237
 238static int php_read(Socket *sock, void *buf, int maxlen, int flags) {
 239  int m = fcntl(sock->fd(), F_GETFL);
 240  if (m < 0) {
 241    return m;
 242  }
 243  int nonblock = (m & O_NONBLOCK);
 244  m = 0;
 245
 246  char *t = (char *)buf;
 247  *t = '\0';
 248  int n = 0;
 249  int no_read = 0;
 250  while (*t != '\n' && *t != '\r' && n < maxlen) {
 251    if (m > 0) {
 252      t++;
 253      n++;
 254    } else if (m == 0) {
 255      no_read++;
 256      if (nonblock && no_read >= 2) {
 257        return n;
 258        /* The first pass, m always is 0, so no_read becomes 1
 259         * in the first pass. no_read becomes 2 in the second pass,
 260         * and if this is nonblocking, we should return.. */
 261      }
 262
 263      if (no_read > 200) {
 264        errno = ECONNRESET;
 265        return -1;
 266      }
 267    }
 268
 269    if (n < maxlen) {
 270      m = recv(sock->fd(), (void *)t, 1, flags);
 271    }
 272
 273    if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
 274      return -1;
 275    }
 276    errno = 0;
 277  }
 278
 279  if (n < maxlen) {
 280    n++;
 281    /* The only reasons it makes it to here is
 282     * if '\n' or '\r' are encountered. So, increase
 283     * the return by 1 to make up for the lack of the
 284     * '\n' or '\r' in the count (since read() takes
 285     * place at the end of the loop..) */
 286  }
 287
 288  return n;
 289}
 290
 291static bool create_new_socket(const Util::HostURL &hosturl,
 292                              Variant &errnum, Variant &errstr, Resource &ret,
 293                              Socket *&sock, double timeout) {
 294  int domain = hosturl.isIPv6() ? AF_INET6 : AF_INET;
 295  int type = SOCK_STREAM;
 296  const std::string scheme = hosturl.getScheme();
 297
 298  if (scheme == "udp" || scheme == "udg") {
 299    type = SOCK_DGRAM;
 300  } else if (scheme == "unix") {
 301    domain = AF_UNIX;
 302  }
 303
 304  sock = new Socket(socket(domain, type, 0), domain,
 305                    hosturl.getHost().c_str(), hosturl.getPort(), timeout);
 306  ret = Resource(sock);
 307  if (!sock->valid()) {
 308    SOCKET_ERROR(sock, "unable to create socket", errno);
 309    errnum = sock->getError();
 310    errstr = String(folly::errnoStr(sock->getError()).toStdString());
 311    return false;
 312  }
 313  return true;
 314}
 315
 316///////////////////////////////////////////////////////////////////////////////
 317
 318Variant f_socket_create(int domain, int type, int protocol) {
 319  check_socket_parameters(domain, type);
 320  int socketId = socket(domain, type, protocol);
 321  if (socketId == -1) {
 322    Socket dummySock; // for setting last socket error
 323    SOCKET_ERROR((&dummySock), "Unable to create socket", errno);
 324    return false;
 325  }
 326  Socket *sock = new Socket(socketId, domain);
 327  Resource ret(sock);
 328  return ret;
 329}
 330
 331Variant f_socket_create_listen(int port, int backlog /* = 128 */) {
 332  Util::HostEnt result;
 333  if (!Util::safe_gethostbyname("0.0.0.0", result)) {
 334    return false;
 335  }
 336
 337  struct sockaddr_in la;
 338  memcpy((char *) &la.sin_addr, result.hostbuf.h_addr,
 339         result.hostbuf.h_length);
 340  la.sin_family = result.hostbuf.h_addrtype;
 341  la.sin_port = htons((unsigned short)port);
 342
 343  Socket *sock = new Socket(socket(PF_INET, SOCK_STREAM, 0), PF_INET,
 344                            "0.0.0.0", port);
 345  Resource ret(sock);
 346  if (!sock->valid()) {
 347    SOCKET_ERROR(sock, "unable to create listening socket", errno);
 348    return false;
 349  }
 350
 351  if (::bind(sock->fd(), (struct sockaddr *)&la, sizeof(la)) < 0) {
 352    SOCKET_ERROR(sock, "unable to bind to given address", errno);
 353    return false;
 354  }
 355
 356  if (listen(sock->fd(), backlog) < 0) {
 357    SOCKET_ERROR(sock, "unable to listen on socket", errno);
 358    return false;
 359  }
 360
 361  return ret;
 362}
 363
 364bool f_socket_create_pair(int domain, int type, int protocol, VRefParam fd) {
 365  check_socket_parameters(domain, type);
 366
 367  int fds_array[2];
 368  if (socketpair(domain, type, protocol, fds_array) != 0) {
 369    Socket dummySock; // for setting last socket error
 370    SOCKET_ERROR((&dummySock), "unable to create socket pair", errno);
 371    return false;
 372  }
 373
 374  Array ret;
 375  ret.set(0, Resource(new Socket(fds_array[0], domain)));
 376  ret.set(1, Resource(new Socket(fds_array[1], domain)));
 377  fd = ret;
 378  return true;
 379}
 380
 381const StaticString
 382  s_l_onoff("l_onoff"),
 383  s_l_linger("l_linger"),
 384  s_sec("sec"),
 385  s_usec("usec");
 386
 387Variant f_socket_get_option(CResRef socket, int level, int optname) {
 388  Socket *sock = socket.getTyped<Socket>();
 389  Array ret;
 390  socklen_t optlen;
 391
 392  switch (optname) {
 393  case SO_LINGER:
 394    {
 395      struct linger linger_val;
 396      optlen = sizeof(linger_val);
 397      if (getsockopt(sock->fd(), level, optname, (char*)&linger_val,
 398                     &optlen) != 0) {
 399        SOCKET_ERROR(sock, "unable to retrieve socket option", errno);
 400        return false;
 401      }
 402
 403      ret.set(s_l_onoff, linger_val.l_onoff);
 404      ret.set(s_l_linger, linger_val.l_linger);
 405    }
 406    break;
 407
 408  case SO_RCVTIMEO:
 409  case SO_SNDTIMEO:
 410    {
 411      struct timeval tv;
 412      optlen = sizeof(tv);
 413      if (getsockopt(sock->fd(), level, optname, (char*)&tv, &optlen) != 0) {
 414        SOCKET_ERROR(sock, "unable to retrieve socket option", errno);
 415        return false;
 416      }
 417      ret.set(s_sec,  (int)tv.tv_sec);
 418      ret.set(s_usec, (int)tv.tv_usec);
 419    }
 420    break;
 421
 422  default:
 423    {
 424      int other_val;
 425      optlen = sizeof(other_val);
 426      if (getsockopt(sock->fd(), level, optname, (char*)&other_val, &optlen)) {
 427        SOCKET_ERROR(sock, "unable to retrieve socket option", errno);
 428        return false;
 429      }
 430      return other_val;
 431    }
 432  }
 433  return ret;
 434}
 435
 436bool f_socket_getpeername(CResRef socket, VRefParam address,
 437                          VRefParam port /* = null */) {
 438  Socket *sock = socket.getTyped<Socket>();
 439
 440  sockaddr_storage sa_storage;
 441  socklen_t salen = sizeof(sockaddr_storage);
 442  struct sockaddr *sa = (struct sockaddr *)&sa_storage;
 443  if (getpeername(sock->fd(), sa, &salen) < 0) {
 444    SOCKET_ERROR(sock, "unable to retrieve peer name", errno);
 445    return false;
 446  }
 447  return get_sockaddr(sa, salen, address, port);
 448}
 449
 450bool f_socket_getsockname(CResRef socket, VRefParam address,
 451                          VRefParam port /* = null */) {
 452  Socket *sock = socket.getTyped<Socket>();
 453
 454  sockaddr_storage sa_storage;
 455  socklen_t salen = sizeof(sockaddr_storage);
 456  struct sockaddr *sa = (struct sockaddr *)&sa_storage;
 457  if (getsockname(sock->fd(), sa, &salen) < 0) {
 458    SOCKET_ERROR(sock, "unable to retrieve peer name", errno);
 459    return false;
 460  }
 461  return get_sockaddr(sa, salen, address, port);
 462}
 463
 464bool f_socket_set_block(CResRef socket) {
 465  Socket *sock = socket.getTyped<Socket>();
 466  return sock->setBlocking(true);
 467}
 468
 469bool f_socket_set_nonblock(CResRef socket) {
 470  Socket *sock = socket.getTyped<Socket>();
 471  return sock->setBlocking(false);
 472}
 473
 474bool f_socket_set_option(CResRef socket, int level, int optname,
 475                         CVarRef optval) {
 476  Socket *sock = socket.getTyped<Socket>();
 477
 478  struct linger lv;
 479  struct timeval tv;
 480  int ov;
 481  int optlen;
 482  void *opt_ptr;
 483
 484  switch (optname) {
 485  case SO_LINGER:
 486    {
 487      Array value = optval.toArray();
 488      if (!value.exists(s_l_onoff)) {
 489        raise_warning("no key \"l_onoff\" passed in optval");
 490        return false;
 491      }
 492      if (!value.exists(s_l_linger)) {
 493        raise_warning("no key \"l_linger\" passed in optval");
 494        return false;
 495      }
 496
 497      lv.l_onoff = (unsigned short)value[s_l_onoff].toInt32();
 498      lv.l_linger = (unsigned short)value[s_l_linger].toInt32();
 499      optlen = sizeof(lv);
 500      opt_ptr = &lv;
 501    }
 502    break;
 503
 504  case SO_RCVTIMEO:
 505  case SO_SNDTIMEO:
 506    {
 507      Array value = optval.toArray();
 508      if (!value.exists(s_sec)) {
 509        raise_warning("no key \"sec\" passed in optval");
 510        return false;
 511      }
 512      if (!value.exists(s_usec)) {
 513        raise_warning("no key \"usec\" passed in optval");
 514        return false;
 515      }
 516
 517      tv.tv_sec = value[s_sec].toInt32();
 518      tv.tv_usec = value[s_usec].toInt32();
 519      if (tv.tv_usec >= 1000000) {
 520        tv.tv_sec += tv.tv_usec / 1000000;
 521        tv.tv_usec %= 1000000;
 522      }
 523      optlen = sizeof(tv);
 524      opt_ptr = &tv;
 525      sock->setTimeout(tv);
 526    }
 527    break;
 528
 529  default:
 530    ov = optval.toInt32();
 531    optlen = sizeof(ov);
 532    opt_ptr = &ov;
 533    break;
 534  }
 535
 536  if (setsockopt(sock->fd(), level, optname, opt_ptr, optlen) != 0) {
 537    SOCKET_ERROR(sock, "unable to set socket option", errno);
 538    return false;
 539  }
 540  return true;
 541}
 542
 543bool f_socket_connect(CResRef socket, const String& address, int port /* = 0 */) {
 544  Socket *sock = socket.getTyped<Socket>();
 545
 546  switch (sock->getType()) {
 547  case AF_INET6:
 548  case AF_INET:
 549    if (port == 0) {
 550      raise_warning("Socket of type AF_INET/6 requires 3 arguments");
 551      return false;
 552    }
 553    break;
 554  default:
 555    break;
 556  }
 557
 558  const char *addr = address.data();
 559  sockaddr_storage sa_storage;
 560  struct sockaddr *sa_ptr;
 561  size_t sa_size;
 562  if (!set_sockaddr(sa_storage, sock, addr, port, sa_ptr, sa_size)) {
 563    return false;
 564  }
 565
 566  IOStatusHelper io("socket::connect", address.data(), port);
 567  int retval = connect(sock->fd(), sa_ptr, sa_size);
 568  if (retval != 0) {
 569    std::string msg = "unable to connect to ";
 570    msg += addr;
 571    msg += ":";
 572    msg += boost::lexical_cast<std::string>(port);
 573    SOCKET_ERROR(sock, msg.c_str(), errno);
 574    return false;
 575  }
 576
 577  return true;
 578}
 579
 580bool f_socket_bind(CResRef socket, const String& address, int port /* = 0 */) {
 581  Socket *sock = socket.getTyped<Socket>();
 582
 583  const char *addr = address.data();
 584  sockaddr_storage sa_storage;
 585  struct sockaddr *sa_ptr;
 586  size_t sa_size;
 587  if (!set_sockaddr(sa_storage, sock, addr, port, sa_ptr, sa_size)) {
 588    return false;
 589  }
 590
 591  long retval = ::bind(sock->fd(), sa_ptr, sa_size);
 592  if (retval != 0) {
 593    std::string msg = "unable to bind address";
 594    msg += addr;
 595    msg += ":";
 596    msg += boost::lexical_cast<std::string>(port);
 597    SOCKET_ERROR(sock, msg.c_str(), errno);
 598    return false;
 599  }
 600
 601  return true;
 602}
 603
 604bool f_socket_listen(CResRef socket, int backlog /* = 0 */) {
 605  Socket *sock = socket.getTyped<Socket>();
 606  if (listen(sock->fd(), backlog) != 0) {
 607    SOCKET_ERROR(sock, "unable to listen on socket", errno);
 608    return false;
 609  }
 610  return true;
 611}
 612
 613Variant f_socket_select(VRefParam read, VRefParam write, VRefParam except,
 614                        CVarRef vtv_sec, int tv_usec /* = 0 */) {
 615  int count = 0;
 616  if (!read.isNull()) {
 617    count += read.toArray().size();
 618  }
 619  if (!write.isNull()) {
 620    count += write.toArray().size();
 621  }
 622  if (!except.isNull()) {
 623    count += except.toArray().size();
 624  }
 625  if (!count) {
 626    return false;
 627  }
 628
 629  struct pollfd *fds = (struct pollfd *)calloc(count, sizeof(struct pollfd));
 630  count = 0;
 631  if (!read.isNull()) {
 632    sock_array_to_fd_set(read.toArray(), fds, count, POLLIN);
 633  }
 634  if (!write.isNull()) {
 635    sock_array_to_fd_set(write.toArray(), fds, count, POLLOUT);
 636  }
 637  if (!except.isNull()) {
 638    sock_array_to_fd_set(except.toArray(), fds, count, POLLPRI);
 639  }
 640
 641  IOStatusHelper io("socket_select");
 642  int timeout_ms = -1;
 643  if (!vtv_sec.isNull()) {
 644    timeout_ms = vtv_sec.toInt32() * 1000 + tv_usec / 1000;
 645  }
 646
 647  /* slight hack to support buffered data; if there is data sitting in the
 648   * read buffer of any of the streams in the read array, let's pretend
 649   * that we selected, but return only the readable sockets */
 650  if (!read.isNull()) {
 651    auto hasData = Array::Create();
 652    for (ArrayIter iter(read.toArray()); iter; ++iter) {
 653      File *file = iter.second().toResource().getTyped<File>();
 654      if (file->bufferedLen() > 0) {
 655        hasData.append(iter.second());
 656      }
 657    }
 658    if (hasData.size() > 0) {
 659      if (!write.isNull()) {
 660        write = Array::Create();
 661      }
 662      if (!except.isNull()) {
 663        except = Array::Create();
 664      }
 665      read = hasData;
 666      return hasData.size();
 667    }
 668  }
 669
 670  int retval = poll(fds, count, timeout_ms);
 671  if (retval == -1) {
 672    raise_warning("unable to select [%d]: %s", errno,
 673                  folly::errnoStr(errno).c_str());
 674    free(fds);
 675    return false;
 676  }
 677
 678  count = 0;
 679  int nfds = 0;
 680  if (!read.isNull()) {
 681    sock_array_from_fd_set(read, fds, nfds, count, POLLIN|POLLERR|POLLHUP);
 682  }
 683  if (!write.isNull()) {
 684    sock_array_from_fd_set(write, fds, nfds, count, POLLOUT|POLLERR);
 685  }
 686  if (!except.isNull()) {
 687    sock_array_from_fd_set(except, fds, nfds, count, POLLPRI|POLLERR);
 688  }
 689
 690  free(fds);
 691  return count;
 692}
 693
 694Variant f_socket_server(const String& hostname, int port /* = -1 */,
 695                        VRefParam errnum /* = null */,
 696                        VRefParam errstr /* = null */) {
 697  Util::HostURL hosturl(static_cast<const std::string>(hostname), port);
 698  return socket_server_impl(hosturl,
 699                            k_STREAM_SERVER_BIND|k_STREAM_SERVER_LISTEN,
 700                            errnum, errstr);
 701}
 702
 703Variant socket_server_impl(const Util::HostURL &hosturl,
 704                           int flags, /* = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN */
 705                           VRefParam errnum /* = null */,
 706                           VRefParam errstr /* = null */) {
 707  Resource ret;
 708  Socket *sock = NULL;
 709  if (!create_new_socket(hosturl, errnum, errstr, ret, sock, 0.0)) {
 710    return false;
 711  }
 712  assert(ret.get() && sock);
 713
 714  sockaddr_storage sa_storage;
 715  struct sockaddr *sa_ptr;
 716  size_t sa_size;
 717  if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(),
 718                    hosturl.getPort(), sa_ptr, sa_size)) {
 719    return false;
 720  }
 721  int yes = 1;
 722  setsockopt(sock->fd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
 723  if ((flags & k_STREAM_SERVER_BIND) != 0 &&
 724      ::bind(sock->fd(), sa_ptr, sa_size) < 0) {
 725    SOCKET_ERROR(sock, "unable to bind to given address", errno);
 726    return false;
 727  }
 728  if ((flags & k_STREAM_SERVER_LISTEN) != 0 && listen(sock->fd(), 128) < 0) {
 729    SOCKET_ERROR(sock, "unable to listen on socket", errno);
 730    return false;
 731  }
 732
 733  return ret;
 734}
 735
 736Variant f_socket_accept(CResRef socket) {
 737  Socket *sock = socket.getTyped<Socket>();
 738  struct sockaddr sa;
 739  socklen_t salen = sizeof(sa);
 740  Socket *new_sock = new Socket(accept(sock->fd(), &sa, &salen),
 741                                sock->getType());
 742  if (!new_sock->valid()) {
 743    SOCKET_ERROR(new_sock, "unable to accept incoming connection", errno);
 744    delete new_sock;
 745    return false;
 746  }
 747  return Resource(new_sock);
 748}
 749
 750Variant f_socket_read(CResRef socket, int length, int type /* = 0 */) {
 751  if (length <= 0) {
 752    return false;
 753  }
 754  Socket *sock = socket.getTyped<Socket>();
 755
 756  char *tmpbuf = (char *)malloc(length + 1);
 757  int retval;
 758  if (type == PHP_NORMAL_READ) {
 759    retval = php_read(sock, tmpbuf, length, 0);
 760  } else {
 761    retval = recv(sock->fd(), tmpbuf, length, 0);
 762  }
 763
 764  if (retval == -1) {
 765    /* if the socket is in non-blocking mode and there's no data to read,
 766    don't output any error, as this is a normal situation, and not an error */
 767    if (errno == EAGAIN || errno == EWOULDBLOCK) {
 768      sock->setError(errno);
 769    } else {
 770      SOCKET_ERROR(sock, "unable to read from socket", errno);
 771    }
 772
 773    free(tmpbuf);
 774    return false;
 775  }
 776
 777  tmpbuf[retval] = '\0' ;
 778  return String(tmpbuf, retval, AttachString);
 779}
 780
 781Variant f_socket_write(CResRef socket, const String& buffer, int length /* = 0 */) {
 782  Socket *sock = socket.getTyped<Socket>();
 783  if (length == 0 || length > buffer.size()) {
 784    length = buffer.size();
 785  }
 786  int retval = write(sock->fd(), buffer.data(), length);
 787  if (retval < 0) {
 788    SOCKET_ERROR(sock, "unable to write to socket", errno);
 789    return false;
 790  }
 791  return retval;
 792}
 793
 794Variant f_socket_send(CResRef socket, const String& buf, int len, int flags) {
 795  Socket *sock = socket.getTyped<Socket>();
 796  if (len > buf.size()) {
 797    len = buf.size();
 798  }
 799  int retval = send(sock->fd(), buf.data(), len, flags);
 800  if (retval == -1) {
 801    SOCKET_ERROR(sock, "unable to write to socket", errno);
 802    return false;
 803  }
 804  return retval;
 805}
 806
 807Variant f_socket_sendto(CResRef socket, const String& buf, int len, int flags,
 808                        const String& addr, int port /* = -1 */) {
 809  Socket *sock = socket.getTyped<Socket>();
 810  if (len > buf.size()) {
 811    len = buf.size();
 812  }
 813  int retval;
 814  switch (sock->getType()) {
 815  case AF_UNIX:
 816    {
 817      struct sockaddr_un  s_un;
 818      memset(&s_un, 0, sizeof(s_un));
 819      s_un.sun_family = AF_UNIX;
 820      snprintf(s_un.sun_path, 108, "%s", addr.data());
 821
 822      retval = sendto(sock->fd(), buf.data(), len, flags,
 823                      (struct sockaddr *)&s_un, SUN_LEN(&s_un));
 824    }
 825    break;
 826  case AF_INET:
 827    {
 828      if (port == -1) {
 829        throw_missing_arguments_nr("socket_sendto", 6, 5);
 830        return false;
 831      }
 832
 833      struct sockaddr_in  sin;
 834      memset(&sin, 0, sizeof(sin));
 835      sin.sin_family = AF_INET;
 836      sin.sin_port = htons((unsigned short) port);
 837      if (!php_set_inet_addr(&sin, addr.c_str(), sock)) {
 838        return false;
 839      }
 840
 841      retval = sendto(sock->fd(), buf.data(), len, flags,
 842                      (struct sockaddr *)&sin, sizeof(sin));
 843    }
 844    break;
 845  case AF_INET6:
 846    {
 847      if (port == -1) {
 848        throw_missing_arguments_nr("socket_sendto", 6, 5);
 849        return false;
 850      }
 851
 852      struct sockaddr_in6  sin6;
 853      memset(&sin6, 0, sizeof(sin6));
 854      sin6.sin6_family = AF_INET6;
 855      sin6.sin6_port = htons((unsigned short) port);
 856
 857      if (!php_set_inet6_addr(&sin6, addr.c_str(), sock)) {
 858        return false;
 859      }
 860
 861      retval = sendto(sock->fd(), buf.data(), len, flags,
 862                      (struct sockaddr *)&sin6, sizeof(sin6));
 863    }
 864    break;
 865  default:
 866    raise_warning("Unsupported socket type %d", sock->getType());
 867    return false;
 868  }
 869
 870  if (retval == -1) {
 871    SOCKET_ERROR(sock, "unable to write to socket", errno);
 872    return false;
 873  }
 874
 875  return retval;
 876}
 877
 878Variant f_socket_recv(CResRef socket, VRefParam buf, int len, int flags) {
 879  if (len <= 0) {
 880    return false;
 881  }
 882  Socket *sock = socket.getTyped<Socket>();
 883
 884  char *recv_buf = (char *)malloc(len + 1);
 885  int retval;
 886  if ((retval = recv(sock->fd(), recv_buf, len, flags)) < 1) {
 887    free(recv_buf);
 888    buf = uninit_null();
 889  } else {
 890    recv_buf[retval] = '\0';
 891    buf = String(recv_buf, retval, AttachString);
 892  }
 893
 894  if (retval == -1) {
 895    SOCKET_ERROR(sock, "unable to read from socket", errno);
 896    return false;
 897  }
 898  return retval;
 899}
 900
 901const StaticString
 902  s_2colons("::"),
 903  s_0_0_0_0("0.0.0.0");
 904
 905Variant f_socket_recvfrom(CResRef socket, VRefParam buf, int len, int flags,
 906                      VRefParam name, VRefParam port /* = -1*/) {
 907  if (len <= 0) {
 908    return false;
 909  }
 910
 911  Socket *sock = socket.getTyped<Socket>();
 912
 913  char *recv_buf = (char *)malloc(len + 2);
 914  socklen_t slen;
 915  int retval;
 916
 917  switch (sock->getType()) {
 918  case AF_UNIX:
 919    {
 920      struct sockaddr_un s_un;
 921      slen = sizeof(s_un);
 922      memset(&s_un, 0, slen);
 923      s_un.sun_family = AF_UNIX;
 924      retval = recvfrom(sock->fd(), recv_buf, len, flags,
 925                        (struct sockaddr *)&s_un, (socklen_t *)&slen);
 926      if (retval < 0) {
 927        free(recv_buf);
 928        SOCKET_ERROR(sock, "unable to recvfrom", errno);
 929        return false;
 930      }
 931
 932      recv_buf[retval] = 0;
 933      buf = String(recv_buf, retval, AttachString);
 934      name = String(s_un.sun_path, CopyString);
 935    }
 936    break;
 937  case AF_INET:
 938    {
 939      if (int(port) == -1) {
 940        throw_missing_arguments_nr("socket_recvfrom", 5, 4);
 941        return false;
 942      }
 943
 944      struct sockaddr_in sin;
 945      slen = sizeof(sin);
 946      memset(&sin, 0, slen);
 947
 948      retval = recvfrom(sock->fd(), recv_buf, len, flags,
 949                        (struct sockaddr *)&sin, (socklen_t *)&slen);
 950      if (retval < 0) {
 951        free(recv_buf);
 952        SOCKET_ERROR(sock, "unable to recvfrom", errno);
 953        return false;
 954      }
 955      recv_buf[retval] = 0;
 956      buf = String(recv_buf, retval, AttachString);
 957
 958      name = String(Util::safe_inet_ntoa(sin.sin_addr));
 959      if (name.toString().empty()) {
 960        name = s_0_0_0_0;
 961      }
 962      port = ntohs(sin.sin_port);
 963    }
 964    break;
 965  case AF_INET6:
 966    {
 967      if (int(port) == -1) {
 968        throw_missing_arguments_nr("socket_recvfrom", 5, 4);
 969        return false;
 970      }
 971
 972      struct sockaddr_in6 sin6;
 973      slen = sizeof(sin6);
 974      memset(&sin6, 0, slen);
 975
 976      retval = recvfrom(sock->fd(), recv_buf, len, flags,
 977                        (struct sockaddr *)&sin6, (socklen_t *)&slen);
 978      if (retval < 0) {
 979        free(recv_buf);
 980        SOCKET_ERROR(sock, "unable to recvfrom", errno);
 981        return false;
 982      }
 983
 984      char addr6[INET6_ADDRSTRLEN];
 985      const char* succ =
 986        inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
 987
 988      recv_buf[retval] = 0;
 989      buf = String(recv_buf, retval, AttachString);
 990      if (succ) {
 991        name = String(addr6, CopyString);
 992      } else {
 993        name = s_2colons;
 994      }
 995      port = ntohs(sin6.sin6_port);
 996    }
 997    break;
 998  default:
 999    raise_warning("Unsupported socket type %d", sock->getType());
1000    return false;
1001  }
1002
1003  return retval;
1004}
1005
1006bool f_socket_shutdown(CResRef socket, int how /* = 0 */) {
1007  Socket *sock = socket.getTyped<Socket>();
1008  if (shutdown(sock->fd(), how) != 0) {
1009    SOCKET_ERROR(sock, "unable to shutdown socket", errno);
1010    return false;
1011  }
1012  return true;
1013}
1014
1015void f_socket_close(CResRef socket) {
1016  Socket *sock = socket.getTyped<Socket>();
1017  sock->close();
1018}
1019
1020String f_socket_strerror(int errnum) {
1021  return String(folly::errnoStr(errnum).toStdString());
1022}
1023
1024int64_t f_socket_last_error(CResRef socket /* = null_object */) {
1025  if (!socket.isNull()) {
1026    Socket *sock = socket.getTyped<Socket>();
1027    return sock->getError();
1028  }
1029  return Socket::getLastError();
1030}
1031
1032void f_socket_clear_error(CResRef socket /* = null_object */) {
1033  if (!socket.isNull()) {
1034    Socket *sock = socket.getTyped<Socket>();
1035    sock->setError(0);
1036  }
1037}
1038///////////////////////////////////////////////////////////////////////////////
1039// fsock: treating sockets as "file"
1040
1041Variant sockopen_impl(const Util::HostURL &hosturl, VRefParam errnum,
1042                      VRefParam errstr, double timeout, bool persistent) {
1043
1044  string key;
1045  if (persistent) {
1046    key = hosturl.getHostURL();
1047    Socket *sock =
1048      dynamic_cast<Socket*>(g_persistentObjects->get("socket", key.c_str()));
1049    if (sock) {
1050      if (sock->getError() == 0 && sock->checkLiveness()) {
1051        return Resource(sock);
1052      }
1053
1054      // socket had an error earlier, we need to remove it from persistent
1055      // storage, and create a new one
1056      g_persistentObjects->remove("socket", key.c_str());
1057    }
1058  }
1059
1060  Resource ret;
1061  Socket *sock = NULL;
1062
1063  if (timeout < 0) timeout = RuntimeOption::SocketDefaultTimeout;
1064  // test if protocol is SSL
1065  SSLSocket *sslsock = SSLSocket::Create(hosturl, timeout);
1066  if (sslsock) {
1067    sock = sslsock;
1068    ret = sock;
1069  } else if (!create_new_socket(hosturl, errnum, errstr, ret, sock, timeout)) {
1070    return false;
1071  }
1072  assert(ret.get() && sock);
1073
1074  sockaddr_storage sa_storage;
1075  struct sockaddr *sa_ptr;
1076  size_t sa_size;
1077  if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(),
1078                    hosturl.getPort(), sa_ptr, sa_size)) {
1079    return false;
1080  }
1081
1082  int retval;
1083  int fd = sock->fd();
1084  IOStatusHelper io("socket::connect",
1085                    hosturl.getHostURL().c_str(), hosturl.getPort());
1086  if (timeout <= 0) {
1087    retval = connect(fd, sa_ptr, sa_size);
1088  } else {
1089    // set non-blocking so we can do timeouts
1090    long arg = fcntl(fd, F_GETFL, NULL);
1091    fcntl(fd, F_SETFL, arg | O_NONBLOCK);
1092
1093    retval = connect(fd, sa_ptr, sa_size);
1094    if (retval < 0) {
1095      if (errno == EINPROGRESS) {
1096        struct pollfd fds[1];
1097        fds[0].fd = fd;
1098        fds[0].events = POLLOUT;
1099        if (poll(fds, 1, (int)(timeout * 1000))) {
1100          socklen_t lon = sizeof(int);
1101          int valopt;
1102          getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon);
1103          if (valopt) {
1104            std::string msg = "failed to connect to " + hosturl.getHostURL();
1105            SOCKET_ERROR(sock, msg.c_str(), valopt);
1106            errnum = sock->getError();
1107            errstr = String(folly::errnoStr(sock->getError()).toStdString());
1108            return false;
1109          } else {
1110            retval = 0; // success
1111          }
1112        } else {
1113          std::string msg = "timed out after ";
1114          msg += boost::lexical_cast<std::string>(timeout);
1115          msg += " seconds when connecting to " + hosturl.getHostURL();
1116          SOCKET_ERROR(sock, msg.c_str(), ETIMEDOUT);
1117          errnum = sock->getError();
1118          errstr = String(folly::errnoStr(sock->getError()).toStdString());
1119          return false;
1120        }
1121      }
1122    }
1123
1124    // set to blocking mode
1125    arg = fcntl(fd, F_GETFL, NULL);
1126    fcntl(fd, F_SETFL, arg & ~O_NONBLOCK);
1127  }
1128
1129  if (retval != 0) {
1130    errnum = sock->getError();
1131    errstr = String(folly::errnoStr(sock->getError()).toStdString());
1132    return false;
1133  }
1134
1135  if (sslsock && !sslsock->onConnect()) {
1136    raise_warning("Failed to enable crypto");
1137    return false;
1138  }
1139
1140  if (persistent) {
1141    assert(!key.empty());
1142    g_persistentObjects->set("socket", key.c_str(), sock);
1143  }
1144
1145  return ret;
1146}
1147
1148Variant f_fsockopen(const String& hostname, int port /* = -1 */,
1149                    VRefParam errnum /* = null */,
1150                    VRefParam errstr /* = null */,
1151                    double timeout /* = -1.0 */) {
1152  Util::HostURL hosturl(static_cast<const std::string>(hostname), port);
1153  return sockopen_impl(hosturl, errnum, errstr, timeout, false);
1154}
1155
1156Variant f_pfsockopen(const String& hostname, int port /* = -1 */,
1157                     VRefParam errnum /* = null */,
1158                     VRefParam errstr /* = null */,
1159                     double timeout /* = -1.0 */) {
1160  // TODO: persistent socket handling
1161  Util::HostURL hosturl(static_cast<const std::string>(hostname), port);
1162  return sockopen_impl(hosturl, errnum, errstr, timeout, true);
1163}
1164
1165String ipaddr_convert(struct sockaddr *addr, int addrlen) {
1166  char buffer[NI_MAXHOST];
1167  int error = getnameinfo(addr, addrlen, buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST);
1168
1169  if (error) {
1170    raise_warning("%s", gai_strerror(error));
1171    return "";
1172  }
1173  return String(buffer, CopyString);
1174}
1175
1176const StaticString
1177  s_family("family"),
1178  s_socktype("socktype"),
1179  s_protocol("protocol"),
1180  s_address("address"),
1181  s_port("port"),
1182  s_flow_info("flow_info"),
1183  s_scope_id("scope_id"),
1184  s_sockaddr("sockaddr");
1185
1186Variant f_getaddrinfo(const String& host, const String& port, int family /* = 0 */,
1187                      int socktype /* = 0 */, int protocol /* = 0 */,
1188                      int flags /* = 0 */) {
1189  const char *hptr = NULL, *pptr = NULL;
1190  if (!host.empty()) {
1191    hptr = host.c_str();
1192  }
1193  if (!port.empty()) {
1194    pptr = port.c_str();
1195  }
1196
1197  struct addrinfo hints, *res;
1198  struct addrinfo *res0 = NULL;
1199  int error;
1200
1201  memset(&hints, 0, sizeof(hints));
1202  hints.ai_family = family;
1203  hints.ai_socktype = socktype;
1204  hints.ai_protocol = protocol;
1205  hints.ai_flags = flags;
1206  error = getaddrinfo(hptr, pptr, &hints, &res0);
1207
1208  if (error) {
1209    raise_warning("%s", gai_strerror(error));
1210
1211    if (res0) {
1212      freeaddrinfo(res0);
1213    }
1214    return false;
1215  }
1216
1217  Array ret = Array::Create();
1218
1219  for (res = res0; res; res = res->ai_next) {
1220    Array data = Array::Create();
1221    Array sockinfo = Array::Create();
1222
1223    data.set(s_family, res->ai_family);
1224    data.set(s_socktype, res->ai_socktype);
1225    data.set(s_protocol, res->ai_protocol);
1226
1227    switch (res->ai_addr->sa_family) {
1228      case AF_INET:
1229      {
1230        struct sockaddr_in *a;
1231        String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
1232        if (!buffer.empty()) {
1233          a = (struct sockaddr_in *)res->ai_addr;
1234          sockinfo.set(s_address, buffer);
1235          sockinfo.set(s_port, ntohs(a->sin_port));
1236        }
1237        break;
1238      }
1239      case AF_INET6:
1240      {
1241        struct sockaddr_in6 *a;
1242        String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
1243        if (!buffer.empty()) {
1244          a = (struct sockaddr_in6 *)res->ai_addr;
1245          sockinfo.set(s_address, buffer);
1246          sockinfo.set(s_port, ntohs(a->sin6_port));
1247          sockinfo.set(s_flow_info, (int32_t)a->sin6_flowinfo);
1248          sockinfo.set(s_scope_id, (int32_t)a->sin6_scope_id);
1249        }
1250        break;
1251      }
1252    }
1253
1254    data.set(s_sockaddr, (sockinfo.empty() ? nullptr : sockinfo));
1255
1256    ret.append(data);
1257  }
1258
1259  if (res0) {
1260    freeaddrinfo(res0);
1261  }
1262
1263  return ret;
1264}
1265
1266///////////////////////////////////////////////////////////////////////////////
1267}