void LibEventServerWithTakeover::start() {

  if (m_server_ssl) {
    // Set a flag to prevent parent class from trying to listen to ssl
    // before the old server releases the port
    m_accept_sock_ssl = -2;
  }

  LibEventServer::start();

  if (m_took_over) {
    Logger::Info("takeover: requesting shutdown of satellites");
    // Use AFDT to synchronously shut down the old server's satellites
    // so we can take their ports using accept.  The main server will be
    // stopped asynchronously.
    uint8_t shutdown_request[3] = P_VERSION C_TERM_REQ;
    uint8_t shutdown_response[3] = {0,0,0};
    uint32_t response_len = sizeof(shutdown_response);
    int should_not_receive_fd;
    afdt_error_t err = AFDT_ERROR_T_INIT;
    // TODO(dreiss): Make this timeout configurable.
    // We can aford to wait a long time here, since we've already started
    // the dispatcher for this server.  We want to give the old server
    // plenty of time to shut down all of its satellite servers.
    struct timeval timeout = { 10 , 0 };
    int ret = afdt_sync_client(
        m_transfer_fname.c_str(),
        shutdown_request,
        sizeof(shutdown_request) - 1,
        shutdown_response,
        &response_len,
        &should_not_receive_fd,
        &timeout,
        &err);
    if (ret < 0) {
      fd_transfer_error_hander(&err, nullptr);
      Logger::Warning("Failed to shut-down old server with AFDT.");
      // The higher-level start logic will try *very* hard to recover from this.
    }
    String resp((const char*)shutdown_response, response_len, CopyString);
    if (resp != s_ver_C_TERM_OK) {
      Logger::Error(
          "Old server could not shut down: "
          "response = '%s'",
          f_addcslashes(resp, null_string).data());
    } else {
      Logger::Info("takeover: old satellites have shut down");
    }
  }

  if (m_server_ssl) {
    if (getAcceptSocketSSL() != 0) {
      Logger::Error("Fail to listen on ssl port %d", m_port_ssl);
      throw FailedToListenException(m_address, m_port_ssl);
    }
    Logger::Info("Listen on ssl port %d",m_port_ssl);
  }

  setupFdServer();
}
Пример #2
0
bool TestExtString::test_addcslashes() {
  VS(f_addcslashes("ABCDEFGH\n", "A..D\n"), "\\A\\B\\C\\DEFGH\\n");
  VS(f_addcslashes(String("\x00\x0D\n", 3, AttachLiteral), null_string),
     "\\000\\r\\n");
  return Count(true);
}
int LibEventServerWithTakeover::getAcceptSocket() {
  int ret;
  const char *address = m_address.empty() ? nullptr : m_address.c_str();

  if (m_accept_sock != -1) {
    Logger::Warning("LibEventServerWithTakeover trying to get a socket, "
        "but m_accept_sock is not -1.  Possibly leaking file descriptors.");
    m_accept_sock = -1;
  }

  ret = evhttp_bind_socket_backlog_fd(m_server, address,
                                   m_port, RuntimeOption::ServerBacklog);
  if (ret >= 0) {
    Logger::Info("takeover: bound directly to port %d", m_port);
    m_accept_sock = ret;
    return 0;
  } else if (errno != EADDRINUSE) {
    return -1;
  }

  if (m_transfer_fname.empty()) {
    return -1;
  }

  Logger::Info("takeover: beginning listen socket acquisition");
  uint8_t fd_request[3] = P_VERSION C_FD_REQ;
  uint8_t fd_response[3] = {0,0,0};
  uint32_t response_len = sizeof(fd_response);
  afdt_error_t err = AFDT_ERROR_T_INIT;
  // TODO(dreiss): Make this timeout configurable.
  struct timeval timeout = { 2 , 0 };
  ret = afdt_sync_client(
      m_transfer_fname.c_str(),
      fd_request,
      sizeof(fd_request) - 1,
      fd_response,
      &response_len,
      &m_accept_sock,
      &timeout,
      &err);
  if (ret < 0) {
    fd_transfer_error_hander(&err, nullptr);
    errno = EADDRINUSE;
    return -1;
  } else if (m_accept_sock < 0) {
    String resp((const char*)fd_response, response_len, CopyString);
    Logger::Error(
        "AFDT did not receive a file descriptor: "
        "response = '%s'",
        f_addcslashes(resp, null_string).data());
    errno = EADDRINUSE;
    return -1;
  }

  Logger::Info("takeover: acquired listen socket");
  m_took_over = true;

  ret = evhttp_accept_socket(m_server, m_accept_sock);
  if (ret < 0) {
    Logger::Error("evhttp_accept_socket: %s",
        folly::errnoStr(errno).c_str());
    int errno_save = errno;
    close(m_accept_sock);
    m_accept_sock = -1;
    errno = errno_save;
    return -1;
  }

  return 0;
}