From 23e1c2d30b3314f37e0642afb3a84aff7e6b93a0 Mon Sep 17 00:00:00 2001 From: Maxim Georgiev Date: Wed, 27 Jan 2016 13:08:50 -0800 Subject: [PATCH] Add mechanizm for caching local and peer addresses in AsyncSSLSocket. Summary: This change adds a flag to AsyncSSLSocket which forces the socket to cache local and remote addresses right after TCP connection is established. Cached address values will be available after the connection is closed. Caching addresses can be halpful in SSL handshake failure investigations. Reviewed By: yfeldblum Differential Revision: D2863274 fb-gh-sync-id: d7b415292988c2fb187a80422e8ccbf8ba8ab0e3 --- folly/io/async/AsyncSSLSocket.cpp | 26 ++++++++++++++++++++++++++ folly/io/async/AsyncSSLSocket.h | 13 ++++++++++++- folly/io/async/AsyncSocket.cpp | 5 ++++- folly/io/async/AsyncSocket.h | 8 ++++---- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/folly/io/async/AsyncSSLSocket.cpp b/folly/io/async/AsyncSSLSocket.cpp index e72894cd..432f9889 100644 --- a/folly/io/async/AsyncSSLSocket.cpp +++ b/folly/io/async/AsyncSSLSocket.cpp @@ -501,6 +501,13 @@ void AsyncSSLSocket::sslAccept(HandshakeCB* callback, uint32_t timeout, handshakeCallback_ != nullptr) { return invalidState(callback); } + + // Cache local and remote socket addresses to keep them available + // after socket file descriptor is closed. + if (cacheAddrOnFailure_ && -1 != getFd()) { + cacheLocalPeerAddr(); + } + handshakeStartTime_ = std::chrono::steady_clock::now(); // Make end time at least >= start time. handshakeEndTime_ = handshakeStartTime_; @@ -665,6 +672,19 @@ void AsyncSSLSocket::invokeHandshakeCB() { } } +void AsyncSSLSocket::cacheLocalPeerAddr() { + SocketAddress address; + try { + getLocalAddress(&address); + getPeerAddress(&address); + } catch (const std::system_error& e) { + // The handle can be still valid while the connection is already closed. + if (e.code() != std::error_code(ENOTCONN, std::system_category())) { + throw; + } + } +} + void AsyncSSLSocket::connect(ConnectCallback* callback, const folly::SocketAddress& address, int timeout, @@ -700,6 +720,12 @@ void AsyncSSLSocket::sslConn(HandshakeCB* callback, uint64_t timeout, DestructorGuard dg(this); assert(eventBase_->isInEventBaseThread()); + // Cache local and remote socket addresses to keep them available + // after socket file descriptor is closed. + if (cacheAddrOnFailure_ && -1 != getFd()) { + cacheLocalPeerAddr(); + } + verifyPeer_ = verifyPeer; // Make sure we're in the uninitialized state diff --git a/folly/io/async/AsyncSSLSocket.h b/folly/io/async/AsyncSSLSocket.h index 33a1d79e..9dbcf2ef 100644 --- a/folly/io/async/AsyncSSLSocket.h +++ b/folly/io/async/AsyncSSLSocket.h @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -749,6 +748,15 @@ class AsyncSSLSocket : public virtual AsyncSocket { return X509_UniquePtr(cert); } + /** + * Force AsyncSSLSocket object to cache local and peer socket addresses. + * If called with "true" before connect() this function forces full local + * and remote socket addresses to be cached in the socket object and available + * through getLocalAddress()/getPeerAddress() methods even after the socket is + * closed. + */ + void forceCacheAddrOnFailure(bool force) { cacheAddrOnFailure_ = force; } + private: void init(); @@ -821,6 +829,8 @@ class AsyncSSLSocket : public virtual AsyncSocket { void invokeHandshakeErr(const AsyncSocketException& ex); void invokeHandshakeCB(); + void cacheLocalPeerAddr(); + static void sslInfoCallback(const SSL *ssl, int type, int val); // SSL related members. @@ -863,6 +873,7 @@ class AsyncSSLSocket : public virtual AsyncSocket { static int sslVerifyCallback(int preverifyOk, X509_STORE_CTX* ctx); bool parseClientHello_{false}; + bool cacheAddrOnFailure_{false}; std::unique_ptr clientHelloInfo_; // Time taken to complete the ssl handshake. diff --git a/folly/io/async/AsyncSocket.cpp b/folly/io/async/AsyncSocket.cpp index fa475faa..2db3b296 100644 --- a/folly/io/async/AsyncSocket.cpp +++ b/folly/io/async/AsyncSocket.cpp @@ -1066,7 +1066,10 @@ bool AsyncSocket::isDetachable() const { } void AsyncSocket::getLocalAddress(folly::SocketAddress* address) const { - address->setFromLocalAddress(fd_); + if (!localAddr_.isInitialized()) { + localAddr_.setFromLocalAddress(fd_); + } + *address = localAddr_; } void AsyncSocket::getPeerAddress(folly::SocketAddress* address) const { diff --git a/folly/io/async/AsyncSocket.h b/folly/io/async/AsyncSocket.h index ceaaaf94..aa6424be 100644 --- a/folly/io/async/AsyncSocket.h +++ b/folly/io/async/AsyncSocket.h @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -786,11 +785,12 @@ class AsyncSocket : virtual public AsyncTransportWrapper { uint8_t shutdownFlags_; ///< Shutdown state (ShutdownFlags) uint16_t eventFlags_; ///< EventBase::HandlerFlags settings int fd_; ///< The socket file descriptor - mutable - folly::SocketAddress addr_; ///< The address we tried to connect to + mutable folly::SocketAddress addr_; ///< The address we tried to connect to + mutable folly::SocketAddress localAddr_; + ///< The address we are connecting from uint32_t sendTimeout_; ///< The send timeout, in milliseconds uint16_t maxReadsPerEvent_; ///< Max reads per event loop iteration - EventBase* eventBase_; ///< The EventBase + EventBase* eventBase_; ///< The EventBase WriteTimeout writeTimeout_; ///< A timeout for connect and write IoHandler ioHandler_; ///< A EventHandler to monitor the fd ImmediateReadCB immediateReadHandler_; ///< LoopCallback for checking read -- 2.34.1