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