1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/*
* 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 <srt_compat.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#if defined(__unix__) && !defined(BSD)
#include <features.h>
#endif
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#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.
FormatMessage(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)
{
strncpy(buf, lpMsgBuf, buflen-1);
buf[buflen-1] = 0;
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
}
|