2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 26 Secure Sockets Layer Proxy */
12 #include "acl/FilledChecklist.h"
13 #include "base/CbcPointer.h"
14 #include "CachePeer.h"
16 #include "client_side.h"
17 #include "client_side_request.h"
19 #include "comm/Connection.h"
20 #include "comm/ConnOpener.h"
21 #include "comm/Read.h"
22 #include "comm/Write.h"
23 #include "errorpage.h"
29 #include "http/Stream.h"
30 #include "HttpRequest.h"
31 #include "ip/QosConfig.h"
34 #include "neighbors.h"
35 #include "PeerSelectState.h"
36 #include "sbuf/SBuf.h"
37 #include "security/BlindPeerConnector.h"
38 #include "SquidConfig.h"
39 #include "SquidTime.h"
40 #include "StatCounters.h"
43 #include "ssl/ServerBump.h"
54 * TunnelStateData is the state engine performing the tasks for
55 * setup of a TCP tunnel from an existing open client FD to a server
56 * then shuffling binary data between the resulting FD pair.
59 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
60 * of pre-formatted data. Then we can use that as the client side of the tunnel
61 * instead of re-implementing it here and occasionally getting the ConnStateData
62 * read/write state wrong.
64 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
66 class TunnelStateData
: public PeerSelectionInitiator
68 CBDATA_CHILD(TunnelStateData
);
71 TunnelStateData(ClientHttpRequest
*);
72 virtual ~TunnelStateData();
73 TunnelStateData(const TunnelStateData
&); // do not implement
74 TunnelStateData
&operator =(const TunnelStateData
&); // do not implement
77 static void ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
78 static void ReadServer(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
79 static void WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
80 static void WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
82 /// Starts reading peer response to our CONNECT request.
83 void readConnectResponse();
85 /// Called when we may be done handling a CONNECT exchange with the peer.
86 void connectExchangeCheckpoint();
88 bool noConnections() const;
90 CbcPointer
<ClientHttpRequest
> http
;
91 HttpRequest::Pointer request
;
92 AccessLogEntryPointer al
;
93 Comm::ConnectionList serverDestinations
;
95 const char * getHost() const {
96 return (server
.conn
!= NULL
&& server
.conn
->getPeer() ? server
.conn
->getPeer()->host
: request
->url
.host());
99 /// Whether we are writing a CONNECT request to a peer.
100 bool waitingForConnectRequest() const { return connectReqWriting
; }
101 /// Whether we are reading a CONNECT response from a peer.
102 bool waitingForConnectResponse() const { return connectRespBuf
; }
103 /// Whether we are waiting for the CONNECT request/response exchange with the peer.
104 bool waitingForConnectExchange() const { return waitingForConnectRequest() || waitingForConnectResponse(); }
106 /// Whether the client sent a CONNECT request to us.
107 bool clientExpectsConnectResponse() const {
108 // If we are forcing a tunnel after receiving a client CONNECT, then we
109 // have already responded to that CONNECT before tunnel.cc started.
110 if (request
&& request
->flags
.forceTunnel
)
113 // We are bumping and we had already send "OK CONNECTED"
114 if (http
.valid() && http
->getConn() && http
->getConn()->serverBump() && http
->getConn()->serverBump()->step
> Ssl::bumpStep1
)
117 return !(request
!= NULL
&&
118 (request
->flags
.interceptTproxy
|| request
->flags
.intercepted
));
121 /// Sends "502 Bad Gateway" error response to the client,
122 /// if it is waiting for Squid CONNECT response, closing connections.
123 void informUserOfPeerError(const char *errMsg
, size_t);
125 /// starts connecting to the next hop, either for the first time or while
126 /// recovering from the previous connect failure
127 void startConnecting();
129 void noteConnectFailure(const Comm::ConnectionPointer
&conn
);
135 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF
)), size_ptr(NULL
), delayedLoops(0),
136 readPending(NULL
), readPendingFunc(NULL
) {}
140 int bytesWanted(int lower
=0, int upper
= INT_MAX
) const;
141 void bytesIn(int const &);
144 void setDelayId(DelayId
const &);
147 void error(int const xerrno
);
148 int debugLevelForError(int const xerrno
) const;
150 void dataSent (size_t amount
);
151 /// writes 'b' buffer, setting the 'writer' member to 'callback'.
152 void write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
);
155 AsyncCall::Pointer writer
; ///< pending Comm::Write callback
156 uint64_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
158 Comm::ConnectionPointer conn
; ///< The currently connected connection.
159 uint8_t delayedLoops
; ///< how many times a read on this connection has been postponed.
161 // XXX: make these an AsyncCall when event API can handle them
162 TunnelStateData
*readPending
;
163 EVH
*readPendingFunc
;
172 Connection client
, server
;
173 int *status_ptr
; ///< pointer for logging HTTP status
174 LogTags
*logTag_ptr
; ///< pointer for logging Squid processing code
175 MemBuf
*connectRespBuf
; ///< accumulates peer CONNECT response when we need it
176 bool connectReqWriting
; ///< whether we are writing a CONNECT request to a peer
177 SBuf preReadClientData
;
178 SBuf preReadServerData
;
179 time_t startTime
; ///< object creation time, before any peer selection/connection attempts
181 void copyRead(Connection
&from
, IOCB
*completion
);
183 /// continue to set up connection to a peer, going async for SSL peers
184 void connectToPeer();
186 /* PeerSelectionInitiator API */
187 virtual void noteDestination(Comm::ConnectionPointer conn
) override
;
188 virtual void noteDestinationsEnd(ErrorState
*selectionError
) override
;
190 void saveError(ErrorState
*finalError
);
191 void sendError(ErrorState
*finalError
, const char *reason
);
194 /// Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
195 class MyAnswerDialer
: public CallDialer
, public Security::PeerConnector::CbDialer
198 typedef void (TunnelStateData::*Method
)(Security::EncryptorAnswer
&);
200 MyAnswerDialer(Method method
, TunnelStateData
*tunnel
):
201 method_(method
), tunnel_(tunnel
), answer_() {}
204 virtual bool canDial(AsyncCall
&call
) { return tunnel_
.valid(); }
205 void dial(AsyncCall
&call
) { ((&(*tunnel_
))->*method_
)(answer_
); }
206 virtual void print(std::ostream
&os
) const {
207 os
<< '(' << tunnel_
.get() << ", " << answer_
<< ')';
210 /* Security::PeerConnector::CbDialer API */
211 virtual Security::EncryptorAnswer
&answer() { return answer_
; }
215 CbcPointer
<TunnelStateData
> tunnel_
;
216 Security::EncryptorAnswer answer_
;
219 /// callback handler after connection setup (including any encryption)
220 void connectedToPeer(Security::EncryptorAnswer
&answer
);
222 /// details of the "last tunneling attempt" failure (if it failed)
223 ErrorState
*savedError
= nullptr;
226 bool keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
);
227 void copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*);
228 void handleConnectResponse(const size_t chunkSize
);
229 void readServer(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
230 void readClient(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
231 void writeClientDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
232 void writeServerDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
234 static void ReadConnectResponseDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
235 void readConnectResponseDone(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
236 void copyClientBytes();
237 void copyServerBytes();
240 static const char *const conn_established
= "HTTP/1.1 200 Connection established\r\n\r\n";
242 static CNCB tunnelConnectDone
;
243 static ERCB tunnelErrorComplete
;
244 static CLCB tunnelServerClosed
;
245 static CLCB tunnelClientClosed
;
246 static CTCB tunnelTimeout
;
247 static EVH tunnelDelayedClientRead
;
248 static EVH tunnelDelayedServerRead
;
249 static void tunnelConnected(const Comm::ConnectionPointer
&server
, void *);
250 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer
&server
, void *);
253 tunnelServerClosed(const CommCloseCbParams
¶ms
)
255 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
256 debugs(26, 3, HERE
<< tunnelState
->server
.conn
);
257 tunnelState
->server
.conn
= NULL
;
258 tunnelState
->server
.writer
= NULL
;
260 if (tunnelState
->request
!= NULL
)
261 tunnelState
->request
->hier
.stopPeerClock(false);
263 if (tunnelState
->noConnections()) {
264 // ConnStateData pipeline should contain the CONNECT we are performing
265 // but it may be invalid already (bug 4392)
266 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn()) {
267 auto ctx
= tunnelState
->http
->getConn()->pipeline
.front();
275 if (!tunnelState
->client
.writer
) {
276 tunnelState
->client
.conn
->close();
282 tunnelClientClosed(const CommCloseCbParams
¶ms
)
284 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
285 debugs(26, 3, HERE
<< tunnelState
->client
.conn
);
286 tunnelState
->client
.conn
= NULL
;
287 tunnelState
->client
.writer
= NULL
;
289 if (tunnelState
->noConnections()) {
290 // ConnStateData pipeline should contain the CONNECT we are performing
291 // but it may be invalid already (bug 4392)
292 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn()) {
293 auto ctx
= tunnelState
->http
->getConn()->pipeline
.front();
301 if (!tunnelState
->server
.writer
) {
302 tunnelState
->server
.conn
->close();
307 TunnelStateData::TunnelStateData(ClientHttpRequest
*clientRequest
) :
308 connectRespBuf(NULL
),
309 connectReqWriting(false),
310 startTime(squid_curtime
)
312 debugs(26, 3, "TunnelStateData constructed this=" << this);
313 client
.readPendingFunc
= &tunnelDelayedClientRead
;
314 server
.readPendingFunc
= &tunnelDelayedServerRead
;
316 assert(clientRequest
);
317 url
= xstrdup(clientRequest
->uri
);
318 request
= clientRequest
->request
;
319 server
.size_ptr
= &clientRequest
->out
.size
;
320 client
.size_ptr
= &clientRequest
->al
->http
.clientRequestSz
.payloadData
;
321 status_ptr
= &clientRequest
->al
->http
.code
;
322 logTag_ptr
= &clientRequest
->logType
;
323 al
= clientRequest
->al
;
324 http
= clientRequest
;
326 client
.conn
= clientRequest
->getConn()->clientConnection
;
327 comm_add_close_handler(client
.conn
->fd
, tunnelClientClosed
, this);
329 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
330 CommTimeoutCbPtrFun(tunnelTimeout
, this));
331 commSetConnTimeout(client
.conn
, Config
.Timeout
.lifetime
, timeoutCall
);
334 TunnelStateData::~TunnelStateData()
336 debugs(26, 3, "TunnelStateData destructed this=" << this);
337 assert(noConnections());
339 serverDestinations
.clear();
340 delete connectRespBuf
;
344 TunnelStateData::Connection::~Connection()
347 eventDelete(readPendingFunc
, readPending
);
353 TunnelStateData::Connection::bytesWanted(int lowerbound
, int upperbound
) const
356 return delayId
.bytesWanted(lowerbound
, upperbound
);
364 TunnelStateData::Connection::bytesIn(int const &count
)
366 debugs(26, 3, HERE
<< "len=" << len
<< " + count=" << count
);
368 delayId
.bytesIn(count
);
375 TunnelStateData::Connection::debugLevelForError(int const xerrno
) const
379 if (xerrno
== ECONNRESET
)
384 if (ignoreErrno(xerrno
))
390 /* Read from server side and queue it for writing to the client */
392 TunnelStateData::ReadServer(const Comm::ConnectionPointer
&c
, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
394 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
395 assert(cbdataReferenceValid(tunnelState
));
396 debugs(26, 3, HERE
<< c
);
398 tunnelState
->readServer(buf
, len
, errcode
, xerrno
);
402 TunnelStateData::readServer(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
404 debugs(26, 3, HERE
<< server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
405 server
.delayedLoops
=0;
408 * Bail out early on Comm::ERR_CLOSING
409 * - close handlers will tidy up for us
412 if (errcode
== Comm::ERR_CLOSING
)
417 statCounter
.server
.all
.kbytes_in
+= len
;
418 statCounter
.server
.other
.kbytes_in
+= len
;
419 request
->hier
.notePeerRead();
422 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
423 copy(len
, server
, client
, WriteClientDone
);
426 /// Called when we read [a part of] CONNECT response from the peer
428 TunnelStateData::readConnectResponseDone(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
430 debugs(26, 3, server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
431 assert(waitingForConnectResponse());
433 if (errcode
== Comm::ERR_CLOSING
)
437 connectRespBuf
->appended(len
);
439 statCounter
.server
.all
.kbytes_in
+= len
;
440 statCounter
.server
.other
.kbytes_in
+= len
;
441 request
->hier
.notePeerRead();
444 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
445 handleConnectResponse(len
);
449 TunnelStateData::informUserOfPeerError(const char *errMsg
, const size_t sz
)
454 *logTag_ptr
= LOG_TCP_TUNNEL
;
456 if (!clientExpectsConnectResponse()) {
457 // closing the connection is the best we can do here
458 debugs(50, 3, server
.conn
<< " closing on error: " << errMsg
);
459 server
.conn
->close();
463 // if we have no reply suitable to relay, use 502 Bad Gateway
464 if (!sz
|| sz
> static_cast<size_t>(connectRespBuf
->contentSize()))
465 return sendError(new ErrorState(ERR_CONNECT_FAIL
, Http::scBadGateway
, request
.getRaw()),
466 "peer error without reply");
468 // if we need to send back the server response. write its headers to the client
470 memcpy(server
.buf
, connectRespBuf
->content(), server
.len
);
471 copy(server
.len
, server
, client
, TunnelStateData::WriteClientDone
);
472 // then close the server FD to prevent any relayed keep-alive causing CVE-2015-5400
473 server
.closeIfOpen();
476 /* Read from client side and queue it for writing to the server */
478 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
480 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
481 assert (cbdataReferenceValid (tunnelState
));
483 tunnelState
->readConnectResponseDone(buf
, len
, errcode
, xerrno
);
486 /// Parses [possibly incomplete] CONNECT response and reacts to it.
487 /// If the tunnel is being closed or more response data is needed, returns false.
488 /// Otherwise, the caller should handle the remaining read data, if any.
490 TunnelStateData::handleConnectResponse(const size_t chunkSize
)
492 assert(waitingForConnectResponse());
494 // Ideally, client and server should use MemBuf or better, but current code
495 // never accumulates more than one read when shoveling data (XXX) so it does
496 // not need to deal with MemBuf complexity. To keep it simple, we use a
497 // dedicated MemBuf for accumulating CONNECT responses. TODO: When shoveling
498 // is optimized, reuse server.buf for CONNEC response accumulation instead.
500 /* mimic the basic parts of HttpStateData::processReplyHeader() */
502 Http::StatusCode parseErr
= Http::scNone
;
503 const bool eof
= !chunkSize
;
504 connectRespBuf
->terminate(); // Http::Message::parse requires terminated string
505 const bool parsed
= rep
.parse(connectRespBuf
->content(), connectRespBuf
->contentSize(), eof
, &parseErr
);
507 if (parseErr
> 0) { // unrecoverable parsing error
508 informUserOfPeerError("malformed CONNECT response from peer", 0);
516 if (!connectRespBuf
->hasSpace()) {
517 informUserOfPeerError("huge CONNECT response from peer", 0);
522 readConnectResponse();
526 // CONNECT response was successfully parsed
527 request
->hier
.peer_reply_status
= rep
.sline
.status();
529 // bail if we did not get an HTTP 200 (Connection Established) response
530 if (rep
.sline
.status() != Http::scOkay
) {
531 // if we ever decide to reuse the peer connection, we must extract the error response first
532 *status_ptr
= rep
.sline
.status(); // we are relaying peer response
533 informUserOfPeerError("unsupported CONNECT response status code", rep
.hdr_sz
);
537 if (rep
.hdr_sz
< connectRespBuf
->contentSize()) {
538 // preserve bytes that the server already sent after the CONNECT response
539 server
.len
= connectRespBuf
->contentSize() - rep
.hdr_sz
;
540 memcpy(server
.buf
, connectRespBuf
->content()+rep
.hdr_sz
, server
.len
);
542 // reset; delay pools were using this field to throttle CONNECT response
546 delete connectRespBuf
;
547 connectRespBuf
= NULL
;
548 connectExchangeCheckpoint();
552 TunnelStateData::Connection::error(int const xerrno
)
554 debugs(50, debugLevelForError(xerrno
), HERE
<< conn
<< ": read/write failure: " << xstrerr(xerrno
));
556 if (!ignoreErrno(xerrno
))
560 /* Read from client side and queue it for writing to the server */
562 TunnelStateData::ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
564 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
565 assert (cbdataReferenceValid (tunnelState
));
567 tunnelState
->readClient(buf
, len
, errcode
, xerrno
);
571 TunnelStateData::readClient(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
573 debugs(26, 3, HERE
<< client
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
574 client
.delayedLoops
=0;
577 * Bail out early on Comm::ERR_CLOSING
578 * - close handlers will tidy up for us
581 if (errcode
== Comm::ERR_CLOSING
)
586 statCounter
.client_http
.kbytes_in
+= len
;
589 if (keepGoingAfterRead(len
, errcode
, xerrno
, client
, server
))
590 copy(len
, client
, server
, WriteServerDone
);
593 /// Updates state after reading from client or server.
594 /// Returns whether the caller should use the data just read.
596 TunnelStateData::keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
)
598 debugs(26, 3, HERE
<< "from={" << from
.conn
<< "}, to={" << to
.conn
<< "}");
600 /* I think this is to prevent free-while-in-a-callback behaviour
602 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
604 const CbcPointer
<TunnelStateData
> safetyLock(this);
606 /* Bump the source connection read timeout on any activity */
607 if (Comm::IsConnOpen(from
.conn
)) {
608 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
609 CommTimeoutCbPtrFun(tunnelTimeout
, this));
610 commSetConnTimeout(from
.conn
, Config
.Timeout
.read
, timeoutCall
);
613 /* Bump the dest connection read timeout on any activity */
614 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
615 if (Comm::IsConnOpen(to
.conn
)) {
616 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
617 CommTimeoutCbPtrFun(tunnelTimeout
, this));
618 commSetConnTimeout(to
.conn
, Config
.Timeout
.read
, timeoutCall
);
623 else if (len
== 0 || !Comm::IsConnOpen(to
.conn
)) {
624 debugs(26, 3, HERE
<< "Nothing to write or client gone. Terminate the tunnel.");
627 /* Only close the remote end if we've finished queueing data to it */
628 if (from
.len
== 0 && Comm::IsConnOpen(to
.conn
) ) {
631 } else if (cbdataReferenceValid(this)) {
639 TunnelStateData::copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*completion
)
641 debugs(26, 3, HERE
<< "Schedule Write");
642 AsyncCall::Pointer call
= commCbCall(5,5, "TunnelBlindCopyWriteHandler",
643 CommIoCbPtrFun(completion
, this));
644 to
.write(from
.buf
, len
, call
, NULL
);
647 /* Writes data from the client buffer to the server side */
649 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
651 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
652 assert (cbdataReferenceValid (tunnelState
));
653 tunnelState
->server
.writer
= NULL
;
655 tunnelState
->writeServerDone(buf
, len
, flag
, xerrno
);
659 TunnelStateData::writeServerDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
661 debugs(26, 3, HERE
<< server
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
663 if (flag
== Comm::ERR_CLOSING
)
666 request
->hier
.notePeerWrite();
669 if (flag
!= Comm::OK
) {
670 debugs(26, 4, "to-server write failed: " << xerrno
);
671 server
.error(xerrno
); // may call comm_close
677 debugs(26, 4, HERE
<< "No read input. Closing server connection.");
678 server
.conn
->close();
683 statCounter
.server
.all
.kbytes_out
+= len
;
684 statCounter
.server
.other
.kbytes_out
+= len
;
685 client
.dataSent(len
);
687 /* If the other end has closed, so should we */
688 if (!Comm::IsConnOpen(client
.conn
)) {
689 debugs(26, 4, HERE
<< "Client gone away. Shutting down server connection.");
690 server
.conn
->close();
694 const CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
696 if (cbdataReferenceValid(this))
700 /* Writes data from the server buffer to the client side */
702 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
704 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
705 assert (cbdataReferenceValid (tunnelState
));
706 tunnelState
->client
.writer
= NULL
;
708 tunnelState
->writeClientDone(buf
, len
, flag
, xerrno
);
712 TunnelStateData::Connection::dataSent(size_t amount
)
714 debugs(26, 3, HERE
<< "len=" << len
<< " - amount=" << amount
);
715 assert(amount
== (size_t)len
);
717 /* increment total object size */
725 TunnelStateData::Connection::write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
728 Comm::Write(conn
, b
, size
, callback
, free_func
);
732 TunnelStateData::writeClientDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
734 debugs(26, 3, HERE
<< client
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
736 if (flag
== Comm::ERR_CLOSING
)
740 if (flag
!= Comm::OK
) {
741 debugs(26, 4, "from-client read failed: " << xerrno
);
742 client
.error(xerrno
); // may call comm_close
748 debugs(26, 4, HERE
<< "Closing client connection due to 0 byte read.");
749 client
.conn
->close();
754 statCounter
.client_http
.kbytes_out
+= len
;
755 server
.dataSent(len
);
757 /* If the other end has closed, so should we */
758 if (!Comm::IsConnOpen(server
.conn
)) {
759 debugs(26, 4, HERE
<< "Server has gone away. Terminating client connection.");
760 client
.conn
->close();
764 CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
766 if (cbdataReferenceValid(this))
771 tunnelTimeout(const CommTimeoutCbParams
&io
)
773 TunnelStateData
*tunnelState
= static_cast<TunnelStateData
*>(io
.data
);
774 debugs(26, 3, HERE
<< io
.conn
);
775 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
776 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
778 tunnelState
->client
.closeIfOpen();
779 tunnelState
->server
.closeIfOpen();
783 TunnelStateData::Connection::closeIfOpen()
785 if (Comm::IsConnOpen(conn
))
790 tunnelDelayedClientRead(void *data
)
795 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
796 tunnel
->client
.readPending
= NULL
;
797 static uint64_t counter
=0;
798 debugs(26, 7, "Client read(2) delayed " << ++counter
<< " times");
799 tunnel
->copyRead(tunnel
->client
, TunnelStateData::ReadClient
);
803 tunnelDelayedServerRead(void *data
)
808 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
809 tunnel
->server
.readPending
= NULL
;
810 static uint64_t counter
=0;
811 debugs(26, 7, "Server read(2) delayed " << ++counter
<< " times");
812 tunnel
->copyRead(tunnel
->server
, TunnelStateData::ReadServer
);
816 TunnelStateData::copyRead(Connection
&from
, IOCB
*completion
)
818 assert(from
.len
== 0);
819 // If only the minimum permitted read size is going to be attempted
820 // then we schedule an event to try again in a few I/O cycles.
821 // Allow at least 1 byte to be read every (0.3*10) seconds.
822 int bw
= from
.bytesWanted(1, SQUID_TCP_SO_RCVBUF
);
823 if (bw
== 1 && ++from
.delayedLoops
< 10) {
824 from
.readPending
= this;
825 eventAdd("tunnelDelayedServerRead", from
.readPendingFunc
, from
.readPending
, 0.3, true);
829 AsyncCall::Pointer call
= commCbCall(5,4, "TunnelBlindCopyReadHandler",
830 CommIoCbPtrFun(completion
, this));
831 comm_read(from
.conn
, from
.buf
, bw
, call
);
835 TunnelStateData::readConnectResponse()
837 assert(waitingForConnectResponse());
839 AsyncCall::Pointer call
= commCbCall(5,4, "readConnectResponseDone",
840 CommIoCbPtrFun(ReadConnectResponseDone
, this));
841 comm_read(server
.conn
, connectRespBuf
->space(),
842 server
.bytesWanted(1, connectRespBuf
->spaceSize()), call
);
846 TunnelStateData::copyClientBytes()
848 if (preReadClientData
.length()) {
849 size_t copyBytes
= preReadClientData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadClientData
.length();
850 memcpy(client
.buf
, preReadClientData
.rawContent(), copyBytes
);
851 preReadClientData
.consume(copyBytes
);
852 client
.bytesIn(copyBytes
);
853 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, client
, server
))
854 copy(copyBytes
, client
, server
, TunnelStateData::WriteServerDone
);
856 copyRead(client
, ReadClient
);
860 TunnelStateData::copyServerBytes()
862 if (preReadServerData
.length()) {
863 size_t copyBytes
= preReadServerData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadServerData
.length();
864 memcpy(server
.buf
, preReadServerData
.rawContent(), copyBytes
);
865 preReadServerData
.consume(copyBytes
);
866 server
.bytesIn(copyBytes
);
867 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, server
, client
))
868 copy(copyBytes
, server
, client
, TunnelStateData::WriteClientDone
);
870 copyRead(server
, ReadServer
);
874 * Set the HTTP status for this request and sets the read handlers for client
875 * and server side connections.
878 tunnelStartShoveling(TunnelStateData
*tunnelState
)
880 assert(!tunnelState
->waitingForConnectExchange());
881 *tunnelState
->status_ptr
= Http::scOkay
;
882 if (tunnelState
->logTag_ptr
)
883 *tunnelState
->logTag_ptr
= LOG_TCP_TUNNEL
;
884 if (cbdataReferenceValid(tunnelState
)) {
886 // Shovel any payload already pushed into reply buffer by the server response
887 if (!tunnelState
->server
.len
)
888 tunnelState
->copyServerBytes();
890 debugs(26, DBG_DATA
, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState
->server
.buf
, tunnelState
->server
.len
) << "\n----------");
891 tunnelState
->copy(tunnelState
->server
.len
, tunnelState
->server
, tunnelState
->client
, TunnelStateData::WriteClientDone
);
894 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn() && !tunnelState
->http
->getConn()->inBuf
.isEmpty()) {
895 SBuf
* const in
= &tunnelState
->http
->getConn()->inBuf
;
896 debugs(26, DBG_DATA
, "Tunnel client PUSH Payload: \n" << *in
<< "\n----------");
897 tunnelState
->preReadClientData
.append(*in
);
898 in
->consume(); // ConnStateData buffer accounting after the shuffle.
900 tunnelState
->copyClientBytes();
905 * All the pieces we need to write to client and/or server connection
907 * Call the tunnelStartShoveling to start the blind pump.
910 tunnelConnectedWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t len
, Comm::Flag flag
, int, void *data
)
912 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
913 debugs(26, 3, HERE
<< conn
<< ", flag=" << flag
);
914 tunnelState
->client
.writer
= NULL
;
916 if (flag
!= Comm::OK
) {
917 *tunnelState
->status_ptr
= Http::scInternalServerError
;
918 tunnelErrorComplete(conn
->fd
, data
, 0);
922 if (auto http
= tunnelState
->http
.get()) {
923 http
->out
.headers_sz
+= len
;
924 http
->out
.size
+= len
;
927 tunnelStartShoveling(tunnelState
);
930 /// Called when we are done writing CONNECT request to a peer.
932 tunnelConnectReqWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t ioSize
, Comm::Flag flag
, int, void *data
)
934 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
935 debugs(26, 3, conn
<< ", flag=" << flag
);
936 tunnelState
->server
.writer
= NULL
;
937 assert(tunnelState
->waitingForConnectRequest());
939 tunnelState
->request
->hier
.notePeerWrite();
941 if (flag
!= Comm::OK
) {
942 *tunnelState
->status_ptr
= Http::scInternalServerError
;
943 tunnelErrorComplete(conn
->fd
, data
, 0);
947 statCounter
.server
.all
.kbytes_out
+= ioSize
;
948 statCounter
.server
.other
.kbytes_out
+= ioSize
;
950 tunnelState
->connectReqWriting
= false;
951 tunnelState
->connectExchangeCheckpoint();
955 TunnelStateData::connectExchangeCheckpoint()
957 if (waitingForConnectResponse()) {
958 debugs(26, 5, "still reading CONNECT response on " << server
.conn
);
959 } else if (waitingForConnectRequest()) {
960 debugs(26, 5, "still writing CONNECT request on " << server
.conn
);
962 assert(!waitingForConnectExchange());
963 debugs(26, 3, "done with CONNECT exchange on " << server
.conn
);
964 tunnelConnected(server
.conn
, this);
969 * handle the write completion from a proxy request to an upstream origin
972 tunnelConnected(const Comm::ConnectionPointer
&server
, void *data
)
974 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
975 debugs(26, 3, HERE
<< server
<< ", tunnelState=" << tunnelState
);
977 if (!tunnelState
->clientExpectsConnectResponse())
978 tunnelStartShoveling(tunnelState
); // ssl-bumped connection, be quiet
980 *tunnelState
->status_ptr
= Http::scOkay
;
981 AsyncCall::Pointer call
= commCbCall(5,5, "tunnelConnectedWriteDone",
982 CommIoCbPtrFun(tunnelConnectedWriteDone
, tunnelState
));
983 tunnelState
->client
.write(conn_established
, strlen(conn_established
), call
, NULL
);
988 tunnelErrorComplete(int fd
/*const Comm::ConnectionPointer &*/, void *data
, size_t)
990 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
991 debugs(26, 3, HERE
<< "FD " << fd
);
992 assert(tunnelState
!= NULL
);
993 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
994 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
996 if (Comm::IsConnOpen(tunnelState
->client
.conn
))
997 tunnelState
->client
.conn
->close();
999 if (Comm::IsConnOpen(tunnelState
->server
.conn
))
1000 tunnelState
->server
.conn
->close();
1003 /// reacts to a failure to establish the given TCP connection
1005 TunnelStateData::noteConnectFailure(const Comm::ConnectionPointer
&conn
)
1007 debugs(26, 4, "removing the failed one from " << serverDestinations
.size() <<
1008 " destinations: " << conn
);
1010 if (CachePeer
*peer
= conn
->getPeer())
1011 peerConnectFailed(peer
);
1013 assert(!serverDestinations
.empty());
1014 serverDestinations
.erase(serverDestinations
.begin());
1016 // Since no TCP payload has been passed to client or server, we may
1017 // TCP-connect to other destinations (including alternate IPs).
1019 if (!FwdState::EnoughTimeToReForward(startTime
))
1020 return sendError(savedError
, "forwarding timeout");
1022 if (!serverDestinations
.empty())
1023 return startConnecting();
1025 if (!PeerSelectionInitiator::subscribed
)
1026 return sendError(savedError
, "tried all destinations");
1028 debugs(26, 4, "wait for more destinations to try");
1029 // expect a noteDestination*() call
1033 tunnelConnectDone(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int xerrno
, void *data
)
1035 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
1037 if (status
!= Comm::OK
) {
1038 ErrorState
*err
= new ErrorState(ERR_CONNECT_FAIL
, Http::scServiceUnavailable
, tunnelState
->request
.getRaw());
1039 err
->xerrno
= xerrno
;
1040 // on timeout is this still: err->xerrno = ETIMEDOUT;
1041 err
->port
= conn
->remote
.port();
1042 tunnelState
->saveError(err
);
1043 tunnelState
->noteConnectFailure(conn
);
1048 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1049 if (conn
->getPeer() && conn
->getPeer()->options
.no_delay
)
1050 tunnelState
->server
.setDelayId(DelayId());
1053 tunnelState
->request
->hier
.resetPeerNotes(conn
, tunnelState
->getHost());
1055 tunnelState
->server
.conn
= conn
;
1056 tunnelState
->request
->peer_host
= conn
->getPeer() ? conn
->getPeer()->host
: NULL
;
1057 comm_add_close_handler(conn
->fd
, tunnelServerClosed
, tunnelState
);
1059 debugs(26, 4, HERE
<< "determine post-connect handling pathway.");
1060 if (conn
->getPeer()) {
1061 tunnelState
->request
->peer_login
= conn
->getPeer()->login
;
1062 tunnelState
->request
->peer_domain
= conn
->getPeer()->domain
;
1063 tunnelState
->request
->flags
.auth_no_keytab
= conn
->getPeer()->options
.auth_no_keytab
;
1064 tunnelState
->request
->flags
.proxying
= !(conn
->getPeer()->options
.originserver
);
1066 tunnelState
->request
->peer_login
= NULL
;
1067 tunnelState
->request
->peer_domain
= NULL
;
1068 tunnelState
->request
->flags
.auth_no_keytab
= false;
1069 tunnelState
->request
->flags
.proxying
= false;
1072 if (tunnelState
->request
->flags
.proxying
)
1073 tunnelState
->connectToPeer();
1075 tunnelConnected(conn
, tunnelState
);
1078 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1079 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1080 commSetConnTimeout(conn
, Config
.Timeout
.read
, timeoutCall
);
1084 tunnelStart(ClientHttpRequest
* http
)
1086 debugs(26, 3, HERE
);
1087 /* Create state structure. */
1088 TunnelStateData
*tunnelState
= NULL
;
1089 ErrorState
*err
= NULL
;
1090 HttpRequest
*request
= http
->request
;
1091 char *url
= http
->uri
;
1094 * client_addr.isNoAddr() indicates this is an "internal" request
1095 * from peer_digest.c, asn.c, netdb.c, etc and should always
1096 * be allowed. yuck, I know.
1099 if (Config
.accessList
.miss
&& !request
->client_addr
.isNoAddr()) {
1101 * Check if this host is allowed to fetch MISSES from us (miss_access)
1102 * default is to allow.
1104 ACLFilledChecklist
ch(Config
.accessList
.miss
, request
, NULL
);
1106 ch
.src_addr
= request
->client_addr
;
1107 ch
.my_addr
= request
->my_addr
;
1108 ch
.syncAle(request
, http
->log_uri
);
1109 if (ch
.fastCheck().denied()) {
1110 debugs(26, 4, HERE
<< "MISS access forbidden.");
1111 err
= new ErrorState(ERR_FORWARDING_DENIED
, Http::scForbidden
, request
);
1112 http
->al
->http
.code
= Http::scForbidden
;
1113 errorSend(http
->getConn()->clientConnection
, err
);
1118 debugs(26, 3, request
->method
<< ' ' << url
<< ' ' << request
->http_ver
);
1119 ++statCounter
.server
.all
.requests
;
1120 ++statCounter
.server
.other
.requests
;
1122 tunnelState
= new TunnelStateData(http
);
1124 //server.setDelayId called from tunnelConnectDone after server side connection established
1126 tunnelState
->startSelectingDestinations(request
, http
->al
, nullptr);
1130 TunnelStateData::connectToPeer()
1132 if (CachePeer
*p
= server
.conn
->getPeer()) {
1133 if (p
->secure
.encryptTransport
) {
1134 AsyncCall::Pointer callback
= asyncCall(5,4,
1135 "TunnelStateData::ConnectedToPeer",
1136 MyAnswerDialer(&TunnelStateData::connectedToPeer
, this));
1137 auto *connector
= new Security::BlindPeerConnector(request
, server
.conn
, callback
, al
);
1138 AsyncJob::Start(connector
); // will call our callback
1143 Security::EncryptorAnswer nil
;
1144 connectedToPeer(nil
);
1148 TunnelStateData::connectedToPeer(Security::EncryptorAnswer
&answer
)
1150 if (ErrorState
*error
= answer
.error
.get()) {
1151 answer
.error
.clear(); // sendError() will own the error
1152 sendError(error
, "TLS peer connection error");
1156 tunnelRelayConnectRequest(server
.conn
, this);
1160 tunnelRelayConnectRequest(const Comm::ConnectionPointer
&srv
, void *data
)
1162 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
1163 assert(!tunnelState
->waitingForConnectExchange());
1164 HttpHeader
hdr_out(hoRequest
);
1165 Http::StateFlags flags
;
1166 debugs(26, 3, HERE
<< srv
<< ", tunnelState=" << tunnelState
);
1167 memset(&flags
, '\0', sizeof(flags
));
1168 flags
.proxying
= tunnelState
->request
->flags
.proxying
;
1171 mb
.appendf("CONNECT %s HTTP/1.1\r\n", tunnelState
->url
);
1172 HttpStateData::httpBuildRequestHeader(tunnelState
->request
.getRaw(),
1173 NULL
, /* StoreEntry */
1174 tunnelState
->al
, /* AccessLogEntry */
1177 hdr_out
.packInto(&mb
);
1179 mb
.append("\r\n", 2);
1181 debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState
->server
.conn
<<
1182 ":\n----------\n" << mb
.buf
<< "\n----------");
1184 AsyncCall::Pointer writeCall
= commCbCall(5,5, "tunnelConnectReqWriteDone",
1185 CommIoCbPtrFun(tunnelConnectReqWriteDone
,
1188 tunnelState
->server
.write(mb
.buf
, mb
.size
, writeCall
, mb
.freeFunc());
1189 tunnelState
->connectReqWriting
= true;
1191 tunnelState
->connectRespBuf
= new MemBuf
;
1192 // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1193 // can hold since any CONNECT response leftovers have to fit into server.buf.
1194 // 2*SQUID_TCP_SO_RCVBUF: Http::Message::parse() zero-terminates, which uses space.
1195 tunnelState
->connectRespBuf
->init(SQUID_TCP_SO_RCVBUF
, 2*SQUID_TCP_SO_RCVBUF
);
1196 tunnelState
->readConnectResponse();
1198 assert(tunnelState
->waitingForConnectExchange());
1200 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1201 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1202 commSetConnTimeout(srv
, Config
.Timeout
.read
, timeoutCall
);
1205 static Comm::ConnectionPointer
1206 borrowPinnedConnection(HttpRequest
*request
, Comm::ConnectionPointer
&serverDestination
)
1208 // pinned_connection may become nil after a pconn race
1209 if (ConnStateData
*pinned_connection
= request
? request
->pinnedConnection() : nullptr) {
1210 Comm::ConnectionPointer serverConn
= pinned_connection
->borrowPinnedConnection(request
, serverDestination
->getPeer());
1218 TunnelStateData::noteDestination(Comm::ConnectionPointer path
)
1220 const bool wasBlocked
= serverDestinations
.empty();
1221 serverDestinations
.push_back(path
);
1224 // else continue to use one of the previously noted destinations;
1225 // if all of them fail, we may try this path
1229 TunnelStateData::noteDestinationsEnd(ErrorState
*selectionError
)
1231 PeerSelectionInitiator::subscribed
= false;
1232 if (serverDestinations
.empty()) { // was blocked, waiting for more paths
1235 return sendError(selectionError
, "path selection has failed");
1238 return sendError(savedError
, "all found paths have failed");
1240 return sendError(new ErrorState(ERR_CANNOT_FORWARD
, Http::scServiceUnavailable
, request
.getRaw()),
1241 "path selection found no paths");
1243 // else continue to use one of the previously noted destinations;
1244 // if all of them fail, tunneling as whole will fail
1245 Must(!selectionError
); // finding at least one path means selection succeeded
1248 /// remembers an error to be used if there will be no more connection attempts
1250 TunnelStateData::saveError(ErrorState
*error
)
1252 debugs(26, 4, savedError
<< " ? " << error
);
1254 delete savedError
; // may be nil
1258 /// Starts sending the given error message to the client, leading to the
1259 /// eventual transaction termination. Call with savedError to send savedError.
1261 TunnelStateData::sendError(ErrorState
*finalError
, const char *reason
)
1263 debugs(26, 3, "aborting transaction for " << reason
);
1266 request
->hier
.stopPeerClock(false);
1270 // get rid of any cached error unless that is what the caller is sending
1271 if (savedError
!= finalError
)
1272 delete savedError
; // may be nil
1273 savedError
= nullptr;
1275 // we cannot try other destinations after responding with an error
1276 PeerSelectionInitiator::subscribed
= false; // may already be false
1278 *status_ptr
= finalError
->httpStatus
;
1279 finalError
->callback
= tunnelErrorComplete
;
1280 finalError
->callback_data
= this;
1281 errorSend(client
.conn
, finalError
);
1285 TunnelStateData::startConnecting()
1288 request
->hier
.startPeerClock();
1290 assert(!serverDestinations
.empty());
1291 Comm::ConnectionPointer
&dest
= serverDestinations
.front();
1292 debugs(26, 3, "to " << dest
);
1294 if (dest
->peerType
== PINNED
) {
1295 Comm::ConnectionPointer serverConn
= borrowPinnedConnection(request
.getRaw(), dest
);
1296 debugs(26,7, "pinned peer connection: " << serverConn
);
1297 if (Comm::IsConnOpen(serverConn
)) {
1298 tunnelConnectDone(serverConn
, Comm::OK
, 0, (void *)this);
1301 // a PINNED path failure is fatal; do not wait for more paths
1302 sendError(new ErrorState(ERR_CANNOT_FORWARD
, Http::scServiceUnavailable
, request
.getRaw()),
1303 "pinned path failure");
1307 GetMarkingsToServer(request
.getRaw(), *dest
);
1309 const time_t connectTimeout
= dest
->connectTimeout(startTime
);
1310 AsyncCall::Pointer call
= commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone
, this));
1311 Comm::ConnOpener
*cs
= new Comm::ConnOpener(dest
, call
, connectTimeout
);
1313 AsyncJob::Start(cs
);
1316 CBDATA_CLASS_INIT(TunnelStateData
);
1319 TunnelStateData::noConnections() const
1321 return !Comm::IsConnOpen(server
.conn
) && !Comm::IsConnOpen(client
.conn
);
1326 TunnelStateData::Connection::setDelayId(DelayId
const &newDelay
)
1335 switchToTunnel(HttpRequest
*request
, Comm::ConnectionPointer
&clientConn
, Comm::ConnectionPointer
&srvConn
)
1337 debugs(26,5, "Revert to tunnel FD " << clientConn
->fd
<< " with FD " << srvConn
->fd
);
1339 /* Create state structure. */
1340 ++statCounter
.server
.all
.requests
;
1341 ++statCounter
.server
.other
.requests
;
1343 auto conn
= request
->clientConnectionManager
.get();
1345 Http::StreamPointer context
= conn
->pipeline
.front();
1346 Must(context
&& context
->http
);
1348 debugs(26, 3, request
->method
<< " " << context
->http
->uri
<< " " << request
->http_ver
);
1350 TunnelStateData
*tunnelState
= new TunnelStateData(context
->http
);
1352 fd_table
[clientConn
->fd
].read_method
= &default_read_method
;
1353 fd_table
[clientConn
->fd
].write_method
= &default_write_method
;
1355 request
->hier
.resetPeerNotes(srvConn
, tunnelState
->getHost());
1357 tunnelState
->server
.conn
= srvConn
;
1360 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1361 if (srvConn
->getPeer() && srvConn
->getPeer()->options
.no_delay
)
1362 tunnelState
->server
.setDelayId(DelayId::DelayClient(context
->http
));
1365 request
->peer_host
= srvConn
->getPeer() ? srvConn
->getPeer()->host
: nullptr;
1366 comm_add_close_handler(srvConn
->fd
, tunnelServerClosed
, tunnelState
);
1368 debugs(26, 4, "determine post-connect handling pathway.");
1369 if (srvConn
->getPeer()) {
1370 request
->peer_login
= srvConn
->getPeer()->login
;
1371 request
->peer_domain
= srvConn
->getPeer()->domain
;
1372 request
->flags
.auth_no_keytab
= srvConn
->getPeer()->options
.auth_no_keytab
;
1373 request
->flags
.proxying
= !(srvConn
->getPeer()->options
.originserver
);
1375 request
->peer_login
= nullptr;
1376 request
->peer_domain
= nullptr;
1377 request
->flags
.auth_no_keytab
= false;
1378 request
->flags
.proxying
= false;
1381 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1382 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1383 commSetConnTimeout(srvConn
, Config
.Timeout
.read
, timeoutCall
);
1384 fd_table
[srvConn
->fd
].read_method
= &default_read_method
;
1385 fd_table
[srvConn
->fd
].write_method
= &default_write_method
;
1387 auto ssl
= fd_table
[srvConn
->fd
].ssl
.get();
1389 BIO
*b
= SSL_get_rbio(ssl
);
1390 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
1391 tunnelState
->preReadServerData
= srvBio
->rBufData();
1392 tunnelStartShoveling(tunnelState
);
1394 #endif //USE_OPENSSL