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