From dfb2b42b968d2a820215e4d147c688423aef33fd Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Thu, 14 May 2020 14:00:32 -0700 Subject: [PATCH] Replace System.Native call in Interop.Errors.cs --- .../Common/src/Interop/Unix/Interop.Errors.cs | 11 + .../Native/Unix/Common/pal_error_common.h | 257 +++++++++++++++++++++ .../Unix/System.IO.Ports.Native/pal_serial.c | 15 ++ .../Unix/System.IO.Ports.Native/pal_serial.h | 4 +- .../Native/Unix/System.Native/pal_errno.c | 252 +------------------- .../System.IO.Ports/src/System.IO.Ports.csproj | 2 +- 6 files changed, 289 insertions(+), 252 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs b/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs index dad7962..e6de6c9 100644 --- a/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs +++ b/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs @@ -182,6 +182,16 @@ internal static partial class Interop return Marshal.PtrToStringAnsi((IntPtr)message)!; } +#if SERIAL_PORTS + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_ConvertErrorPlatformToPal")] + internal static extern Error ConvertErrorPlatformToPal(int platformErrno); + + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_ConvertErrorPalToPlatform")] + internal static extern int ConvertErrorPalToPlatform(Error error); + + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_StrErrorR")] + private static extern unsafe byte* StrErrorR(int platformErrno, byte* buffer, int bufferSize); +#else [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ConvertErrorPlatformToPal")] internal static extern Error ConvertErrorPlatformToPal(int platformErrno); @@ -190,6 +200,7 @@ internal static partial class Interop [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_StrErrorR")] private static extern unsafe byte* StrErrorR(int platformErrno, byte* buffer, int bufferSize); +#endif } } diff --git a/src/libraries/Native/Unix/Common/pal_error_common.h b/src/libraries/Native/Unix/Common/pal_error_common.h index d45bc21..f185811 100644 --- a/src/libraries/Native/Unix/Common/pal_error_common.h +++ b/src/libraries/Native/Unix/Common/pal_error_common.h @@ -6,7 +6,12 @@ #include "pal_compiler.h" #include "pal_types.h" +#include "pal_config.h" +#include "pal_utilities.h" +#include +#include #include +#include // ENODATA is not defined in FreeBSD 10.3 but is defined in 11.0 #if defined(__FreeBSD__) & !defined(ENODATA) @@ -321,3 +326,255 @@ inline static int32_t ConvertErrorPlatformToPal(int32_t platformErrno) return Error_ENONSTANDARD; } + +inline static int32_t ConvertErrorPalToPlatform(int32_t error) +{ + switch (error) + { + case Error_SUCCESS: + return 0; + case Error_E2BIG: + return E2BIG; + case Error_EACCES: + return EACCES; + case Error_EADDRINUSE: + return EADDRINUSE; + case Error_EADDRNOTAVAIL: + return EADDRNOTAVAIL; + case Error_EAFNOSUPPORT: + return EAFNOSUPPORT; + case Error_EAGAIN: + return EAGAIN; + case Error_EALREADY: + return EALREADY; + case Error_EBADF: + return EBADF; + case Error_EBADMSG: + return EBADMSG; + case Error_EBUSY: + return EBUSY; + case Error_ECANCELED: + return ECANCELED; + case Error_ECHILD: + return ECHILD; + case Error_ECONNABORTED: + return ECONNABORTED; + case Error_ECONNREFUSED: + return ECONNREFUSED; + case Error_ECONNRESET: + return ECONNRESET; + case Error_EDEADLK: + return EDEADLK; + case Error_EDESTADDRREQ: + return EDESTADDRREQ; + case Error_EDOM: + return EDOM; + case Error_EDQUOT: + return EDQUOT; + case Error_EEXIST: + return EEXIST; + case Error_EFAULT: + return EFAULT; + case Error_EFBIG: + return EFBIG; + case Error_EHOSTUNREACH: + return EHOSTUNREACH; + case Error_EIDRM: + return EIDRM; + case Error_EILSEQ: + return EILSEQ; + case Error_EINPROGRESS: + return EINPROGRESS; + case Error_EINTR: + return EINTR; + case Error_EINVAL: + return EINVAL; + case Error_EIO: + return EIO; + case Error_EISCONN: + return EISCONN; + case Error_EISDIR: + return EISDIR; + case Error_ELOOP: + return ELOOP; + case Error_EMFILE: + return EMFILE; + case Error_EMLINK: + return EMLINK; + case Error_EMSGSIZE: + return EMSGSIZE; + case Error_EMULTIHOP: + return EMULTIHOP; + case Error_ENAMETOOLONG: + return ENAMETOOLONG; + case Error_ENETDOWN: + return ENETDOWN; + case Error_ENETRESET: + return ENETRESET; + case Error_ENETUNREACH: + return ENETUNREACH; + case Error_ENFILE: + return ENFILE; + case Error_ENOBUFS: + return ENOBUFS; + case Error_ENODEV: + return ENODEV; + case Error_ENOENT: + return ENOENT; + case Error_ENOEXEC: + return ENOEXEC; + case Error_ENOLCK: + return ENOLCK; + case Error_ENOLINK: + return ENOLINK; + case Error_ENOMEM: + return ENOMEM; + case Error_ENOMSG: + return ENOMSG; + case Error_ENOPROTOOPT: + return ENOPROTOOPT; + case Error_ENOSPC: + return ENOSPC; + case Error_ENOSYS: + return ENOSYS; + case Error_ENOTCONN: + return ENOTCONN; + case Error_ENOTDIR: + return ENOTDIR; + case Error_ENOTEMPTY: + return ENOTEMPTY; +#ifdef ENOTRECOVERABLE // not available in NetBSD + case Error_ENOTRECOVERABLE: + return ENOTRECOVERABLE; +#endif + case Error_ENOTSOCK: + return ENOTSOCK; + case Error_ENOTSUP: + return ENOTSUP; + case Error_ENOTTY: + return ENOTTY; + case Error_ENXIO: + return ENXIO; + case Error_EOVERFLOW: + return EOVERFLOW; +#ifdef EOWNERDEAD // not available in NetBSD + case Error_EOWNERDEAD: + return EOWNERDEAD; +#endif + case Error_EPERM: + return EPERM; + case Error_EPIPE: + return EPIPE; + case Error_EPROTO: + return EPROTO; + case Error_EPROTONOSUPPORT: + return EPROTONOSUPPORT; + case Error_EPROTOTYPE: + return EPROTOTYPE; + case Error_ERANGE: + return ERANGE; + case Error_EROFS: + return EROFS; + case Error_ESPIPE: + return ESPIPE; + case Error_ESRCH: + return ESRCH; + case Error_ESTALE: + return ESTALE; + case Error_ETIMEDOUT: + return ETIMEDOUT; + case Error_ETXTBSY: + return ETXTBSY; + case Error_EXDEV: + return EXDEV; + case Error_EPFNOSUPPORT: + return EPFNOSUPPORT; +#ifdef ESOCKTNOSUPPORT + case Error_ESOCKTNOSUPPORT: + return ESOCKTNOSUPPORT; +#endif + case Error_ESHUTDOWN: + return ESHUTDOWN; + case Error_EHOSTDOWN: + return EHOSTDOWN; + case Error_ENODATA: + return ENODATA; + case Error_EHOSTNOTFOUND: + return -(Error_EHOSTNOTFOUND); + case Error_ENONSTANDARD: + break; // fall through to assert + } + + // We should not use this function to round-trip platform -> pal + // -> platform. It's here only to synthesize a platform number + // from the fixed set above. Note that the assert is outside the + // switch rather than in a default case block because not + // having a default will trigger a warning (as error) if there's + // an enum value we haven't handled. Should that trigger, make + // note that there is probably a corresponding missing case in the + // other direction above, but the compiler can't warn in that case + // because the platform values are not part of an enum. + assert_err(false, "Unknown error code", (int) error); + return -1; +} + +static int32_t ConvertErrorPalToGai(int32_t error) +{ + switch (error) + { + case -(Error_EHOSTNOTFOUND): + return EAI_NONAME; + } + // Fall-through for unknown codes. gai_strerror() will handle that. + + return error; +} + + + +inline static const char* StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize) +{ + assert(buffer != NULL); + assert(bufferSize > 0); + + if (bufferSize < 0) + return NULL; + + if (platformErrno < 0) + { + // Not a system error + SafeStringCopy(buffer, (size_t)bufferSize, gai_strerror(ConvertErrorPalToGai(platformErrno))); + return buffer; + } + +// Note that we must use strerror_r because plain strerror is not +// thread-safe. +// +// However, there are two versions of strerror_r: +// - GNU: char* strerror_r(int, char*, size_t); +// - POSIX: int strerror_r(int, char*, size_t); +// +// The former may or may not use the supplied buffer, and returns +// the error message string. The latter stores the error message +// string into the supplied buffer and returns an error code. + +#if HAVE_GNU_STRERROR_R + const char* message = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); + assert(message != NULL); + return message; +#else + int error = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); + if (error == ERANGE) + { + // Buffer is too small to hold the entire message, but has + // still been filled to the extent possible and null-terminated. + return NULL; + } + + // The only other valid error codes are 0 for success or EINVAL for + // an unknown error, but in the latter case a reasonable string (e.g + // "Unknown error: 0x123") is returned. + assert_err(error == 0 || error == EINVAL, "invalid error", error); + return buffer; +#endif +} diff --git a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c index 9eceb7e..4a4babd 100644 --- a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c +++ b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c @@ -72,3 +72,18 @@ int32_t SystemIoPortsNative_Shutdown(intptr_t socket, int32_t socketShutdown) { return Common_Shutdown(socket, socketShutdown); } + +int32_t SystemIoPortsNative_ConvertErrorPlatformToPal(int32_t platformErrno) +{ + return ConvertErrorPlatformToPal(platformErrno); +} + +int32_t SystemIoPortsNative_ConvertErrorPalToPlatform(int32_t error) +{ + return ConvertErrorPalToPlatform(error); +} + +const char* SystemIoPortsNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize) +{ + return StrErrorR(platformErrno, buffer, bufferSize); +} diff --git a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h index 30a2d24..371ceba 100644 --- a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h +++ b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h @@ -4,10 +4,12 @@ #include - PALEXPORT intptr_t SystemIoPortsNative_SerialPortOpen(const char * name); PALEXPORT int SystemIoPortsNative_SerialPortClose(intptr_t fd); PALEXPORT int32_t SystemIoPortsNative_Read(intptr_t fd, void* buffer, int32_t bufferSize); PALEXPORT int32_t SystemIoPortsNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize); PALEXPORT int32_t SystemIoPortsNative_Poll(PollEvent* pollEvents, uint32_t eventCount, int32_t milliseconds, uint32_t* triggered); PALEXPORT int32_t SystemIoPortsNative_Shutdown(intptr_t socket, int32_t socketShutdown); +PALEXPORT int32_t SystemIoPortsNative_ConvertErrorPlatformToPal(int32_t platformErrno); +PALEXPORT int32_t SystemIoPortsNative_ConvertErrorPalToPlatform(int32_t error); +PALEXPORT const char* SystemIoPortsNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize); diff --git a/src/libraries/Native/Unix/System.Native/pal_errno.c b/src/libraries/Native/Unix/System.Native/pal_errno.c index 9ee754b..b0da1ec 100644 --- a/src/libraries/Native/Unix/System.Native/pal_errno.c +++ b/src/libraries/Native/Unix/System.Native/pal_errno.c @@ -2,13 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include "pal_config.h" #include "pal_errno.h" -#include "pal_utilities.h" - -#include -#include -#include int32_t SystemNative_ConvertErrorPlatformToPal(int32_t platformErrno) { @@ -17,252 +11,10 @@ int32_t SystemNative_ConvertErrorPlatformToPal(int32_t platformErrno) int32_t SystemNative_ConvertErrorPalToPlatform(int32_t error) { - switch (error) - { - case Error_SUCCESS: - return 0; - case Error_E2BIG: - return E2BIG; - case Error_EACCES: - return EACCES; - case Error_EADDRINUSE: - return EADDRINUSE; - case Error_EADDRNOTAVAIL: - return EADDRNOTAVAIL; - case Error_EAFNOSUPPORT: - return EAFNOSUPPORT; - case Error_EAGAIN: - return EAGAIN; - case Error_EALREADY: - return EALREADY; - case Error_EBADF: - return EBADF; - case Error_EBADMSG: - return EBADMSG; - case Error_EBUSY: - return EBUSY; - case Error_ECANCELED: - return ECANCELED; - case Error_ECHILD: - return ECHILD; - case Error_ECONNABORTED: - return ECONNABORTED; - case Error_ECONNREFUSED: - return ECONNREFUSED; - case Error_ECONNRESET: - return ECONNRESET; - case Error_EDEADLK: - return EDEADLK; - case Error_EDESTADDRREQ: - return EDESTADDRREQ; - case Error_EDOM: - return EDOM; - case Error_EDQUOT: - return EDQUOT; - case Error_EEXIST: - return EEXIST; - case Error_EFAULT: - return EFAULT; - case Error_EFBIG: - return EFBIG; - case Error_EHOSTUNREACH: - return EHOSTUNREACH; - case Error_EIDRM: - return EIDRM; - case Error_EILSEQ: - return EILSEQ; - case Error_EINPROGRESS: - return EINPROGRESS; - case Error_EINTR: - return EINTR; - case Error_EINVAL: - return EINVAL; - case Error_EIO: - return EIO; - case Error_EISCONN: - return EISCONN; - case Error_EISDIR: - return EISDIR; - case Error_ELOOP: - return ELOOP; - case Error_EMFILE: - return EMFILE; - case Error_EMLINK: - return EMLINK; - case Error_EMSGSIZE: - return EMSGSIZE; - case Error_EMULTIHOP: - return EMULTIHOP; - case Error_ENAMETOOLONG: - return ENAMETOOLONG; - case Error_ENETDOWN: - return ENETDOWN; - case Error_ENETRESET: - return ENETRESET; - case Error_ENETUNREACH: - return ENETUNREACH; - case Error_ENFILE: - return ENFILE; - case Error_ENOBUFS: - return ENOBUFS; - case Error_ENODEV: - return ENODEV; - case Error_ENOENT: - return ENOENT; - case Error_ENOEXEC: - return ENOEXEC; - case Error_ENOLCK: - return ENOLCK; - case Error_ENOLINK: - return ENOLINK; - case Error_ENOMEM: - return ENOMEM; - case Error_ENOMSG: - return ENOMSG; - case Error_ENOPROTOOPT: - return ENOPROTOOPT; - case Error_ENOSPC: - return ENOSPC; - case Error_ENOSYS: - return ENOSYS; - case Error_ENOTCONN: - return ENOTCONN; - case Error_ENOTDIR: - return ENOTDIR; - case Error_ENOTEMPTY: - return ENOTEMPTY; -#ifdef ENOTRECOVERABLE // not available in NetBSD - case Error_ENOTRECOVERABLE: - return ENOTRECOVERABLE; -#endif - case Error_ENOTSOCK: - return ENOTSOCK; - case Error_ENOTSUP: - return ENOTSUP; - case Error_ENOTTY: - return ENOTTY; - case Error_ENXIO: - return ENXIO; - case Error_EOVERFLOW: - return EOVERFLOW; -#ifdef EOWNERDEAD // not available in NetBSD - case Error_EOWNERDEAD: - return EOWNERDEAD; -#endif - case Error_EPERM: - return EPERM; - case Error_EPIPE: - return EPIPE; - case Error_EPROTO: - return EPROTO; - case Error_EPROTONOSUPPORT: - return EPROTONOSUPPORT; - case Error_EPROTOTYPE: - return EPROTOTYPE; - case Error_ERANGE: - return ERANGE; - case Error_EROFS: - return EROFS; - case Error_ESPIPE: - return ESPIPE; - case Error_ESRCH: - return ESRCH; - case Error_ESTALE: - return ESTALE; - case Error_ETIMEDOUT: - return ETIMEDOUT; - case Error_ETXTBSY: - return ETXTBSY; - case Error_EXDEV: - return EXDEV; - case Error_EPFNOSUPPORT: - return EPFNOSUPPORT; -#ifdef ESOCKTNOSUPPORT - case Error_ESOCKTNOSUPPORT: - return ESOCKTNOSUPPORT; -#endif - case Error_ESHUTDOWN: - return ESHUTDOWN; - case Error_EHOSTDOWN: - return EHOSTDOWN; - case Error_ENODATA: - return ENODATA; - case Error_EHOSTNOTFOUND: - return -(Error_EHOSTNOTFOUND); - case Error_ENONSTANDARD: - break; // fall through to assert - } - - // We should not use this function to round-trip platform -> pal - // -> platform. It's here only to synthesize a platform number - // from the fixed set above. Note that the assert is outside the - // switch rather than in a default case block because not - // having a default will trigger a warning (as error) if there's - // an enum value we haven't handled. Should that trigger, make - // note that there is probably a corresponding missing case in the - // other direction above, but the compiler can't warn in that case - // because the platform values are not part of an enum. - assert_err(false, "Unknown error code", (int) error); - return -1; + return ConvertErrorPalToPlatform(error); } -static int32_t SystemNative_ConvertErrorPalToGai(int32_t error) -{ - switch (error) - { - case -(Error_EHOSTNOTFOUND): - return EAI_NONAME; - } - // Fall-through for unknown codes. gai_strerror() will handle that. - - return error; -} - - - const char* SystemNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize) { - assert(buffer != NULL); - assert(bufferSize > 0); - - if (bufferSize < 0) - return NULL; - - if (platformErrno < 0) - { - // Not a system error - SafeStringCopy(buffer, (size_t)bufferSize, gai_strerror(SystemNative_ConvertErrorPalToGai(platformErrno))); - return buffer; - } - -// Note that we must use strerror_r because plain strerror is not -// thread-safe. -// -// However, there are two versions of strerror_r: -// - GNU: char* strerror_r(int, char*, size_t); -// - POSIX: int strerror_r(int, char*, size_t); -// -// The former may or may not use the supplied buffer, and returns -// the error message string. The latter stores the error message -// string into the supplied buffer and returns an error code. - -#if HAVE_GNU_STRERROR_R - const char* message = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); - assert(message != NULL); - return message; -#else - int error = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); - if (error == ERANGE) - { - // Buffer is too small to hold the entire message, but has - // still been filled to the extent possible and null-terminated. - return NULL; - } - - // The only other valid error codes are 0 for success or EINVAL for - // an unknown error, but in the latter case a reasonable string (e.g - // "Unknown error: 0x123") is returned. - assert_err(error == 0 || error == EINVAL, "invalid error", error); - return buffer; -#endif + return StrErrorR(platformErrno, buffer, bufferSize); } diff --git a/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj b/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj index abd8646..d29ea8f 100644 --- a/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj +++ b/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj @@ -1,7 +1,7 @@ true - $(DefineConstants);NOSPAN + $(DefineConstants);NOSPAN;SERIAL_PORTS true annotations netstandard2.0-Windows_NT;netstandard2.0-Linux;netstandard2.0-OSX;netstandard2.0;net461-Windows_NT;netstandard2.0-FreeBSD;$(NetFrameworkCurrent)-Windows_NT -- 2.7.4