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