Commit ab5d1a0b authored by Alan Frindell's avatar Alan Frindell Committed by Facebook GitHub Bot

Optional peerAddress argument for sockets created with fd

Summary: For TCP sockets, it may not be possible to query the peer address from the fd if the endpoint is no longer connected (closed with reset).  In most server cases, the peer address is known when the connection is accepted, so it can be prepopulated.

Reviewed By: mjoras

Differential Revision: D27985942

fbshipit-source-id: 630098ac00930b978fe8a9cad1894834c44d4d93
parent e5cb25c2
...@@ -271,8 +271,9 @@ AsyncSSLSocket::AsyncSSLSocket( ...@@ -271,8 +271,9 @@ AsyncSSLSocket::AsyncSSLSocket(
EventBase* evb, EventBase* evb,
NetworkSocket fd, NetworkSocket fd,
bool server, bool server,
bool deferSecurityNegotiation) bool deferSecurityNegotiation,
: AsyncSocket(evb, fd), const SocketAddress* peerAddress)
: AsyncSocket(evb, fd, 0, peerAddress),
server_(server), server_(server),
ctx_(std::move(ctx)), ctx_(std::move(ctx)),
handshakeTimeout_(this, evb), handshakeTimeout_(this, evb),
...@@ -340,8 +341,10 @@ AsyncSSLSocket::AsyncSSLSocket( ...@@ -340,8 +341,10 @@ AsyncSSLSocket::AsyncSSLSocket(
EventBase* evb, EventBase* evb,
NetworkSocket fd, NetworkSocket fd,
const std::string& serverName, const std::string& serverName,
bool deferSecurityNegotiation) bool deferSecurityNegotiation,
: AsyncSSLSocket(ctx, evb, fd, false, deferSecurityNegotiation) { const SocketAddress* peerAddress)
: AsyncSSLSocket(
ctx, evb, fd, false, deferSecurityNegotiation, peerAddress) {
tlsextHostname_ = serverName; tlsextHostname_ = serverName;
} }
#endif // FOLLY_OPENSSL_HAS_SNI #endif // FOLLY_OPENSSL_HAS_SNI
......
...@@ -252,13 +252,17 @@ class AsyncSSLSocket : public AsyncSocket { ...@@ -252,13 +252,17 @@ class AsyncSSLSocket : public AsyncSocket {
* @param server Is socket in server mode? * @param server Is socket in server mode?
* @param deferSecurityNegotiation * @param deferSecurityNegotiation
* unencrypted data can be sent before sslConn/Accept * unencrypted data can be sent before sslConn/Accept
* @param peerAddress optional peer address (eg: returned from accept). If
* nullptr, AsyncSocket will lazily attempt to determine it from fd
* via a system call
*/ */
AsyncSSLSocket( AsyncSSLSocket(
std::shared_ptr<folly::SSLContext> ctx, std::shared_ptr<folly::SSLContext> ctx,
EventBase* evb, EventBase* evb,
NetworkSocket fd, NetworkSocket fd,
bool server = true, bool server = true,
bool deferSecurityNegotiation = false); bool deferSecurityNegotiation = false,
const SocketAddress* peerAddress = nullptr);
/** /**
* Create a server/client AsyncSSLSocket from an already connected * Create a server/client AsyncSSLSocket from an already connected
...@@ -288,9 +292,10 @@ class AsyncSSLSocket : public AsyncSocket { ...@@ -288,9 +292,10 @@ class AsyncSSLSocket : public AsyncSocket {
EventBase* evb, EventBase* evb,
NetworkSocket fd, NetworkSocket fd,
bool server = true, bool server = true,
bool deferSecurityNegotiation = false) { bool deferSecurityNegotiation = false,
return AsyncSSLSocket::UniquePtr( const folly::SocketAddress* peerAddress = nullptr) {
new AsyncSSLSocket(ctx, evb, fd, server, deferSecurityNegotiation)); return AsyncSSLSocket::UniquePtr(new AsyncSSLSocket(
ctx, evb, fd, server, deferSecurityNegotiation, peerAddress));
} }
/** /**
...@@ -329,13 +334,19 @@ class AsyncSSLSocket : public AsyncSocket { ...@@ -329,13 +334,19 @@ class AsyncSSLSocket : public AsyncSocket {
* @param evb EventBase that will manage this socket. * @param evb EventBase that will manage this socket.
* @param fd File descriptor to take over (should be a connected socket). * @param fd File descriptor to take over (should be a connected socket).
* @param serverName tlsext_hostname that will be sent in ClientHello. * @param serverName tlsext_hostname that will be sent in ClientHello.
* @param deferSecurityNegotiation
* unencrypted data can be sent before sslConn/Accept
* @param peerAddress optional peer address (eg: returned from accept). If
* nullptr, AsyncSocket will lazily attempt to determine it from fd
* via a system call
*/ */
AsyncSSLSocket( AsyncSSLSocket(
const std::shared_ptr<folly::SSLContext>& ctx, const std::shared_ptr<folly::SSLContext>& ctx,
EventBase* evb, EventBase* evb,
NetworkSocket fd, NetworkSocket fd,
const std::string& serverName, const std::string& serverName,
bool deferSecurityNegotiation = false); bool deferSecurityNegotiation = false,
const SocketAddress* peerAddr = nullptr);
static UniquePtr newSocket( static UniquePtr newSocket(
const std::shared_ptr<folly::SSLContext>& ctx, const std::shared_ptr<folly::SSLContext>& ctx,
......
...@@ -563,7 +563,10 @@ AsyncSocket::AsyncSocket( ...@@ -563,7 +563,10 @@ AsyncSocket::AsyncSocket(
} }
AsyncSocket::AsyncSocket( AsyncSocket::AsyncSocket(
EventBase* evb, NetworkSocket fd, uint32_t zeroCopyBufId) EventBase* evb,
NetworkSocket fd,
uint32_t zeroCopyBufId,
const SocketAddress* peerAddress)
: zeroCopyBufId_(zeroCopyBufId), : zeroCopyBufId_(zeroCopyBufId),
eventBase_(evb), eventBase_(evb),
writeTimeout_(this, evb), writeTimeout_(this, evb),
...@@ -576,13 +579,17 @@ AsyncSocket::AsyncSocket( ...@@ -576,13 +579,17 @@ AsyncSocket::AsyncSocket(
disableTransparentFunctions(fd_, noTransparentTls_, noTSocks_); disableTransparentFunctions(fd_, noTransparentTls_, noTSocks_);
setCloseOnExec(); setCloseOnExec();
state_ = StateEnum::ESTABLISHED; state_ = StateEnum::ESTABLISHED;
if (peerAddress) {
addr_ = *peerAddress;
}
} }
AsyncSocket::AsyncSocket(AsyncSocket* oldAsyncSocket) AsyncSocket::AsyncSocket(AsyncSocket* oldAsyncSocket)
: AsyncSocket( : AsyncSocket(
oldAsyncSocket->getEventBase(), oldAsyncSocket->getEventBase(),
oldAsyncSocket->detachNetworkSocket(), oldAsyncSocket->detachNetworkSocket(),
oldAsyncSocket->getZeroCopyBufId()) { oldAsyncSocket->getZeroCopyBufId(),
&oldAsyncSocket->addr_) {
appBytesWritten_ = oldAsyncSocket->appBytesWritten_; appBytesWritten_ = oldAsyncSocket->appBytesWritten_;
rawBytesWritten_ = oldAsyncSocket->rawBytesWritten_; rawBytesWritten_ = oldAsyncSocket->rawBytesWritten_;
byteEventHelper_ = std::move(oldAsyncSocket->byteEventHelper_); byteEventHelper_ = std::move(oldAsyncSocket->byteEventHelper_);
......
...@@ -376,8 +376,15 @@ class AsyncSocket : public AsyncTransport { ...@@ -376,8 +376,15 @@ class AsyncSocket : public AsyncTransport {
* @param evb EventBase that will manage this socket. * @param evb EventBase that will manage this socket.
* @param fd File descriptor to take over (should be a connected socket). * @param fd File descriptor to take over (should be a connected socket).
* @param zeroCopyBufId Zerocopy buf id to start with. * @param zeroCopyBufId Zerocopy buf id to start with.
* @param peerAddress optional peer address (eg: returned from accept). If
* nullptr, AsyncSocket will lazily attempt to determine it from fd
* via a system call
*/ */
AsyncSocket(EventBase* evb, NetworkSocket fd, uint32_t zeroCopyBufId = 0); AsyncSocket(
EventBase* evb,
NetworkSocket fd,
uint32_t zeroCopyBufId = 0,
const SocketAddress* peerAddress = nullptr);
/** /**
* Create an AsyncSocket from a different, already connected AsyncSocket. * Create an AsyncSocket from a different, already connected AsyncSocket.
...@@ -434,8 +441,11 @@ class AsyncSocket : public AsyncTransport { ...@@ -434,8 +441,11 @@ class AsyncSocket : public AsyncTransport {
/** /**
* Helper function to create an AsyncSocket. * Helper function to create an AsyncSocket.
*/ */
static UniquePtr newSocket(EventBase* evb, NetworkSocket fd) { static UniquePtr newSocket(
return UniquePtr{new AsyncSocket(evb, fd)}; EventBase* evb,
NetworkSocket fd,
const SocketAddress* peerAddress = nullptr) {
return UniquePtr{new AsyncSocket(evb, fd, 0, peerAddress)};
} }
/** /**
......
...@@ -5731,8 +5731,11 @@ TEST(AsyncSocket, PreReceivedDataTakeover) { ...@@ -5731,8 +5731,11 @@ TEST(AsyncSocket, PreReceivedDataTakeover) {
socket->writeChain(nullptr, IOBuf::copyBuffer("hello")); socket->writeChain(nullptr, IOBuf::copyBuffer("hello"));
auto fd = server.acceptFD();
SocketAddress peerAddress;
peerAddress.setFromPeerAddress(fd);
auto acceptedSocket = auto acceptedSocket =
AsyncSocket::UniquePtr(new AsyncSocket(&evb, server.acceptFD())); AsyncSocket::UniquePtr(new AsyncSocket(&evb, fd, 0, &peerAddress));
AsyncSocket::UniquePtr takeoverSocket; AsyncSocket::UniquePtr takeoverSocket;
ReadCallback peekCallback(3); ReadCallback peekCallback(3);
...@@ -5753,6 +5756,12 @@ TEST(AsyncSocket, PreReceivedDataTakeover) { ...@@ -5753,6 +5756,12 @@ TEST(AsyncSocket, PreReceivedDataTakeover) {
acceptedSocket->setReadCB(&peekCallback); acceptedSocket->setReadCB(&peekCallback);
evb.loop(); evb.loop();
// Verify we can still get the peer address after the peer socket is reset.
socket->closeWithReset();
evb.loopOnce();
SocketAddress socketPeerAddress;
takeoverSocket->getPeerAddress(&socketPeerAddress);
EXPECT_EQ(socketPeerAddress, peerAddress);
} }
#ifdef MSG_NOSIGNAL #ifdef MSG_NOSIGNAL
......
...@@ -63,7 +63,7 @@ class SSLServerAcceptCallbackBase : public AsyncServerSocket::AcceptCallback { ...@@ -63,7 +63,7 @@ class SSLServerAcceptCallbackBase : public AsyncServerSocket::AcceptCallback {
void connectionAccepted( void connectionAccepted(
folly::NetworkSocket fd, folly::NetworkSocket fd,
const SocketAddress& /* clientAddr */) noexcept override { const SocketAddress& clientAddr) noexcept override {
if (socket_) { if (socket_) {
socket_->detachEventBase(); socket_->detachEventBase();
} }
...@@ -71,7 +71,13 @@ class SSLServerAcceptCallbackBase : public AsyncServerSocket::AcceptCallback { ...@@ -71,7 +71,13 @@ class SSLServerAcceptCallbackBase : public AsyncServerSocket::AcceptCallback {
try { try {
// Create a AsyncSSLSocket object with the fd. The socket should be // Create a AsyncSSLSocket object with the fd. The socket should be
// added to the event base and in the state of accepting SSL connection. // added to the event base and in the state of accepting SSL connection.
socket_ = AsyncSSLSocket::newSocket(ctx_, base_, fd); socket_ = AsyncSSLSocket::newSocket(
ctx_,
base_,
fd,
/*server=*/true,
/*deferSecurityNegotiation=*/false,
&clientAddr);
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG(ERROR) << "Exception %s caught while creating a AsyncSSLSocket " LOG(ERROR) << "Exception %s caught while creating a AsyncSSLSocket "
"object with socket " "object with socket "
......
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