tunnel.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 26 Secure Sockets Layer Proxy */
10
11#include "squid.h"
12#include "acl/FilledChecklist.h"
13#include "base/AsyncCallbacks.h"
14#include "base/CbcPointer.h"
15#include "base/JobWait.h"
16#include "base/Raw.h"
17#include "CachePeer.h"
18#include "cbdata.h"
19#include "client_side.h"
20#include "client_side_request.h"
22#include "comm.h"
23#include "comm/Connection.h"
24#include "comm/ConnOpener.h"
25#include "comm/Read.h"
26#include "comm/Write.h"
27#include "errorpage.h"
28#include "fd.h"
29#include "fde.h"
30#include "FwdState.h"
31#include "globals.h"
32#include "HappyConnOpener.h"
33#include "http.h"
34#include "http/StatusCode.h"
35#include "http/Stream.h"
36#include "HttpRequest.h"
37#include "icmp/net_db.h"
38#include "ip/QosConfig.h"
39#include "LogTags.h"
40#include "MemBuf.h"
41#include "neighbors.h"
42#include "PeerSelectState.h"
43#include "ResolvedPeers.h"
44#include "sbuf/SBuf.h"
46#include "SquidConfig.h"
47#include "StatCounters.h"
48#if USE_OPENSSL
49#include "ssl/bio.h"
50#include "ssl/ServerBump.h"
51#endif
52#include "tools.h"
53#include "tunnel.h"
54#if USE_DELAY_POOLS
55#include "DelayId.h"
56#endif
57
58#include <climits>
59#include <cerrno>
60
66/*
67 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
68 * of pre-formatted data. Then we can use that as the client side of the tunnel
69 * instead of re-implementing it here and occasionally getting the ConnStateData
70 * read/write state wrong.
71 *
72 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
73 */
75{
77
78public:
80 ~TunnelStateData() override;
81 TunnelStateData(const TunnelStateData &); // do not implement
82 TunnelStateData &operator =(const TunnelStateData &); // do not implement
83
84 class Connection;
85 static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
86 static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
87 static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
88 static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
89
90 bool noConnections() const;
92 void closeConnections();
93
94 char *url;
98
99 const char * getHost() const {
100 return (server.conn != nullptr && server.conn->getPeer() ? server.conn->getPeer()->host : request->url.host());
101 };
102
106
109 // If we are forcing a tunnel after receiving a client CONNECT, then we
110 // have already responded to that CONNECT before tunnel.cc started.
112 return false;
113#if USE_OPENSSL
114 // We are bumping and we had already send "OK CONNECTED"
116 return false;
117#endif
118 return !(request != nullptr &&
120 }
121
124 void startConnecting();
125 void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason);
126
129
131 {
132
133 public:
134 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(nullptr), delayedLoops(0),
135 dirty(false),
136 readPending(nullptr), readPendingFunc(nullptr) {}
137
138 ~Connection();
139
141 template <typename Method>
142 void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState);
143
145 void noteClosure();
146
147 int bytesWanted(int lower=0, int upper = INT_MAX) const;
148 void bytesIn(int const &);
149#if USE_DELAY_POOLS
150
151 void setDelayId(DelayId const &);
152#endif
153
154 void error(int const xerrno);
155 int debugLevelForError(int const xerrno) const;
156
157 void dataSent (size_t amount);
159 void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func);
160 int len;
161 char *buf;
163 uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
164
166 uint8_t delayedLoops;
167
168 bool dirty;
169
170 // XXX: make these an AsyncCall when event API can handle them
173
174#if USE_DELAY_POOLS
175
177#endif
178
179 private:
182 };
183
186
189 time_t startTime;
192
195
197
199 const char *banRetries;
200
201 // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
203
206
209
213
214 void copyRead(Connection &from, IOCB *completion);
215
219
220 /* PeerSelectionInitiator API */
222 void noteDestinationsEnd(ErrorState *selectionError) override;
223
224 void syncHierNote(const Comm::ConnectionPointer &server, const char *origin);
225
229
231 void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused);
232
233 void notifyConnOpener();
234
235 void saveError(ErrorState *finalError);
236 void sendError(ErrorState *finalError, const char *reason);
237
238private:
239 void usePinned();
240
243
247
248 template <typename StepStart>
249 void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep);
250
252 const char *checkRetry();
253
254 bool transporting() const;
255
256 // TODO: convert to unique_ptr
259
262
263 void deleteThis();
264
265 void cancelStep(const char *reason);
266
267 bool exhaustedTries() const;
268 void updateAttempts(int);
269
270public:
271 bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
272 void copy(size_t len, Connection &from, Connection &to, IOCB *);
273 void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
274 void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
275 void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
276 void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
277
278 void copyClientBytes();
279 void copyServerBytes();
280
282 void clientClosed();
283
285 void serverClosed();
286
289 void retryOrBail(const char *context);
290};
291
298
300static void
302{
303 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
304 tunnelState->serverClosed();
305}
306
307void
309{
311
312 retryOrBail(__FUNCTION__);
313}
314
316static void
318{
319 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
320 tunnelState->clientClosed();
321}
322
323void
325{
327
328 if (noConnections())
329 return deleteThis();
330
331 if (!server.writer)
332 server.conn->close();
333}
334
336void
338{
340 // ConnStateData pipeline should contain the CONNECT we are performing
341 // but it may be invalid already (bug 4392)
342 if (const auto h = http.valid()) {
343 if (const auto c = h->getConn())
344 if (const auto ctx = c->pipeline.front())
345 ctx->finished();
346 }
347 delete this;
348}
349
351 startTime(squid_curtime),
352 destinations(new ResolvedPeers()),
353 destinationsFound(false),
354 committedToServer(false),
355 n_tries(0),
356 banRetries(nullptr),
357 codeContext(CodeContext::Current())
358{
359 debugs(26, 3, "TunnelStateData constructed this=" << this);
362
363 assert(clientRequest);
364 url = xstrdup(clientRequest->uri);
365 request = clientRequest->request;
366 Must(request);
367 server.size_ptr = &clientRequest->out.size;
369 status_ptr = &clientRequest->al->http.code;
370 al = clientRequest->al;
371 http = clientRequest;
372
374
375 client.initConnection(clientRequest->getConn()->clientConnection, tunnelClientClosed, "tunnelClientClosed", this);
376
377 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
380}
381
383{
384 debugs(26, 3, "TunnelStateData destructed this=" << this);
386 xfree(url);
387 cancelStep("~TunnelStateData");
388 delete savedError;
389}
390
392{
393 if (readPending)
395
396 safe_free(buf);
397}
398
399const char *
401{
402 if (shutting_down)
403 return "shutting down";
404 if (exhaustedTries())
405 return "exhausted tries";
407 return "forwarding timeout";
408 if (banRetries)
409 return banRetries;
410 if (noConnections())
411 return "no connections";
412
413 // TODO: Use std::optional for peer_reply_status to avoid treating zero value specially.
415 return "received HTTP status code is not reforwardable";
416
417 // TODO: check pinned connections; see FwdState::pinnedCanRetry()
418 return nullptr;
419}
420
421void
423{
425
426 const auto *bailDescription = checkRetry();
427 if (!bailDescription) {
428 if (!destinations->empty())
429 return startConnecting(); // try connecting to another destination
430
431 if (subscribed) {
432 debugs(26, 4, "wait for more destinations to try");
433 return; // expect a noteDestination*() call
434 }
435
436 // fall through to bail
437 }
438
439 /* bail */
440
441 if (request)
442 request->hier.stopPeerClock(false);
443
444 // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
445 // Then, the remaining method code (below) should become the common part of
446 // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
447 if (!savedError)
449 const auto canSendError = Comm::IsConnOpen(client.conn) && !client.dirty &&
451 if (canSendError)
452 return sendError(savedError, bailDescription ? bailDescription : context);
454
455 if (noConnections())
456 return deleteThis();
457
458 // This is a "Comm::IsConnOpen(client.conn) but !canSendError" case.
459 // Closing the connection (after finishing writing) is the best we can do.
460 if (!client.writer)
461 client.conn->close();
462 // else writeClientDone() must notice a closed server and close the client
463}
464
465int
466TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
467{
468#if USE_DELAY_POOLS
469 return delayId.bytesWanted(lowerbound, upperbound);
470#else
471 (void)lowerbound;
472 return upperbound;
473#endif
474}
475
476void
478{
479 debugs(26, 3, "len=" << len << " + count=" << count);
480#if USE_DELAY_POOLS
481 delayId.bytesIn(count);
482#endif
483
484 len += count;
485}
486
489void
491{
493 al->hier.resetPeerNotes(conn, origin);
494}
495
497void
499{
500 Assure(n_tries <= newValue); // n_tries cannot decrease
501
502 // Squid probably creates at most one FwdState/TunnelStateData object per
503 // ALE, but, unlike an assignment would, this increment logic works even if
504 // Squid uses multiple such objects for a given ALE in some esoteric cases.
505 al->requestAttempts += (newValue - n_tries);
506
507 n_tries = newValue;
508 debugs(26, 5, n_tries);
509}
510
511int
513{
514#ifdef ECONNRESET
515
516 if (xerrno == ECONNRESET)
517 return 2;
518
519#endif
520
521 if (ignoreErrno(xerrno))
522 return 3;
523
524 return 1;
525}
526
527/* Read from server side and queue it for writing to the client */
528void
529TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
530{
531 TunnelStateData *tunnelState = (TunnelStateData *)data;
532 assert(cbdataReferenceValid(tunnelState));
533 debugs(26, 3, c);
534
535 tunnelState->readServer(buf, len, errcode, xerrno);
536}
537
538void
539TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
540{
541 debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
543
544 /*
545 * Bail out early on Comm::ERR_CLOSING
546 * - close handlers will tidy up for us
547 */
548
549 if (errcode == Comm::ERR_CLOSING)
550 return;
551
552 if (len > 0) {
553 server.bytesIn(len);
557 }
558
559 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
561}
562
563void
565{
566 debugs(50, debugLevelForError(xerrno), conn << ": read/write failure: " << xstrerr(xerrno));
567
568 if (!ignoreErrno(xerrno))
569 conn->close();
570}
571
572/* Read from client side and queue it for writing to the server */
573void
574TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
575{
576 TunnelStateData *tunnelState = (TunnelStateData *)data;
577 assert (cbdataReferenceValid (tunnelState));
578
579 tunnelState->readClient(buf, len, errcode, xerrno);
580}
581
582void
583TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
584{
585 debugs(26, 3, client.conn << ", read " << len << " bytes, err=" << errcode);
587
588 /*
589 * Bail out early on Comm::ERR_CLOSING
590 * - close handlers will tidy up for us
591 */
592
593 if (errcode == Comm::ERR_CLOSING)
594 return;
595
596 if (len > 0) {
597 client.bytesIn(len);
599 }
600
601 if (keepGoingAfterRead(len, errcode, xerrno, client, server))
603}
604
607bool
608TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
609{
610 debugs(26, 3, "from={" << from.conn << "}, to={" << to.conn << "}");
611
612 /* I think this is to prevent free-while-in-a-callback behaviour
613 * - RBC 20030229
614 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
615 */
616 const CbcPointer<TunnelStateData> safetyLock(this);
617
618 /* Bump the source connection read timeout on any activity */
619 if (Comm::IsConnOpen(from.conn)) {
620 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
622 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
623 }
624
625 /* Bump the dest connection read timeout on any activity */
626 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
627 if (Comm::IsConnOpen(to.conn)) {
628 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
630 commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
631 }
632
633 if (errcode)
634 from.error (xerrno);
635 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
636 debugs(26, 3, "Nothing to write or client gone. Terminate the tunnel.");
637 from.conn->close();
638
639 /* Only close the remote end if we've finished queueing data to it */
640 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
641 to.conn->close();
642 }
643 } else if (cbdataReferenceValid(this)) {
644 return true;
645 }
646
647 return false;
648}
649
650void
651TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
652{
653 debugs(26, 3, "Schedule Write");
654 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
655 CommIoCbPtrFun(completion, this));
656 to.write(from.buf, len, call, nullptr);
657}
658
659/* Writes data from the client buffer to the server side */
660void
661TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
662{
663 TunnelStateData *tunnelState = (TunnelStateData *)data;
664 assert (cbdataReferenceValid (tunnelState));
665 tunnelState->server.writer = nullptr;
666
667 tunnelState->writeServerDone(buf, len, flag, xerrno);
668}
669
670void
671TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
672{
673 debugs(26, 3, server.conn << ", " << len << " bytes written, flag=" << flag);
674
675 if (flag == Comm::ERR_CLOSING)
676 return;
677
679
680 /* Error? */
681 if (flag != Comm::OK) {
682 debugs(26, 4, "to-server write failed: " << xerrno);
683 server.error(xerrno); // may call comm_close
684 return;
685 }
686
687 /* EOF? */
688 if (len == 0) {
689 debugs(26, 4, "No read input. Closing server connection.");
690 server.conn->close();
691 return;
692 }
693
694 /* Valid data */
697 client.dataSent(len);
698
699 /* If the other end has closed, so should we */
701 debugs(26, 4, "Client gone away. Shutting down server connection.");
702 server.conn->close();
703 return;
704 }
705
706 const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
707
708 if (cbdataReferenceValid(this))
710}
711
712/* Writes data from the server buffer to the client side */
713void
714TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
715{
716 TunnelStateData *tunnelState = (TunnelStateData *)data;
717 assert (cbdataReferenceValid (tunnelState));
718 tunnelState->client.writer = nullptr;
719
720 tunnelState->writeClientDone(buf, len, flag, xerrno);
721}
722
723void
725{
726 debugs(26, 3, "len=" << len << " - amount=" << amount);
727 assert(amount == (size_t)len);
728 len =0;
729 /* increment total object size */
730
731 if (size_ptr)
732 *size_ptr += amount;
733
734}
735
736void
737TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
738{
739 writer = callback;
740 dirty = true;
741 Comm::Write(conn, b, size, callback, free_func);
742}
743
744template <typename Method>
745void
747{
749 Must(!closer);
750 Must(Comm::IsConnOpen(aConn));
751 conn = aConn;
752 closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
753 comm_add_close_handler(conn->fd, closer);
754}
755
756void
758{
759 debugs(26, 3, conn);
760 conn = nullptr;
761 closer = nullptr;
762 writer = nullptr; // may already be nil
763}
764
765void
766TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
767{
768 debugs(26, 3, client.conn << ", " << len << " bytes written, flag=" << flag);
769
770 if (flag == Comm::ERR_CLOSING)
771 return;
772
773 /* Error? */
774 if (flag != Comm::OK) {
775 debugs(26, 4, "from-client read failed: " << xerrno);
776 client.error(xerrno); // may call comm_close
777 return;
778 }
779
780 /* EOF? */
781 if (len == 0) {
782 debugs(26, 4, "Closing client connection due to 0 byte read.");
783 client.conn->close();
784 return;
785 }
786
787 /* Valid data */
789 server.dataSent(len);
790
791 /* If the other end has closed, so should we */
793 debugs(26, 4, "Server has gone away. Terminating client connection.");
794 client.conn->close();
795 return;
796 }
797
798 CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
799
800 if (cbdataReferenceValid(this))
802}
803
804static void
806{
807 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
808 debugs(26, 3, io.conn);
809 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
810 CbcPointer<TunnelStateData> safetyLock(tunnelState);
811
812 tunnelState->closeConnections();
813}
814
815void
817{
818 debugs(26, 3, "because " << reason << "; " << conn);
820 if (IsConnOpen(conn))
821 conn->close();
822}
823
824void
826{
828 server.conn->close();
830 client.conn->close();
831}
832
833static void
835{
836 if (!data)
837 return;
838
839 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
840 const auto savedContext = CodeContext::Current();
842 tunnel->client.readPending = nullptr;
843 static uint64_t counter=0;
844 debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
846 CodeContext::Reset(savedContext);
847}
848
849static void
851{
852 if (!data)
853 return;
854
855 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
856 const auto savedContext = CodeContext::Current();
858 tunnel->server.readPending = nullptr;
859 static uint64_t counter=0;
860 debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
862 CodeContext::Reset(savedContext);
863}
864
865void
867{
868 assert(from.len == 0);
869 // If only the minimum permitted read size is going to be attempted
870 // then we schedule an event to try again in a few I/O cycles.
871 // Allow at least 1 byte to be read every (0.3*10) seconds.
872 int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
873 // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
874 // from.readPendingFunc is tunnelDelayedClientRead()).
875 // XXX: Bug #4913: For delay pools, use delayRead() API instead.
876 if (bw == 1 && ++from.delayedLoops < 10) {
877 from.readPending = this;
878 eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
879 return;
880 }
881
882 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
883 CommIoCbPtrFun(completion, this));
884 comm_read(from.conn, from.buf, bw, call);
885}
886
887void
889{
891 size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
892 memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
893 preReadClientData.consume(copyBytes);
894 client.bytesIn(copyBytes);
895 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
897 } else
899}
900
901void
903{
905 size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
906 memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
907 preReadServerData.consume(copyBytes);
908 server.bytesIn(copyBytes);
909 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
911 } else
913}
914
919static void
921{
922 assert(!tunnelState->transportWait);
923 assert(!tunnelState->encryptionWait);
924 assert(!tunnelState->peerWait);
925
926 assert(tunnelState->server.conn);
927 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
928 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
929 commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
930
931 *tunnelState->status_ptr = Http::scOkay;
932 if (cbdataReferenceValid(tunnelState)) {
933
934 // Shovel any payload already pushed into reply buffer by the server response
935 if (!tunnelState->server.len)
936 tunnelState->copyServerBytes();
937 else {
938 debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
939 tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
940 }
941
942 if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
943 SBuf * const in = &tunnelState->http->getConn()->inBuf;
944 debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
945 tunnelState->preReadClientData.append(*in);
946 in->consume(); // ConnStateData buffer accounting after the shuffle.
947 }
948 tunnelState->copyClientBytes();
949 }
950}
951
957static void
958tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
959{
960 TunnelStateData *tunnelState = (TunnelStateData *)data;
961 debugs(26, 3, conn << ", flag=" << flag);
962 tunnelState->client.writer = nullptr;
963
964 if (flag != Comm::OK) {
966 tunnelErrorComplete(conn->fd, data, 0);
967 return;
968 }
969
970 if (auto http = tunnelState->http.get()) {
971 http->out.headers_sz += len;
972 http->out.size += len;
973 }
974
975 tunnelStartShoveling(tunnelState);
976}
977
978void
980{
982 server.len = 0;
983
984 // XXX: al->http.code (i.e. *status_ptr) should not be (re)set
985 // until we actually start responding to the client. Right here/now, we only
986 // know how this cache_peer has responded to us.
987 if (answer.peerResponseStatus != Http::scNone)
989
990 auto sawProblem = false;
991
992 if (!answer.positive()) {
993 sawProblem = true;
994 assert(!answer.conn);
995 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
996 sawProblem = true;
997 closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
998 }
999
1000 if (!sawProblem) {
1001 assert(answer.positive()); // paranoid
1002 // copy any post-200 OK bytes to our buffer
1005 return;
1006 }
1007
1008 ErrorState *error = nullptr;
1009 if (answer.positive()) {
1011 } else {
1012 error = answer.squidError.get();
1013 Must(error);
1014 answer.squidError.clear(); // preserve error for errorSendComplete()
1015 }
1016 assert(error);
1018 retryOrBail("tunneler error");
1019}
1020
1021void
1023{
1026
1028 tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1029 else {
1031 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1034 const auto mb = al->reply->pack();
1035 client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1036 delete mb;
1037 }
1038}
1039
1040void
1042{
1043 committedToServer = true;
1044 banRetries = "committed to server";
1045 PeerSelectionInitiator::subscribed = false; // may already be false
1046 server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1047}
1048
1049static void
1050tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
1051{
1052 TunnelStateData *tunnelState = (TunnelStateData *)data;
1053 debugs(26, 3, "FD " << fd);
1054 assert(tunnelState != nullptr);
1055 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
1056 CbcPointer<TunnelStateData> safetyLock(tunnelState);
1057
1058 if (Comm::IsConnOpen(tunnelState->client.conn))
1059 tunnelState->client.conn->close();
1060
1061 if (Comm::IsConnOpen(tunnelState->server.conn))
1062 tunnelState->server.conn->close();
1063}
1064
1065void
1067{
1069
1070 updateAttempts(answer.n_tries);
1071
1072 ErrorState *error = nullptr;
1073 if ((error = answer.error.get())) {
1074 banRetries = "HappyConnOpener gave up";
1075 Must(!Comm::IsConnOpen(answer.conn));
1076 syncHierNote(answer.conn, request->url.host());
1077 answer.error.clear();
1078 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1080 closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1081 }
1082
1083 if (error) {
1085 retryOrBail("tried all destinations");
1086 return;
1087 }
1088
1089 connectDone(answer.conn, request->url.host(), answer.reused);
1090}
1091
1092void
1093TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
1094{
1096
1097 if (reused)
1099 // else Comm::ConnOpener already applied proper/current markings
1100
1101 // TODO: add pconn race state tracking
1102
1103 syncHierNote(conn, origin);
1104
1105#if USE_DELAY_POOLS
1106 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1107 if (conn->getPeer() && conn->getPeer()->options.no_delay)
1109#endif
1110
1112
1113 request->peer_host = conn->getPeer() ? conn->getPeer()->host : nullptr;
1114
1115 bool toOrigin = false; // same semantics as StateFlags::toOrigin
1116 if (const auto * const peer = conn->getPeer()) {
1117 request->prepForPeering(*peer);
1118 toOrigin = peer->options.originserver;
1119 } else {
1121 toOrigin = true;
1122 }
1123
1124 if (!toOrigin)
1126 else {
1128 }
1129}
1130
1132bool
1134{
1136}
1137
1138void
1140{
1141 debugs(26, 3, MYNAME);
1142 /* Create state structure. */
1143 TunnelStateData *tunnelState = nullptr;
1144 ErrorState *err = nullptr;
1146 char *url = http->uri;
1147
1148 /*
1149 * client_addr.isNoAddr() indicates this is an "internal" request
1150 * from peer_digest.c, asn.c, netdb.c, etc and should always
1151 * be allowed. yuck, I know.
1152 */
1153
1155 /*
1156 * Check if this host is allowed to fetch MISSES from us (miss_access)
1157 * default is to allow.
1158 */
1160 ch.al = http->al;
1162 ch.my_addr = request->my_addr;
1164 if (ch.fastCheck().denied()) {
1165 debugs(26, 4, "MISS access forbidden.");
1170 return;
1171 }
1172 }
1173
1174 debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1177
1178 tunnelState = new TunnelStateData(http);
1179#if USE_DELAY_POOLS
1181#endif
1182 tunnelState->startSelectingDestinations(request, http->al, nullptr);
1183}
1184
1185void
1187{
1188 if (const auto p = conn->getPeer()) {
1189 if (p->secure.encryptTransport)
1190 return advanceDestination("secure connection to peer", conn, [this,&conn] {
1192 });
1193 }
1194
1196}
1197
1199void
1201{
1202 const auto callback = asyncCallback(5, 4, TunnelStateData::noteSecurityPeerConnectorAnswer, this);
1203 const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
1204 encryptionWait.start(connector, callback);
1205}
1206
1208template <typename StepStart>
1209void
1210TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1211{
1212 // TODO: Extract destination-specific handling from TunnelStateData so that
1213 // all the awkward, limited-scope advanceDestination() calls can be replaced
1214 // with a single simple try/catch,retry block.
1215 try {
1216 startStep();
1217 // now wait for the step callback
1218 } catch (...) {
1219 debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1220 closePendingConnection(conn, "connection preparation exception");
1221 if (!savedError)
1223 retryOrBail(stepDescription);
1224 }
1225}
1226
1228void
1230{
1232
1233 ErrorState *error = nullptr;
1234 assert(!answer.tunneled);
1235 if ((error = answer.error.get())) {
1236 assert(!answer.conn);
1237 answer.error.clear();
1238 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1240 closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1241 }
1242
1243 if (error) {
1245 retryOrBail("TLS peer connection error");
1246 return;
1247 }
1248
1249 connectedToPeer(answer.conn);
1250}
1251
1252void
1254{
1255 advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1257 });
1258}
1259
1260void
1262{
1263 const auto callback = asyncCallback(5, 4, TunnelStateData::tunnelEstablishmentDone, this);
1264 const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
1265#if USE_DELAY_POOLS
1266 tunneler->setDelayId(server.delayId);
1267#endif
1268 peerWait.start(tunneler, callback);
1269}
1270
1271void
1273{
1274 destinationsFound = true;
1275
1276 if (!path) { // decided to use a pinned connection
1277 // We can call usePinned() without fear of clashing with an earlier
1278 // forwarding attempt because PINNED must be the first destination.
1280 usePinned();
1281 return;
1282 }
1283
1284 destinations->addPath(path);
1285
1286 if (transportWait) {
1287 assert(!transporting());
1289 return; // and continue to wait for tunnelConnectDone() callback
1290 }
1291
1292 if (transporting())
1293 return; // and continue to receive destinations for backup
1294
1296}
1297
1298void
1300{
1303 if (!destinationsFound) {
1304
1305 // XXX: Honor clientExpectsConnectResponse() before replying.
1306
1307 if (selectionError)
1308 return sendError(selectionError, "path selection has failed");
1309
1310 // TODO: Merge with FwdState and remove this likely unnecessary check.
1311 if (savedError)
1312 return sendError(savedError, "path selection found no paths (with an impossible early error)");
1313
1315 "path selection found no paths");
1316 }
1317 // else continue to use one of the previously noted destinations;
1318 // if all of them fail, tunneling as whole will fail
1319 Must(!selectionError); // finding at least one path means selection succeeded
1320
1321 if (transportWait) {
1322 assert(!transporting());
1324 return; // and continue to wait for the noteConnection() callback
1325 }
1326
1327 if (transporting()) {
1328 // We are already using a previously opened connection (but were also
1329 // receiving more destinations in case we need to re-forward).
1330 debugs(17, 7, "keep transporting");
1331 return;
1332 }
1333
1334 // destinationsFound, but none of them worked, and we were waiting for more
1336 // XXX: Honor clientExpectsConnectResponse() before replying.
1337 sendError(savedError, "all found paths have failed");
1338}
1339
1343bool
1345{
1347}
1348
1350void
1352{
1353 debugs(26, 4, savedError << " ? " << error);
1354 assert(error);
1355 delete savedError; // may be nil
1356 savedError = error;
1357}
1358
1361void
1362TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1363{
1364 debugs(26, 3, "aborting transaction for " << reason);
1365
1366 if (request)
1367 request->hier.stopPeerClock(false);
1368
1369 cancelStep(reason);
1370
1371 assert(finalError);
1372
1373 // get rid of any cached error unless that is what the caller is sending
1374 if (savedError != finalError)
1375 delete savedError; // may be nil
1376 savedError = nullptr;
1377
1378 // we cannot try other destinations after responding with an error
1379 PeerSelectionInitiator::subscribed = false; // may already be false
1380
1381 *status_ptr = finalError->httpStatus;
1382 finalError->callback = tunnelErrorComplete;
1383 finalError->callback_data = this;
1384 errorSend(client.conn, finalError);
1385}
1386
1390void
1392{
1393 transportWait.cancel(reason);
1394 encryptionWait.cancel(reason);
1395 peerWait.cancel(reason);
1396}
1397
1398void
1400{
1401 if (request)
1403
1405 assert(!transporting());
1406
1407 delete savedError; // may still be nil
1408 savedError = nullptr;
1409 request->hier.peer_reply_status = Http::scNone; // TODO: Move to startPeerClock()?
1410
1411 const auto callback = asyncCallback(17, 5, TunnelStateData::noteConnection, this);
1412 const auto cs = new HappyConnOpener(destinations, callback, request, startTime, n_tries, al);
1413 cs->setHost(request->url.host());
1414 cs->setRetriable(false);
1415 cs->allowPersistent(false);
1416 destinations->notificationPending = true; // start() is async
1417 transportWait.start(cs, callback);
1418}
1419
1421void
1423{
1424 Must(request);
1425 const auto connManager = request->pinnedConnection();
1426 try {
1427 const auto serverConn = ConnStateData::BorrowPinnedConnection(request.getRaw(), al);
1428 debugs(26, 7, "pinned peer connection: " << serverConn);
1429
1431
1432 // Set HttpRequest pinned related flags for consistency even if
1433 // they are not really used by tunnel.cc code.
1434 request->flags.pinned = true;
1435 if (connManager->pinnedAuth())
1436 request->flags.auth = true;
1437
1438 // the server may close the pinned connection before this request
1439 const auto reused = true;
1440 connectDone(serverConn, connManager->pinning.host, reused);
1441 } catch (ErrorState * const error) {
1442 syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1443 // XXX: Honor clientExpectsConnectResponse() before replying.
1444 // a PINNED path failure is fatal; do not wait for more paths
1445 sendError(error, "pinned path failure");
1446 return;
1447 }
1448
1449}
1450
1452
1453bool
1455{
1457}
1458
1459#if USE_DELAY_POOLS
1460void
1462{
1463 delayId = newDelay;
1464}
1465
1466#endif
1467
1469void
1471{
1473 debugs(17, 7, "reusing pending notification");
1474 } else {
1476 CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
1477 }
1478}
1479
1487void
1489{
1490 Must(Comm::IsConnOpen(clientConn));
1491 Must(Comm::IsConnOpen(srvConn));
1492
1493 debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1494
1495 /* Create state structure. */
1498
1500 Must(conn);
1501 Http::StreamPointer context = conn->pipeline.front();
1502 Must(context && context->http);
1503
1504 debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1505
1506 TunnelStateData *tunnelState = new TunnelStateData(context->http);
1507 tunnelState->commitToServer(srvConn);
1508
1509 request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1510
1511#if USE_DELAY_POOLS
1512 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1513 if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
1514 tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1515#endif
1516
1517 request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1518
1519 debugs(26, 4, "determine post-connect handling pathway.");
1520 if (const auto peer = srvConn->getPeer())
1521 request->prepForPeering(*peer);
1522 else
1524
1525 tunnelState->preReadServerData = preReadServerData;
1526
1527 tunnelStartShoveling(tunnelState);
1528}
1529
#define Assure(condition)
Definition: Assure.h:35
#define asyncCallback(dbgSection, dbgLevel, method, object)
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:58
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:312
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:37
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:34
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:40
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1564
@ LOG_TCP_TUNNEL
an attempt to establish a bidirectional TCP tunnel
Definition: LogTags.h:56
int size
Definition: ModDevPoll.cc:75
time_t squid_curtime
Definition: stub_libtime.cc:20
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition: Read.h:59
class SquidConfig Config
Definition: SquidConfig.cc:12
StatCounters statCounter
Definition: StatCounters.cc:12
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
#define Must(condition)
Definition: TextException.h:75
int conn
the current server connection FD
Definition: Transport.cc:26
void error(char *format,...)
#define assert(EX)
Definition: assert.h:17
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:265
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:320
Acl::Answer const & fastCheck()
Definition: Checklist.cc:332
Ip::Address src_addr
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
MessageSizes clientRequestSz
counters for the original request received from client
HttpReplyPointer reply
class AccessLogEntry::CacheDetails cache
HierarchyLogEntry hier
class AccessLogEntry::HttpDetails http
bool denied() const
Definition: Acl.h:162
void host(const char *src)
Definition: Uri.cc:100
struct CachePeer::@28 options
char * host
Definition: CachePeer.h:65
bool no_delay
Definition: CachePeer.h:127
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
void clear()
make pointer not set; does not invalidate cbdata
Definition: CbcPointer.h:144
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:159
struct ClientHttpRequest::Out out
HttpRequest *const request
ConnStateData * getConn() const
void updateLoggingTags(const LogTags_ot code)
update the code in the transaction processing tags
const AccessLogEntry::Pointer al
access.log entry
static const Pointer & Current()
Definition: CodeContext.cc:33
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:77
Comm::ConnectionPointer conn
Definition: CommCalls.h:80
CachePeer * getPeer() const
Definition: Connection.cc:124
Ssl::ServerBump * serverBump()
Definition: client_side.h:285
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
static DelayId DelayClient(ClientHttpRequest *, HttpReply *reply=nullptr)
Definition: DelayId.cc:68
ERCB * callback
Definition: errorpage.h:185
void * callback_data
Definition: errorpage.h:186
Http::StatusCode httpStatus
Definition: errorpage.h:173
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:436
Final result (an open connection or an error) sent to the job initiator.
bool reused
whether conn was open earlier, by/for somebody else
PeerConnectionPointer conn
CbcPointer< ErrorState > error
problem details (nil on success)
Http::StatusCode peer_reply_status
last HTTP status code received
void startPeerClock()
Start recording total time spent communicating with peers.
Definition: access_log.cc:245
void stopPeerClock(const bool force)
Definition: access_log.cc:252
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:199
MemBuf * pack() const
Definition: HttpReply.cc:112
static HttpReplyPointer MakeConnectionEstablished()
construct and return an HTTP/200 (Connection Established) response
Definition: HttpReply.cc:121
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:232
void prepForDirect()
get ready to be sent directly to an origin server, excluding originserver
Definition: HttpRequest.cc:456
void prepForPeering(const CachePeer &peer)
get ready to be sent to the given cache_peer, including originserver
Definition: HttpRequest.cc:446
HttpRequestMethod method
Definition: HttpRequest.h:114
HierarchyLogEntry hier
Definition: HttpRequest.h:157
RequestFlags flags
Definition: HttpRequest.h:141
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:725
Ip::Address my_addr
Definition: HttpRequest.h:155
char * peer_host
Definition: HttpRequest.h:165
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
Ip::Address client_addr
Definition: HttpRequest.h:149
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
Comm::ConnectionPointer conn
StatusCode peerResponseStatus
the status code of the successfully parsed CONNECT response (or scNone)
SBuf leftovers
peer-generated bytes after a positive answer (or empty)
CbcPointer< ErrorState > squidError
problem details (or nil)
bool isNoAddr() const
Definition: Address.cc:284
void finish()
Definition: JobWait.cc:44
void cancel(const char *reason)
Definition: JobWait.cc:54
JobPointer job() const
Definition: JobWait.h:76
void start(const JobPointer &aJob, const AsyncCall::Pointer &aCallback)
starts waiting for the given job to call the given callback
Definition: JobWait.h:69
void update(const LogTags_ot t)
Definition: LogTags.cc:54
uint64_t payloadData
total size of payload block(s) excluding transfer encoding overheads
Definition: MessageSizes.h:24
Interface for those who need a list of peers to forward a request to.
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:335
Definition: Raw.h:21
C * getRaw() const
Definition: RefCount.h:89
bool interceptTproxy
Set for requests handled by a "tproxy" port.
Definition: RequestFlags.h:70
bool forceTunnel
whether to forward via TunnelStateData (instead of FwdState)
Definition: RequestFlags.h:120
bool intercepted
Definition: RequestFlags.h:66
bool notificationPending
whether HappyConnOpener::noteCandidatesChange() is scheduled to fire
Definition: ResolvedPeers.h:85
bool empty() const
whether we lack any known candidate paths
Definition: ResolvedPeers.h:46
bool destinationsFinalized
whether all of the available candidate paths received from DNS
Definition: ResolvedPeers.h:82
void addPath(const Comm::ConnectionPointer &)
add a candidate path to try after all the existing paths
Definition: SBuf.h:94
const char * rawContent() const
Definition: SBuf.cc:509
SBuf consume(size_type n=npos)
Definition: SBuf.cc:481
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:415
bool isEmpty() const
Definition: SBuf.h:431
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
A simple PeerConnector for SSL/TLS cache_peers. No SslBump capabilities.
CbcPointer< ErrorState > error
problem details (nil on success)
Comm::ConnectionPointer conn
peer connection (secured on success)
bool tunneled
whether we spliced the connections instead of negotiating encryption
Comm::ConnectionPointer clientConnection
Definition: Server.h:100
SBuf inBuf
read I/O buffer for the client connection
Definition: Server.h:113
struct SquidConfig::@107 accessList
int forward_max_tries
Definition: SquidConfig.h:351
time_t lifetime
Definition: SquidConfig.h:114
time_t read
Definition: SquidConfig.h:112
struct SquidConfig::@93 Timeout
acl_access * miss
Definition: SquidConfig.h:362
bool at(const BumpStep stp) const
whether we are currently performing the given processing step
Definition: ServerBump.h:47
struct StatCounters::@122 client_http
struct StatCounters::@123::@133 all
struct StatCounters::@123::@133 other
ByteCounter kbytes_out
Definition: StatCounters.h:46
ByteCounter kbytes_in
Definition: StatCounters.h:45
struct StatCounters::@123 server
void noteClosure()
reacts to the external closure of our connection
Definition: tunnel.cc:757
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition: tunnel.cc:466
void bytesIn(int const &)
Definition: tunnel.cc:477
void write(const char *b, int size, AsyncCall::Pointer &callback, FREE *free_func)
writes 'b' buffer, setting the 'writer' member to 'callback'.
Definition: tunnel.cc:737
void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
initiates Comm::Connection ownership, including closure monitoring
Definition: tunnel.cc:746
void error(int const xerrno)
Definition: tunnel.cc:564
void dataSent(size_t amount)
Definition: tunnel.cc:724
void setDelayId(DelayId const &)
Definition: tunnel.cc:1461
Comm::ConnectionPointer conn
The currently connected connection.
Definition: tunnel.cc:165
AsyncCall::Pointer writer
pending Comm::Write callback
Definition: tunnel.cc:162
uint8_t delayedLoops
how many times a read on this connection has been postponed.
Definition: tunnel.cc:166
AsyncCall::Pointer closer
the registered close handler for the connection
Definition: tunnel.cc:181
bool dirty
whether write() has been called (at least once)
Definition: tunnel.cc:168
TunnelStateData * readPending
Definition: tunnel.cc:171
int debugLevelForError(int const xerrno) const
Definition: tunnel.cc:512
static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:574
const char * banRetries
a reason to ban reforwarding attempts (or nil)
Definition: tunnel.cc:199
SBuf preReadClientData
Definition: tunnel.cc:187
void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:539
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition: tunnel.cc:205
void closeConnections()
closes both client and server connections
Definition: tunnel.cc:825
void copyServerBytes()
Definition: tunnel.cc:902
void notePeerReadyToShovel(const Comm::ConnectionPointer &)
called when negotiations with the peer have been successfully completed
Definition: tunnel.cc:1022
CbcPointer< ClientHttpRequest > http
Definition: tunnel.cc:95
void sendError(ErrorState *finalError, const char *reason)
Definition: tunnel.cc:1362
void serverClosed()
handles Squid-to-server connection closure; may destroy us
Definition: tunnel.cc:308
void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:766
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition: tunnel.cc:1470
void updateAttempts(int)
sets n_tries to the given value (while keeping ALE in sync)
Definition: tunnel.cc:498
char * url
Definition: tunnel.cc:94
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: tunnel.cc:979
bool noConnections() const
Definition: tunnel.cc:1454
Connection client
Definition: tunnel.cc:184
void noteDestinationsEnd(ErrorState *selectionError) override
Definition: tunnel.cc:1299
void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
Start using an established connection.
Definition: tunnel.cc:1093
CBDATA_CHILD(TunnelStateData)
void connectedToPeer(const Comm::ConnectionPointer &)
called after connection setup (including any encryption)
Definition: tunnel.cc:1253
const char * getHost() const
Definition: tunnel.cc:99
TunnelStateData(const TunnelStateData &)
void noteConnection(HappyConnOpenerAnswer &)
Definition: tunnel.cc:1066
static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:714
void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:583
TunnelStateData(ClientHttpRequest *)
Definition: tunnel.cc:350
void copyRead(Connection &from, IOCB *completion)
Definition: tunnel.cc:866
const char * checkRetry()
Definition: tunnel.cc:400
TunnelStateData & operator=(const TunnelStateData &)
void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:671
void saveError(ErrorState *finalError)
remembers an error to be used if there will be no more connection attempts
Definition: tunnel.cc:1351
HttpRequest::Pointer request
Definition: tunnel.cc:96
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: tunnel.cc:1422
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition: tunnel.cc:1261
int n_tries
the number of forwarding attempts so far
Definition: tunnel.cc:196
void connectToPeer(const Comm::ConnectionPointer &)
continue to set up connection to a peer, going async for SSL peers
Definition: tunnel.cc:1186
SBuf preReadServerData
Definition: tunnel.cc:188
void copyClientBytes()
Definition: tunnel.cc:888
void startConnecting()
Definition: tunnel.cc:1399
void copy(size_t len, Connection &from, Connection &to, IOCB *)
Definition: tunnel.cc:651
void commitToServer(const Comm::ConnectionPointer &)
Definition: tunnel.cc:1041
void retryOrBail(const char *context)
Definition: tunnel.cc:422
void clientClosed()
handles client-to-Squid connection closure; may destroy us
Definition: tunnel.cc:324
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: tunnel.cc:190
void syncHierNote(const Comm::ConnectionPointer &server, const char *origin)
Definition: tunnel.cc:490
void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
Definition: tunnel.cc:816
void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &)
callback handler for the Security::PeerConnector encryptor
Definition: tunnel.cc:1229
void deleteThis()
destroys the tunnel (after performing potentially-throwing cleanup)
Definition: tunnel.cc:337
void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
starts a preparation step for an established connection; retries on failures
Definition: tunnel.cc:1210
int * status_ptr
pointer for logging HTTP status
Definition: tunnel.cc:185
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition: tunnel.cc:608
bool committedToServer
whether the decision to tunnel to a particular destination was final
Definition: tunnel.cc:194
bool clientExpectsConnectResponse() const
Whether the client sent a CONNECT request to us.
Definition: tunnel.cc:108
Connection server
Definition: tunnel.cc:184
ErrorState * savedError
details of the "last tunneling attempt" failure (if it failed)
Definition: tunnel.cc:258
static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:529
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition: tunnel.cc:208
void cancelStep(const char *reason)
Definition: tunnel.cc:1391
bool destinationsFound
At least one candidate path found.
Definition: tunnel.cc:191
CodeContext::Pointer codeContext
our creator context
Definition: tunnel.cc:202
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer
Definition: tunnel.cc:1200
JobWait< Http::Tunneler > peerWait
Definition: tunnel.cc:212
~TunnelStateData() override
Definition: tunnel.cc:382
time_t startTime
object creation time, before any peer selection/connection attempts
Definition: tunnel.cc:189
AccessLogEntryPointer al
Definition: tunnel.cc:97
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition: tunnel.cc:1133
bool transporting() const
Definition: tunnel.cc:1344
void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: tunnel.cc:1272
static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:661
int commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:595
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:949
int ignoreErrno(int ierrno)
Definition: comm.cc:1440
#define DBG_DATA
Definition: Stream.h:40
#define MYNAME
Definition: Stream.h:236
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
@ ERR_FORWARDING_DENIED
Definition: forward.h:21
@ ERR_CANNOT_FORWARD
Definition: forward.h:23
void ERCB(int fd, void *, size_t)
error page callback
Definition: errorpage.h:30
void eventDelete(EVH *func, void *arg)
Definition: event.cc:127
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
void EVH(void *)
Definition: event.h:18
#define fd_table
Definition: fde.h:189
int shutting_down
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition: errorpage.cc:748
void FREE(void *)
Definition: forward.h:37
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:33
Flag
Definition: Flag.h:15
@ OK
Definition: Flag.h:16
@ ERR_CLOSING
Definition: Flag.h:24
@ scForbidden
Definition: StatusCode.h:47
@ scInternalServerError
Definition: StatusCode.h:71
@ scNone
Definition: StatusCode.h:21
@ scOkay
Definition: StatusCode.h:26
@ scServiceUnavailable
Definition: StatusCode.h:74
bool IsReforwardableStatus(StatusCode)
whether to send the request to another peer based on the current response status code
Definition: StatusCode.cc:281
#define xfree
#define xstrdup
#define xmalloc
void netdbPingSite(const char *hostname)
Definition: net_db.cc:827
size_t headers_sz
Response header bytes written to the client connection.
uint64_t size
Response header and body bytes written to the client connection.
static CLCB tunnelServerClosed
Definition: tunnel.cc:293
static CTCB tunnelTimeout
Definition: tunnel.cc:295
void tunnelStart(ClientHttpRequest *http)
Definition: tunnel.cc:1139
static ERCB tunnelErrorComplete
Definition: tunnel.cc:292
static EVH tunnelDelayedClientRead
Definition: tunnel.cc:296
static void tunnelStartShoveling(TunnelStateData *tunnelState)
Definition: tunnel.cc:920
static EVH tunnelDelayedServerRead
Definition: tunnel.cc:297
static void tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
Definition: tunnel.cc:958
void switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
Definition: tunnel.cc:1488
static CLCB tunnelClientClosed
Definition: tunnel.cc:294
#define INT_MAX
Definition: types.h:70
#define safe_free(x)
Definition: xalloc.h:73
const char * xstrerr(int error)
Definition: xstrerror.cc:83

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors