2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.161 2003-09-09 16:03:46 mike 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();
174 odr_destroy(h->decode);
175 odr_destroy(h->encode);
177 odr_destroy(h->print);
179 xfree(h->input_buffer);
181 (*cb->bend_close)(h->backend);
182 while (request_deq(&h->incoming));
183 while (request_deq(&h->outgoing));
184 request_delq(&h->incoming);
185 request_delq(&h->outgoing);
187 xmalloc_trav("session closed");
188 if (control_block && control_block->one_shot)
194 static void do_close_req(association *a, int reason, char *message,
198 Z_Close *cls = zget_Close(a->encode);
200 /* Purge request queue */
201 while (request_deq(&a->incoming));
202 while (request_deq(&a->outgoing));
205 yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
206 reason, message ? message : "none");
207 apdu.which = Z_APDU_close;
209 *cls->closeReason = reason;
210 cls->diagnosticInformation = message;
211 process_z_response(a, req, &apdu);
212 iochan_settimeout(a->client_chan, 20);
216 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
217 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
219 a->state = ASSOC_DEAD;
222 static void do_close(association *a, int reason, char *message)
224 do_close_req (a, reason, message, request_get(&a->outgoing));
228 * This is where PDUs from the client are read and the further
229 * processing is initiated. Flow of control moves down through the
230 * various process_* functions below, until the encoded result comes back up
231 * to the output handler in here.
233 * h : the I/O channel that has an outstanding event.
234 * event : the current outstanding event.
236 void ir_session(IOCHAN h, int event)
239 association *assoc = (association *)iochan_getdata(h);
240 COMSTACK conn = assoc->client_link;
243 assert(h && conn && assoc);
244 if (event == EVENT_TIMEOUT)
246 if (assoc->state != ASSOC_UP)
248 yaz_log(LOG_LOG, "Final timeout - closing connection.");
250 destroy_association(assoc);
255 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
256 do_close(assoc, Z_Close_lackOfActivity, 0);
260 if (event & assoc->cs_accept_mask)
262 yaz_log (LOG_DEBUG, "ir_session (accept)");
263 if (!cs_accept (conn))
265 yaz_log (LOG_LOG, "accept failed");
266 destroy_association(assoc);
269 iochan_clearflag (h, EVENT_OUTPUT|EVENT_OUTPUT);
270 if (conn->io_pending)
271 { /* cs_accept didn't complete */
272 assoc->cs_accept_mask =
273 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
274 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
276 iochan_setflag (h, assoc->cs_accept_mask);
279 { /* cs_accept completed. Prepare for reading (cs_get) */
280 assoc->cs_accept_mask = 0;
281 assoc->cs_get_mask = EVENT_INPUT;
282 iochan_setflag (h, assoc->cs_get_mask);
286 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
288 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
290 yaz_log(LOG_DEBUG, "ir_session (input)");
291 /* We aren't speaking to this fellow */
292 if (assoc->state == ASSOC_DEAD)
294 yaz_log(LOG_LOG, "Connection closed - end of session");
296 destroy_association(assoc);
300 assoc->cs_get_mask = EVENT_INPUT;
301 if ((res = cs_get(conn, &assoc->input_buffer,
302 &assoc->input_buffer_len)) <= 0)
304 yaz_log(LOG_LOG, "Connection closed by client");
306 destroy_association(assoc);
310 else if (res == 1) /* incomplete read - wait for more */
312 if (conn->io_pending & CS_WANT_WRITE)
313 assoc->cs_get_mask |= EVENT_OUTPUT;
314 iochan_setflag(h, assoc->cs_get_mask);
317 if (cs_more(conn)) /* more stuff - call us again later, please */
318 iochan_setevent(h, EVENT_INPUT);
320 /* we got a complete PDU. Let's decode it */
321 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
322 assoc->input_buffer[0] & 0xff,
323 assoc->input_buffer[1] & 0xff,
324 assoc->input_buffer[2] & 0xff);
325 req = request_get(&assoc->incoming); /* get a new request */
326 odr_reset(assoc->decode);
327 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
328 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
330 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
332 odr_errmsg(odr_geterror(assoc->decode)),
333 odr_getelement(assoc->decode),
334 odr_offset(assoc->decode));
335 if (assoc->decode->error != OHTTP)
337 yaz_log(LOG_LOG, "PDU dump:");
338 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
339 do_close(assoc, Z_Close_protocolError, "Malformed package");
343 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
344 assoc->state = ASSOC_DEAD;
345 process_gdu_response(assoc, req, p);
349 req->request_mem = odr_extract_mem(assoc->decode);
350 if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
352 yaz_log(LOG_WARN, "ODR print error: %s",
353 odr_errmsg(odr_geterror(assoc->print)));
354 odr_reset(assoc->print);
356 request_enq(&assoc->incoming, req);
359 /* can we do something yet? */
360 req = request_head(&assoc->incoming);
361 if (req->state == REQUEST_IDLE)
363 request_deq(&assoc->incoming);
364 process_gdu_request(assoc, req);
367 if (event & assoc->cs_put_mask)
369 request *req = request_head(&assoc->outgoing);
371 assoc->cs_put_mask = 0;
372 yaz_log(LOG_DEBUG, "ir_session (output)");
373 req->state = REQUEST_PENDING;
374 switch (res = cs_put(conn, req->response, req->len_response))
377 yaz_log(LOG_LOG, "Connection closed by client");
379 destroy_association(assoc);
382 case 0: /* all sent - release the request structure */
383 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
385 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
388 nmem_destroy(req->request_mem);
389 request_deq(&assoc->outgoing);
390 request_release(req);
391 if (!request_head(&assoc->outgoing))
392 { /* restore mask for cs_get operation ... */
393 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
394 iochan_setflag(h, assoc->cs_get_mask);
395 if (assoc->state == ASSOC_DEAD)
396 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
400 assoc->cs_put_mask = EVENT_OUTPUT;
404 if (conn->io_pending & CS_WANT_WRITE)
405 assoc->cs_put_mask |= EVENT_OUTPUT;
406 if (conn->io_pending & CS_WANT_READ)
407 assoc->cs_put_mask |= EVENT_INPUT;
408 iochan_setflag(h, assoc->cs_put_mask);
411 if (event & EVENT_EXCEPT)
413 yaz_log(LOG_LOG, "ir_session (exception)");
415 destroy_association(assoc);
420 static int process_z_request(association *assoc, request *req, char **msg);
422 static void assoc_init_reset(association *assoc)
425 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
427 assoc->init->stream = assoc->encode;
428 assoc->init->print = assoc->print;
429 assoc->init->auth = 0;
430 assoc->init->referenceId = 0;
431 assoc->init->implementation_version = 0;
432 assoc->init->implementation_id = 0;
433 assoc->init->implementation_name = 0;
434 assoc->init->bend_sort = NULL;
435 assoc->init->bend_search = NULL;
436 assoc->init->bend_present = NULL;
437 assoc->init->bend_esrequest = NULL;
438 assoc->init->bend_delete = NULL;
439 assoc->init->bend_scan = NULL;
440 assoc->init->bend_segment = NULL;
441 assoc->init->bend_fetch = NULL;
442 assoc->init->bend_explain = NULL;
444 assoc->init->charneg_request = NULL;
445 assoc->init->charneg_response = NULL;
447 assoc->init->decode = assoc->decode;
448 assoc->init->peer_name =
449 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
452 static int srw_bend_init(association *assoc)
454 const char *encoding = "UTF-8";
456 bend_initresult *binitres;
457 statserv_options_block *cb = statserv_getcontrol();
459 assoc_init_reset(assoc);
461 assoc->maximumRecordSize = 3000000;
462 assoc->preferredMessageSize = 3000000;
464 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
465 assoc->init->charneg_request = ce->u.charNeg3;
467 if (!(binitres = (*cb->bend_init)(assoc->init)))
469 yaz_log(LOG_WARN, "Bad response from backend.");
472 assoc->backend = binitres->handle;
476 static int srw_bend_fetch(association *assoc, int pos,
477 Z_SRW_searchRetrieveRequest *srw_req,
478 Z_SRW_record *record)
481 ODR o = assoc->encode;
483 rr.setname = "default";
486 rr.request_format = VAL_TEXT_XML;
487 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
490 rr.comp = (Z_RecordComposition *)
491 odr_malloc(assoc->decode, sizeof(*rr.comp));
492 rr.comp->which = Z_RecordComp_complex;
493 rr.comp->u.complex = (Z_CompSpec *)
494 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
495 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
496 odr_malloc(assoc->encode, sizeof(bool_t));
497 *rr.comp->u.complex->selectAlternativeSyntax = 0;
498 rr.comp->u.complex->num_dbSpecific = 0;
499 rr.comp->u.complex->dbSpecific = 0;
500 rr.comp->u.complex->num_recordSyntax = 0;
501 rr.comp->u.complex->recordSyntax = 0;
503 rr.comp->u.complex->generic = (Z_Specification *)
504 odr_malloc(assoc->decode, sizeof(Z_Specification));
505 rr.comp->u.complex->generic->which = Z_Schema_uri;
506 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
507 rr.comp->u.complex->generic->elementSpec = 0;
509 rr.stream = assoc->encode;
510 rr.print = assoc->print;
516 rr.output_format = VAL_TEXT_XML;
517 rr.output_format_raw = 0;
520 rr.surrogate_flag = 0;
521 rr.schema = srw_req->recordSchema;
523 if (!assoc->init->bend_fetch)
526 (*assoc->init->bend_fetch)(assoc->backend, &rr);
530 record->recordData_buf = rr.record;
531 record->recordData_len = rr.len;
532 record->recordPosition = odr_intdup(o, pos);
534 record->recordSchema = odr_strdup(o, rr.schema);
536 record->recordSchema = 0;
541 static void srw_bend_search(association *assoc, request *req,
542 Z_SRW_searchRetrieveRequest *srw_req,
543 Z_SRW_searchRetrieveResponse *srw_res)
549 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
550 yaz_log(LOG_DEBUG, "srw_bend_search");
553 yaz_log(LOG_DEBUG, "srw_bend_init");
554 if (!srw_bend_init(assoc))
556 srw_error = 3; /* assume Authentication error */
558 srw_res->num_diagnostics = 1;
559 srw_res->diagnostics = (Z_SRW_diagnostic *)
560 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
561 srw_res->diagnostics[0].code =
562 odr_intdup(assoc->encode, srw_error);
563 srw_res->diagnostics[0].details = 0;
568 rr.setname = "default";
571 rr.basenames = &srw_req->database;
574 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
576 if (srw_req->query_type == Z_SRW_query_type_cql)
578 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
579 ext->direct_reference = odr_getoidbystr(assoc->decode,
580 "1.2.840.10003.16.2");
581 ext->indirect_reference = 0;
583 ext->which = Z_External_CQL;
584 ext->u.cql = srw_req->query.cql;
586 rr.query->which = Z_Query_type_104;
587 rr.query->u.type_104 = ext;
589 else if (srw_req->query_type == Z_SRW_query_type_pqf)
591 Z_RPNQuery *RPNquery;
592 YAZ_PQF_Parser pqf_parser;
594 pqf_parser = yaz_pqf_create ();
596 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
602 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
603 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
604 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
609 rr.query->which = Z_Query_type_1;
610 rr.query->u.type_1 = RPNquery;
612 yaz_pqf_destroy (pqf_parser);
617 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
620 if (!srw_error && !assoc->init->bend_search)
625 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
626 srw_res->num_diagnostics = 1;
627 srw_res->diagnostics = (Z_SRW_diagnostic *)
628 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
629 srw_res->diagnostics[0].code =
630 odr_intdup(assoc->encode, srw_error);
631 srw_res->diagnostics[0].details = 0;
635 rr.stream = assoc->encode;
636 rr.decode = assoc->decode;
637 rr.print = assoc->print;
639 rr.association = assoc;
645 yaz_log_zquery(rr.query);
646 (assoc->init->bend_search)(assoc->backend, &rr);
647 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
650 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
651 srw_res->num_diagnostics = 1;
652 srw_res->diagnostics = (Z_SRW_diagnostic *)
653 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
654 srw_res->diagnostics[0].code =
655 odr_intdup(assoc->encode,
656 yaz_diag_bib1_to_srw (rr.errcode));
657 srw_res->diagnostics[0].details = rr.errstring;
658 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
659 *srw_res->diagnostics[0].code);
664 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
665 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
667 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
668 start, number, rr.hits);
670 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
677 yaz_log(LOG_LOG, "Request out or range");
682 int packing = Z_SRW_recordPacking_string;
683 if (start + number > rr.hits)
684 number = rr.hits - start + 1;
685 if (srw_req->recordPacking &&
686 !strcmp(srw_req->recordPacking, "xml"))
687 packing = Z_SRW_recordPacking_XML;
688 srw_res->records = (Z_SRW_record *)
689 odr_malloc(assoc->encode,
690 number * sizeof(*srw_res->records));
691 for (i = 0; i<number; i++)
695 srw_res->records[j].recordPacking = packing;
696 srw_res->records[j].recordData_buf = 0;
697 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
698 errcode = srw_bend_fetch(assoc, i+start, srw_req,
699 srw_res->records + j);
702 srw_res->num_diagnostics = 1;
703 srw_res->diagnostics = (Z_SRW_diagnostic *)
704 odr_malloc(assoc->encode,
705 sizeof(*srw_res->diagnostics));
706 srw_res->diagnostics[0].code =
707 odr_intdup(assoc->encode,
708 yaz_diag_bib1_to_srw (errcode));
709 srw_res->diagnostics[0].details = rr.errstring;
712 if (srw_res->records[j].recordData_buf)
715 srw_res->num_records = j;
717 srw_res->records = 0;
724 static void srw_bend_explain(association *assoc, request *req,
725 Z_SRW_explainRequest *srw_req,
726 Z_SRW_explainResponse *srw_res)
728 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
731 yaz_log(LOG_DEBUG, "srw_bend_init");
732 if (!srw_bend_init(assoc))
735 if (assoc->init && assoc->init->bend_explain)
739 rr.stream = assoc->encode;
740 rr.decode = assoc->decode;
741 rr.print = assoc->print;
743 (*assoc->init->bend_explain)(assoc->backend, &rr);
746 srw_res->explainData_buf = rr.explain_buf;
747 srw_res->explainData_len = strlen(rr.explain_buf);
752 static int hex_digit (int ch)
754 if (ch >= '0' && ch <= '9')
756 else if (ch >= 'a' && ch <= 'f')
758 else if (ch >= 'A' && ch <= 'F')
763 static char *uri_val(const char *path, const char *name, ODR o)
765 size_t nlen = strlen(name);
769 while (path && *path)
771 const char *p1 = strchr(path, '=');
774 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
780 p1 = strchr(path, '&');
782 p1 = strlen(path) + path;
783 ret = odr_malloc(o, p1 - path + 1);
784 while (*path && *path != '&')
791 else if (*path == '%' && path[1] && path[2])
793 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
802 path = strchr(p1, '&');
809 void uri_val_int(const char *path, const char *name, ODR o, int **intp)
811 const char *v = uri_val(path, name, o);
813 *intp = odr_intdup(o, atoi(v));
816 static void process_http_request(association *assoc, request *req)
818 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
819 ODR o = assoc->encode;
821 Z_HTTP_Response *hres = 0;
824 if (!strcmp(hreq->method, "GET"))
826 char *db = "Default";
827 const char *p0 = hreq->path, *p1;
831 Z_SOAP *soap_package = 0;
832 static Z_SOAP_Handler soap_handlers[2] = {
833 {"http://www.loc.gov/zing/srw/v1.0/", 0,
834 (Z_SOAP_fun) yaz_srw_codec},
841 p1 = strchr(p0, '?');
843 p1 = p0 + strlen(p0);
846 db = odr_malloc(assoc->decode, p1 - p0 + 1);
847 memcpy (db, p0, p1 - p0);
851 if (p1 && *p1 == '?' && p1[1])
853 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
854 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
855 char *query = uri_val(p1, "query", o);
856 char *pQuery = uri_val(p1, "pQuery", o);
857 char *sortKeys = uri_val(p1, "sortKeys", o);
861 sr->u.request->query_type = Z_SRW_query_type_cql;
862 sr->u.request->query.cql = query;
866 sr->u.request->query_type = Z_SRW_query_type_pqf;
867 sr->u.request->query.pqf = pQuery;
871 sr->u.request->sort_type = Z_SRW_sort_type_sort;
872 sr->u.request->sort.sortKeys = sortKeys;
874 sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
875 sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
876 if (!sr->u.request->recordPacking)
877 sr->u.request->recordPacking = "xml";
878 uri_val_int(p1, "maximumRecords", o,
879 &sr->u.request->maximumRecords);
880 uri_val_int(p1, "startRecord", o,
881 &sr->u.request->startRecord);
882 if (sr->u.request->startRecord)
883 yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
884 sr->u.request->database = db;
885 srw_bend_search(assoc, req, sr->u.request, res->u.response);
887 soap_package = odr_malloc(o, sizeof(*soap_package));
888 soap_package->which = Z_SOAP_generic;
890 soap_package->u.generic =
891 odr_malloc(o, sizeof(*soap_package->u.generic));
893 soap_package->u.generic->p = res;
894 soap_package->u.generic->ns = soap_handlers[0].ns;
895 soap_package->u.generic->no = 0;
897 soap_package->ns = "SRU";
899 p = z_get_HTTP_Response(o, 200);
900 hres = p->u.HTTP_Response;
902 ret = z_soap_codec_enc(assoc->encode, &soap_package,
903 &hres->content_buf, &hres->content_len,
904 soap_handlers, charset);
906 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
910 strcpy(ctype, "text/xml; charset=");
911 strcat(ctype, charset);
912 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
918 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
919 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
921 srw_bend_explain(assoc, req, sr->u.explain_request,
922 res->u.explain_response);
924 if (res->u.explain_response->explainData_buf)
926 soap_package = odr_malloc(o, sizeof(*soap_package));
927 soap_package->which = Z_SOAP_generic;
929 soap_package->u.generic =
930 odr_malloc(o, sizeof(*soap_package->u.generic));
932 soap_package->u.generic->p = res;
933 soap_package->u.generic->ns = soap_handlers[0].ns;
934 soap_package->u.generic->no = 0;
936 soap_package->ns = "SRU";
938 p = z_get_HTTP_Response(o, 200);
939 hres = p->u.HTTP_Response;
941 ret = z_soap_codec_enc(assoc->encode, &soap_package,
942 &hres->content_buf, &hres->content_len,
943 soap_handlers, charset);
945 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
949 strcpy(ctype, "text/xml; charset=");
950 strcat(ctype, charset);
951 z_HTTP_header_add(o, &hres->headers, "Content-Type",
958 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
959 !memcmp(hreq->path, "/doc/", 5))
964 strcpy(fpath, DOCDIR);
965 strcat(fpath, hreq->path+4);
966 f = fopen(fpath, "rb");
969 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
978 fseek(f, 0L, SEEK_END);
980 if (sz >= 0 && sz < 500000)
982 const char *ctype = "application/octet-stream";
985 p = z_get_HTTP_Response(o, 200);
986 hres = p->u.HTTP_Response;
987 hres->content_buf = (char *) odr_malloc(o, sz + 1);
988 hres->content_len = sz;
989 fseek(f, 0L, SEEK_SET);
990 fread(hres->content_buf, 1, sz, f);
991 if ((cp = strrchr(fpath, '.'))) {
993 if (!strcmp(cp, "png"))
995 else if (!strcmp(cp, "gif"))
997 else if (!strcmp(cp, "xml"))
999 else if (!strcmp(cp, "html"))
1000 ctype = "text/html";
1002 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1010 if (!strcmp(hreq->path, "/"))
1015 const char *doclink = "";
1016 p = z_get_HTTP_Response(o, 200);
1017 hres = p->u.HTTP_Response;
1018 hres->content_buf = (char *) odr_malloc(o, 400);
1020 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
1021 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
1023 sprintf (hres->content_buf,
1024 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1027 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1030 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1031 YAZ_VERSION "</P>\n"
1034 "</HTML>\n", doclink);
1035 hres->content_len = strlen(hres->content_buf);
1036 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1042 p = z_get_HTTP_Response(o, 404);
1045 else if (!strcmp(hreq->method, "POST"))
1047 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1049 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1051 Z_SOAP *soap_package = 0;
1053 int http_code = 500;
1054 const char *charset_p = 0;
1057 static Z_SOAP_Handler soap_handlers[2] = {
1059 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1060 (Z_SOAP_fun) yaz_srw_codec},
1064 if ((charset_p = strstr(content_type, "; charset=")))
1068 while (i < 20 && charset_p[i] &&
1069 !strchr("; \n\r", charset_p[i]))
1071 charset = odr_malloc(assoc->encode, i+1);
1072 memcpy(charset, charset_p, i);
1074 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1076 ret = z_soap_codec(assoc->decode, &soap_package,
1077 &hreq->content_buf, &hreq->content_len,
1080 if (!ret && soap_package->which == Z_SOAP_generic &&
1081 soap_package->u.generic->no == 0)
1084 Z_SRW_PDU *sr = soap_package->u.generic->p;
1086 if (sr->which == Z_SRW_searchRetrieve_request)
1089 yaz_srw_get(assoc->encode,
1090 Z_SRW_searchRetrieve_response);
1092 if (!sr->u.request->database)
1094 const char *p0 = hreq->path, *p1;
1097 p1 = strchr(p0, '?');
1099 p1 = p0 + strlen(p0);
1102 sr->u.request->database =
1103 odr_malloc(assoc->decode, p1 - p0 + 1);
1104 memcpy (sr->u.request->database, p0, p1 - p0);
1105 sr->u.request->database[p1 - p0] = '\0';
1108 sr->u.request->database = "Default";
1110 srw_bend_search(assoc, req, sr->u.request,
1113 soap_package->u.generic->p = res;
1116 else if (sr->which == Z_SRW_explain_request)
1119 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1121 srw_bend_explain(assoc, req, sr->u.explain_request,
1122 res->u.explain_response);
1123 if (!res->u.explain_response->explainData_buf)
1125 z_soap_error(assoc->encode, soap_package,
1126 "SOAP-ENV:Client", "Explain Not Supported", 0);
1130 soap_package->u.generic->p = res;
1136 z_soap_error(assoc->encode, soap_package,
1137 "SOAP-ENV:Client", "Bad method", 0);
1141 p = z_get_HTTP_Response(o, 200);
1142 hres = p->u.HTTP_Response;
1143 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1144 &hres->content_buf, &hres->content_len,
1145 soap_handlers, charset);
1146 hres->code = http_code;
1148 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1152 strcpy(ctype, "text/xml; charset=");
1153 strcat(ctype, charset);
1154 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1157 if (!p) /* still no response ? */
1158 p = z_get_HTTP_Response(o, 500);
1162 p = z_get_HTTP_Response(o, 405);
1163 hres = p->u.HTTP_Response;
1165 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1167 hres = p->u.HTTP_Response;
1168 if (!strcmp(hreq->version, "1.0"))
1170 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1171 if (v && !strcmp(v, "Keep-Alive"))
1175 hres->version = "1.0";
1179 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1180 if (v && !strcmp(v, "close"))
1184 hres->version = "1.1";
1188 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1189 assoc->state = ASSOC_DEAD;
1194 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1196 if (alive && isdigit(*alive))
1200 if (t < 0 || t > 3600)
1202 iochan_settimeout(assoc->client_chan,t);
1203 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1205 process_gdu_response(assoc, req, p);
1208 static void process_gdu_request(association *assoc, request *req)
1210 if (req->gdu_request->which == Z_GDU_Z3950)
1213 req->apdu_request = req->gdu_request->u.z3950;
1214 if (process_z_request(assoc, req, &msg) < 0)
1215 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1217 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1218 process_http_request(assoc, req);
1221 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1226 * Initiate request processing.
1228 static int process_z_request(association *assoc, request *req, char **msg)
1234 *msg = "Unknown Error";
1235 assert(req && req->state == REQUEST_IDLE);
1236 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1238 *msg = "Missing InitRequest";
1241 switch (req->apdu_request->which)
1243 case Z_APDU_initRequest:
1244 iochan_settimeout(assoc->client_chan,
1245 statserv_getcontrol()->idle_timeout * 60);
1246 res = process_initRequest(assoc, req); break;
1247 case Z_APDU_searchRequest:
1248 res = process_searchRequest(assoc, req, &fd); break;
1249 case Z_APDU_presentRequest:
1250 res = process_presentRequest(assoc, req, &fd); break;
1251 case Z_APDU_scanRequest:
1252 if (assoc->init->bend_scan)
1253 res = process_scanRequest(assoc, req, &fd);
1256 *msg = "Cannot handle Scan APDU";
1260 case Z_APDU_extendedServicesRequest:
1261 if (assoc->init->bend_esrequest)
1262 res = process_ESRequest(assoc, req, &fd);
1265 *msg = "Cannot handle Extended Services APDU";
1269 case Z_APDU_sortRequest:
1270 if (assoc->init->bend_sort)
1271 res = process_sortRequest(assoc, req, &fd);
1274 *msg = "Cannot handle Sort APDU";
1279 process_close(assoc, req);
1281 case Z_APDU_deleteResultSetRequest:
1282 if (assoc->init->bend_delete)
1283 res = process_deleteRequest(assoc, req, &fd);
1286 *msg = "Cannot handle Delete APDU";
1290 case Z_APDU_segmentRequest:
1291 if (assoc->init->bend_segment)
1293 res = process_segmentRequest (assoc, req);
1297 *msg = "Cannot handle Segment APDU";
1302 *msg = "Bad APDU received";
1307 yaz_log(LOG_DEBUG, " result immediately available");
1308 retval = process_z_response(assoc, req, res);
1312 yaz_log(LOG_DEBUG, " result unavailble");
1315 else /* no result yet - one will be provided later */
1319 /* Set up an I/O handler for the fd supplied by the backend */
1321 yaz_log(LOG_DEBUG, " establishing handler for result");
1322 req->state = REQUEST_PENDING;
1323 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1325 iochan_setdata(chan, assoc);
1332 * Handle message from the backend.
1334 void backend_response(IOCHAN i, int event)
1336 association *assoc = (association *)iochan_getdata(i);
1337 request *req = request_head(&assoc->incoming);
1341 yaz_log(LOG_DEBUG, "backend_response");
1342 assert(assoc && req && req->state != REQUEST_IDLE);
1343 /* determine what it is we're waiting for */
1344 switch (req->apdu_request->which)
1346 case Z_APDU_searchRequest:
1347 res = response_searchRequest(assoc, req, 0, &fd); break;
1349 case Z_APDU_presentRequest:
1350 res = response_presentRequest(assoc, req, 0, &fd); break;
1351 case Z_APDU_scanRequest:
1352 res = response_scanRequest(assoc, req, 0, &fd); break;
1355 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1358 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1360 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1361 do_close(assoc, Z_Close_systemProblem, 0);
1365 else if (!res) /* no result yet - try again later */
1367 yaz_log(LOG_DEBUG, " no result yet");
1368 iochan_setfd(i, fd); /* in case fd has changed */
1373 * Encode response, and transfer the request structure to the outgoing queue.
1375 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1377 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1379 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1381 yaz_log(LOG_WARN, "ODR print error: %s",
1382 odr_errmsg(odr_geterror(assoc->print)));
1383 odr_reset(assoc->print);
1385 if (!z_GDU(assoc->encode, &res, 0, 0))
1387 yaz_log(LOG_WARN, "ODR error when decoding PDU: %s [element %s]",
1388 odr_errmsg(odr_geterror(assoc->decode)),
1389 odr_getelement(assoc->decode));
1392 req->response = odr_getbuf(assoc->encode, &req->len_response,
1393 &req->size_response);
1394 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1395 odr_reset(assoc->encode);
1396 req->state = REQUEST_IDLE;
1397 request_enq(&assoc->outgoing, req);
1398 /* turn the work over to the ir_session handler */
1399 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1400 assoc->cs_put_mask = EVENT_OUTPUT;
1401 /* Is there more work to be done? give that to the input handler too */
1403 if (request_head(&assoc->incoming))
1405 yaz_log (LOG_DEBUG, "more work to be done");
1406 iochan_setevent(assoc->client_chan, EVENT_WORK);
1413 * Encode response, and transfer the request structure to the outgoing queue.
1415 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1417 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1418 gres->which = Z_GDU_Z3950;
1419 gres->u.z3950 = res;
1421 return process_gdu_response(assoc, req, gres);
1426 * Handle init request.
1427 * At the moment, we don't check the options
1428 * anywhere else in the code - we just try not to do anything that would
1429 * break a naive client. We'll toss 'em into the association block when
1430 * we need them there.
1432 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1434 statserv_options_block *cb = statserv_getcontrol();
1435 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1436 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1437 Z_InitResponse *resp = apdu->u.initResponse;
1438 bend_initresult *binitres;
1442 yaz_log(LOG_LOG, "Got initRequest");
1443 if (req->implementationId)
1444 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1445 if (req->implementationName)
1446 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1447 if (req->implementationVersion)
1448 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1450 assoc_init_reset(assoc);
1452 assoc->init->auth = req->idAuthentication;
1453 assoc->init->referenceId = req->referenceId;
1455 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1457 Z_CharSetandLanguageNegotiation *negotiation =
1458 yaz_get_charneg_record (req->otherInfo);
1459 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1460 assoc->init->charneg_request = negotiation;
1463 if (!(binitres = (*cb->bend_init)(assoc->init)))
1465 yaz_log(LOG_WARN, "Bad response from backend.");
1469 assoc->backend = binitres->handle;
1470 if ((assoc->init->bend_sort))
1471 yaz_log (LOG_DEBUG, "Sort handler installed");
1472 if ((assoc->init->bend_search))
1473 yaz_log (LOG_DEBUG, "Search handler installed");
1474 if ((assoc->init->bend_present))
1475 yaz_log (LOG_DEBUG, "Present handler installed");
1476 if ((assoc->init->bend_esrequest))
1477 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1478 if ((assoc->init->bend_delete))
1479 yaz_log (LOG_DEBUG, "Delete handler installed");
1480 if ((assoc->init->bend_scan))
1481 yaz_log (LOG_DEBUG, "Scan handler installed");
1482 if ((assoc->init->bend_segment))
1483 yaz_log (LOG_DEBUG, "Segment handler installed");
1485 resp->referenceId = req->referenceId;
1487 /* let's tell the client what we can do */
1488 if (ODR_MASK_GET(req->options, Z_Options_search))
1490 ODR_MASK_SET(resp->options, Z_Options_search);
1491 strcat(options, "srch");
1493 if (ODR_MASK_GET(req->options, Z_Options_present))
1495 ODR_MASK_SET(resp->options, Z_Options_present);
1496 strcat(options, " prst");
1498 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1499 assoc->init->bend_delete)
1501 ODR_MASK_SET(resp->options, Z_Options_delSet);
1502 strcat(options, " del");
1504 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1505 assoc->init->bend_esrequest)
1507 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1508 strcat (options, " extendedServices");
1510 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1512 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1513 strcat(options, " namedresults");
1515 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1517 ODR_MASK_SET(resp->options, Z_Options_scan);
1518 strcat(options, " scan");
1520 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1522 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1523 strcat(options, " concurrop");
1525 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1527 ODR_MASK_SET(resp->options, Z_Options_sort);
1528 strcat(options, " sort");
1531 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1532 && assoc->init->charneg_response)
1534 Z_OtherInformation **p;
1535 Z_OtherInformationUnit *p0;
1537 yaz_oi_APDU(apdu, &p);
1539 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1540 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1542 p0->which = Z_OtherInfo_externallyDefinedInfo;
1543 p0->information.externallyDefinedInfo =
1544 assoc->init->charneg_response;
1546 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1547 strcat(options, " negotiation");
1550 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1552 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1553 assoc->version = 2; /* 1 & 2 are equivalent */
1555 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1557 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1560 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1562 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1566 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1567 assoc->maximumRecordSize = *req->maximumRecordSize;
1568 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1569 assoc->maximumRecordSize = control_block->maxrecordsize;
1570 assoc->preferredMessageSize = *req->preferredMessageSize;
1571 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1572 assoc->preferredMessageSize = assoc->maximumRecordSize;
1574 resp->preferredMessageSize = &assoc->preferredMessageSize;
1575 resp->maximumRecordSize = &assoc->maximumRecordSize;
1577 resp->implementationName = "GFS/YAZ";
1579 if (assoc->init->implementation_id)
1582 odr_malloc (assoc->encode,
1583 strlen(assoc->init->implementation_id) + 10 +
1584 strlen(resp->implementationId));
1585 sprintf (nv, "%s / %s",
1586 resp->implementationId, assoc->init->implementation_id);
1587 resp->implementationId = nv;
1589 if (assoc->init->implementation_name)
1592 odr_malloc (assoc->encode,
1593 strlen(assoc->init->implementation_name) + 10 +
1594 strlen(resp->implementationName));
1595 sprintf (nv, "%s / %s",
1596 resp->implementationName, assoc->init->implementation_name);
1597 resp->implementationName = nv;
1599 if (assoc->init->implementation_version)
1602 odr_malloc (assoc->encode,
1603 strlen(assoc->init->implementation_version) + 10 +
1604 strlen(resp->implementationVersion));
1605 sprintf (nv, "YAZ %s / %s",
1606 resp->implementationVersion,
1607 assoc->init->implementation_version);
1608 resp->implementationVersion = nv;
1611 if (binitres->errcode)
1613 yaz_log(LOG_LOG, "Connection rejected by backend.");
1615 assoc->state = ASSOC_DEAD;
1616 resp->userInformationField = init_diagnostics(assoc->encode,
1618 binitres->errstring);
1621 assoc->state = ASSOC_UP;
1626 * Diagnostic in default format, to be returned as either a surrogate
1627 * or non-surrogate diagnostic in the context of an open session, or
1628 * as User-information when an Init is refused.
1630 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1632 int *err = odr_intdup(odr, error);
1633 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1634 odr_malloc (odr, sizeof(*dr));
1636 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1637 addinfo ? " -- " : "", addinfo ? addinfo : "");
1639 dr->diagnosticSetId =
1640 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1641 dr->condition = err;
1642 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1643 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1648 * Set the specified `errcode' and `errstring' into a UserInfo-1
1649 * external to be returned to the client in accordance with Z35.90
1650 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1651 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1653 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1657 Z_OtherInformation *u;
1658 Z_OtherInformationUnit *l;
1659 Z_DiagnosticFormat *d;
1660 Z_DiagnosticFormat_s *e;
1662 x = (Z_External*) odr_malloc(odr, sizeof *x);
1664 x->indirect_reference = 0;
1665 oid.proto = PROTO_Z3950;
1666 oid.oclass = CLASS_USERINFO;
1667 oid.value = VAL_USERINFO1;
1668 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1669 x->which = Z_External_userInfo1;
1671 u = odr_malloc(odr, sizeof *u);
1673 u->num_elements = 1;
1674 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1675 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1678 l->which = Z_OtherInfo_externallyDefinedInfo;
1680 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1681 l->information.externallyDefinedInfo = x2;
1683 x2->indirect_reference = 0;
1684 oid.oclass = CLASS_DIAGSET;
1685 oid.value = VAL_DIAG1;
1686 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1687 x2->which = Z_External_diag1;
1689 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1692 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1693 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1696 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1697 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1702 * nonsurrogate diagnostic record.
1704 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1706 Z_Records *rec = (Z_Records *)
1707 odr_malloc (assoc->encode, sizeof(*rec));
1708 rec->which = Z_Records_NSD;
1709 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1714 * surrogate diagnostic.
1716 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1717 int error, char *addinfo)
1719 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1720 odr_malloc (assoc->encode, sizeof(*rec));
1721 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1723 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1724 rec->databaseName = dbname;
1725 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1726 rec->u.surrogateDiagnostic = drec;
1727 drec->which = Z_DiagRec_defaultFormat;
1728 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1734 * multiple nonsurrogate diagnostics.
1736 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1738 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1739 int *err = odr_intdup(assoc->encode, error);
1740 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1741 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1742 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1743 odr_malloc (assoc->encode, sizeof(*rec));
1745 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1747 recs->num_diagRecs = 1;
1748 recs->diagRecs = recp;
1750 drec->which = Z_DiagRec_defaultFormat;
1751 drec->u.defaultFormat = rec;
1753 rec->diagnosticSetId =
1754 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1755 rec->condition = err;
1757 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1758 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1762 static Z_Records *pack_records(association *a, char *setname, int start,
1763 int *num, Z_RecordComposition *comp,
1764 int *next, int *pres, oid_value format,
1765 Z_ReferenceId *referenceId,
1768 int recno, total_length = 0, toget = *num, dumped_records = 0;
1769 Z_Records *records =
1770 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1771 Z_NamePlusRecordList *reclist =
1772 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1773 Z_NamePlusRecord **list =
1774 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1776 records->which = Z_Records_DBOSD;
1777 records->u.databaseOrSurDiagnostics = reclist;
1778 reclist->num_records = 0;
1779 reclist->records = list;
1780 *pres = Z_PRES_SUCCESS;
1784 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1785 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1786 a->maximumRecordSize);
1787 for (recno = start; reclist->num_records < toget; recno++)
1790 Z_NamePlusRecord *thisrec;
1791 int this_length = 0;
1793 * we get the number of bytes allocated on the stream before any
1794 * allocation done by the backend - this should give us a reasonable
1795 * idea of the total size of the data so far.
1797 total_length = odr_total(a->encode) - dumped_records;
1803 freq.last_in_set = 0;
1804 freq.setname = setname;
1805 freq.surrogate_flag = 0;
1806 freq.number = recno;
1808 freq.request_format = format;
1809 freq.request_format_raw = oid;
1810 freq.output_format = format;
1811 freq.output_format_raw = 0;
1812 freq.stream = a->encode;
1813 freq.print = a->print;
1814 freq.referenceId = referenceId;
1816 (*a->init->bend_fetch)(a->backend, &freq);
1817 /* backend should be able to signal whether error is system-wide
1818 or only pertaining to current record */
1821 if (!freq.surrogate_flag)
1824 *pres = Z_PRES_FAILURE;
1825 /* for 'present request out of range',
1826 set addinfo to record position if not set */
1827 if (freq.errcode == 13 && freq.errstring == 0)
1829 sprintf (s, "%d", recno);
1832 return diagrec(a, freq.errcode, freq.errstring);
1834 reclist->records[reclist->num_records] =
1835 surrogatediagrec(a, freq.basename, freq.errcode,
1837 reclist->num_records++;
1838 *next = freq.last_in_set ? 0 : recno + 1;
1842 this_length = freq.len;
1844 this_length = odr_total(a->encode) - total_length;
1845 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1846 this_length, total_length);
1847 if (this_length + total_length > a->preferredMessageSize)
1849 /* record is small enough, really */
1850 if (this_length <= a->preferredMessageSize)
1852 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1853 *pres = Z_PRES_PARTIAL_2;
1856 /* record can only be fetched by itself */
1857 if (this_length < a->maximumRecordSize)
1859 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1862 yaz_log(LOG_DEBUG, " Dropped it");
1863 reclist->records[reclist->num_records] =
1864 surrogatediagrec(a, freq.basename, 16, 0);
1865 reclist->num_records++;
1866 *next = freq.last_in_set ? 0 : recno + 1;
1867 dumped_records += this_length;
1871 else /* too big entirely */
1873 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1874 reclist->records[reclist->num_records] =
1875 surrogatediagrec(a, freq.basename, 17, 0);
1876 reclist->num_records++;
1877 *next = freq.last_in_set ? 0 : recno + 1;
1878 dumped_records += this_length;
1883 if (!(thisrec = (Z_NamePlusRecord *)
1884 odr_malloc(a->encode, sizeof(*thisrec))))
1886 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1887 strlen(freq.basename) + 1)))
1889 strcpy(thisrec->databaseName, freq.basename);
1890 thisrec->which = Z_NamePlusRecord_databaseRecord;
1892 if (freq.output_format_raw)
1894 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1895 freq.output_format = ident->value;
1897 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1898 freq.record, freq.len);
1899 if (!thisrec->u.databaseRecord)
1901 reclist->records[reclist->num_records] = thisrec;
1902 reclist->num_records++;
1903 *next = freq.last_in_set ? 0 : recno + 1;
1905 *num = reclist->num_records;
1909 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1912 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1913 bend_search_rr *bsrr =
1914 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1916 yaz_log(LOG_LOG, "Got SearchRequest.");
1918 bsrr->request = reqb;
1919 bsrr->association = assoc;
1920 bsrr->referenceId = req->referenceId;
1921 save_referenceId (reqb, bsrr->referenceId);
1923 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1924 if (req->databaseNames)
1927 for (i = 0; i < req->num_databaseNames; i++)
1928 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1930 yaz_log_zquery(req->query);
1932 if (assoc->init->bend_search)
1934 bsrr->setname = req->resultSetName;
1935 bsrr->replace_set = *req->replaceIndicator;
1936 bsrr->num_bases = req->num_databaseNames;
1937 bsrr->basenames = req->databaseNames;
1938 bsrr->query = req->query;
1939 bsrr->stream = assoc->encode;
1940 bsrr->decode = assoc->decode;
1941 bsrr->print = assoc->print;
1944 bsrr->errstring = NULL;
1945 bsrr->search_info = NULL;
1946 (assoc->init->bend_search)(assoc->backend, bsrr);
1950 return response_searchRequest(assoc, reqb, bsrr, fd);
1953 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1956 * Prepare a searchresponse based on the backend results. We probably want
1957 * to look at making the fetching of records nonblocking as well, but
1958 * so far, we'll keep things simple.
1959 * If bsrt is null, that means we're called in response to a communications
1960 * event, and we'll have to get the response for ourselves.
1962 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1963 bend_search_rr *bsrt, int *fd)
1965 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1966 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1967 Z_SearchResponse *resp = (Z_SearchResponse *)
1968 odr_malloc (assoc->encode, sizeof(*resp));
1969 int *nulint = odr_intdup (assoc->encode, 0);
1970 bool_t *sr = odr_intdup(assoc->encode, 1);
1971 int *next = odr_intdup(assoc->encode, 0);
1972 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1974 apdu->which = Z_APDU_searchResponse;
1975 apdu->u.searchResponse = resp;
1976 resp->referenceId = req->referenceId;
1977 resp->additionalSearchInfo = 0;
1978 resp->otherInfo = 0;
1980 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1982 yaz_log(LOG_FATAL, "Bad result from backend");
1985 else if (bsrt->errcode)
1987 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1988 resp->resultCount = nulint;
1989 resp->numberOfRecordsReturned = nulint;
1990 resp->nextResultSetPosition = nulint;
1991 resp->searchStatus = nulint;
1992 resp->resultSetStatus = none;
1993 resp->presentStatus = 0;
1997 int *toget = odr_intdup(assoc->encode, 0);
1998 int *presst = odr_intdup(assoc->encode, 0);
1999 Z_RecordComposition comp, *compp = 0;
2001 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
2004 resp->resultCount = &bsrt->hits;
2006 comp.which = Z_RecordComp_simple;
2007 /* how many records does the user agent want, then? */
2008 if (bsrt->hits <= *req->smallSetUpperBound)
2010 *toget = bsrt->hits;
2011 if ((comp.u.simple = req->smallSetElementSetNames))
2014 else if (bsrt->hits < *req->largeSetLowerBound)
2016 *toget = *req->mediumSetPresentNumber;
2017 if (*toget > bsrt->hits)
2018 *toget = bsrt->hits;
2019 if ((comp.u.simple = req->mediumSetElementSetNames))
2025 if (*toget && !resp->records)
2030 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2033 form = prefformat->value;
2034 resp->records = pack_records(assoc, req->resultSetName, 1,
2035 toget, compp, next, presst, form, req->referenceId,
2036 req->preferredRecordSyntax);
2039 resp->numberOfRecordsReturned = toget;
2040 resp->nextResultSetPosition = next;
2041 resp->searchStatus = sr;
2042 resp->resultSetStatus = 0;
2043 resp->presentStatus = presst;
2047 if (*resp->resultCount)
2049 resp->numberOfRecordsReturned = nulint;
2050 resp->nextResultSetPosition = next;
2051 resp->searchStatus = sr;
2052 resp->resultSetStatus = 0;
2053 resp->presentStatus = 0;
2056 resp->additionalSearchInfo = bsrt->search_info;
2061 * Maybe we got a little over-friendly when we designed bend_fetch to
2062 * get only one record at a time. Some backends can optimise multiple-record
2063 * fetches, and at any rate, there is some overhead involved in
2064 * all that selecting and hopping around. Problem is, of course, that the
2065 * frontend can't know ahead of time how many records it'll need to
2066 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2067 * is downright lousy as a bulk data transfer protocol.
2069 * To start with, we'll do the fetching of records from the backend
2070 * in one operation: To save some trips in and out of the event-handler,
2071 * and to simplify the interface to pack_records. At any rate, asynch
2072 * operation is more fun in operations that have an unpredictable execution
2073 * speed - which is normally more true for search than for present.
2075 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2078 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2082 Z_PresentResponse *resp;
2086 yaz_log(LOG_LOG, "Got PresentRequest.");
2088 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2091 form = prefformat->value;
2092 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2094 resp->presentStatus = odr_intdup(assoc->encode, 0);
2095 if (assoc->init->bend_present)
2097 bend_present_rr *bprr = (bend_present_rr *)
2098 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2099 bprr->setname = req->resultSetId;
2100 bprr->start = *req->resultSetStartPoint;
2101 bprr->number = *req->numberOfRecordsRequested;
2102 bprr->format = form;
2103 bprr->comp = req->recordComposition;
2104 bprr->referenceId = req->referenceId;
2105 bprr->stream = assoc->encode;
2106 bprr->print = assoc->print;
2107 bprr->request = reqb;
2108 bprr->association = assoc;
2110 bprr->errstring = NULL;
2111 (*assoc->init->bend_present)(assoc->backend, bprr);
2117 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2118 *resp->presentStatus = Z_PRES_FAILURE;
2121 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2122 next = odr_intdup(assoc->encode, 0);
2123 num = odr_intdup(assoc->encode, 0);
2125 apdu->which = Z_APDU_presentResponse;
2126 apdu->u.presentResponse = resp;
2127 resp->referenceId = req->referenceId;
2128 resp->otherInfo = 0;
2132 *num = *req->numberOfRecordsRequested;
2134 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2135 num, req->recordComposition, next, resp->presentStatus,
2136 form, req->referenceId, req->preferredRecordSyntax);
2140 resp->numberOfRecordsReturned = num;
2141 resp->nextResultSetPosition = next;
2147 * Scan was implemented rather in a hurry, and with support for only the basic
2148 * elements of the service in the backend API. Suggestions are welcome.
2150 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2152 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2153 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2154 Z_ScanResponse *res = (Z_ScanResponse *)
2155 odr_malloc (assoc->encode, sizeof(*res));
2156 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2157 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2158 Z_ListEntries *ents = (Z_ListEntries *)
2159 odr_malloc (assoc->encode, sizeof(*ents));
2160 Z_DiagRecs *diagrecs_p = NULL;
2162 bend_scan_rr *bsrr = (bend_scan_rr *)
2163 odr_malloc (assoc->encode, sizeof(*bsrr));
2164 struct scan_entry *save_entries;
2166 yaz_log(LOG_LOG, "Got ScanRequest");
2168 apdu->which = Z_APDU_scanResponse;
2169 apdu->u.scanResponse = res;
2170 res->referenceId = req->referenceId;
2172 /* if step is absent, set it to 0 */
2173 res->stepSize = odr_intdup(assoc->encode, 0);
2175 *res->stepSize = *req->stepSize;
2177 res->scanStatus = scanStatus;
2178 res->numberOfEntriesReturned = numberOfEntriesReturned;
2179 res->positionOfTerm = 0;
2180 res->entries = ents;
2181 ents->num_entries = 0;
2182 ents->entries = NULL;
2183 ents->num_nonsurrogateDiagnostics = 0;
2184 ents->nonsurrogateDiagnostics = NULL;
2185 res->attributeSet = 0;
2188 if (req->databaseNames)
2191 for (i = 0; i < req->num_databaseNames; i++)
2192 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2194 bsrr->num_bases = req->num_databaseNames;
2195 bsrr->basenames = req->databaseNames;
2196 bsrr->num_entries = *req->numberOfTermsRequested;
2197 bsrr->term = req->termListAndStartPoint;
2198 bsrr->referenceId = req->referenceId;
2199 bsrr->stream = assoc->encode;
2200 bsrr->print = assoc->print;
2201 bsrr->step_size = res->stepSize;
2203 /* Note that version 2.0 of YAZ and older did not set entries ..
2204 We do now. And when we do it's easier to extend the scan entry
2205 We know that if the scan handler did set entries, it will
2206 not know of new member display_term.
2208 if (bsrr->num_entries > 0)
2211 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2213 for (i = 0; i<bsrr->num_entries; i++)
2215 bsrr->entries[i].term = 0;
2216 bsrr->entries[i].occurrences = 0;
2217 bsrr->entries[i].errcode = 0;
2218 bsrr->entries[i].errstring = 0;
2219 bsrr->entries[i].display_term = 0;
2222 save_entries = bsrr->entries; /* save it so we can compare later */
2224 if (req->attributeSet &&
2225 (attset = oid_getentbyoid(req->attributeSet)) &&
2226 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2227 bsrr->attributeset = attset->value;
2229 bsrr->attributeset = VAL_NONE;
2230 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2231 bsrr->term_position = req->preferredPositionInResponse ?
2232 *req->preferredPositionInResponse : 1;
2233 ((int (*)(void *, bend_scan_rr *))
2234 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2236 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2240 Z_Entry **tab = (Z_Entry **)
2241 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2243 if (bsrr->status == BEND_SCAN_PARTIAL)
2244 *scanStatus = Z_Scan_partial_5;
2246 *scanStatus = Z_Scan_success;
2247 ents->entries = tab;
2248 ents->num_entries = bsrr->num_entries;
2249 res->numberOfEntriesReturned = &ents->num_entries;
2250 res->positionOfTerm = &bsrr->term_position;
2251 for (i = 0; i < bsrr->num_entries; i++)
2257 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2258 if (bsrr->entries[i].occurrences >= 0)
2260 e->which = Z_Entry_termInfo;
2261 e->u.termInfo = t = (Z_TermInfo *)
2262 odr_malloc(assoc->encode, sizeof(*t));
2263 t->suggestedAttributes = 0;
2265 if (save_entries == bsrr->entries &&
2266 bsrr->entries[i].display_term)
2268 /* the entries was NOT set by the handler. So it's
2269 safe to test for new member display_term. It is
2272 t->displayTerm = odr_strdup(assoc->encode,
2273 bsrr->entries[i].display_term);
2275 t->alternativeTerm = 0;
2276 t->byAttributes = 0;
2277 t->otherTermInfo = 0;
2278 t->globalOccurrences = &bsrr->entries[i].occurrences;
2279 t->term = (Z_Term *)
2280 odr_malloc(assoc->encode, sizeof(*t->term));
2281 t->term->which = Z_Term_general;
2282 t->term->u.general = o =
2283 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2284 o->buf = (unsigned char *)
2285 odr_malloc(assoc->encode, o->len = o->size =
2286 strlen(bsrr->entries[i].term));
2287 memcpy(o->buf, bsrr->entries[i].term, o->len);
2288 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2289 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2293 Z_DiagRecs *drecs = diagrecs (assoc,
2294 bsrr->entries[i].errcode,
2295 bsrr->entries[i].errstring);
2296 assert (drecs->num_diagRecs == 1);
2297 e->which = Z_Entry_surrogateDiagnostic;
2298 assert (drecs->diagRecs[0]);
2299 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2305 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2306 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2311 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2314 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2315 Z_SortResponse *res = (Z_SortResponse *)
2316 odr_malloc (assoc->encode, sizeof(*res));
2317 bend_sort_rr *bsrr = (bend_sort_rr *)
2318 odr_malloc (assoc->encode, sizeof(*bsrr));
2320 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2322 yaz_log(LOG_LOG, "Got SortRequest.");
2324 bsrr->num_input_setnames = req->num_inputResultSetNames;
2325 bsrr->input_setnames = req->inputResultSetNames;
2326 bsrr->referenceId = req->referenceId;
2327 bsrr->output_setname = req->sortedResultSetName;
2328 bsrr->sort_sequence = req->sortSequence;
2329 bsrr->stream = assoc->encode;
2330 bsrr->print = assoc->print;
2332 bsrr->sort_status = Z_SortStatus_failure;
2334 bsrr->errstring = 0;
2336 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2338 res->referenceId = bsrr->referenceId;
2339 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2340 res->resultSetStatus = 0;
2343 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2344 res->diagnostics = dr->diagRecs;
2345 res->num_diagnostics = dr->num_diagRecs;
2349 res->num_diagnostics = 0;
2350 res->diagnostics = 0;
2352 res->resultCount = 0;
2355 apdu->which = Z_APDU_sortResponse;
2356 apdu->u.sortResponse = res;
2360 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2363 Z_DeleteResultSetRequest *req =
2364 reqb->apdu_request->u.deleteResultSetRequest;
2365 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2366 odr_malloc (assoc->encode, sizeof(*res));
2367 bend_delete_rr *bdrr = (bend_delete_rr *)
2368 odr_malloc (assoc->encode, sizeof(*bdrr));
2369 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2371 yaz_log(LOG_LOG, "Got DeleteRequest.");
2373 bdrr->num_setnames = req->num_resultSetList;
2374 bdrr->setnames = req->resultSetList;
2375 bdrr->stream = assoc->encode;
2376 bdrr->print = assoc->print;
2377 bdrr->function = *req->deleteFunction;
2378 bdrr->referenceId = req->referenceId;
2380 if (bdrr->num_setnames > 0)
2383 bdrr->statuses = (int*)
2384 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2385 bdrr->num_setnames);
2386 for (i = 0; i < bdrr->num_setnames; i++)
2387 bdrr->statuses[i] = 0;
2389 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2391 res->referenceId = req->referenceId;
2393 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2395 res->deleteListStatuses = 0;
2396 if (bdrr->num_setnames > 0)
2399 res->deleteListStatuses = (Z_ListStatuses *)
2400 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2401 res->deleteListStatuses->num = bdrr->num_setnames;
2402 res->deleteListStatuses->elements =
2404 odr_malloc (assoc->encode,
2405 sizeof(*res->deleteListStatuses->elements) *
2406 bdrr->num_setnames);
2407 for (i = 0; i<bdrr->num_setnames; i++)
2409 res->deleteListStatuses->elements[i] =
2411 odr_malloc (assoc->encode,
2412 sizeof(**res->deleteListStatuses->elements));
2413 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2414 res->deleteListStatuses->elements[i]->id =
2415 odr_strdup (assoc->encode, bdrr->setnames[i]);
2419 res->numberNotDeleted = 0;
2420 res->bulkStatuses = 0;
2421 res->deleteMessage = 0;
2424 apdu->which = Z_APDU_deleteResultSetResponse;
2425 apdu->u.deleteResultSetResponse = res;
2429 static void process_close(association *assoc, request *reqb)
2431 Z_Close *req = reqb->apdu_request->u.close;
2432 static char *reasons[] =
2439 "securityViolation",
2446 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2447 reasons[*req->closeReason], req->diagnosticInformation ?
2448 req->diagnosticInformation : "NULL");
2449 if (assoc->version < 3) /* to make do_force respond with close */
2451 do_close_req(assoc, Z_Close_finished,
2452 "Association terminated by client", reqb);
2455 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2459 reqb->len_refid = refid->len;
2460 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2461 memcpy (reqb->refid, refid->buf, refid->len);
2465 reqb->len_refid = 0;
2470 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2472 process_z_response (a, req, res);
2475 bend_request bend_request_mk (bend_association a)
2477 request *nreq = request_get (&a->outgoing);
2478 nreq->request_mem = nmem_create ();
2482 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2487 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2488 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2489 id->len = id->size = req->len_refid;
2490 memcpy (id->buf, req->refid, req->len_refid);
2494 void bend_request_destroy (bend_request *req)
2496 nmem_destroy((*req)->request_mem);
2497 request_release(*req);
2501 int bend_backend_respond (bend_association a, bend_request req)
2505 r = process_z_request (a, req, &msg);
2507 yaz_log (LOG_WARN, "%s", msg);
2511 void bend_request_setdata(bend_request r, void *p)
2516 void *bend_request_getdata(bend_request r)
2518 return r->clientData;
2521 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2523 bend_segment_rr req;
2525 req.segment = reqb->apdu_request->u.segmentRequest;
2526 req.stream = assoc->encode;
2527 req.decode = assoc->decode;
2528 req.print = assoc->print;
2529 req.association = assoc;
2531 (*assoc->init->bend_segment)(assoc->backend, &req);
2536 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2538 bend_esrequest_rr esrequest;
2540 Z_ExtendedServicesRequest *req =
2541 reqb->apdu_request->u.extendedServicesRequest;
2542 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2544 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2546 yaz_log(LOG_DEBUG,"inside Process esRequest");
2548 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2549 esrequest.stream = assoc->encode;
2550 esrequest.decode = assoc->decode;
2551 esrequest.print = assoc->print;
2552 esrequest.errcode = 0;
2553 esrequest.errstring = NULL;
2554 esrequest.request = reqb;
2555 esrequest.association = assoc;
2556 esrequest.taskPackage = 0;
2557 esrequest.referenceId = req->referenceId;
2559 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2561 /* If the response is being delayed, return NULL */
2562 if (esrequest.request == NULL)
2565 resp->referenceId = req->referenceId;
2567 if (esrequest.errcode == -1)
2569 /* Backend service indicates request will be processed */
2570 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2571 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2573 else if (esrequest.errcode == 0)
2575 /* Backend service indicates request will be processed */
2576 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2577 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2581 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2582 esrequest.errstring);
2584 /* Backend indicates error, request will not be processed */
2585 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2586 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2587 resp->num_diagnostics = diagRecs->num_diagRecs;
2588 resp->diagnostics = diagRecs->diagRecs;
2590 /* Do something with the members of bend_extendedservice */
2591 if (esrequest.taskPackage)
2592 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2593 (const char *) esrequest.taskPackage,
2595 yaz_log(LOG_DEBUG,"Send the result apdu");