1 /* $Id: yaz-proxy.cpp,v 1.33 2005-06-21 18:46:04 adam Exp $
2 Copyright (c) 1998-2005, Index Data.
4 This file is part of the yaz-proxy.
6 YAZ proxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
11 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with YAZ proxy; see the file LICENSE. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #define HAVE_SYS_STAT_H 1
24 #define HAVE_SYS_TYPES_H 1
34 #include <sys/types.h>
46 #include <yaz/marcdisp.h>
47 #include <yaz/yaz-iconv.h>
49 #include <yaz/diagbib1.h>
51 #include <yaz/pquery.h>
52 #include <yaz/otherinfo.h>
53 #include <yaz/charneg.h>
54 #include "msg-thread.h"
56 using namespace yazpp_1;
58 #define USE_AUTH_MSG 1
61 class Auth_Msg : public IMsg_Thread {
64 IMsg_Thread *handle();
76 m_nmem = nmem_create();
84 IMsg_Thread *Auth_Msg::handle()
86 yaz_log(YLOG_LOG, "Auth_Msg:handle begin");
87 ODR decode = odr_createmem(ODR_DECODE);
90 odr_setbuf(decode, m_apdu_buf, m_apdu_len, 0);
91 int r = z_APDU(decode, &apdu, 0, 0);
94 yaz_log(YLOG_WARN, "decode failed in Auth_Msg::handle");
98 m_ret = m_proxy->handle_authentication(apdu);
100 yaz_log(YLOG_LOG, "Auth_Msg:handle end");
105 void Auth_Msg::result()
107 yaz_log(YLOG_LOG, "Auth_Msg:result proxy ok buf=%p len=%d",
108 m_apdu_buf, m_apdu_len);
109 odr_reset(m_proxy->odr_decode());
110 odr_setbuf(m_proxy->odr_decode(), m_apdu_buf, m_apdu_len, 0);
112 int r = z_APDU(m_proxy->odr_decode(), &apdu, 0, 0);
114 yaz_log(YLOG_LOG, "Auth_Msg::result z_APDU OK");
116 yaz_log(YLOG_LOG, "Auth_Msg::result z_APDU failed");
117 m_proxy->result_authentication(apdu, m_ret);
123 void Yaz_Proxy::result_authentication(Z_APDU *apdu, int ret)
127 Z_APDU *apdu_reject = zget_APDU(odr_encode(), Z_APDU_initResponse);
128 *apdu_reject->u.initResponse->result = 0;
129 send_to_client(apdu_reject);
133 handle_incoming_Z_PDU_2(apdu);
136 static const char *apdu_name(Z_APDU *apdu)
140 case Z_APDU_initRequest:
141 return "initRequest";
142 case Z_APDU_initResponse:
143 return "initResponse";
144 case Z_APDU_searchRequest:
145 return "searchRequest";
146 case Z_APDU_searchResponse:
147 return "searchResponse";
148 case Z_APDU_presentRequest:
149 return "presentRequest";
150 case Z_APDU_presentResponse:
151 return "presentResponse";
152 case Z_APDU_deleteResultSetRequest:
153 return "deleteResultSetRequest";
154 case Z_APDU_deleteResultSetResponse:
155 return "deleteResultSetResponse";
156 case Z_APDU_scanRequest:
157 return "scanRequest";
158 case Z_APDU_scanResponse:
159 return "scanResponse";
160 case Z_APDU_sortRequest:
161 return "sortRequest";
162 case Z_APDU_sortResponse:
163 return "sortResponse";
164 case Z_APDU_extendedServicesRequest:
165 return "extendedServicesRequest";
166 case Z_APDU_extendedServicesResponse:
167 return "extendedServicesResponse";
174 static const char *gdu_name(Z_GDU *gdu)
179 return apdu_name(gdu->u.z3950);
180 case Z_GDU_HTTP_Request:
181 return "HTTP Request";
182 case Z_GDU_HTTP_Response:
183 return "HTTP Response";
185 return "Unknown request/response";
188 Yaz_Proxy::Yaz_Proxy(IPDU_Observable *the_PDU_Observable,
189 ISocketObservable *the_socket_observable,
192 Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
194 m_PDU_Observable = the_PDU_Observable;
195 m_socket_observable = the_socket_observable;
200 m_keepalive_limit_bw = 500000;
201 m_keepalive_limit_pdu = 1000;
203 m_default_target = 0;
204 m_proxy_negotiation_charset = 0;
205 m_proxy_negotiation_lang = 0;
206 m_charset_converter = new Yaz_CharsetConverter;
210 m_client_idletime = 600;
211 m_target_idletime = 600;
212 m_optimize = xstrdup ("1");
213 strcpy(m_session_str, "0 ");
220 m_timeout_mode = timeout_normal;
222 m_max_record_retrieve = 0;
226 m_flag_invalid_session = 0;
228 m_referenceId_mem = nmem_create();
230 m_marcxml_mode = none;
231 m_stylesheet_xsp = 0;
232 m_stylesheet_nprl = 0;
233 m_stylesheet_apdu = 0;
234 m_s2z_stylesheet = 0;
238 m_backend_charset = 0;
240 m_initRequest_apdu = 0;
241 m_initRequest_mem = 0;
242 m_initRequest_preferredMessageSize = 0;
243 m_initRequest_maximumRecordSize = 0;
244 m_initRequest_options = 0;
245 m_initRequest_version = 0;
246 m_initRequest_oi_negotiation_charsets = 0;
247 m_initRequest_oi_negotiation_num_charsets = 0;
248 m_initRequest_oi_negotiation_langs = 0;
249 m_initRequest_oi_negotiation_num_langs = 0;
250 m_initRequest_oi_negotiation_selected = 0;
251 m_apdu_invalid_session = 0;
252 m_mem_invalid_session = 0;
254 m_s2z_odr_search = 0;
256 m_s2z_search_apdu = 0;
257 m_s2z_present_apdu = 0;
258 m_http_keepalive = 0;
261 m_s2z_packing = Z_SRW_recordPacking_string;
262 #if HAVE_GETTIMEOFDAY
263 m_time_tv = xmalloc(sizeof(struct timeval));
264 struct timeval *tv = (struct timeval *) m_time_tv;
270 m_usemarcon_ini_stage1 = 0;
271 m_usemarcon_ini_stage2 = 0;
272 m_usemarcon = new Yaz_usemarcon();
280 void Yaz_Proxy::inc_ref()
285 Yaz_Proxy::~Yaz_Proxy()
287 yaz_log(YLOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str,
288 m_bytes_sent, m_bytes_recv);
289 nmem_destroy(m_initRequest_mem);
290 nmem_destroy(m_mem_invalid_session);
291 nmem_destroy(m_referenceId_mem);
293 xfree(m_proxyTarget);
294 xfree(m_default_target);
295 xfree(m_proxy_negotiation_charset);
296 xfree(m_proxy_negotiation_lang);
297 delete m_charset_converter;
301 if (m_stylesheet_xsp)
302 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
308 xfree (m_backend_type);
309 xfree (m_backend_charset);
310 xfree (m_usemarcon_ini_stage1);
311 xfree (m_usemarcon_ini_stage2);
314 odr_destroy(m_s2z_odr_init);
315 if (m_s2z_odr_search)
316 odr_destroy(m_s2z_odr_search);
324 void Yaz_Proxy::set_debug_mode(int mode)
329 int Yaz_Proxy::set_config(const char *config)
332 m_config = new Yaz_ProxyConfig();
333 xfree(m_config_fname);
334 m_config_fname = xstrdup(config);
335 int r = m_config->read_xml(config);
337 m_config->get_generic_info(&m_log_mask, &m_max_clients);
341 void Yaz_Proxy::set_default_target(const char *target)
343 xfree (m_default_target);
344 m_default_target = 0;
346 m_default_target = (char *) xstrdup (target);
349 void Yaz_Proxy::set_proxy_negotiation (const char *charset, const char *lang)
351 yaz_log(YLOG_LOG, "%sSet the proxy negotiation: charset to '%s', "
352 "language to '%s'", m_session_str, charset?charset:"none",
354 xfree (m_proxy_negotiation_charset);
355 xfree (m_proxy_negotiation_lang);
356 m_proxy_negotiation_charset = m_proxy_negotiation_lang = 0;
358 m_proxy_negotiation_charset = (char *) xstrdup (charset);
360 m_proxy_negotiation_lang = (char *) xstrdup (lang);
363 Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
366 return m_parent->check_reconfigure();
368 Yaz_ProxyConfig *cfg = m_config;
371 yaz_log(YLOG_LOG, "reconfigure");
373 if (m_config_fname && cfg)
375 yaz_log(YLOG_LOG, "reconfigure config %s", m_config_fname);
376 int r = cfg->read_xml(m_config_fname);
378 yaz_log(YLOG_WARN, "reconfigure failed");
382 cfg->get_generic_info(&m_log_mask, &m_max_clients);
386 yaz_log(YLOG_LOG, "reconfigure");
392 IPDU_Observer *Yaz_Proxy::sessionNotify(IPDU_Observable
393 *the_PDU_Observable, int fd)
396 Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable,
397 m_socket_observable, this);
398 new_proxy->m_config = 0;
399 new_proxy->m_config_fname = 0;
400 new_proxy->timeout(m_client_idletime);
401 new_proxy->m_target_idletime = m_target_idletime;
402 new_proxy->set_default_target(m_default_target);
403 new_proxy->m_max_clients = m_max_clients;
404 new_proxy->m_log_mask = m_log_mask;
405 new_proxy->set_APDU_log(get_APDU_log());
406 if (m_log_mask & PROXY_LOG_APDU_CLIENT)
407 new_proxy->set_APDU_yazlog(1);
409 new_proxy->set_APDU_yazlog(0);
410 sprintf(new_proxy->m_session_str, "%ld:%d ", (long) time(0), m_session_no);
412 new_proxy->m_peername = xstrdup(the_PDU_Observable->getpeername());
413 yaz_log (YLOG_LOG, "%sNew session %s", new_proxy->m_session_str,
414 new_proxy->m_peername);
415 new_proxy->set_proxy_negotiation(m_proxy_negotiation_charset,
416 m_proxy_negotiation_lang);
417 // create thread object the first time we get an incoming connection
419 m_my_thread = new Msg_Thread(m_socket_observable);
420 new_proxy->m_my_thread = m_my_thread;
424 char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
427 Z_OtherInformationUnit *oi;
429 ent.proto = PROTO_Z3950;
430 ent.oclass = CLASS_USERINFO;
431 ent.value = (oid_value) VAL_COOKIE;
432 assert (oid_ent_to_oid (&ent, oid));
434 if (oid_ent_to_oid (&ent, oid) &&
435 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
436 oi->which == Z_OtherInfo_characterInfo)
437 return oi->information.characterInfo;
440 char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
443 Z_OtherInformationUnit *oi;
445 ent.proto = PROTO_Z3950;
446 ent.oclass = CLASS_USERINFO;
447 ent.value = (oid_value) VAL_PROXY;
448 if (oid_ent_to_oid (&ent, oid) &&
449 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
450 oi->which == Z_OtherInfo_characterInfo)
451 return oi->information.characterInfo;
454 const char *Yaz_Proxy::load_balance(const char **url)
456 int zurl_in_use[MAX_ZURL_PLEX];
457 int zurl_in_spare[MAX_ZURL_PLEX];
461 for (i = 0; i<MAX_ZURL_PLEX; i++)
464 zurl_in_spare[i] = 0;
466 for (c = m_parent->m_clientPool; c; c = c->m_next)
468 for (i = 0; url[i]; i++)
469 if (!strcmp(url[i], c->get_hostname()))
472 if (c->m_cookie == 0 && c->m_server == 0 && c->m_waiting == 0)
476 int min_use = 100000;
477 int spare_for_min = 0;
479 const char *ret_min = 0;
480 const char *ret_spare = 0;
481 for (i = 0; url[i]; i++)
483 yaz_log(YLOG_DEBUG, "%szurl=%s use=%d spare=%d",
484 m_session_str, url[i], zurl_in_use[i], zurl_in_spare[i]);
485 if (min_use > zurl_in_use[i])
488 min_use = zurl_in_use[i];
489 spare_for_min = zurl_in_spare[i];
491 if (max_spare < zurl_in_spare[i])
494 max_spare = zurl_in_spare[i];
500 Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
501 const char *proxy_host)
504 Yaz_Proxy *parent = m_parent;
505 Yaz_ProxyClient *c = m_client;
509 const char *url[MAX_ZURL_PLEX];
510 Yaz_ProxyConfig *cfg = check_reconfigure();
513 if (parent && parent->m_debug_mode)
515 // only to be enabled for debugging...
516 if (!strcmp(proxy_host, "stop"))
519 xfree(m_default_target);
520 m_default_target = xstrdup(proxy_host);
522 proxy_host = m_default_target;
523 int client_idletime = -1;
524 const char *cql2rpn_fname = 0;
525 const char *negotiation_charset = 0;
526 const char *negotiation_lang = 0;
527 const char *query_charset = 0;
528 url[0] = m_default_target;
533 cfg->get_target_info(proxy_host, url, &m_bw_max,
534 &m_pdu_max, &m_max_record_retrieve,
535 &m_target_idletime, &client_idletime,
536 &parent->m_max_clients,
537 &m_keepalive_limit_bw,
538 &m_keepalive_limit_pdu,
541 &negotiation_charset,
545 if (client_idletime != -1)
547 m_client_idletime = client_idletime;
548 timeout(m_client_idletime);
551 m_cql2rpn.set_pqf_file(cql2rpn_fname);
552 if (negotiation_charset || negotiation_lang)
554 set_proxy_negotiation(negotiation_charset,
557 m_charset_converter->set_target_query_charset(query_charset);
560 yaz_log(YLOG_LOG, "%sNo default target", m_session_str);
563 // we don't handle multiplexing for cookie session, so we just
564 // pick the first one in this case (anonymous users will be able
565 // to use any backend)
566 if (cookie && *cookie)
567 m_proxyTarget = (char*) xstrdup(url[0]);
569 m_proxyTarget = (char*) xstrdup(load_balance(url));
571 if (cookie && *cookie)
572 { // search in sessions with a cookie
573 for (c = parent->m_clientPool; c; c = c->m_next)
576 assert (*c->m_prev == c);
577 if (c->m_cookie && !strcmp(cookie,c->m_cookie) &&
578 !strcmp(m_proxyTarget, c->get_hostname()))
581 // The following handles "cancel"
582 // If connection is busy (waiting for PDU) and
583 // we have an initRequest we can safely do re-open
584 if (c->m_waiting && apdu->which == Z_APDU_initRequest)
586 yaz_log (YLOG_LOG, "%s REOPEN target=%s", m_session_str,
593 c->m_last_resultCount = 0;
594 c->m_sr_transform = 0;
596 c->m_resultSetStartPoint = 0;
597 c->m_target_idletime = m_target_idletime;
598 if (c->client(m_proxyTarget))
605 c->m_seqno = parent->m_seqno;
606 if (c->m_server && c->m_server != this)
607 c->m_server->m_client = 0;
610 yaz_log (YLOG_DEBUG, "get_client 1 %p %p", this, c);
616 apdu->which == Z_APDU_initRequest &&
617 apdu->u.initRequest->idAuthentication == 0 &&
618 !ODR_MASK_GET(apdu->u.initRequest->options, Z_Options_negotiationModel))
620 // anonymous sessions without cookie.
621 // if authentication is set it is NOT anonymous se we can't share them.
622 // If charset and lang negotiation is use it is NOT anonymous session too.
623 for (c = parent->m_clientPool; c; c = c->m_next)
626 assert(*c->m_prev == c);
627 if (c->m_server == 0 && c->m_cookie == 0 &&
629 !strcmp(m_proxyTarget, c->get_hostname()))
632 yaz_log (YLOG_LOG, "%sREUSE %d %s",
633 m_session_str, parent->m_seqno, c->get_hostname());
635 c->m_seqno = parent->m_seqno;
636 assert(c->m_server == 0);
639 if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
640 c->set_APDU_yazlog(1);
642 c->set_APDU_yazlog(0);
654 if (apdu->which != Z_APDU_initRequest)
656 yaz_log (YLOG_LOG, "%sno init request as first PDU", m_session_str);
659 Z_InitRequest *initRequest = apdu->u.initRequest;
661 if (initRequest->idAuthentication)
663 // the client uses authentication. We set the keepalive PDU
664 // to 0 so we don't cache it in releaseClient
665 m_keepalive_limit_pdu = 0;
667 // go through list of clients - and find the lowest/oldest one.
668 Yaz_ProxyClient *c_min = 0;
670 int no_of_clients = 0;
671 if (parent->m_clientPool)
672 yaz_log (YLOG_DEBUG, "Existing sessions");
673 for (c = parent->m_clientPool; c; c = c->m_next)
675 yaz_log (YLOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
676 c->m_waiting, c->get_hostname(),
677 c->m_cookie ? c->m_cookie : "");
679 if (min_seq < 0 || c->m_seqno < min_seq)
681 min_seq = c->m_seqno;
685 if (no_of_clients >= parent->m_max_clients)
688 if (c->m_waiting || strcmp(m_proxyTarget, c->get_hostname()))
690 yaz_log (YLOG_LOG, "%sMAXCLIENTS %d Destroy %d",
691 m_session_str, parent->m_max_clients, c->m_seqno);
692 if (c->m_server && c->m_server != this)
698 yaz_log (YLOG_LOG, "%sMAXCLIENTS %d Reuse %d %d %s",
699 m_session_str, parent->m_max_clients,
700 c->m_seqno, parent->m_seqno, c->get_hostname());
704 c->m_cookie = xstrdup(cookie);
705 c->m_seqno = parent->m_seqno;
706 if (c->m_server && c->m_server != this)
708 c->m_server->m_client = 0;
712 c->m_target_idletime = m_target_idletime;
713 c->timeout(m_target_idletime);
715 if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
716 c->set_APDU_yazlog(1);
718 c->set_APDU_yazlog(0);
725 yaz_log (YLOG_LOG, "%sNEW %d %s",
726 m_session_str, parent->m_seqno, m_proxyTarget);
727 c = new Yaz_ProxyClient(m_PDU_Observable->clone(), parent);
728 c->m_next = parent->m_clientPool;
730 c->m_next->m_prev = &c->m_next;
731 parent->m_clientPool = c;
732 c->m_prev = &parent->m_clientPool;
738 c->m_cookie = xstrdup(cookie);
740 c->m_seqno = parent->m_seqno;
742 c->m_last_resultCount = 0;
745 c->m_sr_transform = 0;
747 c->m_resultSetStartPoint = 0;
749 if (c->client(m_proxyTarget))
754 c->m_target_idletime = m_target_idletime;
757 if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
758 c->set_APDU_yazlog(1);
760 c->set_APDU_yazlog(0);
762 yaz_log (YLOG_DEBUG, "get_client 3 %p %p", this, c);
766 void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
769 for (i = 0; i<num; i++)
772 Z_DefaultDiagFormat *r;
773 Z_DiagRec *p = pp[i];
774 if (p->which != Z_DiagRec_defaultFormat)
776 yaz_log(YLOG_LOG, "%sError no diagnostics", m_session_str);
780 r = p->u.defaultFormat;
781 if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
782 ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
783 yaz_log(YLOG_LOG, "%sError unknown diagnostic set", m_session_str);
786 case Z_DefaultDiagFormat_v2Addinfo:
787 yaz_log(YLOG_LOG, "%sError %d %s:%s",
789 *r->condition, diagbib1_str(*r->condition),
792 case Z_DefaultDiagFormat_v3Addinfo:
793 yaz_log(YLOG_LOG, "%sError %d %s:%s",
795 *r->condition, diagbib1_str(*r->condition),
802 int Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu)
804 if (!m_stylesheet_xsp || p->num_records <= 0)
805 return 0; /* no XSLT to be done ... */
807 m_stylesheet_offset = 0;
808 m_stylesheet_nprl = p;
809 m_stylesheet_apdu = apdu;
810 m_timeout_mode = timeout_xsl;
816 void Yaz_Proxy::convert_xsl_delay()
819 Z_NamePlusRecord *npr = m_stylesheet_nprl->records[m_stylesheet_offset];
820 if (npr->which == Z_NamePlusRecord_databaseRecord)
822 Z_External *r = npr->u.databaseRecord;
823 if (r->which == Z_External_octet)
826 fwrite((char*) r->u.octet_aligned->buf, 1, r->u.octet_aligned->len, stdout);
828 xmlDocPtr res, doc = xmlParseMemory(
829 (char*) r->u.octet_aligned->buf,
830 r->u.octet_aligned->len);
833 yaz_log(YLOG_LOG, "%sXSLT convert %d",
834 m_session_str, m_stylesheet_offset);
835 res = xsltApplyStylesheet((xsltStylesheetPtr) m_stylesheet_xsp,
842 xmlDocDumpFormatMemory (res, &out_buf, &out_len, 1);
844 m_stylesheet_nprl->records[m_stylesheet_offset]->
846 z_ext_record(odr_encode(), VAL_TEXT_XML,
847 (char*) out_buf, out_len);
856 m_stylesheet_offset++;
857 if (m_stylesheet_offset == m_stylesheet_nprl->num_records)
859 m_timeout_mode = timeout_normal;
860 m_stylesheet_nprl = 0;
862 if (m_stylesheet_xsp)
863 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
865 m_stylesheet_xsp = 0;
866 timeout(m_client_idletime);
867 send_PDU_convert(m_stylesheet_apdu);
873 void Yaz_Proxy::convert_to_frontend_type(Z_NamePlusRecordList *p)
875 if (m_frontend_type != VAL_NONE)
878 for (i = 0; i < p->num_records; i++)
880 Z_NamePlusRecord *npr = p->records[i];
881 if (npr->which == Z_NamePlusRecord_databaseRecord)
883 Z_External *r = npr->u.databaseRecord;
884 if (r->which == Z_External_octet)
887 if (m_usemarcon_ini_stage1 && *m_usemarcon_ini_stage1)
889 if (!m_usemarcon->m_stage1)
891 m_usemarcon->m_stage1 = new CDetails();
893 m_usemarcon->m_stage1->SetIniFileName(m_usemarcon_ini_stage1);
894 m_usemarcon->m_stage1->SetMarcRecord((char*) r->u.octet_aligned->buf, r->u.octet_aligned->len);
895 int res = m_usemarcon->m_stage1->Start();
900 m_usemarcon->m_stage1->GetMarcRecord(converted, convlen);
901 if (m_usemarcon_ini_stage2 && *m_usemarcon_ini_stage2)
903 if (!m_usemarcon->m_stage2)
905 m_usemarcon->m_stage2 = new CDetails();
907 m_usemarcon->m_stage2->SetIniFileName(m_usemarcon_ini_stage2);
908 m_usemarcon->m_stage2->SetMarcRecord(converted, convlen);
909 res = m_usemarcon->m_stage2->Start();
913 m_usemarcon->m_stage2->GetMarcRecord(converted, convlen);
917 yaz_log(YLOG_LOG, "%sUSEMARCON stage 2 error %d", m_session_str, res);
920 npr->u.databaseRecord =
921 z_ext_record(odr_encode(),
929 yaz_log(YLOG_LOG, "%sUSEMARCON stage 1 error %d", m_session_str, res);
935 npr->u.databaseRecord =
936 z_ext_record(odr_encode(),
938 (char*) r->u.octet_aligned->buf,
939 r->u.octet_aligned->len);
946 void Yaz_Proxy::convert_records_charset(Z_NamePlusRecordList *p,
947 const char *backend_charset)
949 yaz_log(YLOG_LOG, "%sconvert_to_marc", m_session_str);
950 int sel = m_charset_converter->get_client_charset_selected();
951 const char *client_record_charset =
952 m_charset_converter->get_client_query_charset();
953 if (sel && backend_charset && client_record_charset &&
954 strcmp(backend_charset, client_record_charset))
957 yaz_iconv_t cd = yaz_iconv_open(client_record_charset,
959 yaz_marc_t mt = yaz_marc_create();
960 yaz_marc_xml(mt, YAZ_MARC_ISO2709);
961 yaz_marc_iconv(mt, cd);
962 for (i = 0; i < p->num_records; i++)
964 Z_NamePlusRecord *npr = p->records[i];
965 if (npr->which == Z_NamePlusRecord_databaseRecord)
967 Z_External *r = npr->u.databaseRecord;
968 oident *ent = oid_getentbyoid(r->direct_reference);
969 if (!ent || ent->value == VAL_NONE)
972 if (ent->value == VAL_SUTRS)
974 WRBUF w = wrbuf_alloc();
976 wrbuf_iconv_write(w, cd, (char*) r->u.octet_aligned->buf,
977 r->u.octet_aligned->len);
978 npr->u.databaseRecord =
979 z_ext_record(odr_encode(), ent->value, wrbuf_buf(w),
983 else if (ent->value == VAL_TEXT_XML)
987 else if (r->which == Z_External_octet)
991 if (yaz_marc_decode_buf(mt,
992 (char*) r->u.octet_aligned->buf,
993 r->u.octet_aligned->len,
996 npr->u.databaseRecord =
997 z_ext_record(odr_encode(), ent->value, result, rlen);
998 yaz_log(YLOG_LOG, "%sRecoding MARC record",
1005 yaz_iconv_close(cd);
1006 yaz_marc_destroy(mt);
1010 yaz_log(YLOG_LOG, "%sSkipping marc convert", m_session_str);
1014 void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
1015 const char *backend_charset)
1018 if (!backend_charset)
1019 backend_charset = "MARC-8";
1020 yaz_iconv_t cd = yaz_iconv_open("UTF-8", backend_charset);
1021 yaz_marc_t mt = yaz_marc_create();
1022 yaz_marc_xml(mt, YAZ_MARC_MARCXML);
1023 yaz_marc_iconv(mt, cd);
1024 for (i = 0; i < p->num_records; i++)
1026 Z_NamePlusRecord *npr = p->records[i];
1027 if (npr->which == Z_NamePlusRecord_databaseRecord)
1029 Z_External *r = npr->u.databaseRecord;
1030 if (r->which == Z_External_OPAC)
1032 WRBUF w = wrbuf_alloc();
1034 yaz_display_OPAC(w, r->u.opac, 0);
1035 npr->u.databaseRecord = z_ext_record(
1036 odr_encode(), VAL_TEXT_XML,
1037 wrbuf_buf(w), wrbuf_len(w)
1041 else if (r->which == Z_External_octet)
1045 if (yaz_marc_decode_buf(mt, (char*) r->u.octet_aligned->buf,
1046 r->u.octet_aligned->len,
1049 npr->u.databaseRecord =
1050 z_ext_record(odr_encode(), VAL_TEXT_XML, result, rlen);
1056 yaz_iconv_close(cd);
1057 yaz_marc_destroy(mt);
1060 void Yaz_Proxy::logtime()
1062 #if HAVE_GETTIMEOFDAY
1063 struct timeval *tv = (struct timeval*) m_time_tv;
1067 gettimeofday(&tv1, 0);
1068 long diff = (tv1.tv_sec - tv->tv_sec)*1000000 +
1069 (tv1.tv_usec - tv->tv_usec);
1071 yaz_log(YLOG_LOG, "%sElapsed %ld.%03ld", m_session_str,
1072 diff/1000000, (diff/1000)%1000);
1079 int Yaz_Proxy::send_http_response(int code)
1081 ODR o = odr_encode();
1082 Z_GDU *gdu = z_get_HTTP_Response(o, code);
1083 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
1085 hres->version = odr_strdup(o, m_http_version);
1086 if (m_http_keepalive)
1087 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1091 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
1093 yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
1097 int r = send_GDU(gdu, &len);
1098 m_bytes_sent += len;
1099 m_bw_stat.add_bytes(len);
1104 int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
1106 ODR o = odr_encode();
1107 const char *ctype = "text/xml";
1108 Z_GDU *gdu = z_get_HTTP_Response(o, 200);
1109 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
1111 hres->version = odr_strdup(o, m_http_version);
1112 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1113 if (m_http_keepalive)
1114 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1118 static Z_SOAP_Handler soap_handlers[2] = {
1120 {"http://www.loc.gov/zing/srw/", 0,
1121 (Z_SOAP_fun) yaz_srw_codec},
1126 Z_SOAP *soap_package = (Z_SOAP*) odr_malloc(o, sizeof(Z_SOAP));
1127 soap_package->which = Z_SOAP_generic;
1128 soap_package->u.generic =
1129 (Z_SOAP_Generic *) odr_malloc(o, sizeof(*soap_package->u.generic));
1130 soap_package->u.generic->no = 0;
1131 soap_package->u.generic->ns = soap_handlers[0].ns;
1132 soap_package->u.generic->p = (void *) srw_pdu;
1133 soap_package->ns = m_soap_ns;
1134 z_soap_codec_enc_xsl(o, &soap_package,
1135 &hres->content_buf, &hres->content_len,
1136 soap_handlers, 0, m_s2z_stylesheet);
1137 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
1139 yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
1143 int r = send_GDU(gdu, &len);
1144 m_bytes_sent += len;
1145 m_bw_stat.add_bytes(len);
1150 int Yaz_Proxy::send_to_srw_client_error(int srw_error, const char *add)
1152 ODR o = odr_encode();
1153 Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
1154 Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
1156 srw_res->num_diagnostics = 1;
1157 srw_res->diagnostics = (Z_SRW_diagnostic *)
1158 odr_malloc(o, sizeof(*srw_res->diagnostics));
1159 yaz_mk_std_diagnostic(o, srw_res->diagnostics, srw_error, add);
1160 return send_srw_response(srw_pdu);
1163 int Yaz_Proxy::z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
1164 Z_DefaultDiagFormat *ddf)
1166 int bib1_code = *ddf->condition;
1167 if (bib1_code == 109)
1169 srw_res->num_diagnostics = 1;
1170 srw_res->diagnostics = (Z_SRW_diagnostic *)
1171 odr_malloc(o, sizeof(*srw_res->diagnostics));
1172 yaz_mk_std_diagnostic(o, srw_res->diagnostics,
1173 yaz_diag_bib1_to_srw(*ddf->condition),
1178 int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start)
1180 ODR o = odr_encode();
1181 Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
1182 Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
1184 srw_res->numberOfRecords = odr_intdup (o, hits);
1185 if (records && records->which == Z_Records_DBOSD)
1187 srw_res->num_records =
1188 records->u.databaseOrSurDiagnostics->num_records;
1190 srw_res->records = (Z_SRW_record *)
1191 odr_malloc(o, srw_res->num_records * sizeof(Z_SRW_record));
1192 for (i = 0; i < srw_res->num_records; i++)
1194 Z_NamePlusRecord *npr = records->u.databaseOrSurDiagnostics->records[i];
1195 if (npr->which != Z_NamePlusRecord_databaseRecord)
1197 srw_res->records[i].recordSchema = "diagnostic";
1198 srw_res->records[i].recordPacking = m_s2z_packing;
1199 srw_res->records[i].recordData_buf = "67";
1200 srw_res->records[i].recordData_len = 2;
1201 srw_res->records[i].recordPosition = odr_intdup(o, i+start);
1204 Z_External *r = npr->u.databaseRecord;
1205 oident *ent = oid_getentbyoid(r->direct_reference);
1206 if (r->which == Z_External_octet && ent->value == VAL_TEXT_XML)
1208 srw_res->records[i].recordSchema = m_schema;
1209 srw_res->records[i].recordPacking = m_s2z_packing;
1210 srw_res->records[i].recordData_buf = (char*)
1211 r->u.octet_aligned->buf;
1212 srw_res->records[i].recordData_len = r->u.octet_aligned->len;
1213 srw_res->records[i].recordPosition = odr_intdup(o, i+start);
1217 srw_res->records[i].recordSchema = "diagnostic";
1218 srw_res->records[i].recordPacking = m_s2z_packing;
1219 srw_res->records[i].recordData_buf = "67";
1220 srw_res->records[i].recordData_len = 2;
1221 srw_res->records[i].recordPosition = odr_intdup(o, i+start);
1225 if (records && records->which == Z_Records_NSD)
1228 http_code = z_to_srw_diag(odr_encode(), srw_res,
1229 records->u.nonSurrogateDiagnostic);
1231 return send_http_response(http_code);
1233 return send_srw_response(srw_pdu);
1237 int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
1238 int num_diagnostics)
1240 Yaz_ProxyConfig *cfg = check_reconfigure();
1244 char *b = cfg->get_explain_doc(odr_encode(), 0 /* target */,
1245 m_s2z_database, &len);
1248 Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
1249 Z_SRW_explainResponse *er = res->u.explain_response;
1251 er->record.recordData_buf = b;
1252 er->record.recordData_len = len;
1253 er->record.recordPacking = m_s2z_packing;
1254 er->record.recordSchema = "http://explain.z3950.org/dtd/2.0/";
1256 er->diagnostics = diagnostics;
1257 er->num_diagnostics = num_diagnostics;
1258 return send_srw_response(res);
1261 return send_http_response(404);
1264 int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu)
1268 if (apdu->which == Z_APDU_initResponse)
1270 Z_InitResponse *res = apdu->u.initResponse;
1271 if (*res->result == 0)
1273 send_to_srw_client_error(3, 0);
1275 else if (!m_s2z_search_apdu)
1277 send_srw_explain_response(0, 0);
1281 handle_incoming_Z_PDU(m_s2z_search_apdu);
1284 else if (m_s2z_search_apdu && apdu->which == Z_APDU_searchResponse)
1286 m_s2z_search_apdu = 0;
1287 Z_SearchResponse *res = apdu->u.searchResponse;
1288 m_s2z_hit_count = *res->resultCount;
1289 if (res->records && res->records->which == Z_Records_NSD)
1291 send_to_srw_client_ok(0, res->records, 1);
1293 else if (m_s2z_present_apdu && m_s2z_hit_count > 0)
1296 Z_PresentRequest *pr = m_s2z_present_apdu->u.presentRequest;
1298 if (*pr->resultSetStartPoint <= m_s2z_hit_count)
1300 if (*pr->numberOfRecordsRequested+ *pr->resultSetStartPoint
1302 *pr->numberOfRecordsRequested =
1303 1 + m_s2z_hit_count - *pr->resultSetStartPoint;
1305 handle_incoming_Z_PDU(m_s2z_present_apdu);
1309 m_s2z_present_apdu = 0;
1310 send_to_srw_client_ok(m_s2z_hit_count, res->records, 1);
1313 else if (m_s2z_present_apdu && apdu->which == Z_APDU_presentResponse)
1316 *m_s2z_present_apdu->u.presentRequest->resultSetStartPoint;
1318 m_s2z_present_apdu = 0;
1319 Z_PresentResponse *res = apdu->u.presentResponse;
1320 send_to_srw_client_ok(m_s2z_hit_count, res->records, start);
1326 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
1327 yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
1329 int r = send_Z_PDU(apdu, &len);
1330 m_bytes_sent += len;
1331 m_bw_stat.add_bytes(len);
1338 int Yaz_Proxy::send_to_client(Z_APDU *apdu)
1340 int kill_session = 0;
1341 Z_ReferenceId **new_id = get_referenceIdP(apdu);
1344 *new_id = m_referenceId;
1346 if (apdu->which == Z_APDU_searchResponse)
1348 Z_SearchResponse *sr = apdu->u.searchResponse;
1349 Z_Records *p = sr->records;
1350 if (p && p->which == Z_Records_NSD)
1352 Z_DiagRec dr, *dr_p = &dr;
1353 dr.which = Z_DiagRec_defaultFormat;
1354 dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
1356 *sr->searchStatus = 0;
1357 display_diagrecs(&dr_p, 1);
1361 if (p && p->which == Z_Records_DBOSD)
1365 || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
1368 convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
1369 if (m_marcxml_mode == marcxml)
1370 convert_to_marcxml(p->u.databaseOrSurDiagnostics,
1373 convert_records_charset(p->u.databaseOrSurDiagnostics,
1375 if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
1379 if (sr->resultCount)
1381 yaz_log(YLOG_LOG, "%s%d hits", m_session_str,
1383 if (*sr->resultCount < 0)
1385 m_flag_invalid_session = 1;
1388 *sr->searchStatus = 0;
1390 create_nonSurrogateDiagnostics(odr_encode(), 2, 0);
1391 *sr->resultCount = 0;
1396 else if (apdu->which == Z_APDU_presentResponse)
1398 Z_PresentResponse *sr = apdu->u.presentResponse;
1399 Z_Records *p = sr->records;
1400 if (p && p->which == Z_Records_NSD)
1402 Z_DiagRec dr, *dr_p = &dr;
1403 dr.which = Z_DiagRec_defaultFormat;
1404 dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
1405 if (*sr->presentStatus == Z_PresentStatus_success)
1406 *sr->presentStatus = Z_PresentStatus_failure;
1407 display_diagrecs(&dr_p, 1);
1409 if (p && p->which == Z_Records_DBOSD)
1413 || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
1416 convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
1417 if (m_marcxml_mode == marcxml)
1418 convert_to_marcxml(p->u.databaseOrSurDiagnostics,
1421 convert_records_charset(p->u.databaseOrSurDiagnostics,
1423 if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
1427 else if (apdu->which == Z_APDU_initResponse)
1429 //Get and check negotiation record
1430 //from init response.
1431 handle_charset_lang_negotiation(apdu);
1433 if (m_initRequest_options)
1436 (Odr_bitmask *)odr_malloc(odr_encode(),
1437 sizeof(Odr_bitmask));
1438 ODR_MASK_ZERO(nopt);
1441 for (i = 0; i<24; i++)
1442 if (ODR_MASK_GET(m_initRequest_options, i) &&
1443 ODR_MASK_GET(apdu->u.initResponse->options, i))
1444 ODR_MASK_SET(nopt, i);
1445 apdu->u.initResponse->options = nopt;
1447 if (m_initRequest_version)
1449 Z_ProtocolVersion *nopt =
1450 (Odr_bitmask *)odr_malloc(odr_encode(),
1451 sizeof(Odr_bitmask));
1452 ODR_MASK_ZERO(nopt);
1455 for (i = 0; i<8; i++)
1456 if (ODR_MASK_GET(m_initRequest_version, i) &&
1457 ODR_MASK_GET(apdu->u.initResponse->protocolVersion, i))
1458 ODR_MASK_SET(nopt, i);
1459 apdu->u.initResponse->protocolVersion = nopt;
1461 apdu->u.initResponse->preferredMessageSize =
1462 odr_intdup(odr_encode(),
1463 m_client->m_initResponse_preferredMessageSize >
1464 m_initRequest_preferredMessageSize ?
1465 m_initRequest_preferredMessageSize :
1466 m_client->m_initResponse_preferredMessageSize);
1467 apdu->u.initResponse->maximumRecordSize =
1468 odr_intdup(odr_encode(),
1469 m_client->m_initResponse_maximumRecordSize >
1470 m_initRequest_maximumRecordSize ?
1471 m_initRequest_maximumRecordSize :
1472 m_client->m_initResponse_maximumRecordSize);
1475 int r = send_PDU_convert(apdu);
1482 m_parent->pre_init();
1487 int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
1490 const char *apdu_name_tmp = apdu_name(apdu);
1491 int r = send_Z_PDU(apdu, &len);
1492 if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
1493 yaz_log (YLOG_LOG, "%sSending %s to %s %d bytes",
1495 apdu_name_tmp, get_hostname(), len);
1496 m_bytes_sent += len;
1500 Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
1502 if (apdu->which == Z_APDU_presentRequest)
1504 Z_PresentRequest *pr = apdu->u.presentRequest;
1505 int toget = *pr->numberOfRecordsRequested;
1506 int start = *pr->resultSetStartPoint;
1508 yaz_log(YLOG_LOG, "%sPresent %s %d+%d", m_session_str,
1509 pr->resultSetId, start, toget);
1511 if (*m_parent->m_optimize == '0')
1514 if (!m_client->m_last_resultSetId)
1516 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
1517 new_apdu->u.presentResponse->records =
1518 create_nonSurrogateDiagnostics(odr_encode(), 30,
1520 send_to_client(new_apdu);
1523 if (!strcmp(m_client->m_last_resultSetId, pr->resultSetId))
1525 if (start+toget-1 > m_client->m_last_resultCount)
1527 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
1528 new_apdu->u.presentResponse->records =
1529 create_nonSurrogateDiagnostics(odr_encode(), 13, 0);
1530 send_to_client(new_apdu);
1533 Z_NamePlusRecordList *npr;
1535 yaz_log(YLOG_LOG, "%sCache lookup %d+%d syntax=%s",
1536 m_session_str, start, toget, yaz_z3950oid_to_str(
1537 pr->preferredRecordSyntax, &oclass));
1539 if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget,
1540 pr->preferredRecordSyntax,
1541 pr->recordComposition))
1543 yaz_log (YLOG_LOG, "%sReturned cached records for present request",
1545 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
1546 new_apdu->u.presentResponse->referenceId = pr->referenceId;
1548 new_apdu->u.presentResponse->numberOfRecordsReturned
1549 = odr_intdup(odr_encode(), toget);
1551 new_apdu->u.presentResponse->records = (Z_Records*)
1552 odr_malloc(odr_encode(), sizeof(Z_Records));
1553 new_apdu->u.presentResponse->records->which = Z_Records_DBOSD;
1554 new_apdu->u.presentResponse->records->u.databaseOrSurDiagnostics = npr;
1555 new_apdu->u.presentResponse->nextResultSetPosition =
1556 odr_intdup(odr_encode(), start+toget);
1558 send_to_client(new_apdu);
1564 if (apdu->which != Z_APDU_searchRequest)
1566 Z_SearchRequest *sr = apdu->u.searchRequest;
1567 Yaz_Z_Query *this_query = new Yaz_Z_Query;
1568 Yaz_Z_Databases this_databases;
1570 this_databases.set(sr->num_databaseNames, (const char **)
1573 this_query->set_Z_Query(sr->query);
1575 char query_str[120];
1576 this_query->print(query_str, sizeof(query_str)-1);
1577 yaz_log(YLOG_LOG, "%sSearch %s", m_session_str, query_str);
1579 if (*m_parent->m_optimize != '0' &&
1580 m_client->m_last_ok && m_client->m_last_query &&
1581 m_client->m_last_query->match(this_query) &&
1582 !strcmp(m_client->m_last_resultSetId, sr->resultSetName) &&
1583 m_client->m_last_databases.match(this_databases))
1586 if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
1587 m_client->m_last_resultCount < *sr->largeSetLowerBound)
1589 Z_NamePlusRecordList *npr;
1590 int toget = *sr->mediumSetPresentNumber;
1591 Z_RecordComposition *comp = 0;
1593 if (toget > m_client->m_last_resultCount)
1594 toget = m_client->m_last_resultCount;
1596 if (sr->mediumSetElementSetNames)
1598 comp = (Z_RecordComposition *)
1599 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
1600 comp->which = Z_RecordComp_simple;
1601 comp->u.simple = sr->mediumSetElementSetNames;
1604 if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
1605 sr->preferredRecordSyntax, comp))
1607 yaz_log (YLOG_LOG, "%sReturned cached records for medium set",
1609 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1610 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1611 new_apdu->u.searchResponse->resultCount =
1612 &m_client->m_last_resultCount;
1614 new_apdu->u.searchResponse->numberOfRecordsReturned
1615 = odr_intdup(odr_encode(), toget);
1617 new_apdu->u.searchResponse->presentStatus =
1618 odr_intdup(odr_encode(), Z_PresentStatus_success);
1619 new_apdu->u.searchResponse->records = (Z_Records*)
1620 odr_malloc(odr_encode(), sizeof(Z_Records));
1621 new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
1622 new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
1623 new_apdu->u.searchResponse->nextResultSetPosition =
1624 odr_intdup(odr_encode(), toget+1);
1625 send_to_client(new_apdu);
1631 // send present request (medium size)
1632 yaz_log (YLOG_LOG, "%sOptimizing search for medium set",
1635 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
1636 Z_PresentRequest *pr = new_apdu->u.presentRequest;
1637 pr->referenceId = sr->referenceId;
1638 pr->resultSetId = sr->resultSetName;
1639 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
1640 *pr->numberOfRecordsRequested = toget;
1641 pr->recordComposition = comp;
1642 m_client->m_sr_transform = 1;
1646 else if (m_client->m_last_resultCount >= *sr->largeSetLowerBound ||
1647 m_client->m_last_resultCount <= 0)
1649 // large set. Return pseudo-search response immediately
1650 yaz_log (YLOG_LOG, "%sOptimizing search for large set",
1652 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1653 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1654 new_apdu->u.searchResponse->resultCount =
1655 &m_client->m_last_resultCount;
1656 send_to_client(new_apdu);
1661 Z_NamePlusRecordList *npr;
1662 int toget = m_client->m_last_resultCount;
1663 Z_RecordComposition *comp = 0;
1665 // send a present request (small set)
1667 if (sr->smallSetElementSetNames)
1669 comp = (Z_RecordComposition *)
1670 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
1671 comp->which = Z_RecordComp_simple;
1672 comp->u.simple = sr->smallSetElementSetNames;
1675 if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
1676 sr->preferredRecordSyntax, comp))
1678 yaz_log (YLOG_LOG, "%sReturned cached records for small set",
1680 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1681 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1682 new_apdu->u.searchResponse->resultCount =
1683 &m_client->m_last_resultCount;
1685 new_apdu->u.searchResponse->numberOfRecordsReturned
1686 = odr_intdup(odr_encode(), toget);
1688 new_apdu->u.searchResponse->presentStatus =
1689 odr_intdup(odr_encode(), Z_PresentStatus_success);
1690 new_apdu->u.searchResponse->records = (Z_Records*)
1691 odr_malloc(odr_encode(), sizeof(Z_Records));
1692 new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
1693 new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
1694 new_apdu->u.searchResponse->nextResultSetPosition =
1695 odr_intdup(odr_encode(), toget+1);
1696 send_to_client(new_apdu);
1701 yaz_log (YLOG_LOG, "%sOptimizing search for small set",
1703 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
1704 Z_PresentRequest *pr = new_apdu->u.presentRequest;
1705 pr->referenceId = sr->referenceId;
1706 pr->resultSetId = sr->resultSetName;
1707 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
1708 *pr->numberOfRecordsRequested = toget;
1709 pr->recordComposition = comp;
1710 m_client->m_sr_transform = 1;
1715 else // query doesn't match
1717 delete m_client->m_last_query;
1718 m_client->m_last_query = this_query;
1719 m_client->m_last_ok = 0;
1720 m_client->m_cache.clear();
1721 m_client->m_resultSetStartPoint = 0;
1723 xfree (m_client->m_last_resultSetId);
1724 m_client->m_last_resultSetId = xstrdup (sr->resultSetName);
1726 m_client->m_last_databases.set(sr->num_databaseNames,
1727 (const char **) sr->databaseNames);
1733 void Yaz_Proxy::inc_request_no()
1735 char *cp = strchr(m_session_str, ' ');
1738 sprintf(cp+1, "%d ", m_request_no);
1741 void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
1745 m_bytes_recv += len;
1747 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
1748 yaz_log (YLOG_LOG, "%sReceiving %s from client %d bytes",
1749 m_session_str, gdu_name(apdu), len);
1751 #if HAVE_GETTIMEOFDAY
1752 gettimeofday((struct timeval *) m_time_tv, 0);
1754 m_bw_stat.add_bytes(len);
1755 m_pdu_stat.add_bytes(1);
1757 GDU *gdu = new GDU(apdu);
1758 int qsize = m_in_queue.size();
1759 if (m_timeout_mode != timeout_normal)
1761 yaz_log(YLOG_LOG, "%sAdded gdu in queue of size %d", m_session_str,
1763 m_in_queue.enqueue(gdu);
1767 recv_GDU_reduce(gdu);
1772 void Yaz_Proxy::recv_GDU_reduce(GDU *gdu)
1774 int bw_total = m_bw_stat.get_total();
1775 int pdu_total = m_pdu_stat.get_total();
1778 assert(m_timeout_mode == timeout_normal);
1779 assert(m_timeout_gdu == 0);
1783 if (bw_total > m_bw_max)
1785 reduce = (bw_total/m_bw_max);
1790 if (pdu_total > m_pdu_max)
1792 int nreduce = (m_pdu_max >= 60) ? 1 : 60/m_pdu_max;
1793 reduce = (reduce > nreduce) ? reduce : nreduce;
1800 yaz_log(YLOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
1801 m_session_str, reduce, bw_total, pdu_total,
1802 m_bw_max, m_pdu_max);
1804 m_timeout_mode = timeout_reduce;
1805 m_timeout_gdu = gdu;
1806 // m_bw_hold_PDU = apdu; // save PDU and signal "on hold"
1807 timeout(reduce); // call us reduce seconds later
1810 recv_GDU_normal(gdu);
1813 void Yaz_Proxy::recv_GDU_more()
1816 while (m_timeout_mode == timeout_normal && (g = m_in_queue.dequeue()))
1820 void Yaz_Proxy::recv_GDU_normal(GDU *gdu)
1822 Z_GDU *apdu = gdu->get();
1823 gdu->extract_odr_to(odr_decode());
1826 if (apdu->which == Z_GDU_Z3950)
1827 handle_incoming_Z_PDU(apdu->u.z3950);
1828 else if (apdu->which == Z_GDU_HTTP_Request)
1829 handle_incoming_HTTP(apdu->u.HTTP_Request);
1832 void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)
1834 if (m_max_record_retrieve)
1836 if (apdu->which == Z_APDU_presentRequest)
1838 Z_PresentRequest *pr = apdu->u.presentRequest;
1839 if (pr->numberOfRecordsRequested &&
1840 *pr->numberOfRecordsRequested > m_max_record_retrieve)
1841 *pr->numberOfRecordsRequested = m_max_record_retrieve;
1846 void Yaz_Proxy::handle_charset_lang_negotiation(Z_APDU *apdu)
1848 if (apdu->which == Z_APDU_initRequest)
1850 yaz_log(YLOG_LOG, "%shandle_charset_lang_negotiation",
1852 if (m_initRequest_options &&
1853 !ODR_MASK_GET(m_initRequest_options, Z_Options_negotiationModel) &&
1854 (m_proxy_negotiation_charset || m_proxy_negotiation_lang))
1856 // There is no negotiation proposal from
1857 // client's side. OK. The proxy negotiation
1859 Z_InitRequest *initRequest = apdu->u.initRequest;
1860 Z_OtherInformation **otherInfo;
1861 Z_OtherInformationUnit *oi;
1862 get_otherInfoAPDU(apdu, &otherInfo);
1863 oi = update_otherInformation(otherInfo, 1, NULL, 0, 0);
1866 ODR_MASK_SET(initRequest->options,
1867 Z_Options_negotiationModel);
1868 oi->which = Z_OtherInfo_externallyDefinedInfo;
1869 oi->information.externallyDefinedInfo =
1870 yaz_set_proposal_charneg(odr_encode(),
1871 (const char**)&m_proxy_negotiation_charset,
1872 m_proxy_negotiation_charset ? 1:0,
1873 (const char**)&m_proxy_negotiation_lang,
1874 m_proxy_negotiation_lang ? 1:0,
1878 else if (m_initRequest_options &&
1879 ODR_MASK_GET(m_initRequest_options,
1880 Z_Options_negotiationModel) &&
1881 m_charset_converter->get_target_query_charset())
1883 yaz_log(YLOG_LOG, "%sManaged charset negotiation: charset=%s",
1885 m_charset_converter->get_target_query_charset());
1886 Z_InitRequest *initRequest = apdu->u.initRequest;
1887 Z_CharSetandLanguageNegotiation *negotiation =
1888 yaz_get_charneg_record (initRequest->otherInfo);
1890 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1892 NMEM nmem = nmem_create();
1893 char **charsets = 0;
1894 int num_charsets = 0;
1898 yaz_get_proposal_charneg (nmem, negotiation,
1899 &charsets, &num_charsets,
1900 &langs, &num_langs, &selected);
1902 for (i = 0; i<num_charsets; i++)
1903 yaz_log(YLOG_LOG, "%scharset %s", m_session_str,
1905 for (i = 0; i<num_langs; i++)
1906 yaz_log(YLOG_LOG, "%slang %s", m_session_str,
1909 const char *t_charset =
1910 m_charset_converter->get_target_query_charset();
1911 // sweep through charsets and pick the first supported
1913 for (i = 0; i<num_charsets; i++)
1915 const char *c_charset = charsets[i];
1916 if (!odr_set_charset(odr_decode(), t_charset, c_charset))
1919 if (i != num_charsets)
1921 // got one .. set up ODR for reverse direction
1922 const char *c_charset = charsets[i];
1923 odr_set_charset(odr_encode(), c_charset, t_charset);
1924 m_charset_converter->set_client_query_charset(c_charset);
1925 m_charset_converter->set_client_charset_selected(selected);
1928 ODR_MASK_CLEAR(m_initRequest_options,
1929 Z_Options_negotiationModel);
1930 yaz_del_charneg_record(&initRequest->otherInfo);
1934 yaz_log(YLOG_WARN, "%sUnable to decode charset package",
1939 else if (apdu->which == Z_APDU_initResponse)
1941 Z_InitResponse *initResponse = apdu->u.initResponse;
1942 Z_OtherInformation **otherInfo;
1944 if (ODR_MASK_GET(initResponse->options, Z_Options_negotiationModel))
1950 get_otherInfoAPDU(apdu, &otherInfo);
1952 if (!otherInfo && !(*otherInfo))
1955 Z_CharSetandLanguageNegotiation *charneg =
1956 yaz_get_charneg_record(*otherInfo);
1961 yaz_get_response_charneg(m_referenceId_mem, charneg,
1962 &charset, &lang, &selected);
1964 yaz_log(YLOG_LOG, "%sAccepted charset - '%s' and lang - '%s'",
1965 m_session_str, (charset)?charset:"none", (lang)?lang:"none");
1967 if (m_initRequest_options &&
1968 ODR_MASK_GET(m_initRequest_options, Z_Options_negotiationModel))
1970 yaz_log(YLOG_LOG, "%sClient's negotiation record in use",
1973 else if (m_proxy_negotiation_charset || m_proxy_negotiation_lang)
1975 // negotiation-charset, negotiation-lang
1976 // elements of config file in use.
1978 yaz_log(YLOG_LOG, "%sProxy's negotiation record in use",
1981 // clear negotiation option.
1982 ODR_MASK_CLEAR(initResponse->options, Z_Options_negotiationModel);
1984 // Delete negotiation (charneg-3) entry.
1985 yaz_del_charneg_record(otherInfo);
1990 if (m_proxy_negotiation_charset || m_proxy_negotiation_lang)
1992 yaz_log(YLOG_LOG, "%sTarget did not honor negotiation",
1995 else if (m_charset_converter->get_client_query_charset())
1997 Z_OtherInformation **otherInfo;
1998 Z_OtherInformationUnit *oi;
1999 get_otherInfoAPDU(apdu, &otherInfo);
2000 oi = update_otherInformation(otherInfo, 1, NULL, 0, 0);
2003 ODR_MASK_SET(initResponse->options,
2004 Z_Options_negotiationModel);
2005 ODR_MASK_SET(m_initRequest_options,
2006 Z_Options_negotiationModel);
2008 oi->which = Z_OtherInfo_externallyDefinedInfo;
2009 oi->information.externallyDefinedInfo =
2010 yaz_set_response_charneg(
2012 m_charset_converter->get_client_query_charset(),
2014 m_charset_converter->get_client_charset_selected());
2021 Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
2023 const char *addinfo)
2025 Z_Records *rec = (Z_Records *)
2026 odr_malloc (odr, sizeof(*rec));
2028 odr_malloc (odr, sizeof(*err));
2029 Z_DiagRec *drec = (Z_DiagRec *)
2030 odr_malloc (odr, sizeof(*drec));
2031 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
2032 odr_malloc (odr, sizeof(*dr));
2034 rec->which = Z_Records_NSD;
2035 rec->u.nonSurrogateDiagnostic = dr;
2036 dr->diagnosticSetId =
2037 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
2038 dr->condition = err;
2039 dr->which = Z_DefaultDiagFormat_v2Addinfo;
2040 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
2044 Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu)
2046 if (apdu->which == Z_APDU_searchRequest &&
2047 apdu->u.searchRequest->query &&
2048 apdu->u.searchRequest->query->which == Z_Query_type_104 &&
2049 apdu->u.searchRequest->query->u.type_104->which == Z_External_CQL)
2051 Z_RPNQuery *rpnquery = 0;
2052 Z_SearchRequest *sr = apdu->u.searchRequest;
2055 yaz_log(YLOG_LOG, "%sCQL: %s", m_session_str,
2056 sr->query->u.type_104->u.cql);
2058 int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
2059 &rpnquery, odr_encode(),
2062 yaz_log(YLOG_LOG, "%sNo CQL to RPN table", m_session_str);
2065 yaz_log(YLOG_LOG, "%sCQL Conversion error %d", m_session_str, r);
2066 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
2068 new_apdu->u.searchResponse->referenceId = sr->referenceId;
2069 new_apdu->u.searchResponse->records =
2070 create_nonSurrogateDiagnostics(odr_encode(),
2071 yaz_diag_srw_to_bib1(r),
2073 *new_apdu->u.searchResponse->searchStatus = 0;
2075 send_to_client(new_apdu);
2081 sr->query->which = Z_Query_type_1;
2082 sr->query->u.type_1 = rpnquery;
2089 Z_APDU *Yaz_Proxy::handle_target_charset_conversion(Z_APDU *apdu)
2091 if (apdu->which == Z_APDU_searchRequest &&
2092 apdu->u.searchRequest->query)
2094 if (apdu->u.searchRequest->query->which == Z_Query_type_1
2095 || apdu->u.searchRequest->query->which == Z_Query_type_101)
2098 m_charset_converter->set_client_query_charset("UTF-8");
2099 Z_RPNQuery *rpnquery = apdu->u.searchRequest->query->u.type_1;
2100 m_charset_converter->convert_type_1(rpnquery, odr_encode());
2107 Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
2109 if (apdu->which == Z_APDU_searchRequest)
2111 Z_SearchRequest *sr = apdu->u.searchRequest;
2115 Yaz_ProxyConfig *cfg = check_reconfigure();
2117 err = cfg->check_query(odr_encode(), m_default_target,
2118 sr->query, &addinfo);
2121 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
2123 new_apdu->u.searchResponse->referenceId = sr->referenceId;
2124 new_apdu->u.searchResponse->records =
2125 create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
2126 *new_apdu->u.searchResponse->searchStatus = 0;
2128 send_to_client(new_apdu);
2136 int Yaz_Proxy::handle_authentication(Z_APDU *apdu)
2138 if (apdu->which != Z_APDU_initRequest)
2139 return 1; // pass if no init request
2140 Z_InitRequest *req = apdu->u.initRequest;
2142 Yaz_ProxyConfig *cfg = check_reconfigure();
2144 return 1; // pass if no config
2147 if (req->idAuthentication == 0)
2149 ret = cfg->client_authentication(m_default_target, 0, 0, 0,
2152 else if (req->idAuthentication->which == Z_IdAuthentication_idPass)
2154 ret = cfg->client_authentication(
2156 req->idAuthentication->u.idPass->userId,
2157 req->idAuthentication->u.idPass->groupId,
2158 req->idAuthentication->u.idPass->password,
2161 else if (req->idAuthentication->which == Z_IdAuthentication_open)
2163 char user[64], pass[64];
2166 sscanf(req->idAuthentication->u.open, "%63[^/]/%63s", user, pass);
2167 ret = cfg->client_authentication(m_default_target, user, 0, pass,
2171 ret = cfg->client_authentication(m_default_target, 0, 0, 0,
2174 cfg->target_authentication(m_default_target, odr_encode(), req);
2179 Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
2181 m_marcxml_mode = none;
2182 if (apdu->which == Z_APDU_searchRequest)
2184 Z_SearchRequest *sr = apdu->u.searchRequest;
2187 Yaz_ProxyConfig *cfg = check_reconfigure();
2189 Z_RecordComposition rc_temp, *rc = 0;
2190 if (sr->smallSetElementSetNames)
2192 rc_temp.which = Z_RecordComp_simple;
2193 rc_temp.u.simple = sr->smallSetElementSetNames;
2197 if (sr->preferredRecordSyntax)
2200 ent = oid_getentbyoid(sr->preferredRecordSyntax);
2201 m_frontend_type = ent->value;
2204 m_frontend_type = VAL_NONE;
2206 char *stylesheet_name = 0;
2208 err = cfg->check_syntax(odr_encode(),
2210 sr->preferredRecordSyntax, rc,
2211 &addinfo, &stylesheet_name, &m_schema,
2212 &m_backend_type, &m_backend_charset,
2213 &m_usemarcon_ini_stage1,
2214 &m_usemarcon_ini_stage2);
2215 if (stylesheet_name)
2217 m_parent->low_socket_close();
2220 if (m_stylesheet_xsp)
2221 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
2222 m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
2225 m_stylesheet_offset = 0;
2226 xfree(stylesheet_name);
2228 m_parent->low_socket_open();
2232 sr->smallSetElementSetNames = 0;
2233 sr->mediumSetElementSetNames = 0;
2234 m_marcxml_mode = marcxml;
2238 sr->preferredRecordSyntax =
2239 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN,
2243 sr->preferredRecordSyntax =
2244 yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
2249 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
2251 new_apdu->u.searchResponse->referenceId = sr->referenceId;
2252 new_apdu->u.searchResponse->records =
2253 create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
2254 *new_apdu->u.searchResponse->searchStatus = 0;
2256 send_to_client(new_apdu);
2260 else if (m_backend_type)
2262 sr->preferredRecordSyntax =
2263 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN, m_backend_type);
2266 else if (apdu->which == Z_APDU_presentRequest)
2268 Z_PresentRequest *pr = apdu->u.presentRequest;
2271 Yaz_ProxyConfig *cfg = check_reconfigure();
2273 if (pr->preferredRecordSyntax)
2276 ent = oid_getentbyoid(pr->preferredRecordSyntax);
2277 m_frontend_type = ent->value;
2280 m_frontend_type = VAL_NONE;
2282 char *stylesheet_name = 0;
2284 err = cfg->check_syntax(odr_encode(), m_default_target,
2285 pr->preferredRecordSyntax,
2286 pr->recordComposition,
2287 &addinfo, &stylesheet_name, &m_schema,
2288 &m_backend_type, &m_backend_charset,
2289 &m_usemarcon_ini_stage1,
2290 &m_usemarcon_ini_stage2
2292 if (stylesheet_name)
2294 m_parent->low_socket_close();
2297 if (m_stylesheet_xsp)
2298 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
2299 m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
2302 m_stylesheet_offset = 0;
2303 xfree(stylesheet_name);
2305 m_parent->low_socket_open();
2309 pr->recordComposition = 0;
2310 m_marcxml_mode = marcxml;
2314 pr->preferredRecordSyntax =
2315 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN,
2319 pr->preferredRecordSyntax =
2320 yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
2325 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
2327 new_apdu->u.presentResponse->referenceId = pr->referenceId;
2328 new_apdu->u.presentResponse->records =
2329 create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
2330 *new_apdu->u.presentResponse->presentStatus =
2331 Z_PresentStatus_failure;
2333 send_to_client(new_apdu);
2337 else if (m_backend_type)
2339 pr->preferredRecordSyntax =
2340 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN, m_backend_type);
2346 Z_ElementSetNames *Yaz_Proxy::mk_esn_from_schema(ODR o, const char *schema)
2350 Z_ElementSetNames *esn = (Z_ElementSetNames *)
2351 odr_malloc(o, sizeof(Z_ElementSetNames));
2352 esn->which = Z_ElementSetNames_generic;
2353 esn->u.generic = odr_strdup(o, schema);
2357 void Yaz_Proxy::srw_get_client(const char *db, const char **backend_db)
2360 Yaz_ProxyConfig *cfg = check_reconfigure();
2362 t = cfg->get_explain_name(db, backend_db);
2364 if (m_client && m_default_target && t && strcmp(m_default_target, t))
2371 xfree(m_default_target);
2372 m_default_target = xstrdup(t);
2376 int Yaz_Proxy::file_access(Z_HTTP_Request *hreq)
2379 if (strcmp(hreq->method, "GET"))
2381 if (hreq->path[0] != '/')
2383 yaz_log(YLOG_WARN, "Bad path: %s", hreq->path);
2386 const char *cp = hreq->path;
2389 if (*cp == '/' && strchr("/.", cp[1]))
2391 yaz_log(YLOG_WARN, "Bad path: %s", hreq->path);
2396 const char *fname = hreq->path+1;
2397 if (stat(fname, &sbuf))
2399 yaz_log(YLOG_WARN|YLOG_ERRNO, "%s: stat failed", fname);
2402 if ((sbuf.st_mode & S_IFMT) != S_IFREG)
2404 yaz_log(YLOG_WARN, "%s: not a regular file", fname);
2407 if (sbuf.st_size > (off_t) 1000000)
2409 yaz_log(YLOG_WARN, "%s: too large for transfer", fname);
2413 ODR o = odr_encode();
2414 Yaz_ProxyConfig *cfg = check_reconfigure();
2415 const char *ctype = cfg->check_mime_type(fname);
2416 Z_GDU *gdu = z_get_HTTP_Response(o, 200);
2417 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
2419 hres->version = odr_strdup(o, m_http_version);
2420 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
2421 if (m_http_keepalive)
2422 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
2426 hres->content_len = sbuf.st_size;
2427 hres->content_buf = (char*) odr_malloc(o, hres->content_len);
2428 FILE *f = fopen(fname, "rb");
2431 fread(hres->content_buf, 1, hres->content_len, f);
2438 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
2440 yaz_log (YLOG_LOG, "%sSending file %s to client", m_session_str,
2444 send_GDU(gdu, &len);
2448 void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
2452 odr_destroy(m_s2z_odr_init);
2455 if (m_s2z_odr_search)
2457 odr_destroy(m_s2z_odr_search);
2458 m_s2z_odr_search = 0;
2461 m_http_keepalive = 0;
2463 if (!strcmp(hreq->version, "1.0"))
2465 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
2466 if (v && !strcmp(v, "Keep-Alive"))
2467 m_http_keepalive = 1;
2469 m_http_keepalive = 0;
2470 m_http_version = "1.0";
2474 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
2475 if (v && !strcmp(v, "close"))
2476 m_http_keepalive = 0;
2478 m_http_keepalive = 1;
2479 m_http_version = "1.1";
2482 Z_SRW_PDU *srw_pdu = 0;
2483 Z_SOAP *soap_package = 0;
2485 Z_SRW_diagnostic *diagnostic = 0;
2486 int num_diagnostic = 0;
2488 if (file_access(hreq))
2492 else if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
2494 || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
2495 &charset, &diagnostic, &num_diagnostic) == 0)
2497 m_s2z_odr_init = odr_createmem(ODR_ENCODE);
2498 m_s2z_odr_search = odr_createmem(ODR_ENCODE);
2499 m_soap_ns = odr_strdup(m_s2z_odr_search, soap_package->ns);
2500 m_s2z_init_apdu = 0;
2501 m_s2z_search_apdu = 0;
2502 m_s2z_present_apdu = 0;
2504 m_s2z_stylesheet = 0;
2506 if (srw_pdu->which == Z_SRW_searchRetrieve_request)
2508 Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request;
2510 const char *backend_db = srw_req->database;
2511 srw_get_client(srw_req->database, &backend_db);
2513 m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
2514 // recordXPath unsupported.
2515 if (srw_req->recordXPath)
2517 yaz_add_srw_diagnostic(odr_decode(),
2518 &diagnostic, &num_diagnostic,
2522 if (srw_req->sort_type != Z_SRW_sort_type_none)
2524 yaz_add_srw_diagnostic(odr_decode(),
2525 &diagnostic, &num_diagnostic,
2529 if (srw_req->stylesheet)
2531 odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
2533 // set packing for response records ..
2534 if (srw_req->recordPacking &&
2535 !strcmp(srw_req->recordPacking, "xml"))
2536 m_s2z_packing = Z_SRW_recordPacking_XML;
2538 m_s2z_packing = Z_SRW_recordPacking_string;
2542 Z_SRW_PDU *srw_pdu =
2543 yaz_srw_get(odr_encode(),
2544 Z_SRW_searchRetrieve_response);
2545 Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
2547 srw_res->diagnostics = diagnostic;
2548 srw_res->num_diagnostics = num_diagnostic;
2549 send_srw_response(srw_pdu);
2553 // prepare search PDU
2554 m_s2z_search_apdu = zget_APDU(m_s2z_odr_search,
2555 Z_APDU_searchRequest);
2556 Z_SearchRequest *z_searchRequest =
2557 m_s2z_search_apdu->u.searchRequest;
2559 z_searchRequest->num_databaseNames = 1;
2560 z_searchRequest->databaseNames = (char**)
2561 odr_malloc(m_s2z_odr_search, sizeof(char *));
2562 z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr_search,
2565 // query transformation
2566 Z_Query *query = (Z_Query *)
2567 odr_malloc(m_s2z_odr_search, sizeof(Z_Query));
2568 z_searchRequest->query = query;
2570 if (srw_req->query_type == Z_SRW_query_type_cql)
2572 Z_External *ext = (Z_External *)
2573 odr_malloc(m_s2z_odr_search, sizeof(*ext));
2574 ext->direct_reference =
2575 odr_getoidbystr(m_s2z_odr_search, "1.2.840.10003.16.2");
2576 ext->indirect_reference = 0;
2577 ext->descriptor = 0;
2578 ext->which = Z_External_CQL;
2579 ext->u.cql = srw_req->query.cql;
2581 query->which = Z_Query_type_104;
2582 query->u.type_104 = ext;
2584 else if (srw_req->query_type == Z_SRW_query_type_pqf)
2586 Z_RPNQuery *RPNquery;
2587 YAZ_PQF_Parser pqf_parser;
2589 pqf_parser = yaz_pqf_create ();
2591 RPNquery = yaz_pqf_parse (pqf_parser, m_s2z_odr_search,
2592 srw_req->query.pqf);
2595 const char *pqf_msg;
2597 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
2598 yaz_log(YLOG_LOG, "%*s^\n", off+4, "");
2599 yaz_log(YLOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
2601 send_to_srw_client_error(10, 0);
2604 query->which = Z_Query_type_1;
2605 query->u.type_1 = RPNquery;
2607 yaz_pqf_destroy (pqf_parser);
2611 send_to_srw_client_error(7, "query");
2616 m_s2z_present_apdu = 0;
2618 if (srw_req->maximumRecords)
2619 max = *srw_req->maximumRecords;
2621 if (srw_req->startRecord)
2622 start = *srw_req->startRecord;
2625 // Some backend, such as Voyager doesn't honor piggyback
2626 // So we use present always (0 &&).
2627 if (0 && start <= 1) // Z39.50 piggyback
2629 *z_searchRequest->smallSetUpperBound = max;
2630 *z_searchRequest->mediumSetPresentNumber = max;
2631 *z_searchRequest->largeSetLowerBound = 2000000000; // 2e9
2633 z_searchRequest->preferredRecordSyntax =
2634 yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
2636 if (srw_req->recordSchema)
2638 z_searchRequest->smallSetElementSetNames =
2639 z_searchRequest->mediumSetElementSetNames =
2640 mk_esn_from_schema(m_s2z_odr_search,
2641 srw_req->recordSchema);
2644 else // Z39.50 present
2646 m_s2z_present_apdu = zget_APDU(m_s2z_odr_search,
2647 Z_APDU_presentRequest);
2648 Z_PresentRequest *z_presentRequest =
2649 m_s2z_present_apdu->u.presentRequest;
2650 *z_presentRequest->resultSetStartPoint = start;
2651 *z_presentRequest->numberOfRecordsRequested = max;
2652 z_presentRequest->preferredRecordSyntax =
2653 yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
2655 if (srw_req->recordSchema)
2657 z_presentRequest->recordComposition =
2658 (Z_RecordComposition *)
2659 odr_malloc(m_s2z_odr_search,
2660 sizeof(Z_RecordComposition));
2661 z_presentRequest->recordComposition->which =
2662 Z_RecordComp_simple;
2663 z_presentRequest->recordComposition->u.simple =
2664 mk_esn_from_schema(m_s2z_odr_search,
2665 srw_req->recordSchema);
2671 m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
2672 Z_APDU_initRequest);
2674 // prevent m_initRequest_apdu memory from being grabbed
2675 // in Yaz_Proxy::handle_incoming_Z_PDU
2676 m_initRequest_apdu = m_s2z_init_apdu;
2677 handle_incoming_Z_PDU(m_s2z_init_apdu);
2682 handle_incoming_Z_PDU(m_s2z_search_apdu);
2686 else if (srw_pdu->which == Z_SRW_explain_request)
2688 Z_SRW_explainRequest *srw_req = srw_pdu->u.explain_request;
2690 const char *backend_db = srw_req->database;
2691 srw_get_client(srw_req->database, &backend_db);
2693 m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
2696 if (srw_req->stylesheet)
2698 odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
2700 if (srw_req->recordPacking &&
2701 !strcmp(srw_req->recordPacking, "xml"))
2702 m_s2z_packing = Z_SRW_recordPacking_XML;
2704 m_s2z_packing = Z_SRW_recordPacking_string;
2708 send_srw_explain_response(diagnostic, num_diagnostic);
2714 m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
2715 Z_APDU_initRequest);
2717 // prevent m_initRequest_apdu memory from being grabbed
2718 // in Yaz_Proxy::handle_incoming_Z_PDU
2719 m_initRequest_apdu = m_s2z_init_apdu;
2720 handle_incoming_Z_PDU(m_s2z_init_apdu);
2723 send_srw_explain_response(0, 0);
2726 else if (srw_pdu->which == Z_SRW_scan_request)
2728 m_s2z_database = odr_strdup(m_s2z_odr_init,
2729 srw_pdu->u.scan_request->database);
2731 yaz_add_srw_diagnostic(odr_decode(),
2732 &diagnostic, &num_diagnostic,
2734 Z_SRW_PDU *srw_pdu =
2735 yaz_srw_get(odr_encode(),
2736 Z_SRW_scan_response);
2737 Z_SRW_scanResponse *srw_res = srw_pdu->u.scan_response;
2739 srw_res->diagnostics = diagnostic;
2740 srw_res->num_diagnostics = num_diagnostic;
2741 send_srw_response(srw_pdu);
2748 send_to_srw_client_error(4, 0);
2751 send_http_response(400);
2754 void Yaz_Proxy::handle_init(Z_APDU *apdu)
2756 Z_OtherInformation **oi;
2757 get_otherInfoAPDU(apdu, &oi);
2759 if (apdu->u.initRequest->implementationId)
2760 yaz_log(YLOG_LOG, "%simplementationId: %s",
2761 m_session_str, apdu->u.initRequest->implementationId);
2762 if (apdu->u.initRequest->implementationName)
2763 yaz_log(YLOG_LOG, "%simplementationName: %s",
2764 m_session_str, apdu->u.initRequest->implementationName);
2765 if (apdu->u.initRequest->implementationVersion)
2766 yaz_log(YLOG_LOG, "%simplementationVersion: %s",
2767 m_session_str, apdu->u.initRequest->implementationVersion);
2768 if (m_initRequest_apdu == 0)
2770 if (m_initRequest_mem)
2771 nmem_destroy(m_initRequest_mem);
2773 m_initRequest_apdu = apdu;
2774 m_initRequest_mem = odr_extract_mem(odr_decode());
2776 m_initRequest_preferredMessageSize = *apdu->u.initRequest->
2777 preferredMessageSize;
2778 *apdu->u.initRequest->preferredMessageSize = 1024*1024;
2779 m_initRequest_maximumRecordSize = *apdu->u.initRequest->
2781 *apdu->u.initRequest->maximumRecordSize = 1024*1024;
2783 Z_CharSetandLanguageNegotiation *charSetandLangRecord =
2784 yaz_get_charneg_record(*oi);
2786 // Save proposal charsets and langs.
2787 if (ODR_MASK_GET(apdu->u.initRequest->options,
2788 Z_Options_negotiationModel)
2789 && charSetandLangRecord)
2792 yaz_get_proposal_charneg(m_referenceId_mem,
2793 charSetandLangRecord,
2794 &m_initRequest_oi_negotiation_charsets,
2795 &m_initRequest_oi_negotiation_num_charsets,
2796 &m_initRequest_oi_negotiation_langs,
2797 &m_initRequest_oi_negotiation_num_langs,
2798 &m_initRequest_oi_negotiation_selected);
2800 for (int i = 0; i<m_initRequest_oi_negotiation_num_charsets; i++)
2802 yaz_log(YLOG_LOG, "%scharacters set proposal: %s",
2803 m_session_str,(m_initRequest_oi_negotiation_charsets[i])?
2804 m_initRequest_oi_negotiation_charsets[i]:"none");
2806 for (int i=0; i<m_initRequest_oi_negotiation_num_langs; i++)
2808 yaz_log(YLOG_LOG, "%slanguages proposal: %s",
2809 m_session_str, (m_initRequest_oi_negotiation_langs[i])?
2810 m_initRequest_oi_negotiation_langs[i]:"none");
2812 yaz_log(YLOG_LOG, "%sselected proposal: %d (boolean)",
2813 m_session_str, m_initRequest_oi_negotiation_selected);
2815 // save init options for the response..
2816 m_initRequest_options = apdu->u.initRequest->options;
2818 apdu->u.initRequest->options =
2819 (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
2820 sizeof(Odr_bitmask));
2821 ODR_MASK_ZERO(apdu->u.initRequest->options);
2823 for (i = 0; i<= 24; i++)
2824 ODR_MASK_SET(apdu->u.initRequest->options, i);
2825 // check negotiation option
2826 if (!ODR_MASK_GET(m_initRequest_options,
2827 Z_Options_negotiationModel))
2829 ODR_MASK_CLEAR(apdu->u.initRequest->options,
2830 Z_Options_negotiationModel);
2832 ODR_MASK_CLEAR(apdu->u.initRequest->options,
2833 Z_Options_concurrentOperations);
2835 m_initRequest_version = apdu->u.initRequest->protocolVersion;
2836 apdu->u.initRequest->protocolVersion =
2837 (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
2838 sizeof(Odr_bitmask));
2839 ODR_MASK_ZERO(apdu->u.initRequest->protocolVersion);
2841 for (i = 0; i<= 8; i++)
2842 ODR_MASK_SET(apdu->u.initRequest->protocolVersion, i);
2844 if (m_client->m_init_flag)
2846 if (handle_init_response_for_invalid_session(apdu))
2848 if (m_client->m_initResponse)
2850 Z_APDU *apdu2 = m_client->m_initResponse;
2851 apdu2->u.initResponse->otherInfo = 0;
2852 if (m_client->m_cookie && *m_client->m_cookie)
2853 set_otherInformationString(apdu2, VAL_COOKIE, 1,
2854 m_client->m_cookie);
2855 apdu2->u.initResponse->referenceId =
2856 apdu->u.initRequest->referenceId;
2857 apdu2->u.initResponse->options = m_client->m_initResponse_options;
2858 apdu2->u.initResponse->protocolVersion =
2859 m_client->m_initResponse_version;
2861 send_to_client(apdu2);
2865 m_client->m_init_flag = 1;
2868 Auth_Msg *m = new Auth_Msg;
2870 z_APDU(odr_encode(), &apdu, 0, "encode");
2871 char *apdu_buf = odr_getbuf(odr_encode(), &m->m_apdu_len, 0);
2872 m->m_apdu_buf = (char*) nmem_malloc(m->m_nmem, m->m_apdu_len);
2873 memcpy(m->m_apdu_buf, apdu_buf, m->m_apdu_len);
2874 odr_reset(odr_encode());
2877 m_my_thread->put(m);
2879 int ret = handle_authentication(apdu);
2880 result_authentication(apdu, ret);
2884 void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
2886 Z_ReferenceId **refid = get_referenceIdP(apdu);
2887 nmem_reset(m_referenceId_mem);
2888 if (refid && *refid)
2890 m_referenceId = (Z_ReferenceId *)
2891 nmem_malloc(m_referenceId_mem, sizeof(*m_referenceId));
2892 m_referenceId->len = m_referenceId->size = (*refid)->len;
2893 m_referenceId->buf = (unsigned char *)
2894 nmem_malloc(m_referenceId_mem, (*refid)->len);
2895 memcpy(m_referenceId->buf, (*refid)->buf, (*refid)->len);
2900 if (!m_client && m_flag_invalid_session)
2902 // Got request for a session that is invalid..
2903 m_apdu_invalid_session = apdu; // save package
2904 m_mem_invalid_session = odr_extract_mem(odr_decode());
2905 apdu = m_initRequest_apdu; // but throw an init to the target
2908 // Determine our client.
2909 Z_OtherInformation **oi;
2910 get_otherInfoAPDU(apdu, &oi);
2911 m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
2916 send_http_response(404);
2926 m_client->m_server = this;
2928 if (apdu->which == Z_APDU_initRequest)
2931 handle_incoming_Z_PDU_2(apdu);
2934 void Yaz_Proxy::handle_incoming_Z_PDU_2(Z_APDU *apdu)
2936 handle_max_record_retrieve(apdu);
2939 apdu = handle_syntax_validation(apdu);
2942 apdu = handle_query_transformation(apdu);
2945 apdu = handle_target_charset_conversion(apdu);
2948 apdu = handle_query_validation(apdu);
2951 apdu = result_set_optimize(apdu);
2955 m_client->timeout(m_target_idletime); // mark it active even
2956 // though we didn't use it
2959 // Add otherInformation entry in APDU if
2960 // negotiation is in use.
2962 handle_charset_lang_negotiation(apdu);
2964 // delete other info construct completely if 0 elements
2965 Z_OtherInformation **oi;
2966 get_otherInfoAPDU(apdu, &oi);
2967 if (oi && *oi && (*oi)->num_elements == 0)
2970 if (apdu->which == Z_APDU_presentRequest &&
2971 m_client->m_resultSetStartPoint == 0)
2973 Z_PresentRequest *pr = apdu->u.presentRequest;
2974 m_client->m_resultSetStartPoint = *pr->resultSetStartPoint;
2975 m_client->m_cache.copy_presentRequest(apdu->u.presentRequest);
2977 m_client->m_resultSetStartPoint = 0;
2979 if (m_client->send_to_target(apdu) < 0)
2986 m_client->m_waiting = 1;
2989 void Yaz_Proxy::connectNotify()
2993 void Yaz_Proxy::releaseClient()
2995 xfree(m_proxyTarget);
2997 m_flag_invalid_session = 0;
2998 // only keep if keep_alive flag is set...
3000 m_client->m_pdu_recv < m_keepalive_limit_pdu &&
3001 m_client->m_bytes_recv+m_client->m_bytes_sent < m_keepalive_limit_bw &&
3002 m_client->m_waiting == 0)
3004 yaz_log(YLOG_LOG, "%sShutdown (client to proxy) keepalive %s",
3006 m_client->get_hostname());
3007 yaz_log(YLOG_LOG, "%sbw=%d pdu=%d limit-bw=%d limit-pdu=%d",
3008 m_session_str, m_client->m_pdu_recv,
3009 m_client->m_bytes_sent + m_client->m_bytes_recv,
3010 m_keepalive_limit_bw, m_keepalive_limit_pdu);
3011 assert (m_client->m_waiting != 2);
3012 // Tell client (if any) that no server connection is there..
3013 m_client->m_server = 0;
3018 yaz_log (YLOG_LOG, "%sShutdown (client to proxy) close %s",
3020 m_client->get_hostname());
3021 assert (m_client->m_waiting != 2);
3027 yaz_log (YLOG_LOG, "%sshutdown (client to proxy) bad state",
3033 yaz_log (YLOG_LOG, "%sShutdown (client to proxy)",
3037 m_parent->pre_init();
3040 bool Yaz_Proxy::dec_ref()
3043 assert(m_ref_count >= 0);
3044 bool last = (m_ref_count == 0);
3045 if (m_ref_count == 0)
3053 const char *Yaz_ProxyClient::get_session_str()
3057 return m_server->get_session_str();
3060 void Yaz_ProxyClient::shutdown()
3062 yaz_log (YLOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(),
3068 void Yaz_Proxy::failNotify()
3071 yaz_log (YLOG_LOG, "%sConnection closed by client",
3076 void Yaz_ProxyClient::failNotify()
3079 m_server->inc_request_no();
3080 yaz_log (YLOG_LOG, "%sConnection closed by target %s",
3081 get_session_str(), get_hostname());
3085 void Yaz_ProxyClient::connectNotify()
3087 const char *s = get_session_str();
3088 const char *h = get_hostname();
3089 yaz_log (YLOG_LOG, "%sConnection accepted by %s timeout=%d", s, h,
3091 timeout(m_target_idletime);
3096 IPDU_Observer *Yaz_ProxyClient::sessionNotify(IPDU_Observable
3097 *the_PDU_Observable, int fd)
3099 return new Yaz_ProxyClient(the_PDU_Observable, 0);
3102 Yaz_ProxyClient::~Yaz_ProxyClient()
3107 m_next->m_prev = m_prev;
3108 m_waiting = 2; // for debugging purposes only.
3109 odr_destroy(m_init_odr);
3110 delete m_last_query;
3111 xfree (m_last_resultSetId);
3115 void Yaz_ProxyClient::pre_init_client()
3117 Z_APDU *apdu = create_Z_PDU(Z_APDU_initRequest);
3118 Z_InitRequest *req = apdu->u.initRequest;
3121 for (i = 0; i<= 24; i++)
3122 ODR_MASK_SET(req->options, i);
3123 ODR_MASK_CLEAR(apdu->u.initRequest->options,
3124 Z_Options_negotiationModel);
3125 ODR_MASK_CLEAR(apdu->u.initRequest->options,
3126 Z_Options_concurrentOperations);
3127 for (i = 0; i<= 10; i++)
3128 ODR_MASK_SET(req->protocolVersion, i);
3130 if (send_to_target(apdu) < 0)
3141 void Yaz_Proxy::pre_init()
3144 const char *name = 0;
3145 const char *zurl_in_use[MAX_ZURL_PLEX];
3146 int limit_bw, limit_pdu, limit_req;
3147 int target_idletime, client_idletime;
3149 int keepalive_limit_bw, keepalive_limit_pdu;
3151 const char *cql2rpn = 0;
3152 const char *authentication = 0;
3153 const char *negotiation_charset = 0;
3154 const char *negotiation_lang = 0;
3156 Yaz_ProxyConfig *cfg = check_reconfigure();
3160 if (m_log_mask & PROXY_LOG_APDU_CLIENT)
3165 for (i = 0; cfg && cfg->get_target_no(i, &name, zurl_in_use,
3166 &limit_bw, &limit_pdu, &limit_req,
3167 &target_idletime, &client_idletime,
3169 &keepalive_limit_bw,
3170 &keepalive_limit_pdu,
3174 &negotiation_charset,
3181 for (j = 0; zurl_in_use[j]; j++)
3185 int spare_waiting = 0;
3188 for (c = m_clientPool; c; c = c->m_next)
3190 if (!strcmp(zurl_in_use[j], c->get_hostname()))
3192 if (c->m_cookie == 0)
3194 if (c->m_server == 0)
3206 yaz_log(YLOG_LOG, "%spre-init %s %s use=%d other=%d spare=%d "
3207 "sparew=%d preinit=%d",m_session_str,
3208 name, zurl_in_use[j], in_use, other,
3209 spare, spare_waiting, pre_init);
3210 if (spare + spare_waiting < pre_init)
3212 c = new Yaz_ProxyClient(m_PDU_Observable->clone(), this);
3213 c->m_next = m_clientPool;
3215 c->m_next->m_prev = &c->m_next;
3217 c->m_prev = &m_clientPool;
3219 if (m_log_mask & PROXY_LOG_APDU_SERVER)
3220 c->set_APDU_yazlog(1);
3222 c->set_APDU_yazlog(0);
3224 if (c->client(zurl_in_use[j]))
3232 c->m_target_idletime = target_idletime;
3233 c->m_seqno = m_seqno++;
3240 void Yaz_Proxy::timeoutNotify()
3245 switch(m_timeout_mode)
3247 case timeout_normal:
3250 yaz_log (YLOG_LOG, "%sTimeout (client to proxy)", m_session_str);
3253 case timeout_reduce:
3254 timeout(m_client_idletime);
3255 m_timeout_mode = timeout_normal;
3256 gdu = m_timeout_gdu;
3258 recv_GDU_normal(gdu);
3261 assert(m_stylesheet_nprl);
3262 convert_xsl_delay();
3273 void Yaz_Proxy::markInvalid()
3276 m_flag_invalid_session = 1;
3279 void Yaz_ProxyClient::timeoutNotify()
3282 m_server->inc_request_no();
3284 yaz_log (YLOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(),
3288 if (m_server && m_init_flag)
3290 // target timed out in a session that was properly initialized
3291 // server object stay alive but we mark it as invalid so it
3292 // gets initialized again
3293 m_server->markInvalid();
3299 Yaz_ProxyClient::Yaz_ProxyClient(IPDU_Observable *the_PDU_Observable,
3300 Yaz_Proxy *parent) :
3301 Z_Assoc (the_PDU_Observable)
3308 m_last_resultSetId = 0;
3309 m_last_resultCount = 0;
3313 m_init_odr = odr_createmem (ODR_DECODE);
3315 m_initResponse_options = 0;
3316 m_initResponse_version = 0;
3317 m_initResponse_preferredMessageSize = 0;
3318 m_initResponse_maximumRecordSize = 0;
3319 m_resultSetStartPoint = 0;
3320 m_bytes_sent = m_bytes_recv = 0;
3324 m_target_idletime = 600;
3328 const char *Yaz_Proxy::option(const char *name, const char *value)
3330 if (!strcmp (name, "optimize")) {
3333 m_optimize = xstrdup (value);
3340 void Yaz_ProxyClient::recv_HTTP_response(Z_HTTP_Response *apdu, int len)
3345 void Yaz_ProxyClient::recv_GDU(Z_GDU *apdu, int len)
3347 if (apdu->which == Z_GDU_Z3950)
3348 recv_Z_PDU(apdu->u.z3950, len);
3349 else if (apdu->which == Z_GDU_HTTP_Response)
3350 recv_HTTP_response(apdu->u.HTTP_Response, len);
3355 int Yaz_Proxy::handle_init_response_for_invalid_session(Z_APDU *apdu)
3357 if (!m_flag_invalid_session)
3359 m_flag_invalid_session = 0;
3360 handle_incoming_Z_PDU(m_apdu_invalid_session);
3361 assert (m_mem_invalid_session);
3362 nmem_destroy(m_mem_invalid_session);
3363 m_mem_invalid_session = 0;
3367 void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
3369 m_bytes_recv += len;
3373 if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
3374 yaz_log (YLOG_LOG, "%sReceiving %s from %s %d bytes", get_session_str(),
3375 apdu_name(apdu), get_hostname(), len);
3376 if (apdu->which == Z_APDU_initResponse)
3378 if (!m_server) // if this is a pre init session , check for more
3380 NMEM nmem = odr_extract_mem (odr_decode());
3381 odr_reset (m_init_odr);
3382 nmem_transfer (m_init_odr->mem, nmem);
3383 m_initResponse = apdu;
3384 m_initResponse_options = apdu->u.initResponse->options;
3385 m_initResponse_version = apdu->u.initResponse->protocolVersion;
3386 m_initResponse_preferredMessageSize =
3387 *apdu->u.initResponse->preferredMessageSize;
3388 m_initResponse_maximumRecordSize =
3389 *apdu->u.initResponse->maximumRecordSize;
3391 Z_InitResponse *ir = apdu->u.initResponse;
3392 char *im0 = ir->implementationName;
3395 odr_malloc(m_init_odr, 20 + (im0 ? strlen(im0) : 0));
3402 strcat(im1, "(YAZ Proxy)");
3403 ir->implementationName = im1;
3405 nmem_destroy (nmem);
3407 if (m_server && m_server->handle_init_response_for_invalid_session(apdu))
3410 if (apdu->which == Z_APDU_searchResponse)
3412 Z_SearchResponse *sr = apdu->u.searchResponse;
3413 m_last_resultCount = *sr->resultCount;
3414 int status = *sr->searchStatus;
3415 if (status && (!sr->records || sr->records->which == Z_Records_DBOSD))
3419 if (sr->records && sr->records->which == Z_Records_DBOSD)
3421 m_cache.add(odr_decode(),
3422 sr->records->u.databaseOrSurDiagnostics, 1,
3427 if (apdu->which == Z_APDU_presentResponse)
3429 Z_PresentResponse *pr = apdu->u.presentResponse;
3433 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
3434 Z_SearchResponse *sr = new_apdu->u.searchResponse;
3435 sr->referenceId = pr->referenceId;
3436 *sr->resultCount = m_last_resultCount;
3437 sr->records = pr->records;
3438 sr->nextResultSetPosition = pr->nextResultSetPosition;
3439 sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
3443 pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
3445 m_cache.add(odr_decode(),
3446 pr->records->u.databaseOrSurDiagnostics,
3447 m_resultSetStartPoint, -1);
3448 m_resultSetStartPoint = 0;
3452 set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
3454 Yaz_Proxy *server = m_server; // save it. send_to_client may destroy us
3457 server->send_to_client(apdu);
3458 if (apdu->which == Z_APDU_close)
3461 server->recv_GDU_more();
3465 void Yaz_Proxy::low_socket_close()
3470 for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
3471 if (m_lo_fd[i] >= 0)
3472 ::close(m_lo_fd[i]);
3476 void Yaz_Proxy::low_socket_open()
3481 for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
3482 m_lo_fd[i] = open("/dev/null", O_RDONLY);
3486 int Yaz_Proxy::server(const char *addr)
3488 int r = Z_Assoc::server(addr);
3491 yaz_log(YLOG_LOG, "%sStarted proxy "
3495 " on %s", m_session_str, addr);