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