예제 #1
0
파일: ssl-socket.cpp 프로젝트: BillHu/hhvm
SmartPtr<SSLSocket> SSLSocket::Create(
  int fd, int domain, const HostURL &hosturl, double timeout) {
  CryptoMethod method;
  const std::string scheme = hosturl.getScheme();

  if (scheme == "ssl") {
    method = CryptoMethod::ClientSSLv23;
  } else if (scheme == "sslv2") {
    method = CryptoMethod::ClientSSLv2;
  } else if (scheme == "sslv3") {
    method = CryptoMethod::ClientSSLv3;
  } else if (scheme == "tls") {
    method = CryptoMethod::ClientTLS;
  } else {
    return nullptr;
  }

  auto sock = makeSmartPtr<SSLSocket>(
    fd, domain, hosturl.getHost().c_str(), hosturl.getPort());

  sock->m_data->m_method = method;
  sock->m_data->m_connect_timeout = timeout;
  sock->m_data->m_enable_on_connect = true;

  return sock;
}
예제 #2
0
파일: ext_sockets.cpp 프로젝트: 191919/hhvm
static SmartPtr<Socket> create_new_socket(
  const HostURL &hosturl,
  Variant &errnum,
  Variant &errstr
) {
  int domain = hosturl.isIPv6() ? AF_INET6 : AF_INET;
  int type = SOCK_STREAM;
  const std::string scheme = hosturl.getScheme();

  if (scheme == "udp" || scheme == "udg") {
    type = SOCK_DGRAM;
  } else if (scheme == "unix") {
    domain = AF_UNIX;
  }

  auto sock = makeSmartPtr<Socket>(
    socket(domain, type, 0),
    domain,
    hosturl.getHost().c_str(),
    hosturl.getPort()
  );

  if (!sock->valid()) {
    SOCKET_ERROR(sock, "unable to create socket", errno);
    errnum = sock->getError();
    errstr = HHVM_FN(socket_strerror)(sock->getError());
    sock.reset();
  }
  return sock;
}
예제 #3
0
파일: ext_sockets.cpp 프로젝트: 191919/hhvm
Variant socket_server_impl(
  const HostURL &hosturl,
  int flags, /* = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN */
  VRefParam errnum /* = null */,
  VRefParam errstr /* = null */
) {
  errnum = 0;
  errstr = empty_string();
  auto sock = create_new_socket(hosturl, errnum, errstr);
  if (!sock) {
    return false;
  }

  sockaddr_storage sa_storage;
  struct sockaddr *sa_ptr;
  size_t sa_size;
  if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(),
                    hosturl.getPort(), sa_ptr, sa_size)) {
    return false;
  }
  int yes = 1;
  setsockopt(sock->fd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
  if ((flags & k_STREAM_SERVER_BIND) != 0 &&
      ::bind(sock->fd(), sa_ptr, sa_size) < 0) {
    SOCKET_ERROR(sock, "unable to bind to given address", errno);
    return false;
  }
  if ((flags & k_STREAM_SERVER_LISTEN) != 0 && listen(sock->fd(), 128) < 0) {
    SOCKET_ERROR(sock, "unable to listen on socket", errno);
    return false;
  }

  return Variant(std::move(sock));
}
예제 #4
0
req::ptr<SSLSocket> SSLSocket::Create(
  int fd, int domain, const HostURL &hosturl, double timeout,
  const req::ptr<StreamContext>& ctx) {
  CryptoMethod method;
  const std::string scheme = hosturl.getScheme();

  if (scheme == "ssl") {
    method = CryptoMethod::ClientSSLv23;
  } else if (scheme == "sslv2") {
    method = CryptoMethod::ClientSSLv2;
  } else if (scheme == "sslv3") {
    method = CryptoMethod::ClientSSLv3;
  } else if (scheme == "tls") {
    method = CryptoMethod::ClientTLS;
  } else if (
    scheme == "tcp"
    || (scheme.empty() && (domain == AF_INET || domain == AF_INET6))
  ) {
    method = CryptoMethod::NoCrypto;
  } else {
    return nullptr;
  }

  auto sock = req::make<SSLSocket>(
    fd, domain, ctx, hosturl.getHost().c_str(), hosturl.getPort());

  sock->m_data->m_method = method;
  sock->m_data->m_connect_timeout = timeout;
  sock->m_data->m_enable_on_connect = true;

  return sock;
}
예제 #5
0
req::ptr<SSLSocket> SSLSocket::Create(
  int fd, int domain, const HostURL &hosturl, double timeout,
  const req::ptr<StreamContext>& ctx,
  bool nonblocking
) {
  CryptoMethod method;
  const std::string scheme = hosturl.getScheme();

  if (scheme == "ssl") {
    method = CryptoMethod::ClientSSLv23;
  } else if (scheme == "sslv2") {
    method = CryptoMethod::ClientSSLv2;
  } else if (scheme == "sslv3") {
    method = CryptoMethod::ClientSSLv3;
  } else if (scheme == "tls") {
    method = CryptoMethod::ClientTLS;
  } else if (
    scheme == "tcp"
    || (scheme.empty() && (domain == AF_INET || domain == AF_INET6))
  ) {
    method = CryptoMethod::NoCrypto;
  } else {
    return nullptr;
  }

  return Create(fd, domain, method, hosturl.getHost(), hosturl.getPort(),
                timeout, ctx, nonblocking);
}
예제 #6
0
파일: ext_sockets.cpp 프로젝트: 191919/hhvm
static int connect_with_timeout(int fd, struct sockaddr *sa_ptr,
                                size_t sa_size, double timeout,
                                const HostURL &hosturl,
                                std::string &errstr, int &errnum) {
  if (timeout <= 0) {
    int retval = connect(fd, sa_ptr, sa_size);
    if (retval < 0) {
      errstr = "unable to connect to " + hosturl.getHostURL();
      errnum = errno;
    }
    return retval;
  }

  // set non-blocking so we can do timeouts
  long arg = fcntl(fd, F_GETFL, nullptr);
  fcntl(fd, F_SETFL, arg | O_NONBLOCK);

  int retval = connect(fd, sa_ptr, sa_size);
  if (retval < 0) {
    if (errno == EINPROGRESS) {
      struct pollfd fds[1];
      fds[0].fd = fd;
      fds[0].events = POLLOUT;
      if (poll(fds, 1, (int)(timeout * 1000))) {
        int valopt;
        socklen_t lon = sizeof(int);
        getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon);
        if (valopt) {
          errstr = "failed to connect to " + hosturl.getHostURL();
          errnum = valopt;
        }
        retval = valopt ? -1 : 0;
      } else {
        errstr = "timed out after ";
        errstr += folly::to<std::string>(timeout);
        errstr += " seconds when connecting to " + hosturl.getHostURL();
        errnum = ETIMEDOUT;
        retval = -1;
      }
    } else {
      errstr = "unable to connect to " + hosturl.getHostURL();
      errnum = errno;
    }
  }

  // set to blocking mode
  arg = fcntl(fd, F_GETFL, nullptr);
  fcntl(fd, F_SETFL, arg & ~O_NONBLOCK);

  return retval;
}
예제 #7
0
파일: ext_sockets.cpp 프로젝트: 191919/hhvm
Variant sockopen_impl(const HostURL &hosturl, VRefParam errnum,
                      VRefParam errstr, double timeout, bool persistent) {
  errnum = 0;
  errstr = empty_string();
  std::string key;
  if (persistent) {
    key = hosturl.getHostURL() + ":" +
          folly::to<std::string>(hosturl.getPort());
    auto sockItr = s_sockets.find(key);
    if (sockItr != s_sockets.end()) {
      auto sock = makeSmartPtr<Socket>(sockItr->second);

      if (sock->getError() == 0 && sock->checkLiveness()) {
        return Variant(sock);
      }

      // socket had an error earlier, we need to close it, remove it from
      // persistent storage, and create a new one (in that order)
      sock->close();
      s_sockets.erase(sockItr);
    }
  }

  if (timeout < 0) {
    timeout = ThreadInfo::s_threadInfo.getNoCheck()->
      m_reqInjectionData.getSocketDefaultTimeout();
  }

  auto socket = new_socket_connect(hosturl, timeout, errnum, errstr);
  if (!socket.isResource()) {
    return false;
  }

  if (persistent) {
    assert(!key.empty());
    s_sockets[key] = cast<Socket>(socket)->getData();
    assert(s_sockets[key]);
  }

  return socket;
}
예제 #8
0
Variant sockopen_impl(const HostURL &hosturl, VRefParam errnum,
                      VRefParam errstr, double timeout, bool persistent) {
  errnum = 0;
  errstr = empty_string();
  std::string key;
  if (persistent) {
    key = hosturl.getHostURL() + ":" +
          folly::to<std::string>(hosturl.getPort());
    Socket *sock =
      dynamic_cast<Socket*>(g_persistentResources->get("socket", key.c_str()));
    if (sock) {
      if (sock->getError() == 0 && sock->checkLiveness()) {
        return Resource(sock);
      }

      // socket had an error earlier, we need to close it, remove it from
      // persistent storage, and create a new one (in that order)
      sock->close();
      g_persistentResources->remove("socket", key.c_str());
    }
  }

  if (timeout < 0) {
    timeout = ThreadInfo::s_threadInfo.getNoCheck()->
      m_reqInjectionData.getSocketDefaultTimeout();
  }

  auto socket = new_socket_connect(hosturl, timeout, errnum, errstr);
  if (!socket.isResource()) {
    return false;
  }

  Resource ret = socket.toResource();

  if (persistent) {
    assert(!key.empty());
    g_persistentResources->set("socket", key.c_str(), ret.getTyped<Socket>());
  }

  return ret;
}
예제 #9
0
static bool create_new_socket(const HostURL &hosturl,
                              Variant &errnum, Variant &errstr, Resource &ret,
                              Socket *&sock) {
  int domain = hosturl.isIPv6() ? AF_INET6 : AF_INET;
  int type = SOCK_STREAM;
  const std::string scheme = hosturl.getScheme();

  if (scheme == "udp" || scheme == "udg") {
    type = SOCK_DGRAM;
  } else if (scheme == "unix") {
    domain = AF_UNIX;
  }

  sock = new Socket(socket(domain, type, 0), domain,
                    hosturl.getHost().c_str(), hosturl.getPort());
  ret = Resource(sock);
  if (!sock->valid()) {
    SOCKET_ERROR(sock, "unable to create socket", errno);
    errnum = sock->getError();
    errstr = HHVM_FN(socket_strerror)(sock->getError());
    return false;
  }
  return true;
}
예제 #10
0
파일: ext_sockets.cpp 프로젝트: 191919/hhvm
static Variant new_socket_connect(const HostURL &hosturl, double timeout,
                                  Variant &errnum, Variant &errstr) {
  int domain = AF_UNSPEC;
  int type = SOCK_STREAM;
  auto const& scheme = hosturl.getScheme();
  SmartPtr<Socket> sock;
  SmartPtr<SSLSocket> sslsock;
  std::string sockerr;
  int error;

  if (scheme == "udp" || scheme == "udg") {
    type = SOCK_DGRAM;
  } else if (scheme == "unix") {
    domain = AF_UNIX;
  }

  int fd = -1;
  if (domain == AF_UNIX) {
    sockaddr_storage sa_storage;
    struct sockaddr *sa_ptr;
    size_t sa_size;

    fd = socket(domain, type, 0);
    sock = makeSmartPtr<Socket>(
      fd, domain, hosturl.getHost().c_str(), hosturl.getPort());

    if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(),
                      hosturl.getPort(), sa_ptr, sa_size)) {
      // set_sockaddr raises its own warning on failure
      return false;
    }
    if (connect_with_timeout(fd, sa_ptr, sa_size, timeout,
                             hosturl, sockerr, error) != 0) {
      SOCKET_ERROR(sock, sockerr.c_str(), error);
      errnum = sock->getLastError();
      errstr = HHVM_FN(socket_strerror)(sock->getLastError());
      return false;
    }
  } else {
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family   = domain;
    hints.ai_socktype = type;

    auto port = folly::to<std::string>(hosturl.getPort());
    auto host = hosturl.getHost();

    struct addrinfo *aiHead;
    int errcode = getaddrinfo(host.c_str(), port.c_str(), &hints, &aiHead);
    if (errcode != 0) {
      errstr = String(gai_strerror(errcode), CopyString);
      return false;
    }
    SCOPE_EXIT { freeaddrinfo(aiHead); };

    for (struct addrinfo *ai = aiHead; ai != nullptr; ai = ai->ai_next) {
      domain = ai->ai_family;
      fd = socket(domain, ai->ai_socktype, ai->ai_protocol);
      if (fd == -1) {
        continue;
      }

      if (connect_with_timeout(fd, ai->ai_addr, ai->ai_addrlen, timeout,
                               hosturl, sockerr, error) == 0) {
        break;
      }
      close(fd);
      fd = -1;
    }

    sslsock = SSLSocket::Create(fd, domain, hosturl, timeout);
    if (sslsock) {
      sock = sslsock;
    } else {
      sock = makeSmartPtr<Socket>(fd,
                                  domain,
                                  hosturl.getHost().c_str(),
                                  hosturl.getPort());
    }
  }

  if (!sock->valid()) {
    SOCKET_ERROR(sock,
        sockerr.empty() ? "unable to create socket" : sockerr.c_str(), error);
    errnum = sock->getLastError();
    errstr = HHVM_FN(socket_strerror)(sock->getLastError());
    return false;
  }

  if (sslsock && !sslsock->onConnect()) {
    raise_warning("Failed to enable crypto");
    return false;
  }

  return Variant(std::move(sock));
}