2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.17 2004-01-15 10:16:27 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;
778 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
780 Z_SOAP *soap_package = 0;
783 Z_HTTP_Response *hres = 0;
785 char *stylesheet = 0;
786 Z_SRW_diagnostic *diagnostic = 0;
787 int num_diagnostic = 0;
789 if (!strcmp(hreq->path, "/test"))
791 p = z_get_HTTP_Response(o, 200);
792 hres = p->u.HTTP_Response;
793 hres->content_buf = "1234567890\n";
794 hres->content_len = strlen(hres->content_buf);
799 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
800 yaz_log(LOG_DEBUG, "yaz_srw_decode returned %d", r);
802 if (r == 2) /* not taken */
804 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
805 &diagnostic, &num_diagnostic);
806 yaz_log(LOG_DEBUG, "yaz_sru_decode returned %d", r);
808 if (r == 0) /* decode SRW/SRU OK .. */
811 if (sr->which == Z_SRW_searchRetrieve_request)
814 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
816 stylesheet = sr->u.request->stylesheet;
819 res->u.response->diagnostics = diagnostic;
820 res->u.response->num_diagnostics = num_diagnostic;
824 srw_bend_search(assoc, req, sr->u.request, res->u.response,
827 if (http_code == 200)
828 soap_package->u.generic->p = res;
830 else if (sr->which == Z_SRW_explain_request)
832 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
833 stylesheet = sr->u.explain_request->stylesheet;
836 res->u.explain_response->diagnostics = diagnostic;
837 res->u.explain_response->num_diagnostics = num_diagnostic;
839 srw_bend_explain(assoc, req, sr->u.explain_request,
840 res->u.explain_response, &http_code);
841 if (http_code == 200)
842 soap_package->u.generic->p = res;
844 else if (sr->which == Z_SRW_scan_request)
846 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
847 stylesheet = sr->u.scan_request->stylesheet;
850 res->u.scan_response->diagnostics = diagnostic;
851 res->u.scan_response->num_diagnostics = num_diagnostic;
853 yaz_add_srw_diagnostic(o,
854 &res->u.scan_response->diagnostics,
855 &res->u.scan_response->num_diagnostics,
857 if (http_code == 200)
858 soap_package->u.generic->p = res;
863 z_soap_error(assoc->encode, soap_package,
864 "SOAP-ENV:Client", "Bad method", 0);
866 if (http_code == 200 || http_code == 500)
868 static Z_SOAP_Handler soap_handlers[3] = {
870 {"http://www.loc.gov/zing/srw/", 0,
871 (Z_SOAP_fun) yaz_srw_codec},
872 {"http://www.loc.gov/zing/srw/v1.0/", 0,
873 (Z_SOAP_fun) yaz_srw_codec},
879 p = z_get_HTTP_Response(o, 200);
880 hres = p->u.HTTP_Response;
881 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
882 &hres->content_buf, &hres->content_len,
883 soap_handlers, charset, stylesheet);
884 hres->code = http_code;
886 strcpy(ctype, "text/xml");
889 strcat(ctype, "; charset=");
890 strcat(ctype, charset);
892 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
895 p = z_get_HTTP_Response(o, http_code);
899 p = z_get_HTTP_Response(o, 500);
900 hres = p->u.HTTP_Response;
901 if (!strcmp(hreq->version, "1.0"))
903 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
904 if (v && !strcmp(v, "Keep-Alive"))
908 hres->version = "1.0";
912 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
913 if (v && !strcmp(v, "close"))
917 hres->version = "1.1";
921 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
922 assoc->state = ASSOC_DEAD;
923 assoc->cs_get_mask = 0;
928 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
930 if (alive && isdigit(*alive))
934 if (t < 0 || t > 3600)
936 iochan_settimeout(assoc->client_chan,t);
937 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
939 process_gdu_response(assoc, req, p);
942 static void process_gdu_request(association *assoc, request *req)
944 if (req->gdu_request->which == Z_GDU_Z3950)
947 req->apdu_request = req->gdu_request->u.z3950;
948 if (process_z_request(assoc, req, &msg) < 0)
949 do_close_req(assoc, Z_Close_systemProblem, msg, req);
951 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
952 process_http_request(assoc, req);
955 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
960 * Initiate request processing.
962 static int process_z_request(association *assoc, request *req, char **msg)
968 *msg = "Unknown Error";
969 assert(req && req->state == REQUEST_IDLE);
970 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
972 *msg = "Missing InitRequest";
975 switch (req->apdu_request->which)
977 case Z_APDU_initRequest:
978 iochan_settimeout(assoc->client_chan,
979 statserv_getcontrol()->idle_timeout * 60);
980 res = process_initRequest(assoc, req); break;
981 case Z_APDU_searchRequest:
982 res = process_searchRequest(assoc, req, &fd); break;
983 case Z_APDU_presentRequest:
984 res = process_presentRequest(assoc, req, &fd); break;
985 case Z_APDU_scanRequest:
986 if (assoc->init->bend_scan)
987 res = process_scanRequest(assoc, req, &fd);
990 *msg = "Cannot handle Scan APDU";
994 case Z_APDU_extendedServicesRequest:
995 if (assoc->init->bend_esrequest)
996 res = process_ESRequest(assoc, req, &fd);
999 *msg = "Cannot handle Extended Services APDU";
1003 case Z_APDU_sortRequest:
1004 if (assoc->init->bend_sort)
1005 res = process_sortRequest(assoc, req, &fd);
1008 *msg = "Cannot handle Sort APDU";
1013 process_close(assoc, req);
1015 case Z_APDU_deleteResultSetRequest:
1016 if (assoc->init->bend_delete)
1017 res = process_deleteRequest(assoc, req, &fd);
1020 *msg = "Cannot handle Delete APDU";
1024 case Z_APDU_segmentRequest:
1025 if (assoc->init->bend_segment)
1027 res = process_segmentRequest (assoc, req);
1031 *msg = "Cannot handle Segment APDU";
1036 *msg = "Bad APDU received";
1041 yaz_log(LOG_DEBUG, " result immediately available");
1042 retval = process_z_response(assoc, req, res);
1046 yaz_log(LOG_DEBUG, " result unavailble");
1049 else /* no result yet - one will be provided later */
1053 /* Set up an I/O handler for the fd supplied by the backend */
1055 yaz_log(LOG_DEBUG, " establishing handler for result");
1056 req->state = REQUEST_PENDING;
1057 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1059 iochan_setdata(chan, assoc);
1066 * Handle message from the backend.
1068 void backend_response(IOCHAN i, int event)
1070 association *assoc = (association *)iochan_getdata(i);
1071 request *req = request_head(&assoc->incoming);
1075 yaz_log(LOG_DEBUG, "backend_response");
1076 assert(assoc && req && req->state != REQUEST_IDLE);
1077 /* determine what it is we're waiting for */
1078 switch (req->apdu_request->which)
1080 case Z_APDU_searchRequest:
1081 res = response_searchRequest(assoc, req, 0, &fd); break;
1083 case Z_APDU_presentRequest:
1084 res = response_presentRequest(assoc, req, 0, &fd); break;
1085 case Z_APDU_scanRequest:
1086 res = response_scanRequest(assoc, req, 0, &fd); break;
1089 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1092 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1094 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1095 do_close(assoc, Z_Close_systemProblem, 0);
1099 else if (!res) /* no result yet - try again later */
1101 yaz_log(LOG_DEBUG, " no result yet");
1102 iochan_setfd(i, fd); /* in case fd has changed */
1107 * Encode response, and transfer the request structure to the outgoing queue.
1109 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1111 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1115 if (!z_GDU(assoc->print, &res, 0, 0))
1116 yaz_log(LOG_WARN, "ODR print error: %s",
1117 odr_errmsg(odr_geterror(assoc->print)));
1118 odr_reset(assoc->print);
1120 if (!z_GDU(assoc->encode, &res, 0, 0))
1122 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1123 odr_errmsg(odr_geterror(assoc->decode)),
1124 odr_getelement(assoc->decode));
1125 request_release(req);
1128 req->response = odr_getbuf(assoc->encode, &req->len_response,
1129 &req->size_response);
1130 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1131 odr_reset(assoc->encode);
1132 req->state = REQUEST_IDLE;
1133 request_enq(&assoc->outgoing, req);
1134 /* turn the work over to the ir_session handler */
1135 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1136 assoc->cs_put_mask = EVENT_OUTPUT;
1137 /* Is there more work to be done? give that to the input handler too */
1139 if (request_head(&assoc->incoming))
1141 yaz_log (LOG_DEBUG, "more work to be done");
1142 iochan_setevent(assoc->client_chan, EVENT_WORK);
1149 * Encode response, and transfer the request structure to the outgoing queue.
1151 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1153 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1154 gres->which = Z_GDU_Z3950;
1155 gres->u.z3950 = res;
1157 return process_gdu_response(assoc, req, gres);
1162 * Handle init request.
1163 * At the moment, we don't check the options
1164 * anywhere else in the code - we just try not to do anything that would
1165 * break a naive client. We'll toss 'em into the association block when
1166 * we need them there.
1168 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1170 statserv_options_block *cb = statserv_getcontrol();
1171 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1172 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1173 Z_InitResponse *resp = apdu->u.initResponse;
1174 bend_initresult *binitres;
1178 yaz_log(LOG_LOG, "Got initRequest");
1179 if (req->implementationId)
1180 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1181 if (req->implementationName)
1182 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1183 if (req->implementationVersion)
1184 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1186 assoc_init_reset(assoc);
1188 assoc->init->auth = req->idAuthentication;
1189 assoc->init->referenceId = req->referenceId;
1191 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1193 Z_CharSetandLanguageNegotiation *negotiation =
1194 yaz_get_charneg_record (req->otherInfo);
1196 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1197 assoc->init->charneg_request = negotiation;
1200 if (!(binitres = (*cb->bend_init)(assoc->init)))
1202 yaz_log(LOG_WARN, "Bad response from backend.");
1206 assoc->backend = binitres->handle;
1207 if ((assoc->init->bend_sort))
1208 yaz_log (LOG_DEBUG, "Sort handler installed");
1209 if ((assoc->init->bend_search))
1210 yaz_log (LOG_DEBUG, "Search handler installed");
1211 if ((assoc->init->bend_present))
1212 yaz_log (LOG_DEBUG, "Present handler installed");
1213 if ((assoc->init->bend_esrequest))
1214 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1215 if ((assoc->init->bend_delete))
1216 yaz_log (LOG_DEBUG, "Delete handler installed");
1217 if ((assoc->init->bend_scan))
1218 yaz_log (LOG_DEBUG, "Scan handler installed");
1219 if ((assoc->init->bend_segment))
1220 yaz_log (LOG_DEBUG, "Segment handler installed");
1222 resp->referenceId = req->referenceId;
1224 /* let's tell the client what we can do */
1225 if (ODR_MASK_GET(req->options, Z_Options_search))
1227 ODR_MASK_SET(resp->options, Z_Options_search);
1228 strcat(options, "srch");
1230 if (ODR_MASK_GET(req->options, Z_Options_present))
1232 ODR_MASK_SET(resp->options, Z_Options_present);
1233 strcat(options, " prst");
1235 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1236 assoc->init->bend_delete)
1238 ODR_MASK_SET(resp->options, Z_Options_delSet);
1239 strcat(options, " del");
1241 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1242 assoc->init->bend_esrequest)
1244 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1245 strcat (options, " extendedServices");
1247 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1249 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1250 strcat(options, " namedresults");
1252 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1254 ODR_MASK_SET(resp->options, Z_Options_scan);
1255 strcat(options, " scan");
1257 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1259 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1260 strcat(options, " concurrop");
1262 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1264 ODR_MASK_SET(resp->options, Z_Options_sort);
1265 strcat(options, " sort");
1268 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1269 && assoc->init->charneg_response)
1271 Z_OtherInformation **p;
1272 Z_OtherInformationUnit *p0;
1274 yaz_oi_APDU(apdu, &p);
1276 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1277 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1279 p0->which = Z_OtherInfo_externallyDefinedInfo;
1280 p0->information.externallyDefinedInfo =
1281 assoc->init->charneg_response;
1283 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1284 strcat(options, " negotiation");
1287 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1289 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1290 assoc->version = 1; /* 1 & 2 are equivalent */
1292 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1294 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1297 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1299 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1303 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1304 assoc->maximumRecordSize = *req->maximumRecordSize;
1305 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1306 assoc->maximumRecordSize = control_block->maxrecordsize;
1307 assoc->preferredMessageSize = *req->preferredMessageSize;
1308 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1309 assoc->preferredMessageSize = assoc->maximumRecordSize;
1311 resp->preferredMessageSize = &assoc->preferredMessageSize;
1312 resp->maximumRecordSize = &assoc->maximumRecordSize;
1314 resp->implementationId = odr_prepend(assoc->encode,
1315 assoc->init->implementation_id,
1316 resp->implementationId);
1318 resp->implementationName = odr_prepend(assoc->encode,
1319 assoc->init->implementation_name,
1320 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1322 version = odr_strdup(assoc->encode, "$Revision: 1.17 $");
1323 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1324 version[strlen(version)-2] = '\0';
1325 resp->implementationVersion = odr_prepend(assoc->encode,
1326 assoc->init->implementation_version,
1327 odr_prepend(assoc->encode, &version[11],
1328 resp->implementationVersion));
1330 if (binitres->errcode)
1332 yaz_log(LOG_LOG, "Connection rejected by backend.");
1334 assoc->state = ASSOC_DEAD;
1335 resp->userInformationField = init_diagnostics(assoc->encode,
1337 binitres->errstring);
1340 assoc->state = ASSOC_UP;
1345 * Diagnostic in default format, to be returned as either a surrogate
1346 * or non-surrogate diagnostic in the context of an open session, or
1347 * as User-information when an Init is refused.
1349 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1351 int *err = odr_intdup(odr, error);
1352 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1353 odr_malloc (odr, sizeof(*dr));
1355 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1356 addinfo ? " -- " : "", addinfo ? addinfo : "");
1358 dr->diagnosticSetId =
1359 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1360 dr->condition = err;
1361 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1362 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1367 * Set the specified `errcode' and `errstring' into a UserInfo-1
1368 * external to be returned to the client in accordance with Z35.90
1369 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1370 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1372 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1376 Z_OtherInformation *u;
1377 Z_OtherInformationUnit *l;
1378 Z_DiagnosticFormat *d;
1379 Z_DiagnosticFormat_s *e;
1381 x = (Z_External*) odr_malloc(odr, sizeof *x);
1383 x->indirect_reference = 0;
1384 oid.proto = PROTO_Z3950;
1385 oid.oclass = CLASS_USERINFO;
1386 oid.value = VAL_USERINFO1;
1387 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1388 x->which = Z_External_userInfo1;
1390 u = odr_malloc(odr, sizeof *u);
1392 u->num_elements = 1;
1393 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1394 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1397 l->which = Z_OtherInfo_externallyDefinedInfo;
1399 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1400 l->information.externallyDefinedInfo = x2;
1402 x2->indirect_reference = 0;
1403 oid.oclass = CLASS_DIAGSET;
1404 oid.value = VAL_DIAG1;
1405 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1406 x2->which = Z_External_diag1;
1408 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1411 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1412 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1415 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1416 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1421 * nonsurrogate diagnostic record.
1423 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1425 Z_Records *rec = (Z_Records *)
1426 odr_malloc (assoc->encode, sizeof(*rec));
1427 rec->which = Z_Records_NSD;
1428 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1433 * surrogate diagnostic.
1435 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1436 int error, char *addinfo)
1438 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1439 odr_malloc (assoc->encode, sizeof(*rec));
1440 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1442 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1443 rec->databaseName = dbname;
1444 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1445 rec->u.surrogateDiagnostic = drec;
1446 drec->which = Z_DiagRec_defaultFormat;
1447 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1453 * multiple nonsurrogate diagnostics.
1455 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1457 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1458 int *err = odr_intdup(assoc->encode, error);
1459 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1460 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1461 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1462 odr_malloc (assoc->encode, sizeof(*rec));
1464 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1466 recs->num_diagRecs = 1;
1467 recs->diagRecs = recp;
1469 drec->which = Z_DiagRec_defaultFormat;
1470 drec->u.defaultFormat = rec;
1472 rec->diagnosticSetId =
1473 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1474 rec->condition = err;
1476 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1477 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1481 static Z_Records *pack_records(association *a, char *setname, int start,
1482 int *num, Z_RecordComposition *comp,
1483 int *next, int *pres, oid_value format,
1484 Z_ReferenceId *referenceId,
1487 int recno, total_length = 0, toget = *num, dumped_records = 0;
1488 Z_Records *records =
1489 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1490 Z_NamePlusRecordList *reclist =
1491 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1492 Z_NamePlusRecord **list =
1493 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1495 records->which = Z_Records_DBOSD;
1496 records->u.databaseOrSurDiagnostics = reclist;
1497 reclist->num_records = 0;
1498 reclist->records = list;
1499 *pres = Z_PRES_SUCCESS;
1503 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1504 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1505 a->maximumRecordSize);
1506 for (recno = start; reclist->num_records < toget; recno++)
1509 Z_NamePlusRecord *thisrec;
1510 int this_length = 0;
1512 * we get the number of bytes allocated on the stream before any
1513 * allocation done by the backend - this should give us a reasonable
1514 * idea of the total size of the data so far.
1516 total_length = odr_total(a->encode) - dumped_records;
1522 freq.last_in_set = 0;
1523 freq.setname = setname;
1524 freq.surrogate_flag = 0;
1525 freq.number = recno;
1527 freq.request_format = format;
1528 freq.request_format_raw = oid;
1529 freq.output_format = format;
1530 freq.output_format_raw = 0;
1531 freq.stream = a->encode;
1532 freq.print = a->print;
1533 freq.referenceId = referenceId;
1535 (*a->init->bend_fetch)(a->backend, &freq);
1536 /* backend should be able to signal whether error is system-wide
1537 or only pertaining to current record */
1540 if (!freq.surrogate_flag)
1543 *pres = Z_PRES_FAILURE;
1544 /* for 'present request out of range',
1545 set addinfo to record position if not set */
1546 if (freq.errcode == 13 && freq.errstring == 0)
1548 sprintf (s, "%d", recno);
1551 return diagrec(a, freq.errcode, freq.errstring);
1553 reclist->records[reclist->num_records] =
1554 surrogatediagrec(a, freq.basename, freq.errcode,
1556 reclist->num_records++;
1557 *next = freq.last_in_set ? 0 : recno + 1;
1561 this_length = freq.len;
1563 this_length = odr_total(a->encode) - total_length - dumped_records;
1564 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1565 this_length, total_length, dumped_records);
1566 if (this_length + total_length > a->preferredMessageSize)
1568 /* record is small enough, really */
1569 if (this_length <= a->preferredMessageSize && recno > start)
1571 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1572 *pres = Z_PRES_PARTIAL_2;
1575 /* record can only be fetched by itself */
1576 if (this_length < a->maximumRecordSize)
1578 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1581 yaz_log(LOG_DEBUG, " Dropped it");
1582 reclist->records[reclist->num_records] =
1583 surrogatediagrec(a, freq.basename, 16, 0);
1584 reclist->num_records++;
1585 *next = freq.last_in_set ? 0 : recno + 1;
1586 dumped_records += this_length;
1590 else /* too big entirely */
1592 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1593 reclist->records[reclist->num_records] =
1594 surrogatediagrec(a, freq.basename, 17, 0);
1595 reclist->num_records++;
1596 *next = freq.last_in_set ? 0 : recno + 1;
1597 dumped_records += this_length;
1602 if (!(thisrec = (Z_NamePlusRecord *)
1603 odr_malloc(a->encode, sizeof(*thisrec))))
1605 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1606 strlen(freq.basename) + 1)))
1608 strcpy(thisrec->databaseName, freq.basename);
1609 thisrec->which = Z_NamePlusRecord_databaseRecord;
1611 if (freq.output_format_raw)
1613 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1614 freq.output_format = ident->value;
1616 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1617 freq.record, freq.len);
1618 if (!thisrec->u.databaseRecord)
1620 reclist->records[reclist->num_records] = thisrec;
1621 reclist->num_records++;
1622 *next = freq.last_in_set ? 0 : recno + 1;
1624 *num = reclist->num_records;
1628 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1631 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1632 bend_search_rr *bsrr =
1633 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1635 yaz_log(LOG_LOG, "Got SearchRequest.");
1637 bsrr->request = reqb;
1638 bsrr->association = assoc;
1639 bsrr->referenceId = req->referenceId;
1640 save_referenceId (reqb, bsrr->referenceId);
1642 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1643 if (req->databaseNames)
1646 for (i = 0; i < req->num_databaseNames; i++)
1647 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1649 yaz_log_zquery(req->query);
1651 if (assoc->init->bend_search)
1653 bsrr->setname = req->resultSetName;
1654 bsrr->replace_set = *req->replaceIndicator;
1655 bsrr->num_bases = req->num_databaseNames;
1656 bsrr->basenames = req->databaseNames;
1657 bsrr->query = req->query;
1658 bsrr->stream = assoc->encode;
1659 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1660 bsrr->decode = assoc->decode;
1661 bsrr->print = assoc->print;
1664 bsrr->errstring = NULL;
1665 bsrr->search_info = NULL;
1666 (assoc->init->bend_search)(assoc->backend, bsrr);
1670 return response_searchRequest(assoc, reqb, bsrr, fd);
1673 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1676 * Prepare a searchresponse based on the backend results. We probably want
1677 * to look at making the fetching of records nonblocking as well, but
1678 * so far, we'll keep things simple.
1679 * If bsrt is null, that means we're called in response to a communications
1680 * event, and we'll have to get the response for ourselves.
1682 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1683 bend_search_rr *bsrt, int *fd)
1685 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1686 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1687 Z_SearchResponse *resp = (Z_SearchResponse *)
1688 odr_malloc (assoc->encode, sizeof(*resp));
1689 int *nulint = odr_intdup (assoc->encode, 0);
1690 bool_t *sr = odr_intdup(assoc->encode, 1);
1691 int *next = odr_intdup(assoc->encode, 0);
1692 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1694 apdu->which = Z_APDU_searchResponse;
1695 apdu->u.searchResponse = resp;
1696 resp->referenceId = req->referenceId;
1697 resp->additionalSearchInfo = 0;
1698 resp->otherInfo = 0;
1700 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1702 yaz_log(LOG_FATAL, "Bad result from backend");
1705 else if (bsrt->errcode)
1707 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1708 resp->resultCount = nulint;
1709 resp->numberOfRecordsReturned = nulint;
1710 resp->nextResultSetPosition = nulint;
1711 resp->searchStatus = nulint;
1712 resp->resultSetStatus = none;
1713 resp->presentStatus = 0;
1717 int *toget = odr_intdup(assoc->encode, 0);
1718 int *presst = odr_intdup(assoc->encode, 0);
1719 Z_RecordComposition comp, *compp = 0;
1721 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1724 resp->resultCount = &bsrt->hits;
1726 comp.which = Z_RecordComp_simple;
1727 /* how many records does the user agent want, then? */
1728 if (bsrt->hits <= *req->smallSetUpperBound)
1730 *toget = bsrt->hits;
1731 if ((comp.u.simple = req->smallSetElementSetNames))
1734 else if (bsrt->hits < *req->largeSetLowerBound)
1736 *toget = *req->mediumSetPresentNumber;
1737 if (*toget > bsrt->hits)
1738 *toget = bsrt->hits;
1739 if ((comp.u.simple = req->mediumSetElementSetNames))
1745 if (*toget && !resp->records)
1750 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1753 form = prefformat->value;
1754 resp->records = pack_records(assoc, req->resultSetName, 1,
1755 toget, compp, next, presst, form, req->referenceId,
1756 req->preferredRecordSyntax);
1759 resp->numberOfRecordsReturned = toget;
1760 resp->nextResultSetPosition = next;
1761 resp->searchStatus = sr;
1762 resp->resultSetStatus = 0;
1763 resp->presentStatus = presst;
1767 if (*resp->resultCount)
1769 resp->numberOfRecordsReturned = nulint;
1770 resp->nextResultSetPosition = next;
1771 resp->searchStatus = sr;
1772 resp->resultSetStatus = 0;
1773 resp->presentStatus = 0;
1776 resp->additionalSearchInfo = bsrt->search_info;
1781 * Maybe we got a little over-friendly when we designed bend_fetch to
1782 * get only one record at a time. Some backends can optimise multiple-record
1783 * fetches, and at any rate, there is some overhead involved in
1784 * all that selecting and hopping around. Problem is, of course, that the
1785 * frontend can't know ahead of time how many records it'll need to
1786 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1787 * is downright lousy as a bulk data transfer protocol.
1789 * To start with, we'll do the fetching of records from the backend
1790 * in one operation: To save some trips in and out of the event-handler,
1791 * and to simplify the interface to pack_records. At any rate, asynch
1792 * operation is more fun in operations that have an unpredictable execution
1793 * speed - which is normally more true for search than for present.
1795 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1798 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1802 Z_PresentResponse *resp;
1806 yaz_log(LOG_LOG, "Got PresentRequest.");
1808 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1811 form = prefformat->value;
1812 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1814 resp->presentStatus = odr_intdup(assoc->encode, 0);
1815 if (assoc->init->bend_present)
1817 bend_present_rr *bprr = (bend_present_rr *)
1818 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1819 bprr->setname = req->resultSetId;
1820 bprr->start = *req->resultSetStartPoint;
1821 bprr->number = *req->numberOfRecordsRequested;
1822 bprr->format = form;
1823 bprr->comp = req->recordComposition;
1824 bprr->referenceId = req->referenceId;
1825 bprr->stream = assoc->encode;
1826 bprr->print = assoc->print;
1827 bprr->request = reqb;
1828 bprr->association = assoc;
1830 bprr->errstring = NULL;
1831 (*assoc->init->bend_present)(assoc->backend, bprr);
1837 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1838 *resp->presentStatus = Z_PRES_FAILURE;
1841 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1842 next = odr_intdup(assoc->encode, 0);
1843 num = odr_intdup(assoc->encode, 0);
1845 apdu->which = Z_APDU_presentResponse;
1846 apdu->u.presentResponse = resp;
1847 resp->referenceId = req->referenceId;
1848 resp->otherInfo = 0;
1852 *num = *req->numberOfRecordsRequested;
1854 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1855 num, req->recordComposition, next, resp->presentStatus,
1856 form, req->referenceId, req->preferredRecordSyntax);
1860 resp->numberOfRecordsReturned = num;
1861 resp->nextResultSetPosition = next;
1867 * Scan was implemented rather in a hurry, and with support for only the basic
1868 * elements of the service in the backend API. Suggestions are welcome.
1870 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1872 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1873 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1874 Z_ScanResponse *res = (Z_ScanResponse *)
1875 odr_malloc (assoc->encode, sizeof(*res));
1876 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1877 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1878 Z_ListEntries *ents = (Z_ListEntries *)
1879 odr_malloc (assoc->encode, sizeof(*ents));
1880 Z_DiagRecs *diagrecs_p = NULL;
1882 bend_scan_rr *bsrr = (bend_scan_rr *)
1883 odr_malloc (assoc->encode, sizeof(*bsrr));
1884 struct scan_entry *save_entries;
1886 yaz_log(LOG_LOG, "Got ScanRequest");
1888 apdu->which = Z_APDU_scanResponse;
1889 apdu->u.scanResponse = res;
1890 res->referenceId = req->referenceId;
1892 /* if step is absent, set it to 0 */
1893 res->stepSize = odr_intdup(assoc->encode, 0);
1895 *res->stepSize = *req->stepSize;
1897 res->scanStatus = scanStatus;
1898 res->numberOfEntriesReturned = numberOfEntriesReturned;
1899 res->positionOfTerm = 0;
1900 res->entries = ents;
1901 ents->num_entries = 0;
1902 ents->entries = NULL;
1903 ents->num_nonsurrogateDiagnostics = 0;
1904 ents->nonsurrogateDiagnostics = NULL;
1905 res->attributeSet = 0;
1908 if (req->databaseNames)
1911 for (i = 0; i < req->num_databaseNames; i++)
1912 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1914 bsrr->num_bases = req->num_databaseNames;
1915 bsrr->basenames = req->databaseNames;
1916 bsrr->num_entries = *req->numberOfTermsRequested;
1917 bsrr->term = req->termListAndStartPoint;
1918 bsrr->referenceId = req->referenceId;
1919 bsrr->stream = assoc->encode;
1920 bsrr->print = assoc->print;
1921 bsrr->step_size = res->stepSize;
1923 /* Note that version 2.0 of YAZ and older did not set entries ..
1924 We do now. And when we do it's easier to extend the scan entry
1925 We know that if the scan handler did set entries, it will
1926 not know of new member display_term.
1928 if (bsrr->num_entries > 0)
1931 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1933 for (i = 0; i<bsrr->num_entries; i++)
1935 bsrr->entries[i].term = 0;
1936 bsrr->entries[i].occurrences = 0;
1937 bsrr->entries[i].errcode = 0;
1938 bsrr->entries[i].errstring = 0;
1939 bsrr->entries[i].display_term = 0;
1942 save_entries = bsrr->entries; /* save it so we can compare later */
1944 if (req->attributeSet &&
1945 (attset = oid_getentbyoid(req->attributeSet)) &&
1946 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
1947 bsrr->attributeset = attset->value;
1949 bsrr->attributeset = VAL_NONE;
1950 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
1951 bsrr->term_position = req->preferredPositionInResponse ?
1952 *req->preferredPositionInResponse : 1;
1953 ((int (*)(void *, bend_scan_rr *))
1954 (*assoc->init->bend_scan))(assoc->backend, bsrr);
1956 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
1960 Z_Entry **tab = (Z_Entry **)
1961 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
1963 if (bsrr->status == BEND_SCAN_PARTIAL)
1964 *scanStatus = Z_Scan_partial_5;
1966 *scanStatus = Z_Scan_success;
1967 ents->entries = tab;
1968 ents->num_entries = bsrr->num_entries;
1969 res->numberOfEntriesReturned = &ents->num_entries;
1970 res->positionOfTerm = &bsrr->term_position;
1971 for (i = 0; i < bsrr->num_entries; i++)
1977 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
1978 if (bsrr->entries[i].occurrences >= 0)
1980 e->which = Z_Entry_termInfo;
1981 e->u.termInfo = t = (Z_TermInfo *)
1982 odr_malloc(assoc->encode, sizeof(*t));
1983 t->suggestedAttributes = 0;
1985 if (save_entries == bsrr->entries &&
1986 bsrr->entries[i].display_term)
1988 /* the entries was NOT set by the handler. So it's
1989 safe to test for new member display_term. It is
1992 t->displayTerm = odr_strdup(assoc->encode,
1993 bsrr->entries[i].display_term);
1995 t->alternativeTerm = 0;
1996 t->byAttributes = 0;
1997 t->otherTermInfo = 0;
1998 t->globalOccurrences = &bsrr->entries[i].occurrences;
1999 t->term = (Z_Term *)
2000 odr_malloc(assoc->encode, sizeof(*t->term));
2001 t->term->which = Z_Term_general;
2002 t->term->u.general = o =
2003 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2004 o->buf = (unsigned char *)
2005 odr_malloc(assoc->encode, o->len = o->size =
2006 strlen(bsrr->entries[i].term));
2007 memcpy(o->buf, bsrr->entries[i].term, o->len);
2008 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2009 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2013 Z_DiagRecs *drecs = diagrecs (assoc,
2014 bsrr->entries[i].errcode,
2015 bsrr->entries[i].errstring);
2016 assert (drecs->num_diagRecs == 1);
2017 e->which = Z_Entry_surrogateDiagnostic;
2018 assert (drecs->diagRecs[0]);
2019 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2025 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2026 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2031 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2034 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2035 Z_SortResponse *res = (Z_SortResponse *)
2036 odr_malloc (assoc->encode, sizeof(*res));
2037 bend_sort_rr *bsrr = (bend_sort_rr *)
2038 odr_malloc (assoc->encode, sizeof(*bsrr));
2040 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2042 yaz_log(LOG_LOG, "Got SortRequest.");
2044 bsrr->num_input_setnames = req->num_inputResultSetNames;
2045 bsrr->input_setnames = req->inputResultSetNames;
2046 bsrr->referenceId = req->referenceId;
2047 bsrr->output_setname = req->sortedResultSetName;
2048 bsrr->sort_sequence = req->sortSequence;
2049 bsrr->stream = assoc->encode;
2050 bsrr->print = assoc->print;
2052 bsrr->sort_status = Z_SortStatus_failure;
2054 bsrr->errstring = 0;
2056 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2058 res->referenceId = bsrr->referenceId;
2059 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2060 res->resultSetStatus = 0;
2063 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2064 res->diagnostics = dr->diagRecs;
2065 res->num_diagnostics = dr->num_diagRecs;
2069 res->num_diagnostics = 0;
2070 res->diagnostics = 0;
2072 res->resultCount = 0;
2075 apdu->which = Z_APDU_sortResponse;
2076 apdu->u.sortResponse = res;
2080 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2083 Z_DeleteResultSetRequest *req =
2084 reqb->apdu_request->u.deleteResultSetRequest;
2085 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2086 odr_malloc (assoc->encode, sizeof(*res));
2087 bend_delete_rr *bdrr = (bend_delete_rr *)
2088 odr_malloc (assoc->encode, sizeof(*bdrr));
2089 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2091 yaz_log(LOG_LOG, "Got DeleteRequest.");
2093 bdrr->num_setnames = req->num_resultSetList;
2094 bdrr->setnames = req->resultSetList;
2095 bdrr->stream = assoc->encode;
2096 bdrr->print = assoc->print;
2097 bdrr->function = *req->deleteFunction;
2098 bdrr->referenceId = req->referenceId;
2100 if (bdrr->num_setnames > 0)
2103 bdrr->statuses = (int*)
2104 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2105 bdrr->num_setnames);
2106 for (i = 0; i < bdrr->num_setnames; i++)
2107 bdrr->statuses[i] = 0;
2109 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2111 res->referenceId = req->referenceId;
2113 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2115 res->deleteListStatuses = 0;
2116 if (bdrr->num_setnames > 0)
2119 res->deleteListStatuses = (Z_ListStatuses *)
2120 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2121 res->deleteListStatuses->num = bdrr->num_setnames;
2122 res->deleteListStatuses->elements =
2124 odr_malloc (assoc->encode,
2125 sizeof(*res->deleteListStatuses->elements) *
2126 bdrr->num_setnames);
2127 for (i = 0; i<bdrr->num_setnames; i++)
2129 res->deleteListStatuses->elements[i] =
2131 odr_malloc (assoc->encode,
2132 sizeof(**res->deleteListStatuses->elements));
2133 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2134 res->deleteListStatuses->elements[i]->id =
2135 odr_strdup (assoc->encode, bdrr->setnames[i]);
2139 res->numberNotDeleted = 0;
2140 res->bulkStatuses = 0;
2141 res->deleteMessage = 0;
2144 apdu->which = Z_APDU_deleteResultSetResponse;
2145 apdu->u.deleteResultSetResponse = res;
2149 static void process_close(association *assoc, request *reqb)
2151 Z_Close *req = reqb->apdu_request->u.close;
2152 static char *reasons[] =
2159 "securityViolation",
2166 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2167 reasons[*req->closeReason], req->diagnosticInformation ?
2168 req->diagnosticInformation : "NULL");
2169 if (assoc->version < 3) /* to make do_force respond with close */
2171 do_close_req(assoc, Z_Close_finished,
2172 "Association terminated by client", reqb);
2175 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2179 reqb->len_refid = refid->len;
2180 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2181 memcpy (reqb->refid, refid->buf, refid->len);
2185 reqb->len_refid = 0;
2190 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2192 process_z_response (a, req, res);
2195 bend_request bend_request_mk (bend_association a)
2197 request *nreq = request_get (&a->outgoing);
2198 nreq->request_mem = nmem_create ();
2202 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2207 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2208 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2209 id->len = id->size = req->len_refid;
2210 memcpy (id->buf, req->refid, req->len_refid);
2214 void bend_request_destroy (bend_request *req)
2216 nmem_destroy((*req)->request_mem);
2217 request_release(*req);
2221 int bend_backend_respond (bend_association a, bend_request req)
2225 r = process_z_request (a, req, &msg);
2227 yaz_log (LOG_WARN, "%s", msg);
2231 void bend_request_setdata(bend_request r, void *p)
2236 void *bend_request_getdata(bend_request r)
2238 return r->clientData;
2241 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2243 bend_segment_rr req;
2245 req.segment = reqb->apdu_request->u.segmentRequest;
2246 req.stream = assoc->encode;
2247 req.decode = assoc->decode;
2248 req.print = assoc->print;
2249 req.association = assoc;
2251 (*assoc->init->bend_segment)(assoc->backend, &req);
2256 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2258 bend_esrequest_rr esrequest;
2260 Z_ExtendedServicesRequest *req =
2261 reqb->apdu_request->u.extendedServicesRequest;
2262 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2264 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2266 yaz_log(LOG_DEBUG,"inside Process esRequest");
2268 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2269 esrequest.stream = assoc->encode;
2270 esrequest.decode = assoc->decode;
2271 esrequest.print = assoc->print;
2272 esrequest.errcode = 0;
2273 esrequest.errstring = NULL;
2274 esrequest.request = reqb;
2275 esrequest.association = assoc;
2276 esrequest.taskPackage = 0;
2277 esrequest.referenceId = req->referenceId;
2279 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2281 /* If the response is being delayed, return NULL */
2282 if (esrequest.request == NULL)
2285 resp->referenceId = req->referenceId;
2287 if (esrequest.errcode == -1)
2289 /* Backend service indicates request will be processed */
2290 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2291 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2293 else if (esrequest.errcode == 0)
2295 /* Backend service indicates request will be processed */
2296 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2297 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2301 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2302 esrequest.errstring);
2304 /* Backend indicates error, request will not be processed */
2305 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2306 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2307 resp->num_diagnostics = diagRecs->num_diagRecs;
2308 resp->diagnostics = diagRecs->diagRecs;
2310 /* Do something with the members of bend_extendedservice */
2311 if (esrequest.taskPackage)
2312 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2313 (const char *) esrequest.taskPackage,
2315 yaz_log(LOG_DEBUG,"Send the result apdu");