2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.16 2004-01-09 18:10:31 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 yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
568 &srw_res->num_diagnostics, 1, 0);
573 rr.setname = "default";
576 rr.basenames = &srw_req->database;
579 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
581 if (srw_req->query_type == Z_SRW_query_type_cql)
583 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
584 ext->direct_reference = odr_getoidbystr(assoc->decode,
585 "1.2.840.10003.16.2");
586 ext->indirect_reference = 0;
588 ext->which = Z_External_CQL;
589 ext->u.cql = srw_req->query.cql;
591 rr.query->which = Z_Query_type_104;
592 rr.query->u.type_104 = ext;
594 else if (srw_req->query_type == Z_SRW_query_type_pqf)
596 Z_RPNQuery *RPNquery;
597 YAZ_PQF_Parser pqf_parser;
599 pqf_parser = yaz_pqf_create ();
601 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
607 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
608 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
609 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
614 rr.query->which = Z_Query_type_1;
615 rr.query->u.type_1 = RPNquery;
617 yaz_pqf_destroy (pqf_parser);
622 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
625 if (!srw_error && !assoc->init->bend_search)
630 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
631 srw_res->num_diagnostics = 1;
632 srw_res->diagnostics = (Z_SRW_diagnostic *)
633 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
634 srw_res->diagnostics[0].code =
635 odr_intdup(assoc->encode, srw_error);
636 srw_res->diagnostics[0].details = 0;
640 rr.stream = assoc->encode;
641 rr.decode = assoc->decode;
642 rr.print = assoc->print;
644 rr.association = assoc;
650 yaz_log_zquery(rr.query);
651 (assoc->init->bend_search)(assoc->backend, &rr);
652 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
655 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
656 if (rr.errcode == 109) /* database unavailable */
661 srw_res->num_diagnostics = 1;
662 srw_res->diagnostics = (Z_SRW_diagnostic *)
663 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
664 srw_res->diagnostics[0].code =
665 odr_intdup(assoc->encode,
666 yaz_diag_bib1_to_srw (rr.errcode));
667 srw_res->diagnostics[0].details = rr.errstring;
668 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
669 *srw_res->diagnostics[0].code);
674 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
675 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
677 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
678 start, number, rr.hits);
680 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
687 yaz_log(LOG_LOG, "Request out or range");
692 int packing = Z_SRW_recordPacking_string;
693 if (start + number > rr.hits)
694 number = rr.hits - start + 1;
695 if (srw_req->recordPacking &&
696 !strcmp(srw_req->recordPacking, "xml"))
697 packing = Z_SRW_recordPacking_XML;
698 srw_res->records = (Z_SRW_record *)
699 odr_malloc(assoc->encode,
700 number * sizeof(*srw_res->records));
701 for (i = 0; i<number; i++)
705 srw_res->records[j].recordPacking = packing;
706 srw_res->records[j].recordData_buf = 0;
707 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
708 errcode = srw_bend_fetch(assoc, i+start, srw_req,
709 srw_res->records + j);
712 srw_res->num_diagnostics = 1;
713 srw_res->diagnostics = (Z_SRW_diagnostic *)
714 odr_malloc(assoc->encode,
715 sizeof(*srw_res->diagnostics));
716 srw_res->diagnostics[0].code =
717 odr_intdup(assoc->encode,
718 yaz_diag_bib1_to_srw (errcode));
719 srw_res->diagnostics[0].details = rr.errstring;
722 if (srw_res->records[j].recordData_buf)
725 srw_res->num_records = j;
727 srw_res->records = 0;
733 static void srw_bend_explain(association *assoc, request *req,
734 Z_SRW_explainRequest *srw_req,
735 Z_SRW_explainResponse *srw_res,
738 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
742 yaz_log(LOG_DEBUG, "srw_bend_init");
743 if (!srw_bend_init(assoc))
748 if (assoc->init && assoc->init->bend_explain)
752 rr.stream = assoc->encode;
753 rr.decode = assoc->decode;
754 rr.print = assoc->print;
756 rr.database = srw_req->database;
757 (*assoc->init->bend_explain)(assoc->backend, &rr);
760 int packing = Z_SRW_recordPacking_string;
761 if (srw_req->recordPacking &&
762 !strcmp(srw_req->recordPacking, "xml"))
763 packing = Z_SRW_recordPacking_XML;
764 srw_res->record.recordSchema = 0;
765 srw_res->record.recordPacking = packing;
766 srw_res->record.recordData_buf = rr.explain_buf;
767 srw_res->record.recordData_len = strlen(rr.explain_buf);
768 srw_res->record.recordPosition = 0;
774 static void process_http_request(association *assoc, request *req)
776 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
777 ODR o = assoc->encode;
780 Z_SOAP *soap_package = 0;
783 Z_HTTP_Response *hres;
785 char *stylesheet = 0;
786 Z_SRW_diagnostic *diagnostic = 0;
787 int num_diagnostic = 0;
789 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
790 if (r == 2) /* not taken */
791 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
792 &diagnostic, &num_diagnostic);
793 if (r == 0) /* decode SRW/SRU OK .. */
796 if (sr->which == Z_SRW_searchRetrieve_request)
799 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
801 stylesheet = sr->u.request->stylesheet;
804 res->u.response->diagnostics = diagnostic;
805 res->u.response->num_diagnostics = num_diagnostic;
809 srw_bend_search(assoc, req, sr->u.request, res->u.response,
812 if (http_code == 200)
813 soap_package->u.generic->p = res;
815 else if (sr->which == Z_SRW_explain_request)
817 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
818 stylesheet = sr->u.explain_request->stylesheet;
821 res->u.explain_response->diagnostics = diagnostic;
822 res->u.explain_response->num_diagnostics = num_diagnostic;
824 srw_bend_explain(assoc, req, sr->u.explain_request,
825 res->u.explain_response, &http_code);
826 if (http_code == 200)
827 soap_package->u.generic->p = res;
829 else if (sr->which == Z_SRW_scan_request)
831 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
832 stylesheet = sr->u.scan_request->stylesheet;
835 res->u.scan_response->diagnostics = diagnostic;
836 res->u.scan_response->num_diagnostics = num_diagnostic;
838 yaz_add_srw_diagnostic(o,
839 &res->u.scan_response->diagnostics,
840 &res->u.scan_response->num_diagnostics,
842 if (http_code == 200)
843 soap_package->u.generic->p = res;
848 z_soap_error(assoc->encode, soap_package,
849 "SOAP-ENV:Client", "Bad method", 0);
851 if (http_code == 200 || http_code == 500)
853 static Z_SOAP_Handler soap_handlers[3] = {
855 {"http://www.loc.gov/zing/srw/", 0,
856 (Z_SOAP_fun) yaz_srw_codec},
857 {"http://www.loc.gov/zing/srw/v1.0/", 0,
858 (Z_SOAP_fun) yaz_srw_codec},
864 p = z_get_HTTP_Response(o, 200);
865 hres = p->u.HTTP_Response;
866 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
867 &hres->content_buf, &hres->content_len,
868 soap_handlers, charset, stylesheet);
869 hres->code = http_code;
871 strcpy(ctype, "text/xml");
874 strcat(ctype, "; charset=");
875 strcat(ctype, charset);
877 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
880 p = z_get_HTTP_Response(o, http_code);
883 p = z_get_HTTP_Response(o, 500);
884 hres = p->u.HTTP_Response;
885 if (!strcmp(hreq->version, "1.0"))
887 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
888 if (v && !strcmp(v, "Keep-Alive"))
892 hres->version = "1.0";
896 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
897 if (v && !strcmp(v, "close"))
901 hres->version = "1.1";
905 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
906 assoc->state = ASSOC_DEAD;
907 assoc->cs_get_mask = 0;
912 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
914 if (alive && isdigit(*alive))
918 if (t < 0 || t > 3600)
920 iochan_settimeout(assoc->client_chan,t);
921 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
923 process_gdu_response(assoc, req, p);
926 static void process_gdu_request(association *assoc, request *req)
928 if (req->gdu_request->which == Z_GDU_Z3950)
931 req->apdu_request = req->gdu_request->u.z3950;
932 if (process_z_request(assoc, req, &msg) < 0)
933 do_close_req(assoc, Z_Close_systemProblem, msg, req);
935 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
936 process_http_request(assoc, req);
939 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
944 * Initiate request processing.
946 static int process_z_request(association *assoc, request *req, char **msg)
952 *msg = "Unknown Error";
953 assert(req && req->state == REQUEST_IDLE);
954 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
956 *msg = "Missing InitRequest";
959 switch (req->apdu_request->which)
961 case Z_APDU_initRequest:
962 iochan_settimeout(assoc->client_chan,
963 statserv_getcontrol()->idle_timeout * 60);
964 res = process_initRequest(assoc, req); break;
965 case Z_APDU_searchRequest:
966 res = process_searchRequest(assoc, req, &fd); break;
967 case Z_APDU_presentRequest:
968 res = process_presentRequest(assoc, req, &fd); break;
969 case Z_APDU_scanRequest:
970 if (assoc->init->bend_scan)
971 res = process_scanRequest(assoc, req, &fd);
974 *msg = "Cannot handle Scan APDU";
978 case Z_APDU_extendedServicesRequest:
979 if (assoc->init->bend_esrequest)
980 res = process_ESRequest(assoc, req, &fd);
983 *msg = "Cannot handle Extended Services APDU";
987 case Z_APDU_sortRequest:
988 if (assoc->init->bend_sort)
989 res = process_sortRequest(assoc, req, &fd);
992 *msg = "Cannot handle Sort APDU";
997 process_close(assoc, req);
999 case Z_APDU_deleteResultSetRequest:
1000 if (assoc->init->bend_delete)
1001 res = process_deleteRequest(assoc, req, &fd);
1004 *msg = "Cannot handle Delete APDU";
1008 case Z_APDU_segmentRequest:
1009 if (assoc->init->bend_segment)
1011 res = process_segmentRequest (assoc, req);
1015 *msg = "Cannot handle Segment APDU";
1020 *msg = "Bad APDU received";
1025 yaz_log(LOG_DEBUG, " result immediately available");
1026 retval = process_z_response(assoc, req, res);
1030 yaz_log(LOG_DEBUG, " result unavailble");
1033 else /* no result yet - one will be provided later */
1037 /* Set up an I/O handler for the fd supplied by the backend */
1039 yaz_log(LOG_DEBUG, " establishing handler for result");
1040 req->state = REQUEST_PENDING;
1041 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1043 iochan_setdata(chan, assoc);
1050 * Handle message from the backend.
1052 void backend_response(IOCHAN i, int event)
1054 association *assoc = (association *)iochan_getdata(i);
1055 request *req = request_head(&assoc->incoming);
1059 yaz_log(LOG_DEBUG, "backend_response");
1060 assert(assoc && req && req->state != REQUEST_IDLE);
1061 /* determine what it is we're waiting for */
1062 switch (req->apdu_request->which)
1064 case Z_APDU_searchRequest:
1065 res = response_searchRequest(assoc, req, 0, &fd); break;
1067 case Z_APDU_presentRequest:
1068 res = response_presentRequest(assoc, req, 0, &fd); break;
1069 case Z_APDU_scanRequest:
1070 res = response_scanRequest(assoc, req, 0, &fd); break;
1073 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1076 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1078 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1079 do_close(assoc, Z_Close_systemProblem, 0);
1083 else if (!res) /* no result yet - try again later */
1085 yaz_log(LOG_DEBUG, " no result yet");
1086 iochan_setfd(i, fd); /* in case fd has changed */
1091 * Encode response, and transfer the request structure to the outgoing queue.
1093 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1095 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1099 if (!z_GDU(assoc->print, &res, 0, 0))
1100 yaz_log(LOG_WARN, "ODR print error: %s",
1101 odr_errmsg(odr_geterror(assoc->print)));
1102 odr_reset(assoc->print);
1104 if (!z_GDU(assoc->encode, &res, 0, 0))
1106 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1107 odr_errmsg(odr_geterror(assoc->decode)),
1108 odr_getelement(assoc->decode));
1109 request_release(req);
1112 req->response = odr_getbuf(assoc->encode, &req->len_response,
1113 &req->size_response);
1114 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1115 odr_reset(assoc->encode);
1116 req->state = REQUEST_IDLE;
1117 request_enq(&assoc->outgoing, req);
1118 /* turn the work over to the ir_session handler */
1119 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1120 assoc->cs_put_mask = EVENT_OUTPUT;
1121 /* Is there more work to be done? give that to the input handler too */
1123 if (request_head(&assoc->incoming))
1125 yaz_log (LOG_DEBUG, "more work to be done");
1126 iochan_setevent(assoc->client_chan, EVENT_WORK);
1133 * Encode response, and transfer the request structure to the outgoing queue.
1135 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1137 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1138 gres->which = Z_GDU_Z3950;
1139 gres->u.z3950 = res;
1141 return process_gdu_response(assoc, req, gres);
1146 * Handle init request.
1147 * At the moment, we don't check the options
1148 * anywhere else in the code - we just try not to do anything that would
1149 * break a naive client. We'll toss 'em into the association block when
1150 * we need them there.
1152 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1154 statserv_options_block *cb = statserv_getcontrol();
1155 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1156 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1157 Z_InitResponse *resp = apdu->u.initResponse;
1158 bend_initresult *binitres;
1162 yaz_log(LOG_LOG, "Got initRequest");
1163 if (req->implementationId)
1164 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1165 if (req->implementationName)
1166 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1167 if (req->implementationVersion)
1168 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1170 assoc_init_reset(assoc);
1172 assoc->init->auth = req->idAuthentication;
1173 assoc->init->referenceId = req->referenceId;
1175 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1177 Z_CharSetandLanguageNegotiation *negotiation =
1178 yaz_get_charneg_record (req->otherInfo);
1179 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1180 assoc->init->charneg_request = negotiation;
1183 if (!(binitres = (*cb->bend_init)(assoc->init)))
1185 yaz_log(LOG_WARN, "Bad response from backend.");
1189 assoc->backend = binitres->handle;
1190 if ((assoc->init->bend_sort))
1191 yaz_log (LOG_DEBUG, "Sort handler installed");
1192 if ((assoc->init->bend_search))
1193 yaz_log (LOG_DEBUG, "Search handler installed");
1194 if ((assoc->init->bend_present))
1195 yaz_log (LOG_DEBUG, "Present handler installed");
1196 if ((assoc->init->bend_esrequest))
1197 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1198 if ((assoc->init->bend_delete))
1199 yaz_log (LOG_DEBUG, "Delete handler installed");
1200 if ((assoc->init->bend_scan))
1201 yaz_log (LOG_DEBUG, "Scan handler installed");
1202 if ((assoc->init->bend_segment))
1203 yaz_log (LOG_DEBUG, "Segment handler installed");
1205 resp->referenceId = req->referenceId;
1207 /* let's tell the client what we can do */
1208 if (ODR_MASK_GET(req->options, Z_Options_search))
1210 ODR_MASK_SET(resp->options, Z_Options_search);
1211 strcat(options, "srch");
1213 if (ODR_MASK_GET(req->options, Z_Options_present))
1215 ODR_MASK_SET(resp->options, Z_Options_present);
1216 strcat(options, " prst");
1218 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1219 assoc->init->bend_delete)
1221 ODR_MASK_SET(resp->options, Z_Options_delSet);
1222 strcat(options, " del");
1224 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1225 assoc->init->bend_esrequest)
1227 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1228 strcat (options, " extendedServices");
1230 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1232 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1233 strcat(options, " namedresults");
1235 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1237 ODR_MASK_SET(resp->options, Z_Options_scan);
1238 strcat(options, " scan");
1240 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1242 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1243 strcat(options, " concurrop");
1245 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1247 ODR_MASK_SET(resp->options, Z_Options_sort);
1248 strcat(options, " sort");
1251 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1252 && assoc->init->charneg_response)
1254 Z_OtherInformation **p;
1255 Z_OtherInformationUnit *p0;
1257 yaz_oi_APDU(apdu, &p);
1259 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1260 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1262 p0->which = Z_OtherInfo_externallyDefinedInfo;
1263 p0->information.externallyDefinedInfo =
1264 assoc->init->charneg_response;
1266 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1267 strcat(options, " negotiation");
1270 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1272 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1273 assoc->version = 2; /* 1 & 2 are equivalent */
1275 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1277 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1280 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1282 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1286 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1287 assoc->maximumRecordSize = *req->maximumRecordSize;
1288 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1289 assoc->maximumRecordSize = control_block->maxrecordsize;
1290 assoc->preferredMessageSize = *req->preferredMessageSize;
1291 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1292 assoc->preferredMessageSize = assoc->maximumRecordSize;
1294 resp->preferredMessageSize = &assoc->preferredMessageSize;
1295 resp->maximumRecordSize = &assoc->maximumRecordSize;
1297 resp->implementationId = odr_prepend(assoc->encode,
1298 assoc->init->implementation_id,
1299 resp->implementationId);
1301 resp->implementationName = odr_prepend(assoc->encode,
1302 assoc->init->implementation_name,
1303 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1305 version = odr_strdup(assoc->encode, "$Revision: 1.16 $");
1306 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1307 version[strlen(version)-2] = '\0';
1308 resp->implementationVersion = odr_prepend(assoc->encode,
1309 assoc->init->implementation_version,
1310 odr_prepend(assoc->encode, &version[11],
1311 resp->implementationVersion));
1313 if (binitres->errcode)
1315 yaz_log(LOG_LOG, "Connection rejected by backend.");
1317 assoc->state = ASSOC_DEAD;
1318 resp->userInformationField = init_diagnostics(assoc->encode,
1320 binitres->errstring);
1323 assoc->state = ASSOC_UP;
1328 * Diagnostic in default format, to be returned as either a surrogate
1329 * or non-surrogate diagnostic in the context of an open session, or
1330 * as User-information when an Init is refused.
1332 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1334 int *err = odr_intdup(odr, error);
1335 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1336 odr_malloc (odr, sizeof(*dr));
1338 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1339 addinfo ? " -- " : "", addinfo ? addinfo : "");
1341 dr->diagnosticSetId =
1342 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1343 dr->condition = err;
1344 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1345 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1350 * Set the specified `errcode' and `errstring' into a UserInfo-1
1351 * external to be returned to the client in accordance with Z35.90
1352 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1353 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1355 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1359 Z_OtherInformation *u;
1360 Z_OtherInformationUnit *l;
1361 Z_DiagnosticFormat *d;
1362 Z_DiagnosticFormat_s *e;
1364 x = (Z_External*) odr_malloc(odr, sizeof *x);
1366 x->indirect_reference = 0;
1367 oid.proto = PROTO_Z3950;
1368 oid.oclass = CLASS_USERINFO;
1369 oid.value = VAL_USERINFO1;
1370 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1371 x->which = Z_External_userInfo1;
1373 u = odr_malloc(odr, sizeof *u);
1375 u->num_elements = 1;
1376 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1377 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1380 l->which = Z_OtherInfo_externallyDefinedInfo;
1382 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1383 l->information.externallyDefinedInfo = x2;
1385 x2->indirect_reference = 0;
1386 oid.oclass = CLASS_DIAGSET;
1387 oid.value = VAL_DIAG1;
1388 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1389 x2->which = Z_External_diag1;
1391 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1394 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1395 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1398 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1399 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1404 * nonsurrogate diagnostic record.
1406 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1408 Z_Records *rec = (Z_Records *)
1409 odr_malloc (assoc->encode, sizeof(*rec));
1410 rec->which = Z_Records_NSD;
1411 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1416 * surrogate diagnostic.
1418 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1419 int error, char *addinfo)
1421 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1422 odr_malloc (assoc->encode, sizeof(*rec));
1423 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1425 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1426 rec->databaseName = dbname;
1427 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1428 rec->u.surrogateDiagnostic = drec;
1429 drec->which = Z_DiagRec_defaultFormat;
1430 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1436 * multiple nonsurrogate diagnostics.
1438 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1440 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1441 int *err = odr_intdup(assoc->encode, error);
1442 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1443 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1444 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1445 odr_malloc (assoc->encode, sizeof(*rec));
1447 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1449 recs->num_diagRecs = 1;
1450 recs->diagRecs = recp;
1452 drec->which = Z_DiagRec_defaultFormat;
1453 drec->u.defaultFormat = rec;
1455 rec->diagnosticSetId =
1456 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1457 rec->condition = err;
1459 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1460 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1464 static Z_Records *pack_records(association *a, char *setname, int start,
1465 int *num, Z_RecordComposition *comp,
1466 int *next, int *pres, oid_value format,
1467 Z_ReferenceId *referenceId,
1470 int recno, total_length = 0, toget = *num, dumped_records = 0;
1471 Z_Records *records =
1472 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1473 Z_NamePlusRecordList *reclist =
1474 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1475 Z_NamePlusRecord **list =
1476 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1478 records->which = Z_Records_DBOSD;
1479 records->u.databaseOrSurDiagnostics = reclist;
1480 reclist->num_records = 0;
1481 reclist->records = list;
1482 *pres = Z_PRES_SUCCESS;
1486 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1487 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1488 a->maximumRecordSize);
1489 for (recno = start; reclist->num_records < toget; recno++)
1492 Z_NamePlusRecord *thisrec;
1493 int this_length = 0;
1495 * we get the number of bytes allocated on the stream before any
1496 * allocation done by the backend - this should give us a reasonable
1497 * idea of the total size of the data so far.
1499 total_length = odr_total(a->encode) - dumped_records;
1505 freq.last_in_set = 0;
1506 freq.setname = setname;
1507 freq.surrogate_flag = 0;
1508 freq.number = recno;
1510 freq.request_format = format;
1511 freq.request_format_raw = oid;
1512 freq.output_format = format;
1513 freq.output_format_raw = 0;
1514 freq.stream = a->encode;
1515 freq.print = a->print;
1516 freq.referenceId = referenceId;
1518 (*a->init->bend_fetch)(a->backend, &freq);
1519 /* backend should be able to signal whether error is system-wide
1520 or only pertaining to current record */
1523 if (!freq.surrogate_flag)
1526 *pres = Z_PRES_FAILURE;
1527 /* for 'present request out of range',
1528 set addinfo to record position if not set */
1529 if (freq.errcode == 13 && freq.errstring == 0)
1531 sprintf (s, "%d", recno);
1534 return diagrec(a, freq.errcode, freq.errstring);
1536 reclist->records[reclist->num_records] =
1537 surrogatediagrec(a, freq.basename, freq.errcode,
1539 reclist->num_records++;
1540 *next = freq.last_in_set ? 0 : recno + 1;
1544 this_length = freq.len;
1546 this_length = odr_total(a->encode) - total_length - dumped_records;
1547 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1548 this_length, total_length, dumped_records);
1549 if (this_length + total_length > a->preferredMessageSize)
1551 /* record is small enough, really */
1552 if (this_length <= a->preferredMessageSize && recno > start)
1554 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1555 *pres = Z_PRES_PARTIAL_2;
1558 /* record can only be fetched by itself */
1559 if (this_length < a->maximumRecordSize)
1561 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1564 yaz_log(LOG_DEBUG, " Dropped it");
1565 reclist->records[reclist->num_records] =
1566 surrogatediagrec(a, freq.basename, 16, 0);
1567 reclist->num_records++;
1568 *next = freq.last_in_set ? 0 : recno + 1;
1569 dumped_records += this_length;
1573 else /* too big entirely */
1575 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1576 reclist->records[reclist->num_records] =
1577 surrogatediagrec(a, freq.basename, 17, 0);
1578 reclist->num_records++;
1579 *next = freq.last_in_set ? 0 : recno + 1;
1580 dumped_records += this_length;
1585 if (!(thisrec = (Z_NamePlusRecord *)
1586 odr_malloc(a->encode, sizeof(*thisrec))))
1588 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1589 strlen(freq.basename) + 1)))
1591 strcpy(thisrec->databaseName, freq.basename);
1592 thisrec->which = Z_NamePlusRecord_databaseRecord;
1594 if (freq.output_format_raw)
1596 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1597 freq.output_format = ident->value;
1599 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1600 freq.record, freq.len);
1601 if (!thisrec->u.databaseRecord)
1603 reclist->records[reclist->num_records] = thisrec;
1604 reclist->num_records++;
1605 *next = freq.last_in_set ? 0 : recno + 1;
1607 *num = reclist->num_records;
1611 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1614 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1615 bend_search_rr *bsrr =
1616 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1618 yaz_log(LOG_LOG, "Got SearchRequest.");
1620 bsrr->request = reqb;
1621 bsrr->association = assoc;
1622 bsrr->referenceId = req->referenceId;
1623 save_referenceId (reqb, bsrr->referenceId);
1625 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1626 if (req->databaseNames)
1629 for (i = 0; i < req->num_databaseNames; i++)
1630 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1632 yaz_log_zquery(req->query);
1634 if (assoc->init->bend_search)
1636 bsrr->setname = req->resultSetName;
1637 bsrr->replace_set = *req->replaceIndicator;
1638 bsrr->num_bases = req->num_databaseNames;
1639 bsrr->basenames = req->databaseNames;
1640 bsrr->query = req->query;
1641 bsrr->stream = assoc->encode;
1642 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1643 bsrr->decode = assoc->decode;
1644 bsrr->print = assoc->print;
1647 bsrr->errstring = NULL;
1648 bsrr->search_info = NULL;
1649 (assoc->init->bend_search)(assoc->backend, bsrr);
1653 return response_searchRequest(assoc, reqb, bsrr, fd);
1656 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1659 * Prepare a searchresponse based on the backend results. We probably want
1660 * to look at making the fetching of records nonblocking as well, but
1661 * so far, we'll keep things simple.
1662 * If bsrt is null, that means we're called in response to a communications
1663 * event, and we'll have to get the response for ourselves.
1665 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1666 bend_search_rr *bsrt, int *fd)
1668 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1669 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1670 Z_SearchResponse *resp = (Z_SearchResponse *)
1671 odr_malloc (assoc->encode, sizeof(*resp));
1672 int *nulint = odr_intdup (assoc->encode, 0);
1673 bool_t *sr = odr_intdup(assoc->encode, 1);
1674 int *next = odr_intdup(assoc->encode, 0);
1675 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1677 apdu->which = Z_APDU_searchResponse;
1678 apdu->u.searchResponse = resp;
1679 resp->referenceId = req->referenceId;
1680 resp->additionalSearchInfo = 0;
1681 resp->otherInfo = 0;
1683 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1685 yaz_log(LOG_FATAL, "Bad result from backend");
1688 else if (bsrt->errcode)
1690 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1691 resp->resultCount = nulint;
1692 resp->numberOfRecordsReturned = nulint;
1693 resp->nextResultSetPosition = nulint;
1694 resp->searchStatus = nulint;
1695 resp->resultSetStatus = none;
1696 resp->presentStatus = 0;
1700 int *toget = odr_intdup(assoc->encode, 0);
1701 int *presst = odr_intdup(assoc->encode, 0);
1702 Z_RecordComposition comp, *compp = 0;
1704 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1707 resp->resultCount = &bsrt->hits;
1709 comp.which = Z_RecordComp_simple;
1710 /* how many records does the user agent want, then? */
1711 if (bsrt->hits <= *req->smallSetUpperBound)
1713 *toget = bsrt->hits;
1714 if ((comp.u.simple = req->smallSetElementSetNames))
1717 else if (bsrt->hits < *req->largeSetLowerBound)
1719 *toget = *req->mediumSetPresentNumber;
1720 if (*toget > bsrt->hits)
1721 *toget = bsrt->hits;
1722 if ((comp.u.simple = req->mediumSetElementSetNames))
1728 if (*toget && !resp->records)
1733 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1736 form = prefformat->value;
1737 resp->records = pack_records(assoc, req->resultSetName, 1,
1738 toget, compp, next, presst, form, req->referenceId,
1739 req->preferredRecordSyntax);
1742 resp->numberOfRecordsReturned = toget;
1743 resp->nextResultSetPosition = next;
1744 resp->searchStatus = sr;
1745 resp->resultSetStatus = 0;
1746 resp->presentStatus = presst;
1750 if (*resp->resultCount)
1752 resp->numberOfRecordsReturned = nulint;
1753 resp->nextResultSetPosition = next;
1754 resp->searchStatus = sr;
1755 resp->resultSetStatus = 0;
1756 resp->presentStatus = 0;
1759 resp->additionalSearchInfo = bsrt->search_info;
1764 * Maybe we got a little over-friendly when we designed bend_fetch to
1765 * get only one record at a time. Some backends can optimise multiple-record
1766 * fetches, and at any rate, there is some overhead involved in
1767 * all that selecting and hopping around. Problem is, of course, that the
1768 * frontend can't know ahead of time how many records it'll need to
1769 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1770 * is downright lousy as a bulk data transfer protocol.
1772 * To start with, we'll do the fetching of records from the backend
1773 * in one operation: To save some trips in and out of the event-handler,
1774 * and to simplify the interface to pack_records. At any rate, asynch
1775 * operation is more fun in operations that have an unpredictable execution
1776 * speed - which is normally more true for search than for present.
1778 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1781 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1785 Z_PresentResponse *resp;
1789 yaz_log(LOG_LOG, "Got PresentRequest.");
1791 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1794 form = prefformat->value;
1795 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1797 resp->presentStatus = odr_intdup(assoc->encode, 0);
1798 if (assoc->init->bend_present)
1800 bend_present_rr *bprr = (bend_present_rr *)
1801 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1802 bprr->setname = req->resultSetId;
1803 bprr->start = *req->resultSetStartPoint;
1804 bprr->number = *req->numberOfRecordsRequested;
1805 bprr->format = form;
1806 bprr->comp = req->recordComposition;
1807 bprr->referenceId = req->referenceId;
1808 bprr->stream = assoc->encode;
1809 bprr->print = assoc->print;
1810 bprr->request = reqb;
1811 bprr->association = assoc;
1813 bprr->errstring = NULL;
1814 (*assoc->init->bend_present)(assoc->backend, bprr);
1820 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1821 *resp->presentStatus = Z_PRES_FAILURE;
1824 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1825 next = odr_intdup(assoc->encode, 0);
1826 num = odr_intdup(assoc->encode, 0);
1828 apdu->which = Z_APDU_presentResponse;
1829 apdu->u.presentResponse = resp;
1830 resp->referenceId = req->referenceId;
1831 resp->otherInfo = 0;
1835 *num = *req->numberOfRecordsRequested;
1837 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1838 num, req->recordComposition, next, resp->presentStatus,
1839 form, req->referenceId, req->preferredRecordSyntax);
1843 resp->numberOfRecordsReturned = num;
1844 resp->nextResultSetPosition = next;
1850 * Scan was implemented rather in a hurry, and with support for only the basic
1851 * elements of the service in the backend API. Suggestions are welcome.
1853 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1855 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1856 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1857 Z_ScanResponse *res = (Z_ScanResponse *)
1858 odr_malloc (assoc->encode, sizeof(*res));
1859 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1860 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1861 Z_ListEntries *ents = (Z_ListEntries *)
1862 odr_malloc (assoc->encode, sizeof(*ents));
1863 Z_DiagRecs *diagrecs_p = NULL;
1865 bend_scan_rr *bsrr = (bend_scan_rr *)
1866 odr_malloc (assoc->encode, sizeof(*bsrr));
1867 struct scan_entry *save_entries;
1869 yaz_log(LOG_LOG, "Got ScanRequest");
1871 apdu->which = Z_APDU_scanResponse;
1872 apdu->u.scanResponse = res;
1873 res->referenceId = req->referenceId;
1875 /* if step is absent, set it to 0 */
1876 res->stepSize = odr_intdup(assoc->encode, 0);
1878 *res->stepSize = *req->stepSize;
1880 res->scanStatus = scanStatus;
1881 res->numberOfEntriesReturned = numberOfEntriesReturned;
1882 res->positionOfTerm = 0;
1883 res->entries = ents;
1884 ents->num_entries = 0;
1885 ents->entries = NULL;
1886 ents->num_nonsurrogateDiagnostics = 0;
1887 ents->nonsurrogateDiagnostics = NULL;
1888 res->attributeSet = 0;
1891 if (req->databaseNames)
1894 for (i = 0; i < req->num_databaseNames; i++)
1895 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1897 bsrr->num_bases = req->num_databaseNames;
1898 bsrr->basenames = req->databaseNames;
1899 bsrr->num_entries = *req->numberOfTermsRequested;
1900 bsrr->term = req->termListAndStartPoint;
1901 bsrr->referenceId = req->referenceId;
1902 bsrr->stream = assoc->encode;
1903 bsrr->print = assoc->print;
1904 bsrr->step_size = res->stepSize;
1906 /* Note that version 2.0 of YAZ and older did not set entries ..
1907 We do now. And when we do it's easier to extend the scan entry
1908 We know that if the scan handler did set entries, it will
1909 not know of new member display_term.
1911 if (bsrr->num_entries > 0)
1914 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1916 for (i = 0; i<bsrr->num_entries; i++)
1918 bsrr->entries[i].term = 0;
1919 bsrr->entries[i].occurrences = 0;
1920 bsrr->entries[i].errcode = 0;
1921 bsrr->entries[i].errstring = 0;
1922 bsrr->entries[i].display_term = 0;
1925 save_entries = bsrr->entries; /* save it so we can compare later */
1927 if (req->attributeSet &&
1928 (attset = oid_getentbyoid(req->attributeSet)) &&
1929 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
1930 bsrr->attributeset = attset->value;
1932 bsrr->attributeset = VAL_NONE;
1933 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
1934 bsrr->term_position = req->preferredPositionInResponse ?
1935 *req->preferredPositionInResponse : 1;
1936 ((int (*)(void *, bend_scan_rr *))
1937 (*assoc->init->bend_scan))(assoc->backend, bsrr);
1939 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
1943 Z_Entry **tab = (Z_Entry **)
1944 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
1946 if (bsrr->status == BEND_SCAN_PARTIAL)
1947 *scanStatus = Z_Scan_partial_5;
1949 *scanStatus = Z_Scan_success;
1950 ents->entries = tab;
1951 ents->num_entries = bsrr->num_entries;
1952 res->numberOfEntriesReturned = &ents->num_entries;
1953 res->positionOfTerm = &bsrr->term_position;
1954 for (i = 0; i < bsrr->num_entries; i++)
1960 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
1961 if (bsrr->entries[i].occurrences >= 0)
1963 e->which = Z_Entry_termInfo;
1964 e->u.termInfo = t = (Z_TermInfo *)
1965 odr_malloc(assoc->encode, sizeof(*t));
1966 t->suggestedAttributes = 0;
1968 if (save_entries == bsrr->entries &&
1969 bsrr->entries[i].display_term)
1971 /* the entries was NOT set by the handler. So it's
1972 safe to test for new member display_term. It is
1975 t->displayTerm = odr_strdup(assoc->encode,
1976 bsrr->entries[i].display_term);
1978 t->alternativeTerm = 0;
1979 t->byAttributes = 0;
1980 t->otherTermInfo = 0;
1981 t->globalOccurrences = &bsrr->entries[i].occurrences;
1982 t->term = (Z_Term *)
1983 odr_malloc(assoc->encode, sizeof(*t->term));
1984 t->term->which = Z_Term_general;
1985 t->term->u.general = o =
1986 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
1987 o->buf = (unsigned char *)
1988 odr_malloc(assoc->encode, o->len = o->size =
1989 strlen(bsrr->entries[i].term));
1990 memcpy(o->buf, bsrr->entries[i].term, o->len);
1991 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
1992 bsrr->entries[i].term, bsrr->entries[i].occurrences);
1996 Z_DiagRecs *drecs = diagrecs (assoc,
1997 bsrr->entries[i].errcode,
1998 bsrr->entries[i].errstring);
1999 assert (drecs->num_diagRecs == 1);
2000 e->which = Z_Entry_surrogateDiagnostic;
2001 assert (drecs->diagRecs[0]);
2002 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2008 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2009 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2014 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2017 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2018 Z_SortResponse *res = (Z_SortResponse *)
2019 odr_malloc (assoc->encode, sizeof(*res));
2020 bend_sort_rr *bsrr = (bend_sort_rr *)
2021 odr_malloc (assoc->encode, sizeof(*bsrr));
2023 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2025 yaz_log(LOG_LOG, "Got SortRequest.");
2027 bsrr->num_input_setnames = req->num_inputResultSetNames;
2028 bsrr->input_setnames = req->inputResultSetNames;
2029 bsrr->referenceId = req->referenceId;
2030 bsrr->output_setname = req->sortedResultSetName;
2031 bsrr->sort_sequence = req->sortSequence;
2032 bsrr->stream = assoc->encode;
2033 bsrr->print = assoc->print;
2035 bsrr->sort_status = Z_SortStatus_failure;
2037 bsrr->errstring = 0;
2039 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2041 res->referenceId = bsrr->referenceId;
2042 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2043 res->resultSetStatus = 0;
2046 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2047 res->diagnostics = dr->diagRecs;
2048 res->num_diagnostics = dr->num_diagRecs;
2052 res->num_diagnostics = 0;
2053 res->diagnostics = 0;
2055 res->resultCount = 0;
2058 apdu->which = Z_APDU_sortResponse;
2059 apdu->u.sortResponse = res;
2063 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2066 Z_DeleteResultSetRequest *req =
2067 reqb->apdu_request->u.deleteResultSetRequest;
2068 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2069 odr_malloc (assoc->encode, sizeof(*res));
2070 bend_delete_rr *bdrr = (bend_delete_rr *)
2071 odr_malloc (assoc->encode, sizeof(*bdrr));
2072 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2074 yaz_log(LOG_LOG, "Got DeleteRequest.");
2076 bdrr->num_setnames = req->num_resultSetList;
2077 bdrr->setnames = req->resultSetList;
2078 bdrr->stream = assoc->encode;
2079 bdrr->print = assoc->print;
2080 bdrr->function = *req->deleteFunction;
2081 bdrr->referenceId = req->referenceId;
2083 if (bdrr->num_setnames > 0)
2086 bdrr->statuses = (int*)
2087 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2088 bdrr->num_setnames);
2089 for (i = 0; i < bdrr->num_setnames; i++)
2090 bdrr->statuses[i] = 0;
2092 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2094 res->referenceId = req->referenceId;
2096 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2098 res->deleteListStatuses = 0;
2099 if (bdrr->num_setnames > 0)
2102 res->deleteListStatuses = (Z_ListStatuses *)
2103 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2104 res->deleteListStatuses->num = bdrr->num_setnames;
2105 res->deleteListStatuses->elements =
2107 odr_malloc (assoc->encode,
2108 sizeof(*res->deleteListStatuses->elements) *
2109 bdrr->num_setnames);
2110 for (i = 0; i<bdrr->num_setnames; i++)
2112 res->deleteListStatuses->elements[i] =
2114 odr_malloc (assoc->encode,
2115 sizeof(**res->deleteListStatuses->elements));
2116 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2117 res->deleteListStatuses->elements[i]->id =
2118 odr_strdup (assoc->encode, bdrr->setnames[i]);
2122 res->numberNotDeleted = 0;
2123 res->bulkStatuses = 0;
2124 res->deleteMessage = 0;
2127 apdu->which = Z_APDU_deleteResultSetResponse;
2128 apdu->u.deleteResultSetResponse = res;
2132 static void process_close(association *assoc, request *reqb)
2134 Z_Close *req = reqb->apdu_request->u.close;
2135 static char *reasons[] =
2142 "securityViolation",
2149 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2150 reasons[*req->closeReason], req->diagnosticInformation ?
2151 req->diagnosticInformation : "NULL");
2152 if (assoc->version < 3) /* to make do_force respond with close */
2154 do_close_req(assoc, Z_Close_finished,
2155 "Association terminated by client", reqb);
2158 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2162 reqb->len_refid = refid->len;
2163 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2164 memcpy (reqb->refid, refid->buf, refid->len);
2168 reqb->len_refid = 0;
2173 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2175 process_z_response (a, req, res);
2178 bend_request bend_request_mk (bend_association a)
2180 request *nreq = request_get (&a->outgoing);
2181 nreq->request_mem = nmem_create ();
2185 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2190 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2191 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2192 id->len = id->size = req->len_refid;
2193 memcpy (id->buf, req->refid, req->len_refid);
2197 void bend_request_destroy (bend_request *req)
2199 nmem_destroy((*req)->request_mem);
2200 request_release(*req);
2204 int bend_backend_respond (bend_association a, bend_request req)
2208 r = process_z_request (a, req, &msg);
2210 yaz_log (LOG_WARN, "%s", msg);
2214 void bend_request_setdata(bend_request r, void *p)
2219 void *bend_request_getdata(bend_request r)
2221 return r->clientData;
2224 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2226 bend_segment_rr req;
2228 req.segment = reqb->apdu_request->u.segmentRequest;
2229 req.stream = assoc->encode;
2230 req.decode = assoc->decode;
2231 req.print = assoc->print;
2232 req.association = assoc;
2234 (*assoc->init->bend_segment)(assoc->backend, &req);
2239 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2241 bend_esrequest_rr esrequest;
2243 Z_ExtendedServicesRequest *req =
2244 reqb->apdu_request->u.extendedServicesRequest;
2245 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2247 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2249 yaz_log(LOG_DEBUG,"inside Process esRequest");
2251 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2252 esrequest.stream = assoc->encode;
2253 esrequest.decode = assoc->decode;
2254 esrequest.print = assoc->print;
2255 esrequest.errcode = 0;
2256 esrequest.errstring = NULL;
2257 esrequest.request = reqb;
2258 esrequest.association = assoc;
2259 esrequest.taskPackage = 0;
2260 esrequest.referenceId = req->referenceId;
2262 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2264 /* If the response is being delayed, return NULL */
2265 if (esrequest.request == NULL)
2268 resp->referenceId = req->referenceId;
2270 if (esrequest.errcode == -1)
2272 /* Backend service indicates request will be processed */
2273 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2274 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2276 else if (esrequest.errcode == 0)
2278 /* Backend service indicates request will be processed */
2279 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2280 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2284 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2285 esrequest.errstring);
2287 /* Backend indicates error, request will not be processed */
2288 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2289 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2290 resp->num_diagnostics = diagRecs->num_diagRecs;
2291 resp->diagnostics = diagRecs->diagRecs;
2293 /* Do something with the members of bend_extendedservice */
2294 if (esrequest.taskPackage)
2295 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2296 (const char *) esrequest.taskPackage,
2298 yaz_log(LOG_DEBUG,"Send the result apdu");