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; }
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"); }
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()); } }
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); } }
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"); }
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; }
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 }