Improved reporting of errors under Win32.
[privoxy.git] / errlog.c
1 const char errlog_rcs[] = "$Id: errlog.c,v 1.8 2001/05/26 17:25:14 jongfoster Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/errlog.c,v $
5  *
6  * Purpose     :  Log errors to a designated destination in an elegant,
7  *                printf-like fashion.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
10  *                IJBSWA team.  http://ijbswa.sourceforge.net
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and 
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it 
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  * Revisions   :
35  *    $Log: errlog.c,v $
36  *    Revision 1.8  2001/05/26 17:25:14  jongfoster
37  *    Added support for CLF (Common Log Format) and fixed LOG_LEVEL_LOG
38  *
39  *    Revision 1.7  2001/05/26 15:21:28  jongfoster
40  *    Activity animation in Win32 GUI now works even if debug==0
41  *
42  *    Revision 1.6  2001/05/25 21:55:08  jongfoster
43  *    Now cleans up properly on FATAL (removes taskbar icon etc)
44  *
45  *    Revision 1.5  2001/05/22 18:46:04  oes
46  *
47  *    - Enabled filtering banners by size rather than URL
48  *      by adding patterns that replace all standard banner
49  *      sizes with the "Junkbuster" gif to the re_filterfile
50  *
51  *    - Enabled filtering WebBugs by providing a pattern
52  *      which kills all 1x1 images
53  *
54  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
55  *      which is selected by the (nonstandard and therefore
56  *      capital) letter 'U' in the option string.
57  *      It causes the quantifiers to be ungreedy by default.
58  *      Appending a ? turns back to greedy (!).
59  *
60  *    - Added a new interceptor ijb-send-banner, which
61  *      sends back the "Junkbuster" gif. Without imagelist or
62  *      MSIE detection support, or if tinygif = 1, or the
63  *      URL isn't recognized as an imageurl, a lame HTML
64  *      explanation is sent instead.
65  *
66  *    - Added new feature, which permits blocking remote
67  *      script redirects and firing back a local redirect
68  *      to the browser.
69  *      The feature is conditionally compiled, i.e. it
70  *      can be disabled with --disable-fast-redirects,
71  *      plus it must be activated by a "fast-redirects"
72  *      line in the config file, has its own log level
73  *      and of course wants to be displayed by show-proxy-args
74  *      Note: Boy, all the #ifdefs in 1001 locations and
75  *      all the fumbling with configure.in and acconfig.h
76  *      were *way* more work than the feature itself :-(
77  *
78  *    - Because a generic redirect template was needed for
79  *      this, tinygif = 3 now uses the same.
80  *
81  *    - Moved GIFs, and other static HTTP response templates
82  *      to project.h
83  *
84  *    - Some minor fixes
85  *
86  *    - Removed some >400 CRs again (Jon, you really worked
87  *      a lot! ;-)
88  *
89  *    Revision 1.4  2001/05/21 19:32:54  jongfoster
90  *    Added another #ifdef _WIN_CONSOLE
91  *
92  *    Revision 1.3  2001/05/20 01:11:40  jongfoster
93  *    Added support for LOG_LEVEL_FATAL
94  *    Renamed LOG_LEVEL_FRC to LOG_LEVEL_FORCE,
95  *    and LOG_LEVEL_REF to LOG_LEVEL_RE_FILTER
96  *
97  *    Revision 1.2  2001/05/17 22:42:01  oes
98  *     - Cleaned CRLF's from the sources and related files
99  *     - Repaired logging for REF and FRC
100  *
101  *    Revision 1.1.1.1  2001/05/15 13:58:51  oes
102  *    Initial import of version 2.9.3 source tree
103  *
104  *
105  *********************************************************************/
106 \f
107
108 #include "config.h"
109
110 #include <stdlib.h>
111 #include <stdio.h>
112 #include <stdarg.h>
113 #include <string.h>
114
115 #ifndef _WIN32
116 #include <unistd.h>
117 #endif /* ndef _WIN32 */
118
119 #include <errno.h>
120 /* #include <pthread.h> */
121
122 #ifdef _WIN32
123 #include <windows.h>
124 #ifndef _WIN_CONSOLE
125 #include "w32log.h"
126 #endif /* ndef _WIN_CONSOLE */
127 #endif /* def _WIN32 */
128
129 #include "errlog.h"
130 #include "project.h"
131
132 const char errlog_h_rcs[] = ERRLOG_H_VERSION;
133
134
135 /*
136  * LOG_LEVEL_FATAL cannot be turned off.  (There are
137  * some exceptional situations where we need to get a
138  * message to the user).
139  */
140 #define LOG_LEVEL_MINIMUM  LOG_LEVEL_FATAL
141
142 /* where to log (default: stderr) */
143 static FILE *logfp = NULL;
144
145 /* where to log (NULL == stderr) */
146 static char * logfilename = NULL;
147
148 /* logging detail level.  */
149 static int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR | LOG_LEVEL_INFO);  
150
151 /* static functions */
152 static void fatal_error(const char * error_message);
153 static char * w32_socket_strerr(int errcode, char * tmp_buf);
154
155
156 /*********************************************************************
157  *
158  * Function    :  fatal_error
159  *
160  * Description :  Displays a fatal error to standard error (or, on 
161  *                a WIN32 GUI, to a dialog box), and exits
162  *                JunkBuster with status code 1.
163  *
164  * Parameters  :
165  *          1  :  error_message = The error message to display.
166  *
167  * Returns     :  Does not return.
168  *
169  *********************************************************************/
170 static void fatal_error(const char * error_message)
171 {
172 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
173    MessageBox(g_hwndLogFrame, error_message, "Internet JunkBuster Error", 
174       MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
175
176    /* Cleanup - remove taskbar icon etc. */
177    TermLogWindow();
178
179 #else /* if !defined(_WIN32) || defined(_WIN_CONSOLE) */
180    fputs(error_message, stderr);
181 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
182
183    exit(1);
184 }
185
186
187 /*********************************************************************
188  *
189  * Function    :  init_errlog
190  *
191  * Description :  Initializes the logging module.  Must call before
192  *                calling log_error.
193  *
194  * Parameters  :
195  *          1  :  prog_name  = The program name.
196  *          2  :  logfname   = The logfile name, or NULL for stderr.
197  *          3  :  debuglevel = The debugging level.
198  *
199  * Returns     :  N/A
200  *
201  *********************************************************************/
202 void init_error_log(const char *prog_name, const char *logfname, int debuglevel)
203 {
204    FILE *fp;
205
206    /* FIXME RACE HAZARD: should start critical section error_log_use here */
207
208    /* set the logging detail level */
209    debug = debuglevel | LOG_LEVEL_MINIMUM;
210
211    if ((logfp != NULL) && (logfp != stderr))
212    {
213       fclose(logfp);
214    }
215    logfp = stderr;
216
217    /* set the designated log file */
218    if( logfname )
219    {
220       if( !(fp = fopen(logfname, "a")) )
221       {
222          log_error(LOG_LEVEL_FATAL, "init_errlog(): can't open logfile: %s", logfname);
223       }
224
225       /* set logging to be completely unbuffered */
226       setbuf(fp, NULL);
227
228       logfp = fp;
229    }
230
231    log_error(LOG_LEVEL_INFO, "Internet JunkBuster version " VERSION);
232    if (prog_name != NULL)
233    {
234       log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
235    }
236
237    /* FIXME RACE HAZARD: should end critical section error_log_use here */
238
239 } /* init_error_log */
240
241
242 /*********************************************************************
243  *
244  * Function    :  log_error
245  *
246  * Description :  This is the error-reporting and logging function.
247  *
248  * Parameters  :
249  *          1  :  loglevel  = the type of message to be logged
250  *          2  :  fmt       = the main string we want logged, printf-like
251  *          3  :  ...       = arguments to be inserted in fmt (printf-like).
252  *
253  * Returns     :  N/A
254  *
255  *********************************************************************/
256 void log_error(int loglevel, char *fmt, ...)
257 {
258    va_list ap;
259    char outbuf[BUFSIZ];
260    char * src = fmt;
261    int outc = 0;
262    long this_thread = 1;  /* was: pthread_t this_thread;*/
263
264 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
265    /*
266     * Irrespective of debug setting, a GET/POST/CONNECT makes
267     * the taskbar icon animate.  (There is an option to disable
268     * this but checking that is handled inside LogShowActivity()).
269     */
270    if (loglevel == LOG_LEVEL_GPC)
271    {
272       LogShowActivity();
273    }
274 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
275
276    /* verify if loglevel applies to current settings and bail out if negative */
277    if ((loglevel & debug) == 0)
278    {
279       return;
280    }
281
282    /* FIXME get current thread id */
283    /* this_thread = (long)pthread_self(); */
284
285    switch (loglevel)
286    {
287       case LOG_LEVEL_ERROR:
288          outc = sprintf(outbuf, "IJB(%d) Error: ", this_thread);
289          break;
290       case LOG_LEVEL_FATAL:
291          outc = sprintf(outbuf, "IJB(%d) Fatal error: ", this_thread);
292          break;
293       case LOG_LEVEL_GPC:
294          outc = sprintf(outbuf, "IJB(%d) Request: ", this_thread);
295          break;
296       case LOG_LEVEL_CONNECT:
297          outc = sprintf(outbuf, "IJB(%d) Connect: ", this_thread);
298          break;
299       case LOG_LEVEL_LOG:
300          outc = sprintf(outbuf, "IJB(%d) Writing: ", this_thread);
301          break;
302       case LOG_LEVEL_HEADER:
303          outc = sprintf(outbuf, "IJB(%d) Header: ", this_thread);
304          break;
305       case LOG_LEVEL_INFO:
306          outc = sprintf(outbuf, "IJB(%d) Info: ", this_thread);
307          break;
308 #ifdef PCRS
309       case LOG_LEVEL_RE_FILTER:
310          outc = sprintf(outbuf, "IJB(%d) Re-Filter: ", this_thread);
311          break;
312 #endif /* def PCRS */
313 #ifdef FORCE_LOAD
314       case LOG_LEVEL_FORCE:
315          outc = sprintf(outbuf, "IJB(%d) Force: ", this_thread);
316          break;
317 #endif /* def FORCE_LOAD */
318 #ifdef FAST_REDIRECTS
319       case LOG_LEVEL_REDIRECTS:
320          outc = sprintf(outbuf, "IJB(%d) Redirect: ", this_thread);
321          break;
322 #endif /* def FAST_REDIRECTS */
323       case LOG_LEVEL_CLF:
324          outc = 0;
325          outbuf[0] = '\0';
326          break;
327       default:
328          outc = sprintf(outbuf, "IJB(%d) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
329          break;
330    }
331    
332    /* get ready to scan var. args. */
333    va_start( ap, fmt );
334
335    /* build formatted message from fmt and var-args */
336    while ((*src) && (outc < BUFSIZ-2))
337    {
338       char tempbuf[BUFSIZ];
339       char *sval;
340       int ival;
341       unsigned uval;
342       long lval;
343       unsigned long ulval;
344       int oldoutc;
345       char ch;
346       
347       ch = *src++;
348       if( ch != '%' )
349       {
350          outbuf[outc++] = ch;
351          continue;
352       }
353
354       ch = *src++;
355       switch (ch) {
356          case '%':
357             outbuf[outc++] = '%';
358             break;
359          case 'd':
360             ival = va_arg( ap, int );
361             oldoutc = outc;
362             outc += sprintf(tempbuf, "%d", ival);
363             if (outc < BUFSIZ-1) 
364             {
365                strcpy(outbuf + oldoutc, tempbuf);
366             }
367             else
368             {
369                outbuf[oldoutc] = '\0';
370             }
371             break;
372          case 'u':
373             uval = va_arg( ap, unsigned );
374             oldoutc = outc;
375             outc += sprintf(tempbuf, "%u", uval);
376             if (outc < BUFSIZ-1) 
377             {
378                strcpy(outbuf + oldoutc, tempbuf);
379             }
380             else
381             {
382                outbuf[oldoutc] = '\0';
383             }
384             break;
385          case 'l':
386             /* this is a modifier that must be followed by u or d */
387             ch = *src++;
388             if (ch == 'd')
389             {
390                lval = va_arg( ap, long );
391                oldoutc = outc;
392                outc += sprintf(tempbuf, "%ld", lval);
393             }
394             else if (ch == 'u')
395             {
396                ulval = va_arg( ap, unsigned long );
397                oldoutc = outc;
398                outc += sprintf(tempbuf, "%lu", ulval);
399             }
400             else
401             {
402                /* Error */
403                sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
404                                "Format = \"%s\"\n"
405                                "Exiting.", this_thread, fmt);
406                /* FIXME RACE HAZARD: should start critical section error_log_use here */
407                if( !logfp )
408                {
409                   logfp = stderr;
410                }
411                fputs(outbuf, logfp);
412                /* FIXME RACE HAZARD: should end critical section error_log_use here */
413                fatal_error(outbuf);
414                /* Never get here */
415                break;
416             }
417             if (outc < BUFSIZ-1) 
418             {
419                strcpy(outbuf + oldoutc, tempbuf);
420             }
421             else
422             {
423                outbuf[oldoutc] = '\0';
424             }
425             break;
426          case 'c':
427             /*
428              * Note that char paramaters are converted to int, so we need to
429              * pass "int" to va_arg.  (See K&R, 2nd ed, section A7.3.2, page 202)
430              */
431             outbuf[outc++] = (char) va_arg( ap, int );
432             break;
433          case 's':
434             sval = va_arg( ap, char * );
435             oldoutc = outc;
436             outc += strlen(sval);
437             if (outc < BUFSIZ-1) 
438             {
439                strcpy(outbuf + oldoutc, sval);
440             }
441             else
442             {
443                outbuf[oldoutc] = '\0';
444             }
445             break;
446          case 'N':
447             /* Non-standard: Print a counted string.  Takes 2 parameters:
448              * int length, const char * string
449              */
450             ival = va_arg( ap, int );
451             sval = va_arg( ap, char * );
452             if (ival < 0)
453             {
454                ival = 0;
455             }
456             oldoutc = outc;
457             outc += ival;
458             if (outc < BUFSIZ-1)
459             {
460                memcpy(outbuf + oldoutc, sval, ival);
461             }
462             else
463             {
464                outbuf[oldoutc] = '\0';
465             }
466             break;
467          case 'E':
468             /* Non-standard: Print error code from errno */
469 #ifdef _WIN32
470             ival = WSAGetLastError();
471             sval = w32_socket_strerr(ival, tempbuf);
472 #else /* ifndef _WIN32 */
473             ival = errno; 
474 #ifndef NOSTRERROR
475             sval = strerror(ival);
476 #else /* def NOSTRERROR */
477             sval = NULL;
478 #endif /* def NOSTRERROR */
479             if (sval == NULL)
480             {
481                sprintf(tempbuf, "(errno = %d)", ival);
482                sval = tempbuf;
483             }
484 #endif /* ndef _WIN32 */
485             oldoutc = outc;
486             outc += strlen(sval);
487             if (outc < BUFSIZ-1) 
488             {
489                strcpy(outbuf + oldoutc, sval);
490             }
491             else
492             {
493                outbuf[oldoutc] = '\0';
494             }
495             break;
496          case 'T':
497             /* Non-standard: Print a Common Log File timestamp */
498             {
499                /*
500                 * Write timestamp into tempbuf.
501                 *
502                 * Complex because not all OSs have tm_gmtoff or
503                 * the %z field in strftime()
504                 */
505                time_t now; 
506                struct tm *tm_now; 
507                struct tm gmt; 
508                int days, hrs, mins; 
509                time (&now); 
510                gmt = *gmtime (&now); 
511                tm_now = localtime (&now); 
512                days = tm_now->tm_yday - gmt.tm_yday; 
513                hrs = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + tm_now->tm_hour - gmt.tm_hour); 
514                mins = hrs * 60 + tm_now->tm_min - gmt.tm_min; 
515                strftime (tempbuf, BUFSIZ-6, "%d/%b/%Y:%H:%M:%S ", tm_now); 
516                sprintf (tempbuf + strlen(tempbuf), "%+03d%02d", mins / 60, abs(mins) % 60); 
517             }
518             oldoutc = outc;
519             outc += strlen(tempbuf);
520             if (outc < BUFSIZ-1) 
521             {
522                strcpy(outbuf + oldoutc, tempbuf);
523             }
524             else
525             {
526                outbuf[oldoutc] = '\0';
527             }
528             break;
529          default:
530             sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
531                             "Format = \"%s\"\n"
532                             "Exiting.", this_thread, fmt);
533             /* FIXME RACE HAZARD: should start critical section error_log_use here */
534             if( !logfp )
535             {
536                logfp = stderr;
537             }
538             fputs(outbuf, logfp);
539             /* FIXME RACE HAZARD: should end critical section error_log_use here */
540             fatal_error(outbuf);
541             /* Never get here */
542             break;
543
544       } /* switch( p ) */
545
546    } /* for( p ... ) */
547    
548    /* done with var. args */
549    va_end( ap );
550    
551    if (outc >= BUFSIZ-2)
552    {
553       /* insufficient room for newline and trailing null. */
554
555       static const char warning[] = "... [too long, truncated]\n";
556
557       if (outc < BUFSIZ)
558       {
559          /* Need to add terminating null in this case. */
560          outbuf[outc] = '\0';
561       }
562
563       /* Truncate output */
564       outbuf[BUFSIZ - sizeof(warning)] = '\0';
565
566       /* Append warning */
567       strcat(outbuf, warning);
568    }
569    else
570    {
571       /* Add terminating newline and null */
572       outbuf[outc++] = '\n';
573       outbuf[outc] = '\0';
574    }
575
576    /* FIXME RACE HAZARD: should start critical section error_log_use here */
577
578    /* deal with glibc stupidity - it won't let you initialize logfp */
579    if( !logfp )
580    {
581       logfp = stderr;
582    }
583
584    fputs(outbuf, logfp);
585
586    if (loglevel == LOG_LEVEL_FATAL)
587    {
588       fatal_error(outbuf);
589       /* Never get here */
590    }
591
592    /* FIXME RACE HAZARD: should end critical section error_log_use here */
593
594 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
595    /* Write to display */
596    LogPutString(outbuf);
597 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
598
599 }
600
601
602 /*********************************************************************
603  *
604  * Function    :  w32_socket_strerr
605  *
606  * Description :  Translate the return value from WSAGetLastError()
607  *                into a string.
608  *
609  * Parameters  :
610  *          1  :  errcode = The return value from WSAGetLastError().
611  *          2  :  tmp_buf = A temporary buffer that might be used to
612  *                          store the string.
613  *
614  * Returns     :  String representing the error code.  This may be
615  *                a global string constant or a string stored in
616  *                tmp_buf.
617  *
618  *********************************************************************/
619 static char * w32_socket_strerr(int errcode, char * tmp_buf)
620 {
621 #define TEXT_FOR_ERROR(code,text) \
622    if (errcode == code)           \
623    {                              \
624       return #code " - " text;    \
625    }
626
627    TEXT_FOR_ERROR(WSAEACCES, "Permission denied")
628    TEXT_FOR_ERROR(WSAEADDRINUSE, "Address already in use.")
629    TEXT_FOR_ERROR(WSAEADDRNOTAVAIL, "Cannot assign requested address.");
630    TEXT_FOR_ERROR(WSAEAFNOSUPPORT, "Address family not supported by protocol family.");
631    TEXT_FOR_ERROR(WSAEALREADY, "Operation already in progress.");
632    TEXT_FOR_ERROR(WSAECONNABORTED, "Software caused connection abort.");
633    TEXT_FOR_ERROR(WSAECONNREFUSED, "Connection refused.");
634    TEXT_FOR_ERROR(WSAECONNRESET, "Connection reset by peer.");
635    TEXT_FOR_ERROR(WSAEDESTADDRREQ, "Destination address required.");
636    TEXT_FOR_ERROR(WSAEFAULT, "Bad address.");
637    TEXT_FOR_ERROR(WSAEHOSTDOWN, "Host is down.");
638    TEXT_FOR_ERROR(WSAEHOSTUNREACH, "No route to host.");
639    TEXT_FOR_ERROR(WSAEINPROGRESS, "Operation now in progress.");
640    TEXT_FOR_ERROR(WSAEINTR, "Interrupted function call.");
641    TEXT_FOR_ERROR(WSAEINVAL, "Invalid argument.");
642    TEXT_FOR_ERROR(WSAEISCONN, "Socket is already connected.");
643    TEXT_FOR_ERROR(WSAEMFILE, "Too many open sockets.");
644    TEXT_FOR_ERROR(WSAEMSGSIZE, "Message too long.");
645    TEXT_FOR_ERROR(WSAENETDOWN, "Network is down.");
646    TEXT_FOR_ERROR(WSAENETRESET, "Network dropped connection on reset.");
647    TEXT_FOR_ERROR(WSAENETUNREACH, "Network is unreachable.");
648    TEXT_FOR_ERROR(WSAENOBUFS, "No buffer space available.");
649    TEXT_FOR_ERROR(WSAENOPROTOOPT, "Bad protocol option.");
650    TEXT_FOR_ERROR(WSAENOTCONN, "Socket is not connected.");
651    TEXT_FOR_ERROR(WSAENOTSOCK, "Socket operation on non-socket.");
652    TEXT_FOR_ERROR(WSAEOPNOTSUPP, "Operation not supported.");
653    TEXT_FOR_ERROR(WSAEPFNOSUPPORT, "Protocol family not supported.");
654    TEXT_FOR_ERROR(WSAEPROCLIM, "Too many processes.");
655    TEXT_FOR_ERROR(WSAEPROTONOSUPPORT, "Protocol not supported.");
656    TEXT_FOR_ERROR(WSAEPROTOTYPE, "Protocol wrong type for socket.");
657    TEXT_FOR_ERROR(WSAESHUTDOWN, "Cannot send after socket shutdown.");
658    TEXT_FOR_ERROR(WSAESOCKTNOSUPPORT, "Socket type not supported.");
659    TEXT_FOR_ERROR(WSAETIMEDOUT, "Connection timed out.");
660    TEXT_FOR_ERROR(WSAEWOULDBLOCK, "Resource temporarily unavailable.");
661    TEXT_FOR_ERROR(WSAHOST_NOT_FOUND, "Host not found.");
662    TEXT_FOR_ERROR(WSANOTINITIALISED, "Successful WSAStartup not yet performed.");
663    TEXT_FOR_ERROR(WSANO_DATA, "Valid name, no data record of requested type.");
664    TEXT_FOR_ERROR(WSANO_RECOVERY, "This is a non-recoverable error.");
665    TEXT_FOR_ERROR(WSASYSNOTREADY, "Network subsystem is unavailable.");
666    TEXT_FOR_ERROR(WSATRY_AGAIN, "Non-authoritative host not found.");
667    TEXT_FOR_ERROR(WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range.");
668    TEXT_FOR_ERROR(WSAEDISCON, "Graceful shutdown in progress.");
669    /*
670     * The following error codes are documented in the Microsoft WinSock
671     * reference guide, but don't actually exist.
672     *
673     * TEXT_FOR_ERROR(WSA_INVALID_HANDLE, "Specified event object handle is invalid.");
674     * TEXT_FOR_ERROR(WSA_INVALID_PARAMETER, "One or more parameters are invalid.");
675     * TEXT_FOR_ERROR(WSAINVALIDPROCTABLE, "Invalid procedure table from service provider.");
676     * TEXT_FOR_ERROR(WSAINVALIDPROVIDER, "Invalid service provider version number.");
677     * TEXT_FOR_ERROR(WSA_IO_PENDING, "Overlapped operations will complete later.");
678     * TEXT_FOR_ERROR(WSA_IO_INCOMPLETE, "Overlapped I/O event object not in signaled state.");
679     * TEXT_FOR_ERROR(WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available.");
680     * TEXT_FOR_ERROR(WSAPROVIDERFAILEDINIT, "Unable to initialize a service provider.");
681     * TEXT_FOR_ERROR(WSASYSCALLFAILURE, "System call failure.");
682     * TEXT_FOR_ERROR(WSA_OPERATION_ABORTED, "Overlapped operation aborted.");
683     */
684
685    sprintf(tmp_buf, "(error number %d)", errcode);
686    return tmp_buf;
687 }
688
689
690 /*
691   Local Variables:
692   tab-width: 3
693   end:
694 */
695