2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.8 2003-12-29 13:39:41 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;
729 static void srw_bend_explain(association *assoc, request *req,
730 Z_SRW_explainRequest *srw_req,
731 Z_SRW_explainResponse *srw_res)
733 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
736 yaz_log(LOG_DEBUG, "srw_bend_init");
737 if (!srw_bend_init(assoc))
740 if (assoc->init && assoc->init->bend_explain)
744 rr.stream = assoc->encode;
745 rr.decode = assoc->decode;
746 rr.print = assoc->print;
748 (*assoc->init->bend_explain)(assoc->backend, &rr);
751 int packing = Z_SRW_recordPacking_string;
752 if (srw_req->recordPacking &&
753 !strcmp(srw_req->recordPacking, "xml"))
754 packing = Z_SRW_recordPacking_XML;
755 srw_res->record.recordSchema = 0;
756 srw_res->record.recordPacking = packing;
757 srw_res->record.recordData_buf = rr.explain_buf;
758 srw_res->record.recordData_len = strlen(rr.explain_buf);
759 srw_res->record.recordPosition = 0;
764 static void process_http_request(association *assoc, request *req)
766 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
767 ODR o = assoc->encode;
769 Z_HTTP_Response *hres = 0;
772 if (!strcmp(hreq->method, "GET"))
774 char *db = "Default";
775 const char *p0 = hreq->path, *p1;
776 const char *operation = 0;
780 Z_SOAP *soap_package = 0;
781 static Z_SOAP_Handler soap_handlers[2] = {
782 {"http://www.loc.gov/zing/srw/", 0,
783 (Z_SOAP_fun) yaz_srw_codec},
789 p1 = strchr(p0, '?');
791 p1 = p0 + strlen(p0);
794 db = odr_malloc(assoc->decode, p1 - p0 + 1);
795 memcpy (db, p0, p1 - p0);
799 operation = yaz_uri_val(p1, "operation", o);
801 operation = "explain";
803 if (p1 && !strcmp(operation, "searchRetrieve"))
805 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
806 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
807 char *query = yaz_uri_val(p1, "query", o);
808 char *pQuery = yaz_uri_val(p1, "pQuery", o);
809 char *sortKeys = yaz_uri_val(p1, "sortKeys", o);
813 sr->u.request->query_type = Z_SRW_query_type_cql;
814 sr->u.request->query.cql = query;
818 sr->u.request->query_type = Z_SRW_query_type_pqf;
819 sr->u.request->query.pqf = pQuery;
823 sr->u.request->sort_type = Z_SRW_sort_type_sort;
824 sr->u.request->sort.sortKeys = sortKeys;
826 sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", o);
827 sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", o);
828 if (!sr->u.request->recordPacking)
829 sr->u.request->recordPacking = "xml";
830 yaz_uri_val_int(p1, "maximumRecords", o,
831 &sr->u.request->maximumRecords);
832 yaz_uri_val_int(p1, "startRecord", o,
833 &sr->u.request->startRecord);
834 sr->u.request->database = db;
835 srw_bend_search(assoc, req, sr->u.request, res->u.response);
837 soap_package = odr_malloc(o, sizeof(*soap_package));
838 soap_package->which = Z_SOAP_generic;
840 soap_package->u.generic =
841 odr_malloc(o, sizeof(*soap_package->u.generic));
843 soap_package->u.generic->p = res;
844 soap_package->u.generic->ns = soap_handlers[0].ns;
845 soap_package->u.generic->no = 0;
847 soap_package->ns = "SRU";
849 p = z_get_HTTP_Response(o, 200);
850 hres = p->u.HTTP_Response;
852 ret = z_soap_codec_enc(assoc->encode, &soap_package,
853 &hres->content_buf, &hres->content_len,
854 soap_handlers, charset);
856 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
860 strcpy(ctype, "text/xml; charset=");
861 strcat(ctype, charset);
862 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
865 else if (p1 && !strcmp(operation, "explain"))
867 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
868 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
870 sr->u.explain_request->recordPacking =
871 yaz_uri_val(p1, "recordPacking", o);
872 if (!sr->u.explain_request->recordPacking)
873 sr->u.explain_request->recordPacking = "xml";
875 srw_bend_explain(assoc, req, sr->u.explain_request,
876 res->u.explain_response);
878 if (res->u.explain_response->record.recordData_buf)
880 soap_package = odr_malloc(o, sizeof(*soap_package));
881 soap_package->which = Z_SOAP_generic;
883 soap_package->u.generic =
884 odr_malloc(o, sizeof(*soap_package->u.generic));
886 soap_package->u.generic->p = res;
887 soap_package->u.generic->ns = soap_handlers[0].ns;
888 soap_package->u.generic->no = 0;
890 soap_package->ns = "SRU";
892 p = z_get_HTTP_Response(o, 200);
893 hres = p->u.HTTP_Response;
895 ret = z_soap_codec_enc(assoc->encode, &soap_package,
896 &hres->content_buf, &hres->content_len,
897 soap_handlers, charset);
899 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
903 strcpy(ctype, "text/xml; charset=");
904 strcat(ctype, charset);
905 z_HTTP_header_add(o, &hres->headers, "Content-Type",
912 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
913 !memcmp(hreq->path, "/doc/", 5))
918 strcpy(fpath, DOCDIR);
919 strcat(fpath, hreq->path+4);
920 f = fopen(fpath, "rb");
923 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
932 fseek(f, 0L, SEEK_END);
934 if (sz >= 0 && sz < 500000)
936 const char *ctype = "application/octet-stream";
939 p = z_get_HTTP_Response(o, 200);
940 hres = p->u.HTTP_Response;
941 hres->content_buf = (char *) odr_malloc(o, sz + 1);
942 hres->content_len = sz;
943 fseek(f, 0L, SEEK_SET);
944 fread(hres->content_buf, 1, sz, f);
945 if ((cp = strrchr(fpath, '.'))) {
947 if (!strcmp(cp, "png"))
949 else if (!strcmp(cp, "gif"))
951 else if (!strcmp(cp, "xml"))
953 else if (!strcmp(cp, "html"))
956 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
964 if (!strcmp(hreq->path, "/"))
969 const char *doclink = "";
970 p = z_get_HTTP_Response(o, 200);
971 hres = p->u.HTTP_Response;
972 hres->content_buf = (char *) odr_malloc(o, 400);
974 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
975 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
977 sprintf (hres->content_buf,
978 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
981 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
984 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
988 "</HTML>\n", doclink);
989 hres->content_len = strlen(hres->content_buf);
990 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
996 p = z_get_HTTP_Response(o, 404);
999 else if (!strcmp(hreq->method, "POST"))
1001 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1003 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1005 Z_SOAP *soap_package = 0;
1007 int http_code = 500;
1008 const char *charset_p = 0;
1011 static Z_SOAP_Handler soap_handlers[2] = {
1013 {"http://www.loc.gov/zing/srw/", 0,
1014 (Z_SOAP_fun) yaz_srw_codec},
1018 if ((charset_p = strstr(content_type, "; charset=")))
1022 while (i < 20 && charset_p[i] &&
1023 !strchr("; \n\r", charset_p[i]))
1025 charset = odr_malloc(assoc->encode, i+1);
1026 memcpy(charset, charset_p, i);
1028 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1030 ret = z_soap_codec(assoc->decode, &soap_package,
1031 &hreq->content_buf, &hreq->content_len,
1034 if (!ret && soap_package->which == Z_SOAP_generic &&
1035 soap_package->u.generic->no == 0)
1038 char *db = "Default";
1039 const char *p0 = hreq->path, *p1;
1040 Z_SRW_PDU *sr = soap_package->u.generic->p;
1044 p1 = strchr(p0, '?');
1046 p1 = p0 + strlen(p0);
1049 db = (char*) odr_malloc(assoc->decode, p1 - p0 + 1);
1050 memcpy (db, p0, p1 - p0);
1054 if (sr->which == Z_SRW_searchRetrieve_request)
1057 yaz_srw_get(assoc->encode,
1058 Z_SRW_searchRetrieve_response);
1060 if (!sr->u.request->database)
1061 sr->u.request->database = db;
1063 srw_bend_search(assoc, req, sr->u.request,
1066 soap_package->u.generic->p = res;
1069 else if (sr->which == Z_SRW_explain_request)
1072 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1074 if (!sr->u.explain_request->database)
1075 sr->u.explain_request->database = db;
1077 srw_bend_explain(assoc, req, sr->u.explain_request,
1078 res->u.explain_response);
1079 if (!res->u.explain_response->record.recordData_buf)
1081 z_soap_error(assoc->encode, soap_package,
1082 "SOAP-ENV:Client", "Explain Not Supported", 0);
1086 soap_package->u.generic->p = res;
1092 z_soap_error(assoc->encode, soap_package,
1093 "SOAP-ENV:Client", "Bad method", 0);
1097 p = z_get_HTTP_Response(o, 200);
1098 hres = p->u.HTTP_Response;
1099 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1100 &hres->content_buf, &hres->content_len,
1101 soap_handlers, charset);
1102 hres->code = http_code;
1104 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1108 strcpy(ctype, "text/xml; charset=");
1109 strcat(ctype, charset);
1110 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1113 if (!p) /* still no response ? */
1114 p = z_get_HTTP_Response(o, 500);
1118 p = z_get_HTTP_Response(o, 405);
1119 hres = p->u.HTTP_Response;
1121 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1123 hres = p->u.HTTP_Response;
1124 if (!strcmp(hreq->version, "1.0"))
1126 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1127 if (v && !strcmp(v, "Keep-Alive"))
1131 hres->version = "1.0";
1135 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1136 if (v && !strcmp(v, "close"))
1140 hres->version = "1.1";
1144 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1145 assoc->state = ASSOC_DEAD;
1150 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1152 if (alive && isdigit(*alive))
1156 if (t < 0 || t > 3600)
1158 iochan_settimeout(assoc->client_chan,t);
1159 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1161 process_gdu_response(assoc, req, p);
1164 static void process_gdu_request(association *assoc, request *req)
1166 if (req->gdu_request->which == Z_GDU_Z3950)
1169 req->apdu_request = req->gdu_request->u.z3950;
1170 if (process_z_request(assoc, req, &msg) < 0)
1171 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1173 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1174 process_http_request(assoc, req);
1177 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1182 * Initiate request processing.
1184 static int process_z_request(association *assoc, request *req, char **msg)
1190 *msg = "Unknown Error";
1191 assert(req && req->state == REQUEST_IDLE);
1192 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1194 *msg = "Missing InitRequest";
1197 switch (req->apdu_request->which)
1199 case Z_APDU_initRequest:
1200 iochan_settimeout(assoc->client_chan,
1201 statserv_getcontrol()->idle_timeout * 60);
1202 res = process_initRequest(assoc, req); break;
1203 case Z_APDU_searchRequest:
1204 res = process_searchRequest(assoc, req, &fd); break;
1205 case Z_APDU_presentRequest:
1206 res = process_presentRequest(assoc, req, &fd); break;
1207 case Z_APDU_scanRequest:
1208 if (assoc->init->bend_scan)
1209 res = process_scanRequest(assoc, req, &fd);
1212 *msg = "Cannot handle Scan APDU";
1216 case Z_APDU_extendedServicesRequest:
1217 if (assoc->init->bend_esrequest)
1218 res = process_ESRequest(assoc, req, &fd);
1221 *msg = "Cannot handle Extended Services APDU";
1225 case Z_APDU_sortRequest:
1226 if (assoc->init->bend_sort)
1227 res = process_sortRequest(assoc, req, &fd);
1230 *msg = "Cannot handle Sort APDU";
1235 process_close(assoc, req);
1237 case Z_APDU_deleteResultSetRequest:
1238 if (assoc->init->bend_delete)
1239 res = process_deleteRequest(assoc, req, &fd);
1242 *msg = "Cannot handle Delete APDU";
1246 case Z_APDU_segmentRequest:
1247 if (assoc->init->bend_segment)
1249 res = process_segmentRequest (assoc, req);
1253 *msg = "Cannot handle Segment APDU";
1258 *msg = "Bad APDU received";
1263 yaz_log(LOG_DEBUG, " result immediately available");
1264 retval = process_z_response(assoc, req, res);
1268 yaz_log(LOG_DEBUG, " result unavailble");
1271 else /* no result yet - one will be provided later */
1275 /* Set up an I/O handler for the fd supplied by the backend */
1277 yaz_log(LOG_DEBUG, " establishing handler for result");
1278 req->state = REQUEST_PENDING;
1279 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1281 iochan_setdata(chan, assoc);
1288 * Handle message from the backend.
1290 void backend_response(IOCHAN i, int event)
1292 association *assoc = (association *)iochan_getdata(i);
1293 request *req = request_head(&assoc->incoming);
1297 yaz_log(LOG_DEBUG, "backend_response");
1298 assert(assoc && req && req->state != REQUEST_IDLE);
1299 /* determine what it is we're waiting for */
1300 switch (req->apdu_request->which)
1302 case Z_APDU_searchRequest:
1303 res = response_searchRequest(assoc, req, 0, &fd); break;
1305 case Z_APDU_presentRequest:
1306 res = response_presentRequest(assoc, req, 0, &fd); break;
1307 case Z_APDU_scanRequest:
1308 res = response_scanRequest(assoc, req, 0, &fd); break;
1311 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1314 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1316 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1317 do_close(assoc, Z_Close_systemProblem, 0);
1321 else if (!res) /* no result yet - try again later */
1323 yaz_log(LOG_DEBUG, " no result yet");
1324 iochan_setfd(i, fd); /* in case fd has changed */
1329 * Encode response, and transfer the request structure to the outgoing queue.
1331 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1333 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1335 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1337 yaz_log(LOG_WARN, "ODR print error: %s",
1338 odr_errmsg(odr_geterror(assoc->print)));
1339 odr_reset(assoc->print);
1341 if (!z_GDU(assoc->encode, &res, 0, 0))
1343 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1344 odr_errmsg(odr_geterror(assoc->decode)),
1345 odr_getelement(assoc->decode));
1346 request_release(req);
1349 req->response = odr_getbuf(assoc->encode, &req->len_response,
1350 &req->size_response);
1351 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1352 odr_reset(assoc->encode);
1353 req->state = REQUEST_IDLE;
1354 request_enq(&assoc->outgoing, req);
1355 /* turn the work over to the ir_session handler */
1356 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1357 assoc->cs_put_mask = EVENT_OUTPUT;
1358 /* Is there more work to be done? give that to the input handler too */
1360 if (request_head(&assoc->incoming))
1362 yaz_log (LOG_DEBUG, "more work to be done");
1363 iochan_setevent(assoc->client_chan, EVENT_WORK);
1370 * Encode response, and transfer the request structure to the outgoing queue.
1372 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1374 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1375 gres->which = Z_GDU_Z3950;
1376 gres->u.z3950 = res;
1378 return process_gdu_response(assoc, req, gres);
1383 * Handle init request.
1384 * At the moment, we don't check the options
1385 * anywhere else in the code - we just try not to do anything that would
1386 * break a naive client. We'll toss 'em into the association block when
1387 * we need them there.
1389 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1391 statserv_options_block *cb = statserv_getcontrol();
1392 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1393 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1394 Z_InitResponse *resp = apdu->u.initResponse;
1395 bend_initresult *binitres;
1399 yaz_log(LOG_LOG, "Got initRequest");
1400 if (req->implementationId)
1401 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1402 if (req->implementationName)
1403 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1404 if (req->implementationVersion)
1405 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1407 assoc_init_reset(assoc);
1409 assoc->init->auth = req->idAuthentication;
1410 assoc->init->referenceId = req->referenceId;
1412 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1414 Z_CharSetandLanguageNegotiation *negotiation =
1415 yaz_get_charneg_record (req->otherInfo);
1416 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1417 assoc->init->charneg_request = negotiation;
1420 if (!(binitres = (*cb->bend_init)(assoc->init)))
1422 yaz_log(LOG_WARN, "Bad response from backend.");
1426 assoc->backend = binitres->handle;
1427 if ((assoc->init->bend_sort))
1428 yaz_log (LOG_DEBUG, "Sort handler installed");
1429 if ((assoc->init->bend_search))
1430 yaz_log (LOG_DEBUG, "Search handler installed");
1431 if ((assoc->init->bend_present))
1432 yaz_log (LOG_DEBUG, "Present handler installed");
1433 if ((assoc->init->bend_esrequest))
1434 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1435 if ((assoc->init->bend_delete))
1436 yaz_log (LOG_DEBUG, "Delete handler installed");
1437 if ((assoc->init->bend_scan))
1438 yaz_log (LOG_DEBUG, "Scan handler installed");
1439 if ((assoc->init->bend_segment))
1440 yaz_log (LOG_DEBUG, "Segment handler installed");
1442 resp->referenceId = req->referenceId;
1444 /* let's tell the client what we can do */
1445 if (ODR_MASK_GET(req->options, Z_Options_search))
1447 ODR_MASK_SET(resp->options, Z_Options_search);
1448 strcat(options, "srch");
1450 if (ODR_MASK_GET(req->options, Z_Options_present))
1452 ODR_MASK_SET(resp->options, Z_Options_present);
1453 strcat(options, " prst");
1455 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1456 assoc->init->bend_delete)
1458 ODR_MASK_SET(resp->options, Z_Options_delSet);
1459 strcat(options, " del");
1461 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1462 assoc->init->bend_esrequest)
1464 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1465 strcat (options, " extendedServices");
1467 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1469 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1470 strcat(options, " namedresults");
1472 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1474 ODR_MASK_SET(resp->options, Z_Options_scan);
1475 strcat(options, " scan");
1477 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1479 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1480 strcat(options, " concurrop");
1482 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1484 ODR_MASK_SET(resp->options, Z_Options_sort);
1485 strcat(options, " sort");
1488 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1489 && assoc->init->charneg_response)
1491 Z_OtherInformation **p;
1492 Z_OtherInformationUnit *p0;
1494 yaz_oi_APDU(apdu, &p);
1496 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1497 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1499 p0->which = Z_OtherInfo_externallyDefinedInfo;
1500 p0->information.externallyDefinedInfo =
1501 assoc->init->charneg_response;
1503 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1504 strcat(options, " negotiation");
1507 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1509 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1510 assoc->version = 2; /* 1 & 2 are equivalent */
1512 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1514 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1517 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1519 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1523 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1524 assoc->maximumRecordSize = *req->maximumRecordSize;
1525 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1526 assoc->maximumRecordSize = control_block->maxrecordsize;
1527 assoc->preferredMessageSize = *req->preferredMessageSize;
1528 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1529 assoc->preferredMessageSize = assoc->maximumRecordSize;
1531 resp->preferredMessageSize = &assoc->preferredMessageSize;
1532 resp->maximumRecordSize = &assoc->maximumRecordSize;
1534 resp->implementationId = odr_prepend(assoc->encode,
1535 assoc->init->implementation_id,
1536 resp->implementationId);
1538 resp->implementationName = odr_prepend(assoc->encode,
1539 assoc->init->implementation_name,
1540 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1542 version = odr_strdup(assoc->encode, "$Revision: 1.8 $");
1543 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1544 version[strlen(version)-2] = '\0';
1545 resp->implementationVersion = odr_prepend(assoc->encode,
1546 assoc->init->implementation_version,
1547 odr_prepend(assoc->encode, &version[11],
1548 resp->implementationVersion));
1550 if (binitres->errcode)
1552 yaz_log(LOG_LOG, "Connection rejected by backend.");
1554 assoc->state = ASSOC_DEAD;
1555 resp->userInformationField = init_diagnostics(assoc->encode,
1557 binitres->errstring);
1560 assoc->state = ASSOC_UP;
1565 * Diagnostic in default format, to be returned as either a surrogate
1566 * or non-surrogate diagnostic in the context of an open session, or
1567 * as User-information when an Init is refused.
1569 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1571 int *err = odr_intdup(odr, error);
1572 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1573 odr_malloc (odr, sizeof(*dr));
1575 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1576 addinfo ? " -- " : "", addinfo ? addinfo : "");
1578 dr->diagnosticSetId =
1579 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1580 dr->condition = err;
1581 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1582 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1587 * Set the specified `errcode' and `errstring' into a UserInfo-1
1588 * external to be returned to the client in accordance with Z35.90
1589 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1590 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1592 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1596 Z_OtherInformation *u;
1597 Z_OtherInformationUnit *l;
1598 Z_DiagnosticFormat *d;
1599 Z_DiagnosticFormat_s *e;
1601 x = (Z_External*) odr_malloc(odr, sizeof *x);
1603 x->indirect_reference = 0;
1604 oid.proto = PROTO_Z3950;
1605 oid.oclass = CLASS_USERINFO;
1606 oid.value = VAL_USERINFO1;
1607 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1608 x->which = Z_External_userInfo1;
1610 u = odr_malloc(odr, sizeof *u);
1612 u->num_elements = 1;
1613 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1614 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1617 l->which = Z_OtherInfo_externallyDefinedInfo;
1619 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1620 l->information.externallyDefinedInfo = x2;
1622 x2->indirect_reference = 0;
1623 oid.oclass = CLASS_DIAGSET;
1624 oid.value = VAL_DIAG1;
1625 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1626 x2->which = Z_External_diag1;
1628 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1631 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1632 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1635 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1636 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1641 * nonsurrogate diagnostic record.
1643 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1645 Z_Records *rec = (Z_Records *)
1646 odr_malloc (assoc->encode, sizeof(*rec));
1647 rec->which = Z_Records_NSD;
1648 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1653 * surrogate diagnostic.
1655 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1656 int error, char *addinfo)
1658 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1659 odr_malloc (assoc->encode, sizeof(*rec));
1660 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1662 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1663 rec->databaseName = dbname;
1664 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1665 rec->u.surrogateDiagnostic = drec;
1666 drec->which = Z_DiagRec_defaultFormat;
1667 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1673 * multiple nonsurrogate diagnostics.
1675 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1677 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1678 int *err = odr_intdup(assoc->encode, error);
1679 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1680 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1681 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1682 odr_malloc (assoc->encode, sizeof(*rec));
1684 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1686 recs->num_diagRecs = 1;
1687 recs->diagRecs = recp;
1689 drec->which = Z_DiagRec_defaultFormat;
1690 drec->u.defaultFormat = rec;
1692 rec->diagnosticSetId =
1693 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1694 rec->condition = err;
1696 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1697 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1701 static Z_Records *pack_records(association *a, char *setname, int start,
1702 int *num, Z_RecordComposition *comp,
1703 int *next, int *pres, oid_value format,
1704 Z_ReferenceId *referenceId,
1707 int recno, total_length = 0, toget = *num, dumped_records = 0;
1708 Z_Records *records =
1709 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1710 Z_NamePlusRecordList *reclist =
1711 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1712 Z_NamePlusRecord **list =
1713 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1715 records->which = Z_Records_DBOSD;
1716 records->u.databaseOrSurDiagnostics = reclist;
1717 reclist->num_records = 0;
1718 reclist->records = list;
1719 *pres = Z_PRES_SUCCESS;
1723 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1724 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1725 a->maximumRecordSize);
1726 for (recno = start; reclist->num_records < toget; recno++)
1729 Z_NamePlusRecord *thisrec;
1730 int this_length = 0;
1732 * we get the number of bytes allocated on the stream before any
1733 * allocation done by the backend - this should give us a reasonable
1734 * idea of the total size of the data so far.
1736 total_length = odr_total(a->encode) - dumped_records;
1742 freq.last_in_set = 0;
1743 freq.setname = setname;
1744 freq.surrogate_flag = 0;
1745 freq.number = recno;
1747 freq.request_format = format;
1748 freq.request_format_raw = oid;
1749 freq.output_format = format;
1750 freq.output_format_raw = 0;
1751 freq.stream = a->encode;
1752 freq.print = a->print;
1753 freq.referenceId = referenceId;
1755 (*a->init->bend_fetch)(a->backend, &freq);
1756 /* backend should be able to signal whether error is system-wide
1757 or only pertaining to current record */
1760 if (!freq.surrogate_flag)
1763 *pres = Z_PRES_FAILURE;
1764 /* for 'present request out of range',
1765 set addinfo to record position if not set */
1766 if (freq.errcode == 13 && freq.errstring == 0)
1768 sprintf (s, "%d", recno);
1771 return diagrec(a, freq.errcode, freq.errstring);
1773 reclist->records[reclist->num_records] =
1774 surrogatediagrec(a, freq.basename, freq.errcode,
1776 reclist->num_records++;
1777 *next = freq.last_in_set ? 0 : recno + 1;
1781 this_length = freq.len;
1783 this_length = odr_total(a->encode) - total_length - dumped_records;
1784 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1785 this_length, total_length, dumped_records);
1786 if (this_length + total_length > a->preferredMessageSize)
1788 /* record is small enough, really */
1789 if (this_length <= a->preferredMessageSize && recno > start)
1791 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1792 *pres = Z_PRES_PARTIAL_2;
1795 /* record can only be fetched by itself */
1796 if (this_length < a->maximumRecordSize)
1798 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1801 yaz_log(LOG_DEBUG, " Dropped it");
1802 reclist->records[reclist->num_records] =
1803 surrogatediagrec(a, freq.basename, 16, 0);
1804 reclist->num_records++;
1805 *next = freq.last_in_set ? 0 : recno + 1;
1806 dumped_records += this_length;
1810 else /* too big entirely */
1812 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1813 reclist->records[reclist->num_records] =
1814 surrogatediagrec(a, freq.basename, 17, 0);
1815 reclist->num_records++;
1816 *next = freq.last_in_set ? 0 : recno + 1;
1817 dumped_records += this_length;
1822 if (!(thisrec = (Z_NamePlusRecord *)
1823 odr_malloc(a->encode, sizeof(*thisrec))))
1825 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1826 strlen(freq.basename) + 1)))
1828 strcpy(thisrec->databaseName, freq.basename);
1829 thisrec->which = Z_NamePlusRecord_databaseRecord;
1831 if (freq.output_format_raw)
1833 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1834 freq.output_format = ident->value;
1836 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1837 freq.record, freq.len);
1838 if (!thisrec->u.databaseRecord)
1840 reclist->records[reclist->num_records] = thisrec;
1841 reclist->num_records++;
1842 *next = freq.last_in_set ? 0 : recno + 1;
1844 *num = reclist->num_records;
1848 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1851 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1852 bend_search_rr *bsrr =
1853 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1855 yaz_log(LOG_LOG, "Got SearchRequest.");
1857 bsrr->request = reqb;
1858 bsrr->association = assoc;
1859 bsrr->referenceId = req->referenceId;
1860 save_referenceId (reqb, bsrr->referenceId);
1862 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1863 if (req->databaseNames)
1866 for (i = 0; i < req->num_databaseNames; i++)
1867 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1869 yaz_log_zquery(req->query);
1871 if (assoc->init->bend_search)
1873 bsrr->setname = req->resultSetName;
1874 bsrr->replace_set = *req->replaceIndicator;
1875 bsrr->num_bases = req->num_databaseNames;
1876 bsrr->basenames = req->databaseNames;
1877 bsrr->query = req->query;
1878 bsrr->stream = assoc->encode;
1879 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1880 bsrr->decode = assoc->decode;
1881 bsrr->print = assoc->print;
1884 bsrr->errstring = NULL;
1885 bsrr->search_info = NULL;
1886 (assoc->init->bend_search)(assoc->backend, bsrr);
1890 return response_searchRequest(assoc, reqb, bsrr, fd);
1893 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1896 * Prepare a searchresponse based on the backend results. We probably want
1897 * to look at making the fetching of records nonblocking as well, but
1898 * so far, we'll keep things simple.
1899 * If bsrt is null, that means we're called in response to a communications
1900 * event, and we'll have to get the response for ourselves.
1902 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1903 bend_search_rr *bsrt, int *fd)
1905 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1906 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1907 Z_SearchResponse *resp = (Z_SearchResponse *)
1908 odr_malloc (assoc->encode, sizeof(*resp));
1909 int *nulint = odr_intdup (assoc->encode, 0);
1910 bool_t *sr = odr_intdup(assoc->encode, 1);
1911 int *next = odr_intdup(assoc->encode, 0);
1912 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1914 apdu->which = Z_APDU_searchResponse;
1915 apdu->u.searchResponse = resp;
1916 resp->referenceId = req->referenceId;
1917 resp->additionalSearchInfo = 0;
1918 resp->otherInfo = 0;
1920 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1922 yaz_log(LOG_FATAL, "Bad result from backend");
1925 else if (bsrt->errcode)
1927 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1928 resp->resultCount = nulint;
1929 resp->numberOfRecordsReturned = nulint;
1930 resp->nextResultSetPosition = nulint;
1931 resp->searchStatus = nulint;
1932 resp->resultSetStatus = none;
1933 resp->presentStatus = 0;
1937 int *toget = odr_intdup(assoc->encode, 0);
1938 int *presst = odr_intdup(assoc->encode, 0);
1939 Z_RecordComposition comp, *compp = 0;
1941 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1944 resp->resultCount = &bsrt->hits;
1946 comp.which = Z_RecordComp_simple;
1947 /* how many records does the user agent want, then? */
1948 if (bsrt->hits <= *req->smallSetUpperBound)
1950 *toget = bsrt->hits;
1951 if ((comp.u.simple = req->smallSetElementSetNames))
1954 else if (bsrt->hits < *req->largeSetLowerBound)
1956 *toget = *req->mediumSetPresentNumber;
1957 if (*toget > bsrt->hits)
1958 *toget = bsrt->hits;
1959 if ((comp.u.simple = req->mediumSetElementSetNames))
1965 if (*toget && !resp->records)
1970 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1973 form = prefformat->value;
1974 resp->records = pack_records(assoc, req->resultSetName, 1,
1975 toget, compp, next, presst, form, req->referenceId,
1976 req->preferredRecordSyntax);
1979 resp->numberOfRecordsReturned = toget;
1980 resp->nextResultSetPosition = next;
1981 resp->searchStatus = sr;
1982 resp->resultSetStatus = 0;
1983 resp->presentStatus = presst;
1987 if (*resp->resultCount)
1989 resp->numberOfRecordsReturned = nulint;
1990 resp->nextResultSetPosition = next;
1991 resp->searchStatus = sr;
1992 resp->resultSetStatus = 0;
1993 resp->presentStatus = 0;
1996 resp->additionalSearchInfo = bsrt->search_info;
2001 * Maybe we got a little over-friendly when we designed bend_fetch to
2002 * get only one record at a time. Some backends can optimise multiple-record
2003 * fetches, and at any rate, there is some overhead involved in
2004 * all that selecting and hopping around. Problem is, of course, that the
2005 * frontend can't know ahead of time how many records it'll need to
2006 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2007 * is downright lousy as a bulk data transfer protocol.
2009 * To start with, we'll do the fetching of records from the backend
2010 * in one operation: To save some trips in and out of the event-handler,
2011 * and to simplify the interface to pack_records. At any rate, asynch
2012 * operation is more fun in operations that have an unpredictable execution
2013 * speed - which is normally more true for search than for present.
2015 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2018 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2022 Z_PresentResponse *resp;
2026 yaz_log(LOG_LOG, "Got PresentRequest.");
2028 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2031 form = prefformat->value;
2032 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2034 resp->presentStatus = odr_intdup(assoc->encode, 0);
2035 if (assoc->init->bend_present)
2037 bend_present_rr *bprr = (bend_present_rr *)
2038 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2039 bprr->setname = req->resultSetId;
2040 bprr->start = *req->resultSetStartPoint;
2041 bprr->number = *req->numberOfRecordsRequested;
2042 bprr->format = form;
2043 bprr->comp = req->recordComposition;
2044 bprr->referenceId = req->referenceId;
2045 bprr->stream = assoc->encode;
2046 bprr->print = assoc->print;
2047 bprr->request = reqb;
2048 bprr->association = assoc;
2050 bprr->errstring = NULL;
2051 (*assoc->init->bend_present)(assoc->backend, bprr);
2057 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2058 *resp->presentStatus = Z_PRES_FAILURE;
2061 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2062 next = odr_intdup(assoc->encode, 0);
2063 num = odr_intdup(assoc->encode, 0);
2065 apdu->which = Z_APDU_presentResponse;
2066 apdu->u.presentResponse = resp;
2067 resp->referenceId = req->referenceId;
2068 resp->otherInfo = 0;
2072 *num = *req->numberOfRecordsRequested;
2074 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2075 num, req->recordComposition, next, resp->presentStatus,
2076 form, req->referenceId, req->preferredRecordSyntax);
2080 resp->numberOfRecordsReturned = num;
2081 resp->nextResultSetPosition = next;
2087 * Scan was implemented rather in a hurry, and with support for only the basic
2088 * elements of the service in the backend API. Suggestions are welcome.
2090 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2092 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2093 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2094 Z_ScanResponse *res = (Z_ScanResponse *)
2095 odr_malloc (assoc->encode, sizeof(*res));
2096 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2097 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2098 Z_ListEntries *ents = (Z_ListEntries *)
2099 odr_malloc (assoc->encode, sizeof(*ents));
2100 Z_DiagRecs *diagrecs_p = NULL;
2102 bend_scan_rr *bsrr = (bend_scan_rr *)
2103 odr_malloc (assoc->encode, sizeof(*bsrr));
2104 struct scan_entry *save_entries;
2106 yaz_log(LOG_LOG, "Got ScanRequest");
2108 apdu->which = Z_APDU_scanResponse;
2109 apdu->u.scanResponse = res;
2110 res->referenceId = req->referenceId;
2112 /* if step is absent, set it to 0 */
2113 res->stepSize = odr_intdup(assoc->encode, 0);
2115 *res->stepSize = *req->stepSize;
2117 res->scanStatus = scanStatus;
2118 res->numberOfEntriesReturned = numberOfEntriesReturned;
2119 res->positionOfTerm = 0;
2120 res->entries = ents;
2121 ents->num_entries = 0;
2122 ents->entries = NULL;
2123 ents->num_nonsurrogateDiagnostics = 0;
2124 ents->nonsurrogateDiagnostics = NULL;
2125 res->attributeSet = 0;
2128 if (req->databaseNames)
2131 for (i = 0; i < req->num_databaseNames; i++)
2132 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2134 bsrr->num_bases = req->num_databaseNames;
2135 bsrr->basenames = req->databaseNames;
2136 bsrr->num_entries = *req->numberOfTermsRequested;
2137 bsrr->term = req->termListAndStartPoint;
2138 bsrr->referenceId = req->referenceId;
2139 bsrr->stream = assoc->encode;
2140 bsrr->print = assoc->print;
2141 bsrr->step_size = res->stepSize;
2143 /* Note that version 2.0 of YAZ and older did not set entries ..
2144 We do now. And when we do it's easier to extend the scan entry
2145 We know that if the scan handler did set entries, it will
2146 not know of new member display_term.
2148 if (bsrr->num_entries > 0)
2151 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2153 for (i = 0; i<bsrr->num_entries; i++)
2155 bsrr->entries[i].term = 0;
2156 bsrr->entries[i].occurrences = 0;
2157 bsrr->entries[i].errcode = 0;
2158 bsrr->entries[i].errstring = 0;
2159 bsrr->entries[i].display_term = 0;
2162 save_entries = bsrr->entries; /* save it so we can compare later */
2164 if (req->attributeSet &&
2165 (attset = oid_getentbyoid(req->attributeSet)) &&
2166 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2167 bsrr->attributeset = attset->value;
2169 bsrr->attributeset = VAL_NONE;
2170 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2171 bsrr->term_position = req->preferredPositionInResponse ?
2172 *req->preferredPositionInResponse : 1;
2173 ((int (*)(void *, bend_scan_rr *))
2174 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2176 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2180 Z_Entry **tab = (Z_Entry **)
2181 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2183 if (bsrr->status == BEND_SCAN_PARTIAL)
2184 *scanStatus = Z_Scan_partial_5;
2186 *scanStatus = Z_Scan_success;
2187 ents->entries = tab;
2188 ents->num_entries = bsrr->num_entries;
2189 res->numberOfEntriesReturned = &ents->num_entries;
2190 res->positionOfTerm = &bsrr->term_position;
2191 for (i = 0; i < bsrr->num_entries; i++)
2197 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2198 if (bsrr->entries[i].occurrences >= 0)
2200 e->which = Z_Entry_termInfo;
2201 e->u.termInfo = t = (Z_TermInfo *)
2202 odr_malloc(assoc->encode, sizeof(*t));
2203 t->suggestedAttributes = 0;
2205 if (save_entries == bsrr->entries &&
2206 bsrr->entries[i].display_term)
2208 /* the entries was NOT set by the handler. So it's
2209 safe to test for new member display_term. It is
2212 t->displayTerm = odr_strdup(assoc->encode,
2213 bsrr->entries[i].display_term);
2215 t->alternativeTerm = 0;
2216 t->byAttributes = 0;
2217 t->otherTermInfo = 0;
2218 t->globalOccurrences = &bsrr->entries[i].occurrences;
2219 t->term = (Z_Term *)
2220 odr_malloc(assoc->encode, sizeof(*t->term));
2221 t->term->which = Z_Term_general;
2222 t->term->u.general = o =
2223 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2224 o->buf = (unsigned char *)
2225 odr_malloc(assoc->encode, o->len = o->size =
2226 strlen(bsrr->entries[i].term));
2227 memcpy(o->buf, bsrr->entries[i].term, o->len);
2228 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2229 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2233 Z_DiagRecs *drecs = diagrecs (assoc,
2234 bsrr->entries[i].errcode,
2235 bsrr->entries[i].errstring);
2236 assert (drecs->num_diagRecs == 1);
2237 e->which = Z_Entry_surrogateDiagnostic;
2238 assert (drecs->diagRecs[0]);
2239 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2245 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2246 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2251 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2254 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2255 Z_SortResponse *res = (Z_SortResponse *)
2256 odr_malloc (assoc->encode, sizeof(*res));
2257 bend_sort_rr *bsrr = (bend_sort_rr *)
2258 odr_malloc (assoc->encode, sizeof(*bsrr));
2260 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2262 yaz_log(LOG_LOG, "Got SortRequest.");
2264 bsrr->num_input_setnames = req->num_inputResultSetNames;
2265 bsrr->input_setnames = req->inputResultSetNames;
2266 bsrr->referenceId = req->referenceId;
2267 bsrr->output_setname = req->sortedResultSetName;
2268 bsrr->sort_sequence = req->sortSequence;
2269 bsrr->stream = assoc->encode;
2270 bsrr->print = assoc->print;
2272 bsrr->sort_status = Z_SortStatus_failure;
2274 bsrr->errstring = 0;
2276 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2278 res->referenceId = bsrr->referenceId;
2279 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2280 res->resultSetStatus = 0;
2283 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2284 res->diagnostics = dr->diagRecs;
2285 res->num_diagnostics = dr->num_diagRecs;
2289 res->num_diagnostics = 0;
2290 res->diagnostics = 0;
2292 res->resultCount = 0;
2295 apdu->which = Z_APDU_sortResponse;
2296 apdu->u.sortResponse = res;
2300 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2303 Z_DeleteResultSetRequest *req =
2304 reqb->apdu_request->u.deleteResultSetRequest;
2305 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2306 odr_malloc (assoc->encode, sizeof(*res));
2307 bend_delete_rr *bdrr = (bend_delete_rr *)
2308 odr_malloc (assoc->encode, sizeof(*bdrr));
2309 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2311 yaz_log(LOG_LOG, "Got DeleteRequest.");
2313 bdrr->num_setnames = req->num_resultSetList;
2314 bdrr->setnames = req->resultSetList;
2315 bdrr->stream = assoc->encode;
2316 bdrr->print = assoc->print;
2317 bdrr->function = *req->deleteFunction;
2318 bdrr->referenceId = req->referenceId;
2320 if (bdrr->num_setnames > 0)
2323 bdrr->statuses = (int*)
2324 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2325 bdrr->num_setnames);
2326 for (i = 0; i < bdrr->num_setnames; i++)
2327 bdrr->statuses[i] = 0;
2329 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2331 res->referenceId = req->referenceId;
2333 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2335 res->deleteListStatuses = 0;
2336 if (bdrr->num_setnames > 0)
2339 res->deleteListStatuses = (Z_ListStatuses *)
2340 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2341 res->deleteListStatuses->num = bdrr->num_setnames;
2342 res->deleteListStatuses->elements =
2344 odr_malloc (assoc->encode,
2345 sizeof(*res->deleteListStatuses->elements) *
2346 bdrr->num_setnames);
2347 for (i = 0; i<bdrr->num_setnames; i++)
2349 res->deleteListStatuses->elements[i] =
2351 odr_malloc (assoc->encode,
2352 sizeof(**res->deleteListStatuses->elements));
2353 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2354 res->deleteListStatuses->elements[i]->id =
2355 odr_strdup (assoc->encode, bdrr->setnames[i]);
2359 res->numberNotDeleted = 0;
2360 res->bulkStatuses = 0;
2361 res->deleteMessage = 0;
2364 apdu->which = Z_APDU_deleteResultSetResponse;
2365 apdu->u.deleteResultSetResponse = res;
2369 static void process_close(association *assoc, request *reqb)
2371 Z_Close *req = reqb->apdu_request->u.close;
2372 static char *reasons[] =
2379 "securityViolation",
2386 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2387 reasons[*req->closeReason], req->diagnosticInformation ?
2388 req->diagnosticInformation : "NULL");
2389 if (assoc->version < 3) /* to make do_force respond with close */
2391 do_close_req(assoc, Z_Close_finished,
2392 "Association terminated by client", reqb);
2395 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2399 reqb->len_refid = refid->len;
2400 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2401 memcpy (reqb->refid, refid->buf, refid->len);
2405 reqb->len_refid = 0;
2410 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2412 process_z_response (a, req, res);
2415 bend_request bend_request_mk (bend_association a)
2417 request *nreq = request_get (&a->outgoing);
2418 nreq->request_mem = nmem_create ();
2422 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2427 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2428 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2429 id->len = id->size = req->len_refid;
2430 memcpy (id->buf, req->refid, req->len_refid);
2434 void bend_request_destroy (bend_request *req)
2436 nmem_destroy((*req)->request_mem);
2437 request_release(*req);
2441 int bend_backend_respond (bend_association a, bend_request req)
2445 r = process_z_request (a, req, &msg);
2447 yaz_log (LOG_WARN, "%s", msg);
2451 void bend_request_setdata(bend_request r, void *p)
2456 void *bend_request_getdata(bend_request r)
2458 return r->clientData;
2461 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2463 bend_segment_rr req;
2465 req.segment = reqb->apdu_request->u.segmentRequest;
2466 req.stream = assoc->encode;
2467 req.decode = assoc->decode;
2468 req.print = assoc->print;
2469 req.association = assoc;
2471 (*assoc->init->bend_segment)(assoc->backend, &req);
2476 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2478 bend_esrequest_rr esrequest;
2480 Z_ExtendedServicesRequest *req =
2481 reqb->apdu_request->u.extendedServicesRequest;
2482 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2484 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2486 yaz_log(LOG_DEBUG,"inside Process esRequest");
2488 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2489 esrequest.stream = assoc->encode;
2490 esrequest.decode = assoc->decode;
2491 esrequest.print = assoc->print;
2492 esrequest.errcode = 0;
2493 esrequest.errstring = NULL;
2494 esrequest.request = reqb;
2495 esrequest.association = assoc;
2496 esrequest.taskPackage = 0;
2497 esrequest.referenceId = req->referenceId;
2499 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2501 /* If the response is being delayed, return NULL */
2502 if (esrequest.request == NULL)
2505 resp->referenceId = req->referenceId;
2507 if (esrequest.errcode == -1)
2509 /* Backend service indicates request will be processed */
2510 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2511 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2513 else if (esrequest.errcode == 0)
2515 /* Backend service indicates request will be processed */
2516 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2517 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2521 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2522 esrequest.errstring);
2524 /* Backend indicates error, request will not be processed */
2525 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2526 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2527 resp->num_diagnostics = diagRecs->num_diagRecs;
2528 resp->diagnostics = diagRecs->diagRecs;
2530 /* Do something with the members of bend_extendedservice */
2531 if (esrequest.taskPackage)
2532 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2533 (const char *) esrequest.taskPackage,
2535 yaz_log(LOG_DEBUG,"Send the result apdu");