Skip to content

Commit

Permalink
CBL-1954 Use new NetworkErrorCode enum values (#1308)
Browse files Browse the repository at this point in the history
* Use new NetworkErrorCode enum
* Replace existing Posix error code with newly defined network error codes.
* Remove PosixStatus class.
* Update LiteCore to Commit: b3863874f33cd20895b88f3431dcf81538c9b25b [b386387]
* Fix TestBusyPort 
* Add the new network error codes in CouchbaseLiteError
Add the new network error codes in CouchbaseLiteError enum with the other public network error codes so that the user can actually make sense of them in the replicator callback.
  • Loading branch information
Sandychuang8 committed Jul 31, 2021
1 parent 00941b7 commit d6778e9
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 1,413 deletions.
64 changes: 47 additions & 17 deletions src/Couchbase.Lite.Shared/Support/Status.cs
Expand Up @@ -69,37 +69,66 @@ public static unsafe void ConvertNetworkError(Exception e, C4Error* outError)
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.UnknownHost;
break;
case SocketError.HostUnreachable:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.DNSFailure;
break;
case SocketError.TimedOut:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.Timeout;
break;
case SocketError.ConnectionAborted:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.ConnectionAborted;
break;
case SocketError.ConnectionReset:
case SocketError.Shutdown:
message = se.Message;
c4err.domain = C4ErrorDomain.POSIXDomain;
c4err.code = PosixBase.GetCode(nameof(PosixWindows.ECONNRESET));
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.ConnectionReset;
break;
case SocketError.NetworkUnreachable:
message = se.Message;
c4err.domain = C4ErrorDomain.POSIXDomain;
c4err.code = PosixBase.GetCode(nameof(PosixWindows.ENETRESET));
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.NetworkUnreachable;
break;
case SocketError.ConnectionRefused:
message = se.Message;
c4err.domain = C4ErrorDomain.POSIXDomain;
c4err.code = PosixBase.GetCode(nameof(PosixWindows.ECONNREFUSED));
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.ConnectionRefused;
break;
case SocketError.NetworkDown:
message = se.Message;
c4err.domain = C4ErrorDomain.POSIXDomain;
c4err.code = PosixBase.GetCode(nameof(PosixWindows.ENETDOWN));
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.NetworkDown;
break;
case SocketError.AddressNotAvailable:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.AddressNotAvailable;
break;
case SocketError.NetworkReset:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.NetworkReset;
break;
case SocketError.NotConnected:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.NotConnected;
break;
case SocketError.HostDown:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.HostDown;
break;
case SocketError.HostUnreachable:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.HostUnreachable;
break;
case SocketError.SocketError:
message = se.Message;
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.Unknown;
break;
}

Expand All @@ -110,16 +139,17 @@ public static unsafe void ConvertNetworkError(Exception e, C4Error* outError)
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int) C4NetworkErrorCode.TLSHandshakeFailed;
}
#if __IOS__

#if __IOS__
if (ie.Message == "Connection closed.") {
//AppleTlsContext.cs
//case SslStatus.ClosedAbort:
// throw new IOException("Connection closed.");
message = ie.Message;
c4err.domain = C4ErrorDomain.POSIXDomain;
c4err.code = PosixBase.GetCode(nameof(PosixWindows.ECONNRESET));
c4err.domain = C4ErrorDomain.NetworkDomain;
c4err.code = (int)C4NetworkErrorCode.ConnectionReset;
}
#endif
#endif
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Couchbase.Lite.Shared/Sync/WebSocketWrapper.cs
Expand Up @@ -518,7 +518,7 @@ private async void PerformRead()
if (received == 0) {
if (zeroByteCount++ >= 10) {
WriteLog.To.Sync.I(Tag, "Failed to read from stream too many times, signaling closed...");
DidClose(new CouchbasePosixException(PosixBase.GetCode(nameof(PosixWindows.ECONNRESET))));
DidClose(new CouchbaseNetworkException(C4NetworkErrorCode.ConnectionReset));
return;
}

Expand Down
32 changes: 16 additions & 16 deletions src/Couchbase.Lite.Tests.Shared/CSharpTest.cs
Expand Up @@ -493,10 +493,10 @@ public unsafe void TestConvertError()
var errors = new[]
{
new C4Error(C4NetworkErrorCode.UnknownHost),
new C4Error(C4NetworkErrorCode.DNSFailure),
new C4Error(C4NetworkErrorCode.HostUnreachable),
new C4Error(C4NetworkErrorCode.Timeout),
new C4Error(C4ErrorDomain.POSIXDomain, PosixBase.GetCode(nameof(PosixWindows.ECONNRESET))),
new C4Error(C4ErrorDomain.POSIXDomain, PosixBase.GetCode(nameof(PosixWindows.ECONNREFUSED))),
new C4Error(C4ErrorDomain.NetworkDomain, (int)C4NetworkErrorCode.ConnectionAborted),
new C4Error(C4ErrorDomain.NetworkDomain, (int)C4NetworkErrorCode.ConnectionRefused),
new C4Error(C4ErrorDomain.LiteCoreDomain, (int)C4ErrorCode.UnexpectedError)
};

Expand Down Expand Up @@ -562,16 +562,16 @@ public async Task TestSerialQueue()
[Fact]
public void TestTransientAndNetworkDependent()
{
foreach (var err in new[]
{ "ENETRESET", "ECONNABORTED", "ECONNRESET", "ETIMEDOUT", "ECONNREFUSED" }) {
var code = PosixBase.GetCode(err);
Native.c4error_mayBeTransient(new C4Error(C4ErrorDomain.POSIXDomain, code)).Should().BeTrue($"because {err} should be transient");
foreach (var err in new C4NetworkErrorCode[]
{ C4NetworkErrorCode.NetworkReset, C4NetworkErrorCode.ConnectionAborted, C4NetworkErrorCode.ConnectionReset, C4NetworkErrorCode.Timeout, C4NetworkErrorCode.ConnectionRefused }) {
var code = (int)err;
Native.c4error_mayBeTransient(new C4Error(C4ErrorDomain.NetworkDomain, code)).Should().BeTrue($"because {err} should be transient");
}

foreach (var err in new[]
{ "ENETDOWN", "ENETUNREACH", "ENOTCONN", "ETIMEDOUT", "EHOSTUNREACH", "EADDRNOTAVAIL" }) {
var code = PosixBase.GetCode(err);
Native.c4error_mayBeNetworkDependent(new C4Error(C4ErrorDomain.POSIXDomain, code)).Should().BeTrue($"because {err} should be network dependent");
foreach (var err in new C4NetworkErrorCode[]
{ C4NetworkErrorCode.NetworkDown, C4NetworkErrorCode.NetworkUnreachable, C4NetworkErrorCode.NotConnected, C4NetworkErrorCode.Timeout, C4NetworkErrorCode.HostUnreachable, C4NetworkErrorCode.AddressNotAvailable }) {
var code = (int)err;
Native.c4error_mayBeNetworkDependent(new C4Error(C4ErrorDomain.NetworkDomain, code)).Should().BeTrue($"because {err} should be network dependent");
}
}

Expand Down Expand Up @@ -623,11 +623,11 @@ public void TestCreateExceptions()
webSocketException = new CouchbaseWebsocketException(10404);
webSocketException = new CouchbaseWebsocketException(10404, "HTTP Not Found");

var posixException = CouchbaseException.Create(new C4Error(C4ErrorDomain.POSIXDomain, PosixBase.EACCES)) as CouchbasePosixException;
posixException.Error.Should().Be(PosixBase.EACCES);
posixException.Domain.Should().Be(CouchbaseLiteErrorType.POSIX);
posixException = new CouchbasePosixException(999992);
posixException = new CouchbasePosixException(999992, "new posix lite exception");
//var posixException = CouchbaseException.Create(new C4Error(C4ErrorDomain.POSIXDomain, PosixBase.EACCES)) as CouchbasePosixException;
//posixException.Error.Should().Be(PosixBase.EACCES);
//posixException.Domain.Should().Be(CouchbaseLiteErrorType.POSIX);
//posixException = new CouchbasePosixException(999992);
//posixException = new CouchbasePosixException(999992, "new posix lite exception");

var networkException =
CouchbaseException.Create(new C4Error(C4NetworkErrorCode.InvalidURL)) as CouchbaseNetworkException;
Expand Down
42 changes: 35 additions & 7 deletions src/Couchbase.Lite.Tests.Shared/URLEndpointListenerTest.cs
Expand Up @@ -38,6 +38,7 @@

using FluentAssertions;
using LiteCore.Interop;
using System.Runtime.InteropServices;

#if !WINDOWS_UWP
using Xunit;
Expand Down Expand Up @@ -138,10 +139,12 @@ public void TestEmptyPort()
[Fact]
public void TestBusyPort()
{
_listener = CreateListener(false);
_listener = CreateListener(false, false);
_listener.Start();

//listener1 uses the same port as listener
var config = CreateListenerConfig(false);
var listener1 = Listen(config, PosixBase.GetCode(nameof(PosixWindows.EADDRINUSE)), CouchbaseLiteErrorType.POSIX);
var config = CreateListenerConfig(false, false, stopListener: false);
var listener1 = Listen(config, GetEADDRINUSECode(), CouchbaseLiteErrorType.POSIX, stopListener: false);

_listener.Stop();
listener1.Stop();
Expand Down Expand Up @@ -858,6 +861,22 @@ public void TestStopListener()

#region Private Methods

private int GetEADDRINUSECode()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return 100;
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return 48;
}
else
{
return 98; // Linux
}
}

private void WithActiveReplicatorAndURLEndpointListeners(bool isCloseNotDelete)
{
WaitAssert waitIdleAssert1 = new WaitAssert();
Expand Down Expand Up @@ -1157,9 +1176,10 @@ private void CheckReplicatorServerCert(bool listenerTls, bool replicatorTls)
}

private URLEndpointListenerConfiguration CreateListenerConfig(bool tls = true, bool useDynamicPort = true,
IListenerAuthenticator auth = null, TLSIdentity id = null)
IListenerAuthenticator auth = null, TLSIdentity id = null, bool stopListener = true)
{
_listener?.Stop();
if(stopListener)
_listener?.Stop();

var config = new URLEndpointListenerConfiguration(OtherDb);
if (useDynamicPort) {
Expand Down Expand Up @@ -1194,9 +1214,10 @@ private URLEndpointListener CreateListener(bool tls = true, bool useDynamicPort
}

private URLEndpointListener Listen(URLEndpointListenerConfiguration config,
int expectedErrCode = 0, CouchbaseLiteErrorType expectedErrDomain = 0)
int expectedErrCode = 0, CouchbaseLiteErrorType expectedErrDomain = 0, bool stopListener = true)
{
_listener?.Stop();
if(stopListener)
_listener?.Stop();

_listener = new URLEndpointListener(config);

Expand All @@ -1222,6 +1243,13 @@ private URLEndpointListener CreateListener(bool tls = true, bool useDynamicPort

ne.Domain.Should().Be(expectedErrDomain);
ne.Error.Should().Be(expectedErrCode);
} catch (CouchbasePosixException pe) {
if (expectedErrCode == 0) {
throw;
}

pe.Domain.Should().Be(expectedErrDomain);
pe.Error.Should().Be(expectedErrCode);
}

return _listener;
Expand Down
70 changes: 70 additions & 0 deletions src/LiteCore/src/LiteCore.Shared/API/CouchbaseLiteException.cs
Expand Up @@ -255,6 +255,76 @@ public enum CouchbaseLiteError
/// </summary>
InvalidRedirect = C4NetworkErrorCode.InvalidRedirect + NetworkBase,

/// <summary>
/// Unknown Network error
/// </summary>
Unknown = C4NetworkErrorCode.Unknown + NetworkBase,

/// <summary>
/// Peer's cert has been revoked
/// </summary>
TLSCertRevoked = C4NetworkErrorCode.TLSCertRevoked + NetworkBase,

/// <summary>
/// Peer's cert's Common Name doesn't match hostname
/// </summary>
TLSCertNameMismatch = C4NetworkErrorCode.TLSCertNameMismatch + NetworkBase,

/// <summary>
/// The network subsystem was reset [ENETRESET, retryable]
/// </summary>
NetworkReset = C4NetworkErrorCode.NetworkReset + NetworkBase,

/// <summary>
/// The connection was aborted by the OS [ECONNABORTED, retryable]
/// </summary>
ConnectionAborted = C4NetworkErrorCode.ConnectionAborted + NetworkBase,

/// <summary>
/// The connection was reset by the other side [ECONNRESET, retryable]
/// </summary>
ConnectionReset = C4NetworkErrorCode.ConnectionReset + NetworkBase,

/// <summary>
/// The other side refused the connection [ECONNREFUSED, retryable]
/// </summary>
ConnectionRefused = C4NetworkErrorCode.ConnectionRefused + NetworkBase,

/// <summary>
/// The network subsystem is not functioning [ENETDOWN, retryable]
/// </summary>
NetworkDown = C4NetworkErrorCode.NetworkDown + NetworkBase,

/// <summary>
/// There is no usable network at the moment [ENETUNREACH, retryable]
/// </summary>
NetworkUnreachable = C4NetworkErrorCode.NetworkUnreachable + NetworkBase,

/// <summary>
/// The socket in question is no longer connected [ENOTCONN, retryable]
/// </summary>
NotConnected = C4NetworkErrorCode.NotConnected + NetworkBase,

/// <summary>
/// The other side reports it is down [EHOSTDOWN, retryable]
/// </summary>
HostDown = C4NetworkErrorCode.HostDown + NetworkBase,

/// <summary>
/// There is no network path to the host [EHOSTUNREACH, retryable]
/// </summary>
HostUnreachable = C4NetworkErrorCode.HostUnreachable + NetworkBase,

/// <summary>
/// The address in question is already being used [EADDRNOTAVAIL, retryable]
/// </summary>
AddressNotAvailable = C4NetworkErrorCode.AddressNotAvailable + NetworkBase,

/// <summary>
/// Broken pipe [EPIPE, retryable]
/// </summary>
BrokenPipe = C4NetworkErrorCode.BrokenPipe + NetworkBase,

/// <summary>
/// Not an actual error, but serves as the lower bound for HTTP related
/// errors
Expand Down
11 changes: 11 additions & 0 deletions src/LiteCore/src/LiteCore.Shared/Interop/C4Error_defs.cs
Expand Up @@ -91,6 +91,17 @@ internal enum C4NetworkErrorCode : int
Unknown,
TLSCertRevoked,
TLSCertNameMismatch,
NetworkReset,
ConnectionAborted,
ConnectionReset,
ConnectionRefused,
NetworkDown,
NetworkUnreachable,
NotConnected,
HostDown,
HostUnreachable,
AddressNotAvailable,
BrokenPipe,
NumNetErrorCodesPlus1
}

Expand Down

0 comments on commit d6778e9

Please sign in to comment.