Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 92 additions & 111 deletions src/libraries/Common/src/System/Net/Sockets/SocketErrorPal.Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,6 @@ namespace System.Net.Sockets
{
internal static class SocketErrorPal
{
#if DEBUG
static SocketErrorPal()
{
Debug.Assert(s_nativeErrorToSocketError.Count == NativeErrorToSocketErrorCount,
$"Expected s_nativeErrorToSocketError to have {NativeErrorToSocketErrorCount} count instead of {s_nativeErrorToSocketError.Count}.");

Debug.Assert(s_socketErrorToNativeError.Count == SocketErrorToNativeErrorCount,
$"Expected s_socketErrorToNativeError to have {SocketErrorToNativeErrorCount} count instead of {s_socketErrorToNativeError.Count}.");
}
#endif

private const int NativeErrorToSocketErrorCount = 42;
private const int SocketErrorToNativeErrorCount = 41;

// No Interop.Errors are included for the following SocketErrors, as there's no good mapping:
// - SocketError.NoRecovery
// - SocketError.NotInitialized
Expand All @@ -31,115 +17,109 @@ static SocketErrorPal()
// - SocketError.TypeNotFound
// - SocketError.VersionNotSupported

private static readonly Dictionary<Interop.Error, SocketError> s_nativeErrorToSocketError = new Dictionary<Interop.Error, SocketError>(NativeErrorToSocketErrorCount)
internal static SocketError GetSocketErrorForNativeError(Interop.Error errno) => errno switch
{
{ Interop.Error.EACCES, SocketError.AccessDenied },
{ Interop.Error.EADDRINUSE, SocketError.AddressAlreadyInUse },
{ Interop.Error.EADDRNOTAVAIL, SocketError.AddressNotAvailable },
{ Interop.Error.EAFNOSUPPORT, SocketError.AddressFamilyNotSupported },
{ Interop.Error.EAGAIN, SocketError.WouldBlock },
{ Interop.Error.EALREADY, SocketError.AlreadyInProgress },
{ Interop.Error.EBADF, SocketError.OperationAborted },
{ Interop.Error.ECANCELED, SocketError.OperationAborted },
{ Interop.Error.ECONNABORTED, SocketError.ConnectionAborted },
{ Interop.Error.ECONNREFUSED, SocketError.ConnectionRefused },
{ Interop.Error.ECONNRESET, SocketError.ConnectionReset },
{ Interop.Error.EDESTADDRREQ, SocketError.DestinationAddressRequired },
{ Interop.Error.EFAULT, SocketError.Fault },
{ Interop.Error.EHOSTDOWN, SocketError.HostDown },
{ Interop.Error.ENXIO, SocketError.HostNotFound }, // not perfect, but closest match available
{ Interop.Error.EHOSTUNREACH, SocketError.HostUnreachable },
{ Interop.Error.EINPROGRESS, SocketError.InProgress },
{ Interop.Error.EINTR, SocketError.Interrupted },
{ Interop.Error.EINVAL, SocketError.InvalidArgument },
{ Interop.Error.EISCONN, SocketError.IsConnected },
{ Interop.Error.EMFILE, SocketError.TooManyOpenSockets },
{ Interop.Error.EMSGSIZE, SocketError.MessageSize },
{ Interop.Error.ENETDOWN, SocketError.NetworkDown },
{ Interop.Error.ENETRESET, SocketError.NetworkReset },
{ Interop.Error.ENETUNREACH, SocketError.NetworkUnreachable },
{ Interop.Error.ENFILE, SocketError.TooManyOpenSockets },
{ Interop.Error.ENOBUFS, SocketError.NoBufferSpaceAvailable },
{ Interop.Error.ENODATA, SocketError.NoData },
{ Interop.Error.ENOENT, SocketError.AddressNotAvailable },
{ Interop.Error.ENOPROTOOPT, SocketError.ProtocolOption },
{ Interop.Error.ENOTCONN, SocketError.NotConnected },
{ Interop.Error.ENOTSOCK, SocketError.NotSocket },
{ Interop.Error.ENOTSUP, SocketError.OperationNotSupported },
{ Interop.Error.EPERM, SocketError.AccessDenied },
{ Interop.Error.EPIPE, SocketError.Shutdown },
{ Interop.Error.EPFNOSUPPORT, SocketError.ProtocolFamilyNotSupported },
{ Interop.Error.EPROTONOSUPPORT, SocketError.ProtocolNotSupported },
{ Interop.Error.EPROTOTYPE, SocketError.ProtocolType },
{ Interop.Error.ESOCKTNOSUPPORT, SocketError.SocketNotSupported },
{ Interop.Error.ESHUTDOWN, SocketError.Disconnecting },
{ Interop.Error.SUCCESS, SocketError.Success },
{ Interop.Error.ETIMEDOUT, SocketError.TimedOut },
Interop.Error.EACCES => SocketError.AccessDenied,
Interop.Error.EADDRINUSE => SocketError.AddressAlreadyInUse,
Interop.Error.EADDRNOTAVAIL => SocketError.AddressNotAvailable,
Interop.Error.EAFNOSUPPORT => SocketError.AddressFamilyNotSupported,
Interop.Error.EAGAIN => SocketError.WouldBlock,
Interop.Error.EALREADY => SocketError.AlreadyInProgress,
Interop.Error.EBADF => SocketError.OperationAborted,
Interop.Error.ECANCELED => SocketError.OperationAborted,
Interop.Error.ECONNABORTED => SocketError.ConnectionAborted,
Interop.Error.ECONNREFUSED => SocketError.ConnectionRefused,
Interop.Error.ECONNRESET => SocketError.ConnectionReset,
Interop.Error.EDESTADDRREQ => SocketError.DestinationAddressRequired,
Interop.Error.EFAULT => SocketError.Fault,
Interop.Error.EHOSTDOWN => SocketError.HostDown,
Interop.Error.ENXIO => SocketError.HostNotFound, // not perfect, but closest match available
Interop.Error.EHOSTUNREACH => SocketError.HostUnreachable,
Interop.Error.EINPROGRESS => SocketError.InProgress,
Interop.Error.EINTR => SocketError.Interrupted,
Interop.Error.EINVAL => SocketError.InvalidArgument,
Interop.Error.EISCONN => SocketError.IsConnected,
Interop.Error.EMFILE => SocketError.TooManyOpenSockets,
Interop.Error.EMSGSIZE => SocketError.MessageSize,
Interop.Error.ENETDOWN => SocketError.NetworkDown,
Interop.Error.ENETRESET => SocketError.NetworkReset,
Interop.Error.ENETUNREACH => SocketError.NetworkUnreachable,
Interop.Error.ENFILE => SocketError.TooManyOpenSockets,
Interop.Error.ENOBUFS => SocketError.NoBufferSpaceAvailable,
Interop.Error.ENODATA => SocketError.NoData,
Interop.Error.ENOENT => SocketError.AddressNotAvailable,
Interop.Error.ENOPROTOOPT => SocketError.ProtocolOption,
Interop.Error.ENOTCONN => SocketError.NotConnected,
Interop.Error.ENOTSOCK => SocketError.NotSocket,
Interop.Error.ENOTSUP => SocketError.OperationNotSupported,
Interop.Error.EPERM => SocketError.AccessDenied,
Interop.Error.EPIPE => SocketError.Shutdown,
Interop.Error.EPFNOSUPPORT => SocketError.ProtocolFamilyNotSupported,
Interop.Error.EPROTONOSUPPORT => SocketError.ProtocolNotSupported,
Interop.Error.EPROTOTYPE => SocketError.ProtocolType,
Interop.Error.ESOCKTNOSUPPORT => SocketError.SocketNotSupported,
Interop.Error.ESHUTDOWN => SocketError.Disconnecting,
Interop.Error.SUCCESS => SocketError.Success,
Interop.Error.ETIMEDOUT => SocketError.TimedOut,
_ => SocketError.SocketError, // unknown native error, just treat it as a generic SocketError
};

private static readonly Dictionary<SocketError, Interop.Error> s_socketErrorToNativeError = new Dictionary<SocketError, Interop.Error>(SocketErrorToNativeErrorCount)
private static Interop.Error GetNativeErrorForSocketErrorHelper(SocketError error) => error switch
{
// This is *mostly* an inverse mapping of s_nativeErrorToSocketError. However, some options have multiple mappings and thus
// This is *mostly* an inverse mapping of GetSocketErrorForNativeError. However, some options have multiple mappings and thus
// can't be inverted directly. Other options don't have a mapping from native to SocketError, but when presented with a SocketError,
// we want to provide the closest relevant Error possible, e.g. EINPROGRESS maps to SocketError.InProgress, and vice versa, but
// SocketError.IOPending also maps closest to EINPROGRESS. As such, roundtripping won't necessarily provide the original value 100% of the time,
// but it's the best we can do given the mismatch between Interop.Error and SocketError.

{ SocketError.AccessDenied, Interop.Error.EACCES}, // could also have been EPERM
{ SocketError.AddressAlreadyInUse, Interop.Error.EADDRINUSE },
{ SocketError.AddressNotAvailable, Interop.Error.EADDRNOTAVAIL },
{ SocketError.AddressFamilyNotSupported, Interop.Error.EAFNOSUPPORT },
{ SocketError.AlreadyInProgress, Interop.Error.EALREADY },
{ SocketError.ConnectionAborted, Interop.Error.ECONNABORTED },
{ SocketError.ConnectionRefused, Interop.Error.ECONNREFUSED },
{ SocketError.ConnectionReset, Interop.Error.ECONNRESET },
{ SocketError.DestinationAddressRequired, Interop.Error.EDESTADDRREQ },
{ SocketError.Disconnecting, Interop.Error.ESHUTDOWN },
{ SocketError.Fault, Interop.Error.EFAULT },
{ SocketError.HostDown, Interop.Error.EHOSTDOWN },
{ SocketError.HostNotFound, Interop.Error.EHOSTNOTFOUND },
{ SocketError.HostUnreachable, Interop.Error.EHOSTUNREACH },
{ SocketError.InProgress, Interop.Error.EINPROGRESS },
{ SocketError.Interrupted, Interop.Error.EINTR },
{ SocketError.InvalidArgument, Interop.Error.EINVAL },
{ SocketError.IOPending, Interop.Error.EINPROGRESS },
{ SocketError.IsConnected, Interop.Error.EISCONN },
{ SocketError.MessageSize, Interop.Error.EMSGSIZE },
{ SocketError.NetworkDown, Interop.Error.ENETDOWN },
{ SocketError.NetworkReset, Interop.Error.ENETRESET },
{ SocketError.NetworkUnreachable, Interop.Error.ENETUNREACH },
{ SocketError.NoBufferSpaceAvailable, Interop.Error.ENOBUFS },
{ SocketError.NoData, Interop.Error.ENODATA },
{ SocketError.NotConnected, Interop.Error.ENOTCONN },
{ SocketError.NotSocket, Interop.Error.ENOTSOCK },
{ SocketError.OperationAborted, Interop.Error.ECANCELED },
{ SocketError.OperationNotSupported, Interop.Error.ENOTSUP },
{ SocketError.ProtocolFamilyNotSupported, Interop.Error.EPFNOSUPPORT },
{ SocketError.ProtocolNotSupported, Interop.Error.EPROTONOSUPPORT },
{ SocketError.ProtocolOption, Interop.Error.ENOPROTOOPT },
{ SocketError.ProtocolType, Interop.Error.EPROTOTYPE },
{ SocketError.Shutdown, Interop.Error.EPIPE },
{ SocketError.SocketNotSupported, Interop.Error.ESOCKTNOSUPPORT },
{ SocketError.Success, Interop.Error.SUCCESS },
{ SocketError.TimedOut, Interop.Error.ETIMEDOUT },
{ SocketError.TooManyOpenSockets, Interop.Error.ENFILE }, // could also have been EMFILE
{ SocketError.TryAgain, Interop.Error.EAGAIN }, // not a perfect mapping, but better than nothing
{ SocketError.WouldBlock, Interop.Error.EAGAIN },
{ SocketError.SocketError, Interop.Error.ESOCKETERROR },
SocketError.AccessDenied => Interop.Error.EACCES, // could also have been EPERM
SocketError.AddressAlreadyInUse => Interop.Error.EADDRINUSE,
SocketError.AddressNotAvailable => Interop.Error.EADDRNOTAVAIL,
SocketError.AddressFamilyNotSupported => Interop.Error.EAFNOSUPPORT,
SocketError.AlreadyInProgress => Interop.Error.EALREADY,
SocketError.ConnectionAborted => Interop.Error.ECONNABORTED,
SocketError.ConnectionRefused => Interop.Error.ECONNREFUSED,
SocketError.ConnectionReset => Interop.Error.ECONNRESET,
SocketError.DestinationAddressRequired => Interop.Error.EDESTADDRREQ,
SocketError.Disconnecting => Interop.Error.ESHUTDOWN,
SocketError.Fault => Interop.Error.EFAULT,
SocketError.HostDown => Interop.Error.EHOSTDOWN,
SocketError.HostNotFound => Interop.Error.EHOSTNOTFOUND,
SocketError.HostUnreachable => Interop.Error.EHOSTUNREACH,
SocketError.InProgress => Interop.Error.EINPROGRESS,
SocketError.Interrupted => Interop.Error.EINTR,
SocketError.InvalidArgument => Interop.Error.EINVAL,
SocketError.IOPending => Interop.Error.EINPROGRESS,
SocketError.IsConnected => Interop.Error.EISCONN,
SocketError.MessageSize => Interop.Error.EMSGSIZE,
SocketError.NetworkDown => Interop.Error.ENETDOWN,
SocketError.NetworkReset => Interop.Error.ENETRESET,
SocketError.NetworkUnreachable => Interop.Error.ENETUNREACH,
SocketError.NoBufferSpaceAvailable => Interop.Error.ENOBUFS,
SocketError.NoData => Interop.Error.ENODATA,
SocketError.NotConnected => Interop.Error.ENOTCONN,
SocketError.NotSocket => Interop.Error.ENOTSOCK,
SocketError.OperationAborted => Interop.Error.ECANCELED,
SocketError.OperationNotSupported => Interop.Error.ENOTSUP,
SocketError.ProtocolFamilyNotSupported => Interop.Error.EPFNOSUPPORT,
SocketError.ProtocolNotSupported => Interop.Error.EPROTONOSUPPORT,
SocketError.ProtocolOption => Interop.Error.ENOPROTOOPT,
SocketError.ProtocolType => Interop.Error.EPROTOTYPE,
SocketError.Shutdown => Interop.Error.EPIPE,
SocketError.SocketNotSupported => Interop.Error.ESOCKTNOSUPPORT,
SocketError.Success => Interop.Error.SUCCESS,
SocketError.TimedOut => Interop.Error.ETIMEDOUT,
SocketError.TooManyOpenSockets => Interop.Error.ENFILE, // could also have been EMFILE
SocketError.TryAgain => Interop.Error.EAGAIN, // not a perfect mapping, but better than nothing
SocketError.WouldBlock => Interop.Error.EAGAIN,
SocketError.SocketError => Interop.Error.ESOCKETERROR,
_ => Interop.Error.SUCCESS, // default for unknown mappings
};

internal static SocketError GetSocketErrorForNativeError(Interop.Error errno)
{
SocketError result;
return s_nativeErrorToSocketError.TryGetValue(errno, out result) ?
result :
SocketError.SocketError; // unknown native error, just treat it as a generic SocketError
}

internal static Interop.Error GetNativeErrorForSocketError(SocketError error)
{
Interop.Error errno;
if (!TryGetNativeErrorForSocketError(error, out errno))
Interop.Error errno = GetNativeErrorForSocketErrorHelper(error);
if (errno == Interop.Error.SUCCESS)
{
// Use the SocketError's value, as it at least retains some useful info
errno = (Interop.Error)(int)error;
Expand All @@ -149,7 +129,8 @@ internal static Interop.Error GetNativeErrorForSocketError(SocketError error)

internal static bool TryGetNativeErrorForSocketError(SocketError error, out Interop.Error errno)
{
return s_socketErrorToNativeError.TryGetValue(error, out errno);
errno = GetNativeErrorForSocketErrorHelper(error);
return errno != Interop.Error.SUCCESS;
}
}
}
Loading