]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
merge from trunk r13421
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Thu, 22 May 2014 15:38:42 +0000 (18:38 +0300)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Thu, 22 May 2014 15:38:42 +0000 (18:38 +0300)
1  2 
configure.ac
src/FwdState.cc
src/PeerPoolMgr.cc
src/cache_cf.cc
src/cf.data.pre
src/client_side.cc
src/ssl/PeerConnector.cc
src/ssl/PeerConnector.h
src/tunnel.cc

diff --cc configure.ac
Simple merge
diff --cc src/FwdState.cc
index 8d11b75d6d4ab611927fc32e56f99eba3281597f,8dc659584980c5f2944d0a464ea0a99b03579c69..07aa7166fa1d58ef2a64381785336fb36229f70e
@@@ -700,10 -708,10 +708,10 @@@ FwdState::connectDone(const Comm::Conne
  
              HttpRequest::Pointer requestPointer = request;
              AsyncCall::Pointer callback = asyncCall(17,4,
-                 "FwdState::ConnectedToPeer",
-                 FwdStatePeerAnswerDialer(&FwdState::connectedToPeer, this));
+                                                     "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;
          }
index 0000000000000000000000000000000000000000,04124000ea3a07b3fc872b7c24e4683001ec8bab..14b99683e96ee8d56b5fda098ff9a69cc8920834
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,284 +1,284 @@@
 -            new Ssl::PeerConnector(request, params.conn, securer);
+ #include "squid.h"
+ #include "base/AsyncJobCalls.h"
+ #include "base/RunnersRegistry.h"
+ #include "CachePeer.h"
+ #include "comm/Connection.h"
+ #include "comm/ConnOpener.h"
+ #include "Debug.h"
+ #include "fd.h"
+ #include "FwdState.h"
+ #include "globals.h"
+ #include "HttpRequest.h"
+ #include "neighbors.h"
+ #include "pconn.h"
+ #include "PeerPoolMgr.h"
+ #include "SquidConfig.h"
+ #if USE_OPENSSL
+ #include "ssl/PeerConnector.h"
+ #endif
+ CBDATA_CLASS_INIT(PeerPoolMgr);
+ #if USE_OPENSSL
+ /// Gives Ssl::PeerConnector access to Answer in the PeerPoolMgr callback dialer.
+ class MyAnswerDialer: public UnaryMemFunT<PeerPoolMgr, Ssl::PeerConnectorAnswer, Ssl::PeerConnectorAnswer&>,
+         public Ssl::PeerConnector::CbDialer
+ {
+ public:
+     MyAnswerDialer(const JobPointer &aJob, Method aMethod):
+             UnaryMemFunT<PeerPoolMgr, Ssl::PeerConnectorAnswer, Ssl::PeerConnectorAnswer&>(aJob, aMethod, Ssl::PeerConnectorAnswer()) {}
+     /* Ssl::PeerConnector::CbDialer API */
+     virtual Ssl::PeerConnectorAnswer &answer() { return arg1; }
+ };
+ #endif
+ PeerPoolMgr::PeerPoolMgr(CachePeer *aPeer): AsyncJob("PeerPoolMgr"),
+         peer(cbdataReference(aPeer)),
+         request(),
+         opener(),
+         securer(),
+         closer(),
+         addrUsed(0)
+ {
+ }
+ PeerPoolMgr::~PeerPoolMgr()
+ {
+     cbdataReferenceDone(peer);
+ }
+ void
+ PeerPoolMgr::start()
+ {
+     AsyncJob::start();
+     // ErrorState, getOutgoingAddress(), and other APIs may require a request.
+     // We fake one. TODO: Optionally send this request to peers?
+     request = new HttpRequest(Http::METHOD_OPTIONS, AnyP::PROTO_HTTP, "*");
+     request->SetHost(peer->host);
+     checkpoint("peer initialized");
+ }
+ void
+ PeerPoolMgr::swanSong()
+ {
+     AsyncJob::swanSong();
+ }
+ bool
+ PeerPoolMgr::validPeer() const
+ {
+     return peer && cbdataReferenceValid(peer) && peer->standby.pool;
+ }
+ bool
+ PeerPoolMgr::doneAll() const
+ {
+     return !(validPeer() && peer->standby.limit) && AsyncJob::doneAll();
+ }
+ void
+ PeerPoolMgr::handleOpenedConnection(const CommConnectCbParams &params)
+ {
+     opener = NULL;
+     if (!validPeer()) {
+         debugs(48, 3, "peer gone");
+         if (params.conn != NULL)
+             params.conn->close();
+         return;
+     }
+     if (params.flag != COMM_OK) {
+         /* it might have been a timeout with a partially open link */
+         if (params.conn != NULL)
+             params.conn->close();
+         peerConnectFailed(peer);
+         checkpoint("conn opening failure"); // may retry
+         return;
+     }
+     Must(params.conn != NULL);
+ #if USE_OPENSSL
+     // Handle SSL peers.
+     if (peer->use_ssl) {
+         typedef CommCbMemFunT<PeerPoolMgr, CommCloseCbParams> CloserDialer;
+         closer = JobCallback(48, 3, CloserDialer, this,
+                              PeerPoolMgr::handleSecureClosure);
+         comm_add_close_handler(params.conn->fd, closer);
+         securer = asyncCall(48, 4, "PeerPoolMgr::handleSecuredPeer",
+                             MyAnswerDialer(this, &PeerPoolMgr::handleSecuredPeer));
+         Ssl::PeerConnector *connector =
++            new Ssl::PeerConnector(request, params.conn, NULL, securer);
+         AsyncJob::Start(connector); // will call our callback
+         return;
+     }
+ #endif
+     pushNewConnection(params.conn);
+ }
+ void
+ PeerPoolMgr::pushNewConnection(const Comm::ConnectionPointer &conn)
+ {
+     Must(validPeer());
+     Must(Comm::IsConnOpen(conn));
+     peer->standby.pool->push(conn, NULL /* domain */);
+     // push() will trigger a checkpoint()
+ }
+ #if USE_OPENSSL
+ void
+ PeerPoolMgr::handleSecuredPeer(Ssl::PeerConnectorAnswer &answer)
+ {
+     Must(securer != NULL);
+     securer = NULL;
+     if (closer != NULL) {
+         if (answer.conn != NULL)
+             comm_remove_close_handler(answer.conn->fd, closer);
+         else
+             closer->cancel("securing completed");
+         closer = NULL;
+     }
+     if (!validPeer()) {
+         debugs(48, 3, "peer gone");
+         if (answer.conn != NULL)
+             answer.conn->close();
+         return;
+     }
+     if (answer.error.get()) {
+         if (answer.conn != NULL)
+             answer.conn->close();
+         // PeerConnector calls peerConnectFailed() for us;
+         checkpoint("conn securing failure"); // may retry
+         return;
+     }
+     pushNewConnection(answer.conn);
+ }
+ void
+ PeerPoolMgr::handleSecureClosure(const CommCloseCbParams &params)
+ {
+     Must(closer != NULL);
+     Must(securer != NULL);
+     securer->cancel("conn closed by a 3rd party");
+     securer = NULL;
+     closer = NULL;
+     // allow the closing connection to fully close before we check again
+     Checkpoint(this, "conn closure while securing");
+ }
+ #endif
+ void
+ PeerPoolMgr::openNewConnection()
+ {
+     // KISS: Do nothing else when we are already doing something.
+     if (opener != NULL || securer != NULL || shutting_down) {
+         debugs(48, 7, "busy: " << opener << '|' << securer << '|' << shutting_down);
+         return; // there will be another checkpoint when we are done opening/securing
+     }
+     // Do not talk to a peer until it is ready.
+     if (!neighborUp(peer)) // provides debugging
+         return; // there will be another checkpoint when peer is up
+     // Do not violate peer limits.
+     if (!peerCanOpenMore(peer)) { // provides debugging
+         peer->standby.waitingForClose = true; // may already be true
+         return; // there will be another checkpoint when a peer conn closes
+     }
+     // Do not violate global restrictions.
+     if (fdUsageHigh()) {
+         debugs(48, 7, "overwhelmed");
+         peer->standby.waitingForClose = true; // may already be true
+         // There will be another checkpoint when a peer conn closes OR when
+         // a future pop() fails due to an empty pool. See PconnPool::pop().
+         return;
+     }
+     peer->standby.waitingForClose = false;
+     Comm::ConnectionPointer conn = new Comm::Connection;
+     Must(peer->n_addresses); // guaranteed by neighborUp() above
+     // cycle through all available IP addresses
+     conn->remote = peer->addresses[addrUsed++ % peer->n_addresses];
+     conn->remote.port(peer->http_port);
+     conn->peerType = STANDBY_POOL; // should be reset by peerSelect()
+     conn->setPeer(peer);
+     getOutgoingAddress(request.getRaw(), conn);
+     GetMarkingsToServer(request.getRaw(), *conn);
+     const int ctimeout = peer->connect_timeout > 0 ?
+                          peer->connect_timeout : Config.Timeout.peer_connect;
+     typedef CommCbMemFunT<PeerPoolMgr, CommConnectCbParams> Dialer;
+     opener = JobCallback(48, 5, Dialer, this, PeerPoolMgr::handleOpenedConnection);
+     Comm::ConnOpener *cs = new Comm::ConnOpener(conn, opener, ctimeout);
+     AsyncJob::Start(cs);
+ }
+ void
+ PeerPoolMgr::closeOldConnections(const int howMany)
+ {
+     debugs(48, 8, howMany);
+     peer->standby.pool->closeN(howMany);
+ }
+ void
+ PeerPoolMgr::checkpoint(const char *reason)
+ {
+     if (!validPeer()) {
+         debugs(48, 3, reason << " and peer gone");
+         return; // nothing to do after our owner dies; the job will quit
+     }
+     const int count = peer->standby.pool->count();
+     const int limit = peer->standby.limit;
+     debugs(48, 7, reason << " with " << count << " ? " << limit);
+     if (count < limit)
+         openNewConnection();
+     else if (count > limit)
+         closeOldConnections(count - limit);
+ }
+ void
+ PeerPoolMgr::Checkpoint(const Pointer &mgr, const char *reason)
+ {
+     CallJobHere1(48, 5, mgr, PeerPoolMgr, checkpoint, reason);
+ }
+ /// launches PeerPoolMgrs for peers configured with standby.limit
+ class PeerPoolMgrsRr: public RegisteredRunner
+ {
+ public:
+     /* RegisteredRunner API */
+     virtual void useConfig() { syncConfig(); }
+     virtual void syncConfig();
+ };
+ RunnerRegistrationEntry(PeerPoolMgrsRr);
+ void
+ PeerPoolMgrsRr::syncConfig()
+ {
+     for (CachePeer *p = Config.peers; p; p = p->next) {
+         // On reconfigure, Squid deletes the old config (and old peers in it),
+         // so should always be dealing with a brand new configuration.
+         assert(!p->standby.mgr);
+         assert(!p->standby.pool);
+         if (p->standby.limit) {
+             p->standby.mgr = new PeerPoolMgr(p);
+             p->standby.pool = new PconnPool(p->name, p->standby.mgr);
+             AsyncJob::Start(p->standby.mgr.get());
+         }
+     }
+ }
diff --cc src/cache_cf.cc
Simple merge
diff --cc src/cf.data.pre
Simple merge
Simple merge
index 339d127a311a2b2b98c9c7f5f38ccb3c8c413c34,4fa8be988dd145092a8c0de7c856add3bc66c1e1..62dcad1f3e170d64432c23bd2bfbe2eae15f816e
@@@ -30,13 -28,11 +29,13 @@@ CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeerC
  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)
+         AsyncJob("Ssl::PeerConnector"),
+         request(aRequest),
+         serverConn(aServerConn),
++        clientConn(aClientConn),
+         callback(aCallback)
  {
      // if this throws, the caller's cb dialer is not our CbDialer
      Must(dynamic_cast<CbDialer*>(callback->getDialer()));
@@@ -136,30 -134,6 +135,33 @@@ Ssl::PeerConnector::initializeSsl(
          if (peer->sslSession)
              SSL_set_session(ssl, peer->sslSession);
  
 +    } else if (request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) {
++        // client connection is required for Peek or Stare mode in the case we need to splice
++        // or terminate client and server connections
++        assert(clientConn != NULL);
 +        SSL *clientSsl = fd_table[request->clientConnectionManager->clientConnection->fd].ssl;
 +        BIO *b = SSL_get_rbio(clientSsl);
 +        Ssl::ClientBio *clnBio = static_cast<Ssl::ClientBio *>(b->ptr);
 +        const Ssl::Bio::sslFeatures &features = clnBio->getFeatures();
 +        if (features.sslVersion != -1) {
 +            SSL_set_ssl_method(ssl, Ssl::method(features.toSquidSSLVersion()));
 +            if (!features.serverName.empty())
 +                SSL_set_tlsext_host_name(ssl, features.serverName.c_str());
 +            if (!features.clientRequestedCiphers.empty())
 +                SSL_set_cipher_list(ssl, features.clientRequestedCiphers.c_str());
 +#ifdef SSL_OP_NO_COMPRESSION /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */
 +            if (features.compressMethod == 0)
 +                SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
 +#endif
 +            // Should we allow it for all protocols?
 +            if (features.sslVersion >= 3) {
 +                b = SSL_get_rbio(ssl);
 +                Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
 +                srvBio->setClientFeatures(features);
 +                srvBio->recordInput(true);
 +                srvBio->mode(request->clientConnectionManager->sslBumpMode);
 +            }
 +        }
      } else {
          // While we are peeking at the certificate, we may not know the server
          // name that the client will request (after interception or CONNECT)
@@@ -460,60 -376,40 +462,60 @@@ Ssl::PeerConnector::handleNegotiateErro
      unsigned long ssl_lib_error = SSL_ERROR_NONE;
      SSL *ssl = fd_table[fd].ssl;
      int ssl_error = SSL_get_error(ssl, ret);
 +    BIO *b = SSL_get_rbio(ssl);
 +    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
  
  #ifdef EPROTO
-         int sysErrNo = EPROTO;
+     int sysErrNo = EPROTO;
  #else
-         int sysErrNo = EACCES;
+     int sysErrNo = EACCES;
  #endif
  
-         switch (ssl_error) {
+     switch (ssl_error) {
  
-         case SSL_ERROR_WANT_READ:
-             Comm::SetSelect(fd, COMM_SELECT_READ, &NegotiateSsl, this, 0);
-             return;
+     case SSL_ERROR_WANT_READ:
+         Comm::SetSelect(fd, COMM_SELECT_READ, &NegotiateSsl, this, 0);
+         return;
  
-         case SSL_ERROR_WANT_WRITE:
-             if ((request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) && srvBio->holdWrite()) {
-                 debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
-                 checkForPeekAndSplice(false, Ssl::bumpNone);
-                 return;
-             }
-             Comm::SetSelect(fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0);
+     case SSL_ERROR_WANT_WRITE:
++        if ((request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) && srvBio->holdWrite()) {
++            debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
++            checkForPeekAndSplice(false, Ssl::bumpNone);
 +            return;
++        }
+         Comm::SetSelect(fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0);
+         return;
  
-         case SSL_ERROR_SSL:
-         case SSL_ERROR_SYSCALL:
-             ssl_lib_error = ERR_get_error();
+     case SSL_ERROR_SSL:
+     case SSL_ERROR_SYSCALL:
+         ssl_lib_error = ERR_get_error();
  
-             // If we are in peek-and-splice mode and still we did not write to
-             // server yet, try to see if we should splice.
-             // In this case the connection can be saved.
-             // If the checklist decision is do not splice a new error will
-             // occure in the next SSL_connect call, and we will fail again.
++        // If we are in peek-and-splice mode and still we did not write to
++        // server yet, try to see if we should splice.
++        // In this case the connection can be saved.
++        // If the checklist decision is do not splice a new error will
++        // occure in the next SSL_connect call, and we will fail again.
 +#if 1
-             if ((request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek  || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) && srvBio->holdWrite()) {
-                 debugs(81, DBG_IMPORTANT, "fwdNegotiateSSL: Error but, hold write on SSL connection on FD " << fd);
-                 checkForPeekAndSplice(false, Ssl::bumpNone);
-                 return;
-             }
++        if ((request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek  || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) && srvBio->holdWrite()) {
++            debugs(81, DBG_IMPORTANT, "fwdNegotiateSSL: Error but, hold write on SSL connection on FD " << fd);
++            checkForPeekAndSplice(false, Ssl::bumpNone);
++            return;
++        }
 +#endif
 +
-             // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1
-             if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0)
-                 sysErrNo = errno;
+         // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1
+         if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0)
+             sysErrNo = errno;
  
-             debugs(83, DBG_IMPORTANT, "Error negotiating SSL on FD " << fd <<
-                    ": " << ERR_error_string(ssl_lib_error, NULL) << " (" <<
-                    ssl_error << "/" << ret << "/" << errno << ")");
+         debugs(83, DBG_IMPORTANT, "Error negotiating SSL on FD " << fd <<
+                ": " << ERR_error_string(ssl_lib_error, NULL) << " (" <<
+                ssl_error << "/" << ret << "/" << errno << ")");
  
-             break; // proceed to the general error handling code
+         break; // proceed to the general error handling code
  
-         default:
-             break; // no special error handling for all other errors
-         }
+     default:
+         break; // no special error handling for all other errors
+     }
  
      ErrorState *const anErr = ErrorState::NewForwarding(ERR_SECURE_CONNECT_FAIL, request.getRaw());
      anErr->xerrno = sysErrNo;
index 73c7b2713539dca1982e2c08ad2e6f2d06ea5b38,44732c47a0a4d1aecd62c7ed9de47611002e3cf2..6d1f67152977b40d87687d24fedd759cec6234e6
@@@ -29,8 -29,8 +29,9 @@@
  #ifndef SQUID_SSL_PEER_CONNECTOR_H
  #define SQUID_SSL_PEER_CONNECTOR_H
  
- #include "base/AsyncJob.h"
++#include "acl/Acl.h"
  #include "base/AsyncCbdataCalls.h"
+ #include "base/AsyncJob.h"
  #include "ssl/support.h"
  #include <iosfwd>
  
diff --cc src/tunnel.cc
index 519d1f927e0727b87621e362d6d6e1460f7ec103,0ba51faf74a11891fbf10fa4def6a522729600fa..0b00abebd1cdd65cd14e30f47dcaab53279a47b1
@@@ -955,18 -948,18 +956,19 @@@ tunnelStart(ClientHttpRequest * http, i
  }
  
  void
- TunnelStateData::connectToPeer() {
+ TunnelStateData::connectToPeer()
+ {
      const Comm::ConnectionPointer &srv = server.conn;
 +    const Comm::ConnectionPointer &cln = client.conn;
  
  #if USE_OPENSSL
      if (CachePeer *p = srv->getPeer()) {
          if (p->use_ssl) {
              AsyncCall::Pointer callback = asyncCall(5,4,
-                 "TunnelStateData::ConnectedToPeer",
-                 MyAnswerDialer(&TunnelStateData::connectedToPeer, this));
+                                                     "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;
          }