1933707f3Ssthen /*
2933707f3Ssthen * util/log.c - implementation of the log code
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen */
35933707f3Ssthen /**
36933707f3Ssthen * \file
37933707f3Ssthen * Implementation of log.h.
38933707f3Ssthen */
39933707f3Ssthen
40933707f3Ssthen #include "config.h"
41933707f3Ssthen #include "util/log.h"
42933707f3Ssthen #include "util/locks.h"
43fdfb4ba6Ssthen #include "sldns/sbuffer.h"
445d76a658Ssthen #include <stdarg.h>
45933707f3Ssthen #ifdef HAVE_TIME_H
46933707f3Ssthen #include <time.h>
47933707f3Ssthen #endif
48933707f3Ssthen #ifdef HAVE_SYSLOG_H
49933707f3Ssthen # include <syslog.h>
50933707f3Ssthen #else
51933707f3Ssthen /**define LOG_ constants */
52933707f3Ssthen # define LOG_CRIT 2
53933707f3Ssthen # define LOG_ERR 3
54933707f3Ssthen # define LOG_WARNING 4
55933707f3Ssthen # define LOG_NOTICE 5
56933707f3Ssthen # define LOG_INFO 6
57933707f3Ssthen # define LOG_DEBUG 7
58933707f3Ssthen #endif
59933707f3Ssthen #ifdef UB_ON_WINDOWS
60933707f3Ssthen # include "winrc/win_svc.h"
61933707f3Ssthen #endif
62933707f3Ssthen
63933707f3Ssthen /* default verbosity */
64ebf5bb73Ssthen enum verbosity_value verbosity = NO_VERBOSE;
65933707f3Ssthen /** the file logged to. */
66933707f3Ssthen static FILE* logfile = 0;
67933707f3Ssthen /** if key has been created */
68933707f3Ssthen static int key_created = 0;
69933707f3Ssthen /** pthread key for thread ids in logfile */
7077079be7Ssthen static ub_thread_key_type logkey;
7198f3ca02Sbrad #ifndef THREADS_DISABLED
7298f3ca02Sbrad /** pthread mutex to protect FILE* */
73ebf5bb73Ssthen static lock_basic_type log_lock;
7498f3ca02Sbrad #endif
75933707f3Ssthen /** the identity of this executable/process */
76933707f3Ssthen static const char* ident="unbound";
77eaf2578eSsthen static const char* default_ident="unbound";
78933707f3Ssthen #if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS)
79933707f3Ssthen /** are we using syslog(3) to log to */
80933707f3Ssthen static int logging_to_syslog = 0;
81933707f3Ssthen #endif /* HAVE_SYSLOG_H */
82933707f3Ssthen /** print time in UTC or in secondsfrom1970 */
83933707f3Ssthen static int log_time_asc = 0;
84933707f3Ssthen
85933707f3Ssthen void
log_init(const char * filename,int use_syslog,const char * chrootdir)86933707f3Ssthen log_init(const char* filename, int use_syslog, const char* chrootdir)
87933707f3Ssthen {
88933707f3Ssthen FILE *f;
89933707f3Ssthen if(!key_created) {
90933707f3Ssthen key_created = 1;
91933707f3Ssthen ub_thread_key_create(&logkey, NULL);
92ebf5bb73Ssthen lock_basic_init(&log_lock);
93933707f3Ssthen }
94ebf5bb73Ssthen lock_basic_lock(&log_lock);
95933707f3Ssthen if(logfile
96933707f3Ssthen #if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS)
97933707f3Ssthen || logging_to_syslog
98933707f3Ssthen #endif
9998f3ca02Sbrad ) {
100ebf5bb73Ssthen lock_basic_unlock(&log_lock); /* verbose() needs the lock */
101933707f3Ssthen verbose(VERB_QUERY, "switching log to %s",
102933707f3Ssthen use_syslog?"syslog":(filename&&filename[0]?filename:"stderr"));
103ebf5bb73Ssthen lock_basic_lock(&log_lock);
10498f3ca02Sbrad }
1052be9e038Ssthen if(logfile && logfile != stderr) {
1062be9e038Ssthen FILE* cl = logfile;
1072be9e038Ssthen logfile = NULL; /* set to NULL before it is closed, so that
1082be9e038Ssthen other threads have a valid logfile or NULL */
1092be9e038Ssthen fclose(cl);
1102be9e038Ssthen }
111933707f3Ssthen #ifdef HAVE_SYSLOG_H
112933707f3Ssthen if(logging_to_syslog) {
113933707f3Ssthen closelog();
114933707f3Ssthen logging_to_syslog = 0;
115933707f3Ssthen }
116933707f3Ssthen if(use_syslog) {
117933707f3Ssthen /* do not delay opening until first write, because we may
118933707f3Ssthen * chroot and no longer be able to access dev/log and so on */
119ebf5bb73Ssthen /* the facility is LOG_DAEMON by default, but
120ebf5bb73Ssthen * --with-syslog-facility=LOCAL[0-7] can override it */
121ebf5bb73Ssthen openlog(ident, LOG_NDELAY, UB_SYSLOG_FACILITY);
122933707f3Ssthen logging_to_syslog = 1;
123ebf5bb73Ssthen lock_basic_unlock(&log_lock);
124933707f3Ssthen return;
125933707f3Ssthen }
126933707f3Ssthen #elif defined(UB_ON_WINDOWS)
127933707f3Ssthen if(logging_to_syslog) {
128933707f3Ssthen logging_to_syslog = 0;
129933707f3Ssthen }
130933707f3Ssthen if(use_syslog) {
131933707f3Ssthen logging_to_syslog = 1;
132ebf5bb73Ssthen lock_basic_unlock(&log_lock);
133933707f3Ssthen return;
134933707f3Ssthen }
135933707f3Ssthen #endif /* HAVE_SYSLOG_H */
136933707f3Ssthen if(!filename || !filename[0]) {
137933707f3Ssthen logfile = stderr;
138ebf5bb73Ssthen lock_basic_unlock(&log_lock);
139933707f3Ssthen return;
140933707f3Ssthen }
141933707f3Ssthen /* open the file for logging */
142933707f3Ssthen if(chrootdir && chrootdir[0] && strncmp(filename, chrootdir,
143933707f3Ssthen strlen(chrootdir)) == 0)
144933707f3Ssthen filename += strlen(chrootdir);
145933707f3Ssthen f = fopen(filename, "a");
146933707f3Ssthen if(!f) {
147ebf5bb73Ssthen lock_basic_unlock(&log_lock);
148933707f3Ssthen log_err("Could not open logfile %s: %s", filename,
149933707f3Ssthen strerror(errno));
150933707f3Ssthen return;
151933707f3Ssthen }
152933707f3Ssthen #ifndef UB_ON_WINDOWS
153933707f3Ssthen /* line buffering does not work on windows */
154933707f3Ssthen setvbuf(f, NULL, (int)_IOLBF, 0);
155933707f3Ssthen #endif
156933707f3Ssthen logfile = f;
157ebf5bb73Ssthen lock_basic_unlock(&log_lock);
158933707f3Ssthen }
159933707f3Ssthen
log_file(FILE * f)160933707f3Ssthen void log_file(FILE *f)
161933707f3Ssthen {
162ebf5bb73Ssthen lock_basic_lock(&log_lock);
163933707f3Ssthen logfile = f;
164ebf5bb73Ssthen lock_basic_unlock(&log_lock);
165933707f3Ssthen }
166933707f3Ssthen
log_thread_set(int * num)167933707f3Ssthen void log_thread_set(int* num)
168933707f3Ssthen {
169933707f3Ssthen ub_thread_key_set(logkey, num);
170933707f3Ssthen }
171933707f3Ssthen
log_thread_get(void)172fdfb4ba6Ssthen int log_thread_get(void)
173fdfb4ba6Ssthen {
174fdfb4ba6Ssthen unsigned int* tid;
175fdfb4ba6Ssthen if(!key_created) return 0;
176fdfb4ba6Ssthen tid = (unsigned int*)ub_thread_key_get(logkey);
177fdfb4ba6Ssthen return (int)(tid?*tid:0);
178fdfb4ba6Ssthen }
179fdfb4ba6Ssthen
log_ident_set(const char * id)180933707f3Ssthen void log_ident_set(const char* id)
181933707f3Ssthen {
182933707f3Ssthen ident = id;
183933707f3Ssthen }
184933707f3Ssthen
log_ident_set_default(const char * id)185eaf2578eSsthen void log_ident_set_default(const char* id)
186eaf2578eSsthen {
187eaf2578eSsthen default_ident = id;
188eaf2578eSsthen }
189eaf2578eSsthen
log_ident_revert_to_default(void)190*d896b962Ssthen void log_ident_revert_to_default(void)
191eaf2578eSsthen {
192eaf2578eSsthen ident = default_ident;
193eaf2578eSsthen }
194eaf2578eSsthen
log_ident_set_or_default(const char * identity)195eaf2578eSsthen void log_ident_set_or_default(const char* identity)
196eaf2578eSsthen {
197eaf2578eSsthen if(identity == NULL || identity[0] == 0)
198eaf2578eSsthen log_ident_set(default_ident);
199eaf2578eSsthen else
200eaf2578eSsthen log_ident_set(identity);
201eaf2578eSsthen }
202eaf2578eSsthen
log_set_time_asc(int use_asc)203933707f3Ssthen void log_set_time_asc(int use_asc)
204933707f3Ssthen {
205933707f3Ssthen log_time_asc = use_asc;
206933707f3Ssthen }
207933707f3Ssthen
log_get_lock(void)208938a3a5eSflorian void* log_get_lock(void)
209938a3a5eSflorian {
210938a3a5eSflorian if(!key_created)
211938a3a5eSflorian return NULL;
212938a3a5eSflorian #ifndef THREADS_DISABLED
213938a3a5eSflorian return (void*)&log_lock;
214938a3a5eSflorian #else
215938a3a5eSflorian return NULL;
216938a3a5eSflorian #endif
217938a3a5eSflorian }
218938a3a5eSflorian
219933707f3Ssthen void
log_vmsg(int pri,const char * type,const char * format,va_list args)220933707f3Ssthen log_vmsg(int pri, const char* type,
221933707f3Ssthen const char *format, va_list args)
222933707f3Ssthen {
223933707f3Ssthen char message[MAXSYSLOGMSGLEN];
224933707f3Ssthen unsigned int* tid = (unsigned int*)ub_thread_key_get(logkey);
225933707f3Ssthen time_t now;
226933707f3Ssthen #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R)
227933707f3Ssthen char tmbuf[32];
228933707f3Ssthen struct tm tm;
2293dcb24b8Ssthen #elif defined(UB_ON_WINDOWS)
2303dcb24b8Ssthen char tmbuf[128], dtbuf[128];
231933707f3Ssthen #endif
232933707f3Ssthen (void)pri;
233933707f3Ssthen vsnprintf(message, sizeof(message), format, args);
234933707f3Ssthen #ifdef HAVE_SYSLOG_H
235933707f3Ssthen if(logging_to_syslog) {
236933707f3Ssthen syslog(pri, "[%d:%x] %s: %s",
237933707f3Ssthen (int)getpid(), tid?*tid:0, type, message);
238933707f3Ssthen return;
239933707f3Ssthen }
240933707f3Ssthen #elif defined(UB_ON_WINDOWS)
241933707f3Ssthen if(logging_to_syslog) {
242933707f3Ssthen char m[32768];
243933707f3Ssthen HANDLE* s;
244933707f3Ssthen LPCTSTR str = m;
245933707f3Ssthen DWORD tp = MSG_GENERIC_ERR;
246933707f3Ssthen WORD wt = EVENTLOG_ERROR_TYPE;
247933707f3Ssthen if(strcmp(type, "info") == 0) {
248933707f3Ssthen tp=MSG_GENERIC_INFO;
249933707f3Ssthen wt=EVENTLOG_INFORMATION_TYPE;
250933707f3Ssthen } else if(strcmp(type, "warning") == 0) {
251933707f3Ssthen tp=MSG_GENERIC_WARN;
252933707f3Ssthen wt=EVENTLOG_WARNING_TYPE;
253933707f3Ssthen } else if(strcmp(type, "notice") == 0
254933707f3Ssthen || strcmp(type, "debug") == 0) {
255933707f3Ssthen tp=MSG_GENERIC_SUCCESS;
256933707f3Ssthen wt=EVENTLOG_SUCCESS;
257933707f3Ssthen }
258933707f3Ssthen snprintf(m, sizeof(m), "[%s:%x] %s: %s",
259933707f3Ssthen ident, tid?*tid:0, type, message);
260933707f3Ssthen s = RegisterEventSource(NULL, SERVICE_NAME);
261933707f3Ssthen if(!s) return;
262933707f3Ssthen ReportEvent(s, wt, 0, tp, NULL, 1, 0, &str, NULL);
263933707f3Ssthen DeregisterEventSource(s);
264933707f3Ssthen return;
265933707f3Ssthen }
266933707f3Ssthen #endif /* HAVE_SYSLOG_H */
267ebf5bb73Ssthen lock_basic_lock(&log_lock);
26898f3ca02Sbrad if(!logfile) {
269ebf5bb73Ssthen lock_basic_unlock(&log_lock);
27098f3ca02Sbrad return;
27198f3ca02Sbrad }
2723150e5f6Ssthen now = (time_t)time(NULL);
273933707f3Ssthen #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R)
274933707f3Ssthen if(log_time_asc && strftime(tmbuf, sizeof(tmbuf), "%b %d %H:%M:%S",
275933707f3Ssthen localtime_r(&now, &tm))%(sizeof(tmbuf)) != 0) {
276933707f3Ssthen /* %sizeof buf!=0 because old strftime returned max on error */
277933707f3Ssthen fprintf(logfile, "%s %s[%d:%x] %s: %s\n", tmbuf,
278933707f3Ssthen ident, (int)getpid(), tid?*tid:0, type, message);
279933707f3Ssthen } else
2803dcb24b8Ssthen #elif defined(UB_ON_WINDOWS)
2813dcb24b8Ssthen if(log_time_asc && GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL,
2823dcb24b8Ssthen tmbuf, sizeof(tmbuf)) && GetDateFormat(LOCALE_USER_DEFAULT, 0,
2833dcb24b8Ssthen NULL, NULL, dtbuf, sizeof(dtbuf))) {
2843dcb24b8Ssthen fprintf(logfile, "%s %s %s[%d:%x] %s: %s\n", dtbuf, tmbuf,
2853dcb24b8Ssthen ident, (int)getpid(), tid?*tid:0, type, message);
2863dcb24b8Ssthen } else
287933707f3Ssthen #endif
2885d76a658Ssthen fprintf(logfile, "[" ARG_LL "d] %s[%d:%x] %s: %s\n", (long long)now,
289933707f3Ssthen ident, (int)getpid(), tid?*tid:0, type, message);
290933707f3Ssthen #ifdef UB_ON_WINDOWS
291933707f3Ssthen /* line buffering does not work on windows */
292933707f3Ssthen fflush(logfile);
293933707f3Ssthen #endif
294ebf5bb73Ssthen lock_basic_unlock(&log_lock);
295933707f3Ssthen }
296933707f3Ssthen
297933707f3Ssthen /**
298933707f3Ssthen * implementation of log_info
299933707f3Ssthen * @param format: format string printf-style.
300933707f3Ssthen */
301933707f3Ssthen void
log_info(const char * format,...)302933707f3Ssthen log_info(const char *format, ...)
303933707f3Ssthen {
304933707f3Ssthen va_list args;
305933707f3Ssthen va_start(args, format);
306933707f3Ssthen log_vmsg(LOG_INFO, "info", format, args);
307933707f3Ssthen va_end(args);
308933707f3Ssthen }
309933707f3Ssthen
310933707f3Ssthen /**
311933707f3Ssthen * implementation of log_err
312933707f3Ssthen * @param format: format string printf-style.
313933707f3Ssthen */
314933707f3Ssthen void
log_err(const char * format,...)315933707f3Ssthen log_err(const char *format, ...)
316933707f3Ssthen {
317933707f3Ssthen va_list args;
318933707f3Ssthen va_start(args, format);
319933707f3Ssthen log_vmsg(LOG_ERR, "error", format, args);
320933707f3Ssthen va_end(args);
321933707f3Ssthen }
322933707f3Ssthen
323933707f3Ssthen /**
324933707f3Ssthen * implementation of log_warn
325933707f3Ssthen * @param format: format string printf-style.
326933707f3Ssthen */
327933707f3Ssthen void
log_warn(const char * format,...)328933707f3Ssthen log_warn(const char *format, ...)
329933707f3Ssthen {
330933707f3Ssthen va_list args;
331933707f3Ssthen va_start(args, format);
332933707f3Ssthen log_vmsg(LOG_WARNING, "warning", format, args);
333933707f3Ssthen va_end(args);
334933707f3Ssthen }
335933707f3Ssthen
336933707f3Ssthen /**
337933707f3Ssthen * implementation of fatal_exit
338933707f3Ssthen * @param format: format string printf-style.
339933707f3Ssthen */
340933707f3Ssthen void
fatal_exit(const char * format,...)341933707f3Ssthen fatal_exit(const char *format, ...)
342933707f3Ssthen {
343933707f3Ssthen va_list args;
344933707f3Ssthen va_start(args, format);
345933707f3Ssthen log_vmsg(LOG_CRIT, "fatal error", format, args);
346933707f3Ssthen va_end(args);
347933707f3Ssthen exit(1);
348933707f3Ssthen }
349933707f3Ssthen
350933707f3Ssthen /**
351933707f3Ssthen * implementation of verbose
352933707f3Ssthen * @param level: verbose level for the message.
353933707f3Ssthen * @param format: format string printf-style.
354933707f3Ssthen */
355933707f3Ssthen void
verbose(enum verbosity_value level,const char * format,...)356933707f3Ssthen verbose(enum verbosity_value level, const char* format, ...)
357933707f3Ssthen {
358933707f3Ssthen va_list args;
359933707f3Ssthen va_start(args, format);
360933707f3Ssthen if(verbosity >= level) {
361933707f3Ssthen if(level == VERB_OPS)
362933707f3Ssthen log_vmsg(LOG_NOTICE, "notice", format, args);
363933707f3Ssthen else if(level == VERB_DETAIL)
364933707f3Ssthen log_vmsg(LOG_INFO, "info", format, args);
365933707f3Ssthen else log_vmsg(LOG_DEBUG, "debug", format, args);
366933707f3Ssthen }
367933707f3Ssthen va_end(args);
368933707f3Ssthen }
369933707f3Ssthen
370933707f3Ssthen /** log hex data */
371933707f3Ssthen static void
log_hex_f(enum verbosity_value v,const char * msg,void * data,size_t length)372933707f3Ssthen log_hex_f(enum verbosity_value v, const char* msg, void* data, size_t length)
373933707f3Ssthen {
374933707f3Ssthen size_t i, j;
375933707f3Ssthen uint8_t* data8 = (uint8_t*)data;
376933707f3Ssthen const char* hexchar = "0123456789ABCDEF";
377933707f3Ssthen char buf[1024+1]; /* alloc blocksize hex chars + \0 */
378933707f3Ssthen const size_t blocksize = 512;
379933707f3Ssthen size_t len;
380933707f3Ssthen
381933707f3Ssthen if(length == 0) {
382933707f3Ssthen verbose(v, "%s[%u]", msg, (unsigned)length);
383933707f3Ssthen return;
384933707f3Ssthen }
385933707f3Ssthen
386933707f3Ssthen for(i=0; i<length; i+=blocksize/2) {
387933707f3Ssthen len = blocksize/2;
388933707f3Ssthen if(length - i < blocksize/2)
389933707f3Ssthen len = length - i;
390933707f3Ssthen for(j=0; j<len; j++) {
391933707f3Ssthen buf[j*2] = hexchar[ data8[i+j] >> 4 ];
392933707f3Ssthen buf[j*2 + 1] = hexchar[ data8[i+j] & 0xF ];
393933707f3Ssthen }
394933707f3Ssthen buf[len*2] = 0;
395933707f3Ssthen verbose(v, "%s[%u:%u] %.*s", msg, (unsigned)length,
396933707f3Ssthen (unsigned)i, (int)len*2, buf);
397933707f3Ssthen }
398933707f3Ssthen }
399933707f3Ssthen
400933707f3Ssthen void
log_hex(const char * msg,void * data,size_t length)401933707f3Ssthen log_hex(const char* msg, void* data, size_t length)
402933707f3Ssthen {
403933707f3Ssthen log_hex_f(verbosity, msg, data, length);
404933707f3Ssthen }
405933707f3Ssthen
406f6b99bafSsthen void
log_query(const char * format,...)407f6b99bafSsthen log_query(const char *format, ...)
408f6b99bafSsthen {
409f6b99bafSsthen va_list args;
410f6b99bafSsthen va_start(args, format);
411f6b99bafSsthen log_vmsg(LOG_INFO, "query", format, args);
412f6b99bafSsthen va_end(args);
413f6b99bafSsthen }
414f6b99bafSsthen
415f6b99bafSsthen void
log_reply(const char * format,...)416f6b99bafSsthen log_reply(const char *format, ...)
417f6b99bafSsthen {
418f6b99bafSsthen va_list args;
419f6b99bafSsthen va_start(args, format);
420f6b99bafSsthen log_vmsg(LOG_INFO, "reply", format, args);
421f6b99bafSsthen va_end(args);
422f6b99bafSsthen }
423f6b99bafSsthen
log_buf(enum verbosity_value level,const char * msg,sldns_buffer * buf)4245d76a658Ssthen void log_buf(enum verbosity_value level, const char* msg, sldns_buffer* buf)
425933707f3Ssthen {
426933707f3Ssthen if(verbosity < level)
427933707f3Ssthen return;
4285d76a658Ssthen log_hex_f(level, msg, sldns_buffer_begin(buf), sldns_buffer_limit(buf));
429933707f3Ssthen }
430933707f3Ssthen
431933707f3Ssthen #ifdef USE_WINSOCK
wsa_strerror(DWORD err)432933707f3Ssthen char* wsa_strerror(DWORD err)
433933707f3Ssthen {
434933707f3Ssthen static char unknown[32];
435933707f3Ssthen
436933707f3Ssthen switch(err) {
437933707f3Ssthen case WSA_INVALID_HANDLE: return "Specified event object handle is invalid.";
438933707f3Ssthen case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available.";
439933707f3Ssthen case WSA_INVALID_PARAMETER: return "One or more parameters are invalid.";
440933707f3Ssthen case WSA_OPERATION_ABORTED: return "Overlapped operation aborted.";
441933707f3Ssthen case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state.";
442933707f3Ssthen case WSA_IO_PENDING: return "Overlapped operations will complete later.";
443933707f3Ssthen case WSAEINTR: return "Interrupted function call.";
444933707f3Ssthen case WSAEBADF: return "File handle is not valid.";
445933707f3Ssthen case WSAEACCES: return "Permission denied.";
446933707f3Ssthen case WSAEFAULT: return "Bad address.";
447933707f3Ssthen case WSAEINVAL: return "Invalid argument.";
448933707f3Ssthen case WSAEMFILE: return "Too many open files.";
449933707f3Ssthen case WSAEWOULDBLOCK: return "Resource temporarily unavailable.";
450933707f3Ssthen case WSAEINPROGRESS: return "Operation now in progress.";
451933707f3Ssthen case WSAEALREADY: return "Operation already in progress.";
452933707f3Ssthen case WSAENOTSOCK: return "Socket operation on nonsocket.";
453933707f3Ssthen case WSAEDESTADDRREQ: return "Destination address required.";
454933707f3Ssthen case WSAEMSGSIZE: return "Message too long.";
455933707f3Ssthen case WSAEPROTOTYPE: return "Protocol wrong type for socket.";
456933707f3Ssthen case WSAENOPROTOOPT: return "Bad protocol option.";
457933707f3Ssthen case WSAEPROTONOSUPPORT: return "Protocol not supported.";
458933707f3Ssthen case WSAESOCKTNOSUPPORT: return "Socket type not supported.";
459933707f3Ssthen case WSAEOPNOTSUPP: return "Operation not supported.";
460933707f3Ssthen case WSAEPFNOSUPPORT: return "Protocol family not supported.";
461933707f3Ssthen case WSAEAFNOSUPPORT: return "Address family not supported by protocol family.";
462933707f3Ssthen case WSAEADDRINUSE: return "Address already in use.";
463933707f3Ssthen case WSAEADDRNOTAVAIL: return "Cannot assign requested address.";
464933707f3Ssthen case WSAENETDOWN: return "Network is down.";
465933707f3Ssthen case WSAENETUNREACH: return "Network is unreachable.";
466933707f3Ssthen case WSAENETRESET: return "Network dropped connection on reset.";
467933707f3Ssthen case WSAECONNABORTED: return "Software caused connection abort.";
468933707f3Ssthen case WSAECONNRESET: return "Connection reset by peer.";
469933707f3Ssthen case WSAENOBUFS: return "No buffer space available.";
470933707f3Ssthen case WSAEISCONN: return "Socket is already connected.";
471933707f3Ssthen case WSAENOTCONN: return "Socket is not connected.";
472933707f3Ssthen case WSAESHUTDOWN: return "Cannot send after socket shutdown.";
473933707f3Ssthen case WSAETOOMANYREFS: return "Too many references.";
474933707f3Ssthen case WSAETIMEDOUT: return "Connection timed out.";
475933707f3Ssthen case WSAECONNREFUSED: return "Connection refused.";
476933707f3Ssthen case WSAELOOP: return "Cannot translate name.";
477933707f3Ssthen case WSAENAMETOOLONG: return "Name too long.";
478933707f3Ssthen case WSAEHOSTDOWN: return "Host is down.";
479933707f3Ssthen case WSAEHOSTUNREACH: return "No route to host.";
480933707f3Ssthen case WSAENOTEMPTY: return "Directory not empty.";
481933707f3Ssthen case WSAEPROCLIM: return "Too many processes.";
482933707f3Ssthen case WSAEUSERS: return "User quota exceeded.";
483933707f3Ssthen case WSAEDQUOT: return "Disk quota exceeded.";
484933707f3Ssthen case WSAESTALE: return "Stale file handle reference.";
485933707f3Ssthen case WSAEREMOTE: return "Item is remote.";
486933707f3Ssthen case WSASYSNOTREADY: return "Network subsystem is unavailable.";
487933707f3Ssthen case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range.";
488933707f3Ssthen case WSANOTINITIALISED: return "Successful WSAStartup not yet performed.";
489933707f3Ssthen case WSAEDISCON: return "Graceful shutdown in progress.";
490933707f3Ssthen case WSAENOMORE: return "No more results.";
491933707f3Ssthen case WSAECANCELLED: return "Call has been canceled.";
492933707f3Ssthen case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid.";
493933707f3Ssthen case WSAEINVALIDPROVIDER: return "Service provider is invalid.";
494933707f3Ssthen case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize.";
495933707f3Ssthen case WSASYSCALLFAILURE: return "System call failure.";
496933707f3Ssthen case WSASERVICE_NOT_FOUND: return "Service not found.";
497933707f3Ssthen case WSATYPE_NOT_FOUND: return "Class type not found.";
498933707f3Ssthen case WSA_E_NO_MORE: return "No more results.";
499933707f3Ssthen case WSA_E_CANCELLED: return "Call was canceled.";
500933707f3Ssthen case WSAEREFUSED: return "Database query was refused.";
501933707f3Ssthen case WSAHOST_NOT_FOUND: return "Host not found.";
502933707f3Ssthen case WSATRY_AGAIN: return "Nonauthoritative host not found.";
503933707f3Ssthen case WSANO_RECOVERY: return "This is a nonrecoverable error.";
504933707f3Ssthen case WSANO_DATA: return "Valid name, no data record of requested type.";
505933707f3Ssthen case WSA_QOS_RECEIVERS: return "QOS receivers.";
506933707f3Ssthen case WSA_QOS_SENDERS: return "QOS senders.";
507933707f3Ssthen case WSA_QOS_NO_SENDERS: return "No QOS senders.";
508933707f3Ssthen case WSA_QOS_NO_RECEIVERS: return "QOS no receivers.";
509933707f3Ssthen case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed.";
510933707f3Ssthen case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error.";
511933707f3Ssthen case WSA_QOS_POLICY_FAILURE: return "QOS policy failure.";
512933707f3Ssthen case WSA_QOS_BAD_STYLE: return "QOS bad style.";
513933707f3Ssthen case WSA_QOS_BAD_OBJECT: return "QOS bad object.";
514933707f3Ssthen case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error.";
515933707f3Ssthen case WSA_QOS_GENERIC_ERROR: return "QOS generic error.";
516933707f3Ssthen case WSA_QOS_ESERVICETYPE: return "QOS service type error.";
517933707f3Ssthen case WSA_QOS_EFLOWSPEC: return "QOS flowspec error.";
518933707f3Ssthen case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer.";
519933707f3Ssthen case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style.";
520933707f3Ssthen case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type.";
521933707f3Ssthen case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count.";
522933707f3Ssthen case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length.";
523933707f3Ssthen case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count.";
524933707f3Ssthen /*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/
525933707f3Ssthen case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object.";
526933707f3Ssthen case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor.";
527933707f3Ssthen case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec.";
528933707f3Ssthen case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec.";
529933707f3Ssthen case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object.";
530933707f3Ssthen case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object.";
531933707f3Ssthen case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type.";
532933707f3Ssthen default:
533933707f3Ssthen snprintf(unknown, sizeof(unknown),
534933707f3Ssthen "unknown WSA error code %d", (int)err);
535933707f3Ssthen return unknown;
536933707f3Ssthen }
537933707f3Ssthen }
538933707f3Ssthen #endif /* USE_WINSOCK */
539