]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tunnel.cc
Luyers finished delay pools patch
[thirdparty/squid.git] / src / tunnel.cc
1
2 /*
3 * $Id: tunnel.cc,v 1.86 1998/08/14 09:22:40 wessels Exp $
4 *
5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37
38 typedef struct {
39 char *url;
40 char *host; /* either request->host or proxy host */
41 u_short port;
42 request_t *request;
43 struct {
44 int fd;
45 int len;
46 char *buf;
47 } client, server;
48 size_t *size_ptr; /* pointer to size in an ConnStateData for logging */
49 int proxying;
50 } SslStateData;
51
52 static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
53
54 static CNCB sslConnectDone;
55 static ERCB sslErrorComplete;
56 static PF sslServerClosed;
57 static PF sslClientClosed;
58 static PF sslReadClient;
59 static PF sslReadServer;
60 static PF sslTimeout;
61 static PF sslWriteClient;
62 static PF sslWriteServer;
63 static PSC sslPeerSelectComplete;
64 static PSC sslPeerSelectFail;
65 static void sslStateFree(SslStateData * sslState);
66 static void sslConnected(int fd, void *);
67 static void sslProxyConnected(int fd, void *);
68 static void sslSetSelect(SslStateData * sslState);
69 #if DELAY_POOLS
70 static DEFER sslDeferServerRead;
71 #endif
72
73 static void
74 sslServerClosed(int fd, void *data)
75 {
76 SslStateData *sslState = data;
77 debug(26, 3) ("sslServerClosed: FD %d\n", fd);
78 assert(fd == sslState->server.fd);
79 sslState->server.fd = -1;
80 if (sslState->client.fd == -1)
81 sslStateFree(sslState);
82 }
83
84 static void
85 sslClientClosed(int fd, void *data)
86 {
87 SslStateData *sslState = data;
88 debug(26, 3) ("sslClientClosed: FD %d\n", fd);
89 assert(fd == sslState->client.fd);
90 sslState->client.fd = -1;
91 if (sslState->server.fd == -1)
92 sslStateFree(sslState);
93 }
94
95 static void
96 sslStateFree(SslStateData * sslState)
97 {
98 debug(26, 3) ("sslStateFree: sslState=%p\n", sslState);
99 assert(sslState != NULL);
100 assert(sslState->client.fd == -1);
101 assert(sslState->server.fd == -1);
102 safe_free(sslState->server.buf);
103 safe_free(sslState->client.buf);
104 safe_free(sslState->url);
105 sslState->host = NULL;
106 requestUnlink(sslState->request);
107 sslState->request = NULL;
108 cbdataFree(sslState);
109 }
110
111 #if DELAY_POOLS
112 static int
113 sslDeferServerRead(int fdnotused, void *data)
114 {
115 request_t *r = data;
116 return delayBytesWanted(r->delay_id, 1) == 0;
117 }
118 #endif
119
120 static void
121 sslSetSelect(SslStateData * sslState)
122 {
123 size_t read_sz = SQUID_TCP_SO_RCVBUF;
124 assert(sslState->server.fd > -1 || sslState->client.fd > -1);
125 if (sslState->client.fd > -1) {
126 if (sslState->server.len > 0) {
127 commSetSelect(sslState->client.fd,
128 COMM_SELECT_WRITE,
129 sslWriteClient,
130 sslState,
131 0);
132 }
133 if (sslState->client.len < read_sz) {
134 commSetSelect(sslState->client.fd,
135 COMM_SELECT_READ,
136 sslReadClient,
137 sslState,
138 Config.Timeout.read);
139 }
140 } else if (sslState->client.len == 0) {
141 comm_close(sslState->server.fd);
142 }
143 if (sslState->server.fd > -1) {
144 if (sslState->client.len > 0) {
145 commSetSelect(sslState->server.fd,
146 COMM_SELECT_WRITE,
147 sslWriteServer,
148 sslState,
149 0);
150 }
151 #if DELAY_POOLS
152 read_sz = delayBytesWanted(sslState->request->delay_id, read_sz);
153 assert(read_sz > 0);
154 #endif
155 if (sslState->server.len < read_sz) {
156 /* Have room to read more */
157 commSetSelect(sslState->server.fd,
158 COMM_SELECT_READ,
159 sslReadServer,
160 sslState,
161 Config.Timeout.read);
162 }
163 } else if (sslState->client.fd == -1) {
164 /* client already closed, nothing more to do */
165 } else if (sslState->server.len == 0) {
166 comm_close(sslState->client.fd);
167 }
168 }
169
170 /* Read from server side and queue it for writing to the client */
171 static void
172 sslReadServer(int fd, void *data)
173 {
174 SslStateData *sslState = data;
175 int len;
176 size_t read_sz = SQUID_TCP_SO_RCVBUF - sslState->server.len;
177 assert(fd == sslState->server.fd);
178 debug(26, 3) ("sslReadServer: FD %d, reading %d bytes at offset %d\n",
179 fd, read_sz, sslState->server.len);
180 errno = 0;
181 #if DELAY_POOLS
182 read_sz = delayBytesWanted(sslState->request->delay_id, read_sz);
183 assert(read_sz > 0);
184 #endif
185 len = read(fd, sslState->server.buf + sslState->server.len, read_sz);
186 debug(26, 3) ("sslReadServer: FD %d, read %d bytes\n", fd, len);
187 if (len > 0) {
188 fd_bytes(fd, len, FD_READ);
189 #if DELAY_POOLS
190 delayBytesIn(sslState->request->delay_id, len);
191 #endif
192 kb_incr(&Counter.server.all.kbytes_in, len);
193 kb_incr(&Counter.server.other.kbytes_in, len);
194 sslState->server.len += len;
195 }
196 cbdataLock(sslState);
197 if (len < 0) {
198 debug(50, 1) ("sslReadServer: FD %d: read failure: %s\n",
199 fd, xstrerror());
200 if (!ignoreErrno(errno))
201 comm_close(fd);
202 } else if (len == 0) {
203 comm_close(sslState->server.fd);
204 }
205 if (cbdataValid(sslState))
206 sslSetSelect(sslState);
207 cbdataUnlock(sslState);
208 }
209
210 /* Read from client side and queue it for writing to the server */
211 static void
212 sslReadClient(int fd, void *data)
213 {
214 SslStateData *sslState = data;
215 int len;
216 assert(fd == sslState->client.fd);
217 debug(26, 3) ("sslReadClient: FD %d, reading %d bytes at offset %d\n",
218 fd, SQUID_TCP_SO_RCVBUF - sslState->client.len,
219 sslState->client.len);
220 len = read(fd,
221 sslState->client.buf + sslState->client.len,
222 SQUID_TCP_SO_RCVBUF - sslState->client.len);
223 debug(26, 3) ("sslReadClient: FD %d, read %d bytes\n", fd, len);
224 if (len > 0) {
225 fd_bytes(fd, len, FD_READ);
226 kb_incr(&Counter.client_http.kbytes_in, len);
227 sslState->client.len += len;
228 }
229 cbdataLock(sslState);
230 if (len < 0) {
231 debug(50, 1) ("sslReadClient: FD %d: read failure: %s\n",
232 fd, xstrerror());
233 if (!ignoreErrno(errno))
234 comm_close(fd);
235 } else if (len == 0) {
236 comm_close(fd);
237 }
238 if (cbdataValid(sslState))
239 sslSetSelect(sslState);
240 cbdataUnlock(sslState);
241 }
242
243 /* Writes data from the client buffer to the server side */
244 static void
245 sslWriteServer(int fd, void *data)
246 {
247 SslStateData *sslState = data;
248 int len;
249 assert(fd == sslState->server.fd);
250 debug(26, 3) ("sslWriteServer: FD %d, %d bytes to write\n",
251 fd, sslState->client.len);
252 len = write(fd,
253 sslState->client.buf,
254 sslState->client.len);
255 debug(26, 3) ("sslWriteServer: FD %d, %d bytes written\n", fd, len);
256 if (len > 0) {
257 fd_bytes(fd, len, FD_WRITE);
258 kb_incr(&Counter.server.all.kbytes_out, len);
259 kb_incr(&Counter.server.other.kbytes_out, len);
260 assert(len <= sslState->client.len);
261 sslState->client.len -= len;
262 if (sslState->client.len > 0) {
263 /* we didn't write the whole thing */
264 xmemmove(sslState->client.buf,
265 sslState->client.buf + len,
266 sslState->client.len);
267 }
268 }
269 cbdataLock(sslState);
270 if (len < 0) {
271 debug(50, 1) ("sslWriteServer: FD %d: write failure: %s.\n",
272 fd, xstrerror());
273 if (!ignoreErrno(errno))
274 comm_close(fd);
275 }
276 if (cbdataValid(sslState))
277 sslSetSelect(sslState);
278 cbdataUnlock(sslState);
279 }
280
281 /* Writes data from the server buffer to the client side */
282 static void
283 sslWriteClient(int fd, void *data)
284 {
285 SslStateData *sslState = data;
286 int len;
287 assert(fd == sslState->client.fd);
288 debug(26, 3) ("sslWriteClient: FD %d, %d bytes to write\n",
289 fd, sslState->server.len);
290 len = write(fd,
291 sslState->server.buf,
292 sslState->server.len);
293 debug(26, 3) ("sslWriteClient: FD %d, %d bytes written\n", fd, len);
294 if (len > 0) {
295 fd_bytes(fd, len, FD_WRITE);
296 kb_incr(&Counter.client_http.kbytes_out, len);
297 assert(len <= sslState->server.len);
298 sslState->server.len -= len;
299 /* increment total object size */
300 if (sslState->size_ptr)
301 *sslState->size_ptr += len;
302 if (sslState->server.len > 0) {
303 /* we didn't write the whole thing */
304 xmemmove(sslState->server.buf,
305 sslState->server.buf + len,
306 sslState->server.len);
307 }
308 }
309 cbdataLock(sslState);
310 if (len < 0) {
311 debug(50, 1) ("sslWriteClient: FD %d: write failure: %s.\n",
312 fd, xstrerror());
313 if (!ignoreErrno(errno))
314 comm_close(fd);
315 }
316 if (cbdataValid(sslState))
317 sslSetSelect(sslState);
318 cbdataUnlock(sslState);
319 }
320
321 static void
322 sslTimeout(int fd, void *data)
323 {
324 SslStateData *sslState = data;
325 debug(26, 3) ("sslTimeout: FD %d\n", fd);
326 if (sslState->client.fd > -1)
327 comm_close(sslState->client.fd);
328 if (sslState->server.fd > -1)
329 comm_close(sslState->server.fd);
330 }
331
332 static void
333 sslConnected(int fd, void *data)
334 {
335 SslStateData *sslState = data;
336 debug(26, 3) ("sslConnected: FD %d sslState=%p\n", fd, sslState);
337 xstrncpy(sslState->server.buf, conn_established, SQUID_TCP_SO_RCVBUF);
338 sslState->server.len = strlen(conn_established);
339 sslSetSelect(sslState);
340 }
341
342 static void
343 sslErrorComplete(int fdnotused, void *data, size_t sizenotused)
344 {
345 SslStateData *sslState = data;
346 assert(sslState != NULL);
347 if (sslState->client.fd > -1)
348 comm_close(sslState->client.fd);
349 if (sslState->server.fd > -1)
350 comm_close(sslState->server.fd);
351 }
352
353
354 static void
355 sslConnectDone(int fdnotused, int status, void *data)
356 {
357 SslStateData *sslState = data;
358 request_t *request = sslState->request;
359 ErrorState *err = NULL;
360 if (status == COMM_ERR_DNS) {
361 debug(26, 4) ("sslConnect: Unknown host: %s\n", sslState->host);
362 err = errorCon(ERR_DNS_FAIL, HTTP_NOT_FOUND);
363 err->request = requestLink(request);
364 err->dnsserver_msg = xstrdup(dns_error_message);
365 err->callback = sslErrorComplete;
366 err->callback_data = sslState;
367 errorSend(sslState->client.fd, err);
368 } else if (status != COMM_OK) {
369 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE);
370 err->xerrno = errno;
371 err->host = xstrdup(sslState->host);
372 err->port = sslState->port;
373 err->request = requestLink(request);
374 err->callback = sslErrorComplete;
375 err->callback_data = sslState;
376 errorSend(sslState->client.fd, err);
377 } else {
378 if (sslState->proxying)
379 sslProxyConnected(sslState->server.fd, sslState);
380 else
381 sslConnected(sslState->server.fd, sslState);
382 commSetTimeout(sslState->server.fd,
383 Config.Timeout.read,
384 sslTimeout,
385 sslState);
386 #if DELAY_POOLS
387 commSetDefer(sslState->server.fd, sslDeferServerRead, sslState->request);
388 #endif
389 }
390 }
391
392 void
393 sslStart(int fd, const char *url, request_t * request, size_t * size_ptr)
394 {
395 /* Create state structure. */
396 SslStateData *sslState = NULL;
397 int sock;
398 ErrorState *err = NULL;
399 debug(26, 3) ("sslStart: '%s %s'\n",
400 RequestMethodStr[request->method], url);
401 Counter.server.all.requests++;
402 Counter.server.other.requests++;
403 /* Create socket. */
404 sock = comm_open(SOCK_STREAM,
405 0,
406 Config.Addrs.tcp_outgoing,
407 0,
408 COMM_NONBLOCKING,
409 url);
410 if (sock == COMM_ERROR) {
411 debug(26, 4) ("sslStart: Failed because we're out of sockets.\n");
412 err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
413 err->xerrno = errno;
414 err->request = requestLink(request);
415 errorSend(fd, err);
416 return;
417 }
418 sslState = xcalloc(1, sizeof(SslStateData));
419 cbdataAdd(sslState, MEM_NONE);
420 sslState->url = xstrdup(url);
421 sslState->request = requestLink(request);
422 sslState->size_ptr = size_ptr;
423 sslState->client.fd = fd;
424 sslState->server.fd = sock;
425 sslState->server.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
426 sslState->client.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
427 comm_add_close_handler(sslState->server.fd,
428 sslServerClosed,
429 sslState);
430 comm_add_close_handler(sslState->client.fd,
431 sslClientClosed,
432 sslState);
433 commSetTimeout(sslState->client.fd,
434 Config.Timeout.lifetime,
435 sslTimeout,
436 sslState);
437 commSetTimeout(sslState->server.fd,
438 Config.Timeout.connect,
439 sslTimeout,
440 sslState);
441 peerSelect(request,
442 NULL,
443 sslPeerSelectComplete,
444 sslPeerSelectFail,
445 sslState);
446 /*
447 * Disable the client read handler until peer selection is complete
448 * Take control away from client_side.c.
449 */
450 commSetSelect(sslState->client.fd, COMM_SELECT_READ, NULL, NULL, 0);
451 }
452
453 static void
454 sslProxyConnected(int fd, void *data)
455 {
456 SslStateData *sslState = data;
457 MemBuf mb;
458 HttpHeader hdr_out;
459 Packer p;
460 debug(26, 3) ("sslProxyConnected: FD %d sslState=%p\n", fd, sslState);
461 memBufDefInit(&mb);
462 memBufPrintf(&mb, "CONNECT %s HTTP/1.0\r\n", sslState->url);
463 httpBuildRequestHeader(sslState->request,
464 sslState->request,
465 NULL, /* StoreEntry */
466 &hdr_out,
467 sslState->client.fd,
468 0); /* flags */
469 packerToMemInit(&p, &mb);
470 httpHeaderPackInto(&hdr_out, &p);
471 httpHeaderClean(&hdr_out);
472 packerClean(&p);
473 memBufAppend(&mb, "\r\n", 2);
474 xstrncpy(sslState->client.buf, mb.buf, SQUID_TCP_SO_RCVBUF);
475 debug(26, 3) ("sslProxyConnected: Sending {%s}\n", sslState->client.buf);
476 sslState->client.len = mb.size;
477 memBufClean(&mb);
478 commSetTimeout(sslState->server.fd,
479 Config.Timeout.read,
480 sslTimeout,
481 sslState);
482 sslSetSelect(sslState);
483 }
484
485 static void
486 sslPeerSelectComplete(peer * p, void *data)
487 {
488 SslStateData *sslState = data;
489 request_t *request = sslState->request;
490 peer *g = NULL;
491 sslState->proxying = p ? 1 : 0;
492 sslState->host = p ? p->host : request->host;
493 if (p == NULL) {
494 sslState->port = request->port;
495 } else if (p->http_port != 0) {
496 sslState->port = p->http_port;
497 } else if ((g = peerFindByName(p->host))) {
498 sslState->port = g->http_port;
499 } else {
500 sslState->port = CACHE_HTTP_PORT;
501 }
502 commConnectStart(sslState->server.fd,
503 sslState->host,
504 sslState->port,
505 sslConnectDone,
506 sslState);
507 }
508
509 static void
510 sslPeerSelectFail(peer * peernotused, void *data)
511 {
512 SslStateData *sslState = data;
513 ErrorState *err;
514 err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE);
515 err->request = requestLink(sslState->request);
516 err->callback = sslErrorComplete;
517 err->callback_data = sslState;
518 errorSend(sslState->client.fd, err);
519
520 }