4 Copyright (C) 1999, 2000 Lars Brinkhoff. See COPYING for terms and conditions.
6 See tunnel.h for some documentation about the programming interface.
14 #include <sys/poll_.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/tcp.h>
23 /* #define IO_COUNT_HTTP_HEADER */
24 /* #define USE_SHUTDOWN */
26 #define READ_TRAIL_TIMEOUT (1 * 1000) /* milliseconds */
27 #define ACCEPT_TIMEOUT 10 /* seconds */
29 #define min(a, b) ((a) < (b) ? (a) : (b))
34 typedef unsigned char Request;
36 #error "FIXME: Can't handle SIZEOF_CHAR != 1"
40 typedef unsigned short Length;
42 #error "FIXME: Can't handle SIZEOF_SHORT != 2"
50 TUNNEL_PADDING = 0x03,
52 TUNNEL_PAD1 = TUNNEL_SIMPLE | 0x05,
53 TUNNEL_CLOSE = TUNNEL_SIMPLE | 0x06,
54 TUNNEL_DISCONNECT = TUNNEL_SIMPLE | 0x07
57 static inline const char *
58 REQ_TO_STRING (Request request)
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)";
77 Http_destination dest;
78 struct sockaddr_in address;
80 size_t content_length;
88 size_t out_total_data;
89 time_t out_connect_time;
90 int strict_content_length;
92 int max_connection_age;
95 static const size_t sizeof_header = sizeof (Request) + sizeof (Length);
98 tunnel_is_disconnected (Tunnel *tunnel)
100 return tunnel->out_fd == -1;
104 tunnel_is_connected (Tunnel *tunnel)
106 return !tunnel_is_disconnected (tunnel);
110 tunnel_is_server (Tunnel *tunnel)
112 return tunnel->dest.host_name == NULL;
116 tunnel_is_client (Tunnel *tunnel)
118 return !tunnel_is_server (tunnel);
123 get_proto_number (const char *name)
128 p = getprotobyname (name);
140 tunnel_in_setsockopts (int fd)
143 int tcp = get_proto_number ("tcp");
156 log_debug ("tunnel_in_setsockopts: non-fatal SO_RCVLOWAT error: %s",
165 log_debug ("tunnel_out_setsockopts: SO_RCVLOWAT: %d", i);
167 #endif /* SO_RCVLOWAT */
173 tunnel_out_setsockopts (int fd)
177 int tcp = get_proto_number ("tcp");
189 log_debug ("tunnel_out_setsockopts: "
190 "non-fatal SO_SNDLOWAT error: %s",
199 log_debug ("tunnel_out_setsockopts: non-fatal SO_SNDLOWAT: %d", i);
202 #endif /* SO_SNDLOWAT */
210 l.l_linger = 20 * 100; /* linger for 20 seconds */
217 log_debug ("tunnel_out_setsockopts: non-fatal SO_LINGER error: %s",
226 log_debug ("tunnel_out_setsockopts: SO_LINGER: onoff=%d linger=%d",
227 l.l_onoff, l.l_linger);
229 #endif /* SO_LINGER */
233 int tcp = get_proto_number ("tcp");
245 log_debug ("tunnel_out_setsockopts: "
246 "non-fatal TCP_NODELAY error: %s",
255 log_debug ("tunnel_out_setsockopts: non-fatal TCP_NODELAY: %d", i);
270 log_debug ("tunnel_out_setsockopts: non-fatal SO_SNDBUF error: %s",
279 log_debug ("tunnel_out_setsockopts: SO_SNDBUF: %d", i);
281 #endif /* SO_SNDBUF */
282 #endif /* TCP_NODELAY */
295 log_debug ("tunnel_out_setsockopts: non-fatal SO_KEEPALIVE error: %s",
304 log_debug ("tunnel_out_setsockopts: SO_KEEPALIVE: %d", i);
306 #endif /* SO_KEEPALIVE */
312 tunnel_out_disconnect (Tunnel *tunnel)
314 if (tunnel_is_disconnected (tunnel))
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);
325 close (tunnel->out_fd);
328 tunnel->buf_ptr = tunnel->buf;
331 log_debug ("tunnel_out_disconnect: output disconnected");
335 tunnel_in_disconnect (Tunnel *tunnel)
337 if (tunnel->in_fd == -1)
340 close (tunnel->in_fd);
343 log_debug ("tunnel_in_disconnect: input disconnected");
347 tunnel_out_connect (Tunnel *tunnel)
351 if (tunnel_is_connected (tunnel))
353 log_debug ("tunnel_out_connect: already connected");
354 tunnel_out_disconnect (tunnel);
357 tunnel->out_fd = do_connect (&tunnel->address);
358 if (tunnel->out_fd == -1)
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,
369 tunnel_out_setsockopts (tunnel->out_fd);
372 shutdown (tunnel->out_fd, 0);
375 /* + 1 to allow for TUNNEL_DISCONNECT */
376 n = http_post (tunnel->out_fd,
378 tunnel->content_length + 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);
388 tunnel->buf_ptr = tunnel->buf;
390 tunnel->padding_only = TRUE;
391 time (&tunnel->out_connect_time);
393 log_debug ("tunnel_out_connect: output connected");
399 tunnel_in_connect (Tunnel *tunnel)
401 Http_response *response;
404 log_verbose ("tunnel_in_connect()");
406 if (tunnel->in_fd != -1)
408 log_error ("tunnel_in_connect: already connected");
412 tunnel->in_fd = do_connect (&tunnel->address);
413 if (tunnel->in_fd == -1)
415 log_error ("tunnel_in_connect: do_connect() error: %s",
420 tunnel_in_setsockopts (tunnel->in_fd);
422 if (http_get (tunnel->in_fd, &tunnel->dest) == -1)
426 if (shutdown (tunnel->in_fd, 1) == -1)
428 log_error ("tunnel_in_connect: shutdown() error: %s",
434 n = http_parse_response (tunnel->in_fd, &response);
438 log_error ("tunnel_in_connect: no response; peer "
439 "closed connection");
441 log_error ("tunnel_in_connect: no response; error: %s",
444 else if (response->major_version != 1 ||
445 (response->minor_version != 1 &&
446 response->minor_version != 0))
448 log_error ("tunnel_in_connect: unknown HTTP version: %d.%d",
449 response->major_version, response->minor_version);
452 else if (response->status_code != 200)
454 log_error ("tunnel_in_connect: HTTP error %d", response->status_code);
455 errno = http_error_to_errno (-response->status_code);
459 http_destroy_response (response);
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);
474 log_debug ("tunnel_in_connect: input connected");
478 static inline ssize_t
479 tunnel_write_data (Tunnel *tunnel, void *data, size_t length)
481 if (write_all (tunnel->out_fd, data, length) == -1)
483 log_error ("tunnel_write_data: write error: %s", strerror (errno));
486 tunnel->bytes += length;
491 tunnel_write_request (Tunnel *tunnel, Request request,
492 void *data, Length length)
494 if (tunnel->bytes + sizeof request +
495 (data ? sizeof length + length : 0) > tunnel->content_length)
496 tunnel_padding (tunnel, tunnel->content_length - tunnel->bytes);
498 #if 1 /* FIXME: this is a kludge */
503 if (tunnel_is_client (tunnel) &&
504 tunnel_is_connected (tunnel) &&
505 t - tunnel->out_connect_time > tunnel->max_connection_age)
507 char c = TUNNEL_DISCONNECT;
509 log_debug ("tunnel_write_request: connection > %d seconds old",
510 tunnel->max_connection_age);
512 if (tunnel->strict_content_length)
514 int l = tunnel->content_length - tunnel->bytes - 1;
516 log_debug ("tunnel_write_request: write padding (%d bytes)",
517 tunnel->content_length - tunnel->bytes - 1);
525 tunnel_write_data (tunnel, &c, sizeof c);
528 tunnel_write_data (tunnel, &s, sizeof s);
533 tunnel_write_data (tunnel, &c, sizeof c);
537 char c = TUNNEL_PAD1;
541 tunnel_write_data (tunnel, &c, sizeof c);
545 log_debug ("tunnel_write_request: closing old connection");
546 if (tunnel_write_data (tunnel, &c, sizeof c) <= 0)
548 tunnel_out_disconnect (tunnel);
553 if (tunnel_is_disconnected (tunnel))
555 if (tunnel_is_client (tunnel))
557 if (tunnel_out_connect (tunnel) == -1)
563 log_error ("tunnel_write_request: output is disconnected");
567 if (tunnel_accept (tunnel) == -1)
573 if (request != TUNNEL_PADDING && request != TUNNEL_PAD1)
574 tunnel->padding_only = FALSE;
576 if (tunnel_write_data (tunnel, &request, sizeof request) == -1)
581 tunnel_out_disconnect (tunnel);
582 if (tunnel_is_client (tunnel))
583 tunnel_out_connect (tunnel);
586 log_error ("tunnel_write_request: couldn't write request: "
587 "output is disconnected");
591 /* return tunnel_write_request (tunnel, request, data, length); */
592 if (tunnel_write_data (tunnel, &request, sizeof request) == -1)
598 Length network_length = htons ((short)length);
599 if (tunnel_write_data (tunnel,
601 sizeof network_length) == -1)
605 if (request == TUNNEL_DATA && debug_level >= 5)
607 log_annoying ("tunnel_write_request: TUNNEL_DATA:");
608 dump_buf (debug_file, data, (size_t)length);
612 if (tunnel_write_data (tunnel, data, (size_t)length) == -1)
618 tunnel->out_total_raw += 3 + length;
620 if (request == TUNNEL_DATA)
621 log_verbose ("tunnel_write_request: %s (%d)",
622 REQ_TO_STRING (request), length);
624 log_debug ("tunnel_write_request: %s (%d)",
625 REQ_TO_STRING (request), length);
629 tunnel->out_total_raw += 1;
630 log_debug ("tunnel_write_request: %s", REQ_TO_STRING (request));
633 log_annoying ("tunnel_write_data: out_total_raw = %u",
634 tunnel->out_total_raw);
637 if (tunnel->bytes > tunnel->content_length)
638 log_debug ("tunnel_write_request: tunnel->bytes > tunnel->content_length");
641 if (tunnel->bytes >= tunnel->content_length)
643 char c = TUNNEL_DISCONNECT;
644 tunnel_write_data (tunnel, &c, sizeof c);
645 tunnel_out_disconnect (tunnel);
647 if (tunnel_is_server (tunnel))
648 tunnel_accept (tunnel);
656 tunnel_connect (Tunnel *tunnel)
658 char auth_data[1] = { 42 }; /* dummy data, not used by server */
660 log_verbose ("tunnel_connect()");
662 if (tunnel_is_connected (tunnel))
664 log_error ("tunnel_connect: already connected");
669 if (tunnel_write_request (tunnel, TUNNEL_OPEN,
670 auth_data, sizeof auth_data) == -1)
673 if (tunnel_in_connect (tunnel) <= 0)
680 tunnel_write_or_padding (Tunnel *tunnel, Request request, void *data,
683 static char padding[65536];
687 for (remaining = length; remaining > 0; remaining -= n, wdata += n)
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;
700 if (request == TUNNEL_PADDING)
702 if (n + sizeof_header > remaining)
703 n = remaining - sizeof_header;
704 if (tunnel_write_request (tunnel, request, padding, n) == -1)
710 if (tunnel_write_request (tunnel, request, wdata, n) == -1)
715 return length - remaining;
719 tunnel_write (Tunnel *tunnel, void *data, size_t length)
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);
730 tunnel_padding (Tunnel *tunnel, size_t length)
732 if (length < sizeof_header + 1)
736 for (i = 0; i < length; i++)
737 tunnel_write_request (tunnel, TUNNEL_PAD1, NULL, 0);
741 return tunnel_write_or_padding (tunnel, TUNNEL_PADDING, NULL, length);
745 tunnel_close (Tunnel *tunnel)
751 if (tunnel->strict_content_length)
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);
758 log_debug ("tunnel_close: write TUNNEL_CLOSE request");
759 tunnel_write_request (tunnel, TUNNEL_CLOSE, NULL, 0);
761 tunnel_out_disconnect (tunnel);
763 log_debug ("tunnel_close: reading trailing data from input ...");
764 p.fd = tunnel->in_fd;
766 while (poll (&p, 1, READ_TRAIL_TIMEOUT) > 0)
768 if (p.revents & POLLIN)
770 n = read (tunnel->in_fd, buf, sizeof buf);
773 log_annoying ("read (%d, %p, %d) = %d",
774 tunnel->in_fd, buf, sizeof buf, n);
777 else if (n == -1 && errno == EAGAIN)
780 log_debug ("tunnel_close: ... error: %s", strerror (errno));
782 log_debug ("tunnel_close: ... done (tunnel closed)");
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");
793 tunnel_in_disconnect (tunnel);
796 tunnel->in_total_raw = 0;
797 tunnel->in_total_data = 0;
798 tunnel->out_total_raw = 0;
799 tunnel->out_total_data = 0;
805 tunnel_read_request (Tunnel *tunnel, enum tunnel_request *request,
806 unsigned char *buf, size_t *length)
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);
818 log_error ("tunnel_read_request: error reading request: %s",
824 log_debug ("tunnel_read_request: connection closed by peer");
825 tunnel_in_disconnect (tunnel);
827 if (tunnel_is_client (tunnel)
828 && tunnel_in_connect (tunnel) == -1)
835 tunnel->in_total_raw += n;
836 log_annoying ("request = 0x%x (%s)", req, REQ_TO_STRING (req));
838 if (req & TUNNEL_SIMPLE)
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));
847 n = read_all (tunnel->in_fd, &len, 2);
850 log_error ("tunnel_read_request: error reading request length: %s",
858 tunnel->in_total_raw += n;
859 log_annoying ("length = %d", len);
863 n = read_all (tunnel->in_fd, buf, (size_t)len);
866 log_error ("tunnel_read_request: error reading request data: %s",
872 tunnel->in_total_raw += n;
873 log_annoying ("tunnel_read_request: in_total_raw = %u",
874 tunnel->in_total_raw);
877 if (req == TUNNEL_DATA)
878 log_verbose ("tunnel_read_request: %s (%d)",
879 REQ_TO_STRING (req), len);
881 log_debug ("tunnel_read_request: %s (%d)",
882 REQ_TO_STRING (req), len);
888 tunnel_read (Tunnel *tunnel, void *data, size_t length)
890 enum tunnel_request req;
894 if (tunnel->buf_len > 0)
896 n = min (tunnel->buf_len, length);
897 memcpy (data, tunnel->buf_ptr, n);
898 tunnel->buf_ptr += n;
899 tunnel->buf_len -= n;
903 if (tunnel->in_fd == -1)
905 if (tunnel_is_client (tunnel))
907 if (tunnel_in_connect (tunnel) == -1)
913 if (tunnel_accept (tunnel) == -1)
925 if (tunnel->out_fd == -1 && tunnel_is_server (tunnel))
927 tunnel_accept (tunnel);
932 if (tunnel_read_request (tunnel, &req, tunnel->buf, &len) <= 0)
934 log_annoying ("tunnel_read_request returned <= 0, returning -1");
941 /* do something with tunnel->buf */
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);
960 tunnel->buf[len] = 0;
961 log_error ("tunnel_read: received error: %s", tunnel->buf);
968 case TUNNEL_DISCONNECT:
969 tunnel_in_disconnect (tunnel);
971 if (tunnel_is_client (tunnel)
972 && tunnel_in_connect (tunnel) == -1)
979 log_error ("tunnel_read: protocol error: unknown request 0x%02x", req);
989 tunnel_pollin_fd (Tunnel *tunnel)
991 if (tunnel_is_server (tunnel) &&
992 (tunnel->in_fd == -1 || tunnel->out_fd == -1))
994 if (tunnel->in_fd == -1)
995 log_verbose ("tunnel_pollin_fd: in_fd = -1; returning server_socket = %d",
996 tunnel->server_socket);
998 log_verbose ("tunnel_pollin_fd: out_fd = -1; returning server_socket = %d",
999 tunnel->server_socket);
1000 return tunnel->server_socket;
1002 else if (tunnel->in_fd != -1)
1003 return tunnel->in_fd;
1006 log_error ("tunnel_pollin_fd: returning -1");
1012 If the write connection is up and needs padding to the block length
1013 specified in the second argument, send some padding.
1017 tunnel_maybe_pad (Tunnel *tunnel, size_t length)
1021 if (tunnel_is_disconnected (tunnel) ||
1022 tunnel->bytes % length == 0 ||
1023 tunnel->padding_only)
1026 padding = length - tunnel->bytes % length;
1027 if (padding > tunnel->content_length - tunnel->bytes)
1028 padding = tunnel->content_length - tunnel->bytes;
1030 return tunnel_padding (tunnel, padding);
1035 old_parse_header (int s, int *type)
1037 static const char *end_of_header = "\r\n\r\n";
1044 n = read_all (s, &c, 1);
1055 log_error ("parse_header: unknown HTTP request starting with '%c'", c);
1063 n = read_all (s, &c, 1);
1064 if (n != 1 && errno != EAGAIN)
1068 if (c == end_of_header[i])
1079 tunnel_accept (Tunnel *tunnel)
1081 if (tunnel->in_fd != -1 && tunnel->out_fd != -1)
1083 log_debug ("tunnel_accept: tunnel already established");
1087 while (tunnel->in_fd == -1 || tunnel->out_fd == -1)
1089 struct sockaddr_in addr;
1090 Http_request *request;
1097 p.fd = tunnel->server_socket;
1099 n = poll (&p, 1, (tunnel->in_fd != -1 || tunnel->out_fd != -1 ?
1100 ACCEPT_TIMEOUT * 1000 : -1));
1103 log_error ("tunnel_accept: poll error: %s", strerror (errno));
1108 log_error ("tunnel_accept: poll timed out");
1114 s = accept (tunnel->server_socket, (struct sockaddr *)&addr, &len);
1117 log_error ("tunnel_accept: accept error: %s", strerror (errno));
1121 m = http_parse_request (s, &request);
1125 if (request->method == -1)
1127 log_error ("tunnel_accept: error parsing header: %s",
1131 else if (request->method == HTTP_POST ||
1132 request->method == HTTP_PUT)
1134 if (tunnel->in_fd == -1)
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);
1144 fcntl (tunnel->in_fd,
1146 fcntl (tunnel->in_fd, F_GETFL) | O_NONBLOCK);
1148 tunnel_in_setsockopts (tunnel->in_fd);
1150 log_debug ("tunnel_accept: input connected");
1154 log_error ("rejected tunnel_in: already got a connection");
1158 else if (request->method == HTTP_GET)
1160 if (tunnel->out_fd == -1)
1166 tunnel_out_setsockopts (tunnel->out_fd);
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"
1182 /* +1 to allow for TUNNEL_DISCONNECT */
1183 tunnel->content_length + 1);
1184 if (write_all (tunnel->out_fd, str, strlen (str)) <= 0)
1186 log_error ("tunnel_accept: couldn't write GET header: %s",
1188 close (tunnel->out_fd);
1189 tunnel->out_fd = -1;
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);
1201 log_debug ("tunnel_accept: output connected");
1206 log_error ("tunnel_accept: rejected tunnel_out: "
1207 "already got a connection");
1213 log_error ("tunnel_accept: unknown header type");
1214 log_debug ("tunnel_accept: closing connection");
1218 http_destroy_request (request);
1221 if (tunnel->in_fd == -1 || tunnel->out_fd == -1)
1223 log_error ("tunnel_accept: in_fd = %d, out_fd = %d",
1224 tunnel->in_fd, tunnel->out_fd);
1226 if (tunnel->in_fd != -1)
1227 close (tunnel->in_fd);
1229 log_debug ("tunnel_accept: input disconnected");
1231 tunnel_out_disconnect (tunnel);
1240 tunnel_new_server (int port, size_t content_length)
1244 tunnel = malloc (sizeof (Tunnel));
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;
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;
1268 tunnel->server_socket = server_socket (tunnel->dest.host_port, 1);
1269 if (tunnel->server_socket == -1)
1271 log_error ("tunnel_new_server: server_socket (%d) = -1",
1272 tunnel->dest.host_port);
1273 tunnel_destroy (tunnel);
1281 tunnel_new_client (const char *host, int host_port,
1282 const char *proxy, int proxy_port,
1283 size_t content_length)
1289 log_verbose ("tunnel_new_client (\"%s\", %d, \"%s\", %d, %d)",
1290 host, host_port, proxy ? proxy : "(null)", proxy_port,
1293 tunnel = malloc (sizeof (Tunnel));
1296 log_error ("tunnel_new_client: out of memory");
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;
1319 if (tunnel->dest.proxy_name == NULL)
1321 remote = tunnel->dest.host_name;
1322 remote_port = tunnel->dest.host_port;
1326 remote = tunnel->dest.proxy_name;
1327 remote_port = tunnel->dest.proxy_port;
1330 if (set_address (&tunnel->address, remote, remote_port) == -1)
1332 log_error ("tunnel_new_client: set_address: %s", strerror (errno));
1341 tunnel_destroy (Tunnel *tunnel)
1343 if (tunnel_is_connected (tunnel) || tunnel->in_fd != -1)
1344 tunnel_close (tunnel);
1346 if (tunnel->server_socket != -1)
1347 close (tunnel->server_socket);
1353 tunnel_opt (Tunnel *tunnel, const char *opt, void *data, int get_flag)
1355 if (strcmp (opt, "strict_content_length") == 0)
1358 *(int *)data = tunnel->strict_content_length;
1360 tunnel->strict_content_length = *(int *)data;
1362 else if (strcmp (opt, "keep_alive") == 0)
1365 *(int *)data = tunnel->keep_alive;
1367 tunnel->keep_alive = *(int *)data;
1369 else if (strcmp (opt, "max_connection_age") == 0)
1372 *(int *)data = tunnel->max_connection_age;
1374 tunnel->max_connection_age = *(int *)data;
1376 else if (strcmp (opt, "proxy_authorization") == 0)
1380 if (tunnel->dest.proxy_authorization == NULL)
1381 *(char **)data = NULL;
1383 *(char **)data = strdup (tunnel->dest.proxy_authorization);
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)
1394 else if (strcmp (opt, "user_agent") == 0)
1398 if (tunnel->dest.user_agent == NULL)
1399 *(char **)data = NULL;
1401 *(char **)data = strdup (tunnel->dest.user_agent);
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)
1422 tunnel_setopt (Tunnel *tunnel, const char *opt, void *data)
1424 return tunnel_opt (tunnel, opt, data, FALSE);
1428 tunnel_getopt (Tunnel *tunnel, const char *opt, void *data)
1430 return tunnel_opt (tunnel, opt, data, TRUE);