Fix ssl timeouts during TFO
authorSubodh Iyengar <subodh@fb.com>
Wed, 17 Aug 2016 04:52:12 +0000 (21:52 -0700)
committerFacebook Github Bot 2 <facebook-github-bot-2-bot@fb.com>
Wed, 17 Aug 2016 04:53:42 +0000 (21:53 -0700)
Summary:
Handle handshake timestamps and timeouts when TFO
is used.

If we fallback from TFO to connects, we should unset
the handshake timeout.

When we restart the handshake, we should reset the handshake
timeout and also reset the timestamps of the connection.

Reviewed By: yfeldblum, djwatson

Differential Revision: D3708660

fbshipit-source-id: 960030ca14d9f1cc8cb83059491ceffe6ba8f2ed

folly/io/async/AsyncSSLSocket.cpp
folly/io/async/AsyncSSLSocket.h

index 721fb29510f1f827eb25b5c16928e1a84732ff48..04ca1516d35877c9dc506892427b20423fab5aab 100644 (file)
@@ -716,10 +716,6 @@ void AsyncSSLSocket::sslConn(HandshakeCB* callback, uint64_t timeout,
     return invalidState(callback);
   }
 
-  handshakeStartTime_ = std::chrono::steady_clock::now();
-  // Make end time at least >= start time.
-  handshakeEndTime_ = handshakeStartTime_;
-
   sslState_ = STATE_CONNECTING;
   handshakeCallback_ = callback;
 
@@ -756,10 +752,19 @@ void AsyncSSLSocket::sslConn(HandshakeCB* callback, uint64_t timeout,
 
   SSL_set_ex_data(ssl_, getSSLExDataIndex(), this);
 
-  if (timeout > 0) {
-    handshakeTimeout_.scheduleTimeout(timeout);
-  }
+  handshakeConnectTimeout_ = timeout;
+  startSSLConnect();
+}
 
+// This could be called multiple times, during normal ssl connections
+// and after TFO fallback.
+void AsyncSSLSocket::startSSLConnect() {
+  handshakeStartTime_ = std::chrono::steady_clock::now();
+  // Make end time at least >= start time.
+  handshakeEndTime_ = handshakeStartTime_;
+  if (handshakeConnectTimeout_ > 0) {
+    handshakeTimeout_.scheduleTimeout(handshakeConnectTimeout_);
+  }
   handleConnect();
 }
 
@@ -1094,12 +1099,20 @@ AsyncSSLSocket::handleConnect() noexcept {
       sslState_ == STATE_CONNECTING);
   assert(ssl_);
 
+  auto originalState = state_;
   int ret = SSL_connect(ssl_);
   if (ret <= 0) {
     int sslError;
     unsigned long errError;
     int errnoCopy = errno;
     if (willBlock(ret, &sslError, &errError)) {
+      // We fell back to connecting state due to TFO
+      if (state_ == StateEnum::CONNECTING) {
+        DCHECK_EQ(StateEnum::FAST_OPEN, originalState);
+        if (handshakeTimeout_.isScheduled()) {
+          handshakeTimeout_.cancelTimeout();
+        }
+      }
       return;
     } else {
       sslState_ = STATE_ERROR;
@@ -1147,9 +1160,8 @@ AsyncSSLSocket::handleConnect() noexcept {
 void AsyncSSLSocket::invokeConnectSuccess() {
   if (sslState_ == SSLStateEnum::STATE_CONNECTING) {
     // If we failed TFO, we'd fall back to trying to connect the socket,
-    // when we succeed we should handle the writes that caused us to start
-    // TFO.
-    handleWrite();
+    // to setup things like timeouts.
+    startSSLConnect();
   }
   AsyncSocket::invokeConnectSuccess();
 }
index 0efd73bdc9f9b31b8742cef54a95fdc911c90267..296641db3941a754c45b8e7b605365643b6e0a35 100644 (file)
@@ -815,6 +815,8 @@ class AsyncSSLSocket : public virtual AsyncSocket {
 
   void cacheLocalPeerAddr();
 
+  void startSSLConnect();
+
   static void sslInfoCallback(const SSL *ssl, int type, int val);
 
   // Whether we've applied the TCP_CORK option to the socket
@@ -875,6 +877,7 @@ class AsyncSSLSocket : public virtual AsyncSocket {
   // Time taken to complete the ssl handshake.
   std::chrono::steady_clock::time_point handshakeStartTime_;
   std::chrono::steady_clock::time_point handshakeEndTime_;
+  uint64_t handshakeConnectTimeout_{0};
 };
 
 } // namespace