Update to OpenVPN 2.1rc17
[tomato.git] / release / src / router / openvpn / error.c
blob1d6ed628c74c92b8bd4d1151d7e5eb3eb9d12c44
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "syshead.h"
27 #include "error.h"
28 #include "buffer.h"
29 #include "thread.h"
30 #include "misc.h"
31 #include "win32.h"
32 #include "socket.h"
33 #include "tun.h"
34 #include "otime.h"
35 #include "perf.h"
36 #include "status.h"
37 #include "integer.h"
38 #include "ps.h"
40 #ifdef USE_CRYPTO
41 #include <openssl/err.h>
42 #endif
44 #include "memdbg.h"
46 #if SYSLOG_CAPABILITY
47 #ifndef LOG_OPENVPN
48 #define LOG_OPENVPN LOG_DAEMON
49 #endif
50 #endif
52 /* Globals */
53 unsigned int x_debug_level; /* GLOBAL */
55 /* Mute state */
56 static int mute_cutoff; /* GLOBAL */
57 static int mute_count; /* GLOBAL */
58 static int mute_category; /* GLOBAL */
61 * Output mode priorities are as follows:
63 * (1) --log-x overrides everything
64 * (2) syslog is used if --daemon or --inetd is defined and not --log-x
65 * (3) if OPENVPN_DEBUG_COMMAND_LINE is defined, output
66 * to constant logfile name.
67 * (4) Output to stdout.
70 /* If true, indicates that stdin/stdout/stderr
71 have been redirected due to --log */
72 static bool std_redir; /* GLOBAL */
74 /* Should messages be written to the syslog? */
75 static bool use_syslog; /* GLOBAL */
77 /* Should timestamps be included on messages to stdout/stderr? */
78 static bool suppress_timestamps; /* GLOBAL */
80 /* The program name passed to syslog */
81 #if SYSLOG_CAPABILITY
82 static char *pgmname_syslog; /* GLOBAL */
83 #endif
85 /* If non-null, messages should be written here (used for debugging only) */
86 static FILE *msgfp; /* GLOBAL */
88 /* If true, we forked from main OpenVPN process */
89 static bool forked; /* GLOBAL */
91 /* our default output targets */
92 static FILE *default_out; /* GLOBAL */
93 static FILE *default_err; /* GLOBAL */
95 void
96 msg_forked (void)
98 forked = true;
101 bool
102 set_debug_level (const int level, const unsigned int flags)
104 const int ceiling = 15;
106 if (level >= 0 && level <= ceiling)
108 x_debug_level = level;
109 return true;
111 else if (flags & SDL_CONSTRAIN)
113 x_debug_level = constrain_int (level, 0, ceiling);
114 return true;
116 return false;
119 bool
120 set_mute_cutoff (const int cutoff)
122 if (cutoff >= 0)
124 mute_cutoff = cutoff;
125 return true;
127 else
128 return false;
132 get_debug_level (void)
134 return x_debug_level;
138 get_mute_cutoff (void)
140 return mute_cutoff;
143 void
144 set_suppress_timestamps (bool suppressed)
146 suppress_timestamps = suppressed;
149 void
150 error_reset ()
152 use_syslog = std_redir = false;
153 suppress_timestamps = false;
154 x_debug_level = 1;
155 mute_cutoff = 0;
156 mute_count = 0;
157 mute_category = 0;
158 default_out = OPENVPN_MSG_FP;
159 default_err = OPENVPN_MSG_FP;
161 #ifdef OPENVPN_DEBUG_COMMAND_LINE
162 msgfp = fopen (OPENVPN_DEBUG_FILE, "w");
163 if (!msgfp)
164 openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
165 #else
166 msgfp = NULL;
167 #endif
170 void
171 errors_to_stderr (void)
173 default_err = OPENVPN_ERROR_FP;
177 * Return a file to print messages to before syslog is opened.
179 FILE *
180 msg_fp(const unsigned int flags)
182 FILE *fp = msgfp;
183 if (!fp)
184 fp = (flags & (M_FATAL|M_USAGE_SMALL)) ? default_err : default_out;
185 if (!fp)
186 openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
187 return fp;
190 #define SWAP { tmp = m1; m1 = m2; m2 = tmp; }
192 int x_msg_line_num; /* GLOBAL */
194 void x_msg (const unsigned int flags, const char *format, ...)
196 struct gc_arena gc;
197 va_list arglist;
198 #if SYSLOG_CAPABILITY
199 int level;
200 #endif
201 char *m1;
202 char *m2;
203 char *tmp;
204 int e;
205 const char *prefix;
206 const char *prefix_sep;
208 void usage_small (void);
210 #ifndef HAVE_VARARG_MACROS
211 /* the macro has checked this otherwise */
212 if (!MSG_TEST (flags))
213 return;
214 #endif
216 if (flags & M_ERRNO_SOCK)
217 e = openvpn_errno_socket ();
218 else
219 e = openvpn_errno ();
222 * Apply muting filter.
224 #ifndef HAVE_VARARG_MACROS
225 /* the macro has checked this otherwise */
226 if (!dont_mute (flags))
227 return;
228 #endif
230 gc_init (&gc);
232 mutex_lock_static (L_MSG);
234 m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
235 m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
237 va_start (arglist, format);
238 vsnprintf (m1, ERR_BUF_SIZE, format, arglist);
239 va_end (arglist);
240 m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */
242 if ((flags & (M_ERRNO|M_ERRNO_SOCK)) && e)
244 openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s (errno=%d)",
245 m1, strerror_ts (e, &gc), e);
246 SWAP;
249 #ifdef USE_CRYPTO
250 if (flags & M_SSL)
252 int nerrs = 0;
253 int err;
254 while ((err = ERR_get_error ()))
256 openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s",
257 m1, ERR_error_string (err, NULL));
258 SWAP;
259 ++nerrs;
261 if (!nerrs)
263 openvpn_snprintf (m2, ERR_BUF_SIZE, "%s (OpenSSL)", m1);
264 SWAP;
267 #endif
269 if (flags & M_OPTERR)
271 openvpn_snprintf (m2, ERR_BUF_SIZE, "Options error: %s", m1);
272 SWAP;
275 #if SYSLOG_CAPABILITY
276 if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL))
277 level = LOG_ERR;
278 else if (flags & M_WARN)
279 level = LOG_WARNING;
280 else
281 level = LOG_NOTICE;
282 #endif
284 /* set up client prefix */
285 if (flags & M_NOIPREFIX)
286 prefix = NULL;
287 else
288 prefix = msg_get_prefix ();
289 prefix_sep = " ";
290 if (!prefix)
291 prefix_sep = prefix = "";
293 /* virtual output capability used to copy output to management subsystem */
294 if (!forked)
296 const struct virtual_output *vo = msg_get_virtual_output ();
297 if (vo)
299 openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s",
300 prefix,
301 prefix_sep,
302 m1);
303 virtual_output_print (vo, flags, m2);
307 if (!(flags & M_MSG_VIRT_OUT))
309 if (use_syslog && !std_redir && !forked)
311 #if SYSLOG_CAPABILITY
312 syslog (level, "%s%s%s",
313 prefix,
314 prefix_sep,
315 m1);
316 #endif
318 else
320 FILE *fp = msg_fp(flags);
321 const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME);
323 if ((flags & M_NOPREFIX) || suppress_timestamps)
325 fprintf (fp, "%s%s%s%s",
326 prefix,
327 prefix_sep,
329 (flags&M_NOLF) ? "" : "\n");
331 else
333 #ifdef USE_PTHREAD
334 fprintf (fp, "%s [%d] %s%s%s%s",
335 time_string (0, 0, show_usec, &gc),
336 (int) openvpn_thread_self (),
337 prefix,
338 prefix_sep,
340 (flags&M_NOLF) ? "" : "\n");
341 #else
342 fprintf (fp, "%s %s%s%s%s",
343 time_string (0, 0, show_usec, &gc),
344 prefix,
345 prefix_sep,
347 (flags&M_NOLF) ? "" : "\n");
348 #endif
350 fflush(fp);
351 ++x_msg_line_num;
355 if (flags & M_FATAL)
356 msg (M_INFO, "Exiting");
358 mutex_unlock_static (L_MSG);
360 if (flags & M_FATAL)
361 openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
363 if (flags & M_USAGE_SMALL)
364 usage_small ();
366 gc_free (&gc);
370 * Apply muting filter.
372 bool
373 dont_mute (unsigned int flags)
375 bool ret = true;
376 if (mute_cutoff > 0 && !(flags & M_NOMUTE))
378 const int mute_level = DECODE_MUTE_LEVEL (flags);
379 if (mute_level > 0 && mute_level == mute_category)
381 if (mute_count == mute_cutoff)
382 msg (M_INFO | M_NOMUTE, "NOTE: --mute triggered...");
383 if (++mute_count > mute_cutoff)
384 ret = false;
386 else
388 const int suppressed = mute_count - mute_cutoff;
389 if (suppressed > 0)
390 msg (M_INFO | M_NOMUTE,
391 "%d variation(s) on previous %d message(s) suppressed by --mute",
392 suppressed,
393 mute_cutoff);
394 mute_count = 1;
395 mute_category = mute_level;
398 return ret;
401 void
402 assert_failed (const char *filename, int line)
404 msg (M_FATAL, "Assertion failed at %s:%d", filename, line);
408 * Fail memory allocation. Don't use msg() because it tries
409 * to allocate memory as part of its operation.
411 void
412 out_of_memory (void)
414 fprintf (stderr, PACKAGE_NAME ": Out of Memory\n");
415 exit (1);
418 void
419 open_syslog (const char *pgmname, bool stdio_to_null)
421 #if SYSLOG_CAPABILITY
422 if (!msgfp && !std_redir)
424 if (!use_syslog)
426 pgmname_syslog = string_alloc (pgmname ? pgmname : PACKAGE, NULL);
427 openlog (pgmname_syslog, LOG_PID, LOG_OPENVPN);
428 use_syslog = true;
430 /* Better idea: somehow pipe stdout/stderr output to msg() */
431 if (stdio_to_null)
432 set_std_files_to_null (false);
435 #else
436 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");
437 #endif
440 void
441 close_syslog ()
443 #if SYSLOG_CAPABILITY
444 if (use_syslog)
446 closelog();
447 use_syslog = false;
448 if (pgmname_syslog)
450 free (pgmname_syslog);
451 pgmname_syslog = NULL;
454 #endif
457 #ifdef WIN32
459 static HANDLE orig_stderr;
461 HANDLE
462 get_orig_stderr (void)
464 if (orig_stderr)
465 return orig_stderr;
466 else
467 return GetStdHandle (STD_ERROR_HANDLE);
470 #endif
472 void
473 redirect_stdout_stderr (const char *file, bool append)
475 #if defined(WIN32)
476 if (!std_redir)
478 HANDLE log_handle;
479 int log_fd;
480 struct security_attributes sa;
482 init_security_attributes_allow_all (&sa);
484 log_handle = CreateFile (file,
485 GENERIC_WRITE,
486 FILE_SHARE_READ,
487 &sa.sa,
488 append ? OPEN_ALWAYS : CREATE_ALWAYS,
489 FILE_ATTRIBUTE_NORMAL,
490 NULL);
492 if (log_handle == INVALID_HANDLE_VALUE)
494 msg (M_WARN|M_ERRNO, "Warning: cannot open --log file: %s", file);
495 return;
498 /* append to logfile? */
499 if (append)
501 if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
502 msg (M_ERR, "Error: cannot seek to end of --log file: %s", file);
505 /* save original stderr for password prompts */
506 orig_stderr = GetStdHandle (STD_ERROR_HANDLE);
508 /* set up for redirection */
509 if (!SetStdHandle (STD_OUTPUT_HANDLE, log_handle)
510 || !SetStdHandle (STD_ERROR_HANDLE, log_handle))
511 msg (M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file);
513 /* direct stdout/stderr to point to log_handle */
514 log_fd = _open_osfhandle ((intptr_t)log_handle, _O_TEXT);
515 if (log_fd == -1)
516 msg (M_ERR, "Error: --log redirect failed due to _open_osfhandle failure");
518 /* open log_handle as FILE stream */
519 ASSERT (msgfp == NULL);
520 msgfp = _fdopen (log_fd, "w");
521 if (msgfp == NULL)
522 msg (M_ERR, "Error: --log redirect failed due to _fdopen");
524 std_redir = true;
526 #elif defined(HAVE_DUP2)
527 if (!std_redir)
529 int out = open (file,
530 O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC),
531 S_IRUSR | S_IWUSR);
533 if (out < 0)
535 msg (M_WARN|M_ERRNO, "Warning: Error redirecting stdout/stderr to --log file: %s", file);
536 return;
539 if (dup2 (out, 1) == -1)
540 msg (M_ERR, "--log file redirection error on stdout");
541 if (dup2 (out, 2) == -1)
542 msg (M_ERR, "--log file redirection error on stderr");
544 if (out > 2)
545 close (out);
547 std_redir = true;
550 #else
551 msg (M_WARN, "WARNING: The --log option is not supported on this OS because it lacks the dup2 function");
552 #endif
556 * Functions used to check return status
557 * of I/O operations.
560 unsigned int x_cs_info_level; /* GLOBAL */
561 unsigned int x_cs_verbose_level; /* GLOBAL */
562 unsigned int x_cs_err_delay_ms; /* GLOBAL */
564 void
565 reset_check_status ()
567 x_cs_info_level = 0;
568 x_cs_verbose_level = 0;
571 void
572 set_check_status (unsigned int info_level, unsigned int verbose_level)
574 x_cs_info_level = info_level;
575 x_cs_verbose_level = verbose_level;
579 * Called after most socket or tun/tap operations, via the inline
580 * function check_status().
582 * Decide if we should print an error message, and see if we can
583 * extract any useful info from the error, such as a Path MTU hint
584 * from the OS.
586 void
587 x_check_status (int status,
588 const char *description,
589 struct link_socket *sock,
590 struct tuntap *tt)
592 const int my_errno = (sock ? openvpn_errno_socket () : (int)openvpn_errno ());
593 const char *extended_msg = NULL;
595 msg (x_cs_verbose_level, "%s %s returned %d",
596 sock ? proto2ascii (sock->info.proto, true) : "",
597 description,
598 status);
600 if (status < 0)
602 struct gc_arena gc = gc_new ();
603 #if EXTENDED_SOCKET_ERROR_CAPABILITY
604 /* get extended socket error message and possible PMTU hint from OS */
605 if (sock)
607 int mtu;
608 extended_msg = format_extended_socket_error (sock->sd, &mtu, &gc);
609 if (mtu > 0 && sock->mtu != mtu)
611 sock->mtu = mtu;
612 sock->info.mtu_changed = true;
615 #elif defined(WIN32)
616 /* get possible driver error from TAP-Win32 driver */
617 extended_msg = tap_win32_getinfo (tt, &gc);
618 #endif
619 if (!ignore_sys_error (my_errno))
621 if (extended_msg)
622 msg (x_cs_info_level, "%s %s [%s]: %s (code=%d)",
623 description,
624 sock ? proto2ascii (sock->info.proto, true) : "",
625 extended_msg,
626 strerror_ts (my_errno, &gc),
627 my_errno);
628 else
629 msg (x_cs_info_level, "%s %s: %s (code=%d)",
630 description,
631 sock ? proto2ascii (sock->info.proto, true) : "",
632 strerror_ts (my_errno, &gc),
633 my_errno);
635 if (x_cs_err_delay_ms)
636 sleep_milliseconds (x_cs_err_delay_ms);
638 gc_free (&gc);
643 * In multiclient mode, put a client-specific prefix
644 * before each message.
646 const char *x_msg_prefix; /* GLOBAL */
648 #ifdef USE_PTHREAD
649 pthread_key_t x_msg_prefix_key; /* GLOBAL */
650 #endif
653 * Allow MSG to be redirected through a virtual_output object
656 const struct virtual_output *x_msg_virtual_output; /* GLOBAL */
659 * Init thread-local variables
662 void
663 msg_thread_init (void)
665 #ifdef USE_PTHREAD
666 ASSERT (!pthread_key_create (&x_msg_prefix_key, NULL));
667 #endif
670 void
671 msg_thread_uninit (void)
673 #ifdef USE_PTHREAD
674 pthread_key_delete (x_msg_prefix_key);
675 #endif
679 * Exiting.
682 void
683 openvpn_exit (const int status)
685 #ifdef ENABLE_PLUGIN
686 void plugin_abort (void);
687 #endif
689 #ifdef WIN32
690 uninit_win32 ();
691 #endif
693 close_syslog ();
695 #ifdef ENABLE_PLUGIN
696 plugin_abort ();
697 #endif
699 #if PORT_SHARE
700 if (port_share)
701 port_share_abort (port_share);
702 #endif
704 #ifdef ABORT_ON_ERROR
705 if (status == OPENVPN_EXIT_STATUS_ERROR)
706 abort ();
707 #endif
709 if (status == OPENVPN_EXIT_STATUS_GOOD)
710 perf_output_results ();
712 exit (status);
716 * Translate msg flags into a string
718 const char *
719 msg_flags_string (const unsigned int flags, struct gc_arena *gc)
721 struct buffer out = alloc_buf_gc (16, gc);
722 if (flags == M_INFO)
723 buf_printf (&out, "I");
724 if (flags & M_FATAL)
725 buf_printf (&out, "F");
726 if (flags & M_NONFATAL)
727 buf_printf (&out, "N");
728 if (flags & M_WARN)
729 buf_printf (&out, "W");
730 if (flags & M_DEBUG)
731 buf_printf (&out, "D");
732 return BSTR (&out);
735 #ifdef ENABLE_DEBUG
736 void
737 crash (void)
739 char *null = NULL;
740 *null = 0;
742 #endif
744 #ifdef WIN32
746 const char *
747 strerror_win32 (DWORD errnum, struct gc_arena *gc)
750 * This code can be omitted, though often the Windows
751 * WSA error messages are less informative than the
752 * Posix equivalents.
754 #if 1
755 switch (errnum) {
757 * When the TAP-Win32 driver returns STATUS_UNSUCCESSFUL, this code
758 * gets returned to user space.
760 case ERROR_GEN_FAILURE:
761 return "General failure (ERROR_GEN_FAILURE)";
762 case ERROR_IO_PENDING:
763 return "I/O Operation in progress (ERROR_IO_PENDING)";
764 case WSA_IO_INCOMPLETE:
765 return "I/O Operation in progress (WSA_IO_INCOMPLETE)";
766 case WSAEINTR:
767 return "Interrupted system call (WSAEINTR)";
768 case WSAEBADF:
769 return "Bad file number (WSAEBADF)";
770 case WSAEACCES:
771 return "Permission denied (WSAEACCES)";
772 case WSAEFAULT:
773 return "Bad address (WSAEFAULT)";
774 case WSAEINVAL:
775 return "Invalid argument (WSAEINVAL)";
776 case WSAEMFILE:
777 return "Too many open files (WSAEMFILE)";
778 case WSAEWOULDBLOCK:
779 return "Operation would block (WSAEWOULDBLOCK)";
780 case WSAEINPROGRESS:
781 return "Operation now in progress (WSAEINPROGRESS)";
782 case WSAEALREADY:
783 return "Operation already in progress (WSAEALREADY)";
784 case WSAEDESTADDRREQ:
785 return "Destination address required (WSAEDESTADDRREQ)";
786 case WSAEMSGSIZE:
787 return "Message too long (WSAEMSGSIZE)";
788 case WSAEPROTOTYPE:
789 return "Protocol wrong type for socket (WSAEPROTOTYPE)";
790 case WSAENOPROTOOPT:
791 return "Bad protocol option (WSAENOPROTOOPT)";
792 case WSAEPROTONOSUPPORT:
793 return "Protocol not supported (WSAEPROTONOSUPPORT)";
794 case WSAESOCKTNOSUPPORT:
795 return "Socket type not supported (WSAESOCKTNOSUPPORT)";
796 case WSAEOPNOTSUPP:
797 return "Operation not supported on socket (WSAEOPNOTSUPP)";
798 case WSAEPFNOSUPPORT:
799 return "Protocol family not supported (WSAEPFNOSUPPORT)";
800 case WSAEAFNOSUPPORT:
801 return "Address family not supported by protocol family (WSAEAFNOSUPPORT)";
802 case WSAEADDRINUSE:
803 return "Address already in use (WSAEADDRINUSE)";
804 case WSAENETDOWN:
805 return "Network is down (WSAENETDOWN)";
806 case WSAENETUNREACH:
807 return "Network is unreachable (WSAENETUNREACH)";
808 case WSAENETRESET:
809 return "Net dropped connection or reset (WSAENETRESET)";
810 case WSAECONNABORTED:
811 return "Software caused connection abort (WSAECONNABORTED)";
812 case WSAECONNRESET:
813 return "Connection reset by peer (WSAECONNRESET)";
814 case WSAENOBUFS:
815 return "No buffer space available (WSAENOBUFS)";
816 case WSAEISCONN:
817 return "Socket is already connected (WSAEISCONN)";
818 case WSAENOTCONN:
819 return "Socket is not connected (WSAENOTCONN)";
820 case WSAETIMEDOUT:
821 return "Connection timed out (WSAETIMEDOUT)";
822 case WSAECONNREFUSED:
823 return "Connection refused (WSAECONNREFUSED)";
824 case WSAELOOP:
825 return "Too many levels of symbolic links (WSAELOOP)";
826 case WSAENAMETOOLONG:
827 return "File name too long (WSAENAMETOOLONG)";
828 case WSAEHOSTDOWN:
829 return "Host is down (WSAEHOSTDOWN)";
830 case WSAEHOSTUNREACH:
831 return "No Route to Host (WSAEHOSTUNREACH)";
832 case WSAENOTEMPTY:
833 return "Directory not empty (WSAENOTEMPTY)";
834 case WSAEPROCLIM:
835 return "Too many processes (WSAEPROCLIM)";
836 case WSAEUSERS:
837 return "Too many users (WSAEUSERS)";
838 case WSAEDQUOT:
839 return "Disc Quota Exceeded (WSAEDQUOT)";
840 case WSAESTALE:
841 return "Stale NFS file handle (WSAESTALE)";
842 case WSASYSNOTREADY:
843 return "Network SubSystem is unavailable (WSASYSNOTREADY)";
844 case WSAVERNOTSUPPORTED:
845 return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)";
846 case WSANOTINITIALISED:
847 return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)";
848 case WSAEREMOTE:
849 return "Too many levels of remote in path (WSAEREMOTE)";
850 case WSAHOST_NOT_FOUND:
851 return "Host not found (WSAHOST_NOT_FOUND)";
852 default:
853 break;
855 #endif
857 /* format a windows error message */
859 char message[256];
860 struct buffer out = alloc_buf_gc (256, gc);
861 const int status = FormatMessage (
862 FORMAT_MESSAGE_IGNORE_INSERTS
863 | FORMAT_MESSAGE_FROM_SYSTEM
864 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
865 NULL,
866 errnum,
868 message,
869 sizeof (message),
870 NULL);
871 if (!status)
873 buf_printf (&out, "[Unknown Win32 Error]");
875 else
877 char *cp;
878 for (cp = message; *cp != '\0'; ++cp)
880 if (*cp == '\n' || *cp == '\r')
881 *cp = ' ';
884 buf_printf(&out, "%s", message);
887 return BSTR (&out);
891 #endif