1 /* $Id: yaz-proxy.cpp,v 1.26 2005-05-18 20:15:23 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>
56 static const char *apdu_name(Z_APDU *apdu)
60 case Z_APDU_initRequest:
62 case Z_APDU_initResponse:
63 return "initResponse";
64 case Z_APDU_searchRequest:
65 return "searchRequest";
66 case Z_APDU_searchResponse:
67 return "searchResponse";
68 case Z_APDU_presentRequest:
69 return "presentRequest";
70 case Z_APDU_presentResponse:
71 return "presentResponse";
72 case Z_APDU_deleteResultSetRequest:
73 return "deleteResultSetRequest";
74 case Z_APDU_deleteResultSetResponse:
75 return "deleteResultSetResponse";
76 case Z_APDU_scanRequest:
78 case Z_APDU_scanResponse:
79 return "scanResponse";
80 case Z_APDU_sortRequest:
82 case Z_APDU_sortResponse:
83 return "sortResponse";
84 case Z_APDU_extendedServicesRequest:
85 return "extendedServicesRequest";
86 case Z_APDU_extendedServicesResponse:
87 return "extendedServicesResponse";
94 static const char *gdu_name(Z_GDU *gdu)
99 return apdu_name(gdu->u.z3950);
100 case Z_GDU_HTTP_Request:
101 return "HTTP Request";
102 case Z_GDU_HTTP_Response:
103 return "HTTP Response";
105 return "Unknown request/response";
107 Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
109 Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
111 m_PDU_Observable = the_PDU_Observable;
116 m_keepalive_limit_bw = 500000;
117 m_keepalive_limit_pdu = 1000;
119 m_default_target = 0;
120 m_proxy_negotiation_charset = 0;
121 m_proxy_negotiation_lang = 0;
122 m_charset_converter = new Yaz_CharsetConverter;
126 m_client_idletime = 600;
127 m_target_idletime = 600;
128 m_optimize = xstrdup ("1");
129 strcpy(m_session_str, "0 ");
136 m_max_record_retrieve = 0;
140 m_invalid_session = 0;
142 m_referenceId_mem = nmem_create();
144 m_marcxml_mode = none;
145 m_stylesheet_xsp = 0;
146 m_stylesheet_nprl = 0;
147 m_s2z_stylesheet = 0;
151 m_backend_charset = 0;
153 m_initRequest_apdu = 0;
154 m_initRequest_mem = 0;
155 m_initRequest_preferredMessageSize = 0;
156 m_initRequest_maximumRecordSize = 0;
157 m_initRequest_options = 0;
158 m_initRequest_version = 0;
159 m_initRequest_oi_negotiation_charsets = 0;
160 m_initRequest_oi_negotiation_num_charsets = 0;
161 m_initRequest_oi_negotiation_langs = 0;
162 m_initRequest_oi_negotiation_num_langs = 0;
163 m_initRequest_oi_negotiation_selected = 0;
164 m_apdu_invalid_session = 0;
165 m_mem_invalid_session = 0;
167 m_s2z_odr_search = 0;
169 m_s2z_search_apdu = 0;
170 m_s2z_present_apdu = 0;
171 m_http_keepalive = 0;
174 m_s2z_packing = Z_SRW_recordPacking_string;
175 #if HAVE_GETTIMEOFDAY
176 m_time_tv = xmalloc(sizeof(struct timeval));
177 struct timeval *tv = (struct timeval *) m_time_tv;
183 m_usemarcon_ini_stage1 = 0;
184 m_usemarcon_ini_stage2 = 0;
185 m_usemarcon = new Yaz_usemarcon();
190 Yaz_Proxy::~Yaz_Proxy()
192 yaz_log(YLOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str,
193 m_bytes_sent, m_bytes_recv);
194 nmem_destroy(m_initRequest_mem);
195 nmem_destroy(m_mem_invalid_session);
196 nmem_destroy(m_referenceId_mem);
198 xfree(m_proxyTarget);
199 xfree(m_default_target);
200 xfree(m_proxy_negotiation_charset);
201 xfree(m_proxy_negotiation_lang);
202 delete m_charset_converter;
206 if (m_stylesheet_xsp)
207 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
212 xfree (m_backend_type);
213 xfree (m_backend_charset);
214 xfree (m_usemarcon_ini_stage1);
215 xfree (m_usemarcon_ini_stage2);
218 odr_destroy(m_s2z_odr_init);
219 if (m_s2z_odr_search)
220 odr_destroy(m_s2z_odr_search);
226 void Yaz_Proxy::set_debug_mode(int mode)
231 int Yaz_Proxy::set_config(const char *config)
234 m_config = new Yaz_ProxyConfig();
235 xfree(m_config_fname);
236 m_config_fname = xstrdup(config);
237 int r = m_config->read_xml(config);
239 m_config->get_generic_info(&m_log_mask, &m_max_clients);
243 void Yaz_Proxy::set_default_target(const char *target)
245 xfree (m_default_target);
246 m_default_target = 0;
248 m_default_target = (char *) xstrdup (target);
251 void Yaz_Proxy::set_proxy_negotiation (const char *charset, const char *lang)
253 yaz_log(YLOG_LOG, "%sSet the proxy negotiation: charset to '%s', "
254 "language to '%s'", m_session_str, charset?charset:"none",
256 xfree (m_proxy_negotiation_charset);
257 xfree (m_proxy_negotiation_lang);
258 m_proxy_negotiation_charset = m_proxy_negotiation_lang = 0;
260 m_proxy_negotiation_charset = (char *) xstrdup (charset);
262 m_proxy_negotiation_lang = (char *) xstrdup (lang);
265 Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
268 return m_parent->check_reconfigure();
270 Yaz_ProxyConfig *cfg = m_config;
273 yaz_log(YLOG_LOG, "reconfigure");
275 if (m_config_fname && cfg)
277 yaz_log(YLOG_LOG, "reconfigure config %s", m_config_fname);
278 int r = cfg->read_xml(m_config_fname);
280 yaz_log(YLOG_WARN, "reconfigure failed");
284 cfg->get_generic_info(&m_log_mask, &m_max_clients);
288 yaz_log(YLOG_LOG, "reconfigure");
294 IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
295 *the_PDU_Observable, int fd)
298 Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable, this);
299 new_proxy->m_config = 0;
300 new_proxy->m_config_fname = 0;
301 new_proxy->timeout(m_client_idletime);
302 new_proxy->m_target_idletime = m_target_idletime;
303 new_proxy->set_default_target(m_default_target);
304 new_proxy->m_max_clients = m_max_clients;
305 new_proxy->m_log_mask = m_log_mask;
306 new_proxy->set_APDU_log(get_APDU_log());
307 if (m_log_mask & PROXY_LOG_APDU_CLIENT)
308 new_proxy->set_APDU_yazlog(1);
310 new_proxy->set_APDU_yazlog(0);
311 sprintf(new_proxy->m_session_str, "%ld:%d ", (long) time(0), m_session_no);
313 yaz_log (YLOG_LOG, "%sNew session %s", new_proxy->m_session_str,
314 the_PDU_Observable->getpeername());
315 new_proxy->set_proxy_negotiation(m_proxy_negotiation_charset,
316 m_proxy_negotiation_lang);
320 char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
323 Z_OtherInformationUnit *oi;
325 ent.proto = PROTO_Z3950;
326 ent.oclass = CLASS_USERINFO;
327 ent.value = (oid_value) VAL_COOKIE;
328 assert (oid_ent_to_oid (&ent, oid));
330 if (oid_ent_to_oid (&ent, oid) &&
331 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
332 oi->which == Z_OtherInfo_characterInfo)
333 return oi->information.characterInfo;
336 char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
339 Z_OtherInformationUnit *oi;
341 ent.proto = PROTO_Z3950;
342 ent.oclass = CLASS_USERINFO;
343 ent.value = (oid_value) VAL_PROXY;
344 if (oid_ent_to_oid (&ent, oid) &&
345 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
346 oi->which == Z_OtherInfo_characterInfo)
347 return oi->information.characterInfo;
350 const char *Yaz_Proxy::load_balance(const char **url)
352 int zurl_in_use[MAX_ZURL_PLEX];
353 int zurl_in_spare[MAX_ZURL_PLEX];
357 for (i = 0; i<MAX_ZURL_PLEX; i++)
360 zurl_in_spare[i] = 0;
362 for (c = m_parent->m_clientPool; c; c = c->m_next)
364 for (i = 0; url[i]; i++)
365 if (!strcmp(url[i], c->get_hostname()))
368 if (c->m_cookie == 0 && c->m_server == 0 && c->m_waiting == 0)
372 int min_use = 100000;
373 int spare_for_min = 0;
375 const char *ret_min = 0;
376 const char *ret_spare = 0;
377 for (i = 0; url[i]; i++)
379 yaz_log(YLOG_DEBUG, "%szurl=%s use=%d spare=%d",
380 m_session_str, url[i], zurl_in_use[i], zurl_in_spare[i]);
381 if (min_use > zurl_in_use[i])
384 min_use = zurl_in_use[i];
385 spare_for_min = zurl_in_spare[i];
387 if (max_spare < zurl_in_spare[i])
390 max_spare = zurl_in_spare[i];
393 // use the one with minimum connections if spare is > 3
394 if (spare_for_min > 3)
396 // use one with most spares (if any)
402 Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
403 const char *proxy_host)
406 Yaz_Proxy *parent = m_parent;
407 Yaz_ProxyClient *c = m_client;
411 const char *url[MAX_ZURL_PLEX];
412 Yaz_ProxyConfig *cfg = check_reconfigure();
415 if (parent && parent->m_debug_mode)
417 // only to be enabled for debugging...
418 if (!strcmp(proxy_host, "stop"))
421 xfree(m_default_target);
422 m_default_target = xstrdup(proxy_host);
424 proxy_host = m_default_target;
425 int client_idletime = -1;
426 const char *cql2rpn_fname = 0;
427 const char *negotiation_charset = 0;
428 const char *negotiation_lang = 0;
429 const char *query_charset = 0;
430 url[0] = m_default_target;
435 cfg->get_target_info(proxy_host, url, &m_bw_max,
436 &m_pdu_max, &m_max_record_retrieve,
437 &m_target_idletime, &client_idletime,
438 &parent->m_max_clients,
439 &m_keepalive_limit_bw,
440 &m_keepalive_limit_pdu,
443 &negotiation_charset,
447 if (client_idletime != -1)
449 m_client_idletime = client_idletime;
450 timeout(m_client_idletime);
453 m_cql2rpn.set_pqf_file(cql2rpn_fname);
454 if (negotiation_charset || negotiation_lang)
456 set_proxy_negotiation(negotiation_charset,
459 m_charset_converter->set_target_query_charset(query_charset);
462 yaz_log(YLOG_LOG, "%sNo default target", m_session_str);
465 // we don't handle multiplexing for cookie session, so we just
466 // pick the first one in this case (anonymous users will be able
467 // to use any backend)
468 if (cookie && *cookie)
469 m_proxyTarget = (char*) xstrdup(url[0]);
471 m_proxyTarget = (char*) xstrdup(load_balance(url));
473 if (cookie && *cookie)
474 { // search in sessions with a cookie
475 for (c = parent->m_clientPool; c; c = c->m_next)
478 assert (*c->m_prev == c);
479 if (c->m_cookie && !strcmp(cookie,c->m_cookie) &&
480 !strcmp(m_proxyTarget, c->get_hostname()))
483 // The following handles "cancel"
484 // If connection is busy (waiting for PDU) and
485 // we have an initRequest we can safely do re-open
486 if (c->m_waiting && apdu->which == Z_APDU_initRequest)
488 yaz_log (YLOG_LOG, "%s REOPEN target=%s", m_session_str,
495 c->m_last_resultCount = 0;
496 c->m_sr_transform = 0;
498 c->m_resultSetStartPoint = 0;
499 c->m_target_idletime = m_target_idletime;
500 if (c->client(m_proxyTarget))
507 c->m_seqno = parent->m_seqno;
508 if (c->m_server && c->m_server != this)
509 c->m_server->m_client = 0;
512 yaz_log (YLOG_DEBUG, "get_client 1 %p %p", this, c);
518 apdu->which == Z_APDU_initRequest &&
519 apdu->u.initRequest->idAuthentication == 0 &&
520 !ODR_MASK_GET(apdu->u.initRequest->options, Z_Options_negotiationModel))
522 // anonymous sessions without cookie.
523 // if authentication is set it is NOT anonymous se we can't share them.
524 // If charset and lang negotiation is use it is NOT anonymous session too.
525 for (c = parent->m_clientPool; c; c = c->m_next)
528 assert(*c->m_prev == c);
529 if (c->m_server == 0 && c->m_cookie == 0 &&
531 !strcmp(m_proxyTarget, c->get_hostname()))
534 yaz_log (YLOG_LOG, "%sREUSE %d %s",
535 m_session_str, parent->m_seqno, c->get_hostname());
537 c->m_seqno = parent->m_seqno;
538 assert(c->m_server == 0);
541 if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
542 c->set_APDU_yazlog(1);
544 c->set_APDU_yazlog(0);
556 if (apdu->which != Z_APDU_initRequest)
558 yaz_log (YLOG_LOG, "%sno init request as first PDU", m_session_str);
561 Z_InitRequest *initRequest = apdu->u.initRequest;
563 if (initRequest->idAuthentication)
565 // the client uses authentication. We set the keepalive PDU
566 // to 0 so we don't cache it in releaseClient
567 m_keepalive_limit_pdu = 0;
569 // go through list of clients - and find the lowest/oldest one.
570 Yaz_ProxyClient *c_min = 0;
572 int no_of_clients = 0;
573 if (parent->m_clientPool)
574 yaz_log (YLOG_DEBUG, "Existing sessions");
575 for (c = parent->m_clientPool; c; c = c->m_next)
577 yaz_log (YLOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
578 c->m_waiting, c->get_hostname(),
579 c->m_cookie ? c->m_cookie : "");
581 if (min_seq < 0 || c->m_seqno < min_seq)
583 min_seq = c->m_seqno;
587 if (no_of_clients >= parent->m_max_clients)
590 if (c->m_waiting || strcmp(m_proxyTarget, c->get_hostname()))
592 yaz_log (YLOG_LOG, "%sMAXCLIENTS %d Destroy %d",
593 m_session_str, parent->m_max_clients, c->m_seqno);
594 if (c->m_server && c->m_server != this)
600 yaz_log (YLOG_LOG, "%sMAXCLIENTS %d Reuse %d %d %s",
601 m_session_str, parent->m_max_clients,
602 c->m_seqno, parent->m_seqno, c->get_hostname());
606 c->m_cookie = xstrdup(cookie);
607 c->m_seqno = parent->m_seqno;
608 if (c->m_server && c->m_server != this)
610 c->m_server->m_client = 0;
614 c->m_target_idletime = m_target_idletime;
615 c->timeout(m_target_idletime);
617 if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
618 c->set_APDU_yazlog(1);
620 c->set_APDU_yazlog(0);
627 yaz_log (YLOG_LOG, "%sNEW %d %s",
628 m_session_str, parent->m_seqno, m_proxyTarget);
629 c = new Yaz_ProxyClient(m_PDU_Observable->clone(), parent);
630 c->m_next = parent->m_clientPool;
632 c->m_next->m_prev = &c->m_next;
633 parent->m_clientPool = c;
634 c->m_prev = &parent->m_clientPool;
640 c->m_cookie = xstrdup(cookie);
642 c->m_seqno = parent->m_seqno;
644 c->m_last_resultCount = 0;
647 c->m_sr_transform = 0;
649 c->m_resultSetStartPoint = 0;
651 if (c->client(m_proxyTarget))
656 c->m_target_idletime = m_target_idletime;
659 if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
660 c->set_APDU_yazlog(1);
662 c->set_APDU_yazlog(0);
664 yaz_log (YLOG_DEBUG, "get_client 3 %p %p", this, c);
667 void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
670 for (i = 0; i<num; i++)
673 Z_DefaultDiagFormat *r;
674 Z_DiagRec *p = pp[i];
675 if (p->which != Z_DiagRec_defaultFormat)
677 yaz_log(YLOG_LOG, "%sError no diagnostics", m_session_str);
681 r = p->u.defaultFormat;
682 if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
683 ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
684 yaz_log(YLOG_LOG, "%sError unknown diagnostic set", m_session_str);
687 case Z_DefaultDiagFormat_v2Addinfo:
688 yaz_log(YLOG_LOG, "%sError %d %s:%s",
690 *r->condition, diagbib1_str(*r->condition),
693 case Z_DefaultDiagFormat_v3Addinfo:
694 yaz_log(YLOG_LOG, "%sError %d %s:%s",
696 *r->condition, diagbib1_str(*r->condition),
703 int Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu)
705 if (!m_stylesheet_xsp || p->num_records <= 0)
706 return 0; /* no XSLT to be done ... */
708 m_stylesheet_offset = 0;
709 m_stylesheet_nprl = p;
710 m_stylesheet_apdu = apdu;
715 void Yaz_Proxy::convert_xsl_delay()
718 Z_NamePlusRecord *npr = m_stylesheet_nprl->records[m_stylesheet_offset];
719 if (npr->which == Z_NamePlusRecord_databaseRecord)
721 Z_External *r = npr->u.databaseRecord;
722 if (r->which == Z_External_octet)
725 fwrite((char*) r->u.octet_aligned->buf, 1, r->u.octet_aligned->len, stdout);
727 xmlDocPtr res, doc = xmlParseMemory(
728 (char*) r->u.octet_aligned->buf,
729 r->u.octet_aligned->len);
732 yaz_log(YLOG_LOG, "%sXSLT convert %d",
733 m_session_str, m_stylesheet_offset);
734 res = xsltApplyStylesheet((xsltStylesheetPtr) m_stylesheet_xsp,
741 xmlDocDumpFormatMemory (res, &out_buf, &out_len, 1);
743 m_stylesheet_nprl->records[m_stylesheet_offset]->
745 z_ext_record(odr_encode(), VAL_TEXT_XML,
746 (char*) out_buf, out_len);
755 m_stylesheet_offset++;
756 if (m_stylesheet_offset == m_stylesheet_nprl->num_records)
758 m_stylesheet_nprl = 0;
760 if (m_stylesheet_xsp)
761 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
763 m_stylesheet_xsp = 0;
764 timeout(m_client_idletime);
765 send_PDU_convert(m_stylesheet_apdu);
771 void Yaz_Proxy::convert_to_frontend_type(Z_NamePlusRecordList *p)
773 if (m_frontend_type != VAL_NONE)
776 for (i = 0; i < p->num_records; i++)
778 Z_NamePlusRecord *npr = p->records[i];
779 if (npr->which == Z_NamePlusRecord_databaseRecord)
781 Z_External *r = npr->u.databaseRecord;
782 if (r->which == Z_External_octet)
785 if (m_usemarcon_ini_stage1 && *m_usemarcon_ini_stage1)
787 if (!m_usemarcon->m_stage1)
789 m_usemarcon->m_stage1 = new CDetails();
791 m_usemarcon->m_stage1->SetIniFileName(m_usemarcon_ini_stage1);
792 m_usemarcon->m_stage1->SetMarcRecord((char*) r->u.octet_aligned->buf, r->u.octet_aligned->len);
793 int res = m_usemarcon->m_stage1->Start();
798 m_usemarcon->m_stage1->GetMarcRecord(converted, convlen);
799 if (m_usemarcon_ini_stage2 && *m_usemarcon_ini_stage2)
801 if (!m_usemarcon->m_stage2)
803 m_usemarcon->m_stage2 = new CDetails();
805 m_usemarcon->m_stage2->SetIniFileName(m_usemarcon_ini_stage2);
806 m_usemarcon->m_stage2->SetMarcRecord(converted, convlen);
807 res = m_usemarcon->m_stage2->Start();
811 m_usemarcon->m_stage2->GetMarcRecord(converted, convlen);
815 yaz_log(YLOG_LOG, "%sUSEMARCON stage 2 error %d", m_session_str, res);
818 npr->u.databaseRecord =
819 z_ext_record(odr_encode(),
827 yaz_log(YLOG_LOG, "%sUSEMARCON stage 1 error %d", m_session_str, res);
833 npr->u.databaseRecord =
834 z_ext_record(odr_encode(),
836 (char*) r->u.octet_aligned->buf,
837 r->u.octet_aligned->len);
844 void Yaz_Proxy::convert_records_charset(Z_NamePlusRecordList *p,
845 const char *backend_charset)
847 yaz_log(YLOG_LOG, "%sconvert_to_marc", m_session_str);
848 int sel = m_charset_converter->get_client_charset_selected();
849 const char *client_record_charset =
850 m_charset_converter->get_client_query_charset();
851 if (sel && backend_charset && client_record_charset &&
852 strcmp(backend_charset, client_record_charset))
855 yaz_iconv_t cd = yaz_iconv_open(client_record_charset,
857 yaz_marc_t mt = yaz_marc_create();
858 yaz_marc_xml(mt, YAZ_MARC_ISO2709);
859 yaz_marc_iconv(mt, cd);
860 for (i = 0; i < p->num_records; i++)
862 Z_NamePlusRecord *npr = p->records[i];
863 if (npr->which == Z_NamePlusRecord_databaseRecord)
865 Z_External *r = npr->u.databaseRecord;
866 oident *ent = oid_getentbyoid(r->direct_reference);
867 if (!ent || ent->value == VAL_NONE)
870 if (ent->value == VAL_SUTRS)
872 WRBUF w = wrbuf_alloc();
874 wrbuf_iconv_write(w, cd, (char*) r->u.octet_aligned->buf,
875 r->u.octet_aligned->len);
876 npr->u.databaseRecord =
877 z_ext_record(odr_encode(), ent->value, wrbuf_buf(w),
881 else if (ent->value == VAL_TEXT_XML)
885 else if (r->which == Z_External_octet)
889 if (yaz_marc_decode_buf(mt,
890 (char*) r->u.octet_aligned->buf,
891 r->u.octet_aligned->len,
894 npr->u.databaseRecord =
895 z_ext_record(odr_encode(), ent->value, result, rlen);
896 yaz_log(YLOG_LOG, "%sRecoding MARC record",
904 yaz_marc_destroy(mt);
908 yaz_log(YLOG_LOG, "%sSkipping marc convert", m_session_str);
912 void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
913 const char *backend_charset)
916 if (!backend_charset)
917 backend_charset = "MARC-8";
918 yaz_iconv_t cd = yaz_iconv_open("UTF-8", backend_charset);
919 yaz_marc_t mt = yaz_marc_create();
920 yaz_marc_xml(mt, YAZ_MARC_MARCXML);
921 yaz_marc_iconv(mt, cd);
922 for (i = 0; i < p->num_records; i++)
924 Z_NamePlusRecord *npr = p->records[i];
925 if (npr->which == Z_NamePlusRecord_databaseRecord)
927 Z_External *r = npr->u.databaseRecord;
928 if (r->which == Z_External_OPAC)
930 WRBUF w = wrbuf_alloc();
932 yaz_display_OPAC(w, r->u.opac, 0);
933 npr->u.databaseRecord = z_ext_record(
934 odr_encode(), VAL_TEXT_XML,
935 wrbuf_buf(w), wrbuf_len(w)
939 else if (r->which == Z_External_octet)
943 if (yaz_marc_decode_buf(mt, (char*) r->u.octet_aligned->buf,
944 r->u.octet_aligned->len,
947 npr->u.databaseRecord =
948 z_ext_record(odr_encode(), VAL_TEXT_XML, result, rlen);
955 yaz_marc_destroy(mt);
958 void Yaz_Proxy::logtime()
960 #if HAVE_GETTIMEOFDAY
961 struct timeval *tv = (struct timeval*) m_time_tv;
965 gettimeofday(&tv1, 0);
966 long diff = (tv1.tv_sec - tv->tv_sec)*1000000 +
967 (tv1.tv_usec - tv->tv_usec);
969 yaz_log(YLOG_LOG, "%sElapsed %ld.%03ld", m_session_str,
970 diff/1000000, (diff/1000)%1000);
977 int Yaz_Proxy::send_http_response(int code)
979 ODR o = odr_encode();
980 Z_GDU *gdu = z_get_HTTP_Response(o, code);
981 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
983 hres->version = odr_strdup(o, m_http_version);
984 if (m_http_keepalive)
985 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
989 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
991 yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
995 int r = send_GDU(gdu, &len);
997 m_bw_stat.add_bytes(len);
1002 int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
1004 ODR o = odr_encode();
1005 const char *ctype = "text/xml";
1006 Z_GDU *gdu = z_get_HTTP_Response(o, 200);
1007 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
1009 hres->version = odr_strdup(o, m_http_version);
1010 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1011 if (m_http_keepalive)
1012 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1016 static Z_SOAP_Handler soap_handlers[2] = {
1018 {"http://www.loc.gov/zing/srw/", 0,
1019 (Z_SOAP_fun) yaz_srw_codec},
1024 Z_SOAP *soap_package = (Z_SOAP*) odr_malloc(o, sizeof(Z_SOAP));
1025 soap_package->which = Z_SOAP_generic;
1026 soap_package->u.generic =
1027 (Z_SOAP_Generic *) odr_malloc(o, sizeof(*soap_package->u.generic));
1028 soap_package->u.generic->no = 0;
1029 soap_package->u.generic->ns = soap_handlers[0].ns;
1030 soap_package->u.generic->p = (void *) srw_pdu;
1031 soap_package->ns = m_soap_ns;
1032 z_soap_codec_enc_xsl(o, &soap_package,
1033 &hres->content_buf, &hres->content_len,
1034 soap_handlers, 0, m_s2z_stylesheet);
1035 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
1037 yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
1041 int r = send_GDU(gdu, &len);
1042 m_bytes_sent += len;
1043 m_bw_stat.add_bytes(len);
1048 int Yaz_Proxy::send_to_srw_client_error(int srw_error, const char *add)
1050 ODR o = odr_encode();
1051 Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
1052 Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
1054 srw_res->num_diagnostics = 1;
1055 srw_res->diagnostics = (Z_SRW_diagnostic *)
1056 odr_malloc(o, sizeof(*srw_res->diagnostics));
1057 yaz_mk_std_diagnostic(o, srw_res->diagnostics, srw_error, add);
1058 return send_srw_response(srw_pdu);
1061 int Yaz_Proxy::z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
1062 Z_DefaultDiagFormat *ddf)
1064 int bib1_code = *ddf->condition;
1065 if (bib1_code == 109)
1067 srw_res->num_diagnostics = 1;
1068 srw_res->diagnostics = (Z_SRW_diagnostic *)
1069 odr_malloc(o, sizeof(*srw_res->diagnostics));
1070 yaz_mk_std_diagnostic(o, srw_res->diagnostics,
1071 yaz_diag_bib1_to_srw(*ddf->condition),
1076 int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start)
1078 ODR o = odr_encode();
1079 Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
1080 Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
1082 srw_res->numberOfRecords = odr_intdup (o, hits);
1083 if (records && records->which == Z_Records_DBOSD)
1085 srw_res->num_records =
1086 records->u.databaseOrSurDiagnostics->num_records;
1088 srw_res->records = (Z_SRW_record *)
1089 odr_malloc(o, srw_res->num_records * sizeof(Z_SRW_record));
1090 for (i = 0; i < srw_res->num_records; i++)
1092 Z_NamePlusRecord *npr = records->u.databaseOrSurDiagnostics->records[i];
1093 if (npr->which != Z_NamePlusRecord_databaseRecord)
1095 srw_res->records[i].recordSchema = "diagnostic";
1096 srw_res->records[i].recordPacking = m_s2z_packing;
1097 srw_res->records[i].recordData_buf = "67";
1098 srw_res->records[i].recordData_len = 2;
1099 srw_res->records[i].recordPosition = odr_intdup(o, i+start);
1102 Z_External *r = npr->u.databaseRecord;
1103 oident *ent = oid_getentbyoid(r->direct_reference);
1104 if (r->which == Z_External_octet && ent->value == VAL_TEXT_XML)
1106 srw_res->records[i].recordSchema = m_schema;
1107 srw_res->records[i].recordPacking = m_s2z_packing;
1108 srw_res->records[i].recordData_buf = (char*)
1109 r->u.octet_aligned->buf;
1110 srw_res->records[i].recordData_len = r->u.octet_aligned->len;
1111 srw_res->records[i].recordPosition = odr_intdup(o, i+start);
1115 srw_res->records[i].recordSchema = "diagnostic";
1116 srw_res->records[i].recordPacking = m_s2z_packing;
1117 srw_res->records[i].recordData_buf = "67";
1118 srw_res->records[i].recordData_len = 2;
1119 srw_res->records[i].recordPosition = odr_intdup(o, i+start);
1123 if (records && records->which == Z_Records_NSD)
1126 http_code = z_to_srw_diag(odr_encode(), srw_res,
1127 records->u.nonSurrogateDiagnostic);
1129 return send_http_response(http_code);
1131 return send_srw_response(srw_pdu);
1135 int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
1136 int num_diagnostics)
1138 Yaz_ProxyConfig *cfg = check_reconfigure();
1142 char *b = cfg->get_explain_doc(odr_encode(), 0 /* target */,
1143 m_s2z_database, &len);
1146 Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
1147 Z_SRW_explainResponse *er = res->u.explain_response;
1149 er->record.recordData_buf = b;
1150 er->record.recordData_len = len;
1151 er->record.recordPacking = m_s2z_packing;
1152 er->record.recordSchema = "http://explain.z3950.org/dtd/2.0/";
1154 er->diagnostics = diagnostics;
1155 er->num_diagnostics = num_diagnostics;
1156 return send_srw_response(res);
1159 return send_http_response(404);
1162 int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu)
1166 if (apdu->which == Z_APDU_initResponse)
1168 Z_InitResponse *res = apdu->u.initResponse;
1169 if (*res->result == 0)
1171 send_to_srw_client_error(3, 0);
1173 else if (!m_s2z_search_apdu)
1175 send_srw_explain_response(0, 0);
1179 handle_incoming_Z_PDU(m_s2z_search_apdu);
1182 else if (m_s2z_search_apdu && apdu->which == Z_APDU_searchResponse)
1184 m_s2z_search_apdu = 0;
1185 Z_SearchResponse *res = apdu->u.searchResponse;
1186 m_s2z_hit_count = *res->resultCount;
1187 if (res->records && res->records->which == Z_Records_NSD)
1189 send_to_srw_client_ok(0, res->records, 1);
1191 else if (m_s2z_present_apdu && m_s2z_hit_count > 0)
1194 Z_PresentRequest *pr = m_s2z_present_apdu->u.presentRequest;
1196 if (*pr->resultSetStartPoint <= m_s2z_hit_count)
1198 if (*pr->numberOfRecordsRequested+ *pr->resultSetStartPoint
1200 *pr->numberOfRecordsRequested =
1201 1 + m_s2z_hit_count - *pr->resultSetStartPoint;
1203 handle_incoming_Z_PDU(m_s2z_present_apdu);
1207 m_s2z_present_apdu = 0;
1208 send_to_srw_client_ok(m_s2z_hit_count, res->records, 1);
1211 else if (m_s2z_present_apdu && apdu->which == Z_APDU_presentResponse)
1214 *m_s2z_present_apdu->u.presentRequest->resultSetStartPoint;
1216 m_s2z_present_apdu = 0;
1217 Z_PresentResponse *res = apdu->u.presentResponse;
1218 send_to_srw_client_ok(m_s2z_hit_count, res->records, start);
1224 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
1225 yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
1227 int r = send_Z_PDU(apdu, &len);
1228 m_bytes_sent += len;
1229 m_bw_stat.add_bytes(len);
1236 int Yaz_Proxy::send_to_client(Z_APDU *apdu)
1238 int kill_session = 0;
1239 Z_ReferenceId **new_id = get_referenceIdP(apdu);
1242 *new_id = m_referenceId;
1244 if (apdu->which == Z_APDU_searchResponse)
1246 Z_SearchResponse *sr = apdu->u.searchResponse;
1247 Z_Records *p = sr->records;
1248 if (p && p->which == Z_Records_NSD)
1250 Z_DiagRec dr, *dr_p = &dr;
1251 dr.which = Z_DiagRec_defaultFormat;
1252 dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
1254 *sr->searchStatus = 0;
1255 display_diagrecs(&dr_p, 1);
1259 if (p && p->which == Z_Records_DBOSD)
1263 || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
1266 convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
1267 if (m_marcxml_mode == marcxml)
1268 convert_to_marcxml(p->u.databaseOrSurDiagnostics,
1271 convert_records_charset(p->u.databaseOrSurDiagnostics,
1273 if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
1277 if (sr->resultCount)
1279 yaz_log(YLOG_LOG, "%s%d hits", m_session_str,
1281 if (*sr->resultCount < 0)
1283 m_invalid_session = 1;
1286 *sr->searchStatus = 0;
1288 create_nonSurrogateDiagnostics(odr_encode(), 2, 0);
1289 *sr->resultCount = 0;
1294 else if (apdu->which == Z_APDU_presentResponse)
1296 Z_PresentResponse *sr = apdu->u.presentResponse;
1297 Z_Records *p = sr->records;
1298 if (p && p->which == Z_Records_NSD)
1300 Z_DiagRec dr, *dr_p = &dr;
1301 dr.which = Z_DiagRec_defaultFormat;
1302 dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
1303 if (*sr->presentStatus == Z_PresentStatus_success)
1304 *sr->presentStatus = Z_PresentStatus_failure;
1305 display_diagrecs(&dr_p, 1);
1307 if (p && p->which == Z_Records_DBOSD)
1311 || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
1314 convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
1315 if (m_marcxml_mode == marcxml)
1316 convert_to_marcxml(p->u.databaseOrSurDiagnostics,
1319 convert_records_charset(p->u.databaseOrSurDiagnostics,
1321 if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
1325 else if (apdu->which == Z_APDU_initResponse)
1327 //Get and check negotiation record
1328 //from init response.
1329 handle_charset_lang_negotiation(apdu);
1331 if (m_initRequest_options)
1334 (Odr_bitmask *)odr_malloc(odr_encode(),
1335 sizeof(Odr_bitmask));
1336 ODR_MASK_ZERO(nopt);
1339 for (i = 0; i<24; i++)
1340 if (ODR_MASK_GET(m_initRequest_options, i) &&
1341 ODR_MASK_GET(apdu->u.initResponse->options, i))
1342 ODR_MASK_SET(nopt, i);
1343 apdu->u.initResponse->options = nopt;
1345 if (m_initRequest_version)
1347 Z_ProtocolVersion *nopt =
1348 (Odr_bitmask *)odr_malloc(odr_encode(),
1349 sizeof(Odr_bitmask));
1350 ODR_MASK_ZERO(nopt);
1353 for (i = 0; i<8; i++)
1354 if (ODR_MASK_GET(m_initRequest_version, i) &&
1355 ODR_MASK_GET(apdu->u.initResponse->protocolVersion, i))
1356 ODR_MASK_SET(nopt, i);
1357 apdu->u.initResponse->protocolVersion = nopt;
1359 apdu->u.initResponse->preferredMessageSize =
1360 odr_intdup(odr_encode(),
1361 m_client->m_initResponse_preferredMessageSize >
1362 m_initRequest_preferredMessageSize ?
1363 m_initRequest_preferredMessageSize :
1364 m_client->m_initResponse_preferredMessageSize);
1365 apdu->u.initResponse->maximumRecordSize =
1366 odr_intdup(odr_encode(),
1367 m_client->m_initResponse_maximumRecordSize >
1368 m_initRequest_maximumRecordSize ?
1369 m_initRequest_maximumRecordSize :
1370 m_client->m_initResponse_maximumRecordSize);
1373 int r = send_PDU_convert(apdu);
1380 m_parent->pre_init();
1385 int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
1388 const char *apdu_name_tmp = apdu_name(apdu);
1389 int r = send_Z_PDU(apdu, &len);
1390 if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
1391 yaz_log (YLOG_LOG, "%sSending %s to %s %d bytes",
1393 apdu_name_tmp, get_hostname(), len);
1394 m_bytes_sent += len;
1398 Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
1400 if (apdu->which == Z_APDU_presentRequest)
1402 Z_PresentRequest *pr = apdu->u.presentRequest;
1403 int toget = *pr->numberOfRecordsRequested;
1404 int start = *pr->resultSetStartPoint;
1406 yaz_log(YLOG_LOG, "%sPresent %s %d+%d", m_session_str,
1407 pr->resultSetId, start, toget);
1409 if (*m_parent->m_optimize == '0')
1412 if (!m_client->m_last_resultSetId)
1414 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
1415 new_apdu->u.presentResponse->records =
1416 create_nonSurrogateDiagnostics(odr_encode(), 30,
1418 send_to_client(new_apdu);
1421 if (!strcmp(m_client->m_last_resultSetId, pr->resultSetId))
1423 if (start+toget-1 > m_client->m_last_resultCount)
1425 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
1426 new_apdu->u.presentResponse->records =
1427 create_nonSurrogateDiagnostics(odr_encode(), 13, 0);
1428 send_to_client(new_apdu);
1431 Z_NamePlusRecordList *npr;
1433 yaz_log(YLOG_LOG, "%sCache lookup %d+%d syntax=%s",
1434 m_session_str, start, toget, yaz_z3950oid_to_str(
1435 pr->preferredRecordSyntax, &oclass));
1437 if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget,
1438 pr->preferredRecordSyntax,
1439 pr->recordComposition))
1441 yaz_log (YLOG_LOG, "%sReturned cached records for present request",
1443 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
1444 new_apdu->u.presentResponse->referenceId = pr->referenceId;
1446 new_apdu->u.presentResponse->numberOfRecordsReturned
1447 = odr_intdup(odr_encode(), toget);
1449 new_apdu->u.presentResponse->records = (Z_Records*)
1450 odr_malloc(odr_encode(), sizeof(Z_Records));
1451 new_apdu->u.presentResponse->records->which = Z_Records_DBOSD;
1452 new_apdu->u.presentResponse->records->u.databaseOrSurDiagnostics = npr;
1453 new_apdu->u.presentResponse->nextResultSetPosition =
1454 odr_intdup(odr_encode(), start+toget);
1456 send_to_client(new_apdu);
1462 if (apdu->which != Z_APDU_searchRequest)
1464 Z_SearchRequest *sr = apdu->u.searchRequest;
1465 Yaz_Z_Query *this_query = new Yaz_Z_Query;
1466 Yaz_Z_Databases this_databases;
1468 this_databases.set(sr->num_databaseNames, (const char **)
1471 this_query->set_Z_Query(sr->query);
1473 char query_str[120];
1474 this_query->print(query_str, sizeof(query_str)-1);
1475 yaz_log(YLOG_LOG, "%sSearch %s", m_session_str, query_str);
1477 if (*m_parent->m_optimize != '0' &&
1478 m_client->m_last_ok && m_client->m_last_query &&
1479 m_client->m_last_query->match(this_query) &&
1480 !strcmp(m_client->m_last_resultSetId, sr->resultSetName) &&
1481 m_client->m_last_databases.match(this_databases))
1484 if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
1485 m_client->m_last_resultCount < *sr->largeSetLowerBound)
1487 Z_NamePlusRecordList *npr;
1488 int toget = *sr->mediumSetPresentNumber;
1489 Z_RecordComposition *comp = 0;
1491 if (toget > m_client->m_last_resultCount)
1492 toget = m_client->m_last_resultCount;
1494 if (sr->mediumSetElementSetNames)
1496 comp = (Z_RecordComposition *)
1497 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
1498 comp->which = Z_RecordComp_simple;
1499 comp->u.simple = sr->mediumSetElementSetNames;
1502 if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
1503 sr->preferredRecordSyntax, comp))
1505 yaz_log (YLOG_LOG, "%sReturned cached records for medium set",
1507 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1508 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1509 new_apdu->u.searchResponse->resultCount =
1510 &m_client->m_last_resultCount;
1512 new_apdu->u.searchResponse->numberOfRecordsReturned
1513 = odr_intdup(odr_encode(), toget);
1515 new_apdu->u.searchResponse->presentStatus =
1516 odr_intdup(odr_encode(), Z_PresentStatus_success);
1517 new_apdu->u.searchResponse->records = (Z_Records*)
1518 odr_malloc(odr_encode(), sizeof(Z_Records));
1519 new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
1520 new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
1521 new_apdu->u.searchResponse->nextResultSetPosition =
1522 odr_intdup(odr_encode(), toget+1);
1523 send_to_client(new_apdu);
1529 // send present request (medium size)
1530 yaz_log (YLOG_LOG, "%sOptimizing search for medium set",
1533 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
1534 Z_PresentRequest *pr = new_apdu->u.presentRequest;
1535 pr->referenceId = sr->referenceId;
1536 pr->resultSetId = sr->resultSetName;
1537 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
1538 *pr->numberOfRecordsRequested = toget;
1539 pr->recordComposition = comp;
1540 m_client->m_sr_transform = 1;
1544 else if (m_client->m_last_resultCount >= *sr->largeSetLowerBound ||
1545 m_client->m_last_resultCount <= 0)
1547 // large set. Return pseudo-search response immediately
1548 yaz_log (YLOG_LOG, "%sOptimizing search for large set",
1550 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1551 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1552 new_apdu->u.searchResponse->resultCount =
1553 &m_client->m_last_resultCount;
1554 send_to_client(new_apdu);
1559 Z_NamePlusRecordList *npr;
1560 int toget = m_client->m_last_resultCount;
1561 Z_RecordComposition *comp = 0;
1563 // send a present request (small set)
1565 if (sr->smallSetElementSetNames)
1567 comp = (Z_RecordComposition *)
1568 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
1569 comp->which = Z_RecordComp_simple;
1570 comp->u.simple = sr->smallSetElementSetNames;
1573 if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
1574 sr->preferredRecordSyntax, comp))
1576 yaz_log (YLOG_LOG, "%sReturned cached records for small set",
1578 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1579 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1580 new_apdu->u.searchResponse->resultCount =
1581 &m_client->m_last_resultCount;
1583 new_apdu->u.searchResponse->numberOfRecordsReturned
1584 = odr_intdup(odr_encode(), toget);
1586 new_apdu->u.searchResponse->presentStatus =
1587 odr_intdup(odr_encode(), Z_PresentStatus_success);
1588 new_apdu->u.searchResponse->records = (Z_Records*)
1589 odr_malloc(odr_encode(), sizeof(Z_Records));
1590 new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
1591 new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
1592 new_apdu->u.searchResponse->nextResultSetPosition =
1593 odr_intdup(odr_encode(), toget+1);
1594 send_to_client(new_apdu);
1599 yaz_log (YLOG_LOG, "%sOptimizing search for small set",
1601 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
1602 Z_PresentRequest *pr = new_apdu->u.presentRequest;
1603 pr->referenceId = sr->referenceId;
1604 pr->resultSetId = sr->resultSetName;
1605 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
1606 *pr->numberOfRecordsRequested = toget;
1607 pr->recordComposition = comp;
1608 m_client->m_sr_transform = 1;
1613 else // query doesn't match
1615 delete m_client->m_last_query;
1616 m_client->m_last_query = this_query;
1617 m_client->m_last_ok = 0;
1618 m_client->m_cache.clear();
1619 m_client->m_resultSetStartPoint = 0;
1621 xfree (m_client->m_last_resultSetId);
1622 m_client->m_last_resultSetId = xstrdup (sr->resultSetName);
1624 m_client->m_last_databases.set(sr->num_databaseNames,
1625 (const char **) sr->databaseNames);
1631 void Yaz_Proxy::inc_request_no()
1633 char *cp = strchr(m_session_str, ' ');
1636 sprintf(cp+1, "%d ", m_request_no);
1639 void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
1643 m_bytes_recv += len;
1645 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
1646 yaz_log (YLOG_LOG, "%sReceiving %s from client %d bytes",
1647 m_session_str, gdu_name(apdu), len);
1649 if (m_bw_hold_PDU) // double incoming PDU. shutdown now.
1652 m_bw_stat.add_bytes(len);
1653 m_pdu_stat.add_bytes(1);
1655 #if HAVE_GETTIMEOFDAY
1656 gettimeofday((struct timeval *) m_time_tv, 0);
1659 int bw_total = m_bw_stat.get_total();
1660 int pdu_total = m_pdu_stat.get_total();
1665 if (bw_total > m_bw_max)
1667 reduce = (bw_total/m_bw_max);
1672 if (pdu_total > m_pdu_max)
1674 int nreduce = (m_pdu_max >= 60) ? 1 : 60/m_pdu_max;
1675 reduce = (reduce > nreduce) ? reduce : nreduce;
1681 yaz_log(YLOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
1682 m_session_str, reduce, bw_total, pdu_total,
1683 m_bw_max, m_pdu_max);
1685 m_bw_hold_PDU = apdu; // save PDU and signal "on hold"
1686 timeout(reduce); // call us reduce seconds later
1688 else if (apdu->which == Z_GDU_Z3950)
1689 handle_incoming_Z_PDU(apdu->u.z3950);
1690 else if (apdu->which == Z_GDU_HTTP_Request)
1691 handle_incoming_HTTP(apdu->u.HTTP_Request);
1694 void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)
1696 if (m_max_record_retrieve)
1698 if (apdu->which == Z_APDU_presentRequest)
1700 Z_PresentRequest *pr = apdu->u.presentRequest;
1701 if (pr->numberOfRecordsRequested &&
1702 *pr->numberOfRecordsRequested > m_max_record_retrieve)
1703 *pr->numberOfRecordsRequested = m_max_record_retrieve;
1707 void Yaz_Proxy::handle_charset_lang_negotiation(Z_APDU *apdu)
1709 if (apdu->which == Z_APDU_initRequest)
1711 yaz_log(YLOG_LOG, "%shandle_charset_lang_negotiation",
1713 if (m_initRequest_options &&
1714 !ODR_MASK_GET(m_initRequest_options, Z_Options_negotiationModel) &&
1715 (m_proxy_negotiation_charset || m_proxy_negotiation_lang))
1717 // There is no negotiation proposal from
1718 // client's side. OK. The proxy negotiation
1720 Z_InitRequest *initRequest = apdu->u.initRequest;
1721 Z_OtherInformation **otherInfo;
1722 Z_OtherInformationUnit *oi;
1723 get_otherInfoAPDU(apdu, &otherInfo);
1724 oi = update_otherInformation(otherInfo, 1, NULL, 0, 0);
1727 ODR_MASK_SET(initRequest->options,
1728 Z_Options_negotiationModel);
1729 oi->which = Z_OtherInfo_externallyDefinedInfo;
1730 oi->information.externallyDefinedInfo =
1731 yaz_set_proposal_charneg(odr_encode(),
1732 (const char**)&m_proxy_negotiation_charset,
1733 m_proxy_negotiation_charset ? 1:0,
1734 (const char**)&m_proxy_negotiation_lang,
1735 m_proxy_negotiation_lang ? 1:0,
1739 else if (m_initRequest_options &&
1740 ODR_MASK_GET(m_initRequest_options,
1741 Z_Options_negotiationModel) &&
1742 m_charset_converter->get_target_query_charset())
1744 yaz_log(YLOG_LOG, "%sManaged charset negotiation: charset=%s",
1746 m_charset_converter->get_target_query_charset());
1747 Z_InitRequest *initRequest = apdu->u.initRequest;
1748 Z_CharSetandLanguageNegotiation *negotiation =
1749 yaz_get_charneg_record (initRequest->otherInfo);
1751 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1753 NMEM nmem = nmem_create();
1754 char **charsets = 0;
1755 int num_charsets = 0;
1759 yaz_get_proposal_charneg (nmem, negotiation,
1760 &charsets, &num_charsets,
1761 &langs, &num_langs, &selected);
1763 for (i = 0; i<num_charsets; i++)
1764 yaz_log(YLOG_LOG, "%scharset %s", m_session_str,
1766 for (i = 0; i<num_langs; i++)
1767 yaz_log(YLOG_LOG, "%slang %s", m_session_str,
1770 const char *t_charset =
1771 m_charset_converter->get_target_query_charset();
1772 // sweep through charsets and pick the first supported
1774 for (i = 0; i<num_charsets; i++)
1776 const char *c_charset = charsets[i];
1777 if (!odr_set_charset(odr_decode(), t_charset, c_charset))
1780 if (i != num_charsets)
1782 // got one .. set up ODR for reverse direction
1783 const char *c_charset = charsets[i];
1784 odr_set_charset(odr_encode(), c_charset, t_charset);
1785 m_charset_converter->set_client_query_charset(c_charset);
1786 m_charset_converter->set_client_charset_selected(selected);
1789 ODR_MASK_CLEAR(m_initRequest_options,
1790 Z_Options_negotiationModel);
1791 yaz_del_charneg_record(&initRequest->otherInfo);
1795 yaz_log(YLOG_WARN, "%sUnable to decode charset package",
1800 else if (apdu->which == Z_APDU_initResponse)
1802 Z_InitResponse *initResponse = apdu->u.initResponse;
1803 Z_OtherInformation **otherInfo;
1805 if (ODR_MASK_GET(initResponse->options, Z_Options_negotiationModel))
1811 get_otherInfoAPDU(apdu, &otherInfo);
1813 if (!otherInfo && !(*otherInfo))
1816 Z_CharSetandLanguageNegotiation *charneg =
1817 yaz_get_charneg_record(*otherInfo);
1822 yaz_get_response_charneg(m_referenceId_mem, charneg,
1823 &charset, &lang, &selected);
1825 yaz_log(YLOG_LOG, "%sAccepted charset - '%s' and lang - '%s'",
1826 m_session_str, (charset)?charset:"none", (lang)?lang:"none");
1828 if (m_initRequest_options &&
1829 ODR_MASK_GET(m_initRequest_options, Z_Options_negotiationModel))
1831 yaz_log(YLOG_LOG, "%sClient's negotiation record in use",
1834 else if (m_proxy_negotiation_charset || m_proxy_negotiation_lang)
1836 // negotiation-charset, negotiation-lang
1837 // elements of config file in use.
1839 yaz_log(YLOG_LOG, "%sProxy's negotiation record in use",
1842 // clear negotiation option.
1843 ODR_MASK_CLEAR(initResponse->options, Z_Options_negotiationModel);
1845 // Delete negotiation (charneg-3) entry.
1846 yaz_del_charneg_record(otherInfo);
1851 if (m_proxy_negotiation_charset || m_proxy_negotiation_lang)
1853 yaz_log(YLOG_LOG, "%sTarget did not honor negotiation",
1856 else if (m_charset_converter->get_client_query_charset())
1858 Z_OtherInformation **otherInfo;
1859 Z_OtherInformationUnit *oi;
1860 get_otherInfoAPDU(apdu, &otherInfo);
1861 oi = update_otherInformation(otherInfo, 1, NULL, 0, 0);
1864 ODR_MASK_SET(initResponse->options,
1865 Z_Options_negotiationModel);
1866 ODR_MASK_SET(m_initRequest_options,
1867 Z_Options_negotiationModel);
1869 oi->which = Z_OtherInfo_externallyDefinedInfo;
1870 oi->information.externallyDefinedInfo =
1871 yaz_set_response_charneg(
1873 m_charset_converter->get_client_query_charset(),
1875 m_charset_converter->get_client_charset_selected());
1882 Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
1884 const char *addinfo)
1886 Z_Records *rec = (Z_Records *)
1887 odr_malloc (odr, sizeof(*rec));
1889 odr_malloc (odr, sizeof(*err));
1890 Z_DiagRec *drec = (Z_DiagRec *)
1891 odr_malloc (odr, sizeof(*drec));
1892 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1893 odr_malloc (odr, sizeof(*dr));
1895 rec->which = Z_Records_NSD;
1896 rec->u.nonSurrogateDiagnostic = dr;
1897 dr->diagnosticSetId =
1898 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1899 dr->condition = err;
1900 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1901 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1905 Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu)
1907 if (apdu->which == Z_APDU_searchRequest &&
1908 apdu->u.searchRequest->query &&
1909 apdu->u.searchRequest->query->which == Z_Query_type_104 &&
1910 apdu->u.searchRequest->query->u.type_104->which == Z_External_CQL)
1912 Z_RPNQuery *rpnquery = 0;
1913 Z_SearchRequest *sr = apdu->u.searchRequest;
1916 yaz_log(YLOG_LOG, "%sCQL: %s", m_session_str,
1917 sr->query->u.type_104->u.cql);
1919 int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
1920 &rpnquery, odr_encode(),
1923 yaz_log(YLOG_LOG, "%sNo CQL to RPN table", m_session_str);
1926 yaz_log(YLOG_LOG, "%sCQL Conversion error %d", m_session_str, r);
1927 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1929 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1930 new_apdu->u.searchResponse->records =
1931 create_nonSurrogateDiagnostics(odr_encode(),
1932 yaz_diag_srw_to_bib1(r),
1934 *new_apdu->u.searchResponse->searchStatus = 0;
1936 send_to_client(new_apdu);
1942 sr->query->which = Z_Query_type_1;
1943 sr->query->u.type_1 = rpnquery;
1950 Z_APDU *Yaz_Proxy::handle_target_charset_conversion(Z_APDU *apdu)
1952 if (apdu->which == Z_APDU_searchRequest &&
1953 apdu->u.searchRequest->query)
1955 if (apdu->u.searchRequest->query->which == Z_Query_type_1
1956 || apdu->u.searchRequest->query->which == Z_Query_type_101)
1959 m_charset_converter->set_client_query_charset("UTF-8");
1960 Z_RPNQuery *rpnquery = apdu->u.searchRequest->query->u.type_1;
1961 m_charset_converter->convert_type_1(rpnquery, odr_encode());
1968 Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
1970 if (apdu->which == Z_APDU_searchRequest)
1972 Z_SearchRequest *sr = apdu->u.searchRequest;
1976 Yaz_ProxyConfig *cfg = check_reconfigure();
1978 err = cfg->check_query(odr_encode(), m_default_target,
1979 sr->query, &addinfo);
1982 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
1984 new_apdu->u.searchResponse->referenceId = sr->referenceId;
1985 new_apdu->u.searchResponse->records =
1986 create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
1987 *new_apdu->u.searchResponse->searchStatus = 0;
1989 send_to_client(new_apdu);
1997 int Yaz_Proxy::handle_authentication(Z_APDU *apdu)
1999 if (apdu->which != Z_APDU_initRequest)
2000 return 1; // pass if no init request
2001 Z_InitRequest *req = apdu->u.initRequest;
2003 Yaz_ProxyConfig *cfg = check_reconfigure();
2005 return 1; // pass if no config
2008 if (req->idAuthentication == 0)
2010 ret = cfg->client_authentication(m_default_target, 0, 0, 0);
2012 else if (req->idAuthentication->which == Z_IdAuthentication_idPass)
2014 ret = cfg->client_authentication(m_default_target,
2015 req->idAuthentication->u.idPass->userId,
2016 req->idAuthentication->u.idPass->groupId,
2017 req->idAuthentication->u.idPass->password);
2019 else if (req->idAuthentication->which == Z_IdAuthentication_open)
2021 char user[64], pass[64];
2024 sscanf(req->idAuthentication->u.open, "%63[^/]/%63s", user, pass);
2025 ret = cfg->client_authentication(m_default_target, user, 0, pass);
2028 ret = cfg->client_authentication(m_default_target, 0, 0, 0);
2030 cfg->target_authentication(m_default_target, odr_encode(), req);
2035 Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
2037 m_marcxml_mode = none;
2038 if (apdu->which == Z_APDU_searchRequest)
2040 Z_SearchRequest *sr = apdu->u.searchRequest;
2043 Yaz_ProxyConfig *cfg = check_reconfigure();
2045 Z_RecordComposition rc_temp, *rc = 0;
2046 if (sr->smallSetElementSetNames)
2048 rc_temp.which = Z_RecordComp_simple;
2049 rc_temp.u.simple = sr->smallSetElementSetNames;
2053 if (sr->preferredRecordSyntax)
2056 ent = oid_getentbyoid(sr->preferredRecordSyntax);
2057 m_frontend_type = ent->value;
2060 m_frontend_type = VAL_NONE;
2062 char *stylesheet_name = 0;
2064 err = cfg->check_syntax(odr_encode(),
2066 sr->preferredRecordSyntax, rc,
2067 &addinfo, &stylesheet_name, &m_schema,
2068 &m_backend_type, &m_backend_charset,
2069 &m_usemarcon_ini_stage1,
2070 &m_usemarcon_ini_stage2);
2071 if (stylesheet_name)
2073 m_parent->low_socket_close();
2076 if (m_stylesheet_xsp)
2077 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
2078 m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
2081 m_stylesheet_offset = 0;
2082 xfree(stylesheet_name);
2084 m_parent->low_socket_open();
2088 sr->smallSetElementSetNames = 0;
2089 sr->mediumSetElementSetNames = 0;
2090 m_marcxml_mode = marcxml;
2094 sr->preferredRecordSyntax =
2095 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN,
2099 sr->preferredRecordSyntax =
2100 yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
2105 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
2107 new_apdu->u.searchResponse->referenceId = sr->referenceId;
2108 new_apdu->u.searchResponse->records =
2109 create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
2110 *new_apdu->u.searchResponse->searchStatus = 0;
2112 send_to_client(new_apdu);
2116 else if (m_backend_type)
2118 sr->preferredRecordSyntax =
2119 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN, m_backend_type);
2122 else if (apdu->which == Z_APDU_presentRequest)
2124 Z_PresentRequest *pr = apdu->u.presentRequest;
2127 Yaz_ProxyConfig *cfg = check_reconfigure();
2129 if (pr->preferredRecordSyntax)
2132 ent = oid_getentbyoid(pr->preferredRecordSyntax);
2133 m_frontend_type = ent->value;
2136 m_frontend_type = VAL_NONE;
2138 char *stylesheet_name = 0;
2140 err = cfg->check_syntax(odr_encode(), m_default_target,
2141 pr->preferredRecordSyntax,
2142 pr->recordComposition,
2143 &addinfo, &stylesheet_name, &m_schema,
2144 &m_backend_type, &m_backend_charset,
2145 &m_usemarcon_ini_stage1,
2146 &m_usemarcon_ini_stage2
2148 if (stylesheet_name)
2150 m_parent->low_socket_close();
2153 if (m_stylesheet_xsp)
2154 xsltFreeStylesheet((xsltStylesheetPtr) m_stylesheet_xsp);
2155 m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
2158 m_stylesheet_offset = 0;
2159 xfree(stylesheet_name);
2161 m_parent->low_socket_open();
2165 pr->recordComposition = 0;
2166 m_marcxml_mode = marcxml;
2170 pr->preferredRecordSyntax =
2171 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN,
2175 pr->preferredRecordSyntax =
2176 yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
2181 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
2183 new_apdu->u.presentResponse->referenceId = pr->referenceId;
2184 new_apdu->u.presentResponse->records =
2185 create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
2186 *new_apdu->u.presentResponse->presentStatus =
2187 Z_PresentStatus_failure;
2189 send_to_client(new_apdu);
2193 else if (m_backend_type)
2195 pr->preferredRecordSyntax =
2196 yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN, m_backend_type);
2202 Z_ElementSetNames *Yaz_Proxy::mk_esn_from_schema(ODR o, const char *schema)
2206 Z_ElementSetNames *esn = (Z_ElementSetNames *)
2207 odr_malloc(o, sizeof(Z_ElementSetNames));
2208 esn->which = Z_ElementSetNames_generic;
2209 esn->u.generic = odr_strdup(o, schema);
2213 void Yaz_Proxy::srw_get_client(const char *db, const char **backend_db)
2216 Yaz_ProxyConfig *cfg = check_reconfigure();
2218 t = cfg->get_explain_name(db, backend_db);
2220 if (m_client && m_default_target && t && strcmp(m_default_target, t))
2227 xfree(m_default_target);
2228 m_default_target = xstrdup(t);
2232 int Yaz_Proxy::file_access(Z_HTTP_Request *hreq)
2235 if (strcmp(hreq->method, "GET"))
2237 if (hreq->path[0] != '/')
2239 yaz_log(YLOG_WARN, "Bad path: %s", hreq->path);
2242 const char *cp = hreq->path;
2245 if (*cp == '/' && strchr("/.", cp[1]))
2247 yaz_log(YLOG_WARN, "Bad path: %s", hreq->path);
2252 const char *fname = hreq->path+1;
2253 if (stat(fname, &sbuf))
2255 yaz_log(YLOG_WARN|YLOG_ERRNO, "%s: stat failed", fname);
2258 if ((sbuf.st_mode & S_IFMT) != S_IFREG)
2260 yaz_log(YLOG_WARN, "%s: not a regular file", fname);
2263 if (sbuf.st_size > (off_t) 1000000)
2265 yaz_log(YLOG_WARN, "%s: too large for transfer", fname);
2269 ODR o = odr_encode();
2270 Yaz_ProxyConfig *cfg = check_reconfigure();
2271 const char *ctype = cfg->check_mime_type(fname);
2272 Z_GDU *gdu = z_get_HTTP_Response(o, 200);
2273 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
2275 hres->version = odr_strdup(o, m_http_version);
2276 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
2277 if (m_http_keepalive)
2278 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
2282 hres->content_len = sbuf.st_size;
2283 hres->content_buf = (char*) odr_malloc(o, hres->content_len);
2284 FILE *f = fopen(fname, "rb");
2287 fread(hres->content_buf, 1, hres->content_len, f);
2294 if (m_log_mask & PROXY_LOG_REQ_CLIENT)
2296 yaz_log (YLOG_LOG, "%sSending file %s to client", m_session_str,
2300 send_GDU(gdu, &len);
2304 void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
2308 odr_destroy(m_s2z_odr_init);
2311 if (m_s2z_odr_search)
2313 odr_destroy(m_s2z_odr_search);
2314 m_s2z_odr_search = 0;
2317 m_http_keepalive = 0;
2319 if (!strcmp(hreq->version, "1.0"))
2321 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
2322 if (v && !strcmp(v, "Keep-Alive"))
2323 m_http_keepalive = 1;
2325 m_http_keepalive = 0;
2326 m_http_version = "1.0";
2330 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
2331 if (v && !strcmp(v, "close"))
2332 m_http_keepalive = 0;
2334 m_http_keepalive = 1;
2335 m_http_version = "1.1";
2338 Z_SRW_PDU *srw_pdu = 0;
2339 Z_SOAP *soap_package = 0;
2341 Z_SRW_diagnostic *diagnostic = 0;
2342 int num_diagnostic = 0;
2344 if (file_access(hreq))
2348 else if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
2350 || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
2351 &charset, &diagnostic, &num_diagnostic) == 0)
2353 m_s2z_odr_init = odr_createmem(ODR_ENCODE);
2354 m_s2z_odr_search = odr_createmem(ODR_ENCODE);
2355 m_soap_ns = odr_strdup(m_s2z_odr_search, soap_package->ns);
2356 m_s2z_init_apdu = 0;
2357 m_s2z_search_apdu = 0;
2358 m_s2z_present_apdu = 0;
2360 m_s2z_stylesheet = 0;
2362 if (srw_pdu->which == Z_SRW_searchRetrieve_request)
2364 Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request;
2366 const char *backend_db = srw_req->database;
2367 srw_get_client(srw_req->database, &backend_db);
2369 m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
2370 // recordXPath unsupported.
2371 if (srw_req->recordXPath)
2373 yaz_add_srw_diagnostic(odr_decode(),
2374 &diagnostic, &num_diagnostic,
2378 if (srw_req->sort_type != Z_SRW_sort_type_none)
2380 yaz_add_srw_diagnostic(odr_decode(),
2381 &diagnostic, &num_diagnostic,
2385 if (srw_req->stylesheet)
2387 odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
2389 // set packing for response records ..
2390 if (srw_req->recordPacking &&
2391 !strcmp(srw_req->recordPacking, "xml"))
2392 m_s2z_packing = Z_SRW_recordPacking_XML;
2394 m_s2z_packing = Z_SRW_recordPacking_string;
2398 Z_SRW_PDU *srw_pdu =
2399 yaz_srw_get(odr_encode(),
2400 Z_SRW_searchRetrieve_response);
2401 Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
2403 srw_res->diagnostics = diagnostic;
2404 srw_res->num_diagnostics = num_diagnostic;
2405 send_srw_response(srw_pdu);
2409 // prepare search PDU
2410 m_s2z_search_apdu = zget_APDU(m_s2z_odr_search,
2411 Z_APDU_searchRequest);
2412 Z_SearchRequest *z_searchRequest =
2413 m_s2z_search_apdu->u.searchRequest;
2415 z_searchRequest->num_databaseNames = 1;
2416 z_searchRequest->databaseNames = (char**)
2417 odr_malloc(m_s2z_odr_search, sizeof(char *));
2418 z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr_search,
2421 // query transformation
2422 Z_Query *query = (Z_Query *)
2423 odr_malloc(m_s2z_odr_search, sizeof(Z_Query));
2424 z_searchRequest->query = query;
2426 if (srw_req->query_type == Z_SRW_query_type_cql)
2428 Z_External *ext = (Z_External *)
2429 odr_malloc(m_s2z_odr_search, sizeof(*ext));
2430 ext->direct_reference =
2431 odr_getoidbystr(m_s2z_odr_search, "1.2.840.10003.16.2");
2432 ext->indirect_reference = 0;
2433 ext->descriptor = 0;
2434 ext->which = Z_External_CQL;
2435 ext->u.cql = srw_req->query.cql;
2437 query->which = Z_Query_type_104;
2438 query->u.type_104 = ext;
2440 else if (srw_req->query_type == Z_SRW_query_type_pqf)
2442 Z_RPNQuery *RPNquery;
2443 YAZ_PQF_Parser pqf_parser;
2445 pqf_parser = yaz_pqf_create ();
2447 RPNquery = yaz_pqf_parse (pqf_parser, m_s2z_odr_search,
2448 srw_req->query.pqf);
2451 const char *pqf_msg;
2453 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
2454 yaz_log(YLOG_LOG, "%*s^\n", off+4, "");
2455 yaz_log(YLOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
2457 send_to_srw_client_error(10, 0);
2460 query->which = Z_Query_type_1;
2461 query->u.type_1 = RPNquery;
2463 yaz_pqf_destroy (pqf_parser);
2467 send_to_srw_client_error(7, "query");
2472 m_s2z_present_apdu = 0;
2474 if (srw_req->maximumRecords)
2475 max = *srw_req->maximumRecords;
2477 if (srw_req->startRecord)
2478 start = *srw_req->startRecord;
2481 // Some backend, such as Voyager doesn't honor piggyback
2482 // So we use present always (0 &&).
2483 if (0 && start <= 1) // Z39.50 piggyback
2485 *z_searchRequest->smallSetUpperBound = max;
2486 *z_searchRequest->mediumSetPresentNumber = max;
2487 *z_searchRequest->largeSetLowerBound = 2000000000; // 2e9
2489 z_searchRequest->preferredRecordSyntax =
2490 yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
2492 if (srw_req->recordSchema)
2494 z_searchRequest->smallSetElementSetNames =
2495 z_searchRequest->mediumSetElementSetNames =
2496 mk_esn_from_schema(m_s2z_odr_search,
2497 srw_req->recordSchema);
2500 else // Z39.50 present
2502 m_s2z_present_apdu = zget_APDU(m_s2z_odr_search,
2503 Z_APDU_presentRequest);
2504 Z_PresentRequest *z_presentRequest =
2505 m_s2z_present_apdu->u.presentRequest;
2506 *z_presentRequest->resultSetStartPoint = start;
2507 *z_presentRequest->numberOfRecordsRequested = max;
2508 z_presentRequest->preferredRecordSyntax =
2509 yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
2511 if (srw_req->recordSchema)
2513 z_presentRequest->recordComposition =
2514 (Z_RecordComposition *)
2515 odr_malloc(m_s2z_odr_search,
2516 sizeof(Z_RecordComposition));
2517 z_presentRequest->recordComposition->which =
2518 Z_RecordComp_simple;
2519 z_presentRequest->recordComposition->u.simple =
2520 mk_esn_from_schema(m_s2z_odr_search,
2521 srw_req->recordSchema);
2527 m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
2528 Z_APDU_initRequest);
2530 // prevent m_initRequest_apdu memory from being grabbed
2531 // in Yaz_Proxy::handle_incoming_Z_PDU
2532 m_initRequest_apdu = m_s2z_init_apdu;
2533 handle_incoming_Z_PDU(m_s2z_init_apdu);
2538 handle_incoming_Z_PDU(m_s2z_search_apdu);
2542 else if (srw_pdu->which == Z_SRW_explain_request)
2544 Z_SRW_explainRequest *srw_req = srw_pdu->u.explain_request;
2546 const char *backend_db = srw_req->database;
2547 srw_get_client(srw_req->database, &backend_db);
2549 m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
2552 if (srw_req->stylesheet)
2554 odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
2556 if (srw_req->recordPacking &&
2557 !strcmp(srw_req->recordPacking, "xml"))
2558 m_s2z_packing = Z_SRW_recordPacking_XML;
2560 m_s2z_packing = Z_SRW_recordPacking_string;
2564 send_srw_explain_response(diagnostic, num_diagnostic);
2570 m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
2571 Z_APDU_initRequest);
2573 // prevent m_initRequest_apdu memory from being grabbed
2574 // in Yaz_Proxy::handle_incoming_Z_PDU
2575 m_initRequest_apdu = m_s2z_init_apdu;
2576 handle_incoming_Z_PDU(m_s2z_init_apdu);
2579 send_srw_explain_response(0, 0);
2582 else if (srw_pdu->which == Z_SRW_scan_request)
2584 m_s2z_database = odr_strdup(m_s2z_odr_init,
2585 srw_pdu->u.scan_request->database);
2587 yaz_add_srw_diagnostic(odr_decode(),
2588 &diagnostic, &num_diagnostic,
2590 Z_SRW_PDU *srw_pdu =
2591 yaz_srw_get(odr_encode(),
2592 Z_SRW_scan_response);
2593 Z_SRW_scanResponse *srw_res = srw_pdu->u.scan_response;
2595 srw_res->diagnostics = diagnostic;
2596 srw_res->num_diagnostics = num_diagnostic;
2597 send_srw_response(srw_pdu);
2604 send_to_srw_client_error(4, 0);
2607 send_http_response(400);
2610 void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
2612 Z_ReferenceId **refid = get_referenceIdP(apdu);
2613 nmem_reset(m_referenceId_mem);
2614 if (refid && *refid)
2616 m_referenceId = (Z_ReferenceId *)
2617 nmem_malloc(m_referenceId_mem, sizeof(*m_referenceId));
2618 m_referenceId->len = m_referenceId->size = (*refid)->len;
2619 m_referenceId->buf = (unsigned char *)
2620 nmem_malloc(m_referenceId_mem, (*refid)->len);
2621 memcpy(m_referenceId->buf, (*refid)->buf, (*refid)->len);
2626 if (!m_client && m_invalid_session)
2628 m_apdu_invalid_session = apdu;
2629 m_mem_invalid_session = odr_extract_mem(odr_decode());
2630 apdu = m_initRequest_apdu;
2633 // Determine our client.
2634 Z_OtherInformation **oi;
2635 get_otherInfoAPDU(apdu, &oi);
2636 m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
2641 send_http_response(404);
2651 m_client->m_server = this;
2653 if (apdu->which == Z_APDU_initRequest)
2655 if (apdu->u.initRequest->implementationId)
2656 yaz_log(YLOG_LOG, "%simplementationId: %s",
2657 m_session_str, apdu->u.initRequest->implementationId);
2658 if (apdu->u.initRequest->implementationName)
2659 yaz_log(YLOG_LOG, "%simplementationName: %s",
2660 m_session_str, apdu->u.initRequest->implementationName);
2661 if (apdu->u.initRequest->implementationVersion)
2662 yaz_log(YLOG_LOG, "%simplementationVersion: %s",
2663 m_session_str, apdu->u.initRequest->implementationVersion);
2664 if (m_initRequest_apdu == 0)
2666 if (m_initRequest_mem)
2667 nmem_destroy(m_initRequest_mem);
2669 m_initRequest_apdu = apdu;
2670 m_initRequest_mem = odr_extract_mem(odr_decode());
2672 m_initRequest_preferredMessageSize = *apdu->u.initRequest->
2673 preferredMessageSize;
2674 *apdu->u.initRequest->preferredMessageSize = 1024*1024;
2675 m_initRequest_maximumRecordSize = *apdu->u.initRequest->
2677 *apdu->u.initRequest->maximumRecordSize = 1024*1024;
2679 // Save proposal charsets and langs.
2680 if (ODR_MASK_GET(apdu->u.initRequest->options,
2681 Z_Options_negotiationModel))
2683 Z_CharSetandLanguageNegotiation *charSetandLangRecord =
2684 yaz_get_charneg_record(*oi);
2686 yaz_get_proposal_charneg(m_referenceId_mem,
2687 charSetandLangRecord,
2688 &m_initRequest_oi_negotiation_charsets,
2689 &m_initRequest_oi_negotiation_num_charsets,
2690 &m_initRequest_oi_negotiation_langs,
2691 &m_initRequest_oi_negotiation_num_langs,
2692 &m_initRequest_oi_negotiation_selected);
2694 for (int i=0; i<m_initRequest_oi_negotiation_num_charsets; i++)
2696 yaz_log(YLOG_LOG, "%scharacters set proposal: %s",
2697 m_session_str,(m_initRequest_oi_negotiation_charsets[i])?
2698 m_initRequest_oi_negotiation_charsets[i]:"none");
2700 for (int i=0; i<m_initRequest_oi_negotiation_num_langs; i++)
2702 yaz_log(YLOG_LOG, "%slanguages proposal: %s",
2703 m_session_str, (m_initRequest_oi_negotiation_langs[i])?
2704 m_initRequest_oi_negotiation_langs[i]:"none");
2706 yaz_log(YLOG_LOG, "%sselected proposal: %d (boolean)",
2707 m_session_str, m_initRequest_oi_negotiation_selected);
2709 // save init options for the response..
2710 m_initRequest_options = apdu->u.initRequest->options;
2712 apdu->u.initRequest->options =
2713 (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
2714 sizeof(Odr_bitmask));
2715 ODR_MASK_ZERO(apdu->u.initRequest->options);
2717 for (i = 0; i<= 24; i++)
2718 ODR_MASK_SET(apdu->u.initRequest->options, i);
2719 // check negotiation option
2720 if (!ODR_MASK_GET(m_initRequest_options,
2721 Z_Options_negotiationModel))
2723 ODR_MASK_CLEAR(apdu->u.initRequest->options,
2724 Z_Options_negotiationModel);
2726 ODR_MASK_CLEAR(apdu->u.initRequest->options,
2727 Z_Options_concurrentOperations);
2729 m_initRequest_version = apdu->u.initRequest->protocolVersion;
2730 apdu->u.initRequest->protocolVersion =
2731 (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
2732 sizeof(Odr_bitmask));
2733 ODR_MASK_ZERO(apdu->u.initRequest->protocolVersion);
2735 for (i = 0; i<= 8; i++)
2736 ODR_MASK_SET(apdu->u.initRequest->protocolVersion, i);
2738 if (m_client->m_init_flag)
2740 if (handle_init_response_for_invalid_session(apdu))
2742 if (m_client->m_initResponse)
2744 Z_APDU *apdu2 = m_client->m_initResponse;
2745 apdu2->u.initResponse->otherInfo = 0;
2746 if (m_client->m_cookie && *m_client->m_cookie)
2747 set_otherInformationString(apdu2, VAL_COOKIE, 1,
2748 m_client->m_cookie);
2749 apdu2->u.initResponse->referenceId =
2750 apdu->u.initRequest->referenceId;
2751 apdu2->u.initResponse->options = m_client->m_initResponse_options;
2752 apdu2->u.initResponse->protocolVersion =
2753 m_client->m_initResponse_version;
2755 send_to_client(apdu2);
2759 m_client->m_init_flag = 1;
2762 if (!handle_authentication(apdu))
2764 Z_APDU *apdu_reject = zget_APDU(odr_encode(), Z_APDU_initResponse);
2765 *apdu_reject->u.initResponse->result = 0;
2766 send_to_client(apdu_reject);
2772 handle_max_record_retrieve(apdu);
2775 apdu = handle_syntax_validation(apdu);
2778 apdu = handle_query_transformation(apdu);
2781 apdu = handle_target_charset_conversion(apdu);
2784 apdu = handle_query_validation(apdu);
2787 apdu = result_set_optimize(apdu);
2791 m_client->timeout(m_target_idletime); // mark it active even
2792 // though we didn't use it
2795 // Add otherInformation entry in APDU if
2796 // negotiatoin in use.
2798 handle_charset_lang_negotiation(apdu);
2800 // delete other info construct completely if 0 elements
2801 get_otherInfoAPDU(apdu, &oi);
2802 if (oi && *oi && (*oi)->num_elements == 0)
2805 if (apdu->which == Z_APDU_presentRequest &&
2806 m_client->m_resultSetStartPoint == 0)
2808 Z_PresentRequest *pr = apdu->u.presentRequest;
2809 m_client->m_resultSetStartPoint = *pr->resultSetStartPoint;
2810 m_client->m_cache.copy_presentRequest(apdu->u.presentRequest);
2812 m_client->m_resultSetStartPoint = 0;
2814 if (m_client->send_to_target(apdu) < 0)
2821 m_client->m_waiting = 1;
2824 void Yaz_Proxy::connectNotify()
2828 void Yaz_Proxy::releaseClient()
2830 xfree(m_proxyTarget);
2832 m_invalid_session = 0;
2833 // only keep if keep_alive flag is set...
2835 m_client->m_pdu_recv < m_keepalive_limit_pdu &&
2836 m_client->m_bytes_recv+m_client->m_bytes_sent < m_keepalive_limit_bw &&
2837 m_client->m_waiting == 0)
2839 yaz_log(YLOG_LOG, "%sShutdown (client to proxy) keepalive %s",
2841 m_client->get_hostname());
2842 yaz_log(YLOG_LOG, "%sbw=%d pdu=%d limit-bw=%d limit-pdu=%d",
2843 m_session_str, m_client->m_pdu_recv,
2844 m_client->m_bytes_sent + m_client->m_bytes_recv,
2845 m_keepalive_limit_bw, m_keepalive_limit_pdu);
2846 assert (m_client->m_waiting != 2);
2847 // Tell client (if any) that no server connection is there..
2848 m_client->m_server = 0;
2853 yaz_log (YLOG_LOG, "%sShutdown (client to proxy) close %s",
2855 m_client->get_hostname());
2856 assert (m_client->m_waiting != 2);
2862 yaz_log (YLOG_LOG, "%sshutdown (client to proxy) bad state",
2868 yaz_log (YLOG_LOG, "%sShutdown (client to proxy)",
2872 m_parent->pre_init();
2875 void Yaz_Proxy::shutdown()
2881 const char *Yaz_ProxyClient::get_session_str()
2885 return m_server->get_session_str();
2888 void Yaz_ProxyClient::shutdown()
2890 yaz_log (YLOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(),
2896 void Yaz_Proxy::failNotify()
2899 yaz_log (YLOG_LOG, "%sConnection closed by client",
2904 void Yaz_ProxyClient::failNotify()
2907 m_server->inc_request_no();
2908 yaz_log (YLOG_LOG, "%sConnection closed by target %s",
2909 get_session_str(), get_hostname());
2913 void Yaz_ProxyClient::connectNotify()
2915 const char *s = get_session_str();
2916 const char *h = get_hostname();
2917 yaz_log (YLOG_LOG, "%sConnection accepted by %s timeout=%d", s, h,
2919 timeout(m_target_idletime);
2924 IYaz_PDU_Observer *Yaz_ProxyClient::sessionNotify(IYaz_PDU_Observable
2925 *the_PDU_Observable, int fd)
2927 return new Yaz_ProxyClient(the_PDU_Observable, 0);
2930 Yaz_ProxyClient::~Yaz_ProxyClient()
2935 m_next->m_prev = m_prev;
2936 m_waiting = 2; // for debugging purposes only.
2937 odr_destroy(m_init_odr);
2938 delete m_last_query;
2939 xfree (m_last_resultSetId);
2943 void Yaz_ProxyClient::pre_init_client()
2945 Z_APDU *apdu = create_Z_PDU(Z_APDU_initRequest);
2946 Z_InitRequest *req = apdu->u.initRequest;
2949 for (i = 0; i<= 24; i++)
2950 ODR_MASK_SET(req->options, i);
2951 ODR_MASK_CLEAR(apdu->u.initRequest->options,
2952 Z_Options_negotiationModel);
2953 ODR_MASK_CLEAR(apdu->u.initRequest->options,
2954 Z_Options_concurrentOperations);
2955 for (i = 0; i<= 10; i++)
2956 ODR_MASK_SET(req->protocolVersion, i);
2958 if (send_to_target(apdu) < 0)
2969 void Yaz_Proxy::pre_init()
2972 const char *name = 0;
2973 const char *zurl_in_use[MAX_ZURL_PLEX];
2974 int limit_bw, limit_pdu, limit_req;
2975 int target_idletime, client_idletime;
2977 int keepalive_limit_bw, keepalive_limit_pdu;
2979 const char *cql2rpn = 0;
2980 const char *authentication = 0;
2981 const char *negotiation_charset = 0;
2982 const char *negotiation_lang = 0;
2984 Yaz_ProxyConfig *cfg = check_reconfigure();
2988 if (m_log_mask & PROXY_LOG_APDU_CLIENT)
2993 for (i = 0; cfg && cfg->get_target_no(i, &name, zurl_in_use,
2994 &limit_bw, &limit_pdu, &limit_req,
2995 &target_idletime, &client_idletime,
2997 &keepalive_limit_bw,
2998 &keepalive_limit_pdu,
3002 &negotiation_charset,
3009 for (j = 0; zurl_in_use[j]; j++)
3013 int spare_waiting = 0;
3016 for (c = m_clientPool; c; c = c->m_next)
3018 if (!strcmp(zurl_in_use[j], c->get_hostname()))
3020 if (c->m_cookie == 0)
3022 if (c->m_server == 0)
3034 yaz_log(YLOG_LOG, "%spre-init %s %s use=%d other=%d spare=%d "
3035 "sparew=%d preinit=%d",m_session_str,
3036 name, zurl_in_use[j], in_use, other,
3037 spare, spare_waiting, pre_init);
3038 if (spare + spare_waiting < pre_init)
3040 c = new Yaz_ProxyClient(m_PDU_Observable->clone(), this);
3041 c->m_next = m_clientPool;
3043 c->m_next->m_prev = &c->m_next;
3045 c->m_prev = &m_clientPool;
3047 if (m_log_mask & PROXY_LOG_APDU_SERVER)
3048 c->set_APDU_yazlog(1);
3050 c->set_APDU_yazlog(0);
3052 if (c->client(zurl_in_use[j]))
3060 c->m_target_idletime = target_idletime;
3061 c->m_seqno = m_seqno++;
3068 void Yaz_Proxy::timeoutNotify()
3074 timeout(m_client_idletime);
3075 Z_GDU *apdu = m_bw_hold_PDU;
3078 if (apdu->which == Z_GDU_Z3950)
3079 handle_incoming_Z_PDU(apdu->u.z3950);
3080 else if (apdu->which == Z_GDU_HTTP_Request)
3081 handle_incoming_HTTP(apdu->u.HTTP_Request);
3083 else if (m_stylesheet_nprl)
3084 convert_xsl_delay();
3089 yaz_log (YLOG_LOG, "%sTimeout (client to proxy)", m_session_str);
3100 void Yaz_Proxy::markInvalid()
3103 m_invalid_session = 1;
3106 void Yaz_ProxyClient::timeoutNotify()
3109 m_server->inc_request_no();
3111 yaz_log (YLOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(),
3115 if (m_server && m_init_flag)
3117 // target timed out in a session that was properly initialized
3118 // server object stay alive but we mark it as invalid so it
3119 // gets initialized again
3120 m_server->markInvalid();
3126 Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable,
3127 Yaz_Proxy *parent) :
3128 Yaz_Z_Assoc (the_PDU_Observable)
3135 m_last_resultSetId = 0;
3136 m_last_resultCount = 0;
3140 m_init_odr = odr_createmem (ODR_DECODE);
3142 m_initResponse_options = 0;
3143 m_initResponse_version = 0;
3144 m_initResponse_preferredMessageSize = 0;
3145 m_initResponse_maximumRecordSize = 0;
3146 m_resultSetStartPoint = 0;
3147 m_bytes_sent = m_bytes_recv = 0;
3151 m_target_idletime = 600;
3155 const char *Yaz_Proxy::option(const char *name, const char *value)
3157 if (!strcmp (name, "optimize")) {
3160 m_optimize = xstrdup (value);
3167 void Yaz_ProxyClient::recv_HTTP_response(Z_HTTP_Response *apdu, int len)
3172 void Yaz_ProxyClient::recv_GDU(Z_GDU *apdu, int len)
3174 if (apdu->which == Z_GDU_Z3950)
3175 recv_Z_PDU(apdu->u.z3950, len);
3176 else if (apdu->which == Z_GDU_HTTP_Response)
3177 recv_HTTP_response(apdu->u.HTTP_Response, len);
3182 int Yaz_Proxy::handle_init_response_for_invalid_session(Z_APDU *apdu)
3184 if (!m_invalid_session)
3186 m_invalid_session = 0;
3187 handle_incoming_Z_PDU(m_apdu_invalid_session);
3188 assert (m_mem_invalid_session);
3189 nmem_destroy(m_mem_invalid_session);
3190 m_mem_invalid_session = 0;
3194 void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
3196 m_bytes_recv += len;
3200 if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
3201 yaz_log (YLOG_LOG, "%sReceiving %s from %s %d bytes", get_session_str(),
3202 apdu_name(apdu), get_hostname(), len);
3203 if (apdu->which == Z_APDU_initResponse)
3205 if (!m_server) // if this is a pre init session , check for more
3207 NMEM nmem = odr_extract_mem (odr_decode());
3208 odr_reset (m_init_odr);
3209 nmem_transfer (m_init_odr->mem, nmem);
3210 m_initResponse = apdu;
3211 m_initResponse_options = apdu->u.initResponse->options;
3212 m_initResponse_version = apdu->u.initResponse->protocolVersion;
3213 m_initResponse_preferredMessageSize =
3214 *apdu->u.initResponse->preferredMessageSize;
3215 m_initResponse_maximumRecordSize =
3216 *apdu->u.initResponse->maximumRecordSize;
3218 Z_InitResponse *ir = apdu->u.initResponse;
3219 char *im0 = ir->implementationName;
3222 odr_malloc(m_init_odr, 20 + (im0 ? strlen(im0) : 0));
3229 strcat(im1, "(YAZ Proxy)");
3230 ir->implementationName = im1;
3232 nmem_destroy (nmem);
3234 if (m_server && m_server->handle_init_response_for_invalid_session(apdu))
3237 if (apdu->which == Z_APDU_searchResponse)
3239 Z_SearchResponse *sr = apdu->u.searchResponse;
3240 m_last_resultCount = *sr->resultCount;
3241 int status = *sr->searchStatus;
3242 if (status && (!sr->records || sr->records->which == Z_Records_DBOSD))
3246 if (sr->records && sr->records->which == Z_Records_DBOSD)
3248 m_cache.add(odr_decode(),
3249 sr->records->u.databaseOrSurDiagnostics, 1,
3254 if (apdu->which == Z_APDU_presentResponse)
3256 Z_PresentResponse *pr = apdu->u.presentResponse;
3260 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
3261 Z_SearchResponse *sr = new_apdu->u.searchResponse;
3262 sr->referenceId = pr->referenceId;
3263 *sr->resultCount = m_last_resultCount;
3264 sr->records = pr->records;
3265 sr->nextResultSetPosition = pr->nextResultSetPosition;
3266 sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
3270 pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
3272 m_cache.add(odr_decode(),
3273 pr->records->u.databaseOrSurDiagnostics,
3274 m_resultSetStartPoint, -1);
3275 m_resultSetStartPoint = 0;
3279 set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
3282 m_server->send_to_client(apdu);
3284 if (apdu->which == Z_APDU_close)
3290 void Yaz_Proxy::low_socket_close()
3295 for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
3296 if (m_lo_fd[i] >= 0)
3297 ::close(m_lo_fd[i]);
3301 void Yaz_Proxy::low_socket_open()
3306 for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
3307 m_lo_fd[i] = open("/dev/null", O_RDONLY);
3311 int Yaz_Proxy::server(const char *addr)
3313 int r = Yaz_Z_Assoc::server(addr);
3316 yaz_log(YLOG_LOG, "%sStarted proxy "
3320 " on %s", m_session_str, addr);