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