OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / httptunnel / tunnel.c
1 /*
2 tunnel.c
3
4 Copyright (C) 1999, 2000 Lars Brinkhoff.  See COPYING for terms and conditions.
5
6 See tunnel.h for some documentation about the programming interface.
7 */
8
9 #include <time.h>
10 #include <stdio.h>
11 #include <netdb_.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
14 #include <sys/poll_.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/tcp.h>
18
19 #include "http.h"
20 #include "tunnel.h"
21 #include "common.h"
22
23 /* #define IO_COUNT_HTTP_HEADER */
24 /* #define USE_SHUTDOWN */
25
26 #define READ_TRAIL_TIMEOUT (1 * 1000) /* milliseconds */
27 #define ACCEPT_TIMEOUT 10 /* seconds */
28
29 #define min(a, b) ((a) < (b) ? (a) : (b))
30 #define TUNNEL_IN 1
31 #define TUNNEL_OUT 2
32
33 #if SIZEOF_CHAR == 1
34 typedef unsigned char Request;
35 #else
36 #error "FIXME: Can't handle SIZEOF_CHAR != 1"
37 #endif
38
39 #if SIZEOF_SHORT == 2
40 typedef unsigned short Length;
41 #else
42 #error "FIXME: Can't handle SIZEOF_SHORT != 2"
43 #endif
44
45 enum tunnel_request
46 {
47   TUNNEL_SIMPLE = 0x40,
48   TUNNEL_OPEN = 0x01,
49   TUNNEL_DATA = 0x02,
50   TUNNEL_PADDING = 0x03,
51   TUNNEL_ERROR = 0x04,
52   TUNNEL_PAD1 = TUNNEL_SIMPLE | 0x05,
53   TUNNEL_CLOSE = TUNNEL_SIMPLE | 0x06,
54   TUNNEL_DISCONNECT = TUNNEL_SIMPLE | 0x07
55 };
56
57 static inline const char *
58 REQ_TO_STRING (Request request)
59 {
60   switch (request)
61     {
62     case TUNNEL_OPEN:           return "TUNNEL_OPEN";
63     case TUNNEL_DATA:           return "TUNNEL_DATA";
64     case TUNNEL_PADDING:        return "TUNNEL_PADDING";
65     case TUNNEL_ERROR:          return "TUNNEL_ERROR";
66     case TUNNEL_PAD1:           return "TUNNEL_PAD1";
67     case TUNNEL_CLOSE:          return "TUNNEL_CLOSE";
68     case TUNNEL_DISCONNECT:     return "TUNNEL_DISCONNECT";
69     default:                    return "(unknown)";
70     }
71 }
72
73 struct tunnel
74 {
75   int in_fd, out_fd;
76   int server_socket;
77   Http_destination dest;
78   struct sockaddr_in address;
79   size_t bytes;
80   size_t content_length;
81   char buf[65536];
82   char *buf_ptr;
83   size_t buf_len;
84   int padding_only;
85   size_t in_total_raw;
86   size_t in_total_data;
87   size_t out_total_raw;
88   size_t out_total_data;
89   time_t out_connect_time;
90   int strict_content_length;
91   int keep_alive;
92   int max_connection_age;
93 };
94
95 static const size_t sizeof_header = sizeof (Request) + sizeof (Length);
96
97 static inline int
98 tunnel_is_disconnected (Tunnel *tunnel)
99 {
100   return tunnel->out_fd == -1;
101 }
102
103 static inline int
104 tunnel_is_connected (Tunnel *tunnel)
105 {
106   return !tunnel_is_disconnected (tunnel);
107 }
108
109 static inline int
110 tunnel_is_server (Tunnel *tunnel)
111 {
112   return tunnel->dest.host_name == NULL;
113 }
114
115 static inline int
116 tunnel_is_client (Tunnel *tunnel)
117 {
118   return !tunnel_is_server (tunnel);
119 }
120
121 #if 1
122 static int
123 get_proto_number (const char *name)
124 {
125   struct protoent *p;
126   int number;
127
128   p = getprotobyname (name);
129   if (p == NULL)
130     number = -1;
131   else
132     number = p->p_proto;
133   endprotoent ();
134
135   return number;
136 }
137 #endif
138
139 static int
140 tunnel_in_setsockopts (int fd)
141 {
142 #ifdef SO_RCVLOWAT
143   int tcp = get_proto_number ("tcp");
144
145   if (tcp != -1)
146     {
147       int i, n;
148
149       i = 1;
150       if (setsockopt (fd,
151                       tcp,
152                       SO_RCVLOWAT,
153                       (void *)&i,
154                       sizeof i) == -1)
155         {
156           log_debug ("tunnel_in_setsockopts: non-fatal SO_RCVLOWAT error: %s",
157                      strerror (errno));
158         }
159       n = sizeof i;
160       getsockopt (fd,
161                   tcp,
162                   SO_RCVLOWAT,
163                   (void *)&i,
164                   &n);
165       log_debug ("tunnel_out_setsockopts: SO_RCVLOWAT: %d", i);
166     }
167 #endif /* SO_RCVLOWAT */
168
169   return 0;
170 }
171
172 static int
173 tunnel_out_setsockopts (int fd)
174 {
175 #ifdef SO_SNDLOWAT
176   {
177     int tcp = get_proto_number ("tcp");
178     int i, n;
179  
180     if (tcp != -1)
181       {
182         i = 1;
183         if (setsockopt (fd,
184                         tcp,
185                         SO_SNDLOWAT,
186                         (void *)&i,
187                         sizeof i) == -1)
188           {
189             log_debug ("tunnel_out_setsockopts: "
190                        "non-fatal SO_SNDLOWAT error: %s",
191                        strerror (errno));
192           }
193         n = sizeof i;
194         getsockopt (fd,
195                     tcp,
196                     SO_SNDLOWAT,
197                     (void *)&i,
198                     &n);
199         log_debug ("tunnel_out_setsockopts: non-fatal SO_SNDLOWAT: %d", i);
200       }
201   }
202 #endif /* SO_SNDLOWAT */
203
204 #ifdef SO_LINGER
205   {
206     struct linger l;
207     int n;
208
209     l.l_onoff = 1;
210     l.l_linger = 20 * 100; /* linger for 20 seconds */
211     if (setsockopt (fd,
212                     SOL_SOCKET,
213                     SO_LINGER,
214                     (void *)&l,
215                     sizeof l) == -1)
216       {
217         log_debug ("tunnel_out_setsockopts: non-fatal SO_LINGER error: %s",
218                    strerror (errno));
219       }
220     n = sizeof l;
221     getsockopt (fd,
222                 SOL_SOCKET,
223                 SO_LINGER,
224                 (void *)&l,
225                 &n);
226     log_debug ("tunnel_out_setsockopts: SO_LINGER: onoff=%d linger=%d",
227                l.l_onoff, l.l_linger);
228   }
229 #endif /* SO_LINGER */
230
231 #ifdef TCP_NODELAY
232   {
233     int tcp = get_proto_number ("tcp");
234     int i, n;
235  
236     if (tcp != -1)
237       {
238         i = 1;
239         if (setsockopt (fd,
240                         tcp,
241                         TCP_NODELAY,
242                         (void *)&i,
243                         sizeof i) == -1)
244           {
245             log_debug ("tunnel_out_setsockopts: "
246                        "non-fatal TCP_NODELAY error: %s",
247                        strerror (errno));
248           }
249         n = sizeof i;
250         getsockopt (fd,
251                     tcp,
252                     TCP_NODELAY,
253                     (void *)&i,
254                     &n);
255         log_debug ("tunnel_out_setsockopts: non-fatal TCP_NODELAY: %d", i);
256       }
257   }
258 #else
259 #ifdef SO_SNDBUF
260   {
261     int i, n;
262
263     i = 0;
264     if (setsockopt (fd,
265                     SOL_SOCKET,
266                     SO_SNDBUF,
267                     (void *)&i,
268                     sizeof i) == -1)
269       {
270         log_debug ("tunnel_out_setsockopts: non-fatal SO_SNDBUF error: %s",
271                    strerror (errno));
272       }
273     n = sizeof i;
274     getsockopt (fd,
275                 SOL_SOCKET,
276                 SO_SNDBUF,
277                 (void *)&i,
278                 &n);
279     log_debug ("tunnel_out_setsockopts: SO_SNDBUF: %d", i);
280   }
281 #endif /* SO_SNDBUF */
282 #endif /* TCP_NODELAY */
283
284 #ifdef SO_KEEPALIVE
285   {
286     int i, n;
287
288     i = 1;
289     if (setsockopt (fd,
290                     SOL_SOCKET,
291                     SO_KEEPALIVE,
292                     (void *)&i,
293                     sizeof i) == -1)
294       {
295         log_debug ("tunnel_out_setsockopts: non-fatal SO_KEEPALIVE error: %s",
296                    strerror (errno));
297       }
298     n = sizeof i;
299     getsockopt (fd,
300                 SOL_SOCKET,
301                 SO_KEEPALIVE,
302                 (void *)&i,
303                 &n);
304     log_debug ("tunnel_out_setsockopts: SO_KEEPALIVE: %d", i);
305   }
306 #endif /* SO_KEEPALIVE */
307
308   return 0;
309 }
310
311 static void
312 tunnel_out_disconnect (Tunnel *tunnel)
313 {
314   if (tunnel_is_disconnected (tunnel))
315     return;
316
317 #ifdef DEBUG_MODE
318   if (tunnel_is_client (tunnel) &&
319       tunnel->bytes != tunnel->content_length + 1)
320     log_error ("tunnel_out_disconnect: warning: "
321                "bytes=%d != content_length=%d",
322                tunnel->bytes, tunnel->content_length + 1);
323 #endif
324
325   close (tunnel->out_fd);
326   tunnel->out_fd = -1;
327   tunnel->bytes = 0;
328   tunnel->buf_ptr = tunnel->buf;
329   tunnel->buf_len = 0;
330
331   log_debug ("tunnel_out_disconnect: output disconnected");
332 }
333
334 static void
335 tunnel_in_disconnect (Tunnel *tunnel)
336 {
337   if (tunnel->in_fd == -1)
338     return;
339
340   close (tunnel->in_fd);
341   tunnel->in_fd = -1;
342
343   log_debug ("tunnel_in_disconnect: input disconnected");
344 }
345
346 static int
347 tunnel_out_connect (Tunnel *tunnel)
348 {
349   ssize_t n;
350
351   if (tunnel_is_connected (tunnel))
352     {
353       log_debug ("tunnel_out_connect: already connected");
354       tunnel_out_disconnect (tunnel);
355     }
356
357   tunnel->out_fd = do_connect (&tunnel->address);
358   if (tunnel->out_fd == -1)
359     {
360       log_error ("tunnel_out_connect: do_connect(%d.%d.%d.%d) error: %s",
361                   tunnel->address.sin_addr.s_addr >> 24,
362                  (tunnel->address.sin_addr.s_addr >> 16) & 0xff,
363                  (tunnel->address.sin_addr.s_addr >>  8) & 0xff,
364                   tunnel->address.sin_addr.s_addr        & 0xff,
365                  strerror (errno));
366       return -1;
367     }
368
369   tunnel_out_setsockopts (tunnel->out_fd);
370
371 #ifdef USE_SHUTDOWN
372   shutdown (tunnel->out_fd, 0);
373 #endif
374
375   /* + 1 to allow for TUNNEL_DISCONNECT */
376   n = http_post (tunnel->out_fd,
377                  &tunnel->dest,
378                  tunnel->content_length + 1);
379   if (n == -1)
380     return -1;
381 #ifdef IO_COUNT_HTTP_HEADER
382   tunnel->out_total_raw += n;
383   log_annoying ("tunnel_out_connect: out_total_raw = %u",
384                 tunnel->out_total_raw);
385 #endif
386
387   tunnel->bytes = 0;
388   tunnel->buf_ptr = tunnel->buf;
389   tunnel->buf_len = 0;
390   tunnel->padding_only = TRUE;
391   time (&tunnel->out_connect_time);
392
393   log_debug ("tunnel_out_connect: output connected");
394
395   return 0;
396 }
397
398 static int
399 tunnel_in_connect (Tunnel *tunnel)
400 {
401   Http_response *response;
402   ssize_t n;
403
404   log_verbose ("tunnel_in_connect()");
405
406   if (tunnel->in_fd != -1)
407     {
408       log_error ("tunnel_in_connect: already connected");
409       return -1;
410     }
411
412   tunnel->in_fd = do_connect (&tunnel->address);
413   if (tunnel->in_fd == -1)
414     {
415       log_error ("tunnel_in_connect: do_connect() error: %s",
416                  strerror (errno));
417       return -1;
418     }
419
420   tunnel_in_setsockopts (tunnel->in_fd);
421
422   if (http_get (tunnel->in_fd, &tunnel->dest) == -1)
423     return -1;
424
425 #ifdef USE_SHUTDOWN
426   if (shutdown (tunnel->in_fd, 1) == -1)
427     {
428       log_error ("tunnel_in_connect: shutdown() error: %s",
429                  strerror (errno));
430       return -1;
431     }
432 #endif
433
434   n = http_parse_response (tunnel->in_fd, &response);
435   if (n <= 0)
436     {
437       if (n == 0)
438         log_error ("tunnel_in_connect: no response; peer "
439                    "closed connection");
440       else
441         log_error ("tunnel_in_connect: no response; error: %s",
442                    strerror (errno));
443     }
444   else if (response->major_version != 1 ||
445            (response->minor_version != 1 &&
446             response->minor_version != 0))
447     {
448       log_error ("tunnel_in_connect: unknown HTTP version: %d.%d",
449                  response->major_version, response->minor_version);
450       n = -1;
451     }
452   else if (response->status_code != 200)
453     {
454       log_error ("tunnel_in_connect: HTTP error %d", response->status_code);
455       errno = http_error_to_errno (-response->status_code);
456       n = -1;
457     }
458
459   http_destroy_response (response);
460
461   if (n > 0)
462     {
463 #ifdef IO_COUNT_HTTP_HEADER
464       tunnel->in_total_raw += n;
465       log_annoying ("tunnel_in_connect: in_total_raw = %u",
466                     tunnel->in_total_raw);
467 #endif
468     }
469   else
470     {
471       return n;
472     }
473
474   log_debug ("tunnel_in_connect: input connected");
475   return 1;
476 }
477
478 static inline ssize_t
479 tunnel_write_data (Tunnel *tunnel, void *data, size_t length)
480 {
481   if (write_all (tunnel->out_fd, data, length) == -1)
482     {
483       log_error ("tunnel_write_data: write error: %s", strerror (errno));
484       return -1;
485     }
486   tunnel->bytes += length;
487   return length;
488 }
489
490 static int
491 tunnel_write_request (Tunnel *tunnel, Request request,
492                       void *data, Length length)
493 {
494   if (tunnel->bytes + sizeof request +
495       (data ? sizeof length + length : 0) > tunnel->content_length)
496     tunnel_padding (tunnel, tunnel->content_length - tunnel->bytes);
497
498 #if 1 /* FIXME: this is a kludge */
499   {
500     time_t t;
501
502     time (&t);
503     if (tunnel_is_client (tunnel) &&
504         tunnel_is_connected (tunnel) &&
505         t - tunnel->out_connect_time > tunnel->max_connection_age)
506       {
507         char c = TUNNEL_DISCONNECT;
508
509         log_debug ("tunnel_write_request: connection > %d seconds old",
510                    tunnel->max_connection_age);
511
512         if (tunnel->strict_content_length)
513           {
514             int l = tunnel->content_length - tunnel->bytes - 1;
515
516             log_debug ("tunnel_write_request: write padding (%d bytes)",
517                        tunnel->content_length - tunnel->bytes - 1);
518             if (l > 3)
519             {
520                 char c;
521                 short s;
522                 int i;
523
524                 c = TUNNEL_PADDING;
525                 tunnel_write_data (tunnel, &c, sizeof c);
526
527                 s = htons(l-2);
528                 tunnel_write_data (tunnel, &s, sizeof s);
529
530                 l -= 2;
531                 c = 0;
532                 for (i=0; i<l; i++)
533                         tunnel_write_data (tunnel, &c, sizeof c);
534             }
535             else
536             {
537                 char c = TUNNEL_PAD1;
538                 int i;
539                 
540                 for (i=0; i<l; i++)
541                         tunnel_write_data (tunnel, &c, sizeof c);
542             }
543           }
544
545         log_debug ("tunnel_write_request: closing old connection");
546         if (tunnel_write_data (tunnel, &c, sizeof c) <= 0)
547           return -1;
548         tunnel_out_disconnect (tunnel);
549       }
550   }
551 #endif
552
553   if (tunnel_is_disconnected (tunnel))
554     {
555       if (tunnel_is_client (tunnel))
556         {
557           if (tunnel_out_connect (tunnel) == -1)
558             return -1;
559         }
560       else
561         {
562 #if 0
563           log_error ("tunnel_write_request: output is disconnected");
564           errno = EIO;
565           return -1;
566 #else
567           if (tunnel_accept (tunnel) == -1)
568             return -1;
569 #endif
570         }
571     }
572
573   if (request != TUNNEL_PADDING && request != TUNNEL_PAD1)
574     tunnel->padding_only = FALSE;
575
576   if (tunnel_write_data (tunnel, &request, sizeof request) == -1)
577     {
578       if (errno != EPIPE)
579         return -1;
580
581       tunnel_out_disconnect (tunnel);
582       if (tunnel_is_client (tunnel))
583         tunnel_out_connect (tunnel);
584       else
585         {
586           log_error ("tunnel_write_request: couldn't write request: "
587                      "output is disconnected");
588           errno = EIO;
589           return -1;
590         }
591       /* return tunnel_write_request (tunnel, request, data, length); */
592       if (tunnel_write_data (tunnel, &request, sizeof request) == -1)
593         return -1;
594     }
595
596   if (data)
597     {
598       Length network_length = htons ((short)length);
599       if (tunnel_write_data (tunnel,
600                              &network_length,
601                              sizeof network_length) == -1)
602         return -1;
603
604 #ifdef DEBUG_MODE
605       if (request == TUNNEL_DATA && debug_level >= 5)
606         {
607           log_annoying ("tunnel_write_request: TUNNEL_DATA:");
608           dump_buf (debug_file, data, (size_t)length);
609         }
610 #endif
611
612       if (tunnel_write_data (tunnel, data, (size_t)length) == -1)
613         return -1;
614     }
615
616   if (data)
617     {
618       tunnel->out_total_raw += 3 + length;
619
620       if (request == TUNNEL_DATA)
621         log_verbose ("tunnel_write_request: %s (%d)",
622                      REQ_TO_STRING (request), length);
623       else
624         log_debug ("tunnel_write_request: %s (%d)",
625                      REQ_TO_STRING (request), length);
626     }
627   else
628     {
629       tunnel->out_total_raw += 1;
630       log_debug ("tunnel_write_request: %s", REQ_TO_STRING (request));
631     }
632
633   log_annoying ("tunnel_write_data: out_total_raw = %u",
634                 tunnel->out_total_raw);
635
636 #ifdef DEBUG_MODE
637   if (tunnel->bytes > tunnel->content_length)
638     log_debug ("tunnel_write_request: tunnel->bytes > tunnel->content_length");
639 #endif
640                     
641   if (tunnel->bytes >= tunnel->content_length)
642     {
643       char c = TUNNEL_DISCONNECT;
644       tunnel_write_data (tunnel, &c, sizeof c);
645       tunnel_out_disconnect (tunnel);
646 #if 0
647       if (tunnel_is_server (tunnel))
648         tunnel_accept (tunnel);
649 #endif
650     }
651
652   return 0;
653 }
654
655 int
656 tunnel_connect (Tunnel *tunnel)
657 {
658   char auth_data[1] = { 42 }; /* dummy data, not used by server */
659
660   log_verbose ("tunnel_connect()");
661
662   if (tunnel_is_connected (tunnel))
663     {
664       log_error ("tunnel_connect: already connected");
665       errno = EINVAL;
666       return -1;
667     }
668
669   if (tunnel_write_request (tunnel, TUNNEL_OPEN,
670                             auth_data, sizeof auth_data) == -1)
671     return -1;
672
673   if (tunnel_in_connect (tunnel) <= 0)
674     return -1;
675
676   return 0;
677 }
678
679 static inline int
680 tunnel_write_or_padding (Tunnel *tunnel, Request request, void *data,
681                          size_t length)
682 {
683   static char padding[65536];
684   size_t n, remaining;
685   char *wdata = data;
686
687   for (remaining = length; remaining > 0; remaining -= n, wdata += n)
688     {
689       if (tunnel->bytes + remaining > tunnel->content_length - sizeof_header &&
690           tunnel->content_length - tunnel->bytes > sizeof_header)
691         n = tunnel->content_length - sizeof_header - tunnel->bytes;
692       else if (remaining > tunnel->content_length - sizeof_header)
693         n = tunnel->content_length - sizeof_header;
694       else
695         n = remaining;
696
697       if (n > 65535)
698         n = 65535;
699
700       if (request == TUNNEL_PADDING)
701         {
702           if (n + sizeof_header > remaining)
703             n = remaining - sizeof_header;
704           if (tunnel_write_request (tunnel, request, padding, n) == -1)
705             break;
706           n += sizeof_header;
707         }
708       else
709         {
710           if (tunnel_write_request (tunnel, request, wdata, n) == -1)
711             break;
712         }
713     }
714
715   return length - remaining;
716 }
717
718 ssize_t
719 tunnel_write (Tunnel *tunnel, void *data, size_t length)
720 {
721   ssize_t n;
722
723   n = tunnel_write_or_padding (tunnel, TUNNEL_DATA, data, length);
724   tunnel->out_total_data += length;
725   log_verbose ("tunnel_write: out_total_data = %u", tunnel->out_total_data);
726   return n;
727 }
728
729 ssize_t
730 tunnel_padding (Tunnel *tunnel, size_t length)
731 {
732   if (length < sizeof_header + 1)
733     {
734       int i;
735
736       for (i = 0; i < length; i++)
737         tunnel_write_request (tunnel, TUNNEL_PAD1, NULL, 0);
738       return length;
739     }
740
741   return tunnel_write_or_padding (tunnel, TUNNEL_PADDING, NULL, length);
742 }
743
744 int
745 tunnel_close (Tunnel *tunnel)
746 {
747   struct pollfd p;
748   char buf[10240];
749   ssize_t n;
750
751   if (tunnel->strict_content_length)
752     {
753       log_debug ("tunnel_close: write padding (%d bytes)",
754                  tunnel->content_length - tunnel->bytes - 1);
755       tunnel_padding (tunnel, tunnel->content_length - tunnel->bytes - 1);
756     }
757
758   log_debug ("tunnel_close: write TUNNEL_CLOSE request");
759   tunnel_write_request (tunnel, TUNNEL_CLOSE, NULL, 0);
760
761   tunnel_out_disconnect (tunnel);
762
763   log_debug ("tunnel_close: reading trailing data from input ...");
764   p.fd = tunnel->in_fd;
765   p.events = POLLIN;
766   while (poll (&p, 1, READ_TRAIL_TIMEOUT) > 0)
767     {
768       if (p.revents & POLLIN)
769         {
770           n = read (tunnel->in_fd, buf, sizeof buf);
771           if (n > 0)
772             {
773               log_annoying ("read (%d, %p, %d) = %d",
774                             tunnel->in_fd, buf, sizeof buf, n);
775               continue;
776             }
777           else if (n == -1 && errno == EAGAIN)
778             continue;
779           else if (n == -1)
780             log_debug ("tunnel_close: ... error: %s", strerror (errno));
781           else
782             log_debug ("tunnel_close: ... done (tunnel closed)");
783         }
784       if (p.revents & POLLHUP)
785         log_debug ("POLLHUP");
786       if (p.revents & POLLERR)
787         log_debug ("POLLERR");
788       if (p.revents & POLLNVAL)
789         log_debug ("POLLNVAL");
790       break;
791     }
792
793   tunnel_in_disconnect (tunnel);
794
795   tunnel->buf_len = 0;
796   tunnel->in_total_raw = 0;
797   tunnel->in_total_data = 0;
798   tunnel->out_total_raw = 0;
799   tunnel->out_total_data = 0;
800
801   return 0;
802 }
803
804 static int
805 tunnel_read_request (Tunnel *tunnel, enum tunnel_request *request,
806                      unsigned char *buf, size_t *length)
807 {
808   Request req;
809   Length len;
810   ssize_t n;
811
812   log_annoying ("read (%d, %p, %d) ...", tunnel->in_fd, &req, 1);
813   n = read (tunnel->in_fd, &req, 1);
814   log_annoying ("... = %d", n);
815   if (n == -1)
816     {
817       if (errno != EAGAIN)
818         log_error ("tunnel_read_request: error reading request: %s",
819                    strerror (errno));
820       return n;
821     }
822   else if (n == 0)
823     {
824       log_debug ("tunnel_read_request: connection closed by peer");
825       tunnel_in_disconnect (tunnel);
826
827       if (tunnel_is_client (tunnel)
828           && tunnel_in_connect (tunnel) == -1)
829         return -1;
830
831       errno = EAGAIN;
832       return -1;
833     }
834   *request = req;
835   tunnel->in_total_raw += n;
836   log_annoying ("request = 0x%x (%s)", req, REQ_TO_STRING (req));
837
838   if (req & TUNNEL_SIMPLE)
839     {
840       log_annoying ("tunnel_read_request: in_total_raw = %u",
841                     tunnel->in_total_raw);
842       log_debug ("tunnel_read_request:  %s", REQ_TO_STRING (req));
843       *length = 0;
844       return 1;
845     }
846
847   n = read_all (tunnel->in_fd, &len, 2);
848   if (n <= 0)
849     {
850       log_error ("tunnel_read_request: error reading request length: %s",
851                  strerror (errno));
852       if (n == 0)
853         errno = EIO;
854       return -1;
855     }
856   len = ntohs (len);
857   *length = len;
858   tunnel->in_total_raw += n;
859   log_annoying ("length = %d", len);
860
861   if (len > 0)
862     {
863       n = read_all (tunnel->in_fd, buf, (size_t)len);
864       if (n <= 0)
865         {
866           log_error ("tunnel_read_request: error reading request data: %s",
867                      strerror (errno));
868           if (n == 0)
869             errno = EIO;
870           return -1;
871         }
872       tunnel->in_total_raw += n;
873       log_annoying ("tunnel_read_request: in_total_raw = %u",
874                     tunnel->in_total_raw);
875     }
876
877   if (req == TUNNEL_DATA)
878     log_verbose ("tunnel_read_request:  %s (%d)",
879                  REQ_TO_STRING (req), len);
880   else
881     log_debug ("tunnel_read_request:  %s (%d)",
882                REQ_TO_STRING (req), len);
883
884   return 1;
885 }
886
887 ssize_t
888 tunnel_read (Tunnel *tunnel, void *data, size_t length)
889 {
890   enum tunnel_request req;
891   size_t len;
892   ssize_t n;
893
894   if (tunnel->buf_len > 0)
895     {
896       n = min (tunnel->buf_len, length);
897       memcpy (data, tunnel->buf_ptr, n);
898       tunnel->buf_ptr += n;
899       tunnel->buf_len -= n;
900       return n;
901     }
902
903   if (tunnel->in_fd == -1)
904     {
905       if (tunnel_is_client (tunnel))
906         {
907           if (tunnel_in_connect (tunnel) == -1)
908             return -1;
909         }
910       else
911         {
912 #if 1
913           if (tunnel_accept (tunnel) == -1)
914             return -1;
915 #else
916           errno = EAGAIN;
917           return -1;
918 #endif
919         }
920
921       errno = EAGAIN;
922       return -1;
923     }
924
925   if (tunnel->out_fd == -1 && tunnel_is_server (tunnel))
926     {
927       tunnel_accept (tunnel);
928       errno = EAGAIN;
929       return -1;
930     }
931
932   if (tunnel_read_request (tunnel, &req, tunnel->buf, &len) <= 0)
933     {
934 log_annoying ("tunnel_read_request returned <= 0, returning -1");
935       return -1;
936     }
937
938   switch (req)
939     {
940     case TUNNEL_OPEN:
941       /* do something with tunnel->buf */
942       break;
943
944     case TUNNEL_DATA:
945       tunnel->buf_ptr = tunnel->buf;
946       tunnel->buf_len = len;
947       tunnel->in_total_data += len;
948       log_verbose ("tunnel_read: in_total_data = %u", tunnel->in_total_data);
949       return tunnel_read (tunnel, data, length);
950
951     case TUNNEL_PADDING:
952       /* discard data */
953       break;
954
955     case TUNNEL_PAD1:
956       /* do nothing */
957       break;
958
959     case TUNNEL_ERROR:
960       tunnel->buf[len] = 0;
961       log_error ("tunnel_read: received error: %s", tunnel->buf);
962       errno = EIO;
963       return -1;
964
965     case TUNNEL_CLOSE:
966       return 0;
967
968     case TUNNEL_DISCONNECT:
969       tunnel_in_disconnect (tunnel);
970
971       if (tunnel_is_client (tunnel)
972           && tunnel_in_connect (tunnel) == -1)
973         return -1;
974
975       errno = EAGAIN;
976       return -1;
977
978     default:
979       log_error ("tunnel_read: protocol error: unknown request 0x%02x", req);
980       errno = EINVAL;
981       return -1;
982     }
983
984   errno = EAGAIN;
985   return -1;
986 }
987
988 int
989 tunnel_pollin_fd (Tunnel *tunnel)
990 {
991   if (tunnel_is_server (tunnel) &&
992       (tunnel->in_fd == -1 || tunnel->out_fd == -1))
993     {
994       if (tunnel->in_fd == -1)
995         log_verbose ("tunnel_pollin_fd: in_fd = -1; returning server_socket = %d",
996                      tunnel->server_socket);
997       else
998         log_verbose ("tunnel_pollin_fd: out_fd = -1; returning server_socket = %d",
999                      tunnel->server_socket);
1000       return tunnel->server_socket;
1001     }
1002   else if (tunnel->in_fd != -1)
1003     return tunnel->in_fd;
1004   else
1005     {
1006       log_error ("tunnel_pollin_fd: returning -1");
1007       return -1;
1008     }
1009 }
1010
1011 /*
1012 If the write connection is up and needs padding to the block length
1013 specified in the second argument, send some padding.
1014 */
1015
1016 int
1017 tunnel_maybe_pad (Tunnel *tunnel, size_t length)
1018 {
1019   size_t padding;
1020
1021   if (tunnel_is_disconnected (tunnel) ||
1022       tunnel->bytes % length == 0 ||
1023       tunnel->padding_only)
1024     return 0;
1025
1026   padding = length - tunnel->bytes % length;
1027   if (padding > tunnel->content_length - tunnel->bytes)
1028     padding = tunnel->content_length - tunnel->bytes;
1029
1030   return tunnel_padding (tunnel, padding);
1031 }
1032
1033 #if 0
1034 ssize_t
1035 old_parse_header (int s, int *type)
1036 {
1037   static const char *end_of_header = "\r\n\r\n";
1038   ssize_t n, len = 0;
1039   char c;
1040   int i;
1041
1042   *type = -1;
1043
1044   n = read_all (s, &c, 1);
1045   if (n != 1)
1046     return -1;
1047   len += n;
1048
1049   if (c == 'P')
1050     *type = TUNNEL_IN;
1051   else if (c == 'G')
1052     *type = TUNNEL_OUT;
1053   else
1054     {
1055       log_error ("parse_header: unknown HTTP request starting with '%c'", c);
1056       errno = EINVAL;
1057       return -1;
1058     }
1059
1060   i = 0;
1061   while (i < 4)
1062     {
1063       n = read_all (s, &c, 1);
1064       if (n != 1 && errno != EAGAIN)
1065         return n;
1066       len += n;
1067
1068       if (c == end_of_header[i])
1069         i++;
1070       else
1071         i = 0;
1072     }
1073
1074   return len;
1075 }
1076 #endif
1077
1078 int
1079 tunnel_accept (Tunnel *tunnel)
1080 {
1081   if (tunnel->in_fd != -1 && tunnel->out_fd != -1)
1082     {
1083       log_debug ("tunnel_accept: tunnel already established");
1084       return 0;
1085     }
1086
1087   while (tunnel->in_fd == -1 || tunnel->out_fd == -1)
1088     {
1089       struct sockaddr_in addr; 
1090       Http_request *request;
1091       struct pollfd p;
1092       ssize_t m;
1093       int len;
1094       int n;
1095       int s;
1096
1097       p.fd = tunnel->server_socket;
1098       p.events = POLLIN;
1099       n = poll (&p, 1, (tunnel->in_fd != -1 || tunnel->out_fd != -1 ?
1100                         ACCEPT_TIMEOUT * 1000 : -1));
1101       if (n == -1)
1102         {
1103           log_error ("tunnel_accept: poll error: %s", strerror (errno));
1104           return -1;
1105         }
1106       else if (n == 0)
1107         {
1108           log_error ("tunnel_accept: poll timed out");
1109           errno = ETIMEDOUT;
1110           break;
1111         }
1112
1113       len = sizeof addr;
1114       s = accept (tunnel->server_socket, (struct sockaddr *)&addr, &len);
1115       if (s == -1)
1116         {
1117           log_error ("tunnel_accept: accept error: %s", strerror (errno));
1118           return -1;
1119         }
1120
1121       m = http_parse_request (s, &request);
1122       if (m <= 0)
1123         return m;
1124
1125       if (request->method == -1)
1126         {
1127           log_error ("tunnel_accept: error parsing header: %s",
1128                      strerror (errno));
1129           close (s);
1130         }
1131       else if (request->method == HTTP_POST ||
1132                request->method == HTTP_PUT)
1133         {
1134           if (tunnel->in_fd == -1)
1135             {
1136               tunnel->in_fd = s;
1137
1138 #ifdef IO_COUNT_HTTP_HEADER
1139               tunnel->in_total_raw += m; /* from parse_header() */
1140               log_annoying ("tunnel_accept: in_total_raw = %u",
1141                             tunnel->in_total_raw);
1142 #endif
1143
1144               fcntl (tunnel->in_fd,
1145                      F_SETFL,
1146                      fcntl (tunnel->in_fd, F_GETFL) | O_NONBLOCK);
1147
1148               tunnel_in_setsockopts (tunnel->in_fd);
1149
1150               log_debug ("tunnel_accept: input connected");
1151             }
1152           else
1153             {
1154               log_error ("rejected tunnel_in: already got a connection");
1155               close (s);
1156             }
1157         }
1158       else if (request->method == HTTP_GET)
1159         {
1160           if (tunnel->out_fd == -1)
1161             {
1162               char str[1024];
1163
1164               tunnel->out_fd = s;
1165
1166               tunnel_out_setsockopts (tunnel->out_fd);
1167
1168               sprintf (str,
1169 "HTTP/1.1 200 OK\r\n"
1170 /* "Date: %s\r\n" */
1171 /* "Server: %s\r\n" */
1172 /* "Last-Modified: %s\r\n" */
1173 /* "ETag: %s\r\n" */
1174 /* "Accept-Ranges: %s\r\n" */
1175 "Content-Length: %d\r\n"
1176 "Connection: close\r\n"
1177 "Pragma: no-cache\r\n"
1178 "Cache-Control: no-cache, no-store, must-revalidate\r\n"
1179 "Expires: 0\r\n" /* FIXME: "0" is not a legitimate HTTP date. */
1180 "Content-Type: text/html\r\n"
1181 "\r\n",
1182                        /* +1 to allow for TUNNEL_DISCONNECT */
1183                        tunnel->content_length + 1);
1184               if (write_all (tunnel->out_fd, str, strlen (str)) <= 0)
1185                 {
1186                   log_error ("tunnel_accept: couldn't write GET header: %s",
1187                              strerror (errno));
1188                   close (tunnel->out_fd);
1189                   tunnel->out_fd = -1;
1190                 }
1191               else
1192                 {
1193                   tunnel->bytes = 0;
1194                   tunnel->buf_len = 0;
1195                   tunnel->buf_ptr = tunnel->buf;
1196 #ifdef IO_COUNT_HTTP_HEADER
1197                   tunnel->out_total_raw += strlen (str);
1198                   log_annoying ("tunnel_accept: out_total_raw = %u",
1199                                 tunnel->out_total_raw);
1200 #endif
1201                   log_debug ("tunnel_accept: output connected");
1202                 }
1203             }
1204           else
1205             {
1206               log_error ("tunnel_accept: rejected tunnel_out: "
1207                          "already got a connection");
1208               close (s);
1209             }
1210         }
1211       else
1212         {
1213           log_error ("tunnel_accept: unknown header type");
1214           log_debug ("tunnel_accept: closing connection");
1215           close (s);
1216         }
1217
1218       http_destroy_request (request);
1219     }
1220
1221   if (tunnel->in_fd == -1 || tunnel->out_fd == -1)
1222     {
1223       log_error ("tunnel_accept: in_fd = %d, out_fd = %d",
1224                  tunnel->in_fd, tunnel->out_fd);
1225
1226       if (tunnel->in_fd != -1)
1227         close (tunnel->in_fd);
1228       tunnel->in_fd = -1;
1229       log_debug ("tunnel_accept: input disconnected");
1230
1231       tunnel_out_disconnect (tunnel);
1232
1233       return -1;
1234     }
1235
1236   return 0;
1237 }
1238
1239 Tunnel *
1240 tunnel_new_server (int port, size_t content_length)
1241 {
1242   Tunnel *tunnel;
1243
1244   tunnel = malloc (sizeof (Tunnel));
1245   if (tunnel == NULL)
1246     return NULL;
1247
1248   /* If content_length is 0, a value must be determined automatically. */
1249   /* For now, a default value will do. */
1250   if (content_length == 0)
1251     content_length = DEFAULT_CONTENT_LENGTH;
1252
1253   tunnel->in_fd = -1;
1254   tunnel->out_fd = -1;
1255   tunnel->server_socket = -1;
1256   tunnel->dest.host_name = NULL;
1257   tunnel->dest.host_port = port;
1258   tunnel->buf_ptr = tunnel->buf;
1259   tunnel->buf_len = 0;
1260   /* -1 to allow for TUNNEL_DISCONNECT */
1261   tunnel->content_length = content_length - 1;
1262   tunnel->in_total_raw = 0;
1263   tunnel->in_total_data = 0;
1264   tunnel->out_total_raw = 0;
1265   tunnel->out_total_data = 0;
1266   tunnel->strict_content_length = FALSE;
1267
1268   tunnel->server_socket = server_socket (tunnel->dest.host_port, 1);
1269   if (tunnel->server_socket == -1)
1270     {
1271       log_error ("tunnel_new_server: server_socket (%d) = -1",
1272                  tunnel->dest.host_port);
1273       tunnel_destroy (tunnel);
1274       return NULL;
1275     }
1276
1277   return tunnel;
1278 }
1279
1280 Tunnel *
1281 tunnel_new_client (const char *host, int host_port,
1282                    const char *proxy, int proxy_port,
1283                    size_t content_length)
1284 {
1285   const char *remote;
1286   int remote_port;
1287   Tunnel *tunnel;
1288
1289   log_verbose ("tunnel_new_client (\"%s\", %d, \"%s\", %d, %d)",
1290                host, host_port, proxy ? proxy : "(null)", proxy_port, 
1291                content_length);
1292
1293   tunnel = malloc (sizeof (Tunnel));
1294   if (tunnel == NULL)
1295     {
1296       log_error ("tunnel_new_client: out of memory");
1297       return NULL;
1298     }
1299
1300   tunnel->in_fd = -1;
1301   tunnel->out_fd = -1;
1302   tunnel->server_socket = -1;
1303   tunnel->dest.host_name = host;
1304   tunnel->dest.host_port = host_port;
1305   tunnel->dest.proxy_name = proxy;
1306   tunnel->dest.proxy_port = proxy_port;
1307   tunnel->dest.proxy_authorization = NULL;
1308   tunnel->dest.user_agent = NULL;
1309   /* -1 to allow for TUNNEL_DISCONNECT */
1310   tunnel->content_length = content_length - 1;
1311   tunnel->buf_ptr = tunnel->buf;
1312   tunnel->buf_len = 0;
1313   tunnel->in_total_raw = 0;
1314   tunnel->in_total_data = 0;
1315   tunnel->out_total_raw = 0;
1316   tunnel->out_total_data = 0;
1317   tunnel->strict_content_length = FALSE;
1318
1319   if (tunnel->dest.proxy_name == NULL)
1320     {
1321       remote = tunnel->dest.host_name;
1322       remote_port = tunnel->dest.host_port;
1323     }
1324   else
1325     {
1326       remote = tunnel->dest.proxy_name;
1327       remote_port = tunnel->dest.proxy_port;
1328     }
1329
1330   if (set_address (&tunnel->address, remote, remote_port) == -1)
1331     {
1332       log_error ("tunnel_new_client: set_address: %s", strerror (errno));
1333       free (tunnel);
1334       return NULL;
1335     }
1336
1337   return tunnel;
1338 }
1339
1340 void
1341 tunnel_destroy (Tunnel *tunnel)
1342 {
1343   if (tunnel_is_connected (tunnel) || tunnel->in_fd != -1)
1344     tunnel_close (tunnel);
1345
1346   if (tunnel->server_socket != -1)
1347     close (tunnel->server_socket);
1348
1349   free (tunnel);
1350 }
1351
1352 static int
1353 tunnel_opt (Tunnel *tunnel, const char *opt, void *data, int get_flag)
1354 {
1355   if (strcmp (opt, "strict_content_length") == 0)
1356     {
1357       if (get_flag)
1358         *(int *)data = tunnel->strict_content_length;
1359       else
1360         tunnel->strict_content_length = *(int *)data;
1361     }
1362   else if (strcmp (opt, "keep_alive") == 0)
1363     {
1364       if (get_flag)
1365         *(int *)data = tunnel->keep_alive;
1366       else
1367         tunnel->keep_alive = *(int *)data;
1368     }
1369   else if (strcmp (opt, "max_connection_age") == 0)
1370     {
1371       if (get_flag)
1372         *(int *)data = tunnel->max_connection_age;
1373       else
1374         tunnel->max_connection_age = *(int *)data;
1375     }
1376   else if (strcmp (opt, "proxy_authorization") == 0)
1377     {
1378       if (get_flag)
1379         {
1380           if (tunnel->dest.proxy_authorization == NULL)
1381             *(char **)data = NULL;
1382           else
1383             *(char **)data = strdup (tunnel->dest.proxy_authorization);
1384         }
1385       else
1386         {
1387           if (tunnel->dest.proxy_authorization != NULL)
1388             free ((char *)tunnel->dest.proxy_authorization);
1389           tunnel->dest.proxy_authorization = strdup ((char *)data);
1390           if (tunnel->dest.proxy_authorization == NULL)
1391             return -1;
1392         }
1393     }
1394   else if (strcmp (opt, "user_agent") == 0)
1395     {
1396       if (get_flag)
1397         {
1398           if (tunnel->dest.user_agent == NULL)
1399             *(char **)data = NULL;
1400           else
1401             *(char **)data = strdup (tunnel->dest.user_agent);
1402         }
1403       else
1404         {
1405           if (tunnel->dest.user_agent != NULL)
1406             free ((char *)tunnel->dest.user_agent);
1407           tunnel->dest.user_agent = strdup ((char *)data);
1408           if (tunnel->dest.user_agent == NULL)
1409             return -1;
1410         }
1411     }
1412   else
1413     {
1414       errno = EINVAL;
1415       return -1;
1416     }
1417
1418   return 0;
1419 }
1420
1421 int
1422 tunnel_setopt (Tunnel *tunnel, const char *opt, void *data)
1423 {
1424   return tunnel_opt (tunnel, opt, data, FALSE);
1425 }
1426
1427 int
1428 tunnel_getopt (Tunnel *tunnel, const char *opt, void *data)
1429 {
1430   return tunnel_opt (tunnel, opt, data, TRUE);
1431 }