2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.29 2004-09-30 11:15:52 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;
475 if (!(binitres = (*cb->bend_init)(assoc->init)))
477 yaz_log(LOG_WARN, "Bad response from backend.");
480 assoc->backend = binitres->handle;
484 static int srw_bend_fetch(association *assoc, int pos,
485 Z_SRW_searchRetrieveRequest *srw_req,
486 Z_SRW_record *record)
489 ODR o = assoc->encode;
491 rr.setname = "default";
494 rr.request_format = VAL_TEXT_XML;
495 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
498 rr.comp = (Z_RecordComposition *)
499 odr_malloc(assoc->decode, sizeof(*rr.comp));
500 rr.comp->which = Z_RecordComp_complex;
501 rr.comp->u.complex = (Z_CompSpec *)
502 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
503 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
504 odr_malloc(assoc->encode, sizeof(bool_t));
505 *rr.comp->u.complex->selectAlternativeSyntax = 0;
506 rr.comp->u.complex->num_dbSpecific = 0;
507 rr.comp->u.complex->dbSpecific = 0;
508 rr.comp->u.complex->num_recordSyntax = 0;
509 rr.comp->u.complex->recordSyntax = 0;
511 rr.comp->u.complex->generic = (Z_Specification *)
512 odr_malloc(assoc->decode, sizeof(Z_Specification));
514 /* schema uri = recordSchema (or NULL if recordSchema is not given) */
515 rr.comp->u.complex->generic->which = Z_Schema_uri;
516 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
518 /* ESN = recordSchema if recordSchema is present */
519 rr.comp->u.complex->generic->elementSpec = 0;
520 if (srw_req->recordSchema)
522 rr.comp->u.complex->generic->elementSpec =
523 (Z_ElementSpec *) odr_malloc(assoc->encode, sizeof(Z_ElementSpec));
524 rr.comp->u.complex->generic->elementSpec->which =
525 Z_ElementSpec_elementSetName;
526 rr.comp->u.complex->generic->elementSpec->u.elementSetName =
527 srw_req->recordSchema;
530 rr.stream = assoc->encode;
531 rr.print = assoc->print;
537 rr.output_format = VAL_TEXT_XML;
538 rr.output_format_raw = 0;
541 rr.surrogate_flag = 0;
542 rr.schema = srw_req->recordSchema;
544 if (!assoc->init->bend_fetch)
547 (*assoc->init->bend_fetch)(assoc->backend, &rr);
551 record->recordData_buf = rr.record;
552 record->recordData_len = rr.len;
553 record->recordPosition = odr_intdup(o, pos);
555 record->recordSchema = odr_strdup(o, rr.schema);
557 record->recordSchema = 0;
562 static void srw_bend_search(association *assoc, request *req,
563 Z_SRW_searchRetrieveRequest *srw_req,
564 Z_SRW_searchRetrieveResponse *srw_res,
572 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
573 yaz_log(LOG_DEBUG, "srw_bend_search");
576 yaz_log(LOG_DEBUG, "srw_bend_init");
577 if (!srw_bend_init(assoc))
579 srw_error = 3; /* assume Authentication error */
581 yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
582 &srw_res->num_diagnostics, 1, 0);
587 rr.setname = "default";
590 rr.basenames = &srw_req->database;
593 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
595 if (srw_req->query_type == Z_SRW_query_type_cql)
597 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
598 ext->direct_reference = odr_getoidbystr(assoc->decode,
599 "1.2.840.10003.16.2");
600 ext->indirect_reference = 0;
602 ext->which = Z_External_CQL;
603 ext->u.cql = srw_req->query.cql;
605 rr.query->which = Z_Query_type_104;
606 rr.query->u.type_104 = ext;
608 else if (srw_req->query_type == Z_SRW_query_type_pqf)
610 Z_RPNQuery *RPNquery;
611 YAZ_PQF_Parser pqf_parser;
613 pqf_parser = yaz_pqf_create ();
615 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
621 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
623 yaz_log(LOG_LOG, "%*s^\n", (int)off+4, "");
624 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
629 rr.query->which = Z_Query_type_1;
630 rr.query->u.type_1 = RPNquery;
632 yaz_pqf_destroy (pqf_parser);
637 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
640 if (!srw_error && !assoc->init->bend_search)
645 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
646 srw_res->num_diagnostics = 1;
647 srw_res->diagnostics = (Z_SRW_diagnostic *)
648 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
649 yaz_mk_std_diagnostic(assoc->encode,
650 srw_res->diagnostics, srw_error, 0);
654 rr.stream = assoc->encode;
655 rr.decode = assoc->decode;
656 rr.print = assoc->print;
658 rr.association = assoc;
664 yaz_log_zquery(rr.query);
665 (assoc->init->bend_search)(assoc->backend, &rr);
668 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
669 if (rr.errcode == 109) /* database unavailable */
674 srw_res->num_diagnostics = 1;
675 srw_res->diagnostics = (Z_SRW_diagnostic *)
676 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
677 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
678 yaz_diag_bib1_to_srw (rr.errcode),
680 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %s",
681 srw_res->diagnostics[0].uri);
685 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
686 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
688 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
689 start, number, rr.hits);
691 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
698 yaz_log(LOG_LOG, "Request out or range");
703 int packing = Z_SRW_recordPacking_string;
704 if (start + number > rr.hits)
705 number = rr.hits - start + 1;
706 if (srw_req->recordPacking &&
707 !strcmp(srw_req->recordPacking, "xml"))
708 packing = Z_SRW_recordPacking_XML;
709 srw_res->records = (Z_SRW_record *)
710 odr_malloc(assoc->encode,
711 number * sizeof(*srw_res->records));
712 for (i = 0; i<number; i++)
716 srw_res->records[j].recordPacking = packing;
717 srw_res->records[j].recordData_buf = 0;
718 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
719 errcode = srw_bend_fetch(assoc, i+start, srw_req,
720 srw_res->records + j);
723 srw_res->num_diagnostics = 1;
724 srw_res->diagnostics = (Z_SRW_diagnostic *)
725 odr_malloc(assoc->encode,
726 sizeof(*srw_res->diagnostics));
728 yaz_mk_std_diagnostic(assoc->encode,
729 srw_res->diagnostics,
730 yaz_diag_bib1_to_srw (errcode),
734 if (srw_res->records[j].recordData_buf)
737 srw_res->num_records = j;
739 srw_res->records = 0;
745 static void srw_bend_explain(association *assoc, request *req,
746 Z_SRW_explainRequest *srw_req,
747 Z_SRW_explainResponse *srw_res,
750 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
754 yaz_log(LOG_DEBUG, "srw_bend_init");
755 if (!srw_bend_init(assoc))
760 if (assoc->init && assoc->init->bend_explain)
764 rr.stream = assoc->encode;
765 rr.decode = assoc->decode;
766 rr.print = assoc->print;
768 rr.database = srw_req->database;
769 rr.schema = "http://explain.z3950.org/dtd/2.0/";
770 (*assoc->init->bend_explain)(assoc->backend, &rr);
773 int packing = Z_SRW_recordPacking_string;
774 if (srw_req->recordPacking &&
775 !strcmp(srw_req->recordPacking, "xml"))
776 packing = Z_SRW_recordPacking_XML;
777 srw_res->record.recordSchema = 0;
778 srw_res->record.recordPacking = packing;
779 srw_res->record.recordData_buf = rr.explain_buf;
780 srw_res->record.recordData_len = strlen(rr.explain_buf);
781 srw_res->record.recordPosition = 0;
787 static void process_http_request(association *assoc, request *req)
789 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
790 ODR o = assoc->encode;
791 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
793 Z_SOAP *soap_package = 0;
796 Z_HTTP_Response *hres = 0;
798 char *stylesheet = 0;
799 Z_SRW_diagnostic *diagnostic = 0;
800 int num_diagnostic = 0;
802 if (!strcmp(hreq->path, "/test"))
804 p = z_get_HTTP_Response(o, 200);
805 hres = p->u.HTTP_Response;
806 hres->content_buf = "1234567890\n";
807 hres->content_len = strlen(hres->content_buf);
812 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
813 yaz_log(LOG_DEBUG, "yaz_srw_decode returned %d", r);
815 if (r == 2) /* not taken */
817 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
818 &diagnostic, &num_diagnostic);
819 yaz_log(LOG_DEBUG, "yaz_sru_decode returned %d", r);
821 if (r == 0) /* decode SRW/SRU OK .. */
824 if (sr->which == Z_SRW_searchRetrieve_request)
827 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
829 stylesheet = sr->u.request->stylesheet;
832 res->u.response->diagnostics = diagnostic;
833 res->u.response->num_diagnostics = num_diagnostic;
837 srw_bend_search(assoc, req, sr->u.request, res->u.response,
840 if (http_code == 200)
841 soap_package->u.generic->p = res;
843 else if (sr->which == Z_SRW_explain_request)
845 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
846 stylesheet = sr->u.explain_request->stylesheet;
849 res->u.explain_response->diagnostics = diagnostic;
850 res->u.explain_response->num_diagnostics = num_diagnostic;
852 srw_bend_explain(assoc, req, sr->u.explain_request,
853 res->u.explain_response, &http_code);
854 if (http_code == 200)
855 soap_package->u.generic->p = res;
857 else if (sr->which == Z_SRW_scan_request)
859 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
860 stylesheet = sr->u.scan_request->stylesheet;
863 res->u.scan_response->diagnostics = diagnostic;
864 res->u.scan_response->num_diagnostics = num_diagnostic;
866 yaz_add_srw_diagnostic(o,
867 &res->u.scan_response->diagnostics,
868 &res->u.scan_response->num_diagnostics,
870 if (http_code == 200)
871 soap_package->u.generic->p = res;
875 yaz_log(LOG_LOG, "generate soap error");
877 z_soap_error(assoc->encode, soap_package,
878 "SOAP-ENV:Client", "Bad method", 0);
880 if (http_code == 200 || http_code == 500)
882 static Z_SOAP_Handler soap_handlers[3] = {
884 {"http://www.loc.gov/zing/srw/", 0,
885 (Z_SOAP_fun) yaz_srw_codec},
886 {"http://www.loc.gov/zing/srw/v1.0/", 0,
887 (Z_SOAP_fun) yaz_srw_codec},
893 p = z_get_HTTP_Response(o, 200);
894 hres = p->u.HTTP_Response;
895 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
896 &hres->content_buf, &hres->content_len,
897 soap_handlers, charset, stylesheet);
898 hres->code = http_code;
900 strcpy(ctype, "text/xml");
903 strcat(ctype, "; charset=");
904 strcat(ctype, charset);
906 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
909 p = z_get_HTTP_Response(o, http_code);
913 p = z_get_HTTP_Response(o, 500);
914 hres = p->u.HTTP_Response;
915 if (!strcmp(hreq->version, "1.0"))
917 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
918 if (v && !strcmp(v, "Keep-Alive"))
922 hres->version = "1.0";
926 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
927 if (v && !strcmp(v, "close"))
931 hres->version = "1.1";
935 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
936 assoc->state = ASSOC_DEAD;
937 assoc->cs_get_mask = 0;
942 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
944 if (alive && isdigit(*alive))
948 if (t < 0 || t > 3600)
950 iochan_settimeout(assoc->client_chan,t);
951 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
953 process_gdu_response(assoc, req, p);
956 static void process_gdu_request(association *assoc, request *req)
958 if (req->gdu_request->which == Z_GDU_Z3950)
961 req->apdu_request = req->gdu_request->u.z3950;
962 if (process_z_request(assoc, req, &msg) < 0)
963 do_close_req(assoc, Z_Close_systemProblem, msg, req);
965 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
966 process_http_request(assoc, req);
969 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
974 * Initiate request processing.
976 static int process_z_request(association *assoc, request *req, char **msg)
982 *msg = "Unknown Error";
983 assert(req && req->state == REQUEST_IDLE);
984 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
986 *msg = "Missing InitRequest";
989 switch (req->apdu_request->which)
991 case Z_APDU_initRequest:
992 iochan_settimeout(assoc->client_chan,
993 statserv_getcontrol()->idle_timeout * 60);
994 res = process_initRequest(assoc, req); break;
995 case Z_APDU_searchRequest:
996 res = process_searchRequest(assoc, req, &fd); break;
997 case Z_APDU_presentRequest:
998 res = process_presentRequest(assoc, req, &fd); break;
999 case Z_APDU_scanRequest:
1000 if (assoc->init->bend_scan)
1001 res = process_scanRequest(assoc, req, &fd);
1004 *msg = "Cannot handle Scan APDU";
1008 case Z_APDU_extendedServicesRequest:
1009 if (assoc->init->bend_esrequest)
1010 res = process_ESRequest(assoc, req, &fd);
1013 *msg = "Cannot handle Extended Services APDU";
1017 case Z_APDU_sortRequest:
1018 if (assoc->init->bend_sort)
1019 res = process_sortRequest(assoc, req, &fd);
1022 *msg = "Cannot handle Sort APDU";
1027 process_close(assoc, req);
1029 case Z_APDU_deleteResultSetRequest:
1030 if (assoc->init->bend_delete)
1031 res = process_deleteRequest(assoc, req, &fd);
1034 *msg = "Cannot handle Delete APDU";
1038 case Z_APDU_segmentRequest:
1039 if (assoc->init->bend_segment)
1041 res = process_segmentRequest (assoc, req);
1045 *msg = "Cannot handle Segment APDU";
1049 case Z_APDU_triggerResourceControlRequest:
1052 *msg = "Bad APDU received";
1057 yaz_log(LOG_DEBUG, " result immediately available");
1058 retval = process_z_response(assoc, req, res);
1062 yaz_log(LOG_DEBUG, " result unavailble");
1065 else /* no result yet - one will be provided later */
1069 /* Set up an I/O handler for the fd supplied by the backend */
1071 yaz_log(LOG_DEBUG, " establishing handler for result");
1072 req->state = REQUEST_PENDING;
1073 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1075 iochan_setdata(chan, assoc);
1082 * Handle message from the backend.
1084 void backend_response(IOCHAN i, int event)
1086 association *assoc = (association *)iochan_getdata(i);
1087 request *req = request_head(&assoc->incoming);
1091 yaz_log(LOG_DEBUG, "backend_response");
1092 assert(assoc && req && req->state != REQUEST_IDLE);
1093 /* determine what it is we're waiting for */
1094 switch (req->apdu_request->which)
1096 case Z_APDU_searchRequest:
1097 res = response_searchRequest(assoc, req, 0, &fd); break;
1099 case Z_APDU_presentRequest:
1100 res = response_presentRequest(assoc, req, 0, &fd); break;
1101 case Z_APDU_scanRequest:
1102 res = response_scanRequest(assoc, req, 0, &fd); break;
1105 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1108 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1110 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1111 do_close(assoc, Z_Close_systemProblem, 0);
1115 else if (!res) /* no result yet - try again later */
1117 yaz_log(LOG_DEBUG, " no result yet");
1118 iochan_setfd(i, fd); /* in case fd has changed */
1123 * Encode response, and transfer the request structure to the outgoing queue.
1125 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1127 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1131 if (!z_GDU(assoc->print, &res, 0, 0))
1132 yaz_log(LOG_WARN, "ODR print error: %s",
1133 odr_errmsg(odr_geterror(assoc->print)));
1134 odr_reset(assoc->print);
1136 if (!z_GDU(assoc->encode, &res, 0, 0))
1138 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1139 odr_errmsg(odr_geterror(assoc->decode)),
1140 odr_getelement(assoc->decode));
1141 request_release(req);
1144 req->response = odr_getbuf(assoc->encode, &req->len_response,
1145 &req->size_response);
1146 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1147 odr_reset(assoc->encode);
1148 req->state = REQUEST_IDLE;
1149 request_enq(&assoc->outgoing, req);
1150 /* turn the work over to the ir_session handler */
1151 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1152 assoc->cs_put_mask = EVENT_OUTPUT;
1153 /* Is there more work to be done? give that to the input handler too */
1155 if (request_head(&assoc->incoming))
1157 yaz_log (LOG_DEBUG, "more work to be done");
1158 iochan_setevent(assoc->client_chan, EVENT_WORK);
1165 * Encode response, and transfer the request structure to the outgoing queue.
1167 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1169 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1170 gres->which = Z_GDU_Z3950;
1171 gres->u.z3950 = res;
1173 return process_gdu_response(assoc, req, gres);
1178 * Handle init request.
1179 * At the moment, we don't check the options
1180 * anywhere else in the code - we just try not to do anything that would
1181 * break a naive client. We'll toss 'em into the association block when
1182 * we need them there.
1184 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1186 statserv_options_block *cb = statserv_getcontrol();
1187 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1188 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1189 Z_InitResponse *resp = apdu->u.initResponse;
1190 bend_initresult *binitres;
1194 yaz_log(LOG_LOG, "Got initRequest");
1195 if (req->implementationId)
1196 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1197 if (req->implementationName)
1198 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1199 if (req->implementationVersion)
1200 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1202 assoc_init_reset(assoc);
1204 assoc->init->auth = req->idAuthentication;
1205 assoc->init->referenceId = req->referenceId;
1207 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1209 Z_CharSetandLanguageNegotiation *negotiation =
1210 yaz_get_charneg_record (req->otherInfo);
1212 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1213 assoc->init->charneg_request = negotiation;
1217 if (!(binitres = (*cb->bend_init)(assoc->init)))
1219 yaz_log(LOG_WARN, "Bad response from backend.");
1223 assoc->backend = binitres->handle;
1224 if ((assoc->init->bend_sort))
1225 yaz_log (LOG_DEBUG, "Sort handler installed");
1226 if ((assoc->init->bend_search))
1227 yaz_log (LOG_DEBUG, "Search handler installed");
1228 if ((assoc->init->bend_present))
1229 yaz_log (LOG_DEBUG, "Present handler installed");
1230 if ((assoc->init->bend_esrequest))
1231 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1232 if ((assoc->init->bend_delete))
1233 yaz_log (LOG_DEBUG, "Delete handler installed");
1234 if ((assoc->init->bend_scan))
1235 yaz_log (LOG_DEBUG, "Scan handler installed");
1236 if ((assoc->init->bend_segment))
1237 yaz_log (LOG_DEBUG, "Segment handler installed");
1239 resp->referenceId = req->referenceId;
1241 /* let's tell the client what we can do */
1242 if (ODR_MASK_GET(req->options, Z_Options_search))
1244 ODR_MASK_SET(resp->options, Z_Options_search);
1245 strcat(options, "srch");
1247 if (ODR_MASK_GET(req->options, Z_Options_present))
1249 ODR_MASK_SET(resp->options, Z_Options_present);
1250 strcat(options, " prst");
1252 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1253 assoc->init->bend_delete)
1255 ODR_MASK_SET(resp->options, Z_Options_delSet);
1256 strcat(options, " del");
1258 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1259 assoc->init->bend_esrequest)
1261 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1262 strcat (options, " extendedServices");
1264 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1266 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1267 strcat(options, " namedresults");
1269 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1271 ODR_MASK_SET(resp->options, Z_Options_scan);
1272 strcat(options, " scan");
1274 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1276 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1277 strcat(options, " concurrop");
1279 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1281 ODR_MASK_SET(resp->options, Z_Options_sort);
1282 strcat(options, " sort");
1285 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1286 && assoc->init->charneg_response)
1288 Z_OtherInformation **p;
1289 Z_OtherInformationUnit *p0;
1291 yaz_oi_APDU(apdu, &p);
1293 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1294 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1296 p0->which = Z_OtherInfo_externallyDefinedInfo;
1297 p0->information.externallyDefinedInfo =
1298 assoc->init->charneg_response;
1300 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1301 strcat(options, " negotiation");
1304 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1306 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1308 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1309 assoc->version = 1; /* 1 & 2 are equivalent */
1311 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1313 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1316 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1318 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1322 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1323 assoc->maximumRecordSize = *req->maximumRecordSize;
1324 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1325 assoc->maximumRecordSize = control_block->maxrecordsize;
1326 assoc->preferredMessageSize = *req->preferredMessageSize;
1327 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1328 assoc->preferredMessageSize = assoc->maximumRecordSize;
1330 resp->preferredMessageSize = &assoc->preferredMessageSize;
1331 resp->maximumRecordSize = &assoc->maximumRecordSize;
1333 resp->implementationId = odr_prepend(assoc->encode,
1334 assoc->init->implementation_id,
1335 resp->implementationId);
1337 resp->implementationName = odr_prepend(assoc->encode,
1338 assoc->init->implementation_name,
1339 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1341 version = odr_strdup(assoc->encode, "$Revision: 1.29 $");
1342 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1343 version[strlen(version)-2] = '\0';
1344 resp->implementationVersion = odr_prepend(assoc->encode,
1345 assoc->init->implementation_version,
1346 odr_prepend(assoc->encode, &version[11],
1347 resp->implementationVersion));
1349 if (binitres->errcode)
1351 yaz_log(LOG_LOG, "Connection rejected by backend.");
1353 assoc->state = ASSOC_DEAD;
1354 resp->userInformationField = init_diagnostics(assoc->encode,
1356 binitres->errstring);
1359 assoc->state = ASSOC_UP;
1364 * Diagnostic in default format, to be returned as either a surrogate
1365 * or non-surrogate diagnostic in the context of an open session, or
1366 * as User-information when an Init is refused.
1368 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1370 int *err = odr_intdup(odr, error);
1371 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1372 odr_malloc (odr, sizeof(*dr));
1374 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1375 addinfo ? " -- " : "", addinfo ? addinfo : "");
1377 dr->diagnosticSetId =
1378 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1379 dr->condition = err;
1380 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1381 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1386 * Set the specified `errcode' and `errstring' into a UserInfo-1
1387 * external to be returned to the client in accordance with Z35.90
1388 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1389 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1391 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1395 Z_OtherInformation *u;
1396 Z_OtherInformationUnit *l;
1397 Z_DiagnosticFormat *d;
1398 Z_DiagnosticFormat_s *e;
1400 x = (Z_External*) odr_malloc(odr, sizeof *x);
1402 x->indirect_reference = 0;
1403 oid.proto = PROTO_Z3950;
1404 oid.oclass = CLASS_USERINFO;
1405 oid.value = VAL_USERINFO1;
1406 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1407 x->which = Z_External_userInfo1;
1409 u = odr_malloc(odr, sizeof *u);
1411 u->num_elements = 1;
1412 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1413 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1416 l->which = Z_OtherInfo_externallyDefinedInfo;
1418 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1419 l->information.externallyDefinedInfo = x2;
1421 x2->indirect_reference = 0;
1422 oid.oclass = CLASS_DIAGSET;
1423 oid.value = VAL_DIAG1;
1424 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1425 x2->which = Z_External_diag1;
1427 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1430 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1431 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1434 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1435 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1441 * nonsurrogate diagnostic record.
1443 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1445 Z_Records *rec = (Z_Records *)
1446 odr_malloc (assoc->encode, sizeof(*rec));
1447 rec->which = Z_Records_NSD;
1448 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1453 * surrogate diagnostic.
1455 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1456 int error, char *addinfo)
1458 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1459 odr_malloc (assoc->encode, sizeof(*rec));
1460 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1462 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1463 rec->databaseName = dbname;
1464 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1465 rec->u.surrogateDiagnostic = drec;
1466 drec->which = Z_DiagRec_defaultFormat;
1467 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1473 * multiple nonsurrogate diagnostics.
1475 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1477 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1478 int *err = odr_intdup(assoc->encode, error);
1479 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1480 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1481 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1482 odr_malloc (assoc->encode, sizeof(*rec));
1484 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1486 recs->num_diagRecs = 1;
1487 recs->diagRecs = recp;
1489 drec->which = Z_DiagRec_defaultFormat;
1490 drec->u.defaultFormat = rec;
1492 rec->diagnosticSetId =
1493 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1494 rec->condition = err;
1496 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1497 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1501 static Z_Records *pack_records(association *a, char *setname, int start,
1502 int *num, Z_RecordComposition *comp,
1503 int *next, int *pres, oid_value format,
1504 Z_ReferenceId *referenceId,
1507 int recno, total_length = 0, toget = *num, dumped_records = 0;
1508 Z_Records *records =
1509 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1510 Z_NamePlusRecordList *reclist =
1511 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1512 Z_NamePlusRecord **list =
1513 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1515 records->which = Z_Records_DBOSD;
1516 records->u.databaseOrSurDiagnostics = reclist;
1517 reclist->num_records = 0;
1518 reclist->records = list;
1519 *pres = Z_PresentStatus_success;
1523 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1524 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1525 a->maximumRecordSize);
1526 for (recno = start; reclist->num_records < toget; recno++)
1529 Z_NamePlusRecord *thisrec;
1530 int this_length = 0;
1532 * we get the number of bytes allocated on the stream before any
1533 * allocation done by the backend - this should give us a reasonable
1534 * idea of the total size of the data so far.
1536 total_length = odr_total(a->encode) - dumped_records;
1542 freq.last_in_set = 0;
1543 freq.setname = setname;
1544 freq.surrogate_flag = 0;
1545 freq.number = recno;
1547 freq.request_format = format;
1548 freq.request_format_raw = oid;
1549 freq.output_format = format;
1550 freq.output_format_raw = 0;
1551 freq.stream = a->encode;
1552 freq.print = a->print;
1553 freq.referenceId = referenceId;
1555 (*a->init->bend_fetch)(a->backend, &freq);
1556 /* backend should be able to signal whether error is system-wide
1557 or only pertaining to current record */
1560 if (!freq.surrogate_flag)
1563 *pres = Z_PresentStatus_failure;
1564 /* for 'present request out of range',
1565 set addinfo to record position if not set */
1566 if (freq.errcode == 13 && freq.errstring == 0)
1568 sprintf (s, "%d", recno);
1571 return diagrec(a, freq.errcode, freq.errstring);
1573 reclist->records[reclist->num_records] =
1574 surrogatediagrec(a, freq.basename, freq.errcode,
1576 reclist->num_records++;
1577 *next = freq.last_in_set ? 0 : recno + 1;
1581 this_length = freq.len;
1583 this_length = odr_total(a->encode) - total_length - dumped_records;
1584 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1585 this_length, total_length, dumped_records);
1586 if (a->preferredMessageSize > 0 &&
1587 this_length + total_length > a->preferredMessageSize)
1589 /* record is small enough, really */
1590 if (this_length <= a->preferredMessageSize && recno > start)
1592 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1593 *pres = Z_PresentStatus_partial_2;
1596 /* record can only be fetched by itself */
1597 if (this_length < a->maximumRecordSize)
1599 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1602 yaz_log(LOG_DEBUG, " Dropped it");
1603 reclist->records[reclist->num_records] =
1604 surrogatediagrec(a, freq.basename, 16, 0);
1605 reclist->num_records++;
1606 *next = freq.last_in_set ? 0 : recno + 1;
1607 dumped_records += this_length;
1611 else /* too big entirely */
1613 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1614 reclist->records[reclist->num_records] =
1615 surrogatediagrec(a, freq.basename, 17, 0);
1616 reclist->num_records++;
1617 *next = freq.last_in_set ? 0 : recno + 1;
1618 dumped_records += this_length;
1623 if (!(thisrec = (Z_NamePlusRecord *)
1624 odr_malloc(a->encode, sizeof(*thisrec))))
1626 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1627 strlen(freq.basename) + 1)))
1629 strcpy(thisrec->databaseName, freq.basename);
1630 thisrec->which = Z_NamePlusRecord_databaseRecord;
1632 if (freq.output_format_raw)
1634 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1635 freq.output_format = ident->value;
1637 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1638 freq.record, freq.len);
1639 if (!thisrec->u.databaseRecord)
1641 reclist->records[reclist->num_records] = thisrec;
1642 reclist->num_records++;
1643 *next = freq.last_in_set ? 0 : recno + 1;
1645 *num = reclist->num_records;
1649 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1652 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1653 bend_search_rr *bsrr =
1654 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1656 yaz_log(LOG_LOG, "Got SearchRequest.");
1658 bsrr->request = reqb;
1659 bsrr->association = assoc;
1660 bsrr->referenceId = req->referenceId;
1661 save_referenceId (reqb, bsrr->referenceId);
1663 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1664 if (req->databaseNames)
1667 for (i = 0; i < req->num_databaseNames; i++)
1668 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1670 yaz_log_zquery(req->query);
1672 if (assoc->init->bend_search)
1674 bsrr->setname = req->resultSetName;
1675 bsrr->replace_set = *req->replaceIndicator;
1676 bsrr->num_bases = req->num_databaseNames;
1677 bsrr->basenames = req->databaseNames;
1678 bsrr->query = req->query;
1679 bsrr->stream = assoc->encode;
1680 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1681 bsrr->decode = assoc->decode;
1682 bsrr->print = assoc->print;
1685 bsrr->errstring = NULL;
1686 bsrr->search_info = NULL;
1687 (assoc->init->bend_search)(assoc->backend, bsrr);
1691 return response_searchRequest(assoc, reqb, bsrr, fd);
1694 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1697 * Prepare a searchresponse based on the backend results. We probably want
1698 * to look at making the fetching of records nonblocking as well, but
1699 * so far, we'll keep things simple.
1700 * If bsrt is null, that means we're called in response to a communications
1701 * event, and we'll have to get the response for ourselves.
1703 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1704 bend_search_rr *bsrt, int *fd)
1706 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1707 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1708 Z_SearchResponse *resp = (Z_SearchResponse *)
1709 odr_malloc (assoc->encode, sizeof(*resp));
1710 int *nulint = odr_intdup (assoc->encode, 0);
1711 bool_t *sr = odr_intdup(assoc->encode, 1);
1712 int *next = odr_intdup(assoc->encode, 0);
1713 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1715 apdu->which = Z_APDU_searchResponse;
1716 apdu->u.searchResponse = resp;
1717 resp->referenceId = req->referenceId;
1718 resp->additionalSearchInfo = 0;
1719 resp->otherInfo = 0;
1721 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1723 yaz_log(LOG_FATAL, "Bad result from backend");
1726 else if (bsrt->errcode)
1728 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1729 resp->resultCount = nulint;
1730 resp->numberOfRecordsReturned = nulint;
1731 resp->nextResultSetPosition = nulint;
1732 resp->searchStatus = nulint;
1733 resp->resultSetStatus = none;
1734 resp->presentStatus = 0;
1738 int *toget = odr_intdup(assoc->encode, 0);
1739 int *presst = odr_intdup(assoc->encode, 0);
1740 Z_RecordComposition comp, *compp = 0;
1742 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1745 resp->resultCount = &bsrt->hits;
1747 comp.which = Z_RecordComp_simple;
1748 /* how many records does the user agent want, then? */
1749 if (bsrt->hits <= *req->smallSetUpperBound)
1751 *toget = bsrt->hits;
1752 if ((comp.u.simple = req->smallSetElementSetNames))
1755 else if (bsrt->hits < *req->largeSetLowerBound)
1757 *toget = *req->mediumSetPresentNumber;
1758 if (*toget > bsrt->hits)
1759 *toget = bsrt->hits;
1760 if ((comp.u.simple = req->mediumSetElementSetNames))
1766 if (*toget && !resp->records)
1771 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1774 form = prefformat->value;
1775 resp->records = pack_records(assoc, req->resultSetName, 1,
1776 toget, compp, next, presst, form, req->referenceId,
1777 req->preferredRecordSyntax);
1780 resp->numberOfRecordsReturned = toget;
1781 resp->nextResultSetPosition = next;
1782 resp->searchStatus = sr;
1783 resp->resultSetStatus = 0;
1784 resp->presentStatus = presst;
1788 if (*resp->resultCount)
1790 resp->numberOfRecordsReturned = nulint;
1791 resp->nextResultSetPosition = next;
1792 resp->searchStatus = sr;
1793 resp->resultSetStatus = 0;
1794 resp->presentStatus = 0;
1797 resp->additionalSearchInfo = bsrt->search_info;
1802 * Maybe we got a little over-friendly when we designed bend_fetch to
1803 * get only one record at a time. Some backends can optimise multiple-record
1804 * fetches, and at any rate, there is some overhead involved in
1805 * all that selecting and hopping around. Problem is, of course, that the
1806 * frontend can't know ahead of time how many records it'll need to
1807 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1808 * is downright lousy as a bulk data transfer protocol.
1810 * To start with, we'll do the fetching of records from the backend
1811 * in one operation: To save some trips in and out of the event-handler,
1812 * and to simplify the interface to pack_records. At any rate, asynch
1813 * operation is more fun in operations that have an unpredictable execution
1814 * speed - which is normally more true for search than for present.
1816 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1819 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1823 Z_PresentResponse *resp;
1827 yaz_log(LOG_LOG, "Got PresentRequest.");
1829 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1832 form = prefformat->value;
1833 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1835 resp->presentStatus = odr_intdup(assoc->encode, 0);
1836 if (assoc->init->bend_present)
1838 bend_present_rr *bprr = (bend_present_rr *)
1839 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1840 bprr->setname = req->resultSetId;
1841 bprr->start = *req->resultSetStartPoint;
1842 bprr->number = *req->numberOfRecordsRequested;
1843 bprr->format = form;
1844 bprr->comp = req->recordComposition;
1845 bprr->referenceId = req->referenceId;
1846 bprr->stream = assoc->encode;
1847 bprr->print = assoc->print;
1848 bprr->request = reqb;
1849 bprr->association = assoc;
1851 bprr->errstring = NULL;
1852 (*assoc->init->bend_present)(assoc->backend, bprr);
1858 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1859 *resp->presentStatus = Z_PresentStatus_failure;
1862 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1863 next = odr_intdup(assoc->encode, 0);
1864 num = odr_intdup(assoc->encode, 0);
1866 apdu->which = Z_APDU_presentResponse;
1867 apdu->u.presentResponse = resp;
1868 resp->referenceId = req->referenceId;
1869 resp->otherInfo = 0;
1873 *num = *req->numberOfRecordsRequested;
1875 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1876 num, req->recordComposition, next, resp->presentStatus,
1877 form, req->referenceId, req->preferredRecordSyntax);
1881 resp->numberOfRecordsReturned = num;
1882 resp->nextResultSetPosition = next;
1888 * Scan was implemented rather in a hurry, and with support for only the basic
1889 * elements of the service in the backend API. Suggestions are welcome.
1891 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1893 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1894 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1895 Z_ScanResponse *res = (Z_ScanResponse *)
1896 odr_malloc (assoc->encode, sizeof(*res));
1897 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1898 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1899 Z_ListEntries *ents = (Z_ListEntries *)
1900 odr_malloc (assoc->encode, sizeof(*ents));
1901 Z_DiagRecs *diagrecs_p = NULL;
1903 bend_scan_rr *bsrr = (bend_scan_rr *)
1904 odr_malloc (assoc->encode, sizeof(*bsrr));
1905 struct scan_entry *save_entries;
1907 yaz_log(LOG_LOG, "Got ScanRequest");
1909 apdu->which = Z_APDU_scanResponse;
1910 apdu->u.scanResponse = res;
1911 res->referenceId = req->referenceId;
1913 /* if step is absent, set it to 0 */
1914 res->stepSize = odr_intdup(assoc->encode, 0);
1916 *res->stepSize = *req->stepSize;
1918 res->scanStatus = scanStatus;
1919 res->numberOfEntriesReturned = numberOfEntriesReturned;
1920 res->positionOfTerm = 0;
1921 res->entries = ents;
1922 ents->num_entries = 0;
1923 ents->entries = NULL;
1924 ents->num_nonsurrogateDiagnostics = 0;
1925 ents->nonsurrogateDiagnostics = NULL;
1926 res->attributeSet = 0;
1929 if (req->databaseNames)
1932 for (i = 0; i < req->num_databaseNames; i++)
1933 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1935 bsrr->num_bases = req->num_databaseNames;
1936 bsrr->basenames = req->databaseNames;
1937 bsrr->num_entries = *req->numberOfTermsRequested;
1938 bsrr->term = req->termListAndStartPoint;
1939 bsrr->referenceId = req->referenceId;
1940 bsrr->stream = assoc->encode;
1941 bsrr->print = assoc->print;
1942 bsrr->step_size = res->stepSize;
1944 /* Note that version 2.0 of YAZ and older did not set entries ..
1945 We do now. And when we do it's easier to extend the scan entry
1946 We know that if the scan handler did set entries, it will
1947 not know of new member display_term.
1949 if (bsrr->num_entries > 0)
1952 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1954 for (i = 0; i<bsrr->num_entries; i++)
1956 bsrr->entries[i].term = 0;
1957 bsrr->entries[i].occurrences = 0;
1958 bsrr->entries[i].errcode = 0;
1959 bsrr->entries[i].errstring = 0;
1960 bsrr->entries[i].display_term = 0;
1963 save_entries = bsrr->entries; /* save it so we can compare later */
1965 if (req->attributeSet &&
1966 (attset = oid_getentbyoid(req->attributeSet)) &&
1967 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
1968 bsrr->attributeset = attset->value;
1970 bsrr->attributeset = VAL_NONE;
1971 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
1972 bsrr->term_position = req->preferredPositionInResponse ?
1973 *req->preferredPositionInResponse : 1;
1974 ((int (*)(void *, bend_scan_rr *))
1975 (*assoc->init->bend_scan))(assoc->backend, bsrr);
1977 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
1981 Z_Entry **tab = (Z_Entry **)
1982 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
1984 if (bsrr->status == BEND_SCAN_PARTIAL)
1985 *scanStatus = Z_Scan_partial_5;
1987 *scanStatus = Z_Scan_success;
1988 ents->entries = tab;
1989 ents->num_entries = bsrr->num_entries;
1990 res->numberOfEntriesReturned = &ents->num_entries;
1991 res->positionOfTerm = &bsrr->term_position;
1992 for (i = 0; i < bsrr->num_entries; i++)
1998 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
1999 if (bsrr->entries[i].occurrences >= 0)
2001 e->which = Z_Entry_termInfo;
2002 e->u.termInfo = t = (Z_TermInfo *)
2003 odr_malloc(assoc->encode, sizeof(*t));
2004 t->suggestedAttributes = 0;
2006 if (save_entries == bsrr->entries &&
2007 bsrr->entries[i].display_term)
2009 /* the entries was NOT set by the handler. So it's
2010 safe to test for new member display_term. It is
2013 t->displayTerm = odr_strdup(assoc->encode,
2014 bsrr->entries[i].display_term);
2016 t->alternativeTerm = 0;
2017 t->byAttributes = 0;
2018 t->otherTermInfo = 0;
2019 t->globalOccurrences = &bsrr->entries[i].occurrences;
2020 t->term = (Z_Term *)
2021 odr_malloc(assoc->encode, sizeof(*t->term));
2022 t->term->which = Z_Term_general;
2023 t->term->u.general = o =
2024 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2025 o->buf = (unsigned char *)
2026 odr_malloc(assoc->encode, o->len = o->size =
2027 strlen(bsrr->entries[i].term));
2028 memcpy(o->buf, bsrr->entries[i].term, o->len);
2029 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2030 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2034 Z_DiagRecs *drecs = diagrecs (assoc,
2035 bsrr->entries[i].errcode,
2036 bsrr->entries[i].errstring);
2037 assert (drecs->num_diagRecs == 1);
2038 e->which = Z_Entry_surrogateDiagnostic;
2039 assert (drecs->diagRecs[0]);
2040 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2046 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2047 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2052 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2055 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2056 Z_SortResponse *res = (Z_SortResponse *)
2057 odr_malloc (assoc->encode, sizeof(*res));
2058 bend_sort_rr *bsrr = (bend_sort_rr *)
2059 odr_malloc (assoc->encode, sizeof(*bsrr));
2061 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2063 yaz_log(LOG_LOG, "Got SortRequest.");
2065 bsrr->num_input_setnames = req->num_inputResultSetNames;
2066 bsrr->input_setnames = req->inputResultSetNames;
2067 bsrr->referenceId = req->referenceId;
2068 bsrr->output_setname = req->sortedResultSetName;
2069 bsrr->sort_sequence = req->sortSequence;
2070 bsrr->stream = assoc->encode;
2071 bsrr->print = assoc->print;
2073 bsrr->sort_status = Z_SortResponse_failure;
2075 bsrr->errstring = 0;
2077 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2079 res->referenceId = bsrr->referenceId;
2080 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2081 res->resultSetStatus = 0;
2084 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2085 res->diagnostics = dr->diagRecs;
2086 res->num_diagnostics = dr->num_diagRecs;
2090 res->num_diagnostics = 0;
2091 res->diagnostics = 0;
2093 res->resultCount = 0;
2096 apdu->which = Z_APDU_sortResponse;
2097 apdu->u.sortResponse = res;
2101 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2104 Z_DeleteResultSetRequest *req =
2105 reqb->apdu_request->u.deleteResultSetRequest;
2106 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2107 odr_malloc (assoc->encode, sizeof(*res));
2108 bend_delete_rr *bdrr = (bend_delete_rr *)
2109 odr_malloc (assoc->encode, sizeof(*bdrr));
2110 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2112 yaz_log(LOG_LOG, "Got DeleteRequest.");
2114 bdrr->num_setnames = req->num_resultSetList;
2115 bdrr->setnames = req->resultSetList;
2116 bdrr->stream = assoc->encode;
2117 bdrr->print = assoc->print;
2118 bdrr->function = *req->deleteFunction;
2119 bdrr->referenceId = req->referenceId;
2121 if (bdrr->num_setnames > 0)
2124 bdrr->statuses = (int*)
2125 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2126 bdrr->num_setnames);
2127 for (i = 0; i < bdrr->num_setnames; i++)
2128 bdrr->statuses[i] = 0;
2130 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2132 res->referenceId = req->referenceId;
2134 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2136 res->deleteListStatuses = 0;
2137 if (bdrr->num_setnames > 0)
2140 res->deleteListStatuses = (Z_ListStatuses *)
2141 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2142 res->deleteListStatuses->num = bdrr->num_setnames;
2143 res->deleteListStatuses->elements =
2145 odr_malloc (assoc->encode,
2146 sizeof(*res->deleteListStatuses->elements) *
2147 bdrr->num_setnames);
2148 for (i = 0; i<bdrr->num_setnames; i++)
2150 res->deleteListStatuses->elements[i] =
2152 odr_malloc (assoc->encode,
2153 sizeof(**res->deleteListStatuses->elements));
2154 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2155 res->deleteListStatuses->elements[i]->id =
2156 odr_strdup (assoc->encode, bdrr->setnames[i]);
2160 res->numberNotDeleted = 0;
2161 res->bulkStatuses = 0;
2162 res->deleteMessage = 0;
2165 apdu->which = Z_APDU_deleteResultSetResponse;
2166 apdu->u.deleteResultSetResponse = res;
2170 static void process_close(association *assoc, request *reqb)
2172 Z_Close *req = reqb->apdu_request->u.close;
2173 static char *reasons[] =
2180 "securityViolation",
2187 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2188 reasons[*req->closeReason], req->diagnosticInformation ?
2189 req->diagnosticInformation : "NULL");
2190 if (assoc->version < 3) /* to make do_force respond with close */
2192 do_close_req(assoc, Z_Close_finished,
2193 "Association terminated by client", reqb);
2196 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2200 reqb->len_refid = refid->len;
2201 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2202 memcpy (reqb->refid, refid->buf, refid->len);
2206 reqb->len_refid = 0;
2211 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2213 process_z_response (a, req, res);
2216 bend_request bend_request_mk (bend_association a)
2218 request *nreq = request_get (&a->outgoing);
2219 nreq->request_mem = nmem_create ();
2223 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2228 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2229 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2230 id->len = id->size = req->len_refid;
2231 memcpy (id->buf, req->refid, req->len_refid);
2235 void bend_request_destroy (bend_request *req)
2237 nmem_destroy((*req)->request_mem);
2238 request_release(*req);
2242 int bend_backend_respond (bend_association a, bend_request req)
2246 r = process_z_request (a, req, &msg);
2248 yaz_log (LOG_WARN, "%s", msg);
2252 void bend_request_setdata(bend_request r, void *p)
2257 void *bend_request_getdata(bend_request r)
2259 return r->clientData;
2262 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2264 bend_segment_rr req;
2266 req.segment = reqb->apdu_request->u.segmentRequest;
2267 req.stream = assoc->encode;
2268 req.decode = assoc->decode;
2269 req.print = assoc->print;
2270 req.association = assoc;
2272 (*assoc->init->bend_segment)(assoc->backend, &req);
2277 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2279 bend_esrequest_rr esrequest;
2281 Z_ExtendedServicesRequest *req =
2282 reqb->apdu_request->u.extendedServicesRequest;
2283 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2285 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2287 yaz_log(LOG_DEBUG,"inside Process esRequest");
2289 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2290 esrequest.stream = assoc->encode;
2291 esrequest.decode = assoc->decode;
2292 esrequest.print = assoc->print;
2293 esrequest.errcode = 0;
2294 esrequest.errstring = NULL;
2295 esrequest.request = reqb;
2296 esrequest.association = assoc;
2297 esrequest.taskPackage = 0;
2298 esrequest.referenceId = req->referenceId;
2300 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2302 /* If the response is being delayed, return NULL */
2303 if (esrequest.request == NULL)
2306 resp->referenceId = req->referenceId;
2308 if (esrequest.errcode == -1)
2310 /* Backend service indicates request will be processed */
2311 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2312 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2314 else if (esrequest.errcode == 0)
2316 /* Backend service indicates request will be processed */
2317 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2318 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2322 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2323 esrequest.errstring);
2325 /* Backend indicates error, request will not be processed */
2326 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2327 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2328 resp->num_diagnostics = diagRecs->num_diagRecs;
2329 resp->diagnostics = diagRecs->diagRecs;
2331 /* Do something with the members of bend_extendedservice */
2332 if (esrequest.taskPackage)
2333 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2334 (const char *) esrequest.taskPackage,
2336 yaz_log(LOG_DEBUG,"Send the result apdu");