Comm::AcceptLimiter Comm::AcceptLimiter::Instance_;
-Comm::AcceptLimiter &Comm::AcceptLimiter::Instance()
+Comm::AcceptLimiter &
+Comm::AcceptLimiter::Instance()
{
return Instance_;
}
void
-Comm::AcceptLimiter::defer(Comm::TcpAcceptor *afd)
+Comm::AcceptLimiter::defer(const Comm::TcpAcceptor::Pointer &afd)
{
- ++ afd->isLimited;
- debugs(5, 5, HERE << afd->conn << " x" << afd->isLimited);
- deferred.push_back(afd);
+ ++ (afd->isLimited);
+ debugs(5, 5, afd->conn << " x" << afd->isLimited);
+ deferred_.push_back(afd);
}
void
-Comm::AcceptLimiter::removeDead(const Comm::TcpAcceptor *afd)
+Comm::AcceptLimiter::removeDead(const Comm::TcpAcceptor::Pointer &afd)
{
- for (unsigned int i = 0; i < deferred.size() && afd->isLimited > 0; ++i) {
- if (deferred[i] == afd) {
- -- deferred[i]->isLimited;
- deferred[i] = NULL; // fast. kick() will skip empty entries later.
- debugs(5, 5, HERE << afd->conn << " x" << afd->isLimited);
+ uint64_t abandonedClients = 0;
+ for (unsigned int i = 0; i < deferred_.size() && afd->isLimited > 0; ++i) {
+ if (deferred_[i] == afd) {
+ -- deferred_[i]->isLimited;
+ deferred_[i] = NULL; // fast. kick() will skip empty entries later.
+ debugs(5, 5, afd->conn << " x" << afd->isLimited);
+ ++abandonedClients;
}
}
+ debugs(5,4, "Abandoned " << abandonedClients << " client TCP SYN by closing socket: " << afd->conn);
}
void
// TODO: this could be optimized further with an iterator to search
// looking for first non-NULL, followed by dumping the first N
// with only one shift()/pop_front operation
+ // OR, by reimplementing as a list instead of Vector.
- debugs(5, 5, HERE << " size=" << deferred.size());
- while (deferred.size() > 0 && fdNFree() >= RESERVED_FD) {
+ debugs(5, 5, "size=" << deferred_.size());
+ while (deferred_.size() > 0 && fdNFree() >= RESERVED_FD) {
/* NP: shift() is equivalent to pop_front(). Giving us a FIFO queue. */
- TcpAcceptor *temp = deferred.shift();
- if (temp != NULL) {
- debugs(5, 5, HERE << " doing one.");
+ TcpAcceptor::Pointer temp = deferred_.shift();
+ if (temp.valid()) {
+ debugs(5, 5, "doing one.");
-- temp->isLimited;
temp->acceptNext();
break;
#define _SQUID_SRC_COMM_ACCEPT_LIMITER_H
#include "Array.h"
+#include "comm/TcpAcceptor.h"
namespace Comm
{
-class TcpAcceptor;
-
/**
* FIFO Queue holding listener socket handlers which have been activated
* ready to dupe their FD and accept() a new client connection.
* removeDead - used only by Comm layer ConnAcceptor to remove themselves when dying.
* kick - used by Comm layer when FD are closed.
*/
+/* TODO this algorithm can be optimized further:
+ *
+ * 1) reduce overheads by only pushing one entry per port to the list?
+ * use TcpAcceptor::isLimited as a flag whether to re-list when kick()'ing
+ * or to NULL an entry while scanning the list for empty spaces.
+ * Side effect: TcpAcceptor->kick() becomes allowed to pull off multiple accept()'s in bunches
+ *
+ * 2) re-implement as a list instead of vector?
+ * storing head/tail pointers for fast push/pop and avoiding the whole shift() overhead
+ */
class AcceptLimiter
{
static AcceptLimiter &Instance();
/** delay accepting a new client connection. */
- void defer(Comm::TcpAcceptor *afd);
+ void defer(const TcpAcceptor::Pointer &afd);
/** remove all records of an acceptor. Only to be called by the ConnAcceptor::swanSong() */
- void removeDead(const Comm::TcpAcceptor *afd);
+ void removeDead(const TcpAcceptor::Pointer &afd);
/** try to accept and begin processing any delayed client connections. */
void kick();
static AcceptLimiter Instance_;
/** FIFO queue */
- Vector<Comm::TcpAcceptor*> deferred;
+ Vector<TcpAcceptor::Pointer> deferred_;
};
}; // namepace Comm
#ifndef SQUID_COMM_TCPACCEPTOR_H
#define SQUID_COMM_TCPACCEPTOR_H
-#include "base/AsyncCall.h"
+#include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
#include "base/Subscription.h"
-#include "CommCalls.h"
#include "comm_err_t.h"
#include "comm/forward.h"
-#include "comm/TcpAcceptor.h"
-#include "ip/Address.h"
-
-#if HAVE_MAP
-#include <map>
-#endif
namespace Comm
{
*/
class TcpAcceptor : public AsyncJob
{
+public:
+ typedef CbcPointer<Comm::TcpAcceptor> Pointer;
+
private:
virtual void start();
virtual bool doneAll() const;
#include "comm/AcceptLimiter.h"
Comm::AcceptLimiter dummy;
Comm::AcceptLimiter & Comm::AcceptLimiter::Instance() STUB_RETVAL(dummy)
-void Comm::AcceptLimiter::defer(Comm::TcpAcceptor *afd) STUB
-void Comm::AcceptLimiter::removeDead(const Comm::TcpAcceptor *afd) STUB
+void Comm::AcceptLimiter::defer(const Comm::TcpAcceptor::Pointer &afd) STUB
+void Comm::AcceptLimiter::removeDead(const Comm::TcpAcceptor::Pointer &afd) STUB
void Comm::AcceptLimiter::kick() STUB
#include "comm/Connection.h"