/* * SRT - Secure, Reliable, Transport * Copyright (c) 2018 Haivision Systems Inc. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * */ // Implementation file for srt_compat.h /***************************************************************************** written by Haivision Systems Inc. *****************************************************************************/ // Prevents from misconfiguration through preprocessor. #include "platform_sys.h" #include #include #include #include #if defined(__unix__) && !defined(BSD) && !defined(SUNOS) #include #endif #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #include #endif static const char* SysStrError_Fallback(int errnum, char* buf, size_t buflen) { #if defined(_MSC_VER) && _MSC_VER < 1900 _snprintf(buf, buflen - 1, "ERROR CODE %d", errnum); buf[buflen - 1] = '\0'; #else snprintf(buf, buflen, "ERROR CODE %d", errnum); #endif return buf; } // This function is a portable and thread-safe version of `strerror`. // It requires a user-supplied buffer to store the message. The returned // value is always equal to the given buffer pointer. If the system // error message is longer than the given buflen, it will be trimmed. // When the error code is incorrect for the given error message function, // a fallback message will be returned, either as returned by the underlying // function, or crafted by this function as a response to error in an // underlying function. extern const char * SysStrError(int errnum, char * buf, size_t buflen) { if (buf == NULL || buflen < 4) // Required to put ??? into it as a fallback { errno = EFAULT; return buf; } buf[0] = '\0'; #if defined(_WIN32) const char* lpMsgBuf; // Note: Intentionally the "fixed char size" types are used despite using // character size dependent FormatMessage (instead of FormatMessageA) so that // your compilation fails when you use wide characters. // The problem is that when TCHAR != char, then the buffer written this way // would have to be converted to ASCII, not just copied by strncpy. FormatMessageA(0 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, // no lpSource errnum, // dwMessageId (as controlled by FORMAT_MESSAGE_FROM_SYSTEM) MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // This below parameter normally should contain a pointer to an allocated buffer, // and this way it's LPTSTR. But when FORMAT_MESSAGE_ALLOCATE_BUFFER, then it is // expected to be a the value of LPTSTR* type, converted to LPTSTR, that designates // a pointer to a variable of type LPTSTR, to which the newly allocated buffer is // assigned. This buffer should be freed afterwards using LocalFree(). (LPSTR)&lpMsgBuf, 0, NULL); if (lpMsgBuf) { #ifdef _MSC_VER strncpy_s(buf, buflen, lpMsgBuf, _TRUNCATE); #else strncpy(buf, lpMsgBuf, buflen-1); buf[buflen-1] = 0; #endif LocalFree((HLOCAL)lpMsgBuf); } else { SysStrError_Fallback(errnum, buf, buflen); } return buf; #elif (!defined(__GNU_LIBRARY__) && !defined(__GLIBC__) ) \ || (( (_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600)) && ! _GNU_SOURCE ) // POSIX/XSI-compliant version. // Overall general POSIX version: returns status. // 0 for success, otherwise it's: // - possibly -1 and the error code is in ::errno // - possibly the error code itself // The details of the errror are not interesting; simply // craft a fallback message in this case. if (strerror_r(errnum, buf, buflen) != 0) { return SysStrError_Fallback(errnum, buf, buflen); } return buf; #else // GLIBC is non-standard under these conditions. // GNU version: returns the pointer to the message. // This is either equal to the local buffer (buf) // or some system-wide (constant) storage. To maintain // stability of the API, this overall function shall // always return the local buffer and the message in // this buffer - so these cases should be distinguished // and the internal storage copied to the buffer. char * gnu_buffer = strerror_r(errnum, buf, buflen); if (!gnu_buffer) { // This should never happen, so just a paranoid check return SysStrError_Fallback(errnum, buf, buflen); } // If they are the same, the message is already copied // (and it's usually a "fallback message" for an error case). if (gnu_buffer != buf) { strncpy(buf, gnu_buffer, buflen-1); buf[buflen-1] = 0; // guarantee what strncpy doesn't } return buf; #endif }