void AsyncServerSocket::handlerReady()

in folly/io/async/AsyncServerSocket.cpp [921:1065]


void AsyncServerSocket::handlerReady(
    uint16_t /* events */,
    NetworkSocket fd,
    sa_family_t addressFamily) noexcept {
  assert(!callbacks_.empty());
  DestructorGuard dg(this);

  // Only accept up to maxAcceptAtOnce_ connections at a time,
  // to avoid starving other I/O handlers using this EventBase.
  for (uint32_t n = 0; n < maxAcceptAtOnce_; ++n) {
    SocketAddress address;

    sockaddr_storage addrStorage = {};
    socklen_t addrLen = sizeof(addrStorage);
    auto saddr = reinterpret_cast<sockaddr*>(&addrStorage);

    // In some cases, accept() doesn't seem to update these correctly.
    saddr->sa_family = addressFamily;
    if (addressFamily == AF_UNIX) {
      addrLen = sizeof(struct sockaddr_un);
    }

    // Accept a new client socket
#if FOLLY_HAVE_ACCEPT4
    auto clientSocket = NetworkSocket::fromFd(
        accept4(fd.toFd(), saddr, &addrLen, SOCK_NONBLOCK));
#else
    auto clientSocket = netops::accept(fd, saddr, &addrLen);
#endif

    address.setFromSockaddr(saddr, addrLen);

    if (clientSocket != NetworkSocket() && connectionEventCallback_) {
      connectionEventCallback_->onConnectionAccepted(clientSocket, address);
    }

    // Connection accepted, get the SYN packet from the client if
    // TOS reflect is enabled
    if (kIsLinux && clientSocket != NetworkSocket() && tosReflect_) {
      std::array<uint32_t, 64> buffer;
      socklen_t len = sizeof(buffer);
      int ret = netops::getsockopt(
          clientSocket, IPPROTO_TCP, TCP_SAVED_SYN, &buffer, &len);

      if (ret == 0) {
        uint32_t tosWord = folly::Endian::big(buffer[0]);
        if (addressFamily == AF_INET6) {
          tosWord = (tosWord & 0x0FC00000) >> 20;
          // Set the TOS on the return socket only if it is non-zero
          if (tosWord) {
            ret = netops::setsockopt(
                clientSocket,
                IPPROTO_IPV6,
                IPV6_TCLASS,
                &tosWord,
                sizeof(tosWord));
          }
        } else if (addressFamily == AF_INET) {
          tosWord = (tosWord & 0x00FC0000) >> 16;
          if (tosWord) {
            ret = netops::setsockopt(
                clientSocket, IPPROTO_IP, IP_TOS, &tosWord, sizeof(tosWord));
          }
        }

        if (ret != 0) {
          LOG(ERROR) << "Unable to set TOS for accepted socket "
                     << clientSocket;
        }
      } else {
        LOG(ERROR) << "Unable to get SYN packet for accepted socket "
                   << clientSocket;
      }
    }

    std::chrono::time_point<std::chrono::steady_clock> nowMs =
        std::chrono::steady_clock::now();
    auto timeSinceLastAccept = std::max<int64_t>(
        0,
        nowMs.time_since_epoch().count() -
            lastAccepTimestamp_.time_since_epoch().count());
    lastAccepTimestamp_ = nowMs;
    if (acceptRate_ < 1) {
      acceptRate_ *= 1 + acceptRateAdjustSpeed_ * timeSinceLastAccept;
      if (acceptRate_ >= 1) {
        acceptRate_ = 1;
      } else if (rand() > acceptRate_ * RAND_MAX) {
        ++numDroppedConnections_;
        if (clientSocket != NetworkSocket()) {
          closeNoInt(clientSocket);
          if (connectionEventCallback_) {
            connectionEventCallback_->onConnectionDropped(
                clientSocket, address);
          }
        }
        continue;
      }
    }

    if (clientSocket == NetworkSocket()) {
      if (errno == EAGAIN) {
        // No more sockets to accept right now.
        // Check for this code first, since it's the most common.
        return;
      } else if (errno == EMFILE || errno == ENFILE) {
        // We're out of file descriptors.  Perhaps we're accepting connections
        // too quickly. Pause accepting briefly to back off and give the server
        // a chance to recover.
        LOG(ERROR) << "accept failed: out of file descriptors; entering accept "
                      "back-off state";
        enterBackoff();

        // Dispatch the error message
        dispatchError("accept() failed", errno);
      } else {
        dispatchError("accept() failed", errno);
      }
      if (connectionEventCallback_) {
        connectionEventCallback_->onConnectionAcceptError(errno);
      }
      return;
    }

#if !FOLLY_HAVE_ACCEPT4
    // Explicitly set the new connection to non-blocking mode
    if (netops::set_socket_non_blocking(clientSocket) != 0) {
      closeNoInt(clientSocket);
      dispatchError(
          "failed to set accepted socket to non-blocking mode", errno);
      if (connectionEventCallback_) {
        connectionEventCallback_->onConnectionDropped(clientSocket, address);
      }
      return;
    }
#endif

    // Inform the callback about the new connection
    dispatchSocket(clientSocket, std::move(address));

    // If we aren't accepting any more, break out of the loop
    if (!accepting_ || callbacks_.empty()) {
      break;
    }
  }
}