From 9c4af9d938abac93a949d756353c1bd89b769012 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Thu, 30 Mar 2006 10:35:14 +0000 Subject: [PATCH] Implement max-connect facility which makes the server sleep if a certain number of connections has been initiated from a single IP. --- etc/config.xml | 4 +- etc/yazproxy.xsd | 3 +- include/yazproxy/Makefile.am | 2 +- include/yazproxy/bw.h | 12 +++- include/yazproxy/limit-connect.h | 52 +++++++++++++++++ include/yazproxy/proxy.h | 8 ++- src/Makefile.am | 4 +- src/limit-connect.cpp | 117 ++++++++++++++++++++++++++++++++++++++ src/proxyp.h | 12 ++-- src/yaz-proxy-config.cpp | 42 +++++++------- src/yaz-proxy.cpp | 57 +++++++++++-------- 11 files changed, 251 insertions(+), 62 deletions(-) create mode 100644 include/yazproxy/limit-connect.h create mode 100644 src/limit-connect.cpp diff --git a/etc/config.xml b/etc/config.xml index 6116436..0379c13 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -1,5 +1,5 @@ - + 2000000 60 100 + 3 @@ -47,5 +48,6 @@ 2 + 3 client-requests server-requests diff --git a/etc/yazproxy.xsd b/etc/yazproxy.xsd index b601c54..a75be50 100644 --- a/etc/yazproxy.xsd +++ b/etc/yazproxy.xsd @@ -1,6 +1,6 @@ + diff --git a/include/yazproxy/Makefile.am b/include/yazproxy/Makefile.am index e982516..59eda06 100644 --- a/include/yazproxy/Makefile.am +++ b/include/yazproxy/Makefile.am @@ -1,2 +1,2 @@ -pkginclude_HEADERS = proxy.h bw.h module.h +pkginclude_HEADERS = proxy.h bw.h module.h limit-connect.h diff --git a/include/yazproxy/bw.h b/include/yazproxy/bw.h index fe532e7..227b0ff 100644 --- a/include/yazproxy/bw.h +++ b/include/yazproxy/bw.h @@ -1,7 +1,7 @@ -/* $Id: bw.h,v 1.4 2005-06-25 15:58:33 adam Exp $ - Copyright (c) 1998-2004, Index Data. +/* $Id: bw.h,v 1.5 2006-03-30 10:35:15 adam Exp $ + Copyright (c) 1998-2006, Index Data. -This file is part of the yaz-proxy. +This file is part of the yazproxy. YAZ proxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -19,6 +19,11 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef YAZPROXY_YAZ_BW_H +#define YAZPROXY_YAZ_BW_H + +#include + class YAZ_EXPORT Yaz_bw { public: Yaz_bw(int sz); @@ -31,6 +36,7 @@ class YAZ_EXPORT Yaz_bw { int m_ptr; int m_size; }; +#endif /* * Local variables: diff --git a/include/yazproxy/limit-connect.h b/include/yazproxy/limit-connect.h new file mode 100644 index 0000000..cfe8ae0 --- /dev/null +++ b/include/yazproxy/limit-connect.h @@ -0,0 +1,52 @@ +/* $Id: limit-connect.h,v 1.1 2006-03-30 10:35:15 adam Exp $ + Copyright (c) 1998-2006, Index Data. + +This file is part of the yazproxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#ifndef YAZPROXY_LIMIT_CONNECT_H +#define YAZPROXY_LIMIT_CONNECT_H + +#include +#include + +class LimitConnect { +public: + LimitConnect(); + ~LimitConnect(); + void add_connect(const char *peername); + int get_total(const char *peername); + void cleanup(bool all); +private: + struct Peer; + + int m_period; + Peer *m_peers; + Peer **lookup(const char *peername); +}; + +#endif + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/include/yazproxy/proxy.h b/include/yazproxy/proxy.h index fb470cb..fe0f2df 100644 --- a/include/yazproxy/proxy.h +++ b/include/yazproxy/proxy.h @@ -1,7 +1,7 @@ -/* $Id: proxy.h,v 1.28 2006-03-29 13:33:46 adam Exp $ - Copyright (c) 1998-2005, Index Data. +/* $Id: proxy.h,v 1.29 2006-03-30 10:35:15 adam Exp $ + Copyright (c) 1998-2006, Index Data. -This file is part of the yaz-proxy. +This file is part of the yazproxy. YAZ proxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -31,6 +31,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include #include #include +#include class Yaz_Proxy; @@ -197,6 +198,7 @@ class YAZ_EXPORT Yaz_Proxy : public yazpp_1::Z_Assoc { Yaz_usemarcon *m_usemarcon; Yaz_CharsetConverter *m_charset_converter; yazpp_1::GDUQueue m_in_queue; + LimitConnect m_connect; public: Yaz_Proxy(yazpp_1::IPDU_Observable *the_PDU_Observable, yazpp_1::ISocketObservable *the_socket_observable, diff --git a/src/Makefile.am b/src/Makefile.am index d117d71..8c18ee0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.12 2006-03-25 10:56:28 adam Exp $ +## $Id: Makefile.am,v 1.13 2006-03-30 10:35:15 adam Exp $ AM_CXXFLAGS = $(YAZPPINC) -I$(srcdir)/../include $(XSLT_CFLAGS) $(USEMARCONINC) @@ -7,7 +7,7 @@ libyazproxy_la_LDFLAGS=-version-info 1:0:0 libyazproxy_la_SOURCES= yaz-proxy.cpp yaz-proxy-config.cpp yaz-bw.cpp \ proxyp.h yaz-usemarcon.cpp charset-converter.cpp msg-thread.cpp msg-thread.h \ - modules.cpp + modules.cpp limit-connect.cpp bin_PROGRAMS = yazproxy check_PROGRAMS = cdetails diff --git a/src/limit-connect.cpp b/src/limit-connect.cpp new file mode 100644 index 0000000..9197ea3 --- /dev/null +++ b/src/limit-connect.cpp @@ -0,0 +1,117 @@ +/* $Id: limit-connect.cpp,v 1.1 2006-03-30 10:35:15 adam Exp $ + Copyright (c) 1998-2006, Index Data. + +This file is part of the yazproxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. +*/ + +#include + +#include +#include +#include + +struct LimitConnect::Peer { + friend class LimitConnect; + + Peer(int sz, const char *peername); + ~Peer(); + void add_connect(); + + char *m_peername; + Yaz_bw m_bw; + Peer *m_next; +}; + +LimitConnect::LimitConnect() +{ + m_period = 60; + m_peers = 0; +} + +LimitConnect::~LimitConnect() +{ + cleanup(true); +} + +LimitConnect::Peer::Peer(int sz, const char *peername) : m_bw(sz) +{ + m_peername = xstrdup(peername); + m_next = 0; +} + +LimitConnect::Peer::~Peer() +{ + xfree(m_peername); +} + +void LimitConnect::Peer::add_connect() +{ + m_bw.add_bytes(1); +} + +LimitConnect::Peer **LimitConnect::lookup(const char *peername) +{ + Peer **p = &m_peers; + while (*p) + { + if (!strcmp((*p)->m_peername, peername)) + break; + p = &(*p)->m_next; + } + return p; +} + +void LimitConnect::add_connect(const char *peername) +{ + Peer **p = lookup(peername); + if (!*p) + *p = new Peer(m_period, peername); + (*p)->add_connect(); +} + +int LimitConnect::get_total(const char *peername) +{ + Peer **p = lookup(peername); + if (!*p) + return 0; + return (*p)->m_bw.get_total(); +} + +void LimitConnect::cleanup(bool all) +{ + Peer **p = &m_peers; + while (*p) + { + Peer *tp = *p; + if (all || (tp->m_bw.get_total() == 0)) + { + *p = tp->m_next; + delete tp; + } + else + p = &tp->m_next; + } +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/proxyp.h b/src/proxyp.h index b161fdf..1e62cca 100644 --- a/src/proxyp.h +++ b/src/proxyp.h @@ -1,7 +1,7 @@ -/* $Id: proxyp.h,v 1.13 2006-03-29 13:33:47 adam Exp $ - Copyright (c) 1998-2005, Index Data. +/* $Id: proxyp.h,v 1.14 2006-03-30 10:35:15 adam Exp $ + Copyright (c) 1998-2006, Index Data. -This file is part of the yaz-proxy. +This file is part of the yazproxy. YAZ proxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -91,7 +91,6 @@ public: int *limit_pdu, int *limit_req, int *limit_search, - int *limit_connect, int *target_idletime, int *client_idletime, int *max_clients, @@ -105,11 +104,12 @@ public: const char **query_charset, const char **default_client_query_charset); - void get_generic_info(int *log_mask, int *max_clients); + void get_generic_info(int *log_mask, int *max_clients, + int *max_connect); void get_target_info(const char *name, const char **url, int *limit_bw, int *limit_pdu, int *limit_req, - int *limit_search, int *limit_connect, + int *limit_search, int *target_idletime, int *client_idletime, int *max_clients, int *keepalive_limit_bw, int *keepalive_limit_pdu, diff --git a/src/yaz-proxy-config.cpp b/src/yaz-proxy-config.cpp index f7ab3d9..219bf9a 100644 --- a/src/yaz-proxy-config.cpp +++ b/src/yaz-proxy-config.cpp @@ -1,7 +1,7 @@ -/* $Id: yaz-proxy-config.cpp,v 1.25 2006-03-25 10:59:14 adam Exp $ - Copyright (c) 1998-2005, Index Data. +/* $Id: yaz-proxy-config.cpp,v 1.26 2006-03-30 10:35:15 adam Exp $ + Copyright (c) 1998-2006, Index Data. -This file is part of the yaz-proxy. +This file is part of the yazproxy. YAZ proxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -39,7 +39,7 @@ class Yaz_ProxyConfigP { xmlNodePtr m_proxyPtr; void return_target_info(xmlNodePtr ptr, const char **url, int *limit_bw, int *limit_pdu, int *limit_req, - int *limit_search, int *limit_connect, + int *limit_search, int *target_idletime, int *client_idletime, int *keepalive_limit_bw, int *keepalive_limit_pdu, int *pre_init, const char **cql2rpn, @@ -49,7 +49,7 @@ class Yaz_ProxyConfigP { const char **default_client_query_charset); void return_limit(xmlNodePtr ptr, int *limit_bw, int *limit_pdu, int *limit_req, - int *limit_search, int *limit_connect); + int *limit_search); int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query, char **addinfo); xmlNodePtr find_target_node(const char *name, const char *db); @@ -172,8 +172,7 @@ void Yaz_ProxyConfigP::return_limit(xmlNodePtr ptr, int *limit_bw, int *limit_pdu, int *limit_req, - int *limit_search, - int *limit_connect) + int *limit_search) { for (ptr = ptr->children; ptr; ptr = ptr->next) { @@ -205,13 +204,6 @@ void Yaz_ProxyConfigP::return_limit(xmlNodePtr ptr, if (t) *limit_search = atoi(t); } - if (ptr->type == XML_ELEMENT_NODE - && !strcmp((const char *) ptr->name, "connect")) - { - const char *t = get_text(ptr); - if (t) - *limit_connect = atoi(t); - } } } #endif @@ -223,7 +215,6 @@ void Yaz_ProxyConfigP::return_target_info(xmlNodePtr ptr, int *limit_pdu, int *limit_req, int *limit_search, - int *limit_connect, int *target_idletime, int *client_idletime, int *keepalive_limit_bw, @@ -263,12 +254,12 @@ void Yaz_ProxyConfigP::return_target_info(xmlNodePtr ptr, *keepalive_limit_bw = 500000; *keepalive_limit_pdu = 1000; return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu, - &dummy, &dummy, &dummy); + &dummy, &dummy); } if (ptr->type == XML_ELEMENT_NODE && !strcmp((const char *) ptr->name, "limit")) return_limit(ptr, limit_bw, limit_pdu, limit_req, - limit_search, limit_connect); + limit_search); if (ptr->type == XML_ELEMENT_NODE && !strcmp((const char *) ptr->name, "target-timeout")) { @@ -933,7 +924,6 @@ int Yaz_ProxyConfig::get_target_no(int no, int *limit_pdu, int *limit_req, int *limit_search, - int *limit_connect, int *target_idletime, int *client_idletime, int *max_clients, @@ -970,7 +960,7 @@ int Yaz_ProxyConfig::get_target_no(int no, m_cp->return_target_info( ptr, url, limit_bw, limit_pdu, limit_req, - limit_search, limit_connect, + limit_search, target_idletime, client_idletime, keepalive_limit_bw, keepalive_limit_pdu, pre_init, cql2rpn, @@ -992,8 +982,10 @@ int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len) } void Yaz_ProxyConfig::get_generic_info(int *log_mask, - int *max_clients) + int *max_clients, + int *max_connect) { + *max_connect = 0; #if HAVE_XSLT xmlNodePtr ptr; if (!m_cp->m_proxyPtr) @@ -1039,6 +1031,13 @@ void Yaz_ProxyConfig::get_generic_info(int *log_mask, *max_clients = 1; } } + if (ptr->type == XML_ELEMENT_NODE && + !strcmp((const char *) ptr->name, "max-connect")) + { + const char *t = m_cp->get_text(ptr); + if (t) + *max_connect = atoi(t); + } } #endif } @@ -1167,7 +1166,6 @@ void Yaz_ProxyConfig::get_target_info(const char *name, int *limit_pdu, int *limit_req, int *limit_search, - int *limit_connect, int *target_idletime, int *client_idletime, int *max_clients, @@ -1212,7 +1210,7 @@ void Yaz_ProxyConfig::get_target_info(const char *name, url[1] = 0; } m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req, - limit_search, limit_connect, + limit_search, target_idletime, client_idletime, keepalive_limit_bw, keepalive_limit_pdu, pre_init, cql2rpn, diff --git a/src/yaz-proxy.cpp b/src/yaz-proxy.cpp index 07b8b45..10cc687 100644 --- a/src/yaz-proxy.cpp +++ b/src/yaz-proxy.cpp @@ -1,7 +1,7 @@ -/* $Id: yaz-proxy.cpp,v 1.44 2006-03-25 10:59:14 adam Exp $ - Copyright (c) 1998-2005, Index Data. +/* $Id: yaz-proxy.cpp,v 1.45 2006-03-30 10:35:15 adam Exp $ + Copyright (c) 1998-2006, Index Data. -This file is part of the yaz-proxy. +This file is part of the yazproxy. YAZ proxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -87,7 +87,6 @@ Auth_Msg::~Auth_Msg() IMsg_Thread *Auth_Msg::handle() { - yaz_log(YLOG_LOG, "Auth_Msg:handle begin"); ODR decode = odr_createmem(ODR_DECODE); Z_APDU *apdu; @@ -101,26 +100,22 @@ IMsg_Thread *Auth_Msg::handle() { m_ret = m_proxy->handle_authentication(apdu); } - yaz_log(YLOG_LOG, "Auth_Msg:handle end"); odr_destroy(decode); return this; } void Auth_Msg::result() { - yaz_log(YLOG_LOG, "Auth_Msg:result proxy ok buf=%p len=%d", - m_apdu_buf, m_apdu_len); if (m_proxy->dec_ref(false)) + { yaz_log(YLOG_LOG, "Auth_Msg::proxy deleted meanwhile"); + } else { - yaz_log(YLOG_LOG, "Auth_Msg::proxy still alive"); odr_setbuf(m_proxy->odr_decode(), m_apdu_buf, m_apdu_len, 0); Z_APDU *apdu = 0; int r = z_APDU(m_proxy->odr_decode(), &apdu, 0, 0); - if (r) - yaz_log(YLOG_LOG, "Auth_Msg::result z_APDU OK"); - else + if (!r) yaz_log(YLOG_LOG, "Auth_Msg::result z_APDU failed"); m_proxy->result_authentication(apdu, m_ret); } @@ -356,7 +351,8 @@ int Yaz_Proxy::set_config(const char *config) m_config_fname = xstrdup(config); int r = m_config->read_xml(config); if (!r) - m_config->get_generic_info(&m_log_mask, &m_max_clients); + m_config->get_generic_info(&m_log_mask, &m_max_clients, + &m_connect_max); return r; } @@ -407,7 +403,8 @@ Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure() else { m_log_mask = 0; - cfg->get_generic_info(&m_log_mask, &m_max_clients); + cfg->get_generic_info(&m_log_mask, &m_max_clients, + &m_connect_max); } } else @@ -561,7 +558,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie, int pre_init = 0; cfg->get_target_info(proxy_host, url, &m_bw_max, &m_pdu_max, &m_max_record_retrieve, - &m_search_max, &m_connect_max, + &m_search_max, &m_target_idletime, &client_idletime, &parent->m_max_clients, &m_keepalive_limit_bw, @@ -1841,9 +1838,29 @@ void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len) void Yaz_Proxy::recv_GDU_reduce(GDU *gdu) { + int reduce = 0; + + if (1) + { + m_parent->m_connect.add_connect(m_peername); + int connect_total = m_parent->m_connect.get_total(m_peername); + int connect_max = m_parent->m_connect_max; + + if (connect_max && connect_total > connect_max) + { + yaz_log(YLOG_LOG, "%sconnect delay total=%d max=%d", + m_session_str, connect_total, connect_max); + reduce = connect_total / connect_max; + } + else + yaz_log(YLOG_LOG, "%sconnect OK total=%d", m_session_str, + connect_total); + m_parent->m_connect.cleanup(false); + } + + int bw_total = m_bw_stat.get_total(); int pdu_total = m_pdu_stat.get_total(); - int reduce = 0; assert(m_timeout_mode == timeout_busy); assert(m_timeout_gdu == 0); @@ -1928,8 +1945,6 @@ void Yaz_Proxy::handle_charset_lang_negotiation(Z_APDU *apdu) { if (apdu->which == Z_APDU_initRequest) { - yaz_log(YLOG_LOG, "%shandle_charset_lang_negotiation", - m_session_str); if (m_initRequest_options && !ODR_MASK_GET(m_initRequest_options, Z_Options_negotiationModel) && (m_proxy_negotiation_charset || m_proxy_negotiation_lang)) @@ -2978,7 +2993,6 @@ void Yaz_Proxy::handle_init(Z_APDU *apdu) m_client->m_init_flag = 1; #if USE_AUTH_MSG - yaz_log(YLOG_LOG, "%suse_auth_msg", m_session_str); Auth_Msg *m = new Auth_Msg; m->m_proxy = this; z_APDU(odr_encode(), &apdu, 0, "encode"); @@ -3149,8 +3163,6 @@ void Yaz_Proxy::releaseClient() bool Yaz_Proxy::dec_ref(bool main_ptr) { - yaz_log(YLOG_LOG, "%sdec_ref count=%d", m_session_str, m_ref_count); - assert(m_ref_count > 0); if (main_ptr) { @@ -3202,7 +3214,6 @@ void Yaz_Proxy::failNotify() void Yaz_Proxy::send_response_fail_client(const char *addr) { - yaz_log(YLOG_LOG, "%ssend_close_response", get_session_str()); if (m_http_version) { Z_SRW_diagnostic *diagnostic = 0; @@ -3291,7 +3302,7 @@ void Yaz_Proxy::pre_init() int i; const char *name = 0; const char *zurl_in_use[MAX_ZURL_PLEX]; - int limit_bw, limit_pdu, limit_req, limit_search, limit_connect; + int limit_bw, limit_pdu, limit_req, limit_search; int target_idletime, client_idletime; int max_clients; int keepalive_limit_bw, keepalive_limit_pdu; @@ -3312,7 +3323,7 @@ void Yaz_Proxy::pre_init() for (i = 0; cfg && cfg->get_target_no(i, &name, zurl_in_use, &limit_bw, &limit_pdu, &limit_req, - &limit_search, &limit_connect, + &limit_search, &target_idletime, &client_idletime, &max_clients, &keepalive_limit_bw, -- 1.7.10.4