From: Christos Tsantilas Date: Fri, 2 May 2014 15:15:18 +0000 (+0300) Subject: First implementation of do splice. Works only if the openSSL version of client and... X-Git-Tag: SQUID_3_5_0_1~89^2~20^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=93ead3fdee9c68c63b9e4e90b01ae10de8f28442;p=thirdparty%2Fsquid.git First implementation of do splice. Works only if the openSSL version of client and squid are the same and compiled to support similar set of features --- diff --git a/src/FwdState.cc b/src/FwdState.cc index 3e492e37f6..8d11b75d6d 100644 --- a/src/FwdState.cc +++ b/src/FwdState.cc @@ -703,7 +703,7 @@ FwdState::connectDone(const Comm::ConnectionPointer &conn, comm_err_t status, in "FwdState::ConnectedToPeer", FwdStatePeerAnswerDialer(&FwdState::connectedToPeer, this)); Ssl::PeerConnector *connector = - new Ssl::PeerConnector(requestPointer, serverConnection(), callback); + new Ssl::PeerConnector(requestPointer, serverConnection(), clientConn, callback); AsyncJob::Start(connector); // will call our callback return; } diff --git a/src/ssl/PeerConnector.cc b/src/ssl/PeerConnector.cc index 0682abdce0..01e6332401 100644 --- a/src/ssl/PeerConnector.cc +++ b/src/ssl/PeerConnector.cc @@ -29,10 +29,12 @@ CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeerConnector); Ssl::PeerConnector::PeerConnector( HttpRequestPointer &aRequest, const Comm::ConnectionPointer &aServerConn, + const Comm::ConnectionPointer &aClientConn, AsyncCall::Pointer &aCallback): AsyncJob("Ssl::PeerConnector"), request(aRequest), serverConn(aServerConn), + clientConn(aClientConn), callback(aCallback) { // if this throws, the caller's cb dialer is not our CbDialer @@ -262,6 +264,7 @@ Ssl::PeerConnector::negotiateSsl() callBack(); } +void switchToTunnel(HttpRequest *request, int *status_ptr, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn); void Ssl::PeerConnector::checkForPeekAndSplice() { @@ -269,13 +272,17 @@ Ssl::PeerConnector::checkForPeekAndSplice() BIO *b = SSL_get_rbio(ssl); Ssl::ServerBio *srvBio = static_cast(b->ptr); debugs(83,5, "Will check for peek and splice on fd " << serverConn->fd); - const bool splice = false; + const bool splice = true; if (!splice) { //Allow write, proceed with the connection srvBio->holdWrite(false); srvBio->recordInput(false); Comm::SetSelect(serverConn->fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0); debugs(83,5, "Retry the fwdNegotiateSSL on fd " << serverConn->fd); + } else { + static int status_code = 0; + debugs(83,5, "Revert to tunnel fd " << clientConn->fd << " with fd " << serverConn->fd); + switchToTunnel(request.getRaw(), &status_code, clientConn, serverConn); } } diff --git a/src/ssl/PeerConnector.h b/src/ssl/PeerConnector.h index 44c94eb51e..8ab4b702ab 100644 --- a/src/ssl/PeerConnector.h +++ b/src/ssl/PeerConnector.h @@ -97,6 +97,7 @@ public: public: PeerConnector(HttpRequestPointer &aRequest, const Comm::ConnectionPointer &aServerConn, + const Comm::ConnectionPointer &aClientConn, AsyncCall::Pointer &aCallback); virtual ~PeerConnector(); @@ -159,6 +160,7 @@ private: HttpRequestPointer request; ///< peer connection trigger or cause Comm::ConnectionPointer serverConn; ///< TCP connection to the peer + Comm::ConnectionPointer clientConn; ///< TCP connection to the client AsyncCall::Pointer callback; ///< we call this with the results AsyncCall::Pointer closeHandler; ///< we call this when the connection closed diff --git a/src/tunnel.cc b/src/tunnel.cc index 7e491338b8..d8a4d8f4e2 100644 --- a/src/tunnel.cc +++ b/src/tunnel.cc @@ -43,6 +43,7 @@ #include "comm/Write.h" #include "errorpage.h" #include "fde.h" +#include "globals.h" #include "FwdState.h" #include "http.h" #include "HttpRequest.h" @@ -53,6 +54,7 @@ #include "SquidConfig.h" #include "StatCounters.h" #if USE_OPENSSL +#include "ssl/bio.h" #include "ssl/PeerConnector.h" #endif #include "tools.h" @@ -949,6 +951,7 @@ tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr, const void TunnelStateData::connectToPeer() { const Comm::ConnectionPointer &srv = server.conn; + const Comm::ConnectionPointer &cln = client.conn; #if USE_OPENSSL if (CachePeer *p = srv->getPeer()) { @@ -957,7 +960,7 @@ TunnelStateData::connectToPeer() { "TunnelStateData::ConnectedToPeer", MyAnswerDialer(&TunnelStateData::connectedToPeer, this)); Ssl::PeerConnector *connector = - new Ssl::PeerConnector(request, srv, callback); + new Ssl::PeerConnector(request, srv, cln, callback); AsyncJob::Start(connector); // will call our callback return; } @@ -1087,3 +1090,76 @@ TunnelStateData::Connection::setDelayId(DelayId const &newDelay) } #endif + +int default_read_method(int, char *, int); +int default_write_method(int, const char *, int); +void +switchToTunnel(HttpRequest *request, int *status_ptr, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn) +{ + debugs(26, 3, HERE); + /* Create state structure. */ + TunnelStateData *tunnelState = NULL; + const char *url = urlCanonical(request); + + debugs(26, 3, HERE << "'" << request->method << " " << url << " " << request->http_ver << "'"); + ++statCounter.server.all.requests; + ++statCounter.server.other.requests; + + tunnelState = new TunnelStateData; +#if USE_DELAY_POOLS + //tunnelState->server.setDelayId(DelayId::DelayClient(http)); +#endif + tunnelState->url = xstrdup(url); + tunnelState->request = request; + tunnelState->server.size_ptr = NULL;//???? + tunnelState->status_ptr = status_ptr; + tunnelState->client.conn = clientConn; + + comm_add_close_handler(tunnelState->client.conn->fd, + tunnelClientClosed, + tunnelState); + + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); + commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall); + fd_table[clientConn->fd].read_method = &default_read_method; + fd_table[clientConn->fd].write_method = &default_write_method; + +//Server connection +#if USE_DELAY_POOLS + /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */ +// if (conn->getPeer() && conn->getPeer()->options.no_delay) +// tunnelState->server.setDelayId(DelayId()); +#endif + + tunnelState->request->hier.note(srvConn, tunnelState->getHost()); + + tunnelState->server.conn = srvConn; + tunnelState->request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : NULL; + comm_add_close_handler(srvConn->fd, tunnelServerClosed, tunnelState); + + debugs(26, 4, HERE << "determine post-connect handling pathway."); + if (srvConn->getPeer()) { + tunnelState->request->peer_login = srvConn->getPeer()->login; + tunnelState->request->flags.proxying = !(srvConn->getPeer()->options.originserver); + } else { + tunnelState->request->peer_login = NULL; + tunnelState->request->flags.proxying = false; + } + + timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); + commSetConnTimeout(srvConn, Config.Timeout.read, timeoutCall); + fd_table[srvConn->fd].read_method = &default_read_method; + fd_table[srvConn->fd].write_method = &default_write_method; + + SSL *ssl = fd_table[srvConn->fd].ssl; + assert(ssl); + BIO *b = SSL_get_rbio(ssl); + Ssl::ServerBio *srvBio = static_cast(b->ptr); + const MemBuf &buf = srvBio->rBufData(); + + AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone", + CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState)); + Comm::Write(tunnelState->client.conn, buf.content(), buf.contentSize(), call, NULL); +}