2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.14 2004-01-07 20:36:44 adam Exp $
9 * Frontend server logic.
11 * This code receives incoming APDUs, and handles client requests by means
14 * Some of the code is getting quite involved, compared to simpler servers -
15 * primarily because it is asynchronous both in the communication with
16 * the user and the backend. We think the complexity will pay off in
17 * the form of greater flexibility when more asynchronous facilities
20 * Memory management has become somewhat involved. In the simple case, where
21 * only one PDU is pending at a time, it will simply reuse the same memory,
22 * once it has found its working size. When we enable multiple concurrent
23 * operations, perhaps even with multiple parallel calls to the backend, it
24 * will maintain a pool of buffers for encoding and decoding, trying to
25 * minimize memory allocation/deallocation during normal operation.
31 #include <sys/types.h>
34 #define S_ISREG(x) (x & _S_IFREG)
44 #include <yaz/yconfig.h>
45 #include <yaz/xmalloc.h>
46 #include <yaz/comstack.h>
49 #include <yaz/proto.h>
52 #include <yaz/logrpn.h>
53 #include <yaz/statserv.h>
54 #include <yaz/diagbib1.h>
55 #include <yaz/charneg.h>
56 #include <yaz/otherinfo.h>
57 #include <yaz/yaz-util.h>
58 #include <yaz/pquery.h>
61 #include <yaz/backend.h>
63 static void process_gdu_request(association *assoc, request *req);
64 static int process_z_request(association *assoc, request *req, char **msg);
65 void backend_response(IOCHAN i, int event);
66 static int process_gdu_response(association *assoc, request *req, Z_GDU *res);
67 static int process_z_response(association *assoc, request *req, Z_APDU *res);
68 static Z_APDU *process_initRequest(association *assoc, request *reqb);
69 static Z_External *init_diagnostics(ODR odr, int errcode, char *errstring);
70 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
72 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
73 bend_search_rr *bsrr, int *fd);
74 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
76 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
77 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
78 static void process_close(association *assoc, request *reqb);
79 void save_referenceId (request *reqb, Z_ReferenceId *refid);
80 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
82 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
84 static FILE *apduf = 0; /* for use in static mode */
85 static statserv_options_block *control_block = 0;
87 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
90 * Create and initialize a new association-handle.
91 * channel : iochannel for the current line.
92 * link : communications channel.
93 * Returns: 0 or a new association handle.
95 association *create_association(IOCHAN channel, COMSTACK link)
100 control_block = statserv_getcontrol();
101 if (!(anew = (association *)xmalloc(sizeof(*anew))))
105 anew->client_chan = channel;
106 anew->client_link = link;
107 anew->cs_get_mask = 0;
108 anew->cs_put_mask = 0;
109 anew->cs_accept_mask = 0;
110 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
111 !(anew->encode = odr_createmem(ODR_ENCODE)))
113 if (*control_block->apdufile)
118 strcpy(filename, control_block->apdufile);
119 if (!(anew->print = odr_createmem(ODR_PRINT)))
121 if (*control_block->apdufile == '@')
123 odr_setprint(anew->print, yaz_log_file());
125 else if (*control_block->apdufile != '-')
127 strcpy(filename, control_block->apdufile);
128 if (!control_block->dynamic)
132 if (!(apduf = fopen(filename, "w")))
134 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
137 setvbuf(apduf, 0, _IONBF, 0);
143 sprintf(filename + strlen(filename), ".%d", getpid());
144 if (!(f = fopen(filename, "w")))
146 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
149 setvbuf(f, 0, _IONBF, 0);
151 odr_setprint(anew->print, f);
156 anew->input_buffer = 0;
157 anew->input_buffer_len = 0;
159 anew->state = ASSOC_NEW;
160 request_initq(&anew->incoming);
161 request_initq(&anew->outgoing);
162 anew->proto = cs_getproto(link);
167 * Free association and release resources.
169 void destroy_association(association *h)
171 statserv_options_block *cb = statserv_getcontrol();
175 odr_destroy(h->decode);
176 odr_destroy(h->encode);
178 odr_destroy(h->print);
180 xfree(h->input_buffer);
182 (*cb->bend_close)(h->backend);
183 while ((req = request_deq(&h->incoming)))
184 request_release(req);
185 while ((req = request_deq(&h->outgoing)))
186 request_release(req);
187 request_delq(&h->incoming);
188 request_delq(&h->outgoing);
190 xmalloc_trav("session closed");
191 if (control_block && control_block->one_shot)
197 static void do_close_req(association *a, int reason, char *message,
201 Z_Close *cls = zget_Close(a->encode);
203 /* Purge request queue */
204 while (request_deq(&a->incoming));
205 while (request_deq(&a->outgoing));
208 yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
209 reason, message ? message : "none");
210 apdu.which = Z_APDU_close;
212 *cls->closeReason = reason;
213 cls->diagnosticInformation = message;
214 process_z_response(a, req, &apdu);
215 iochan_settimeout(a->client_chan, 20);
219 request_release(req);
220 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
221 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
223 a->state = ASSOC_DEAD;
226 static void do_close(association *a, int reason, char *message)
228 request *req = request_get(&a->outgoing);
229 do_close_req (a, reason, message, req);
233 * This is where PDUs from the client are read and the further
234 * processing is initiated. Flow of control moves down through the
235 * various process_* functions below, until the encoded result comes back up
236 * to the output handler in here.
238 * h : the I/O channel that has an outstanding event.
239 * event : the current outstanding event.
241 void ir_session(IOCHAN h, int event)
244 association *assoc = (association *)iochan_getdata(h);
245 COMSTACK conn = assoc->client_link;
248 assert(h && conn && assoc);
249 if (event == EVENT_TIMEOUT)
251 if (assoc->state != ASSOC_UP)
253 yaz_log(LOG_LOG, "Final timeout - closing connection.");
255 destroy_association(assoc);
260 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
261 do_close(assoc, Z_Close_lackOfActivity, 0);
265 if (event & assoc->cs_accept_mask)
267 yaz_log (LOG_DEBUG, "ir_session (accept)");
268 if (!cs_accept (conn))
270 yaz_log (LOG_LOG, "accept failed");
271 destroy_association(assoc);
274 iochan_clearflag (h, EVENT_OUTPUT);
275 if (conn->io_pending)
276 { /* cs_accept didn't complete */
277 assoc->cs_accept_mask =
278 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
279 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
281 iochan_setflag (h, assoc->cs_accept_mask);
284 { /* cs_accept completed. Prepare for reading (cs_get) */
285 assoc->cs_accept_mask = 0;
286 assoc->cs_get_mask = EVENT_INPUT;
287 iochan_setflag (h, assoc->cs_get_mask);
291 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
293 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
295 yaz_log(LOG_DEBUG, "ir_session (input)");
296 /* We aren't speaking to this fellow */
297 if (assoc->state == ASSOC_DEAD)
299 yaz_log(LOG_LOG, "Connection closed - end of session");
301 destroy_association(assoc);
305 assoc->cs_get_mask = EVENT_INPUT;
306 if ((res = cs_get(conn, &assoc->input_buffer,
307 &assoc->input_buffer_len)) <= 0)
309 yaz_log(LOG_LOG, "Connection closed by client");
311 destroy_association(assoc);
315 else if (res == 1) /* incomplete read - wait for more */
317 if (conn->io_pending & CS_WANT_WRITE)
318 assoc->cs_get_mask |= EVENT_OUTPUT;
319 iochan_setflag(h, assoc->cs_get_mask);
322 if (cs_more(conn)) /* more stuff - call us again later, please */
323 iochan_setevent(h, EVENT_INPUT);
325 /* we got a complete PDU. Let's decode it */
326 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
327 assoc->input_buffer[0] & 0xff,
328 assoc->input_buffer[1] & 0xff,
329 assoc->input_buffer[2] & 0xff);
330 req = request_get(&assoc->incoming); /* get a new request */
331 odr_reset(assoc->decode);
332 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
333 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
335 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
337 odr_errmsg(odr_geterror(assoc->decode)),
338 odr_getelement(assoc->decode),
339 odr_offset(assoc->decode));
340 if (assoc->decode->error != OHTTP)
342 yaz_log(LOG_LOG, "PDU dump:");
343 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
344 request_release(req);
345 do_close(assoc, Z_Close_protocolError,"Malformed package");
349 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
350 assoc->state = ASSOC_DEAD;
351 process_gdu_response(assoc, req, p);
355 req->request_mem = odr_extract_mem(assoc->decode);
358 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
359 yaz_log(LOG_WARN, "ODR print error: %s",
360 odr_errmsg(odr_geterror(assoc->print)));
361 odr_reset(assoc->print);
363 request_enq(&assoc->incoming, req);
366 /* can we do something yet? */
367 req = request_head(&assoc->incoming);
368 if (req->state == REQUEST_IDLE)
370 request_deq(&assoc->incoming);
371 process_gdu_request(assoc, req);
374 if (event & assoc->cs_put_mask)
376 request *req = request_head(&assoc->outgoing);
378 assoc->cs_put_mask = 0;
379 yaz_log(LOG_DEBUG, "ir_session (output)");
380 req->state = REQUEST_PENDING;
381 switch (res = cs_put(conn, req->response, req->len_response))
384 yaz_log(LOG_LOG, "Connection closed by client");
386 destroy_association(assoc);
389 case 0: /* all sent - release the request structure */
390 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
392 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
395 nmem_destroy(req->request_mem);
396 request_deq(&assoc->outgoing);
397 request_release(req);
398 if (!request_head(&assoc->outgoing))
399 { /* restore mask for cs_get operation ... */
400 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
401 iochan_setflag(h, assoc->cs_get_mask);
402 if (assoc->state == ASSOC_DEAD)
403 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
407 assoc->cs_put_mask = EVENT_OUTPUT;
411 if (conn->io_pending & CS_WANT_WRITE)
412 assoc->cs_put_mask |= EVENT_OUTPUT;
413 if (conn->io_pending & CS_WANT_READ)
414 assoc->cs_put_mask |= EVENT_INPUT;
415 iochan_setflag(h, assoc->cs_put_mask);
418 if (event & EVENT_EXCEPT)
420 yaz_log(LOG_LOG, "ir_session (exception)");
422 destroy_association(assoc);
427 static int process_z_request(association *assoc, request *req, char **msg);
429 static void assoc_init_reset(association *assoc)
432 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
434 assoc->init->stream = assoc->encode;
435 assoc->init->print = assoc->print;
436 assoc->init->auth = 0;
437 assoc->init->referenceId = 0;
438 assoc->init->implementation_version = 0;
439 assoc->init->implementation_id = 0;
440 assoc->init->implementation_name = 0;
441 assoc->init->bend_sort = NULL;
442 assoc->init->bend_search = NULL;
443 assoc->init->bend_present = NULL;
444 assoc->init->bend_esrequest = NULL;
445 assoc->init->bend_delete = NULL;
446 assoc->init->bend_scan = NULL;
447 assoc->init->bend_segment = NULL;
448 assoc->init->bend_fetch = NULL;
449 assoc->init->bend_explain = NULL;
451 assoc->init->charneg_request = NULL;
452 assoc->init->charneg_response = NULL;
454 assoc->init->decode = assoc->decode;
455 assoc->init->peer_name =
456 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
459 static int srw_bend_init(association *assoc)
461 const char *encoding = "UTF-8";
463 bend_initresult *binitres;
464 statserv_options_block *cb = statserv_getcontrol();
466 assoc_init_reset(assoc);
468 assoc->maximumRecordSize = 3000000;
469 assoc->preferredMessageSize = 3000000;
471 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
472 assoc->init->charneg_request = ce->u.charNeg3;
474 if (!(binitres = (*cb->bend_init)(assoc->init)))
476 yaz_log(LOG_WARN, "Bad response from backend.");
479 assoc->backend = binitres->handle;
483 static int srw_bend_fetch(association *assoc, int pos,
484 Z_SRW_searchRetrieveRequest *srw_req,
485 Z_SRW_record *record)
488 ODR o = assoc->encode;
490 rr.setname = "default";
493 rr.request_format = VAL_TEXT_XML;
494 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
497 rr.comp = (Z_RecordComposition *)
498 odr_malloc(assoc->decode, sizeof(*rr.comp));
499 rr.comp->which = Z_RecordComp_complex;
500 rr.comp->u.complex = (Z_CompSpec *)
501 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
502 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
503 odr_malloc(assoc->encode, sizeof(bool_t));
504 *rr.comp->u.complex->selectAlternativeSyntax = 0;
505 rr.comp->u.complex->num_dbSpecific = 0;
506 rr.comp->u.complex->dbSpecific = 0;
507 rr.comp->u.complex->num_recordSyntax = 0;
508 rr.comp->u.complex->recordSyntax = 0;
510 rr.comp->u.complex->generic = (Z_Specification *)
511 odr_malloc(assoc->decode, sizeof(Z_Specification));
512 rr.comp->u.complex->generic->which = Z_Schema_uri;
513 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
514 rr.comp->u.complex->generic->elementSpec = 0;
516 rr.stream = assoc->encode;
517 rr.print = assoc->print;
523 rr.output_format = VAL_TEXT_XML;
524 rr.output_format_raw = 0;
527 rr.surrogate_flag = 0;
528 rr.schema = srw_req->recordSchema;
530 if (!assoc->init->bend_fetch)
533 (*assoc->init->bend_fetch)(assoc->backend, &rr);
537 record->recordData_buf = rr.record;
538 record->recordData_len = rr.len;
539 record->recordPosition = odr_intdup(o, pos);
541 record->recordSchema = odr_strdup(o, rr.schema);
543 record->recordSchema = 0;
548 static void srw_bend_search(association *assoc, request *req,
549 Z_SRW_searchRetrieveRequest *srw_req,
550 Z_SRW_searchRetrieveResponse *srw_res,
558 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
559 yaz_log(LOG_DEBUG, "srw_bend_search");
562 yaz_log(LOG_DEBUG, "srw_bend_init");
563 if (!srw_bend_init(assoc))
565 srw_error = 3; /* assume Authentication error */
567 srw_res->num_diagnostics = 1;
568 srw_res->diagnostics = (Z_SRW_diagnostic *)
569 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
570 srw_res->diagnostics[0].code =
571 odr_intdup(assoc->encode, srw_error);
572 srw_res->diagnostics[0].details = 0;
577 rr.setname = "default";
580 rr.basenames = &srw_req->database;
583 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
585 if (srw_req->query_type == Z_SRW_query_type_cql)
587 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
588 ext->direct_reference = odr_getoidbystr(assoc->decode,
589 "1.2.840.10003.16.2");
590 ext->indirect_reference = 0;
592 ext->which = Z_External_CQL;
593 ext->u.cql = srw_req->query.cql;
595 rr.query->which = Z_Query_type_104;
596 rr.query->u.type_104 = ext;
598 else if (srw_req->query_type == Z_SRW_query_type_pqf)
600 Z_RPNQuery *RPNquery;
601 YAZ_PQF_Parser pqf_parser;
603 pqf_parser = yaz_pqf_create ();
605 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
611 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
612 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
613 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
618 rr.query->which = Z_Query_type_1;
619 rr.query->u.type_1 = RPNquery;
621 yaz_pqf_destroy (pqf_parser);
626 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
629 if (!srw_error && !assoc->init->bend_search)
634 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
635 srw_res->num_diagnostics = 1;
636 srw_res->diagnostics = (Z_SRW_diagnostic *)
637 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
638 srw_res->diagnostics[0].code =
639 odr_intdup(assoc->encode, srw_error);
640 srw_res->diagnostics[0].details = 0;
644 rr.stream = assoc->encode;
645 rr.decode = assoc->decode;
646 rr.print = assoc->print;
648 rr.association = assoc;
654 yaz_log_zquery(rr.query);
655 (assoc->init->bend_search)(assoc->backend, &rr);
656 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
659 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
660 if (rr.errcode == 109) /* database unavailable */
665 srw_res->num_diagnostics = 1;
666 srw_res->diagnostics = (Z_SRW_diagnostic *)
667 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
668 srw_res->diagnostics[0].code =
669 odr_intdup(assoc->encode,
670 yaz_diag_bib1_to_srw (rr.errcode));
671 srw_res->diagnostics[0].details = rr.errstring;
672 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
673 *srw_res->diagnostics[0].code);
678 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
679 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
681 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
682 start, number, rr.hits);
684 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
691 yaz_log(LOG_LOG, "Request out or range");
696 int packing = Z_SRW_recordPacking_string;
697 if (start + number > rr.hits)
698 number = rr.hits - start + 1;
699 if (srw_req->recordPacking &&
700 !strcmp(srw_req->recordPacking, "xml"))
701 packing = Z_SRW_recordPacking_XML;
702 srw_res->records = (Z_SRW_record *)
703 odr_malloc(assoc->encode,
704 number * sizeof(*srw_res->records));
705 for (i = 0; i<number; i++)
709 srw_res->records[j].recordPacking = packing;
710 srw_res->records[j].recordData_buf = 0;
711 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
712 errcode = srw_bend_fetch(assoc, i+start, srw_req,
713 srw_res->records + j);
716 srw_res->num_diagnostics = 1;
717 srw_res->diagnostics = (Z_SRW_diagnostic *)
718 odr_malloc(assoc->encode,
719 sizeof(*srw_res->diagnostics));
720 srw_res->diagnostics[0].code =
721 odr_intdup(assoc->encode,
722 yaz_diag_bib1_to_srw (errcode));
723 srw_res->diagnostics[0].details = rr.errstring;
726 if (srw_res->records[j].recordData_buf)
729 srw_res->num_records = j;
731 srw_res->records = 0;
737 static void srw_bend_explain(association *assoc, request *req,
738 Z_SRW_explainRequest *srw_req,
739 Z_SRW_explainResponse *srw_res,
742 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
746 yaz_log(LOG_DEBUG, "srw_bend_init");
747 if (!srw_bend_init(assoc))
752 if (assoc->init && assoc->init->bend_explain)
756 rr.stream = assoc->encode;
757 rr.decode = assoc->decode;
758 rr.print = assoc->print;
760 rr.database = srw_req->database;
761 (*assoc->init->bend_explain)(assoc->backend, &rr);
764 int packing = Z_SRW_recordPacking_string;
765 if (srw_req->recordPacking &&
766 !strcmp(srw_req->recordPacking, "xml"))
767 packing = Z_SRW_recordPacking_XML;
768 srw_res->record.recordSchema = 0;
769 srw_res->record.recordPacking = packing;
770 srw_res->record.recordData_buf = rr.explain_buf;
771 srw_res->record.recordData_len = strlen(rr.explain_buf);
772 srw_res->record.recordPosition = 0;
778 static void process_http_request(association *assoc, request *req)
780 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
781 ODR o = assoc->encode;
784 Z_SOAP *soap_package = 0;
787 Z_HTTP_Response *hres;
789 char *stylesheet = 0;
791 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
792 if (r == 2) /* not taken */
793 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
794 if (r == 0) /* decode SRW/SRU OK .. */
797 if (sr->which == Z_SRW_searchRetrieve_request)
800 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
802 stylesheet = sr->u.request->stylesheet;
803 srw_bend_search(assoc, req, sr->u.request, res->u.response,
805 if (http_code == 200)
806 soap_package->u.generic->p = res;
808 else if (sr->which == Z_SRW_explain_request)
810 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
811 stylesheet = sr->u.explain_request->stylesheet;
812 srw_bend_explain(assoc, req, sr->u.explain_request,
813 res->u.explain_response, &http_code);
814 if (http_code == 200)
815 soap_package->u.generic->p = res;
820 z_soap_error(assoc->encode, soap_package,
821 "SOAP-ENV:Client", "Bad method", 0);
823 if (http_code == 200 || http_code == 500)
825 static Z_SOAP_Handler soap_handlers[3] = {
827 {"http://www.loc.gov/zing/srw/", 0,
828 (Z_SOAP_fun) yaz_srw_codec},
829 {"http://www.loc.gov/zing/srw/v1.0/", 0,
830 (Z_SOAP_fun) yaz_srw_codec},
836 p = z_get_HTTP_Response(o, 200);
837 hres = p->u.HTTP_Response;
838 ret = z_soap_codec_enc(assoc->encode, &soap_package,
839 &hres->content_buf, &hres->content_len,
840 soap_handlers, charset, stylesheet);
841 hres->code = http_code;
843 strcpy(ctype, "text/xml");
846 strcat(ctype, "; charset=");
847 strcat(ctype, charset);
849 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
852 p = z_get_HTTP_Response(o, http_code);
855 p = z_get_HTTP_Response(o, 500);
856 hres = p->u.HTTP_Response;
857 if (!strcmp(hreq->version, "1.0"))
859 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
860 if (v && !strcmp(v, "Keep-Alive"))
864 hres->version = "1.0";
868 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
869 if (v && !strcmp(v, "close"))
873 hres->version = "1.1";
877 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
878 assoc->state = ASSOC_DEAD;
879 assoc->cs_get_mask = 0;
884 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
886 if (alive && isdigit(*alive))
890 if (t < 0 || t > 3600)
892 iochan_settimeout(assoc->client_chan,t);
893 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
895 process_gdu_response(assoc, req, p);
898 static void process_gdu_request(association *assoc, request *req)
900 if (req->gdu_request->which == Z_GDU_Z3950)
903 req->apdu_request = req->gdu_request->u.z3950;
904 if (process_z_request(assoc, req, &msg) < 0)
905 do_close_req(assoc, Z_Close_systemProblem, msg, req);
907 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
908 process_http_request(assoc, req);
911 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
916 * Initiate request processing.
918 static int process_z_request(association *assoc, request *req, char **msg)
924 *msg = "Unknown Error";
925 assert(req && req->state == REQUEST_IDLE);
926 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
928 *msg = "Missing InitRequest";
931 switch (req->apdu_request->which)
933 case Z_APDU_initRequest:
934 iochan_settimeout(assoc->client_chan,
935 statserv_getcontrol()->idle_timeout * 60);
936 res = process_initRequest(assoc, req); break;
937 case Z_APDU_searchRequest:
938 res = process_searchRequest(assoc, req, &fd); break;
939 case Z_APDU_presentRequest:
940 res = process_presentRequest(assoc, req, &fd); break;
941 case Z_APDU_scanRequest:
942 if (assoc->init->bend_scan)
943 res = process_scanRequest(assoc, req, &fd);
946 *msg = "Cannot handle Scan APDU";
950 case Z_APDU_extendedServicesRequest:
951 if (assoc->init->bend_esrequest)
952 res = process_ESRequest(assoc, req, &fd);
955 *msg = "Cannot handle Extended Services APDU";
959 case Z_APDU_sortRequest:
960 if (assoc->init->bend_sort)
961 res = process_sortRequest(assoc, req, &fd);
964 *msg = "Cannot handle Sort APDU";
969 process_close(assoc, req);
971 case Z_APDU_deleteResultSetRequest:
972 if (assoc->init->bend_delete)
973 res = process_deleteRequest(assoc, req, &fd);
976 *msg = "Cannot handle Delete APDU";
980 case Z_APDU_segmentRequest:
981 if (assoc->init->bend_segment)
983 res = process_segmentRequest (assoc, req);
987 *msg = "Cannot handle Segment APDU";
992 *msg = "Bad APDU received";
997 yaz_log(LOG_DEBUG, " result immediately available");
998 retval = process_z_response(assoc, req, res);
1002 yaz_log(LOG_DEBUG, " result unavailble");
1005 else /* no result yet - one will be provided later */
1009 /* Set up an I/O handler for the fd supplied by the backend */
1011 yaz_log(LOG_DEBUG, " establishing handler for result");
1012 req->state = REQUEST_PENDING;
1013 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1015 iochan_setdata(chan, assoc);
1022 * Handle message from the backend.
1024 void backend_response(IOCHAN i, int event)
1026 association *assoc = (association *)iochan_getdata(i);
1027 request *req = request_head(&assoc->incoming);
1031 yaz_log(LOG_DEBUG, "backend_response");
1032 assert(assoc && req && req->state != REQUEST_IDLE);
1033 /* determine what it is we're waiting for */
1034 switch (req->apdu_request->which)
1036 case Z_APDU_searchRequest:
1037 res = response_searchRequest(assoc, req, 0, &fd); break;
1039 case Z_APDU_presentRequest:
1040 res = response_presentRequest(assoc, req, 0, &fd); break;
1041 case Z_APDU_scanRequest:
1042 res = response_scanRequest(assoc, req, 0, &fd); break;
1045 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1048 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1050 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1051 do_close(assoc, Z_Close_systemProblem, 0);
1055 else if (!res) /* no result yet - try again later */
1057 yaz_log(LOG_DEBUG, " no result yet");
1058 iochan_setfd(i, fd); /* in case fd has changed */
1063 * Encode response, and transfer the request structure to the outgoing queue.
1065 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1067 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1071 if (!z_GDU(assoc->print, &res, 0, 0))
1072 yaz_log(LOG_WARN, "ODR print error: %s",
1073 odr_errmsg(odr_geterror(assoc->print)));
1074 odr_reset(assoc->print);
1076 if (!z_GDU(assoc->encode, &res, 0, 0))
1078 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1079 odr_errmsg(odr_geterror(assoc->decode)),
1080 odr_getelement(assoc->decode));
1081 request_release(req);
1084 req->response = odr_getbuf(assoc->encode, &req->len_response,
1085 &req->size_response);
1086 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1087 odr_reset(assoc->encode);
1088 req->state = REQUEST_IDLE;
1089 request_enq(&assoc->outgoing, req);
1090 /* turn the work over to the ir_session handler */
1091 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1092 assoc->cs_put_mask = EVENT_OUTPUT;
1093 /* Is there more work to be done? give that to the input handler too */
1095 if (request_head(&assoc->incoming))
1097 yaz_log (LOG_DEBUG, "more work to be done");
1098 iochan_setevent(assoc->client_chan, EVENT_WORK);
1105 * Encode response, and transfer the request structure to the outgoing queue.
1107 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1109 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1110 gres->which = Z_GDU_Z3950;
1111 gres->u.z3950 = res;
1113 return process_gdu_response(assoc, req, gres);
1118 * Handle init request.
1119 * At the moment, we don't check the options
1120 * anywhere else in the code - we just try not to do anything that would
1121 * break a naive client. We'll toss 'em into the association block when
1122 * we need them there.
1124 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1126 statserv_options_block *cb = statserv_getcontrol();
1127 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1128 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1129 Z_InitResponse *resp = apdu->u.initResponse;
1130 bend_initresult *binitres;
1134 yaz_log(LOG_LOG, "Got initRequest");
1135 if (req->implementationId)
1136 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1137 if (req->implementationName)
1138 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1139 if (req->implementationVersion)
1140 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1142 assoc_init_reset(assoc);
1144 assoc->init->auth = req->idAuthentication;
1145 assoc->init->referenceId = req->referenceId;
1147 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1149 Z_CharSetandLanguageNegotiation *negotiation =
1150 yaz_get_charneg_record (req->otherInfo);
1151 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1152 assoc->init->charneg_request = negotiation;
1155 if (!(binitres = (*cb->bend_init)(assoc->init)))
1157 yaz_log(LOG_WARN, "Bad response from backend.");
1161 assoc->backend = binitres->handle;
1162 if ((assoc->init->bend_sort))
1163 yaz_log (LOG_DEBUG, "Sort handler installed");
1164 if ((assoc->init->bend_search))
1165 yaz_log (LOG_DEBUG, "Search handler installed");
1166 if ((assoc->init->bend_present))
1167 yaz_log (LOG_DEBUG, "Present handler installed");
1168 if ((assoc->init->bend_esrequest))
1169 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1170 if ((assoc->init->bend_delete))
1171 yaz_log (LOG_DEBUG, "Delete handler installed");
1172 if ((assoc->init->bend_scan))
1173 yaz_log (LOG_DEBUG, "Scan handler installed");
1174 if ((assoc->init->bend_segment))
1175 yaz_log (LOG_DEBUG, "Segment handler installed");
1177 resp->referenceId = req->referenceId;
1179 /* let's tell the client what we can do */
1180 if (ODR_MASK_GET(req->options, Z_Options_search))
1182 ODR_MASK_SET(resp->options, Z_Options_search);
1183 strcat(options, "srch");
1185 if (ODR_MASK_GET(req->options, Z_Options_present))
1187 ODR_MASK_SET(resp->options, Z_Options_present);
1188 strcat(options, " prst");
1190 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1191 assoc->init->bend_delete)
1193 ODR_MASK_SET(resp->options, Z_Options_delSet);
1194 strcat(options, " del");
1196 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1197 assoc->init->bend_esrequest)
1199 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1200 strcat (options, " extendedServices");
1202 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1204 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1205 strcat(options, " namedresults");
1207 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1209 ODR_MASK_SET(resp->options, Z_Options_scan);
1210 strcat(options, " scan");
1212 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1214 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1215 strcat(options, " concurrop");
1217 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1219 ODR_MASK_SET(resp->options, Z_Options_sort);
1220 strcat(options, " sort");
1223 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1224 && assoc->init->charneg_response)
1226 Z_OtherInformation **p;
1227 Z_OtherInformationUnit *p0;
1229 yaz_oi_APDU(apdu, &p);
1231 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1232 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1234 p0->which = Z_OtherInfo_externallyDefinedInfo;
1235 p0->information.externallyDefinedInfo =
1236 assoc->init->charneg_response;
1238 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1239 strcat(options, " negotiation");
1242 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1244 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1245 assoc->version = 2; /* 1 & 2 are equivalent */
1247 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1249 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1252 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1254 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1258 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1259 assoc->maximumRecordSize = *req->maximumRecordSize;
1260 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1261 assoc->maximumRecordSize = control_block->maxrecordsize;
1262 assoc->preferredMessageSize = *req->preferredMessageSize;
1263 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1264 assoc->preferredMessageSize = assoc->maximumRecordSize;
1266 resp->preferredMessageSize = &assoc->preferredMessageSize;
1267 resp->maximumRecordSize = &assoc->maximumRecordSize;
1269 resp->implementationId = odr_prepend(assoc->encode,
1270 assoc->init->implementation_id,
1271 resp->implementationId);
1273 resp->implementationName = odr_prepend(assoc->encode,
1274 assoc->init->implementation_name,
1275 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1277 version = odr_strdup(assoc->encode, "$Revision: 1.14 $");
1278 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1279 version[strlen(version)-2] = '\0';
1280 resp->implementationVersion = odr_prepend(assoc->encode,
1281 assoc->init->implementation_version,
1282 odr_prepend(assoc->encode, &version[11],
1283 resp->implementationVersion));
1285 if (binitres->errcode)
1287 yaz_log(LOG_LOG, "Connection rejected by backend.");
1289 assoc->state = ASSOC_DEAD;
1290 resp->userInformationField = init_diagnostics(assoc->encode,
1292 binitres->errstring);
1295 assoc->state = ASSOC_UP;
1300 * Diagnostic in default format, to be returned as either a surrogate
1301 * or non-surrogate diagnostic in the context of an open session, or
1302 * as User-information when an Init is refused.
1304 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1306 int *err = odr_intdup(odr, error);
1307 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1308 odr_malloc (odr, sizeof(*dr));
1310 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1311 addinfo ? " -- " : "", addinfo ? addinfo : "");
1313 dr->diagnosticSetId =
1314 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1315 dr->condition = err;
1316 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1317 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1322 * Set the specified `errcode' and `errstring' into a UserInfo-1
1323 * external to be returned to the client in accordance with Z35.90
1324 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1325 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1327 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1331 Z_OtherInformation *u;
1332 Z_OtherInformationUnit *l;
1333 Z_DiagnosticFormat *d;
1334 Z_DiagnosticFormat_s *e;
1336 x = (Z_External*) odr_malloc(odr, sizeof *x);
1338 x->indirect_reference = 0;
1339 oid.proto = PROTO_Z3950;
1340 oid.oclass = CLASS_USERINFO;
1341 oid.value = VAL_USERINFO1;
1342 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1343 x->which = Z_External_userInfo1;
1345 u = odr_malloc(odr, sizeof *u);
1347 u->num_elements = 1;
1348 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1349 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1352 l->which = Z_OtherInfo_externallyDefinedInfo;
1354 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1355 l->information.externallyDefinedInfo = x2;
1357 x2->indirect_reference = 0;
1358 oid.oclass = CLASS_DIAGSET;
1359 oid.value = VAL_DIAG1;
1360 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1361 x2->which = Z_External_diag1;
1363 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1366 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1367 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1370 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1371 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1376 * nonsurrogate diagnostic record.
1378 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1380 Z_Records *rec = (Z_Records *)
1381 odr_malloc (assoc->encode, sizeof(*rec));
1382 rec->which = Z_Records_NSD;
1383 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1388 * surrogate diagnostic.
1390 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1391 int error, char *addinfo)
1393 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1394 odr_malloc (assoc->encode, sizeof(*rec));
1395 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1397 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1398 rec->databaseName = dbname;
1399 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1400 rec->u.surrogateDiagnostic = drec;
1401 drec->which = Z_DiagRec_defaultFormat;
1402 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1408 * multiple nonsurrogate diagnostics.
1410 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1412 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1413 int *err = odr_intdup(assoc->encode, error);
1414 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1415 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1416 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1417 odr_malloc (assoc->encode, sizeof(*rec));
1419 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1421 recs->num_diagRecs = 1;
1422 recs->diagRecs = recp;
1424 drec->which = Z_DiagRec_defaultFormat;
1425 drec->u.defaultFormat = rec;
1427 rec->diagnosticSetId =
1428 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1429 rec->condition = err;
1431 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1432 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1436 static Z_Records *pack_records(association *a, char *setname, int start,
1437 int *num, Z_RecordComposition *comp,
1438 int *next, int *pres, oid_value format,
1439 Z_ReferenceId *referenceId,
1442 int recno, total_length = 0, toget = *num, dumped_records = 0;
1443 Z_Records *records =
1444 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1445 Z_NamePlusRecordList *reclist =
1446 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1447 Z_NamePlusRecord **list =
1448 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1450 records->which = Z_Records_DBOSD;
1451 records->u.databaseOrSurDiagnostics = reclist;
1452 reclist->num_records = 0;
1453 reclist->records = list;
1454 *pres = Z_PRES_SUCCESS;
1458 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1459 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1460 a->maximumRecordSize);
1461 for (recno = start; reclist->num_records < toget; recno++)
1464 Z_NamePlusRecord *thisrec;
1465 int this_length = 0;
1467 * we get the number of bytes allocated on the stream before any
1468 * allocation done by the backend - this should give us a reasonable
1469 * idea of the total size of the data so far.
1471 total_length = odr_total(a->encode) - dumped_records;
1477 freq.last_in_set = 0;
1478 freq.setname = setname;
1479 freq.surrogate_flag = 0;
1480 freq.number = recno;
1482 freq.request_format = format;
1483 freq.request_format_raw = oid;
1484 freq.output_format = format;
1485 freq.output_format_raw = 0;
1486 freq.stream = a->encode;
1487 freq.print = a->print;
1488 freq.referenceId = referenceId;
1490 (*a->init->bend_fetch)(a->backend, &freq);
1491 /* backend should be able to signal whether error is system-wide
1492 or only pertaining to current record */
1495 if (!freq.surrogate_flag)
1498 *pres = Z_PRES_FAILURE;
1499 /* for 'present request out of range',
1500 set addinfo to record position if not set */
1501 if (freq.errcode == 13 && freq.errstring == 0)
1503 sprintf (s, "%d", recno);
1506 return diagrec(a, freq.errcode, freq.errstring);
1508 reclist->records[reclist->num_records] =
1509 surrogatediagrec(a, freq.basename, freq.errcode,
1511 reclist->num_records++;
1512 *next = freq.last_in_set ? 0 : recno + 1;
1516 this_length = freq.len;
1518 this_length = odr_total(a->encode) - total_length - dumped_records;
1519 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1520 this_length, total_length, dumped_records);
1521 if (this_length + total_length > a->preferredMessageSize)
1523 /* record is small enough, really */
1524 if (this_length <= a->preferredMessageSize && recno > start)
1526 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1527 *pres = Z_PRES_PARTIAL_2;
1530 /* record can only be fetched by itself */
1531 if (this_length < a->maximumRecordSize)
1533 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1536 yaz_log(LOG_DEBUG, " Dropped it");
1537 reclist->records[reclist->num_records] =
1538 surrogatediagrec(a, freq.basename, 16, 0);
1539 reclist->num_records++;
1540 *next = freq.last_in_set ? 0 : recno + 1;
1541 dumped_records += this_length;
1545 else /* too big entirely */
1547 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1548 reclist->records[reclist->num_records] =
1549 surrogatediagrec(a, freq.basename, 17, 0);
1550 reclist->num_records++;
1551 *next = freq.last_in_set ? 0 : recno + 1;
1552 dumped_records += this_length;
1557 if (!(thisrec = (Z_NamePlusRecord *)
1558 odr_malloc(a->encode, sizeof(*thisrec))))
1560 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1561 strlen(freq.basename) + 1)))
1563 strcpy(thisrec->databaseName, freq.basename);
1564 thisrec->which = Z_NamePlusRecord_databaseRecord;
1566 if (freq.output_format_raw)
1568 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1569 freq.output_format = ident->value;
1571 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1572 freq.record, freq.len);
1573 if (!thisrec->u.databaseRecord)
1575 reclist->records[reclist->num_records] = thisrec;
1576 reclist->num_records++;
1577 *next = freq.last_in_set ? 0 : recno + 1;
1579 *num = reclist->num_records;
1583 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1586 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1587 bend_search_rr *bsrr =
1588 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1590 yaz_log(LOG_LOG, "Got SearchRequest.");
1592 bsrr->request = reqb;
1593 bsrr->association = assoc;
1594 bsrr->referenceId = req->referenceId;
1595 save_referenceId (reqb, bsrr->referenceId);
1597 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1598 if (req->databaseNames)
1601 for (i = 0; i < req->num_databaseNames; i++)
1602 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1604 yaz_log_zquery(req->query);
1606 if (assoc->init->bend_search)
1608 bsrr->setname = req->resultSetName;
1609 bsrr->replace_set = *req->replaceIndicator;
1610 bsrr->num_bases = req->num_databaseNames;
1611 bsrr->basenames = req->databaseNames;
1612 bsrr->query = req->query;
1613 bsrr->stream = assoc->encode;
1614 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1615 bsrr->decode = assoc->decode;
1616 bsrr->print = assoc->print;
1619 bsrr->errstring = NULL;
1620 bsrr->search_info = NULL;
1621 (assoc->init->bend_search)(assoc->backend, bsrr);
1625 return response_searchRequest(assoc, reqb, bsrr, fd);
1628 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1631 * Prepare a searchresponse based on the backend results. We probably want
1632 * to look at making the fetching of records nonblocking as well, but
1633 * so far, we'll keep things simple.
1634 * If bsrt is null, that means we're called in response to a communications
1635 * event, and we'll have to get the response for ourselves.
1637 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1638 bend_search_rr *bsrt, int *fd)
1640 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1641 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1642 Z_SearchResponse *resp = (Z_SearchResponse *)
1643 odr_malloc (assoc->encode, sizeof(*resp));
1644 int *nulint = odr_intdup (assoc->encode, 0);
1645 bool_t *sr = odr_intdup(assoc->encode, 1);
1646 int *next = odr_intdup(assoc->encode, 0);
1647 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1649 apdu->which = Z_APDU_searchResponse;
1650 apdu->u.searchResponse = resp;
1651 resp->referenceId = req->referenceId;
1652 resp->additionalSearchInfo = 0;
1653 resp->otherInfo = 0;
1655 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1657 yaz_log(LOG_FATAL, "Bad result from backend");
1660 else if (bsrt->errcode)
1662 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1663 resp->resultCount = nulint;
1664 resp->numberOfRecordsReturned = nulint;
1665 resp->nextResultSetPosition = nulint;
1666 resp->searchStatus = nulint;
1667 resp->resultSetStatus = none;
1668 resp->presentStatus = 0;
1672 int *toget = odr_intdup(assoc->encode, 0);
1673 int *presst = odr_intdup(assoc->encode, 0);
1674 Z_RecordComposition comp, *compp = 0;
1676 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1679 resp->resultCount = &bsrt->hits;
1681 comp.which = Z_RecordComp_simple;
1682 /* how many records does the user agent want, then? */
1683 if (bsrt->hits <= *req->smallSetUpperBound)
1685 *toget = bsrt->hits;
1686 if ((comp.u.simple = req->smallSetElementSetNames))
1689 else if (bsrt->hits < *req->largeSetLowerBound)
1691 *toget = *req->mediumSetPresentNumber;
1692 if (*toget > bsrt->hits)
1693 *toget = bsrt->hits;
1694 if ((comp.u.simple = req->mediumSetElementSetNames))
1700 if (*toget && !resp->records)
1705 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1708 form = prefformat->value;
1709 resp->records = pack_records(assoc, req->resultSetName, 1,
1710 toget, compp, next, presst, form, req->referenceId,
1711 req->preferredRecordSyntax);
1714 resp->numberOfRecordsReturned = toget;
1715 resp->nextResultSetPosition = next;
1716 resp->searchStatus = sr;
1717 resp->resultSetStatus = 0;
1718 resp->presentStatus = presst;
1722 if (*resp->resultCount)
1724 resp->numberOfRecordsReturned = nulint;
1725 resp->nextResultSetPosition = next;
1726 resp->searchStatus = sr;
1727 resp->resultSetStatus = 0;
1728 resp->presentStatus = 0;
1731 resp->additionalSearchInfo = bsrt->search_info;
1736 * Maybe we got a little over-friendly when we designed bend_fetch to
1737 * get only one record at a time. Some backends can optimise multiple-record
1738 * fetches, and at any rate, there is some overhead involved in
1739 * all that selecting and hopping around. Problem is, of course, that the
1740 * frontend can't know ahead of time how many records it'll need to
1741 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1742 * is downright lousy as a bulk data transfer protocol.
1744 * To start with, we'll do the fetching of records from the backend
1745 * in one operation: To save some trips in and out of the event-handler,
1746 * and to simplify the interface to pack_records. At any rate, asynch
1747 * operation is more fun in operations that have an unpredictable execution
1748 * speed - which is normally more true for search than for present.
1750 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1753 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1757 Z_PresentResponse *resp;
1761 yaz_log(LOG_LOG, "Got PresentRequest.");
1763 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1766 form = prefformat->value;
1767 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1769 resp->presentStatus = odr_intdup(assoc->encode, 0);
1770 if (assoc->init->bend_present)
1772 bend_present_rr *bprr = (bend_present_rr *)
1773 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1774 bprr->setname = req->resultSetId;
1775 bprr->start = *req->resultSetStartPoint;
1776 bprr->number = *req->numberOfRecordsRequested;
1777 bprr->format = form;
1778 bprr->comp = req->recordComposition;
1779 bprr->referenceId = req->referenceId;
1780 bprr->stream = assoc->encode;
1781 bprr->print = assoc->print;
1782 bprr->request = reqb;
1783 bprr->association = assoc;
1785 bprr->errstring = NULL;
1786 (*assoc->init->bend_present)(assoc->backend, bprr);
1792 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1793 *resp->presentStatus = Z_PRES_FAILURE;
1796 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1797 next = odr_intdup(assoc->encode, 0);
1798 num = odr_intdup(assoc->encode, 0);
1800 apdu->which = Z_APDU_presentResponse;
1801 apdu->u.presentResponse = resp;
1802 resp->referenceId = req->referenceId;
1803 resp->otherInfo = 0;
1807 *num = *req->numberOfRecordsRequested;
1809 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1810 num, req->recordComposition, next, resp->presentStatus,
1811 form, req->referenceId, req->preferredRecordSyntax);
1815 resp->numberOfRecordsReturned = num;
1816 resp->nextResultSetPosition = next;
1822 * Scan was implemented rather in a hurry, and with support for only the basic
1823 * elements of the service in the backend API. Suggestions are welcome.
1825 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1827 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1828 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1829 Z_ScanResponse *res = (Z_ScanResponse *)
1830 odr_malloc (assoc->encode, sizeof(*res));
1831 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1832 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1833 Z_ListEntries *ents = (Z_ListEntries *)
1834 odr_malloc (assoc->encode, sizeof(*ents));
1835 Z_DiagRecs *diagrecs_p = NULL;
1837 bend_scan_rr *bsrr = (bend_scan_rr *)
1838 odr_malloc (assoc->encode, sizeof(*bsrr));
1839 struct scan_entry *save_entries;
1841 yaz_log(LOG_LOG, "Got ScanRequest");
1843 apdu->which = Z_APDU_scanResponse;
1844 apdu->u.scanResponse = res;
1845 res->referenceId = req->referenceId;
1847 /* if step is absent, set it to 0 */
1848 res->stepSize = odr_intdup(assoc->encode, 0);
1850 *res->stepSize = *req->stepSize;
1852 res->scanStatus = scanStatus;
1853 res->numberOfEntriesReturned = numberOfEntriesReturned;
1854 res->positionOfTerm = 0;
1855 res->entries = ents;
1856 ents->num_entries = 0;
1857 ents->entries = NULL;
1858 ents->num_nonsurrogateDiagnostics = 0;
1859 ents->nonsurrogateDiagnostics = NULL;
1860 res->attributeSet = 0;
1863 if (req->databaseNames)
1866 for (i = 0; i < req->num_databaseNames; i++)
1867 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1869 bsrr->num_bases = req->num_databaseNames;
1870 bsrr->basenames = req->databaseNames;
1871 bsrr->num_entries = *req->numberOfTermsRequested;
1872 bsrr->term = req->termListAndStartPoint;
1873 bsrr->referenceId = req->referenceId;
1874 bsrr->stream = assoc->encode;
1875 bsrr->print = assoc->print;
1876 bsrr->step_size = res->stepSize;
1878 /* Note that version 2.0 of YAZ and older did not set entries ..
1879 We do now. And when we do it's easier to extend the scan entry
1880 We know that if the scan handler did set entries, it will
1881 not know of new member display_term.
1883 if (bsrr->num_entries > 0)
1886 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1888 for (i = 0; i<bsrr->num_entries; i++)
1890 bsrr->entries[i].term = 0;
1891 bsrr->entries[i].occurrences = 0;
1892 bsrr->entries[i].errcode = 0;
1893 bsrr->entries[i].errstring = 0;
1894 bsrr->entries[i].display_term = 0;
1897 save_entries = bsrr->entries; /* save it so we can compare later */
1899 if (req->attributeSet &&
1900 (attset = oid_getentbyoid(req->attributeSet)) &&
1901 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
1902 bsrr->attributeset = attset->value;
1904 bsrr->attributeset = VAL_NONE;
1905 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
1906 bsrr->term_position = req->preferredPositionInResponse ?
1907 *req->preferredPositionInResponse : 1;
1908 ((int (*)(void *, bend_scan_rr *))
1909 (*assoc->init->bend_scan))(assoc->backend, bsrr);
1911 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
1915 Z_Entry **tab = (Z_Entry **)
1916 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
1918 if (bsrr->status == BEND_SCAN_PARTIAL)
1919 *scanStatus = Z_Scan_partial_5;
1921 *scanStatus = Z_Scan_success;
1922 ents->entries = tab;
1923 ents->num_entries = bsrr->num_entries;
1924 res->numberOfEntriesReturned = &ents->num_entries;
1925 res->positionOfTerm = &bsrr->term_position;
1926 for (i = 0; i < bsrr->num_entries; i++)
1932 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
1933 if (bsrr->entries[i].occurrences >= 0)
1935 e->which = Z_Entry_termInfo;
1936 e->u.termInfo = t = (Z_TermInfo *)
1937 odr_malloc(assoc->encode, sizeof(*t));
1938 t->suggestedAttributes = 0;
1940 if (save_entries == bsrr->entries &&
1941 bsrr->entries[i].display_term)
1943 /* the entries was NOT set by the handler. So it's
1944 safe to test for new member display_term. It is
1947 t->displayTerm = odr_strdup(assoc->encode,
1948 bsrr->entries[i].display_term);
1950 t->alternativeTerm = 0;
1951 t->byAttributes = 0;
1952 t->otherTermInfo = 0;
1953 t->globalOccurrences = &bsrr->entries[i].occurrences;
1954 t->term = (Z_Term *)
1955 odr_malloc(assoc->encode, sizeof(*t->term));
1956 t->term->which = Z_Term_general;
1957 t->term->u.general = o =
1958 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
1959 o->buf = (unsigned char *)
1960 odr_malloc(assoc->encode, o->len = o->size =
1961 strlen(bsrr->entries[i].term));
1962 memcpy(o->buf, bsrr->entries[i].term, o->len);
1963 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
1964 bsrr->entries[i].term, bsrr->entries[i].occurrences);
1968 Z_DiagRecs *drecs = diagrecs (assoc,
1969 bsrr->entries[i].errcode,
1970 bsrr->entries[i].errstring);
1971 assert (drecs->num_diagRecs == 1);
1972 e->which = Z_Entry_surrogateDiagnostic;
1973 assert (drecs->diagRecs[0]);
1974 e->u.surrogateDiagnostic = drecs->diagRecs[0];
1980 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
1981 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
1986 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
1989 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
1990 Z_SortResponse *res = (Z_SortResponse *)
1991 odr_malloc (assoc->encode, sizeof(*res));
1992 bend_sort_rr *bsrr = (bend_sort_rr *)
1993 odr_malloc (assoc->encode, sizeof(*bsrr));
1995 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1997 yaz_log(LOG_LOG, "Got SortRequest.");
1999 bsrr->num_input_setnames = req->num_inputResultSetNames;
2000 bsrr->input_setnames = req->inputResultSetNames;
2001 bsrr->referenceId = req->referenceId;
2002 bsrr->output_setname = req->sortedResultSetName;
2003 bsrr->sort_sequence = req->sortSequence;
2004 bsrr->stream = assoc->encode;
2005 bsrr->print = assoc->print;
2007 bsrr->sort_status = Z_SortStatus_failure;
2009 bsrr->errstring = 0;
2011 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2013 res->referenceId = bsrr->referenceId;
2014 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2015 res->resultSetStatus = 0;
2018 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2019 res->diagnostics = dr->diagRecs;
2020 res->num_diagnostics = dr->num_diagRecs;
2024 res->num_diagnostics = 0;
2025 res->diagnostics = 0;
2027 res->resultCount = 0;
2030 apdu->which = Z_APDU_sortResponse;
2031 apdu->u.sortResponse = res;
2035 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2038 Z_DeleteResultSetRequest *req =
2039 reqb->apdu_request->u.deleteResultSetRequest;
2040 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2041 odr_malloc (assoc->encode, sizeof(*res));
2042 bend_delete_rr *bdrr = (bend_delete_rr *)
2043 odr_malloc (assoc->encode, sizeof(*bdrr));
2044 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2046 yaz_log(LOG_LOG, "Got DeleteRequest.");
2048 bdrr->num_setnames = req->num_resultSetList;
2049 bdrr->setnames = req->resultSetList;
2050 bdrr->stream = assoc->encode;
2051 bdrr->print = assoc->print;
2052 bdrr->function = *req->deleteFunction;
2053 bdrr->referenceId = req->referenceId;
2055 if (bdrr->num_setnames > 0)
2058 bdrr->statuses = (int*)
2059 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2060 bdrr->num_setnames);
2061 for (i = 0; i < bdrr->num_setnames; i++)
2062 bdrr->statuses[i] = 0;
2064 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2066 res->referenceId = req->referenceId;
2068 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2070 res->deleteListStatuses = 0;
2071 if (bdrr->num_setnames > 0)
2074 res->deleteListStatuses = (Z_ListStatuses *)
2075 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2076 res->deleteListStatuses->num = bdrr->num_setnames;
2077 res->deleteListStatuses->elements =
2079 odr_malloc (assoc->encode,
2080 sizeof(*res->deleteListStatuses->elements) *
2081 bdrr->num_setnames);
2082 for (i = 0; i<bdrr->num_setnames; i++)
2084 res->deleteListStatuses->elements[i] =
2086 odr_malloc (assoc->encode,
2087 sizeof(**res->deleteListStatuses->elements));
2088 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2089 res->deleteListStatuses->elements[i]->id =
2090 odr_strdup (assoc->encode, bdrr->setnames[i]);
2094 res->numberNotDeleted = 0;
2095 res->bulkStatuses = 0;
2096 res->deleteMessage = 0;
2099 apdu->which = Z_APDU_deleteResultSetResponse;
2100 apdu->u.deleteResultSetResponse = res;
2104 static void process_close(association *assoc, request *reqb)
2106 Z_Close *req = reqb->apdu_request->u.close;
2107 static char *reasons[] =
2114 "securityViolation",
2121 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2122 reasons[*req->closeReason], req->diagnosticInformation ?
2123 req->diagnosticInformation : "NULL");
2124 if (assoc->version < 3) /* to make do_force respond with close */
2126 do_close_req(assoc, Z_Close_finished,
2127 "Association terminated by client", reqb);
2130 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2134 reqb->len_refid = refid->len;
2135 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2136 memcpy (reqb->refid, refid->buf, refid->len);
2140 reqb->len_refid = 0;
2145 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2147 process_z_response (a, req, res);
2150 bend_request bend_request_mk (bend_association a)
2152 request *nreq = request_get (&a->outgoing);
2153 nreq->request_mem = nmem_create ();
2157 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2162 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2163 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2164 id->len = id->size = req->len_refid;
2165 memcpy (id->buf, req->refid, req->len_refid);
2169 void bend_request_destroy (bend_request *req)
2171 nmem_destroy((*req)->request_mem);
2172 request_release(*req);
2176 int bend_backend_respond (bend_association a, bend_request req)
2180 r = process_z_request (a, req, &msg);
2182 yaz_log (LOG_WARN, "%s", msg);
2186 void bend_request_setdata(bend_request r, void *p)
2191 void *bend_request_getdata(bend_request r)
2193 return r->clientData;
2196 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2198 bend_segment_rr req;
2200 req.segment = reqb->apdu_request->u.segmentRequest;
2201 req.stream = assoc->encode;
2202 req.decode = assoc->decode;
2203 req.print = assoc->print;
2204 req.association = assoc;
2206 (*assoc->init->bend_segment)(assoc->backend, &req);
2211 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2213 bend_esrequest_rr esrequest;
2215 Z_ExtendedServicesRequest *req =
2216 reqb->apdu_request->u.extendedServicesRequest;
2217 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2219 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2221 yaz_log(LOG_DEBUG,"inside Process esRequest");
2223 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2224 esrequest.stream = assoc->encode;
2225 esrequest.decode = assoc->decode;
2226 esrequest.print = assoc->print;
2227 esrequest.errcode = 0;
2228 esrequest.errstring = NULL;
2229 esrequest.request = reqb;
2230 esrequest.association = assoc;
2231 esrequest.taskPackage = 0;
2232 esrequest.referenceId = req->referenceId;
2234 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2236 /* If the response is being delayed, return NULL */
2237 if (esrequest.request == NULL)
2240 resp->referenceId = req->referenceId;
2242 if (esrequest.errcode == -1)
2244 /* Backend service indicates request will be processed */
2245 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2246 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2248 else if (esrequest.errcode == 0)
2250 /* Backend service indicates request will be processed */
2251 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2252 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2256 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2257 esrequest.errstring);
2259 /* Backend indicates error, request will not be processed */
2260 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2261 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2262 resp->num_diagnostics = diagRecs->num_diagRecs;
2263 resp->diagnostics = diagRecs->diagRecs;
2265 /* Do something with the members of bend_extendedservice */
2266 if (esrequest.taskPackage)
2267 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2268 (const char *) esrequest.taskPackage,
2270 yaz_log(LOG_DEBUG,"Send the result apdu");