2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.163 2003-10-20 20:48:37 adam Exp $
9 * Frontend server logic.
11 * This code receives incoming APDUs, and handles client requests by means
14 * Some of the code is getting quite involved, compared to simpler servers -
15 * primarily because it is asynchronous both in the communication with
16 * the user and the backend. We think the complexity will pay off in
17 * the form of greater flexibility when more asynchronous facilities
20 * Memory management has become somewhat involved. In the simple case, where
21 * only one PDU is pending at a time, it will simply reuse the same memory,
22 * once it has found its working size. When we enable multiple concurrent
23 * operations, perhaps even with multiple parallel calls to the backend, it
24 * will maintain a pool of buffers for encoding and decoding, trying to
25 * minimize memory allocation/deallocation during normal operation.
31 #include <sys/types.h>
34 #define S_ISREG(x) (x & _S_IFREG)
44 #include <yaz/yconfig.h>
45 #include <yaz/xmalloc.h>
46 #include <yaz/comstack.h>
49 #include <yaz/proto.h>
52 #include <yaz/logrpn.h>
53 #include <yaz/statserv.h>
54 #include <yaz/diagbib1.h>
55 #include <yaz/charneg.h>
56 #include <yaz/otherinfo.h>
57 #include <yaz/yaz-util.h>
58 #include <yaz/pquery.h>
61 #include <yaz/backend.h>
63 static void process_gdu_request(association *assoc, request *req);
64 static int process_z_request(association *assoc, request *req, char **msg);
65 void backend_response(IOCHAN i, int event);
66 static int process_gdu_response(association *assoc, request *req, Z_GDU *res);
67 static int process_z_response(association *assoc, request *req, Z_APDU *res);
68 static Z_APDU *process_initRequest(association *assoc, request *reqb);
69 static Z_External *init_diagnostics(ODR odr, int errcode, char *errstring);
70 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
72 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
73 bend_search_rr *bsrr, int *fd);
74 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
76 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
77 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
78 static void process_close(association *assoc, request *reqb);
79 void save_referenceId (request *reqb, Z_ReferenceId *refid);
80 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
82 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
84 static FILE *apduf = 0; /* for use in static mode */
85 static statserv_options_block *control_block = 0;
87 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
90 * Create and initialize a new association-handle.
91 * channel : iochannel for the current line.
92 * link : communications channel.
93 * Returns: 0 or a new association handle.
95 association *create_association(IOCHAN channel, COMSTACK link)
100 control_block = statserv_getcontrol();
101 if (!(anew = (association *)xmalloc(sizeof(*anew))))
105 anew->client_chan = channel;
106 anew->client_link = link;
107 anew->cs_get_mask = 0;
108 anew->cs_put_mask = 0;
109 anew->cs_accept_mask = 0;
110 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
111 !(anew->encode = odr_createmem(ODR_ENCODE)))
113 if (*control_block->apdufile)
118 strcpy(filename, control_block->apdufile);
119 if (!(anew->print = odr_createmem(ODR_PRINT)))
121 if (*control_block->apdufile == '@')
123 odr_setprint(anew->print, yaz_log_file());
125 else if (*control_block->apdufile != '-')
127 strcpy(filename, control_block->apdufile);
128 if (!control_block->dynamic)
132 if (!(apduf = fopen(filename, "w")))
134 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
137 setvbuf(apduf, 0, _IONBF, 0);
143 sprintf(filename + strlen(filename), ".%d", getpid());
144 if (!(f = fopen(filename, "w")))
146 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
149 setvbuf(f, 0, _IONBF, 0);
151 odr_setprint(anew->print, f);
156 anew->input_buffer = 0;
157 anew->input_buffer_len = 0;
159 anew->state = ASSOC_NEW;
160 request_initq(&anew->incoming);
161 request_initq(&anew->outgoing);
162 anew->proto = cs_getproto(link);
167 * Free association and release resources.
169 void destroy_association(association *h)
171 statserv_options_block *cb = statserv_getcontrol();
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 request_release(req);
217 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
218 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
220 a->state = ASSOC_DEAD;
223 static void do_close(association *a, int reason, char *message)
225 request *req = request_get(&a->outgoing);
226 do_close_req (a, reason, message, req);
230 * This is where PDUs from the client are read and the further
231 * processing is initiated. Flow of control moves down through the
232 * various process_* functions below, until the encoded result comes back up
233 * to the output handler in here.
235 * h : the I/O channel that has an outstanding event.
236 * event : the current outstanding event.
238 void ir_session(IOCHAN h, int event)
241 association *assoc = (association *)iochan_getdata(h);
242 COMSTACK conn = assoc->client_link;
245 assert(h && conn && assoc);
246 if (event == EVENT_TIMEOUT)
248 if (assoc->state != ASSOC_UP)
250 yaz_log(LOG_LOG, "Final timeout - closing connection.");
252 destroy_association(assoc);
257 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
258 do_close(assoc, Z_Close_lackOfActivity, 0);
262 if (event & assoc->cs_accept_mask)
264 yaz_log (LOG_DEBUG, "ir_session (accept)");
265 if (!cs_accept (conn))
267 yaz_log (LOG_LOG, "accept failed");
268 destroy_association(assoc);
271 iochan_clearflag (h, EVENT_OUTPUT|EVENT_OUTPUT);
272 if (conn->io_pending)
273 { /* cs_accept didn't complete */
274 assoc->cs_accept_mask =
275 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
276 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
278 iochan_setflag (h, assoc->cs_accept_mask);
281 { /* cs_accept completed. Prepare for reading (cs_get) */
282 assoc->cs_accept_mask = 0;
283 assoc->cs_get_mask = EVENT_INPUT;
284 iochan_setflag (h, assoc->cs_get_mask);
288 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
290 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
292 yaz_log(LOG_DEBUG, "ir_session (input)");
293 /* We aren't speaking to this fellow */
294 if (assoc->state == ASSOC_DEAD)
296 yaz_log(LOG_LOG, "Connection closed - end of session");
298 destroy_association(assoc);
302 assoc->cs_get_mask = EVENT_INPUT;
303 if ((res = cs_get(conn, &assoc->input_buffer,
304 &assoc->input_buffer_len)) <= 0)
306 yaz_log(LOG_LOG, "Connection closed by client");
308 destroy_association(assoc);
312 else if (res == 1) /* incomplete read - wait for more */
314 if (conn->io_pending & CS_WANT_WRITE)
315 assoc->cs_get_mask |= EVENT_OUTPUT;
316 iochan_setflag(h, assoc->cs_get_mask);
319 if (cs_more(conn)) /* more stuff - call us again later, please */
320 iochan_setevent(h, EVENT_INPUT);
322 /* we got a complete PDU. Let's decode it */
323 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
324 assoc->input_buffer[0] & 0xff,
325 assoc->input_buffer[1] & 0xff,
326 assoc->input_buffer[2] & 0xff);
327 req = request_get(&assoc->incoming); /* get a new request */
328 odr_reset(assoc->decode);
329 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
330 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
332 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
334 odr_errmsg(odr_geterror(assoc->decode)),
335 odr_getelement(assoc->decode),
336 odr_offset(assoc->decode));
337 if (assoc->decode->error != OHTTP)
339 yaz_log(LOG_LOG, "PDU dump:");
340 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
341 request_release(req);
342 do_close(assoc, Z_Close_protocolError,"Malformed package");
346 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
347 assoc->state = ASSOC_DEAD;
348 process_gdu_response(assoc, req, p);
352 req->request_mem = odr_extract_mem(assoc->decode);
353 if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
355 yaz_log(LOG_WARN, "ODR print error: %s",
356 odr_errmsg(odr_geterror(assoc->print)));
357 odr_reset(assoc->print);
359 request_enq(&assoc->incoming, req);
362 /* can we do something yet? */
363 req = request_head(&assoc->incoming);
364 if (req->state == REQUEST_IDLE)
366 request_deq(&assoc->incoming);
367 process_gdu_request(assoc, req);
370 if (event & assoc->cs_put_mask)
372 request *req = request_head(&assoc->outgoing);
374 assoc->cs_put_mask = 0;
375 yaz_log(LOG_DEBUG, "ir_session (output)");
376 req->state = REQUEST_PENDING;
377 switch (res = cs_put(conn, req->response, req->len_response))
380 yaz_log(LOG_LOG, "Connection closed by client");
382 destroy_association(assoc);
385 case 0: /* all sent - release the request structure */
386 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
388 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
391 nmem_destroy(req->request_mem);
392 request_deq(&assoc->outgoing);
393 request_release(req);
394 if (!request_head(&assoc->outgoing))
395 { /* restore mask for cs_get operation ... */
396 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
397 iochan_setflag(h, assoc->cs_get_mask);
398 if (assoc->state == ASSOC_DEAD)
399 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
403 assoc->cs_put_mask = EVENT_OUTPUT;
407 if (conn->io_pending & CS_WANT_WRITE)
408 assoc->cs_put_mask |= EVENT_OUTPUT;
409 if (conn->io_pending & CS_WANT_READ)
410 assoc->cs_put_mask |= EVENT_INPUT;
411 iochan_setflag(h, assoc->cs_put_mask);
414 if (event & EVENT_EXCEPT)
416 yaz_log(LOG_LOG, "ir_session (exception)");
418 destroy_association(assoc);
423 static int process_z_request(association *assoc, request *req, char **msg);
425 static void assoc_init_reset(association *assoc)
428 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
430 assoc->init->stream = assoc->encode;
431 assoc->init->print = assoc->print;
432 assoc->init->auth = 0;
433 assoc->init->referenceId = 0;
434 assoc->init->implementation_version = 0;
435 assoc->init->implementation_id = 0;
436 assoc->init->implementation_name = 0;
437 assoc->init->bend_sort = NULL;
438 assoc->init->bend_search = NULL;
439 assoc->init->bend_present = NULL;
440 assoc->init->bend_esrequest = NULL;
441 assoc->init->bend_delete = NULL;
442 assoc->init->bend_scan = NULL;
443 assoc->init->bend_segment = NULL;
444 assoc->init->bend_fetch = NULL;
445 assoc->init->bend_explain = NULL;
447 assoc->init->charneg_request = NULL;
448 assoc->init->charneg_response = NULL;
450 assoc->init->decode = assoc->decode;
451 assoc->init->peer_name =
452 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
455 static int srw_bend_init(association *assoc)
457 const char *encoding = "UTF-8";
459 bend_initresult *binitres;
460 statserv_options_block *cb = statserv_getcontrol();
462 assoc_init_reset(assoc);
464 assoc->maximumRecordSize = 3000000;
465 assoc->preferredMessageSize = 3000000;
467 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
468 assoc->init->charneg_request = ce->u.charNeg3;
470 if (!(binitres = (*cb->bend_init)(assoc->init)))
472 yaz_log(LOG_WARN, "Bad response from backend.");
475 assoc->backend = binitres->handle;
479 static int srw_bend_fetch(association *assoc, int pos,
480 Z_SRW_searchRetrieveRequest *srw_req,
481 Z_SRW_record *record)
484 ODR o = assoc->encode;
486 rr.setname = "default";
489 rr.request_format = VAL_TEXT_XML;
490 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
493 rr.comp = (Z_RecordComposition *)
494 odr_malloc(assoc->decode, sizeof(*rr.comp));
495 rr.comp->which = Z_RecordComp_complex;
496 rr.comp->u.complex = (Z_CompSpec *)
497 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
498 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
499 odr_malloc(assoc->encode, sizeof(bool_t));
500 *rr.comp->u.complex->selectAlternativeSyntax = 0;
501 rr.comp->u.complex->num_dbSpecific = 0;
502 rr.comp->u.complex->dbSpecific = 0;
503 rr.comp->u.complex->num_recordSyntax = 0;
504 rr.comp->u.complex->recordSyntax = 0;
506 rr.comp->u.complex->generic = (Z_Specification *)
507 odr_malloc(assoc->decode, sizeof(Z_Specification));
508 rr.comp->u.complex->generic->which = Z_Schema_uri;
509 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
510 rr.comp->u.complex->generic->elementSpec = 0;
512 rr.stream = assoc->encode;
513 rr.print = assoc->print;
519 rr.output_format = VAL_TEXT_XML;
520 rr.output_format_raw = 0;
523 rr.surrogate_flag = 0;
524 rr.schema = srw_req->recordSchema;
526 if (!assoc->init->bend_fetch)
529 (*assoc->init->bend_fetch)(assoc->backend, &rr);
533 record->recordData_buf = rr.record;
534 record->recordData_len = rr.len;
535 record->recordPosition = odr_intdup(o, pos);
537 record->recordSchema = odr_strdup(o, rr.schema);
539 record->recordSchema = 0;
544 static void srw_bend_search(association *assoc, request *req,
545 Z_SRW_searchRetrieveRequest *srw_req,
546 Z_SRW_searchRetrieveResponse *srw_res)
552 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
553 yaz_log(LOG_DEBUG, "srw_bend_search");
556 yaz_log(LOG_DEBUG, "srw_bend_init");
557 if (!srw_bend_init(assoc))
559 srw_error = 3; /* assume Authentication error */
561 srw_res->num_diagnostics = 1;
562 srw_res->diagnostics = (Z_SRW_diagnostic *)
563 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
564 srw_res->diagnostics[0].code =
565 odr_intdup(assoc->encode, srw_error);
566 srw_res->diagnostics[0].details = 0;
571 rr.setname = "default";
574 rr.basenames = &srw_req->database;
577 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
579 if (srw_req->query_type == Z_SRW_query_type_cql)
581 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
582 ext->direct_reference = odr_getoidbystr(assoc->decode,
583 "1.2.840.10003.16.2");
584 ext->indirect_reference = 0;
586 ext->which = Z_External_CQL;
587 ext->u.cql = srw_req->query.cql;
589 rr.query->which = Z_Query_type_104;
590 rr.query->u.type_104 = ext;
592 else if (srw_req->query_type == Z_SRW_query_type_pqf)
594 Z_RPNQuery *RPNquery;
595 YAZ_PQF_Parser pqf_parser;
597 pqf_parser = yaz_pqf_create ();
599 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
605 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
606 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
607 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
612 rr.query->which = Z_Query_type_1;
613 rr.query->u.type_1 = RPNquery;
615 yaz_pqf_destroy (pqf_parser);
620 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
623 if (!srw_error && !assoc->init->bend_search)
628 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
629 srw_res->num_diagnostics = 1;
630 srw_res->diagnostics = (Z_SRW_diagnostic *)
631 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
632 srw_res->diagnostics[0].code =
633 odr_intdup(assoc->encode, srw_error);
634 srw_res->diagnostics[0].details = 0;
638 rr.stream = assoc->encode;
639 rr.decode = assoc->decode;
640 rr.print = assoc->print;
642 rr.association = assoc;
648 yaz_log_zquery(rr.query);
649 (assoc->init->bend_search)(assoc->backend, &rr);
650 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
653 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
654 srw_res->num_diagnostics = 1;
655 srw_res->diagnostics = (Z_SRW_diagnostic *)
656 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
657 srw_res->diagnostics[0].code =
658 odr_intdup(assoc->encode,
659 yaz_diag_bib1_to_srw (rr.errcode));
660 srw_res->diagnostics[0].details = rr.errstring;
661 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
662 *srw_res->diagnostics[0].code);
667 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
668 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
670 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
671 start, number, rr.hits);
673 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
680 yaz_log(LOG_LOG, "Request out or range");
685 int packing = Z_SRW_recordPacking_string;
686 if (start + number > rr.hits)
687 number = rr.hits - start + 1;
688 if (srw_req->recordPacking &&
689 !strcmp(srw_req->recordPacking, "xml"))
690 packing = Z_SRW_recordPacking_XML;
691 srw_res->records = (Z_SRW_record *)
692 odr_malloc(assoc->encode,
693 number * sizeof(*srw_res->records));
694 for (i = 0; i<number; i++)
698 srw_res->records[j].recordPacking = packing;
699 srw_res->records[j].recordData_buf = 0;
700 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
701 errcode = srw_bend_fetch(assoc, i+start, srw_req,
702 srw_res->records + j);
705 srw_res->num_diagnostics = 1;
706 srw_res->diagnostics = (Z_SRW_diagnostic *)
707 odr_malloc(assoc->encode,
708 sizeof(*srw_res->diagnostics));
709 srw_res->diagnostics[0].code =
710 odr_intdup(assoc->encode,
711 yaz_diag_bib1_to_srw (errcode));
712 srw_res->diagnostics[0].details = rr.errstring;
715 if (srw_res->records[j].recordData_buf)
718 srw_res->num_records = j;
720 srw_res->records = 0;
727 static void srw_bend_explain(association *assoc, request *req,
728 Z_SRW_explainRequest *srw_req,
729 Z_SRW_explainResponse *srw_res)
731 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
734 yaz_log(LOG_DEBUG, "srw_bend_init");
735 if (!srw_bend_init(assoc))
738 if (assoc->init && assoc->init->bend_explain)
742 rr.stream = assoc->encode;
743 rr.decode = assoc->decode;
744 rr.print = assoc->print;
746 (*assoc->init->bend_explain)(assoc->backend, &rr);
749 srw_res->explainData_buf = rr.explain_buf;
750 srw_res->explainData_len = strlen(rr.explain_buf);
755 static int hex_digit (int ch)
757 if (ch >= '0' && ch <= '9')
759 else if (ch >= 'a' && ch <= 'f')
761 else if (ch >= 'A' && ch <= 'F')
766 static char *uri_val(const char *path, const char *name, ODR o)
768 size_t nlen = strlen(name);
772 while (path && *path)
774 const char *p1 = strchr(path, '=');
777 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
783 p1 = strchr(path, '&');
785 p1 = strlen(path) + path;
786 ret = odr_malloc(o, p1 - path + 1);
787 while (*path && *path != '&')
794 else if (*path == '%' && path[1] && path[2])
796 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
805 path = strchr(p1, '&');
812 void uri_val_int(const char *path, const char *name, ODR o, int **intp)
814 const char *v = uri_val(path, name, o);
816 *intp = odr_intdup(o, atoi(v));
819 static void process_http_request(association *assoc, request *req)
821 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
822 ODR o = assoc->encode;
824 Z_HTTP_Response *hres = 0;
827 if (!strcmp(hreq->method, "GET"))
829 char *db = "Default";
830 const char *p0 = hreq->path, *p1;
834 Z_SOAP *soap_package = 0;
835 static Z_SOAP_Handler soap_handlers[2] = {
836 {"http://www.loc.gov/zing/srw/v1.0/", 0,
837 (Z_SOAP_fun) yaz_srw_codec},
844 p1 = strchr(p0, '?');
846 p1 = p0 + strlen(p0);
849 db = odr_malloc(assoc->decode, p1 - p0 + 1);
850 memcpy (db, p0, p1 - p0);
854 if (p1 && *p1 == '?' && p1[1])
856 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
857 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
858 char *query = uri_val(p1, "query", o);
859 char *pQuery = uri_val(p1, "pQuery", o);
860 char *sortKeys = uri_val(p1, "sortKeys", o);
864 sr->u.request->query_type = Z_SRW_query_type_cql;
865 sr->u.request->query.cql = query;
869 sr->u.request->query_type = Z_SRW_query_type_pqf;
870 sr->u.request->query.pqf = pQuery;
874 sr->u.request->sort_type = Z_SRW_sort_type_sort;
875 sr->u.request->sort.sortKeys = sortKeys;
877 sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
878 sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
879 if (!sr->u.request->recordPacking)
880 sr->u.request->recordPacking = "xml";
881 uri_val_int(p1, "maximumRecords", o,
882 &sr->u.request->maximumRecords);
883 uri_val_int(p1, "startRecord", o,
884 &sr->u.request->startRecord);
885 if (sr->u.request->startRecord)
886 yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
887 sr->u.request->database = db;
888 srw_bend_search(assoc, req, sr->u.request, res->u.response);
890 soap_package = odr_malloc(o, sizeof(*soap_package));
891 soap_package->which = Z_SOAP_generic;
893 soap_package->u.generic =
894 odr_malloc(o, sizeof(*soap_package->u.generic));
896 soap_package->u.generic->p = res;
897 soap_package->u.generic->ns = soap_handlers[0].ns;
898 soap_package->u.generic->no = 0;
900 soap_package->ns = "SRU";
902 p = z_get_HTTP_Response(o, 200);
903 hres = p->u.HTTP_Response;
905 ret = z_soap_codec_enc(assoc->encode, &soap_package,
906 &hres->content_buf, &hres->content_len,
907 soap_handlers, charset);
909 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
913 strcpy(ctype, "text/xml; charset=");
914 strcat(ctype, charset);
915 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
921 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
922 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
924 srw_bend_explain(assoc, req, sr->u.explain_request,
925 res->u.explain_response);
927 if (res->u.explain_response->explainData_buf)
929 soap_package = odr_malloc(o, sizeof(*soap_package));
930 soap_package->which = Z_SOAP_generic;
932 soap_package->u.generic =
933 odr_malloc(o, sizeof(*soap_package->u.generic));
935 soap_package->u.generic->p = res;
936 soap_package->u.generic->ns = soap_handlers[0].ns;
937 soap_package->u.generic->no = 0;
939 soap_package->ns = "SRU";
941 p = z_get_HTTP_Response(o, 200);
942 hres = p->u.HTTP_Response;
944 ret = z_soap_codec_enc(assoc->encode, &soap_package,
945 &hres->content_buf, &hres->content_len,
946 soap_handlers, charset);
948 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
952 strcpy(ctype, "text/xml; charset=");
953 strcat(ctype, charset);
954 z_HTTP_header_add(o, &hres->headers, "Content-Type",
961 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
962 !memcmp(hreq->path, "/doc/", 5))
967 strcpy(fpath, DOCDIR);
968 strcat(fpath, hreq->path+4);
969 f = fopen(fpath, "rb");
972 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
981 fseek(f, 0L, SEEK_END);
983 if (sz >= 0 && sz < 500000)
985 const char *ctype = "application/octet-stream";
988 p = z_get_HTTP_Response(o, 200);
989 hres = p->u.HTTP_Response;
990 hres->content_buf = (char *) odr_malloc(o, sz + 1);
991 hres->content_len = sz;
992 fseek(f, 0L, SEEK_SET);
993 fread(hres->content_buf, 1, sz, f);
994 if ((cp = strrchr(fpath, '.'))) {
996 if (!strcmp(cp, "png"))
998 else if (!strcmp(cp, "gif"))
1000 else if (!strcmp(cp, "xml"))
1002 else if (!strcmp(cp, "html"))
1003 ctype = "text/html";
1005 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1013 if (!strcmp(hreq->path, "/"))
1018 const char *doclink = "";
1019 p = z_get_HTTP_Response(o, 200);
1020 hres = p->u.HTTP_Response;
1021 hres->content_buf = (char *) odr_malloc(o, 400);
1023 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
1024 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
1026 sprintf (hres->content_buf,
1027 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1030 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1033 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1034 YAZ_VERSION "</P>\n"
1037 "</HTML>\n", doclink);
1038 hres->content_len = strlen(hres->content_buf);
1039 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1045 p = z_get_HTTP_Response(o, 404);
1048 else if (!strcmp(hreq->method, "POST"))
1050 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1052 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1054 Z_SOAP *soap_package = 0;
1056 int http_code = 500;
1057 const char *charset_p = 0;
1060 static Z_SOAP_Handler soap_handlers[2] = {
1062 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1063 (Z_SOAP_fun) yaz_srw_codec},
1067 if ((charset_p = strstr(content_type, "; charset=")))
1071 while (i < 20 && charset_p[i] &&
1072 !strchr("; \n\r", charset_p[i]))
1074 charset = odr_malloc(assoc->encode, i+1);
1075 memcpy(charset, charset_p, i);
1077 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1079 ret = z_soap_codec(assoc->decode, &soap_package,
1080 &hreq->content_buf, &hreq->content_len,
1083 if (!ret && soap_package->which == Z_SOAP_generic &&
1084 soap_package->u.generic->no == 0)
1087 Z_SRW_PDU *sr = soap_package->u.generic->p;
1089 if (sr->which == Z_SRW_searchRetrieve_request)
1092 yaz_srw_get(assoc->encode,
1093 Z_SRW_searchRetrieve_response);
1095 if (!sr->u.request->database)
1097 const char *p0 = hreq->path, *p1;
1100 p1 = strchr(p0, '?');
1102 p1 = p0 + strlen(p0);
1105 sr->u.request->database =
1106 odr_malloc(assoc->decode, p1 - p0 + 1);
1107 memcpy (sr->u.request->database, p0, p1 - p0);
1108 sr->u.request->database[p1 - p0] = '\0';
1111 sr->u.request->database = "Default";
1113 srw_bend_search(assoc, req, sr->u.request,
1116 soap_package->u.generic->p = res;
1119 else if (sr->which == Z_SRW_explain_request)
1122 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1124 srw_bend_explain(assoc, req, sr->u.explain_request,
1125 res->u.explain_response);
1126 if (!res->u.explain_response->explainData_buf)
1128 z_soap_error(assoc->encode, soap_package,
1129 "SOAP-ENV:Client", "Explain Not Supported", 0);
1133 soap_package->u.generic->p = res;
1139 z_soap_error(assoc->encode, soap_package,
1140 "SOAP-ENV:Client", "Bad method", 0);
1144 p = z_get_HTTP_Response(o, 200);
1145 hres = p->u.HTTP_Response;
1146 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1147 &hres->content_buf, &hres->content_len,
1148 soap_handlers, charset);
1149 hres->code = http_code;
1151 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1155 strcpy(ctype, "text/xml; charset=");
1156 strcat(ctype, charset);
1157 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1160 if (!p) /* still no response ? */
1161 p = z_get_HTTP_Response(o, 500);
1165 p = z_get_HTTP_Response(o, 405);
1166 hres = p->u.HTTP_Response;
1168 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1170 hres = p->u.HTTP_Response;
1171 if (!strcmp(hreq->version, "1.0"))
1173 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1174 if (v && !strcmp(v, "Keep-Alive"))
1178 hres->version = "1.0";
1182 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1183 if (v && !strcmp(v, "close"))
1187 hres->version = "1.1";
1191 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1192 assoc->state = ASSOC_DEAD;
1197 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1199 if (alive && isdigit(*alive))
1203 if (t < 0 || t > 3600)
1205 iochan_settimeout(assoc->client_chan,t);
1206 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1208 process_gdu_response(assoc, req, p);
1211 static void process_gdu_request(association *assoc, request *req)
1213 if (req->gdu_request->which == Z_GDU_Z3950)
1216 req->apdu_request = req->gdu_request->u.z3950;
1217 if (process_z_request(assoc, req, &msg) < 0)
1218 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1220 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1221 process_http_request(assoc, req);
1224 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1229 * Initiate request processing.
1231 static int process_z_request(association *assoc, request *req, char **msg)
1237 *msg = "Unknown Error";
1238 assert(req && req->state == REQUEST_IDLE);
1239 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1241 *msg = "Missing InitRequest";
1244 switch (req->apdu_request->which)
1246 case Z_APDU_initRequest:
1247 iochan_settimeout(assoc->client_chan,
1248 statserv_getcontrol()->idle_timeout * 60);
1249 res = process_initRequest(assoc, req); break;
1250 case Z_APDU_searchRequest:
1251 res = process_searchRequest(assoc, req, &fd); break;
1252 case Z_APDU_presentRequest:
1253 res = process_presentRequest(assoc, req, &fd); break;
1254 case Z_APDU_scanRequest:
1255 if (assoc->init->bend_scan)
1256 res = process_scanRequest(assoc, req, &fd);
1259 *msg = "Cannot handle Scan APDU";
1263 case Z_APDU_extendedServicesRequest:
1264 if (assoc->init->bend_esrequest)
1265 res = process_ESRequest(assoc, req, &fd);
1268 *msg = "Cannot handle Extended Services APDU";
1272 case Z_APDU_sortRequest:
1273 if (assoc->init->bend_sort)
1274 res = process_sortRequest(assoc, req, &fd);
1277 *msg = "Cannot handle Sort APDU";
1282 process_close(assoc, req);
1284 case Z_APDU_deleteResultSetRequest:
1285 if (assoc->init->bend_delete)
1286 res = process_deleteRequest(assoc, req, &fd);
1289 *msg = "Cannot handle Delete APDU";
1293 case Z_APDU_segmentRequest:
1294 if (assoc->init->bend_segment)
1296 res = process_segmentRequest (assoc, req);
1300 *msg = "Cannot handle Segment APDU";
1305 *msg = "Bad APDU received";
1310 yaz_log(LOG_DEBUG, " result immediately available");
1311 retval = process_z_response(assoc, req, res);
1315 yaz_log(LOG_DEBUG, " result unavailble");
1318 else /* no result yet - one will be provided later */
1322 /* Set up an I/O handler for the fd supplied by the backend */
1324 yaz_log(LOG_DEBUG, " establishing handler for result");
1325 req->state = REQUEST_PENDING;
1326 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1328 iochan_setdata(chan, assoc);
1335 * Handle message from the backend.
1337 void backend_response(IOCHAN i, int event)
1339 association *assoc = (association *)iochan_getdata(i);
1340 request *req = request_head(&assoc->incoming);
1344 yaz_log(LOG_DEBUG, "backend_response");
1345 assert(assoc && req && req->state != REQUEST_IDLE);
1346 /* determine what it is we're waiting for */
1347 switch (req->apdu_request->which)
1349 case Z_APDU_searchRequest:
1350 res = response_searchRequest(assoc, req, 0, &fd); break;
1352 case Z_APDU_presentRequest:
1353 res = response_presentRequest(assoc, req, 0, &fd); break;
1354 case Z_APDU_scanRequest:
1355 res = response_scanRequest(assoc, req, 0, &fd); break;
1358 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1361 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1363 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1364 do_close(assoc, Z_Close_systemProblem, 0);
1368 else if (!res) /* no result yet - try again later */
1370 yaz_log(LOG_DEBUG, " no result yet");
1371 iochan_setfd(i, fd); /* in case fd has changed */
1376 * Encode response, and transfer the request structure to the outgoing queue.
1378 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1380 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1382 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1384 yaz_log(LOG_WARN, "ODR print error: %s",
1385 odr_errmsg(odr_geterror(assoc->print)));
1386 odr_reset(assoc->print);
1388 if (!z_GDU(assoc->encode, &res, 0, 0))
1390 yaz_log(LOG_WARN, "ODR error when decoding PDU: %s [element %s]",
1391 odr_errmsg(odr_geterror(assoc->decode)),
1392 odr_getelement(assoc->decode));
1393 request_release(req);
1396 req->response = odr_getbuf(assoc->encode, &req->len_response,
1397 &req->size_response);
1398 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1399 odr_reset(assoc->encode);
1400 req->state = REQUEST_IDLE;
1401 request_enq(&assoc->outgoing, req);
1402 /* turn the work over to the ir_session handler */
1403 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1404 assoc->cs_put_mask = EVENT_OUTPUT;
1405 /* Is there more work to be done? give that to the input handler too */
1407 if (request_head(&assoc->incoming))
1409 yaz_log (LOG_DEBUG, "more work to be done");
1410 iochan_setevent(assoc->client_chan, EVENT_WORK);
1417 * Encode response, and transfer the request structure to the outgoing queue.
1419 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1421 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1422 gres->which = Z_GDU_Z3950;
1423 gres->u.z3950 = res;
1425 return process_gdu_response(assoc, req, gres);
1430 * Handle init request.
1431 * At the moment, we don't check the options
1432 * anywhere else in the code - we just try not to do anything that would
1433 * break a naive client. We'll toss 'em into the association block when
1434 * we need them there.
1436 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1438 statserv_options_block *cb = statserv_getcontrol();
1439 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1440 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1441 Z_InitResponse *resp = apdu->u.initResponse;
1442 bend_initresult *binitres;
1446 yaz_log(LOG_LOG, "Got initRequest");
1447 if (req->implementationId)
1448 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1449 if (req->implementationName)
1450 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1451 if (req->implementationVersion)
1452 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1454 assoc_init_reset(assoc);
1456 assoc->init->auth = req->idAuthentication;
1457 assoc->init->referenceId = req->referenceId;
1459 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1461 Z_CharSetandLanguageNegotiation *negotiation =
1462 yaz_get_charneg_record (req->otherInfo);
1463 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1464 assoc->init->charneg_request = negotiation;
1467 if (!(binitres = (*cb->bend_init)(assoc->init)))
1469 yaz_log(LOG_WARN, "Bad response from backend.");
1473 assoc->backend = binitres->handle;
1474 if ((assoc->init->bend_sort))
1475 yaz_log (LOG_DEBUG, "Sort handler installed");
1476 if ((assoc->init->bend_search))
1477 yaz_log (LOG_DEBUG, "Search handler installed");
1478 if ((assoc->init->bend_present))
1479 yaz_log (LOG_DEBUG, "Present handler installed");
1480 if ((assoc->init->bend_esrequest))
1481 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1482 if ((assoc->init->bend_delete))
1483 yaz_log (LOG_DEBUG, "Delete handler installed");
1484 if ((assoc->init->bend_scan))
1485 yaz_log (LOG_DEBUG, "Scan handler installed");
1486 if ((assoc->init->bend_segment))
1487 yaz_log (LOG_DEBUG, "Segment handler installed");
1489 resp->referenceId = req->referenceId;
1491 /* let's tell the client what we can do */
1492 if (ODR_MASK_GET(req->options, Z_Options_search))
1494 ODR_MASK_SET(resp->options, Z_Options_search);
1495 strcat(options, "srch");
1497 if (ODR_MASK_GET(req->options, Z_Options_present))
1499 ODR_MASK_SET(resp->options, Z_Options_present);
1500 strcat(options, " prst");
1502 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1503 assoc->init->bend_delete)
1505 ODR_MASK_SET(resp->options, Z_Options_delSet);
1506 strcat(options, " del");
1508 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1509 assoc->init->bend_esrequest)
1511 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1512 strcat (options, " extendedServices");
1514 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1516 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1517 strcat(options, " namedresults");
1519 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1521 ODR_MASK_SET(resp->options, Z_Options_scan);
1522 strcat(options, " scan");
1524 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1526 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1527 strcat(options, " concurrop");
1529 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1531 ODR_MASK_SET(resp->options, Z_Options_sort);
1532 strcat(options, " sort");
1535 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1536 && assoc->init->charneg_response)
1538 Z_OtherInformation **p;
1539 Z_OtherInformationUnit *p0;
1541 yaz_oi_APDU(apdu, &p);
1543 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1544 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1546 p0->which = Z_OtherInfo_externallyDefinedInfo;
1547 p0->information.externallyDefinedInfo =
1548 assoc->init->charneg_response;
1550 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1551 strcat(options, " negotiation");
1554 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1556 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1557 assoc->version = 2; /* 1 & 2 are equivalent */
1559 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1561 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1564 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1566 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1570 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1571 assoc->maximumRecordSize = *req->maximumRecordSize;
1572 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1573 assoc->maximumRecordSize = control_block->maxrecordsize;
1574 assoc->preferredMessageSize = *req->preferredMessageSize;
1575 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1576 assoc->preferredMessageSize = assoc->maximumRecordSize;
1578 resp->preferredMessageSize = &assoc->preferredMessageSize;
1579 resp->maximumRecordSize = &assoc->maximumRecordSize;
1581 resp->implementationName = "GFS/YAZ";
1583 if (assoc->init->implementation_id)
1586 odr_malloc (assoc->encode,
1587 strlen(assoc->init->implementation_id) + 10 +
1588 strlen(resp->implementationId));
1589 sprintf (nv, "%s / %s",
1590 resp->implementationId, assoc->init->implementation_id);
1591 resp->implementationId = nv;
1593 if (assoc->init->implementation_name)
1596 odr_malloc (assoc->encode,
1597 strlen(assoc->init->implementation_name) + 10 +
1598 strlen(resp->implementationName));
1599 sprintf (nv, "%s / %s",
1600 resp->implementationName, assoc->init->implementation_name);
1601 resp->implementationName = nv;
1603 if (assoc->init->implementation_version)
1606 odr_malloc (assoc->encode,
1607 strlen(assoc->init->implementation_version) + 10 +
1608 strlen(resp->implementationVersion));
1609 sprintf (nv, "YAZ %s / %s",
1610 resp->implementationVersion,
1611 assoc->init->implementation_version);
1612 resp->implementationVersion = nv;
1615 if (binitres->errcode)
1617 yaz_log(LOG_LOG, "Connection rejected by backend.");
1619 assoc->state = ASSOC_DEAD;
1620 resp->userInformationField = init_diagnostics(assoc->encode,
1622 binitres->errstring);
1625 assoc->state = ASSOC_UP;
1630 * Diagnostic in default format, to be returned as either a surrogate
1631 * or non-surrogate diagnostic in the context of an open session, or
1632 * as User-information when an Init is refused.
1634 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1636 int *err = odr_intdup(odr, error);
1637 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1638 odr_malloc (odr, sizeof(*dr));
1640 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1641 addinfo ? " -- " : "", addinfo ? addinfo : "");
1643 dr->diagnosticSetId =
1644 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1645 dr->condition = err;
1646 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1647 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1652 * Set the specified `errcode' and `errstring' into a UserInfo-1
1653 * external to be returned to the client in accordance with Z35.90
1654 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1655 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1657 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1661 Z_OtherInformation *u;
1662 Z_OtherInformationUnit *l;
1663 Z_DiagnosticFormat *d;
1664 Z_DiagnosticFormat_s *e;
1666 x = (Z_External*) odr_malloc(odr, sizeof *x);
1668 x->indirect_reference = 0;
1669 oid.proto = PROTO_Z3950;
1670 oid.oclass = CLASS_USERINFO;
1671 oid.value = VAL_USERINFO1;
1672 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1673 x->which = Z_External_userInfo1;
1675 u = odr_malloc(odr, sizeof *u);
1677 u->num_elements = 1;
1678 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1679 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1682 l->which = Z_OtherInfo_externallyDefinedInfo;
1684 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1685 l->information.externallyDefinedInfo = x2;
1687 x2->indirect_reference = 0;
1688 oid.oclass = CLASS_DIAGSET;
1689 oid.value = VAL_DIAG1;
1690 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1691 x2->which = Z_External_diag1;
1693 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1696 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1697 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1700 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1701 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1706 * nonsurrogate diagnostic record.
1708 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1710 Z_Records *rec = (Z_Records *)
1711 odr_malloc (assoc->encode, sizeof(*rec));
1712 rec->which = Z_Records_NSD;
1713 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1718 * surrogate diagnostic.
1720 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1721 int error, char *addinfo)
1723 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1724 odr_malloc (assoc->encode, sizeof(*rec));
1725 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1727 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1728 rec->databaseName = dbname;
1729 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1730 rec->u.surrogateDiagnostic = drec;
1731 drec->which = Z_DiagRec_defaultFormat;
1732 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1738 * multiple nonsurrogate diagnostics.
1740 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1742 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1743 int *err = odr_intdup(assoc->encode, error);
1744 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1745 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1746 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1747 odr_malloc (assoc->encode, sizeof(*rec));
1749 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1751 recs->num_diagRecs = 1;
1752 recs->diagRecs = recp;
1754 drec->which = Z_DiagRec_defaultFormat;
1755 drec->u.defaultFormat = rec;
1757 rec->diagnosticSetId =
1758 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1759 rec->condition = err;
1761 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1762 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1766 static Z_Records *pack_records(association *a, char *setname, int start,
1767 int *num, Z_RecordComposition *comp,
1768 int *next, int *pres, oid_value format,
1769 Z_ReferenceId *referenceId,
1772 int recno, total_length = 0, toget = *num, dumped_records = 0;
1773 Z_Records *records =
1774 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1775 Z_NamePlusRecordList *reclist =
1776 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1777 Z_NamePlusRecord **list =
1778 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1780 records->which = Z_Records_DBOSD;
1781 records->u.databaseOrSurDiagnostics = reclist;
1782 reclist->num_records = 0;
1783 reclist->records = list;
1784 *pres = Z_PRES_SUCCESS;
1788 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1789 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1790 a->maximumRecordSize);
1791 for (recno = start; reclist->num_records < toget; recno++)
1794 Z_NamePlusRecord *thisrec;
1795 int this_length = 0;
1797 * we get the number of bytes allocated on the stream before any
1798 * allocation done by the backend - this should give us a reasonable
1799 * idea of the total size of the data so far.
1801 total_length = odr_total(a->encode) - dumped_records;
1807 freq.last_in_set = 0;
1808 freq.setname = setname;
1809 freq.surrogate_flag = 0;
1810 freq.number = recno;
1812 freq.request_format = format;
1813 freq.request_format_raw = oid;
1814 freq.output_format = format;
1815 freq.output_format_raw = 0;
1816 freq.stream = a->encode;
1817 freq.print = a->print;
1818 freq.referenceId = referenceId;
1820 (*a->init->bend_fetch)(a->backend, &freq);
1821 /* backend should be able to signal whether error is system-wide
1822 or only pertaining to current record */
1825 if (!freq.surrogate_flag)
1828 *pres = Z_PRES_FAILURE;
1829 /* for 'present request out of range',
1830 set addinfo to record position if not set */
1831 if (freq.errcode == 13 && freq.errstring == 0)
1833 sprintf (s, "%d", recno);
1836 return diagrec(a, freq.errcode, freq.errstring);
1838 reclist->records[reclist->num_records] =
1839 surrogatediagrec(a, freq.basename, freq.errcode,
1841 reclist->num_records++;
1842 *next = freq.last_in_set ? 0 : recno + 1;
1846 this_length = freq.len;
1848 this_length = odr_total(a->encode) - total_length;
1849 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1850 this_length, total_length);
1851 if (this_length + total_length > a->preferredMessageSize)
1853 /* record is small enough, really */
1854 if (this_length <= a->preferredMessageSize)
1856 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1857 *pres = Z_PRES_PARTIAL_2;
1860 /* record can only be fetched by itself */
1861 if (this_length < a->maximumRecordSize)
1863 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1866 yaz_log(LOG_DEBUG, " Dropped it");
1867 reclist->records[reclist->num_records] =
1868 surrogatediagrec(a, freq.basename, 16, 0);
1869 reclist->num_records++;
1870 *next = freq.last_in_set ? 0 : recno + 1;
1871 dumped_records += this_length;
1875 else /* too big entirely */
1877 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1878 reclist->records[reclist->num_records] =
1879 surrogatediagrec(a, freq.basename, 17, 0);
1880 reclist->num_records++;
1881 *next = freq.last_in_set ? 0 : recno + 1;
1882 dumped_records += this_length;
1887 if (!(thisrec = (Z_NamePlusRecord *)
1888 odr_malloc(a->encode, sizeof(*thisrec))))
1890 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1891 strlen(freq.basename) + 1)))
1893 strcpy(thisrec->databaseName, freq.basename);
1894 thisrec->which = Z_NamePlusRecord_databaseRecord;
1896 if (freq.output_format_raw)
1898 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1899 freq.output_format = ident->value;
1901 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1902 freq.record, freq.len);
1903 if (!thisrec->u.databaseRecord)
1905 reclist->records[reclist->num_records] = thisrec;
1906 reclist->num_records++;
1907 *next = freq.last_in_set ? 0 : recno + 1;
1909 *num = reclist->num_records;
1913 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1916 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1917 bend_search_rr *bsrr =
1918 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1920 yaz_log(LOG_LOG, "Got SearchRequest.");
1922 bsrr->request = reqb;
1923 bsrr->association = assoc;
1924 bsrr->referenceId = req->referenceId;
1925 save_referenceId (reqb, bsrr->referenceId);
1927 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1928 if (req->databaseNames)
1931 for (i = 0; i < req->num_databaseNames; i++)
1932 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1934 yaz_log_zquery(req->query);
1936 if (assoc->init->bend_search)
1938 bsrr->setname = req->resultSetName;
1939 bsrr->replace_set = *req->replaceIndicator;
1940 bsrr->num_bases = req->num_databaseNames;
1941 bsrr->basenames = req->databaseNames;
1942 bsrr->query = req->query;
1943 bsrr->stream = assoc->encode;
1944 bsrr->decode = assoc->decode;
1945 bsrr->print = assoc->print;
1948 bsrr->errstring = NULL;
1949 bsrr->search_info = NULL;
1950 (assoc->init->bend_search)(assoc->backend, bsrr);
1954 return response_searchRequest(assoc, reqb, bsrr, fd);
1957 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1960 * Prepare a searchresponse based on the backend results. We probably want
1961 * to look at making the fetching of records nonblocking as well, but
1962 * so far, we'll keep things simple.
1963 * If bsrt is null, that means we're called in response to a communications
1964 * event, and we'll have to get the response for ourselves.
1966 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1967 bend_search_rr *bsrt, int *fd)
1969 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1970 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1971 Z_SearchResponse *resp = (Z_SearchResponse *)
1972 odr_malloc (assoc->encode, sizeof(*resp));
1973 int *nulint = odr_intdup (assoc->encode, 0);
1974 bool_t *sr = odr_intdup(assoc->encode, 1);
1975 int *next = odr_intdup(assoc->encode, 0);
1976 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1978 apdu->which = Z_APDU_searchResponse;
1979 apdu->u.searchResponse = resp;
1980 resp->referenceId = req->referenceId;
1981 resp->additionalSearchInfo = 0;
1982 resp->otherInfo = 0;
1984 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1986 yaz_log(LOG_FATAL, "Bad result from backend");
1989 else if (bsrt->errcode)
1991 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1992 resp->resultCount = nulint;
1993 resp->numberOfRecordsReturned = nulint;
1994 resp->nextResultSetPosition = nulint;
1995 resp->searchStatus = nulint;
1996 resp->resultSetStatus = none;
1997 resp->presentStatus = 0;
2001 int *toget = odr_intdup(assoc->encode, 0);
2002 int *presst = odr_intdup(assoc->encode, 0);
2003 Z_RecordComposition comp, *compp = 0;
2005 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
2008 resp->resultCount = &bsrt->hits;
2010 comp.which = Z_RecordComp_simple;
2011 /* how many records does the user agent want, then? */
2012 if (bsrt->hits <= *req->smallSetUpperBound)
2014 *toget = bsrt->hits;
2015 if ((comp.u.simple = req->smallSetElementSetNames))
2018 else if (bsrt->hits < *req->largeSetLowerBound)
2020 *toget = *req->mediumSetPresentNumber;
2021 if (*toget > bsrt->hits)
2022 *toget = bsrt->hits;
2023 if ((comp.u.simple = req->mediumSetElementSetNames))
2029 if (*toget && !resp->records)
2034 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2037 form = prefformat->value;
2038 resp->records = pack_records(assoc, req->resultSetName, 1,
2039 toget, compp, next, presst, form, req->referenceId,
2040 req->preferredRecordSyntax);
2043 resp->numberOfRecordsReturned = toget;
2044 resp->nextResultSetPosition = next;
2045 resp->searchStatus = sr;
2046 resp->resultSetStatus = 0;
2047 resp->presentStatus = presst;
2051 if (*resp->resultCount)
2053 resp->numberOfRecordsReturned = nulint;
2054 resp->nextResultSetPosition = next;
2055 resp->searchStatus = sr;
2056 resp->resultSetStatus = 0;
2057 resp->presentStatus = 0;
2060 resp->additionalSearchInfo = bsrt->search_info;
2065 * Maybe we got a little over-friendly when we designed bend_fetch to
2066 * get only one record at a time. Some backends can optimise multiple-record
2067 * fetches, and at any rate, there is some overhead involved in
2068 * all that selecting and hopping around. Problem is, of course, that the
2069 * frontend can't know ahead of time how many records it'll need to
2070 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2071 * is downright lousy as a bulk data transfer protocol.
2073 * To start with, we'll do the fetching of records from the backend
2074 * in one operation: To save some trips in and out of the event-handler,
2075 * and to simplify the interface to pack_records. At any rate, asynch
2076 * operation is more fun in operations that have an unpredictable execution
2077 * speed - which is normally more true for search than for present.
2079 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2082 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2086 Z_PresentResponse *resp;
2090 yaz_log(LOG_LOG, "Got PresentRequest.");
2092 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2095 form = prefformat->value;
2096 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2098 resp->presentStatus = odr_intdup(assoc->encode, 0);
2099 if (assoc->init->bend_present)
2101 bend_present_rr *bprr = (bend_present_rr *)
2102 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2103 bprr->setname = req->resultSetId;
2104 bprr->start = *req->resultSetStartPoint;
2105 bprr->number = *req->numberOfRecordsRequested;
2106 bprr->format = form;
2107 bprr->comp = req->recordComposition;
2108 bprr->referenceId = req->referenceId;
2109 bprr->stream = assoc->encode;
2110 bprr->print = assoc->print;
2111 bprr->request = reqb;
2112 bprr->association = assoc;
2114 bprr->errstring = NULL;
2115 (*assoc->init->bend_present)(assoc->backend, bprr);
2121 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2122 *resp->presentStatus = Z_PRES_FAILURE;
2125 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2126 next = odr_intdup(assoc->encode, 0);
2127 num = odr_intdup(assoc->encode, 0);
2129 apdu->which = Z_APDU_presentResponse;
2130 apdu->u.presentResponse = resp;
2131 resp->referenceId = req->referenceId;
2132 resp->otherInfo = 0;
2136 *num = *req->numberOfRecordsRequested;
2138 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2139 num, req->recordComposition, next, resp->presentStatus,
2140 form, req->referenceId, req->preferredRecordSyntax);
2144 resp->numberOfRecordsReturned = num;
2145 resp->nextResultSetPosition = next;
2151 * Scan was implemented rather in a hurry, and with support for only the basic
2152 * elements of the service in the backend API. Suggestions are welcome.
2154 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2156 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2157 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2158 Z_ScanResponse *res = (Z_ScanResponse *)
2159 odr_malloc (assoc->encode, sizeof(*res));
2160 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2161 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2162 Z_ListEntries *ents = (Z_ListEntries *)
2163 odr_malloc (assoc->encode, sizeof(*ents));
2164 Z_DiagRecs *diagrecs_p = NULL;
2166 bend_scan_rr *bsrr = (bend_scan_rr *)
2167 odr_malloc (assoc->encode, sizeof(*bsrr));
2168 struct scan_entry *save_entries;
2170 yaz_log(LOG_LOG, "Got ScanRequest");
2172 apdu->which = Z_APDU_scanResponse;
2173 apdu->u.scanResponse = res;
2174 res->referenceId = req->referenceId;
2176 /* if step is absent, set it to 0 */
2177 res->stepSize = odr_intdup(assoc->encode, 0);
2179 *res->stepSize = *req->stepSize;
2181 res->scanStatus = scanStatus;
2182 res->numberOfEntriesReturned = numberOfEntriesReturned;
2183 res->positionOfTerm = 0;
2184 res->entries = ents;
2185 ents->num_entries = 0;
2186 ents->entries = NULL;
2187 ents->num_nonsurrogateDiagnostics = 0;
2188 ents->nonsurrogateDiagnostics = NULL;
2189 res->attributeSet = 0;
2192 if (req->databaseNames)
2195 for (i = 0; i < req->num_databaseNames; i++)
2196 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2198 bsrr->num_bases = req->num_databaseNames;
2199 bsrr->basenames = req->databaseNames;
2200 bsrr->num_entries = *req->numberOfTermsRequested;
2201 bsrr->term = req->termListAndStartPoint;
2202 bsrr->referenceId = req->referenceId;
2203 bsrr->stream = assoc->encode;
2204 bsrr->print = assoc->print;
2205 bsrr->step_size = res->stepSize;
2207 /* Note that version 2.0 of YAZ and older did not set entries ..
2208 We do now. And when we do it's easier to extend the scan entry
2209 We know that if the scan handler did set entries, it will
2210 not know of new member display_term.
2212 if (bsrr->num_entries > 0)
2215 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2217 for (i = 0; i<bsrr->num_entries; i++)
2219 bsrr->entries[i].term = 0;
2220 bsrr->entries[i].occurrences = 0;
2221 bsrr->entries[i].errcode = 0;
2222 bsrr->entries[i].errstring = 0;
2223 bsrr->entries[i].display_term = 0;
2226 save_entries = bsrr->entries; /* save it so we can compare later */
2228 if (req->attributeSet &&
2229 (attset = oid_getentbyoid(req->attributeSet)) &&
2230 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2231 bsrr->attributeset = attset->value;
2233 bsrr->attributeset = VAL_NONE;
2234 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2235 bsrr->term_position = req->preferredPositionInResponse ?
2236 *req->preferredPositionInResponse : 1;
2237 ((int (*)(void *, bend_scan_rr *))
2238 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2240 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2244 Z_Entry **tab = (Z_Entry **)
2245 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2247 if (bsrr->status == BEND_SCAN_PARTIAL)
2248 *scanStatus = Z_Scan_partial_5;
2250 *scanStatus = Z_Scan_success;
2251 ents->entries = tab;
2252 ents->num_entries = bsrr->num_entries;
2253 res->numberOfEntriesReturned = &ents->num_entries;
2254 res->positionOfTerm = &bsrr->term_position;
2255 for (i = 0; i < bsrr->num_entries; i++)
2261 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2262 if (bsrr->entries[i].occurrences >= 0)
2264 e->which = Z_Entry_termInfo;
2265 e->u.termInfo = t = (Z_TermInfo *)
2266 odr_malloc(assoc->encode, sizeof(*t));
2267 t->suggestedAttributes = 0;
2269 if (save_entries == bsrr->entries &&
2270 bsrr->entries[i].display_term)
2272 /* the entries was NOT set by the handler. So it's
2273 safe to test for new member display_term. It is
2276 t->displayTerm = odr_strdup(assoc->encode,
2277 bsrr->entries[i].display_term);
2279 t->alternativeTerm = 0;
2280 t->byAttributes = 0;
2281 t->otherTermInfo = 0;
2282 t->globalOccurrences = &bsrr->entries[i].occurrences;
2283 t->term = (Z_Term *)
2284 odr_malloc(assoc->encode, sizeof(*t->term));
2285 t->term->which = Z_Term_general;
2286 t->term->u.general = o =
2287 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2288 o->buf = (unsigned char *)
2289 odr_malloc(assoc->encode, o->len = o->size =
2290 strlen(bsrr->entries[i].term));
2291 memcpy(o->buf, bsrr->entries[i].term, o->len);
2292 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2293 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2297 Z_DiagRecs *drecs = diagrecs (assoc,
2298 bsrr->entries[i].errcode,
2299 bsrr->entries[i].errstring);
2300 assert (drecs->num_diagRecs == 1);
2301 e->which = Z_Entry_surrogateDiagnostic;
2302 assert (drecs->diagRecs[0]);
2303 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2309 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2310 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2315 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2318 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2319 Z_SortResponse *res = (Z_SortResponse *)
2320 odr_malloc (assoc->encode, sizeof(*res));
2321 bend_sort_rr *bsrr = (bend_sort_rr *)
2322 odr_malloc (assoc->encode, sizeof(*bsrr));
2324 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2326 yaz_log(LOG_LOG, "Got SortRequest.");
2328 bsrr->num_input_setnames = req->num_inputResultSetNames;
2329 bsrr->input_setnames = req->inputResultSetNames;
2330 bsrr->referenceId = req->referenceId;
2331 bsrr->output_setname = req->sortedResultSetName;
2332 bsrr->sort_sequence = req->sortSequence;
2333 bsrr->stream = assoc->encode;
2334 bsrr->print = assoc->print;
2336 bsrr->sort_status = Z_SortStatus_failure;
2338 bsrr->errstring = 0;
2340 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2342 res->referenceId = bsrr->referenceId;
2343 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2344 res->resultSetStatus = 0;
2347 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2348 res->diagnostics = dr->diagRecs;
2349 res->num_diagnostics = dr->num_diagRecs;
2353 res->num_diagnostics = 0;
2354 res->diagnostics = 0;
2356 res->resultCount = 0;
2359 apdu->which = Z_APDU_sortResponse;
2360 apdu->u.sortResponse = res;
2364 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2367 Z_DeleteResultSetRequest *req =
2368 reqb->apdu_request->u.deleteResultSetRequest;
2369 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2370 odr_malloc (assoc->encode, sizeof(*res));
2371 bend_delete_rr *bdrr = (bend_delete_rr *)
2372 odr_malloc (assoc->encode, sizeof(*bdrr));
2373 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2375 yaz_log(LOG_LOG, "Got DeleteRequest.");
2377 bdrr->num_setnames = req->num_resultSetList;
2378 bdrr->setnames = req->resultSetList;
2379 bdrr->stream = assoc->encode;
2380 bdrr->print = assoc->print;
2381 bdrr->function = *req->deleteFunction;
2382 bdrr->referenceId = req->referenceId;
2384 if (bdrr->num_setnames > 0)
2387 bdrr->statuses = (int*)
2388 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2389 bdrr->num_setnames);
2390 for (i = 0; i < bdrr->num_setnames; i++)
2391 bdrr->statuses[i] = 0;
2393 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2395 res->referenceId = req->referenceId;
2397 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2399 res->deleteListStatuses = 0;
2400 if (bdrr->num_setnames > 0)
2403 res->deleteListStatuses = (Z_ListStatuses *)
2404 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2405 res->deleteListStatuses->num = bdrr->num_setnames;
2406 res->deleteListStatuses->elements =
2408 odr_malloc (assoc->encode,
2409 sizeof(*res->deleteListStatuses->elements) *
2410 bdrr->num_setnames);
2411 for (i = 0; i<bdrr->num_setnames; i++)
2413 res->deleteListStatuses->elements[i] =
2415 odr_malloc (assoc->encode,
2416 sizeof(**res->deleteListStatuses->elements));
2417 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2418 res->deleteListStatuses->elements[i]->id =
2419 odr_strdup (assoc->encode, bdrr->setnames[i]);
2423 res->numberNotDeleted = 0;
2424 res->bulkStatuses = 0;
2425 res->deleteMessage = 0;
2428 apdu->which = Z_APDU_deleteResultSetResponse;
2429 apdu->u.deleteResultSetResponse = res;
2433 static void process_close(association *assoc, request *reqb)
2435 Z_Close *req = reqb->apdu_request->u.close;
2436 static char *reasons[] =
2443 "securityViolation",
2450 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2451 reasons[*req->closeReason], req->diagnosticInformation ?
2452 req->diagnosticInformation : "NULL");
2453 if (assoc->version < 3) /* to make do_force respond with close */
2455 do_close_req(assoc, Z_Close_finished,
2456 "Association terminated by client", reqb);
2459 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2463 reqb->len_refid = refid->len;
2464 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2465 memcpy (reqb->refid, refid->buf, refid->len);
2469 reqb->len_refid = 0;
2474 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2476 process_z_response (a, req, res);
2479 bend_request bend_request_mk (bend_association a)
2481 request *nreq = request_get (&a->outgoing);
2482 nreq->request_mem = nmem_create ();
2486 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2491 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2492 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2493 id->len = id->size = req->len_refid;
2494 memcpy (id->buf, req->refid, req->len_refid);
2498 void bend_request_destroy (bend_request *req)
2500 nmem_destroy((*req)->request_mem);
2501 request_release(*req);
2505 int bend_backend_respond (bend_association a, bend_request req)
2509 r = process_z_request (a, req, &msg);
2511 yaz_log (LOG_WARN, "%s", msg);
2515 void bend_request_setdata(bend_request r, void *p)
2520 void *bend_request_getdata(bend_request r)
2522 return r->clientData;
2525 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2527 bend_segment_rr req;
2529 req.segment = reqb->apdu_request->u.segmentRequest;
2530 req.stream = assoc->encode;
2531 req.decode = assoc->decode;
2532 req.print = assoc->print;
2533 req.association = assoc;
2535 (*assoc->init->bend_segment)(assoc->backend, &req);
2540 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2542 bend_esrequest_rr esrequest;
2544 Z_ExtendedServicesRequest *req =
2545 reqb->apdu_request->u.extendedServicesRequest;
2546 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2548 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2550 yaz_log(LOG_DEBUG,"inside Process esRequest");
2552 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2553 esrequest.stream = assoc->encode;
2554 esrequest.decode = assoc->decode;
2555 esrequest.print = assoc->print;
2556 esrequest.errcode = 0;
2557 esrequest.errstring = NULL;
2558 esrequest.request = reqb;
2559 esrequest.association = assoc;
2560 esrequest.taskPackage = 0;
2561 esrequest.referenceId = req->referenceId;
2563 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2565 /* If the response is being delayed, return NULL */
2566 if (esrequest.request == NULL)
2569 resp->referenceId = req->referenceId;
2571 if (esrequest.errcode == -1)
2573 /* Backend service indicates request will be processed */
2574 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2575 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2577 else if (esrequest.errcode == 0)
2579 /* Backend service indicates request will be processed */
2580 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2581 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2585 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2586 esrequest.errstring);
2588 /* Backend indicates error, request will not be processed */
2589 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2590 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2591 resp->num_diagnostics = diagRecs->num_diagRecs;
2592 resp->diagnostics = diagRecs->diagRecs;
2594 /* Do something with the members of bend_extendedservice */
2595 if (esrequest.taskPackage)
2596 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2597 (const char *) esrequest.taskPackage,
2599 yaz_log(LOG_DEBUG,"Send the result apdu");