Set the appropriate AsyncSocketExceptionType from SSLException
authorNeel Goyal <ngoyal@fb.com>
Mon, 2 May 2016 16:30:18 +0000 (09:30 -0700)
committerFacebook Github Bot 7 <facebook-github-bot-7-bot@fb.com>
Mon, 2 May 2016 16:35:33 +0000 (09:35 -0700)
Summary:
We should use the appropriate AsyncSocketExceptionType when firing SSLExceptions.  This derives the type from the constructor args, and introduces a `NETWORK_ERROR` exception type.  Open to suggestions on reusing something there.

Additionally, rename getType() to getSSLError() to prevent hiding the AsyncSocketException::getType.

Reviewed By: siyengar

Differential Revision: D3241204

fb-gh-sync-id: de631dfb3554177d5bd561f4b91e767c882767d3
fbshipit-source-id: de631dfb3554177d5bd561f4b91e767c882767d3

folly/io/async/AsyncSocketException.h
folly/io/async/ssl/SSLErrors.cpp
folly/io/async/ssl/SSLErrors.h
folly/io/async/test/AsyncSocketExceptionTest.cpp

index 3113197c4b207b94208c1c3500ea958883bb81fb..85054d867ef192c7bd07253b405786769e996fc6 100644 (file)
@@ -23,21 +23,22 @@ namespace folly {
 
 class AsyncSocketException : public std::runtime_error {
  public:
 
 class AsyncSocketException : public std::runtime_error {
  public:
-  enum AsyncSocketExceptionType
-  { UNKNOWN = 0
-  , NOT_OPEN = 1
-  , ALREADY_OPEN = 2
-  , TIMED_OUT = 3
-  , END_OF_FILE = 4
-  , INTERRUPTED = 5
-  , BAD_ARGS = 6
-  , CORRUPTED_DATA = 7
-  , INTERNAL_ERROR = 8
-  , NOT_SUPPORTED = 9
-  , INVALID_STATE = 10
-  , SSL_ERROR = 12
-  , COULD_NOT_BIND = 13
-  , SASL_HANDSHAKE_TIMEOUT = 14
+  enum AsyncSocketExceptionType {
+    UNKNOWN = 0,
+    NOT_OPEN = 1,
+    ALREADY_OPEN = 2,
+    TIMED_OUT = 3,
+    END_OF_FILE = 4,
+    INTERRUPTED = 5,
+    BAD_ARGS = 6,
+    CORRUPTED_DATA = 7,
+    INTERNAL_ERROR = 8,
+    NOT_SUPPORTED = 9,
+    INVALID_STATE = 10,
+    SSL_ERROR = 12,
+    COULD_NOT_BIND = 13,
+    SASL_HANDSHAKE_TIMEOUT = 14,
+    NETWORK_ERROR = 15
   };
 
   AsyncSocketException(AsyncSocketExceptionType type,
   };
 
   AsyncSocketException(AsyncSocketExceptionType type,
index 7bbb78c3d2d3176b100c0dd2b1d7c19c1ca66f96..c34e8bbd7782695b9ea94ce2bb3d8b212969534c 100644 (file)
@@ -68,6 +68,36 @@ const StringPiece getSSLErrorString(SSLError error) {
   }
   return ret;
 }
   }
   return ret;
 }
+
+AsyncSocketException::AsyncSocketExceptionType exTypefromSSLErrInfo(
+    int sslErr,
+    unsigned long errError,
+    int sslOperationReturnValue) {
+  if (sslErr == SSL_ERROR_ZERO_RETURN) {
+    return AsyncSocketException::END_OF_FILE;
+  } else if (sslErr == SSL_ERROR_SYSCALL) {
+    if (errError == 0 && sslOperationReturnValue == 0) {
+      return AsyncSocketException::END_OF_FILE;
+    } else {
+      return AsyncSocketException::NETWORK_ERROR;
+    }
+  } else {
+    // Assume an actual SSL error
+    return AsyncSocketException::SSL_ERROR;
+  }
+}
+
+AsyncSocketException::AsyncSocketExceptionType exTypefromSSLErr(SSLError err) {
+  switch (err) {
+    case SSLError::EOF_ERROR:
+      return AsyncSocketException::END_OF_FILE;
+    case SSLError::NETWORK_ERROR:
+      return AsyncSocketException::NETWORK_ERROR;
+    default:
+      // everything else is a SSL_ERROR
+      return AsyncSocketException::SSL_ERROR;
+  }
+}
 }
 
 namespace folly {
 }
 
 namespace folly {
@@ -78,7 +108,7 @@ SSLException::SSLException(
     int sslOperationReturnValue,
     int errno_copy)
     : AsyncSocketException(
     int sslOperationReturnValue,
     int errno_copy)
     : AsyncSocketException(
-          AsyncSocketException::SSL_ERROR,
+          exTypefromSSLErrInfo(sslErr, errError, sslOperationReturnValue),
           decodeOpenSSLError(sslErr, errError, sslOperationReturnValue),
           sslErr == SSL_ERROR_SYSCALL ? errno_copy : 0) {
   if (sslErr == SSL_ERROR_ZERO_RETURN) {
           decodeOpenSSLError(sslErr, errError, sslOperationReturnValue),
           sslErr == SSL_ERROR_SYSCALL ? errno_copy : 0) {
   if (sslErr == SSL_ERROR_ZERO_RETURN) {
@@ -93,7 +123,7 @@ SSLException::SSLException(
 
 SSLException::SSLException(SSLError error)
     : AsyncSocketException(
 
 SSLException::SSLException(SSLError error)
     : AsyncSocketException(
-          AsyncSocketException::SSL_ERROR,
+          exTypefromSSLErr(error),
           getSSLErrorString(error).str(),
           0),
       sslError(error) {}
           getSSLErrorString(error).str(),
           0),
       sslError(error) {}
index 5bd37fde3af3eebdbaf30ee6b86df78bc32e45ef..ad7475b418cc240760dd9d20e0a220b4d5f290d1 100644 (file)
@@ -39,7 +39,7 @@ class SSLException : public folly::AsyncSocketException {
 
   explicit SSLException(SSLError error);
 
 
   explicit SSLException(SSLError error);
 
-  SSLError getType() const {
+  SSLError getSSLError() const {
     return sslError;
   }
 
     return sslError;
   }
 
index 662a3737cae10023a1cfaebcb4f7c390700b2649..50c665990ec889fd9248e0f31c3268ddbeb51555 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <gtest/gtest.h>
+#include <array>
+
 #include <folly/io/async/AsyncSocketException.h>
 #include <folly/io/async/AsyncSocketException.h>
+#include <folly/io/async/ssl/SSLErrors.h>
+#include <gtest/gtest.h>
+#include <openssl/ssl.h>
 
 using namespace testing;
 
 
 using namespace testing;
 
@@ -45,4 +49,47 @@ TEST(AsyncSocketException, SimpleTest) {
       std::string(ex2.what()));
 }
 
       std::string(ex2.what()));
 }
 
+TEST(AsyncSocketException, SSLExceptionType) {
+  {
+    SSLException eof(SSL_ERROR_ZERO_RETURN, 0, 0, 0);
+    EXPECT_EQ(eof.getType(), AsyncSocketException::END_OF_FILE);
+
+    SSLException netEof(SSL_ERROR_SYSCALL, 0, 0, 0);
+    EXPECT_EQ(netEof.getType(), AsyncSocketException::END_OF_FILE);
+
+    SSLException netOther(SSL_ERROR_SYSCALL, 0, 1, 0);
+    EXPECT_EQ(netOther.getType(), AsyncSocketException::NETWORK_ERROR);
+
+    std::array<int, 6> sslErrs{{SSL_ERROR_SSL,
+                                SSL_ERROR_WANT_READ,
+                                SSL_ERROR_WANT_WRITE,
+                                SSL_ERROR_WANT_X509_LOOKUP,
+                                SSL_ERROR_WANT_CONNECT,
+                                SSL_ERROR_WANT_ACCEPT}};
+
+    for (auto& e : sslErrs) {
+      SSLException sslEx(e, 0, 0, 0);
+      EXPECT_EQ(sslEx.getType(), AsyncSocketException::SSL_ERROR);
+    }
+  }
+
+  {
+    SSLException eof(SSLError::EOF_ERROR);
+    EXPECT_EQ(eof.getType(), AsyncSocketException::END_OF_FILE);
+
+    SSLException net(SSLError::NETWORK_ERROR);
+    EXPECT_EQ(net.getType(), AsyncSocketException::NETWORK_ERROR);
+
+    std::array<SSLError, 4> errs{{SSLError::CLIENT_RENEGOTIATION,
+                                  SSLError::INVALID_RENEGOTIATION,
+                                  SSLError::EARLY_WRITE,
+                                  SSLError::SSL_ERROR}};
+
+    for (auto& e : errs) {
+      SSLException sslEx(e);
+      EXPECT_EQ(sslEx.getType(), AsyncSocketException::SSL_ERROR);
+    }
+  }
+}
+
 } // namespace folly
 } // namespace folly