Commit adc966e1 authored by Cameron Pickett's avatar Cameron Pickett Committed by JoelMarcey

Add specific multi-bind to AsyncServerSocket

Summary:
Add a bind api similar to binding by port across all interfaces.
However, this bind will only attempt to bind sockets to the supplied
IP addresses. I'd like to add this to aid in moving TURN to IPv6.

TURN will use two specified addresses, one for IPv4, and one for IPv6, to
handle incoming connections from clients. In order to avoid duplicating
workers, we'd like to take advantage of the multi-socket implementation
of AsyncServerSocket. However, we don't want to bind to all interfaces,
especially for port 443.

Test Plan:
Plan to test by adapting TurnTcpListener to use this new API. See that
1. using one address still works as expected,
2. using zero addesses will cause exception
3. using multiple addresses works as expected

Will write unit tests if needed

Reviewed By: davejwatson@fb.com

Subscribers: hannesr, trunkagent, net-systems@, folly-diffs@, naizhi

FB internal diff: D1729442

Tasks: 3633642

Signature: t1:1729442:1418752467:22a60da4ec9009ea0b7fe28a8a436a179e0449aa
parent 1a608d58
...@@ -273,6 +273,29 @@ void AsyncServerSocket::useExistingSocket(int fd) { ...@@ -273,6 +273,29 @@ void AsyncServerSocket::useExistingSocket(int fd) {
useExistingSockets({fd}); useExistingSockets({fd});
} }
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) {
::close(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_.push_back(
ServerEventHandler(eventBase_, fd, this, address.getFamily()));
}
}
void AsyncServerSocket::bind(const SocketAddress& address) { void AsyncServerSocket::bind(const SocketAddress& address) {
assert(eventBase_ == nullptr || eventBase_->isInEventBaseThread()); assert(eventBase_ == nullptr || eventBase_->isInEventBaseThread());
...@@ -295,27 +318,29 @@ void AsyncServerSocket::bind(const SocketAddress& address) { ...@@ -295,27 +318,29 @@ void AsyncServerSocket::bind(const SocketAddress& address) {
"Attempted to bind to multiple fds"); "Attempted to bind to multiple fds");
} }
// Bind to the socket bindSocket(fd, address, !sockets_.empty());
sockaddr_storage addrStorage; }
address.getAddress(&addrStorage);
sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage); void AsyncServerSocket::bind(
if (::bind(fd, saddr, address.getActualSize()) != 0) { const std::vector<IPAddress>& ipAddresses,
if (sockets_.size() == 0) { uint16_t port) {
::close(fd); if (ipAddresses.empty()) {
} throw std::invalid_argument("No ip addresses were provided");
folly::throwSystemError(errno, }
"failed to bind to async server socket: " + if (!sockets_.empty()) {
address.describe()); throw std::invalid_argument("Cannot call bind on a AsyncServerSocket "
"that already has a socket.");
} }
// Record the address family that we are using, for (const IPAddress& ipAddress : ipAddresses) {
// so we know how much address space we need to record accepted addresses. SocketAddress address(ipAddress.toFullyQualified(), port);
int fd = createSocket(address.getFamily());
// If we just created this socket, update the EventHandler and set socket_ bindSocket(fd, address, false);
}
if (sockets_.size() == 0) { if (sockets_.size() == 0) {
sockets_.push_back( throw std::runtime_error(
ServerEventHandler(eventBase_, fd, this, address.getFamily())); "did not bind any async server socket for port and addresses");
sockets_[0].changeHandlerFD(fd);
} }
} }
......
...@@ -255,6 +255,17 @@ class AsyncServerSocket : public DelayedDestruction { ...@@ -255,6 +255,17 @@ class AsyncServerSocket : public DelayedDestruction {
*/ */
virtual void bind(const SocketAddress& address); virtual void bind(const SocketAddress& address);
/**
* Bind to the specified port for the specified addresses.
*
* This must be called from the primary EventBase thread.
*
* Throws TTransportException on error.
*/
virtual void bind(
const std::vector<IPAddress>& ipAddresses,
uint16_t port);
/** /**
* Bind to the specified port. * Bind to the specified port.
* *
...@@ -639,6 +650,7 @@ class AsyncServerSocket : public DelayedDestruction { ...@@ -639,6 +650,7 @@ class AsyncServerSocket : public DelayedDestruction {
int createSocket(int family); int createSocket(int family);
void setupSocket(int fd); void setupSocket(int fd);
void bindSocket(int fd, const SocketAddress& address, bool isExistingSocket);
void dispatchSocket(int socket, SocketAddress&& address); void dispatchSocket(int socket, SocketAddress&& address);
void dispatchError(const char *msg, int errnoValue); void dispatchError(const char *msg, int errnoValue);
void enterBackoff(); void enterBackoff();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment