2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.19 2004-01-27 12:15:12 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 yaz_mk_std_diagnostic(assoc->encode,
635 srw_res->diagnostics, srw_error, 0);
639 rr.stream = assoc->encode;
640 rr.decode = assoc->decode;
641 rr.print = assoc->print;
643 rr.association = assoc;
649 yaz_log_zquery(rr.query);
650 (assoc->init->bend_search)(assoc->backend, &rr);
651 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
654 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
655 if (rr.errcode == 109) /* database unavailable */
660 srw_res->num_diagnostics = 1;
661 srw_res->diagnostics = (Z_SRW_diagnostic *)
662 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
663 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
664 yaz_diag_bib1_to_srw (rr.errcode),
666 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
667 *srw_res->diagnostics[0].code);
671 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
672 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
674 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
675 start, number, rr.hits);
677 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
684 yaz_log(LOG_LOG, "Request out or range");
689 int packing = Z_SRW_recordPacking_string;
690 if (start + number > rr.hits)
691 number = rr.hits - start + 1;
692 if (srw_req->recordPacking &&
693 !strcmp(srw_req->recordPacking, "xml"))
694 packing = Z_SRW_recordPacking_XML;
695 srw_res->records = (Z_SRW_record *)
696 odr_malloc(assoc->encode,
697 number * sizeof(*srw_res->records));
698 for (i = 0; i<number; i++)
702 srw_res->records[j].recordPacking = packing;
703 srw_res->records[j].recordData_buf = 0;
704 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
705 errcode = srw_bend_fetch(assoc, i+start, srw_req,
706 srw_res->records + j);
709 srw_res->num_diagnostics = 1;
710 srw_res->diagnostics = (Z_SRW_diagnostic *)
711 odr_malloc(assoc->encode,
712 sizeof(*srw_res->diagnostics));
714 yaz_mk_std_diagnostic(assoc->encode,
715 srw_res->diagnostics,
716 yaz_diag_bib1_to_srw (errcode),
720 if (srw_res->records[j].recordData_buf)
723 srw_res->num_records = j;
725 srw_res->records = 0;
731 static void srw_bend_explain(association *assoc, request *req,
732 Z_SRW_explainRequest *srw_req,
733 Z_SRW_explainResponse *srw_res,
736 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
740 yaz_log(LOG_DEBUG, "srw_bend_init");
741 if (!srw_bend_init(assoc))
746 if (assoc->init && assoc->init->bend_explain)
750 rr.stream = assoc->encode;
751 rr.decode = assoc->decode;
752 rr.print = assoc->print;
754 rr.database = srw_req->database;
755 (*assoc->init->bend_explain)(assoc->backend, &rr);
758 int packing = Z_SRW_recordPacking_string;
759 if (srw_req->recordPacking &&
760 !strcmp(srw_req->recordPacking, "xml"))
761 packing = Z_SRW_recordPacking_XML;
762 srw_res->record.recordSchema = 0;
763 srw_res->record.recordPacking = packing;
764 srw_res->record.recordData_buf = rr.explain_buf;
765 srw_res->record.recordData_len = strlen(rr.explain_buf);
766 srw_res->record.recordPosition = 0;
772 static void process_http_request(association *assoc, request *req)
774 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
775 ODR o = assoc->encode;
776 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
778 Z_SOAP *soap_package = 0;
781 Z_HTTP_Response *hres = 0;
783 char *stylesheet = 0;
784 Z_SRW_diagnostic *diagnostic = 0;
785 int num_diagnostic = 0;
787 if (!strcmp(hreq->path, "/test"))
789 p = z_get_HTTP_Response(o, 200);
790 hres = p->u.HTTP_Response;
791 hres->content_buf = "1234567890\n";
792 hres->content_len = strlen(hres->content_buf);
797 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
798 yaz_log(LOG_DEBUG, "yaz_srw_decode returned %d", r);
800 if (r == 2) /* not taken */
802 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
803 &diagnostic, &num_diagnostic);
804 yaz_log(LOG_DEBUG, "yaz_sru_decode returned %d", r);
806 if (r == 0) /* decode SRW/SRU OK .. */
809 if (sr->which == Z_SRW_searchRetrieve_request)
812 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
814 stylesheet = sr->u.request->stylesheet;
817 res->u.response->diagnostics = diagnostic;
818 res->u.response->num_diagnostics = num_diagnostic;
822 srw_bend_search(assoc, req, sr->u.request, res->u.response,
825 if (http_code == 200)
826 soap_package->u.generic->p = res;
828 else if (sr->which == Z_SRW_explain_request)
830 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
831 stylesheet = sr->u.explain_request->stylesheet;
834 res->u.explain_response->diagnostics = diagnostic;
835 res->u.explain_response->num_diagnostics = num_diagnostic;
837 srw_bend_explain(assoc, req, sr->u.explain_request,
838 res->u.explain_response, &http_code);
839 if (http_code == 200)
840 soap_package->u.generic->p = res;
842 else if (sr->which == Z_SRW_scan_request)
844 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
845 stylesheet = sr->u.scan_request->stylesheet;
848 res->u.scan_response->diagnostics = diagnostic;
849 res->u.scan_response->num_diagnostics = num_diagnostic;
851 yaz_add_srw_diagnostic(o,
852 &res->u.scan_response->diagnostics,
853 &res->u.scan_response->num_diagnostics,
855 if (http_code == 200)
856 soap_package->u.generic->p = res;
861 z_soap_error(assoc->encode, soap_package,
862 "SOAP-ENV:Client", "Bad method", 0);
864 if (http_code == 200 || http_code == 500)
866 static Z_SOAP_Handler soap_handlers[3] = {
868 {"http://www.loc.gov/zing/srw/", 0,
869 (Z_SOAP_fun) yaz_srw_codec},
870 {"http://www.loc.gov/zing/srw/v1.0/", 0,
871 (Z_SOAP_fun) yaz_srw_codec},
877 p = z_get_HTTP_Response(o, 200);
878 hres = p->u.HTTP_Response;
879 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
880 &hres->content_buf, &hres->content_len,
881 soap_handlers, charset, stylesheet);
882 hres->code = http_code;
884 strcpy(ctype, "text/xml");
887 strcat(ctype, "; charset=");
888 strcat(ctype, charset);
890 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
893 p = z_get_HTTP_Response(o, http_code);
897 p = z_get_HTTP_Response(o, 500);
898 hres = p->u.HTTP_Response;
899 if (!strcmp(hreq->version, "1.0"))
901 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
902 if (v && !strcmp(v, "Keep-Alive"))
906 hres->version = "1.0";
910 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
911 if (v && !strcmp(v, "close"))
915 hres->version = "1.1";
919 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
920 assoc->state = ASSOC_DEAD;
921 assoc->cs_get_mask = 0;
926 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
928 if (alive && isdigit(*alive))
932 if (t < 0 || t > 3600)
934 iochan_settimeout(assoc->client_chan,t);
935 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
937 process_gdu_response(assoc, req, p);
940 static void process_gdu_request(association *assoc, request *req)
942 if (req->gdu_request->which == Z_GDU_Z3950)
945 req->apdu_request = req->gdu_request->u.z3950;
946 if (process_z_request(assoc, req, &msg) < 0)
947 do_close_req(assoc, Z_Close_systemProblem, msg, req);
949 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
950 process_http_request(assoc, req);
953 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
958 * Initiate request processing.
960 static int process_z_request(association *assoc, request *req, char **msg)
966 *msg = "Unknown Error";
967 assert(req && req->state == REQUEST_IDLE);
968 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
970 *msg = "Missing InitRequest";
973 switch (req->apdu_request->which)
975 case Z_APDU_initRequest:
976 iochan_settimeout(assoc->client_chan,
977 statserv_getcontrol()->idle_timeout * 60);
978 res = process_initRequest(assoc, req); break;
979 case Z_APDU_searchRequest:
980 res = process_searchRequest(assoc, req, &fd); break;
981 case Z_APDU_presentRequest:
982 res = process_presentRequest(assoc, req, &fd); break;
983 case Z_APDU_scanRequest:
984 if (assoc->init->bend_scan)
985 res = process_scanRequest(assoc, req, &fd);
988 *msg = "Cannot handle Scan APDU";
992 case Z_APDU_extendedServicesRequest:
993 if (assoc->init->bend_esrequest)
994 res = process_ESRequest(assoc, req, &fd);
997 *msg = "Cannot handle Extended Services APDU";
1001 case Z_APDU_sortRequest:
1002 if (assoc->init->bend_sort)
1003 res = process_sortRequest(assoc, req, &fd);
1006 *msg = "Cannot handle Sort APDU";
1011 process_close(assoc, req);
1013 case Z_APDU_deleteResultSetRequest:
1014 if (assoc->init->bend_delete)
1015 res = process_deleteRequest(assoc, req, &fd);
1018 *msg = "Cannot handle Delete APDU";
1022 case Z_APDU_segmentRequest:
1023 if (assoc->init->bend_segment)
1025 res = process_segmentRequest (assoc, req);
1029 *msg = "Cannot handle Segment APDU";
1034 *msg = "Bad APDU received";
1039 yaz_log(LOG_DEBUG, " result immediately available");
1040 retval = process_z_response(assoc, req, res);
1044 yaz_log(LOG_DEBUG, " result unavailble");
1047 else /* no result yet - one will be provided later */
1051 /* Set up an I/O handler for the fd supplied by the backend */
1053 yaz_log(LOG_DEBUG, " establishing handler for result");
1054 req->state = REQUEST_PENDING;
1055 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1057 iochan_setdata(chan, assoc);
1064 * Handle message from the backend.
1066 void backend_response(IOCHAN i, int event)
1068 association *assoc = (association *)iochan_getdata(i);
1069 request *req = request_head(&assoc->incoming);
1073 yaz_log(LOG_DEBUG, "backend_response");
1074 assert(assoc && req && req->state != REQUEST_IDLE);
1075 /* determine what it is we're waiting for */
1076 switch (req->apdu_request->which)
1078 case Z_APDU_searchRequest:
1079 res = response_searchRequest(assoc, req, 0, &fd); break;
1081 case Z_APDU_presentRequest:
1082 res = response_presentRequest(assoc, req, 0, &fd); break;
1083 case Z_APDU_scanRequest:
1084 res = response_scanRequest(assoc, req, 0, &fd); break;
1087 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1090 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1092 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1093 do_close(assoc, Z_Close_systemProblem, 0);
1097 else if (!res) /* no result yet - try again later */
1099 yaz_log(LOG_DEBUG, " no result yet");
1100 iochan_setfd(i, fd); /* in case fd has changed */
1105 * Encode response, and transfer the request structure to the outgoing queue.
1107 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1109 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1113 if (!z_GDU(assoc->print, &res, 0, 0))
1114 yaz_log(LOG_WARN, "ODR print error: %s",
1115 odr_errmsg(odr_geterror(assoc->print)));
1116 odr_reset(assoc->print);
1118 if (!z_GDU(assoc->encode, &res, 0, 0))
1120 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1121 odr_errmsg(odr_geterror(assoc->decode)),
1122 odr_getelement(assoc->decode));
1123 request_release(req);
1126 req->response = odr_getbuf(assoc->encode, &req->len_response,
1127 &req->size_response);
1128 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1129 odr_reset(assoc->encode);
1130 req->state = REQUEST_IDLE;
1131 request_enq(&assoc->outgoing, req);
1132 /* turn the work over to the ir_session handler */
1133 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1134 assoc->cs_put_mask = EVENT_OUTPUT;
1135 /* Is there more work to be done? give that to the input handler too */
1137 if (request_head(&assoc->incoming))
1139 yaz_log (LOG_DEBUG, "more work to be done");
1140 iochan_setevent(assoc->client_chan, EVENT_WORK);
1147 * Encode response, and transfer the request structure to the outgoing queue.
1149 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1151 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1152 gres->which = Z_GDU_Z3950;
1153 gres->u.z3950 = res;
1155 return process_gdu_response(assoc, req, gres);
1160 * Handle init request.
1161 * At the moment, we don't check the options
1162 * anywhere else in the code - we just try not to do anything that would
1163 * break a naive client. We'll toss 'em into the association block when
1164 * we need them there.
1166 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1168 statserv_options_block *cb = statserv_getcontrol();
1169 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1170 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1171 Z_InitResponse *resp = apdu->u.initResponse;
1172 bend_initresult *binitres;
1176 yaz_log(LOG_LOG, "Got initRequest");
1177 if (req->implementationId)
1178 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1179 if (req->implementationName)
1180 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1181 if (req->implementationVersion)
1182 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1184 assoc_init_reset(assoc);
1186 assoc->init->auth = req->idAuthentication;
1187 assoc->init->referenceId = req->referenceId;
1189 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1191 Z_CharSetandLanguageNegotiation *negotiation =
1192 yaz_get_charneg_record (req->otherInfo);
1194 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1195 assoc->init->charneg_request = negotiation;
1198 if (!(binitres = (*cb->bend_init)(assoc->init)))
1200 yaz_log(LOG_WARN, "Bad response from backend.");
1204 assoc->backend = binitres->handle;
1205 if ((assoc->init->bend_sort))
1206 yaz_log (LOG_DEBUG, "Sort handler installed");
1207 if ((assoc->init->bend_search))
1208 yaz_log (LOG_DEBUG, "Search handler installed");
1209 if ((assoc->init->bend_present))
1210 yaz_log (LOG_DEBUG, "Present handler installed");
1211 if ((assoc->init->bend_esrequest))
1212 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1213 if ((assoc->init->bend_delete))
1214 yaz_log (LOG_DEBUG, "Delete handler installed");
1215 if ((assoc->init->bend_scan))
1216 yaz_log (LOG_DEBUG, "Scan handler installed");
1217 if ((assoc->init->bend_segment))
1218 yaz_log (LOG_DEBUG, "Segment handler installed");
1220 resp->referenceId = req->referenceId;
1222 /* let's tell the client what we can do */
1223 if (ODR_MASK_GET(req->options, Z_Options_search))
1225 ODR_MASK_SET(resp->options, Z_Options_search);
1226 strcat(options, "srch");
1228 if (ODR_MASK_GET(req->options, Z_Options_present))
1230 ODR_MASK_SET(resp->options, Z_Options_present);
1231 strcat(options, " prst");
1233 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1234 assoc->init->bend_delete)
1236 ODR_MASK_SET(resp->options, Z_Options_delSet);
1237 strcat(options, " del");
1239 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1240 assoc->init->bend_esrequest)
1242 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1243 strcat (options, " extendedServices");
1245 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1247 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1248 strcat(options, " namedresults");
1250 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1252 ODR_MASK_SET(resp->options, Z_Options_scan);
1253 strcat(options, " scan");
1255 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1257 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1258 strcat(options, " concurrop");
1260 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1262 ODR_MASK_SET(resp->options, Z_Options_sort);
1263 strcat(options, " sort");
1266 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1267 && assoc->init->charneg_response)
1269 Z_OtherInformation **p;
1270 Z_OtherInformationUnit *p0;
1272 yaz_oi_APDU(apdu, &p);
1274 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1275 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1277 p0->which = Z_OtherInfo_externallyDefinedInfo;
1278 p0->information.externallyDefinedInfo =
1279 assoc->init->charneg_response;
1281 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1282 strcat(options, " negotiation");
1285 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1287 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1288 assoc->version = 1; /* 1 & 2 are equivalent */
1290 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1292 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1295 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1297 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1301 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1302 assoc->maximumRecordSize = *req->maximumRecordSize;
1303 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1304 assoc->maximumRecordSize = control_block->maxrecordsize;
1305 assoc->preferredMessageSize = *req->preferredMessageSize;
1306 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1307 assoc->preferredMessageSize = assoc->maximumRecordSize;
1309 resp->preferredMessageSize = &assoc->preferredMessageSize;
1310 resp->maximumRecordSize = &assoc->maximumRecordSize;
1312 resp->implementationId = odr_prepend(assoc->encode,
1313 assoc->init->implementation_id,
1314 resp->implementationId);
1316 resp->implementationName = odr_prepend(assoc->encode,
1317 assoc->init->implementation_name,
1318 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1320 version = odr_strdup(assoc->encode, "$Revision: 1.19 $");
1321 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1322 version[strlen(version)-2] = '\0';
1323 resp->implementationVersion = odr_prepend(assoc->encode,
1324 assoc->init->implementation_version,
1325 odr_prepend(assoc->encode, &version[11],
1326 resp->implementationVersion));
1328 if (binitres->errcode)
1330 yaz_log(LOG_LOG, "Connection rejected by backend.");
1332 assoc->state = ASSOC_DEAD;
1333 resp->userInformationField = init_diagnostics(assoc->encode,
1335 binitres->errstring);
1338 assoc->state = ASSOC_UP;
1343 * Diagnostic in default format, to be returned as either a surrogate
1344 * or non-surrogate diagnostic in the context of an open session, or
1345 * as User-information when an Init is refused.
1347 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1349 int *err = odr_intdup(odr, error);
1350 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1351 odr_malloc (odr, sizeof(*dr));
1353 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1354 addinfo ? " -- " : "", addinfo ? addinfo : "");
1356 dr->diagnosticSetId =
1357 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1358 dr->condition = err;
1359 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1360 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1365 * Set the specified `errcode' and `errstring' into a UserInfo-1
1366 * external to be returned to the client in accordance with Z35.90
1367 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1368 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1370 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1374 Z_OtherInformation *u;
1375 Z_OtherInformationUnit *l;
1376 Z_DiagnosticFormat *d;
1377 Z_DiagnosticFormat_s *e;
1379 x = (Z_External*) odr_malloc(odr, sizeof *x);
1381 x->indirect_reference = 0;
1382 oid.proto = PROTO_Z3950;
1383 oid.oclass = CLASS_USERINFO;
1384 oid.value = VAL_USERINFO1;
1385 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1386 x->which = Z_External_userInfo1;
1388 u = odr_malloc(odr, sizeof *u);
1390 u->num_elements = 1;
1391 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1392 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1395 l->which = Z_OtherInfo_externallyDefinedInfo;
1397 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1398 l->information.externallyDefinedInfo = x2;
1400 x2->indirect_reference = 0;
1401 oid.oclass = CLASS_DIAGSET;
1402 oid.value = VAL_DIAG1;
1403 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1404 x2->which = Z_External_diag1;
1406 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1409 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1410 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1413 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1414 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1419 * nonsurrogate diagnostic record.
1421 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1423 Z_Records *rec = (Z_Records *)
1424 odr_malloc (assoc->encode, sizeof(*rec));
1425 rec->which = Z_Records_NSD;
1426 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1431 * surrogate diagnostic.
1433 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1434 int error, char *addinfo)
1436 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1437 odr_malloc (assoc->encode, sizeof(*rec));
1438 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1440 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1441 rec->databaseName = dbname;
1442 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1443 rec->u.surrogateDiagnostic = drec;
1444 drec->which = Z_DiagRec_defaultFormat;
1445 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1451 * multiple nonsurrogate diagnostics.
1453 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1455 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1456 int *err = odr_intdup(assoc->encode, error);
1457 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1458 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1459 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1460 odr_malloc (assoc->encode, sizeof(*rec));
1462 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1464 recs->num_diagRecs = 1;
1465 recs->diagRecs = recp;
1467 drec->which = Z_DiagRec_defaultFormat;
1468 drec->u.defaultFormat = rec;
1470 rec->diagnosticSetId =
1471 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1472 rec->condition = err;
1474 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1475 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1479 static Z_Records *pack_records(association *a, char *setname, int start,
1480 int *num, Z_RecordComposition *comp,
1481 int *next, int *pres, oid_value format,
1482 Z_ReferenceId *referenceId,
1485 int recno, total_length = 0, toget = *num, dumped_records = 0;
1486 Z_Records *records =
1487 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1488 Z_NamePlusRecordList *reclist =
1489 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1490 Z_NamePlusRecord **list =
1491 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1493 records->which = Z_Records_DBOSD;
1494 records->u.databaseOrSurDiagnostics = reclist;
1495 reclist->num_records = 0;
1496 reclist->records = list;
1497 *pres = Z_PRES_SUCCESS;
1501 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1502 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1503 a->maximumRecordSize);
1504 for (recno = start; reclist->num_records < toget; recno++)
1507 Z_NamePlusRecord *thisrec;
1508 int this_length = 0;
1510 * we get the number of bytes allocated on the stream before any
1511 * allocation done by the backend - this should give us a reasonable
1512 * idea of the total size of the data so far.
1514 total_length = odr_total(a->encode) - dumped_records;
1520 freq.last_in_set = 0;
1521 freq.setname = setname;
1522 freq.surrogate_flag = 0;
1523 freq.number = recno;
1525 freq.request_format = format;
1526 freq.request_format_raw = oid;
1527 freq.output_format = format;
1528 freq.output_format_raw = 0;
1529 freq.stream = a->encode;
1530 freq.print = a->print;
1531 freq.referenceId = referenceId;
1533 (*a->init->bend_fetch)(a->backend, &freq);
1534 /* backend should be able to signal whether error is system-wide
1535 or only pertaining to current record */
1538 if (!freq.surrogate_flag)
1541 *pres = Z_PRES_FAILURE;
1542 /* for 'present request out of range',
1543 set addinfo to record position if not set */
1544 if (freq.errcode == 13 && freq.errstring == 0)
1546 sprintf (s, "%d", recno);
1549 return diagrec(a, freq.errcode, freq.errstring);
1551 reclist->records[reclist->num_records] =
1552 surrogatediagrec(a, freq.basename, freq.errcode,
1554 reclist->num_records++;
1555 *next = freq.last_in_set ? 0 : recno + 1;
1559 this_length = freq.len;
1561 this_length = odr_total(a->encode) - total_length - dumped_records;
1562 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1563 this_length, total_length, dumped_records);
1564 if (a->preferredMessageSize > 0 &&
1565 this_length + total_length > a->preferredMessageSize)
1567 /* record is small enough, really */
1568 if (this_length <= a->preferredMessageSize && recno > start)
1570 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1571 *pres = Z_PRES_PARTIAL_2;
1574 /* record can only be fetched by itself */
1575 if (this_length < a->maximumRecordSize)
1577 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1580 yaz_log(LOG_DEBUG, " Dropped it");
1581 reclist->records[reclist->num_records] =
1582 surrogatediagrec(a, freq.basename, 16, 0);
1583 reclist->num_records++;
1584 *next = freq.last_in_set ? 0 : recno + 1;
1585 dumped_records += this_length;
1589 else /* too big entirely */
1591 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1592 reclist->records[reclist->num_records] =
1593 surrogatediagrec(a, freq.basename, 17, 0);
1594 reclist->num_records++;
1595 *next = freq.last_in_set ? 0 : recno + 1;
1596 dumped_records += this_length;
1601 if (!(thisrec = (Z_NamePlusRecord *)
1602 odr_malloc(a->encode, sizeof(*thisrec))))
1604 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1605 strlen(freq.basename) + 1)))
1607 strcpy(thisrec->databaseName, freq.basename);
1608 thisrec->which = Z_NamePlusRecord_databaseRecord;
1610 if (freq.output_format_raw)
1612 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1613 freq.output_format = ident->value;
1615 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1616 freq.record, freq.len);
1617 if (!thisrec->u.databaseRecord)
1619 reclist->records[reclist->num_records] = thisrec;
1620 reclist->num_records++;
1621 *next = freq.last_in_set ? 0 : recno + 1;
1623 *num = reclist->num_records;
1627 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1630 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1631 bend_search_rr *bsrr =
1632 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1634 yaz_log(LOG_LOG, "Got SearchRequest.");
1636 bsrr->request = reqb;
1637 bsrr->association = assoc;
1638 bsrr->referenceId = req->referenceId;
1639 save_referenceId (reqb, bsrr->referenceId);
1641 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1642 if (req->databaseNames)
1645 for (i = 0; i < req->num_databaseNames; i++)
1646 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1648 yaz_log_zquery(req->query);
1650 if (assoc->init->bend_search)
1652 bsrr->setname = req->resultSetName;
1653 bsrr->replace_set = *req->replaceIndicator;
1654 bsrr->num_bases = req->num_databaseNames;
1655 bsrr->basenames = req->databaseNames;
1656 bsrr->query = req->query;
1657 bsrr->stream = assoc->encode;
1658 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1659 bsrr->decode = assoc->decode;
1660 bsrr->print = assoc->print;
1663 bsrr->errstring = NULL;
1664 bsrr->search_info = NULL;
1665 (assoc->init->bend_search)(assoc->backend, bsrr);
1669 return response_searchRequest(assoc, reqb, bsrr, fd);
1672 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1675 * Prepare a searchresponse based on the backend results. We probably want
1676 * to look at making the fetching of records nonblocking as well, but
1677 * so far, we'll keep things simple.
1678 * If bsrt is null, that means we're called in response to a communications
1679 * event, and we'll have to get the response for ourselves.
1681 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1682 bend_search_rr *bsrt, int *fd)
1684 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1685 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1686 Z_SearchResponse *resp = (Z_SearchResponse *)
1687 odr_malloc (assoc->encode, sizeof(*resp));
1688 int *nulint = odr_intdup (assoc->encode, 0);
1689 bool_t *sr = odr_intdup(assoc->encode, 1);
1690 int *next = odr_intdup(assoc->encode, 0);
1691 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1693 apdu->which = Z_APDU_searchResponse;
1694 apdu->u.searchResponse = resp;
1695 resp->referenceId = req->referenceId;
1696 resp->additionalSearchInfo = 0;
1697 resp->otherInfo = 0;
1699 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1701 yaz_log(LOG_FATAL, "Bad result from backend");
1704 else if (bsrt->errcode)
1706 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1707 resp->resultCount = nulint;
1708 resp->numberOfRecordsReturned = nulint;
1709 resp->nextResultSetPosition = nulint;
1710 resp->searchStatus = nulint;
1711 resp->resultSetStatus = none;
1712 resp->presentStatus = 0;
1716 int *toget = odr_intdup(assoc->encode, 0);
1717 int *presst = odr_intdup(assoc->encode, 0);
1718 Z_RecordComposition comp, *compp = 0;
1720 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1723 resp->resultCount = &bsrt->hits;
1725 comp.which = Z_RecordComp_simple;
1726 /* how many records does the user agent want, then? */
1727 if (bsrt->hits <= *req->smallSetUpperBound)
1729 *toget = bsrt->hits;
1730 if ((comp.u.simple = req->smallSetElementSetNames))
1733 else if (bsrt->hits < *req->largeSetLowerBound)
1735 *toget = *req->mediumSetPresentNumber;
1736 if (*toget > bsrt->hits)
1737 *toget = bsrt->hits;
1738 if ((comp.u.simple = req->mediumSetElementSetNames))
1744 if (*toget && !resp->records)
1749 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1752 form = prefformat->value;
1753 resp->records = pack_records(assoc, req->resultSetName, 1,
1754 toget, compp, next, presst, form, req->referenceId,
1755 req->preferredRecordSyntax);
1758 resp->numberOfRecordsReturned = toget;
1759 resp->nextResultSetPosition = next;
1760 resp->searchStatus = sr;
1761 resp->resultSetStatus = 0;
1762 resp->presentStatus = presst;
1766 if (*resp->resultCount)
1768 resp->numberOfRecordsReturned = nulint;
1769 resp->nextResultSetPosition = next;
1770 resp->searchStatus = sr;
1771 resp->resultSetStatus = 0;
1772 resp->presentStatus = 0;
1775 resp->additionalSearchInfo = bsrt->search_info;
1780 * Maybe we got a little over-friendly when we designed bend_fetch to
1781 * get only one record at a time. Some backends can optimise multiple-record
1782 * fetches, and at any rate, there is some overhead involved in
1783 * all that selecting and hopping around. Problem is, of course, that the
1784 * frontend can't know ahead of time how many records it'll need to
1785 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1786 * is downright lousy as a bulk data transfer protocol.
1788 * To start with, we'll do the fetching of records from the backend
1789 * in one operation: To save some trips in and out of the event-handler,
1790 * and to simplify the interface to pack_records. At any rate, asynch
1791 * operation is more fun in operations that have an unpredictable execution
1792 * speed - which is normally more true for search than for present.
1794 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1797 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1801 Z_PresentResponse *resp;
1805 yaz_log(LOG_LOG, "Got PresentRequest.");
1807 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1810 form = prefformat->value;
1811 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1813 resp->presentStatus = odr_intdup(assoc->encode, 0);
1814 if (assoc->init->bend_present)
1816 bend_present_rr *bprr = (bend_present_rr *)
1817 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1818 bprr->setname = req->resultSetId;
1819 bprr->start = *req->resultSetStartPoint;
1820 bprr->number = *req->numberOfRecordsRequested;
1821 bprr->format = form;
1822 bprr->comp = req->recordComposition;
1823 bprr->referenceId = req->referenceId;
1824 bprr->stream = assoc->encode;
1825 bprr->print = assoc->print;
1826 bprr->request = reqb;
1827 bprr->association = assoc;
1829 bprr->errstring = NULL;
1830 (*assoc->init->bend_present)(assoc->backend, bprr);
1836 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1837 *resp->presentStatus = Z_PRES_FAILURE;
1840 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1841 next = odr_intdup(assoc->encode, 0);
1842 num = odr_intdup(assoc->encode, 0);
1844 apdu->which = Z_APDU_presentResponse;
1845 apdu->u.presentResponse = resp;
1846 resp->referenceId = req->referenceId;
1847 resp->otherInfo = 0;
1851 *num = *req->numberOfRecordsRequested;
1853 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1854 num, req->recordComposition, next, resp->presentStatus,
1855 form, req->referenceId, req->preferredRecordSyntax);
1859 resp->numberOfRecordsReturned = num;
1860 resp->nextResultSetPosition = next;
1866 * Scan was implemented rather in a hurry, and with support for only the basic
1867 * elements of the service in the backend API. Suggestions are welcome.
1869 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1871 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1872 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1873 Z_ScanResponse *res = (Z_ScanResponse *)
1874 odr_malloc (assoc->encode, sizeof(*res));
1875 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1876 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1877 Z_ListEntries *ents = (Z_ListEntries *)
1878 odr_malloc (assoc->encode, sizeof(*ents));
1879 Z_DiagRecs *diagrecs_p = NULL;
1881 bend_scan_rr *bsrr = (bend_scan_rr *)
1882 odr_malloc (assoc->encode, sizeof(*bsrr));
1883 struct scan_entry *save_entries;
1885 yaz_log(LOG_LOG, "Got ScanRequest");
1887 apdu->which = Z_APDU_scanResponse;
1888 apdu->u.scanResponse = res;
1889 res->referenceId = req->referenceId;
1891 /* if step is absent, set it to 0 */
1892 res->stepSize = odr_intdup(assoc->encode, 0);
1894 *res->stepSize = *req->stepSize;
1896 res->scanStatus = scanStatus;
1897 res->numberOfEntriesReturned = numberOfEntriesReturned;
1898 res->positionOfTerm = 0;
1899 res->entries = ents;
1900 ents->num_entries = 0;
1901 ents->entries = NULL;
1902 ents->num_nonsurrogateDiagnostics = 0;
1903 ents->nonsurrogateDiagnostics = NULL;
1904 res->attributeSet = 0;
1907 if (req->databaseNames)
1910 for (i = 0; i < req->num_databaseNames; i++)
1911 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1913 bsrr->num_bases = req->num_databaseNames;
1914 bsrr->basenames = req->databaseNames;
1915 bsrr->num_entries = *req->numberOfTermsRequested;
1916 bsrr->term = req->termListAndStartPoint;
1917 bsrr->referenceId = req->referenceId;
1918 bsrr->stream = assoc->encode;
1919 bsrr->print = assoc->print;
1920 bsrr->step_size = res->stepSize;
1922 /* Note that version 2.0 of YAZ and older did not set entries ..
1923 We do now. And when we do it's easier to extend the scan entry
1924 We know that if the scan handler did set entries, it will
1925 not know of new member display_term.
1927 if (bsrr->num_entries > 0)
1930 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1932 for (i = 0; i<bsrr->num_entries; i++)
1934 bsrr->entries[i].term = 0;
1935 bsrr->entries[i].occurrences = 0;
1936 bsrr->entries[i].errcode = 0;
1937 bsrr->entries[i].errstring = 0;
1938 bsrr->entries[i].display_term = 0;
1941 save_entries = bsrr->entries; /* save it so we can compare later */
1943 if (req->attributeSet &&
1944 (attset = oid_getentbyoid(req->attributeSet)) &&
1945 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
1946 bsrr->attributeset = attset->value;
1948 bsrr->attributeset = VAL_NONE;
1949 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
1950 bsrr->term_position = req->preferredPositionInResponse ?
1951 *req->preferredPositionInResponse : 1;
1952 ((int (*)(void *, bend_scan_rr *))
1953 (*assoc->init->bend_scan))(assoc->backend, bsrr);
1955 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
1959 Z_Entry **tab = (Z_Entry **)
1960 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
1962 if (bsrr->status == BEND_SCAN_PARTIAL)
1963 *scanStatus = Z_Scan_partial_5;
1965 *scanStatus = Z_Scan_success;
1966 ents->entries = tab;
1967 ents->num_entries = bsrr->num_entries;
1968 res->numberOfEntriesReturned = &ents->num_entries;
1969 res->positionOfTerm = &bsrr->term_position;
1970 for (i = 0; i < bsrr->num_entries; i++)
1976 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
1977 if (bsrr->entries[i].occurrences >= 0)
1979 e->which = Z_Entry_termInfo;
1980 e->u.termInfo = t = (Z_TermInfo *)
1981 odr_malloc(assoc->encode, sizeof(*t));
1982 t->suggestedAttributes = 0;
1984 if (save_entries == bsrr->entries &&
1985 bsrr->entries[i].display_term)
1987 /* the entries was NOT set by the handler. So it's
1988 safe to test for new member display_term. It is
1991 t->displayTerm = odr_strdup(assoc->encode,
1992 bsrr->entries[i].display_term);
1994 t->alternativeTerm = 0;
1995 t->byAttributes = 0;
1996 t->otherTermInfo = 0;
1997 t->globalOccurrences = &bsrr->entries[i].occurrences;
1998 t->term = (Z_Term *)
1999 odr_malloc(assoc->encode, sizeof(*t->term));
2000 t->term->which = Z_Term_general;
2001 t->term->u.general = o =
2002 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2003 o->buf = (unsigned char *)
2004 odr_malloc(assoc->encode, o->len = o->size =
2005 strlen(bsrr->entries[i].term));
2006 memcpy(o->buf, bsrr->entries[i].term, o->len);
2007 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2008 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2012 Z_DiagRecs *drecs = diagrecs (assoc,
2013 bsrr->entries[i].errcode,
2014 bsrr->entries[i].errstring);
2015 assert (drecs->num_diagRecs == 1);
2016 e->which = Z_Entry_surrogateDiagnostic;
2017 assert (drecs->diagRecs[0]);
2018 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2024 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2025 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2030 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2033 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2034 Z_SortResponse *res = (Z_SortResponse *)
2035 odr_malloc (assoc->encode, sizeof(*res));
2036 bend_sort_rr *bsrr = (bend_sort_rr *)
2037 odr_malloc (assoc->encode, sizeof(*bsrr));
2039 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2041 yaz_log(LOG_LOG, "Got SortRequest.");
2043 bsrr->num_input_setnames = req->num_inputResultSetNames;
2044 bsrr->input_setnames = req->inputResultSetNames;
2045 bsrr->referenceId = req->referenceId;
2046 bsrr->output_setname = req->sortedResultSetName;
2047 bsrr->sort_sequence = req->sortSequence;
2048 bsrr->stream = assoc->encode;
2049 bsrr->print = assoc->print;
2051 bsrr->sort_status = Z_SortStatus_failure;
2053 bsrr->errstring = 0;
2055 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2057 res->referenceId = bsrr->referenceId;
2058 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2059 res->resultSetStatus = 0;
2062 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2063 res->diagnostics = dr->diagRecs;
2064 res->num_diagnostics = dr->num_diagRecs;
2068 res->num_diagnostics = 0;
2069 res->diagnostics = 0;
2071 res->resultCount = 0;
2074 apdu->which = Z_APDU_sortResponse;
2075 apdu->u.sortResponse = res;
2079 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2082 Z_DeleteResultSetRequest *req =
2083 reqb->apdu_request->u.deleteResultSetRequest;
2084 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2085 odr_malloc (assoc->encode, sizeof(*res));
2086 bend_delete_rr *bdrr = (bend_delete_rr *)
2087 odr_malloc (assoc->encode, sizeof(*bdrr));
2088 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2090 yaz_log(LOG_LOG, "Got DeleteRequest.");
2092 bdrr->num_setnames = req->num_resultSetList;
2093 bdrr->setnames = req->resultSetList;
2094 bdrr->stream = assoc->encode;
2095 bdrr->print = assoc->print;
2096 bdrr->function = *req->deleteFunction;
2097 bdrr->referenceId = req->referenceId;
2099 if (bdrr->num_setnames > 0)
2102 bdrr->statuses = (int*)
2103 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2104 bdrr->num_setnames);
2105 for (i = 0; i < bdrr->num_setnames; i++)
2106 bdrr->statuses[i] = 0;
2108 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2110 res->referenceId = req->referenceId;
2112 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2114 res->deleteListStatuses = 0;
2115 if (bdrr->num_setnames > 0)
2118 res->deleteListStatuses = (Z_ListStatuses *)
2119 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2120 res->deleteListStatuses->num = bdrr->num_setnames;
2121 res->deleteListStatuses->elements =
2123 odr_malloc (assoc->encode,
2124 sizeof(*res->deleteListStatuses->elements) *
2125 bdrr->num_setnames);
2126 for (i = 0; i<bdrr->num_setnames; i++)
2128 res->deleteListStatuses->elements[i] =
2130 odr_malloc (assoc->encode,
2131 sizeof(**res->deleteListStatuses->elements));
2132 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2133 res->deleteListStatuses->elements[i]->id =
2134 odr_strdup (assoc->encode, bdrr->setnames[i]);
2138 res->numberNotDeleted = 0;
2139 res->bulkStatuses = 0;
2140 res->deleteMessage = 0;
2143 apdu->which = Z_APDU_deleteResultSetResponse;
2144 apdu->u.deleteResultSetResponse = res;
2148 static void process_close(association *assoc, request *reqb)
2150 Z_Close *req = reqb->apdu_request->u.close;
2151 static char *reasons[] =
2158 "securityViolation",
2165 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2166 reasons[*req->closeReason], req->diagnosticInformation ?
2167 req->diagnosticInformation : "NULL");
2168 if (assoc->version < 3) /* to make do_force respond with close */
2170 do_close_req(assoc, Z_Close_finished,
2171 "Association terminated by client", reqb);
2174 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2178 reqb->len_refid = refid->len;
2179 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2180 memcpy (reqb->refid, refid->buf, refid->len);
2184 reqb->len_refid = 0;
2189 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2191 process_z_response (a, req, res);
2194 bend_request bend_request_mk (bend_association a)
2196 request *nreq = request_get (&a->outgoing);
2197 nreq->request_mem = nmem_create ();
2201 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2206 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2207 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2208 id->len = id->size = req->len_refid;
2209 memcpy (id->buf, req->refid, req->len_refid);
2213 void bend_request_destroy (bend_request *req)
2215 nmem_destroy((*req)->request_mem);
2216 request_release(*req);
2220 int bend_backend_respond (bend_association a, bend_request req)
2224 r = process_z_request (a, req, &msg);
2226 yaz_log (LOG_WARN, "%s", msg);
2230 void bend_request_setdata(bend_request r, void *p)
2235 void *bend_request_getdata(bend_request r)
2237 return r->clientData;
2240 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2242 bend_segment_rr req;
2244 req.segment = reqb->apdu_request->u.segmentRequest;
2245 req.stream = assoc->encode;
2246 req.decode = assoc->decode;
2247 req.print = assoc->print;
2248 req.association = assoc;
2250 (*assoc->init->bend_segment)(assoc->backend, &req);
2255 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2257 bend_esrequest_rr esrequest;
2259 Z_ExtendedServicesRequest *req =
2260 reqb->apdu_request->u.extendedServicesRequest;
2261 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2263 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2265 yaz_log(LOG_DEBUG,"inside Process esRequest");
2267 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2268 esrequest.stream = assoc->encode;
2269 esrequest.decode = assoc->decode;
2270 esrequest.print = assoc->print;
2271 esrequest.errcode = 0;
2272 esrequest.errstring = NULL;
2273 esrequest.request = reqb;
2274 esrequest.association = assoc;
2275 esrequest.taskPackage = 0;
2276 esrequest.referenceId = req->referenceId;
2278 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2280 /* If the response is being delayed, return NULL */
2281 if (esrequest.request == NULL)
2284 resp->referenceId = req->referenceId;
2286 if (esrequest.errcode == -1)
2288 /* Backend service indicates request will be processed */
2289 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2290 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2292 else if (esrequest.errcode == 0)
2294 /* Backend service indicates request will be processed */
2295 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2296 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2300 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2301 esrequest.errstring);
2303 /* Backend indicates error, request will not be processed */
2304 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2305 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2306 resp->num_diagnostics = diagRecs->num_diagRecs;
2307 resp->diagnostics = diagRecs->diagRecs;
2309 /* Do something with the members of bend_extendedservice */
2310 if (esrequest.taskPackage)
2311 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2312 (const char *) esrequest.taskPackage,
2314 yaz_log(LOG_DEBUG,"Send the result apdu");