]>
Commit | Line | Data |
---|---|---|
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 | 53 | class TunnelStateData |
62e76326 | 54 | { |
a46d2c0e | 55 | |
56 | public: | |
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 | ||
112 | private: | |
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 | 121 | static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n"; |
983061ed | 122 | |
11007d4b | 123 | static CNCB tunnelConnectDone; |
124 | static ERCB tunnelErrorComplete; | |
125 | static PF tunnelServerClosed; | |
126 | static PF tunnelClientClosed; | |
127 | static PF tunnelTimeout; | |
128 | static PSC tunnelPeerSelectComplete; | |
fa34dd97 | 129 | static void tunnelStateFree(TunnelStateData * tunnelState); |
fb046c1b AJ |
130 | static void tunnelConnected(Comm::ConnectionPointer &server, void *); |
131 | static void tunnelRelayConnectRequest(Comm::ConnectionPointer &server, void *); | |
30a4f2a8 | 132 | |
b8d8561b | 133 | static void |
11007d4b | 134 | tunnelServerClosed(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 | 151 | static void |
11007d4b | 152 | tunnelClientClosed(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 | 169 | static void |
fa34dd97 | 170 | tunnelStateFree(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 | 181 | TunnelStateData::Connection::~Connection() |
a46d2c0e | 182 | { |
cfd66529 | 183 | safe_free(buf); |
a46d2c0e | 184 | } |
185 | ||
186 | int | |
fa34dd97 | 187 | TunnelStateData::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 | 197 | void |
fa34dd97 | 198 | TunnelStateData::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 | 207 | int |
fa34dd97 | 208 | TunnelStateData::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 | 224 | void |
fa34dd97 | 225 | TunnelStateData::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 | 234 | void |
fa34dd97 | 235 | TunnelStateData::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 | ||
256 | void | |
fa34dd97 | 257 | TunnelStateData::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 | 270 | void |
fa34dd97 | 271 | TunnelStateData::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 | 279 | void |
fa34dd97 | 280 | TunnelStateData::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 | 300 | void |
60dafd5e | 301 | TunnelStateData::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 | 329 | void |
fa34dd97 | 330 | TunnelStateData::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 | 339 | void |
fa34dd97 | 340 | TunnelStateData::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 | 379 | void |
fa34dd97 | 380 | TunnelStateData::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 | ||
389 | void | |
fa34dd97 | 390 | TunnelStateData::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 | ||
400 | void | |
fa34dd97 | 401 | TunnelStateData::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 | 438 | static void |
11007d4b | 439 | tunnelTimeout(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 | 451 | void |
fa34dd97 | 452 | TunnelStateData::Connection::closeIfOpen() |
a46d2c0e | 453 | { |
97c81191 | 454 | if (Comm::IsConnOpen(conn)) |
fb046c1b | 455 | conn->close(); |
a46d2c0e | 456 | } |
457 | ||
458 | void | |
fa34dd97 | 459 | TunnelStateData::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 | 465 | static void |
11007d4b | 466 | tunnelConnectedWriteDone(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 | 481 | static void |
fb046c1b | 482 | tunnelConnected(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 | 491 | static void |
11007d4b | 492 | tunnelErrorComplete(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 | 509 | static void |
aed188fd | 510 | tunnelConnectDone(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 | 577 | void |
47f6e231 | 578 | tunnelStart(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 | 639 | static void |
fb046c1b | 640 | tunnelRelayConnectRequest(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 | 667 | static void |
00ae51e4 | 668 | tunnelPeerSelectComplete(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 | 688 | CBDATA_CLASS_INIT(TunnelStateData); |
a46d2c0e | 689 | |
690 | void * | |
fa34dd97 | 691 | TunnelStateData::operator new (size_t) |
a46d2c0e | 692 | { |
fa34dd97 | 693 | CBDATA_INIT_TYPE(TunnelStateData); |
694 | TunnelStateData *result = cbdataAlloc(TunnelStateData); | |
a46d2c0e | 695 | return result; |
696 | } | |
697 | ||
698 | void | |
fa34dd97 | 699 | TunnelStateData::operator delete (void *address) |
a46d2c0e | 700 | { |
fa34dd97 | 701 | TunnelStateData *t = static_cast<TunnelStateData *>(address); |
a46d2c0e | 702 | cbdataFree(t); |
703 | } | |
704 | ||
a46d2c0e | 705 | bool |
fa34dd97 | 706 | TunnelStateData::noConnections() const |
a46d2c0e | 707 | { |
97c81191 | 708 | return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn); |
a46d2c0e | 709 | } |
710 | ||
711 | #if DELAY_POOLS | |
712 | void | |
fa34dd97 | 713 | TunnelStateData::Connection::setDelayId(DelayId const &newDelay) |
a46d2c0e | 714 | { |
715 | delayId = newDelay; | |
716 | } | |
717 | ||
718 | #endif |