]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tunnel.cc
negotiate_wrapper_auth: fix warnings on MacOSX by simplification
[thirdparty/squid.git] / src / tunnel.cc
1
2 /*
3 * $Id$
4 *
5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see 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 #include "errorpage.h"
38 #include "HttpRequest.h"
39 #include "fde.h"
40 #include "Array.h"
41 #include "comm.h"
42 #include "comm/Connection.h"
43 #include "comm/ConnOpener.h"
44 #include "comm/Write.h"
45 #include "client_side_request.h"
46 #include "acl/FilledChecklist.h"
47 #if USE_DELAY_POOLS
48 #include "DelayId.h"
49 #endif
50 #include "client_side.h"
51 #include "MemBuf.h"
52 #include "http.h"
53 #include "PeerSelectState.h"
54
55 class TunnelStateData
56 {
57
58 public:
59
60 class Connection;
61 void *operator new(size_t);
62 void operator delete (void *);
63 static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
64 static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
65 static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
66 static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
67
68 bool noConnections() const;
69 char *url;
70 HttpRequest *request;
71 Comm::ConnectionList serverDestinations;
72
73 const char * getHost() const {
74 return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->GetHost());
75 };
76
77 class Connection
78 {
79
80 public:
81 Connection() : len (0), buf(), size_ptr(NULL) { buf.init(SQUID_TCP_SO_RCVBUF,SQUID_TCP_SO_RCVBUF); }
82 ~Connection() {};
83
84 int bytesWanted() const;
85 void bytesIn(int const &);
86 #if USE_DELAY_POOLS
87
88 void setDelayId(DelayId const &);
89 #endif
90
91 void error(int const xerrno);
92 int debugLevelForError(int const xerrno) const;
93 void closeIfOpen();
94 void dataSent(size_t amount);
95 int len;
96 MemBuf buf;
97 int64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
98
99 Comm::ConnectionPointer conn; ///< The currently connected connection.
100
101 private:
102 #if USE_DELAY_POOLS
103
104 DelayId delayId;
105 #endif
106
107 };
108
109 Connection client, server;
110 int *status_ptr; /* pointer to status for logging */
111 void copyRead(Connection &from, IOCB *completion);
112
113 private:
114 CBDATA_CLASS(TunnelStateData);
115 void copy(size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, AsyncCall::Pointer &);
116 void readServer(char *buf, size_t len, comm_err_t errcode, int xerrno);
117 void readClient(char *buf, size_t len, comm_err_t errcode, int xerrno);
118 void writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno);
119 void writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno);
120 };
121
122 static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
123
124 static CNCB tunnelConnectDone;
125 static ERCB tunnelErrorComplete;
126 static PF tunnelServerClosed;
127 static PF tunnelClientClosed;
128 static CTCB tunnelTimeout;
129 static PSC tunnelPeerSelectComplete;
130 static void tunnelStateFree(TunnelStateData * tunnelState);
131 static void tunnelConnected(const Comm::ConnectionPointer &server, void *);
132 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *);
133
134 static void
135 tunnelServerClosed(int fd, void *data)
136 {
137 TunnelStateData *tunnelState = (TunnelStateData *)data;
138 debugs(26, 3, HERE << "FD " << fd);
139 tunnelState->server.conn = NULL;
140
141 if (tunnelState->noConnections()) {
142 tunnelStateFree(tunnelState);
143 return;
144 }
145
146 if (!tunnelState->server.len) {
147 tunnelState->client.conn->close();
148 return;
149 }
150 }
151
152 static void
153 tunnelClientClosed(int fd, void *data)
154 {
155 TunnelStateData *tunnelState = (TunnelStateData *)data;
156 debugs(26, 3, HERE << "FD " << fd);
157 tunnelState->client.conn = NULL;
158
159 if (tunnelState->noConnections()) {
160 tunnelStateFree(tunnelState);
161 return;
162 }
163
164 if (!tunnelState->client.len) {
165 tunnelState->server.conn->close();
166 return;
167 }
168 }
169
170 static void
171 tunnelStateFree(TunnelStateData * tunnelState)
172 {
173 debugs(26, 3, HERE << "tunnelState=" << tunnelState);
174 assert(tunnelState != NULL);
175 assert(tunnelState->noConnections());
176 safe_free(tunnelState->url);
177 tunnelState->serverDestinations.clean();
178 HTTPMSGUNLOCK(tunnelState->request);
179 delete tunnelState;
180 }
181
182 int
183 TunnelStateData::Connection::bytesWanted() const
184 {
185 #if USE_DELAY_POOLS
186 return delayId.bytesWanted(1, buf.spaceSize());
187 #else
188 return buf.spaceSize();
189 #endif
190 }
191
192 void
193 TunnelStateData::Connection::bytesIn(int const &count)
194 {
195 debugs(26, 3, HERE << "len=" << len << " + count=" << count);
196 #if USE_DELAY_POOLS
197 delayId.bytesIn(count);
198 #endif
199
200 len += count;
201 }
202
203 int
204 TunnelStateData::Connection::debugLevelForError(int const xerrno) const
205 {
206 #ifdef ECONNRESET
207
208 if (xerrno == ECONNRESET)
209 return 2;
210
211 #endif
212
213 if (ignoreErrno(xerrno))
214 return 3;
215
216 return 1;
217 }
218
219 /* Read from server side and queue it for writing to the client */
220 void
221 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
222 {
223 TunnelStateData *tunnelState = (TunnelStateData *)data;
224 assert(cbdataReferenceValid(tunnelState));
225 debugs(26, 3, HERE << c);
226
227 tunnelState->readServer(buf, len, errcode, xerrno);
228 }
229
230 void
231 TunnelStateData::readServer(char *buf, size_t len, comm_err_t errcode, int xerrno)
232 {
233 debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
234
235 /*
236 * Bail out early on COMM_ERR_CLOSING
237 * - close handlers will tidy up for us
238 */
239
240 if (errcode == COMM_ERR_CLOSING)
241 return;
242
243 if (len > 0) {
244 server.bytesIn(len);
245 kb_incr(&statCounter.server.all.kbytes_in, len);
246 kb_incr(&statCounter.server.other.kbytes_in, len);
247 }
248
249 AsyncCall::Pointer call = commCbCall(5,5, "TunnelStateData::WriteClientDone",
250 CommIoCbPtrFun(WriteClientDone, this));
251
252 copy (len, errcode, xerrno, server, client, call);
253 }
254
255 void
256 TunnelStateData::Connection::error(int const xerrno)
257 {
258 /* XXX fixme xstrerror and xerrno... */
259 errno = xerrno;
260
261 debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerror());
262
263 if (!ignoreErrno(xerrno))
264 conn->close();
265 }
266
267 /* Read from client side and queue it for writing to the server */
268 void
269 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
270 {
271 TunnelStateData *tunnelState = (TunnelStateData *)data;
272 assert (cbdataReferenceValid (tunnelState));
273
274 tunnelState->readClient(buf, len, errcode, xerrno);
275 }
276
277 void
278 TunnelStateData::readClient(char *buf, size_t len, comm_err_t errcode, int xerrno)
279 {
280 debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
281
282 /*
283 * Bail out early on COMM_ERR_CLOSING
284 * - close handlers will tidy up for us
285 */
286
287 if (errcode == COMM_ERR_CLOSING)
288 return;
289
290 if (len > 0) {
291 client.bytesIn(len);
292 kb_incr(&statCounter.client_http.kbytes_in, len);
293 }
294
295 AsyncCall::Pointer call = commCbCall(5,5, "TunnelStateData::WriteServerDone",
296 CommIoCbPtrFun(WriteServerDone, this));
297
298 copy (len, errcode, xerrno, client, server, call);
299 }
300
301 void
302 TunnelStateData::copy(size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, AsyncCall::Pointer &call)
303 {
304 debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
305
306 /* I think this is to prevent free-while-in-a-callback behaviour
307 * - RBC 20030229
308 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
309 */
310 cbdataInternalLock(this); /* ??? should be locked by the caller... */
311
312 /* Bump the source connection read timeout on any activity */
313 if (Comm::IsConnOpen(from.conn)) {
314 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
315 CommTimeoutCbPtrFun(tunnelTimeout, this));
316 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
317 }
318
319 if (errcode)
320 from.error (xerrno);
321 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
322 debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
323 from.conn->close();
324
325 /* Only close the remote end if we've finished queueing data to it */
326 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
327 to.conn->close();
328 }
329 } else if (cbdataReferenceValid(this)) {
330 debugs(26, 3, HERE << "Schedule Write");
331 Comm::Write(to.conn, &from.buf, call);
332 }
333
334 cbdataInternalUnlock(this); /* ??? */
335 }
336
337 /* Writes data from the client buffer to the server side */
338 void
339 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
340 {
341 TunnelStateData *tunnelState = (TunnelStateData *)data;
342 assert (cbdataReferenceValid (tunnelState));
343
344 tunnelState->writeServerDone(buf, len, flag, xerrno);
345 }
346
347 void
348 TunnelStateData::writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno)
349 {
350 debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
351
352 /* Error? */
353 if (flag != COMM_OK) {
354 if (flag != COMM_ERR_CLOSING) {
355 debugs(26, 4, HERE << "calling TunnelStateData::server.error(" << xerrno <<")");
356 server.error(xerrno); // may call comm_close
357 }
358 return;
359 }
360
361 /* EOF? */
362 if (len == 0) {
363 debugs(26, 4, HERE << "No read input. Closing server connection.");
364 server.conn->close();
365 return;
366 }
367
368 /* Valid data */
369 kb_incr(&statCounter.server.all.kbytes_out, len);
370 kb_incr(&statCounter.server.other.kbytes_out, len);
371 client.dataSent(len);
372
373 /* If the other end has closed, so should we */
374 if (!Comm::IsConnOpen(client.conn)) {
375 debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
376 server.conn->close();
377 return;
378 }
379
380 cbdataInternalLock(this); /* ??? should be locked by the caller... */
381
382 if (cbdataReferenceValid(this))
383 copyRead(client, ReadClient);
384
385 cbdataInternalUnlock(this); /* ??? */
386 }
387
388 /* Writes data from the server buffer to the client side */
389 void
390 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
391 {
392 TunnelStateData *tunnelState = (TunnelStateData *)data;
393 assert (cbdataReferenceValid (tunnelState));
394
395 tunnelState->writeClientDone(buf, len, flag, xerrno);
396 }
397
398 void
399 TunnelStateData::Connection::dataSent(size_t amount)
400 {
401 debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
402 assert(amount == (size_t)len);
403 len =0;
404 /* increment total object size */
405
406 if (size_ptr)
407 *size_ptr += amount;
408 }
409
410 void
411 TunnelStateData::writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno)
412 {
413 debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
414
415 /* Error? */
416 if (flag != COMM_OK) {
417 if (flag != COMM_ERR_CLOSING) {
418 debugs(26, 4, HERE << "Closing client connection due to comm flags.");
419 client.error(xerrno); // may call comm_close
420 }
421 return;
422 }
423
424 /* EOF? */
425 if (len == 0) {
426 debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
427 client.conn->close();
428 return;
429 }
430
431 /* Valid data */
432 kb_incr(&statCounter.client_http.kbytes_out, len);
433 server.dataSent(len);
434
435 /* If the other end has closed, so should we */
436 if (!Comm::IsConnOpen(server.conn)) {
437 debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
438 client.conn->close();
439 return;
440 }
441
442 cbdataInternalLock(this); /* ??? should be locked by the caller... */
443
444 if (cbdataReferenceValid(this))
445 copyRead(server, ReadServer);
446
447 cbdataInternalUnlock(this); /* ??? */
448 }
449
450 static void
451 tunnelTimeout(const CommTimeoutCbParams &io)
452 {
453 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
454 debugs(26, 3, HERE << io.conn);
455 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
456 cbdataInternalLock(tunnelState);
457
458 tunnelState->client.closeIfOpen();
459 tunnelState->server.closeIfOpen();
460 cbdataInternalUnlock(tunnelState);
461 }
462
463 void
464 TunnelStateData::Connection::closeIfOpen()
465 {
466 if (Comm::IsConnOpen(conn))
467 conn->close();
468 }
469
470 void
471 TunnelStateData::copyRead(Connection &from, IOCB *completion)
472 {
473 assert(from.len == 0);
474 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
475 CommIoCbPtrFun(completion, this));
476 comm_read(from.conn, from.buf.space(), from.bytesWanted(), call);
477 }
478
479 /**
480 * All the pieces we need to write to client and/or server connection
481 * have been written.
482 * - Set the HTTP status for this request.
483 * - Start the blind pump.
484 */
485 static void
486 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
487 {
488 TunnelStateData *tunnelState = (TunnelStateData *)data;
489 debugs(26, 3, HERE << conn << ", flag=" << flag);
490
491 if (flag != COMM_OK) {
492 *tunnelState->status_ptr = HTTP_INTERNAL_SERVER_ERROR;
493 tunnelErrorComplete(conn->fd, data, 0);
494 return;
495 }
496
497 *tunnelState->status_ptr = HTTP_OK;
498 if (cbdataReferenceValid(tunnelState)) {
499 tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
500 tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
501 }
502 }
503
504 /*
505 * handle the write completion from a proxy request to an upstream origin
506 */
507 static void
508 tunnelConnected(const Comm::ConnectionPointer &server, void *data)
509 {
510 TunnelStateData *tunnelState = (TunnelStateData *)data;
511 debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
512 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
513 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
514 Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL);
515 }
516
517 static void
518 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
519 {
520 TunnelStateData *tunnelState = (TunnelStateData *)data;
521 debugs(26, 3, HERE << "FD " << fd);
522 assert(tunnelState != NULL);
523 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
524 cbdataInternalLock(tunnelState);
525
526 if (Comm::IsConnOpen(tunnelState->client.conn))
527 tunnelState->client.conn->close();
528
529 if (Comm::IsConnOpen(tunnelState->server.conn))
530 tunnelState->server.conn->close();
531
532 cbdataInternalUnlock(tunnelState);
533 }
534
535
536 static void
537 tunnelConnectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
538 {
539 TunnelStateData *tunnelState = (TunnelStateData *)data;
540
541 if (status != COMM_OK) {
542 debugs(26, 4, HERE << conn << ", comm failure recovery.");
543 /* At this point only the TCP handshake has failed. no data has been passed.
544 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
545 */
546 tunnelState->serverDestinations.shift();
547 if (status != COMM_TIMEOUT && tunnelState->serverDestinations.size() > 0) {
548 /* Try another IP of this destination host */
549 debugs(26, 4, HERE << "retry with : " << tunnelState->serverDestinations[0]);
550 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
551 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
552 cs->setHost(tunnelState->url);
553 AsyncJob::Start(cs);
554 } else {
555 debugs(26, 4, HERE << "terminate with error.");
556 ErrorState *err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, tunnelState->request);
557 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
558 err->xerrno = xerrno;
559 // on timeout is this still: err->xerrno = ETIMEDOUT;
560 err->port = conn->remote.GetPort();
561 err->callback = tunnelErrorComplete;
562 err->callback_data = tunnelState;
563 errorSend(tunnelState->client.conn, err);
564 }
565 return;
566 }
567
568 #if USE_DELAY_POOLS
569 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
570 if (conn->getPeer() && conn->getPeer()->options.no_delay)
571 tunnelState->server.setDelayId(DelayId());
572 #endif
573
574 tunnelState->request->hier.note(conn, tunnelState->getHost());
575
576 tunnelState->server.conn = conn;
577 tunnelState->request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
578 comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
579
580 debugs(26, 4, HERE << "determine post-connect handling pathway.");
581 if (conn->getPeer()) {
582 tunnelState->request->peer_login = conn->getPeer()->login;
583 tunnelState->request->flags.proxying = (conn->getPeer()->options.originserver?0:1);
584 } else {
585 tunnelState->request->peer_login = NULL;
586 tunnelState->request->flags.proxying = 0;
587 }
588
589 if (tunnelState->request->flags.proxying)
590 tunnelRelayConnectRequest(conn, tunnelState);
591 else {
592 tunnelConnected(conn, tunnelState);
593 }
594
595 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
596 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
597 commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
598 }
599
600 extern tos_t GetTosToServer(HttpRequest * request);
601 extern nfmark_t GetNfmarkToServer(HttpRequest * request);
602
603 void
604 tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
605 {
606 debugs(26, 3, HERE);
607 /* Create state structure. */
608 TunnelStateData *tunnelState = NULL;
609 ErrorState *err = NULL;
610 HttpRequest *request = http->request;
611 char *url = http->uri;
612
613 /*
614 * client_addr.IsNoAddr() indicates this is an "internal" request
615 * from peer_digest.c, asn.c, netdb.c, etc and should always
616 * be allowed. yuck, I know.
617 */
618
619 if (!request->client_addr.IsNoAddr() && Config.accessList.miss) {
620 /*
621 * Check if this host is allowed to fetch MISSES from us (miss_access)
622 * default is to allow.
623 */
624 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
625 ch.src_addr = request->client_addr;
626 ch.my_addr = request->my_addr;
627 if (ch.fastCheck() == ACCESS_DENIED) {
628 debugs(26, 4, HERE << "MISS access forbidden.");
629 err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN, request);
630 *status_ptr = HTTP_FORBIDDEN;
631 errorSend(http->getConn()->clientConnection, err);
632 return;
633 }
634 }
635
636 debugs(26, 3, HERE << "'" << RequestMethodStr(request->method) << " " << url << " " << request->http_ver << "'");
637 statCounter.server.all.requests++;
638 statCounter.server.other.requests++;
639
640 tunnelState = new TunnelStateData;
641 #if USE_DELAY_POOLS
642 tunnelState->server.setDelayId(DelayId::DelayClient(http));
643 #endif
644 tunnelState->url = xstrdup(url);
645 tunnelState->request = HTTPMSGLOCK(request);
646 tunnelState->server.size_ptr = size_ptr;
647 tunnelState->status_ptr = status_ptr;
648 tunnelState->client.conn = http->getConn()->clientConnection;
649
650 comm_add_close_handler(tunnelState->client.conn->fd,
651 tunnelClientClosed,
652 tunnelState);
653
654 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
655 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
656 commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
657
658 peerSelect(&(tunnelState->serverDestinations), request,
659 NULL,
660 tunnelPeerSelectComplete,
661 tunnelState);
662 }
663
664 static void
665 tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
666 {
667 TunnelStateData *tunnelState = (TunnelStateData *)data;
668 HttpHeader hdr_out(hoRequest);
669 Packer p;
670 http_state_flags flags;
671 debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
672 memset(&flags, '\0', sizeof(flags));
673 flags.proxying = tunnelState->request->flags.proxying;
674 MemBuf mb;
675 mb.init();
676 mb.Printf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
677 HttpStateData::httpBuildRequestHeader(tunnelState->request,
678 NULL, /* StoreEntry */
679 &hdr_out,
680 flags); /* flags */
681 packerToMemInit(&p, &mb);
682 hdr_out.packInto(&p);
683 hdr_out.clean();
684 packerClean(&p);
685 mb.append("\r\n", 2);
686
687 AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone",
688 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
689 Comm::Write(srv, &mb, writeCall);
690
691 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
692 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
693 commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
694 }
695
696 static void
697 tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, void *data)
698 {
699 TunnelStateData *tunnelState = (TunnelStateData *)data;
700
701 if (peer_paths == NULL || peer_paths->size() < 1) {
702 debugs(26, 3, HERE << "No paths found. Aborting CONNECT");
703 ErrorState *err;
704 err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, tunnelState->request);
705 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
706 err->callback = tunnelErrorComplete;
707 err->callback_data = tunnelState;
708 errorSend(tunnelState->client.conn, err);
709 return;
710 }
711 debugs(26, 3, HERE << "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
712 tunnelState->serverDestinations[0] << "}");
713
714 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
715 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
716 cs->setHost(tunnelState->url);
717 AsyncJob::Start(cs);
718 }
719
720 CBDATA_CLASS_INIT(TunnelStateData);
721
722 void *
723 TunnelStateData::operator new (size_t)
724 {
725 CBDATA_INIT_TYPE(TunnelStateData);
726 TunnelStateData *result = cbdataAlloc(TunnelStateData);
727 return result;
728 }
729
730 void
731 TunnelStateData::operator delete (void *address)
732 {
733 TunnelStateData *t = static_cast<TunnelStateData *>(address);
734 cbdataFree(t);
735 }
736
737 bool
738 TunnelStateData::noConnections() const
739 {
740 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
741 }
742
743 #if USE_DELAY_POOLS
744 void
745 TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
746 {
747 delayId = newDelay;
748 }
749
750 #endif