예제 #1
0
bool Acceptor::canAccept(const SocketAddress& address) {
  if (!connectionCounter_) {
    return true;
  }

  uint64_t maxConnections = connectionCounter_->getMaxConnections();
  if (maxConnections == 0) {
    return true;
  }

  uint64_t currentConnections = connectionCounter_->getNumConnections();
  if (currentConnections < maxConnections) {
    return true;
  }

  if (loadShedConfig_.isWhitelisted(address)) {
    return true;
  }

  // Take care of comparing connection count against max connections across
  // all acceptors. Expensive since a lock must be taken to get the counter.
  auto connectionCountForLoadShedding = getConnectionCountForLoadShedding();
  if (connectionCountForLoadShedding < loadShedConfig_.getMaxConnections()) {
    return true;
  }

  VLOG(4) << address.describe() << " not whitelisted";
  return false;
}
예제 #2
0
 virtual void transportActive(Context* ctx) override {
   auto sock = ctx->getTransport();
   SocketAddress localAddress;
   sock->getLocalAddress(&localAddress);
   write(ctx, "Welcome to " + localAddress.describe() + "!\r\n");
   write(ctx, "Type 'bye' to disconnect.\r\n");
 }
예제 #3
0
void AsyncServerSocket::bindSocket(
    int fd,
    const SocketAddress& address,
    bool isExistingSocket) {
  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);

  if (fsp::bind(fd, saddr, address.getActualSize()) != 0) {
    if (!isExistingSocket) {
      closeNoInt(fd);
    }
    folly::throwSystemError(errno,
        "failed to bind to async server socket: " +
        address.describe());
  }

#if __linux__
  if (noTransparentTls_) {
    // Ignore return value, errors are ok
    setsockopt(fd, SOL_SOCKET, SO_NO_TRANSPARENT_TLS, nullptr, 0);
  }
#endif

  // If we just created this socket, update the EventHandler and set socket_
  if (!isExistingSocket) {
    sockets_.emplace_back(eventBase_, fd, this, address.getFamily());
  }
}
예제 #4
0
void AsyncServerSocket::setupSocket(int fd) {
  // Get the address family
  SocketAddress address;
  address.setFromLocalAddress(fd);

  // Put the socket in non-blocking mode
  if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) {
    folly::throwSystemError(errno,
                            "failed to put socket in non-blocking mode");
  }

  // Set reuseaddr to avoid 2MSL delay on server restart
  int one = 1;
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) {
    // This isn't a fatal error; just log an error message and continue
    LOG(ERROR) << "failed to set SO_REUSEADDR on async server socket " << errno;
  }

  // Set reuseport to support multiple accept threads
  int zero = 0;
  if (reusePortEnabled_ &&
      setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)) != 0) {
    LOG(ERROR) << "failed to set SO_REUSEPORT on async server socket "
               << strerror(errno);
    folly::throwSystemError(errno,
                            "failed to bind to async server socket: " +
                            address.describe());
  }

  // Set keepalive as desired
  if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
                 (keepAliveEnabled_) ? &one : &zero, sizeof(int)) != 0) {
    LOG(ERROR) << "failed to set SO_KEEPALIVE on async server socket: " <<
            strerror(errno);
  }

  // Setup FD_CLOEXEC flag
  if (closeOnExec_ &&
      (-1 == folly::setCloseOnExec(fd, closeOnExec_))) {
    LOG(ERROR) << "failed to set FD_CLOEXEC on async server socket: " <<
            strerror(errno);
  }

  // Set TCP nodelay if available, MAC OS X Hack
  // See http://lists.danga.com/pipermail/memcached/2005-March/001240.html
#ifndef TCP_NOPUSH
  auto family = address.getFamily();
  if (family != AF_UNIX) {
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0) {
      // This isn't a fatal error; just log an error message and continue
      LOG(ERROR) << "failed to set TCP_NODELAY on async server socket: " <<
              strerror(errno);
    }
  }
#endif

  if (shutdownSocketSet_) {
    shutdownSocketSet_->add(fd);
  }
}
예제 #5
0
 void transportActive(Context* ctx) override {
   SocketAddress localAddress;
   ctx->getTransport()->getLocalAddress(&localAddress);
   write(ctx, "Welcome to " + localAddress.describe() + "!\r\n");
   write(ctx, "Type the name of a file and it will be streamed to you!\r\n");
   write(ctx, "Type 'bye' to exit.\r\n");
 }
예제 #6
0
bool Acceptor::canAccept(const SocketAddress& address) {
  if (!connectionCounter_) {
    return true;
  }

  const auto totalConnLimit = loadShedConfig_.getMaxConnections();
  if (totalConnLimit == 0) {
    return true;
  }

  uint64_t currentConnections = connectionCounter_->getNumConnections();
  uint64_t maxConnections = getWorkerMaxConnections();
  if (currentConnections < maxConnections) {
    return true;
  }

  if (loadShedConfig_.isWhitelisted(address)) {
    return true;
  }

  // Take care of the connection counts across all acceptors.
  // Expensive since a lock must be taken to get the counter.

  // getConnectionCountForLoadShedding() call can be very expensive,
  // don't call it if you are not going to use the results.
  const auto totalConnExceeded =
    totalConnLimit > 0 && getConnectionCountForLoadShedding() >= totalConnLimit;

  const auto activeConnLimit = loadShedConfig_.getMaxActiveConnections();
  // getActiveConnectionCountForLoadShedding() call can be very expensive,
  // don't call it if you are not going to use the results.
  const auto activeConnExceeded =
    !totalConnExceeded &&
    activeConnLimit > 0 &&
    getActiveConnectionCountForLoadShedding() >= activeConnLimit;

  if (!activeConnExceeded && !totalConnExceeded) {
    return true;
  }

  VLOG(4) << address.describe() << " not whitelisted";
  return false;
}
예제 #7
0
void AsyncServerSocket::bindSocket(
    int fd,
    const SocketAddress& address,
    bool isExistingSocket) {
  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);
  if (::bind(fd, saddr, address.getActualSize()) != 0) {
    if (!isExistingSocket) {
      closeNoInt(fd);
    }
    folly::throwSystemError(errno,
        "failed to bind to async server socket: " +
        address.describe());
  }

  // If we just created this socket, update the EventHandler and set socket_
  if (!isExistingSocket) {
    sockets_.emplace_back(eventBase_, fd, this, address.getFamily());
  }
}
TEST(SocketAddress, Unix) {
  SocketAddress addr;

  // Test a small path
  addr.setFromPath("foo");
  EXPECT_EQ(addr.getFamily(), AF_UNIX);
  EXPECT_EQ(addr.describe(), "foo");
  EXPECT_THROW(addr.getAddressStr(), std::invalid_argument);
  EXPECT_THROW(addr.getPort(), std::invalid_argument);
  EXPECT_TRUE(addr.isPrivateAddress());
  EXPECT_TRUE(addr.isLoopbackAddress());

  // Test a path that is too large
  const char longPath[] =
      "abcdefghijklmnopqrstuvwxyz0123456789"
      "abcdefghijklmnopqrstuvwxyz0123456789"
      "abcdefghijklmnopqrstuvwxyz0123456789"
      "abcdefghijklmnopqrstuvwxyz0123456789";
  EXPECT_THROW(addr.setFromPath(longPath), std::invalid_argument);
  // The original address should still be the same
  EXPECT_EQ(addr.getFamily(), AF_UNIX);
  EXPECT_EQ(addr.describe(), "foo");

  // Test a path that exactly fits in sockaddr_un
  // (not including the NUL terminator)
  const char exactLengthPath[] =
      "abcdefghijklmnopqrstuvwxyz0123456789"
      "abcdefghijklmnopqrstuvwxyz0123456789"
      "abcdefghijklmnopqrstuvwxyz0123456789";
  addr.setFromPath(exactLengthPath);
  EXPECT_EQ(addr.describe(), exactLengthPath);

  // Test converting a unix socket address to an IPv4 one, then back
  addr.setFromHostPort("127.0.0.1", 1234);
  EXPECT_EQ(addr.getFamily(), AF_INET);
  EXPECT_EQ(addr.describe(), "127.0.0.1:1234");
  addr.setFromPath("/i/am/a/unix/address");
  EXPECT_EQ(addr.getFamily(), AF_UNIX);
  EXPECT_EQ(addr.describe(), "/i/am/a/unix/address");

  // Test copy constructor and assignment operator
  {
    SocketAddress copy(addr);
    EXPECT_EQ(copy, addr);
    copy.setFromPath("/abc");
    EXPECT_NE(copy, addr);
    copy = addr;
    EXPECT_EQ(copy, addr);
    copy.setFromIpPort("127.0.0.1", 80);
    EXPECT_NE(copy, addr);
    copy = addr;
    EXPECT_EQ(copy, addr);
  }

  {
    SocketAddress copy(addr);
    EXPECT_EQ(copy, addr);
    EXPECT_EQ(copy.describe(), "/i/am/a/unix/address");
    EXPECT_EQ(copy.getPath(), "/i/am/a/unix/address");

    SocketAddress other("127.0.0.1", 80);
    EXPECT_NE(other, addr);
    other = copy;
    EXPECT_EQ(other, copy);
    EXPECT_EQ(other, addr);
    EXPECT_EQ(copy, addr);
  }

#if __GXX_EXPERIMENTAL_CXX0X__
  {
    SocketAddress copy;
    {
      // move a unix address into a non-unix address
      SocketAddress tmpCopy(addr);
      copy = std::move(tmpCopy);
    }
    EXPECT_EQ(copy, addr);

    copy.setFromPath("/another/path");
    {
      // move a unix address into a unix address
      SocketAddress tmpCopy(addr);
      copy = std::move(tmpCopy);
    }
    EXPECT_EQ(copy, addr);

    {
      // move a non-unix address into a unix address
      SocketAddress tmp("127.0.0.1", 80);
      copy = std::move(tmp);
    }
    EXPECT_EQ(copy.getAddressStr(), "127.0.0.1");
    EXPECT_EQ(copy.getPort(), 80);

    copy = addr;
    // move construct a unix address
    SocketAddress other(std::move(copy));
    EXPECT_EQ(other, addr);
    EXPECT_EQ(other.getPath(), addr.getPath());
  }
#endif
}