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