2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.5 2003-12-20 00:51:19 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)
555 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
556 yaz_log(LOG_DEBUG, "srw_bend_search");
559 yaz_log(LOG_DEBUG, "srw_bend_init");
560 if (!srw_bend_init(assoc))
562 srw_error = 3; /* assume Authentication error */
564 srw_res->num_diagnostics = 1;
565 srw_res->diagnostics = (Z_SRW_diagnostic *)
566 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
567 srw_res->diagnostics[0].code =
568 odr_intdup(assoc->encode, srw_error);
569 srw_res->diagnostics[0].details = 0;
574 rr.setname = "default";
577 rr.basenames = &srw_req->database;
580 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
582 if (srw_req->query_type == Z_SRW_query_type_cql)
584 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
585 ext->direct_reference = odr_getoidbystr(assoc->decode,
586 "1.2.840.10003.16.2");
587 ext->indirect_reference = 0;
589 ext->which = Z_External_CQL;
590 ext->u.cql = srw_req->query.cql;
592 rr.query->which = Z_Query_type_104;
593 rr.query->u.type_104 = ext;
595 else if (srw_req->query_type == Z_SRW_query_type_pqf)
597 Z_RPNQuery *RPNquery;
598 YAZ_PQF_Parser pqf_parser;
600 pqf_parser = yaz_pqf_create ();
602 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
608 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
609 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
610 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
615 rr.query->which = Z_Query_type_1;
616 rr.query->u.type_1 = RPNquery;
618 yaz_pqf_destroy (pqf_parser);
623 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
626 if (!srw_error && !assoc->init->bend_search)
631 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
632 srw_res->num_diagnostics = 1;
633 srw_res->diagnostics = (Z_SRW_diagnostic *)
634 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
635 srw_res->diagnostics[0].code =
636 odr_intdup(assoc->encode, srw_error);
637 srw_res->diagnostics[0].details = 0;
641 rr.stream = assoc->encode;
642 rr.decode = assoc->decode;
643 rr.print = assoc->print;
645 rr.association = assoc;
651 yaz_log_zquery(rr.query);
652 (assoc->init->bend_search)(assoc->backend, &rr);
653 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
656 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
657 srw_res->num_diagnostics = 1;
658 srw_res->diagnostics = (Z_SRW_diagnostic *)
659 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
660 srw_res->diagnostics[0].code =
661 odr_intdup(assoc->encode,
662 yaz_diag_bib1_to_srw (rr.errcode));
663 srw_res->diagnostics[0].details = rr.errstring;
664 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
665 *srw_res->diagnostics[0].code);
670 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
671 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
673 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
674 start, number, rr.hits);
676 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
683 yaz_log(LOG_LOG, "Request out or range");
688 int packing = Z_SRW_recordPacking_string;
689 if (start + number > rr.hits)
690 number = rr.hits - start + 1;
691 if (srw_req->recordPacking &&
692 !strcmp(srw_req->recordPacking, "xml"))
693 packing = Z_SRW_recordPacking_XML;
694 srw_res->records = (Z_SRW_record *)
695 odr_malloc(assoc->encode,
696 number * sizeof(*srw_res->records));
697 for (i = 0; i<number; i++)
701 srw_res->records[j].recordPacking = packing;
702 srw_res->records[j].recordData_buf = 0;
703 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
704 errcode = srw_bend_fetch(assoc, i+start, srw_req,
705 srw_res->records + j);
708 srw_res->num_diagnostics = 1;
709 srw_res->diagnostics = (Z_SRW_diagnostic *)
710 odr_malloc(assoc->encode,
711 sizeof(*srw_res->diagnostics));
712 srw_res->diagnostics[0].code =
713 odr_intdup(assoc->encode,
714 yaz_diag_bib1_to_srw (errcode));
715 srw_res->diagnostics[0].details = rr.errstring;
718 if (srw_res->records[j].recordData_buf)
721 srw_res->num_records = j;
723 srw_res->records = 0;
730 static void srw_bend_explain(association *assoc, request *req,
731 Z_SRW_explainRequest *srw_req,
732 Z_SRW_explainResponse *srw_res)
734 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
737 yaz_log(LOG_DEBUG, "srw_bend_init");
738 if (!srw_bend_init(assoc))
741 if (assoc->init && assoc->init->bend_explain)
745 rr.stream = assoc->encode;
746 rr.decode = assoc->decode;
747 rr.print = assoc->print;
749 (*assoc->init->bend_explain)(assoc->backend, &rr);
752 int packing = Z_SRW_recordPacking_string;
753 if (srw_req->recordPacking &&
754 !strcmp(srw_req->recordPacking, "xml"))
755 packing = Z_SRW_recordPacking_XML;
756 srw_res->record.recordSchema = 0;
757 srw_res->record.recordPacking = packing;
758 srw_res->record.recordData_buf = rr.explain_buf;
759 srw_res->record.recordData_len = strlen(rr.explain_buf);
760 srw_res->record.recordPosition = 0;
765 static void process_http_request(association *assoc, request *req)
767 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
768 ODR o = assoc->encode;
770 Z_HTTP_Response *hres = 0;
773 if (!strcmp(hreq->method, "GET"))
775 char *db = "Default";
776 const char *p0 = hreq->path, *p1;
777 const char *operation = 0;
781 Z_SOAP *soap_package = 0;
782 static Z_SOAP_Handler soap_handlers[2] = {
783 {"http://www.loc.gov/zing/srw/", 0,
784 (Z_SOAP_fun) yaz_srw_codec},
790 p1 = strchr(p0, '?');
792 p1 = p0 + strlen(p0);
795 db = odr_malloc(assoc->decode, p1 - p0 + 1);
796 memcpy (db, p0, p1 - p0);
800 operation = yaz_uri_val(p1, "operation", o);
802 operation = "explain";
804 if (p1 && !strcmp(operation, "searchRetrieve"))
806 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
807 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
808 char *query = yaz_uri_val(p1, "query", o);
809 char *pQuery = yaz_uri_val(p1, "pQuery", o);
810 char *sortKeys = yaz_uri_val(p1, "sortKeys", o);
814 sr->u.request->query_type = Z_SRW_query_type_cql;
815 sr->u.request->query.cql = query;
819 sr->u.request->query_type = Z_SRW_query_type_pqf;
820 sr->u.request->query.pqf = pQuery;
824 sr->u.request->sort_type = Z_SRW_sort_type_sort;
825 sr->u.request->sort.sortKeys = sortKeys;
827 sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", o);
828 sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", o);
829 if (!sr->u.request->recordPacking)
830 sr->u.request->recordPacking = "xml";
831 yaz_uri_val_int(p1, "maximumRecords", o,
832 &sr->u.request->maximumRecords);
833 yaz_uri_val_int(p1, "startRecord", o,
834 &sr->u.request->startRecord);
835 sr->u.request->database = db;
836 srw_bend_search(assoc, req, sr->u.request, res->u.response);
838 soap_package = odr_malloc(o, sizeof(*soap_package));
839 soap_package->which = Z_SOAP_generic;
841 soap_package->u.generic =
842 odr_malloc(o, sizeof(*soap_package->u.generic));
844 soap_package->u.generic->p = res;
845 soap_package->u.generic->ns = soap_handlers[0].ns;
846 soap_package->u.generic->no = 0;
848 soap_package->ns = "SRU";
850 p = z_get_HTTP_Response(o, 200);
851 hres = p->u.HTTP_Response;
853 ret = z_soap_codec_enc(assoc->encode, &soap_package,
854 &hres->content_buf, &hres->content_len,
855 soap_handlers, charset);
857 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
861 strcpy(ctype, "text/xml; charset=");
862 strcat(ctype, charset);
863 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
866 else if (p1 && !strcmp(operation, "explain"))
868 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
869 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
871 sr->u.explain_request->recordPacking =
872 yaz_uri_val(p1, "recordPacking", o);
873 if (!sr->u.explain_request->recordPacking)
874 sr->u.explain_request->recordPacking = "xml";
876 srw_bend_explain(assoc, req, sr->u.explain_request,
877 res->u.explain_response);
879 if (res->u.explain_response->record.recordData_buf)
881 soap_package = odr_malloc(o, sizeof(*soap_package));
882 soap_package->which = Z_SOAP_generic;
884 soap_package->u.generic =
885 odr_malloc(o, sizeof(*soap_package->u.generic));
887 soap_package->u.generic->p = res;
888 soap_package->u.generic->ns = soap_handlers[0].ns;
889 soap_package->u.generic->no = 0;
891 soap_package->ns = "SRU";
893 p = z_get_HTTP_Response(o, 200);
894 hres = p->u.HTTP_Response;
896 ret = z_soap_codec_enc(assoc->encode, &soap_package,
897 &hres->content_buf, &hres->content_len,
898 soap_handlers, charset);
900 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
904 strcpy(ctype, "text/xml; charset=");
905 strcat(ctype, charset);
906 z_HTTP_header_add(o, &hres->headers, "Content-Type",
913 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
914 !memcmp(hreq->path, "/doc/", 5))
919 strcpy(fpath, DOCDIR);
920 strcat(fpath, hreq->path+4);
921 f = fopen(fpath, "rb");
924 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
933 fseek(f, 0L, SEEK_END);
935 if (sz >= 0 && sz < 500000)
937 const char *ctype = "application/octet-stream";
940 p = z_get_HTTP_Response(o, 200);
941 hres = p->u.HTTP_Response;
942 hres->content_buf = (char *) odr_malloc(o, sz + 1);
943 hres->content_len = sz;
944 fseek(f, 0L, SEEK_SET);
945 fread(hres->content_buf, 1, sz, f);
946 if ((cp = strrchr(fpath, '.'))) {
948 if (!strcmp(cp, "png"))
950 else if (!strcmp(cp, "gif"))
952 else if (!strcmp(cp, "xml"))
954 else if (!strcmp(cp, "html"))
957 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
965 if (!strcmp(hreq->path, "/"))
970 const char *doclink = "";
971 p = z_get_HTTP_Response(o, 200);
972 hres = p->u.HTTP_Response;
973 hres->content_buf = (char *) odr_malloc(o, 400);
975 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
976 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
978 sprintf (hres->content_buf,
979 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
982 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
985 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
989 "</HTML>\n", doclink);
990 hres->content_len = strlen(hres->content_buf);
991 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
997 p = z_get_HTTP_Response(o, 404);
1000 else if (!strcmp(hreq->method, "POST"))
1002 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1004 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1006 Z_SOAP *soap_package = 0;
1008 int http_code = 500;
1009 const char *charset_p = 0;
1012 static Z_SOAP_Handler soap_handlers[2] = {
1014 {"http://www.loc.gov/zing/srw/", 0,
1015 (Z_SOAP_fun) yaz_srw_codec},
1019 if ((charset_p = strstr(content_type, "; charset=")))
1023 while (i < 20 && charset_p[i] &&
1024 !strchr("; \n\r", charset_p[i]))
1026 charset = odr_malloc(assoc->encode, i+1);
1027 memcpy(charset, charset_p, i);
1029 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1031 ret = z_soap_codec(assoc->decode, &soap_package,
1032 &hreq->content_buf, &hreq->content_len,
1035 if (!ret && soap_package->which == Z_SOAP_generic &&
1036 soap_package->u.generic->no == 0)
1039 char *db = "Default";
1040 const char *p0 = hreq->path, *p1;
1041 Z_SRW_PDU *sr = soap_package->u.generic->p;
1045 p1 = strchr(p0, '?');
1047 p1 = p0 + strlen(p0);
1050 db = (char*) odr_malloc(assoc->decode, p1 - p0 + 1);
1051 memcpy (db, p0, p1 - p0);
1055 if (sr->which == Z_SRW_searchRetrieve_request)
1058 yaz_srw_get(assoc->encode,
1059 Z_SRW_searchRetrieve_response);
1061 if (!sr->u.request->database)
1062 sr->u.request->database = db;
1064 srw_bend_search(assoc, req, sr->u.request,
1067 soap_package->u.generic->p = res;
1070 else if (sr->which == Z_SRW_explain_request)
1073 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1075 if (!sr->u.explain_request->database)
1076 sr->u.explain_request->database = db;
1078 srw_bend_explain(assoc, req, sr->u.explain_request,
1079 res->u.explain_response);
1080 if (!res->u.explain_response->record.recordData_buf)
1082 z_soap_error(assoc->encode, soap_package,
1083 "SOAP-ENV:Client", "Explain Not Supported", 0);
1087 soap_package->u.generic->p = res;
1093 z_soap_error(assoc->encode, soap_package,
1094 "SOAP-ENV:Client", "Bad method", 0);
1098 p = z_get_HTTP_Response(o, 200);
1099 hres = p->u.HTTP_Response;
1100 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1101 &hres->content_buf, &hres->content_len,
1102 soap_handlers, charset);
1103 hres->code = http_code;
1105 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1109 strcpy(ctype, "text/xml; charset=");
1110 strcat(ctype, charset);
1111 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1114 if (!p) /* still no response ? */
1115 p = z_get_HTTP_Response(o, 500);
1119 p = z_get_HTTP_Response(o, 405);
1120 hres = p->u.HTTP_Response;
1122 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1124 hres = p->u.HTTP_Response;
1125 if (!strcmp(hreq->version, "1.0"))
1127 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1128 if (v && !strcmp(v, "Keep-Alive"))
1132 hres->version = "1.0";
1136 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1137 if (v && !strcmp(v, "close"))
1141 hres->version = "1.1";
1145 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1146 assoc->state = ASSOC_DEAD;
1151 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1153 if (alive && isdigit(*alive))
1157 if (t < 0 || t > 3600)
1159 iochan_settimeout(assoc->client_chan,t);
1160 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1162 process_gdu_response(assoc, req, p);
1165 static void process_gdu_request(association *assoc, request *req)
1167 if (req->gdu_request->which == Z_GDU_Z3950)
1170 req->apdu_request = req->gdu_request->u.z3950;
1171 if (process_z_request(assoc, req, &msg) < 0)
1172 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1174 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1175 process_http_request(assoc, req);
1178 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1183 * Initiate request processing.
1185 static int process_z_request(association *assoc, request *req, char **msg)
1191 *msg = "Unknown Error";
1192 assert(req && req->state == REQUEST_IDLE);
1193 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1195 *msg = "Missing InitRequest";
1198 switch (req->apdu_request->which)
1200 case Z_APDU_initRequest:
1201 iochan_settimeout(assoc->client_chan,
1202 statserv_getcontrol()->idle_timeout * 60);
1203 res = process_initRequest(assoc, req); break;
1204 case Z_APDU_searchRequest:
1205 res = process_searchRequest(assoc, req, &fd); break;
1206 case Z_APDU_presentRequest:
1207 res = process_presentRequest(assoc, req, &fd); break;
1208 case Z_APDU_scanRequest:
1209 if (assoc->init->bend_scan)
1210 res = process_scanRequest(assoc, req, &fd);
1213 *msg = "Cannot handle Scan APDU";
1217 case Z_APDU_extendedServicesRequest:
1218 if (assoc->init->bend_esrequest)
1219 res = process_ESRequest(assoc, req, &fd);
1222 *msg = "Cannot handle Extended Services APDU";
1226 case Z_APDU_sortRequest:
1227 if (assoc->init->bend_sort)
1228 res = process_sortRequest(assoc, req, &fd);
1231 *msg = "Cannot handle Sort APDU";
1236 process_close(assoc, req);
1238 case Z_APDU_deleteResultSetRequest:
1239 if (assoc->init->bend_delete)
1240 res = process_deleteRequest(assoc, req, &fd);
1243 *msg = "Cannot handle Delete APDU";
1247 case Z_APDU_segmentRequest:
1248 if (assoc->init->bend_segment)
1250 res = process_segmentRequest (assoc, req);
1254 *msg = "Cannot handle Segment APDU";
1259 *msg = "Bad APDU received";
1264 yaz_log(LOG_DEBUG, " result immediately available");
1265 retval = process_z_response(assoc, req, res);
1269 yaz_log(LOG_DEBUG, " result unavailble");
1272 else /* no result yet - one will be provided later */
1276 /* Set up an I/O handler for the fd supplied by the backend */
1278 yaz_log(LOG_DEBUG, " establishing handler for result");
1279 req->state = REQUEST_PENDING;
1280 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1282 iochan_setdata(chan, assoc);
1289 * Handle message from the backend.
1291 void backend_response(IOCHAN i, int event)
1293 association *assoc = (association *)iochan_getdata(i);
1294 request *req = request_head(&assoc->incoming);
1298 yaz_log(LOG_DEBUG, "backend_response");
1299 assert(assoc && req && req->state != REQUEST_IDLE);
1300 /* determine what it is we're waiting for */
1301 switch (req->apdu_request->which)
1303 case Z_APDU_searchRequest:
1304 res = response_searchRequest(assoc, req, 0, &fd); break;
1306 case Z_APDU_presentRequest:
1307 res = response_presentRequest(assoc, req, 0, &fd); break;
1308 case Z_APDU_scanRequest:
1309 res = response_scanRequest(assoc, req, 0, &fd); break;
1312 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1315 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1317 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1318 do_close(assoc, Z_Close_systemProblem, 0);
1322 else if (!res) /* no result yet - try again later */
1324 yaz_log(LOG_DEBUG, " no result yet");
1325 iochan_setfd(i, fd); /* in case fd has changed */
1330 * Encode response, and transfer the request structure to the outgoing queue.
1332 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1334 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1336 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1338 yaz_log(LOG_WARN, "ODR print error: %s",
1339 odr_errmsg(odr_geterror(assoc->print)));
1340 odr_reset(assoc->print);
1342 if (!z_GDU(assoc->encode, &res, 0, 0))
1344 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1345 odr_errmsg(odr_geterror(assoc->decode)),
1346 odr_getelement(assoc->decode));
1347 request_release(req);
1350 req->response = odr_getbuf(assoc->encode, &req->len_response,
1351 &req->size_response);
1352 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1353 odr_reset(assoc->encode);
1354 req->state = REQUEST_IDLE;
1355 request_enq(&assoc->outgoing, req);
1356 /* turn the work over to the ir_session handler */
1357 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1358 assoc->cs_put_mask = EVENT_OUTPUT;
1359 /* Is there more work to be done? give that to the input handler too */
1361 if (request_head(&assoc->incoming))
1363 yaz_log (LOG_DEBUG, "more work to be done");
1364 iochan_setevent(assoc->client_chan, EVENT_WORK);
1371 * Encode response, and transfer the request structure to the outgoing queue.
1373 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1375 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1376 gres->which = Z_GDU_Z3950;
1377 gres->u.z3950 = res;
1379 return process_gdu_response(assoc, req, gres);
1384 * Handle init request.
1385 * At the moment, we don't check the options
1386 * anywhere else in the code - we just try not to do anything that would
1387 * break a naive client. We'll toss 'em into the association block when
1388 * we need them there.
1390 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1392 statserv_options_block *cb = statserv_getcontrol();
1393 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1394 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1395 Z_InitResponse *resp = apdu->u.initResponse;
1396 bend_initresult *binitres;
1400 yaz_log(LOG_LOG, "Got initRequest");
1401 if (req->implementationId)
1402 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1403 if (req->implementationName)
1404 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1405 if (req->implementationVersion)
1406 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1408 assoc_init_reset(assoc);
1410 assoc->init->auth = req->idAuthentication;
1411 assoc->init->referenceId = req->referenceId;
1413 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1415 Z_CharSetandLanguageNegotiation *negotiation =
1416 yaz_get_charneg_record (req->otherInfo);
1417 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1418 assoc->init->charneg_request = negotiation;
1421 if (!(binitres = (*cb->bend_init)(assoc->init)))
1423 yaz_log(LOG_WARN, "Bad response from backend.");
1427 assoc->backend = binitres->handle;
1428 if ((assoc->init->bend_sort))
1429 yaz_log (LOG_DEBUG, "Sort handler installed");
1430 if ((assoc->init->bend_search))
1431 yaz_log (LOG_DEBUG, "Search handler installed");
1432 if ((assoc->init->bend_present))
1433 yaz_log (LOG_DEBUG, "Present handler installed");
1434 if ((assoc->init->bend_esrequest))
1435 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1436 if ((assoc->init->bend_delete))
1437 yaz_log (LOG_DEBUG, "Delete handler installed");
1438 if ((assoc->init->bend_scan))
1439 yaz_log (LOG_DEBUG, "Scan handler installed");
1440 if ((assoc->init->bend_segment))
1441 yaz_log (LOG_DEBUG, "Segment handler installed");
1443 resp->referenceId = req->referenceId;
1445 /* let's tell the client what we can do */
1446 if (ODR_MASK_GET(req->options, Z_Options_search))
1448 ODR_MASK_SET(resp->options, Z_Options_search);
1449 strcat(options, "srch");
1451 if (ODR_MASK_GET(req->options, Z_Options_present))
1453 ODR_MASK_SET(resp->options, Z_Options_present);
1454 strcat(options, " prst");
1456 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1457 assoc->init->bend_delete)
1459 ODR_MASK_SET(resp->options, Z_Options_delSet);
1460 strcat(options, " del");
1462 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1463 assoc->init->bend_esrequest)
1465 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1466 strcat (options, " extendedServices");
1468 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1470 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1471 strcat(options, " namedresults");
1473 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1475 ODR_MASK_SET(resp->options, Z_Options_scan);
1476 strcat(options, " scan");
1478 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1480 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1481 strcat(options, " concurrop");
1483 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1485 ODR_MASK_SET(resp->options, Z_Options_sort);
1486 strcat(options, " sort");
1489 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1490 && assoc->init->charneg_response)
1492 Z_OtherInformation **p;
1493 Z_OtherInformationUnit *p0;
1495 yaz_oi_APDU(apdu, &p);
1497 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1498 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1500 p0->which = Z_OtherInfo_externallyDefinedInfo;
1501 p0->information.externallyDefinedInfo =
1502 assoc->init->charneg_response;
1504 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1505 strcat(options, " negotiation");
1508 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1510 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1511 assoc->version = 2; /* 1 & 2 are equivalent */
1513 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1515 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1518 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1520 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1524 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1525 assoc->maximumRecordSize = *req->maximumRecordSize;
1526 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1527 assoc->maximumRecordSize = control_block->maxrecordsize;
1528 assoc->preferredMessageSize = *req->preferredMessageSize;
1529 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1530 assoc->preferredMessageSize = assoc->maximumRecordSize;
1532 resp->preferredMessageSize = &assoc->preferredMessageSize;
1533 resp->maximumRecordSize = &assoc->maximumRecordSize;
1535 resp->implementationId = odr_prepend(assoc->encode,
1536 assoc->init->implementation_id,
1537 resp->implementationId);
1539 resp->implementationName = odr_prepend(assoc->encode,
1540 assoc->init->implementation_name,
1541 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1543 version = odr_strdup(assoc->encode, "$Revision: 1.5 $");
1544 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1545 version[strlen(version)-2] = '\0';
1546 resp->implementationVersion = odr_prepend(assoc->encode,
1547 assoc->init->implementation_version,
1548 odr_prepend(assoc->encode, &version[11],
1549 resp->implementationVersion));
1551 if (binitres->errcode)
1553 yaz_log(LOG_LOG, "Connection rejected by backend.");
1555 assoc->state = ASSOC_DEAD;
1556 resp->userInformationField = init_diagnostics(assoc->encode,
1558 binitres->errstring);
1561 assoc->state = ASSOC_UP;
1566 * Diagnostic in default format, to be returned as either a surrogate
1567 * or non-surrogate diagnostic in the context of an open session, or
1568 * as User-information when an Init is refused.
1570 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1572 int *err = odr_intdup(odr, error);
1573 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1574 odr_malloc (odr, sizeof(*dr));
1576 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1577 addinfo ? " -- " : "", addinfo ? addinfo : "");
1579 dr->diagnosticSetId =
1580 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1581 dr->condition = err;
1582 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1583 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1588 * Set the specified `errcode' and `errstring' into a UserInfo-1
1589 * external to be returned to the client in accordance with Z35.90
1590 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1591 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1593 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1597 Z_OtherInformation *u;
1598 Z_OtherInformationUnit *l;
1599 Z_DiagnosticFormat *d;
1600 Z_DiagnosticFormat_s *e;
1602 x = (Z_External*) odr_malloc(odr, sizeof *x);
1604 x->indirect_reference = 0;
1605 oid.proto = PROTO_Z3950;
1606 oid.oclass = CLASS_USERINFO;
1607 oid.value = VAL_USERINFO1;
1608 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1609 x->which = Z_External_userInfo1;
1611 u = odr_malloc(odr, sizeof *u);
1613 u->num_elements = 1;
1614 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1615 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1618 l->which = Z_OtherInfo_externallyDefinedInfo;
1620 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1621 l->information.externallyDefinedInfo = x2;
1623 x2->indirect_reference = 0;
1624 oid.oclass = CLASS_DIAGSET;
1625 oid.value = VAL_DIAG1;
1626 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1627 x2->which = Z_External_diag1;
1629 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1632 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1633 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1636 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1637 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1642 * nonsurrogate diagnostic record.
1644 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1646 Z_Records *rec = (Z_Records *)
1647 odr_malloc (assoc->encode, sizeof(*rec));
1648 rec->which = Z_Records_NSD;
1649 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1654 * surrogate diagnostic.
1656 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1657 int error, char *addinfo)
1659 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1660 odr_malloc (assoc->encode, sizeof(*rec));
1661 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1663 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1664 rec->databaseName = dbname;
1665 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1666 rec->u.surrogateDiagnostic = drec;
1667 drec->which = Z_DiagRec_defaultFormat;
1668 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1674 * multiple nonsurrogate diagnostics.
1676 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1678 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1679 int *err = odr_intdup(assoc->encode, error);
1680 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1681 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1682 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1683 odr_malloc (assoc->encode, sizeof(*rec));
1685 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1687 recs->num_diagRecs = 1;
1688 recs->diagRecs = recp;
1690 drec->which = Z_DiagRec_defaultFormat;
1691 drec->u.defaultFormat = rec;
1693 rec->diagnosticSetId =
1694 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1695 rec->condition = err;
1697 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1698 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1702 static Z_Records *pack_records(association *a, char *setname, int start,
1703 int *num, Z_RecordComposition *comp,
1704 int *next, int *pres, oid_value format,
1705 Z_ReferenceId *referenceId,
1708 int recno, total_length = 0, toget = *num, dumped_records = 0;
1709 Z_Records *records =
1710 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1711 Z_NamePlusRecordList *reclist =
1712 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1713 Z_NamePlusRecord **list =
1714 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1716 records->which = Z_Records_DBOSD;
1717 records->u.databaseOrSurDiagnostics = reclist;
1718 reclist->num_records = 0;
1719 reclist->records = list;
1720 *pres = Z_PRES_SUCCESS;
1724 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1725 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1726 a->maximumRecordSize);
1727 for (recno = start; reclist->num_records < toget; recno++)
1730 Z_NamePlusRecord *thisrec;
1731 int this_length = 0;
1733 * we get the number of bytes allocated on the stream before any
1734 * allocation done by the backend - this should give us a reasonable
1735 * idea of the total size of the data so far.
1737 total_length = odr_total(a->encode) - dumped_records;
1743 freq.last_in_set = 0;
1744 freq.setname = setname;
1745 freq.surrogate_flag = 0;
1746 freq.number = recno;
1748 freq.request_format = format;
1749 freq.request_format_raw = oid;
1750 freq.output_format = format;
1751 freq.output_format_raw = 0;
1752 freq.stream = a->encode;
1753 freq.print = a->print;
1754 freq.referenceId = referenceId;
1756 (*a->init->bend_fetch)(a->backend, &freq);
1757 /* backend should be able to signal whether error is system-wide
1758 or only pertaining to current record */
1761 if (!freq.surrogate_flag)
1764 *pres = Z_PRES_FAILURE;
1765 /* for 'present request out of range',
1766 set addinfo to record position if not set */
1767 if (freq.errcode == 13 && freq.errstring == 0)
1769 sprintf (s, "%d", recno);
1772 return diagrec(a, freq.errcode, freq.errstring);
1774 reclist->records[reclist->num_records] =
1775 surrogatediagrec(a, freq.basename, freq.errcode,
1777 reclist->num_records++;
1778 *next = freq.last_in_set ? 0 : recno + 1;
1782 this_length = freq.len;
1784 this_length = odr_total(a->encode) - total_length;
1785 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1786 this_length, total_length);
1787 if (this_length + total_length > a->preferredMessageSize)
1789 /* record is small enough, really */
1790 if (this_length <= a->preferredMessageSize)
1792 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1793 *pres = Z_PRES_PARTIAL_2;
1796 /* record can only be fetched by itself */
1797 if (this_length < a->maximumRecordSize)
1799 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1802 yaz_log(LOG_DEBUG, " Dropped it");
1803 reclist->records[reclist->num_records] =
1804 surrogatediagrec(a, freq.basename, 16, 0);
1805 reclist->num_records++;
1806 *next = freq.last_in_set ? 0 : recno + 1;
1807 dumped_records += this_length;
1811 else /* too big entirely */
1813 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1814 reclist->records[reclist->num_records] =
1815 surrogatediagrec(a, freq.basename, 17, 0);
1816 reclist->num_records++;
1817 *next = freq.last_in_set ? 0 : recno + 1;
1818 dumped_records += this_length;
1823 if (!(thisrec = (Z_NamePlusRecord *)
1824 odr_malloc(a->encode, sizeof(*thisrec))))
1826 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1827 strlen(freq.basename) + 1)))
1829 strcpy(thisrec->databaseName, freq.basename);
1830 thisrec->which = Z_NamePlusRecord_databaseRecord;
1832 if (freq.output_format_raw)
1834 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1835 freq.output_format = ident->value;
1837 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1838 freq.record, freq.len);
1839 if (!thisrec->u.databaseRecord)
1841 reclist->records[reclist->num_records] = thisrec;
1842 reclist->num_records++;
1843 *next = freq.last_in_set ? 0 : recno + 1;
1845 *num = reclist->num_records;
1849 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1852 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1853 bend_search_rr *bsrr =
1854 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1856 yaz_log(LOG_LOG, "Got SearchRequest.");
1858 bsrr->request = reqb;
1859 bsrr->association = assoc;
1860 bsrr->referenceId = req->referenceId;
1861 save_referenceId (reqb, bsrr->referenceId);
1863 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1864 if (req->databaseNames)
1867 for (i = 0; i < req->num_databaseNames; i++)
1868 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1870 yaz_log_zquery(req->query);
1872 if (assoc->init->bend_search)
1874 bsrr->setname = req->resultSetName;
1875 bsrr->replace_set = *req->replaceIndicator;
1876 bsrr->num_bases = req->num_databaseNames;
1877 bsrr->basenames = req->databaseNames;
1878 bsrr->query = req->query;
1879 bsrr->stream = assoc->encode;
1880 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1881 bsrr->decode = assoc->decode;
1882 bsrr->print = assoc->print;
1885 bsrr->errstring = NULL;
1886 bsrr->search_info = NULL;
1887 (assoc->init->bend_search)(assoc->backend, bsrr);
1891 return response_searchRequest(assoc, reqb, bsrr, fd);
1894 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1897 * Prepare a searchresponse based on the backend results. We probably want
1898 * to look at making the fetching of records nonblocking as well, but
1899 * so far, we'll keep things simple.
1900 * If bsrt is null, that means we're called in response to a communications
1901 * event, and we'll have to get the response for ourselves.
1903 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1904 bend_search_rr *bsrt, int *fd)
1906 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1907 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1908 Z_SearchResponse *resp = (Z_SearchResponse *)
1909 odr_malloc (assoc->encode, sizeof(*resp));
1910 int *nulint = odr_intdup (assoc->encode, 0);
1911 bool_t *sr = odr_intdup(assoc->encode, 1);
1912 int *next = odr_intdup(assoc->encode, 0);
1913 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1915 apdu->which = Z_APDU_searchResponse;
1916 apdu->u.searchResponse = resp;
1917 resp->referenceId = req->referenceId;
1918 resp->additionalSearchInfo = 0;
1919 resp->otherInfo = 0;
1921 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1923 yaz_log(LOG_FATAL, "Bad result from backend");
1926 else if (bsrt->errcode)
1928 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1929 resp->resultCount = nulint;
1930 resp->numberOfRecordsReturned = nulint;
1931 resp->nextResultSetPosition = nulint;
1932 resp->searchStatus = nulint;
1933 resp->resultSetStatus = none;
1934 resp->presentStatus = 0;
1938 int *toget = odr_intdup(assoc->encode, 0);
1939 int *presst = odr_intdup(assoc->encode, 0);
1940 Z_RecordComposition comp, *compp = 0;
1942 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1945 resp->resultCount = &bsrt->hits;
1947 comp.which = Z_RecordComp_simple;
1948 /* how many records does the user agent want, then? */
1949 if (bsrt->hits <= *req->smallSetUpperBound)
1951 *toget = bsrt->hits;
1952 if ((comp.u.simple = req->smallSetElementSetNames))
1955 else if (bsrt->hits < *req->largeSetLowerBound)
1957 *toget = *req->mediumSetPresentNumber;
1958 if (*toget > bsrt->hits)
1959 *toget = bsrt->hits;
1960 if ((comp.u.simple = req->mediumSetElementSetNames))
1966 if (*toget && !resp->records)
1971 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1974 form = prefformat->value;
1975 resp->records = pack_records(assoc, req->resultSetName, 1,
1976 toget, compp, next, presst, form, req->referenceId,
1977 req->preferredRecordSyntax);
1980 resp->numberOfRecordsReturned = toget;
1981 resp->nextResultSetPosition = next;
1982 resp->searchStatus = sr;
1983 resp->resultSetStatus = 0;
1984 resp->presentStatus = presst;
1988 if (*resp->resultCount)
1990 resp->numberOfRecordsReturned = nulint;
1991 resp->nextResultSetPosition = next;
1992 resp->searchStatus = sr;
1993 resp->resultSetStatus = 0;
1994 resp->presentStatus = 0;
1997 resp->additionalSearchInfo = bsrt->search_info;
2002 * Maybe we got a little over-friendly when we designed bend_fetch to
2003 * get only one record at a time. Some backends can optimise multiple-record
2004 * fetches, and at any rate, there is some overhead involved in
2005 * all that selecting and hopping around. Problem is, of course, that the
2006 * frontend can't know ahead of time how many records it'll need to
2007 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2008 * is downright lousy as a bulk data transfer protocol.
2010 * To start with, we'll do the fetching of records from the backend
2011 * in one operation: To save some trips in and out of the event-handler,
2012 * and to simplify the interface to pack_records. At any rate, asynch
2013 * operation is more fun in operations that have an unpredictable execution
2014 * speed - which is normally more true for search than for present.
2016 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2019 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2023 Z_PresentResponse *resp;
2027 yaz_log(LOG_LOG, "Got PresentRequest.");
2029 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2032 form = prefformat->value;
2033 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2035 resp->presentStatus = odr_intdup(assoc->encode, 0);
2036 if (assoc->init->bend_present)
2038 bend_present_rr *bprr = (bend_present_rr *)
2039 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2040 bprr->setname = req->resultSetId;
2041 bprr->start = *req->resultSetStartPoint;
2042 bprr->number = *req->numberOfRecordsRequested;
2043 bprr->format = form;
2044 bprr->comp = req->recordComposition;
2045 bprr->referenceId = req->referenceId;
2046 bprr->stream = assoc->encode;
2047 bprr->print = assoc->print;
2048 bprr->request = reqb;
2049 bprr->association = assoc;
2051 bprr->errstring = NULL;
2052 (*assoc->init->bend_present)(assoc->backend, bprr);
2058 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2059 *resp->presentStatus = Z_PRES_FAILURE;
2062 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2063 next = odr_intdup(assoc->encode, 0);
2064 num = odr_intdup(assoc->encode, 0);
2066 apdu->which = Z_APDU_presentResponse;
2067 apdu->u.presentResponse = resp;
2068 resp->referenceId = req->referenceId;
2069 resp->otherInfo = 0;
2073 *num = *req->numberOfRecordsRequested;
2075 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2076 num, req->recordComposition, next, resp->presentStatus,
2077 form, req->referenceId, req->preferredRecordSyntax);
2081 resp->numberOfRecordsReturned = num;
2082 resp->nextResultSetPosition = next;
2088 * Scan was implemented rather in a hurry, and with support for only the basic
2089 * elements of the service in the backend API. Suggestions are welcome.
2091 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2093 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2094 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2095 Z_ScanResponse *res = (Z_ScanResponse *)
2096 odr_malloc (assoc->encode, sizeof(*res));
2097 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2098 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2099 Z_ListEntries *ents = (Z_ListEntries *)
2100 odr_malloc (assoc->encode, sizeof(*ents));
2101 Z_DiagRecs *diagrecs_p = NULL;
2103 bend_scan_rr *bsrr = (bend_scan_rr *)
2104 odr_malloc (assoc->encode, sizeof(*bsrr));
2105 struct scan_entry *save_entries;
2107 yaz_log(LOG_LOG, "Got ScanRequest");
2109 apdu->which = Z_APDU_scanResponse;
2110 apdu->u.scanResponse = res;
2111 res->referenceId = req->referenceId;
2113 /* if step is absent, set it to 0 */
2114 res->stepSize = odr_intdup(assoc->encode, 0);
2116 *res->stepSize = *req->stepSize;
2118 res->scanStatus = scanStatus;
2119 res->numberOfEntriesReturned = numberOfEntriesReturned;
2120 res->positionOfTerm = 0;
2121 res->entries = ents;
2122 ents->num_entries = 0;
2123 ents->entries = NULL;
2124 ents->num_nonsurrogateDiagnostics = 0;
2125 ents->nonsurrogateDiagnostics = NULL;
2126 res->attributeSet = 0;
2129 if (req->databaseNames)
2132 for (i = 0; i < req->num_databaseNames; i++)
2133 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2135 bsrr->num_bases = req->num_databaseNames;
2136 bsrr->basenames = req->databaseNames;
2137 bsrr->num_entries = *req->numberOfTermsRequested;
2138 bsrr->term = req->termListAndStartPoint;
2139 bsrr->referenceId = req->referenceId;
2140 bsrr->stream = assoc->encode;
2141 bsrr->print = assoc->print;
2142 bsrr->step_size = res->stepSize;
2144 /* Note that version 2.0 of YAZ and older did not set entries ..
2145 We do now. And when we do it's easier to extend the scan entry
2146 We know that if the scan handler did set entries, it will
2147 not know of new member display_term.
2149 if (bsrr->num_entries > 0)
2152 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2154 for (i = 0; i<bsrr->num_entries; i++)
2156 bsrr->entries[i].term = 0;
2157 bsrr->entries[i].occurrences = 0;
2158 bsrr->entries[i].errcode = 0;
2159 bsrr->entries[i].errstring = 0;
2160 bsrr->entries[i].display_term = 0;
2163 save_entries = bsrr->entries; /* save it so we can compare later */
2165 if (req->attributeSet &&
2166 (attset = oid_getentbyoid(req->attributeSet)) &&
2167 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2168 bsrr->attributeset = attset->value;
2170 bsrr->attributeset = VAL_NONE;
2171 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2172 bsrr->term_position = req->preferredPositionInResponse ?
2173 *req->preferredPositionInResponse : 1;
2174 ((int (*)(void *, bend_scan_rr *))
2175 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2177 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2181 Z_Entry **tab = (Z_Entry **)
2182 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2184 if (bsrr->status == BEND_SCAN_PARTIAL)
2185 *scanStatus = Z_Scan_partial_5;
2187 *scanStatus = Z_Scan_success;
2188 ents->entries = tab;
2189 ents->num_entries = bsrr->num_entries;
2190 res->numberOfEntriesReturned = &ents->num_entries;
2191 res->positionOfTerm = &bsrr->term_position;
2192 for (i = 0; i < bsrr->num_entries; i++)
2198 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2199 if (bsrr->entries[i].occurrences >= 0)
2201 e->which = Z_Entry_termInfo;
2202 e->u.termInfo = t = (Z_TermInfo *)
2203 odr_malloc(assoc->encode, sizeof(*t));
2204 t->suggestedAttributes = 0;
2206 if (save_entries == bsrr->entries &&
2207 bsrr->entries[i].display_term)
2209 /* the entries was NOT set by the handler. So it's
2210 safe to test for new member display_term. It is
2213 t->displayTerm = odr_strdup(assoc->encode,
2214 bsrr->entries[i].display_term);
2216 t->alternativeTerm = 0;
2217 t->byAttributes = 0;
2218 t->otherTermInfo = 0;
2219 t->globalOccurrences = &bsrr->entries[i].occurrences;
2220 t->term = (Z_Term *)
2221 odr_malloc(assoc->encode, sizeof(*t->term));
2222 t->term->which = Z_Term_general;
2223 t->term->u.general = o =
2224 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2225 o->buf = (unsigned char *)
2226 odr_malloc(assoc->encode, o->len = o->size =
2227 strlen(bsrr->entries[i].term));
2228 memcpy(o->buf, bsrr->entries[i].term, o->len);
2229 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2230 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2234 Z_DiagRecs *drecs = diagrecs (assoc,
2235 bsrr->entries[i].errcode,
2236 bsrr->entries[i].errstring);
2237 assert (drecs->num_diagRecs == 1);
2238 e->which = Z_Entry_surrogateDiagnostic;
2239 assert (drecs->diagRecs[0]);
2240 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2246 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2247 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2252 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2255 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2256 Z_SortResponse *res = (Z_SortResponse *)
2257 odr_malloc (assoc->encode, sizeof(*res));
2258 bend_sort_rr *bsrr = (bend_sort_rr *)
2259 odr_malloc (assoc->encode, sizeof(*bsrr));
2261 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2263 yaz_log(LOG_LOG, "Got SortRequest.");
2265 bsrr->num_input_setnames = req->num_inputResultSetNames;
2266 bsrr->input_setnames = req->inputResultSetNames;
2267 bsrr->referenceId = req->referenceId;
2268 bsrr->output_setname = req->sortedResultSetName;
2269 bsrr->sort_sequence = req->sortSequence;
2270 bsrr->stream = assoc->encode;
2271 bsrr->print = assoc->print;
2273 bsrr->sort_status = Z_SortStatus_failure;
2275 bsrr->errstring = 0;
2277 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2279 res->referenceId = bsrr->referenceId;
2280 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2281 res->resultSetStatus = 0;
2284 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2285 res->diagnostics = dr->diagRecs;
2286 res->num_diagnostics = dr->num_diagRecs;
2290 res->num_diagnostics = 0;
2291 res->diagnostics = 0;
2293 res->resultCount = 0;
2296 apdu->which = Z_APDU_sortResponse;
2297 apdu->u.sortResponse = res;
2301 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2304 Z_DeleteResultSetRequest *req =
2305 reqb->apdu_request->u.deleteResultSetRequest;
2306 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2307 odr_malloc (assoc->encode, sizeof(*res));
2308 bend_delete_rr *bdrr = (bend_delete_rr *)
2309 odr_malloc (assoc->encode, sizeof(*bdrr));
2310 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2312 yaz_log(LOG_LOG, "Got DeleteRequest.");
2314 bdrr->num_setnames = req->num_resultSetList;
2315 bdrr->setnames = req->resultSetList;
2316 bdrr->stream = assoc->encode;
2317 bdrr->print = assoc->print;
2318 bdrr->function = *req->deleteFunction;
2319 bdrr->referenceId = req->referenceId;
2321 if (bdrr->num_setnames > 0)
2324 bdrr->statuses = (int*)
2325 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2326 bdrr->num_setnames);
2327 for (i = 0; i < bdrr->num_setnames; i++)
2328 bdrr->statuses[i] = 0;
2330 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2332 res->referenceId = req->referenceId;
2334 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2336 res->deleteListStatuses = 0;
2337 if (bdrr->num_setnames > 0)
2340 res->deleteListStatuses = (Z_ListStatuses *)
2341 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2342 res->deleteListStatuses->num = bdrr->num_setnames;
2343 res->deleteListStatuses->elements =
2345 odr_malloc (assoc->encode,
2346 sizeof(*res->deleteListStatuses->elements) *
2347 bdrr->num_setnames);
2348 for (i = 0; i<bdrr->num_setnames; i++)
2350 res->deleteListStatuses->elements[i] =
2352 odr_malloc (assoc->encode,
2353 sizeof(**res->deleteListStatuses->elements));
2354 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2355 res->deleteListStatuses->elements[i]->id =
2356 odr_strdup (assoc->encode, bdrr->setnames[i]);
2360 res->numberNotDeleted = 0;
2361 res->bulkStatuses = 0;
2362 res->deleteMessage = 0;
2365 apdu->which = Z_APDU_deleteResultSetResponse;
2366 apdu->u.deleteResultSetResponse = res;
2370 static void process_close(association *assoc, request *reqb)
2372 Z_Close *req = reqb->apdu_request->u.close;
2373 static char *reasons[] =
2380 "securityViolation",
2387 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2388 reasons[*req->closeReason], req->diagnosticInformation ?
2389 req->diagnosticInformation : "NULL");
2390 if (assoc->version < 3) /* to make do_force respond with close */
2392 do_close_req(assoc, Z_Close_finished,
2393 "Association terminated by client", reqb);
2396 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2400 reqb->len_refid = refid->len;
2401 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2402 memcpy (reqb->refid, refid->buf, refid->len);
2406 reqb->len_refid = 0;
2411 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2413 process_z_response (a, req, res);
2416 bend_request bend_request_mk (bend_association a)
2418 request *nreq = request_get (&a->outgoing);
2419 nreq->request_mem = nmem_create ();
2423 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2428 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2429 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2430 id->len = id->size = req->len_refid;
2431 memcpy (id->buf, req->refid, req->len_refid);
2435 void bend_request_destroy (bend_request *req)
2437 nmem_destroy((*req)->request_mem);
2438 request_release(*req);
2442 int bend_backend_respond (bend_association a, bend_request req)
2446 r = process_z_request (a, req, &msg);
2448 yaz_log (LOG_WARN, "%s", msg);
2452 void bend_request_setdata(bend_request r, void *p)
2457 void *bend_request_getdata(bend_request r)
2459 return r->clientData;
2462 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2464 bend_segment_rr req;
2466 req.segment = reqb->apdu_request->u.segmentRequest;
2467 req.stream = assoc->encode;
2468 req.decode = assoc->decode;
2469 req.print = assoc->print;
2470 req.association = assoc;
2472 (*assoc->init->bend_segment)(assoc->backend, &req);
2477 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2479 bend_esrequest_rr esrequest;
2481 Z_ExtendedServicesRequest *req =
2482 reqb->apdu_request->u.extendedServicesRequest;
2483 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2485 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2487 yaz_log(LOG_DEBUG,"inside Process esRequest");
2489 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2490 esrequest.stream = assoc->encode;
2491 esrequest.decode = assoc->decode;
2492 esrequest.print = assoc->print;
2493 esrequest.errcode = 0;
2494 esrequest.errstring = NULL;
2495 esrequest.request = reqb;
2496 esrequest.association = assoc;
2497 esrequest.taskPackage = 0;
2498 esrequest.referenceId = req->referenceId;
2500 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2502 /* If the response is being delayed, return NULL */
2503 if (esrequest.request == NULL)
2506 resp->referenceId = req->referenceId;
2508 if (esrequest.errcode == -1)
2510 /* Backend service indicates request will be processed */
2511 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2512 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2514 else if (esrequest.errcode == 0)
2516 /* Backend service indicates request will be processed */
2517 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2518 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2522 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2523 esrequest.errstring);
2525 /* Backend indicates error, request will not be processed */
2526 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2527 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2528 resp->num_diagnostics = diagRecs->num_diagRecs;
2529 resp->diagnostics = diagRecs->diagRecs;
2531 /* Do something with the members of bend_extendedservice */
2532 if (esrequest.taskPackage)
2533 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2534 (const char *) esrequest.taskPackage,
2536 yaz_log(LOG_DEBUG,"Send the result apdu");