예제 #1
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;
}
예제 #2
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;
}
예제 #3
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;
}