2005-09-26 07:28:27 +02:00
/*
* 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 .
*
2010-04-28 18:31:36 +02:00
* Copyright ( C ) 2002 - 2010 OpenVPN Technologies , Inc . < sales @ openvpn . net >
2005-09-26 07:28:27 +02:00
*
* 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
*/
# 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"
2006-02-16 19:12:24 +01:00
# include "ps.h"
2011-10-18 10:12:51 +02:00
# include "mstats.h"
2005-09-26 07:28:27 +02:00
# ifdef USE_CRYPTO
2011-06-29 14:53:41 +02:00
# ifdef USE_OPENSSL
2005-09-26 07:28:27 +02:00
# include <openssl/err.h>
# endif
2011-06-29 14:53:41 +02:00
# endif
2005-09-26 07:28:27 +02:00
# 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 timestamps be included on messages to stdout/stderr? */
static bool suppress_timestamps ; /* GLOBAL */
/* The program name passed to syslog */
2008-07-26 10:27:50 +02:00
# if SYSLOG_CAPABILITY
2005-09-26 07:28:27 +02:00
static char * pgmname_syslog ; /* GLOBAL */
2008-07-26 10:27:50 +02:00
# endif
2005-09-26 07:28:27 +02:00
/* If non-null, messages should be written here (used for debugging only) */
static FILE * msgfp ; /* GLOBAL */
2006-02-16 19:12:24 +01:00
/* If true, we forked from main OpenVPN process */
static bool forked ; /* GLOBAL */
2009-04-13 05:30:30 +02:00
/* our default output targets */
static FILE * default_out ; /* GLOBAL */
static FILE * default_err ; /* GLOBAL */
2006-02-16 19:12:24 +01:00
void
msg_forked ( void )
{
forked = true ;
}
2005-09-26 07:28:27 +02:00
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
error_reset ( )
{
use_syslog = std_redir = false ;
suppress_timestamps = false ;
x_debug_level = 1 ;
mute_cutoff = 0 ;
mute_count = 0 ;
mute_category = 0 ;
2009-04-13 05:30:30 +02:00
default_out = OPENVPN_MSG_FP ;
default_err = OPENVPN_MSG_FP ;
2005-09-26 07:28:27 +02:00
# 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
}
2009-04-13 05:30:30 +02:00
void
errors_to_stderr ( void )
{
default_err = OPENVPN_ERROR_FP ;
}
2005-09-26 07:28:27 +02:00
/*
* Return a file to print messages to before syslog is opened .
*/
FILE *
2009-04-13 05:30:30 +02:00
msg_fp ( const unsigned int flags )
2005-09-26 07:28:27 +02:00
{
FILE * fp = msgfp ;
if ( ! fp )
2009-04-13 05:30:30 +02:00
fp = ( flags & ( M_FATAL | M_USAGE_SMALL ) ) ? default_err : default_out ;
2005-09-26 07:28:27 +02:00
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 , . . . )
{
struct gc_arena gc ;
va_list arglist ;
# 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
if ( flags & M_ERRNO_SOCK )
e = openvpn_errno_socket ( ) ;
else
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 ) ;
va_start ( arglist , format ) ;
vsnprintf ( m1 , ERR_BUF_SIZE , format , arglist ) ;
va_end ( arglist ) ;
m1 [ ERR_BUF_SIZE - 1 ] = 0 ; /* windows vsnprintf needs this */
if ( ( flags & ( M_ERRNO | M_ERRNO_SOCK ) ) & & e )
{
openvpn_snprintf ( m2 , ERR_BUF_SIZE , " %s: %s (errno=%d) " ,
m1 , strerror_ts ( e , & gc ) , e ) ;
SWAP ;
}
# ifdef USE_CRYPTO
2011-06-29 14:53:41 +02:00
# ifdef USE_OPENSSL
2005-09-26 07:28:27 +02:00
if ( flags & M_SSL )
{
int nerrs = 0 ;
int 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 ;
}
}
2011-06-29 14:53:41 +02:00
# endif
2005-09-26 07:28:27 +02:00
# 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 */
2008-06-11 10:45:09 +02:00
if ( flags & M_NOIPREFIX )
prefix = NULL ;
else
prefix = msg_get_prefix ( ) ;
2005-09-26 07:28:27 +02:00
prefix_sep = " " ;
if ( ! prefix )
prefix_sep = prefix = " " ;
/* virtual output capability used to copy output to management subsystem */
2006-02-16 19:12:24 +01:00
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 ) ;
}
}
2005-09-26 07:28:27 +02:00
if ( ! ( flags & M_MSG_VIRT_OUT ) )
{
2006-02-16 19:12:24 +01:00
if ( use_syslog & & ! std_redir & & ! forked )
2005-09-26 07:28:27 +02:00
{
# if SYSLOG_CAPABILITY
syslog ( level , " %s%s%s " ,
prefix ,
prefix_sep ,
m1 ) ;
# endif
}
else
{
2009-04-13 05:30:30 +02:00
FILE * fp = msg_fp ( flags ) ;
2005-09-26 07:28:27 +02:00
const bool show_usec = check_debug_level ( DEBUG_LEVEL_USEC_TIME ) ;
if ( ( flags & M_NOPREFIX ) | | suppress_timestamps )
{
2005-10-20 07:58:08 +02:00
fprintf ( fp , " %s%s%s%s " ,
2005-09-26 07:28:27 +02:00
prefix ,
prefix_sep ,
2005-10-20 07:58:08 +02:00
m1 ,
( flags & M_NOLF ) ? " " : " \n " ) ;
2005-09-26 07:28:27 +02:00
}
else
{
2005-10-20 07:58:08 +02:00
fprintf ( fp , " %s %s%s%s%s " ,
2005-09-26 07:28:27 +02:00
time_string ( 0 , 0 , show_usec , & gc ) ,
prefix ,
prefix_sep ,
2005-10-20 07:58:08 +02:00
m1 ,
( flags & M_NOLF ) ? " " : " \n " ) ;
2005-09-26 07:28:27 +02:00
}
fflush ( fp ) ;
+ + x_msg_line_num ;
}
}
if ( flags & M_FATAL )
2011-03-13 07:59:25 +01:00
msg ( M_INFO , " Exiting due to fatal error " ) ;
2005-09-26 07:28:27 +02:00
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 )
{
2012-02-10 15:13:42 +01:00
struct gc_arena gc = gc_new ( ) ;
2005-09-26 07:28:27 +02:00
HANDLE log_handle ;
int log_fd ;
2010-07-27 23:46:34 +02:00
SECURITY_ATTRIBUTES saAttr ;
saAttr . nLength = sizeof ( SECURITY_ATTRIBUTES ) ;
saAttr . bInheritHandle = TRUE ;
saAttr . lpSecurityDescriptor = NULL ;
2005-09-26 07:28:27 +02:00
2012-02-10 15:13:42 +01:00
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 ) ;
2005-09-26 07:28:27 +02:00
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 ) ;
2010-07-27 23:46:34 +02:00
#if 0 /* seems not be necessary with stdout/stderr redirection below*/
2005-09-26 07:28:27 +02:00
/* 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 ) ;
2010-07-27 23:46:34 +02:00
# endif
2005-09-26 07:28:27 +02:00
/* 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 ) ;
2010-12-13 12:49:00 +01:00
msgfp = _fdopen ( log_fd , " wt " ) ;
2005-09-26 07:28:27 +02:00
if ( msgfp = = NULL )
msg ( M_ERR , " Error: --log redirect failed due to _fdopen " ) ;
2010-07-16 20:01:11 +02:00
/* 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 " ) ;
2005-09-26 07:28:27 +02:00
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 )
{
2009-01-27 20:32:46 +01:00
const int my_errno = ( sock ? openvpn_errno_socket ( ) : ( int ) openvpn_errno ( ) ) ;
2005-09-26 07:28:27 +02:00
const char * extended_msg = NULL ;
msg ( x_cs_verbose_level , " %s %s returned %d " ,
sock ? proto2ascii ( sock - > info . proto , 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-Win32 driver */
extended_msg = tap_win32_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 , 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 , true ) : " " ,
strerror_ts ( my_errno , & gc ) ,
my_errno ) ;
if ( x_cs_err_delay_ms )
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 )
{
2011-03-13 07:59:25 +01:00
if ( ! forked )
{
void tun_abort ( ) ;
2005-09-26 07:28:27 +02:00
# ifdef ENABLE_PLUGIN
2011-03-13 07:59:25 +01:00
void plugin_abort ( void ) ;
2005-09-26 07:28:27 +02:00
# endif
2011-03-13 07:59:25 +01:00
tun_abort ( ) ;
2010-01-12 19:26:22 +01:00
2005-09-26 07:28:27 +02:00
# ifdef WIN32
2011-03-13 07:59:25 +01:00
uninit_win32 ( ) ;
2005-09-26 07:28:27 +02:00
# endif
2011-03-13 07:59:25 +01:00
close_syslog ( ) ;
2005-09-26 07:28:27 +02:00
# ifdef ENABLE_PLUGIN
2011-03-13 07:59:25 +01:00
plugin_abort ( ) ;
2005-09-26 07:28:27 +02:00
# endif
2006-02-16 19:12:24 +01:00
# if PORT_SHARE
2011-03-13 07:59:25 +01:00
if ( port_share )
port_share_abort ( port_share ) ;
2006-02-16 19:12:24 +01:00
# endif
2011-10-18 10:12:51 +02:00
# ifdef ENABLE_MEMSTATS
mstats_close ( ) ;
# endif
2005-09-26 07:28:27 +02:00
# ifdef ABORT_ON_ERROR
2011-03-13 07:59:25 +01:00
if ( status = = OPENVPN_EXIT_STATUS_ERROR )
abort ( ) ;
2005-09-26 07:28:27 +02:00
# endif
2011-03-13 07:59:25 +01:00
if ( status = = OPENVPN_EXIT_STATUS_GOOD )
perf_output_results ( ) ;
}
2005-09-26 07:28:27 +02:00
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 ) ;
}
2006-02-03 10:04:52 +01:00
# ifdef ENABLE_DEBUG
void
crash ( void )
{
char * null = NULL ;
* null = 0 ;
}
# endif
2005-09-26 07:28:27 +02:00
# 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 - Win32 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