2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.11 2003-12-30 00:29:53 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);
356 if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
358 yaz_log(LOG_WARN, "ODR print error: %s",
359 odr_errmsg(odr_geterror(assoc->print)));
360 odr_reset(assoc->print);
362 request_enq(&assoc->incoming, req);
365 /* can we do something yet? */
366 req = request_head(&assoc->incoming);
367 if (req->state == REQUEST_IDLE)
369 request_deq(&assoc->incoming);
370 process_gdu_request(assoc, req);
373 if (event & assoc->cs_put_mask)
375 request *req = request_head(&assoc->outgoing);
377 assoc->cs_put_mask = 0;
378 yaz_log(LOG_DEBUG, "ir_session (output)");
379 req->state = REQUEST_PENDING;
380 switch (res = cs_put(conn, req->response, req->len_response))
383 yaz_log(LOG_LOG, "Connection closed by client");
385 destroy_association(assoc);
388 case 0: /* all sent - release the request structure */
389 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
391 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
394 nmem_destroy(req->request_mem);
395 request_deq(&assoc->outgoing);
396 request_release(req);
397 if (!request_head(&assoc->outgoing))
398 { /* restore mask for cs_get operation ... */
399 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
400 iochan_setflag(h, assoc->cs_get_mask);
401 if (assoc->state == ASSOC_DEAD)
402 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
406 assoc->cs_put_mask = EVENT_OUTPUT;
410 if (conn->io_pending & CS_WANT_WRITE)
411 assoc->cs_put_mask |= EVENT_OUTPUT;
412 if (conn->io_pending & CS_WANT_READ)
413 assoc->cs_put_mask |= EVENT_INPUT;
414 iochan_setflag(h, assoc->cs_put_mask);
417 if (event & EVENT_EXCEPT)
419 yaz_log(LOG_LOG, "ir_session (exception)");
421 destroy_association(assoc);
426 static int process_z_request(association *assoc, request *req, char **msg);
428 static void assoc_init_reset(association *assoc)
431 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
433 assoc->init->stream = assoc->encode;
434 assoc->init->print = assoc->print;
435 assoc->init->auth = 0;
436 assoc->init->referenceId = 0;
437 assoc->init->implementation_version = 0;
438 assoc->init->implementation_id = 0;
439 assoc->init->implementation_name = 0;
440 assoc->init->bend_sort = NULL;
441 assoc->init->bend_search = NULL;
442 assoc->init->bend_present = NULL;
443 assoc->init->bend_esrequest = NULL;
444 assoc->init->bend_delete = NULL;
445 assoc->init->bend_scan = NULL;
446 assoc->init->bend_segment = NULL;
447 assoc->init->bend_fetch = NULL;
448 assoc->init->bend_explain = NULL;
450 assoc->init->charneg_request = NULL;
451 assoc->init->charneg_response = NULL;
453 assoc->init->decode = assoc->decode;
454 assoc->init->peer_name =
455 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
458 static int srw_bend_init(association *assoc)
460 const char *encoding = "UTF-8";
462 bend_initresult *binitres;
463 statserv_options_block *cb = statserv_getcontrol();
465 assoc_init_reset(assoc);
467 assoc->maximumRecordSize = 3000000;
468 assoc->preferredMessageSize = 3000000;
470 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
471 assoc->init->charneg_request = ce->u.charNeg3;
473 if (!(binitres = (*cb->bend_init)(assoc->init)))
475 yaz_log(LOG_WARN, "Bad response from backend.");
478 assoc->backend = binitres->handle;
482 static int srw_bend_fetch(association *assoc, int pos,
483 Z_SRW_searchRetrieveRequest *srw_req,
484 Z_SRW_record *record)
487 ODR o = assoc->encode;
489 rr.setname = "default";
492 rr.request_format = VAL_TEXT_XML;
493 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
496 rr.comp = (Z_RecordComposition *)
497 odr_malloc(assoc->decode, sizeof(*rr.comp));
498 rr.comp->which = Z_RecordComp_complex;
499 rr.comp->u.complex = (Z_CompSpec *)
500 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
501 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
502 odr_malloc(assoc->encode, sizeof(bool_t));
503 *rr.comp->u.complex->selectAlternativeSyntax = 0;
504 rr.comp->u.complex->num_dbSpecific = 0;
505 rr.comp->u.complex->dbSpecific = 0;
506 rr.comp->u.complex->num_recordSyntax = 0;
507 rr.comp->u.complex->recordSyntax = 0;
509 rr.comp->u.complex->generic = (Z_Specification *)
510 odr_malloc(assoc->decode, sizeof(Z_Specification));
511 rr.comp->u.complex->generic->which = Z_Schema_uri;
512 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
513 rr.comp->u.complex->generic->elementSpec = 0;
515 rr.stream = assoc->encode;
516 rr.print = assoc->print;
522 rr.output_format = VAL_TEXT_XML;
523 rr.output_format_raw = 0;
526 rr.surrogate_flag = 0;
527 rr.schema = srw_req->recordSchema;
529 if (!assoc->init->bend_fetch)
532 (*assoc->init->bend_fetch)(assoc->backend, &rr);
536 record->recordData_buf = rr.record;
537 record->recordData_len = rr.len;
538 record->recordPosition = odr_intdup(o, pos);
540 record->recordSchema = odr_strdup(o, rr.schema);
542 record->recordSchema = 0;
547 static void srw_bend_search(association *assoc, request *req,
548 Z_SRW_searchRetrieveRequest *srw_req,
549 Z_SRW_searchRetrieveResponse *srw_res,
557 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
558 yaz_log(LOG_DEBUG, "srw_bend_search");
561 yaz_log(LOG_DEBUG, "srw_bend_init");
562 if (!srw_bend_init(assoc))
564 srw_error = 3; /* assume Authentication error */
566 srw_res->num_diagnostics = 1;
567 srw_res->diagnostics = (Z_SRW_diagnostic *)
568 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
569 srw_res->diagnostics[0].code =
570 odr_intdup(assoc->encode, srw_error);
571 srw_res->diagnostics[0].details = 0;
576 rr.setname = "default";
579 rr.basenames = &srw_req->database;
582 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
584 if (srw_req->query_type == Z_SRW_query_type_cql)
586 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
587 ext->direct_reference = odr_getoidbystr(assoc->decode,
588 "1.2.840.10003.16.2");
589 ext->indirect_reference = 0;
591 ext->which = Z_External_CQL;
592 ext->u.cql = srw_req->query.cql;
594 rr.query->which = Z_Query_type_104;
595 rr.query->u.type_104 = ext;
597 else if (srw_req->query_type == Z_SRW_query_type_pqf)
599 Z_RPNQuery *RPNquery;
600 YAZ_PQF_Parser pqf_parser;
602 pqf_parser = yaz_pqf_create ();
604 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
610 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
611 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
612 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
617 rr.query->which = Z_Query_type_1;
618 rr.query->u.type_1 = RPNquery;
620 yaz_pqf_destroy (pqf_parser);
625 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
628 if (!srw_error && !assoc->init->bend_search)
633 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
634 srw_res->num_diagnostics = 1;
635 srw_res->diagnostics = (Z_SRW_diagnostic *)
636 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
637 srw_res->diagnostics[0].code =
638 odr_intdup(assoc->encode, srw_error);
639 srw_res->diagnostics[0].details = 0;
643 rr.stream = assoc->encode;
644 rr.decode = assoc->decode;
645 rr.print = assoc->print;
647 rr.association = assoc;
653 yaz_log_zquery(rr.query);
654 (assoc->init->bend_search)(assoc->backend, &rr);
655 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
658 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
659 if (rr.errcode == 109) /* database unavailable */
664 srw_res->num_diagnostics = 1;
665 srw_res->diagnostics = (Z_SRW_diagnostic *)
666 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
667 srw_res->diagnostics[0].code =
668 odr_intdup(assoc->encode,
669 yaz_diag_bib1_to_srw (rr.errcode));
670 srw_res->diagnostics[0].details = rr.errstring;
671 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
672 *srw_res->diagnostics[0].code);
677 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
678 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
680 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
681 start, number, rr.hits);
683 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
690 yaz_log(LOG_LOG, "Request out or range");
695 int packing = Z_SRW_recordPacking_string;
696 if (start + number > rr.hits)
697 number = rr.hits - start + 1;
698 if (srw_req->recordPacking &&
699 !strcmp(srw_req->recordPacking, "xml"))
700 packing = Z_SRW_recordPacking_XML;
701 srw_res->records = (Z_SRW_record *)
702 odr_malloc(assoc->encode,
703 number * sizeof(*srw_res->records));
704 for (i = 0; i<number; i++)
708 srw_res->records[j].recordPacking = packing;
709 srw_res->records[j].recordData_buf = 0;
710 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
711 errcode = srw_bend_fetch(assoc, i+start, srw_req,
712 srw_res->records + j);
715 srw_res->num_diagnostics = 1;
716 srw_res->diagnostics = (Z_SRW_diagnostic *)
717 odr_malloc(assoc->encode,
718 sizeof(*srw_res->diagnostics));
719 srw_res->diagnostics[0].code =
720 odr_intdup(assoc->encode,
721 yaz_diag_bib1_to_srw (errcode));
722 srw_res->diagnostics[0].details = rr.errstring;
725 if (srw_res->records[j].recordData_buf)
728 srw_res->num_records = j;
730 srw_res->records = 0;
736 static void srw_bend_explain(association *assoc, request *req,
737 Z_SRW_explainRequest *srw_req,
738 Z_SRW_explainResponse *srw_res,
741 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
745 yaz_log(LOG_DEBUG, "srw_bend_init");
746 if (!srw_bend_init(assoc))
751 if (assoc->init && assoc->init->bend_explain)
755 rr.stream = assoc->encode;
756 rr.decode = assoc->decode;
757 rr.print = assoc->print;
759 rr.database = srw_req->database;
760 (*assoc->init->bend_explain)(assoc->backend, &rr);
763 int packing = Z_SRW_recordPacking_string;
764 if (srw_req->recordPacking &&
765 !strcmp(srw_req->recordPacking, "xml"))
766 packing = Z_SRW_recordPacking_XML;
767 srw_res->record.recordSchema = 0;
768 srw_res->record.recordPacking = packing;
769 srw_res->record.recordData_buf = rr.explain_buf;
770 srw_res->record.recordData_len = strlen(rr.explain_buf);
771 srw_res->record.recordPosition = 0;
777 static void process_http_request(association *assoc, request *req)
779 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
780 ODR o = assoc->encode;
782 Z_HTTP_Response *hres = 0;
785 if (!strcmp(hreq->method, "GET"))
787 char *db = "Default";
788 const char *p0 = hreq->path, *p1;
789 const char *operation = 0;
793 Z_SOAP *soap_package = 0;
794 static Z_SOAP_Handler soap_handlers[2] = {
795 {"http://www.loc.gov/zing/srw/", 0,
796 (Z_SOAP_fun) yaz_srw_codec},
802 p1 = strchr(p0, '?');
804 p1 = p0 + strlen(p0);
807 db = odr_malloc(assoc->decode, p1 - p0 + 1);
808 memcpy (db, p0, p1 - p0);
812 operation = yaz_uri_val(p1, "operation", o);
814 operation = "explain";
816 if (p1 && !strcmp(operation, "searchRetrieve"))
818 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
819 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
820 char *query = yaz_uri_val(p1, "query", o);
821 char *pQuery = yaz_uri_val(p1, "pQuery", o);
822 char *sortKeys = yaz_uri_val(p1, "sortKeys", o);
827 sr->u.request->query_type = Z_SRW_query_type_cql;
828 sr->u.request->query.cql = query;
832 sr->u.request->query_type = Z_SRW_query_type_pqf;
833 sr->u.request->query.pqf = pQuery;
837 sr->u.request->sort_type = Z_SRW_sort_type_sort;
838 sr->u.request->sort.sortKeys = sortKeys;
840 sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", o);
841 sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", o);
842 if (!sr->u.request->recordPacking)
843 sr->u.request->recordPacking = "xml";
844 yaz_uri_val_int(p1, "maximumRecords", o,
845 &sr->u.request->maximumRecords);
846 yaz_uri_val_int(p1, "startRecord", o,
847 &sr->u.request->startRecord);
848 sr->u.request->database = db;
849 srw_bend_search(assoc, req, sr->u.request, res->u.response,
852 soap_package = odr_malloc(o, sizeof(*soap_package));
853 soap_package->which = Z_SOAP_generic;
855 soap_package->u.generic =
856 odr_malloc(o, sizeof(*soap_package->u.generic));
858 soap_package->u.generic->p = res;
859 soap_package->u.generic->ns = soap_handlers[0].ns;
860 soap_package->u.generic->no = 0;
862 soap_package->ns = "SRU";
864 p = z_get_HTTP_Response(o, http_code);
865 if (http_code == 200)
867 hres = p->u.HTTP_Response;
869 ret = z_soap_codec_enc(assoc->encode, &soap_package,
870 &hres->content_buf, &hres->content_len,
871 soap_handlers, charset);
873 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
877 strcpy(ctype, "text/xml; charset=");
878 strcat(ctype, charset);
879 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
883 else if (p1 && !strcmp(operation, "explain"))
885 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
886 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
889 sr->u.explain_request->database = db;
890 sr->u.explain_request->recordPacking =
891 yaz_uri_val(p1, "recordPacking", o);
892 if (!sr->u.explain_request->recordPacking)
893 sr->u.explain_request->recordPacking = "xml";
895 srw_bend_explain(assoc, req, sr->u.explain_request,
896 res->u.explain_response, &http_code);
898 if (res->u.explain_response->record.recordData_buf)
900 soap_package = odr_malloc(o, sizeof(*soap_package));
901 soap_package->which = Z_SOAP_generic;
903 soap_package->u.generic =
904 odr_malloc(o, sizeof(*soap_package->u.generic));
906 soap_package->u.generic->p = res;
907 soap_package->u.generic->ns = soap_handlers[0].ns;
908 soap_package->u.generic->no = 0;
910 soap_package->ns = "SRU";
912 p = z_get_HTTP_Response(o, 200);
913 hres = p->u.HTTP_Response;
915 ret = z_soap_codec_enc(assoc->encode, &soap_package,
916 &hres->content_buf, &hres->content_len,
917 soap_handlers, charset);
919 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
923 strcpy(ctype, "text/xml; charset=");
924 strcat(ctype, charset);
925 z_HTTP_header_add(o, &hres->headers, "Content-Type",
932 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
933 !memcmp(hreq->path, "/doc/", 5))
938 strcpy(fpath, DOCDIR);
939 strcat(fpath, hreq->path+4);
940 f = fopen(fpath, "rb");
943 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
952 fseek(f, 0L, SEEK_END);
954 if (sz >= 0 && sz < 500000)
956 const char *ctype = "application/octet-stream";
959 p = z_get_HTTP_Response(o, 200);
960 hres = p->u.HTTP_Response;
961 hres->content_buf = (char *) odr_malloc(o, sz + 1);
962 hres->content_len = sz;
963 fseek(f, 0L, SEEK_SET);
964 fread(hres->content_buf, 1, sz, f);
965 if ((cp = strrchr(fpath, '.'))) {
967 if (!strcmp(cp, "png"))
969 else if (!strcmp(cp, "gif"))
971 else if (!strcmp(cp, "xml"))
973 else if (!strcmp(cp, "html"))
976 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
984 if (!strcmp(hreq->path, "/"))
989 const char *doclink = "";
990 p = z_get_HTTP_Response(o, 200);
991 hres = p->u.HTTP_Response;
992 hres->content_buf = (char *) odr_malloc(o, 400);
994 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
995 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
997 sprintf (hres->content_buf,
998 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1001 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1004 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1005 YAZ_VERSION "</P>\n"
1008 "</HTML>\n", doclink);
1009 hres->content_len = strlen(hres->content_buf);
1010 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1016 p = z_get_HTTP_Response(o, 404);
1019 else if (!strcmp(hreq->method, "POST"))
1021 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1023 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1025 Z_SOAP *soap_package = 0;
1027 int http_code = 500;
1028 const char *charset_p = 0;
1031 static Z_SOAP_Handler soap_handlers[3] = {
1033 {"http://www.loc.gov/zing/srw/", 0,
1034 (Z_SOAP_fun) yaz_srw_codec},
1035 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1036 (Z_SOAP_fun) yaz_srw_codec},
1040 if ((charset_p = strstr(content_type, "; charset=")))
1044 while (i < 20 && charset_p[i] &&
1045 !strchr("; \n\r", charset_p[i]))
1047 charset = odr_malloc(assoc->encode, i+1);
1048 memcpy(charset, charset_p, i);
1050 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1052 ret = z_soap_codec(assoc->decode, &soap_package,
1053 &hreq->content_buf, &hreq->content_len,
1056 if (!ret && soap_package->which == Z_SOAP_generic)
1059 char *db = "Default";
1060 const char *p0 = hreq->path, *p1;
1061 Z_SRW_PDU *sr = soap_package->u.generic->p;
1065 p1 = strchr(p0, '?');
1067 p1 = p0 + strlen(p0);
1070 db = (char*) odr_malloc(assoc->decode, p1 - p0 + 1);
1071 memcpy (db, p0, p1 - p0);
1075 if (sr->which == Z_SRW_searchRetrieve_request)
1078 yaz_srw_get(assoc->encode,
1079 Z_SRW_searchRetrieve_response);
1081 if (!sr->u.request->database)
1082 sr->u.request->database = db;
1084 if (soap_package->u.generic->no == 1) /* SRW 1.0 */
1085 res->srw_version = 0;
1087 srw_bend_search(assoc, req, sr->u.request,
1088 res->u.response, &http_code);
1090 soap_package->u.generic->p = res;
1092 else if (sr->which == Z_SRW_explain_request)
1095 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1096 sr->u.explain_request->database = db;
1098 if (soap_package->u.generic->no == 1) /* SRW 1.0 */
1099 res->srw_version = 0;
1101 srw_bend_explain(assoc, req, sr->u.explain_request,
1102 res->u.explain_response, &http_code);
1103 if (http_code == 200)
1104 soap_package->u.generic->p = res;
1108 z_soap_error(assoc->encode, soap_package,
1109 "SOAP-ENV:Client", "Bad method", 0);
1114 if (http_code == 200 || http_code == 500)
1116 p = z_get_HTTP_Response(o, 200);
1117 hres = p->u.HTTP_Response;
1118 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1119 &hres->content_buf, &hres->content_len,
1120 soap_handlers, charset);
1121 hres->code = http_code;
1123 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1127 strcpy(ctype, "text/xml; charset=");
1128 strcat(ctype, charset);
1129 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1133 p = z_get_HTTP_Response(o, http_code);
1135 if (!p) /* still no response ? */
1136 p = z_get_HTTP_Response(o, 500);
1140 p = z_get_HTTP_Response(o, 405);
1141 hres = p->u.HTTP_Response;
1143 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1145 hres = p->u.HTTP_Response;
1146 if (!strcmp(hreq->version, "1.0"))
1148 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1149 if (v && !strcmp(v, "Keep-Alive"))
1153 hres->version = "1.0";
1157 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1158 if (v && !strcmp(v, "close"))
1162 hres->version = "1.1";
1166 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1167 assoc->state = ASSOC_DEAD;
1172 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1174 if (alive && isdigit(*alive))
1178 if (t < 0 || t > 3600)
1180 iochan_settimeout(assoc->client_chan,t);
1181 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1183 process_gdu_response(assoc, req, p);
1186 static void process_gdu_request(association *assoc, request *req)
1188 if (req->gdu_request->which == Z_GDU_Z3950)
1191 req->apdu_request = req->gdu_request->u.z3950;
1192 if (process_z_request(assoc, req, &msg) < 0)
1193 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1195 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1196 process_http_request(assoc, req);
1199 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1204 * Initiate request processing.
1206 static int process_z_request(association *assoc, request *req, char **msg)
1212 *msg = "Unknown Error";
1213 assert(req && req->state == REQUEST_IDLE);
1214 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1216 *msg = "Missing InitRequest";
1219 switch (req->apdu_request->which)
1221 case Z_APDU_initRequest:
1222 iochan_settimeout(assoc->client_chan,
1223 statserv_getcontrol()->idle_timeout * 60);
1224 res = process_initRequest(assoc, req); break;
1225 case Z_APDU_searchRequest:
1226 res = process_searchRequest(assoc, req, &fd); break;
1227 case Z_APDU_presentRequest:
1228 res = process_presentRequest(assoc, req, &fd); break;
1229 case Z_APDU_scanRequest:
1230 if (assoc->init->bend_scan)
1231 res = process_scanRequest(assoc, req, &fd);
1234 *msg = "Cannot handle Scan APDU";
1238 case Z_APDU_extendedServicesRequest:
1239 if (assoc->init->bend_esrequest)
1240 res = process_ESRequest(assoc, req, &fd);
1243 *msg = "Cannot handle Extended Services APDU";
1247 case Z_APDU_sortRequest:
1248 if (assoc->init->bend_sort)
1249 res = process_sortRequest(assoc, req, &fd);
1252 *msg = "Cannot handle Sort APDU";
1257 process_close(assoc, req);
1259 case Z_APDU_deleteResultSetRequest:
1260 if (assoc->init->bend_delete)
1261 res = process_deleteRequest(assoc, req, &fd);
1264 *msg = "Cannot handle Delete APDU";
1268 case Z_APDU_segmentRequest:
1269 if (assoc->init->bend_segment)
1271 res = process_segmentRequest (assoc, req);
1275 *msg = "Cannot handle Segment APDU";
1280 *msg = "Bad APDU received";
1285 yaz_log(LOG_DEBUG, " result immediately available");
1286 retval = process_z_response(assoc, req, res);
1290 yaz_log(LOG_DEBUG, " result unavailble");
1293 else /* no result yet - one will be provided later */
1297 /* Set up an I/O handler for the fd supplied by the backend */
1299 yaz_log(LOG_DEBUG, " establishing handler for result");
1300 req->state = REQUEST_PENDING;
1301 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1303 iochan_setdata(chan, assoc);
1310 * Handle message from the backend.
1312 void backend_response(IOCHAN i, int event)
1314 association *assoc = (association *)iochan_getdata(i);
1315 request *req = request_head(&assoc->incoming);
1319 yaz_log(LOG_DEBUG, "backend_response");
1320 assert(assoc && req && req->state != REQUEST_IDLE);
1321 /* determine what it is we're waiting for */
1322 switch (req->apdu_request->which)
1324 case Z_APDU_searchRequest:
1325 res = response_searchRequest(assoc, req, 0, &fd); break;
1327 case Z_APDU_presentRequest:
1328 res = response_presentRequest(assoc, req, 0, &fd); break;
1329 case Z_APDU_scanRequest:
1330 res = response_scanRequest(assoc, req, 0, &fd); break;
1333 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1336 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1338 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1339 do_close(assoc, Z_Close_systemProblem, 0);
1343 else if (!res) /* no result yet - try again later */
1345 yaz_log(LOG_DEBUG, " no result yet");
1346 iochan_setfd(i, fd); /* in case fd has changed */
1351 * Encode response, and transfer the request structure to the outgoing queue.
1353 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1355 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1357 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1359 yaz_log(LOG_WARN, "ODR print error: %s",
1360 odr_errmsg(odr_geterror(assoc->print)));
1361 odr_reset(assoc->print);
1363 if (!z_GDU(assoc->encode, &res, 0, 0))
1365 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1366 odr_errmsg(odr_geterror(assoc->decode)),
1367 odr_getelement(assoc->decode));
1368 request_release(req);
1371 req->response = odr_getbuf(assoc->encode, &req->len_response,
1372 &req->size_response);
1373 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1374 odr_reset(assoc->encode);
1375 req->state = REQUEST_IDLE;
1376 request_enq(&assoc->outgoing, req);
1377 /* turn the work over to the ir_session handler */
1378 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1379 assoc->cs_put_mask = EVENT_OUTPUT;
1380 /* Is there more work to be done? give that to the input handler too */
1382 if (request_head(&assoc->incoming))
1384 yaz_log (LOG_DEBUG, "more work to be done");
1385 iochan_setevent(assoc->client_chan, EVENT_WORK);
1392 * Encode response, and transfer the request structure to the outgoing queue.
1394 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1396 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1397 gres->which = Z_GDU_Z3950;
1398 gres->u.z3950 = res;
1400 return process_gdu_response(assoc, req, gres);
1405 * Handle init request.
1406 * At the moment, we don't check the options
1407 * anywhere else in the code - we just try not to do anything that would
1408 * break a naive client. We'll toss 'em into the association block when
1409 * we need them there.
1411 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1413 statserv_options_block *cb = statserv_getcontrol();
1414 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1415 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1416 Z_InitResponse *resp = apdu->u.initResponse;
1417 bend_initresult *binitres;
1421 yaz_log(LOG_LOG, "Got initRequest");
1422 if (req->implementationId)
1423 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1424 if (req->implementationName)
1425 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1426 if (req->implementationVersion)
1427 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1429 assoc_init_reset(assoc);
1431 assoc->init->auth = req->idAuthentication;
1432 assoc->init->referenceId = req->referenceId;
1434 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1436 Z_CharSetandLanguageNegotiation *negotiation =
1437 yaz_get_charneg_record (req->otherInfo);
1438 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1439 assoc->init->charneg_request = negotiation;
1442 if (!(binitres = (*cb->bend_init)(assoc->init)))
1444 yaz_log(LOG_WARN, "Bad response from backend.");
1448 assoc->backend = binitres->handle;
1449 if ((assoc->init->bend_sort))
1450 yaz_log (LOG_DEBUG, "Sort handler installed");
1451 if ((assoc->init->bend_search))
1452 yaz_log (LOG_DEBUG, "Search handler installed");
1453 if ((assoc->init->bend_present))
1454 yaz_log (LOG_DEBUG, "Present handler installed");
1455 if ((assoc->init->bend_esrequest))
1456 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1457 if ((assoc->init->bend_delete))
1458 yaz_log (LOG_DEBUG, "Delete handler installed");
1459 if ((assoc->init->bend_scan))
1460 yaz_log (LOG_DEBUG, "Scan handler installed");
1461 if ((assoc->init->bend_segment))
1462 yaz_log (LOG_DEBUG, "Segment handler installed");
1464 resp->referenceId = req->referenceId;
1466 /* let's tell the client what we can do */
1467 if (ODR_MASK_GET(req->options, Z_Options_search))
1469 ODR_MASK_SET(resp->options, Z_Options_search);
1470 strcat(options, "srch");
1472 if (ODR_MASK_GET(req->options, Z_Options_present))
1474 ODR_MASK_SET(resp->options, Z_Options_present);
1475 strcat(options, " prst");
1477 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1478 assoc->init->bend_delete)
1480 ODR_MASK_SET(resp->options, Z_Options_delSet);
1481 strcat(options, " del");
1483 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1484 assoc->init->bend_esrequest)
1486 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1487 strcat (options, " extendedServices");
1489 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1491 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1492 strcat(options, " namedresults");
1494 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1496 ODR_MASK_SET(resp->options, Z_Options_scan);
1497 strcat(options, " scan");
1499 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1501 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1502 strcat(options, " concurrop");
1504 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1506 ODR_MASK_SET(resp->options, Z_Options_sort);
1507 strcat(options, " sort");
1510 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1511 && assoc->init->charneg_response)
1513 Z_OtherInformation **p;
1514 Z_OtherInformationUnit *p0;
1516 yaz_oi_APDU(apdu, &p);
1518 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1519 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1521 p0->which = Z_OtherInfo_externallyDefinedInfo;
1522 p0->information.externallyDefinedInfo =
1523 assoc->init->charneg_response;
1525 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1526 strcat(options, " negotiation");
1529 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1531 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1532 assoc->version = 2; /* 1 & 2 are equivalent */
1534 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1536 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1539 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1541 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1545 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1546 assoc->maximumRecordSize = *req->maximumRecordSize;
1547 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1548 assoc->maximumRecordSize = control_block->maxrecordsize;
1549 assoc->preferredMessageSize = *req->preferredMessageSize;
1550 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1551 assoc->preferredMessageSize = assoc->maximumRecordSize;
1553 resp->preferredMessageSize = &assoc->preferredMessageSize;
1554 resp->maximumRecordSize = &assoc->maximumRecordSize;
1556 resp->implementationId = odr_prepend(assoc->encode,
1557 assoc->init->implementation_id,
1558 resp->implementationId);
1560 resp->implementationName = odr_prepend(assoc->encode,
1561 assoc->init->implementation_name,
1562 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1564 version = odr_strdup(assoc->encode, "$Revision: 1.11 $");
1565 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1566 version[strlen(version)-2] = '\0';
1567 resp->implementationVersion = odr_prepend(assoc->encode,
1568 assoc->init->implementation_version,
1569 odr_prepend(assoc->encode, &version[11],
1570 resp->implementationVersion));
1572 if (binitres->errcode)
1574 yaz_log(LOG_LOG, "Connection rejected by backend.");
1576 assoc->state = ASSOC_DEAD;
1577 resp->userInformationField = init_diagnostics(assoc->encode,
1579 binitres->errstring);
1582 assoc->state = ASSOC_UP;
1587 * Diagnostic in default format, to be returned as either a surrogate
1588 * or non-surrogate diagnostic in the context of an open session, or
1589 * as User-information when an Init is refused.
1591 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1593 int *err = odr_intdup(odr, error);
1594 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1595 odr_malloc (odr, sizeof(*dr));
1597 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1598 addinfo ? " -- " : "", addinfo ? addinfo : "");
1600 dr->diagnosticSetId =
1601 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1602 dr->condition = err;
1603 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1604 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1609 * Set the specified `errcode' and `errstring' into a UserInfo-1
1610 * external to be returned to the client in accordance with Z35.90
1611 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1612 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1614 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1618 Z_OtherInformation *u;
1619 Z_OtherInformationUnit *l;
1620 Z_DiagnosticFormat *d;
1621 Z_DiagnosticFormat_s *e;
1623 x = (Z_External*) odr_malloc(odr, sizeof *x);
1625 x->indirect_reference = 0;
1626 oid.proto = PROTO_Z3950;
1627 oid.oclass = CLASS_USERINFO;
1628 oid.value = VAL_USERINFO1;
1629 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1630 x->which = Z_External_userInfo1;
1632 u = odr_malloc(odr, sizeof *u);
1634 u->num_elements = 1;
1635 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1636 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1639 l->which = Z_OtherInfo_externallyDefinedInfo;
1641 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1642 l->information.externallyDefinedInfo = x2;
1644 x2->indirect_reference = 0;
1645 oid.oclass = CLASS_DIAGSET;
1646 oid.value = VAL_DIAG1;
1647 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1648 x2->which = Z_External_diag1;
1650 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1653 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1654 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1657 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1658 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1663 * nonsurrogate diagnostic record.
1665 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1667 Z_Records *rec = (Z_Records *)
1668 odr_malloc (assoc->encode, sizeof(*rec));
1669 rec->which = Z_Records_NSD;
1670 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1675 * surrogate diagnostic.
1677 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1678 int error, char *addinfo)
1680 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1681 odr_malloc (assoc->encode, sizeof(*rec));
1682 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1684 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1685 rec->databaseName = dbname;
1686 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1687 rec->u.surrogateDiagnostic = drec;
1688 drec->which = Z_DiagRec_defaultFormat;
1689 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1695 * multiple nonsurrogate diagnostics.
1697 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1699 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1700 int *err = odr_intdup(assoc->encode, error);
1701 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1702 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1703 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1704 odr_malloc (assoc->encode, sizeof(*rec));
1706 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1708 recs->num_diagRecs = 1;
1709 recs->diagRecs = recp;
1711 drec->which = Z_DiagRec_defaultFormat;
1712 drec->u.defaultFormat = rec;
1714 rec->diagnosticSetId =
1715 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1716 rec->condition = err;
1718 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1719 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1723 static Z_Records *pack_records(association *a, char *setname, int start,
1724 int *num, Z_RecordComposition *comp,
1725 int *next, int *pres, oid_value format,
1726 Z_ReferenceId *referenceId,
1729 int recno, total_length = 0, toget = *num, dumped_records = 0;
1730 Z_Records *records =
1731 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1732 Z_NamePlusRecordList *reclist =
1733 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1734 Z_NamePlusRecord **list =
1735 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1737 records->which = Z_Records_DBOSD;
1738 records->u.databaseOrSurDiagnostics = reclist;
1739 reclist->num_records = 0;
1740 reclist->records = list;
1741 *pres = Z_PRES_SUCCESS;
1745 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1746 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1747 a->maximumRecordSize);
1748 for (recno = start; reclist->num_records < toget; recno++)
1751 Z_NamePlusRecord *thisrec;
1752 int this_length = 0;
1754 * we get the number of bytes allocated on the stream before any
1755 * allocation done by the backend - this should give us a reasonable
1756 * idea of the total size of the data so far.
1758 total_length = odr_total(a->encode) - dumped_records;
1764 freq.last_in_set = 0;
1765 freq.setname = setname;
1766 freq.surrogate_flag = 0;
1767 freq.number = recno;
1769 freq.request_format = format;
1770 freq.request_format_raw = oid;
1771 freq.output_format = format;
1772 freq.output_format_raw = 0;
1773 freq.stream = a->encode;
1774 freq.print = a->print;
1775 freq.referenceId = referenceId;
1777 (*a->init->bend_fetch)(a->backend, &freq);
1778 /* backend should be able to signal whether error is system-wide
1779 or only pertaining to current record */
1782 if (!freq.surrogate_flag)
1785 *pres = Z_PRES_FAILURE;
1786 /* for 'present request out of range',
1787 set addinfo to record position if not set */
1788 if (freq.errcode == 13 && freq.errstring == 0)
1790 sprintf (s, "%d", recno);
1793 return diagrec(a, freq.errcode, freq.errstring);
1795 reclist->records[reclist->num_records] =
1796 surrogatediagrec(a, freq.basename, freq.errcode,
1798 reclist->num_records++;
1799 *next = freq.last_in_set ? 0 : recno + 1;
1803 this_length = freq.len;
1805 this_length = odr_total(a->encode) - total_length - dumped_records;
1806 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1807 this_length, total_length, dumped_records);
1808 if (this_length + total_length > a->preferredMessageSize)
1810 /* record is small enough, really */
1811 if (this_length <= a->preferredMessageSize && recno > start)
1813 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1814 *pres = Z_PRES_PARTIAL_2;
1817 /* record can only be fetched by itself */
1818 if (this_length < a->maximumRecordSize)
1820 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1823 yaz_log(LOG_DEBUG, " Dropped it");
1824 reclist->records[reclist->num_records] =
1825 surrogatediagrec(a, freq.basename, 16, 0);
1826 reclist->num_records++;
1827 *next = freq.last_in_set ? 0 : recno + 1;
1828 dumped_records += this_length;
1832 else /* too big entirely */
1834 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1835 reclist->records[reclist->num_records] =
1836 surrogatediagrec(a, freq.basename, 17, 0);
1837 reclist->num_records++;
1838 *next = freq.last_in_set ? 0 : recno + 1;
1839 dumped_records += this_length;
1844 if (!(thisrec = (Z_NamePlusRecord *)
1845 odr_malloc(a->encode, sizeof(*thisrec))))
1847 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1848 strlen(freq.basename) + 1)))
1850 strcpy(thisrec->databaseName, freq.basename);
1851 thisrec->which = Z_NamePlusRecord_databaseRecord;
1853 if (freq.output_format_raw)
1855 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1856 freq.output_format = ident->value;
1858 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1859 freq.record, freq.len);
1860 if (!thisrec->u.databaseRecord)
1862 reclist->records[reclist->num_records] = thisrec;
1863 reclist->num_records++;
1864 *next = freq.last_in_set ? 0 : recno + 1;
1866 *num = reclist->num_records;
1870 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1873 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1874 bend_search_rr *bsrr =
1875 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1877 yaz_log(LOG_LOG, "Got SearchRequest.");
1879 bsrr->request = reqb;
1880 bsrr->association = assoc;
1881 bsrr->referenceId = req->referenceId;
1882 save_referenceId (reqb, bsrr->referenceId);
1884 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1885 if (req->databaseNames)
1888 for (i = 0; i < req->num_databaseNames; i++)
1889 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1891 yaz_log_zquery(req->query);
1893 if (assoc->init->bend_search)
1895 bsrr->setname = req->resultSetName;
1896 bsrr->replace_set = *req->replaceIndicator;
1897 bsrr->num_bases = req->num_databaseNames;
1898 bsrr->basenames = req->databaseNames;
1899 bsrr->query = req->query;
1900 bsrr->stream = assoc->encode;
1901 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1902 bsrr->decode = assoc->decode;
1903 bsrr->print = assoc->print;
1906 bsrr->errstring = NULL;
1907 bsrr->search_info = NULL;
1908 (assoc->init->bend_search)(assoc->backend, bsrr);
1912 return response_searchRequest(assoc, reqb, bsrr, fd);
1915 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1918 * Prepare a searchresponse based on the backend results. We probably want
1919 * to look at making the fetching of records nonblocking as well, but
1920 * so far, we'll keep things simple.
1921 * If bsrt is null, that means we're called in response to a communications
1922 * event, and we'll have to get the response for ourselves.
1924 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1925 bend_search_rr *bsrt, int *fd)
1927 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1928 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1929 Z_SearchResponse *resp = (Z_SearchResponse *)
1930 odr_malloc (assoc->encode, sizeof(*resp));
1931 int *nulint = odr_intdup (assoc->encode, 0);
1932 bool_t *sr = odr_intdup(assoc->encode, 1);
1933 int *next = odr_intdup(assoc->encode, 0);
1934 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1936 apdu->which = Z_APDU_searchResponse;
1937 apdu->u.searchResponse = resp;
1938 resp->referenceId = req->referenceId;
1939 resp->additionalSearchInfo = 0;
1940 resp->otherInfo = 0;
1942 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1944 yaz_log(LOG_FATAL, "Bad result from backend");
1947 else if (bsrt->errcode)
1949 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1950 resp->resultCount = nulint;
1951 resp->numberOfRecordsReturned = nulint;
1952 resp->nextResultSetPosition = nulint;
1953 resp->searchStatus = nulint;
1954 resp->resultSetStatus = none;
1955 resp->presentStatus = 0;
1959 int *toget = odr_intdup(assoc->encode, 0);
1960 int *presst = odr_intdup(assoc->encode, 0);
1961 Z_RecordComposition comp, *compp = 0;
1963 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1966 resp->resultCount = &bsrt->hits;
1968 comp.which = Z_RecordComp_simple;
1969 /* how many records does the user agent want, then? */
1970 if (bsrt->hits <= *req->smallSetUpperBound)
1972 *toget = bsrt->hits;
1973 if ((comp.u.simple = req->smallSetElementSetNames))
1976 else if (bsrt->hits < *req->largeSetLowerBound)
1978 *toget = *req->mediumSetPresentNumber;
1979 if (*toget > bsrt->hits)
1980 *toget = bsrt->hits;
1981 if ((comp.u.simple = req->mediumSetElementSetNames))
1987 if (*toget && !resp->records)
1992 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1995 form = prefformat->value;
1996 resp->records = pack_records(assoc, req->resultSetName, 1,
1997 toget, compp, next, presst, form, req->referenceId,
1998 req->preferredRecordSyntax);
2001 resp->numberOfRecordsReturned = toget;
2002 resp->nextResultSetPosition = next;
2003 resp->searchStatus = sr;
2004 resp->resultSetStatus = 0;
2005 resp->presentStatus = presst;
2009 if (*resp->resultCount)
2011 resp->numberOfRecordsReturned = nulint;
2012 resp->nextResultSetPosition = next;
2013 resp->searchStatus = sr;
2014 resp->resultSetStatus = 0;
2015 resp->presentStatus = 0;
2018 resp->additionalSearchInfo = bsrt->search_info;
2023 * Maybe we got a little over-friendly when we designed bend_fetch to
2024 * get only one record at a time. Some backends can optimise multiple-record
2025 * fetches, and at any rate, there is some overhead involved in
2026 * all that selecting and hopping around. Problem is, of course, that the
2027 * frontend can't know ahead of time how many records it'll need to
2028 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2029 * is downright lousy as a bulk data transfer protocol.
2031 * To start with, we'll do the fetching of records from the backend
2032 * in one operation: To save some trips in and out of the event-handler,
2033 * and to simplify the interface to pack_records. At any rate, asynch
2034 * operation is more fun in operations that have an unpredictable execution
2035 * speed - which is normally more true for search than for present.
2037 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2040 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2044 Z_PresentResponse *resp;
2048 yaz_log(LOG_LOG, "Got PresentRequest.");
2050 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2053 form = prefformat->value;
2054 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2056 resp->presentStatus = odr_intdup(assoc->encode, 0);
2057 if (assoc->init->bend_present)
2059 bend_present_rr *bprr = (bend_present_rr *)
2060 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2061 bprr->setname = req->resultSetId;
2062 bprr->start = *req->resultSetStartPoint;
2063 bprr->number = *req->numberOfRecordsRequested;
2064 bprr->format = form;
2065 bprr->comp = req->recordComposition;
2066 bprr->referenceId = req->referenceId;
2067 bprr->stream = assoc->encode;
2068 bprr->print = assoc->print;
2069 bprr->request = reqb;
2070 bprr->association = assoc;
2072 bprr->errstring = NULL;
2073 (*assoc->init->bend_present)(assoc->backend, bprr);
2079 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2080 *resp->presentStatus = Z_PRES_FAILURE;
2083 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2084 next = odr_intdup(assoc->encode, 0);
2085 num = odr_intdup(assoc->encode, 0);
2087 apdu->which = Z_APDU_presentResponse;
2088 apdu->u.presentResponse = resp;
2089 resp->referenceId = req->referenceId;
2090 resp->otherInfo = 0;
2094 *num = *req->numberOfRecordsRequested;
2096 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2097 num, req->recordComposition, next, resp->presentStatus,
2098 form, req->referenceId, req->preferredRecordSyntax);
2102 resp->numberOfRecordsReturned = num;
2103 resp->nextResultSetPosition = next;
2109 * Scan was implemented rather in a hurry, and with support for only the basic
2110 * elements of the service in the backend API. Suggestions are welcome.
2112 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2114 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2115 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2116 Z_ScanResponse *res = (Z_ScanResponse *)
2117 odr_malloc (assoc->encode, sizeof(*res));
2118 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2119 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2120 Z_ListEntries *ents = (Z_ListEntries *)
2121 odr_malloc (assoc->encode, sizeof(*ents));
2122 Z_DiagRecs *diagrecs_p = NULL;
2124 bend_scan_rr *bsrr = (bend_scan_rr *)
2125 odr_malloc (assoc->encode, sizeof(*bsrr));
2126 struct scan_entry *save_entries;
2128 yaz_log(LOG_LOG, "Got ScanRequest");
2130 apdu->which = Z_APDU_scanResponse;
2131 apdu->u.scanResponse = res;
2132 res->referenceId = req->referenceId;
2134 /* if step is absent, set it to 0 */
2135 res->stepSize = odr_intdup(assoc->encode, 0);
2137 *res->stepSize = *req->stepSize;
2139 res->scanStatus = scanStatus;
2140 res->numberOfEntriesReturned = numberOfEntriesReturned;
2141 res->positionOfTerm = 0;
2142 res->entries = ents;
2143 ents->num_entries = 0;
2144 ents->entries = NULL;
2145 ents->num_nonsurrogateDiagnostics = 0;
2146 ents->nonsurrogateDiagnostics = NULL;
2147 res->attributeSet = 0;
2150 if (req->databaseNames)
2153 for (i = 0; i < req->num_databaseNames; i++)
2154 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2156 bsrr->num_bases = req->num_databaseNames;
2157 bsrr->basenames = req->databaseNames;
2158 bsrr->num_entries = *req->numberOfTermsRequested;
2159 bsrr->term = req->termListAndStartPoint;
2160 bsrr->referenceId = req->referenceId;
2161 bsrr->stream = assoc->encode;
2162 bsrr->print = assoc->print;
2163 bsrr->step_size = res->stepSize;
2165 /* Note that version 2.0 of YAZ and older did not set entries ..
2166 We do now. And when we do it's easier to extend the scan entry
2167 We know that if the scan handler did set entries, it will
2168 not know of new member display_term.
2170 if (bsrr->num_entries > 0)
2173 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2175 for (i = 0; i<bsrr->num_entries; i++)
2177 bsrr->entries[i].term = 0;
2178 bsrr->entries[i].occurrences = 0;
2179 bsrr->entries[i].errcode = 0;
2180 bsrr->entries[i].errstring = 0;
2181 bsrr->entries[i].display_term = 0;
2184 save_entries = bsrr->entries; /* save it so we can compare later */
2186 if (req->attributeSet &&
2187 (attset = oid_getentbyoid(req->attributeSet)) &&
2188 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2189 bsrr->attributeset = attset->value;
2191 bsrr->attributeset = VAL_NONE;
2192 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2193 bsrr->term_position = req->preferredPositionInResponse ?
2194 *req->preferredPositionInResponse : 1;
2195 ((int (*)(void *, bend_scan_rr *))
2196 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2198 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2202 Z_Entry **tab = (Z_Entry **)
2203 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2205 if (bsrr->status == BEND_SCAN_PARTIAL)
2206 *scanStatus = Z_Scan_partial_5;
2208 *scanStatus = Z_Scan_success;
2209 ents->entries = tab;
2210 ents->num_entries = bsrr->num_entries;
2211 res->numberOfEntriesReturned = &ents->num_entries;
2212 res->positionOfTerm = &bsrr->term_position;
2213 for (i = 0; i < bsrr->num_entries; i++)
2219 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2220 if (bsrr->entries[i].occurrences >= 0)
2222 e->which = Z_Entry_termInfo;
2223 e->u.termInfo = t = (Z_TermInfo *)
2224 odr_malloc(assoc->encode, sizeof(*t));
2225 t->suggestedAttributes = 0;
2227 if (save_entries == bsrr->entries &&
2228 bsrr->entries[i].display_term)
2230 /* the entries was NOT set by the handler. So it's
2231 safe to test for new member display_term. It is
2234 t->displayTerm = odr_strdup(assoc->encode,
2235 bsrr->entries[i].display_term);
2237 t->alternativeTerm = 0;
2238 t->byAttributes = 0;
2239 t->otherTermInfo = 0;
2240 t->globalOccurrences = &bsrr->entries[i].occurrences;
2241 t->term = (Z_Term *)
2242 odr_malloc(assoc->encode, sizeof(*t->term));
2243 t->term->which = Z_Term_general;
2244 t->term->u.general = o =
2245 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2246 o->buf = (unsigned char *)
2247 odr_malloc(assoc->encode, o->len = o->size =
2248 strlen(bsrr->entries[i].term));
2249 memcpy(o->buf, bsrr->entries[i].term, o->len);
2250 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2251 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2255 Z_DiagRecs *drecs = diagrecs (assoc,
2256 bsrr->entries[i].errcode,
2257 bsrr->entries[i].errstring);
2258 assert (drecs->num_diagRecs == 1);
2259 e->which = Z_Entry_surrogateDiagnostic;
2260 assert (drecs->diagRecs[0]);
2261 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2267 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2268 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2273 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2276 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2277 Z_SortResponse *res = (Z_SortResponse *)
2278 odr_malloc (assoc->encode, sizeof(*res));
2279 bend_sort_rr *bsrr = (bend_sort_rr *)
2280 odr_malloc (assoc->encode, sizeof(*bsrr));
2282 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2284 yaz_log(LOG_LOG, "Got SortRequest.");
2286 bsrr->num_input_setnames = req->num_inputResultSetNames;
2287 bsrr->input_setnames = req->inputResultSetNames;
2288 bsrr->referenceId = req->referenceId;
2289 bsrr->output_setname = req->sortedResultSetName;
2290 bsrr->sort_sequence = req->sortSequence;
2291 bsrr->stream = assoc->encode;
2292 bsrr->print = assoc->print;
2294 bsrr->sort_status = Z_SortStatus_failure;
2296 bsrr->errstring = 0;
2298 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2300 res->referenceId = bsrr->referenceId;
2301 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2302 res->resultSetStatus = 0;
2305 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2306 res->diagnostics = dr->diagRecs;
2307 res->num_diagnostics = dr->num_diagRecs;
2311 res->num_diagnostics = 0;
2312 res->diagnostics = 0;
2314 res->resultCount = 0;
2317 apdu->which = Z_APDU_sortResponse;
2318 apdu->u.sortResponse = res;
2322 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2325 Z_DeleteResultSetRequest *req =
2326 reqb->apdu_request->u.deleteResultSetRequest;
2327 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2328 odr_malloc (assoc->encode, sizeof(*res));
2329 bend_delete_rr *bdrr = (bend_delete_rr *)
2330 odr_malloc (assoc->encode, sizeof(*bdrr));
2331 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2333 yaz_log(LOG_LOG, "Got DeleteRequest.");
2335 bdrr->num_setnames = req->num_resultSetList;
2336 bdrr->setnames = req->resultSetList;
2337 bdrr->stream = assoc->encode;
2338 bdrr->print = assoc->print;
2339 bdrr->function = *req->deleteFunction;
2340 bdrr->referenceId = req->referenceId;
2342 if (bdrr->num_setnames > 0)
2345 bdrr->statuses = (int*)
2346 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2347 bdrr->num_setnames);
2348 for (i = 0; i < bdrr->num_setnames; i++)
2349 bdrr->statuses[i] = 0;
2351 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2353 res->referenceId = req->referenceId;
2355 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2357 res->deleteListStatuses = 0;
2358 if (bdrr->num_setnames > 0)
2361 res->deleteListStatuses = (Z_ListStatuses *)
2362 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2363 res->deleteListStatuses->num = bdrr->num_setnames;
2364 res->deleteListStatuses->elements =
2366 odr_malloc (assoc->encode,
2367 sizeof(*res->deleteListStatuses->elements) *
2368 bdrr->num_setnames);
2369 for (i = 0; i<bdrr->num_setnames; i++)
2371 res->deleteListStatuses->elements[i] =
2373 odr_malloc (assoc->encode,
2374 sizeof(**res->deleteListStatuses->elements));
2375 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2376 res->deleteListStatuses->elements[i]->id =
2377 odr_strdup (assoc->encode, bdrr->setnames[i]);
2381 res->numberNotDeleted = 0;
2382 res->bulkStatuses = 0;
2383 res->deleteMessage = 0;
2386 apdu->which = Z_APDU_deleteResultSetResponse;
2387 apdu->u.deleteResultSetResponse = res;
2391 static void process_close(association *assoc, request *reqb)
2393 Z_Close *req = reqb->apdu_request->u.close;
2394 static char *reasons[] =
2401 "securityViolation",
2408 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2409 reasons[*req->closeReason], req->diagnosticInformation ?
2410 req->diagnosticInformation : "NULL");
2411 if (assoc->version < 3) /* to make do_force respond with close */
2413 do_close_req(assoc, Z_Close_finished,
2414 "Association terminated by client", reqb);
2417 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2421 reqb->len_refid = refid->len;
2422 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2423 memcpy (reqb->refid, refid->buf, refid->len);
2427 reqb->len_refid = 0;
2432 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2434 process_z_response (a, req, res);
2437 bend_request bend_request_mk (bend_association a)
2439 request *nreq = request_get (&a->outgoing);
2440 nreq->request_mem = nmem_create ();
2444 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2449 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2450 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2451 id->len = id->size = req->len_refid;
2452 memcpy (id->buf, req->refid, req->len_refid);
2456 void bend_request_destroy (bend_request *req)
2458 nmem_destroy((*req)->request_mem);
2459 request_release(*req);
2463 int bend_backend_respond (bend_association a, bend_request req)
2467 r = process_z_request (a, req, &msg);
2469 yaz_log (LOG_WARN, "%s", msg);
2473 void bend_request_setdata(bend_request r, void *p)
2478 void *bend_request_getdata(bend_request r)
2480 return r->clientData;
2483 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2485 bend_segment_rr req;
2487 req.segment = reqb->apdu_request->u.segmentRequest;
2488 req.stream = assoc->encode;
2489 req.decode = assoc->decode;
2490 req.print = assoc->print;
2491 req.association = assoc;
2493 (*assoc->init->bend_segment)(assoc->backend, &req);
2498 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2500 bend_esrequest_rr esrequest;
2502 Z_ExtendedServicesRequest *req =
2503 reqb->apdu_request->u.extendedServicesRequest;
2504 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2506 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2508 yaz_log(LOG_DEBUG,"inside Process esRequest");
2510 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2511 esrequest.stream = assoc->encode;
2512 esrequest.decode = assoc->decode;
2513 esrequest.print = assoc->print;
2514 esrequest.errcode = 0;
2515 esrequest.errstring = NULL;
2516 esrequest.request = reqb;
2517 esrequest.association = assoc;
2518 esrequest.taskPackage = 0;
2519 esrequest.referenceId = req->referenceId;
2521 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2523 /* If the response is being delayed, return NULL */
2524 if (esrequest.request == NULL)
2527 resp->referenceId = req->referenceId;
2529 if (esrequest.errcode == -1)
2531 /* Backend service indicates request will be processed */
2532 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2533 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2535 else if (esrequest.errcode == 0)
2537 /* Backend service indicates request will be processed */
2538 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2539 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2543 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2544 esrequest.errstring);
2546 /* Backend indicates error, request will not be processed */
2547 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2548 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2549 resp->num_diagnostics = diagRecs->num_diagRecs;
2550 resp->diagnostics = diagRecs->diagRecs;
2552 /* Do something with the members of bend_extendedservice */
2553 if (esrequest.taskPackage)
2554 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2555 (const char *) esrequest.taskPackage,
2557 yaz_log(LOG_DEBUG,"Send the result apdu");