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