diff --git a/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs b/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs index e6de6c91723c36..44feca11efc63b 100644 --- a/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs +++ b/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs @@ -103,6 +103,7 @@ internal enum Error // Custom Error codes to track errors beyond kernel interface. EHOSTNOTFOUND = 0x20001, // Name lookup failed + ESOCKETERROR = 0x20002, // Unspecified socket error // POSIX permits these to have the same value and we make them always equal so // that we do not introduce a dependency on distinguishing between them that diff --git a/src/libraries/Common/src/System/Net/Sockets/SocketErrorPal.Unix.cs b/src/libraries/Common/src/System/Net/Sockets/SocketErrorPal.Unix.cs index 9381197e04699f..df797c51f12fbb 100644 --- a/src/libraries/Common/src/System/Net/Sockets/SocketErrorPal.Unix.cs +++ b/src/libraries/Common/src/System/Net/Sockets/SocketErrorPal.Unix.cs @@ -21,7 +21,7 @@ static SocketErrorPal() #endif private const int NativeErrorToSocketErrorCount = 42; - private const int SocketErrorToNativeErrorCount = 40; + private const int SocketErrorToNativeErrorCount = 41; // No Interop.Errors are included for the following SocketErrors, as there's no good mapping: // - SocketError.NoRecovery @@ -126,6 +126,7 @@ static SocketErrorPal() { 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 }, }; internal static SocketError GetSocketErrorForNativeError(Interop.Error errno) diff --git a/src/libraries/Native/Unix/Common/pal_error_common.h b/src/libraries/Native/Unix/Common/pal_error_common.h index f185811e6fb227..4be1cad4103365 100644 --- a/src/libraries/Native/Unix/Common/pal_error_common.h +++ b/src/libraries/Native/Unix/Common/pal_error_common.h @@ -124,6 +124,7 @@ typedef enum // Error codes to track errors beyond kernel. Error_EHOSTNOTFOUND = 0x20001, // Name lookup failed. + Error_ESOCKETERROR = 0x20002, // Unidentified socket error. // POSIX permits these to have the same value and we make them // always equal so that we cannot introduce a dependency on @@ -137,6 +138,17 @@ typedef enum Error_ENONSTANDARD = 0x1FFFF, } Error; +/* + Some pal errors don't have a corresponding errno value. + We define values for these errors. + We want these values to be distinct from real errno values. + We base of the Error enum values which are chosen to be out of the + typical errno range, and make them negative because POSIX + requires errno values to be positive. +*/ +#define EHOSTNOTFOUND (-Error_EHOSTNOTFOUND) +#define ESOCKETERROR (-Error_ESOCKETERROR) + inline static int32_t ConvertErrorPlatformToPal(int32_t platformErrno) { switch (platformErrno) @@ -500,7 +512,10 @@ inline static int32_t ConvertErrorPalToPlatform(int32_t error) case Error_ENODATA: return ENODATA; case Error_EHOSTNOTFOUND: - return -(Error_EHOSTNOTFOUND); + return EHOSTNOTFOUND; + case Error_ESOCKETERROR: + return ESOCKETERROR; + case Error_ENONSTANDARD: break; // fall through to assert } @@ -518,16 +533,19 @@ inline static int32_t ConvertErrorPalToPlatform(int32_t error) return -1; } -static int32_t ConvertErrorPalToGai(int32_t error) +static bool TryConvertErrorToGai(int32_t error, int32_t* gaiError) { + assert(gaiError != NULL); + switch (error) { - case -(Error_EHOSTNOTFOUND): - return EAI_NONAME; + case EHOSTNOTFOUND: + *gaiError = EAI_NONAME; + return true; + default: + *gaiError = error; + return false; } - // Fall-through for unknown codes. gai_strerror() will handle that. - - return error; } @@ -543,8 +561,17 @@ inline static const char* StrErrorR(int32_t platformErrno, char* buffer, int32_t if (platformErrno < 0) { // Not a system error - SafeStringCopy(buffer, (size_t)bufferSize, gai_strerror(ConvertErrorPalToGai(platformErrno))); - return buffer; + int32_t gaiError; + if (TryConvertErrorToGai(platformErrno, &gaiError)) + { + SafeStringCopy(buffer, (size_t)bufferSize, gai_strerror(gaiError)); + return buffer; + } + else if (platformErrno == ESOCKETERROR) + { + SafeStringCopy(buffer, (size_t)bufferSize, "Unknown socket error"); + return buffer; + } } // Note that we must use strerror_r because plain strerror is not diff --git a/src/libraries/System.Net.Primitives/src/System/Net/SocketException.Unix.cs b/src/libraries/System.Net.Primitives/src/System/Net/SocketException.Unix.cs index fc5ca779598ce1..4fcc9af3d158a8 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/SocketException.Unix.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/SocketException.Unix.cs @@ -26,15 +26,11 @@ private SocketException(Interop.ErrorInfo error) : this(SocketErrorPal.GetSocket private static int GetNativeErrorForSocketError(SocketError error) { int nativeErr = (int)error; - if (error != SocketError.SocketError) - { - Interop.Error interopErr; - // If an interop error was not found, then don't invoke Info().RawErrno as that will fail with assert. - if (SocketErrorPal.TryGetNativeErrorForSocketError(error, out interopErr)) - { - nativeErr = interopErr.Info().RawErrno; - } + // If an interop error was not found, then don't invoke Info().RawErrno as that will fail with assert. + if (SocketErrorPal.TryGetNativeErrorForSocketError(error, out Interop.Error interopErr)) + { + nativeErr = interopErr.Info().RawErrno; } return nativeErr;