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.
7 *
8 * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
9 *
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.
13 *
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.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29
30 #include "syshead.h"
31
32 #include "error.h"
33 #include "buffer.h"
34 #include "init.h"
35 #include "misc.h"
36 #include "win32.h"
37 #include "socket.h"
38 #include "tun.h"
39 #include "otime.h"
40 #include "perf.h"
41 #include "status.h"
42 #include "integer.h"
43 #include "ps.h"
44 #include "mstats.h"
45
46
47 #if SYSLOG_CAPABILITY
48 #ifndef LOG_OPENVPN
49 #define LOG_OPENVPN LOG_DAEMON
50 #endif
51 #endif
52
53 /* Globals */
54 unsigned int x_debug_level; /* GLOBAL */
55
56 /* Mute state */
57 static int mute_cutoff; /* GLOBAL */
58 static int mute_count; /* GLOBAL */
59 static int mute_category; /* GLOBAL */
60
61 /*
62 * Output mode priorities are as follows:
63 *
64 * (1) --log-x overrides everything
65 * (2) syslog is used if --daemon is defined and not --log-x
66 * (3) if OPENVPN_DEBUG_COMMAND_LINE is defined, output
67 * to constant logfile name.
68 * (4) Output to stdout.
69 */
70
71 /* If true, indicates that stdin/stdout/stderr
72 * have been redirected due to --log */
73 static bool std_redir; /* GLOBAL */
74
75 /* Should messages be written to the syslog? */
76 static bool use_syslog; /* GLOBAL */
77
78 /* Should stdout/stderr be be parsable and always be prefixed with time
79 * and message flags */
80 static bool machine_readable_output; /* GLOBAL */
81
82 /* Should timestamps be included on messages to stdout/stderr? */
83 static bool suppress_timestamps; /* GLOBAL */
84
85 /* The program name passed to syslog */
86 #if SYSLOG_CAPABILITY
87 static char *pgmname_syslog; /* GLOBAL */
88 #endif
89
90 /* If non-null, messages should be written here (used for debugging only) */
91 static FILE *msgfp; /* GLOBAL */
92
93 /* If true, we forked from main OpenVPN process */
94 static bool forked; /* GLOBAL */
95
96 /* our default output targets */
97 static FILE *default_out; /* GLOBAL */
98 static FILE *default_err; /* GLOBAL */
99
100 void
msg_forked(void)101 msg_forked(void)
102 {
103 forked = true;
104 }
105
106 bool
set_debug_level(const int level,const unsigned int flags)107 set_debug_level(const int level, const unsigned int flags)
108 {
109 const int ceiling = 15;
110
111 if (level >= 0 && level <= ceiling)
112 {
113 x_debug_level = level;
114 return true;
115 }
116 else if (flags & SDL_CONSTRAIN)
117 {
118 x_debug_level = constrain_int(level, 0, ceiling);
119 return true;
120 }
121 return false;
122 }
123
124 bool
set_mute_cutoff(const int cutoff)125 set_mute_cutoff(const int cutoff)
126 {
127 if (cutoff >= 0)
128 {
129 mute_cutoff = cutoff;
130 return true;
131 }
132 else
133 {
134 return false;
135 }
136 }
137
138 int
get_debug_level(void)139 get_debug_level(void)
140 {
141 return x_debug_level;
142 }
143
144 int
get_mute_cutoff(void)145 get_mute_cutoff(void)
146 {
147 return mute_cutoff;
148 }
149
150 void
set_suppress_timestamps(bool suppressed)151 set_suppress_timestamps(bool suppressed)
152 {
153 suppress_timestamps = suppressed;
154 }
155
156 void
set_machine_readable_output(bool parsable)157 set_machine_readable_output(bool parsable)
158 {
159 machine_readable_output = parsable;
160 }
161
162 void
error_reset(void)163 error_reset(void)
164 {
165 use_syslog = std_redir = false;
166 suppress_timestamps = false;
167 machine_readable_output = false;
168 x_debug_level = 1;
169 mute_cutoff = 0;
170 mute_count = 0;
171 mute_category = 0;
172 default_out = OPENVPN_MSG_FP;
173 default_err = OPENVPN_MSG_FP;
174
175 #ifdef OPENVPN_DEBUG_COMMAND_LINE
176 msgfp = fopen(OPENVPN_DEBUG_FILE, "w");
177 if (!msgfp)
178 {
179 openvpn_exit(OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
180 }
181 #else /* ifdef OPENVPN_DEBUG_COMMAND_LINE */
182 msgfp = NULL;
183 #endif
184 }
185
186 void
errors_to_stderr(void)187 errors_to_stderr(void)
188 {
189 default_err = OPENVPN_ERROR_FP;
190 }
191
192 /*
193 * Return a file to print messages to before syslog is opened.
194 */
195 FILE *
msg_fp(const unsigned int flags)196 msg_fp(const unsigned int flags)
197 {
198 FILE *fp = msgfp;
199 if (!fp)
200 {
201 fp = (flags & (M_FATAL|M_USAGE_SMALL)) ? default_err : default_out;
202 }
203 if (!fp)
204 {
205 openvpn_exit(OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
206 }
207 return fp;
208 }
209
210 #define SWAP { tmp = m1; m1 = m2; m2 = tmp; }
211
212 int x_msg_line_num; /* GLOBAL */
213
214 void
x_msg(const unsigned int flags,const char * format,...)215 x_msg(const unsigned int flags, const char *format, ...)
216 {
217 va_list arglist;
218 va_start(arglist, format);
219 x_msg_va(flags, format, arglist);
220 va_end(arglist);
221 }
222
223 void
x_msg_va(const unsigned int flags,const char * format,va_list arglist)224 x_msg_va(const unsigned int flags, const char *format, va_list arglist)
225 {
226 struct gc_arena gc;
227 #if SYSLOG_CAPABILITY
228 int level;
229 #endif
230 char *m1;
231 char *m2;
232 char *tmp;
233 int e;
234 const char *prefix;
235 const char *prefix_sep;
236
237 void usage_small(void);
238
239 /* the macro has checked this otherwise */
240 if (!msg_test(flags))
241 {
242 return;
243 }
244
245 e = openvpn_errno();
246
247 /*
248 * Apply muting filter.
249 */
250 /* the macro has checked this otherwise */
251 if (!dont_mute(flags))
252 {
253 return;
254 }
255
256 gc_init(&gc);
257
258 m1 = (char *) gc_malloc(ERR_BUF_SIZE, false, &gc);
259 m2 = (char *) gc_malloc(ERR_BUF_SIZE, false, &gc);
260
261 vsnprintf(m1, ERR_BUF_SIZE, format, arglist);
262 m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */
263
264 if ((flags & M_ERRNO) && e)
265 {
266 openvpn_snprintf(m2, ERR_BUF_SIZE, "%s: %s (errno=%d)",
267 m1, strerror(e), e);
268 SWAP;
269 }
270
271 if (flags & M_OPTERR)
272 {
273 openvpn_snprintf(m2, ERR_BUF_SIZE, "Options error: %s", m1);
274 SWAP;
275 }
276
277 #if SYSLOG_CAPABILITY
278 if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL))
279 {
280 level = LOG_ERR;
281 }
282 else if (flags & M_WARN)
283 {
284 level = LOG_WARNING;
285 }
286 else
287 {
288 level = LOG_NOTICE;
289 }
290 #endif
291
292 /* set up client prefix */
293 if (flags & M_NOIPREFIX)
294 {
295 prefix = NULL;
296 }
297 else
298 {
299 prefix = msg_get_prefix();
300 }
301 prefix_sep = " ";
302 if (!prefix)
303 {
304 prefix_sep = prefix = "";
305 }
306
307 /* virtual output capability used to copy output to management subsystem */
308 if (!forked)
309 {
310 const struct virtual_output *vo = msg_get_virtual_output();
311 if (vo)
312 {
313 openvpn_snprintf(m2, ERR_BUF_SIZE, "%s%s%s",
314 prefix,
315 prefix_sep,
316 m1);
317 virtual_output_print(vo, flags, m2);
318 }
319 }
320
321 if (!(flags & M_MSG_VIRT_OUT))
322 {
323 if (use_syslog && !std_redir && !forked)
324 {
325 #if SYSLOG_CAPABILITY
326 syslog(level, "%s%s%s",
327 prefix,
328 prefix_sep,
329 m1);
330 #endif
331 }
332 else
333 {
334 FILE *fp = msg_fp(flags);
335 const bool show_usec = check_debug_level(DEBUG_LEVEL_USEC_TIME);
336
337 if (machine_readable_output)
338 {
339 struct timeval tv;
340 gettimeofday(&tv, NULL);
341
342 fprintf(fp, "%" PRIi64 ".%06ld %x %s%s%s%s",
343 (int64_t)tv.tv_sec,
344 (long)tv.tv_usec,
345 flags,
346 prefix,
347 prefix_sep,
348 m1,
349 "\n");
350
351 }
352 else if ((flags & M_NOPREFIX) || suppress_timestamps)
353 {
354 fprintf(fp, "%s%s%s%s",
355 prefix,
356 prefix_sep,
357 m1,
358 (flags&M_NOLF) ? "" : "\n");
359 }
360 else
361 {
362 fprintf(fp, "%s %s%s%s%s",
363 time_string(0, 0, show_usec, &gc),
364 prefix,
365 prefix_sep,
366 m1,
367 (flags&M_NOLF) ? "" : "\n");
368 }
369 fflush(fp);
370 ++x_msg_line_num;
371 }
372 }
373
374 if (flags & M_FATAL)
375 {
376 msg(M_INFO, "Exiting due to fatal error");
377 }
378
379 if (flags & M_FATAL)
380 {
381 openvpn_exit(OPENVPN_EXIT_STATUS_ERROR); /* exit point */
382
383 }
384 if (flags & M_USAGE_SMALL)
385 {
386 usage_small();
387 }
388
389 gc_free(&gc);
390 }
391
392 /*
393 * Apply muting filter.
394 */
395 bool
dont_mute(unsigned int flags)396 dont_mute(unsigned int flags)
397 {
398 bool ret = true;
399 if (mute_cutoff > 0 && !(flags & M_NOMUTE))
400 {
401 const int mute_level = DECODE_MUTE_LEVEL(flags);
402 if (mute_level > 0 && mute_level == mute_category)
403 {
404 if (mute_count == mute_cutoff)
405 {
406 msg(M_INFO | M_NOMUTE, "NOTE: --mute triggered...");
407 }
408 if (++mute_count > mute_cutoff)
409 {
410 ret = false;
411 }
412 }
413 else
414 {
415 const int suppressed = mute_count - mute_cutoff;
416 if (suppressed > 0)
417 {
418 msg(M_INFO | M_NOMUTE,
419 "%d variation(s) on previous %d message(s) suppressed by --mute",
420 suppressed,
421 mute_cutoff);
422 }
423 mute_count = 1;
424 mute_category = mute_level;
425 }
426 }
427 return ret;
428 }
429
430 void
assert_failed(const char * filename,int line,const char * condition)431 assert_failed(const char *filename, int line, const char *condition)
432 {
433 if (condition)
434 {
435 msg(M_FATAL, "Assertion failed at %s:%d (%s)", filename, line, condition);
436 }
437 else
438 {
439 msg(M_FATAL, "Assertion failed at %s:%d", filename, line);
440 }
441 _exit(1);
442 }
443
444 /*
445 * Fail memory allocation. Don't use msg() because it tries
446 * to allocate memory as part of its operation.
447 */
448 void
out_of_memory(void)449 out_of_memory(void)
450 {
451 fprintf(stderr, PACKAGE_NAME ": Out of Memory\n");
452 exit(1);
453 }
454
455 void
open_syslog(const char * pgmname,bool stdio_to_null)456 open_syslog(const char *pgmname, bool stdio_to_null)
457 {
458 #if SYSLOG_CAPABILITY
459 if (!msgfp && !std_redir)
460 {
461 if (!use_syslog)
462 {
463 pgmname_syslog = string_alloc(pgmname ? pgmname : PACKAGE, NULL);
464 openlog(pgmname_syslog, LOG_PID, LOG_OPENVPN);
465 use_syslog = true;
466
467 /* Better idea: somehow pipe stdout/stderr output to msg() */
468 if (stdio_to_null)
469 {
470 set_std_files_to_null(false);
471 }
472 }
473 }
474 #else /* if SYSLOG_CAPABILITY */
475 msg(M_WARN, "Warning on use of --daemon: this operating system lacks daemon logging features, therefore when I become a daemon, I won't be able to log status or error messages");
476 #endif
477 }
478
479 void
close_syslog(void)480 close_syslog(void)
481 {
482 #if SYSLOG_CAPABILITY
483 if (use_syslog)
484 {
485 closelog();
486 use_syslog = false;
487 free(pgmname_syslog);
488 pgmname_syslog = NULL;
489 }
490 #endif
491 }
492
493 #ifdef _WIN32
494
495 static HANDLE orig_stderr;
496
497 HANDLE
get_orig_stderr(void)498 get_orig_stderr(void)
499 {
500 if (orig_stderr)
501 {
502 return orig_stderr;
503 }
504 else
505 {
506 return GetStdHandle(STD_ERROR_HANDLE);
507 }
508 }
509
510 #endif
511
512 void
redirect_stdout_stderr(const char * file,bool append)513 redirect_stdout_stderr(const char *file, bool append)
514 {
515 #if defined(_WIN32)
516 if (!std_redir)
517 {
518 struct gc_arena gc = gc_new();
519 HANDLE log_handle;
520 int log_fd;
521
522 SECURITY_ATTRIBUTES saAttr;
523 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
524 saAttr.bInheritHandle = TRUE;
525 saAttr.lpSecurityDescriptor = NULL;
526
527 log_handle = CreateFileW(wide_string(file, &gc),
528 GENERIC_WRITE,
529 FILE_SHARE_READ,
530 &saAttr,
531 append ? OPEN_ALWAYS : CREATE_ALWAYS,
532 FILE_ATTRIBUTE_NORMAL,
533 NULL);
534
535 gc_free(&gc);
536
537 if (log_handle == INVALID_HANDLE_VALUE)
538 {
539 msg(M_WARN|M_ERRNO, "Warning: cannot open --log file: %s", file);
540 return;
541 }
542
543 /* append to logfile? */
544 if (append)
545 {
546 if (SetFilePointer(log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
547 {
548 msg(M_ERR, "Error: cannot seek to end of --log file: %s", file);
549 }
550 }
551
552 /* save original stderr for password prompts */
553 orig_stderr = GetStdHandle(STD_ERROR_HANDLE);
554
555 #if 0 /* seems not be necessary with stdout/stderr redirection below*/
556 /* set up for redirection */
557 if (!SetStdHandle(STD_OUTPUT_HANDLE, log_handle)
558 || !SetStdHandle(STD_ERROR_HANDLE, log_handle))
559 {
560 msg(M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file);
561 }
562 #endif
563
564 /* direct stdout/stderr to point to log_handle */
565 log_fd = _open_osfhandle((intptr_t)log_handle, _O_TEXT);
566 if (log_fd == -1)
567 {
568 msg(M_ERR, "Error: --log redirect failed due to _open_osfhandle failure");
569 }
570
571 /* open log_handle as FILE stream */
572 ASSERT(msgfp == NULL);
573 msgfp = _fdopen(log_fd, "wt");
574 if (msgfp == NULL)
575 {
576 msg(M_ERR, "Error: --log redirect failed due to _fdopen");
577 }
578
579 /* redirect C-library stdout/stderr to log file */
580 if (_dup2(log_fd, 1) == -1 || _dup2(log_fd, 2) == -1)
581 {
582 msg(M_WARN, "Error: --log redirect of stdout/stderr failed");
583 }
584
585 std_redir = true;
586 }
587 #elif defined(HAVE_DUP2)
588 if (!std_redir)
589 {
590 int out = open(file,
591 O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC),
592 S_IRUSR | S_IWUSR);
593
594 if (out < 0)
595 {
596 msg(M_WARN|M_ERRNO, "Warning: Error redirecting stdout/stderr to --log file: %s", file);
597 return;
598 }
599
600 if (dup2(out, 1) == -1)
601 {
602 msg(M_ERR, "--log file redirection error on stdout");
603 }
604 if (dup2(out, 2) == -1)
605 {
606 msg(M_ERR, "--log file redirection error on stderr");
607 }
608
609 if (out > 2)
610 {
611 close(out);
612 }
613
614 std_redir = true;
615 }
616
617 #else /* if defined(_WIN32) */
618 msg(M_WARN, "WARNING: The --log option is not supported on this OS because it lacks the dup2 function");
619 #endif /* if defined(_WIN32) */
620 }
621
622 /*
623 * Functions used to check return status
624 * of I/O operations.
625 */
626
627 unsigned int x_cs_info_level; /* GLOBAL */
628 unsigned int x_cs_verbose_level; /* GLOBAL */
629 unsigned int x_cs_err_delay_ms; /* GLOBAL */
630
631 void
reset_check_status(void)632 reset_check_status(void)
633 {
634 x_cs_info_level = 0;
635 x_cs_verbose_level = 0;
636 }
637
638 void
set_check_status(unsigned int info_level,unsigned int verbose_level)639 set_check_status(unsigned int info_level, unsigned int verbose_level)
640 {
641 x_cs_info_level = info_level;
642 x_cs_verbose_level = verbose_level;
643 }
644
645 /*
646 * Called after most socket or tun/tap operations, via the inline
647 * function check_status().
648 *
649 * Decide if we should print an error message, and see if we can
650 * extract any useful info from the error, such as a Path MTU hint
651 * from the OS.
652 */
653 void
x_check_status(int status,const char * description,struct link_socket * sock,struct tuntap * tt)654 x_check_status(int status,
655 const char *description,
656 struct link_socket *sock,
657 struct tuntap *tt)
658 {
659 const int my_errno = openvpn_errno();
660 const char *extended_msg = NULL;
661
662 msg(x_cs_verbose_level, "%s %s returned %d",
663 sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "",
664 description,
665 status);
666
667 if (status < 0)
668 {
669 struct gc_arena gc = gc_new();
670 #if EXTENDED_SOCKET_ERROR_CAPABILITY
671 /* get extended socket error message and possible PMTU hint from OS */
672 if (sock)
673 {
674 int mtu;
675 extended_msg = format_extended_socket_error(sock->sd, &mtu, &gc);
676 if (mtu > 0 && sock->mtu != mtu)
677 {
678 sock->mtu = mtu;
679 sock->info.mtu_changed = true;
680 }
681 }
682 #elif defined(_WIN32)
683 /* get possible driver error from TAP-Windows driver */
684 if (tuntap_defined(tt))
685 {
686 extended_msg = tap_win_getinfo(tt, &gc);
687 }
688 #endif
689 if (!ignore_sys_error(my_errno))
690 {
691 if (extended_msg)
692 {
693 msg(x_cs_info_level, "%s %s [%s]: %s (fd=%d,code=%d)", description,
694 sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "",
695 extended_msg, strerror(my_errno), sock ? sock->sd : -1, my_errno);
696 }
697 else
698 {
699 msg(x_cs_info_level, "%s %s: %s (fd=%d,code=%d)", description,
700 sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "",
701 strerror(my_errno), sock ? sock->sd : -1, my_errno);
702 }
703
704 if (x_cs_err_delay_ms)
705 {
706 platform_sleep_milliseconds(x_cs_err_delay_ms);
707 }
708 }
709 gc_free(&gc);
710 }
711 }
712
713 /*
714 * In multiclient mode, put a client-specific prefix
715 * before each message.
716 */
717 const char *x_msg_prefix; /* GLOBAL */
718
719 /*
720 * Allow MSG to be redirected through a virtual_output object
721 */
722
723 const struct virtual_output *x_msg_virtual_output; /* GLOBAL */
724
725 /*
726 * Exiting.
727 */
728
729 void
openvpn_exit(const int status)730 openvpn_exit(const int status)
731 {
732 if (!forked)
733 {
734 tun_abort();
735
736 #ifdef _WIN32
737 uninit_win32();
738 #endif
739 remove_pid_file();
740
741 close_syslog();
742
743 #ifdef ENABLE_PLUGIN
744 plugin_abort();
745 #endif
746
747 #if PORT_SHARE
748 if (port_share)
749 {
750 port_share_abort(port_share);
751 }
752 #endif
753
754 #ifdef ENABLE_MEMSTATS
755 mstats_close();
756 #endif
757
758 #ifdef ABORT_ON_ERROR
759 if (status == OPENVPN_EXIT_STATUS_ERROR)
760 {
761 abort();
762 }
763 #endif
764
765 if (status == OPENVPN_EXIT_STATUS_GOOD)
766 {
767 perf_output_results();
768 }
769 }
770
771 exit(status);
772 }
773
774 /*
775 * Translate msg flags into a string
776 */
777 const char *
msg_flags_string(const unsigned int flags,struct gc_arena * gc)778 msg_flags_string(const unsigned int flags, struct gc_arena *gc)
779 {
780 struct buffer out = alloc_buf_gc(16, gc);
781 if (flags == M_INFO)
782 {
783 buf_printf(&out, "I");
784 }
785 if (flags & M_FATAL)
786 {
787 buf_printf(&out, "F");
788 }
789 if (flags & M_NONFATAL)
790 {
791 buf_printf(&out, "N");
792 }
793 if (flags & M_WARN)
794 {
795 buf_printf(&out, "W");
796 }
797 if (flags & M_DEBUG)
798 {
799 buf_printf(&out, "D");
800 }
801 return BSTR(&out);
802 }
803
804 #ifdef ENABLE_DEBUG
805 void
crash(void)806 crash(void)
807 {
808 char *null = NULL;
809 *null = 0;
810 }
811 #endif
812
813 #ifdef _WIN32
814
815 const char *
strerror_win32(DWORD errnum,struct gc_arena * gc)816 strerror_win32(DWORD errnum, struct gc_arena *gc)
817 {
818 /*
819 * This code can be omitted, though often the Windows
820 * WSA error messages are less informative than the
821 * Posix equivalents.
822 */
823 #if 1
824 switch (errnum)
825 {
826 /*
827 * When the TAP-Windows driver returns STATUS_UNSUCCESSFUL, this code
828 * gets returned to user space.
829 */
830 case ERROR_GEN_FAILURE:
831 return "General failure (ERROR_GEN_FAILURE)";
832
833 case ERROR_IO_PENDING:
834 return "I/O Operation in progress (ERROR_IO_PENDING)";
835
836 case WSA_IO_INCOMPLETE:
837 return "I/O Operation in progress (WSA_IO_INCOMPLETE)";
838
839 case WSAEINTR:
840 return "Interrupted system call (WSAEINTR)";
841
842 case WSAEBADF:
843 return "Bad file number (WSAEBADF)";
844
845 case WSAEACCES:
846 return "Permission denied (WSAEACCES)";
847
848 case WSAEFAULT:
849 return "Bad address (WSAEFAULT)";
850
851 case WSAEINVAL:
852 return "Invalid argument (WSAEINVAL)";
853
854 case WSAEMFILE:
855 return "Too many open files (WSAEMFILE)";
856
857 case WSAEWOULDBLOCK:
858 return "Operation would block (WSAEWOULDBLOCK)";
859
860 case WSAEINPROGRESS:
861 return "Operation now in progress (WSAEINPROGRESS)";
862
863 case WSAEALREADY:
864 return "Operation already in progress (WSAEALREADY)";
865
866 case WSAEDESTADDRREQ:
867 return "Destination address required (WSAEDESTADDRREQ)";
868
869 case WSAEMSGSIZE:
870 return "Message too long (WSAEMSGSIZE)";
871
872 case WSAEPROTOTYPE:
873 return "Protocol wrong type for socket (WSAEPROTOTYPE)";
874
875 case WSAENOPROTOOPT:
876 return "Bad protocol option (WSAENOPROTOOPT)";
877
878 case WSAEPROTONOSUPPORT:
879 return "Protocol not supported (WSAEPROTONOSUPPORT)";
880
881 case WSAESOCKTNOSUPPORT:
882 return "Socket type not supported (WSAESOCKTNOSUPPORT)";
883
884 case WSAEOPNOTSUPP:
885 return "Operation not supported on socket (WSAEOPNOTSUPP)";
886
887 case WSAEPFNOSUPPORT:
888 return "Protocol family not supported (WSAEPFNOSUPPORT)";
889
890 case WSAEAFNOSUPPORT:
891 return "Address family not supported by protocol family (WSAEAFNOSUPPORT)";
892
893 case WSAEADDRINUSE:
894 return "Address already in use (WSAEADDRINUSE)";
895
896 case WSAENETDOWN:
897 return "Network is down (WSAENETDOWN)";
898
899 case WSAENETUNREACH:
900 return "Network is unreachable (WSAENETUNREACH)";
901
902 case WSAENETRESET:
903 return "Net dropped connection or reset (WSAENETRESET)";
904
905 case WSAECONNABORTED:
906 return "Software caused connection abort (WSAECONNABORTED)";
907
908 case WSAECONNRESET:
909 return "Connection reset by peer (WSAECONNRESET)";
910
911 case WSAENOBUFS:
912 return "No buffer space available (WSAENOBUFS)";
913
914 case WSAEISCONN:
915 return "Socket is already connected (WSAEISCONN)";
916
917 case WSAENOTCONN:
918 return "Socket is not connected (WSAENOTCONN)";
919
920 case WSAETIMEDOUT:
921 return "Connection timed out (WSAETIMEDOUT)";
922
923 case WSAECONNREFUSED:
924 return "Connection refused (WSAECONNREFUSED)";
925
926 case WSAELOOP:
927 return "Too many levels of symbolic links (WSAELOOP)";
928
929 case WSAENAMETOOLONG:
930 return "File name too long (WSAENAMETOOLONG)";
931
932 case WSAEHOSTDOWN:
933 return "Host is down (WSAEHOSTDOWN)";
934
935 case WSAEHOSTUNREACH:
936 return "No Route to Host (WSAEHOSTUNREACH)";
937
938 case WSAENOTEMPTY:
939 return "Directory not empty (WSAENOTEMPTY)";
940
941 case WSAEPROCLIM:
942 return "Too many processes (WSAEPROCLIM)";
943
944 case WSAEUSERS:
945 return "Too many users (WSAEUSERS)";
946
947 case WSAEDQUOT:
948 return "Disc Quota Exceeded (WSAEDQUOT)";
949
950 case WSAESTALE:
951 return "Stale NFS file handle (WSAESTALE)";
952
953 case WSASYSNOTREADY:
954 return "Network SubSystem is unavailable (WSASYSNOTREADY)";
955
956 case WSAVERNOTSUPPORTED:
957 return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)";
958
959 case WSANOTINITIALISED:
960 return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)";
961
962 case WSAEREMOTE:
963 return "Too many levels of remote in path (WSAEREMOTE)";
964
965 case WSAHOST_NOT_FOUND:
966 return "Host not found (WSAHOST_NOT_FOUND)";
967
968 default:
969 break;
970 }
971 #endif /* if 1 */
972
973 /* format a windows error message */
974 {
975 char message[256];
976 struct buffer out = alloc_buf_gc(256, gc);
977 const int status = FormatMessage(
978 FORMAT_MESSAGE_IGNORE_INSERTS
979 | FORMAT_MESSAGE_FROM_SYSTEM
980 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
981 NULL,
982 errnum,
983 0,
984 message,
985 sizeof(message),
986 NULL);
987 if (!status)
988 {
989 buf_printf(&out, "[Unknown Win32 Error]");
990 }
991 else
992 {
993 char *cp;
994 for (cp = message; *cp != '\0'; ++cp)
995 {
996 if (*cp == '\n' || *cp == '\r')
997 {
998 *cp = ' ';
999 }
1000 }
1001
1002 buf_printf(&out, "%s", message);
1003 }
1004
1005 return BSTR(&out);
1006 }
1007 }
1008
1009 #endif /* ifdef _WIN32 */
1010