Filter frontend_net honors connect-max
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 29 Jun 2009 15:22:43 +0000 (17:22 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 29 Jun 2009 15:22:43 +0000 (17:22 +0200)
When a certain number of connections is in use (connect-max) from same
originating IP, the frontend_net will close the connection.

etc/config-shared1.xml
src/filter_frontend_net.cpp
src/filter_limit.cpp
src/filter_limit.hpp
src/origin.cpp
src/origin.hpp
xml/schema/metaproxy.rnc
xml/schema/metaproxy.rng
xml/schema/metaproxy.xsd

index 0a3ca95..0dc2b2d 100644 (file)
@@ -4,6 +4,7 @@
   <filters>
     <filter id="frontend" type="frontend_net">
       <port>@:9000</port>
+      <connect-max>3</connect-max>
     </filter>
     <filter id="backend" type="z3950_client">
     </filter>
index f9142e6..1a91c07 100644 (file)
@@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yazpp/z-assoc.h>
 #include <yazpp/pdu-assoc.h>
 #include <yazpp/socket-manager.h>
+#include <yazpp/limit-connect.h>
 #include <yaz/log.h>
 
 #include <iostream>
@@ -43,8 +44,8 @@ namespace metaproxy_1 {
             std::vector<std::string> m_ports;
             int m_listen_duration;
             int m_session_timeout;
+            int m_connect_max;
             yazpp_1::SocketManager mySocketManager;
-            
             ZAssocServer **az;
         };
     }
@@ -97,7 +98,8 @@ namespace metaproxy_1 {
     class ZAssocServer : public yazpp_1::Z_Assoc {
     public:
         ~ZAssocServer();
-        ZAssocServer(yazpp_1::IPDU_Observable *PDU_Observable, int timeout);
+        ZAssocServer(yazpp_1::IPDU_Observable *PDU_Observable, int timeout,
+                     int connect_max);
         void set_package(const mp::Package *package);
         void set_thread_pool(ThreadPoolSocketObserver *m_thread_pool_observer);
     private:
@@ -113,6 +115,8 @@ namespace metaproxy_1 {
         mp::ThreadPoolSocketObserver *m_thread_pool_observer;
         const mp::Package *m_package;
         int m_session_timeout;
+        int m_connect_max;
+        yazpp_1::LimitConnect limit_connect;
     };
 }
 
@@ -245,8 +249,9 @@ void mp::ZAssocChild::connectNotify()
 }
 
 mp::ZAssocServer::ZAssocServer(yazpp_1::IPDU_Observable *PDU_Observable,
-                               int timeout)
-    :  Z_Assoc(PDU_Observable), m_session_timeout(timeout)
+                               int timeout, int connect_max)
+    :  Z_Assoc(PDU_Observable), m_session_timeout(timeout),
+       m_connect_max(connect_max)
 {
     m_package = 0;
 }
@@ -265,6 +270,16 @@ void mp::ZAssocServer::set_thread_pool(ThreadPoolSocketObserver *observer)
 yazpp_1::IPDU_Observer *mp::ZAssocServer::sessionNotify(yazpp_1::IPDU_Observable
                                                 *the_PDU_Observable, int fd)
 {
+
+    const char *peername = the_PDU_Observable->getpeername();
+    if (peername)
+    {
+        limit_connect.add_connect(peername);
+        limit_connect.cleanup(false);
+        int con_sz = limit_connect.get_total(peername);
+        if (m_connect_max && con_sz > m_connect_max)
+            return 0;
+    }
     mp::ZAssocChild *my =
        new mp::ZAssocChild(the_PDU_Observable, m_thread_pool_observer,
                              m_package);
@@ -392,6 +407,10 @@ void mp::filter::FrontendNet::configure(const xmlNode * ptr, bool test_only)
                                                    + timeout_str);
             m_p->m_session_timeout = timeout;
         }
+        else if (!strcmp((const char *) ptr->name, "connect-max"))
+        {
+            m_p->m_connect_max = mp::xml::get_int(ptr->children, 0);
+        }
         else
         {
             throw mp::filter::FilterException("Bad element " 
@@ -419,7 +438,8 @@ void mp::filter::FrontendNet::set_ports(std::vector<std::string> &ports)
         
         // create ZAssoc with PDU Assoc
         m_p->az[i] = new mp::ZAssocServer(as, 
-                                          m_p->m_session_timeout);
+                                          m_p->m_session_timeout,
+                                          m_p->m_connect_max);
         if (m_p->az[i]->server(m_p->m_ports[i].c_str()))
         {
             throw mp::filter::FilterException("Unable to bind to address " 
index 3158ee0..c43608f 100644 (file)
@@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include <time.h>
 #include <yaz/log.h>
+#include <yazpp/bw.h>
 #include "package.hpp"
 #include "util.hpp"
 
@@ -31,11 +32,12 @@ namespace metaproxy_1 {
     namespace filter {
         class Limit::Ses {
         public:
-            Yaz_bw bw_stat;
-            Yaz_bw pdu_stat;
-            Yaz_bw search_stat;
+            yazpp_1::Yaz_bw bw_stat;
+            yazpp_1::Yaz_bw pdu_stat;
+            yazpp_1::Yaz_bw search_stat;
             Ses() : bw_stat(60), pdu_stat(60), search_stat(60) {};
         };
+
         class Limit::Impl {
         public:
             Impl();
@@ -43,10 +45,8 @@ namespace metaproxy_1 {
             void process(metaproxy_1::Package & package);
             void configure(const xmlNode * ptr);
         private:
-            
             boost::mutex m_session_mutex;
             std::map<mp::Session,Limit::Ses *> m_sessions;
-
             int m_bw_max;
             int m_pdu_max;
             int m_search_max;
@@ -166,9 +166,6 @@ void yf::Limit::Impl::process(mp::Package &package)
             }
         }
         
-        yaz_log(YLOG_LOG, "sz = %d . total = %d", sz,
-                ses->bw_stat.get_total());
-        
         int bw_total = ses->bw_stat.get_total();
         int pdu_total = ses->pdu_stat.get_total();
         int search_total = ses->search_stat.get_total();
@@ -209,50 +206,6 @@ extern "C" {
     };
 }
 
-// bandwidth class (taken from YAZ Proxy)
-
-Yaz_bw::Yaz_bw(int sz)
-{
-    m_sec = 0;
-    m_size = sz;
-    m_bucket = new int[m_size];
-    m_ptr = 0;
-}
-
-Yaz_bw::~Yaz_bw()
-{
-    delete [] m_bucket;
-}
-
-int Yaz_bw::get_total()
-{
-    add_bytes(0);
-    int bw = 0;
-    int i;
-    for (i = 0; i<m_size; i++)
-        bw += m_bucket[i];
-    return bw;
-}
-
-void Yaz_bw::add_bytes(int b)
-{
-    long now = time(0);
-
-    if (now >= m_sec)
-    {
-        int d = now - m_sec;
-        if (d > m_size)
-            d = m_size;
-        while (--d >= 0)
-        {
-            if (++m_ptr == m_size)
-                m_ptr = 0;
-            m_bucket[m_ptr] = 0;
-        }
-        m_bucket[m_ptr] += b;
-    }
-    m_sec = now;
-}
 
 /*
  * Local variables:
index 3b5fd57..2b44893 100644 (file)
@@ -42,18 +42,6 @@ extern "C" {
     extern struct metaproxy_1_filter_struct metaproxy_1_filter_limit;
 }
 
-class Yaz_bw {
- public:
-    Yaz_bw(int sz);
-    ~Yaz_bw();
-    void add_bytes(int m);
-    int get_total();
- private:
-    long m_sec;   // time of most recent bucket
-    int *m_bucket;
-    int m_ptr;
-    int m_size;
-};
 #endif
 
 /*
index 28c809c..ac2da44 100644 (file)
@@ -67,6 +67,11 @@ void mp::Origin::set_tcpip_address(std::string addr, unsigned long s)
     m_origin_id = s;
 }
 
+std::string mp::Origin::get_address()
+{
+    return m_address;
+}
+
 std::ostream& std::operator<<(std::ostream& os,  mp::Origin& o)
 {
     if (o.m_address != "")
index eeb4af5..3038287 100644 (file)
@@ -56,6 +56,9 @@ namespace metaproxy_1 {
 
         /// set max sockets (for outgoing connections to a given target)
         int get_max_sockets();
+        
+        /// get tcpip address
+        std::string get_address();
     private:
         friend std::ostream& 
         std::operator<<(std::ostream& os,  metaproxy_1::Origin& o);
index ebb819f..440a4ea 100644 (file)
@@ -100,7 +100,8 @@ filter_frontend_net =
   attribute name { xsd:NCName }?,
   element mp:threads { xsd:integer }?,
   element mp:port { xsd:string }+,
-  element mp:timeout { xsd:integer }?
+  element mp:timeout { xsd:integer }?,
+  element mp:connect-max { xsd:integer }?
 
 filter_http_file =
   attribute type { "http_file" },
index 245993c..bebd320 100644 (file)
         <data type="integer"/>
       </element>
     </optional>
+    <optional>
+      <element name="mp:connect-max">
+        <data type="integer"/>
+      </element>
+    </optional>
   </define>
   <define name="filter_http_file">
     <attribute name="type">
index ffeafa3..dfb47c9 100644 (file)
       <xs:element minOccurs="0" ref="mp:threads"/>
       <xs:element maxOccurs="unbounded" ref="mp:port"/>
       <xs:element minOccurs="0" ref="mp:timeout"/>
+      <xs:element minOccurs="0" ref="mp:connect-max"/>
     </xs:sequence>
   </xs:group>
   <xs:element name="threads" type="xs:integer"/>
   <xs:element name="port" type="xs:string"/>
   <xs:element name="timeout" type="xs:integer"/>
+  <xs:element name="connect-max" type="xs:integer"/>
   <xs:attributeGroup name="filter_frontend_net">
     <xs:attribute name="type" use="required">
       <xs:simpleType>