Squid Web Cache master
Loading...
Searching...
No Matches
tunnel.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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 explicit Connection(const char *aSide);
135 ~Connection();
136
138 template <typename Method>
139 void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState);
140
142 void noteClosure();
143
145 void noteEof();
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
164 const char * const side;
165
166 char *buf;
168 uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
169
171 uint8_t delayedLoops;
172
173 bool dirty;
174
175 bool receivedEof = false;
176
177 // XXX: make these an AsyncCall when event API can handle them
180
181#if USE_DELAY_POOLS
182
184#endif
185
186 private:
189 };
190
193
196 time_t startTime;
199
202
204
206 const char *banRetries;
207
208 // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
210
213
216
220
223
224 void copyRead(Connection &from, Connection &to, IOCB *completion);
225
229
230 /* PeerSelectionInitiator API */
231 void noteDestination(Comm::ConnectionPointer conn) override;
232 void noteDestinationsEnd(ErrorState *selectionError) override;
233
234 void syncHierNote(const Comm::ConnectionPointer &server, const char *origin);
235
239
241 void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused);
242
243 void notifyConnOpener();
244
245 void saveError(ErrorState *finalError);
246 void sendError(ErrorState *finalError, const char *reason);
247
248private:
249 void usePinned();
250
253
257
258 template <typename StepStart>
259 void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep);
260
262 const char *checkRetry();
263
264 bool transporting() const;
265
266 // TODO: convert to unique_ptr
269
272
274 void deleteThis();
275
276 void cancelStep(const char *reason);
277
278 bool exhaustedTries() const;
279 void updateAttempts(int);
280
281public:
282 bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
283 void copy(size_t len, Connection &from, Connection &to, IOCB *);
284 void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
285 void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
286 void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
287 void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
288
289 void copyClientBytes();
290 void copyServerBytes();
291
293 void clientClosed();
294
296 void serverClosed();
297
300 void retryOrBail(const char *context);
301};
302
309
310static std::ostream &
311operator <<(std::ostream &os, const TunnelStateData::Connection &c)
312{
313 os << '{';
314 os << c.side;
315
316 if (c.conn)
317 os << ' ' << c.conn->id;
318
319 if (c.len)
320 os << " buf=" << c.len;
321
322 if (c.writer)
323 os << " writing";
324 else if (!c.dirty)
325 os << " clean";
326
327 if (c.delayedLoops)
328 os << " delayedLoops=" << c.delayedLoops;
329 if (c.readPending)
330 os << " delaying";
331
332 if (c.receivedEof)
333 os << " rEOF";
334
335 os << '}';
336 return os;
337}
338
340static void
342{
343 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
344 tunnelState->serverClosed();
345}
346
347void
356
358static void
360{
361 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
362 tunnelState->clientClosed();
363}
364
365void
371
376void
378{
379 if (noConnections())
380 return deleteThis();
381
382 // XXX: The code below should precede the noConnections() check above. When
383 // there is no writer, we should trigger an immediate noConnections()
384 // outcome instead of waiting for an asynchronous call to our own closure
385 // callback (that will call this method again). We should not move this code
386 // until a noConnections() outcome guarantees a nil writer because such a
387 // move will unnecessary delay deleteThis().
388
389 if (remainingConnection.writer) {
390 debugs(26, 5, "waiting to finish writing to " << remainingConnection);
391 // the write completion callback must close its remainingConnection
392 // after noticing that the other connection is gone
393 return;
394 }
395
396 // XXX: Stop abusing connection closure callback for terminating tunneling
397 // in cases like this, where our code knows that tunneling must end. The
398 // closure callback should be dedicated to handling rare connection closures
399 // originated _outside_ of TunnelStateData (e.g., during shutdown). In all
400 // other cases, our own close()-calling code must detail the
401 // closure-triggering error (if any) _and_ clear all callbacks: Our code
402 // does not need to be (asynchronously) notified of the closure that it
403 // itself has initiated! Until that (significant) refactoring,
404 // serverClosed() and clientClosed() callbacks will continue to mishandle
405 // those rare closures as regular ones, and access.log records will continue
406 // to lack some tunneling error indicators/details.
407 //
408 // This asynchronous close() leads to another finishWritingAndDelete() call
409 // but with true noConnections() that finally triggers deleteThis().
410 remainingConnection.conn->close();
411}
412
414void
416{
418 // ConnStateData pipeline should contain the CONNECT we are performing
419 // but it may be invalid already (bug 4392)
420 if (const auto h = http.valid()) {
421 if (const auto c = h->getConn())
422 if (const auto ctx = c->pipeline.front())
423 ctx->finished();
424 }
425 delete this;
426}
427
428// TODO: Replace with a reusable API guaranteeing non-nil pointer forwarding.
430static auto &
432{
433 Assure(cr);
434 Assure(cr->request);
435 return *cr->request;
436}
437
439 client("client"),
440 server("server"),
441 startTime(squid_curtime),
442 destinations(new ResolvedPeers()),
443 destinationsFound(false),
444 committedToServer(false),
445 n_tries(0),
446 banRetries(nullptr),
447 codeContext(CodeContext::Current()),
448 peeringTimer(&guaranteedRequest(clientRequest))
449{
450 debugs(26, 3, "TunnelStateData constructed this=" << this);
453
454 assert(clientRequest);
455 url = xstrdup(clientRequest->uri);
456 request = clientRequest->request;
457 Must(request);
458 server.size_ptr = &clientRequest->out.size;
460 status_ptr = &clientRequest->al->http.code;
461 al = clientRequest->al;
462 http = clientRequest;
463
465
466 client.initConnection(clientRequest->getConn()->clientConnection, tunnelClientClosed, "tunnelClientClosed", this);
467
468 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
471}
472
474{
475 debugs(26, 3, "TunnelStateData destructed this=" << this);
477 xfree(url);
478 cancelStep("~TunnelStateData");
479 delete savedError;
480}
481
483 len(0),
484 side(aSide),
485 buf(static_cast<char *>(xmalloc(SQUID_TCP_SO_RCVBUF))),
486 size_ptr(nullptr),
487 delayedLoops(0),
488 dirty(false),
489 readPending(nullptr),
490 readPendingFunc(nullptr)
491{
492}
493
495{
496 if (readPending)
497 eventDelete(readPendingFunc, readPending);
498
499 safe_free(buf);
500}
501
502const char *
504{
505 if (shutting_down)
506 return "shutting down";
507 if (exhaustedTries())
508 return "exhausted tries";
510 return "forwarding timeout";
511 if (banRetries)
512 return banRetries;
513 if (noConnections())
514 return "no connections";
515
516 // TODO: Use std::optional for peer_reply_status to avoid treating zero value specially.
518 return "received HTTP status code is not reforwardable";
519
520 // TODO: check pinned connections; see FwdState::pinnedCanRetry()
521 return nullptr;
522}
523
524void
526{
528
529 const auto *bailDescription = checkRetry();
530 if (!bailDescription) {
531 if (!destinations->empty())
532 return startConnecting(); // try connecting to another destination
533
534 if (subscribed) {
535 debugs(26, 4, "wait for more destinations to try");
536 return; // expect a noteDestination*() call
537 }
538
539 // fall through to bail
540 }
541
542 /* bail */
543
545
546 // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
547 // Then, the remaining method code (below) should become the common part of
548 // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
549 if (!savedError)
551 const auto canSendError = Comm::IsConnOpen(client.conn) && !client.dirty &&
553 if (canSendError)
554 return sendError(savedError, bailDescription ? bailDescription : context);
556
558}
559
560int
561TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
562{
563#if USE_DELAY_POOLS
564 return delayId.bytesWanted(lowerbound, upperbound);
565#else
566 (void)lowerbound;
567 return upperbound;
568#endif
569}
570
571void
573{
574 debugs(26, 3, "len=" << len << " + count=" << count);
575#if USE_DELAY_POOLS
576 delayId.bytesIn(count);
577#endif
578
579 len += count;
580}
581
584void
586{
587 request->hier.resetPeerNotes(conn, origin);
588 al->hier.resetPeerNotes(conn, origin);
589}
590
592void
594{
595 Assure(n_tries <= newValue); // n_tries cannot decrease
596
597 // Squid probably creates at most one FwdState/TunnelStateData object per
598 // ALE, but, unlike an assignment would, this increment logic works even if
599 // Squid uses multiple such objects for a given ALE in some esoteric cases.
600 al->requestAttempts += (newValue - n_tries);
601
602 n_tries = newValue;
603 debugs(26, 5, n_tries);
604}
605
606int
608{
609#ifdef ECONNRESET
610
611 if (xerrno == ECONNRESET)
612 return 2;
613
614#endif
615
616 if (ignoreErrno(xerrno))
617 return 3;
618
619 return 1;
620}
621
622/* Read from server side and queue it for writing to the client */
623void
624TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
625{
626 TunnelStateData *tunnelState = (TunnelStateData *)data;
627 assert(cbdataReferenceValid(tunnelState));
628 debugs(26, 3, c);
629
630 tunnelState->readServer(buf, len, errcode, xerrno);
631}
632
633void
634TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
635{
636 debugs(26, 3, server << ", read " << len << " bytes, err=" << errcode);
638
639 /*
640 * Bail out early on Comm::ERR_CLOSING
641 * - close handlers will tidy up for us
642 */
643
644 if (errcode == Comm::ERR_CLOSING)
645 return;
646
647 if (len > 0) {
648 server.bytesIn(len);
652 }
653
654 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
656}
657
658void
660{
661 debugs(50, debugLevelForError(xerrno), *this << ": read/write failure: " << xstrerr(xerrno));
662
663 if (!ignoreErrno(xerrno))
664 conn->close();
665}
666
667/* Read from client side and queue it for writing to the server */
668void
669TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
670{
671 TunnelStateData *tunnelState = (TunnelStateData *)data;
672 assert (cbdataReferenceValid (tunnelState));
673
674 tunnelState->readClient(buf, len, errcode, xerrno);
675}
676
677void
678TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
679{
680 debugs(26, 3, client << ", read " << len << " bytes, err=" << errcode);
682
683 /*
684 * Bail out early on Comm::ERR_CLOSING
685 * - close handlers will tidy up for us
686 */
687
688 if (errcode == Comm::ERR_CLOSING)
689 return;
690
691 if (len > 0) {
692 client.bytesIn(len);
694 }
695
696 if (keepGoingAfterRead(len, errcode, xerrno, client, server))
698}
699
702bool
703TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
704{
705 debugs(26, 3, "from=" << from << "; writing to=" << to);
706
707 /* I think this is to prevent free-while-in-a-callback behaviour
708 * - RBC 20030229
709 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
710 */
711 const CbcPointer<TunnelStateData> safetyLock(this);
712
713 /* Bump the source connection read timeout on any activity */
714 if (Comm::IsConnOpen(from.conn)) {
715 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
717 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
718 }
719
720 /* Bump the dest connection read timeout on any activity */
721 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
722 if (Comm::IsConnOpen(to.conn)) {
723 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
725 commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
726 }
727
728 if (errcode) {
729 from.error (xerrno);
730 return false;
731 }
732
733 if (len == 0) {
734 debugs(26, 3, "closing " << from << " after a zero-byte read");
735 from.conn->close();
736
737 /* Only close the remote end if we've finished queueing data to it */
738 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
739 to.conn->close();
740 }
741 return false;
742 }
743
744 // Stop reading from source if the destination is gone. This both increases
745 // `from` chances to realize what happened at the `to` end and terminates an
746 // otherwise potentially infinite stream of incoming `from` bytes.
747 if (!Comm::IsConnOpen(to.conn)) {
748 debugs(26, 3, "closing " << from << " because " << to << " is gone");
749 from.conn->close();
750 return false;
751 }
752
753 if (!cbdataReferenceValid(this))
754 return false;
755
756 Assure(len > 0);
757 return true;
758}
759
760void
761TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
762{
763 debugs(26, 3, "Schedule Write");
764 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
765 CommIoCbPtrFun(completion, this));
766 to.write(from.buf, len, call, nullptr);
767}
768
769/* Writes data from the client buffer to the server side */
770void
771TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
772{
773 TunnelStateData *tunnelState = (TunnelStateData *)data;
774 assert (cbdataReferenceValid (tunnelState));
775 tunnelState->server.writer = nullptr;
776
777 tunnelState->writeServerDone(buf, len, flag, xerrno);
778}
779
780void
781TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
782{
783 debugs(26, 3, server << ", " << len << " bytes written, flag=" << flag);
784
785 if (flag == Comm::ERR_CLOSING)
786 return;
787
789
790 /* Error? */
791 if (flag != Comm::OK) {
792 debugs(26, 4, "to-server write failed: " << xerrno);
793 server.error(xerrno); // may call comm_close
794 return;
795 }
796
797 /* EOF? */
798 if (len == 0) {
799 debugs(26, 4, "No read input. Closing server connection.");
800 server.conn->close();
801 return;
802 }
803
804 /* Valid data */
807 client.dataSent(len);
808
809 /* If the other end has closed, so should we */
811 debugs(26, 4, "Client gone away. Shutting down server connection.");
812 server.conn->close();
813 return;
814 }
815
816 const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
817
818 if (cbdataReferenceValid(this))
820}
821
822/* Writes data from the server buffer to the client side */
823void
824TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
825{
826 TunnelStateData *tunnelState = (TunnelStateData *)data;
827 assert (cbdataReferenceValid (tunnelState));
828 tunnelState->client.writer = nullptr;
829
830 tunnelState->writeClientDone(buf, len, flag, xerrno);
831}
832
833void
835{
836 debugs(26, 3, "len=" << len << " - amount=" << amount);
837 assert(amount == (size_t)len);
838 len =0;
839 /* increment total object size */
840
841 if (size_ptr)
842 *size_ptr += amount;
843
844}
845
846void
847TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
848{
849 writer = callback;
850 dirty = true;
851 Comm::Write(conn, b, size, callback, free_func);
852}
853
854template <typename Method>
855void
856TunnelStateData::Connection::initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
857{
858 debugs(26, 3, *this << " uses " << aConn);
859 Must(!Comm::IsConnOpen(conn));
860 Must(!closer);
861 Must(Comm::IsConnOpen(aConn));
862 conn = aConn;
863 closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
864 comm_add_close_handler(conn->fd, closer);
865}
866
867void
869{
870 debugs(26, 3, *this);
871 conn = nullptr;
872 closer = nullptr;
873 writer = nullptr; // may already be nil
874}
875
876void
878{
879 debugs(26, 3, "from " << *this);
880 receivedEof = true;
881}
882
883void
884TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
885{
886 debugs(26, 3, client << ", " << len << " bytes written, flag=" << flag);
887
888 if (flag == Comm::ERR_CLOSING)
889 return;
890
891 /* Error? */
892 if (flag != Comm::OK) {
893 debugs(26, 4, "to-client write failed: " << xerrno);
894 client.error(xerrno); // may call comm_close
895 return;
896 }
897
898 /* EOF? */
899 if (len == 0) {
900 debugs(26, 4, "Closing client connection due to 0 byte read.");
901 client.conn->close();
902 return;
903 }
904
905 /* Valid data */
907 server.dataSent(len);
908
909 /* If the other end has closed, so should we */
911 debugs(26, 4, "Server has gone away. Terminating client connection.");
912 client.conn->close();
913 return;
914 }
915
916 CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
917
918 if (cbdataReferenceValid(this))
920}
921
922static void
924{
925 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
926 debugs(26, 3, io.conn);
927 /* Temporary lock to protect our own feet (comm_close -> tunnelClientClosed -> Free) */
928 CbcPointer<TunnelStateData> safetyLock(tunnelState);
929
930 tunnelState->closeConnections();
931}
932
933void
935{
936 debugs(26, 3, "because " << reason << "; " << conn);
938 if (IsConnOpen(conn))
939 conn->close();
940}
941
942void
950
951static void
953{
954 if (!data)
955 return;
956
957 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
958 const auto savedContext = CodeContext::Current();
960 tunnel->client.readPending = nullptr;
961 static uint64_t counter=0;
962 debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
963 tunnel->copyRead(tunnel->client, tunnel->server, TunnelStateData::ReadClient);
964 CodeContext::Reset(savedContext);
965}
966
967static void
969{
970 if (!data)
971 return;
972
973 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
974 const auto savedContext = CodeContext::Current();
976 tunnel->server.readPending = nullptr;
977 static uint64_t counter=0;
978 debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
979 tunnel->copyRead(tunnel->server, tunnel->client, TunnelStateData::ReadServer);
980 CodeContext::Reset(savedContext);
981}
982
983void
985{
986 debugs(26, 5, "from=" << from << "; writing to=" << to);
987
988 assert(from.len == 0);
989 // If only the minimum permitted read size is going to be attempted
990 // then we schedule an event to try again in a few I/O cycles.
991 // Allow at least 1 byte to be read every (0.3*10) seconds.
992 int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
993 // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
994 // from.readPendingFunc is tunnelDelayedClientRead()).
995 // XXX: Bug #4913: For delay pools, use delayRead() API instead.
996 if (bw == 1 && ++from.delayedLoops < 10) {
997 from.readPending = this;
998 eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
999 return;
1000 }
1001
1002 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
1003 CommIoCbPtrFun(completion, this));
1004 comm_read(from.conn, from.buf, bw, call);
1005}
1006
1007void
1009{
1010 if (preReadClientData.length()) {
1011 debugs(26, 7, "pre-read bytes: " << preReadClientData.length());
1013 memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
1014 preReadClientData.consume(copyBytes);
1015 client.bytesIn(copyBytes);
1016 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
1018 } else
1020}
1021
1022void
1024{
1025 if (preReadServerData.length()) {
1026 debugs(26, 7, "pre-read bytes: " << preReadServerData.length());
1028 memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
1029 preReadServerData.consume(copyBytes);
1030 server.bytesIn(copyBytes);
1031 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
1033 } else
1035}
1036
1041static void
1043{
1044 assert(!tunnelState->transportWait);
1045 assert(!tunnelState->encryptionWait);
1046 assert(!tunnelState->peerWait);
1047
1048 assert(tunnelState->server.conn);
1049 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1050 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1051 commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
1052
1053 *tunnelState->status_ptr = Http::scOkay;
1054 if (cbdataReferenceValid(tunnelState)) {
1055
1056 // Shovel any payload already pushed into reply buffer by the server response
1057 if (!tunnelState->server.len)
1058 tunnelState->copyServerBytes();
1059 else {
1060 debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
1061 tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
1062 }
1063
1064 if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
1065 SBuf * const in = &tunnelState->http->getConn()->inBuf;
1066 debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
1067 tunnelState->preReadClientData.append(*in);
1068 in->consume(); // ConnStateData buffer accounting after the shuffle.
1069 }
1070 tunnelState->copyClientBytes();
1071 }
1072}
1073
1079static void
1080tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
1081{
1082 TunnelStateData *tunnelState = (TunnelStateData *)data;
1083 debugs(26, 3, tunnelState->client << ", flag=" << flag);
1084 tunnelState->client.writer = nullptr;
1085
1086 if (flag != Comm::OK) {
1088 tunnelErrorComplete(conn->fd, data, 0);
1089 return;
1090 }
1091
1092 if (auto http = tunnelState->http.get()) {
1093 http->out.headers_sz += len;
1094 http->out.size += len;
1095 }
1096
1097 tunnelStartShoveling(tunnelState);
1098}
1099
1100void
1102{
1103 peerWait.finish();
1104 server.len = 0;
1105
1106 // XXX: al->http.code (i.e. *status_ptr) should not be (re)set
1107 // until we actually start responding to the client. Right here/now, we only
1108 // know how this cache_peer has responded to us.
1109 if (answer.peerResponseStatus != Http::scNone)
1111
1112 auto sawProblem = false;
1113
1114 if (!answer.positive()) {
1115 sawProblem = true;
1116 assert(!answer.conn);
1117 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1118 sawProblem = true;
1119 closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
1120 }
1121
1122 if (!sawProblem) {
1123 assert(answer.positive()); // paranoid
1124 // copy any post-200 OK bytes to our buffer
1127 return;
1128 }
1129
1130 ErrorState *error = nullptr;
1131 if (answer.positive()) {
1133 } else {
1134 error = answer.squidError.get();
1135 Must(error);
1136 answer.squidError.clear(); // preserve error for errorSendComplete()
1137 }
1138 assert(error);
1140 retryOrBail("tunneler error");
1141}
1142
1143void
1145{
1147 commitToServer(conn);
1148
1150 tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1151 else {
1153 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1156 const auto mb = al->reply->pack();
1157 client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1158 delete mb;
1159 }
1160}
1161
1162void
1164{
1165 committedToServer = true;
1166 banRetries = "committed to server";
1167 PeerSelectionInitiator::subscribed = false; // may already be false
1168 server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1169}
1170
1171static void
1172tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
1173{
1174 TunnelStateData *tunnelState = (TunnelStateData *)data;
1175 debugs(26, 3, "FD " << fd);
1176 assert(tunnelState != nullptr);
1177 /* temporary lock to save our own feet (comm_close -> tunnelClientClosed -> Free) */
1178 CbcPointer<TunnelStateData> safetyLock(tunnelState);
1179
1180 if (Comm::IsConnOpen(tunnelState->client.conn))
1181 tunnelState->client.conn->close();
1182
1183 if (Comm::IsConnOpen(tunnelState->server.conn))
1184 tunnelState->server.conn->close();
1185}
1186
1187void
1189{
1191
1192 updateAttempts(answer.n_tries);
1193
1194 ErrorState *error = nullptr;
1195 if ((error = answer.error.get())) {
1196 banRetries = "HappyConnOpener gave up";
1197 Must(!Comm::IsConnOpen(answer.conn));
1198 syncHierNote(answer.conn, request->url.host());
1199 answer.error.clear();
1200 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1202 closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1203 }
1204
1205 if (error) {
1207 retryOrBail("tried all destinations");
1208 return;
1209 }
1210
1211 connectDone(answer.conn, request->url.host(), answer.reused);
1212}
1213
1214void
1215TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
1216{
1217 Must(Comm::IsConnOpen(conn));
1218
1219 if (reused)
1221 // else Comm::ConnOpener already applied proper/current markings
1222
1223 // TODO: add pconn race state tracking
1224
1225 syncHierNote(conn, origin);
1226
1227#if USE_DELAY_POOLS
1228 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1229 if (conn->getPeer() && conn->getPeer()->options.no_delay)
1231#endif
1232
1234
1235 bool toOrigin = false; // same semantics as StateFlags::toOrigin
1236 if (const auto * const peer = conn->getPeer()) {
1237 request->prepForPeering(*peer);
1238 toOrigin = peer->options.originserver;
1239 } else {
1241 toOrigin = true;
1242 }
1243
1244 if (!toOrigin)
1245 connectToPeer(conn);
1246 else {
1248 }
1249}
1250
1252bool
1257
1258void
1260{
1261 debugs(26, 3, MYNAME);
1262 /* Create state structure. */
1263 TunnelStateData *tunnelState = nullptr;
1264 ErrorState *err = nullptr;
1266 char *url = http->uri;
1267
1268 /*
1269 * client_addr.isNoAddr() indicates this is an "internal" request
1270 * from peer_digest.c, asn.c, netdb.c, etc and should always
1271 * be allowed. yuck, I know.
1272 */
1273
1275 /*
1276 * Check if this host is allowed to fetch MISSES from us (miss_access)
1277 * default is to allow.
1278 */
1280 ch.al = http->al;
1282 ch.my_addr = request->my_addr;
1284 if (ch.fastCheck().denied()) {
1285 debugs(26, 4, "MISS access forbidden.");
1290 return;
1291 }
1292 }
1293
1294 debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1297
1298 tunnelState = new TunnelStateData(http);
1299#if USE_DELAY_POOLS
1301#endif
1302 tunnelState->startSelectingDestinations(request, http->al, nullptr);
1303}
1304
1305void
1307{
1308 if (const auto p = conn->getPeer()) {
1309 if (p->secure.encryptTransport)
1310 return advanceDestination("secure connection to peer", conn, [this,&conn] {
1312 });
1313 }
1314
1315 connectedToPeer(conn);
1316}
1317
1319void
1321{
1322 const auto callback = asyncCallback(5, 4, TunnelStateData::noteSecurityPeerConnectorAnswer, this);
1323 const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
1324 encryptionWait.start(connector, callback);
1325}
1326
1328template <typename StepStart>
1329void
1330TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1331{
1332 // TODO: Extract destination-specific handling from TunnelStateData so that
1333 // all the awkward, limited-scope advanceDestination() calls can be replaced
1334 // with a single simple try/catch,retry block.
1335 try {
1336 startStep();
1337 // now wait for the step callback
1338 } catch (...) {
1339 debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1340 closePendingConnection(conn, "connection preparation exception");
1341 if (!savedError)
1343 retryOrBail(stepDescription);
1344 }
1345}
1346
1348void
1350{
1352
1353 ErrorState *error = nullptr;
1354 assert(!answer.tunneled);
1355 if ((error = answer.error.get())) {
1356 assert(!answer.conn);
1357 answer.error.clear();
1358 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1360 closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1361 }
1362
1363 if (error) {
1365 retryOrBail("TLS peer connection error");
1366 return;
1367 }
1368
1369 connectedToPeer(answer.conn);
1370}
1371
1372void
1374{
1375 advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1377 });
1378}
1379
1380void
1382{
1383 const auto callback = asyncCallback(5, 4, TunnelStateData::tunnelEstablishmentDone, this);
1384 const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
1385#if USE_DELAY_POOLS
1386 tunneler->setDelayId(server.delayId);
1387#endif
1388 peerWait.start(tunneler, callback);
1389}
1390
1391void
1393{
1394 destinationsFound = true;
1395
1396 if (!path) { // decided to use a pinned connection
1397 // We can call usePinned() without fear of clashing with an earlier
1398 // forwarding attempt because PINNED must be the first destination.
1400 usePinned();
1401 return;
1402 }
1403
1404 destinations->addPath(path);
1405
1406 if (transportWait) {
1407 assert(!transporting());
1409 return; // and continue to wait for tunnelConnectDone() callback
1410 }
1411
1412 if (transporting())
1413 return; // and continue to receive destinations for backup
1414
1416}
1417
1418void
1420{
1423 if (!destinationsFound) {
1424
1425 // XXX: Honor clientExpectsConnectResponse() before replying.
1426
1427 if (selectionError)
1428 return sendError(selectionError, "path selection has failed");
1429
1430 // TODO: Merge with FwdState and remove this likely unnecessary check.
1431 if (savedError)
1432 return sendError(savedError, "path selection found no paths (with an impossible early error)");
1433
1435 "path selection found no paths");
1436 }
1437 // else continue to use one of the previously noted destinations;
1438 // if all of them fail, tunneling as whole will fail
1439 Must(!selectionError); // finding at least one path means selection succeeded
1440
1441 if (transportWait) {
1442 assert(!transporting());
1444 return; // and continue to wait for the noteConnection() callback
1445 }
1446
1447 if (transporting()) {
1448 // We are already using a previously opened connection (but were also
1449 // receiving more destinations in case we need to re-forward).
1450 debugs(17, 7, "keep transporting");
1451 return;
1452 }
1453
1454 // destinationsFound, but none of them worked, and we were waiting for more
1455 debugs(17, 7, "no more destinations to try after " << n_tries << " failed attempts");
1456 if (!savedError) {
1457 // retryOrBail() must be preceded by saveError(), but in case we forgot:
1458 const auto finalError = new ErrorState(ERR_CANNOT_FORWARD, Http::scBadGateway, request.getRaw(), al);
1459 static const auto d = MakeNamedErrorDetail("RETRY_TO_NONE");
1460 finalError->detailError(d);
1461 saveError(finalError);
1462 } // else use actual error from last forwarding attempt
1463
1464 // XXX: Honor clientExpectsConnectResponse() before replying.
1465 sendError(savedError, "all found paths have failed");
1466}
1467
1471bool
1476
1478void
1480{
1481 debugs(26, 4, savedError << " ? " << error);
1482 assert(error);
1483 delete savedError; // may be nil
1484 savedError = error;
1485}
1486
1489void
1490TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1491{
1492 debugs(26, 3, "aborting transaction for " << reason);
1493
1495
1496 cancelStep(reason);
1497
1498 assert(finalError);
1499
1500 // get rid of any cached error unless that is what the caller is sending
1501 if (savedError != finalError)
1502 delete savedError; // may be nil
1503 savedError = nullptr;
1504
1505 // we cannot try other destinations after responding with an error
1506 PeerSelectionInitiator::subscribed = false; // may already be false
1507
1508 *status_ptr = finalError->httpStatus;
1509 finalError->callback = tunnelErrorComplete;
1510 finalError->callback_data = this;
1511 errorSend(client.conn, finalError);
1512}
1513
1517void
1519{
1520 transportWait.cancel(reason);
1521 encryptionWait.cancel(reason);
1522 peerWait.cancel(reason);
1523}
1524
1525void
1527{
1529 assert(!transporting());
1530
1531 delete savedError; // may still be nil
1532 savedError = nullptr;
1534
1535 const auto callback = asyncCallback(17, 5, TunnelStateData::noteConnection, this);
1536 const auto cs = new HappyConnOpener(destinations, callback, request, startTime, n_tries, al);
1537 cs->setHost(request->url.host());
1538 cs->setRetriable(false);
1539 cs->allowPersistent(false);
1540 destinations->notificationPending = true; // start() is async
1541 transportWait.start(cs, callback);
1542}
1543
1545void
1547{
1548 Must(request);
1549 const auto connManager = request->pinnedConnection();
1550 Comm::ConnectionPointer serverConn = nullptr;
1551
1552 try {
1554 debugs(26, 7, "pinned peer connection: " << serverConn);
1555 } catch (ErrorState * const error) {
1556 syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1557 // XXX: Honor clientExpectsConnectResponse() before replying.
1558 // a PINNED path failure is fatal; do not wait for more paths
1559 sendError(error, "pinned path failure");
1560 return;
1561 }
1562
1564
1565 // Set HttpRequest pinned related flags for consistency even if
1566 // they are not really used by tunnel.cc code.
1567 request->flags.pinned = true;
1568
1569 Assure(connManager);
1570 if (connManager->pinnedAuth())
1571 request->flags.auth = true;
1572
1573 // the server may close the pinned connection before this request
1574 const auto reused = true;
1575 connectDone(serverConn, connManager->pinning.host, reused);
1576}
1577
1579
1580bool
1585
1586#if USE_DELAY_POOLS
1587void
1589{
1590 delayId = newDelay;
1591}
1592
1593#endif
1594
1596void
1598{
1600 debugs(17, 7, "reusing pending notification");
1601 } else {
1603 CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
1604 }
1605}
1606
1614void
1616{
1617 Must(Comm::IsConnOpen(clientConn));
1618 Must(Comm::IsConnOpen(srvConn));
1619
1620 debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1621
1622 /* Create state structure. */
1625
1626 auto conn = request->clientConnectionManager.get();
1627 Must(conn);
1628 Http::StreamPointer context = conn->pipeline.front();
1629 Must(context && context->http);
1630
1631 debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1632
1633 TunnelStateData *tunnelState = new TunnelStateData(context->http);
1634 tunnelState->commitToServer(srvConn);
1635
1636 request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1637
1638#if USE_DELAY_POOLS
1639 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1640 if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
1641 tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1642#endif
1643
1644 debugs(26, 4, "determine post-connect handling pathway.");
1645 if (const auto peer = srvConn->getPeer())
1646 request->prepForPeering(*peer);
1647 else
1649
1650 tunnelState->preReadServerData = preReadServerData;
1651
1652 tunnelStartShoveling(tunnelState);
1653}
1654
#define Assure(condition)
Definition Assure.h:35
#define asyncCallback(dbgSection, dbgLevel, method, object)
#define CallJobHere(debugSection, debugLevel, job, Class, method)
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
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
Definition Detail.cc:54
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition FwdState.cc:1569
@ LOG_TCP_TUNNEL
an attempt to establish a bidirectional TCP tunnel
Definition LogTags.h:59
int size
Definition ModDevPoll.cc:70
time_t squid_curtime
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition Read.h:59
class SquidConfig Config
StatCounters statCounter
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
#define Must(condition)
void error(char *format,...)
#define assert(EX)
Definition assert.h:17
#define SQUID_TCP_SO_RCVBUF
Definition autoconf.h:1458
static char server[MAXLINE]
int cbdataReferenceValid(const void *p)
Definition cbdata.cc:270
#define CBDATA_CLASS_INIT(type)
Definition cbdata.h:325
Acl::Answer const & fastCheck()
Definition Checklist.cc:298
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:88
void host(const char *src)
Definition Uri.cc:154
struct CachePeer::@20 options
char * host
Definition CachePeer.h:66
bool no_delay
Definition CachePeer.h:128
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()
static void Reset()
forgets the current context, setting it to nil/unknown
Comm::ConnectionPointer conn
Definition CommCalls.h:80
InstanceId< Connection, uint64_t > id
Definition Connection.h:184
CachePeer * getPeer() const
Ssl::ServerBump * serverBump()
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
static DelayId DelayClient(ClientHttpRequest *, HttpReply *reply=nullptr)
Definition DelayId.cc:64
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:431
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 resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
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
void prepForDirect()
get ready to be sent directly to an origin server, excluding originserver
void prepForPeering(const CachePeer &peer)
get ready to be sent to the given cache_peer, including originserver
HttpRequestMethod method
HierarchyLogEntry hier
RequestFlags flags
ConnStateData * pinnedConnection()
Ip::Address my_addr
AnyP::Uri url
the request URI
Ip::Address client_addr
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:304
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:63
uint64_t payloadData
total size of payload block(s) excluding transfer encoding overheads
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)
void stop()
pauses timer if stop() has not been called
Definition FwdState.h:64
Definition Raw.h:21
C * getRaw() const
Definition RefCount.h:89
bool interceptTproxy
Set for requests handled by a "tproxy" port.
bool forceTunnel
whether to forward via TunnelStateData (instead of FwdState)
bool notificationPending
whether HappyConnOpener::noteCandidatesChange() is scheduled to fire
bool empty() const
whether we lack any known candidate paths
bool destinationsFinalized
whether all of the available candidate paths received from DNS
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:419
bool isEmpty() const
Definition SBuf.h:435
SBuf & append(const SBuf &S)
Definition SBuf.cc:185
A PeerConnector for TLS cache_peers and origin servers. 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
int forward_max_tries
struct SquidConfig::@77 Timeout
time_t lifetime
struct SquidConfig::@91 accessList
acl_access * miss
bool at(const BumpStep stp) const
whether we are currently performing the given processing step
Definition ServerBump.h:47
ByteCounter kbytes_out
struct StatCounters::@105 server
ByteCounter kbytes_in
struct StatCounters::@105::@115 other
struct StatCounters::@104 client_http
struct StatCounters::@105::@115 all
const char *const side
Definition tunnel.cc:164
void noteClosure()
reacts to the external closure of our connection
Definition tunnel.cc:868
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition tunnel.cc:561
void bytesIn(int const &)
Definition tunnel.cc:572
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:847
void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
initiates Comm::Connection ownership, including closure monitoring
Definition tunnel.cc:856
void error(int const xerrno)
Definition tunnel.cc:659
bool receivedEof
whether read() has returned zero bytes
Definition tunnel.cc:175
void dataSent(size_t amount)
Definition tunnel.cc:834
void setDelayId(DelayId const &)
Definition tunnel.cc:1588
Comm::ConnectionPointer conn
The currently connected connection.
Definition tunnel.cc:170
AsyncCall::Pointer writer
pending Comm::Write callback
Definition tunnel.cc:167
Connection(const char *aSide)
Definition tunnel.cc:482
uint8_t delayedLoops
how many times a read on this connection has been postponed.
Definition tunnel.cc:171
AsyncCall::Pointer closer
the registered close handler for the connection
Definition tunnel.cc:188
bool dirty
whether write() has been called (at least once)
Definition tunnel.cc:173
TunnelStateData * readPending
Definition tunnel.cc:178
int debugLevelForError(int const xerrno) const
Definition tunnel.cc:607
void noteEof()
reacts to a successful zero-size read(2)
Definition tunnel.cc:877
static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition tunnel.cc:669
const char * banRetries
a reason to ban reforwarding attempts (or nil)
Definition tunnel.cc:206
SBuf preReadClientData
Definition tunnel.cc:194
void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition tunnel.cc:634
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition tunnel.cc:212
void closeConnections()
closes both client and server connections
Definition tunnel.cc:943
void copyServerBytes()
Definition tunnel.cc:1023
void notePeerReadyToShovel(const Comm::ConnectionPointer &)
called when negotiations with the peer have been successfully completed
Definition tunnel.cc:1144
CbcPointer< ClientHttpRequest > http
Definition tunnel.cc:95
void copyRead(Connection &from, Connection &to, IOCB *completion)
Definition tunnel.cc:984
void sendError(ErrorState *finalError, const char *reason)
Definition tunnel.cc:1490
void serverClosed()
handles Squid-to-server connection closure; may destroy us
Definition tunnel.cc:348
void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition tunnel.cc:884
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition tunnel.cc:1597
void updateAttempts(int)
sets n_tries to the given value (while keeping ALE in sync)
Definition tunnel.cc:593
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition tunnel.cc:1101
void finishWritingAndDelete(Connection &)
Definition tunnel.cc:377
bool noConnections() const
Definition tunnel.cc:1581
Connection client
Definition tunnel.cc:191
void noteDestinationsEnd(ErrorState *selectionError) override
Definition tunnel.cc:1419
void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
Start using an established connection.
Definition tunnel.cc:1215
CBDATA_CHILD(TunnelStateData)
void connectedToPeer(const Comm::ConnectionPointer &)
called after connection setup (including any encryption)
Definition tunnel.cc:1373
const char * getHost() const
Definition tunnel.cc:99
TunnelStateData(const TunnelStateData &)
void noteConnection(HappyConnOpenerAnswer &)
Definition tunnel.cc:1188
static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition tunnel.cc:824
void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition tunnel.cc:678
TunnelStateData(ClientHttpRequest *)
Definition tunnel.cc:438
const char * checkRetry()
Definition tunnel.cc:503
TunnelStateData & operator=(const TunnelStateData &)
void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition tunnel.cc:781
void saveError(ErrorState *finalError)
remembers an error to be used if there will be no more connection attempts
Definition tunnel.cc:1479
HttpRequest::Pointer request
Definition tunnel.cc:96
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition tunnel.cc:1546
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition tunnel.cc:1381
int n_tries
the number of forwarding attempts so far
Definition tunnel.cc:203
void connectToPeer(const Comm::ConnectionPointer &)
continue to set up connection to a peer, going async for SSL peers
Definition tunnel.cc:1306
SBuf preReadServerData
Definition tunnel.cc:195
void copyClientBytes()
Definition tunnel.cc:1008
void startConnecting()
Definition tunnel.cc:1526
void copy(size_t len, Connection &from, Connection &to, IOCB *)
Definition tunnel.cc:761
void commitToServer(const Comm::ConnectionPointer &)
Definition tunnel.cc:1163
void retryOrBail(const char *context)
Definition tunnel.cc:525
void clientClosed()
handles client-to-Squid connection closure; may destroy us
Definition tunnel.cc:366
ResolvedPeersPointer destinations
paths for forwarding the request
Definition tunnel.cc:197
PeeringActivityTimer peeringTimer
Measures time spent on selecting and communicating with peers.
Definition tunnel.cc:222
void syncHierNote(const Comm::ConnectionPointer &server, const char *origin)
Definition tunnel.cc:585
void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
Definition tunnel.cc:934
void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &)
callback handler for the Security::PeerConnector encryptor
Definition tunnel.cc:1349
void deleteThis()
destroys the tunnel (after performing potentially-throwing cleanup)
Definition tunnel.cc:415
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:1330
int * status_ptr
pointer for logging HTTP status
Definition tunnel.cc:192
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition tunnel.cc:703
bool committedToServer
whether the decision to tunnel to a particular destination was final
Definition tunnel.cc:201
bool clientExpectsConnectResponse() const
Whether the client sent a CONNECT request to us.
Definition tunnel.cc:108
Connection server
Definition tunnel.cc:191
ErrorState * savedError
details of the "last tunneling attempt" failure (if it failed)
Definition tunnel.cc:268
static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition tunnel.cc:624
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition tunnel.cc:215
void cancelStep(const char *reason)
Definition tunnel.cc:1518
bool destinationsFound
At least one candidate path found.
Definition tunnel.cc:198
CodeContext::Pointer codeContext
our creator context
Definition tunnel.cc:209
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer
Definition tunnel.cc:1320
JobWait< Http::Tunneler > peerWait
Definition tunnel.cc:219
~TunnelStateData() override
Definition tunnel.cc:473
time_t startTime
object creation time, before any peer selection/connection attempts
Definition tunnel.cc:196
AccessLogEntryPointer al
Definition tunnel.cc:97
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition tunnel.cc:1253
bool transporting() const
Definition tunnel.cc:1472
void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition tunnel.cc:1392
static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition tunnel.cc:771
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition comm.cc:942
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition comm.cc:594
int ignoreErrno(int ierrno)
Definition comm.cc:1407
#define DBG_DATA
Definition Stream.h:40
#define MYNAME
Definition Stream.h:219
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
@ 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:792
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:48
@ scInternalServerError
Definition StatusCode.h:73
@ scNone
Definition StatusCode.h:21
@ scOkay
Definition StatusCode.h:27
@ scBadGateway
Definition StatusCode.h:75
@ scServiceUnavailable
Definition StatusCode.h:76
bool IsReforwardableStatus(StatusCode)
whether to send the request to another peer based on the current response status code
#define xfree
#define xstrdup
#define xmalloc
void netdbPingSite(const char *hostname)
Definition net_db.cc:811
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 auto & guaranteedRequest(const ClientHttpRequest *const cr)
safely extracts HttpRequest from a never-nil ClientHttpRequest pointer
Definition tunnel.cc:431
static CLCB tunnelServerClosed
Definition tunnel.cc:304
static CTCB tunnelTimeout
Definition tunnel.cc:306
static std::ostream & operator<<(std::ostream &os, const TunnelStateData::Connection &c)
Definition tunnel.cc:311
void tunnelStart(ClientHttpRequest *http)
Definition tunnel.cc:1259
static ERCB tunnelErrorComplete
Definition tunnel.cc:303
static EVH tunnelDelayedClientRead
Definition tunnel.cc:307
static void tunnelStartShoveling(TunnelStateData *tunnelState)
Definition tunnel.cc:1042
static EVH tunnelDelayedServerRead
Definition tunnel.cc:308
static void tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
Definition tunnel.cc:1080
void switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
Definition tunnel.cc:1615
static CLCB tunnelClientClosed
Definition tunnel.cc:305
#define INT_MAX
Definition types.h:70
#define safe_free(x)
Definition xalloc.h:73
const char * xstrerr(int error)
Definition xstrerror.cc:83