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