2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.2 2003-11-17 21:32:58 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();
175 odr_destroy(h->decode);
176 odr_destroy(h->encode);
178 odr_destroy(h->print);
180 xfree(h->input_buffer);
182 (*cb->bend_close)(h->backend);
183 while ((req = request_deq(&h->incoming)))
184 request_release(req);
185 while ((req = request_deq(&h->outgoing)))
186 request_release(req);
187 request_delq(&h->incoming);
188 request_delq(&h->outgoing);
190 xmalloc_trav("session closed");
191 if (control_block && control_block->one_shot)
197 static void do_close_req(association *a, int reason, char *message,
201 Z_Close *cls = zget_Close(a->encode);
203 /* Purge request queue */
204 while (request_deq(&a->incoming));
205 while (request_deq(&a->outgoing));
208 yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
209 reason, message ? message : "none");
210 apdu.which = Z_APDU_close;
212 *cls->closeReason = reason;
213 cls->diagnosticInformation = message;
214 process_z_response(a, req, &apdu);
215 iochan_settimeout(a->client_chan, 20);
219 request_release(req);
220 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
221 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
223 a->state = ASSOC_DEAD;
226 static void do_close(association *a, int reason, char *message)
228 request *req = request_get(&a->outgoing);
229 do_close_req (a, reason, message, req);
233 * This is where PDUs from the client are read and the further
234 * processing is initiated. Flow of control moves down through the
235 * various process_* functions below, until the encoded result comes back up
236 * to the output handler in here.
238 * h : the I/O channel that has an outstanding event.
239 * event : the current outstanding event.
241 void ir_session(IOCHAN h, int event)
244 association *assoc = (association *)iochan_getdata(h);
245 COMSTACK conn = assoc->client_link;
248 assert(h && conn && assoc);
249 if (event == EVENT_TIMEOUT)
251 if (assoc->state != ASSOC_UP)
253 yaz_log(LOG_LOG, "Final timeout - closing connection.");
255 destroy_association(assoc);
260 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
261 do_close(assoc, Z_Close_lackOfActivity, 0);
265 if (event & assoc->cs_accept_mask)
267 yaz_log (LOG_DEBUG, "ir_session (accept)");
268 if (!cs_accept (conn))
270 yaz_log (LOG_LOG, "accept failed");
271 destroy_association(assoc);
274 iochan_clearflag (h, EVENT_OUTPUT|EVENT_OUTPUT);
275 if (conn->io_pending)
276 { /* cs_accept didn't complete */
277 assoc->cs_accept_mask =
278 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
279 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
281 iochan_setflag (h, assoc->cs_accept_mask);
284 { /* cs_accept completed. Prepare for reading (cs_get) */
285 assoc->cs_accept_mask = 0;
286 assoc->cs_get_mask = EVENT_INPUT;
287 iochan_setflag (h, assoc->cs_get_mask);
291 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
293 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
295 yaz_log(LOG_DEBUG, "ir_session (input)");
296 /* We aren't speaking to this fellow */
297 if (assoc->state == ASSOC_DEAD)
299 yaz_log(LOG_LOG, "Connection closed - end of session");
301 destroy_association(assoc);
305 assoc->cs_get_mask = EVENT_INPUT;
306 if ((res = cs_get(conn, &assoc->input_buffer,
307 &assoc->input_buffer_len)) <= 0)
309 yaz_log(LOG_LOG, "Connection closed by client");
311 destroy_association(assoc);
315 else if (res == 1) /* incomplete read - wait for more */
317 if (conn->io_pending & CS_WANT_WRITE)
318 assoc->cs_get_mask |= EVENT_OUTPUT;
319 iochan_setflag(h, assoc->cs_get_mask);
322 if (cs_more(conn)) /* more stuff - call us again later, please */
323 iochan_setevent(h, EVENT_INPUT);
325 /* we got a complete PDU. Let's decode it */
326 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
327 assoc->input_buffer[0] & 0xff,
328 assoc->input_buffer[1] & 0xff,
329 assoc->input_buffer[2] & 0xff);
330 req = request_get(&assoc->incoming); /* get a new request */
331 odr_reset(assoc->decode);
332 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
333 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
335 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
337 odr_errmsg(odr_geterror(assoc->decode)),
338 odr_getelement(assoc->decode),
339 odr_offset(assoc->decode));
340 if (assoc->decode->error != OHTTP)
342 yaz_log(LOG_LOG, "PDU dump:");
343 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
344 request_release(req);
345 do_close(assoc, Z_Close_protocolError,"Malformed package");
349 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
350 assoc->state = ASSOC_DEAD;
351 process_gdu_response(assoc, req, p);
355 req->request_mem = odr_extract_mem(assoc->decode);
356 if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
358 yaz_log(LOG_WARN, "ODR print error: %s",
359 odr_errmsg(odr_geterror(assoc->print)));
360 odr_reset(assoc->print);
362 request_enq(&assoc->incoming, req);
365 /* can we do something yet? */
366 req = request_head(&assoc->incoming);
367 if (req->state == REQUEST_IDLE)
369 request_deq(&assoc->incoming);
370 process_gdu_request(assoc, req);
373 if (event & assoc->cs_put_mask)
375 request *req = request_head(&assoc->outgoing);
377 assoc->cs_put_mask = 0;
378 yaz_log(LOG_DEBUG, "ir_session (output)");
379 req->state = REQUEST_PENDING;
380 switch (res = cs_put(conn, req->response, req->len_response))
383 yaz_log(LOG_LOG, "Connection closed by client");
385 destroy_association(assoc);
388 case 0: /* all sent - release the request structure */
389 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
391 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
394 nmem_destroy(req->request_mem);
395 request_deq(&assoc->outgoing);
396 request_release(req);
397 if (!request_head(&assoc->outgoing))
398 { /* restore mask for cs_get operation ... */
399 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
400 iochan_setflag(h, assoc->cs_get_mask);
401 if (assoc->state == ASSOC_DEAD)
402 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
406 assoc->cs_put_mask = EVENT_OUTPUT;
410 if (conn->io_pending & CS_WANT_WRITE)
411 assoc->cs_put_mask |= EVENT_OUTPUT;
412 if (conn->io_pending & CS_WANT_READ)
413 assoc->cs_put_mask |= EVENT_INPUT;
414 iochan_setflag(h, assoc->cs_put_mask);
417 if (event & EVENT_EXCEPT)
419 yaz_log(LOG_LOG, "ir_session (exception)");
421 destroy_association(assoc);
426 static int process_z_request(association *assoc, request *req, char **msg);
428 static void assoc_init_reset(association *assoc)
431 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
433 assoc->init->stream = assoc->encode;
434 assoc->init->print = assoc->print;
435 assoc->init->auth = 0;
436 assoc->init->referenceId = 0;
437 assoc->init->implementation_version = 0;
438 assoc->init->implementation_id = 0;
439 assoc->init->implementation_name = 0;
440 assoc->init->bend_sort = NULL;
441 assoc->init->bend_search = NULL;
442 assoc->init->bend_present = NULL;
443 assoc->init->bend_esrequest = NULL;
444 assoc->init->bend_delete = NULL;
445 assoc->init->bend_scan = NULL;
446 assoc->init->bend_segment = NULL;
447 assoc->init->bend_fetch = NULL;
448 assoc->init->bend_explain = NULL;
450 assoc->init->charneg_request = NULL;
451 assoc->init->charneg_response = NULL;
453 assoc->init->decode = assoc->decode;
454 assoc->init->peer_name =
455 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
458 static int srw_bend_init(association *assoc)
460 const char *encoding = "UTF-8";
462 bend_initresult *binitres;
463 statserv_options_block *cb = statserv_getcontrol();
465 assoc_init_reset(assoc);
467 assoc->maximumRecordSize = 3000000;
468 assoc->preferredMessageSize = 3000000;
470 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
471 assoc->init->charneg_request = ce->u.charNeg3;
473 if (!(binitres = (*cb->bend_init)(assoc->init)))
475 yaz_log(LOG_WARN, "Bad response from backend.");
478 assoc->backend = binitres->handle;
482 static int srw_bend_fetch(association *assoc, int pos,
483 Z_SRW_searchRetrieveRequest *srw_req,
484 Z_SRW_record *record)
487 ODR o = assoc->encode;
489 rr.setname = "default";
492 rr.request_format = VAL_TEXT_XML;
493 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
496 rr.comp = (Z_RecordComposition *)
497 odr_malloc(assoc->decode, sizeof(*rr.comp));
498 rr.comp->which = Z_RecordComp_complex;
499 rr.comp->u.complex = (Z_CompSpec *)
500 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
501 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
502 odr_malloc(assoc->encode, sizeof(bool_t));
503 *rr.comp->u.complex->selectAlternativeSyntax = 0;
504 rr.comp->u.complex->num_dbSpecific = 0;
505 rr.comp->u.complex->dbSpecific = 0;
506 rr.comp->u.complex->num_recordSyntax = 0;
507 rr.comp->u.complex->recordSyntax = 0;
509 rr.comp->u.complex->generic = (Z_Specification *)
510 odr_malloc(assoc->decode, sizeof(Z_Specification));
511 rr.comp->u.complex->generic->which = Z_Schema_uri;
512 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
513 rr.comp->u.complex->generic->elementSpec = 0;
515 rr.stream = assoc->encode;
516 rr.print = assoc->print;
522 rr.output_format = VAL_TEXT_XML;
523 rr.output_format_raw = 0;
526 rr.surrogate_flag = 0;
527 rr.schema = srw_req->recordSchema;
529 if (!assoc->init->bend_fetch)
532 (*assoc->init->bend_fetch)(assoc->backend, &rr);
536 record->recordData_buf = rr.record;
537 record->recordData_len = rr.len;
538 record->recordPosition = odr_intdup(o, pos);
540 record->recordSchema = odr_strdup(o, rr.schema);
542 record->recordSchema = 0;
547 static void srw_bend_search(association *assoc, request *req,
548 Z_SRW_searchRetrieveRequest *srw_req,
549 Z_SRW_searchRetrieveResponse *srw_res)
555 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
556 yaz_log(LOG_DEBUG, "srw_bend_search");
559 yaz_log(LOG_DEBUG, "srw_bend_init");
560 if (!srw_bend_init(assoc))
562 srw_error = 3; /* assume Authentication error */
564 srw_res->num_diagnostics = 1;
565 srw_res->diagnostics = (Z_SRW_diagnostic *)
566 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
567 srw_res->diagnostics[0].code =
568 odr_intdup(assoc->encode, srw_error);
569 srw_res->diagnostics[0].details = 0;
574 rr.setname = "default";
577 rr.basenames = &srw_req->database;
580 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
582 if (srw_req->query_type == Z_SRW_query_type_cql)
584 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
585 ext->direct_reference = odr_getoidbystr(assoc->decode,
586 "1.2.840.10003.16.2");
587 ext->indirect_reference = 0;
589 ext->which = Z_External_CQL;
590 ext->u.cql = srw_req->query.cql;
592 rr.query->which = Z_Query_type_104;
593 rr.query->u.type_104 = ext;
595 else if (srw_req->query_type == Z_SRW_query_type_pqf)
597 Z_RPNQuery *RPNquery;
598 YAZ_PQF_Parser pqf_parser;
600 pqf_parser = yaz_pqf_create ();
602 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
608 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
609 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
610 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
615 rr.query->which = Z_Query_type_1;
616 rr.query->u.type_1 = RPNquery;
618 yaz_pqf_destroy (pqf_parser);
623 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
626 if (!srw_error && !assoc->init->bend_search)
631 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
632 srw_res->num_diagnostics = 1;
633 srw_res->diagnostics = (Z_SRW_diagnostic *)
634 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
635 srw_res->diagnostics[0].code =
636 odr_intdup(assoc->encode, srw_error);
637 srw_res->diagnostics[0].details = 0;
641 rr.stream = assoc->encode;
642 rr.decode = assoc->decode;
643 rr.print = assoc->print;
645 rr.association = assoc;
651 yaz_log_zquery(rr.query);
652 (assoc->init->bend_search)(assoc->backend, &rr);
653 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
656 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
657 srw_res->num_diagnostics = 1;
658 srw_res->diagnostics = (Z_SRW_diagnostic *)
659 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
660 srw_res->diagnostics[0].code =
661 odr_intdup(assoc->encode,
662 yaz_diag_bib1_to_srw (rr.errcode));
663 srw_res->diagnostics[0].details = rr.errstring;
664 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
665 *srw_res->diagnostics[0].code);
670 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
671 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
673 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
674 start, number, rr.hits);
676 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
683 yaz_log(LOG_LOG, "Request out or range");
688 int packing = Z_SRW_recordPacking_string;
689 if (start + number > rr.hits)
690 number = rr.hits - start + 1;
691 if (srw_req->recordPacking &&
692 !strcmp(srw_req->recordPacking, "xml"))
693 packing = Z_SRW_recordPacking_XML;
694 srw_res->records = (Z_SRW_record *)
695 odr_malloc(assoc->encode,
696 number * sizeof(*srw_res->records));
697 for (i = 0; i<number; i++)
701 srw_res->records[j].recordPacking = packing;
702 srw_res->records[j].recordData_buf = 0;
703 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
704 errcode = srw_bend_fetch(assoc, i+start, srw_req,
705 srw_res->records + j);
708 srw_res->num_diagnostics = 1;
709 srw_res->diagnostics = (Z_SRW_diagnostic *)
710 odr_malloc(assoc->encode,
711 sizeof(*srw_res->diagnostics));
712 srw_res->diagnostics[0].code =
713 odr_intdup(assoc->encode,
714 yaz_diag_bib1_to_srw (errcode));
715 srw_res->diagnostics[0].details = rr.errstring;
718 if (srw_res->records[j].recordData_buf)
721 srw_res->num_records = j;
723 srw_res->records = 0;
730 static void srw_bend_explain(association *assoc, request *req,
731 Z_SRW_explainRequest *srw_req,
732 Z_SRW_explainResponse *srw_res)
734 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
737 yaz_log(LOG_DEBUG, "srw_bend_init");
738 if (!srw_bend_init(assoc))
741 if (assoc->init && assoc->init->bend_explain)
745 rr.stream = assoc->encode;
746 rr.decode = assoc->decode;
747 rr.print = assoc->print;
749 (*assoc->init->bend_explain)(assoc->backend, &rr);
752 srw_res->explainData_buf = rr.explain_buf;
753 srw_res->explainData_len = strlen(rr.explain_buf);
758 static int hex_digit (int ch)
760 if (ch >= '0' && ch <= '9')
762 else if (ch >= 'a' && ch <= 'f')
764 else if (ch >= 'A' && ch <= 'F')
769 static char *uri_val(const char *path, const char *name, ODR o)
771 size_t nlen = strlen(name);
775 while (path && *path)
777 const char *p1 = strchr(path, '=');
780 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
786 p1 = strchr(path, '&');
788 p1 = strlen(path) + path;
789 ret = odr_malloc(o, p1 - path + 1);
790 while (*path && *path != '&')
797 else if (*path == '%' && path[1] && path[2])
799 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
808 path = strchr(p1, '&');
815 void uri_val_int(const char *path, const char *name, ODR o, int **intp)
817 const char *v = uri_val(path, name, o);
819 *intp = odr_intdup(o, atoi(v));
822 static void process_http_request(association *assoc, request *req)
824 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
825 ODR o = assoc->encode;
827 Z_HTTP_Response *hres = 0;
830 if (!strcmp(hreq->method, "GET"))
832 char *db = "Default";
833 const char *p0 = hreq->path, *p1;
837 Z_SOAP *soap_package = 0;
838 static Z_SOAP_Handler soap_handlers[2] = {
839 {"http://www.loc.gov/zing/srw/v1.0/", 0,
840 (Z_SOAP_fun) yaz_srw_codec},
847 p1 = strchr(p0, '?');
849 p1 = p0 + strlen(p0);
852 db = odr_malloc(assoc->decode, p1 - p0 + 1);
853 memcpy (db, p0, p1 - p0);
857 if (p1 && *p1 == '?' && p1[1])
859 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
860 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
861 char *query = uri_val(p1, "query", o);
862 char *pQuery = uri_val(p1, "pQuery", o);
863 char *sortKeys = uri_val(p1, "sortKeys", o);
867 sr->u.request->query_type = Z_SRW_query_type_cql;
868 sr->u.request->query.cql = query;
872 sr->u.request->query_type = Z_SRW_query_type_pqf;
873 sr->u.request->query.pqf = pQuery;
877 sr->u.request->sort_type = Z_SRW_sort_type_sort;
878 sr->u.request->sort.sortKeys = sortKeys;
880 sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
881 sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
882 if (!sr->u.request->recordPacking)
883 sr->u.request->recordPacking = "xml";
884 uri_val_int(p1, "maximumRecords", o,
885 &sr->u.request->maximumRecords);
886 uri_val_int(p1, "startRecord", o,
887 &sr->u.request->startRecord);
888 if (sr->u.request->startRecord)
889 yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
890 sr->u.request->database = db;
891 srw_bend_search(assoc, req, sr->u.request, res->u.response);
893 soap_package = odr_malloc(o, sizeof(*soap_package));
894 soap_package->which = Z_SOAP_generic;
896 soap_package->u.generic =
897 odr_malloc(o, sizeof(*soap_package->u.generic));
899 soap_package->u.generic->p = res;
900 soap_package->u.generic->ns = soap_handlers[0].ns;
901 soap_package->u.generic->no = 0;
903 soap_package->ns = "SRU";
905 p = z_get_HTTP_Response(o, 200);
906 hres = p->u.HTTP_Response;
908 ret = z_soap_codec_enc(assoc->encode, &soap_package,
909 &hres->content_buf, &hres->content_len,
910 soap_handlers, charset);
912 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
916 strcpy(ctype, "text/xml; charset=");
917 strcat(ctype, charset);
918 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
924 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
925 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
927 srw_bend_explain(assoc, req, sr->u.explain_request,
928 res->u.explain_response);
930 if (res->u.explain_response->explainData_buf)
932 soap_package = odr_malloc(o, sizeof(*soap_package));
933 soap_package->which = Z_SOAP_generic;
935 soap_package->u.generic =
936 odr_malloc(o, sizeof(*soap_package->u.generic));
938 soap_package->u.generic->p = res;
939 soap_package->u.generic->ns = soap_handlers[0].ns;
940 soap_package->u.generic->no = 0;
942 soap_package->ns = "SRU";
944 p = z_get_HTTP_Response(o, 200);
945 hres = p->u.HTTP_Response;
947 ret = z_soap_codec_enc(assoc->encode, &soap_package,
948 &hres->content_buf, &hres->content_len,
949 soap_handlers, charset);
951 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
955 strcpy(ctype, "text/xml; charset=");
956 strcat(ctype, charset);
957 z_HTTP_header_add(o, &hres->headers, "Content-Type",
964 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
965 !memcmp(hreq->path, "/doc/", 5))
970 strcpy(fpath, DOCDIR);
971 strcat(fpath, hreq->path+4);
972 f = fopen(fpath, "rb");
975 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
984 fseek(f, 0L, SEEK_END);
986 if (sz >= 0 && sz < 500000)
988 const char *ctype = "application/octet-stream";
991 p = z_get_HTTP_Response(o, 200);
992 hres = p->u.HTTP_Response;
993 hres->content_buf = (char *) odr_malloc(o, sz + 1);
994 hres->content_len = sz;
995 fseek(f, 0L, SEEK_SET);
996 fread(hres->content_buf, 1, sz, f);
997 if ((cp = strrchr(fpath, '.'))) {
999 if (!strcmp(cp, "png"))
1000 ctype = "image/png";
1001 else if (!strcmp(cp, "gif"))
1002 ctype = "image/gif";
1003 else if (!strcmp(cp, "xml"))
1005 else if (!strcmp(cp, "html"))
1006 ctype = "text/html";
1008 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1016 if (!strcmp(hreq->path, "/"))
1021 const char *doclink = "";
1022 p = z_get_HTTP_Response(o, 200);
1023 hres = p->u.HTTP_Response;
1024 hres->content_buf = (char *) odr_malloc(o, 400);
1026 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
1027 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
1029 sprintf (hres->content_buf,
1030 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1033 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1036 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1037 YAZ_VERSION "</P>\n"
1040 "</HTML>\n", doclink);
1041 hres->content_len = strlen(hres->content_buf);
1042 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1048 p = z_get_HTTP_Response(o, 404);
1051 else if (!strcmp(hreq->method, "POST"))
1053 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1055 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1057 Z_SOAP *soap_package = 0;
1059 int http_code = 500;
1060 const char *charset_p = 0;
1063 static Z_SOAP_Handler soap_handlers[2] = {
1065 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1066 (Z_SOAP_fun) yaz_srw_codec},
1070 if ((charset_p = strstr(content_type, "; charset=")))
1074 while (i < 20 && charset_p[i] &&
1075 !strchr("; \n\r", charset_p[i]))
1077 charset = odr_malloc(assoc->encode, i+1);
1078 memcpy(charset, charset_p, i);
1080 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1082 ret = z_soap_codec(assoc->decode, &soap_package,
1083 &hreq->content_buf, &hreq->content_len,
1086 if (!ret && soap_package->which == Z_SOAP_generic &&
1087 soap_package->u.generic->no == 0)
1090 Z_SRW_PDU *sr = soap_package->u.generic->p;
1092 if (sr->which == Z_SRW_searchRetrieve_request)
1095 yaz_srw_get(assoc->encode,
1096 Z_SRW_searchRetrieve_response);
1098 if (!sr->u.request->database)
1100 const char *p0 = hreq->path, *p1;
1103 p1 = strchr(p0, '?');
1105 p1 = p0 + strlen(p0);
1108 sr->u.request->database =
1109 odr_malloc(assoc->decode, p1 - p0 + 1);
1110 memcpy (sr->u.request->database, p0, p1 - p0);
1111 sr->u.request->database[p1 - p0] = '\0';
1114 sr->u.request->database = "Default";
1116 srw_bend_search(assoc, req, sr->u.request,
1119 soap_package->u.generic->p = res;
1122 else if (sr->which == Z_SRW_explain_request)
1125 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1127 srw_bend_explain(assoc, req, sr->u.explain_request,
1128 res->u.explain_response);
1129 if (!res->u.explain_response->explainData_buf)
1131 z_soap_error(assoc->encode, soap_package,
1132 "SOAP-ENV:Client", "Explain Not Supported", 0);
1136 soap_package->u.generic->p = res;
1142 z_soap_error(assoc->encode, soap_package,
1143 "SOAP-ENV:Client", "Bad method", 0);
1147 p = z_get_HTTP_Response(o, 200);
1148 hres = p->u.HTTP_Response;
1149 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1150 &hres->content_buf, &hres->content_len,
1151 soap_handlers, charset);
1152 hres->code = http_code;
1154 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1158 strcpy(ctype, "text/xml; charset=");
1159 strcat(ctype, charset);
1160 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1163 if (!p) /* still no response ? */
1164 p = z_get_HTTP_Response(o, 500);
1168 p = z_get_HTTP_Response(o, 405);
1169 hres = p->u.HTTP_Response;
1171 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1173 hres = p->u.HTTP_Response;
1174 if (!strcmp(hreq->version, "1.0"))
1176 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1177 if (v && !strcmp(v, "Keep-Alive"))
1181 hres->version = "1.0";
1185 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1186 if (v && !strcmp(v, "close"))
1190 hres->version = "1.1";
1194 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1195 assoc->state = ASSOC_DEAD;
1200 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1202 if (alive && isdigit(*alive))
1206 if (t < 0 || t > 3600)
1208 iochan_settimeout(assoc->client_chan,t);
1209 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1211 process_gdu_response(assoc, req, p);
1214 static void process_gdu_request(association *assoc, request *req)
1216 if (req->gdu_request->which == Z_GDU_Z3950)
1219 req->apdu_request = req->gdu_request->u.z3950;
1220 if (process_z_request(assoc, req, &msg) < 0)
1221 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1223 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1224 process_http_request(assoc, req);
1227 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1232 * Initiate request processing.
1234 static int process_z_request(association *assoc, request *req, char **msg)
1240 *msg = "Unknown Error";
1241 assert(req && req->state == REQUEST_IDLE);
1242 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1244 *msg = "Missing InitRequest";
1247 switch (req->apdu_request->which)
1249 case Z_APDU_initRequest:
1250 iochan_settimeout(assoc->client_chan,
1251 statserv_getcontrol()->idle_timeout * 60);
1252 res = process_initRequest(assoc, req); break;
1253 case Z_APDU_searchRequest:
1254 res = process_searchRequest(assoc, req, &fd); break;
1255 case Z_APDU_presentRequest:
1256 res = process_presentRequest(assoc, req, &fd); break;
1257 case Z_APDU_scanRequest:
1258 if (assoc->init->bend_scan)
1259 res = process_scanRequest(assoc, req, &fd);
1262 *msg = "Cannot handle Scan APDU";
1266 case Z_APDU_extendedServicesRequest:
1267 if (assoc->init->bend_esrequest)
1268 res = process_ESRequest(assoc, req, &fd);
1271 *msg = "Cannot handle Extended Services APDU";
1275 case Z_APDU_sortRequest:
1276 if (assoc->init->bend_sort)
1277 res = process_sortRequest(assoc, req, &fd);
1280 *msg = "Cannot handle Sort APDU";
1285 process_close(assoc, req);
1287 case Z_APDU_deleteResultSetRequest:
1288 if (assoc->init->bend_delete)
1289 res = process_deleteRequest(assoc, req, &fd);
1292 *msg = "Cannot handle Delete APDU";
1296 case Z_APDU_segmentRequest:
1297 if (assoc->init->bend_segment)
1299 res = process_segmentRequest (assoc, req);
1303 *msg = "Cannot handle Segment APDU";
1308 *msg = "Bad APDU received";
1313 yaz_log(LOG_DEBUG, " result immediately available");
1314 retval = process_z_response(assoc, req, res);
1318 yaz_log(LOG_DEBUG, " result unavailble");
1321 else /* no result yet - one will be provided later */
1325 /* Set up an I/O handler for the fd supplied by the backend */
1327 yaz_log(LOG_DEBUG, " establishing handler for result");
1328 req->state = REQUEST_PENDING;
1329 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1331 iochan_setdata(chan, assoc);
1338 * Handle message from the backend.
1340 void backend_response(IOCHAN i, int event)
1342 association *assoc = (association *)iochan_getdata(i);
1343 request *req = request_head(&assoc->incoming);
1347 yaz_log(LOG_DEBUG, "backend_response");
1348 assert(assoc && req && req->state != REQUEST_IDLE);
1349 /* determine what it is we're waiting for */
1350 switch (req->apdu_request->which)
1352 case Z_APDU_searchRequest:
1353 res = response_searchRequest(assoc, req, 0, &fd); break;
1355 case Z_APDU_presentRequest:
1356 res = response_presentRequest(assoc, req, 0, &fd); break;
1357 case Z_APDU_scanRequest:
1358 res = response_scanRequest(assoc, req, 0, &fd); break;
1361 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1364 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1366 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1367 do_close(assoc, Z_Close_systemProblem, 0);
1371 else if (!res) /* no result yet - try again later */
1373 yaz_log(LOG_DEBUG, " no result yet");
1374 iochan_setfd(i, fd); /* in case fd has changed */
1379 * Encode response, and transfer the request structure to the outgoing queue.
1381 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1383 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1385 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1387 yaz_log(LOG_WARN, "ODR print error: %s",
1388 odr_errmsg(odr_geterror(assoc->print)));
1389 odr_reset(assoc->print);
1391 if (!z_GDU(assoc->encode, &res, 0, 0))
1393 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1394 odr_errmsg(odr_geterror(assoc->decode)),
1395 odr_getelement(assoc->decode));
1396 request_release(req);
1399 req->response = odr_getbuf(assoc->encode, &req->len_response,
1400 &req->size_response);
1401 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1402 odr_reset(assoc->encode);
1403 req->state = REQUEST_IDLE;
1404 request_enq(&assoc->outgoing, req);
1405 /* turn the work over to the ir_session handler */
1406 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1407 assoc->cs_put_mask = EVENT_OUTPUT;
1408 /* Is there more work to be done? give that to the input handler too */
1410 if (request_head(&assoc->incoming))
1412 yaz_log (LOG_DEBUG, "more work to be done");
1413 iochan_setevent(assoc->client_chan, EVENT_WORK);
1420 * Encode response, and transfer the request structure to the outgoing queue.
1422 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1424 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1425 gres->which = Z_GDU_Z3950;
1426 gres->u.z3950 = res;
1428 return process_gdu_response(assoc, req, gres);
1433 * Handle init request.
1434 * At the moment, we don't check the options
1435 * anywhere else in the code - we just try not to do anything that would
1436 * break a naive client. We'll toss 'em into the association block when
1437 * we need them there.
1439 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1441 statserv_options_block *cb = statserv_getcontrol();
1442 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1443 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1444 Z_InitResponse *resp = apdu->u.initResponse;
1445 bend_initresult *binitres;
1449 yaz_log(LOG_LOG, "Got initRequest");
1450 if (req->implementationId)
1451 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1452 if (req->implementationName)
1453 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1454 if (req->implementationVersion)
1455 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1457 assoc_init_reset(assoc);
1459 assoc->init->auth = req->idAuthentication;
1460 assoc->init->referenceId = req->referenceId;
1462 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1464 Z_CharSetandLanguageNegotiation *negotiation =
1465 yaz_get_charneg_record (req->otherInfo);
1466 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1467 assoc->init->charneg_request = negotiation;
1470 if (!(binitres = (*cb->bend_init)(assoc->init)))
1472 yaz_log(LOG_WARN, "Bad response from backend.");
1476 assoc->backend = binitres->handle;
1477 if ((assoc->init->bend_sort))
1478 yaz_log (LOG_DEBUG, "Sort handler installed");
1479 if ((assoc->init->bend_search))
1480 yaz_log (LOG_DEBUG, "Search handler installed");
1481 if ((assoc->init->bend_present))
1482 yaz_log (LOG_DEBUG, "Present handler installed");
1483 if ((assoc->init->bend_esrequest))
1484 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1485 if ((assoc->init->bend_delete))
1486 yaz_log (LOG_DEBUG, "Delete handler installed");
1487 if ((assoc->init->bend_scan))
1488 yaz_log (LOG_DEBUG, "Scan handler installed");
1489 if ((assoc->init->bend_segment))
1490 yaz_log (LOG_DEBUG, "Segment handler installed");
1492 resp->referenceId = req->referenceId;
1494 /* let's tell the client what we can do */
1495 if (ODR_MASK_GET(req->options, Z_Options_search))
1497 ODR_MASK_SET(resp->options, Z_Options_search);
1498 strcat(options, "srch");
1500 if (ODR_MASK_GET(req->options, Z_Options_present))
1502 ODR_MASK_SET(resp->options, Z_Options_present);
1503 strcat(options, " prst");
1505 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1506 assoc->init->bend_delete)
1508 ODR_MASK_SET(resp->options, Z_Options_delSet);
1509 strcat(options, " del");
1511 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1512 assoc->init->bend_esrequest)
1514 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1515 strcat (options, " extendedServices");
1517 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1519 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1520 strcat(options, " namedresults");
1522 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1524 ODR_MASK_SET(resp->options, Z_Options_scan);
1525 strcat(options, " scan");
1527 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1529 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1530 strcat(options, " concurrop");
1532 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1534 ODR_MASK_SET(resp->options, Z_Options_sort);
1535 strcat(options, " sort");
1538 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1539 && assoc->init->charneg_response)
1541 Z_OtherInformation **p;
1542 Z_OtherInformationUnit *p0;
1544 yaz_oi_APDU(apdu, &p);
1546 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1547 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1549 p0->which = Z_OtherInfo_externallyDefinedInfo;
1550 p0->information.externallyDefinedInfo =
1551 assoc->init->charneg_response;
1553 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1554 strcat(options, " negotiation");
1557 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1559 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1560 assoc->version = 2; /* 1 & 2 are equivalent */
1562 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1564 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1567 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1569 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1573 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1574 assoc->maximumRecordSize = *req->maximumRecordSize;
1575 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1576 assoc->maximumRecordSize = control_block->maxrecordsize;
1577 assoc->preferredMessageSize = *req->preferredMessageSize;
1578 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1579 assoc->preferredMessageSize = assoc->maximumRecordSize;
1581 resp->preferredMessageSize = &assoc->preferredMessageSize;
1582 resp->maximumRecordSize = &assoc->maximumRecordSize;
1584 resp->implementationName = "GFS/YAZ";
1586 if (assoc->init->implementation_id)
1589 odr_malloc (assoc->encode,
1590 strlen(assoc->init->implementation_id) + 10 +
1591 strlen(resp->implementationId));
1592 sprintf (nv, "%s/%s",
1593 assoc->init->implementation_id,
1594 resp->implementationId);
1595 resp->implementationId = nv;
1597 if (assoc->init->implementation_name)
1600 odr_malloc (assoc->encode,
1601 strlen(assoc->init->implementation_name) + 10 +
1602 strlen(resp->implementationName));
1603 sprintf (nv, "%s/%s",
1604 assoc->init->implementation_name,
1605 resp->implementationName);
1606 resp->implementationName = nv;
1608 if (assoc->init->implementation_version)
1611 odr_malloc (assoc->encode,
1612 strlen(assoc->init->implementation_version) + 10 +
1613 strlen(resp->implementationVersion));
1614 sprintf (nv, "%s/YAZ %s",
1615 assoc->init->implementation_version,
1616 resp->implementationVersion);
1617 resp->implementationVersion = nv;
1620 if (binitres->errcode)
1622 yaz_log(LOG_LOG, "Connection rejected by backend.");
1624 assoc->state = ASSOC_DEAD;
1625 resp->userInformationField = init_diagnostics(assoc->encode,
1627 binitres->errstring);
1630 assoc->state = ASSOC_UP;
1635 * Diagnostic in default format, to be returned as either a surrogate
1636 * or non-surrogate diagnostic in the context of an open session, or
1637 * as User-information when an Init is refused.
1639 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1641 int *err = odr_intdup(odr, error);
1642 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1643 odr_malloc (odr, sizeof(*dr));
1645 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1646 addinfo ? " -- " : "", addinfo ? addinfo : "");
1648 dr->diagnosticSetId =
1649 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1650 dr->condition = err;
1651 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1652 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1657 * Set the specified `errcode' and `errstring' into a UserInfo-1
1658 * external to be returned to the client in accordance with Z35.90
1659 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1660 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1662 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1666 Z_OtherInformation *u;
1667 Z_OtherInformationUnit *l;
1668 Z_DiagnosticFormat *d;
1669 Z_DiagnosticFormat_s *e;
1671 x = (Z_External*) odr_malloc(odr, sizeof *x);
1673 x->indirect_reference = 0;
1674 oid.proto = PROTO_Z3950;
1675 oid.oclass = CLASS_USERINFO;
1676 oid.value = VAL_USERINFO1;
1677 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1678 x->which = Z_External_userInfo1;
1680 u = odr_malloc(odr, sizeof *u);
1682 u->num_elements = 1;
1683 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1684 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1687 l->which = Z_OtherInfo_externallyDefinedInfo;
1689 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1690 l->information.externallyDefinedInfo = x2;
1692 x2->indirect_reference = 0;
1693 oid.oclass = CLASS_DIAGSET;
1694 oid.value = VAL_DIAG1;
1695 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1696 x2->which = Z_External_diag1;
1698 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1701 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1702 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1705 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1706 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1711 * nonsurrogate diagnostic record.
1713 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1715 Z_Records *rec = (Z_Records *)
1716 odr_malloc (assoc->encode, sizeof(*rec));
1717 rec->which = Z_Records_NSD;
1718 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1723 * surrogate diagnostic.
1725 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1726 int error, char *addinfo)
1728 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1729 odr_malloc (assoc->encode, sizeof(*rec));
1730 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1732 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1733 rec->databaseName = dbname;
1734 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1735 rec->u.surrogateDiagnostic = drec;
1736 drec->which = Z_DiagRec_defaultFormat;
1737 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1743 * multiple nonsurrogate diagnostics.
1745 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1747 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1748 int *err = odr_intdup(assoc->encode, error);
1749 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1750 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1751 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1752 odr_malloc (assoc->encode, sizeof(*rec));
1754 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1756 recs->num_diagRecs = 1;
1757 recs->diagRecs = recp;
1759 drec->which = Z_DiagRec_defaultFormat;
1760 drec->u.defaultFormat = rec;
1762 rec->diagnosticSetId =
1763 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1764 rec->condition = err;
1766 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1767 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1771 static Z_Records *pack_records(association *a, char *setname, int start,
1772 int *num, Z_RecordComposition *comp,
1773 int *next, int *pres, oid_value format,
1774 Z_ReferenceId *referenceId,
1777 int recno, total_length = 0, toget = *num, dumped_records = 0;
1778 Z_Records *records =
1779 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1780 Z_NamePlusRecordList *reclist =
1781 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1782 Z_NamePlusRecord **list =
1783 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1785 records->which = Z_Records_DBOSD;
1786 records->u.databaseOrSurDiagnostics = reclist;
1787 reclist->num_records = 0;
1788 reclist->records = list;
1789 *pres = Z_PRES_SUCCESS;
1793 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1794 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1795 a->maximumRecordSize);
1796 for (recno = start; reclist->num_records < toget; recno++)
1799 Z_NamePlusRecord *thisrec;
1800 int this_length = 0;
1802 * we get the number of bytes allocated on the stream before any
1803 * allocation done by the backend - this should give us a reasonable
1804 * idea of the total size of the data so far.
1806 total_length = odr_total(a->encode) - dumped_records;
1812 freq.last_in_set = 0;
1813 freq.setname = setname;
1814 freq.surrogate_flag = 0;
1815 freq.number = recno;
1817 freq.request_format = format;
1818 freq.request_format_raw = oid;
1819 freq.output_format = format;
1820 freq.output_format_raw = 0;
1821 freq.stream = a->encode;
1822 freq.print = a->print;
1823 freq.referenceId = referenceId;
1825 (*a->init->bend_fetch)(a->backend, &freq);
1826 /* backend should be able to signal whether error is system-wide
1827 or only pertaining to current record */
1830 if (!freq.surrogate_flag)
1833 *pres = Z_PRES_FAILURE;
1834 /* for 'present request out of range',
1835 set addinfo to record position if not set */
1836 if (freq.errcode == 13 && freq.errstring == 0)
1838 sprintf (s, "%d", recno);
1841 return diagrec(a, freq.errcode, freq.errstring);
1843 reclist->records[reclist->num_records] =
1844 surrogatediagrec(a, freq.basename, freq.errcode,
1846 reclist->num_records++;
1847 *next = freq.last_in_set ? 0 : recno + 1;
1851 this_length = freq.len;
1853 this_length = odr_total(a->encode) - total_length;
1854 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1855 this_length, total_length);
1856 if (this_length + total_length > a->preferredMessageSize)
1858 /* record is small enough, really */
1859 if (this_length <= a->preferredMessageSize)
1861 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1862 *pres = Z_PRES_PARTIAL_2;
1865 /* record can only be fetched by itself */
1866 if (this_length < a->maximumRecordSize)
1868 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1871 yaz_log(LOG_DEBUG, " Dropped it");
1872 reclist->records[reclist->num_records] =
1873 surrogatediagrec(a, freq.basename, 16, 0);
1874 reclist->num_records++;
1875 *next = freq.last_in_set ? 0 : recno + 1;
1876 dumped_records += this_length;
1880 else /* too big entirely */
1882 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1883 reclist->records[reclist->num_records] =
1884 surrogatediagrec(a, freq.basename, 17, 0);
1885 reclist->num_records++;
1886 *next = freq.last_in_set ? 0 : recno + 1;
1887 dumped_records += this_length;
1892 if (!(thisrec = (Z_NamePlusRecord *)
1893 odr_malloc(a->encode, sizeof(*thisrec))))
1895 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1896 strlen(freq.basename) + 1)))
1898 strcpy(thisrec->databaseName, freq.basename);
1899 thisrec->which = Z_NamePlusRecord_databaseRecord;
1901 if (freq.output_format_raw)
1903 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1904 freq.output_format = ident->value;
1906 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1907 freq.record, freq.len);
1908 if (!thisrec->u.databaseRecord)
1910 reclist->records[reclist->num_records] = thisrec;
1911 reclist->num_records++;
1912 *next = freq.last_in_set ? 0 : recno + 1;
1914 *num = reclist->num_records;
1918 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1921 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1922 bend_search_rr *bsrr =
1923 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1925 yaz_log(LOG_LOG, "Got SearchRequest.");
1927 bsrr->request = reqb;
1928 bsrr->association = assoc;
1929 bsrr->referenceId = req->referenceId;
1930 save_referenceId (reqb, bsrr->referenceId);
1932 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1933 if (req->databaseNames)
1936 for (i = 0; i < req->num_databaseNames; i++)
1937 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1939 yaz_log_zquery(req->query);
1941 if (assoc->init->bend_search)
1943 bsrr->setname = req->resultSetName;
1944 bsrr->replace_set = *req->replaceIndicator;
1945 bsrr->num_bases = req->num_databaseNames;
1946 bsrr->basenames = req->databaseNames;
1947 bsrr->query = req->query;
1948 bsrr->stream = assoc->encode;
1949 bsrr->decode = assoc->decode;
1950 bsrr->print = assoc->print;
1953 bsrr->errstring = NULL;
1954 bsrr->search_info = NULL;
1955 (assoc->init->bend_search)(assoc->backend, bsrr);
1959 return response_searchRequest(assoc, reqb, bsrr, fd);
1962 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1965 * Prepare a searchresponse based on the backend results. We probably want
1966 * to look at making the fetching of records nonblocking as well, but
1967 * so far, we'll keep things simple.
1968 * If bsrt is null, that means we're called in response to a communications
1969 * event, and we'll have to get the response for ourselves.
1971 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1972 bend_search_rr *bsrt, int *fd)
1974 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1975 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1976 Z_SearchResponse *resp = (Z_SearchResponse *)
1977 odr_malloc (assoc->encode, sizeof(*resp));
1978 int *nulint = odr_intdup (assoc->encode, 0);
1979 bool_t *sr = odr_intdup(assoc->encode, 1);
1980 int *next = odr_intdup(assoc->encode, 0);
1981 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1983 apdu->which = Z_APDU_searchResponse;
1984 apdu->u.searchResponse = resp;
1985 resp->referenceId = req->referenceId;
1986 resp->additionalSearchInfo = 0;
1987 resp->otherInfo = 0;
1989 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1991 yaz_log(LOG_FATAL, "Bad result from backend");
1994 else if (bsrt->errcode)
1996 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1997 resp->resultCount = nulint;
1998 resp->numberOfRecordsReturned = nulint;
1999 resp->nextResultSetPosition = nulint;
2000 resp->searchStatus = nulint;
2001 resp->resultSetStatus = none;
2002 resp->presentStatus = 0;
2006 int *toget = odr_intdup(assoc->encode, 0);
2007 int *presst = odr_intdup(assoc->encode, 0);
2008 Z_RecordComposition comp, *compp = 0;
2010 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
2013 resp->resultCount = &bsrt->hits;
2015 comp.which = Z_RecordComp_simple;
2016 /* how many records does the user agent want, then? */
2017 if (bsrt->hits <= *req->smallSetUpperBound)
2019 *toget = bsrt->hits;
2020 if ((comp.u.simple = req->smallSetElementSetNames))
2023 else if (bsrt->hits < *req->largeSetLowerBound)
2025 *toget = *req->mediumSetPresentNumber;
2026 if (*toget > bsrt->hits)
2027 *toget = bsrt->hits;
2028 if ((comp.u.simple = req->mediumSetElementSetNames))
2034 if (*toget && !resp->records)
2039 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2042 form = prefformat->value;
2043 resp->records = pack_records(assoc, req->resultSetName, 1,
2044 toget, compp, next, presst, form, req->referenceId,
2045 req->preferredRecordSyntax);
2048 resp->numberOfRecordsReturned = toget;
2049 resp->nextResultSetPosition = next;
2050 resp->searchStatus = sr;
2051 resp->resultSetStatus = 0;
2052 resp->presentStatus = presst;
2056 if (*resp->resultCount)
2058 resp->numberOfRecordsReturned = nulint;
2059 resp->nextResultSetPosition = next;
2060 resp->searchStatus = sr;
2061 resp->resultSetStatus = 0;
2062 resp->presentStatus = 0;
2065 resp->additionalSearchInfo = bsrt->search_info;
2070 * Maybe we got a little over-friendly when we designed bend_fetch to
2071 * get only one record at a time. Some backends can optimise multiple-record
2072 * fetches, and at any rate, there is some overhead involved in
2073 * all that selecting and hopping around. Problem is, of course, that the
2074 * frontend can't know ahead of time how many records it'll need to
2075 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2076 * is downright lousy as a bulk data transfer protocol.
2078 * To start with, we'll do the fetching of records from the backend
2079 * in one operation: To save some trips in and out of the event-handler,
2080 * and to simplify the interface to pack_records. At any rate, asynch
2081 * operation is more fun in operations that have an unpredictable execution
2082 * speed - which is normally more true for search than for present.
2084 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2087 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2091 Z_PresentResponse *resp;
2095 yaz_log(LOG_LOG, "Got PresentRequest.");
2097 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2100 form = prefformat->value;
2101 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2103 resp->presentStatus = odr_intdup(assoc->encode, 0);
2104 if (assoc->init->bend_present)
2106 bend_present_rr *bprr = (bend_present_rr *)
2107 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2108 bprr->setname = req->resultSetId;
2109 bprr->start = *req->resultSetStartPoint;
2110 bprr->number = *req->numberOfRecordsRequested;
2111 bprr->format = form;
2112 bprr->comp = req->recordComposition;
2113 bprr->referenceId = req->referenceId;
2114 bprr->stream = assoc->encode;
2115 bprr->print = assoc->print;
2116 bprr->request = reqb;
2117 bprr->association = assoc;
2119 bprr->errstring = NULL;
2120 (*assoc->init->bend_present)(assoc->backend, bprr);
2126 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2127 *resp->presentStatus = Z_PRES_FAILURE;
2130 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2131 next = odr_intdup(assoc->encode, 0);
2132 num = odr_intdup(assoc->encode, 0);
2134 apdu->which = Z_APDU_presentResponse;
2135 apdu->u.presentResponse = resp;
2136 resp->referenceId = req->referenceId;
2137 resp->otherInfo = 0;
2141 *num = *req->numberOfRecordsRequested;
2143 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2144 num, req->recordComposition, next, resp->presentStatus,
2145 form, req->referenceId, req->preferredRecordSyntax);
2149 resp->numberOfRecordsReturned = num;
2150 resp->nextResultSetPosition = next;
2156 * Scan was implemented rather in a hurry, and with support for only the basic
2157 * elements of the service in the backend API. Suggestions are welcome.
2159 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2161 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2162 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2163 Z_ScanResponse *res = (Z_ScanResponse *)
2164 odr_malloc (assoc->encode, sizeof(*res));
2165 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2166 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2167 Z_ListEntries *ents = (Z_ListEntries *)
2168 odr_malloc (assoc->encode, sizeof(*ents));
2169 Z_DiagRecs *diagrecs_p = NULL;
2171 bend_scan_rr *bsrr = (bend_scan_rr *)
2172 odr_malloc (assoc->encode, sizeof(*bsrr));
2173 struct scan_entry *save_entries;
2175 yaz_log(LOG_LOG, "Got ScanRequest");
2177 apdu->which = Z_APDU_scanResponse;
2178 apdu->u.scanResponse = res;
2179 res->referenceId = req->referenceId;
2181 /* if step is absent, set it to 0 */
2182 res->stepSize = odr_intdup(assoc->encode, 0);
2184 *res->stepSize = *req->stepSize;
2186 res->scanStatus = scanStatus;
2187 res->numberOfEntriesReturned = numberOfEntriesReturned;
2188 res->positionOfTerm = 0;
2189 res->entries = ents;
2190 ents->num_entries = 0;
2191 ents->entries = NULL;
2192 ents->num_nonsurrogateDiagnostics = 0;
2193 ents->nonsurrogateDiagnostics = NULL;
2194 res->attributeSet = 0;
2197 if (req->databaseNames)
2200 for (i = 0; i < req->num_databaseNames; i++)
2201 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2203 bsrr->num_bases = req->num_databaseNames;
2204 bsrr->basenames = req->databaseNames;
2205 bsrr->num_entries = *req->numberOfTermsRequested;
2206 bsrr->term = req->termListAndStartPoint;
2207 bsrr->referenceId = req->referenceId;
2208 bsrr->stream = assoc->encode;
2209 bsrr->print = assoc->print;
2210 bsrr->step_size = res->stepSize;
2212 /* Note that version 2.0 of YAZ and older did not set entries ..
2213 We do now. And when we do it's easier to extend the scan entry
2214 We know that if the scan handler did set entries, it will
2215 not know of new member display_term.
2217 if (bsrr->num_entries > 0)
2220 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2222 for (i = 0; i<bsrr->num_entries; i++)
2224 bsrr->entries[i].term = 0;
2225 bsrr->entries[i].occurrences = 0;
2226 bsrr->entries[i].errcode = 0;
2227 bsrr->entries[i].errstring = 0;
2228 bsrr->entries[i].display_term = 0;
2231 save_entries = bsrr->entries; /* save it so we can compare later */
2233 if (req->attributeSet &&
2234 (attset = oid_getentbyoid(req->attributeSet)) &&
2235 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2236 bsrr->attributeset = attset->value;
2238 bsrr->attributeset = VAL_NONE;
2239 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2240 bsrr->term_position = req->preferredPositionInResponse ?
2241 *req->preferredPositionInResponse : 1;
2242 ((int (*)(void *, bend_scan_rr *))
2243 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2245 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2249 Z_Entry **tab = (Z_Entry **)
2250 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2252 if (bsrr->status == BEND_SCAN_PARTIAL)
2253 *scanStatus = Z_Scan_partial_5;
2255 *scanStatus = Z_Scan_success;
2256 ents->entries = tab;
2257 ents->num_entries = bsrr->num_entries;
2258 res->numberOfEntriesReturned = &ents->num_entries;
2259 res->positionOfTerm = &bsrr->term_position;
2260 for (i = 0; i < bsrr->num_entries; i++)
2266 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2267 if (bsrr->entries[i].occurrences >= 0)
2269 e->which = Z_Entry_termInfo;
2270 e->u.termInfo = t = (Z_TermInfo *)
2271 odr_malloc(assoc->encode, sizeof(*t));
2272 t->suggestedAttributes = 0;
2274 if (save_entries == bsrr->entries &&
2275 bsrr->entries[i].display_term)
2277 /* the entries was NOT set by the handler. So it's
2278 safe to test for new member display_term. It is
2281 t->displayTerm = odr_strdup(assoc->encode,
2282 bsrr->entries[i].display_term);
2284 t->alternativeTerm = 0;
2285 t->byAttributes = 0;
2286 t->otherTermInfo = 0;
2287 t->globalOccurrences = &bsrr->entries[i].occurrences;
2288 t->term = (Z_Term *)
2289 odr_malloc(assoc->encode, sizeof(*t->term));
2290 t->term->which = Z_Term_general;
2291 t->term->u.general = o =
2292 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2293 o->buf = (unsigned char *)
2294 odr_malloc(assoc->encode, o->len = o->size =
2295 strlen(bsrr->entries[i].term));
2296 memcpy(o->buf, bsrr->entries[i].term, o->len);
2297 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2298 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2302 Z_DiagRecs *drecs = diagrecs (assoc,
2303 bsrr->entries[i].errcode,
2304 bsrr->entries[i].errstring);
2305 assert (drecs->num_diagRecs == 1);
2306 e->which = Z_Entry_surrogateDiagnostic;
2307 assert (drecs->diagRecs[0]);
2308 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2314 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2315 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2320 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2323 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2324 Z_SortResponse *res = (Z_SortResponse *)
2325 odr_malloc (assoc->encode, sizeof(*res));
2326 bend_sort_rr *bsrr = (bend_sort_rr *)
2327 odr_malloc (assoc->encode, sizeof(*bsrr));
2329 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2331 yaz_log(LOG_LOG, "Got SortRequest.");
2333 bsrr->num_input_setnames = req->num_inputResultSetNames;
2334 bsrr->input_setnames = req->inputResultSetNames;
2335 bsrr->referenceId = req->referenceId;
2336 bsrr->output_setname = req->sortedResultSetName;
2337 bsrr->sort_sequence = req->sortSequence;
2338 bsrr->stream = assoc->encode;
2339 bsrr->print = assoc->print;
2341 bsrr->sort_status = Z_SortStatus_failure;
2343 bsrr->errstring = 0;
2345 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2347 res->referenceId = bsrr->referenceId;
2348 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2349 res->resultSetStatus = 0;
2352 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2353 res->diagnostics = dr->diagRecs;
2354 res->num_diagnostics = dr->num_diagRecs;
2358 res->num_diagnostics = 0;
2359 res->diagnostics = 0;
2361 res->resultCount = 0;
2364 apdu->which = Z_APDU_sortResponse;
2365 apdu->u.sortResponse = res;
2369 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2372 Z_DeleteResultSetRequest *req =
2373 reqb->apdu_request->u.deleteResultSetRequest;
2374 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2375 odr_malloc (assoc->encode, sizeof(*res));
2376 bend_delete_rr *bdrr = (bend_delete_rr *)
2377 odr_malloc (assoc->encode, sizeof(*bdrr));
2378 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2380 yaz_log(LOG_LOG, "Got DeleteRequest.");
2382 bdrr->num_setnames = req->num_resultSetList;
2383 bdrr->setnames = req->resultSetList;
2384 bdrr->stream = assoc->encode;
2385 bdrr->print = assoc->print;
2386 bdrr->function = *req->deleteFunction;
2387 bdrr->referenceId = req->referenceId;
2389 if (bdrr->num_setnames > 0)
2392 bdrr->statuses = (int*)
2393 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2394 bdrr->num_setnames);
2395 for (i = 0; i < bdrr->num_setnames; i++)
2396 bdrr->statuses[i] = 0;
2398 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2400 res->referenceId = req->referenceId;
2402 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2404 res->deleteListStatuses = 0;
2405 if (bdrr->num_setnames > 0)
2408 res->deleteListStatuses = (Z_ListStatuses *)
2409 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2410 res->deleteListStatuses->num = bdrr->num_setnames;
2411 res->deleteListStatuses->elements =
2413 odr_malloc (assoc->encode,
2414 sizeof(*res->deleteListStatuses->elements) *
2415 bdrr->num_setnames);
2416 for (i = 0; i<bdrr->num_setnames; i++)
2418 res->deleteListStatuses->elements[i] =
2420 odr_malloc (assoc->encode,
2421 sizeof(**res->deleteListStatuses->elements));
2422 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2423 res->deleteListStatuses->elements[i]->id =
2424 odr_strdup (assoc->encode, bdrr->setnames[i]);
2428 res->numberNotDeleted = 0;
2429 res->bulkStatuses = 0;
2430 res->deleteMessage = 0;
2433 apdu->which = Z_APDU_deleteResultSetResponse;
2434 apdu->u.deleteResultSetResponse = res;
2438 static void process_close(association *assoc, request *reqb)
2440 Z_Close *req = reqb->apdu_request->u.close;
2441 static char *reasons[] =
2448 "securityViolation",
2455 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2456 reasons[*req->closeReason], req->diagnosticInformation ?
2457 req->diagnosticInformation : "NULL");
2458 if (assoc->version < 3) /* to make do_force respond with close */
2460 do_close_req(assoc, Z_Close_finished,
2461 "Association terminated by client", reqb);
2464 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2468 reqb->len_refid = refid->len;
2469 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2470 memcpy (reqb->refid, refid->buf, refid->len);
2474 reqb->len_refid = 0;
2479 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2481 process_z_response (a, req, res);
2484 bend_request bend_request_mk (bend_association a)
2486 request *nreq = request_get (&a->outgoing);
2487 nreq->request_mem = nmem_create ();
2491 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2496 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2497 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2498 id->len = id->size = req->len_refid;
2499 memcpy (id->buf, req->refid, req->len_refid);
2503 void bend_request_destroy (bend_request *req)
2505 nmem_destroy((*req)->request_mem);
2506 request_release(*req);
2510 int bend_backend_respond (bend_association a, bend_request req)
2514 r = process_z_request (a, req, &msg);
2516 yaz_log (LOG_WARN, "%s", msg);
2520 void bend_request_setdata(bend_request r, void *p)
2525 void *bend_request_getdata(bend_request r)
2527 return r->clientData;
2530 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2532 bend_segment_rr req;
2534 req.segment = reqb->apdu_request->u.segmentRequest;
2535 req.stream = assoc->encode;
2536 req.decode = assoc->decode;
2537 req.print = assoc->print;
2538 req.association = assoc;
2540 (*assoc->init->bend_segment)(assoc->backend, &req);
2545 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2547 bend_esrequest_rr esrequest;
2549 Z_ExtendedServicesRequest *req =
2550 reqb->apdu_request->u.extendedServicesRequest;
2551 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2553 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2555 yaz_log(LOG_DEBUG,"inside Process esRequest");
2557 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2558 esrequest.stream = assoc->encode;
2559 esrequest.decode = assoc->decode;
2560 esrequest.print = assoc->print;
2561 esrequest.errcode = 0;
2562 esrequest.errstring = NULL;
2563 esrequest.request = reqb;
2564 esrequest.association = assoc;
2565 esrequest.taskPackage = 0;
2566 esrequest.referenceId = req->referenceId;
2568 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2570 /* If the response is being delayed, return NULL */
2571 if (esrequest.request == NULL)
2574 resp->referenceId = req->referenceId;
2576 if (esrequest.errcode == -1)
2578 /* Backend service indicates request will be processed */
2579 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2580 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2582 else if (esrequest.errcode == 0)
2584 /* Backend service indicates request will be processed */
2585 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2586 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2590 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2591 esrequest.errstring);
2593 /* Backend indicates error, request will not be processed */
2594 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2595 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2596 resp->num_diagnostics = diagRecs->num_diagRecs;
2597 resp->diagnostics = diagRecs->diagRecs;
2599 /* Do something with the members of bend_extendedservice */
2600 if (esrequest.taskPackage)
2601 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2602 (const char *) esrequest.taskPackage,
2604 yaz_log(LOG_DEBUG,"Send the result apdu");