]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tunnel.cc
Cleanup: Refactor ConnStateData pipeline handling
[thirdparty/squid.git] / src / tunnel.cc
1 /*
2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9 /* DEBUG: section 26 Secure Sockets Layer Proxy */
10
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "base/CbcPointer.h"
14 #include "CachePeer.h"
15 #include "cbdata.h"
16 #include "client_side.h"
17 #include "client_side_request.h"
18 #include "comm.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"
24 #include "fde.h"
25 #include "FwdState.h"
26 #include "globals.h"
27 #include "http.h"
28 #include "HttpRequest.h"
29 #include "HttpStateFlags.h"
30 #include "ip/QosConfig.h"
31 #include "LogTags.h"
32 #include "MemBuf.h"
33 #include "PeerSelectState.h"
34 #include "SBuf.h"
35 #include "SquidConfig.h"
36 #include "SquidTime.h"
37 #include "StatCounters.h"
38 #if USE_OPENSSL
39 #include "ssl/bio.h"
40 #include "ssl/PeerConnector.h"
41 #include "ssl/ServerBump.h"
42 #else
43 #include "security/EncryptorAnswer.h"
44 #endif
45 #include "tools.h"
46 #if USE_DELAY_POOLS
47 #include "DelayId.h"
48 #endif
49
50 #include <climits>
51 #include <cerrno>
52
53 /**
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.
57 */
58 /*
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.
63 *
64 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
65 */
66 class TunnelStateData
67 {
68 CBDATA_CLASS(TunnelStateData);
69
70 public:
71 TunnelStateData();
72 ~TunnelStateData();
73 TunnelStateData(const TunnelStateData &); // do not implement
74 TunnelStateData &operator =(const TunnelStateData &); // do not implement
75
76 class Connection;
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);
81
82 /// Starts reading peer response to our CONNECT request.
83 void readConnectResponse();
84
85 /// Called when we may be done handling a CONNECT exchange with the peer.
86 void connectExchangeCheckpoint();
87
88 bool noConnections() const;
89 char *url;
90 CbcPointer<ClientHttpRequest> http;
91 HttpRequest::Pointer request;
92 AccessLogEntryPointer al;
93 Comm::ConnectionList serverDestinations;
94
95 const char * getHost() const {
96 return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->url.host());
97 };
98
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(); }
105
106 /// Whether the client sent a CONNECT request to us.
107 bool clientExpectsConnectResponse() const {
108 #if USE_OPENSSL
109 // We are bumping and we had already send "OK CONNECTED"
110 if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->step > Ssl::bumpStep1)
111 return false;
112 #endif
113 return !(request != NULL &&
114 (request->flags.interceptTproxy || request->flags.intercepted));
115 }
116
117 /// Sends "502 Bad Gateway" error response to the client,
118 /// if it is waiting for Squid CONNECT response, closing connections.
119 void informUserOfPeerError(const char *errMsg, size_t);
120
121 class Connection
122 {
123
124 public:
125 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), delayedLoops(0),
126 readPending(NULL), readPendingFunc(NULL) {}
127
128 ~Connection();
129
130 int bytesWanted(int lower=0, int upper = INT_MAX) const;
131 void bytesIn(int const &);
132 #if USE_DELAY_POOLS
133
134 void setDelayId(DelayId const &);
135 #endif
136
137 void error(int const xerrno);
138 int debugLevelForError(int const xerrno) const;
139 void closeIfOpen();
140 void dataSent (size_t amount);
141 /// writes 'b' buffer, setting the 'writer' member to 'callback'.
142 void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func);
143 int len;
144 char *buf;
145 AsyncCall::Pointer writer; ///< pending Comm::Write callback
146 uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
147
148 Comm::ConnectionPointer conn; ///< The currently connected connection.
149 uint8_t delayedLoops; ///< how many times a read on this connection has been postponed.
150
151 // XXX: make these an AsyncCall when event API can handle them
152 TunnelStateData *readPending;
153 EVH *readPendingFunc;
154 private:
155 #if USE_DELAY_POOLS
156
157 DelayId delayId;
158 #endif
159
160 };
161
162 Connection client, server;
163 int *status_ptr; ///< pointer for logging HTTP status
164 LogTags *logTag_ptr; ///< pointer for logging Squid processing code
165 MemBuf *connectRespBuf; ///< accumulates peer CONNECT response when we need it
166 bool connectReqWriting; ///< whether we are writing a CONNECT request to a peer
167 SBuf preReadClientData;
168 time_t started; ///< when this tunnel was initiated.
169
170 void copyRead(Connection &from, IOCB *completion);
171
172 /// continue to set up connection to a peer, going async for SSL peers
173 void connectToPeer();
174
175 private:
176 #if USE_OPENSSL
177 /// Gives PeerConnector access to Answer in the TunnelStateData callback dialer.
178 class MyAnswerDialer: public CallDialer, public Ssl::PeerConnector::CbDialer
179 {
180 public:
181 typedef void (TunnelStateData::*Method)(Security::EncryptorAnswer &);
182
183 MyAnswerDialer(Method method, TunnelStateData *tunnel):
184 method_(method), tunnel_(tunnel), answer_() {}
185
186 /* CallDialer API */
187 virtual bool canDial(AsyncCall &call) { return tunnel_.valid(); }
188 void dial(AsyncCall &call) { ((&(*tunnel_))->*method_)(answer_); }
189 virtual void print(std::ostream &os) const {
190 os << '(' << tunnel_.get() << ", " << answer_ << ')';
191 }
192
193 /* Ssl::PeerConnector::CbDialer API */
194 virtual Security::EncryptorAnswer &answer() { return answer_; }
195
196 private:
197 Method method_;
198 CbcPointer<TunnelStateData> tunnel_;
199 Security::EncryptorAnswer answer_;
200 };
201 #endif
202
203 /// callback handler after connection setup (including any encryption)
204 void connectedToPeer(Security::EncryptorAnswer &answer);
205
206 public:
207 bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
208 void copy(size_t len, Connection &from, Connection &to, IOCB *);
209 void handleConnectResponse(const size_t chunkSize);
210 void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
211 void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
212 void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
213 void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
214
215 static void ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
216 void readConnectResponseDone(char *buf, size_t len, Comm::Flag errcode, int xerrno);
217 void copyClientBytes();
218 };
219
220 static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
221
222 static CNCB tunnelConnectDone;
223 static ERCB tunnelErrorComplete;
224 static CLCB tunnelServerClosed;
225 static CLCB tunnelClientClosed;
226 static CTCB tunnelTimeout;
227 static PSC tunnelPeerSelectComplete;
228 static EVH tunnelDelayedClientRead;
229 static EVH tunnelDelayedServerRead;
230 static void tunnelConnected(const Comm::ConnectionPointer &server, void *);
231 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *);
232
233 static void
234 tunnelServerClosed(const CommCloseCbParams &params)
235 {
236 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
237 debugs(26, 3, HERE << tunnelState->server.conn);
238 tunnelState->server.conn = NULL;
239 tunnelState->server.writer = NULL;
240
241 if (tunnelState->request != NULL)
242 tunnelState->request->hier.stopPeerClock(false);
243
244 if (tunnelState->noConnections()) {
245 // ConnStateData pipeline should contain the CONNECT we are performing
246 auto ctx = tunnelState->http->getConn()->pipeline.front();
247 if (ctx != nullptr)
248 ctx->finished();
249 delete tunnelState;
250 return;
251 }
252
253 if (!tunnelState->client.writer) {
254 tunnelState->client.conn->close();
255 return;
256 }
257 }
258
259 static void
260 tunnelClientClosed(const CommCloseCbParams &params)
261 {
262 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
263 debugs(26, 3, HERE << tunnelState->client.conn);
264 tunnelState->client.conn = NULL;
265 tunnelState->client.writer = NULL;
266
267 if (tunnelState->noConnections()) {
268 // ConnStateData pipeline should contain the CONNECT we are performing
269 auto ctx = tunnelState->http->getConn()->pipeline.front();
270 if (ctx != nullptr)
271 ctx->finished();
272 delete tunnelState;
273 return;
274 }
275
276 if (!tunnelState->server.writer) {
277 tunnelState->server.conn->close();
278 return;
279 }
280 }
281
282 TunnelStateData::TunnelStateData() :
283 url(NULL),
284 http(),
285 request(NULL),
286 status_ptr(NULL),
287 logTag_ptr(NULL),
288 connectRespBuf(NULL),
289 connectReqWriting(false),
290 started(squid_curtime)
291 {
292 debugs(26, 3, "TunnelStateData constructed this=" << this);
293 client.readPendingFunc = &tunnelDelayedClientRead;
294 server.readPendingFunc = &tunnelDelayedServerRead;
295 }
296
297 TunnelStateData::~TunnelStateData()
298 {
299 debugs(26, 3, "TunnelStateData destructed this=" << this);
300 assert(noConnections());
301 xfree(url);
302 serverDestinations.clear();
303 delete connectRespBuf;
304 }
305
306 TunnelStateData::Connection::~Connection()
307 {
308 if (readPending)
309 eventDelete(readPendingFunc, readPending);
310
311 safe_free(buf);
312 }
313
314 int
315 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
316 {
317 #if USE_DELAY_POOLS
318 return delayId.bytesWanted(lowerbound, upperbound);
319 #else
320
321 return upperbound;
322 #endif
323 }
324
325 void
326 TunnelStateData::Connection::bytesIn(int const &count)
327 {
328 debugs(26, 3, HERE << "len=" << len << " + count=" << count);
329 #if USE_DELAY_POOLS
330 delayId.bytesIn(count);
331 #endif
332
333 len += count;
334 }
335
336 int
337 TunnelStateData::Connection::debugLevelForError(int const xerrno) const
338 {
339 #ifdef ECONNRESET
340
341 if (xerrno == ECONNRESET)
342 return 2;
343
344 #endif
345
346 if (ignoreErrno(xerrno))
347 return 3;
348
349 return 1;
350 }
351
352 /* Read from server side and queue it for writing to the client */
353 void
354 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
355 {
356 TunnelStateData *tunnelState = (TunnelStateData *)data;
357 assert(cbdataReferenceValid(tunnelState));
358 debugs(26, 3, HERE << c);
359
360 tunnelState->readServer(buf, len, errcode, xerrno);
361 }
362
363 void
364 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
365 {
366 debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
367 server.delayedLoops=0;
368
369 /*
370 * Bail out early on Comm::ERR_CLOSING
371 * - close handlers will tidy up for us
372 */
373
374 if (errcode == Comm::ERR_CLOSING)
375 return;
376
377 if (len > 0) {
378 server.bytesIn(len);
379 statCounter.server.all.kbytes_in += len;
380 statCounter.server.other.kbytes_in += len;
381 }
382
383 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
384 copy(len, server, client, WriteClientDone);
385 }
386
387 /// Called when we read [a part of] CONNECT response from the peer
388 void
389 TunnelStateData::readConnectResponseDone(char *, size_t len, Comm::Flag errcode, int xerrno)
390 {
391 debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
392 assert(waitingForConnectResponse());
393
394 if (errcode == Comm::ERR_CLOSING)
395 return;
396
397 if (len > 0) {
398 connectRespBuf->appended(len);
399 server.bytesIn(len);
400 statCounter.server.all.kbytes_in += len;
401 statCounter.server.other.kbytes_in += len;
402 }
403
404 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
405 handleConnectResponse(len);
406 }
407
408 void
409 TunnelStateData::informUserOfPeerError(const char *errMsg, const size_t sz)
410 {
411 server.len = 0;
412
413 if (logTag_ptr)
414 *logTag_ptr = LOG_TCP_TUNNEL;
415
416 if (!clientExpectsConnectResponse()) {
417 // closing the connection is the best we can do here
418 debugs(50, 3, server.conn << " closing on error: " << errMsg);
419 server.conn->close();
420 return;
421 }
422
423 // if we have no reply suitable to relay, use 502 Bad Gateway
424 if (!sz || sz > static_cast<size_t>(connectRespBuf->contentSize())) {
425 ErrorState *err = new ErrorState(ERR_CONNECT_FAIL, Http::scBadGateway, request.getRaw());
426 *status_ptr = Http::scBadGateway;
427 err->callback = tunnelErrorComplete;
428 err->callback_data = this;
429 errorSend(http->getConn()->clientConnection, err);
430 return;
431 }
432
433 // if we need to send back the server response. write its headers to the client
434 server.len = sz;
435 memcpy(server.buf, connectRespBuf->content(), server.len);
436 copy(server.len, server, client, TunnelStateData::WriteClientDone);
437 // then close the server FD to prevent any relayed keep-alive causing CVE-2015-5400
438 server.closeIfOpen();
439 }
440
441 /* Read from client side and queue it for writing to the server */
442 void
443 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
444 {
445 TunnelStateData *tunnelState = (TunnelStateData *)data;
446 assert (cbdataReferenceValid (tunnelState));
447
448 tunnelState->readConnectResponseDone(buf, len, errcode, xerrno);
449 }
450
451 /// Parses [possibly incomplete] CONNECT response and reacts to it.
452 /// If the tunnel is being closed or more response data is needed, returns false.
453 /// Otherwise, the caller should handle the remaining read data, if any.
454 void
455 TunnelStateData::handleConnectResponse(const size_t chunkSize)
456 {
457 assert(waitingForConnectResponse());
458
459 // Ideally, client and server should use MemBuf or better, but current code
460 // never accumulates more than one read when shoveling data (XXX) so it does
461 // not need to deal with MemBuf complexity. To keep it simple, we use a
462 // dedicated MemBuf for accumulating CONNECT responses. TODO: When shoveling
463 // is optimized, reuse server.buf for CONNEC response accumulation instead.
464
465 /* mimic the basic parts of HttpStateData::processReplyHeader() */
466 HttpReply rep;
467 Http::StatusCode parseErr = Http::scNone;
468 const bool eof = !chunkSize;
469 connectRespBuf->terminate(); // HttpMsg::parse requires terminated string
470 const bool parsed = rep.parse(connectRespBuf->content(), connectRespBuf->contentSize(), eof, &parseErr);
471 if (!parsed) {
472 if (parseErr > 0) { // unrecoverable parsing error
473 informUserOfPeerError("malformed CONNECT response from peer", 0);
474 return;
475 }
476
477 // need more data
478 assert(!eof);
479 assert(!parseErr);
480
481 if (!connectRespBuf->hasSpace()) {
482 informUserOfPeerError("huge CONNECT response from peer", 0);
483 return;
484 }
485
486 // keep reading
487 readConnectResponse();
488 return;
489 }
490
491 // CONNECT response was successfully parsed
492 *status_ptr = rep.sline.status();
493
494 // we need to relay the 401/407 responses when login=PASS(THRU)
495 const char *pwd = server.conn->getPeer()->login;
496 const bool relay = pwd && (strcmp(pwd, "PASS") != 0 || strcmp(pwd, "PASSTHRU") != 0) &&
497 (*status_ptr == Http::scProxyAuthenticationRequired ||
498 *status_ptr == Http::scUnauthorized);
499
500 // bail if we did not get an HTTP 200 (Connection Established) response
501 if (rep.sline.status() != Http::scOkay) {
502 // if we ever decide to reuse the peer connection, we must extract the error response first
503 informUserOfPeerError("unsupported CONNECT response status code", (relay ? rep.hdr_sz : 0));
504 return;
505 }
506
507 if (rep.hdr_sz < connectRespBuf->contentSize()) {
508 // preserve bytes that the server already sent after the CONNECT response
509 server.len = connectRespBuf->contentSize() - rep.hdr_sz;
510 memcpy(server.buf, connectRespBuf->content()+rep.hdr_sz, server.len);
511 } else {
512 // reset; delay pools were using this field to throttle CONNECT response
513 server.len = 0;
514 }
515
516 delete connectRespBuf;
517 connectRespBuf = NULL;
518 connectExchangeCheckpoint();
519 }
520
521 void
522 TunnelStateData::Connection::error(int const xerrno)
523 {
524 /* XXX fixme xstrerror and xerrno... */
525 errno = xerrno;
526
527 debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerror());
528
529 if (!ignoreErrno(xerrno))
530 conn->close();
531 }
532
533 /* Read from client side and queue it for writing to the server */
534 void
535 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
536 {
537 TunnelStateData *tunnelState = (TunnelStateData *)data;
538 assert (cbdataReferenceValid (tunnelState));
539
540 tunnelState->readClient(buf, len, errcode, xerrno);
541 }
542
543 void
544 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
545 {
546 debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
547 client.delayedLoops=0;
548
549 /*
550 * Bail out early on Comm::ERR_CLOSING
551 * - close handlers will tidy up for us
552 */
553
554 if (errcode == Comm::ERR_CLOSING)
555 return;
556
557 if (len > 0) {
558 client.bytesIn(len);
559 statCounter.client_http.kbytes_in += len;
560 }
561
562 if (keepGoingAfterRead(len, errcode, xerrno, client, server))
563 copy(len, client, server, WriteServerDone);
564 }
565
566 /// Updates state after reading from client or server.
567 /// Returns whether the caller should use the data just read.
568 bool
569 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
570 {
571 debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
572
573 /* I think this is to prevent free-while-in-a-callback behaviour
574 * - RBC 20030229
575 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
576 */
577 const CbcPointer<TunnelStateData> safetyLock(this);
578
579 /* Bump the source connection read timeout on any activity */
580 if (Comm::IsConnOpen(from.conn)) {
581 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
582 CommTimeoutCbPtrFun(tunnelTimeout, this));
583 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
584 }
585
586 /* Bump the dest connection read timeout on any activity */
587 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
588 if (Comm::IsConnOpen(to.conn)) {
589 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
590 CommTimeoutCbPtrFun(tunnelTimeout, this));
591 commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
592 }
593
594 if (errcode)
595 from.error (xerrno);
596 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
597 debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
598 from.conn->close();
599
600 /* Only close the remote end if we've finished queueing data to it */
601 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
602 to.conn->close();
603 }
604 } else if (cbdataReferenceValid(this)) {
605 return true;
606 }
607
608 return false;
609 }
610
611 void
612 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
613 {
614 debugs(26, 3, HERE << "Schedule Write");
615 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
616 CommIoCbPtrFun(completion, this));
617 to.write(from.buf, len, call, NULL);
618 }
619
620 /* Writes data from the client buffer to the server side */
621 void
622 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
623 {
624 TunnelStateData *tunnelState = (TunnelStateData *)data;
625 assert (cbdataReferenceValid (tunnelState));
626 tunnelState->server.writer = NULL;
627
628 tunnelState->writeServerDone(buf, len, flag, xerrno);
629 }
630
631 void
632 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
633 {
634 debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
635
636 /* Error? */
637 if (flag != Comm::OK) {
638 if (flag != Comm::ERR_CLOSING) {
639 debugs(26, 4, HERE << "calling TunnelStateData::server.error(" << xerrno <<")");
640 server.error(xerrno); // may call comm_close
641 }
642 return;
643 }
644
645 /* EOF? */
646 if (len == 0) {
647 debugs(26, 4, HERE << "No read input. Closing server connection.");
648 server.conn->close();
649 return;
650 }
651
652 /* Valid data */
653 statCounter.server.all.kbytes_out += len;
654 statCounter.server.other.kbytes_out += len;
655 client.dataSent(len);
656
657 /* If the other end has closed, so should we */
658 if (!Comm::IsConnOpen(client.conn)) {
659 debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
660 server.conn->close();
661 return;
662 }
663
664 const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
665
666 if (cbdataReferenceValid(this))
667 copyClientBytes();
668 }
669
670 /* Writes data from the server buffer to the client side */
671 void
672 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
673 {
674 TunnelStateData *tunnelState = (TunnelStateData *)data;
675 assert (cbdataReferenceValid (tunnelState));
676 tunnelState->client.writer = NULL;
677
678 tunnelState->writeClientDone(buf, len, flag, xerrno);
679 }
680
681 void
682 TunnelStateData::Connection::dataSent(size_t amount)
683 {
684 debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
685 assert(amount == (size_t)len);
686 len =0;
687 /* increment total object size */
688
689 if (size_ptr)
690 *size_ptr += amount;
691 }
692
693 void
694 TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
695 {
696 writer = callback;
697 Comm::Write(conn, b, size, callback, free_func);
698 }
699
700 void
701 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
702 {
703 debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
704
705 /* Error? */
706 if (flag != Comm::OK) {
707 if (flag != Comm::ERR_CLOSING) {
708 debugs(26, 4, HERE << "Closing client connection due to comm flags.");
709 client.error(xerrno); // may call comm_close
710 }
711 return;
712 }
713
714 /* EOF? */
715 if (len == 0) {
716 debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
717 client.conn->close();
718 return;
719 }
720
721 /* Valid data */
722 statCounter.client_http.kbytes_out += len;
723 server.dataSent(len);
724
725 /* If the other end has closed, so should we */
726 if (!Comm::IsConnOpen(server.conn)) {
727 debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
728 client.conn->close();
729 return;
730 }
731
732 CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
733
734 if (cbdataReferenceValid(this))
735 copyRead(server, ReadServer);
736 }
737
738 static void
739 tunnelTimeout(const CommTimeoutCbParams &io)
740 {
741 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
742 debugs(26, 3, HERE << io.conn);
743 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
744 CbcPointer<TunnelStateData> safetyLock(tunnelState);
745
746 tunnelState->client.closeIfOpen();
747 tunnelState->server.closeIfOpen();
748 }
749
750 void
751 TunnelStateData::Connection::closeIfOpen()
752 {
753 if (Comm::IsConnOpen(conn))
754 conn->close();
755 }
756
757 static void
758 tunnelDelayedClientRead(void *data)
759 {
760 if (!data)
761 return;
762
763 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
764 tunnel->client.readPending = NULL;
765 static uint64_t counter=0;
766 debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
767 tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
768 }
769
770 static void
771 tunnelDelayedServerRead(void *data)
772 {
773 if (!data)
774 return;
775
776 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
777 tunnel->server.readPending = NULL;
778 static uint64_t counter=0;
779 debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
780 tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
781 }
782
783 void
784 TunnelStateData::copyRead(Connection &from, IOCB *completion)
785 {
786 assert(from.len == 0);
787 // If only the minimum permitted read size is going to be attempted
788 // then we schedule an event to try again in a few I/O cycles.
789 // Allow at least 1 byte to be read every (0.3*10) seconds.
790 int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
791 if (bw == 1 && ++from.delayedLoops < 10) {
792 from.readPending = this;
793 eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
794 return;
795 }
796
797 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
798 CommIoCbPtrFun(completion, this));
799 comm_read(from.conn, from.buf, bw, call);
800 }
801
802 void
803 TunnelStateData::readConnectResponse()
804 {
805 assert(waitingForConnectResponse());
806
807 AsyncCall::Pointer call = commCbCall(5,4, "readConnectResponseDone",
808 CommIoCbPtrFun(ReadConnectResponseDone, this));
809 comm_read(server.conn, connectRespBuf->space(),
810 server.bytesWanted(1, connectRespBuf->spaceSize()), call);
811 }
812
813 void
814 TunnelStateData::copyClientBytes()
815 {
816 if (preReadClientData.length()) {
817 size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
818 memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
819 preReadClientData.consume(copyBytes);
820 client.bytesIn(copyBytes);
821 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
822 copy(copyBytes, client, server, TunnelStateData::WriteServerDone);
823 } else
824 copyRead(client, ReadClient);
825 }
826
827 /**
828 * Set the HTTP status for this request and sets the read handlers for client
829 * and server side connections.
830 */
831 static void
832 tunnelStartShoveling(TunnelStateData *tunnelState)
833 {
834 assert(!tunnelState->waitingForConnectExchange());
835 *tunnelState->status_ptr = Http::scOkay;
836 if (tunnelState->logTag_ptr)
837 *tunnelState->logTag_ptr = LOG_TCP_TUNNEL;
838 if (cbdataReferenceValid(tunnelState)) {
839
840 // Shovel any payload already pushed into reply buffer by the server response
841 if (!tunnelState->server.len)
842 tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
843 else {
844 debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
845 tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
846 }
847
848 if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
849 SBuf * const in = &tunnelState->http->getConn()->inBuf;
850 debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
851 tunnelState->preReadClientData.append(*in);
852 in->consume(); // ConnStateData buffer accounting after the shuffle.
853 }
854 tunnelState->copyClientBytes();
855 }
856 }
857
858 /**
859 * All the pieces we need to write to client and/or server connection
860 * have been written.
861 * Call the tunnelStartShoveling to start the blind pump.
862 */
863 static void
864 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag flag, int, void *data)
865 {
866 TunnelStateData *tunnelState = (TunnelStateData *)data;
867 debugs(26, 3, HERE << conn << ", flag=" << flag);
868 tunnelState->client.writer = NULL;
869
870 if (flag != Comm::OK) {
871 *tunnelState->status_ptr = Http::scInternalServerError;
872 tunnelErrorComplete(conn->fd, data, 0);
873 return;
874 }
875
876 tunnelStartShoveling(tunnelState);
877 }
878
879 /// Called when we are done writing CONNECT request to a peer.
880 static void
881 tunnelConnectReqWriteDone(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag flag, int, void *data)
882 {
883 TunnelStateData *tunnelState = (TunnelStateData *)data;
884 debugs(26, 3, conn << ", flag=" << flag);
885 tunnelState->server.writer = NULL;
886 assert(tunnelState->waitingForConnectRequest());
887
888 if (flag != Comm::OK) {
889 *tunnelState->status_ptr = Http::scInternalServerError;
890 tunnelErrorComplete(conn->fd, data, 0);
891 return;
892 }
893
894 tunnelState->connectReqWriting = false;
895 tunnelState->connectExchangeCheckpoint();
896 }
897
898 void
899 TunnelStateData::connectExchangeCheckpoint()
900 {
901 if (waitingForConnectResponse()) {
902 debugs(26, 5, "still reading CONNECT response on " << server.conn);
903 } else if (waitingForConnectRequest()) {
904 debugs(26, 5, "still writing CONNECT request on " << server.conn);
905 } else {
906 assert(!waitingForConnectExchange());
907 debugs(26, 3, "done with CONNECT exchange on " << server.conn);
908 tunnelConnected(server.conn, this);
909 }
910 }
911
912 /*
913 * handle the write completion from a proxy request to an upstream origin
914 */
915 static void
916 tunnelConnected(const Comm::ConnectionPointer &server, void *data)
917 {
918 TunnelStateData *tunnelState = (TunnelStateData *)data;
919 debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
920
921 if (!tunnelState->clientExpectsConnectResponse())
922 tunnelStartShoveling(tunnelState); // ssl-bumped connection, be quiet
923 else {
924 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
925 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
926 tunnelState->client.write(conn_established, strlen(conn_established), call, NULL);
927 }
928 }
929
930 static void
931 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
932 {
933 TunnelStateData *tunnelState = (TunnelStateData *)data;
934 debugs(26, 3, HERE << "FD " << fd);
935 assert(tunnelState != NULL);
936 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
937 CbcPointer<TunnelStateData> safetyLock(tunnelState);
938
939 if (Comm::IsConnOpen(tunnelState->client.conn))
940 tunnelState->client.conn->close();
941
942 if (Comm::IsConnOpen(tunnelState->server.conn))
943 tunnelState->server.conn->close();
944 }
945
946 static void
947 tunnelConnectDone(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
948 {
949 TunnelStateData *tunnelState = (TunnelStateData *)data;
950
951 if (status != Comm::OK) {
952 debugs(26, 4, HERE << conn << ", comm failure recovery.");
953 /* At this point only the TCP handshake has failed. no data has been passed.
954 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
955 */
956 debugs(26, 4, "removing server 1 of " << tunnelState->serverDestinations.size() <<
957 " from destinations (" << tunnelState->serverDestinations[0] << ")");
958 tunnelState->serverDestinations.erase(tunnelState->serverDestinations.begin());
959 time_t fwdTimeout = tunnelState->started + Config.Timeout.forward;
960 if (fwdTimeout > squid_curtime && tunnelState->serverDestinations.size() > 0) {
961 // find remaining forward_timeout available for this attempt
962 fwdTimeout -= squid_curtime;
963 if (fwdTimeout > Config.Timeout.connect)
964 fwdTimeout = Config.Timeout.connect;
965 /* Try another IP of this destination host */
966 GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
967 debugs(26, 4, HERE << "retry with : " << tunnelState->serverDestinations[0]);
968 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
969 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, fwdTimeout);
970 cs->setHost(tunnelState->url);
971 AsyncJob::Start(cs);
972 } else {
973 debugs(26, 4, HERE << "terminate with error.");
974 ErrorState *err = new ErrorState(ERR_CONNECT_FAIL, Http::scServiceUnavailable, tunnelState->request.getRaw());
975 *tunnelState->status_ptr = Http::scServiceUnavailable;
976 err->xerrno = xerrno;
977 // on timeout is this still: err->xerrno = ETIMEDOUT;
978 err->port = conn->remote.port();
979 err->callback = tunnelErrorComplete;
980 err->callback_data = tunnelState;
981 errorSend(tunnelState->client.conn, err);
982 if (tunnelState->request != NULL)
983 tunnelState->request->hier.stopPeerClock(false);
984 }
985 return;
986 }
987
988 #if USE_DELAY_POOLS
989 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
990 if (conn->getPeer() && conn->getPeer()->options.no_delay)
991 tunnelState->server.setDelayId(DelayId());
992 #endif
993
994 tunnelState->request->hier.note(conn, tunnelState->getHost());
995
996 tunnelState->server.conn = conn;
997 tunnelState->request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
998 comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
999
1000 debugs(26, 4, HERE << "determine post-connect handling pathway.");
1001 if (conn->getPeer()) {
1002 tunnelState->request->peer_login = conn->getPeer()->login;
1003 tunnelState->request->peer_domain = conn->getPeer()->domain;
1004 tunnelState->request->flags.proxying = !(conn->getPeer()->options.originserver);
1005 } else {
1006 tunnelState->request->peer_login = NULL;
1007 tunnelState->request->peer_domain = NULL;
1008 tunnelState->request->flags.proxying = false;
1009 }
1010
1011 if (tunnelState->request->flags.proxying)
1012 tunnelState->connectToPeer();
1013 else {
1014 tunnelConnected(conn, tunnelState);
1015 }
1016
1017 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1018 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1019 commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
1020 }
1021
1022 void
1023 tunnelStart(ClientHttpRequest * http)
1024 {
1025 debugs(26, 3, HERE);
1026 /* Create state structure. */
1027 TunnelStateData *tunnelState = NULL;
1028 ErrorState *err = NULL;
1029 HttpRequest *request = http->request;
1030 char *url = http->uri;
1031
1032 /*
1033 * client_addr.isNoAddr() indicates this is an "internal" request
1034 * from peer_digest.c, asn.c, netdb.c, etc and should always
1035 * be allowed. yuck, I know.
1036 */
1037
1038 if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
1039 /*
1040 * Check if this host is allowed to fetch MISSES from us (miss_access)
1041 * default is to allow.
1042 */
1043 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
1044 ch.src_addr = request->client_addr;
1045 ch.my_addr = request->my_addr;
1046 if (ch.fastCheck() == ACCESS_DENIED) {
1047 debugs(26, 4, HERE << "MISS access forbidden.");
1048 err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request);
1049 http->al->http.code = Http::scForbidden;
1050 errorSend(http->getConn()->clientConnection, err);
1051 return;
1052 }
1053 }
1054
1055 debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1056 ++statCounter.server.all.requests;
1057 ++statCounter.server.other.requests;
1058
1059 tunnelState = new TunnelStateData;
1060 #if USE_DELAY_POOLS
1061 tunnelState->server.setDelayId(DelayId::DelayClient(http));
1062 #endif
1063 tunnelState->url = xstrdup(url);
1064 tunnelState->request = request;
1065 tunnelState->server.size_ptr = &http->out.size;
1066 tunnelState->client.size_ptr = &http->al->http.clientRequestSz.payloadData;
1067 tunnelState->status_ptr = &http->al->http.code;
1068 tunnelState->logTag_ptr = &http->logType;
1069 tunnelState->client.conn = http->getConn()->clientConnection;
1070 tunnelState->http = http;
1071 tunnelState->al = http->al;
1072 //tunnelState->started is set in TunnelStateData ctor
1073
1074 comm_add_close_handler(tunnelState->client.conn->fd,
1075 tunnelClientClosed,
1076 tunnelState);
1077
1078 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1079 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1080 commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
1081
1082 peerSelect(&(tunnelState->serverDestinations), request, http->al,
1083 NULL,
1084 tunnelPeerSelectComplete,
1085 tunnelState);
1086 }
1087
1088 void
1089 TunnelStateData::connectToPeer()
1090 {
1091 #if USE_OPENSSL
1092 if (CachePeer *p = server.conn->getPeer()) {
1093 if (p->secure.encryptTransport) {
1094 AsyncCall::Pointer callback = asyncCall(5,4,
1095 "TunnelStateData::ConnectedToPeer",
1096 MyAnswerDialer(&TunnelStateData::connectedToPeer, this));
1097 Ssl::BlindPeerConnector *connector =
1098 new Ssl::BlindPeerConnector(request, server.conn, callback);
1099 AsyncJob::Start(connector); // will call our callback
1100 return;
1101 }
1102 }
1103 #endif
1104
1105 Security::EncryptorAnswer nil;
1106 connectedToPeer(nil);
1107 }
1108
1109 void
1110 TunnelStateData::connectedToPeer(Security::EncryptorAnswer &answer)
1111 {
1112 if (ErrorState *error = answer.error.get()) {
1113 *status_ptr = error->httpStatus;
1114 error->callback = tunnelErrorComplete;
1115 error->callback_data = this;
1116 errorSend(client.conn, error);
1117 answer.error.clear(); // preserve error for errorSendComplete()
1118 return;
1119 }
1120
1121 tunnelRelayConnectRequest(server.conn, this);
1122 }
1123
1124 static void
1125 tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
1126 {
1127 TunnelStateData *tunnelState = (TunnelStateData *)data;
1128 assert(!tunnelState->waitingForConnectExchange());
1129 HttpHeader hdr_out(hoRequest);
1130 HttpStateFlags flags;
1131 debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
1132 memset(&flags, '\0', sizeof(flags));
1133 flags.proxying = tunnelState->request->flags.proxying;
1134 MemBuf mb;
1135 mb.init();
1136 mb.appendf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
1137 HttpStateData::httpBuildRequestHeader(tunnelState->request.getRaw(),
1138 NULL, /* StoreEntry */
1139 tunnelState->al, /* AccessLogEntry */
1140 &hdr_out,
1141 flags); /* flags */
1142 hdr_out.packInto(&mb);
1143 hdr_out.clean();
1144 mb.append("\r\n", 2);
1145
1146 debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn <<
1147 ":\n----------\n" << mb.buf << "\n----------");
1148
1149 AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone",
1150 CommIoCbPtrFun(tunnelConnectReqWriteDone,
1151 tunnelState));
1152
1153 tunnelState->server.write(mb.buf, mb.size, writeCall, mb.freeFunc());
1154 tunnelState->connectReqWriting = true;
1155
1156 tunnelState->connectRespBuf = new MemBuf;
1157 // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1158 // can hold since any CONNECT response leftovers have to fit into server.buf.
1159 // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space.
1160 tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF);
1161 tunnelState->readConnectResponse();
1162
1163 assert(tunnelState->waitingForConnectExchange());
1164
1165 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1166 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1167 commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
1168 }
1169
1170 static void
1171 tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, ErrorState *err, void *data)
1172 {
1173 TunnelStateData *tunnelState = (TunnelStateData *)data;
1174
1175 if (peer_paths == NULL || peer_paths->size() < 1) {
1176 debugs(26, 3, HERE << "No paths found. Aborting CONNECT");
1177 if (!err) {
1178 err = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, tunnelState->request.getRaw());
1179 }
1180 *tunnelState->status_ptr = err->httpStatus;
1181 err->callback = tunnelErrorComplete;
1182 err->callback_data = tunnelState;
1183 errorSend(tunnelState->client.conn, err);
1184 return;
1185 }
1186 delete err;
1187
1188 GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
1189
1190 if (tunnelState->request != NULL)
1191 tunnelState->request->hier.startPeerClock();
1192
1193 debugs(26, 3, HERE << "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
1194 tunnelState->serverDestinations[0] << "}");
1195
1196 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
1197 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
1198 cs->setHost(tunnelState->url);
1199 AsyncJob::Start(cs);
1200 }
1201
1202 CBDATA_CLASS_INIT(TunnelStateData);
1203
1204 bool
1205 TunnelStateData::noConnections() const
1206 {
1207 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
1208 }
1209
1210 #if USE_DELAY_POOLS
1211 void
1212 TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
1213 {
1214 delayId = newDelay;
1215 }
1216
1217 #endif
1218
1219 #if USE_OPENSSL
1220 void
1221 switchToTunnel(HttpRequest *request, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn)
1222 {
1223 debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1224 /* Create state structure. */
1225 TunnelStateData *tunnelState = NULL;
1226 const SBuf url(request->effectiveRequestUri());
1227
1228 debugs(26, 3, request->method << " " << url << " " << request->http_ver);
1229 ++statCounter.server.all.requests;
1230 ++statCounter.server.other.requests;
1231
1232 tunnelState = new TunnelStateData;
1233 tunnelState->url = SBufToCstring(url);
1234 tunnelState->request = request;
1235 tunnelState->server.size_ptr = NULL; //Set later if ClientSocketContext is available
1236
1237 // Temporary static variable to store the unneeded for our case status code
1238 static int status_code = 0;
1239 tunnelState->status_ptr = &status_code;
1240 tunnelState->client.conn = clientConn;
1241
1242 ConnStateData *conn;
1243 if ((conn = request->clientConnectionManager.get())) {
1244 ClientSocketContext::Pointer context = conn->pipeline.front();
1245 if (context != nullptr && context->http != nullptr) {
1246 tunnelState->logTag_ptr = &context->http->logType;
1247 tunnelState->server.size_ptr = &context->http->out.size;
1248
1249 #if USE_DELAY_POOLS
1250 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1251 if (srvConn->getPeer() && srvConn->getPeer()->options.no_delay)
1252 tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1253 #endif
1254 }
1255 }
1256
1257 comm_add_close_handler(tunnelState->client.conn->fd,
1258 tunnelClientClosed,
1259 tunnelState);
1260
1261 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1262 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1263 commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
1264 fd_table[clientConn->fd].read_method = &default_read_method;
1265 fd_table[clientConn->fd].write_method = &default_write_method;
1266
1267 tunnelState->request->hier.note(srvConn, tunnelState->getHost());
1268
1269 tunnelState->server.conn = srvConn;
1270 tunnelState->request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : NULL;
1271 comm_add_close_handler(srvConn->fd, tunnelServerClosed, tunnelState);
1272
1273 debugs(26, 4, "determine post-connect handling pathway.");
1274 if (srvConn->getPeer()) {
1275 tunnelState->request->peer_login = srvConn->getPeer()->login;
1276 tunnelState->request->peer_domain = srvConn->getPeer()->domain;
1277 tunnelState->request->flags.proxying = !(srvConn->getPeer()->options.originserver);
1278 } else {
1279 tunnelState->request->peer_login = NULL;
1280 tunnelState->request->peer_domain = NULL;
1281 tunnelState->request->flags.proxying = false;
1282 }
1283
1284 timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1285 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1286 commSetConnTimeout(srvConn, Config.Timeout.read, timeoutCall);
1287 fd_table[srvConn->fd].read_method = &default_read_method;
1288 fd_table[srvConn->fd].write_method = &default_write_method;
1289
1290 auto ssl = fd_table[srvConn->fd].ssl;
1291 assert(ssl);
1292 BIO *b = SSL_get_rbio(ssl);
1293 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
1294 const MemBuf &buf = srvBio->rBufData();
1295
1296 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1297 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
1298 tunnelState->client.write(buf.content(), buf.contentSize(), call, NULL);
1299 }
1300 #endif //USE_OPENSSL
1301