2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.12 2003-12-31 00:14:01 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|EVENT_OUTPUT);
275 if (conn->io_pending)
276 { /* cs_accept didn't complete */
277 assoc->cs_accept_mask =
278 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
279 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
281 iochan_setflag (h, assoc->cs_accept_mask);
284 { /* cs_accept completed. Prepare for reading (cs_get) */
285 assoc->cs_accept_mask = 0;
286 assoc->cs_get_mask = EVENT_INPUT;
287 iochan_setflag (h, assoc->cs_get_mask);
291 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
293 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
295 yaz_log(LOG_DEBUG, "ir_session (input)");
296 /* We aren't speaking to this fellow */
297 if (assoc->state == ASSOC_DEAD)
299 yaz_log(LOG_LOG, "Connection closed - end of session");
301 destroy_association(assoc);
305 assoc->cs_get_mask = EVENT_INPUT;
306 if ((res = cs_get(conn, &assoc->input_buffer,
307 &assoc->input_buffer_len)) <= 0)
309 yaz_log(LOG_LOG, "Connection closed by client");
311 destroy_association(assoc);
315 else if (res == 1) /* incomplete read - wait for more */
317 if (conn->io_pending & CS_WANT_WRITE)
318 assoc->cs_get_mask |= EVENT_OUTPUT;
319 iochan_setflag(h, assoc->cs_get_mask);
322 if (cs_more(conn)) /* more stuff - call us again later, please */
323 iochan_setevent(h, EVENT_INPUT);
325 /* we got a complete PDU. Let's decode it */
326 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
327 assoc->input_buffer[0] & 0xff,
328 assoc->input_buffer[1] & 0xff,
329 assoc->input_buffer[2] & 0xff);
330 req = request_get(&assoc->incoming); /* get a new request */
331 odr_reset(assoc->decode);
332 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
333 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
335 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
337 odr_errmsg(odr_geterror(assoc->decode)),
338 odr_getelement(assoc->decode),
339 odr_offset(assoc->decode));
340 if (assoc->decode->error != OHTTP)
342 yaz_log(LOG_LOG, "PDU dump:");
343 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
344 request_release(req);
345 do_close(assoc, Z_Close_protocolError,"Malformed package");
349 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
350 assoc->state = ASSOC_DEAD;
351 process_gdu_response(assoc, req, p);
355 req->request_mem = odr_extract_mem(assoc->decode);
358 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
359 yaz_log(LOG_WARN, "ODR print error: %s",
360 odr_errmsg(odr_geterror(assoc->print)));
361 odr_reset(assoc->print);
363 request_enq(&assoc->incoming, req);
366 /* can we do something yet? */
367 req = request_head(&assoc->incoming);
368 if (req->state == REQUEST_IDLE)
370 request_deq(&assoc->incoming);
371 process_gdu_request(assoc, req);
374 if (event & assoc->cs_put_mask)
376 request *req = request_head(&assoc->outgoing);
378 assoc->cs_put_mask = 0;
379 yaz_log(LOG_DEBUG, "ir_session (output)");
380 req->state = REQUEST_PENDING;
381 switch (res = cs_put(conn, req->response, req->len_response))
384 yaz_log(LOG_LOG, "Connection closed by client");
386 destroy_association(assoc);
389 case 0: /* all sent - release the request structure */
390 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
392 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
395 nmem_destroy(req->request_mem);
396 request_deq(&assoc->outgoing);
397 request_release(req);
398 if (!request_head(&assoc->outgoing))
399 { /* restore mask for cs_get operation ... */
400 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
401 iochan_setflag(h, assoc->cs_get_mask);
402 if (assoc->state == ASSOC_DEAD)
403 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
407 assoc->cs_put_mask = EVENT_OUTPUT;
411 if (conn->io_pending & CS_WANT_WRITE)
412 assoc->cs_put_mask |= EVENT_OUTPUT;
413 if (conn->io_pending & CS_WANT_READ)
414 assoc->cs_put_mask |= EVENT_INPUT;
415 iochan_setflag(h, assoc->cs_put_mask);
418 if (event & EVENT_EXCEPT)
420 yaz_log(LOG_LOG, "ir_session (exception)");
422 destroy_association(assoc);
427 static int process_z_request(association *assoc, request *req, char **msg);
429 static void assoc_init_reset(association *assoc)
432 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
434 assoc->init->stream = assoc->encode;
435 assoc->init->print = assoc->print;
436 assoc->init->auth = 0;
437 assoc->init->referenceId = 0;
438 assoc->init->implementation_version = 0;
439 assoc->init->implementation_id = 0;
440 assoc->init->implementation_name = 0;
441 assoc->init->bend_sort = NULL;
442 assoc->init->bend_search = NULL;
443 assoc->init->bend_present = NULL;
444 assoc->init->bend_esrequest = NULL;
445 assoc->init->bend_delete = NULL;
446 assoc->init->bend_scan = NULL;
447 assoc->init->bend_segment = NULL;
448 assoc->init->bend_fetch = NULL;
449 assoc->init->bend_explain = NULL;
451 assoc->init->charneg_request = NULL;
452 assoc->init->charneg_response = NULL;
454 assoc->init->decode = assoc->decode;
455 assoc->init->peer_name =
456 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
459 static int srw_bend_init(association *assoc)
461 const char *encoding = "UTF-8";
463 bend_initresult *binitres;
464 statserv_options_block *cb = statserv_getcontrol();
466 assoc_init_reset(assoc);
468 assoc->maximumRecordSize = 3000000;
469 assoc->preferredMessageSize = 3000000;
471 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
472 assoc->init->charneg_request = ce->u.charNeg3;
474 if (!(binitres = (*cb->bend_init)(assoc->init)))
476 yaz_log(LOG_WARN, "Bad response from backend.");
479 assoc->backend = binitres->handle;
483 static int srw_bend_fetch(association *assoc, int pos,
484 Z_SRW_searchRetrieveRequest *srw_req,
485 Z_SRW_record *record)
488 ODR o = assoc->encode;
490 rr.setname = "default";
493 rr.request_format = VAL_TEXT_XML;
494 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
497 rr.comp = (Z_RecordComposition *)
498 odr_malloc(assoc->decode, sizeof(*rr.comp));
499 rr.comp->which = Z_RecordComp_complex;
500 rr.comp->u.complex = (Z_CompSpec *)
501 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
502 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
503 odr_malloc(assoc->encode, sizeof(bool_t));
504 *rr.comp->u.complex->selectAlternativeSyntax = 0;
505 rr.comp->u.complex->num_dbSpecific = 0;
506 rr.comp->u.complex->dbSpecific = 0;
507 rr.comp->u.complex->num_recordSyntax = 0;
508 rr.comp->u.complex->recordSyntax = 0;
510 rr.comp->u.complex->generic = (Z_Specification *)
511 odr_malloc(assoc->decode, sizeof(Z_Specification));
512 rr.comp->u.complex->generic->which = Z_Schema_uri;
513 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
514 rr.comp->u.complex->generic->elementSpec = 0;
516 rr.stream = assoc->encode;
517 rr.print = assoc->print;
523 rr.output_format = VAL_TEXT_XML;
524 rr.output_format_raw = 0;
527 rr.surrogate_flag = 0;
528 rr.schema = srw_req->recordSchema;
530 if (!assoc->init->bend_fetch)
533 (*assoc->init->bend_fetch)(assoc->backend, &rr);
537 record->recordData_buf = rr.record;
538 record->recordData_len = rr.len;
539 record->recordPosition = odr_intdup(o, pos);
541 record->recordSchema = odr_strdup(o, rr.schema);
543 record->recordSchema = 0;
548 static void srw_bend_search(association *assoc, request *req,
549 Z_SRW_searchRetrieveRequest *srw_req,
550 Z_SRW_searchRetrieveResponse *srw_res,
558 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
559 yaz_log(LOG_DEBUG, "srw_bend_search");
562 yaz_log(LOG_DEBUG, "srw_bend_init");
563 if (!srw_bend_init(assoc))
565 srw_error = 3; /* assume Authentication error */
567 srw_res->num_diagnostics = 1;
568 srw_res->diagnostics = (Z_SRW_diagnostic *)
569 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
570 srw_res->diagnostics[0].code =
571 odr_intdup(assoc->encode, srw_error);
572 srw_res->diagnostics[0].details = 0;
577 rr.setname = "default";
580 rr.basenames = &srw_req->database;
583 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
585 if (srw_req->query_type == Z_SRW_query_type_cql)
587 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
588 ext->direct_reference = odr_getoidbystr(assoc->decode,
589 "1.2.840.10003.16.2");
590 ext->indirect_reference = 0;
592 ext->which = Z_External_CQL;
593 ext->u.cql = srw_req->query.cql;
595 rr.query->which = Z_Query_type_104;
596 rr.query->u.type_104 = ext;
598 else if (srw_req->query_type == Z_SRW_query_type_pqf)
600 Z_RPNQuery *RPNquery;
601 YAZ_PQF_Parser pqf_parser;
603 pqf_parser = yaz_pqf_create ();
605 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
611 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
612 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
613 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
618 rr.query->which = Z_Query_type_1;
619 rr.query->u.type_1 = RPNquery;
621 yaz_pqf_destroy (pqf_parser);
626 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
629 if (!srw_error && !assoc->init->bend_search)
634 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
635 srw_res->num_diagnostics = 1;
636 srw_res->diagnostics = (Z_SRW_diagnostic *)
637 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
638 srw_res->diagnostics[0].code =
639 odr_intdup(assoc->encode, srw_error);
640 srw_res->diagnostics[0].details = 0;
644 rr.stream = assoc->encode;
645 rr.decode = assoc->decode;
646 rr.print = assoc->print;
648 rr.association = assoc;
654 yaz_log_zquery(rr.query);
655 (assoc->init->bend_search)(assoc->backend, &rr);
656 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
659 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
660 if (rr.errcode == 109) /* database unavailable */
665 srw_res->num_diagnostics = 1;
666 srw_res->diagnostics = (Z_SRW_diagnostic *)
667 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
668 srw_res->diagnostics[0].code =
669 odr_intdup(assoc->encode,
670 yaz_diag_bib1_to_srw (rr.errcode));
671 srw_res->diagnostics[0].details = rr.errstring;
672 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
673 *srw_res->diagnostics[0].code);
678 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
679 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
681 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
682 start, number, rr.hits);
684 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
691 yaz_log(LOG_LOG, "Request out or range");
696 int packing = Z_SRW_recordPacking_string;
697 if (start + number > rr.hits)
698 number = rr.hits - start + 1;
699 if (srw_req->recordPacking &&
700 !strcmp(srw_req->recordPacking, "xml"))
701 packing = Z_SRW_recordPacking_XML;
702 srw_res->records = (Z_SRW_record *)
703 odr_malloc(assoc->encode,
704 number * sizeof(*srw_res->records));
705 for (i = 0; i<number; i++)
709 srw_res->records[j].recordPacking = packing;
710 srw_res->records[j].recordData_buf = 0;
711 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
712 errcode = srw_bend_fetch(assoc, i+start, srw_req,
713 srw_res->records + j);
716 srw_res->num_diagnostics = 1;
717 srw_res->diagnostics = (Z_SRW_diagnostic *)
718 odr_malloc(assoc->encode,
719 sizeof(*srw_res->diagnostics));
720 srw_res->diagnostics[0].code =
721 odr_intdup(assoc->encode,
722 yaz_diag_bib1_to_srw (errcode));
723 srw_res->diagnostics[0].details = rr.errstring;
726 if (srw_res->records[j].recordData_buf)
729 srw_res->num_records = j;
731 srw_res->records = 0;
737 static void srw_bend_explain(association *assoc, request *req,
738 Z_SRW_explainRequest *srw_req,
739 Z_SRW_explainResponse *srw_res,
742 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
746 yaz_log(LOG_DEBUG, "srw_bend_init");
747 if (!srw_bend_init(assoc))
752 if (assoc->init && assoc->init->bend_explain)
756 rr.stream = assoc->encode;
757 rr.decode = assoc->decode;
758 rr.print = assoc->print;
760 rr.database = srw_req->database;
761 (*assoc->init->bend_explain)(assoc->backend, &rr);
764 int packing = Z_SRW_recordPacking_string;
765 if (srw_req->recordPacking &&
766 !strcmp(srw_req->recordPacking, "xml"))
767 packing = Z_SRW_recordPacking_XML;
768 srw_res->record.recordSchema = 0;
769 srw_res->record.recordPacking = packing;
770 srw_res->record.recordData_buf = rr.explain_buf;
771 srw_res->record.recordData_len = strlen(rr.explain_buf);
772 srw_res->record.recordPosition = 0;
778 static void process_http_request(association *assoc, request *req)
780 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
781 ODR o = assoc->encode;
783 Z_HTTP_Response *hres = 0;
786 if (!strcmp(hreq->method, "GET"))
788 char *db = "Default";
789 const char *p0 = hreq->path, *p1;
790 const char *operation = 0;
794 Z_SOAP *soap_package = 0;
795 static Z_SOAP_Handler soap_handlers[2] = {
796 {"http://www.loc.gov/zing/srw/", 0,
797 (Z_SOAP_fun) yaz_srw_codec},
803 p1 = strchr(p0, '?');
805 p1 = p0 + strlen(p0);
808 db = odr_malloc(assoc->decode, p1 - p0 + 1);
809 memcpy (db, p0, p1 - p0);
813 operation = yaz_uri_val(p1, "operation", o);
815 operation = "explain";
817 if (p1 && !strcmp(operation, "searchRetrieve"))
819 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
820 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
821 char *query = yaz_uri_val(p1, "query", o);
822 char *pQuery = yaz_uri_val(p1, "pQuery", o);
823 char *sortKeys = yaz_uri_val(p1, "sortKeys", o);
828 sr->u.request->query_type = Z_SRW_query_type_cql;
829 sr->u.request->query.cql = query;
833 sr->u.request->query_type = Z_SRW_query_type_pqf;
834 sr->u.request->query.pqf = pQuery;
838 sr->u.request->sort_type = Z_SRW_sort_type_sort;
839 sr->u.request->sort.sortKeys = sortKeys;
841 sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", o);
842 sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", o);
843 if (!sr->u.request->recordPacking)
844 sr->u.request->recordPacking = "xml";
845 yaz_uri_val_int(p1, "maximumRecords", o,
846 &sr->u.request->maximumRecords);
847 yaz_uri_val_int(p1, "startRecord", o,
848 &sr->u.request->startRecord);
849 sr->u.request->database = db;
850 srw_bend_search(assoc, req, sr->u.request, res->u.response,
853 soap_package = odr_malloc(o, sizeof(*soap_package));
854 soap_package->which = Z_SOAP_generic;
856 soap_package->u.generic =
857 odr_malloc(o, sizeof(*soap_package->u.generic));
859 soap_package->u.generic->p = res;
860 soap_package->u.generic->ns = soap_handlers[0].ns;
861 soap_package->u.generic->no = 0;
863 soap_package->ns = "SRU";
865 p = z_get_HTTP_Response(o, http_code);
866 if (http_code == 200)
868 hres = p->u.HTTP_Response;
870 ret = z_soap_codec_enc(assoc->encode, &soap_package,
871 &hres->content_buf, &hres->content_len,
872 soap_handlers, charset);
874 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
878 strcpy(ctype, "text/xml; charset=");
879 strcat(ctype, charset);
880 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
884 else if (p1 && !strcmp(operation, "explain"))
886 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
887 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
890 sr->u.explain_request->database = db;
891 sr->u.explain_request->recordPacking =
892 yaz_uri_val(p1, "recordPacking", o);
893 if (!sr->u.explain_request->recordPacking)
894 sr->u.explain_request->recordPacking = "xml";
896 srw_bend_explain(assoc, req, sr->u.explain_request,
897 res->u.explain_response, &http_code);
899 if (res->u.explain_response->record.recordData_buf)
901 soap_package = odr_malloc(o, sizeof(*soap_package));
902 soap_package->which = Z_SOAP_generic;
904 soap_package->u.generic =
905 odr_malloc(o, sizeof(*soap_package->u.generic));
907 soap_package->u.generic->p = res;
908 soap_package->u.generic->ns = soap_handlers[0].ns;
909 soap_package->u.generic->no = 0;
911 soap_package->ns = "SRU";
913 p = z_get_HTTP_Response(o, 200);
914 hres = p->u.HTTP_Response;
916 ret = z_soap_codec_enc(assoc->encode, &soap_package,
917 &hres->content_buf, &hres->content_len,
918 soap_handlers, charset);
920 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
924 strcpy(ctype, "text/xml; charset=");
925 strcat(ctype, charset);
926 z_HTTP_header_add(o, &hres->headers, "Content-Type",
933 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
934 !memcmp(hreq->path, "/doc/", 5))
939 strcpy(fpath, DOCDIR);
940 strcat(fpath, hreq->path+4);
941 f = fopen(fpath, "rb");
944 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
953 fseek(f, 0L, SEEK_END);
955 if (sz >= 0 && sz < 500000)
957 const char *ctype = "application/octet-stream";
960 p = z_get_HTTP_Response(o, 200);
961 hres = p->u.HTTP_Response;
962 hres->content_buf = (char *) odr_malloc(o, sz + 1);
963 hres->content_len = sz;
964 fseek(f, 0L, SEEK_SET);
965 fread(hres->content_buf, 1, sz, f);
966 if ((cp = strrchr(fpath, '.'))) {
968 if (!strcmp(cp, "png"))
970 else if (!strcmp(cp, "gif"))
972 else if (!strcmp(cp, "xml"))
974 else if (!strcmp(cp, "html"))
977 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
985 if (!strcmp(hreq->path, "/"))
990 const char *doclink = "";
991 p = z_get_HTTP_Response(o, 200);
992 hres = p->u.HTTP_Response;
993 hres->content_buf = (char *) odr_malloc(o, 400);
995 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
996 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
998 sprintf (hres->content_buf,
999 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1002 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1005 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1006 YAZ_VERSION "</P>\n"
1009 "</HTML>\n", doclink);
1010 hres->content_len = strlen(hres->content_buf);
1011 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1017 p = z_get_HTTP_Response(o, 404);
1020 else if (!strcmp(hreq->method, "POST"))
1022 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1024 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1026 Z_SOAP *soap_package = 0;
1028 int http_code = 500;
1029 const char *charset_p = 0;
1032 static Z_SOAP_Handler soap_handlers[3] = {
1034 {"http://www.loc.gov/zing/srw/", 0,
1035 (Z_SOAP_fun) yaz_srw_codec},
1036 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1037 (Z_SOAP_fun) yaz_srw_codec},
1041 if ((charset_p = strstr(content_type, "; charset=")))
1045 while (i < 20 && charset_p[i] &&
1046 !strchr("; \n\r", charset_p[i]))
1048 charset = odr_malloc(assoc->encode, i+1);
1049 memcpy(charset, charset_p, i);
1051 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1053 ret = z_soap_codec(assoc->decode, &soap_package,
1054 &hreq->content_buf, &hreq->content_len,
1057 if (!ret && soap_package->which == Z_SOAP_generic)
1060 char *db = "Default";
1061 const char *p0 = hreq->path, *p1;
1062 Z_SRW_PDU *sr = soap_package->u.generic->p;
1066 p1 = strchr(p0, '?');
1068 p1 = p0 + strlen(p0);
1071 db = (char*) odr_malloc(assoc->decode, p1 - p0 + 1);
1072 memcpy (db, p0, p1 - p0);
1076 if (sr->which == Z_SRW_searchRetrieve_request)
1079 yaz_srw_get(assoc->encode,
1080 Z_SRW_searchRetrieve_response);
1082 if (!sr->u.request->database)
1083 sr->u.request->database = db;
1085 if (soap_package->u.generic->no == 1) /* SRW 1.0 */
1086 res->srw_version = 0;
1088 srw_bend_search(assoc, req, sr->u.request,
1089 res->u.response, &http_code);
1091 soap_package->u.generic->p = res;
1093 else if (sr->which == Z_SRW_explain_request)
1096 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1097 sr->u.explain_request->database = db;
1099 if (soap_package->u.generic->no == 1) /* SRW 1.0 */
1100 res->srw_version = 0;
1102 srw_bend_explain(assoc, req, sr->u.explain_request,
1103 res->u.explain_response, &http_code);
1104 if (http_code == 200)
1105 soap_package->u.generic->p = res;
1109 z_soap_error(assoc->encode, soap_package,
1110 "SOAP-ENV:Client", "Bad method", 0);
1115 if (http_code == 200 || http_code == 500)
1117 p = z_get_HTTP_Response(o, 200);
1118 hres = p->u.HTTP_Response;
1119 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1120 &hres->content_buf, &hres->content_len,
1121 soap_handlers, charset);
1122 hres->code = http_code;
1124 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1128 strcpy(ctype, "text/xml; charset=");
1129 strcat(ctype, charset);
1130 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1134 p = z_get_HTTP_Response(o, http_code);
1136 if (!p) /* still no response ? */
1137 p = z_get_HTTP_Response(o, 500);
1141 p = z_get_HTTP_Response(o, 405);
1142 hres = p->u.HTTP_Response;
1144 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1146 hres = p->u.HTTP_Response;
1147 if (!strcmp(hreq->version, "1.0"))
1149 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1150 if (v && !strcmp(v, "Keep-Alive"))
1154 hres->version = "1.0";
1158 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1159 if (v && !strcmp(v, "close"))
1163 hres->version = "1.1";
1167 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1168 assoc->state = ASSOC_DEAD;
1173 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1175 if (alive && isdigit(*alive))
1179 if (t < 0 || t > 3600)
1181 iochan_settimeout(assoc->client_chan,t);
1182 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1184 process_gdu_response(assoc, req, p);
1187 static void process_gdu_request(association *assoc, request *req)
1189 if (req->gdu_request->which == Z_GDU_Z3950)
1192 req->apdu_request = req->gdu_request->u.z3950;
1193 if (process_z_request(assoc, req, &msg) < 0)
1194 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1196 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1197 process_http_request(assoc, req);
1200 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1205 * Initiate request processing.
1207 static int process_z_request(association *assoc, request *req, char **msg)
1213 *msg = "Unknown Error";
1214 assert(req && req->state == REQUEST_IDLE);
1215 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1217 *msg = "Missing InitRequest";
1220 switch (req->apdu_request->which)
1222 case Z_APDU_initRequest:
1223 iochan_settimeout(assoc->client_chan,
1224 statserv_getcontrol()->idle_timeout * 60);
1225 res = process_initRequest(assoc, req); break;
1226 case Z_APDU_searchRequest:
1227 res = process_searchRequest(assoc, req, &fd); break;
1228 case Z_APDU_presentRequest:
1229 res = process_presentRequest(assoc, req, &fd); break;
1230 case Z_APDU_scanRequest:
1231 if (assoc->init->bend_scan)
1232 res = process_scanRequest(assoc, req, &fd);
1235 *msg = "Cannot handle Scan APDU";
1239 case Z_APDU_extendedServicesRequest:
1240 if (assoc->init->bend_esrequest)
1241 res = process_ESRequest(assoc, req, &fd);
1244 *msg = "Cannot handle Extended Services APDU";
1248 case Z_APDU_sortRequest:
1249 if (assoc->init->bend_sort)
1250 res = process_sortRequest(assoc, req, &fd);
1253 *msg = "Cannot handle Sort APDU";
1258 process_close(assoc, req);
1260 case Z_APDU_deleteResultSetRequest:
1261 if (assoc->init->bend_delete)
1262 res = process_deleteRequest(assoc, req, &fd);
1265 *msg = "Cannot handle Delete APDU";
1269 case Z_APDU_segmentRequest:
1270 if (assoc->init->bend_segment)
1272 res = process_segmentRequest (assoc, req);
1276 *msg = "Cannot handle Segment APDU";
1281 *msg = "Bad APDU received";
1286 yaz_log(LOG_DEBUG, " result immediately available");
1287 retval = process_z_response(assoc, req, res);
1291 yaz_log(LOG_DEBUG, " result unavailble");
1294 else /* no result yet - one will be provided later */
1298 /* Set up an I/O handler for the fd supplied by the backend */
1300 yaz_log(LOG_DEBUG, " establishing handler for result");
1301 req->state = REQUEST_PENDING;
1302 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1304 iochan_setdata(chan, assoc);
1311 * Handle message from the backend.
1313 void backend_response(IOCHAN i, int event)
1315 association *assoc = (association *)iochan_getdata(i);
1316 request *req = request_head(&assoc->incoming);
1320 yaz_log(LOG_DEBUG, "backend_response");
1321 assert(assoc && req && req->state != REQUEST_IDLE);
1322 /* determine what it is we're waiting for */
1323 switch (req->apdu_request->which)
1325 case Z_APDU_searchRequest:
1326 res = response_searchRequest(assoc, req, 0, &fd); break;
1328 case Z_APDU_presentRequest:
1329 res = response_presentRequest(assoc, req, 0, &fd); break;
1330 case Z_APDU_scanRequest:
1331 res = response_scanRequest(assoc, req, 0, &fd); break;
1334 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1337 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1339 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1340 do_close(assoc, Z_Close_systemProblem, 0);
1344 else if (!res) /* no result yet - try again later */
1346 yaz_log(LOG_DEBUG, " no result yet");
1347 iochan_setfd(i, fd); /* in case fd has changed */
1352 * Encode response, and transfer the request structure to the outgoing queue.
1354 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1356 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1360 if (!z_GDU(assoc->print, &res, 0, 0))
1361 yaz_log(LOG_WARN, "ODR print error: %s",
1362 odr_errmsg(odr_geterror(assoc->print)));
1363 odr_reset(assoc->print);
1365 if (!z_GDU(assoc->encode, &res, 0, 0))
1367 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1368 odr_errmsg(odr_geterror(assoc->decode)),
1369 odr_getelement(assoc->decode));
1370 request_release(req);
1373 req->response = odr_getbuf(assoc->encode, &req->len_response,
1374 &req->size_response);
1375 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1376 odr_reset(assoc->encode);
1377 req->state = REQUEST_IDLE;
1378 request_enq(&assoc->outgoing, req);
1379 /* turn the work over to the ir_session handler */
1380 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1381 assoc->cs_put_mask = EVENT_OUTPUT;
1382 /* Is there more work to be done? give that to the input handler too */
1384 if (request_head(&assoc->incoming))
1386 yaz_log (LOG_DEBUG, "more work to be done");
1387 iochan_setevent(assoc->client_chan, EVENT_WORK);
1394 * Encode response, and transfer the request structure to the outgoing queue.
1396 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1398 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1399 gres->which = Z_GDU_Z3950;
1400 gres->u.z3950 = res;
1402 return process_gdu_response(assoc, req, gres);
1407 * Handle init request.
1408 * At the moment, we don't check the options
1409 * anywhere else in the code - we just try not to do anything that would
1410 * break a naive client. We'll toss 'em into the association block when
1411 * we need them there.
1413 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1415 statserv_options_block *cb = statserv_getcontrol();
1416 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1417 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1418 Z_InitResponse *resp = apdu->u.initResponse;
1419 bend_initresult *binitres;
1423 yaz_log(LOG_LOG, "Got initRequest");
1424 if (req->implementationId)
1425 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1426 if (req->implementationName)
1427 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1428 if (req->implementationVersion)
1429 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1431 assoc_init_reset(assoc);
1433 assoc->init->auth = req->idAuthentication;
1434 assoc->init->referenceId = req->referenceId;
1436 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1438 Z_CharSetandLanguageNegotiation *negotiation =
1439 yaz_get_charneg_record (req->otherInfo);
1440 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1441 assoc->init->charneg_request = negotiation;
1444 if (!(binitres = (*cb->bend_init)(assoc->init)))
1446 yaz_log(LOG_WARN, "Bad response from backend.");
1450 assoc->backend = binitres->handle;
1451 if ((assoc->init->bend_sort))
1452 yaz_log (LOG_DEBUG, "Sort handler installed");
1453 if ((assoc->init->bend_search))
1454 yaz_log (LOG_DEBUG, "Search handler installed");
1455 if ((assoc->init->bend_present))
1456 yaz_log (LOG_DEBUG, "Present handler installed");
1457 if ((assoc->init->bend_esrequest))
1458 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1459 if ((assoc->init->bend_delete))
1460 yaz_log (LOG_DEBUG, "Delete handler installed");
1461 if ((assoc->init->bend_scan))
1462 yaz_log (LOG_DEBUG, "Scan handler installed");
1463 if ((assoc->init->bend_segment))
1464 yaz_log (LOG_DEBUG, "Segment handler installed");
1466 resp->referenceId = req->referenceId;
1468 /* let's tell the client what we can do */
1469 if (ODR_MASK_GET(req->options, Z_Options_search))
1471 ODR_MASK_SET(resp->options, Z_Options_search);
1472 strcat(options, "srch");
1474 if (ODR_MASK_GET(req->options, Z_Options_present))
1476 ODR_MASK_SET(resp->options, Z_Options_present);
1477 strcat(options, " prst");
1479 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1480 assoc->init->bend_delete)
1482 ODR_MASK_SET(resp->options, Z_Options_delSet);
1483 strcat(options, " del");
1485 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1486 assoc->init->bend_esrequest)
1488 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1489 strcat (options, " extendedServices");
1491 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1493 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1494 strcat(options, " namedresults");
1496 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1498 ODR_MASK_SET(resp->options, Z_Options_scan);
1499 strcat(options, " scan");
1501 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1503 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1504 strcat(options, " concurrop");
1506 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1508 ODR_MASK_SET(resp->options, Z_Options_sort);
1509 strcat(options, " sort");
1512 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1513 && assoc->init->charneg_response)
1515 Z_OtherInformation **p;
1516 Z_OtherInformationUnit *p0;
1518 yaz_oi_APDU(apdu, &p);
1520 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1521 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1523 p0->which = Z_OtherInfo_externallyDefinedInfo;
1524 p0->information.externallyDefinedInfo =
1525 assoc->init->charneg_response;
1527 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1528 strcat(options, " negotiation");
1531 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1533 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1534 assoc->version = 2; /* 1 & 2 are equivalent */
1536 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1538 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1541 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1543 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1547 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1548 assoc->maximumRecordSize = *req->maximumRecordSize;
1549 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1550 assoc->maximumRecordSize = control_block->maxrecordsize;
1551 assoc->preferredMessageSize = *req->preferredMessageSize;
1552 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1553 assoc->preferredMessageSize = assoc->maximumRecordSize;
1555 resp->preferredMessageSize = &assoc->preferredMessageSize;
1556 resp->maximumRecordSize = &assoc->maximumRecordSize;
1558 resp->implementationId = odr_prepend(assoc->encode,
1559 assoc->init->implementation_id,
1560 resp->implementationId);
1562 resp->implementationName = odr_prepend(assoc->encode,
1563 assoc->init->implementation_name,
1564 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1566 version = odr_strdup(assoc->encode, "$Revision: 1.12 $");
1567 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1568 version[strlen(version)-2] = '\0';
1569 resp->implementationVersion = odr_prepend(assoc->encode,
1570 assoc->init->implementation_version,
1571 odr_prepend(assoc->encode, &version[11],
1572 resp->implementationVersion));
1574 if (binitres->errcode)
1576 yaz_log(LOG_LOG, "Connection rejected by backend.");
1578 assoc->state = ASSOC_DEAD;
1579 resp->userInformationField = init_diagnostics(assoc->encode,
1581 binitres->errstring);
1584 assoc->state = ASSOC_UP;
1589 * Diagnostic in default format, to be returned as either a surrogate
1590 * or non-surrogate diagnostic in the context of an open session, or
1591 * as User-information when an Init is refused.
1593 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1595 int *err = odr_intdup(odr, error);
1596 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1597 odr_malloc (odr, sizeof(*dr));
1599 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1600 addinfo ? " -- " : "", addinfo ? addinfo : "");
1602 dr->diagnosticSetId =
1603 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1604 dr->condition = err;
1605 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1606 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1611 * Set the specified `errcode' and `errstring' into a UserInfo-1
1612 * external to be returned to the client in accordance with Z35.90
1613 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1614 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1616 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1620 Z_OtherInformation *u;
1621 Z_OtherInformationUnit *l;
1622 Z_DiagnosticFormat *d;
1623 Z_DiagnosticFormat_s *e;
1625 x = (Z_External*) odr_malloc(odr, sizeof *x);
1627 x->indirect_reference = 0;
1628 oid.proto = PROTO_Z3950;
1629 oid.oclass = CLASS_USERINFO;
1630 oid.value = VAL_USERINFO1;
1631 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1632 x->which = Z_External_userInfo1;
1634 u = odr_malloc(odr, sizeof *u);
1636 u->num_elements = 1;
1637 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1638 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1641 l->which = Z_OtherInfo_externallyDefinedInfo;
1643 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1644 l->information.externallyDefinedInfo = x2;
1646 x2->indirect_reference = 0;
1647 oid.oclass = CLASS_DIAGSET;
1648 oid.value = VAL_DIAG1;
1649 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1650 x2->which = Z_External_diag1;
1652 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1655 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1656 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1659 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1660 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1665 * nonsurrogate diagnostic record.
1667 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1669 Z_Records *rec = (Z_Records *)
1670 odr_malloc (assoc->encode, sizeof(*rec));
1671 rec->which = Z_Records_NSD;
1672 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1677 * surrogate diagnostic.
1679 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1680 int error, char *addinfo)
1682 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1683 odr_malloc (assoc->encode, sizeof(*rec));
1684 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1686 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1687 rec->databaseName = dbname;
1688 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1689 rec->u.surrogateDiagnostic = drec;
1690 drec->which = Z_DiagRec_defaultFormat;
1691 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1697 * multiple nonsurrogate diagnostics.
1699 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1701 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1702 int *err = odr_intdup(assoc->encode, error);
1703 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1704 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1705 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1706 odr_malloc (assoc->encode, sizeof(*rec));
1708 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1710 recs->num_diagRecs = 1;
1711 recs->diagRecs = recp;
1713 drec->which = Z_DiagRec_defaultFormat;
1714 drec->u.defaultFormat = rec;
1716 rec->diagnosticSetId =
1717 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1718 rec->condition = err;
1720 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1721 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1725 static Z_Records *pack_records(association *a, char *setname, int start,
1726 int *num, Z_RecordComposition *comp,
1727 int *next, int *pres, oid_value format,
1728 Z_ReferenceId *referenceId,
1731 int recno, total_length = 0, toget = *num, dumped_records = 0;
1732 Z_Records *records =
1733 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1734 Z_NamePlusRecordList *reclist =
1735 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1736 Z_NamePlusRecord **list =
1737 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1739 records->which = Z_Records_DBOSD;
1740 records->u.databaseOrSurDiagnostics = reclist;
1741 reclist->num_records = 0;
1742 reclist->records = list;
1743 *pres = Z_PRES_SUCCESS;
1747 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1748 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1749 a->maximumRecordSize);
1750 for (recno = start; reclist->num_records < toget; recno++)
1753 Z_NamePlusRecord *thisrec;
1754 int this_length = 0;
1756 * we get the number of bytes allocated on the stream before any
1757 * allocation done by the backend - this should give us a reasonable
1758 * idea of the total size of the data so far.
1760 total_length = odr_total(a->encode) - dumped_records;
1766 freq.last_in_set = 0;
1767 freq.setname = setname;
1768 freq.surrogate_flag = 0;
1769 freq.number = recno;
1771 freq.request_format = format;
1772 freq.request_format_raw = oid;
1773 freq.output_format = format;
1774 freq.output_format_raw = 0;
1775 freq.stream = a->encode;
1776 freq.print = a->print;
1777 freq.referenceId = referenceId;
1779 (*a->init->bend_fetch)(a->backend, &freq);
1780 /* backend should be able to signal whether error is system-wide
1781 or only pertaining to current record */
1784 if (!freq.surrogate_flag)
1787 *pres = Z_PRES_FAILURE;
1788 /* for 'present request out of range',
1789 set addinfo to record position if not set */
1790 if (freq.errcode == 13 && freq.errstring == 0)
1792 sprintf (s, "%d", recno);
1795 return diagrec(a, freq.errcode, freq.errstring);
1797 reclist->records[reclist->num_records] =
1798 surrogatediagrec(a, freq.basename, freq.errcode,
1800 reclist->num_records++;
1801 *next = freq.last_in_set ? 0 : recno + 1;
1805 this_length = freq.len;
1807 this_length = odr_total(a->encode) - total_length - dumped_records;
1808 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1809 this_length, total_length, dumped_records);
1810 if (this_length + total_length > a->preferredMessageSize)
1812 /* record is small enough, really */
1813 if (this_length <= a->preferredMessageSize && recno > start)
1815 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1816 *pres = Z_PRES_PARTIAL_2;
1819 /* record can only be fetched by itself */
1820 if (this_length < a->maximumRecordSize)
1822 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1825 yaz_log(LOG_DEBUG, " Dropped it");
1826 reclist->records[reclist->num_records] =
1827 surrogatediagrec(a, freq.basename, 16, 0);
1828 reclist->num_records++;
1829 *next = freq.last_in_set ? 0 : recno + 1;
1830 dumped_records += this_length;
1834 else /* too big entirely */
1836 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1837 reclist->records[reclist->num_records] =
1838 surrogatediagrec(a, freq.basename, 17, 0);
1839 reclist->num_records++;
1840 *next = freq.last_in_set ? 0 : recno + 1;
1841 dumped_records += this_length;
1846 if (!(thisrec = (Z_NamePlusRecord *)
1847 odr_malloc(a->encode, sizeof(*thisrec))))
1849 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1850 strlen(freq.basename) + 1)))
1852 strcpy(thisrec->databaseName, freq.basename);
1853 thisrec->which = Z_NamePlusRecord_databaseRecord;
1855 if (freq.output_format_raw)
1857 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1858 freq.output_format = ident->value;
1860 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1861 freq.record, freq.len);
1862 if (!thisrec->u.databaseRecord)
1864 reclist->records[reclist->num_records] = thisrec;
1865 reclist->num_records++;
1866 *next = freq.last_in_set ? 0 : recno + 1;
1868 *num = reclist->num_records;
1872 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1875 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1876 bend_search_rr *bsrr =
1877 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1879 yaz_log(LOG_LOG, "Got SearchRequest.");
1881 bsrr->request = reqb;
1882 bsrr->association = assoc;
1883 bsrr->referenceId = req->referenceId;
1884 save_referenceId (reqb, bsrr->referenceId);
1886 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1887 if (req->databaseNames)
1890 for (i = 0; i < req->num_databaseNames; i++)
1891 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1893 yaz_log_zquery(req->query);
1895 if (assoc->init->bend_search)
1897 bsrr->setname = req->resultSetName;
1898 bsrr->replace_set = *req->replaceIndicator;
1899 bsrr->num_bases = req->num_databaseNames;
1900 bsrr->basenames = req->databaseNames;
1901 bsrr->query = req->query;
1902 bsrr->stream = assoc->encode;
1903 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1904 bsrr->decode = assoc->decode;
1905 bsrr->print = assoc->print;
1908 bsrr->errstring = NULL;
1909 bsrr->search_info = NULL;
1910 (assoc->init->bend_search)(assoc->backend, bsrr);
1914 return response_searchRequest(assoc, reqb, bsrr, fd);
1917 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1920 * Prepare a searchresponse based on the backend results. We probably want
1921 * to look at making the fetching of records nonblocking as well, but
1922 * so far, we'll keep things simple.
1923 * If bsrt is null, that means we're called in response to a communications
1924 * event, and we'll have to get the response for ourselves.
1926 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1927 bend_search_rr *bsrt, int *fd)
1929 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1930 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1931 Z_SearchResponse *resp = (Z_SearchResponse *)
1932 odr_malloc (assoc->encode, sizeof(*resp));
1933 int *nulint = odr_intdup (assoc->encode, 0);
1934 bool_t *sr = odr_intdup(assoc->encode, 1);
1935 int *next = odr_intdup(assoc->encode, 0);
1936 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1938 apdu->which = Z_APDU_searchResponse;
1939 apdu->u.searchResponse = resp;
1940 resp->referenceId = req->referenceId;
1941 resp->additionalSearchInfo = 0;
1942 resp->otherInfo = 0;
1944 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1946 yaz_log(LOG_FATAL, "Bad result from backend");
1949 else if (bsrt->errcode)
1951 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1952 resp->resultCount = nulint;
1953 resp->numberOfRecordsReturned = nulint;
1954 resp->nextResultSetPosition = nulint;
1955 resp->searchStatus = nulint;
1956 resp->resultSetStatus = none;
1957 resp->presentStatus = 0;
1961 int *toget = odr_intdup(assoc->encode, 0);
1962 int *presst = odr_intdup(assoc->encode, 0);
1963 Z_RecordComposition comp, *compp = 0;
1965 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1968 resp->resultCount = &bsrt->hits;
1970 comp.which = Z_RecordComp_simple;
1971 /* how many records does the user agent want, then? */
1972 if (bsrt->hits <= *req->smallSetUpperBound)
1974 *toget = bsrt->hits;
1975 if ((comp.u.simple = req->smallSetElementSetNames))
1978 else if (bsrt->hits < *req->largeSetLowerBound)
1980 *toget = *req->mediumSetPresentNumber;
1981 if (*toget > bsrt->hits)
1982 *toget = bsrt->hits;
1983 if ((comp.u.simple = req->mediumSetElementSetNames))
1989 if (*toget && !resp->records)
1994 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1997 form = prefformat->value;
1998 resp->records = pack_records(assoc, req->resultSetName, 1,
1999 toget, compp, next, presst, form, req->referenceId,
2000 req->preferredRecordSyntax);
2003 resp->numberOfRecordsReturned = toget;
2004 resp->nextResultSetPosition = next;
2005 resp->searchStatus = sr;
2006 resp->resultSetStatus = 0;
2007 resp->presentStatus = presst;
2011 if (*resp->resultCount)
2013 resp->numberOfRecordsReturned = nulint;
2014 resp->nextResultSetPosition = next;
2015 resp->searchStatus = sr;
2016 resp->resultSetStatus = 0;
2017 resp->presentStatus = 0;
2020 resp->additionalSearchInfo = bsrt->search_info;
2025 * Maybe we got a little over-friendly when we designed bend_fetch to
2026 * get only one record at a time. Some backends can optimise multiple-record
2027 * fetches, and at any rate, there is some overhead involved in
2028 * all that selecting and hopping around. Problem is, of course, that the
2029 * frontend can't know ahead of time how many records it'll need to
2030 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2031 * is downright lousy as a bulk data transfer protocol.
2033 * To start with, we'll do the fetching of records from the backend
2034 * in one operation: To save some trips in and out of the event-handler,
2035 * and to simplify the interface to pack_records. At any rate, asynch
2036 * operation is more fun in operations that have an unpredictable execution
2037 * speed - which is normally more true for search than for present.
2039 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2042 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2046 Z_PresentResponse *resp;
2050 yaz_log(LOG_LOG, "Got PresentRequest.");
2052 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2055 form = prefformat->value;
2056 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2058 resp->presentStatus = odr_intdup(assoc->encode, 0);
2059 if (assoc->init->bend_present)
2061 bend_present_rr *bprr = (bend_present_rr *)
2062 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2063 bprr->setname = req->resultSetId;
2064 bprr->start = *req->resultSetStartPoint;
2065 bprr->number = *req->numberOfRecordsRequested;
2066 bprr->format = form;
2067 bprr->comp = req->recordComposition;
2068 bprr->referenceId = req->referenceId;
2069 bprr->stream = assoc->encode;
2070 bprr->print = assoc->print;
2071 bprr->request = reqb;
2072 bprr->association = assoc;
2074 bprr->errstring = NULL;
2075 (*assoc->init->bend_present)(assoc->backend, bprr);
2081 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2082 *resp->presentStatus = Z_PRES_FAILURE;
2085 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2086 next = odr_intdup(assoc->encode, 0);
2087 num = odr_intdup(assoc->encode, 0);
2089 apdu->which = Z_APDU_presentResponse;
2090 apdu->u.presentResponse = resp;
2091 resp->referenceId = req->referenceId;
2092 resp->otherInfo = 0;
2096 *num = *req->numberOfRecordsRequested;
2098 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2099 num, req->recordComposition, next, resp->presentStatus,
2100 form, req->referenceId, req->preferredRecordSyntax);
2104 resp->numberOfRecordsReturned = num;
2105 resp->nextResultSetPosition = next;
2111 * Scan was implemented rather in a hurry, and with support for only the basic
2112 * elements of the service in the backend API. Suggestions are welcome.
2114 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2116 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2117 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2118 Z_ScanResponse *res = (Z_ScanResponse *)
2119 odr_malloc (assoc->encode, sizeof(*res));
2120 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2121 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2122 Z_ListEntries *ents = (Z_ListEntries *)
2123 odr_malloc (assoc->encode, sizeof(*ents));
2124 Z_DiagRecs *diagrecs_p = NULL;
2126 bend_scan_rr *bsrr = (bend_scan_rr *)
2127 odr_malloc (assoc->encode, sizeof(*bsrr));
2128 struct scan_entry *save_entries;
2130 yaz_log(LOG_LOG, "Got ScanRequest");
2132 apdu->which = Z_APDU_scanResponse;
2133 apdu->u.scanResponse = res;
2134 res->referenceId = req->referenceId;
2136 /* if step is absent, set it to 0 */
2137 res->stepSize = odr_intdup(assoc->encode, 0);
2139 *res->stepSize = *req->stepSize;
2141 res->scanStatus = scanStatus;
2142 res->numberOfEntriesReturned = numberOfEntriesReturned;
2143 res->positionOfTerm = 0;
2144 res->entries = ents;
2145 ents->num_entries = 0;
2146 ents->entries = NULL;
2147 ents->num_nonsurrogateDiagnostics = 0;
2148 ents->nonsurrogateDiagnostics = NULL;
2149 res->attributeSet = 0;
2152 if (req->databaseNames)
2155 for (i = 0; i < req->num_databaseNames; i++)
2156 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2158 bsrr->num_bases = req->num_databaseNames;
2159 bsrr->basenames = req->databaseNames;
2160 bsrr->num_entries = *req->numberOfTermsRequested;
2161 bsrr->term = req->termListAndStartPoint;
2162 bsrr->referenceId = req->referenceId;
2163 bsrr->stream = assoc->encode;
2164 bsrr->print = assoc->print;
2165 bsrr->step_size = res->stepSize;
2167 /* Note that version 2.0 of YAZ and older did not set entries ..
2168 We do now. And when we do it's easier to extend the scan entry
2169 We know that if the scan handler did set entries, it will
2170 not know of new member display_term.
2172 if (bsrr->num_entries > 0)
2175 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2177 for (i = 0; i<bsrr->num_entries; i++)
2179 bsrr->entries[i].term = 0;
2180 bsrr->entries[i].occurrences = 0;
2181 bsrr->entries[i].errcode = 0;
2182 bsrr->entries[i].errstring = 0;
2183 bsrr->entries[i].display_term = 0;
2186 save_entries = bsrr->entries; /* save it so we can compare later */
2188 if (req->attributeSet &&
2189 (attset = oid_getentbyoid(req->attributeSet)) &&
2190 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2191 bsrr->attributeset = attset->value;
2193 bsrr->attributeset = VAL_NONE;
2194 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2195 bsrr->term_position = req->preferredPositionInResponse ?
2196 *req->preferredPositionInResponse : 1;
2197 ((int (*)(void *, bend_scan_rr *))
2198 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2200 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2204 Z_Entry **tab = (Z_Entry **)
2205 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2207 if (bsrr->status == BEND_SCAN_PARTIAL)
2208 *scanStatus = Z_Scan_partial_5;
2210 *scanStatus = Z_Scan_success;
2211 ents->entries = tab;
2212 ents->num_entries = bsrr->num_entries;
2213 res->numberOfEntriesReturned = &ents->num_entries;
2214 res->positionOfTerm = &bsrr->term_position;
2215 for (i = 0; i < bsrr->num_entries; i++)
2221 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2222 if (bsrr->entries[i].occurrences >= 0)
2224 e->which = Z_Entry_termInfo;
2225 e->u.termInfo = t = (Z_TermInfo *)
2226 odr_malloc(assoc->encode, sizeof(*t));
2227 t->suggestedAttributes = 0;
2229 if (save_entries == bsrr->entries &&
2230 bsrr->entries[i].display_term)
2232 /* the entries was NOT set by the handler. So it's
2233 safe to test for new member display_term. It is
2236 t->displayTerm = odr_strdup(assoc->encode,
2237 bsrr->entries[i].display_term);
2239 t->alternativeTerm = 0;
2240 t->byAttributes = 0;
2241 t->otherTermInfo = 0;
2242 t->globalOccurrences = &bsrr->entries[i].occurrences;
2243 t->term = (Z_Term *)
2244 odr_malloc(assoc->encode, sizeof(*t->term));
2245 t->term->which = Z_Term_general;
2246 t->term->u.general = o =
2247 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2248 o->buf = (unsigned char *)
2249 odr_malloc(assoc->encode, o->len = o->size =
2250 strlen(bsrr->entries[i].term));
2251 memcpy(o->buf, bsrr->entries[i].term, o->len);
2252 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2253 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2257 Z_DiagRecs *drecs = diagrecs (assoc,
2258 bsrr->entries[i].errcode,
2259 bsrr->entries[i].errstring);
2260 assert (drecs->num_diagRecs == 1);
2261 e->which = Z_Entry_surrogateDiagnostic;
2262 assert (drecs->diagRecs[0]);
2263 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2269 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2270 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2275 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2278 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2279 Z_SortResponse *res = (Z_SortResponse *)
2280 odr_malloc (assoc->encode, sizeof(*res));
2281 bend_sort_rr *bsrr = (bend_sort_rr *)
2282 odr_malloc (assoc->encode, sizeof(*bsrr));
2284 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2286 yaz_log(LOG_LOG, "Got SortRequest.");
2288 bsrr->num_input_setnames = req->num_inputResultSetNames;
2289 bsrr->input_setnames = req->inputResultSetNames;
2290 bsrr->referenceId = req->referenceId;
2291 bsrr->output_setname = req->sortedResultSetName;
2292 bsrr->sort_sequence = req->sortSequence;
2293 bsrr->stream = assoc->encode;
2294 bsrr->print = assoc->print;
2296 bsrr->sort_status = Z_SortStatus_failure;
2298 bsrr->errstring = 0;
2300 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2302 res->referenceId = bsrr->referenceId;
2303 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2304 res->resultSetStatus = 0;
2307 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2308 res->diagnostics = dr->diagRecs;
2309 res->num_diagnostics = dr->num_diagRecs;
2313 res->num_diagnostics = 0;
2314 res->diagnostics = 0;
2316 res->resultCount = 0;
2319 apdu->which = Z_APDU_sortResponse;
2320 apdu->u.sortResponse = res;
2324 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2327 Z_DeleteResultSetRequest *req =
2328 reqb->apdu_request->u.deleteResultSetRequest;
2329 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2330 odr_malloc (assoc->encode, sizeof(*res));
2331 bend_delete_rr *bdrr = (bend_delete_rr *)
2332 odr_malloc (assoc->encode, sizeof(*bdrr));
2333 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2335 yaz_log(LOG_LOG, "Got DeleteRequest.");
2337 bdrr->num_setnames = req->num_resultSetList;
2338 bdrr->setnames = req->resultSetList;
2339 bdrr->stream = assoc->encode;
2340 bdrr->print = assoc->print;
2341 bdrr->function = *req->deleteFunction;
2342 bdrr->referenceId = req->referenceId;
2344 if (bdrr->num_setnames > 0)
2347 bdrr->statuses = (int*)
2348 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2349 bdrr->num_setnames);
2350 for (i = 0; i < bdrr->num_setnames; i++)
2351 bdrr->statuses[i] = 0;
2353 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2355 res->referenceId = req->referenceId;
2357 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2359 res->deleteListStatuses = 0;
2360 if (bdrr->num_setnames > 0)
2363 res->deleteListStatuses = (Z_ListStatuses *)
2364 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2365 res->deleteListStatuses->num = bdrr->num_setnames;
2366 res->deleteListStatuses->elements =
2368 odr_malloc (assoc->encode,
2369 sizeof(*res->deleteListStatuses->elements) *
2370 bdrr->num_setnames);
2371 for (i = 0; i<bdrr->num_setnames; i++)
2373 res->deleteListStatuses->elements[i] =
2375 odr_malloc (assoc->encode,
2376 sizeof(**res->deleteListStatuses->elements));
2377 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2378 res->deleteListStatuses->elements[i]->id =
2379 odr_strdup (assoc->encode, bdrr->setnames[i]);
2383 res->numberNotDeleted = 0;
2384 res->bulkStatuses = 0;
2385 res->deleteMessage = 0;
2388 apdu->which = Z_APDU_deleteResultSetResponse;
2389 apdu->u.deleteResultSetResponse = res;
2393 static void process_close(association *assoc, request *reqb)
2395 Z_Close *req = reqb->apdu_request->u.close;
2396 static char *reasons[] =
2403 "securityViolation",
2410 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2411 reasons[*req->closeReason], req->diagnosticInformation ?
2412 req->diagnosticInformation : "NULL");
2413 if (assoc->version < 3) /* to make do_force respond with close */
2415 do_close_req(assoc, Z_Close_finished,
2416 "Association terminated by client", reqb);
2419 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2423 reqb->len_refid = refid->len;
2424 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2425 memcpy (reqb->refid, refid->buf, refid->len);
2429 reqb->len_refid = 0;
2434 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2436 process_z_response (a, req, res);
2439 bend_request bend_request_mk (bend_association a)
2441 request *nreq = request_get (&a->outgoing);
2442 nreq->request_mem = nmem_create ();
2446 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2451 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2452 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2453 id->len = id->size = req->len_refid;
2454 memcpy (id->buf, req->refid, req->len_refid);
2458 void bend_request_destroy (bend_request *req)
2460 nmem_destroy((*req)->request_mem);
2461 request_release(*req);
2465 int bend_backend_respond (bend_association a, bend_request req)
2469 r = process_z_request (a, req, &msg);
2471 yaz_log (LOG_WARN, "%s", msg);
2475 void bend_request_setdata(bend_request r, void *p)
2480 void *bend_request_getdata(bend_request r)
2482 return r->clientData;
2485 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2487 bend_segment_rr req;
2489 req.segment = reqb->apdu_request->u.segmentRequest;
2490 req.stream = assoc->encode;
2491 req.decode = assoc->decode;
2492 req.print = assoc->print;
2493 req.association = assoc;
2495 (*assoc->init->bend_segment)(assoc->backend, &req);
2500 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2502 bend_esrequest_rr esrequest;
2504 Z_ExtendedServicesRequest *req =
2505 reqb->apdu_request->u.extendedServicesRequest;
2506 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2508 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2510 yaz_log(LOG_DEBUG,"inside Process esRequest");
2512 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2513 esrequest.stream = assoc->encode;
2514 esrequest.decode = assoc->decode;
2515 esrequest.print = assoc->print;
2516 esrequest.errcode = 0;
2517 esrequest.errstring = NULL;
2518 esrequest.request = reqb;
2519 esrequest.association = assoc;
2520 esrequest.taskPackage = 0;
2521 esrequest.referenceId = req->referenceId;
2523 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2525 /* If the response is being delayed, return NULL */
2526 if (esrequest.request == NULL)
2529 resp->referenceId = req->referenceId;
2531 if (esrequest.errcode == -1)
2533 /* Backend service indicates request will be processed */
2534 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2535 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2537 else if (esrequest.errcode == 0)
2539 /* Backend service indicates request will be processed */
2540 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2541 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2545 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2546 esrequest.errstring);
2548 /* Backend indicates error, request will not be processed */
2549 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2550 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2551 resp->num_diagnostics = diagRecs->num_diagRecs;
2552 resp->diagnostics = diagRecs->diagRecs;
2554 /* Do something with the members of bend_extendedservice */
2555 if (esrequest.taskPackage)
2556 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2557 (const char *) esrequest.taskPackage,
2559 yaz_log(LOG_DEBUG,"Send the result apdu");