@@ -81,6 +81,7 @@ module Simplex.Messaging.Protocol
8181 CommandError (.. ),
8282 ProxyError (.. ),
8383 BrokerErrorType (.. ),
84+ NetworkError (.. ),
8485 BlockingInfo (.. ),
8586 BlockingReason (.. ),
8687 RawTransmission ,
@@ -168,6 +169,7 @@ module Simplex.Messaging.Protocol
168169 noMsgFlags ,
169170 messageId ,
170171 messageTs ,
172+ toNetworkError ,
171173
172174 -- * Parse and serialize
173175 ProtocolMsgTag (.. ),
@@ -212,7 +214,7 @@ module Simplex.Messaging.Protocol
212214where
213215
214216import Control.Applicative (optional , (<|>) )
215- import Control.Exception (Exception )
217+ import Control.Exception (Exception , SomeException , displayException , fromException )
216218import Control.Monad.Except
217219import Data.Aeson (FromJSON (.. ), ToJSON (.. ))
218220import qualified Data.Aeson.TH as J
@@ -241,6 +243,7 @@ import GHC.TypeLits (ErrorMessage (..), TypeError, type (+))
241243import qualified GHC.TypeLits as TE
242244import qualified GHC.TypeLits as Type
243245import Network.Socket (ServiceName )
246+ import qualified Network.TLS as TLS
244247import Simplex.Messaging.Agent.Store.DB (Binary (.. ), FromField (.. ), ToField (.. ))
245248import qualified Simplex.Messaging.Crypto as C
246249import Simplex.Messaging.Encoding
@@ -1555,7 +1558,7 @@ data BrokerErrorType
15551558 | -- | unexpected response
15561559 UNEXPECTED { respErr :: String }
15571560 | -- | network error
1558- NETWORK
1561+ NETWORK { networkError :: NetworkError }
15591562 | -- | no compatible server host (e.g. onion when public is required, or vice versa)
15601563 HOST
15611564 | -- | service unavailable client-side - used in agent errors
@@ -1566,6 +1569,24 @@ data BrokerErrorType
15661569 TIMEOUT
15671570 deriving (Eq , Read , Show , Exception )
15681571
1572+ data NetworkError
1573+ = NEConnectError { connectError :: String }
1574+ | NETLSError { tlsError :: String }
1575+ | NEUnknownCAError
1576+ | NEFailedError
1577+ | NETimeoutError
1578+ | NESubscribeError { subscribeError :: String }
1579+ deriving (Eq , Read , Show )
1580+
1581+ toNetworkError :: SomeException -> NetworkError
1582+ toNetworkError e = maybe (NEConnectError err) fromTLSError (fromException e)
1583+ where
1584+ err = displayException e
1585+ fromTLSError :: TLS. TLSException -> NetworkError
1586+ fromTLSError = \ case
1587+ TLS. HandshakeFailed (TLS. Error_Protocol _ TLS. UnknownCa ) -> NEUnknownCAError
1588+ _ -> NETLSError err
1589+
15691590data BlockingInfo = BlockingInfo
15701591 { reason :: BlockingReason
15711592 }
@@ -2001,7 +2022,7 @@ instance Encoding BrokerErrorType where
20012022 RESPONSE e -> " RESPONSE " <> smpEncode e
20022023 UNEXPECTED e -> " UNEXPECTED " <> smpEncode e
20032024 TRANSPORT e -> " TRANSPORT " <> smpEncode e
2004- NETWORK -> " NETWORK"
2025+ NETWORK e -> " NETWORK" -- TODO once all upgrade: "NETWORK " <> smpEncode e
20052026 TIMEOUT -> " TIMEOUT"
20062027 HOST -> " HOST"
20072028 NO_SERVICE -> " NO_SERVICE"
@@ -2010,7 +2031,7 @@ instance Encoding BrokerErrorType where
20102031 " RESPONSE" -> RESPONSE <$> _smpP
20112032 " UNEXPECTED" -> UNEXPECTED <$> _smpP
20122033 " TRANSPORT" -> TRANSPORT <$> _smpP
2013- " NETWORK" -> pure NETWORK
2034+ " NETWORK" -> NETWORK <$> (_smpP <|> pure NEFailedError )
20142035 " TIMEOUT" -> pure TIMEOUT
20152036 " HOST" -> pure HOST
20162037 " NO_SERVICE" -> pure NO_SERVICE
@@ -2021,7 +2042,7 @@ instance StrEncoding BrokerErrorType where
20212042 RESPONSE e -> " RESPONSE " <> encodeUtf8 (T. pack e)
20222043 UNEXPECTED e -> " UNEXPECTED " <> encodeUtf8 (T. pack e)
20232044 TRANSPORT e -> " TRANSPORT " <> smpEncode e
2024- NETWORK -> " NETWORK"
2045+ NETWORK e -> " NETWORK" -- TODO once all upgrade: "NETWORK " <> strEncode e
20252046 TIMEOUT -> " TIMEOUT"
20262047 HOST -> " HOST"
20272048 NO_SERVICE -> " NO_SERVICE"
@@ -2030,13 +2051,50 @@ instance StrEncoding BrokerErrorType where
20302051 " RESPONSE" -> RESPONSE <$> _textP
20312052 " UNEXPECTED" -> UNEXPECTED <$> _textP
20322053 " TRANSPORT" -> TRANSPORT <$> _smpP
2033- " NETWORK" -> pure NETWORK
2054+ " NETWORK" -> NETWORK <$> (_strP <|> pure NEFailedError )
20342055 " TIMEOUT" -> pure TIMEOUT
20352056 " HOST" -> pure HOST
20362057 " NO_SERVICE" -> pure NO_SERVICE
20372058 _ -> fail " bad BrokerErrorType"
2038- where
2039- _textP = A. space *> (T. unpack . safeDecodeUtf8 <$> A. takeByteString)
2059+
2060+ instance Encoding NetworkError where
2061+ smpEncode = \ case
2062+ NEConnectError e -> " CONNECT " <> smpEncode e
2063+ NETLSError e -> " TLS " <> smpEncode e
2064+ NEUnknownCAError -> " UNKNOWNCA"
2065+ NEFailedError -> " FAILED"
2066+ NETimeoutError -> " TIMEOUT"
2067+ NESubscribeError e -> " SUBSCRIBE " <> smpEncode e
2068+ smpP =
2069+ A. takeTill (== ' ' ) >>= \ case
2070+ " CONNECT" -> NEConnectError <$> _smpP
2071+ " TLS" -> NETLSError <$> _smpP
2072+ " UNKNOWNCA" -> pure NEUnknownCAError
2073+ " FAILED" -> pure NEFailedError
2074+ " TIMEOUT" -> pure NETimeoutError
2075+ " SUBSCRIBE" -> NESubscribeError <$> _smpP
2076+ _ -> fail " bad NetworkError"
2077+
2078+ instance StrEncoding NetworkError where
2079+ strEncode = \ case
2080+ NEConnectError e -> " CONNECT " <> encodeUtf8 (T. pack e)
2081+ NETLSError e -> " TLS " <> encodeUtf8 (T. pack e)
2082+ NEUnknownCAError -> " UNKNOWNCA"
2083+ NEFailedError -> " FAILED"
2084+ NETimeoutError -> " TIMEOUT"
2085+ NESubscribeError e -> " SUBSCRIBE " <> encodeUtf8 (T. pack e)
2086+ strP =
2087+ A. takeTill (== ' ' ) >>= \ case
2088+ " CONNECT" -> NEConnectError <$> _textP
2089+ " TLS" -> NETLSError <$> _textP
2090+ " UNKNOWNCA" -> pure NEUnknownCAError
2091+ " FAILED" -> pure NEFailedError
2092+ " TIMEOUT" -> pure NETimeoutError
2093+ " SUBSCRIBE" -> NESubscribeError <$> _textP
2094+ _ -> fail " bad NetworkError"
2095+
2096+ _textP :: Parser String
2097+ _textP = A. space *> (T. unpack . safeDecodeUtf8 <$> A. takeByteString)
20402098
20412099-- | Send signed SMP transmission to TCP transport.
20422100tPut :: Transport c => THandle v c p -> NonEmpty (Either TransportError SentRawTransmission ) -> IO [Either TransportError () ]
@@ -2200,6 +2258,8 @@ $(J.deriveJSON defaultJSON ''MsgFlags)
22002258
22012259$ (J. deriveJSON (sumTypeJSON id ) ''CommandError)
22022260
2261+ $ (J. deriveJSON (sumTypeJSON $ dropPrefix " NE" ) ''NetworkError)
2262+
22032263$ (J. deriveJSON (sumTypeJSON id ) ''BrokerErrorType)
22042264
22052265$ (J. deriveJSON defaultJSON ''BlockingInfo)
0 commit comments