]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tunnel.cc
Clarified some comments in HttpHeaderFieldStat
[thirdparty/squid.git] / src / tunnel.cc
CommitLineData
95d659f0 1
983061ed 2/*
30a4f2a8 3 * DEBUG: section 26 Secure Sockets Layer Proxy
4 * AUTHOR: Duane Wessels
5 *
2b6662ba 6 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 7 * ----------------------------------------------------------
30a4f2a8 8 *
2b6662ba 9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
30a4f2a8 17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
26ac0430 22 *
30a4f2a8 23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
26ac0430 27 *
30a4f2a8 28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
cbdec147 30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 31 *
983061ed 32 */
983061ed 33
582c2af2 34#include "squid.h"
a011edee 35#include "acl/FilledChecklist.h"
cfd66529 36#include "Array.h"
a011edee
FC
37#include "CachePeer.h"
38#include "client_side_request.h"
39#include "client_side.h"
9f518b4a 40#include "comm.h"
cfd66529 41#include "comm/Connection.h"
aed188fd 42#include "comm/ConnOpener.h"
ec41b64c 43#include "comm/Write.h"
a011edee
FC
44#include "errorpage.h"
45#include "fde.h"
e5ee81f0 46#include "http.h"
a011edee
FC
47#include "HttpRequest.h"
48#include "MemBuf.h"
cfd66529 49#include "PeerSelectState.h"
4d5904f7 50#include "SquidConfig.h"
e4f1fdae 51#include "StatCounters.h"
4e540555 52#include "tools.h"
582c2af2
FC
53#if USE_DELAY_POOLS
54#include "DelayId.h"
55#endif
56
57#if HAVE_LIMITS_H
58#include <limits.h>
59#endif
21d845b1
FC
60#if HAVE_ERRNO_H
61#include <errno.h>
62#endif
582c2af2 63
fa34dd97 64class TunnelStateData
62e76326 65{
a46d2c0e 66
67public:
68
69 class Connection;
70 void *operator new(size_t);
71 void operator delete (void *);
e0d28505
AJ
72 static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
73 static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
74 static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
75 static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
a46d2c0e 76
77 bool noConnections() const;
983061ed 78 char *url;
190154cf 79 HttpRequest *request;
00ae51e4 80 Comm::ConnectionList serverDestinations;
62e76326 81
fb046c1b
AJ
82 const char * getHost() const {
83 return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->GetHost());
84 };
85
a46d2c0e 86 class Connection
62e76326 87 {
a46d2c0e 88
89 public:
8a467c4b 90 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL) {}
a46d2c0e 91
8a467c4b
AJ
92 ~Connection();
93
94 int bytesWanted(int lower=0, int upper = INT_MAX) const;
a46d2c0e 95 void bytesIn(int const &);
9a0a18de 96#if USE_DELAY_POOLS
a46d2c0e 97
98 void setDelayId(DelayId const &);
99#endif
100
101 void error(int const xerrno);
5c926411 102 int debugLevelForError(int const xerrno) const;
a46d2c0e 103 void closeIfOpen();
8a467c4b 104 void dataSent (size_t amount);
62e76326 105 int len;
8a467c4b 106 char *buf;
47f6e231 107 int64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
62e76326 108
fb046c1b 109 Comm::ConnectionPointer conn; ///< The currently connected connection.
fb046c1b 110
a46d2c0e 111 private:
9a0a18de 112#if USE_DELAY_POOLS
62e76326 113
a46d2c0e 114 DelayId delayId;
59715b38 115#endif
62e76326 116
a46d2c0e 117 };
118
119 Connection client, server;
120 int *status_ptr; /* pointer to status for logging */
121 void copyRead(Connection &from, IOCB *completion);
122
123private:
fa34dd97 124 CBDATA_CLASS(TunnelStateData);
8a467c4b 125 void copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *);
a46d2c0e 126 void readServer(char *buf, size_t len, comm_err_t errcode, int xerrno);
127 void readClient(char *buf, size_t len, comm_err_t errcode, int xerrno);
128 void writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno);
129 void writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno);
130};
983061ed 131
3c4fcf0f 132static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
983061ed 133
11007d4b 134static CNCB tunnelConnectDone;
135static ERCB tunnelErrorComplete;
575d05c4
AJ
136static CLCB tunnelServerClosed;
137static CLCB tunnelClientClosed;
8d77a37c 138static CTCB tunnelTimeout;
11007d4b 139static PSC tunnelPeerSelectComplete;
fa34dd97 140static void tunnelStateFree(TunnelStateData * tunnelState);
f01d4b80
AJ
141static void tunnelConnected(const Comm::ConnectionPointer &server, void *);
142static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *);
30a4f2a8 143
b8d8561b 144static void
575d05c4 145tunnelServerClosed(const CommCloseCbParams &params)
30a4f2a8 146{
575d05c4
AJ
147 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
148 debugs(26, 3, HERE << tunnelState->server.conn);
fb046c1b 149 tunnelState->server.conn = NULL;
62e76326 150
71a2ced6 151 if (tunnelState->noConnections()) {
11007d4b 152 tunnelStateFree(tunnelState);
26ac0430 153 return;
71a2ced6 154 }
26ac0430 155
71a2ced6 156 if (!tunnelState->server.len) {
fb046c1b 157 tunnelState->client.conn->close();
26ac0430 158 return;
71a2ced6 159 }
30a4f2a8 160}
161
b177367b 162static void
575d05c4 163tunnelClientClosed(const CommCloseCbParams &params)
30a4f2a8 164{
575d05c4
AJ
165 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
166 debugs(26, 3, HERE << tunnelState->client.conn);
fb046c1b 167 tunnelState->client.conn = NULL;
62e76326 168
71a2ced6 169 if (tunnelState->noConnections()) {
11007d4b 170 tunnelStateFree(tunnelState);
26ac0430 171 return;
71a2ced6 172 }
26ac0430 173
71a2ced6 174 if (!tunnelState->client.len) {
fb046c1b 175 tunnelState->server.conn->close();
26ac0430 176 return;
71a2ced6 177 }
30a4f2a8 178}
983061ed 179
b177367b 180static void
fa34dd97 181tunnelStateFree(TunnelStateData * tunnelState)
983061ed 182{
fd54d9b2 183 debugs(26, 3, HERE << "tunnelState=" << tunnelState);
11007d4b 184 assert(tunnelState != NULL);
185 assert(tunnelState->noConnections());
186 safe_free(tunnelState->url);
00ae51e4 187 tunnelState->serverDestinations.clean();
11007d4b 188 HTTPMSGUNLOCK(tunnelState->request);
189 delete tunnelState;
983061ed 190}
191
8a467c4b
AJ
192TunnelStateData::Connection::~Connection()
193{
194 safe_free(buf);
195}
196
a46d2c0e 197int
8a467c4b 198TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
447e176b 199{
9a0a18de 200#if USE_DELAY_POOLS
8a467c4b 201 return delayId.bytesWanted(lowerbound, upperbound);
a46d2c0e 202#else
8a467c4b
AJ
203
204 return upperbound;
a46d2c0e 205#endif
206}
62e76326 207
a46d2c0e 208void
fa34dd97 209TunnelStateData::Connection::bytesIn(int const &count)
a46d2c0e 210{
fd54d9b2 211 debugs(26, 3, HERE << "len=" << len << " + count=" << count);
9a0a18de 212#if USE_DELAY_POOLS
a46d2c0e 213 delayId.bytesIn(count);
214#endif
62e76326 215
a46d2c0e 216 len += count;
447e176b 217}
62e76326 218
a46d2c0e 219int
fa34dd97 220TunnelStateData::Connection::debugLevelForError(int const xerrno) const
a46d2c0e 221{
222#ifdef ECONNRESET
223
224 if (xerrno == ECONNRESET)
225 return 2;
226
447e176b 227#endif
228
a46d2c0e 229 if (ignoreErrno(xerrno))
230 return 3;
231
232 return 1;
233}
adb78bd4 234
983061ed 235/* Read from server side and queue it for writing to the client */
a46d2c0e 236void
fd54d9b2 237TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 238{
fa34dd97 239 TunnelStateData *tunnelState = (TunnelStateData *)data;
e0d28505 240 assert(cbdataReferenceValid(tunnelState));
fd54d9b2 241 debugs(26, 3, HERE << c);
c4b7a5a9 242
11007d4b 243 tunnelState->readServer(buf, len, errcode, xerrno);
a46d2c0e 244}
62e76326 245
a46d2c0e 246void
fa34dd97 247TunnelStateData::readServer(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 248{
fd54d9b2 249 debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
d01053a2 250
a46d2c0e 251 /*
252 * Bail out early on COMM_ERR_CLOSING
26ac0430 253 * - close handlers will tidy up for us
a46d2c0e 254 */
a55f4cea 255
a46d2c0e 256 if (errcode == COMM_ERR_CLOSING)
257 return;
62e76326 258
ee1679df 259 if (len > 0) {
a46d2c0e 260 server.bytesIn(len);
e4f1fdae
FC
261 kb_incr(&(statCounter.server.all.kbytes_in), len);
262 kb_incr(&(statCounter.server.other.kbytes_in), len);
ee1679df 263 }
62e76326 264
8a467c4b 265 copy (len, errcode, xerrno, server, client, WriteClientDone);
a46d2c0e 266}
267
268void
fa34dd97 269TunnelStateData::Connection::error(int const xerrno)
a46d2c0e 270{
271 /* XXX fixme xstrerror and xerrno... */
272 errno = xerrno;
273
e0d28505 274 debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerror());
62e76326 275
a46d2c0e 276 if (!ignoreErrno(xerrno))
fb046c1b 277 conn->close();
983061ed 278}
279
280/* Read from client side and queue it for writing to the server */
a46d2c0e 281void
e0d28505 282TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 283{
fa34dd97 284 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 285 assert (cbdataReferenceValid (tunnelState));
62e76326 286
11007d4b 287 tunnelState->readClient(buf, len, errcode, xerrno);
a46d2c0e 288}
62e76326 289
a46d2c0e 290void
fa34dd97 291TunnelStateData::readClient(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 292{
fd54d9b2 293 debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
d01053a2 294
a46d2c0e 295 /*
296 * Bail out early on COMM_ERR_CLOSING
26ac0430 297 * - close handlers will tidy up for us
a46d2c0e 298 */
a55f4cea 299
a46d2c0e 300 if (errcode == COMM_ERR_CLOSING)
301 return;
a55f4cea 302
a46d2c0e 303 if (len > 0) {
304 client.bytesIn(len);
e4f1fdae 305 kb_incr(&(statCounter.client_http.kbytes_in), len);
a46d2c0e 306 }
62e76326 307
8a467c4b 308 copy (len, errcode, xerrno, client, server, WriteServerDone);
a46d2c0e 309}
62e76326 310
a46d2c0e 311void
8a467c4b 312TunnelStateData::copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *completion)
a46d2c0e 313{
fd54d9b2
AJ
314 debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
315
a46d2c0e 316 /* I think this is to prevent free-while-in-a-callback behaviour
26ac0430 317 * - RBC 20030229
fb046c1b 318 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
a46d2c0e 319 */
320 cbdataInternalLock(this); /* ??? should be locked by the caller... */
62e76326 321
60dafd5e 322 /* Bump the source connection read timeout on any activity */
8d77a37c
AJ
323 if (Comm::IsConnOpen(from.conn)) {
324 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 325 CommTimeoutCbPtrFun(tunnelTimeout, this));
8d77a37c
AJ
326 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
327 }
99c02c10 328
58c0b17d 329 if (errcode)
a46d2c0e 330 from.error (xerrno);
60dafd5e 331 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
fd54d9b2 332 debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
fb046c1b 333 from.conn->close();
62e76326 334
60dafd5e 335 /* Only close the remote end if we've finished queueing data to it */
97c81191 336 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
fb046c1b 337 to.conn->close();
c4b7a5a9 338 }
ec41b64c 339 } else if (cbdataReferenceValid(this)) {
fd54d9b2 340 debugs(26, 3, HERE << "Schedule Write");
8a467c4b
AJ
341 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
342 CommIoCbPtrFun(completion, this));
343 Comm::Write(to.conn, from.buf, len, call, NULL);
ec41b64c 344 }
a55f4cea 345
a46d2c0e 346 cbdataInternalUnlock(this); /* ??? */
983061ed 347}
348
349/* Writes data from the client buffer to the server side */
a46d2c0e 350void
e0d28505 351TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 352{
fa34dd97 353 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 354 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 355
11007d4b 356 tunnelState->writeServerDone(buf, len, flag, xerrno);
a46d2c0e 357}
a55f4cea 358
a46d2c0e 359void
fa34dd97 360TunnelStateData::writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 361{
fd54d9b2 362 debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
62e76326 363
5dacdf3f 364 /* Error? */
58c0b17d 365 if (flag != COMM_OK) {
fd54d9b2
AJ
366 if (flag != COMM_ERR_CLOSING) {
367 debugs(26, 4, HERE << "calling TunnelStateData::server.error(" << xerrno <<")");
58c0b17d 368 server.error(xerrno); // may call comm_close
fd54d9b2 369 }
5dacdf3f 370 return;
c4b7a5a9 371 }
62e76326 372
5dacdf3f 373 /* EOF? */
a46d2c0e 374 if (len == 0) {
fd54d9b2 375 debugs(26, 4, HERE << "No read input. Closing server connection.");
fb046c1b 376 server.conn->close();
a46d2c0e 377 return;
378 }
62e76326 379
5dacdf3f 380 /* Valid data */
e4f1fdae
FC
381 kb_incr(&(statCounter.server.all.kbytes_out), len);
382 kb_incr(&(statCounter.server.other.kbytes_out), len);
5dacdf3f 383 client.dataSent(len);
384
a46d2c0e 385 /* If the other end has closed, so should we */
97c81191 386 if (!Comm::IsConnOpen(client.conn)) {
fd54d9b2 387 debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
fb046c1b 388 server.conn->close();
a55f4cea 389 return;
c4b7a5a9 390 }
62e76326 391
a46d2c0e 392 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a46d2c0e 393
5dacdf3f 394 if (cbdataReferenceValid(this))
a46d2c0e 395 copyRead(client, ReadClient);
396
397 cbdataInternalUnlock(this); /* ??? */
983061ed 398}
399
400/* Writes data from the server buffer to the client side */
a46d2c0e 401void
e0d28505 402TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 403{
fa34dd97 404 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 405 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 406
11007d4b 407 tunnelState->writeClientDone(buf, len, flag, xerrno);
a46d2c0e 408}
409
410void
e0d28505 411TunnelStateData::Connection::dataSent(size_t amount)
a46d2c0e 412{
fd54d9b2 413 debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
a46d2c0e 414 assert(amount == (size_t)len);
415 len =0;
416 /* increment total object size */
417
418 if (size_ptr)
419 *size_ptr += amount;
420}
421
422void
fa34dd97 423TunnelStateData::writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 424{
fd54d9b2 425 debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
62e76326 426
5dacdf3f 427 /* Error? */
58c0b17d 428 if (flag != COMM_OK) {
fd54d9b2
AJ
429 if (flag != COMM_ERR_CLOSING) {
430 debugs(26, 4, HERE << "Closing client connection due to comm flags.");
58c0b17d 431 client.error(xerrno); // may call comm_close
fd54d9b2 432 }
5dacdf3f 433 return;
c4b7a5a9 434 }
62e76326 435
5dacdf3f 436 /* EOF? */
a46d2c0e 437 if (len == 0) {
fd54d9b2 438 debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
fb046c1b 439 client.conn->close();
62e76326 440 return;
983061ed 441 }
62e76326 442
5dacdf3f 443 /* Valid data */
e4f1fdae 444 kb_incr(&(statCounter.client_http.kbytes_out), len);
5dacdf3f 445 server.dataSent(len);
446
a46d2c0e 447 /* If the other end has closed, so should we */
97c81191 448 if (!Comm::IsConnOpen(server.conn)) {
fd54d9b2 449 debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
fb046c1b 450 client.conn->close();
a55f4cea 451 return;
983061ed 452 }
62e76326 453
a46d2c0e 454 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a55f4cea 455
5dacdf3f 456 if (cbdataReferenceValid(this))
a46d2c0e 457 copyRead(server, ReadServer);
2c202d66 458
a46d2c0e 459 cbdataInternalUnlock(this); /* ??? */
983061ed 460}
461
b8d8561b 462static void
8d77a37c 463tunnelTimeout(const CommTimeoutCbParams &io)
983061ed 464{
8d77a37c
AJ
465 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
466 debugs(26, 3, HERE << io.conn);
11007d4b 467 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
468 cbdataInternalLock(tunnelState);
a55f4cea 469
11007d4b 470 tunnelState->client.closeIfOpen();
471 tunnelState->server.closeIfOpen();
472 cbdataInternalUnlock(tunnelState);
a46d2c0e 473}
62e76326 474
a46d2c0e 475void
fa34dd97 476TunnelStateData::Connection::closeIfOpen()
a46d2c0e 477{
97c81191 478 if (Comm::IsConnOpen(conn))
fb046c1b 479 conn->close();
a46d2c0e 480}
481
482void
fa34dd97 483TunnelStateData::copyRead(Connection &from, IOCB *completion)
a46d2c0e 484{
485 assert(from.len == 0);
fd54d9b2 486 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
abd8f140 487 CommIoCbPtrFun(completion, this));
8a467c4b 488 comm_read(from.conn, from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), call);
983061ed 489}
490
379e8c1c 491/**
87f237a9 492 * Set the HTTP status for this request and sets the read handlers for client
379e8c1c
AR
493 * and server side connections.
494 */
495static void
496tunnelStartShoveling(TunnelStateData *tunnelState)
497{
498 *tunnelState->status_ptr = HTTP_OK;
499 if (cbdataReferenceValid(tunnelState)) {
500 tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
501 tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
502 }
503}
504
b0388924
AJ
505/**
506 * All the pieces we need to write to client and/or server connection
1b76e6c1 507 * have been written.
379e8c1c 508 * Call the tunnelStartShoveling to start the blind pump.
b0388924 509 */
c4b7a5a9 510static void
e0d28505 511tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
c4b7a5a9 512{
fa34dd97 513 TunnelStateData *tunnelState = (TunnelStateData *)data;
fd54d9b2 514 debugs(26, 3, HERE << conn << ", flag=" << flag);
62e76326 515
516 if (flag != COMM_OK) {
1b76e6c1 517 *tunnelState->status_ptr = HTTP_INTERNAL_SERVER_ERROR;
e0d28505 518 tunnelErrorComplete(conn->fd, data, 0);
62e76326 519 return;
520 }
521
379e8c1c 522 tunnelStartShoveling(tunnelState);
c4b7a5a9 523}
524
c4b7a5a9 525/*
1b76e6c1 526 * handle the write completion from a proxy request to an upstream origin
c4b7a5a9 527 */
b8d8561b 528static void
f01d4b80 529tunnelConnected(const Comm::ConnectionPointer &server, void *data)
983061ed 530{
fa34dd97 531 TunnelStateData *tunnelState = (TunnelStateData *)data;
f01d4b80 532 debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
379e8c1c 533
b58b5f77 534 if (tunnelState->request && (tunnelState->request->flags.spoofClientIp() || tunnelState->request->flags.intercepted()))
379e8c1c
AR
535 tunnelStartShoveling(tunnelState); // ssl-bumped connection, be quiet
536 else {
537 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
538 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
539 Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL);
540 }
983061ed 541}
542
b8d8561b 543static void
fd54d9b2 544tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
30a4f2a8 545{
fa34dd97 546 TunnelStateData *tunnelState = (TunnelStateData *)data;
fd54d9b2 547 debugs(26, 3, HERE << "FD " << fd);
11007d4b 548 assert(tunnelState != NULL);
549 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
550 cbdataInternalLock(tunnelState);
62e76326 551
97c81191 552 if (Comm::IsConnOpen(tunnelState->client.conn))
fb046c1b 553 tunnelState->client.conn->close();
62e76326 554
97c81191 555 if (Comm::IsConnOpen(tunnelState->server.conn))
fb046c1b 556 tunnelState->server.conn->close();
380963c2 557
11007d4b 558 cbdataInternalUnlock(tunnelState);
30a4f2a8 559}
560
b8d8561b 561static void
f01d4b80 562tunnelConnectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
983061ed 563{
fa34dd97 564 TunnelStateData *tunnelState = (TunnelStateData *)data;
cfd66529
AJ
565
566 if (status != COMM_OK) {
fd54d9b2 567 debugs(26, 4, HERE << conn << ", comm failure recovery.");
aed188fd
AJ
568 /* At this point only the TCP handshake has failed. no data has been passed.
569 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
570 */
00ae51e4
AJ
571 tunnelState->serverDestinations.shift();
572 if (status != COMM_TIMEOUT && tunnelState->serverDestinations.size() > 0) {
aed188fd 573 /* Try another IP of this destination host */
fd54d9b2 574 debugs(26, 4, HERE << "retry with : " << tunnelState->serverDestinations[0]);
aed188fd 575 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
00ae51e4 576 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
aed188fd 577 cs->setHost(tunnelState->url);
855150a4 578 AsyncJob::Start(cs);
aed188fd 579 } else {
fd54d9b2 580 debugs(26, 4, HERE << "terminate with error.");
913524f0 581 ErrorState *err = new ErrorState(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, tunnelState->request);
aed188fd
AJ
582 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
583 err->xerrno = xerrno;
584 // on timeout is this still: err->xerrno = ETIMEDOUT;
585 err->port = conn->remote.GetPort();
586 err->callback = tunnelErrorComplete;
587 err->callback_data = tunnelState;
e0d28505 588 errorSend(tunnelState->client.conn, err);
aed188fd 589 }
cfd66529
AJ
590 return;
591 }
592
4beb4bab
AJ
593#if USE_DELAY_POOLS
594 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
595 if (conn->getPeer() && conn->getPeer()->options.no_delay)
596 tunnelState->server.setDelayId(DelayId());
597#endif
598
a14f38d0 599 tunnelState->request->hier.note(conn, tunnelState->getHost());
4beb4bab 600
fb046c1b 601 tunnelState->server.conn = conn;
4beb4bab 602 tunnelState->request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
fb046c1b 603 comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
cfd66529 604
fd54d9b2 605 debugs(26, 4, HERE << "determine post-connect handling pathway.");
739b352a
AJ
606 if (conn->getPeer()) {
607 tunnelState->request->peer_login = conn->getPeer()->login;
d60a166f
FC
608 if (conn->getPeer()->options.originserver)
609 tunnelState->request->flags.setProxying();
610 else
611 tunnelState->request->flags.clearProxying();
fe40a877 612 } else {
cfd66529 613 tunnelState->request->peer_login = NULL;
d60a166f 614 tunnelState->request->flags.clearProxying();
cfd66529 615 }
62e76326 616
d60a166f 617 if (tunnelState->request->flags.proxying())
fb046c1b 618 tunnelRelayConnectRequest(conn, tunnelState);
cfd66529 619 else {
fb046c1b 620 tunnelConnected(conn, tunnelState);
983061ed 621 }
cfd66529 622
8d77a37c 623 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 624 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
8d77a37c 625 commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
983061ed 626}
30a4f2a8 627
425de4c8
AJ
628extern tos_t GetTosToServer(HttpRequest * request);
629extern nfmark_t GetNfmarkToServer(HttpRequest * request);
630
770f051d 631void
47f6e231 632tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
30a4f2a8 633{
fd54d9b2 634 debugs(26, 3, HERE);
30a4f2a8 635 /* Create state structure. */
fa34dd97 636 TunnelStateData *tunnelState = NULL;
9b312a19 637 ErrorState *err = NULL;
190154cf 638 HttpRequest *request = http->request;
d5964d58 639 char *url = http->uri;
fb046c1b 640
f1003989 641 /*
cc192b50 642 * client_addr.IsNoAddr() indicates this is an "internal" request
a4b8110e 643 * from peer_digest.c, asn.c, netdb.c, etc and should always
644 * be allowed. yuck, I know.
645 */
62e76326 646
b8a25eaa 647 if (Config.accessList.miss && !request->client_addr.IsNoAddr()) {
62e76326 648 /*
649 * Check if this host is allowed to fetch MISSES from us (miss_access)
b50e327b 650 * default is to allow.
62e76326 651 */
c0941a6a 652 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
62e76326 653 ch.src_addr = request->client_addr;
654 ch.my_addr = request->my_addr;
2efeb0b7 655 if (ch.fastCheck() == ACCESS_DENIED) {
fd54d9b2 656 debugs(26, 4, HERE << "MISS access forbidden.");
913524f0 657 err = new ErrorState(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN, request);
62e76326 658 *status_ptr = HTTP_FORBIDDEN;
73c36fd9 659 errorSend(http->getConn()->clientConnection, err);
62e76326 660 return;
661 }
f1003989 662 }
62e76326 663
c9fd01b4 664 debugs(26, 3, HERE << "'" << RequestMethodStr(request->method) << " " << url << " " << request->http_ver << "'");
5db6bf73
FC
665 ++statCounter.server.all.requests;
666 ++statCounter.server.other.requests;
62e76326 667
fa34dd97 668 tunnelState = new TunnelStateData;
9a0a18de 669#if USE_DELAY_POOLS
11007d4b 670 tunnelState->server.setDelayId(DelayId::DelayClient(http));
59715b38 671#endif
11007d4b 672 tunnelState->url = xstrdup(url);
673 tunnelState->request = HTTPMSGLOCK(request);
674 tunnelState->server.size_ptr = size_ptr;
675 tunnelState->status_ptr = status_ptr;
73c36fd9 676 tunnelState->client.conn = http->getConn()->clientConnection;
fb046c1b
AJ
677
678 comm_add_close_handler(tunnelState->client.conn->fd,
11007d4b 679 tunnelClientClosed,
680 tunnelState);
8d77a37c
AJ
681
682 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 683 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
8d77a37c 684 commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
cfd66529 685
00ae51e4 686 peerSelect(&(tunnelState->serverDestinations), request,
62e76326 687 NULL,
11007d4b 688 tunnelPeerSelectComplete,
689 tunnelState);
30a4f2a8 690}
98ffb7e4 691
b8d8561b 692static void
b0388924 693tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
98ffb7e4 694{
fa34dd97 695 TunnelStateData *tunnelState = (TunnelStateData *)data;
75faaa7a 696 HttpHeader hdr_out(hoRequest);
e1e72f06 697 Packer p;
b4b5fd95 698 http_state_flags flags;
b0388924 699 debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
b4b5fd95 700 memset(&flags, '\0', sizeof(flags));
d60a166f 701 flags.proxying = tunnelState->request->flags.proxying();
032785bf 702 MemBuf mb;
2fe7eff9 703 mb.init();
3872be7c 704 mb.Printf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
11007d4b 705 HttpStateData::httpBuildRequestHeader(tunnelState->request,
e5ee81f0 706 NULL, /* StoreEntry */
4bf68cfa 707 NULL, /* AccessLogEntry */
e5ee81f0 708 &hdr_out,
709 flags); /* flags */
e1e72f06 710 packerToMemInit(&p, &mb);
a9925b40 711 hdr_out.packInto(&p);
519e0948 712 hdr_out.clean();
e1e72f06 713 packerClean(&p);
2fe7eff9 714 mb.append("\r\n", 2);
c4b7a5a9 715
8d77a37c 716 AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone",
dc49061a 717 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
8d77a37c
AJ
718 Comm::Write(srv, &mb, writeCall);
719
720 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 721 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
8d77a37c 722 commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
98ffb7e4 723}
33ea9fff 724
33ea9fff 725static void
a37fdd8a 726tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, ErrorState *err, void *data)
33ea9fff 727{
fa34dd97 728 TunnelStateData *tunnelState = (TunnelStateData *)data;
62e76326 729
cfd66529 730 if (peer_paths == NULL || peer_paths->size() < 1) {
fd54d9b2 731 debugs(26, 3, HERE << "No paths found. Aborting CONNECT");
a37fdd8a
AJ
732 if (!err) {
733 err = new ErrorState(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, tunnelState->request);
734 }
735 *tunnelState->status_ptr = err->httpStatus;
11007d4b 736 err->callback = tunnelErrorComplete;
737 err->callback_data = tunnelState;
e0d28505 738 errorSend(tunnelState->client.conn, err);
62e76326 739 return;
db1cd23c 740 }
a37fdd8a
AJ
741 delete err;
742
fd54d9b2
AJ
743 debugs(26, 3, HERE << "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
744 tunnelState->serverDestinations[0] << "}");
62e76326 745
cfd66529 746 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
00ae51e4 747 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
aed188fd 748 cs->setHost(tunnelState->url);
855150a4 749 AsyncJob::Start(cs);
33ea9fff 750}
a46d2c0e 751
fa34dd97 752CBDATA_CLASS_INIT(TunnelStateData);
a46d2c0e 753
754void *
fa34dd97 755TunnelStateData::operator new (size_t)
a46d2c0e 756{
fa34dd97 757 CBDATA_INIT_TYPE(TunnelStateData);
758 TunnelStateData *result = cbdataAlloc(TunnelStateData);
a46d2c0e 759 return result;
760}
761
762void
fa34dd97 763TunnelStateData::operator delete (void *address)
a46d2c0e 764{
fa34dd97 765 TunnelStateData *t = static_cast<TunnelStateData *>(address);
a46d2c0e 766 cbdataFree(t);
767}
768
a46d2c0e 769bool
fa34dd97 770TunnelStateData::noConnections() const
a46d2c0e 771{
97c81191 772 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
a46d2c0e 773}
774
9a0a18de 775#if USE_DELAY_POOLS
a46d2c0e 776void
fa34dd97 777TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
a46d2c0e 778{
779 delayId = newDelay;
780}
781
782#endif