5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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.
37 #include "errorpage.h"
38 #include "HttpRequest.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"
50 #include "client_side.h"
53 #include "PeerSelectState.h"
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
);
68 bool noConnections() const;
71 Comm::ConnectionList serverDestinations
;
73 const char * getHost() const {
74 return (server
.conn
!= NULL
&& server
.conn
->getPeer() ? server
.conn
->getPeer()->host
: request
->GetHost());
81 Connection() : len (0), buf(), size_ptr(NULL
) { buf
.init(SQUID_TCP_SO_RCVBUF
,SQUID_TCP_SO_RCVBUF
); }
84 int bytesWanted() const;
85 void bytesIn(int const &);
88 void setDelayId(DelayId
const &);
91 void error(int const xerrno
);
92 int debugLevelForError(int const xerrno
) const;
94 void dataSent(size_t amount
);
97 int64_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
99 Comm::ConnectionPointer conn
; ///< The currently connected connection.
109 Connection client
, server
;
110 int *status_ptr
; /* pointer to status for logging */
111 void copyRead(Connection
&from
, IOCB
*completion
);
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
);
122 static const char *const conn_established
= "HTTP/1.1 200 Connection established\r\n\r\n";
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 *);
135 tunnelServerClosed(int fd
, void *data
)
137 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
138 debugs(26, 3, HERE
<< "FD " << fd
);
139 tunnelState
->server
.conn
= NULL
;
141 if (tunnelState
->noConnections()) {
142 tunnelStateFree(tunnelState
);
146 if (!tunnelState
->server
.len
) {
147 tunnelState
->client
.conn
->close();
153 tunnelClientClosed(int fd
, void *data
)
155 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
156 debugs(26, 3, HERE
<< "FD " << fd
);
157 tunnelState
->client
.conn
= NULL
;
159 if (tunnelState
->noConnections()) {
160 tunnelStateFree(tunnelState
);
164 if (!tunnelState
->client
.len
) {
165 tunnelState
->server
.conn
->close();
171 tunnelStateFree(TunnelStateData
* tunnelState
)
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
);
183 TunnelStateData::Connection::bytesWanted() const
186 return delayId
.bytesWanted(1, buf
.spaceSize());
188 return buf
.spaceSize();
193 TunnelStateData::Connection::bytesIn(int const &count
)
195 debugs(26, 3, HERE
<< "len=" << len
<< " + count=" << count
);
197 delayId
.bytesIn(count
);
204 TunnelStateData::Connection::debugLevelForError(int const xerrno
) const
208 if (xerrno
== ECONNRESET
)
213 if (ignoreErrno(xerrno
))
219 /* Read from server side and queue it for writing to the client */
221 TunnelStateData::ReadServer(const Comm::ConnectionPointer
&c
, char *buf
, size_t len
, comm_err_t errcode
, int xerrno
, void *data
)
223 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
224 assert(cbdataReferenceValid(tunnelState
));
225 debugs(26, 3, HERE
<< c
);
227 tunnelState
->readServer(buf
, len
, errcode
, xerrno
);
231 TunnelStateData::readServer(char *buf
, size_t len
, comm_err_t errcode
, int xerrno
)
233 debugs(26, 3, HERE
<< server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
236 * Bail out early on COMM_ERR_CLOSING
237 * - close handlers will tidy up for us
240 if (errcode
== COMM_ERR_CLOSING
)
245 kb_incr(&statCounter
.server
.all
.kbytes_in
, len
);
246 kb_incr(&statCounter
.server
.other
.kbytes_in
, len
);
249 AsyncCall::Pointer call
= commCbCall(5,5, "TunnelStateData::WriteClientDone",
250 CommIoCbPtrFun(WriteClientDone
, this));
252 copy (len
, errcode
, xerrno
, server
, client
, call
);
256 TunnelStateData::Connection::error(int const xerrno
)
258 /* XXX fixme xstrerror and xerrno... */
261 debugs(50, debugLevelForError(xerrno
), HERE
<< conn
<< ": read/write failure: " << xstrerror());
263 if (!ignoreErrno(xerrno
))
267 /* Read from client side and queue it for writing to the server */
269 TunnelStateData::ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, comm_err_t errcode
, int xerrno
, void *data
)
271 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
272 assert (cbdataReferenceValid (tunnelState
));
274 tunnelState
->readClient(buf
, len
, errcode
, xerrno
);
278 TunnelStateData::readClient(char *buf
, size_t len
, comm_err_t errcode
, int xerrno
)
280 debugs(26, 3, HERE
<< client
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
283 * Bail out early on COMM_ERR_CLOSING
284 * - close handlers will tidy up for us
287 if (errcode
== COMM_ERR_CLOSING
)
292 kb_incr(&statCounter
.client_http
.kbytes_in
, len
);
295 AsyncCall::Pointer call
= commCbCall(5,5, "TunnelStateData::WriteServerDone",
296 CommIoCbPtrFun(WriteServerDone
, this));
298 copy (len
, errcode
, xerrno
, client
, server
, call
);
302 TunnelStateData::copy(size_t len
, comm_err_t errcode
, int xerrno
, Connection
&from
, Connection
&to
, AsyncCall::Pointer
&call
)
304 debugs(26, 3, HERE
<< "from={" << from
.conn
<< "}, to={" << to
.conn
<< "}");
306 /* I think this is to prevent free-while-in-a-callback behaviour
308 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
310 cbdataInternalLock(this); /* ??? should be locked by the caller... */
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
);
321 else if (len
== 0 || !Comm::IsConnOpen(to
.conn
)) {
322 debugs(26, 3, HERE
<< "Nothing to write or client gone. Terminate the tunnel.");
325 /* Only close the remote end if we've finished queueing data to it */
326 if (from
.len
== 0 && Comm::IsConnOpen(to
.conn
) ) {
329 } else if (cbdataReferenceValid(this)) {
330 debugs(26, 3, HERE
<< "Schedule Write");
331 Comm::Write(to
.conn
, &from
.buf
, call
);
334 cbdataInternalUnlock(this); /* ??? */
337 /* Writes data from the client buffer to the server side */
339 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
341 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
342 assert (cbdataReferenceValid (tunnelState
));
344 tunnelState
->writeServerDone(buf
, len
, flag
, xerrno
);
348 TunnelStateData::writeServerDone(char *buf
, size_t len
, comm_err_t flag
, int xerrno
)
350 debugs(26, 3, HERE
<< server
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
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
363 debugs(26, 4, HERE
<< "No read input. Closing server connection.");
364 server
.conn
->close();
369 kb_incr(&statCounter
.server
.all
.kbytes_out
, len
);
370 kb_incr(&statCounter
.server
.other
.kbytes_out
, len
);
371 client
.dataSent(len
);
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();
380 cbdataInternalLock(this); /* ??? should be locked by the caller... */
382 if (cbdataReferenceValid(this))
383 copyRead(client
, ReadClient
);
385 cbdataInternalUnlock(this); /* ??? */
388 /* Writes data from the server buffer to the client side */
390 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
392 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
393 assert (cbdataReferenceValid (tunnelState
));
395 tunnelState
->writeClientDone(buf
, len
, flag
, xerrno
);
399 TunnelStateData::Connection::dataSent(size_t amount
)
401 debugs(26, 3, HERE
<< "len=" << len
<< " - amount=" << amount
);
402 assert(amount
== (size_t)len
);
404 /* increment total object size */
411 TunnelStateData::writeClientDone(char *buf
, size_t len
, comm_err_t flag
, int xerrno
)
413 debugs(26, 3, HERE
<< client
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
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
426 debugs(26, 4, HERE
<< "Closing client connection due to 0 byte read.");
427 client
.conn
->close();
432 kb_incr(&statCounter
.client_http
.kbytes_out
, len
);
433 server
.dataSent(len
);
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();
442 cbdataInternalLock(this); /* ??? should be locked by the caller... */
444 if (cbdataReferenceValid(this))
445 copyRead(server
, ReadServer
);
447 cbdataInternalUnlock(this); /* ??? */
451 tunnelTimeout(const CommTimeoutCbParams
&io
)
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
);
458 tunnelState
->client
.closeIfOpen();
459 tunnelState
->server
.closeIfOpen();
460 cbdataInternalUnlock(tunnelState
);
464 TunnelStateData::Connection::closeIfOpen()
466 if (Comm::IsConnOpen(conn
))
471 TunnelStateData::copyRead(Connection
&from
, IOCB
*completion
)
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
);
480 * All the pieces we need to write to client and/or server connection
482 * - Set the HTTP status for this request.
483 * - Start the blind pump.
486 tunnelConnectedWriteDone(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
488 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
489 debugs(26, 3, HERE
<< conn
<< ", flag=" << flag
);
491 if (flag
!= COMM_OK
) {
492 *tunnelState
->status_ptr
= HTTP_INTERNAL_SERVER_ERROR
;
493 tunnelErrorComplete(conn
->fd
, data
, 0);
497 *tunnelState
->status_ptr
= HTTP_OK
;
498 if (cbdataReferenceValid(tunnelState
)) {
499 tunnelState
->copyRead(tunnelState
->server
, TunnelStateData::ReadServer
);
500 tunnelState
->copyRead(tunnelState
->client
, TunnelStateData::ReadClient
);
505 * handle the write completion from a proxy request to an upstream origin
508 tunnelConnected(const Comm::ConnectionPointer
&server
, void *data
)
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
);
518 tunnelErrorComplete(int fd
/*const Comm::ConnectionPointer &*/, void *data
, size_t)
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
);
526 if (Comm::IsConnOpen(tunnelState
->client
.conn
))
527 tunnelState
->client
.conn
->close();
529 if (Comm::IsConnOpen(tunnelState
->server
.conn
))
530 tunnelState
->server
.conn
->close();
532 cbdataInternalUnlock(tunnelState
);
537 tunnelConnectDone(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
539 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
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.
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
);
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
);
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());
574 tunnelState
->request
->hier
.note(conn
, tunnelState
->getHost());
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
);
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);
585 tunnelState
->request
->peer_login
= NULL
;
586 tunnelState
->request
->flags
.proxying
= 0;
589 if (tunnelState
->request
->flags
.proxying
)
590 tunnelRelayConnectRequest(conn
, tunnelState
);
592 tunnelConnected(conn
, tunnelState
);
595 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
596 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
597 commSetConnTimeout(conn
, Config
.Timeout
.read
, timeoutCall
);
600 extern tos_t
GetTosToServer(HttpRequest
* request
);
601 extern nfmark_t
GetNfmarkToServer(HttpRequest
* request
);
604 tunnelStart(ClientHttpRequest
* http
, int64_t * size_ptr
, int *status_ptr
)
607 /* Create state structure. */
608 TunnelStateData
*tunnelState
= NULL
;
609 ErrorState
*err
= NULL
;
610 HttpRequest
*request
= http
->request
;
611 char *url
= http
->uri
;
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.
619 if (!request
->client_addr
.IsNoAddr() && Config
.accessList
.miss
) {
621 * Check if this host is allowed to fetch MISSES from us (miss_access)
622 * default is to allow.
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
);
636 debugs(26, 3, HERE
<< "'" << RequestMethodStr(request
->method
) << " " << url
<< " " << request
->http_ver
<< "'");
637 statCounter
.server
.all
.requests
++;
638 statCounter
.server
.other
.requests
++;
640 tunnelState
= new TunnelStateData
;
642 tunnelState
->server
.setDelayId(DelayId::DelayClient(http
));
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
;
650 comm_add_close_handler(tunnelState
->client
.conn
->fd
,
654 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
655 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
656 commSetConnTimeout(tunnelState
->client
.conn
, Config
.Timeout
.lifetime
, timeoutCall
);
658 peerSelect(&(tunnelState
->serverDestinations
), request
,
660 tunnelPeerSelectComplete
,
665 tunnelRelayConnectRequest(const Comm::ConnectionPointer
&srv
, void *data
)
667 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
668 HttpHeader
hdr_out(hoRequest
);
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
;
676 mb
.Printf("CONNECT %s HTTP/1.1\r\n", tunnelState
->url
);
677 HttpStateData::httpBuildRequestHeader(tunnelState
->request
,
678 NULL
, /* StoreEntry */
681 packerToMemInit(&p
, &mb
);
682 hdr_out
.packInto(&p
);
685 mb
.append("\r\n", 2);
687 AsyncCall::Pointer writeCall
= commCbCall(5,5, "tunnelConnectedWriteDone",
688 CommIoCbPtrFun(tunnelConnectedWriteDone
, tunnelState
));
689 Comm::Write(srv
, &mb
, writeCall
);
691 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
692 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
693 commSetConnTimeout(srv
, Config
.Timeout
.read
, timeoutCall
);
697 tunnelPeerSelectComplete(Comm::ConnectionList
*peer_paths
, void *data
)
699 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
701 if (peer_paths
== NULL
|| peer_paths
->size() < 1) {
702 debugs(26, 3, HERE
<< "No paths found. Aborting CONNECT");
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
);
711 debugs(26, 3, HERE
<< "paths=" << peer_paths
->size() << ", p[0]={" << (*peer_paths
)[0] << "}, serverDest[0]={" <<
712 tunnelState
->serverDestinations
[0] << "}");
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
);
720 CBDATA_CLASS_INIT(TunnelStateData
);
723 TunnelStateData::operator new (size_t)
725 CBDATA_INIT_TYPE(TunnelStateData
);
726 TunnelStateData
*result
= cbdataAlloc(TunnelStateData
);
731 TunnelStateData::operator delete (void *address
)
733 TunnelStateData
*t
= static_cast<TunnelStateData
*>(address
);
738 TunnelStateData::noConnections() const
740 return !Comm::IsConnOpen(server
.conn
) && !Comm::IsConnOpen(client
.conn
);
745 TunnelStateData::Connection::setDelayId(DelayId
const &newDelay
)