2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.162 2003-10-20 18:20:55 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 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
217 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
219 a->state = ASSOC_DEAD;
222 static void do_close(association *a, int reason, char *message)
224 request *req = request_get(&a->outgoing);
225 request_release(req);
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));
1395 req->response = odr_getbuf(assoc->encode, &req->len_response,
1396 &req->size_response);
1397 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1398 odr_reset(assoc->encode);
1399 req->state = REQUEST_IDLE;
1400 request_enq(&assoc->outgoing, req);
1401 /* turn the work over to the ir_session handler */
1402 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1403 assoc->cs_put_mask = EVENT_OUTPUT;
1404 /* Is there more work to be done? give that to the input handler too */
1406 if (request_head(&assoc->incoming))
1408 yaz_log (LOG_DEBUG, "more work to be done");
1409 iochan_setevent(assoc->client_chan, EVENT_WORK);
1416 * Encode response, and transfer the request structure to the outgoing queue.
1418 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1420 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1421 gres->which = Z_GDU_Z3950;
1422 gres->u.z3950 = res;
1424 return process_gdu_response(assoc, req, gres);
1429 * Handle init request.
1430 * At the moment, we don't check the options
1431 * anywhere else in the code - we just try not to do anything that would
1432 * break a naive client. We'll toss 'em into the association block when
1433 * we need them there.
1435 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1437 statserv_options_block *cb = statserv_getcontrol();
1438 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1439 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1440 Z_InitResponse *resp = apdu->u.initResponse;
1441 bend_initresult *binitres;
1445 yaz_log(LOG_LOG, "Got initRequest");
1446 if (req->implementationId)
1447 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1448 if (req->implementationName)
1449 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1450 if (req->implementationVersion)
1451 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1453 assoc_init_reset(assoc);
1455 assoc->init->auth = req->idAuthentication;
1456 assoc->init->referenceId = req->referenceId;
1458 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1460 Z_CharSetandLanguageNegotiation *negotiation =
1461 yaz_get_charneg_record (req->otherInfo);
1462 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1463 assoc->init->charneg_request = negotiation;
1466 if (!(binitres = (*cb->bend_init)(assoc->init)))
1468 yaz_log(LOG_WARN, "Bad response from backend.");
1472 assoc->backend = binitres->handle;
1473 if ((assoc->init->bend_sort))
1474 yaz_log (LOG_DEBUG, "Sort handler installed");
1475 if ((assoc->init->bend_search))
1476 yaz_log (LOG_DEBUG, "Search handler installed");
1477 if ((assoc->init->bend_present))
1478 yaz_log (LOG_DEBUG, "Present handler installed");
1479 if ((assoc->init->bend_esrequest))
1480 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1481 if ((assoc->init->bend_delete))
1482 yaz_log (LOG_DEBUG, "Delete handler installed");
1483 if ((assoc->init->bend_scan))
1484 yaz_log (LOG_DEBUG, "Scan handler installed");
1485 if ((assoc->init->bend_segment))
1486 yaz_log (LOG_DEBUG, "Segment handler installed");
1488 resp->referenceId = req->referenceId;
1490 /* let's tell the client what we can do */
1491 if (ODR_MASK_GET(req->options, Z_Options_search))
1493 ODR_MASK_SET(resp->options, Z_Options_search);
1494 strcat(options, "srch");
1496 if (ODR_MASK_GET(req->options, Z_Options_present))
1498 ODR_MASK_SET(resp->options, Z_Options_present);
1499 strcat(options, " prst");
1501 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1502 assoc->init->bend_delete)
1504 ODR_MASK_SET(resp->options, Z_Options_delSet);
1505 strcat(options, " del");
1507 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1508 assoc->init->bend_esrequest)
1510 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1511 strcat (options, " extendedServices");
1513 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1515 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1516 strcat(options, " namedresults");
1518 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1520 ODR_MASK_SET(resp->options, Z_Options_scan);
1521 strcat(options, " scan");
1523 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1525 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1526 strcat(options, " concurrop");
1528 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1530 ODR_MASK_SET(resp->options, Z_Options_sort);
1531 strcat(options, " sort");
1534 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1535 && assoc->init->charneg_response)
1537 Z_OtherInformation **p;
1538 Z_OtherInformationUnit *p0;
1540 yaz_oi_APDU(apdu, &p);
1542 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1543 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1545 p0->which = Z_OtherInfo_externallyDefinedInfo;
1546 p0->information.externallyDefinedInfo =
1547 assoc->init->charneg_response;
1549 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1550 strcat(options, " negotiation");
1553 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1555 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1556 assoc->version = 2; /* 1 & 2 are equivalent */
1558 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1560 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1563 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1565 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1569 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1570 assoc->maximumRecordSize = *req->maximumRecordSize;
1571 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1572 assoc->maximumRecordSize = control_block->maxrecordsize;
1573 assoc->preferredMessageSize = *req->preferredMessageSize;
1574 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1575 assoc->preferredMessageSize = assoc->maximumRecordSize;
1577 resp->preferredMessageSize = &assoc->preferredMessageSize;
1578 resp->maximumRecordSize = &assoc->maximumRecordSize;
1580 resp->implementationName = "GFS/YAZ";
1582 if (assoc->init->implementation_id)
1585 odr_malloc (assoc->encode,
1586 strlen(assoc->init->implementation_id) + 10 +
1587 strlen(resp->implementationId));
1588 sprintf (nv, "%s / %s",
1589 resp->implementationId, assoc->init->implementation_id);
1590 resp->implementationId = nv;
1592 if (assoc->init->implementation_name)
1595 odr_malloc (assoc->encode,
1596 strlen(assoc->init->implementation_name) + 10 +
1597 strlen(resp->implementationName));
1598 sprintf (nv, "%s / %s",
1599 resp->implementationName, assoc->init->implementation_name);
1600 resp->implementationName = nv;
1602 if (assoc->init->implementation_version)
1605 odr_malloc (assoc->encode,
1606 strlen(assoc->init->implementation_version) + 10 +
1607 strlen(resp->implementationVersion));
1608 sprintf (nv, "YAZ %s / %s",
1609 resp->implementationVersion,
1610 assoc->init->implementation_version);
1611 resp->implementationVersion = nv;
1614 if (binitres->errcode)
1616 yaz_log(LOG_LOG, "Connection rejected by backend.");
1618 assoc->state = ASSOC_DEAD;
1619 resp->userInformationField = init_diagnostics(assoc->encode,
1621 binitres->errstring);
1624 assoc->state = ASSOC_UP;
1629 * Diagnostic in default format, to be returned as either a surrogate
1630 * or non-surrogate diagnostic in the context of an open session, or
1631 * as User-information when an Init is refused.
1633 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1635 int *err = odr_intdup(odr, error);
1636 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1637 odr_malloc (odr, sizeof(*dr));
1639 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1640 addinfo ? " -- " : "", addinfo ? addinfo : "");
1642 dr->diagnosticSetId =
1643 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1644 dr->condition = err;
1645 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1646 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1651 * Set the specified `errcode' and `errstring' into a UserInfo-1
1652 * external to be returned to the client in accordance with Z35.90
1653 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1654 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1656 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1660 Z_OtherInformation *u;
1661 Z_OtherInformationUnit *l;
1662 Z_DiagnosticFormat *d;
1663 Z_DiagnosticFormat_s *e;
1665 x = (Z_External*) odr_malloc(odr, sizeof *x);
1667 x->indirect_reference = 0;
1668 oid.proto = PROTO_Z3950;
1669 oid.oclass = CLASS_USERINFO;
1670 oid.value = VAL_USERINFO1;
1671 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1672 x->which = Z_External_userInfo1;
1674 u = odr_malloc(odr, sizeof *u);
1676 u->num_elements = 1;
1677 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1678 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1681 l->which = Z_OtherInfo_externallyDefinedInfo;
1683 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1684 l->information.externallyDefinedInfo = x2;
1686 x2->indirect_reference = 0;
1687 oid.oclass = CLASS_DIAGSET;
1688 oid.value = VAL_DIAG1;
1689 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1690 x2->which = Z_External_diag1;
1692 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1695 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1696 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1699 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1700 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1705 * nonsurrogate diagnostic record.
1707 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1709 Z_Records *rec = (Z_Records *)
1710 odr_malloc (assoc->encode, sizeof(*rec));
1711 rec->which = Z_Records_NSD;
1712 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1717 * surrogate diagnostic.
1719 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1720 int error, char *addinfo)
1722 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1723 odr_malloc (assoc->encode, sizeof(*rec));
1724 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1726 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1727 rec->databaseName = dbname;
1728 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1729 rec->u.surrogateDiagnostic = drec;
1730 drec->which = Z_DiagRec_defaultFormat;
1731 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1737 * multiple nonsurrogate diagnostics.
1739 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1741 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1742 int *err = odr_intdup(assoc->encode, error);
1743 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1744 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1745 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1746 odr_malloc (assoc->encode, sizeof(*rec));
1748 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1750 recs->num_diagRecs = 1;
1751 recs->diagRecs = recp;
1753 drec->which = Z_DiagRec_defaultFormat;
1754 drec->u.defaultFormat = rec;
1756 rec->diagnosticSetId =
1757 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1758 rec->condition = err;
1760 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1761 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1765 static Z_Records *pack_records(association *a, char *setname, int start,
1766 int *num, Z_RecordComposition *comp,
1767 int *next, int *pres, oid_value format,
1768 Z_ReferenceId *referenceId,
1771 int recno, total_length = 0, toget = *num, dumped_records = 0;
1772 Z_Records *records =
1773 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1774 Z_NamePlusRecordList *reclist =
1775 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1776 Z_NamePlusRecord **list =
1777 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1779 records->which = Z_Records_DBOSD;
1780 records->u.databaseOrSurDiagnostics = reclist;
1781 reclist->num_records = 0;
1782 reclist->records = list;
1783 *pres = Z_PRES_SUCCESS;
1787 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1788 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1789 a->maximumRecordSize);
1790 for (recno = start; reclist->num_records < toget; recno++)
1793 Z_NamePlusRecord *thisrec;
1794 int this_length = 0;
1796 * we get the number of bytes allocated on the stream before any
1797 * allocation done by the backend - this should give us a reasonable
1798 * idea of the total size of the data so far.
1800 total_length = odr_total(a->encode) - dumped_records;
1806 freq.last_in_set = 0;
1807 freq.setname = setname;
1808 freq.surrogate_flag = 0;
1809 freq.number = recno;
1811 freq.request_format = format;
1812 freq.request_format_raw = oid;
1813 freq.output_format = format;
1814 freq.output_format_raw = 0;
1815 freq.stream = a->encode;
1816 freq.print = a->print;
1817 freq.referenceId = referenceId;
1819 (*a->init->bend_fetch)(a->backend, &freq);
1820 /* backend should be able to signal whether error is system-wide
1821 or only pertaining to current record */
1824 if (!freq.surrogate_flag)
1827 *pres = Z_PRES_FAILURE;
1828 /* for 'present request out of range',
1829 set addinfo to record position if not set */
1830 if (freq.errcode == 13 && freq.errstring == 0)
1832 sprintf (s, "%d", recno);
1835 return diagrec(a, freq.errcode, freq.errstring);
1837 reclist->records[reclist->num_records] =
1838 surrogatediagrec(a, freq.basename, freq.errcode,
1840 reclist->num_records++;
1841 *next = freq.last_in_set ? 0 : recno + 1;
1845 this_length = freq.len;
1847 this_length = odr_total(a->encode) - total_length;
1848 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1849 this_length, total_length);
1850 if (this_length + total_length > a->preferredMessageSize)
1852 /* record is small enough, really */
1853 if (this_length <= a->preferredMessageSize)
1855 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1856 *pres = Z_PRES_PARTIAL_2;
1859 /* record can only be fetched by itself */
1860 if (this_length < a->maximumRecordSize)
1862 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1865 yaz_log(LOG_DEBUG, " Dropped it");
1866 reclist->records[reclist->num_records] =
1867 surrogatediagrec(a, freq.basename, 16, 0);
1868 reclist->num_records++;
1869 *next = freq.last_in_set ? 0 : recno + 1;
1870 dumped_records += this_length;
1874 else /* too big entirely */
1876 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1877 reclist->records[reclist->num_records] =
1878 surrogatediagrec(a, freq.basename, 17, 0);
1879 reclist->num_records++;
1880 *next = freq.last_in_set ? 0 : recno + 1;
1881 dumped_records += this_length;
1886 if (!(thisrec = (Z_NamePlusRecord *)
1887 odr_malloc(a->encode, sizeof(*thisrec))))
1889 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1890 strlen(freq.basename) + 1)))
1892 strcpy(thisrec->databaseName, freq.basename);
1893 thisrec->which = Z_NamePlusRecord_databaseRecord;
1895 if (freq.output_format_raw)
1897 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1898 freq.output_format = ident->value;
1900 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1901 freq.record, freq.len);
1902 if (!thisrec->u.databaseRecord)
1904 reclist->records[reclist->num_records] = thisrec;
1905 reclist->num_records++;
1906 *next = freq.last_in_set ? 0 : recno + 1;
1908 *num = reclist->num_records;
1912 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1915 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1916 bend_search_rr *bsrr =
1917 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1919 yaz_log(LOG_LOG, "Got SearchRequest.");
1921 bsrr->request = reqb;
1922 bsrr->association = assoc;
1923 bsrr->referenceId = req->referenceId;
1924 save_referenceId (reqb, bsrr->referenceId);
1926 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1927 if (req->databaseNames)
1930 for (i = 0; i < req->num_databaseNames; i++)
1931 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1933 yaz_log_zquery(req->query);
1935 if (assoc->init->bend_search)
1937 bsrr->setname = req->resultSetName;
1938 bsrr->replace_set = *req->replaceIndicator;
1939 bsrr->num_bases = req->num_databaseNames;
1940 bsrr->basenames = req->databaseNames;
1941 bsrr->query = req->query;
1942 bsrr->stream = assoc->encode;
1943 bsrr->decode = assoc->decode;
1944 bsrr->print = assoc->print;
1947 bsrr->errstring = NULL;
1948 bsrr->search_info = NULL;
1949 (assoc->init->bend_search)(assoc->backend, bsrr);
1953 return response_searchRequest(assoc, reqb, bsrr, fd);
1956 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1959 * Prepare a searchresponse based on the backend results. We probably want
1960 * to look at making the fetching of records nonblocking as well, but
1961 * so far, we'll keep things simple.
1962 * If bsrt is null, that means we're called in response to a communications
1963 * event, and we'll have to get the response for ourselves.
1965 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1966 bend_search_rr *bsrt, int *fd)
1968 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1969 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1970 Z_SearchResponse *resp = (Z_SearchResponse *)
1971 odr_malloc (assoc->encode, sizeof(*resp));
1972 int *nulint = odr_intdup (assoc->encode, 0);
1973 bool_t *sr = odr_intdup(assoc->encode, 1);
1974 int *next = odr_intdup(assoc->encode, 0);
1975 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1977 apdu->which = Z_APDU_searchResponse;
1978 apdu->u.searchResponse = resp;
1979 resp->referenceId = req->referenceId;
1980 resp->additionalSearchInfo = 0;
1981 resp->otherInfo = 0;
1983 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1985 yaz_log(LOG_FATAL, "Bad result from backend");
1988 else if (bsrt->errcode)
1990 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1991 resp->resultCount = nulint;
1992 resp->numberOfRecordsReturned = nulint;
1993 resp->nextResultSetPosition = nulint;
1994 resp->searchStatus = nulint;
1995 resp->resultSetStatus = none;
1996 resp->presentStatus = 0;
2000 int *toget = odr_intdup(assoc->encode, 0);
2001 int *presst = odr_intdup(assoc->encode, 0);
2002 Z_RecordComposition comp, *compp = 0;
2004 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
2007 resp->resultCount = &bsrt->hits;
2009 comp.which = Z_RecordComp_simple;
2010 /* how many records does the user agent want, then? */
2011 if (bsrt->hits <= *req->smallSetUpperBound)
2013 *toget = bsrt->hits;
2014 if ((comp.u.simple = req->smallSetElementSetNames))
2017 else if (bsrt->hits < *req->largeSetLowerBound)
2019 *toget = *req->mediumSetPresentNumber;
2020 if (*toget > bsrt->hits)
2021 *toget = bsrt->hits;
2022 if ((comp.u.simple = req->mediumSetElementSetNames))
2028 if (*toget && !resp->records)
2033 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2036 form = prefformat->value;
2037 resp->records = pack_records(assoc, req->resultSetName, 1,
2038 toget, compp, next, presst, form, req->referenceId,
2039 req->preferredRecordSyntax);
2042 resp->numberOfRecordsReturned = toget;
2043 resp->nextResultSetPosition = next;
2044 resp->searchStatus = sr;
2045 resp->resultSetStatus = 0;
2046 resp->presentStatus = presst;
2050 if (*resp->resultCount)
2052 resp->numberOfRecordsReturned = nulint;
2053 resp->nextResultSetPosition = next;
2054 resp->searchStatus = sr;
2055 resp->resultSetStatus = 0;
2056 resp->presentStatus = 0;
2059 resp->additionalSearchInfo = bsrt->search_info;
2064 * Maybe we got a little over-friendly when we designed bend_fetch to
2065 * get only one record at a time. Some backends can optimise multiple-record
2066 * fetches, and at any rate, there is some overhead involved in
2067 * all that selecting and hopping around. Problem is, of course, that the
2068 * frontend can't know ahead of time how many records it'll need to
2069 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2070 * is downright lousy as a bulk data transfer protocol.
2072 * To start with, we'll do the fetching of records from the backend
2073 * in one operation: To save some trips in and out of the event-handler,
2074 * and to simplify the interface to pack_records. At any rate, asynch
2075 * operation is more fun in operations that have an unpredictable execution
2076 * speed - which is normally more true for search than for present.
2078 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2081 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2085 Z_PresentResponse *resp;
2089 yaz_log(LOG_LOG, "Got PresentRequest.");
2091 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2094 form = prefformat->value;
2095 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2097 resp->presentStatus = odr_intdup(assoc->encode, 0);
2098 if (assoc->init->bend_present)
2100 bend_present_rr *bprr = (bend_present_rr *)
2101 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2102 bprr->setname = req->resultSetId;
2103 bprr->start = *req->resultSetStartPoint;
2104 bprr->number = *req->numberOfRecordsRequested;
2105 bprr->format = form;
2106 bprr->comp = req->recordComposition;
2107 bprr->referenceId = req->referenceId;
2108 bprr->stream = assoc->encode;
2109 bprr->print = assoc->print;
2110 bprr->request = reqb;
2111 bprr->association = assoc;
2113 bprr->errstring = NULL;
2114 (*assoc->init->bend_present)(assoc->backend, bprr);
2120 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2121 *resp->presentStatus = Z_PRES_FAILURE;
2124 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2125 next = odr_intdup(assoc->encode, 0);
2126 num = odr_intdup(assoc->encode, 0);
2128 apdu->which = Z_APDU_presentResponse;
2129 apdu->u.presentResponse = resp;
2130 resp->referenceId = req->referenceId;
2131 resp->otherInfo = 0;
2135 *num = *req->numberOfRecordsRequested;
2137 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2138 num, req->recordComposition, next, resp->presentStatus,
2139 form, req->referenceId, req->preferredRecordSyntax);
2143 resp->numberOfRecordsReturned = num;
2144 resp->nextResultSetPosition = next;
2150 * Scan was implemented rather in a hurry, and with support for only the basic
2151 * elements of the service in the backend API. Suggestions are welcome.
2153 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2155 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2156 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2157 Z_ScanResponse *res = (Z_ScanResponse *)
2158 odr_malloc (assoc->encode, sizeof(*res));
2159 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2160 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2161 Z_ListEntries *ents = (Z_ListEntries *)
2162 odr_malloc (assoc->encode, sizeof(*ents));
2163 Z_DiagRecs *diagrecs_p = NULL;
2165 bend_scan_rr *bsrr = (bend_scan_rr *)
2166 odr_malloc (assoc->encode, sizeof(*bsrr));
2167 struct scan_entry *save_entries;
2169 yaz_log(LOG_LOG, "Got ScanRequest");
2171 apdu->which = Z_APDU_scanResponse;
2172 apdu->u.scanResponse = res;
2173 res->referenceId = req->referenceId;
2175 /* if step is absent, set it to 0 */
2176 res->stepSize = odr_intdup(assoc->encode, 0);
2178 *res->stepSize = *req->stepSize;
2180 res->scanStatus = scanStatus;
2181 res->numberOfEntriesReturned = numberOfEntriesReturned;
2182 res->positionOfTerm = 0;
2183 res->entries = ents;
2184 ents->num_entries = 0;
2185 ents->entries = NULL;
2186 ents->num_nonsurrogateDiagnostics = 0;
2187 ents->nonsurrogateDiagnostics = NULL;
2188 res->attributeSet = 0;
2191 if (req->databaseNames)
2194 for (i = 0; i < req->num_databaseNames; i++)
2195 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2197 bsrr->num_bases = req->num_databaseNames;
2198 bsrr->basenames = req->databaseNames;
2199 bsrr->num_entries = *req->numberOfTermsRequested;
2200 bsrr->term = req->termListAndStartPoint;
2201 bsrr->referenceId = req->referenceId;
2202 bsrr->stream = assoc->encode;
2203 bsrr->print = assoc->print;
2204 bsrr->step_size = res->stepSize;
2206 /* Note that version 2.0 of YAZ and older did not set entries ..
2207 We do now. And when we do it's easier to extend the scan entry
2208 We know that if the scan handler did set entries, it will
2209 not know of new member display_term.
2211 if (bsrr->num_entries > 0)
2214 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2216 for (i = 0; i<bsrr->num_entries; i++)
2218 bsrr->entries[i].term = 0;
2219 bsrr->entries[i].occurrences = 0;
2220 bsrr->entries[i].errcode = 0;
2221 bsrr->entries[i].errstring = 0;
2222 bsrr->entries[i].display_term = 0;
2225 save_entries = bsrr->entries; /* save it so we can compare later */
2227 if (req->attributeSet &&
2228 (attset = oid_getentbyoid(req->attributeSet)) &&
2229 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2230 bsrr->attributeset = attset->value;
2232 bsrr->attributeset = VAL_NONE;
2233 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2234 bsrr->term_position = req->preferredPositionInResponse ?
2235 *req->preferredPositionInResponse : 1;
2236 ((int (*)(void *, bend_scan_rr *))
2237 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2239 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2243 Z_Entry **tab = (Z_Entry **)
2244 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2246 if (bsrr->status == BEND_SCAN_PARTIAL)
2247 *scanStatus = Z_Scan_partial_5;
2249 *scanStatus = Z_Scan_success;
2250 ents->entries = tab;
2251 ents->num_entries = bsrr->num_entries;
2252 res->numberOfEntriesReturned = &ents->num_entries;
2253 res->positionOfTerm = &bsrr->term_position;
2254 for (i = 0; i < bsrr->num_entries; i++)
2260 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2261 if (bsrr->entries[i].occurrences >= 0)
2263 e->which = Z_Entry_termInfo;
2264 e->u.termInfo = t = (Z_TermInfo *)
2265 odr_malloc(assoc->encode, sizeof(*t));
2266 t->suggestedAttributes = 0;
2268 if (save_entries == bsrr->entries &&
2269 bsrr->entries[i].display_term)
2271 /* the entries was NOT set by the handler. So it's
2272 safe to test for new member display_term. It is
2275 t->displayTerm = odr_strdup(assoc->encode,
2276 bsrr->entries[i].display_term);
2278 t->alternativeTerm = 0;
2279 t->byAttributes = 0;
2280 t->otherTermInfo = 0;
2281 t->globalOccurrences = &bsrr->entries[i].occurrences;
2282 t->term = (Z_Term *)
2283 odr_malloc(assoc->encode, sizeof(*t->term));
2284 t->term->which = Z_Term_general;
2285 t->term->u.general = o =
2286 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2287 o->buf = (unsigned char *)
2288 odr_malloc(assoc->encode, o->len = o->size =
2289 strlen(bsrr->entries[i].term));
2290 memcpy(o->buf, bsrr->entries[i].term, o->len);
2291 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2292 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2296 Z_DiagRecs *drecs = diagrecs (assoc,
2297 bsrr->entries[i].errcode,
2298 bsrr->entries[i].errstring);
2299 assert (drecs->num_diagRecs == 1);
2300 e->which = Z_Entry_surrogateDiagnostic;
2301 assert (drecs->diagRecs[0]);
2302 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2308 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2309 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2314 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2317 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2318 Z_SortResponse *res = (Z_SortResponse *)
2319 odr_malloc (assoc->encode, sizeof(*res));
2320 bend_sort_rr *bsrr = (bend_sort_rr *)
2321 odr_malloc (assoc->encode, sizeof(*bsrr));
2323 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2325 yaz_log(LOG_LOG, "Got SortRequest.");
2327 bsrr->num_input_setnames = req->num_inputResultSetNames;
2328 bsrr->input_setnames = req->inputResultSetNames;
2329 bsrr->referenceId = req->referenceId;
2330 bsrr->output_setname = req->sortedResultSetName;
2331 bsrr->sort_sequence = req->sortSequence;
2332 bsrr->stream = assoc->encode;
2333 bsrr->print = assoc->print;
2335 bsrr->sort_status = Z_SortStatus_failure;
2337 bsrr->errstring = 0;
2339 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2341 res->referenceId = bsrr->referenceId;
2342 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2343 res->resultSetStatus = 0;
2346 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2347 res->diagnostics = dr->diagRecs;
2348 res->num_diagnostics = dr->num_diagRecs;
2352 res->num_diagnostics = 0;
2353 res->diagnostics = 0;
2355 res->resultCount = 0;
2358 apdu->which = Z_APDU_sortResponse;
2359 apdu->u.sortResponse = res;
2363 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2366 Z_DeleteResultSetRequest *req =
2367 reqb->apdu_request->u.deleteResultSetRequest;
2368 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2369 odr_malloc (assoc->encode, sizeof(*res));
2370 bend_delete_rr *bdrr = (bend_delete_rr *)
2371 odr_malloc (assoc->encode, sizeof(*bdrr));
2372 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2374 yaz_log(LOG_LOG, "Got DeleteRequest.");
2376 bdrr->num_setnames = req->num_resultSetList;
2377 bdrr->setnames = req->resultSetList;
2378 bdrr->stream = assoc->encode;
2379 bdrr->print = assoc->print;
2380 bdrr->function = *req->deleteFunction;
2381 bdrr->referenceId = req->referenceId;
2383 if (bdrr->num_setnames > 0)
2386 bdrr->statuses = (int*)
2387 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2388 bdrr->num_setnames);
2389 for (i = 0; i < bdrr->num_setnames; i++)
2390 bdrr->statuses[i] = 0;
2392 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2394 res->referenceId = req->referenceId;
2396 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2398 res->deleteListStatuses = 0;
2399 if (bdrr->num_setnames > 0)
2402 res->deleteListStatuses = (Z_ListStatuses *)
2403 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2404 res->deleteListStatuses->num = bdrr->num_setnames;
2405 res->deleteListStatuses->elements =
2407 odr_malloc (assoc->encode,
2408 sizeof(*res->deleteListStatuses->elements) *
2409 bdrr->num_setnames);
2410 for (i = 0; i<bdrr->num_setnames; i++)
2412 res->deleteListStatuses->elements[i] =
2414 odr_malloc (assoc->encode,
2415 sizeof(**res->deleteListStatuses->elements));
2416 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2417 res->deleteListStatuses->elements[i]->id =
2418 odr_strdup (assoc->encode, bdrr->setnames[i]);
2422 res->numberNotDeleted = 0;
2423 res->bulkStatuses = 0;
2424 res->deleteMessage = 0;
2427 apdu->which = Z_APDU_deleteResultSetResponse;
2428 apdu->u.deleteResultSetResponse = res;
2432 static void process_close(association *assoc, request *reqb)
2434 Z_Close *req = reqb->apdu_request->u.close;
2435 static char *reasons[] =
2442 "securityViolation",
2449 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2450 reasons[*req->closeReason], req->diagnosticInformation ?
2451 req->diagnosticInformation : "NULL");
2452 if (assoc->version < 3) /* to make do_force respond with close */
2454 do_close_req(assoc, Z_Close_finished,
2455 "Association terminated by client", reqb);
2458 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2462 reqb->len_refid = refid->len;
2463 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2464 memcpy (reqb->refid, refid->buf, refid->len);
2468 reqb->len_refid = 0;
2473 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2475 process_z_response (a, req, res);
2478 bend_request bend_request_mk (bend_association a)
2480 request *nreq = request_get (&a->outgoing);
2481 nreq->request_mem = nmem_create ();
2485 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2490 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2491 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2492 id->len = id->size = req->len_refid;
2493 memcpy (id->buf, req->refid, req->len_refid);
2497 void bend_request_destroy (bend_request *req)
2499 nmem_destroy((*req)->request_mem);
2500 request_release(*req);
2504 int bend_backend_respond (bend_association a, bend_request req)
2508 r = process_z_request (a, req, &msg);
2510 yaz_log (LOG_WARN, "%s", msg);
2514 void bend_request_setdata(bend_request r, void *p)
2519 void *bend_request_getdata(bend_request r)
2521 return r->clientData;
2524 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2526 bend_segment_rr req;
2528 req.segment = reqb->apdu_request->u.segmentRequest;
2529 req.stream = assoc->encode;
2530 req.decode = assoc->decode;
2531 req.print = assoc->print;
2532 req.association = assoc;
2534 (*assoc->init->bend_segment)(assoc->backend, &req);
2539 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2541 bend_esrequest_rr esrequest;
2543 Z_ExtendedServicesRequest *req =
2544 reqb->apdu_request->u.extendedServicesRequest;
2545 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2547 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2549 yaz_log(LOG_DEBUG,"inside Process esRequest");
2551 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2552 esrequest.stream = assoc->encode;
2553 esrequest.decode = assoc->decode;
2554 esrequest.print = assoc->print;
2555 esrequest.errcode = 0;
2556 esrequest.errstring = NULL;
2557 esrequest.request = reqb;
2558 esrequest.association = assoc;
2559 esrequest.taskPackage = 0;
2560 esrequest.referenceId = req->referenceId;
2562 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2564 /* If the response is being delayed, return NULL */
2565 if (esrequest.request == NULL)
2568 resp->referenceId = req->referenceId;
2570 if (esrequest.errcode == -1)
2572 /* Backend service indicates request will be processed */
2573 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2574 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2576 else if (esrequest.errcode == 0)
2578 /* Backend service indicates request will be processed */
2579 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2580 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2584 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2585 esrequest.errstring);
2587 /* Backend indicates error, request will not be processed */
2588 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2589 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2590 resp->num_diagnostics = diagRecs->num_diagRecs;
2591 resp->diagnostics = diagRecs->diagRecs;
2593 /* Do something with the members of bend_extendedservice */
2594 if (esrequest.taskPackage)
2595 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2596 (const char *) esrequest.taskPackage,
2598 yaz_log(LOG_DEBUG,"Send the result apdu");