CRLF->LF
[privoxy.git] / jcc.c
1 const char jcc_rcs[] = "$Id: jcc.c,v 1.5 2001/05/22 18:46:04 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
5  *
6  * Purpose     :  Main file.  Contains main() method, main loop, and 
7  *                the main connection-handling function.
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: jcc.c,v $
36  *    Revision 1.5  2001/05/22 18:46:04  oes
37  *
38  *    - Enabled filtering banners by size rather than URL
39  *      by adding patterns that replace all standard banner
40  *      sizes with the "Junkbuster" gif to the re_filterfile
41  *
42  *    - Enabled filtering WebBugs by providing a pattern
43  *      which kills all 1x1 images
44  *
45  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
46  *      which is selected by the (nonstandard and therefore
47  *      capital) letter 'U' in the option string.
48  *      It causes the quantifiers to be ungreedy by default.
49  *      Appending a ? turns back to greedy (!).
50  *
51  *    - Added a new interceptor ijb-send-banner, which
52  *      sends back the "Junkbuster" gif. Without imagelist or
53  *      MSIE detection support, or if tinygif = 1, or the
54  *      URL isn't recognized as an imageurl, a lame HTML
55  *      explanation is sent instead.
56  *
57  *    - Added new feature, which permits blocking remote
58  *      script redirects and firing back a local redirect
59  *      to the browser.
60  *      The feature is conditionally compiled, i.e. it
61  *      can be disabled with --disable-fast-redirects,
62  *      plus it must be activated by a "fast-redirects"
63  *      line in the config file, has its own log level
64  *      and of course wants to be displayed by show-proxy-args
65  *      Note: Boy, all the #ifdefs in 1001 locations and
66  *      all the fumbling with configure.in and acconfig.h
67  *      were *way* more work than the feature itself :-(
68  *
69  *    - Because a generic redirect template was needed for
70  *      this, tinygif = 3 now uses the same.
71  *
72  *    - Moved GIFs, and other static HTTP response templates
73  *      to project.h
74  *
75  *    - Some minor fixes
76  *
77  *    - Removed some >400 CRs again (Jon, you really worked
78  *      a lot! ;-)
79  *
80  *    Revision 1.4  2001/05/21 19:34:01  jongfoster
81  *    Made failure to bind() a fatal error.
82  *
83  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
84  *    Version 2.9.4 checkin.
85  *    - Merged popupfile and cookiefile, and added control over PCRS
86  *      filtering, in new "permissionsfile".
87  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
88  *      file error you now get a message box (in the Win32 GUI) rather
89  *      than the program exiting with no explanation.
90  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
91  *      skipping.
92  *    - Removed tabs from "config"
93  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
94  *    - Bumped up version number.
95  *
96  *    Revision 1.2  2001/05/17 22:34:44  oes
97  *     - Added hint on GIF char array generation to jcc.c
98  *     - Cleaned CRLF's from the sources and related files
99  *     - Repaired logging for REF and FRC
100  *
101  *    Revision 1.1.1.1  2001/05/15 13:58:56  oes
102  *    Initial import of version 2.9.3 source tree
103  *
104  *
105  *********************************************************************/
106 \f
107
108 #include "config.h"
109
110 #include <stdio.h>
111 #include <sys/types.h>
112 #include <stdlib.h>
113 #include <string.h>
114 #include <signal.h>
115 #include <fcntl.h>
116 #include <errno.h>
117
118 #ifdef _WIN32
119
120 # include <sys/timeb.h>
121 # include <windows.h>
122 # include <io.h>
123 # include <process.h>
124 # ifdef TOGGLE
125 #  include <time.h>
126 # endif /* def TOGGLE */
127
128 # include "win32.h"
129 # ifndef _WIN_CONSOLE
130 #  include "w32log.h"
131 # endif /* ndef _WIN_CONSOLE */
132
133 #else /* ifndef _WIN32 */
134
135 # include <unistd.h>
136 # include <sys/time.h>
137 # include <sys/wait.h>
138 # include <sys/stat.h>
139 # include <signal.h>
140
141 # ifdef __BEOS__
142 #  include <socket.h>  /* BeOS has select() for sockets only. */
143 #  include <OS.h>      /* declarations for threads and stuff. */
144 # endif
145
146 # ifndef FD_ZERO
147 #  include <select.h>
148 # endif
149
150 #endif
151
152 #include "project.h"
153 #include "jcc.h"
154 #include "filters.h"
155 #include "loaders.h"
156 #include "showargs.h"
157 #include "parsers.h"
158 #include "killpopup.h"
159 #include "miscutil.h"
160 #include "errlog.h"
161 #include "jbsockets.h"
162 #include "gateway.h"
163
164 const char jcc_h_rcs[] = JCC_H_VERSION;
165 const char project_h_rcs[] = PROJECT_H_VERSION;
166
167 const char DEFAULT_USER_AGENT[] ="User-Agent: Mozilla (X11; I; Linux 2.0.32 i586)";
168
169 struct client_state  clients[1];
170 struct file_list     files[1];
171
172 #ifdef STATISTICS
173 int urls_read     = 0;     /* total nr of urls read inc rejected */
174 int urls_rejected = 0;     /* total nr of urls rejected */
175 #endif /* def STATISTICS */
176
177
178 static void listen_loop(void);
179 static void chat(struct client_state *csp);
180 #ifdef AMIGA
181 void serve(struct client_state *csp);
182 #else /* ifndef AMIGA */
183 static void serve(struct client_state *csp);
184 #endif /* def AMIGA */
185
186 #ifdef __BEOS__
187 static int32 server_thread(void *data);
188 #endif /* def __BEOS__ */
189
190 #ifdef _WIN32
191 #define sleep(N)  Sleep(((N) * 1000))
192 #endif
193
194
195 /*********************************************************************
196  *
197  * Function    :  chat
198  *
199  * Description :  Once a connection to the client has been accepted,
200  *                this function is called (via serve()) to handle the
201  *                main business of the communication.  When this 
202  *                function returns, the caller must close the client
203  *                socket handle.
204  *
205  * Parameters  :
206  *          1  :  csp = Current client state (buffers, headers, etc...)
207  *
208  * Returns     :  On success, the number of bytes written are returned (zero
209  *                indicates nothing was written).  On error, -1 is returned,
210  *                and errno is set appropriately.  If count is zero and the
211  *                file descriptor refers to a regular file, 0 will be
212  *                returned without causing any other effect.  For a special
213  *                file, the results are not portable.
214  *
215  *********************************************************************/
216 static void chat(struct client_state *csp)
217 {
218 /* This next line is a little ugly, but it simplifies the if statement below. */
219 /* Basically if TOGGLE, then we want the if to test "csp->toggled_on", else we don't */
220 #ifdef TOGGLE
221 #   define IS_TOGGLED_ON csp->toggled_on &&
222 #else /* ifndef TOGGLE */
223 #   define IS_TOGGLED_ON
224 #endif /* ndef TOGGLE */
225
226 /* This next line is a little ugly, but it simplifies the if statement below. */
227 /* Basically if TRUST_FILES, then we want the if to call "trust_url", else we don't */
228 #ifdef TRUST_FILES
229 #   define IS_TRUSTED_URL (p = trust_url(http, csp)) ||
230 #else /* ifndef TRUST_FILES */
231 #   define IS_TRUSTED_URL
232 #endif /* ndef TRUST_FILES */
233
234    char buf[BUFSIZ], *hdr, *p, *req;
235    char *err = NULL;
236    char *eno;
237    fd_set rfds;
238    int n, maxfd, server_body, ms_iis5_hack = 0;
239    const struct gateway *gw;
240    struct http_request *http;
241 #ifdef KILLPOPUPS
242    int block_popups;         /* bool, 1==will block popups */
243    int block_popups_now = 0; /* bool, 1==currently blocking popups */
244 #endif /* def KILLPOPUPS */
245 #ifdef PCRS
246    int pcrs_filter;   /* bool, 1==will filter through pcrs */
247    int filtering = 0; /* bool, 1==currently filtering through pcrs */
248 #endif /* def PCRS */
249
250    http = csp->http;
251
252    /*
253     * Read the client's request.  Note that since we're not using select() we
254     * could get blocked here if a client connected, then didn't say anything!
255     */
256
257    while (FOREVER)
258    {
259       n = read_socket(csp->cfd, buf, sizeof(buf));
260
261       if (n <= 0) break;      /* error! */
262
263       add_to_iob(csp, buf, n);
264
265       req = get_header(csp);
266
267       if (req == NULL)
268       {
269          break;    /* no HTTP request! */
270       }
271
272       if (*req == '\0')
273       {
274          continue;   /* more to come! */
275       }
276  
277 #ifdef FORCE_LOAD
278       /* If this request contains the FORCE_PREFIX,
279                  * better get rid of it now and set the force flag --oes
280        */
281
282                 if(strstr(req, FORCE_PREFIX))
283       {
284                    strclean(req, FORCE_PREFIX);
285                    log_error(LOG_LEVEL_FORCE, "Enforcing request \"%s\".\n", req);
286                    csp->force = 1;
287                 } 
288       else
289       {
290                    csp->force = 0;
291                 }
292 #endif /* def FORCE_LOAD */
293   
294       parse_http_request(req, http, csp);
295       freez(req);
296       break;
297    }
298
299    if (http->cmd == NULL)
300    {
301       strcpy(buf, CHEADER);
302       write_socket(csp->cfd, buf, strlen(buf));
303       return;
304    }
305
306    /* decide how to route the HTTP request */
307
308    if ((gw = forward_url(http, csp)) == NULL)
309    {
310       log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!?  This can't happen!");
311       /* Never get here - LOG_LEVEL_FATAL causes program exit */
312    }
313
314    /* build the http request to send to the server
315     * we have to do one of the following:
316     *
317     * create = use the original HTTP request to create a new
318     *          HTTP request that has only the path component
319     *          without the http://domainspec
320     * pass   = pass the original HTTP request unchanged
321     *
322     * drop   = drop the HTTP request
323     *
324     * here's the matrix:
325     *                        SSL
326     *                    0        1
327     *                +--------+--------+
328     *                |        |        |
329     *             0  | create | drop   |
330     *                |        |        |
331     *  Forwarding    +--------+--------+
332     *                |        |        |
333     *             1  | pass   | pass   |
334     *                |        |        |
335     *                +--------+--------+
336     *
337     */
338
339    if (gw->forward_host)
340    {
341       /* if forwarding, just pass the request as is */
342       enlist(csp->headers, http->cmd);
343    }
344    else
345    {
346       if (http->ssl == 0)
347       {
348          /* otherwise elide the host information from the url */
349          p = NULL;
350          p = strsav(p, http->gpc);
351          p = strsav(p, " ");
352          p = strsav(p, http->path);
353          p = strsav(p, " ");
354          p = strsav(p, http->ver);
355          enlist(csp->headers, p);
356          freez(p);
357       }
358    }
359
360    /* decide what we're to do with cookies */
361
362 #ifdef TOGGLE
363    if (!csp->toggled_on)
364    {
365       /* Most compatible set of permissions */
366       csp->permissions = PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | PERMIT_POPUPS;
367    }
368    else
369    {
370       csp->permissions = url_permissions(http, csp);
371    }
372 #else /* ifndef TOGGLE */
373    csp->permissions = url_permissions(http, csp);
374 #endif /* ndef TOGGLE */
375
376 #ifdef KILLPOPUPS
377    block_popups               = ((csp->permissions & PERMIT_POPUPS) == 0);
378 #endif /* def KILLPOPUPS */
379 #ifdef PCRS
380    pcrs_filter                = (csp->rlist != NULL) &&  /* There are expressions to be used */
381                                 ((csp->permissions & PERMIT_RE_FILTER) != 0);
382 #endif /* def PCRS */
383
384
385    /* grab the rest of the client's headers */
386
387    while (FOREVER)
388    {
389       if ( ( p = get_header(csp) ) && ( *p == '\0' ) )
390       {
391          n = read_socket(csp->cfd, buf, sizeof(buf));
392          if (n <= 0)
393          {
394             log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
395             return;
396          }
397          add_to_iob(csp, buf, n);
398          continue;
399       }
400
401       if (p == NULL) break;
402
403       enlist(csp->headers, p);
404       freez(p);
405    }
406
407    /* filter it as required */
408
409    hdr = sed(client_patterns, add_client_headers, csp);
410
411    destroy_list(csp->headers);
412
413         /* Check the request against all rules, unless
414          * we're toggled off or in force mode. 
415     */
416  
417    if (IS_TOGGLED_ON
418 #ifdef FORCE_LOAD
419        (!csp->force) && 
420 #endif /* def FORCE_LOAD */
421        ( (p = intercept_url(http, csp)) ||
422          IS_TRUSTED_URL
423          (p = block_url(http, csp))
424 #ifdef FAST_REDIRECTS
425          || (fast_redirects && (p = redirect_url(http, csp))) 
426 #endif /* def FAST_REDIRECTS */
427       ))
428    {
429 #ifdef STATISTICS
430       csp->rejected = 1;
431 #endif /* def STATISTICS */
432
433       log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path);
434
435 #if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
436       /* Block as image?  */
437       if ( (tinygif > 0) && block_imageurl(http, csp) )
438       {
439          /* Send "blocked" image */
440          log_error(LOG_LEVEL_GPC, "%s%s image crunch!",
441                    http->hostport, http->path);
442
443          if ((tinygif == 2) || strstr(http->path, "ijb-send-banner"))
444          {
445             write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1);
446          }
447          if (tinygif == 1)
448          {
449             write_socket(csp->cfd, BLANKGIF, sizeof(BLANKGIF)-1);
450          }
451          else if ((tinygif == 3) && (tinygifurl))
452          {
453             p = (char *)malloc(strlen(HTTP_REDIRECT_TEMPLATE) + strlen(tinygifurl));
454                  sprintf(p, HTTP_REDIRECT_TEMPLATE, tinygifurl);
455             write_socket(csp->cfd, p, strlen(p));
456          }
457          else
458          {
459             write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1);
460          }
461       }
462       else
463 #endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
464       /* Block as HTML */
465       {
466          /* Send HTML "blocked" message, interception, or redirection result */
467          write_socket(csp->cfd, p, strlen(p));
468       }
469
470       log_error(LOG_LEVEL_LOG, "%s", p);
471
472       freez(p);
473       freez(hdr);
474       return;
475    }
476
477    log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path);
478
479    if (gw->forward_host)
480    {
481       log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s",
482                gw->forward_host, gw->forward_port, http->hostport);
483    }
484    else
485    {
486       log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport);
487    }
488
489    /* here we connect to the server, gateway, or the forwarder */
490
491    csp->sfd = (gw->conn)(gw, http, csp);
492
493    if (csp->sfd < 0)
494    {
495       log_error(LOG_LEVEL_CONNECT, "connect to: %s failed: %E",
496                 http->hostport);
497
498       if (errno == EINVAL)
499       {
500          err = zalloc(strlen(CNXDOM) + strlen(http->host));
501          sprintf(err, CNXDOM, http->host);
502       }
503       else
504       {
505          eno = safe_strerror(errno);
506          err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
507          sprintf(err, CFAIL, http->hostport, eno);
508       }
509
510       write_socket(csp->cfd, err, strlen(err));
511
512       log_error(LOG_LEVEL_LOG, err);
513
514       freez(err);
515       freez(hdr);
516       return;
517    }
518
519    log_error(LOG_LEVEL_CONNECT, "OK");
520
521    if (gw->forward_host || (http->ssl == 0))
522    {
523       /* write the client's (modified) header to the server
524        * (along with anything else that may be in the buffer)
525        */
526
527       n = strlen(hdr);
528
529       if ((write_socket(csp->sfd, hdr, n) != n)
530           || (flush_socket(csp->sfd, csp   ) <  0))
531       {
532          log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E",
533                     http->hostport);
534
535          eno = safe_strerror(errno);
536          err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
537          sprintf(err, CFAIL, http->hostport, eno);
538          write_socket(csp->cfd, err, strlen(err));
539
540          freez(err);
541          freez(hdr);
542          return;
543       }
544    }
545    else
546    {
547       /*
548        * We're running an SSL tunnel and we're not forwarding,
549        * so just send the "connect succeeded" message to the
550        * client, flush the rest, and get out of the way.
551        */
552       if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0)
553       {
554          freez(hdr);
555          return;
556       }
557       IOB_RESET(csp);
558    }
559
560    /* we're finished with the client's header */
561    freez(hdr);
562
563    maxfd = ( csp->cfd > csp->sfd ) ? csp->cfd : csp->sfd;
564
565    /* pass data between the client and server
566     * until one or the other shuts down the connection.
567     */
568
569    server_body = 0;
570
571    while (FOREVER)
572    {
573       FD_ZERO(&rfds);
574
575       FD_SET(csp->cfd, &rfds);
576       FD_SET(csp->sfd, &rfds);
577
578       n = select(maxfd+1, &rfds, NULL, NULL, NULL);
579
580       if (n < 0)
581       {
582          log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
583          return;
584       }
585
586       /* this is the body of the browser's request
587        * just read it and write it.
588        */
589
590       if (FD_ISSET(csp->cfd, &rfds))
591       {
592          n = read_socket(csp->cfd, buf, sizeof(buf));
593
594          if (n <= 0) break; /* "game over, man" */
595
596          if (write_socket(csp->sfd, buf, n) != n)
597          {
598             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
599             return;
600          }
601          continue;
602       }
603
604       /*
605        * The server wants to talk.  It could be the header or the body.
606        * If `hdr' is null, then it's the header otherwise it's the body.
607        * FIXME: Does `hdr' really mean `host'?
608        */
609
610
611       if (FD_ISSET(csp->sfd, &rfds))
612       {
613          fflush( 0 );
614          n = read_socket(csp->sfd, buf, sizeof(buf) - 1);
615
616          if (n < 0)
617          {
618             log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host);
619
620             eno = safe_strerror(errno);
621             sprintf(buf, CFAIL, http->hostport, eno);
622             freez(eno);
623             write_socket(csp->cfd, buf, strlen(buf));
624             return;
625          }
626
627          /* Add a trailing zero.  This lets filter_popups
628           * use string operations.
629           */
630          buf[n] = '\0';
631
632 #ifdef KILLPOPUPS
633          /* Filter the popups on this read. */
634          if (block_popups_now)
635          {
636             filter_popups(buf, n);
637          }
638 #endif /* def KILLPOPUPS */
639
640          /* Normally, this would indicate that we've read
641           * as much as the server has sent us and we can
642           * close the client connection.  However, Microsoft
643           * in its wisdom has released IIS/5 with a bug that
644           * prevents it from sending the trailing \r\n in
645           * a 302 redirect header (and possibly other headers).
646           * To work around this if we've haven't parsed
647           * a full header we'll append a trailing \r\n
648           * and see if this now generates a valid one.
649           *
650           * This hack shouldn't have any impacts.  If we've
651           * already transmitted the header or if this is a
652           * SSL connection, then we won't bother with this
653           * hack.  So we only work on partially received
654           * headers.  If we append a \r\n and this still
655           * doesn't generate a valid header, then we won't
656           * transmit anything to the client.
657           */
658          if (n == 0)
659          {
660             /* This hack must only be enforced for headers. */
661             if (server_body || http->ssl)
662             {
663 #ifdef PCRS
664                if (filtering)
665                {
666                   re_process_buffer(csp);
667                }
668 #endif /* def PCRS */
669                break; /* "game over, man" */
670             }
671
672             /* Let's pretend the server just sent us a blank line. */
673             n = sprintf(buf, "\r\n");
674
675             /*
676              * Now, let the normal header parsing algorithm below do its
677              * job.  If it fails, we'll exit instead of continuing.
678              */
679
680             ms_iis5_hack = 1;
681          }
682
683          /*
684           * If this is an SSL connection or we're in the body
685           * of the server document, just write it to the client.
686           */
687
688          if (server_body || http->ssl)
689          {
690 #ifdef PCRS
691             if (filtering)
692             {
693                add_to_iob(csp, buf, n); /* Buffer the body for filtering */
694             }
695             else
696 #endif /* def PCRS */
697             {
698                /* just write */
699                if (write_socket(csp->cfd, buf, n) != n)
700                {
701                   log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
702                   return;
703                }
704             }
705             continue;
706          }
707          else
708          {
709             /* we're still looking for the end of the
710              * server's header ... (does that make header
711              * parsing an "out of body experience" ?
712              */
713
714             /* buffer up the data we just read */
715             add_to_iob(csp, buf, n);
716
717             /* get header lines from the iob */
718
719             while ((p = get_header(csp)))
720             {
721                if (*p == '\0')
722                {
723                   /* see following note */
724                   break;
725                }
726                enlist(csp->headers, p);
727                freez(p);
728             }
729
730             /* NOTE: there are no "empty" headers so
731              * if the pointer `p' is not NULL we must
732              * assume that we reached the end of the
733              * buffer before we hit the end of the header.
734              */
735
736             if (p)
737             {
738                if (ms_iis5_hack)
739                {
740                   /* Well, we tried our MS IIS/5
741                    * hack and it didn't work.
742                    * The header is incomplete
743                    * and there isn't anything
744                    * we can do about it.
745                    */
746                   break;
747                }
748                else
749                {
750                   /* Since we have to wait for
751                    * more from the server before
752                    * we can parse the headers
753                    * we just continue here.
754                    */
755                   continue;
756                }
757             }
758
759             /* we have now received the entire header.
760              * filter it and send the result to the client
761              */
762
763             hdr = sed(server_patterns, add_server_headers, csp);
764             n   = strlen(hdr);
765
766             /* write the server's (modified) header to
767              * the client (along with anything else that
768              * may be in the buffer)
769              */
770
771 #ifdef KILLPOPUPS
772             /* Start blocking popups if appropriate. */
773
774             if (csp->is_text  &&  /* It's a text / * MIME-Type */
775                 !http->ssl    &&  /* We talk plaintext */
776                 block_popups)
777             {
778                block_popups_now = 1;
779             }
780
781 #endif /* def KILLPOPUPS */
782
783 #ifdef PCRS
784             /* Start re_filtering this if appropriate. */
785
786             if (csp->is_text  &&  /* It's a text / * MIME-Type */
787                 !http->ssl    &&  /* We talk plaintext */
788                 pcrs_filter)      /* Policy allows */
789             {
790                filtering = 1;
791             }
792
793 /* This next line is a little ugly, but it simplifies the if statement below. */
794 /* Basically if using PCRS, we want the OR condition to require "!filtering"  */
795 #define NOT_FILTERING_AND !filtering &&
796
797 #else /* not def PCRS */
798
799 #define NOT_FILTERING_AND
800
801 #endif /* def PCRS */
802
803
804             if ((write_socket(csp->cfd, hdr, n) != n)
805                 || (NOT_FILTERING_AND (flush_socket(csp->cfd, csp) < 0)))
806             {
807                log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
808
809                /* the write failed, so don't bother
810                 * mentioning it to the client...
811                 * it probably can't hear us anyway.
812                 */
813                freez(hdr);
814                return;
815             }
816
817             /* we're finished with the server's header */
818
819             freez(hdr);
820             server_body = 1;
821
822             /* If this was a MS IIS/5 hack then it means
823              * the server has already closed the
824              * connection.  Nothing more to read.  Time
825              * to bail.
826              */
827             if (ms_iis5_hack)
828             {
829                break;
830             }
831          }
832          continue;
833       }
834
835       return; /* huh? we should never get here */
836    }
837
838
839 }
840
841
842 /*********************************************************************
843  *
844  * Function    :  serve
845  *
846  * Description :  This is little more than chat.  We only "serve" to
847  *                to close any socket that chat may have opened.
848  *
849  * Parameters  :
850  *          1  :  csp = Current client state (buffers, headers, etc...)
851  *
852  * Returns     :  N/A
853  *
854  *********************************************************************/
855 #ifdef AMIGA
856 void serve(struct client_state *csp)
857 #else /* ifndef AMIGA */
858 static void serve(struct client_state *csp)
859 #endif /* def AMIGA */
860 {
861    chat(csp);
862    close_socket(csp->cfd);
863
864    if (csp->sfd >= 0)
865    {
866       close_socket(csp->sfd);
867    }
868
869    csp->active = 0;
870
871 }
872
873
874 #ifdef __BEOS__
875
876 /*********************************************************************
877  *
878  * Function    :  server_thread
879  *
880  * Description :  We only exist to call `serve' in a threaded environment.
881  *
882  * Parameters  :
883  *          1  :  data = Current client state (buffers, headers, etc...)
884  *
885  * Returns     :  Always 0.
886  *
887  *********************************************************************/
888 static int32 server_thread(void *data)
889 {
890    serve((struct client_state *) data);
891    return 0;
892
893 }
894
895 #endif
896
897
898 /*********************************************************************
899  *
900  * Function    :  main
901  *
902  * Description :  Load the config file and start the listen loop.
903  *                This function is a lot more *sane* with the `load_config'
904  *                and `listen_loop' functions; although it stills does
905  *                a *little* too much for my taste.
906  *
907  * Parameters  :
908  *          1  :  argc = Number of parameters (including $0).
909  *          2  :  argv = Array of (char *)'s to the parameters.
910  *
911  * Returns     :  1 if : can't open config file, unrecognized directive,
912  *                stats requested in multi-thread mode, can't open the
913  *                log file, can't open the jar file, listen port is invalid,
914  *                any load fails, and can't bind port.
915  *
916  *                Else main never returns, the process must be signaled
917  *                to terminate execution.  Or, on Windows, use the 
918  *                "File", "Exit" menu option.
919  *
920  *********************************************************************/
921 #ifdef __MINGW32__
922 int _main(int argc, const char *argv[])
923 #else
924 int main(int argc, const char *argv[])
925 #endif
926 {
927    configfile =
928 #ifdef AMIGA
929    "AmiTCP:db/junkbuster.config"
930 #elif !defined(_WIN32)
931    "config"
932 #else
933    "junkbstr.txt"
934 #endif
935       ;
936
937 #if !defined(_WIN32) || defined(_WIN_CONSOLE)
938    if ((argc >= 2) && (strcmp(argv[1], "--help")==0))
939    {
940       printf("JunkBuster proxy version " VERSION ".\n\n"
941          "Usage: %s [configfile]\n\n"
942          "See " HOME_PAGE_URL " for details.\n"
943          "This program is distributed under the GNU GPL, version 2 or later.\n",
944          argv[0]);
945       exit(2);
946    }
947    if ((argc >= 2) && (strcmp(argv[1], "--version")==0))
948    {
949       printf(VERSION "\n");
950       exit(2);
951    }
952 #endif /* !defined(_WIN32) || defined(_WIN_CONSOLE) */
953
954 #ifdef AMIGA
955    InitAmiga();
956 #endif
957
958    Argc = argc;
959    Argv = argv;
960
961    if (argc > 1)
962    {
963       configfile = argv[1];
964    }
965
966    remove_all_loaders();
967    memset( proxy_args, 0, sizeof( proxy_args ) );
968    files->next = NULL;
969
970    load_config( 0 );
971
972    /*
973     * Since load_config acts as a signal handler too, it returns
974     * its status in configret.  Check it for an error in loading.
975     */
976    if ( 0 != configret )
977    {
978       /* load config failed!  Exit with error. */
979       return( 1 );
980    }
981
982 #ifdef _WIN32
983    InitWin32();
984 #endif
985
986
987 #ifndef _WIN32
988    signal(SIGPIPE, SIG_IGN);
989    signal(SIGCHLD, SIG_IGN);
990    signal(SIGHUP, load_config);
991
992 #else /* ifdef _WIN32 */
993 # ifdef _WIN_CONSOLE
994    /*
995     * We *are* in a windows console app.
996     * Print a verbose messages about FAQ's and such
997     */
998    printf(win32_blurb);
999 # endif /* def _WIN_CONSOLE */
1000 #endif /* def _WIN32 */
1001
1002
1003    listen_loop();
1004
1005    /* NOTREACHED */
1006    return(-1);
1007
1008 }
1009
1010
1011 /*********************************************************************
1012  *
1013  * Function    :  listen_loop
1014  *
1015  * Description :  bind the listen port and enter a "FOREVER" listening loop.
1016  *
1017  * Parameters  :  N/A
1018  *
1019  * Returns     :  Never.
1020  *
1021  *********************************************************************/
1022 static void listen_loop(void)
1023 {
1024    struct client_state *csp = NULL;
1025    int bfd;
1026
1027    log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
1028              haddr ? haddr : "INADDR_ANY", hport);
1029
1030    bfd = bind_port(haddr, hport);
1031    config_changed = 0;
1032
1033    if (bfd < 0)
1034    {
1035       log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E "
1036          "- There may be another junkbuster or some other "
1037          "proxy running on port %d", 
1038          (NULL != haddr) ? haddr : "INADDR_ANY", hport, hport
1039       );
1040       /* shouldn't get here */
1041       return;
1042    }
1043
1044
1045    while (FOREVER)
1046    {
1047 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1048       while (waitpid(-1, NULL, WNOHANG) > 0)
1049       {
1050          /* zombie children */
1051       }
1052 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1053       sweep();
1054
1055       if ( NULL == (csp = (struct client_state *) malloc(sizeof(*csp))) )
1056       {
1057          log_error(LOG_LEVEL_ERROR, "malloc(%d) for csp failed: %E", sizeof(*csp));
1058          continue;
1059       }
1060
1061       memset(csp, '\0', sizeof(*csp));
1062
1063       csp->active = 1;
1064       csp->sfd    = -1;
1065
1066       if ( config_changed )
1067       {
1068          /*
1069           * Since we were listening to the "old port", we will not see
1070           * a "listen" param change until the next IJB request.  So, at
1071           * least 1 more request must be made for us to find the new
1072           * setting.  I am simply closing the old socket and binding the
1073           * new one.
1074           *
1075           * Which-ever is correct, we will serve 1 more page via the
1076           * old settings.  This should probably be a "show-proxy-args"
1077           * request.  This should not be a so common of an operation
1078           * that this will hurt people's feelings.
1079           */
1080          close_socket(bfd);
1081
1082          log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
1083                    haddr ? haddr : "INADDR_ANY", hport);
1084          bfd = bind_port(haddr, hport);
1085
1086          config_changed = 0;
1087       }
1088
1089       log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
1090
1091       if (!accept_connection(csp, bfd))
1092       {
1093          log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
1094
1095 #ifdef AMIGA
1096          if(!childs)
1097          {
1098             exit(1); 
1099          }
1100 #endif
1101          continue;
1102       }
1103       else
1104       {
1105          log_error(LOG_LEVEL_CONNECT, "OK");
1106       }
1107
1108 #if defined(TOGGLE)
1109       /* by haroon - most of credit to srt19170 */
1110       csp->toggled_on = g_bToggleIJB;
1111 #endif
1112
1113       /* add it to the list of clients */
1114       csp->next = clients->next;
1115       clients->next = csp;
1116
1117       if (run_loader(csp))
1118       {
1119          log_error(LOG_LEVEL_FATAL, "a loader failed - must exit");
1120          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1121       }
1122
1123       if (multi_threaded)
1124       {
1125          int child_id;
1126
1127 /* this is a switch () statment in the C preprocessor - ugh */
1128 #undef SELECTED_ONE_OPTION
1129
1130 #if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION)
1131 #define SELECTED_ONE_OPTION
1132          child_id = _beginthread(
1133             (void*)serve,
1134             64 * 1024,
1135             csp);
1136 #endif
1137
1138 #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION)
1139 #define SELECTED_ONE_OPTION
1140          {
1141             thread_id tid = spawn_thread
1142                (server_thread, "server", B_NORMAL_PRIORITY, csp);
1143
1144             if ((tid >= 0) && (resume_thread(tid) == B_OK))
1145             {
1146                child_id = (int) tid;
1147             }
1148             else
1149             {
1150                child_id = -1;
1151             }
1152          }
1153 #endif
1154
1155 #if defined(AMIGA) && !defined(SELECTED_ONE_OPTION)
1156 #define SELECTED_ONE_OPTION
1157          csp->cfd = ReleaseSocket(csp->cfd, -1);
1158          if((child_id = (int)CreateNewProcTags(
1159             NP_Entry, (ULONG)server_thread,
1160             NP_Output, Output(),
1161             NP_CloseOutput, FALSE,
1162             NP_Name, (ULONG)"junkbuster child",
1163             NP_StackSize, 20*1024,
1164             TAG_DONE)))
1165          {
1166             childs++;
1167             ((struct Task *)child_id)->tc_UserData = csp;
1168             Signal((struct Task *)child_id, SIGF_SINGLE);
1169             Wait(SIGF_SINGLE);
1170          }
1171 #endif
1172
1173 #if !defined(SELECTED_ONE_OPTION)
1174          child_id = fork();
1175 #endif
1176
1177 #undef SELECTED_ONE_OPTION
1178 /* end of cpp switch () */
1179
1180          if (child_id < 0) /* failed */
1181          {
1182             char buf[BUFSIZ];
1183
1184             log_error(LOG_LEVEL_ERROR, "can't fork: %E");
1185
1186             sprintf(buf , "JunkBuster: can't fork: errno = %d", errno);
1187
1188             write_socket(csp->cfd, buf, strlen(buf));
1189             close_socket(csp->cfd);
1190             csp->active = 0;
1191             sleep(5);
1192             continue;
1193          }
1194
1195 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1196          /* This block is only needed when using fork().
1197           * When using threads, the server thread was
1198           * created and run by the call to _beginthread().
1199           */
1200          if (child_id == 0)   /* child */
1201          {
1202             serve(csp);
1203             _exit(0);
1204
1205          }
1206          else  /* parent */
1207          {
1208             /* in a fork()'d environment, the parent's
1209              * copy of the client socket and the CSP
1210              * are not used.
1211              */
1212
1213 #if !defined(_WIN32) && defined(__CYGWIN__)
1214             wait( NULL );
1215 #endif /* !defined(_WIN32) && defined(__CYGWIN__) */
1216             close_socket(csp->cfd);
1217             csp->active = 0;
1218          }
1219 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1220       }
1221       else
1222       {
1223          serve(csp);
1224       }
1225    }
1226    /* NOTREACHED */
1227
1228 }
1229
1230
1231 /*
1232   Local Variables:
1233   tab-width: 3
1234   end:
1235 */