X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Fyaz-proxy.cpp;h=7f073cccf0dc063395400e8ead8937b82b7d82e4;hb=8090f2db8d6c91708d7ea2df62135e9ed7c7eed9;hp=af246fae1e7386eff24638019779116b90301c82;hpb=d7f41f16caf965adb1a5ffcdaa937787dfcc030a;p=yazproxy-moved-to-github.git diff --git a/src/yaz-proxy.cpp b/src/yaz-proxy.cpp index af246fa..7f073cc 100644 --- a/src/yaz-proxy.cpp +++ b/src/yaz-proxy.cpp @@ -1,4 +1,4 @@ -/* $Id: yaz-proxy.cpp,v 1.34 2005-06-25 15:58:33 adam Exp $ +/* $Id: yaz-proxy.cpp,v 1.42 2006-03-09 00:08:29 adam Exp $ Copyright (c) 1998-2005, Index Data. This file is part of the yaz-proxy. @@ -106,15 +106,20 @@ void Auth_Msg::result() { yaz_log(YLOG_LOG, "Auth_Msg:result proxy ok buf=%p len=%d", m_apdu_buf, m_apdu_len); - odr_reset(m_proxy->odr_decode()); - 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"); + if (m_proxy->dec_ref(false)) + yaz_log(YLOG_LOG, "Auth_Msg::proxy deleted meanwhile"); else - yaz_log(YLOG_LOG, "Auth_Msg::result z_APDU failed"); - m_proxy->result_authentication(apdu, m_ret); + { + 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 + yaz_log(YLOG_LOG, "Auth_Msg::result z_APDU failed"); + m_proxy->result_authentication(apdu, m_ret); + } delete this; } @@ -122,12 +127,12 @@ void Auth_Msg::result() void Yaz_Proxy::result_authentication(Z_APDU *apdu, int ret) { - if (ret == 0) + if (apdu == 0 || ret == 0) { Z_APDU *apdu_reject = zget_APDU(odr_encode(), Z_APDU_initResponse); *apdu_reject->u.initResponse->result = 0; send_to_client(apdu_reject); - dec_ref(); + dec_ref(false); } else handle_incoming_Z_PDU_2(apdu); @@ -214,9 +219,10 @@ Yaz_Proxy::Yaz_Proxy(IPDU_Observable *the_PDU_Observable, m_session_no = 0; m_bytes_sent = 0; m_bytes_recv = 0; - m_bw_hold_PDU = 0; m_bw_max = 0; m_pdu_max = 0; + m_search_max = 0; + m_connect_max = 0; m_timeout_mode = timeout_normal; m_timeout_gdu = 0; m_max_record_retrieve = 0; @@ -274,12 +280,13 @@ Yaz_Proxy::Yaz_Proxy(IPDU_Observable *the_PDU_Observable, low_socket_open(); m_my_thread = 0; m_ref_count = 1; + m_main_ptr_dec = false; m_peername = 0; } void Yaz_Proxy::inc_ref() { -// m_ref_count++; + m_ref_count++; } Yaz_Proxy::~Yaz_Proxy() @@ -416,7 +423,7 @@ IPDU_Observer *Yaz_Proxy::sessionNotify(IPDU_Observable m_proxy_negotiation_lang); // create thread object the first time we get an incoming connection if (!m_my_thread) - m_my_thread = new Msg_Thread(m_socket_observable); + m_my_thread = new Msg_Thread(m_socket_observable, 1); new_proxy->m_my_thread = m_my_thread; return new_proxy; } @@ -532,6 +539,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_target_idletime, &client_idletime, &parent->m_max_clients, &m_keepalive_limit_bw, @@ -690,7 +698,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie, yaz_log (YLOG_LOG, "%sMAXCLIENTS %d Destroy %d", m_session_str, parent->m_max_clients, c->m_seqno); if (c->m_server && c->m_server != this) - delete c->m_server; + delete c->m_server; // PROBLEM: m_ref_count! c->m_server = 0; } else @@ -706,7 +714,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie, if (c->m_server && c->m_server != this) { c->m_server->m_client = 0; - delete c->m_server; + delete c->m_server; // PROBLEM: m_ref_count! } (parent->m_seqno)++; c->m_target_idletime = m_target_idletime; @@ -802,7 +810,9 @@ void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num) int Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu) { if (!m_stylesheet_xsp || p->num_records <= 0) + { return 0; /* no XSLT to be done ... */ + } m_stylesheet_offset = 0; m_stylesheet_nprl = p; @@ -1031,7 +1041,7 @@ void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p, { WRBUF w = wrbuf_alloc(); - yaz_display_OPAC(w, r->u.opac, 0); + yaz_opac_decode_wrbuf(mt, r->u.opac, w); npr->u.databaseRecord = z_ext_record( odr_encode(), VAL_TEXT_XML, wrbuf_buf(w), wrbuf_len(w) @@ -1098,6 +1108,9 @@ int Yaz_Proxy::send_http_response(int code) m_bytes_sent += len; m_bw_stat.add_bytes(len); logtime(); + + recv_GDU_more(true); + return r; } @@ -1144,20 +1157,20 @@ int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu) m_bytes_sent += len; m_bw_stat.add_bytes(len); logtime(); + + recv_GDU_more(true); + return r; } int Yaz_Proxy::send_to_srw_client_error(int srw_error, const char *add) { ODR o = odr_encode(); - Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response); - Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response; - - srw_res->num_diagnostics = 1; - srw_res->diagnostics = (Z_SRW_diagnostic *) - odr_malloc(o, sizeof(*srw_res->diagnostics)); - yaz_mk_std_diagnostic(o, srw_res->diagnostics, srw_error, add); - return send_srw_response(srw_pdu); + Z_SRW_diagnostic *diagnostic = (Z_SRW_diagnostic *) + odr_malloc(o, sizeof(*diagnostic)); + int num_diagnostic = 1; + yaz_mk_std_diagnostic(o, diagnostic, srw_error, add); + return send_srw_search_response(diagnostic, num_diagnostic); } int Yaz_Proxy::z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res, @@ -1234,6 +1247,18 @@ int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start) } +int Yaz_Proxy::send_srw_search_response(Z_SRW_diagnostic *diagnostics, + int num_diagnostics) +{ + ODR o = odr_encode(); + Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response); + Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response; + + srw_res->num_diagnostics = num_diagnostics; + srw_res->diagnostics = diagnostics; + return send_srw_response(srw_pdu); +} + int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics, int num_diagnostics) { @@ -1755,18 +1780,9 @@ void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len) m_pdu_stat.add_bytes(1); GDU *gdu = new GDU(apdu); - int qsize = m_in_queue.size(); - if (m_timeout_mode != timeout_normal) - { - yaz_log(YLOG_LOG, "%sAdded gdu in queue of size %d", m_session_str, - qsize); - m_in_queue.enqueue(gdu); - } - else - { - recv_GDU_reduce(gdu); - recv_GDU_more(); - } + m_in_queue.enqueue(gdu); + + recv_GDU_more(false); } void Yaz_Proxy::recv_GDU_reduce(GDU *gdu) @@ -1775,7 +1791,7 @@ void Yaz_Proxy::recv_GDU_reduce(GDU *gdu) int pdu_total = m_pdu_stat.get_total(); int reduce = 0; - assert(m_timeout_mode == timeout_normal); + assert(m_timeout_mode == timeout_busy); assert(m_timeout_gdu == 0); if (m_bw_max) @@ -1795,6 +1811,13 @@ void Yaz_Proxy::recv_GDU_reduce(GDU *gdu) } m_http_version = 0; +#if 0 + /* uncomment to force a big reduce */ + m_timeout_mode = timeout_reduce; + m_timeout_gdu = gdu; + timeout(3); // call us reduce seconds later + return; +#endif if (reduce) { yaz_log(YLOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d", @@ -1803,24 +1826,28 @@ void Yaz_Proxy::recv_GDU_reduce(GDU *gdu) m_timeout_mode = timeout_reduce; m_timeout_gdu = gdu; - // m_bw_hold_PDU = apdu; // save PDU and signal "on hold" timeout(reduce); // call us reduce seconds later } else recv_GDU_normal(gdu); } -void Yaz_Proxy::recv_GDU_more() +void Yaz_Proxy::recv_GDU_more(bool normal) { GDU *g; + if (normal && m_timeout_mode == timeout_busy) + m_timeout_mode = timeout_normal; while (m_timeout_mode == timeout_normal && (g = m_in_queue.dequeue())) + { + m_timeout_mode = timeout_busy; recv_GDU_reduce(g); + } } void Yaz_Proxy::recv_GDU_normal(GDU *gdu) { - Z_GDU *apdu = gdu->get(); - gdu->extract_odr_to(odr_decode()); + Z_GDU *apdu = 0; + gdu->move_away_gdu(odr_decode(), &apdu); delete gdu; if (apdu->which == Z_GDU_Z3950) @@ -2002,9 +2029,10 @@ void Yaz_Proxy::handle_charset_lang_negotiation(Z_APDU *apdu) { ODR_MASK_SET(initResponse->options, Z_Options_negotiationModel); - ODR_MASK_SET(m_initRequest_options, - Z_Options_negotiationModel); - + if (m_initRequest_options) + ODR_MASK_SET(m_initRequest_options, + Z_Options_negotiationModel); + oi->which = Z_OtherInfo_externallyDefinedInfo; oi->information.externallyDefinedInfo = yaz_set_response_charneg( @@ -2442,6 +2470,7 @@ int Yaz_Proxy::file_access(Z_HTTP_Request *hreq) } int len; send_GDU(gdu, &len); + recv_GDU_more(true); return 1; } @@ -2595,7 +2624,8 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq) const char *pqf_msg; size_t off; int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off); - yaz_log(YLOG_LOG, "%*s^\n", off+4, ""); + int ioff = off; + yaz_log(YLOG_LOG, "%*s^\n", ioff+4, ""); yaz_log(YLOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code); send_to_srw_client_error(10, 0); @@ -2859,12 +2889,14 @@ void Yaz_Proxy::handle_init(Z_APDU *apdu) m_client->m_initResponse_version; send_to_client(apdu2); + m_timeout_mode = timeout_normal; return; } } 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"); @@ -2912,12 +2944,13 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu) if (!m_client) { if (m_http_version) - { + { // HTTP. Send not found send_http_response(404); return; } else { + // Z39.50 just shutdown delete this; return; } @@ -2953,6 +2986,7 @@ void Yaz_Proxy::handle_incoming_Z_PDU_2(Z_APDU *apdu) if (!apdu) { m_client->timeout(m_target_idletime); // mark it active even + recv_GDU_more(true); // though we didn't use it return; } @@ -2978,9 +3012,7 @@ void Yaz_Proxy::handle_incoming_Z_PDU_2(Z_APDU *apdu) } if (m_client->send_to_target(apdu) < 0) { - delete m_client; - m_client = 0; - delete this; + m_client->shutdown(); } else m_client->m_waiting = 1; @@ -3037,17 +3069,28 @@ void Yaz_Proxy::releaseClient() m_parent->pre_init(); } -bool Yaz_Proxy::dec_ref() +bool Yaz_Proxy::dec_ref(bool main_ptr) { - --m_ref_count; - assert(m_ref_count >= 0); - bool last = (m_ref_count == 0); - if (m_ref_count == 0) + yaz_log(YLOG_LOG, "%sdec_ref count=%d", m_session_str, m_ref_count); + + assert(m_ref_count > 0); + if (main_ptr) { - releaseClient(); - delete this; + if (m_main_ptr_dec) + return false; + m_main_ptr_dec = true; } - return last; + + m_http_keepalive = 0; + + --m_ref_count; + if (m_ref_count > 0) + return false; + + releaseClient(); + + delete this; + return true; } const char *Yaz_ProxyClient::get_session_str() @@ -3061,8 +3104,14 @@ void Yaz_ProxyClient::shutdown() { yaz_log (YLOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(), get_hostname()); - delete m_server; - delete this; + + if (m_server) + { + m_waiting = 1; // ensure it's released from Proxy in releaseClient + m_server->dec_ref(true); + } + else + delete this; } void Yaz_Proxy::failNotify() @@ -3070,15 +3119,35 @@ void Yaz_Proxy::failNotify() inc_request_no(); yaz_log (YLOG_LOG, "%sConnection closed by client", get_session_str()); - dec_ref(); + dec_ref(true); } +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; + int num_diagnostic = 0; + + yaz_add_srw_diagnostic(odr_encode(), + &diagnostic, &num_diagnostic, + YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, addr); + if (m_s2z_search_apdu) + send_srw_search_response(diagnostic, num_diagnostic); + else + send_srw_explain_response(diagnostic, num_diagnostic); + } +} void Yaz_ProxyClient::failNotify() { if (m_server) m_server->inc_request_no(); yaz_log (YLOG_LOG, "%sConnection closed by target %s", get_session_str(), get_hostname()); + + if (m_server) + m_server->send_response_fail_client(get_hostname()); shutdown(); } @@ -3143,7 +3212,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; + int limit_bw, limit_pdu, limit_req, limit_search, limit_connect; int target_idletime, client_idletime; int max_clients; int keepalive_limit_bw, keepalive_limit_pdu; @@ -3164,6 +3233,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, &target_idletime, &client_idletime, &max_clients, &keepalive_limit_bw, @@ -3245,14 +3315,15 @@ void Yaz_Proxy::timeoutNotify() switch(m_timeout_mode) { case timeout_normal: + case timeout_busy: inc_request_no(); m_in_queue.clear(); yaz_log (YLOG_LOG, "%sTimeout (client to proxy)", m_session_str); - dec_ref(); + dec_ref(true); break; case timeout_reduce: timeout(m_client_idletime); - m_timeout_mode = timeout_normal; + m_timeout_mode = timeout_busy; gdu = m_timeout_gdu; m_timeout_gdu = 0; recv_GDU_normal(gdu); @@ -3260,7 +3331,7 @@ void Yaz_Proxy::timeoutNotify() case timeout_xsl: assert(m_stylesheet_nprl); convert_xsl_delay(); - recv_GDU_more(); + recv_GDU_more(true); } } else @@ -3283,17 +3354,12 @@ void Yaz_ProxyClient::timeoutNotify() yaz_log (YLOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(), get_hostname()); - m_waiting = 1; - m_root->pre_init(); - if (m_server && m_init_flag) - { - // target timed out in a session that was properly initialized - // server object stay alive but we mark it as invalid so it - // gets initialized again - m_server->markInvalid(); - m_server = 0; - } + + if (m_server) + m_server->send_response_fail_client(get_hostname()); shutdown(); + + m_root->pre_init(); } Yaz_ProxyClient::Yaz_ProxyClient(IPDU_Observable *the_PDU_Observable, @@ -3458,8 +3524,7 @@ void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len) if (apdu->which == Z_APDU_close) shutdown(); else if (server) - server->recv_GDU_more(); - + server->recv_GDU_more(true); } void Yaz_Proxy::low_socket_close()