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