2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.28 2004-09-30 11:13:42 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->schema.uri =
524 rr.comp->u.complex->generic->elementSpec =
525 odr_malloc(assoc->encode, sizeof(Z_ElementSpec));
526 rr.comp->u.complex->generic->elementSpec->which =
527 Z_ElementSpec_elementSetName;
528 rr.comp->u.complex->generic->elementSpec->u.elementSetName =
529 srw_req->recordSchema;
532 rr.stream = assoc->encode;
533 rr.print = assoc->print;
539 rr.output_format = VAL_TEXT_XML;
540 rr.output_format_raw = 0;
543 rr.surrogate_flag = 0;
544 rr.schema = srw_req->recordSchema;
546 if (!assoc->init->bend_fetch)
549 (*assoc->init->bend_fetch)(assoc->backend, &rr);
553 record->recordData_buf = rr.record;
554 record->recordData_len = rr.len;
555 record->recordPosition = odr_intdup(o, pos);
557 record->recordSchema = odr_strdup(o, rr.schema);
559 record->recordSchema = 0;
564 static void srw_bend_search(association *assoc, request *req,
565 Z_SRW_searchRetrieveRequest *srw_req,
566 Z_SRW_searchRetrieveResponse *srw_res,
574 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
575 yaz_log(LOG_DEBUG, "srw_bend_search");
578 yaz_log(LOG_DEBUG, "srw_bend_init");
579 if (!srw_bend_init(assoc))
581 srw_error = 3; /* assume Authentication error */
583 yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
584 &srw_res->num_diagnostics, 1, 0);
589 rr.setname = "default";
592 rr.basenames = &srw_req->database;
595 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
597 if (srw_req->query_type == Z_SRW_query_type_cql)
599 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
600 ext->direct_reference = odr_getoidbystr(assoc->decode,
601 "1.2.840.10003.16.2");
602 ext->indirect_reference = 0;
604 ext->which = Z_External_CQL;
605 ext->u.cql = srw_req->query.cql;
607 rr.query->which = Z_Query_type_104;
608 rr.query->u.type_104 = ext;
610 else if (srw_req->query_type == Z_SRW_query_type_pqf)
612 Z_RPNQuery *RPNquery;
613 YAZ_PQF_Parser pqf_parser;
615 pqf_parser = yaz_pqf_create ();
617 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
623 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
625 yaz_log(LOG_LOG, "%*s^\n", (int)off+4, "");
626 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
631 rr.query->which = Z_Query_type_1;
632 rr.query->u.type_1 = RPNquery;
634 yaz_pqf_destroy (pqf_parser);
639 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
642 if (!srw_error && !assoc->init->bend_search)
647 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
648 srw_res->num_diagnostics = 1;
649 srw_res->diagnostics = (Z_SRW_diagnostic *)
650 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
651 yaz_mk_std_diagnostic(assoc->encode,
652 srw_res->diagnostics, srw_error, 0);
656 rr.stream = assoc->encode;
657 rr.decode = assoc->decode;
658 rr.print = assoc->print;
660 rr.association = assoc;
666 yaz_log_zquery(rr.query);
667 (assoc->init->bend_search)(assoc->backend, &rr);
670 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
671 if (rr.errcode == 109) /* database unavailable */
676 srw_res->num_diagnostics = 1;
677 srw_res->diagnostics = (Z_SRW_diagnostic *)
678 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
679 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
680 yaz_diag_bib1_to_srw (rr.errcode),
682 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %s",
683 srw_res->diagnostics[0].uri);
687 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
688 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
690 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
691 start, number, rr.hits);
693 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
700 yaz_log(LOG_LOG, "Request out or range");
705 int packing = Z_SRW_recordPacking_string;
706 if (start + number > rr.hits)
707 number = rr.hits - start + 1;
708 if (srw_req->recordPacking &&
709 !strcmp(srw_req->recordPacking, "xml"))
710 packing = Z_SRW_recordPacking_XML;
711 srw_res->records = (Z_SRW_record *)
712 odr_malloc(assoc->encode,
713 number * sizeof(*srw_res->records));
714 for (i = 0; i<number; i++)
718 srw_res->records[j].recordPacking = packing;
719 srw_res->records[j].recordData_buf = 0;
720 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
721 errcode = srw_bend_fetch(assoc, i+start, srw_req,
722 srw_res->records + j);
725 srw_res->num_diagnostics = 1;
726 srw_res->diagnostics = (Z_SRW_diagnostic *)
727 odr_malloc(assoc->encode,
728 sizeof(*srw_res->diagnostics));
730 yaz_mk_std_diagnostic(assoc->encode,
731 srw_res->diagnostics,
732 yaz_diag_bib1_to_srw (errcode),
736 if (srw_res->records[j].recordData_buf)
739 srw_res->num_records = j;
741 srw_res->records = 0;
747 static void srw_bend_explain(association *assoc, request *req,
748 Z_SRW_explainRequest *srw_req,
749 Z_SRW_explainResponse *srw_res,
752 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
756 yaz_log(LOG_DEBUG, "srw_bend_init");
757 if (!srw_bend_init(assoc))
762 if (assoc->init && assoc->init->bend_explain)
766 rr.stream = assoc->encode;
767 rr.decode = assoc->decode;
768 rr.print = assoc->print;
770 rr.database = srw_req->database;
771 rr.schema = "http://explain.z3950.org/dtd/2.0/";
772 (*assoc->init->bend_explain)(assoc->backend, &rr);
775 int packing = Z_SRW_recordPacking_string;
776 if (srw_req->recordPacking &&
777 !strcmp(srw_req->recordPacking, "xml"))
778 packing = Z_SRW_recordPacking_XML;
779 srw_res->record.recordSchema = 0;
780 srw_res->record.recordPacking = packing;
781 srw_res->record.recordData_buf = rr.explain_buf;
782 srw_res->record.recordData_len = strlen(rr.explain_buf);
783 srw_res->record.recordPosition = 0;
789 static void process_http_request(association *assoc, request *req)
791 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
792 ODR o = assoc->encode;
793 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
795 Z_SOAP *soap_package = 0;
798 Z_HTTP_Response *hres = 0;
800 char *stylesheet = 0;
801 Z_SRW_diagnostic *diagnostic = 0;
802 int num_diagnostic = 0;
804 if (!strcmp(hreq->path, "/test"))
806 p = z_get_HTTP_Response(o, 200);
807 hres = p->u.HTTP_Response;
808 hres->content_buf = "1234567890\n";
809 hres->content_len = strlen(hres->content_buf);
814 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
815 yaz_log(LOG_DEBUG, "yaz_srw_decode returned %d", r);
817 if (r == 2) /* not taken */
819 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
820 &diagnostic, &num_diagnostic);
821 yaz_log(LOG_DEBUG, "yaz_sru_decode returned %d", r);
823 if (r == 0) /* decode SRW/SRU OK .. */
826 if (sr->which == Z_SRW_searchRetrieve_request)
829 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
831 stylesheet = sr->u.request->stylesheet;
834 res->u.response->diagnostics = diagnostic;
835 res->u.response->num_diagnostics = num_diagnostic;
839 srw_bend_search(assoc, req, sr->u.request, res->u.response,
842 if (http_code == 200)
843 soap_package->u.generic->p = res;
845 else if (sr->which == Z_SRW_explain_request)
847 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
848 stylesheet = sr->u.explain_request->stylesheet;
851 res->u.explain_response->diagnostics = diagnostic;
852 res->u.explain_response->num_diagnostics = num_diagnostic;
854 srw_bend_explain(assoc, req, sr->u.explain_request,
855 res->u.explain_response, &http_code);
856 if (http_code == 200)
857 soap_package->u.generic->p = res;
859 else if (sr->which == Z_SRW_scan_request)
861 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
862 stylesheet = sr->u.scan_request->stylesheet;
865 res->u.scan_response->diagnostics = diagnostic;
866 res->u.scan_response->num_diagnostics = num_diagnostic;
868 yaz_add_srw_diagnostic(o,
869 &res->u.scan_response->diagnostics,
870 &res->u.scan_response->num_diagnostics,
872 if (http_code == 200)
873 soap_package->u.generic->p = res;
877 yaz_log(LOG_LOG, "generate soap error");
879 z_soap_error(assoc->encode, soap_package,
880 "SOAP-ENV:Client", "Bad method", 0);
882 if (http_code == 200 || http_code == 500)
884 static Z_SOAP_Handler soap_handlers[3] = {
886 {"http://www.loc.gov/zing/srw/", 0,
887 (Z_SOAP_fun) yaz_srw_codec},
888 {"http://www.loc.gov/zing/srw/v1.0/", 0,
889 (Z_SOAP_fun) yaz_srw_codec},
895 p = z_get_HTTP_Response(o, 200);
896 hres = p->u.HTTP_Response;
897 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
898 &hres->content_buf, &hres->content_len,
899 soap_handlers, charset, stylesheet);
900 hres->code = http_code;
902 strcpy(ctype, "text/xml");
905 strcat(ctype, "; charset=");
906 strcat(ctype, charset);
908 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
911 p = z_get_HTTP_Response(o, http_code);
915 p = z_get_HTTP_Response(o, 500);
916 hres = p->u.HTTP_Response;
917 if (!strcmp(hreq->version, "1.0"))
919 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
920 if (v && !strcmp(v, "Keep-Alive"))
924 hres->version = "1.0";
928 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
929 if (v && !strcmp(v, "close"))
933 hres->version = "1.1";
937 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
938 assoc->state = ASSOC_DEAD;
939 assoc->cs_get_mask = 0;
944 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
946 if (alive && isdigit(*alive))
950 if (t < 0 || t > 3600)
952 iochan_settimeout(assoc->client_chan,t);
953 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
955 process_gdu_response(assoc, req, p);
958 static void process_gdu_request(association *assoc, request *req)
960 if (req->gdu_request->which == Z_GDU_Z3950)
963 req->apdu_request = req->gdu_request->u.z3950;
964 if (process_z_request(assoc, req, &msg) < 0)
965 do_close_req(assoc, Z_Close_systemProblem, msg, req);
967 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
968 process_http_request(assoc, req);
971 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
976 * Initiate request processing.
978 static int process_z_request(association *assoc, request *req, char **msg)
984 *msg = "Unknown Error";
985 assert(req && req->state == REQUEST_IDLE);
986 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
988 *msg = "Missing InitRequest";
991 switch (req->apdu_request->which)
993 case Z_APDU_initRequest:
994 iochan_settimeout(assoc->client_chan,
995 statserv_getcontrol()->idle_timeout * 60);
996 res = process_initRequest(assoc, req); break;
997 case Z_APDU_searchRequest:
998 res = process_searchRequest(assoc, req, &fd); break;
999 case Z_APDU_presentRequest:
1000 res = process_presentRequest(assoc, req, &fd); break;
1001 case Z_APDU_scanRequest:
1002 if (assoc->init->bend_scan)
1003 res = process_scanRequest(assoc, req, &fd);
1006 *msg = "Cannot handle Scan APDU";
1010 case Z_APDU_extendedServicesRequest:
1011 if (assoc->init->bend_esrequest)
1012 res = process_ESRequest(assoc, req, &fd);
1015 *msg = "Cannot handle Extended Services APDU";
1019 case Z_APDU_sortRequest:
1020 if (assoc->init->bend_sort)
1021 res = process_sortRequest(assoc, req, &fd);
1024 *msg = "Cannot handle Sort APDU";
1029 process_close(assoc, req);
1031 case Z_APDU_deleteResultSetRequest:
1032 if (assoc->init->bend_delete)
1033 res = process_deleteRequest(assoc, req, &fd);
1036 *msg = "Cannot handle Delete APDU";
1040 case Z_APDU_segmentRequest:
1041 if (assoc->init->bend_segment)
1043 res = process_segmentRequest (assoc, req);
1047 *msg = "Cannot handle Segment APDU";
1051 case Z_APDU_triggerResourceControlRequest:
1054 *msg = "Bad APDU received";
1059 yaz_log(LOG_DEBUG, " result immediately available");
1060 retval = process_z_response(assoc, req, res);
1064 yaz_log(LOG_DEBUG, " result unavailble");
1067 else /* no result yet - one will be provided later */
1071 /* Set up an I/O handler for the fd supplied by the backend */
1073 yaz_log(LOG_DEBUG, " establishing handler for result");
1074 req->state = REQUEST_PENDING;
1075 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1077 iochan_setdata(chan, assoc);
1084 * Handle message from the backend.
1086 void backend_response(IOCHAN i, int event)
1088 association *assoc = (association *)iochan_getdata(i);
1089 request *req = request_head(&assoc->incoming);
1093 yaz_log(LOG_DEBUG, "backend_response");
1094 assert(assoc && req && req->state != REQUEST_IDLE);
1095 /* determine what it is we're waiting for */
1096 switch (req->apdu_request->which)
1098 case Z_APDU_searchRequest:
1099 res = response_searchRequest(assoc, req, 0, &fd); break;
1101 case Z_APDU_presentRequest:
1102 res = response_presentRequest(assoc, req, 0, &fd); break;
1103 case Z_APDU_scanRequest:
1104 res = response_scanRequest(assoc, req, 0, &fd); break;
1107 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1110 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1112 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1113 do_close(assoc, Z_Close_systemProblem, 0);
1117 else if (!res) /* no result yet - try again later */
1119 yaz_log(LOG_DEBUG, " no result yet");
1120 iochan_setfd(i, fd); /* in case fd has changed */
1125 * Encode response, and transfer the request structure to the outgoing queue.
1127 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1129 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1133 if (!z_GDU(assoc->print, &res, 0, 0))
1134 yaz_log(LOG_WARN, "ODR print error: %s",
1135 odr_errmsg(odr_geterror(assoc->print)));
1136 odr_reset(assoc->print);
1138 if (!z_GDU(assoc->encode, &res, 0, 0))
1140 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1141 odr_errmsg(odr_geterror(assoc->decode)),
1142 odr_getelement(assoc->decode));
1143 request_release(req);
1146 req->response = odr_getbuf(assoc->encode, &req->len_response,
1147 &req->size_response);
1148 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1149 odr_reset(assoc->encode);
1150 req->state = REQUEST_IDLE;
1151 request_enq(&assoc->outgoing, req);
1152 /* turn the work over to the ir_session handler */
1153 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1154 assoc->cs_put_mask = EVENT_OUTPUT;
1155 /* Is there more work to be done? give that to the input handler too */
1157 if (request_head(&assoc->incoming))
1159 yaz_log (LOG_DEBUG, "more work to be done");
1160 iochan_setevent(assoc->client_chan, EVENT_WORK);
1167 * Encode response, and transfer the request structure to the outgoing queue.
1169 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1171 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1172 gres->which = Z_GDU_Z3950;
1173 gres->u.z3950 = res;
1175 return process_gdu_response(assoc, req, gres);
1180 * Handle init request.
1181 * At the moment, we don't check the options
1182 * anywhere else in the code - we just try not to do anything that would
1183 * break a naive client. We'll toss 'em into the association block when
1184 * we need them there.
1186 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1188 statserv_options_block *cb = statserv_getcontrol();
1189 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1190 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1191 Z_InitResponse *resp = apdu->u.initResponse;
1192 bend_initresult *binitres;
1196 yaz_log(LOG_LOG, "Got initRequest");
1197 if (req->implementationId)
1198 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1199 if (req->implementationName)
1200 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1201 if (req->implementationVersion)
1202 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1204 assoc_init_reset(assoc);
1206 assoc->init->auth = req->idAuthentication;
1207 assoc->init->referenceId = req->referenceId;
1209 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1211 Z_CharSetandLanguageNegotiation *negotiation =
1212 yaz_get_charneg_record (req->otherInfo);
1214 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1215 assoc->init->charneg_request = negotiation;
1219 if (!(binitres = (*cb->bend_init)(assoc->init)))
1221 yaz_log(LOG_WARN, "Bad response from backend.");
1225 assoc->backend = binitres->handle;
1226 if ((assoc->init->bend_sort))
1227 yaz_log (LOG_DEBUG, "Sort handler installed");
1228 if ((assoc->init->bend_search))
1229 yaz_log (LOG_DEBUG, "Search handler installed");
1230 if ((assoc->init->bend_present))
1231 yaz_log (LOG_DEBUG, "Present handler installed");
1232 if ((assoc->init->bend_esrequest))
1233 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1234 if ((assoc->init->bend_delete))
1235 yaz_log (LOG_DEBUG, "Delete handler installed");
1236 if ((assoc->init->bend_scan))
1237 yaz_log (LOG_DEBUG, "Scan handler installed");
1238 if ((assoc->init->bend_segment))
1239 yaz_log (LOG_DEBUG, "Segment handler installed");
1241 resp->referenceId = req->referenceId;
1243 /* let's tell the client what we can do */
1244 if (ODR_MASK_GET(req->options, Z_Options_search))
1246 ODR_MASK_SET(resp->options, Z_Options_search);
1247 strcat(options, "srch");
1249 if (ODR_MASK_GET(req->options, Z_Options_present))
1251 ODR_MASK_SET(resp->options, Z_Options_present);
1252 strcat(options, " prst");
1254 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1255 assoc->init->bend_delete)
1257 ODR_MASK_SET(resp->options, Z_Options_delSet);
1258 strcat(options, " del");
1260 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1261 assoc->init->bend_esrequest)
1263 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1264 strcat (options, " extendedServices");
1266 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1268 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1269 strcat(options, " namedresults");
1271 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1273 ODR_MASK_SET(resp->options, Z_Options_scan);
1274 strcat(options, " scan");
1276 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1278 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1279 strcat(options, " concurrop");
1281 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1283 ODR_MASK_SET(resp->options, Z_Options_sort);
1284 strcat(options, " sort");
1287 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1288 && assoc->init->charneg_response)
1290 Z_OtherInformation **p;
1291 Z_OtherInformationUnit *p0;
1293 yaz_oi_APDU(apdu, &p);
1295 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1296 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1298 p0->which = Z_OtherInfo_externallyDefinedInfo;
1299 p0->information.externallyDefinedInfo =
1300 assoc->init->charneg_response;
1302 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1303 strcat(options, " negotiation");
1306 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1308 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1310 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1311 assoc->version = 1; /* 1 & 2 are equivalent */
1313 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1315 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1318 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1320 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1324 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1325 assoc->maximumRecordSize = *req->maximumRecordSize;
1326 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1327 assoc->maximumRecordSize = control_block->maxrecordsize;
1328 assoc->preferredMessageSize = *req->preferredMessageSize;
1329 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1330 assoc->preferredMessageSize = assoc->maximumRecordSize;
1332 resp->preferredMessageSize = &assoc->preferredMessageSize;
1333 resp->maximumRecordSize = &assoc->maximumRecordSize;
1335 resp->implementationId = odr_prepend(assoc->encode,
1336 assoc->init->implementation_id,
1337 resp->implementationId);
1339 resp->implementationName = odr_prepend(assoc->encode,
1340 assoc->init->implementation_name,
1341 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1343 version = odr_strdup(assoc->encode, "$Revision: 1.28 $");
1344 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1345 version[strlen(version)-2] = '\0';
1346 resp->implementationVersion = odr_prepend(assoc->encode,
1347 assoc->init->implementation_version,
1348 odr_prepend(assoc->encode, &version[11],
1349 resp->implementationVersion));
1351 if (binitres->errcode)
1353 yaz_log(LOG_LOG, "Connection rejected by backend.");
1355 assoc->state = ASSOC_DEAD;
1356 resp->userInformationField = init_diagnostics(assoc->encode,
1358 binitres->errstring);
1361 assoc->state = ASSOC_UP;
1366 * Diagnostic in default format, to be returned as either a surrogate
1367 * or non-surrogate diagnostic in the context of an open session, or
1368 * as User-information when an Init is refused.
1370 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1372 int *err = odr_intdup(odr, error);
1373 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1374 odr_malloc (odr, sizeof(*dr));
1376 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1377 addinfo ? " -- " : "", addinfo ? addinfo : "");
1379 dr->diagnosticSetId =
1380 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1381 dr->condition = err;
1382 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1383 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1388 * Set the specified `errcode' and `errstring' into a UserInfo-1
1389 * external to be returned to the client in accordance with Z35.90
1390 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1391 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1393 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1397 Z_OtherInformation *u;
1398 Z_OtherInformationUnit *l;
1399 Z_DiagnosticFormat *d;
1400 Z_DiagnosticFormat_s *e;
1402 x = (Z_External*) odr_malloc(odr, sizeof *x);
1404 x->indirect_reference = 0;
1405 oid.proto = PROTO_Z3950;
1406 oid.oclass = CLASS_USERINFO;
1407 oid.value = VAL_USERINFO1;
1408 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1409 x->which = Z_External_userInfo1;
1411 u = odr_malloc(odr, sizeof *u);
1413 u->num_elements = 1;
1414 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1415 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1418 l->which = Z_OtherInfo_externallyDefinedInfo;
1420 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1421 l->information.externallyDefinedInfo = x2;
1423 x2->indirect_reference = 0;
1424 oid.oclass = CLASS_DIAGSET;
1425 oid.value = VAL_DIAG1;
1426 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1427 x2->which = Z_External_diag1;
1429 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1432 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1433 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1436 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1437 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1443 * nonsurrogate diagnostic record.
1445 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1447 Z_Records *rec = (Z_Records *)
1448 odr_malloc (assoc->encode, sizeof(*rec));
1449 rec->which = Z_Records_NSD;
1450 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1455 * surrogate diagnostic.
1457 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1458 int error, char *addinfo)
1460 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1461 odr_malloc (assoc->encode, sizeof(*rec));
1462 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1464 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1465 rec->databaseName = dbname;
1466 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1467 rec->u.surrogateDiagnostic = drec;
1468 drec->which = Z_DiagRec_defaultFormat;
1469 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1475 * multiple nonsurrogate diagnostics.
1477 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1479 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1480 int *err = odr_intdup(assoc->encode, error);
1481 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1482 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1483 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1484 odr_malloc (assoc->encode, sizeof(*rec));
1486 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1488 recs->num_diagRecs = 1;
1489 recs->diagRecs = recp;
1491 drec->which = Z_DiagRec_defaultFormat;
1492 drec->u.defaultFormat = rec;
1494 rec->diagnosticSetId =
1495 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1496 rec->condition = err;
1498 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1499 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1503 static Z_Records *pack_records(association *a, char *setname, int start,
1504 int *num, Z_RecordComposition *comp,
1505 int *next, int *pres, oid_value format,
1506 Z_ReferenceId *referenceId,
1509 int recno, total_length = 0, toget = *num, dumped_records = 0;
1510 Z_Records *records =
1511 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1512 Z_NamePlusRecordList *reclist =
1513 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1514 Z_NamePlusRecord **list =
1515 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1517 records->which = Z_Records_DBOSD;
1518 records->u.databaseOrSurDiagnostics = reclist;
1519 reclist->num_records = 0;
1520 reclist->records = list;
1521 *pres = Z_PresentStatus_success;
1525 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1526 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1527 a->maximumRecordSize);
1528 for (recno = start; reclist->num_records < toget; recno++)
1531 Z_NamePlusRecord *thisrec;
1532 int this_length = 0;
1534 * we get the number of bytes allocated on the stream before any
1535 * allocation done by the backend - this should give us a reasonable
1536 * idea of the total size of the data so far.
1538 total_length = odr_total(a->encode) - dumped_records;
1544 freq.last_in_set = 0;
1545 freq.setname = setname;
1546 freq.surrogate_flag = 0;
1547 freq.number = recno;
1549 freq.request_format = format;
1550 freq.request_format_raw = oid;
1551 freq.output_format = format;
1552 freq.output_format_raw = 0;
1553 freq.stream = a->encode;
1554 freq.print = a->print;
1555 freq.referenceId = referenceId;
1557 (*a->init->bend_fetch)(a->backend, &freq);
1558 /* backend should be able to signal whether error is system-wide
1559 or only pertaining to current record */
1562 if (!freq.surrogate_flag)
1565 *pres = Z_PresentStatus_failure;
1566 /* for 'present request out of range',
1567 set addinfo to record position if not set */
1568 if (freq.errcode == 13 && freq.errstring == 0)
1570 sprintf (s, "%d", recno);
1573 return diagrec(a, freq.errcode, freq.errstring);
1575 reclist->records[reclist->num_records] =
1576 surrogatediagrec(a, freq.basename, freq.errcode,
1578 reclist->num_records++;
1579 *next = freq.last_in_set ? 0 : recno + 1;
1583 this_length = freq.len;
1585 this_length = odr_total(a->encode) - total_length - dumped_records;
1586 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1587 this_length, total_length, dumped_records);
1588 if (a->preferredMessageSize > 0 &&
1589 this_length + total_length > a->preferredMessageSize)
1591 /* record is small enough, really */
1592 if (this_length <= a->preferredMessageSize && recno > start)
1594 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1595 *pres = Z_PresentStatus_partial_2;
1598 /* record can only be fetched by itself */
1599 if (this_length < a->maximumRecordSize)
1601 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1604 yaz_log(LOG_DEBUG, " Dropped it");
1605 reclist->records[reclist->num_records] =
1606 surrogatediagrec(a, freq.basename, 16, 0);
1607 reclist->num_records++;
1608 *next = freq.last_in_set ? 0 : recno + 1;
1609 dumped_records += this_length;
1613 else /* too big entirely */
1615 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1616 reclist->records[reclist->num_records] =
1617 surrogatediagrec(a, freq.basename, 17, 0);
1618 reclist->num_records++;
1619 *next = freq.last_in_set ? 0 : recno + 1;
1620 dumped_records += this_length;
1625 if (!(thisrec = (Z_NamePlusRecord *)
1626 odr_malloc(a->encode, sizeof(*thisrec))))
1628 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1629 strlen(freq.basename) + 1)))
1631 strcpy(thisrec->databaseName, freq.basename);
1632 thisrec->which = Z_NamePlusRecord_databaseRecord;
1634 if (freq.output_format_raw)
1636 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1637 freq.output_format = ident->value;
1639 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1640 freq.record, freq.len);
1641 if (!thisrec->u.databaseRecord)
1643 reclist->records[reclist->num_records] = thisrec;
1644 reclist->num_records++;
1645 *next = freq.last_in_set ? 0 : recno + 1;
1647 *num = reclist->num_records;
1651 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1654 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1655 bend_search_rr *bsrr =
1656 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1658 yaz_log(LOG_LOG, "Got SearchRequest.");
1660 bsrr->request = reqb;
1661 bsrr->association = assoc;
1662 bsrr->referenceId = req->referenceId;
1663 save_referenceId (reqb, bsrr->referenceId);
1665 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1666 if (req->databaseNames)
1669 for (i = 0; i < req->num_databaseNames; i++)
1670 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1672 yaz_log_zquery(req->query);
1674 if (assoc->init->bend_search)
1676 bsrr->setname = req->resultSetName;
1677 bsrr->replace_set = *req->replaceIndicator;
1678 bsrr->num_bases = req->num_databaseNames;
1679 bsrr->basenames = req->databaseNames;
1680 bsrr->query = req->query;
1681 bsrr->stream = assoc->encode;
1682 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1683 bsrr->decode = assoc->decode;
1684 bsrr->print = assoc->print;
1687 bsrr->errstring = NULL;
1688 bsrr->search_info = NULL;
1689 (assoc->init->bend_search)(assoc->backend, bsrr);
1693 return response_searchRequest(assoc, reqb, bsrr, fd);
1696 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1699 * Prepare a searchresponse based on the backend results. We probably want
1700 * to look at making the fetching of records nonblocking as well, but
1701 * so far, we'll keep things simple.
1702 * If bsrt is null, that means we're called in response to a communications
1703 * event, and we'll have to get the response for ourselves.
1705 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1706 bend_search_rr *bsrt, int *fd)
1708 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1709 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1710 Z_SearchResponse *resp = (Z_SearchResponse *)
1711 odr_malloc (assoc->encode, sizeof(*resp));
1712 int *nulint = odr_intdup (assoc->encode, 0);
1713 bool_t *sr = odr_intdup(assoc->encode, 1);
1714 int *next = odr_intdup(assoc->encode, 0);
1715 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1717 apdu->which = Z_APDU_searchResponse;
1718 apdu->u.searchResponse = resp;
1719 resp->referenceId = req->referenceId;
1720 resp->additionalSearchInfo = 0;
1721 resp->otherInfo = 0;
1723 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1725 yaz_log(LOG_FATAL, "Bad result from backend");
1728 else if (bsrt->errcode)
1730 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1731 resp->resultCount = nulint;
1732 resp->numberOfRecordsReturned = nulint;
1733 resp->nextResultSetPosition = nulint;
1734 resp->searchStatus = nulint;
1735 resp->resultSetStatus = none;
1736 resp->presentStatus = 0;
1740 int *toget = odr_intdup(assoc->encode, 0);
1741 int *presst = odr_intdup(assoc->encode, 0);
1742 Z_RecordComposition comp, *compp = 0;
1744 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1747 resp->resultCount = &bsrt->hits;
1749 comp.which = Z_RecordComp_simple;
1750 /* how many records does the user agent want, then? */
1751 if (bsrt->hits <= *req->smallSetUpperBound)
1753 *toget = bsrt->hits;
1754 if ((comp.u.simple = req->smallSetElementSetNames))
1757 else if (bsrt->hits < *req->largeSetLowerBound)
1759 *toget = *req->mediumSetPresentNumber;
1760 if (*toget > bsrt->hits)
1761 *toget = bsrt->hits;
1762 if ((comp.u.simple = req->mediumSetElementSetNames))
1768 if (*toget && !resp->records)
1773 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1776 form = prefformat->value;
1777 resp->records = pack_records(assoc, req->resultSetName, 1,
1778 toget, compp, next, presst, form, req->referenceId,
1779 req->preferredRecordSyntax);
1782 resp->numberOfRecordsReturned = toget;
1783 resp->nextResultSetPosition = next;
1784 resp->searchStatus = sr;
1785 resp->resultSetStatus = 0;
1786 resp->presentStatus = presst;
1790 if (*resp->resultCount)
1792 resp->numberOfRecordsReturned = nulint;
1793 resp->nextResultSetPosition = next;
1794 resp->searchStatus = sr;
1795 resp->resultSetStatus = 0;
1796 resp->presentStatus = 0;
1799 resp->additionalSearchInfo = bsrt->search_info;
1804 * Maybe we got a little over-friendly when we designed bend_fetch to
1805 * get only one record at a time. Some backends can optimise multiple-record
1806 * fetches, and at any rate, there is some overhead involved in
1807 * all that selecting and hopping around. Problem is, of course, that the
1808 * frontend can't know ahead of time how many records it'll need to
1809 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1810 * is downright lousy as a bulk data transfer protocol.
1812 * To start with, we'll do the fetching of records from the backend
1813 * in one operation: To save some trips in and out of the event-handler,
1814 * and to simplify the interface to pack_records. At any rate, asynch
1815 * operation is more fun in operations that have an unpredictable execution
1816 * speed - which is normally more true for search than for present.
1818 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1821 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1825 Z_PresentResponse *resp;
1829 yaz_log(LOG_LOG, "Got PresentRequest.");
1831 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1834 form = prefformat->value;
1835 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1837 resp->presentStatus = odr_intdup(assoc->encode, 0);
1838 if (assoc->init->bend_present)
1840 bend_present_rr *bprr = (bend_present_rr *)
1841 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1842 bprr->setname = req->resultSetId;
1843 bprr->start = *req->resultSetStartPoint;
1844 bprr->number = *req->numberOfRecordsRequested;
1845 bprr->format = form;
1846 bprr->comp = req->recordComposition;
1847 bprr->referenceId = req->referenceId;
1848 bprr->stream = assoc->encode;
1849 bprr->print = assoc->print;
1850 bprr->request = reqb;
1851 bprr->association = assoc;
1853 bprr->errstring = NULL;
1854 (*assoc->init->bend_present)(assoc->backend, bprr);
1860 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1861 *resp->presentStatus = Z_PresentStatus_failure;
1864 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1865 next = odr_intdup(assoc->encode, 0);
1866 num = odr_intdup(assoc->encode, 0);
1868 apdu->which = Z_APDU_presentResponse;
1869 apdu->u.presentResponse = resp;
1870 resp->referenceId = req->referenceId;
1871 resp->otherInfo = 0;
1875 *num = *req->numberOfRecordsRequested;
1877 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1878 num, req->recordComposition, next, resp->presentStatus,
1879 form, req->referenceId, req->preferredRecordSyntax);
1883 resp->numberOfRecordsReturned = num;
1884 resp->nextResultSetPosition = next;
1890 * Scan was implemented rather in a hurry, and with support for only the basic
1891 * elements of the service in the backend API. Suggestions are welcome.
1893 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1895 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1896 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1897 Z_ScanResponse *res = (Z_ScanResponse *)
1898 odr_malloc (assoc->encode, sizeof(*res));
1899 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1900 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1901 Z_ListEntries *ents = (Z_ListEntries *)
1902 odr_malloc (assoc->encode, sizeof(*ents));
1903 Z_DiagRecs *diagrecs_p = NULL;
1905 bend_scan_rr *bsrr = (bend_scan_rr *)
1906 odr_malloc (assoc->encode, sizeof(*bsrr));
1907 struct scan_entry *save_entries;
1909 yaz_log(LOG_LOG, "Got ScanRequest");
1911 apdu->which = Z_APDU_scanResponse;
1912 apdu->u.scanResponse = res;
1913 res->referenceId = req->referenceId;
1915 /* if step is absent, set it to 0 */
1916 res->stepSize = odr_intdup(assoc->encode, 0);
1918 *res->stepSize = *req->stepSize;
1920 res->scanStatus = scanStatus;
1921 res->numberOfEntriesReturned = numberOfEntriesReturned;
1922 res->positionOfTerm = 0;
1923 res->entries = ents;
1924 ents->num_entries = 0;
1925 ents->entries = NULL;
1926 ents->num_nonsurrogateDiagnostics = 0;
1927 ents->nonsurrogateDiagnostics = NULL;
1928 res->attributeSet = 0;
1931 if (req->databaseNames)
1934 for (i = 0; i < req->num_databaseNames; i++)
1935 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1937 bsrr->num_bases = req->num_databaseNames;
1938 bsrr->basenames = req->databaseNames;
1939 bsrr->num_entries = *req->numberOfTermsRequested;
1940 bsrr->term = req->termListAndStartPoint;
1941 bsrr->referenceId = req->referenceId;
1942 bsrr->stream = assoc->encode;
1943 bsrr->print = assoc->print;
1944 bsrr->step_size = res->stepSize;
1946 /* Note that version 2.0 of YAZ and older did not set entries ..
1947 We do now. And when we do it's easier to extend the scan entry
1948 We know that if the scan handler did set entries, it will
1949 not know of new member display_term.
1951 if (bsrr->num_entries > 0)
1954 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1956 for (i = 0; i<bsrr->num_entries; i++)
1958 bsrr->entries[i].term = 0;
1959 bsrr->entries[i].occurrences = 0;
1960 bsrr->entries[i].errcode = 0;
1961 bsrr->entries[i].errstring = 0;
1962 bsrr->entries[i].display_term = 0;
1965 save_entries = bsrr->entries; /* save it so we can compare later */
1967 if (req->attributeSet &&
1968 (attset = oid_getentbyoid(req->attributeSet)) &&
1969 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
1970 bsrr->attributeset = attset->value;
1972 bsrr->attributeset = VAL_NONE;
1973 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
1974 bsrr->term_position = req->preferredPositionInResponse ?
1975 *req->preferredPositionInResponse : 1;
1976 ((int (*)(void *, bend_scan_rr *))
1977 (*assoc->init->bend_scan))(assoc->backend, bsrr);
1979 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
1983 Z_Entry **tab = (Z_Entry **)
1984 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
1986 if (bsrr->status == BEND_SCAN_PARTIAL)
1987 *scanStatus = Z_Scan_partial_5;
1989 *scanStatus = Z_Scan_success;
1990 ents->entries = tab;
1991 ents->num_entries = bsrr->num_entries;
1992 res->numberOfEntriesReturned = &ents->num_entries;
1993 res->positionOfTerm = &bsrr->term_position;
1994 for (i = 0; i < bsrr->num_entries; i++)
2000 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2001 if (bsrr->entries[i].occurrences >= 0)
2003 e->which = Z_Entry_termInfo;
2004 e->u.termInfo = t = (Z_TermInfo *)
2005 odr_malloc(assoc->encode, sizeof(*t));
2006 t->suggestedAttributes = 0;
2008 if (save_entries == bsrr->entries &&
2009 bsrr->entries[i].display_term)
2011 /* the entries was NOT set by the handler. So it's
2012 safe to test for new member display_term. It is
2015 t->displayTerm = odr_strdup(assoc->encode,
2016 bsrr->entries[i].display_term);
2018 t->alternativeTerm = 0;
2019 t->byAttributes = 0;
2020 t->otherTermInfo = 0;
2021 t->globalOccurrences = &bsrr->entries[i].occurrences;
2022 t->term = (Z_Term *)
2023 odr_malloc(assoc->encode, sizeof(*t->term));
2024 t->term->which = Z_Term_general;
2025 t->term->u.general = o =
2026 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2027 o->buf = (unsigned char *)
2028 odr_malloc(assoc->encode, o->len = o->size =
2029 strlen(bsrr->entries[i].term));
2030 memcpy(o->buf, bsrr->entries[i].term, o->len);
2031 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2032 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2036 Z_DiagRecs *drecs = diagrecs (assoc,
2037 bsrr->entries[i].errcode,
2038 bsrr->entries[i].errstring);
2039 assert (drecs->num_diagRecs == 1);
2040 e->which = Z_Entry_surrogateDiagnostic;
2041 assert (drecs->diagRecs[0]);
2042 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2048 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2049 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2054 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2057 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2058 Z_SortResponse *res = (Z_SortResponse *)
2059 odr_malloc (assoc->encode, sizeof(*res));
2060 bend_sort_rr *bsrr = (bend_sort_rr *)
2061 odr_malloc (assoc->encode, sizeof(*bsrr));
2063 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2065 yaz_log(LOG_LOG, "Got SortRequest.");
2067 bsrr->num_input_setnames = req->num_inputResultSetNames;
2068 bsrr->input_setnames = req->inputResultSetNames;
2069 bsrr->referenceId = req->referenceId;
2070 bsrr->output_setname = req->sortedResultSetName;
2071 bsrr->sort_sequence = req->sortSequence;
2072 bsrr->stream = assoc->encode;
2073 bsrr->print = assoc->print;
2075 bsrr->sort_status = Z_SortResponse_failure;
2077 bsrr->errstring = 0;
2079 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2081 res->referenceId = bsrr->referenceId;
2082 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2083 res->resultSetStatus = 0;
2086 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2087 res->diagnostics = dr->diagRecs;
2088 res->num_diagnostics = dr->num_diagRecs;
2092 res->num_diagnostics = 0;
2093 res->diagnostics = 0;
2095 res->resultCount = 0;
2098 apdu->which = Z_APDU_sortResponse;
2099 apdu->u.sortResponse = res;
2103 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2106 Z_DeleteResultSetRequest *req =
2107 reqb->apdu_request->u.deleteResultSetRequest;
2108 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2109 odr_malloc (assoc->encode, sizeof(*res));
2110 bend_delete_rr *bdrr = (bend_delete_rr *)
2111 odr_malloc (assoc->encode, sizeof(*bdrr));
2112 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2114 yaz_log(LOG_LOG, "Got DeleteRequest.");
2116 bdrr->num_setnames = req->num_resultSetList;
2117 bdrr->setnames = req->resultSetList;
2118 bdrr->stream = assoc->encode;
2119 bdrr->print = assoc->print;
2120 bdrr->function = *req->deleteFunction;
2121 bdrr->referenceId = req->referenceId;
2123 if (bdrr->num_setnames > 0)
2126 bdrr->statuses = (int*)
2127 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2128 bdrr->num_setnames);
2129 for (i = 0; i < bdrr->num_setnames; i++)
2130 bdrr->statuses[i] = 0;
2132 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2134 res->referenceId = req->referenceId;
2136 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2138 res->deleteListStatuses = 0;
2139 if (bdrr->num_setnames > 0)
2142 res->deleteListStatuses = (Z_ListStatuses *)
2143 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2144 res->deleteListStatuses->num = bdrr->num_setnames;
2145 res->deleteListStatuses->elements =
2147 odr_malloc (assoc->encode,
2148 sizeof(*res->deleteListStatuses->elements) *
2149 bdrr->num_setnames);
2150 for (i = 0; i<bdrr->num_setnames; i++)
2152 res->deleteListStatuses->elements[i] =
2154 odr_malloc (assoc->encode,
2155 sizeof(**res->deleteListStatuses->elements));
2156 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2157 res->deleteListStatuses->elements[i]->id =
2158 odr_strdup (assoc->encode, bdrr->setnames[i]);
2162 res->numberNotDeleted = 0;
2163 res->bulkStatuses = 0;
2164 res->deleteMessage = 0;
2167 apdu->which = Z_APDU_deleteResultSetResponse;
2168 apdu->u.deleteResultSetResponse = res;
2172 static void process_close(association *assoc, request *reqb)
2174 Z_Close *req = reqb->apdu_request->u.close;
2175 static char *reasons[] =
2182 "securityViolation",
2189 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2190 reasons[*req->closeReason], req->diagnosticInformation ?
2191 req->diagnosticInformation : "NULL");
2192 if (assoc->version < 3) /* to make do_force respond with close */
2194 do_close_req(assoc, Z_Close_finished,
2195 "Association terminated by client", reqb);
2198 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2202 reqb->len_refid = refid->len;
2203 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2204 memcpy (reqb->refid, refid->buf, refid->len);
2208 reqb->len_refid = 0;
2213 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2215 process_z_response (a, req, res);
2218 bend_request bend_request_mk (bend_association a)
2220 request *nreq = request_get (&a->outgoing);
2221 nreq->request_mem = nmem_create ();
2225 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2230 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2231 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2232 id->len = id->size = req->len_refid;
2233 memcpy (id->buf, req->refid, req->len_refid);
2237 void bend_request_destroy (bend_request *req)
2239 nmem_destroy((*req)->request_mem);
2240 request_release(*req);
2244 int bend_backend_respond (bend_association a, bend_request req)
2248 r = process_z_request (a, req, &msg);
2250 yaz_log (LOG_WARN, "%s", msg);
2254 void bend_request_setdata(bend_request r, void *p)
2259 void *bend_request_getdata(bend_request r)
2261 return r->clientData;
2264 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2266 bend_segment_rr req;
2268 req.segment = reqb->apdu_request->u.segmentRequest;
2269 req.stream = assoc->encode;
2270 req.decode = assoc->decode;
2271 req.print = assoc->print;
2272 req.association = assoc;
2274 (*assoc->init->bend_segment)(assoc->backend, &req);
2279 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2281 bend_esrequest_rr esrequest;
2283 Z_ExtendedServicesRequest *req =
2284 reqb->apdu_request->u.extendedServicesRequest;
2285 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2287 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2289 yaz_log(LOG_DEBUG,"inside Process esRequest");
2291 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2292 esrequest.stream = assoc->encode;
2293 esrequest.decode = assoc->decode;
2294 esrequest.print = assoc->print;
2295 esrequest.errcode = 0;
2296 esrequest.errstring = NULL;
2297 esrequest.request = reqb;
2298 esrequest.association = assoc;
2299 esrequest.taskPackage = 0;
2300 esrequest.referenceId = req->referenceId;
2302 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2304 /* If the response is being delayed, return NULL */
2305 if (esrequest.request == NULL)
2308 resp->referenceId = req->referenceId;
2310 if (esrequest.errcode == -1)
2312 /* Backend service indicates request will be processed */
2313 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2314 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2316 else if (esrequest.errcode == 0)
2318 /* Backend service indicates request will be processed */
2319 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2320 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2324 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2325 esrequest.errstring);
2327 /* Backend indicates error, request will not be processed */
2328 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2329 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2330 resp->num_diagnostics = diagRecs->num_diagRecs;
2331 resp->diagnostics = diagRecs->diagRecs;
2333 /* Do something with the members of bend_extendedservice */
2334 if (esrequest.taskPackage)
2335 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2336 (const char *) esrequest.taskPackage,
2338 yaz_log(LOG_DEBUG,"Send the result apdu");