2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.155 2003-04-29 21:20: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 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
662 if (srw_req->maximumRecords && *srw_req->maximumRecords > 0)
664 int number = *srw_req->maximumRecords;
668 if (srw_req->startRecord)
669 start = *srw_req->startRecord;
671 yaz_log(LOG_DEBUG, "srw_bend_search. start=%d max=%d",
672 start, *srw_req->maximumRecords);
674 if (start <= rr.hits)
677 int packing = Z_SRW_recordPacking_string;
678 if (start + number > rr.hits)
679 number = rr.hits - start + 1;
680 if (srw_req->recordPacking &&
681 !strcmp(srw_req->recordPacking, "xml"))
682 packing = Z_SRW_recordPacking_XML;
683 srw_res->records = (Z_SRW_record *)
684 odr_malloc(assoc->encode,
685 number * sizeof(*srw_res->records));
686 for (i = 0; i<number; i++)
690 srw_res->records[j].recordPacking = packing;
691 srw_res->records[j].recordData_buf = 0;
692 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
693 errcode = srw_bend_fetch(assoc, i+start, srw_req,
694 srw_res->records + j);
697 srw_res->num_diagnostics = 1;
698 srw_res->diagnostics = (Z_SRW_diagnostic *)
699 odr_malloc(assoc->encode,
700 sizeof(*srw_res->diagnostics));
701 srw_res->diagnostics[0].code =
702 odr_intdup(assoc->encode,
703 yaz_diag_bib1_to_srw (errcode));
704 srw_res->diagnostics[0].details = rr.errstring;
707 if (srw_res->records[j].recordData_buf)
710 srw_res->num_records = j;
712 srw_res->records = 0;
719 static void srw_bend_explain(association *assoc, request *req,
720 Z_SRW_explainRequest *srw_req,
721 Z_SRW_explainResponse *srw_res)
723 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
726 yaz_log(LOG_DEBUG, "srw_bend_init");
727 if (!srw_bend_init(assoc))
730 if (assoc->init && assoc->init->bend_explain)
734 rr.stream = assoc->encode;
735 rr.decode = assoc->decode;
736 rr.print = assoc->print;
738 (*assoc->init->bend_explain)(assoc->backend, &rr);
741 srw_res->explainData_buf = rr.explain_buf;
742 srw_res->explainData_len = strlen(rr.explain_buf);
747 static int hex_digit (int ch)
749 if (ch >= '0' && ch <= '9')
751 else if (ch >= 'a' && ch <= 'f')
753 else if (ch >= 'A' && ch <= 'F')
758 static char *uri_val(const char *path, const char *name, ODR o)
760 size_t nlen = strlen(name);
764 while (path && *path)
766 const char *p1 = strchr(path, '=');
769 if (p1 - path == nlen && !memcmp(path, name, nlen))
775 p1 = strchr(path, '&');
777 p1 = strlen(path) + path;
778 ret = odr_malloc(o, p1 - path + 1);
779 while (*path && *path != '&')
786 else if (*path == '%' && path[1] && path[2])
788 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
797 path = strchr(p1, '&');
804 void uri_val_int(const char *path, const char *name, ODR o, int **intp)
806 const char *v = uri_val(path, name, o);
808 *intp = odr_intdup(o, atoi(v));
811 static void process_http_request(association *assoc, request *req)
813 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
814 ODR o = assoc->encode;
816 Z_HTTP_Response *hres = 0;
819 if (!strcmp(hreq->method, "GET"))
821 char *db = "Default";
822 const char *p0 = hreq->path, *p1;
826 Z_SOAP *soap_package = 0;
827 static Z_SOAP_Handler soap_handlers[2] = {
828 {"http://www.loc.gov/zing/srw/v1.0/", 0,
829 (Z_SOAP_fun) yaz_srw_codec},
836 p1 = strchr(p0, '?');
838 p1 = p0 + strlen(p0);
841 db = odr_malloc(assoc->decode, p1 - p0 + 1);
842 memcpy (db, p0, p1 - p0);
846 if (p1 && *p1 == '?' && p1[1])
848 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
849 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
850 char *query = uri_val(p1, "query", o);
851 char *pQuery = uri_val(p1, "pQuery", o);
852 char *sortKeys = uri_val(p1, "sortKeys", o);
856 sr->u.request->query_type = Z_SRW_query_type_cql;
857 sr->u.request->query.cql = query;
861 sr->u.request->query_type = Z_SRW_query_type_pqf;
862 sr->u.request->query.pqf = pQuery;
866 sr->u.request->sort_type = Z_SRW_sort_type_sort;
867 sr->u.request->sort.sortKeys = sortKeys;
869 sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
870 sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
871 if (!sr->u.request->recordPacking)
872 sr->u.request->recordPacking = "xml";
873 uri_val_int(p1, "maximumRecords", o,
874 &sr->u.request->maximumRecords);
875 uri_val_int(p1, "startRecord", o,
876 &sr->u.request->startRecord);
877 if (sr->u.request->startRecord)
878 yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
879 sr->u.request->database = db;
880 srw_bend_search(assoc, req, sr->u.request, res->u.response);
882 soap_package = odr_malloc(o, sizeof(*soap_package));
883 soap_package->which = Z_SOAP_generic;
885 soap_package->u.generic =
886 odr_malloc(o, sizeof(*soap_package->u.generic));
888 soap_package->u.generic->p = res;
889 soap_package->u.generic->ns = soap_handlers[0].ns;
890 soap_package->u.generic->no = 0;
892 soap_package->ns = "SRU";
894 p = z_get_HTTP_Response(o, 200);
895 hres = p->u.HTTP_Response;
897 ret = z_soap_codec_enc(assoc->encode, &soap_package,
898 &hres->content_buf, &hres->content_len,
899 soap_handlers, charset);
901 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
905 strcpy(ctype, "text/xml; charset=");
906 strcat(ctype, charset);
907 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
913 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
914 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
916 srw_bend_explain(assoc, req, sr->u.explain_request,
917 res->u.explain_response);
919 if (res->u.explain_response->explainData_buf)
921 soap_package = odr_malloc(o, sizeof(*soap_package));
922 soap_package->which = Z_SOAP_generic;
924 soap_package->u.generic =
925 odr_malloc(o, sizeof(*soap_package->u.generic));
927 soap_package->u.generic->p = res;
928 soap_package->u.generic->ns = soap_handlers[0].ns;
929 soap_package->u.generic->no = 0;
931 soap_package->ns = "SRU";
933 p = z_get_HTTP_Response(o, 200);
934 hres = p->u.HTTP_Response;
936 ret = z_soap_codec_enc(assoc->encode, &soap_package,
937 &hres->content_buf, &hres->content_len,
938 soap_handlers, charset);
940 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
944 strcpy(ctype, "text/xml; charset=");
945 strcat(ctype, charset);
946 z_HTTP_header_add(o, &hres->headers, "Content-Type",
953 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
954 !memcmp(hreq->path, "/doc/", 5))
959 strcpy(fpath, DOCDIR);
960 strcat(fpath, hreq->path+4);
961 f = fopen(fpath, "rb");
964 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
973 fseek(f, 0L, SEEK_END);
975 if (sz >= 0 && sz < 500000)
977 const char *ctype = "application/octet-stream";
980 p = z_get_HTTP_Response(o, 200);
981 hres = p->u.HTTP_Response;
982 hres->content_buf = (char *) odr_malloc(o, sz + 1);
983 hres->content_len = sz;
984 fseek(f, 0L, SEEK_SET);
985 fread(hres->content_buf, 1, sz, f);
986 if ((cp = strrchr(fpath, '.'))) {
988 if (!strcmp(cp, "png"))
990 else if (!strcmp(cp, "gif"))
992 else if (!strcmp(cp, "xml"))
994 else if (!strcmp(cp, "html"))
997 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1005 if (!strcmp(hreq->path, "/"))
1010 const char *doclink = "";
1011 p = z_get_HTTP_Response(o, 200);
1012 hres = p->u.HTTP_Response;
1013 hres->content_buf = (char *) odr_malloc(o, 400);
1015 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
1016 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
1018 sprintf (hres->content_buf,
1019 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1022 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1025 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1026 YAZ_VERSION "</P>\n"
1029 "</HTML>\n", doclink);
1030 hres->content_len = strlen(hres->content_buf);
1031 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1037 p = z_get_HTTP_Response(o, 404);
1040 else if (!strcmp(hreq->method, "POST"))
1042 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1044 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1046 Z_SOAP *soap_package = 0;
1048 int http_code = 500;
1049 const char *charset_p = 0;
1052 static Z_SOAP_Handler soap_handlers[2] = {
1054 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1055 (Z_SOAP_fun) yaz_srw_codec},
1059 if ((charset_p = strstr(content_type, "; charset=")))
1063 while (i < 20 && charset_p[i] &&
1064 !strchr("; \n\r", charset_p[i]))
1066 charset = odr_malloc(assoc->encode, i+1);
1067 memcpy(charset, charset_p, i);
1069 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1071 ret = z_soap_codec(assoc->decode, &soap_package,
1072 &hreq->content_buf, &hreq->content_len,
1075 if (!ret && soap_package->which == Z_SOAP_generic &&
1076 soap_package->u.generic->no == 0)
1079 Z_SRW_PDU *sr = soap_package->u.generic->p;
1081 if (sr->which == Z_SRW_searchRetrieve_request)
1084 yaz_srw_get(assoc->encode,
1085 Z_SRW_searchRetrieve_response);
1087 if (!sr->u.request->database)
1089 const char *p0 = hreq->path, *p1;
1092 p1 = strchr(p0, '?');
1094 p1 = p0 + strlen(p0);
1097 sr->u.request->database =
1098 odr_malloc(assoc->decode, p1 - p0 + 1);
1099 memcpy (sr->u.request->database, p0, p1 - p0);
1100 sr->u.request->database[p1 - p0] = '\0';
1103 sr->u.request->database = "Default";
1105 srw_bend_search(assoc, req, sr->u.request,
1108 soap_package->u.generic->p = res;
1111 else if (sr->which == Z_SRW_explain_request)
1114 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1116 srw_bend_explain(assoc, req, sr->u.explain_request,
1117 res->u.explain_response);
1118 if (!res->u.explain_response->explainData_buf)
1120 z_soap_error(assoc->encode, soap_package,
1121 "SOAP-ENV:Client", "Explain Not Supported", 0);
1125 soap_package->u.generic->p = res;
1131 z_soap_error(assoc->encode, soap_package,
1132 "SOAP-ENV:Client", "Bad method", 0);
1136 p = z_get_HTTP_Response(o, 200);
1137 hres = p->u.HTTP_Response;
1138 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1139 &hres->content_buf, &hres->content_len,
1140 soap_handlers, charset);
1141 hres->code = http_code;
1143 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1147 strcpy(ctype, "text/xml; charset=");
1148 strcat(ctype, charset);
1149 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1152 if (!p) /* still no response ? */
1153 p = z_get_HTTP_Response(o, 500);
1157 p = z_get_HTTP_Response(o, 405);
1158 hres = p->u.HTTP_Response;
1160 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1162 hres = p->u.HTTP_Response;
1163 if (!strcmp(hreq->version, "1.0"))
1165 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1166 if (v && !strcmp(v, "Keep-Alive"))
1170 hres->version = "1.0";
1174 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1175 if (v && !strcmp(v, "close"))
1179 hres->version = "1.1";
1183 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1184 assoc->state = ASSOC_DEAD;
1189 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1191 if (alive && isdigit(*alive))
1195 if (t < 0 || t > 3600)
1197 iochan_settimeout(assoc->client_chan,t);
1198 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1200 process_gdu_response(assoc, req, p);
1203 static void process_gdu_request(association *assoc, request *req)
1205 if (req->gdu_request->which == Z_GDU_Z3950)
1208 req->apdu_request = req->gdu_request->u.z3950;
1209 if (process_z_request(assoc, req, &msg) < 0)
1210 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1212 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1213 process_http_request(assoc, req);
1216 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1221 * Initiate request processing.
1223 static int process_z_request(association *assoc, request *req, char **msg)
1229 *msg = "Unknown Error";
1230 assert(req && req->state == REQUEST_IDLE);
1231 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1233 *msg = "Missing InitRequest";
1236 switch (req->apdu_request->which)
1238 case Z_APDU_initRequest:
1239 iochan_settimeout(assoc->client_chan,
1240 statserv_getcontrol()->idle_timeout * 60);
1241 res = process_initRequest(assoc, req); break;
1242 case Z_APDU_searchRequest:
1243 res = process_searchRequest(assoc, req, &fd); break;
1244 case Z_APDU_presentRequest:
1245 res = process_presentRequest(assoc, req, &fd); break;
1246 case Z_APDU_scanRequest:
1247 if (assoc->init->bend_scan)
1248 res = process_scanRequest(assoc, req, &fd);
1251 *msg = "Cannot handle Scan APDU";
1255 case Z_APDU_extendedServicesRequest:
1256 if (assoc->init->bend_esrequest)
1257 res = process_ESRequest(assoc, req, &fd);
1260 *msg = "Cannot handle Extended Services APDU";
1264 case Z_APDU_sortRequest:
1265 if (assoc->init->bend_sort)
1266 res = process_sortRequest(assoc, req, &fd);
1269 *msg = "Cannot handle Sort APDU";
1274 process_close(assoc, req);
1276 case Z_APDU_deleteResultSetRequest:
1277 if (assoc->init->bend_delete)
1278 res = process_deleteRequest(assoc, req, &fd);
1281 *msg = "Cannot handle Delete APDU";
1285 case Z_APDU_segmentRequest:
1286 if (assoc->init->bend_segment)
1288 res = process_segmentRequest (assoc, req);
1292 *msg = "Cannot handle Segment APDU";
1297 *msg = "Bad APDU received";
1302 yaz_log(LOG_DEBUG, " result immediately available");
1303 retval = process_z_response(assoc, req, res);
1307 yaz_log(LOG_DEBUG, " result unavailble");
1310 else /* no result yet - one will be provided later */
1314 /* Set up an I/O handler for the fd supplied by the backend */
1316 yaz_log(LOG_DEBUG, " establishing handler for result");
1317 req->state = REQUEST_PENDING;
1318 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1320 iochan_setdata(chan, assoc);
1327 * Handle message from the backend.
1329 void backend_response(IOCHAN i, int event)
1331 association *assoc = (association *)iochan_getdata(i);
1332 request *req = request_head(&assoc->incoming);
1336 yaz_log(LOG_DEBUG, "backend_response");
1337 assert(assoc && req && req->state != REQUEST_IDLE);
1338 /* determine what it is we're waiting for */
1339 switch (req->apdu_request->which)
1341 case Z_APDU_searchRequest:
1342 res = response_searchRequest(assoc, req, 0, &fd); break;
1344 case Z_APDU_presentRequest:
1345 res = response_presentRequest(assoc, req, 0, &fd); break;
1346 case Z_APDU_scanRequest:
1347 res = response_scanRequest(assoc, req, 0, &fd); break;
1350 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1353 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1355 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1356 do_close(assoc, Z_Close_systemProblem, 0);
1360 else if (!res) /* no result yet - try again later */
1362 yaz_log(LOG_DEBUG, " no result yet");
1363 iochan_setfd(i, fd); /* in case fd has changed */
1368 * Encode response, and transfer the request structure to the outgoing queue.
1370 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1372 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1374 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1376 yaz_log(LOG_WARN, "ODR print error: %s",
1377 odr_errmsg(odr_geterror(assoc->print)));
1378 odr_reset(assoc->print);
1380 if (!z_GDU(assoc->encode, &res, 0, 0))
1382 yaz_log(LOG_WARN, "ODR error when encoding response: %s",
1383 odr_errmsg(odr_geterror(assoc->decode)));
1386 req->response = odr_getbuf(assoc->encode, &req->len_response,
1387 &req->size_response);
1388 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1389 odr_reset(assoc->encode);
1390 req->state = REQUEST_IDLE;
1391 request_enq(&assoc->outgoing, req);
1392 /* turn the work over to the ir_session handler */
1393 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1394 assoc->cs_put_mask = EVENT_OUTPUT;
1395 /* Is there more work to be done? give that to the input handler too */
1397 if (request_head(&assoc->incoming))
1399 yaz_log (LOG_DEBUG, "more work to be done");
1400 iochan_setevent(assoc->client_chan, EVENT_WORK);
1407 * Encode response, and transfer the request structure to the outgoing queue.
1409 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1411 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1412 gres->which = Z_GDU_Z3950;
1413 gres->u.z3950 = res;
1415 return process_gdu_response(assoc, req, gres);
1420 * Handle init request.
1421 * At the moment, we don't check the options
1422 * anywhere else in the code - we just try not to do anything that would
1423 * break a naive client. We'll toss 'em into the association block when
1424 * we need them there.
1426 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1428 statserv_options_block *cb = statserv_getcontrol();
1429 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1430 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1431 Z_InitResponse *resp = apdu->u.initResponse;
1432 bend_initresult *binitres;
1436 yaz_log(LOG_LOG, "Got initRequest");
1437 if (req->implementationId)
1438 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1439 if (req->implementationName)
1440 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1441 if (req->implementationVersion)
1442 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1444 assoc_init_reset(assoc);
1446 assoc->init->auth = req->idAuthentication;
1447 assoc->init->referenceId = req->referenceId;
1449 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1451 Z_CharSetandLanguageNegotiation *negotiation =
1452 yaz_get_charneg_record (req->otherInfo);
1453 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1454 assoc->init->charneg_request = negotiation;
1457 if (!(binitres = (*cb->bend_init)(assoc->init)))
1459 yaz_log(LOG_WARN, "Bad response from backend.");
1463 assoc->backend = binitres->handle;
1464 if ((assoc->init->bend_sort))
1465 yaz_log (LOG_DEBUG, "Sort handler installed");
1466 if ((assoc->init->bend_search))
1467 yaz_log (LOG_DEBUG, "Search handler installed");
1468 if ((assoc->init->bend_present))
1469 yaz_log (LOG_DEBUG, "Present handler installed");
1470 if ((assoc->init->bend_esrequest))
1471 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1472 if ((assoc->init->bend_delete))
1473 yaz_log (LOG_DEBUG, "Delete handler installed");
1474 if ((assoc->init->bend_scan))
1475 yaz_log (LOG_DEBUG, "Scan handler installed");
1476 if ((assoc->init->bend_segment))
1477 yaz_log (LOG_DEBUG, "Segment handler installed");
1479 resp->referenceId = req->referenceId;
1481 /* let's tell the client what we can do */
1482 if (ODR_MASK_GET(req->options, Z_Options_search))
1484 ODR_MASK_SET(resp->options, Z_Options_search);
1485 strcat(options, "srch");
1487 if (ODR_MASK_GET(req->options, Z_Options_present))
1489 ODR_MASK_SET(resp->options, Z_Options_present);
1490 strcat(options, " prst");
1492 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1493 assoc->init->bend_delete)
1495 ODR_MASK_SET(resp->options, Z_Options_delSet);
1496 strcat(options, " del");
1498 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1499 assoc->init->bend_esrequest)
1501 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1502 strcat (options, " extendedServices");
1504 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1506 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1507 strcat(options, " namedresults");
1509 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1511 ODR_MASK_SET(resp->options, Z_Options_scan);
1512 strcat(options, " scan");
1514 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1516 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1517 strcat(options, " concurrop");
1519 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1521 ODR_MASK_SET(resp->options, Z_Options_sort);
1522 strcat(options, " sort");
1525 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1526 && assoc->init->charneg_response)
1528 Z_OtherInformation **p;
1529 Z_OtherInformationUnit *p0;
1531 yaz_oi_APDU(apdu, &p);
1533 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1534 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1536 p0->which = Z_OtherInfo_externallyDefinedInfo;
1537 p0->information.externallyDefinedInfo =
1538 assoc->init->charneg_response;
1540 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1541 strcat(options, " negotiation");
1544 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1546 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1547 assoc->version = 2; /* 1 & 2 are equivalent */
1549 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1551 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1554 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1556 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1560 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1561 assoc->maximumRecordSize = *req->maximumRecordSize;
1562 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1563 assoc->maximumRecordSize = control_block->maxrecordsize;
1564 assoc->preferredMessageSize = *req->preferredMessageSize;
1565 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1566 assoc->preferredMessageSize = assoc->maximumRecordSize;
1568 resp->preferredMessageSize = &assoc->preferredMessageSize;
1569 resp->maximumRecordSize = &assoc->maximumRecordSize;
1571 resp->implementationName = "GFS/YAZ";
1573 if (assoc->init->implementation_id)
1576 odr_malloc (assoc->encode,
1577 strlen(assoc->init->implementation_id) + 10 +
1578 strlen(resp->implementationId));
1579 sprintf (nv, "%s / %s",
1580 resp->implementationId, assoc->init->implementation_id);
1581 resp->implementationId = nv;
1583 if (assoc->init->implementation_name)
1586 odr_malloc (assoc->encode,
1587 strlen(assoc->init->implementation_name) + 10 +
1588 strlen(resp->implementationName));
1589 sprintf (nv, "%s / %s",
1590 resp->implementationName, assoc->init->implementation_name);
1591 resp->implementationName = nv;
1593 if (assoc->init->implementation_version)
1596 odr_malloc (assoc->encode,
1597 strlen(assoc->init->implementation_version) + 10 +
1598 strlen(resp->implementationVersion));
1599 sprintf (nv, "YAZ %s / %s",
1600 resp->implementationVersion,
1601 assoc->init->implementation_version);
1602 resp->implementationVersion = nv;
1605 if (binitres->errcode)
1607 yaz_log(LOG_LOG, "Connection rejected by backend.");
1609 assoc->state = ASSOC_DEAD;
1612 assoc->state = ASSOC_UP;
1617 * These functions should be merged.
1620 static void set_addinfo (Z_DefaultDiagFormat *dr, char *addinfo, ODR odr)
1622 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1623 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1627 * nonsurrogate diagnostic record.
1629 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1631 Z_Records *rec = (Z_Records *)
1632 odr_malloc (assoc->encode, sizeof(*rec));
1633 int *err = odr_intdup(assoc->encode, error);
1634 Z_DiagRec *drec = (Z_DiagRec *)
1635 odr_malloc (assoc->encode, sizeof(*drec));
1636 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1637 odr_malloc (assoc->encode, sizeof(*dr));
1639 yaz_log(LOG_LOG, "[%d] %s %s%s", error, diagbib1_str(error),
1640 addinfo ? " -- " : "", addinfo ? addinfo : "");
1641 rec->which = Z_Records_NSD;
1642 rec->u.nonSurrogateDiagnostic = dr;
1643 dr->diagnosticSetId =
1644 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1645 dr->condition = err;
1646 set_addinfo (dr, addinfo, assoc->encode);
1651 * surrogate diagnostic.
1653 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1654 int error, char *addinfo)
1656 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1657 odr_malloc (assoc->encode, sizeof(*rec));
1658 int *err = odr_intdup(assoc->encode, error);
1659 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1660 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1661 odr_malloc (assoc->encode, sizeof(*dr));
1663 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1664 rec->databaseName = dbname;
1665 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1666 rec->u.surrogateDiagnostic = drec;
1667 drec->which = Z_DiagRec_defaultFormat;
1668 drec->u.defaultFormat = dr;
1669 dr->diagnosticSetId =
1670 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1671 dr->condition = err;
1672 set_addinfo (dr, addinfo, assoc->encode);
1678 * multiple nonsurrogate diagnostics.
1680 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1682 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1683 int *err = odr_intdup(assoc->encode, error);
1684 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1685 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1686 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1687 odr_malloc (assoc->encode, sizeof(*rec));
1689 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1691 recs->num_diagRecs = 1;
1692 recs->diagRecs = recp;
1694 drec->which = Z_DiagRec_defaultFormat;
1695 drec->u.defaultFormat = rec;
1697 rec->diagnosticSetId =
1698 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1699 rec->condition = err;
1701 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1702 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1706 static Z_Records *pack_records(association *a, char *setname, int start,
1707 int *num, Z_RecordComposition *comp,
1708 int *next, int *pres, oid_value format,
1709 Z_ReferenceId *referenceId,
1712 int recno, total_length = 0, toget = *num, dumped_records = 0;
1713 Z_Records *records =
1714 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1715 Z_NamePlusRecordList *reclist =
1716 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1717 Z_NamePlusRecord **list =
1718 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1720 records->which = Z_Records_DBOSD;
1721 records->u.databaseOrSurDiagnostics = reclist;
1722 reclist->num_records = 0;
1723 reclist->records = list;
1724 *pres = Z_PRES_SUCCESS;
1728 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1729 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1730 a->maximumRecordSize);
1731 for (recno = start; reclist->num_records < toget; recno++)
1734 Z_NamePlusRecord *thisrec;
1735 int this_length = 0;
1737 * we get the number of bytes allocated on the stream before any
1738 * allocation done by the backend - this should give us a reasonable
1739 * idea of the total size of the data so far.
1741 total_length = odr_total(a->encode) - dumped_records;
1747 freq.last_in_set = 0;
1748 freq.setname = setname;
1749 freq.surrogate_flag = 0;
1750 freq.number = recno;
1752 freq.request_format = format;
1753 freq.request_format_raw = oid;
1754 freq.output_format = format;
1755 freq.output_format_raw = 0;
1756 freq.stream = a->encode;
1757 freq.print = a->print;
1758 freq.referenceId = referenceId;
1760 (*a->init->bend_fetch)(a->backend, &freq);
1761 /* backend should be able to signal whether error is system-wide
1762 or only pertaining to current record */
1765 if (!freq.surrogate_flag)
1768 *pres = Z_PRES_FAILURE;
1769 /* for 'present request out of range',
1770 set addinfo to record position if not set */
1771 if (freq.errcode == 13 && freq.errstring == 0)
1773 sprintf (s, "%d", recno);
1776 return diagrec(a, freq.errcode, freq.errstring);
1778 reclist->records[reclist->num_records] =
1779 surrogatediagrec(a, freq.basename, freq.errcode,
1781 reclist->num_records++;
1782 *next = freq.last_in_set ? 0 : recno + 1;
1786 this_length = freq.len;
1788 this_length = odr_total(a->encode) - total_length;
1789 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1790 this_length, total_length);
1791 if (this_length + total_length > a->preferredMessageSize)
1793 /* record is small enough, really */
1794 if (this_length <= a->preferredMessageSize)
1796 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1797 *pres = Z_PRES_PARTIAL_2;
1800 /* record can only be fetched by itself */
1801 if (this_length < a->maximumRecordSize)
1803 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1806 yaz_log(LOG_DEBUG, " Dropped it");
1807 reclist->records[reclist->num_records] =
1808 surrogatediagrec(a, freq.basename, 16, 0);
1809 reclist->num_records++;
1810 *next = freq.last_in_set ? 0 : recno + 1;
1811 dumped_records += this_length;
1815 else /* too big entirely */
1817 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1818 reclist->records[reclist->num_records] =
1819 surrogatediagrec(a, freq.basename, 17, 0);
1820 reclist->num_records++;
1821 *next = freq.last_in_set ? 0 : recno + 1;
1822 dumped_records += this_length;
1827 if (!(thisrec = (Z_NamePlusRecord *)
1828 odr_malloc(a->encode, sizeof(*thisrec))))
1830 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1831 strlen(freq.basename) + 1)))
1833 strcpy(thisrec->databaseName, freq.basename);
1834 thisrec->which = Z_NamePlusRecord_databaseRecord;
1836 if (freq.output_format_raw)
1838 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1839 freq.output_format = ident->value;
1841 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1842 freq.record, freq.len);
1843 if (!thisrec->u.databaseRecord)
1845 reclist->records[reclist->num_records] = thisrec;
1846 reclist->num_records++;
1847 *next = freq.last_in_set ? 0 : recno + 1;
1849 *num = reclist->num_records;
1853 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1856 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1857 bend_search_rr *bsrr =
1858 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1860 yaz_log(LOG_LOG, "Got SearchRequest.");
1862 bsrr->request = reqb;
1863 bsrr->association = assoc;
1864 bsrr->referenceId = req->referenceId;
1865 save_referenceId (reqb, bsrr->referenceId);
1867 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1868 if (req->databaseNames)
1871 for (i = 0; i < req->num_databaseNames; i++)
1872 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1874 yaz_log_zquery(req->query);
1876 if (assoc->init->bend_search)
1878 bsrr->setname = req->resultSetName;
1879 bsrr->replace_set = *req->replaceIndicator;
1880 bsrr->num_bases = req->num_databaseNames;
1881 bsrr->basenames = req->databaseNames;
1882 bsrr->query = req->query;
1883 bsrr->stream = assoc->encode;
1884 bsrr->decode = assoc->decode;
1885 bsrr->print = assoc->print;
1888 bsrr->errstring = NULL;
1889 bsrr->search_info = NULL;
1890 (assoc->init->bend_search)(assoc->backend, bsrr);
1894 return response_searchRequest(assoc, reqb, bsrr, fd);
1897 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1900 * Prepare a searchresponse based on the backend results. We probably want
1901 * to look at making the fetching of records nonblocking as well, but
1902 * so far, we'll keep things simple.
1903 * If bsrt is null, that means we're called in response to a communications
1904 * event, and we'll have to get the response for ourselves.
1906 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1907 bend_search_rr *bsrt, int *fd)
1909 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1910 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1911 Z_SearchResponse *resp = (Z_SearchResponse *)
1912 odr_malloc (assoc->encode, sizeof(*resp));
1913 int *nulint = odr_intdup (assoc->encode, 0);
1914 bool_t *sr = odr_intdup(assoc->encode, 1);
1915 int *next = odr_intdup(assoc->encode, 0);
1916 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1918 apdu->which = Z_APDU_searchResponse;
1919 apdu->u.searchResponse = resp;
1920 resp->referenceId = req->referenceId;
1921 resp->additionalSearchInfo = 0;
1922 resp->otherInfo = 0;
1924 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1926 yaz_log(LOG_FATAL, "Bad result from backend");
1929 else if (bsrt->errcode)
1931 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1932 resp->resultCount = nulint;
1933 resp->numberOfRecordsReturned = nulint;
1934 resp->nextResultSetPosition = nulint;
1935 resp->searchStatus = nulint;
1936 resp->resultSetStatus = none;
1937 resp->presentStatus = 0;
1941 int *toget = odr_intdup(assoc->encode, 0);
1942 int *presst = odr_intdup(assoc->encode, 0);
1943 Z_RecordComposition comp, *compp = 0;
1945 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1948 resp->resultCount = &bsrt->hits;
1950 comp.which = Z_RecordComp_simple;
1951 /* how many records does the user agent want, then? */
1952 if (bsrt->hits <= *req->smallSetUpperBound)
1954 *toget = bsrt->hits;
1955 if ((comp.u.simple = req->smallSetElementSetNames))
1958 else if (bsrt->hits < *req->largeSetLowerBound)
1960 *toget = *req->mediumSetPresentNumber;
1961 if (*toget > bsrt->hits)
1962 *toget = bsrt->hits;
1963 if ((comp.u.simple = req->mediumSetElementSetNames))
1969 if (*toget && !resp->records)
1974 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1977 form = prefformat->value;
1978 resp->records = pack_records(assoc, req->resultSetName, 1,
1979 toget, compp, next, presst, form, req->referenceId,
1980 req->preferredRecordSyntax);
1983 resp->numberOfRecordsReturned = toget;
1984 resp->nextResultSetPosition = next;
1985 resp->searchStatus = sr;
1986 resp->resultSetStatus = 0;
1987 resp->presentStatus = presst;
1991 if (*resp->resultCount)
1993 resp->numberOfRecordsReturned = nulint;
1994 resp->nextResultSetPosition = next;
1995 resp->searchStatus = sr;
1996 resp->resultSetStatus = 0;
1997 resp->presentStatus = 0;
2000 resp->additionalSearchInfo = bsrt->search_info;
2005 * Maybe we got a little over-friendly when we designed bend_fetch to
2006 * get only one record at a time. Some backends can optimise multiple-record
2007 * fetches, and at any rate, there is some overhead involved in
2008 * all that selecting and hopping around. Problem is, of course, that the
2009 * frontend can't know ahead of time how many records it'll need to
2010 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2011 * is downright lousy as a bulk data transfer protocol.
2013 * To start with, we'll do the fetching of records from the backend
2014 * in one operation: To save some trips in and out of the event-handler,
2015 * and to simplify the interface to pack_records. At any rate, asynch
2016 * operation is more fun in operations that have an unpredictable execution
2017 * speed - which is normally more true for search than for present.
2019 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2022 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2026 Z_PresentResponse *resp;
2030 yaz_log(LOG_LOG, "Got PresentRequest.");
2032 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2035 form = prefformat->value;
2036 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2038 resp->presentStatus = odr_intdup(assoc->encode, 0);
2039 if (assoc->init->bend_present)
2041 bend_present_rr *bprr = (bend_present_rr *)
2042 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2043 bprr->setname = req->resultSetId;
2044 bprr->start = *req->resultSetStartPoint;
2045 bprr->number = *req->numberOfRecordsRequested;
2046 bprr->format = form;
2047 bprr->comp = req->recordComposition;
2048 bprr->referenceId = req->referenceId;
2049 bprr->stream = assoc->encode;
2050 bprr->print = assoc->print;
2051 bprr->request = reqb;
2052 bprr->association = assoc;
2054 bprr->errstring = NULL;
2055 (*assoc->init->bend_present)(assoc->backend, bprr);
2061 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2062 *resp->presentStatus = Z_PRES_FAILURE;
2065 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2066 next = odr_intdup(assoc->encode, 0);
2067 num = odr_intdup(assoc->encode, 0);
2069 apdu->which = Z_APDU_presentResponse;
2070 apdu->u.presentResponse = resp;
2071 resp->referenceId = req->referenceId;
2072 resp->otherInfo = 0;
2076 *num = *req->numberOfRecordsRequested;
2078 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2079 num, req->recordComposition, next, resp->presentStatus,
2080 form, req->referenceId, req->preferredRecordSyntax);
2084 resp->numberOfRecordsReturned = num;
2085 resp->nextResultSetPosition = next;
2091 * Scan was implemented rather in a hurry, and with support for only the basic
2092 * elements of the service in the backend API. Suggestions are welcome.
2094 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2096 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2097 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2098 Z_ScanResponse *res = (Z_ScanResponse *)
2099 odr_malloc (assoc->encode, sizeof(*res));
2100 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2101 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2102 Z_ListEntries *ents = (Z_ListEntries *)
2103 odr_malloc (assoc->encode, sizeof(*ents));
2104 Z_DiagRecs *diagrecs_p = NULL;
2106 bend_scan_rr *bsrr = (bend_scan_rr *)
2107 odr_malloc (assoc->encode, sizeof(*bsrr));
2108 struct scan_entry *save_entries;
2110 yaz_log(LOG_LOG, "Got ScanRequest");
2112 apdu->which = Z_APDU_scanResponse;
2113 apdu->u.scanResponse = res;
2114 res->referenceId = req->referenceId;
2116 /* if step is absent, set it to 0 */
2117 res->stepSize = odr_intdup(assoc->encode, 0);
2119 *res->stepSize = *req->stepSize;
2121 res->scanStatus = scanStatus;
2122 res->numberOfEntriesReturned = numberOfEntriesReturned;
2123 res->positionOfTerm = 0;
2124 res->entries = ents;
2125 ents->num_entries = 0;
2126 ents->entries = NULL;
2127 ents->num_nonsurrogateDiagnostics = 0;
2128 ents->nonsurrogateDiagnostics = NULL;
2129 res->attributeSet = 0;
2132 if (req->databaseNames)
2135 for (i = 0; i < req->num_databaseNames; i++)
2136 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2138 bsrr->num_bases = req->num_databaseNames;
2139 bsrr->basenames = req->databaseNames;
2140 bsrr->num_entries = *req->numberOfTermsRequested;
2141 bsrr->term = req->termListAndStartPoint;
2142 bsrr->referenceId = req->referenceId;
2143 bsrr->stream = assoc->encode;
2144 bsrr->print = assoc->print;
2145 bsrr->step_size = res->stepSize;
2147 /* Note that version 2.0 of YAZ and older did not set entries ..
2148 We do now. And when we do it's easier to extend the scan entry
2149 We know that if the scan handler did set entries, it will
2150 not know of new member display_term.
2152 if (bsrr->num_entries > 0)
2155 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2157 for (i = 0; i<bsrr->num_entries; i++)
2159 bsrr->entries[i].term = 0;
2160 bsrr->entries[i].occurrences = 0;
2161 bsrr->entries[i].errcode = 0;
2162 bsrr->entries[i].errstring = 0;
2163 bsrr->entries[i].display_term = 0;
2166 save_entries = bsrr->entries; /* save it so we can compare later */
2168 if (req->attributeSet &&
2169 (attset = oid_getentbyoid(req->attributeSet)) &&
2170 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2171 bsrr->attributeset = attset->value;
2173 bsrr->attributeset = VAL_NONE;
2174 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2175 bsrr->term_position = req->preferredPositionInResponse ?
2176 *req->preferredPositionInResponse : 1;
2177 ((int (*)(void *, bend_scan_rr *))
2178 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2180 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2184 Z_Entry **tab = (Z_Entry **)
2185 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2187 if (bsrr->status == BEND_SCAN_PARTIAL)
2188 *scanStatus = Z_Scan_partial_5;
2190 *scanStatus = Z_Scan_success;
2191 ents->entries = tab;
2192 ents->num_entries = bsrr->num_entries;
2193 res->numberOfEntriesReturned = &ents->num_entries;
2194 res->positionOfTerm = &bsrr->term_position;
2195 for (i = 0; i < bsrr->num_entries; i++)
2201 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2202 if (bsrr->entries[i].occurrences >= 0)
2204 e->which = Z_Entry_termInfo;
2205 e->u.termInfo = t = (Z_TermInfo *)
2206 odr_malloc(assoc->encode, sizeof(*t));
2207 t->suggestedAttributes = 0;
2209 if (save_entries == bsrr->entries &&
2210 bsrr->entries[i].display_term)
2212 /* the entries was NOT set by the handler. So it's
2213 safe to test for new member display_term. It is
2216 t->displayTerm = odr_strdup(assoc->encode,
2217 bsrr->entries[i].display_term);
2219 t->alternativeTerm = 0;
2220 t->byAttributes = 0;
2221 t->otherTermInfo = 0;
2222 t->globalOccurrences = &bsrr->entries[i].occurrences;
2223 t->term = (Z_Term *)
2224 odr_malloc(assoc->encode, sizeof(*t->term));
2225 t->term->which = Z_Term_general;
2226 t->term->u.general = o =
2227 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2228 o->buf = (unsigned char *)
2229 odr_malloc(assoc->encode, o->len = o->size =
2230 strlen(bsrr->entries[i].term));
2231 memcpy(o->buf, bsrr->entries[i].term, o->len);
2232 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2233 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2237 Z_DiagRecs *drecs = diagrecs (assoc,
2238 bsrr->entries[i].errcode,
2239 bsrr->entries[i].errstring);
2240 assert (drecs->num_diagRecs == 1);
2241 e->which = Z_Entry_surrogateDiagnostic;
2242 assert (drecs->diagRecs[0]);
2243 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2249 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2250 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2255 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2258 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2259 Z_SortResponse *res = (Z_SortResponse *)
2260 odr_malloc (assoc->encode, sizeof(*res));
2261 bend_sort_rr *bsrr = (bend_sort_rr *)
2262 odr_malloc (assoc->encode, sizeof(*bsrr));
2264 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2266 yaz_log(LOG_LOG, "Got SortRequest.");
2268 bsrr->num_input_setnames = req->num_inputResultSetNames;
2269 bsrr->input_setnames = req->inputResultSetNames;
2270 bsrr->referenceId = req->referenceId;
2271 bsrr->output_setname = req->sortedResultSetName;
2272 bsrr->sort_sequence = req->sortSequence;
2273 bsrr->stream = assoc->encode;
2274 bsrr->print = assoc->print;
2276 bsrr->sort_status = Z_SortStatus_failure;
2278 bsrr->errstring = 0;
2280 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2282 res->referenceId = bsrr->referenceId;
2283 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2284 res->resultSetStatus = 0;
2287 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2288 res->diagnostics = dr->diagRecs;
2289 res->num_diagnostics = dr->num_diagRecs;
2293 res->num_diagnostics = 0;
2294 res->diagnostics = 0;
2298 apdu->which = Z_APDU_sortResponse;
2299 apdu->u.sortResponse = res;
2303 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2306 Z_DeleteResultSetRequest *req =
2307 reqb->apdu_request->u.deleteResultSetRequest;
2308 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2309 odr_malloc (assoc->encode, sizeof(*res));
2310 bend_delete_rr *bdrr = (bend_delete_rr *)
2311 odr_malloc (assoc->encode, sizeof(*bdrr));
2312 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2314 yaz_log(LOG_LOG, "Got DeleteRequest.");
2316 bdrr->num_setnames = req->num_resultSetList;
2317 bdrr->setnames = req->resultSetList;
2318 bdrr->stream = assoc->encode;
2319 bdrr->print = assoc->print;
2320 bdrr->function = *req->deleteFunction;
2321 bdrr->referenceId = req->referenceId;
2323 if (bdrr->num_setnames > 0)
2326 bdrr->statuses = (int*)
2327 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2328 bdrr->num_setnames);
2329 for (i = 0; i < bdrr->num_setnames; i++)
2330 bdrr->statuses[i] = 0;
2332 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2334 res->referenceId = req->referenceId;
2336 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2338 res->deleteListStatuses = 0;
2339 if (bdrr->num_setnames > 0)
2342 res->deleteListStatuses = (Z_ListStatuses *)
2343 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2344 res->deleteListStatuses->num = bdrr->num_setnames;
2345 res->deleteListStatuses->elements =
2347 odr_malloc (assoc->encode,
2348 sizeof(*res->deleteListStatuses->elements) *
2349 bdrr->num_setnames);
2350 for (i = 0; i<bdrr->num_setnames; i++)
2352 res->deleteListStatuses->elements[i] =
2354 odr_malloc (assoc->encode,
2355 sizeof(**res->deleteListStatuses->elements));
2356 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2357 res->deleteListStatuses->elements[i]->id =
2358 odr_strdup (assoc->encode, bdrr->setnames[i]);
2362 res->numberNotDeleted = 0;
2363 res->bulkStatuses = 0;
2364 res->deleteMessage = 0;
2367 apdu->which = Z_APDU_deleteResultSetResponse;
2368 apdu->u.deleteResultSetResponse = res;
2372 static void process_close(association *assoc, request *reqb)
2374 Z_Close *req = reqb->apdu_request->u.close;
2375 static char *reasons[] =
2382 "securityViolation",
2389 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2390 reasons[*req->closeReason], req->diagnosticInformation ?
2391 req->diagnosticInformation : "NULL");
2392 if (assoc->version < 3) /* to make do_force respond with close */
2394 do_close_req(assoc, Z_Close_finished,
2395 "Association terminated by client", reqb);
2398 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2402 reqb->len_refid = refid->len;
2403 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2404 memcpy (reqb->refid, refid->buf, refid->len);
2408 reqb->len_refid = 0;
2413 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2415 process_z_response (a, req, res);
2418 bend_request bend_request_mk (bend_association a)
2420 request *nreq = request_get (&a->outgoing);
2421 nreq->request_mem = nmem_create ();
2425 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2430 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2431 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2432 id->len = id->size = req->len_refid;
2433 memcpy (id->buf, req->refid, req->len_refid);
2437 void bend_request_destroy (bend_request *req)
2439 nmem_destroy((*req)->request_mem);
2440 request_release(*req);
2444 int bend_backend_respond (bend_association a, bend_request req)
2448 r = process_z_request (a, req, &msg);
2450 yaz_log (LOG_WARN, "%s", msg);
2454 void bend_request_setdata(bend_request r, void *p)
2459 void *bend_request_getdata(bend_request r)
2461 return r->clientData;
2464 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2466 bend_segment_rr req;
2468 req.segment = reqb->apdu_request->u.segmentRequest;
2469 req.stream = assoc->encode;
2470 req.decode = assoc->decode;
2471 req.print = assoc->print;
2472 req.association = assoc;
2474 (*assoc->init->bend_segment)(assoc->backend, &req);
2479 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2481 bend_esrequest_rr esrequest;
2483 Z_ExtendedServicesRequest *req =
2484 reqb->apdu_request->u.extendedServicesRequest;
2485 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2487 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2489 yaz_log(LOG_DEBUG,"inside Process esRequest");
2491 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2492 esrequest.stream = assoc->encode;
2493 esrequest.decode = assoc->decode;
2494 esrequest.print = assoc->print;
2495 esrequest.errcode = 0;
2496 esrequest.errstring = NULL;
2497 esrequest.request = reqb;
2498 esrequest.association = assoc;
2499 esrequest.taskPackage = 0;
2500 esrequest.referenceId = req->referenceId;
2502 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2504 /* If the response is being delayed, return NULL */
2505 if (esrequest.request == NULL)
2508 resp->referenceId = req->referenceId;
2510 if (esrequest.errcode == -1)
2512 /* Backend service indicates request will be processed */
2513 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2514 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2516 else if (esrequest.errcode == 0)
2518 /* Backend service indicates request will be processed */
2519 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2520 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2524 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2525 esrequest.errstring);
2527 /* Backend indicates error, request will not be processed */
2528 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2529 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2530 resp->num_diagnostics = diagRecs->num_diagRecs;
2531 resp->diagnostics = diagRecs->diagRecs;
2533 /* Do something with the members of bend_extendedservice */
2534 if (esrequest.taskPackage)
2535 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2536 (const char *) esrequest.taskPackage,
2538 yaz_log(LOG_DEBUG,"Send the result apdu");