/src/openvpn/error.c
C | 912 lines | 696 code | 111 blank | 105 comment | 102 complexity | e81f23a3c68090ffc3fb6b5520fcc6e2 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0
- /*
- * OpenVPN -- An application to securely tunnel IP networks
- * over a single TCP/UDP port, with support for SSL/TLS-based
- * session authentication and key exchange,
- * packet encryption, packet authentication, and
- * packet compression.
- *
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #elif defined(_MSC_VER)
- #include "config-msvc.h"
- #endif
- #include "syshead.h"
- #include "error.h"
- #include "buffer.h"
- #include "misc.h"
- #include "win32.h"
- #include "socket.h"
- #include "tun.h"
- #include "otime.h"
- #include "perf.h"
- #include "status.h"
- #include "integer.h"
- #include "ps.h"
- #include "mstats.h"
- #ifdef ENABLE_CRYPTO
- #ifdef ENABLE_CRYPTO_OPENSSL
- #include <openssl/err.h>
- #endif
- #endif
- #include "memdbg.h"
- #if SYSLOG_CAPABILITY
- #ifndef LOG_OPENVPN
- #define LOG_OPENVPN LOG_DAEMON
- #endif
- #endif
- /* Globals */
- unsigned int x_debug_level; /* GLOBAL */
- /* Mute state */
- static int mute_cutoff; /* GLOBAL */
- static int mute_count; /* GLOBAL */
- static int mute_category; /* GLOBAL */
- /*
- * Output mode priorities are as follows:
- *
- * (1) --log-x overrides everything
- * (2) syslog is used if --daemon or --inetd is defined and not --log-x
- * (3) if OPENVPN_DEBUG_COMMAND_LINE is defined, output
- * to constant logfile name.
- * (4) Output to stdout.
- */
- /* If true, indicates that stdin/stdout/stderr
- have been redirected due to --log */
- static bool std_redir; /* GLOBAL */
- /* Should messages be written to the syslog? */
- static bool use_syslog; /* GLOBAL */
- /* Should stdout/stderr be be parsable and always be prefixed with time
- * and message flags */
- static bool machine_readable_output; /* GLOBAL */
- /* Should timestamps be included on messages to stdout/stderr? */
- static bool suppress_timestamps; /* GLOBAL */
- /* The program name passed to syslog */
- #if SYSLOG_CAPABILITY
- static char *pgmname_syslog; /* GLOBAL */
- #endif
- /* If non-null, messages should be written here (used for debugging only) */
- static FILE *msgfp; /* GLOBAL */
- /* If true, we forked from main OpenVPN process */
- static bool forked; /* GLOBAL */
- /* our default output targets */
- static FILE *default_out; /* GLOBAL */
- static FILE *default_err; /* GLOBAL */
- void
- msg_forked (void)
- {
- forked = true;
- }
- bool
- set_debug_level (const int level, const unsigned int flags)
- {
- const int ceiling = 15;
- if (level >= 0 && level <= ceiling)
- {
- x_debug_level = level;
- return true;
- }
- else if (flags & SDL_CONSTRAIN)
- {
- x_debug_level = constrain_int (level, 0, ceiling);
- return true;
- }
- return false;
- }
- bool
- set_mute_cutoff (const int cutoff)
- {
- if (cutoff >= 0)
- {
- mute_cutoff = cutoff;
- return true;
- }
- else
- return false;
- }
- int
- get_debug_level (void)
- {
- return x_debug_level;
- }
- int
- get_mute_cutoff (void)
- {
- return mute_cutoff;
- }
- void
- set_suppress_timestamps (bool suppressed)
- {
- suppress_timestamps = suppressed;
- }
- void
- set_machine_readable_output (bool parsable)
- {
- machine_readable_output = parsable;
- }
- void
- error_reset ()
- {
- use_syslog = std_redir = false;
- suppress_timestamps = false;
- machine_readable_output = false;
- x_debug_level = 1;
- mute_cutoff = 0;
- mute_count = 0;
- mute_category = 0;
- default_out = OPENVPN_MSG_FP;
- default_err = OPENVPN_MSG_FP;
- #ifdef OPENVPN_DEBUG_COMMAND_LINE
- msgfp = fopen (OPENVPN_DEBUG_FILE, "w");
- if (!msgfp)
- openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
- #else
- msgfp = NULL;
- #endif
- }
- void
- errors_to_stderr (void)
- {
- default_err = OPENVPN_ERROR_FP;
- }
- /*
- * Return a file to print messages to before syslog is opened.
- */
- FILE *
- msg_fp(const unsigned int flags)
- {
- FILE *fp = msgfp;
- if (!fp)
- fp = (flags & (M_FATAL|M_USAGE_SMALL)) ? default_err : default_out;
- if (!fp)
- openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
- return fp;
- }
- #define SWAP { tmp = m1; m1 = m2; m2 = tmp; }
- int x_msg_line_num; /* GLOBAL */
- void x_msg (const unsigned int flags, const char *format, ...)
- {
- va_list arglist;
- va_start (arglist, format);
- x_msg_va (flags, format, arglist);
- va_end (arglist);
- }
- void x_msg_va (const unsigned int flags, const char *format, va_list arglist)
- {
- struct gc_arena gc;
- #if SYSLOG_CAPABILITY
- int level;
- #endif
- char *m1;
- char *m2;
- char *tmp;
- int e;
- const char *prefix;
- const char *prefix_sep;
- void usage_small (void);
- #ifndef HAVE_VARARG_MACROS
- /* the macro has checked this otherwise */
- if (!MSG_TEST (flags))
- return;
- #endif
- e = openvpn_errno ();
- /*
- * Apply muting filter.
- */
- #ifndef HAVE_VARARG_MACROS
- /* the macro has checked this otherwise */
- if (!dont_mute (flags))
- return;
- #endif
- gc_init (&gc);
- m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
- m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
- vsnprintf (m1, ERR_BUF_SIZE, format, arglist);
- m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */
- if ((flags & M_ERRNO) && e)
- {
- openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s (errno=%d)",
- m1, strerror_ts (e, &gc), e);
- SWAP;
- }
- #ifdef ENABLE_CRYPTO
- #ifdef ENABLE_CRYPTO_OPENSSL
- if (flags & M_SSL)
- {
- int nerrs = 0;
- size_t err;
- while ((err = ERR_get_error ()))
- {
- openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s",
- m1, ERR_error_string (err, NULL));
- SWAP;
- ++nerrs;
- }
- if (!nerrs)
- {
- openvpn_snprintf (m2, ERR_BUF_SIZE, "%s (OpenSSL)", m1);
- SWAP;
- }
- }
- #endif
- #endif
- if (flags & M_OPTERR)
- {
- openvpn_snprintf (m2, ERR_BUF_SIZE, "Options error: %s", m1);
- SWAP;
- }
- #if SYSLOG_CAPABILITY
- if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL))
- level = LOG_ERR;
- else if (flags & M_WARN)
- level = LOG_WARNING;
- else
- level = LOG_NOTICE;
- #endif
- /* set up client prefix */
- if (flags & M_NOIPREFIX)
- prefix = NULL;
- else
- prefix = msg_get_prefix ();
- prefix_sep = " ";
- if (!prefix)
- prefix_sep = prefix = "";
- /* virtual output capability used to copy output to management subsystem */
- if (!forked)
- {
- const struct virtual_output *vo = msg_get_virtual_output ();
- if (vo)
- {
- openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s",
- prefix,
- prefix_sep,
- m1);
- virtual_output_print (vo, flags, m2);
- }
- }
- if (!(flags & M_MSG_VIRT_OUT))
- {
- if (use_syslog && !std_redir && !forked)
- {
- #if SYSLOG_CAPABILITY
- syslog (level, "%s%s%s",
- prefix,
- prefix_sep,
- m1);
- #endif
- }
- else
- {
- FILE *fp = msg_fp(flags);
- const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME);
- if (machine_readable_output)
- {
- struct timeval tv;
- gettimeofday (&tv, NULL);
- fprintf (fp, "%lu.%06lu %x %s%s%s%s",
- tv.tv_sec,
- tv.tv_usec,
- flags,
- prefix,
- prefix_sep,
- m1,
- "\n");
- }
- else if ((flags & M_NOPREFIX) || suppress_timestamps)
- {
- fprintf (fp, "%s%s%s%s",
- prefix,
- prefix_sep,
- m1,
- (flags&M_NOLF) ? "" : "\n");
- }
- else
- {
- fprintf (fp, "%s %s%s%s%s",
- time_string (0, 0, show_usec, &gc),
- prefix,
- prefix_sep,
- m1,
- (flags&M_NOLF) ? "" : "\n");
- }
- fflush(fp);
- ++x_msg_line_num;
- }
- }
- if (flags & M_FATAL)
- msg (M_INFO, "Exiting due to fatal error");
- if (flags & M_FATAL)
- openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
- if (flags & M_USAGE_SMALL)
- usage_small ();
- gc_free (&gc);
- }
- /*
- * Apply muting filter.
- */
- bool
- dont_mute (unsigned int flags)
- {
- bool ret = true;
- if (mute_cutoff > 0 && !(flags & M_NOMUTE))
- {
- const int mute_level = DECODE_MUTE_LEVEL (flags);
- if (mute_level > 0 && mute_level == mute_category)
- {
- if (mute_count == mute_cutoff)
- msg (M_INFO | M_NOMUTE, "NOTE: --mute triggered...");
- if (++mute_count > mute_cutoff)
- ret = false;
- }
- else
- {
- const int suppressed = mute_count - mute_cutoff;
- if (suppressed > 0)
- msg (M_INFO | M_NOMUTE,
- "%d variation(s) on previous %d message(s) suppressed by --mute",
- suppressed,
- mute_cutoff);
- mute_count = 1;
- mute_category = mute_level;
- }
- }
- return ret;
- }
- void
- assert_failed (const char *filename, int line)
- {
- msg (M_FATAL, "Assertion failed at %s:%d", filename, line);
- }
- /*
- * Fail memory allocation. Don't use msg() because it tries
- * to allocate memory as part of its operation.
- */
- void
- out_of_memory (void)
- {
- fprintf (stderr, PACKAGE_NAME ": Out of Memory\n");
- exit (1);
- }
- void
- open_syslog (const char *pgmname, bool stdio_to_null)
- {
- #if SYSLOG_CAPABILITY
- if (!msgfp && !std_redir)
- {
- if (!use_syslog)
- {
- pgmname_syslog = string_alloc (pgmname ? pgmname : PACKAGE, NULL);
- openlog (pgmname_syslog, LOG_PID, LOG_OPENVPN);
- use_syslog = true;
- /* Better idea: somehow pipe stdout/stderr output to msg() */
- if (stdio_to_null)
- set_std_files_to_null (false);
- }
- }
- #else
- msg (M_WARN, "Warning on use of --daemon/--inetd: this operating system lacks daemon logging features, therefore when I become a daemon, I won't be able to log status or error messages");
- #endif
- }
- void
- close_syslog ()
- {
- #if SYSLOG_CAPABILITY
- if (use_syslog)
- {
- closelog();
- use_syslog = false;
- if (pgmname_syslog)
- {
- free (pgmname_syslog);
- pgmname_syslog = NULL;
- }
- }
- #endif
- }
- #ifdef WIN32
- static HANDLE orig_stderr;
- HANDLE
- get_orig_stderr (void)
- {
- if (orig_stderr)
- return orig_stderr;
- else
- return GetStdHandle (STD_ERROR_HANDLE);
- }
- #endif
- void
- redirect_stdout_stderr (const char *file, bool append)
- {
- #if defined(WIN32)
- if (!std_redir)
- {
- struct gc_arena gc = gc_new ();
- HANDLE log_handle;
- int log_fd;
- SECURITY_ATTRIBUTES saAttr;
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
- log_handle = CreateFileW (wide_string (file, &gc),
- GENERIC_WRITE,
- FILE_SHARE_READ,
- &saAttr,
- append ? OPEN_ALWAYS : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- gc_free (&gc);
- if (log_handle == INVALID_HANDLE_VALUE)
- {
- msg (M_WARN|M_ERRNO, "Warning: cannot open --log file: %s", file);
- return;
- }
- /* append to logfile? */
- if (append)
- {
- if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
- msg (M_ERR, "Error: cannot seek to end of --log file: %s", file);
- }
-
- /* save original stderr for password prompts */
- orig_stderr = GetStdHandle (STD_ERROR_HANDLE);
- #if 0 /* seems not be necessary with stdout/stderr redirection below*/
- /* set up for redirection */
- if (!SetStdHandle (STD_OUTPUT_HANDLE, log_handle)
- || !SetStdHandle (STD_ERROR_HANDLE, log_handle))
- msg (M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file);
- #endif
- /* direct stdout/stderr to point to log_handle */
- log_fd = _open_osfhandle ((intptr_t)log_handle, _O_TEXT);
- if (log_fd == -1)
- msg (M_ERR, "Error: --log redirect failed due to _open_osfhandle failure");
-
- /* open log_handle as FILE stream */
- ASSERT (msgfp == NULL);
- msgfp = _fdopen (log_fd, "wt");
- if (msgfp == NULL)
- msg (M_ERR, "Error: --log redirect failed due to _fdopen");
- /* redirect C-library stdout/stderr to log file */
- if (_dup2 (log_fd, 1) == -1 || _dup2 (log_fd, 2) == -1)
- msg (M_WARN, "Error: --log redirect of stdout/stderr failed");
- std_redir = true;
- }
- #elif defined(HAVE_DUP2)
- if (!std_redir)
- {
- int out = open (file,
- O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC),
- S_IRUSR | S_IWUSR);
- if (out < 0)
- {
- msg (M_WARN|M_ERRNO, "Warning: Error redirecting stdout/stderr to --log file: %s", file);
- return;
- }
- if (dup2 (out, 1) == -1)
- msg (M_ERR, "--log file redirection error on stdout");
- if (dup2 (out, 2) == -1)
- msg (M_ERR, "--log file redirection error on stderr");
- if (out > 2)
- close (out);
- std_redir = true;
- }
- #else
- msg (M_WARN, "WARNING: The --log option is not supported on this OS because it lacks the dup2 function");
- #endif
- }
- /*
- * Functions used to check return status
- * of I/O operations.
- */
- unsigned int x_cs_info_level; /* GLOBAL */
- unsigned int x_cs_verbose_level; /* GLOBAL */
- unsigned int x_cs_err_delay_ms; /* GLOBAL */
- void
- reset_check_status ()
- {
- x_cs_info_level = 0;
- x_cs_verbose_level = 0;
- }
- void
- set_check_status (unsigned int info_level, unsigned int verbose_level)
- {
- x_cs_info_level = info_level;
- x_cs_verbose_level = verbose_level;
- }
- /*
- * Called after most socket or tun/tap operations, via the inline
- * function check_status().
- *
- * Decide if we should print an error message, and see if we can
- * extract any useful info from the error, such as a Path MTU hint
- * from the OS.
- */
- void
- x_check_status (int status,
- const char *description,
- struct link_socket *sock,
- struct tuntap *tt)
- {
- const int my_errno = openvpn_errno ();
- const char *extended_msg = NULL;
- msg (x_cs_verbose_level, "%s %s returned %d",
- sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",
- description,
- status);
- if (status < 0)
- {
- struct gc_arena gc = gc_new ();
- #if EXTENDED_SOCKET_ERROR_CAPABILITY
- /* get extended socket error message and possible PMTU hint from OS */
- if (sock)
- {
- int mtu;
- extended_msg = format_extended_socket_error (sock->sd, &mtu, &gc);
- if (mtu > 0 && sock->mtu != mtu)
- {
- sock->mtu = mtu;
- sock->info.mtu_changed = true;
- }
- }
- #elif defined(WIN32)
- /* get possible driver error from TAP-Windows driver */
- extended_msg = tap_win_getinfo (tt, &gc);
- #endif
- if (!ignore_sys_error (my_errno))
- {
- if (extended_msg)
- msg (x_cs_info_level, "%s %s [%s]: %s (code=%d)",
- description,
- sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",
- extended_msg,
- strerror_ts (my_errno, &gc),
- my_errno);
- else
- msg (x_cs_info_level, "%s %s: %s (code=%d)",
- description,
- sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",
- strerror_ts (my_errno, &gc),
- my_errno);
- if (x_cs_err_delay_ms)
- platform_sleep_milliseconds (x_cs_err_delay_ms);
- }
- gc_free (&gc);
- }
- }
- /*
- * In multiclient mode, put a client-specific prefix
- * before each message.
- */
- const char *x_msg_prefix; /* GLOBAL */
- /*
- * Allow MSG to be redirected through a virtual_output object
- */
- const struct virtual_output *x_msg_virtual_output; /* GLOBAL */
- /*
- * Exiting.
- */
- void
- openvpn_exit (const int status)
- {
- if (!forked)
- {
- void tun_abort();
- #ifdef ENABLE_PLUGIN
- void plugin_abort (void);
- #endif
- tun_abort();
- #ifdef WIN32
- uninit_win32 ();
- #endif
- close_syslog ();
- #ifdef ENABLE_PLUGIN
- plugin_abort ();
- #endif
- #if PORT_SHARE
- if (port_share)
- port_share_abort (port_share);
- #endif
- #ifdef ENABLE_MEMSTATS
- mstats_close();
- #endif
- #ifdef ABORT_ON_ERROR
- if (status == OPENVPN_EXIT_STATUS_ERROR)
- abort ();
- #endif
- if (status == OPENVPN_EXIT_STATUS_GOOD)
- perf_output_results ();
- }
- exit (status);
- }
- /*
- * Translate msg flags into a string
- */
- const char *
- msg_flags_string (const unsigned int flags, struct gc_arena *gc)
- {
- struct buffer out = alloc_buf_gc (16, gc);
- if (flags == M_INFO)
- buf_printf (&out, "I");
- if (flags & M_FATAL)
- buf_printf (&out, "F");
- if (flags & M_NONFATAL)
- buf_printf (&out, "N");
- if (flags & M_WARN)
- buf_printf (&out, "W");
- if (flags & M_DEBUG)
- buf_printf (&out, "D");
- return BSTR (&out);
- }
- #ifdef ENABLE_DEBUG
- void
- crash (void)
- {
- char *null = NULL;
- *null = 0;
- }
- #endif
- #ifdef WIN32
- const char *
- strerror_win32 (DWORD errnum, struct gc_arena *gc)
- {
- /*
- * This code can be omitted, though often the Windows
- * WSA error messages are less informative than the
- * Posix equivalents.
- */
- #if 1
- switch (errnum) {
- /*
- * When the TAP-Windows driver returns STATUS_UNSUCCESSFUL, this code
- * gets returned to user space.
- */
- case ERROR_GEN_FAILURE:
- return "General failure (ERROR_GEN_FAILURE)";
- case ERROR_IO_PENDING:
- return "I/O Operation in progress (ERROR_IO_PENDING)";
- case WSA_IO_INCOMPLETE:
- return "I/O Operation in progress (WSA_IO_INCOMPLETE)";
- case WSAEINTR:
- return "Interrupted system call (WSAEINTR)";
- case WSAEBADF:
- return "Bad file number (WSAEBADF)";
- case WSAEACCES:
- return "Permission denied (WSAEACCES)";
- case WSAEFAULT:
- return "Bad address (WSAEFAULT)";
- case WSAEINVAL:
- return "Invalid argument (WSAEINVAL)";
- case WSAEMFILE:
- return "Too many open files (WSAEMFILE)";
- case WSAEWOULDBLOCK:
- return "Operation would block (WSAEWOULDBLOCK)";
- case WSAEINPROGRESS:
- return "Operation now in progress (WSAEINPROGRESS)";
- case WSAEALREADY:
- return "Operation already in progress (WSAEALREADY)";
- case WSAEDESTADDRREQ:
- return "Destination address required (WSAEDESTADDRREQ)";
- case WSAEMSGSIZE:
- return "Message too long (WSAEMSGSIZE)";
- case WSAEPROTOTYPE:
- return "Protocol wrong type for socket (WSAEPROTOTYPE)";
- case WSAENOPROTOOPT:
- return "Bad protocol option (WSAENOPROTOOPT)";
- case WSAEPROTONOSUPPORT:
- return "Protocol not supported (WSAEPROTONOSUPPORT)";
- case WSAESOCKTNOSUPPORT:
- return "Socket type not supported (WSAESOCKTNOSUPPORT)";
- case WSAEOPNOTSUPP:
- return "Operation not supported on socket (WSAEOPNOTSUPP)";
- case WSAEPFNOSUPPORT:
- return "Protocol family not supported (WSAEPFNOSUPPORT)";
- case WSAEAFNOSUPPORT:
- return "Address family not supported by protocol family (WSAEAFNOSUPPORT)";
- case WSAEADDRINUSE:
- return "Address already in use (WSAEADDRINUSE)";
- case WSAENETDOWN:
- return "Network is down (WSAENETDOWN)";
- case WSAENETUNREACH:
- return "Network is unreachable (WSAENETUNREACH)";
- case WSAENETRESET:
- return "Net dropped connection or reset (WSAENETRESET)";
- case WSAECONNABORTED:
- return "Software caused connection abort (WSAECONNABORTED)";
- case WSAECONNRESET:
- return "Connection reset by peer (WSAECONNRESET)";
- case WSAENOBUFS:
- return "No buffer space available (WSAENOBUFS)";
- case WSAEISCONN:
- return "Socket is already connected (WSAEISCONN)";
- case WSAENOTCONN:
- return "Socket is not connected (WSAENOTCONN)";
- case WSAETIMEDOUT:
- return "Connection timed out (WSAETIMEDOUT)";
- case WSAECONNREFUSED:
- return "Connection refused (WSAECONNREFUSED)";
- case WSAELOOP:
- return "Too many levels of symbolic links (WSAELOOP)";
- case WSAENAMETOOLONG:
- return "File name too long (WSAENAMETOOLONG)";
- case WSAEHOSTDOWN:
- return "Host is down (WSAEHOSTDOWN)";
- case WSAEHOSTUNREACH:
- return "No Route to Host (WSAEHOSTUNREACH)";
- case WSAENOTEMPTY:
- return "Directory not empty (WSAENOTEMPTY)";
- case WSAEPROCLIM:
- return "Too many processes (WSAEPROCLIM)";
- case WSAEUSERS:
- return "Too many users (WSAEUSERS)";
- case WSAEDQUOT:
- return "Disc Quota Exceeded (WSAEDQUOT)";
- case WSAESTALE:
- return "Stale NFS file handle (WSAESTALE)";
- case WSASYSNOTREADY:
- return "Network SubSystem is unavailable (WSASYSNOTREADY)";
- case WSAVERNOTSUPPORTED:
- return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)";
- case WSANOTINITIALISED:
- return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)";
- case WSAEREMOTE:
- return "Too many levels of remote in path (WSAEREMOTE)";
- case WSAHOST_NOT_FOUND:
- return "Host not found (WSAHOST_NOT_FOUND)";
- default:
- break;
- }
- #endif
- /* format a windows error message */
- {
- char message[256];
- struct buffer out = alloc_buf_gc (256, gc);
- const int status = FormatMessage (
- FORMAT_MESSAGE_IGNORE_INSERTS
- | FORMAT_MESSAGE_FROM_SYSTEM
- | FORMAT_MESSAGE_ARGUMENT_ARRAY,
- NULL,
- errnum,
- 0,
- message,
- sizeof (message),
- NULL);
- if (!status)
- {
- buf_printf (&out, "[Unknown Win32 Error]");
- }
- else
- {
- char *cp;
- for (cp = message; *cp != '\0'; ++cp)
- {
- if (*cp == '\n' || *cp == '\r')
- *cp = ' ';
- }
-
- buf_printf(&out, "%s", message);
- }
-
- return BSTR (&out);
- }
- }
- #endif