2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.156 2003-05-20 08:22:33 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_APDU *process_searchRequest(association *assoc, request *reqb,
71 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
72 bend_search_rr *bsrr, int *fd);
73 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
75 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
76 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
77 static void process_close(association *assoc, request *reqb);
78 void save_referenceId (request *reqb, Z_ReferenceId *refid);
79 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
81 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
83 static FILE *apduf = 0; /* for use in static mode */
84 static statserv_options_block *control_block = 0;
86 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
89 * Create and initialize a new association-handle.
90 * channel : iochannel for the current line.
91 * link : communications channel.
92 * Returns: 0 or a new association handle.
94 association *create_association(IOCHAN channel, COMSTACK link)
99 control_block = statserv_getcontrol();
100 if (!(anew = (association *)xmalloc(sizeof(*anew))))
104 anew->client_chan = channel;
105 anew->client_link = link;
106 anew->cs_get_mask = 0;
107 anew->cs_put_mask = 0;
108 anew->cs_accept_mask = 0;
109 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
110 !(anew->encode = odr_createmem(ODR_ENCODE)))
112 if (*control_block->apdufile)
117 strcpy(filename, control_block->apdufile);
118 if (!(anew->print = odr_createmem(ODR_PRINT)))
120 if (*control_block->apdufile == '@')
122 odr_setprint(anew->print, yaz_log_file());
124 else if (*control_block->apdufile != '-')
126 strcpy(filename, control_block->apdufile);
127 if (!control_block->dynamic)
131 if (!(apduf = fopen(filename, "w")))
133 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
136 setvbuf(apduf, 0, _IONBF, 0);
142 sprintf(filename + strlen(filename), ".%d", getpid());
143 if (!(f = fopen(filename, "w")))
145 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
148 setvbuf(f, 0, _IONBF, 0);
150 odr_setprint(anew->print, f);
155 anew->input_buffer = 0;
156 anew->input_buffer_len = 0;
158 anew->state = ASSOC_NEW;
159 request_initq(&anew->incoming);
160 request_initq(&anew->outgoing);
161 anew->proto = cs_getproto(link);
166 * Free association and release resources.
168 void destroy_association(association *h)
170 statserv_options_block *cb = statserv_getcontrol();
173 odr_destroy(h->decode);
174 odr_destroy(h->encode);
176 odr_destroy(h->print);
178 xfree(h->input_buffer);
180 (*cb->bend_close)(h->backend);
181 while (request_deq(&h->incoming));
182 while (request_deq(&h->outgoing));
183 request_delq(&h->incoming);
184 request_delq(&h->outgoing);
186 xmalloc_trav("session closed");
187 if (control_block && control_block->one_shot)
193 static void do_close_req(association *a, int reason, char *message,
197 Z_Close *cls = zget_Close(a->encode);
199 /* Purge request queue */
200 while (request_deq(&a->incoming));
201 while (request_deq(&a->outgoing));
204 yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
205 reason, message ? message : "none");
206 apdu.which = Z_APDU_close;
208 *cls->closeReason = reason;
209 cls->diagnosticInformation = message;
210 process_z_response(a, req, &apdu);
211 iochan_settimeout(a->client_chan, 20);
215 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
216 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
218 a->state = ASSOC_DEAD;
221 static void do_close(association *a, int reason, char *message)
223 do_close_req (a, reason, message, request_get(&a->outgoing));
227 * This is where PDUs from the client are read and the further
228 * processing is initiated. Flow of control moves down through the
229 * various process_* functions below, until the encoded result comes back up
230 * to the output handler in here.
232 * h : the I/O channel that has an outstanding event.
233 * event : the current outstanding event.
235 void ir_session(IOCHAN h, int event)
238 association *assoc = (association *)iochan_getdata(h);
239 COMSTACK conn = assoc->client_link;
242 assert(h && conn && assoc);
243 if (event == EVENT_TIMEOUT)
245 if (assoc->state != ASSOC_UP)
247 yaz_log(LOG_LOG, "Final timeout - closing connection.");
249 destroy_association(assoc);
254 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
255 do_close(assoc, Z_Close_lackOfActivity, 0);
259 if (event & assoc->cs_accept_mask)
261 yaz_log (LOG_DEBUG, "ir_session (accept)");
262 if (!cs_accept (conn))
264 yaz_log (LOG_LOG, "accept failed");
265 destroy_association(assoc);
268 iochan_clearflag (h, EVENT_OUTPUT|EVENT_OUTPUT);
269 if (conn->io_pending)
270 { /* cs_accept didn't complete */
271 assoc->cs_accept_mask =
272 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
273 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
275 iochan_setflag (h, assoc->cs_accept_mask);
278 { /* cs_accept completed. Prepare for reading (cs_get) */
279 assoc->cs_accept_mask = 0;
280 assoc->cs_get_mask = EVENT_INPUT;
281 iochan_setflag (h, assoc->cs_get_mask);
285 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
287 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
289 yaz_log(LOG_DEBUG, "ir_session (input)");
290 /* We aren't speaking to this fellow */
291 if (assoc->state == ASSOC_DEAD)
293 yaz_log(LOG_LOG, "Connection closed - end of session");
295 destroy_association(assoc);
299 assoc->cs_get_mask = EVENT_INPUT;
300 if ((res = cs_get(conn, &assoc->input_buffer,
301 &assoc->input_buffer_len)) <= 0)
303 yaz_log(LOG_LOG, "Connection closed by client");
305 destroy_association(assoc);
309 else if (res == 1) /* incomplete read - wait for more */
311 if (conn->io_pending & CS_WANT_WRITE)
312 assoc->cs_get_mask |= EVENT_OUTPUT;
313 iochan_setflag(h, assoc->cs_get_mask);
316 if (cs_more(conn)) /* more stuff - call us again later, please */
317 iochan_setevent(h, EVENT_INPUT);
319 /* we got a complete PDU. Let's decode it */
320 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
321 assoc->input_buffer[0] & 0xff,
322 assoc->input_buffer[1] & 0xff,
323 assoc->input_buffer[2] & 0xff);
324 req = request_get(&assoc->incoming); /* get a new request */
325 odr_reset(assoc->decode);
326 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
327 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
329 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ",
330 odr_errmsg(odr_geterror(assoc->decode)),
331 odr_offset(assoc->decode));
332 if (assoc->decode->error != OHTTP)
334 yaz_log(LOG_LOG, "PDU dump:");
335 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
336 do_close(assoc, Z_Close_protocolError, "Malformed package");
340 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
341 assoc->state = ASSOC_DEAD;
342 process_gdu_response(assoc, req, p);
346 req->request_mem = odr_extract_mem(assoc->decode);
347 if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
349 yaz_log(LOG_WARN, "ODR print error: %s",
350 odr_errmsg(odr_geterror(assoc->print)));
351 odr_reset(assoc->print);
353 request_enq(&assoc->incoming, req);
356 /* can we do something yet? */
357 req = request_head(&assoc->incoming);
358 if (req->state == REQUEST_IDLE)
360 request_deq(&assoc->incoming);
361 process_gdu_request(assoc, req);
364 if (event & assoc->cs_put_mask)
366 request *req = request_head(&assoc->outgoing);
368 assoc->cs_put_mask = 0;
369 yaz_log(LOG_DEBUG, "ir_session (output)");
370 req->state = REQUEST_PENDING;
371 switch (res = cs_put(conn, req->response, req->len_response))
374 yaz_log(LOG_LOG, "Connection closed by client");
376 destroy_association(assoc);
379 case 0: /* all sent - release the request structure */
380 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
382 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
385 nmem_destroy(req->request_mem);
386 request_deq(&assoc->outgoing);
387 request_release(req);
388 if (!request_head(&assoc->outgoing))
389 { /* restore mask for cs_get operation ... */
390 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
391 iochan_setflag(h, assoc->cs_get_mask);
392 if (assoc->state == ASSOC_DEAD)
393 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
397 assoc->cs_put_mask = EVENT_OUTPUT;
401 if (conn->io_pending & CS_WANT_WRITE)
402 assoc->cs_put_mask |= EVENT_OUTPUT;
403 if (conn->io_pending & CS_WANT_READ)
404 assoc->cs_put_mask |= EVENT_INPUT;
405 iochan_setflag(h, assoc->cs_put_mask);
408 if (event & EVENT_EXCEPT)
410 yaz_log(LOG_LOG, "ir_session (exception)");
412 destroy_association(assoc);
417 static int process_z_request(association *assoc, request *req, char **msg);
419 static void assoc_init_reset(association *assoc)
422 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
424 assoc->init->stream = assoc->encode;
425 assoc->init->print = assoc->print;
426 assoc->init->auth = 0;
427 assoc->init->referenceId = 0;
428 assoc->init->implementation_version = 0;
429 assoc->init->implementation_id = 0;
430 assoc->init->implementation_name = 0;
431 assoc->init->bend_sort = NULL;
432 assoc->init->bend_search = NULL;
433 assoc->init->bend_present = NULL;
434 assoc->init->bend_esrequest = NULL;
435 assoc->init->bend_delete = NULL;
436 assoc->init->bend_scan = NULL;
437 assoc->init->bend_segment = NULL;
438 assoc->init->bend_fetch = NULL;
439 assoc->init->bend_explain = NULL;
441 assoc->init->charneg_request = NULL;
442 assoc->init->charneg_response = NULL;
444 assoc->init->decode = assoc->decode;
445 assoc->init->peer_name =
446 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
449 static int srw_bend_init(association *assoc)
451 const char *encoding = "UTF-8";
453 bend_initresult *binitres;
454 statserv_options_block *cb = statserv_getcontrol();
456 assoc_init_reset(assoc);
458 assoc->maximumRecordSize = 3000000;
459 assoc->preferredMessageSize = 3000000;
461 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
462 assoc->init->charneg_request = ce->u.charNeg3;
464 if (!(binitres = (*cb->bend_init)(assoc->init)))
466 yaz_log(LOG_WARN, "Bad response from backend.");
469 assoc->backend = binitres->handle;
473 static int srw_bend_fetch(association *assoc, int pos,
474 Z_SRW_searchRetrieveRequest *srw_req,
475 Z_SRW_record *record)
478 ODR o = assoc->encode;
480 rr.setname = "default";
483 rr.request_format = VAL_TEXT_XML;
484 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
487 rr.comp = (Z_RecordComposition *)
488 odr_malloc(assoc->decode, sizeof(*rr.comp));
489 rr.comp->which = Z_RecordComp_complex;
490 rr.comp->u.complex = (Z_CompSpec *)
491 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
492 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
493 odr_malloc(assoc->encode, sizeof(bool_t));
494 *rr.comp->u.complex->selectAlternativeSyntax = 0;
495 rr.comp->u.complex->num_dbSpecific = 0;
496 rr.comp->u.complex->dbSpecific = 0;
497 rr.comp->u.complex->num_recordSyntax = 0;
498 rr.comp->u.complex->recordSyntax = 0;
500 rr.comp->u.complex->generic = (Z_Specification *)
501 odr_malloc(assoc->decode, sizeof(Z_Specification));
502 rr.comp->u.complex->generic->which = Z_Schema_uri;
503 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
504 rr.comp->u.complex->generic->elementSpec = 0;
506 rr.stream = assoc->encode;
507 rr.print = assoc->print;
513 rr.output_format = VAL_TEXT_XML;
514 rr.output_format_raw = 0;
517 rr.surrogate_flag = 0;
518 rr.schema = srw_req->recordSchema;
520 if (!assoc->init->bend_fetch)
523 (*assoc->init->bend_fetch)(assoc->backend, &rr);
527 record->recordData_buf = rr.record;
528 record->recordData_len = rr.len;
529 record->recordPosition = odr_intdup(o, pos);
531 record->recordSchema = odr_strdup(o, rr.schema);
533 record->recordSchema = 0;
538 static void srw_bend_search(association *assoc, request *req,
539 Z_SRW_searchRetrieveRequest *srw_req,
540 Z_SRW_searchRetrieveResponse *srw_res)
546 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
547 yaz_log(LOG_DEBUG, "srw_bend_search");
550 yaz_log(LOG_DEBUG, "srw_bend_init");
551 if (!srw_bend_init(assoc))
553 srw_error = 3; /* assume Authentication error */
555 srw_res->num_diagnostics = 1;
556 srw_res->diagnostics = (Z_SRW_diagnostic *)
557 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
558 srw_res->diagnostics[0].code =
559 odr_intdup(assoc->encode, srw_error);
560 srw_res->diagnostics[0].details = 0;
565 rr.setname = "default";
568 rr.basenames = &srw_req->database;
571 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
573 if (srw_req->query_type == Z_SRW_query_type_cql)
575 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
576 ext->direct_reference = odr_getoidbystr(assoc->decode,
577 "1.2.840.10003.16.2");
578 ext->indirect_reference = 0;
580 ext->which = Z_External_CQL;
581 ext->u.cql = srw_req->query.cql;
583 rr.query->which = Z_Query_type_104;
584 rr.query->u.type_104 = ext;
586 else if (srw_req->query_type == Z_SRW_query_type_pqf)
588 Z_RPNQuery *RPNquery;
589 YAZ_PQF_Parser pqf_parser;
591 pqf_parser = yaz_pqf_create ();
593 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
599 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
600 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
601 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
606 rr.query->which = Z_Query_type_1;
607 rr.query->u.type_1 = RPNquery;
609 yaz_pqf_destroy (pqf_parser);
614 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
617 if (!srw_error && !assoc->init->bend_search)
622 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
623 srw_res->num_diagnostics = 1;
624 srw_res->diagnostics = (Z_SRW_diagnostic *)
625 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
626 srw_res->diagnostics[0].code =
627 odr_intdup(assoc->encode, srw_error);
628 srw_res->diagnostics[0].details = 0;
632 rr.stream = assoc->encode;
633 rr.decode = assoc->decode;
634 rr.print = assoc->print;
636 rr.association = assoc;
642 yaz_log_zquery(rr.query);
643 (assoc->init->bend_search)(assoc->backend, &rr);
644 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
647 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
648 srw_res->num_diagnostics = 1;
649 srw_res->diagnostics = (Z_SRW_diagnostic *)
650 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
651 srw_res->diagnostics[0].code =
652 odr_intdup(assoc->encode,
653 yaz_diag_bib1_to_srw (rr.errcode));
654 srw_res->diagnostics[0].details = rr.errstring;
655 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
656 *srw_res->diagnostics[0].code);
661 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
662 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
664 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
665 start, number, rr.hits);
667 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
674 yaz_log(LOG_LOG, "Request out or range");
679 int packing = Z_SRW_recordPacking_string;
680 if (start + number > rr.hits)
681 number = rr.hits - start + 1;
682 if (srw_req->recordPacking &&
683 !strcmp(srw_req->recordPacking, "xml"))
684 packing = Z_SRW_recordPacking_XML;
685 srw_res->records = (Z_SRW_record *)
686 odr_malloc(assoc->encode,
687 number * sizeof(*srw_res->records));
688 for (i = 0; i<number; i++)
692 srw_res->records[j].recordPacking = packing;
693 srw_res->records[j].recordData_buf = 0;
694 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
695 errcode = srw_bend_fetch(assoc, i+start, srw_req,
696 srw_res->records + j);
699 srw_res->num_diagnostics = 1;
700 srw_res->diagnostics = (Z_SRW_diagnostic *)
701 odr_malloc(assoc->encode,
702 sizeof(*srw_res->diagnostics));
703 srw_res->diagnostics[0].code =
704 odr_intdup(assoc->encode,
705 yaz_diag_bib1_to_srw (errcode));
706 srw_res->diagnostics[0].details = rr.errstring;
709 if (srw_res->records[j].recordData_buf)
712 srw_res->num_records = j;
714 srw_res->records = 0;
721 static void srw_bend_explain(association *assoc, request *req,
722 Z_SRW_explainRequest *srw_req,
723 Z_SRW_explainResponse *srw_res)
725 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
728 yaz_log(LOG_DEBUG, "srw_bend_init");
729 if (!srw_bend_init(assoc))
732 if (assoc->init && assoc->init->bend_explain)
736 rr.stream = assoc->encode;
737 rr.decode = assoc->decode;
738 rr.print = assoc->print;
740 (*assoc->init->bend_explain)(assoc->backend, &rr);
743 srw_res->explainData_buf = rr.explain_buf;
744 srw_res->explainData_len = strlen(rr.explain_buf);
749 static int hex_digit (int ch)
751 if (ch >= '0' && ch <= '9')
753 else if (ch >= 'a' && ch <= 'f')
755 else if (ch >= 'A' && ch <= 'F')
760 static char *uri_val(const char *path, const char *name, ODR o)
762 size_t nlen = strlen(name);
766 while (path && *path)
768 const char *p1 = strchr(path, '=');
771 if (p1 - path == nlen && !memcmp(path, name, nlen))
777 p1 = strchr(path, '&');
779 p1 = strlen(path) + path;
780 ret = odr_malloc(o, p1 - path + 1);
781 while (*path && *path != '&')
788 else if (*path == '%' && path[1] && path[2])
790 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
799 path = strchr(p1, '&');
806 void uri_val_int(const char *path, const char *name, ODR o, int **intp)
808 const char *v = uri_val(path, name, o);
810 *intp = odr_intdup(o, atoi(v));
813 static void process_http_request(association *assoc, request *req)
815 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
816 ODR o = assoc->encode;
818 Z_HTTP_Response *hres = 0;
821 if (!strcmp(hreq->method, "GET"))
823 char *db = "Default";
824 const char *p0 = hreq->path, *p1;
828 Z_SOAP *soap_package = 0;
829 static Z_SOAP_Handler soap_handlers[2] = {
830 {"http://www.loc.gov/zing/srw/v1.0/", 0,
831 (Z_SOAP_fun) yaz_srw_codec},
838 p1 = strchr(p0, '?');
840 p1 = p0 + strlen(p0);
843 db = odr_malloc(assoc->decode, p1 - p0 + 1);
844 memcpy (db, p0, p1 - p0);
848 if (p1 && *p1 == '?' && p1[1])
850 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
851 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
852 char *query = uri_val(p1, "query", o);
853 char *pQuery = uri_val(p1, "pQuery", o);
854 char *sortKeys = uri_val(p1, "sortKeys", o);
858 sr->u.request->query_type = Z_SRW_query_type_cql;
859 sr->u.request->query.cql = query;
863 sr->u.request->query_type = Z_SRW_query_type_pqf;
864 sr->u.request->query.pqf = pQuery;
868 sr->u.request->sort_type = Z_SRW_sort_type_sort;
869 sr->u.request->sort.sortKeys = sortKeys;
871 sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
872 sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
873 if (!sr->u.request->recordPacking)
874 sr->u.request->recordPacking = "xml";
875 uri_val_int(p1, "maximumRecords", o,
876 &sr->u.request->maximumRecords);
877 uri_val_int(p1, "startRecord", o,
878 &sr->u.request->startRecord);
879 if (sr->u.request->startRecord)
880 yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
881 sr->u.request->database = db;
882 srw_bend_search(assoc, req, sr->u.request, res->u.response);
884 soap_package = odr_malloc(o, sizeof(*soap_package));
885 soap_package->which = Z_SOAP_generic;
887 soap_package->u.generic =
888 odr_malloc(o, sizeof(*soap_package->u.generic));
890 soap_package->u.generic->p = res;
891 soap_package->u.generic->ns = soap_handlers[0].ns;
892 soap_package->u.generic->no = 0;
894 soap_package->ns = "SRU";
896 p = z_get_HTTP_Response(o, 200);
897 hres = p->u.HTTP_Response;
899 ret = z_soap_codec_enc(assoc->encode, &soap_package,
900 &hres->content_buf, &hres->content_len,
901 soap_handlers, charset);
903 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
907 strcpy(ctype, "text/xml; charset=");
908 strcat(ctype, charset);
909 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
915 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
916 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
918 srw_bend_explain(assoc, req, sr->u.explain_request,
919 res->u.explain_response);
921 if (res->u.explain_response->explainData_buf)
923 soap_package = odr_malloc(o, sizeof(*soap_package));
924 soap_package->which = Z_SOAP_generic;
926 soap_package->u.generic =
927 odr_malloc(o, sizeof(*soap_package->u.generic));
929 soap_package->u.generic->p = res;
930 soap_package->u.generic->ns = soap_handlers[0].ns;
931 soap_package->u.generic->no = 0;
933 soap_package->ns = "SRU";
935 p = z_get_HTTP_Response(o, 200);
936 hres = p->u.HTTP_Response;
938 ret = z_soap_codec_enc(assoc->encode, &soap_package,
939 &hres->content_buf, &hres->content_len,
940 soap_handlers, charset);
942 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
946 strcpy(ctype, "text/xml; charset=");
947 strcat(ctype, charset);
948 z_HTTP_header_add(o, &hres->headers, "Content-Type",
955 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
956 !memcmp(hreq->path, "/doc/", 5))
961 strcpy(fpath, DOCDIR);
962 strcat(fpath, hreq->path+4);
963 f = fopen(fpath, "rb");
966 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
975 fseek(f, 0L, SEEK_END);
977 if (sz >= 0 && sz < 500000)
979 const char *ctype = "application/octet-stream";
982 p = z_get_HTTP_Response(o, 200);
983 hres = p->u.HTTP_Response;
984 hres->content_buf = (char *) odr_malloc(o, sz + 1);
985 hres->content_len = sz;
986 fseek(f, 0L, SEEK_SET);
987 fread(hres->content_buf, 1, sz, f);
988 if ((cp = strrchr(fpath, '.'))) {
990 if (!strcmp(cp, "png"))
992 else if (!strcmp(cp, "gif"))
994 else if (!strcmp(cp, "xml"))
996 else if (!strcmp(cp, "html"))
999 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1007 if (!strcmp(hreq->path, "/"))
1012 const char *doclink = "";
1013 p = z_get_HTTP_Response(o, 200);
1014 hres = p->u.HTTP_Response;
1015 hres->content_buf = (char *) odr_malloc(o, 400);
1017 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
1018 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
1020 sprintf (hres->content_buf,
1021 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1024 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1027 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1028 YAZ_VERSION "</P>\n"
1031 "</HTML>\n", doclink);
1032 hres->content_len = strlen(hres->content_buf);
1033 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1039 p = z_get_HTTP_Response(o, 404);
1042 else if (!strcmp(hreq->method, "POST"))
1044 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1046 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1048 Z_SOAP *soap_package = 0;
1050 int http_code = 500;
1051 const char *charset_p = 0;
1054 static Z_SOAP_Handler soap_handlers[2] = {
1056 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1057 (Z_SOAP_fun) yaz_srw_codec},
1061 if ((charset_p = strstr(content_type, "; charset=")))
1065 while (i < 20 && charset_p[i] &&
1066 !strchr("; \n\r", charset_p[i]))
1068 charset = odr_malloc(assoc->encode, i+1);
1069 memcpy(charset, charset_p, i);
1071 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1073 ret = z_soap_codec(assoc->decode, &soap_package,
1074 &hreq->content_buf, &hreq->content_len,
1077 if (!ret && soap_package->which == Z_SOAP_generic &&
1078 soap_package->u.generic->no == 0)
1081 Z_SRW_PDU *sr = soap_package->u.generic->p;
1083 if (sr->which == Z_SRW_searchRetrieve_request)
1086 yaz_srw_get(assoc->encode,
1087 Z_SRW_searchRetrieve_response);
1089 if (!sr->u.request->database)
1091 const char *p0 = hreq->path, *p1;
1094 p1 = strchr(p0, '?');
1096 p1 = p0 + strlen(p0);
1099 sr->u.request->database =
1100 odr_malloc(assoc->decode, p1 - p0 + 1);
1101 memcpy (sr->u.request->database, p0, p1 - p0);
1102 sr->u.request->database[p1 - p0] = '\0';
1105 sr->u.request->database = "Default";
1107 srw_bend_search(assoc, req, sr->u.request,
1110 soap_package->u.generic->p = res;
1113 else if (sr->which == Z_SRW_explain_request)
1116 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1118 srw_bend_explain(assoc, req, sr->u.explain_request,
1119 res->u.explain_response);
1120 if (!res->u.explain_response->explainData_buf)
1122 z_soap_error(assoc->encode, soap_package,
1123 "SOAP-ENV:Client", "Explain Not Supported", 0);
1127 soap_package->u.generic->p = res;
1133 z_soap_error(assoc->encode, soap_package,
1134 "SOAP-ENV:Client", "Bad method", 0);
1138 p = z_get_HTTP_Response(o, 200);
1139 hres = p->u.HTTP_Response;
1140 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1141 &hres->content_buf, &hres->content_len,
1142 soap_handlers, charset);
1143 hres->code = http_code;
1145 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1149 strcpy(ctype, "text/xml; charset=");
1150 strcat(ctype, charset);
1151 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1154 if (!p) /* still no response ? */
1155 p = z_get_HTTP_Response(o, 500);
1159 p = z_get_HTTP_Response(o, 405);
1160 hres = p->u.HTTP_Response;
1162 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1164 hres = p->u.HTTP_Response;
1165 if (!strcmp(hreq->version, "1.0"))
1167 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1168 if (v && !strcmp(v, "Keep-Alive"))
1172 hres->version = "1.0";
1176 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1177 if (v && !strcmp(v, "close"))
1181 hres->version = "1.1";
1185 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1186 assoc->state = ASSOC_DEAD;
1191 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1193 if (alive && isdigit(*alive))
1197 if (t < 0 || t > 3600)
1199 iochan_settimeout(assoc->client_chan,t);
1200 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1202 process_gdu_response(assoc, req, p);
1205 static void process_gdu_request(association *assoc, request *req)
1207 if (req->gdu_request->which == Z_GDU_Z3950)
1210 req->apdu_request = req->gdu_request->u.z3950;
1211 if (process_z_request(assoc, req, &msg) < 0)
1212 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1214 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1215 process_http_request(assoc, req);
1218 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1223 * Initiate request processing.
1225 static int process_z_request(association *assoc, request *req, char **msg)
1231 *msg = "Unknown Error";
1232 assert(req && req->state == REQUEST_IDLE);
1233 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1235 *msg = "Missing InitRequest";
1238 switch (req->apdu_request->which)
1240 case Z_APDU_initRequest:
1241 iochan_settimeout(assoc->client_chan,
1242 statserv_getcontrol()->idle_timeout * 60);
1243 res = process_initRequest(assoc, req); break;
1244 case Z_APDU_searchRequest:
1245 res = process_searchRequest(assoc, req, &fd); break;
1246 case Z_APDU_presentRequest:
1247 res = process_presentRequest(assoc, req, &fd); break;
1248 case Z_APDU_scanRequest:
1249 if (assoc->init->bend_scan)
1250 res = process_scanRequest(assoc, req, &fd);
1253 *msg = "Cannot handle Scan APDU";
1257 case Z_APDU_extendedServicesRequest:
1258 if (assoc->init->bend_esrequest)
1259 res = process_ESRequest(assoc, req, &fd);
1262 *msg = "Cannot handle Extended Services APDU";
1266 case Z_APDU_sortRequest:
1267 if (assoc->init->bend_sort)
1268 res = process_sortRequest(assoc, req, &fd);
1271 *msg = "Cannot handle Sort APDU";
1276 process_close(assoc, req);
1278 case Z_APDU_deleteResultSetRequest:
1279 if (assoc->init->bend_delete)
1280 res = process_deleteRequest(assoc, req, &fd);
1283 *msg = "Cannot handle Delete APDU";
1287 case Z_APDU_segmentRequest:
1288 if (assoc->init->bend_segment)
1290 res = process_segmentRequest (assoc, req);
1294 *msg = "Cannot handle Segment APDU";
1299 *msg = "Bad APDU received";
1304 yaz_log(LOG_DEBUG, " result immediately available");
1305 retval = process_z_response(assoc, req, res);
1309 yaz_log(LOG_DEBUG, " result unavailble");
1312 else /* no result yet - one will be provided later */
1316 /* Set up an I/O handler for the fd supplied by the backend */
1318 yaz_log(LOG_DEBUG, " establishing handler for result");
1319 req->state = REQUEST_PENDING;
1320 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1322 iochan_setdata(chan, assoc);
1329 * Handle message from the backend.
1331 void backend_response(IOCHAN i, int event)
1333 association *assoc = (association *)iochan_getdata(i);
1334 request *req = request_head(&assoc->incoming);
1338 yaz_log(LOG_DEBUG, "backend_response");
1339 assert(assoc && req && req->state != REQUEST_IDLE);
1340 /* determine what it is we're waiting for */
1341 switch (req->apdu_request->which)
1343 case Z_APDU_searchRequest:
1344 res = response_searchRequest(assoc, req, 0, &fd); break;
1346 case Z_APDU_presentRequest:
1347 res = response_presentRequest(assoc, req, 0, &fd); break;
1348 case Z_APDU_scanRequest:
1349 res = response_scanRequest(assoc, req, 0, &fd); break;
1352 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1355 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1357 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1358 do_close(assoc, Z_Close_systemProblem, 0);
1362 else if (!res) /* no result yet - try again later */
1364 yaz_log(LOG_DEBUG, " no result yet");
1365 iochan_setfd(i, fd); /* in case fd has changed */
1370 * Encode response, and transfer the request structure to the outgoing queue.
1372 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1374 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1376 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1378 yaz_log(LOG_WARN, "ODR print error: %s",
1379 odr_errmsg(odr_geterror(assoc->print)));
1380 odr_reset(assoc->print);
1382 if (!z_GDU(assoc->encode, &res, 0, 0))
1384 yaz_log(LOG_WARN, "ODR error when encoding response: %s",
1385 odr_errmsg(odr_geterror(assoc->decode)));
1388 req->response = odr_getbuf(assoc->encode, &req->len_response,
1389 &req->size_response);
1390 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1391 odr_reset(assoc->encode);
1392 req->state = REQUEST_IDLE;
1393 request_enq(&assoc->outgoing, req);
1394 /* turn the work over to the ir_session handler */
1395 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1396 assoc->cs_put_mask = EVENT_OUTPUT;
1397 /* Is there more work to be done? give that to the input handler too */
1399 if (request_head(&assoc->incoming))
1401 yaz_log (LOG_DEBUG, "more work to be done");
1402 iochan_setevent(assoc->client_chan, EVENT_WORK);
1409 * Encode response, and transfer the request structure to the outgoing queue.
1411 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1413 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1414 gres->which = Z_GDU_Z3950;
1415 gres->u.z3950 = res;
1417 return process_gdu_response(assoc, req, gres);
1422 * Handle init request.
1423 * At the moment, we don't check the options
1424 * anywhere else in the code - we just try not to do anything that would
1425 * break a naive client. We'll toss 'em into the association block when
1426 * we need them there.
1428 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1430 statserv_options_block *cb = statserv_getcontrol();
1431 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1432 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1433 Z_InitResponse *resp = apdu->u.initResponse;
1434 bend_initresult *binitres;
1438 yaz_log(LOG_LOG, "Got initRequest");
1439 if (req->implementationId)
1440 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1441 if (req->implementationName)
1442 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1443 if (req->implementationVersion)
1444 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1446 assoc_init_reset(assoc);
1448 assoc->init->auth = req->idAuthentication;
1449 assoc->init->referenceId = req->referenceId;
1451 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1453 Z_CharSetandLanguageNegotiation *negotiation =
1454 yaz_get_charneg_record (req->otherInfo);
1455 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1456 assoc->init->charneg_request = negotiation;
1459 if (!(binitres = (*cb->bend_init)(assoc->init)))
1461 yaz_log(LOG_WARN, "Bad response from backend.");
1465 assoc->backend = binitres->handle;
1466 if ((assoc->init->bend_sort))
1467 yaz_log (LOG_DEBUG, "Sort handler installed");
1468 if ((assoc->init->bend_search))
1469 yaz_log (LOG_DEBUG, "Search handler installed");
1470 if ((assoc->init->bend_present))
1471 yaz_log (LOG_DEBUG, "Present handler installed");
1472 if ((assoc->init->bend_esrequest))
1473 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1474 if ((assoc->init->bend_delete))
1475 yaz_log (LOG_DEBUG, "Delete handler installed");
1476 if ((assoc->init->bend_scan))
1477 yaz_log (LOG_DEBUG, "Scan handler installed");
1478 if ((assoc->init->bend_segment))
1479 yaz_log (LOG_DEBUG, "Segment handler installed");
1481 resp->referenceId = req->referenceId;
1483 /* let's tell the client what we can do */
1484 if (ODR_MASK_GET(req->options, Z_Options_search))
1486 ODR_MASK_SET(resp->options, Z_Options_search);
1487 strcat(options, "srch");
1489 if (ODR_MASK_GET(req->options, Z_Options_present))
1491 ODR_MASK_SET(resp->options, Z_Options_present);
1492 strcat(options, " prst");
1494 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1495 assoc->init->bend_delete)
1497 ODR_MASK_SET(resp->options, Z_Options_delSet);
1498 strcat(options, " del");
1500 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1501 assoc->init->bend_esrequest)
1503 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1504 strcat (options, " extendedServices");
1506 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1508 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1509 strcat(options, " namedresults");
1511 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1513 ODR_MASK_SET(resp->options, Z_Options_scan);
1514 strcat(options, " scan");
1516 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1518 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1519 strcat(options, " concurrop");
1521 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1523 ODR_MASK_SET(resp->options, Z_Options_sort);
1524 strcat(options, " sort");
1527 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1528 && assoc->init->charneg_response)
1530 Z_OtherInformation **p;
1531 Z_OtherInformationUnit *p0;
1533 yaz_oi_APDU(apdu, &p);
1535 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1536 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1538 p0->which = Z_OtherInfo_externallyDefinedInfo;
1539 p0->information.externallyDefinedInfo =
1540 assoc->init->charneg_response;
1542 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1543 strcat(options, " negotiation");
1546 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1548 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1549 assoc->version = 2; /* 1 & 2 are equivalent */
1551 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1553 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1556 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1558 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1562 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1563 assoc->maximumRecordSize = *req->maximumRecordSize;
1564 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1565 assoc->maximumRecordSize = control_block->maxrecordsize;
1566 assoc->preferredMessageSize = *req->preferredMessageSize;
1567 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1568 assoc->preferredMessageSize = assoc->maximumRecordSize;
1570 resp->preferredMessageSize = &assoc->preferredMessageSize;
1571 resp->maximumRecordSize = &assoc->maximumRecordSize;
1573 resp->implementationName = "GFS/YAZ";
1575 if (assoc->init->implementation_id)
1578 odr_malloc (assoc->encode,
1579 strlen(assoc->init->implementation_id) + 10 +
1580 strlen(resp->implementationId));
1581 sprintf (nv, "%s / %s",
1582 resp->implementationId, assoc->init->implementation_id);
1583 resp->implementationId = nv;
1585 if (assoc->init->implementation_name)
1588 odr_malloc (assoc->encode,
1589 strlen(assoc->init->implementation_name) + 10 +
1590 strlen(resp->implementationName));
1591 sprintf (nv, "%s / %s",
1592 resp->implementationName, assoc->init->implementation_name);
1593 resp->implementationName = nv;
1595 if (assoc->init->implementation_version)
1598 odr_malloc (assoc->encode,
1599 strlen(assoc->init->implementation_version) + 10 +
1600 strlen(resp->implementationVersion));
1601 sprintf (nv, "YAZ %s / %s",
1602 resp->implementationVersion,
1603 assoc->init->implementation_version);
1604 resp->implementationVersion = nv;
1607 if (binitres->errcode)
1609 yaz_log(LOG_LOG, "Connection rejected by backend.");
1611 assoc->state = ASSOC_DEAD;
1614 assoc->state = ASSOC_UP;
1619 * These functions should be merged.
1622 static void set_addinfo (Z_DefaultDiagFormat *dr, char *addinfo, ODR odr)
1624 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1625 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1629 * nonsurrogate diagnostic record.
1631 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1633 Z_Records *rec = (Z_Records *)
1634 odr_malloc (assoc->encode, sizeof(*rec));
1635 int *err = odr_intdup(assoc->encode, error);
1636 Z_DiagRec *drec = (Z_DiagRec *)
1637 odr_malloc (assoc->encode, sizeof(*drec));
1638 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1639 odr_malloc (assoc->encode, sizeof(*dr));
1641 yaz_log(LOG_LOG, "[%d] %s %s%s", error, diagbib1_str(error),
1642 addinfo ? " -- " : "", addinfo ? addinfo : "");
1643 rec->which = Z_Records_NSD;
1644 rec->u.nonSurrogateDiagnostic = dr;
1645 dr->diagnosticSetId =
1646 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1647 dr->condition = err;
1648 set_addinfo (dr, addinfo, assoc->encode);
1653 * surrogate diagnostic.
1655 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1656 int error, char *addinfo)
1658 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1659 odr_malloc (assoc->encode, sizeof(*rec));
1660 int *err = odr_intdup(assoc->encode, error);
1661 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1662 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1663 odr_malloc (assoc->encode, sizeof(*dr));
1665 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1666 rec->databaseName = dbname;
1667 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1668 rec->u.surrogateDiagnostic = drec;
1669 drec->which = Z_DiagRec_defaultFormat;
1670 drec->u.defaultFormat = dr;
1671 dr->diagnosticSetId =
1672 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1673 dr->condition = err;
1674 set_addinfo (dr, addinfo, assoc->encode);
1680 * multiple nonsurrogate diagnostics.
1682 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1684 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1685 int *err = odr_intdup(assoc->encode, error);
1686 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1687 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1688 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1689 odr_malloc (assoc->encode, sizeof(*rec));
1691 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1693 recs->num_diagRecs = 1;
1694 recs->diagRecs = recp;
1696 drec->which = Z_DiagRec_defaultFormat;
1697 drec->u.defaultFormat = rec;
1699 rec->diagnosticSetId =
1700 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1701 rec->condition = err;
1703 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1704 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1708 static Z_Records *pack_records(association *a, char *setname, int start,
1709 int *num, Z_RecordComposition *comp,
1710 int *next, int *pres, oid_value format,
1711 Z_ReferenceId *referenceId,
1714 int recno, total_length = 0, toget = *num, dumped_records = 0;
1715 Z_Records *records =
1716 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1717 Z_NamePlusRecordList *reclist =
1718 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1719 Z_NamePlusRecord **list =
1720 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1722 records->which = Z_Records_DBOSD;
1723 records->u.databaseOrSurDiagnostics = reclist;
1724 reclist->num_records = 0;
1725 reclist->records = list;
1726 *pres = Z_PRES_SUCCESS;
1730 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1731 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1732 a->maximumRecordSize);
1733 for (recno = start; reclist->num_records < toget; recno++)
1736 Z_NamePlusRecord *thisrec;
1737 int this_length = 0;
1739 * we get the number of bytes allocated on the stream before any
1740 * allocation done by the backend - this should give us a reasonable
1741 * idea of the total size of the data so far.
1743 total_length = odr_total(a->encode) - dumped_records;
1749 freq.last_in_set = 0;
1750 freq.setname = setname;
1751 freq.surrogate_flag = 0;
1752 freq.number = recno;
1754 freq.request_format = format;
1755 freq.request_format_raw = oid;
1756 freq.output_format = format;
1757 freq.output_format_raw = 0;
1758 freq.stream = a->encode;
1759 freq.print = a->print;
1760 freq.referenceId = referenceId;
1762 (*a->init->bend_fetch)(a->backend, &freq);
1763 /* backend should be able to signal whether error is system-wide
1764 or only pertaining to current record */
1767 if (!freq.surrogate_flag)
1770 *pres = Z_PRES_FAILURE;
1771 /* for 'present request out of range',
1772 set addinfo to record position if not set */
1773 if (freq.errcode == 13 && freq.errstring == 0)
1775 sprintf (s, "%d", recno);
1778 return diagrec(a, freq.errcode, freq.errstring);
1780 reclist->records[reclist->num_records] =
1781 surrogatediagrec(a, freq.basename, freq.errcode,
1783 reclist->num_records++;
1784 *next = freq.last_in_set ? 0 : recno + 1;
1788 this_length = freq.len;
1790 this_length = odr_total(a->encode) - total_length;
1791 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1792 this_length, total_length);
1793 if (this_length + total_length > a->preferredMessageSize)
1795 /* record is small enough, really */
1796 if (this_length <= a->preferredMessageSize)
1798 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1799 *pres = Z_PRES_PARTIAL_2;
1802 /* record can only be fetched by itself */
1803 if (this_length < a->maximumRecordSize)
1805 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1808 yaz_log(LOG_DEBUG, " Dropped it");
1809 reclist->records[reclist->num_records] =
1810 surrogatediagrec(a, freq.basename, 16, 0);
1811 reclist->num_records++;
1812 *next = freq.last_in_set ? 0 : recno + 1;
1813 dumped_records += this_length;
1817 else /* too big entirely */
1819 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1820 reclist->records[reclist->num_records] =
1821 surrogatediagrec(a, freq.basename, 17, 0);
1822 reclist->num_records++;
1823 *next = freq.last_in_set ? 0 : recno + 1;
1824 dumped_records += this_length;
1829 if (!(thisrec = (Z_NamePlusRecord *)
1830 odr_malloc(a->encode, sizeof(*thisrec))))
1832 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1833 strlen(freq.basename) + 1)))
1835 strcpy(thisrec->databaseName, freq.basename);
1836 thisrec->which = Z_NamePlusRecord_databaseRecord;
1838 if (freq.output_format_raw)
1840 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1841 freq.output_format = ident->value;
1843 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1844 freq.record, freq.len);
1845 if (!thisrec->u.databaseRecord)
1847 reclist->records[reclist->num_records] = thisrec;
1848 reclist->num_records++;
1849 *next = freq.last_in_set ? 0 : recno + 1;
1851 *num = reclist->num_records;
1855 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1858 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1859 bend_search_rr *bsrr =
1860 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1862 yaz_log(LOG_LOG, "Got SearchRequest.");
1864 bsrr->request = reqb;
1865 bsrr->association = assoc;
1866 bsrr->referenceId = req->referenceId;
1867 save_referenceId (reqb, bsrr->referenceId);
1869 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1870 if (req->databaseNames)
1873 for (i = 0; i < req->num_databaseNames; i++)
1874 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1876 yaz_log_zquery(req->query);
1878 if (assoc->init->bend_search)
1880 bsrr->setname = req->resultSetName;
1881 bsrr->replace_set = *req->replaceIndicator;
1882 bsrr->num_bases = req->num_databaseNames;
1883 bsrr->basenames = req->databaseNames;
1884 bsrr->query = req->query;
1885 bsrr->stream = assoc->encode;
1886 bsrr->decode = assoc->decode;
1887 bsrr->print = assoc->print;
1890 bsrr->errstring = NULL;
1891 bsrr->search_info = NULL;
1892 (assoc->init->bend_search)(assoc->backend, bsrr);
1896 return response_searchRequest(assoc, reqb, bsrr, fd);
1899 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1902 * Prepare a searchresponse based on the backend results. We probably want
1903 * to look at making the fetching of records nonblocking as well, but
1904 * so far, we'll keep things simple.
1905 * If bsrt is null, that means we're called in response to a communications
1906 * event, and we'll have to get the response for ourselves.
1908 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1909 bend_search_rr *bsrt, int *fd)
1911 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1912 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1913 Z_SearchResponse *resp = (Z_SearchResponse *)
1914 odr_malloc (assoc->encode, sizeof(*resp));
1915 int *nulint = odr_intdup (assoc->encode, 0);
1916 bool_t *sr = odr_intdup(assoc->encode, 1);
1917 int *next = odr_intdup(assoc->encode, 0);
1918 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1920 apdu->which = Z_APDU_searchResponse;
1921 apdu->u.searchResponse = resp;
1922 resp->referenceId = req->referenceId;
1923 resp->additionalSearchInfo = 0;
1924 resp->otherInfo = 0;
1926 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1928 yaz_log(LOG_FATAL, "Bad result from backend");
1931 else if (bsrt->errcode)
1933 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1934 resp->resultCount = nulint;
1935 resp->numberOfRecordsReturned = nulint;
1936 resp->nextResultSetPosition = nulint;
1937 resp->searchStatus = nulint;
1938 resp->resultSetStatus = none;
1939 resp->presentStatus = 0;
1943 int *toget = odr_intdup(assoc->encode, 0);
1944 int *presst = odr_intdup(assoc->encode, 0);
1945 Z_RecordComposition comp, *compp = 0;
1947 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1950 resp->resultCount = &bsrt->hits;
1952 comp.which = Z_RecordComp_simple;
1953 /* how many records does the user agent want, then? */
1954 if (bsrt->hits <= *req->smallSetUpperBound)
1956 *toget = bsrt->hits;
1957 if ((comp.u.simple = req->smallSetElementSetNames))
1960 else if (bsrt->hits < *req->largeSetLowerBound)
1962 *toget = *req->mediumSetPresentNumber;
1963 if (*toget > bsrt->hits)
1964 *toget = bsrt->hits;
1965 if ((comp.u.simple = req->mediumSetElementSetNames))
1971 if (*toget && !resp->records)
1976 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1979 form = prefformat->value;
1980 resp->records = pack_records(assoc, req->resultSetName, 1,
1981 toget, compp, next, presst, form, req->referenceId,
1982 req->preferredRecordSyntax);
1985 resp->numberOfRecordsReturned = toget;
1986 resp->nextResultSetPosition = next;
1987 resp->searchStatus = sr;
1988 resp->resultSetStatus = 0;
1989 resp->presentStatus = presst;
1993 if (*resp->resultCount)
1995 resp->numberOfRecordsReturned = nulint;
1996 resp->nextResultSetPosition = next;
1997 resp->searchStatus = sr;
1998 resp->resultSetStatus = 0;
1999 resp->presentStatus = 0;
2002 resp->additionalSearchInfo = bsrt->search_info;
2007 * Maybe we got a little over-friendly when we designed bend_fetch to
2008 * get only one record at a time. Some backends can optimise multiple-record
2009 * fetches, and at any rate, there is some overhead involved in
2010 * all that selecting and hopping around. Problem is, of course, that the
2011 * frontend can't know ahead of time how many records it'll need to
2012 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2013 * is downright lousy as a bulk data transfer protocol.
2015 * To start with, we'll do the fetching of records from the backend
2016 * in one operation: To save some trips in and out of the event-handler,
2017 * and to simplify the interface to pack_records. At any rate, asynch
2018 * operation is more fun in operations that have an unpredictable execution
2019 * speed - which is normally more true for search than for present.
2021 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2024 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2028 Z_PresentResponse *resp;
2032 yaz_log(LOG_LOG, "Got PresentRequest.");
2034 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2037 form = prefformat->value;
2038 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2040 resp->presentStatus = odr_intdup(assoc->encode, 0);
2041 if (assoc->init->bend_present)
2043 bend_present_rr *bprr = (bend_present_rr *)
2044 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2045 bprr->setname = req->resultSetId;
2046 bprr->start = *req->resultSetStartPoint;
2047 bprr->number = *req->numberOfRecordsRequested;
2048 bprr->format = form;
2049 bprr->comp = req->recordComposition;
2050 bprr->referenceId = req->referenceId;
2051 bprr->stream = assoc->encode;
2052 bprr->print = assoc->print;
2053 bprr->request = reqb;
2054 bprr->association = assoc;
2056 bprr->errstring = NULL;
2057 (*assoc->init->bend_present)(assoc->backend, bprr);
2063 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2064 *resp->presentStatus = Z_PRES_FAILURE;
2067 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2068 next = odr_intdup(assoc->encode, 0);
2069 num = odr_intdup(assoc->encode, 0);
2071 apdu->which = Z_APDU_presentResponse;
2072 apdu->u.presentResponse = resp;
2073 resp->referenceId = req->referenceId;
2074 resp->otherInfo = 0;
2078 *num = *req->numberOfRecordsRequested;
2080 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2081 num, req->recordComposition, next, resp->presentStatus,
2082 form, req->referenceId, req->preferredRecordSyntax);
2086 resp->numberOfRecordsReturned = num;
2087 resp->nextResultSetPosition = next;
2093 * Scan was implemented rather in a hurry, and with support for only the basic
2094 * elements of the service in the backend API. Suggestions are welcome.
2096 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2098 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2099 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2100 Z_ScanResponse *res = (Z_ScanResponse *)
2101 odr_malloc (assoc->encode, sizeof(*res));
2102 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2103 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2104 Z_ListEntries *ents = (Z_ListEntries *)
2105 odr_malloc (assoc->encode, sizeof(*ents));
2106 Z_DiagRecs *diagrecs_p = NULL;
2108 bend_scan_rr *bsrr = (bend_scan_rr *)
2109 odr_malloc (assoc->encode, sizeof(*bsrr));
2110 struct scan_entry *save_entries;
2112 yaz_log(LOG_LOG, "Got ScanRequest");
2114 apdu->which = Z_APDU_scanResponse;
2115 apdu->u.scanResponse = res;
2116 res->referenceId = req->referenceId;
2118 /* if step is absent, set it to 0 */
2119 res->stepSize = odr_intdup(assoc->encode, 0);
2121 *res->stepSize = *req->stepSize;
2123 res->scanStatus = scanStatus;
2124 res->numberOfEntriesReturned = numberOfEntriesReturned;
2125 res->positionOfTerm = 0;
2126 res->entries = ents;
2127 ents->num_entries = 0;
2128 ents->entries = NULL;
2129 ents->num_nonsurrogateDiagnostics = 0;
2130 ents->nonsurrogateDiagnostics = NULL;
2131 res->attributeSet = 0;
2134 if (req->databaseNames)
2137 for (i = 0; i < req->num_databaseNames; i++)
2138 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2140 bsrr->num_bases = req->num_databaseNames;
2141 bsrr->basenames = req->databaseNames;
2142 bsrr->num_entries = *req->numberOfTermsRequested;
2143 bsrr->term = req->termListAndStartPoint;
2144 bsrr->referenceId = req->referenceId;
2145 bsrr->stream = assoc->encode;
2146 bsrr->print = assoc->print;
2147 bsrr->step_size = res->stepSize;
2149 /* Note that version 2.0 of YAZ and older did not set entries ..
2150 We do now. And when we do it's easier to extend the scan entry
2151 We know that if the scan handler did set entries, it will
2152 not know of new member display_term.
2154 if (bsrr->num_entries > 0)
2157 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2159 for (i = 0; i<bsrr->num_entries; i++)
2161 bsrr->entries[i].term = 0;
2162 bsrr->entries[i].occurrences = 0;
2163 bsrr->entries[i].errcode = 0;
2164 bsrr->entries[i].errstring = 0;
2165 bsrr->entries[i].display_term = 0;
2168 save_entries = bsrr->entries; /* save it so we can compare later */
2170 if (req->attributeSet &&
2171 (attset = oid_getentbyoid(req->attributeSet)) &&
2172 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2173 bsrr->attributeset = attset->value;
2175 bsrr->attributeset = VAL_NONE;
2176 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2177 bsrr->term_position = req->preferredPositionInResponse ?
2178 *req->preferredPositionInResponse : 1;
2179 ((int (*)(void *, bend_scan_rr *))
2180 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2182 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2186 Z_Entry **tab = (Z_Entry **)
2187 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2189 if (bsrr->status == BEND_SCAN_PARTIAL)
2190 *scanStatus = Z_Scan_partial_5;
2192 *scanStatus = Z_Scan_success;
2193 ents->entries = tab;
2194 ents->num_entries = bsrr->num_entries;
2195 res->numberOfEntriesReturned = &ents->num_entries;
2196 res->positionOfTerm = &bsrr->term_position;
2197 for (i = 0; i < bsrr->num_entries; i++)
2203 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2204 if (bsrr->entries[i].occurrences >= 0)
2206 e->which = Z_Entry_termInfo;
2207 e->u.termInfo = t = (Z_TermInfo *)
2208 odr_malloc(assoc->encode, sizeof(*t));
2209 t->suggestedAttributes = 0;
2211 if (save_entries == bsrr->entries &&
2212 bsrr->entries[i].display_term)
2214 /* the entries was NOT set by the handler. So it's
2215 safe to test for new member display_term. It is
2218 t->displayTerm = odr_strdup(assoc->encode,
2219 bsrr->entries[i].display_term);
2221 t->alternativeTerm = 0;
2222 t->byAttributes = 0;
2223 t->otherTermInfo = 0;
2224 t->globalOccurrences = &bsrr->entries[i].occurrences;
2225 t->term = (Z_Term *)
2226 odr_malloc(assoc->encode, sizeof(*t->term));
2227 t->term->which = Z_Term_general;
2228 t->term->u.general = o =
2229 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2230 o->buf = (unsigned char *)
2231 odr_malloc(assoc->encode, o->len = o->size =
2232 strlen(bsrr->entries[i].term));
2233 memcpy(o->buf, bsrr->entries[i].term, o->len);
2234 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2235 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2239 Z_DiagRecs *drecs = diagrecs (assoc,
2240 bsrr->entries[i].errcode,
2241 bsrr->entries[i].errstring);
2242 assert (drecs->num_diagRecs == 1);
2243 e->which = Z_Entry_surrogateDiagnostic;
2244 assert (drecs->diagRecs[0]);
2245 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2251 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2252 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2257 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2260 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2261 Z_SortResponse *res = (Z_SortResponse *)
2262 odr_malloc (assoc->encode, sizeof(*res));
2263 bend_sort_rr *bsrr = (bend_sort_rr *)
2264 odr_malloc (assoc->encode, sizeof(*bsrr));
2266 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2268 yaz_log(LOG_LOG, "Got SortRequest.");
2270 bsrr->num_input_setnames = req->num_inputResultSetNames;
2271 bsrr->input_setnames = req->inputResultSetNames;
2272 bsrr->referenceId = req->referenceId;
2273 bsrr->output_setname = req->sortedResultSetName;
2274 bsrr->sort_sequence = req->sortSequence;
2275 bsrr->stream = assoc->encode;
2276 bsrr->print = assoc->print;
2278 bsrr->sort_status = Z_SortStatus_failure;
2280 bsrr->errstring = 0;
2282 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2284 res->referenceId = bsrr->referenceId;
2285 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2286 res->resultSetStatus = 0;
2289 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2290 res->diagnostics = dr->diagRecs;
2291 res->num_diagnostics = dr->num_diagRecs;
2295 res->num_diagnostics = 0;
2296 res->diagnostics = 0;
2300 apdu->which = Z_APDU_sortResponse;
2301 apdu->u.sortResponse = res;
2305 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2308 Z_DeleteResultSetRequest *req =
2309 reqb->apdu_request->u.deleteResultSetRequest;
2310 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2311 odr_malloc (assoc->encode, sizeof(*res));
2312 bend_delete_rr *bdrr = (bend_delete_rr *)
2313 odr_malloc (assoc->encode, sizeof(*bdrr));
2314 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2316 yaz_log(LOG_LOG, "Got DeleteRequest.");
2318 bdrr->num_setnames = req->num_resultSetList;
2319 bdrr->setnames = req->resultSetList;
2320 bdrr->stream = assoc->encode;
2321 bdrr->print = assoc->print;
2322 bdrr->function = *req->deleteFunction;
2323 bdrr->referenceId = req->referenceId;
2325 if (bdrr->num_setnames > 0)
2328 bdrr->statuses = (int*)
2329 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2330 bdrr->num_setnames);
2331 for (i = 0; i < bdrr->num_setnames; i++)
2332 bdrr->statuses[i] = 0;
2334 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2336 res->referenceId = req->referenceId;
2338 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2340 res->deleteListStatuses = 0;
2341 if (bdrr->num_setnames > 0)
2344 res->deleteListStatuses = (Z_ListStatuses *)
2345 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2346 res->deleteListStatuses->num = bdrr->num_setnames;
2347 res->deleteListStatuses->elements =
2349 odr_malloc (assoc->encode,
2350 sizeof(*res->deleteListStatuses->elements) *
2351 bdrr->num_setnames);
2352 for (i = 0; i<bdrr->num_setnames; i++)
2354 res->deleteListStatuses->elements[i] =
2356 odr_malloc (assoc->encode,
2357 sizeof(**res->deleteListStatuses->elements));
2358 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2359 res->deleteListStatuses->elements[i]->id =
2360 odr_strdup (assoc->encode, bdrr->setnames[i]);
2364 res->numberNotDeleted = 0;
2365 res->bulkStatuses = 0;
2366 res->deleteMessage = 0;
2369 apdu->which = Z_APDU_deleteResultSetResponse;
2370 apdu->u.deleteResultSetResponse = res;
2374 static void process_close(association *assoc, request *reqb)
2376 Z_Close *req = reqb->apdu_request->u.close;
2377 static char *reasons[] =
2384 "securityViolation",
2391 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2392 reasons[*req->closeReason], req->diagnosticInformation ?
2393 req->diagnosticInformation : "NULL");
2394 if (assoc->version < 3) /* to make do_force respond with close */
2396 do_close_req(assoc, Z_Close_finished,
2397 "Association terminated by client", reqb);
2400 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2404 reqb->len_refid = refid->len;
2405 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2406 memcpy (reqb->refid, refid->buf, refid->len);
2410 reqb->len_refid = 0;
2415 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2417 process_z_response (a, req, res);
2420 bend_request bend_request_mk (bend_association a)
2422 request *nreq = request_get (&a->outgoing);
2423 nreq->request_mem = nmem_create ();
2427 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2432 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2433 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2434 id->len = id->size = req->len_refid;
2435 memcpy (id->buf, req->refid, req->len_refid);
2439 void bend_request_destroy (bend_request *req)
2441 nmem_destroy((*req)->request_mem);
2442 request_release(*req);
2446 int bend_backend_respond (bend_association a, bend_request req)
2450 r = process_z_request (a, req, &msg);
2452 yaz_log (LOG_WARN, "%s", msg);
2456 void bend_request_setdata(bend_request r, void *p)
2461 void *bend_request_getdata(bend_request r)
2463 return r->clientData;
2466 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2468 bend_segment_rr req;
2470 req.segment = reqb->apdu_request->u.segmentRequest;
2471 req.stream = assoc->encode;
2472 req.decode = assoc->decode;
2473 req.print = assoc->print;
2474 req.association = assoc;
2476 (*assoc->init->bend_segment)(assoc->backend, &req);
2481 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2483 bend_esrequest_rr esrequest;
2485 Z_ExtendedServicesRequest *req =
2486 reqb->apdu_request->u.extendedServicesRequest;
2487 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2489 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2491 yaz_log(LOG_DEBUG,"inside Process esRequest");
2493 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2494 esrequest.stream = assoc->encode;
2495 esrequest.decode = assoc->decode;
2496 esrequest.print = assoc->print;
2497 esrequest.errcode = 0;
2498 esrequest.errstring = NULL;
2499 esrequest.request = reqb;
2500 esrequest.association = assoc;
2501 esrequest.taskPackage = 0;
2502 esrequest.referenceId = req->referenceId;
2504 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2506 /* If the response is being delayed, return NULL */
2507 if (esrequest.request == NULL)
2510 resp->referenceId = req->referenceId;
2512 if (esrequest.errcode == -1)
2514 /* Backend service indicates request will be processed */
2515 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2516 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2518 else if (esrequest.errcode == 0)
2520 /* Backend service indicates request will be processed */
2521 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2522 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2526 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2527 esrequest.errstring);
2529 /* Backend indicates error, request will not be processed */
2530 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2531 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2532 resp->num_diagnostics = diagRecs->num_diagRecs;
2533 resp->diagnostics = diagRecs->diagRecs;
2535 /* Do something with the members of bend_extendedservice */
2536 if (esrequest.taskPackage)
2537 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2538 (const char *) esrequest.taskPackage,
2540 yaz_log(LOG_DEBUG,"Send the result apdu");