Add mechanizm for caching local and peer addresses in AsyncSSLSocket.
authorMaxim Georgiev <maxgeorg@fb.com>
Wed, 27 Jan 2016 21:08:50 +0000 (13:08 -0800)
committerfacebook-github-bot-1 <folly-bot@fb.com>
Wed, 27 Jan 2016 21:20:23 +0000 (13:20 -0800)
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
folly/io/async/AsyncSSLSocket.h
folly/io/async/AsyncSocket.cpp
folly/io/async/AsyncSocket.h

index e72894cd9ac9bae46f0ad59e65713da6f8085e22..432f9889e1345bb7743eb734cb609729010e3b9a 100644 (file)
@@ -501,6 +501,13 @@ void AsyncSSLSocket::sslAccept(HandshakeCB* callback, uint32_t timeout,
       handshakeCallback_ != nullptr) {
     return invalidState(callback);
   }
       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_;
   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,
 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());
 
   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
   verifyPeer_ = verifyPeer;
 
   // Make sure we're in the uninitialized state
index 33a1d79e68a559a9679a65399e954af2709bd285..9dbcf2efa4cbdd8275c0ce35411e53d11cad8a2c 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <arpa/inet.h>
 #include <iomanip>
 
 #include <arpa/inet.h>
 #include <iomanip>
-#include <openssl/ssl.h>
 
 #include <folly/Optional.h>
 #include <folly/String.h>
 
 #include <folly/Optional.h>
 #include <folly/String.h>
@@ -749,6 +748,15 @@ class AsyncSSLSocket : public virtual AsyncSocket {
     return X509_UniquePtr(cert);
   }
 
     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();
  private:
 
   void init();
@@ -821,6 +829,8 @@ class AsyncSSLSocket : public virtual AsyncSocket {
   void invokeHandshakeErr(const AsyncSocketException& ex);
   void invokeHandshakeCB();
 
   void invokeHandshakeErr(const AsyncSocketException& ex);
   void invokeHandshakeCB();
 
+  void cacheLocalPeerAddr();
+
   static void sslInfoCallback(const SSL *ssl, int type, int val);
 
   // SSL related members.
   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};
   static int sslVerifyCallback(int preverifyOk, X509_STORE_CTX* ctx);
 
   bool parseClientHello_{false};
+  bool cacheAddrOnFailure_{false};
   std::unique_ptr<ClientHelloInfo> clientHelloInfo_;
 
   // Time taken to complete the ssl handshake.
   std::unique_ptr<ClientHelloInfo> clientHelloInfo_;
 
   // Time taken to complete the ssl handshake.
index fa475faa7ba85de7ea7caf7f4efbbc704f1a2e7b..2db3b2962b0bf7a39d82a80f2ea07c961d0c1126 100644 (file)
@@ -1066,7 +1066,10 @@ bool AsyncSocket::isDetachable() const {
 }
 
 void AsyncSocket::getLocalAddress(folly::SocketAddress* address) 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 {
 }
 
 void AsyncSocket::getPeerAddress(folly::SocketAddress* address) const {
index ceaaaf94286784a4ac4b8b072219141f5b108d15..aa6424be9cdf0e274f3ea30fd4662c8924400452 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
 
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <glog/logging.h>
 #include <folly/SocketAddress.h>
 #include <folly/io/ShutdownSocketSet.h>
 #include <folly/io/IOBuf.h>
 #include <folly/SocketAddress.h>
 #include <folly/io/ShutdownSocketSet.h>
 #include <folly/io/IOBuf.h>
@@ -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
   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
   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
   WriteTimeout writeTimeout_;           ///< A timeout for connect and write
   IoHandler ioHandler_;                 ///< A EventHandler to monitor the fd
   ImmediateReadCB immediateReadHandler_; ///< LoopCallback for checking read