2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.159 2003-05-24 19:34:43 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 [element %s] "
331 odr_errmsg(odr_geterror(assoc->decode)),
332 odr_getelement(assoc->decode),
333 odr_offset(assoc->decode));
334 if (assoc->decode->error != OHTTP)
336 yaz_log(LOG_LOG, "PDU dump:");
337 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
338 do_close(assoc, Z_Close_protocolError, "Malformed package");
342 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
343 assoc->state = ASSOC_DEAD;
344 process_gdu_response(assoc, req, p);
348 req->request_mem = odr_extract_mem(assoc->decode);
349 if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
351 yaz_log(LOG_WARN, "ODR print error: %s",
352 odr_errmsg(odr_geterror(assoc->print)));
353 odr_reset(assoc->print);
355 request_enq(&assoc->incoming, req);
358 /* can we do something yet? */
359 req = request_head(&assoc->incoming);
360 if (req->state == REQUEST_IDLE)
362 request_deq(&assoc->incoming);
363 process_gdu_request(assoc, req);
366 if (event & assoc->cs_put_mask)
368 request *req = request_head(&assoc->outgoing);
370 assoc->cs_put_mask = 0;
371 yaz_log(LOG_DEBUG, "ir_session (output)");
372 req->state = REQUEST_PENDING;
373 switch (res = cs_put(conn, req->response, req->len_response))
376 yaz_log(LOG_LOG, "Connection closed by client");
378 destroy_association(assoc);
381 case 0: /* all sent - release the request structure */
382 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
384 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
387 nmem_destroy(req->request_mem);
388 request_deq(&assoc->outgoing);
389 request_release(req);
390 if (!request_head(&assoc->outgoing))
391 { /* restore mask for cs_get operation ... */
392 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
393 iochan_setflag(h, assoc->cs_get_mask);
394 if (assoc->state == ASSOC_DEAD)
395 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
399 assoc->cs_put_mask = EVENT_OUTPUT;
403 if (conn->io_pending & CS_WANT_WRITE)
404 assoc->cs_put_mask |= EVENT_OUTPUT;
405 if (conn->io_pending & CS_WANT_READ)
406 assoc->cs_put_mask |= EVENT_INPUT;
407 iochan_setflag(h, assoc->cs_put_mask);
410 if (event & EVENT_EXCEPT)
412 yaz_log(LOG_LOG, "ir_session (exception)");
414 destroy_association(assoc);
419 static int process_z_request(association *assoc, request *req, char **msg);
421 static void assoc_init_reset(association *assoc)
424 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
426 assoc->init->stream = assoc->encode;
427 assoc->init->print = assoc->print;
428 assoc->init->auth = 0;
429 assoc->init->referenceId = 0;
430 assoc->init->implementation_version = 0;
431 assoc->init->implementation_id = 0;
432 assoc->init->implementation_name = 0;
433 assoc->init->bend_sort = NULL;
434 assoc->init->bend_search = NULL;
435 assoc->init->bend_present = NULL;
436 assoc->init->bend_esrequest = NULL;
437 assoc->init->bend_delete = NULL;
438 assoc->init->bend_scan = NULL;
439 assoc->init->bend_segment = NULL;
440 assoc->init->bend_fetch = NULL;
441 assoc->init->bend_explain = NULL;
443 assoc->init->charneg_request = NULL;
444 assoc->init->charneg_response = NULL;
446 assoc->init->decode = assoc->decode;
447 assoc->init->peer_name =
448 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
451 static int srw_bend_init(association *assoc)
453 const char *encoding = "UTF-8";
455 bend_initresult *binitres;
456 statserv_options_block *cb = statserv_getcontrol();
458 assoc_init_reset(assoc);
460 assoc->maximumRecordSize = 3000000;
461 assoc->preferredMessageSize = 3000000;
463 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
464 assoc->init->charneg_request = ce->u.charNeg3;
466 if (!(binitres = (*cb->bend_init)(assoc->init)))
468 yaz_log(LOG_WARN, "Bad response from backend.");
471 assoc->backend = binitres->handle;
475 static int srw_bend_fetch(association *assoc, int pos,
476 Z_SRW_searchRetrieveRequest *srw_req,
477 Z_SRW_record *record)
480 ODR o = assoc->encode;
482 rr.setname = "default";
485 rr.request_format = VAL_TEXT_XML;
486 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
489 rr.comp = (Z_RecordComposition *)
490 odr_malloc(assoc->decode, sizeof(*rr.comp));
491 rr.comp->which = Z_RecordComp_complex;
492 rr.comp->u.complex = (Z_CompSpec *)
493 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
494 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
495 odr_malloc(assoc->encode, sizeof(bool_t));
496 *rr.comp->u.complex->selectAlternativeSyntax = 0;
497 rr.comp->u.complex->num_dbSpecific = 0;
498 rr.comp->u.complex->dbSpecific = 0;
499 rr.comp->u.complex->num_recordSyntax = 0;
500 rr.comp->u.complex->recordSyntax = 0;
502 rr.comp->u.complex->generic = (Z_Specification *)
503 odr_malloc(assoc->decode, sizeof(Z_Specification));
504 rr.comp->u.complex->generic->which = Z_Schema_uri;
505 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
506 rr.comp->u.complex->generic->elementSpec = 0;
508 rr.stream = assoc->encode;
509 rr.print = assoc->print;
515 rr.output_format = VAL_TEXT_XML;
516 rr.output_format_raw = 0;
519 rr.surrogate_flag = 0;
520 rr.schema = srw_req->recordSchema;
522 if (!assoc->init->bend_fetch)
525 (*assoc->init->bend_fetch)(assoc->backend, &rr);
529 record->recordData_buf = rr.record;
530 record->recordData_len = rr.len;
531 record->recordPosition = odr_intdup(o, pos);
533 record->recordSchema = odr_strdup(o, rr.schema);
535 record->recordSchema = 0;
540 static void srw_bend_search(association *assoc, request *req,
541 Z_SRW_searchRetrieveRequest *srw_req,
542 Z_SRW_searchRetrieveResponse *srw_res)
548 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
549 yaz_log(LOG_DEBUG, "srw_bend_search");
552 yaz_log(LOG_DEBUG, "srw_bend_init");
553 if (!srw_bend_init(assoc))
555 srw_error = 3; /* assume Authentication error */
557 srw_res->num_diagnostics = 1;
558 srw_res->diagnostics = (Z_SRW_diagnostic *)
559 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
560 srw_res->diagnostics[0].code =
561 odr_intdup(assoc->encode, srw_error);
562 srw_res->diagnostics[0].details = 0;
567 rr.setname = "default";
570 rr.basenames = &srw_req->database;
573 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
575 if (srw_req->query_type == Z_SRW_query_type_cql)
577 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
578 ext->direct_reference = odr_getoidbystr(assoc->decode,
579 "1.2.840.10003.16.2");
580 ext->indirect_reference = 0;
582 ext->which = Z_External_CQL;
583 ext->u.cql = srw_req->query.cql;
585 rr.query->which = Z_Query_type_104;
586 rr.query->u.type_104 = ext;
588 else if (srw_req->query_type == Z_SRW_query_type_pqf)
590 Z_RPNQuery *RPNquery;
591 YAZ_PQF_Parser pqf_parser;
593 pqf_parser = yaz_pqf_create ();
595 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
601 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
602 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
603 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
608 rr.query->which = Z_Query_type_1;
609 rr.query->u.type_1 = RPNquery;
611 yaz_pqf_destroy (pqf_parser);
616 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
619 if (!srw_error && !assoc->init->bend_search)
624 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
625 srw_res->num_diagnostics = 1;
626 srw_res->diagnostics = (Z_SRW_diagnostic *)
627 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
628 srw_res->diagnostics[0].code =
629 odr_intdup(assoc->encode, srw_error);
630 srw_res->diagnostics[0].details = 0;
634 rr.stream = assoc->encode;
635 rr.decode = assoc->decode;
636 rr.print = assoc->print;
638 rr.association = assoc;
644 yaz_log_zquery(rr.query);
645 (assoc->init->bend_search)(assoc->backend, &rr);
646 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
649 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
650 srw_res->num_diagnostics = 1;
651 srw_res->diagnostics = (Z_SRW_diagnostic *)
652 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
653 srw_res->diagnostics[0].code =
654 odr_intdup(assoc->encode,
655 yaz_diag_bib1_to_srw (rr.errcode));
656 srw_res->diagnostics[0].details = rr.errstring;
657 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
658 *srw_res->diagnostics[0].code);
663 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
664 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
666 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
667 start, number, rr.hits);
669 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
676 yaz_log(LOG_LOG, "Request out or range");
681 int packing = Z_SRW_recordPacking_string;
682 if (start + number > rr.hits)
683 number = rr.hits - start + 1;
684 if (srw_req->recordPacking &&
685 !strcmp(srw_req->recordPacking, "xml"))
686 packing = Z_SRW_recordPacking_XML;
687 srw_res->records = (Z_SRW_record *)
688 odr_malloc(assoc->encode,
689 number * sizeof(*srw_res->records));
690 for (i = 0; i<number; i++)
694 srw_res->records[j].recordPacking = packing;
695 srw_res->records[j].recordData_buf = 0;
696 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
697 errcode = srw_bend_fetch(assoc, i+start, srw_req,
698 srw_res->records + j);
701 srw_res->num_diagnostics = 1;
702 srw_res->diagnostics = (Z_SRW_diagnostic *)
703 odr_malloc(assoc->encode,
704 sizeof(*srw_res->diagnostics));
705 srw_res->diagnostics[0].code =
706 odr_intdup(assoc->encode,
707 yaz_diag_bib1_to_srw (errcode));
708 srw_res->diagnostics[0].details = rr.errstring;
711 if (srw_res->records[j].recordData_buf)
714 srw_res->num_records = j;
716 srw_res->records = 0;
723 static void srw_bend_explain(association *assoc, request *req,
724 Z_SRW_explainRequest *srw_req,
725 Z_SRW_explainResponse *srw_res)
727 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
730 yaz_log(LOG_DEBUG, "srw_bend_init");
731 if (!srw_bend_init(assoc))
734 if (assoc->init && assoc->init->bend_explain)
738 rr.stream = assoc->encode;
739 rr.decode = assoc->decode;
740 rr.print = assoc->print;
742 (*assoc->init->bend_explain)(assoc->backend, &rr);
745 srw_res->explainData_buf = rr.explain_buf;
746 srw_res->explainData_len = strlen(rr.explain_buf);
751 static int hex_digit (int ch)
753 if (ch >= '0' && ch <= '9')
755 else if (ch >= 'a' && ch <= 'f')
757 else if (ch >= 'A' && ch <= 'F')
762 static char *uri_val(const char *path, const char *name, ODR o)
764 size_t nlen = strlen(name);
768 while (path && *path)
770 const char *p1 = strchr(path, '=');
773 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
779 p1 = strchr(path, '&');
781 p1 = strlen(path) + path;
782 ret = odr_malloc(o, p1 - path + 1);
783 while (*path && *path != '&')
790 else if (*path == '%' && path[1] && path[2])
792 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
801 path = strchr(p1, '&');
808 void uri_val_int(const char *path, const char *name, ODR o, int **intp)
810 const char *v = uri_val(path, name, o);
812 *intp = odr_intdup(o, atoi(v));
815 static void process_http_request(association *assoc, request *req)
817 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
818 ODR o = assoc->encode;
820 Z_HTTP_Response *hres = 0;
823 if (!strcmp(hreq->method, "GET"))
825 char *db = "Default";
826 const char *p0 = hreq->path, *p1;
830 Z_SOAP *soap_package = 0;
831 static Z_SOAP_Handler soap_handlers[2] = {
832 {"http://www.loc.gov/zing/srw/v1.0/", 0,
833 (Z_SOAP_fun) yaz_srw_codec},
840 p1 = strchr(p0, '?');
842 p1 = p0 + strlen(p0);
845 db = odr_malloc(assoc->decode, p1 - p0 + 1);
846 memcpy (db, p0, p1 - p0);
850 if (p1 && *p1 == '?' && p1[1])
852 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
853 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
854 char *query = uri_val(p1, "query", o);
855 char *pQuery = uri_val(p1, "pQuery", o);
856 char *sortKeys = uri_val(p1, "sortKeys", o);
860 sr->u.request->query_type = Z_SRW_query_type_cql;
861 sr->u.request->query.cql = query;
865 sr->u.request->query_type = Z_SRW_query_type_pqf;
866 sr->u.request->query.pqf = pQuery;
870 sr->u.request->sort_type = Z_SRW_sort_type_sort;
871 sr->u.request->sort.sortKeys = sortKeys;
873 sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
874 sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
875 if (!sr->u.request->recordPacking)
876 sr->u.request->recordPacking = "xml";
877 uri_val_int(p1, "maximumRecords", o,
878 &sr->u.request->maximumRecords);
879 uri_val_int(p1, "startRecord", o,
880 &sr->u.request->startRecord);
881 if (sr->u.request->startRecord)
882 yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
883 sr->u.request->database = db;
884 srw_bend_search(assoc, req, sr->u.request, res->u.response);
886 soap_package = odr_malloc(o, sizeof(*soap_package));
887 soap_package->which = Z_SOAP_generic;
889 soap_package->u.generic =
890 odr_malloc(o, sizeof(*soap_package->u.generic));
892 soap_package->u.generic->p = res;
893 soap_package->u.generic->ns = soap_handlers[0].ns;
894 soap_package->u.generic->no = 0;
896 soap_package->ns = "SRU";
898 p = z_get_HTTP_Response(o, 200);
899 hres = p->u.HTTP_Response;
901 ret = z_soap_codec_enc(assoc->encode, &soap_package,
902 &hres->content_buf, &hres->content_len,
903 soap_handlers, charset);
905 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
909 strcpy(ctype, "text/xml; charset=");
910 strcat(ctype, charset);
911 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
917 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
918 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
920 srw_bend_explain(assoc, req, sr->u.explain_request,
921 res->u.explain_response);
923 if (res->u.explain_response->explainData_buf)
925 soap_package = odr_malloc(o, sizeof(*soap_package));
926 soap_package->which = Z_SOAP_generic;
928 soap_package->u.generic =
929 odr_malloc(o, sizeof(*soap_package->u.generic));
931 soap_package->u.generic->p = res;
932 soap_package->u.generic->ns = soap_handlers[0].ns;
933 soap_package->u.generic->no = 0;
935 soap_package->ns = "SRU";
937 p = z_get_HTTP_Response(o, 200);
938 hres = p->u.HTTP_Response;
940 ret = z_soap_codec_enc(assoc->encode, &soap_package,
941 &hres->content_buf, &hres->content_len,
942 soap_handlers, charset);
944 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
948 strcpy(ctype, "text/xml; charset=");
949 strcat(ctype, charset);
950 z_HTTP_header_add(o, &hres->headers, "Content-Type",
957 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
958 !memcmp(hreq->path, "/doc/", 5))
963 strcpy(fpath, DOCDIR);
964 strcat(fpath, hreq->path+4);
965 f = fopen(fpath, "rb");
968 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
977 fseek(f, 0L, SEEK_END);
979 if (sz >= 0 && sz < 500000)
981 const char *ctype = "application/octet-stream";
984 p = z_get_HTTP_Response(o, 200);
985 hres = p->u.HTTP_Response;
986 hres->content_buf = (char *) odr_malloc(o, sz + 1);
987 hres->content_len = sz;
988 fseek(f, 0L, SEEK_SET);
989 fread(hres->content_buf, 1, sz, f);
990 if ((cp = strrchr(fpath, '.'))) {
992 if (!strcmp(cp, "png"))
994 else if (!strcmp(cp, "gif"))
996 else if (!strcmp(cp, "xml"))
998 else if (!strcmp(cp, "html"))
1001 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1009 if (!strcmp(hreq->path, "/"))
1014 const char *doclink = "";
1015 p = z_get_HTTP_Response(o, 200);
1016 hres = p->u.HTTP_Response;
1017 hres->content_buf = (char *) odr_malloc(o, 400);
1019 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
1020 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
1022 sprintf (hres->content_buf,
1023 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1026 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1029 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1030 YAZ_VERSION "</P>\n"
1033 "</HTML>\n", doclink);
1034 hres->content_len = strlen(hres->content_buf);
1035 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1041 p = z_get_HTTP_Response(o, 404);
1044 else if (!strcmp(hreq->method, "POST"))
1046 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1048 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1050 Z_SOAP *soap_package = 0;
1052 int http_code = 500;
1053 const char *charset_p = 0;
1056 static Z_SOAP_Handler soap_handlers[2] = {
1058 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1059 (Z_SOAP_fun) yaz_srw_codec},
1063 if ((charset_p = strstr(content_type, "; charset=")))
1067 while (i < 20 && charset_p[i] &&
1068 !strchr("; \n\r", charset_p[i]))
1070 charset = odr_malloc(assoc->encode, i+1);
1071 memcpy(charset, charset_p, i);
1073 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1075 ret = z_soap_codec(assoc->decode, &soap_package,
1076 &hreq->content_buf, &hreq->content_len,
1079 if (!ret && soap_package->which == Z_SOAP_generic &&
1080 soap_package->u.generic->no == 0)
1083 Z_SRW_PDU *sr = soap_package->u.generic->p;
1085 if (sr->which == Z_SRW_searchRetrieve_request)
1088 yaz_srw_get(assoc->encode,
1089 Z_SRW_searchRetrieve_response);
1091 if (!sr->u.request->database)
1093 const char *p0 = hreq->path, *p1;
1096 p1 = strchr(p0, '?');
1098 p1 = p0 + strlen(p0);
1101 sr->u.request->database =
1102 odr_malloc(assoc->decode, p1 - p0 + 1);
1103 memcpy (sr->u.request->database, p0, p1 - p0);
1104 sr->u.request->database[p1 - p0] = '\0';
1107 sr->u.request->database = "Default";
1109 srw_bend_search(assoc, req, sr->u.request,
1112 soap_package->u.generic->p = res;
1115 else if (sr->which == Z_SRW_explain_request)
1118 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1120 srw_bend_explain(assoc, req, sr->u.explain_request,
1121 res->u.explain_response);
1122 if (!res->u.explain_response->explainData_buf)
1124 z_soap_error(assoc->encode, soap_package,
1125 "SOAP-ENV:Client", "Explain Not Supported", 0);
1129 soap_package->u.generic->p = res;
1135 z_soap_error(assoc->encode, soap_package,
1136 "SOAP-ENV:Client", "Bad method", 0);
1140 p = z_get_HTTP_Response(o, 200);
1141 hres = p->u.HTTP_Response;
1142 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1143 &hres->content_buf, &hres->content_len,
1144 soap_handlers, charset);
1145 hres->code = http_code;
1147 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1151 strcpy(ctype, "text/xml; charset=");
1152 strcat(ctype, charset);
1153 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1156 if (!p) /* still no response ? */
1157 p = z_get_HTTP_Response(o, 500);
1161 p = z_get_HTTP_Response(o, 405);
1162 hres = p->u.HTTP_Response;
1164 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1166 hres = p->u.HTTP_Response;
1167 if (!strcmp(hreq->version, "1.0"))
1169 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1170 if (v && !strcmp(v, "Keep-Alive"))
1174 hres->version = "1.0";
1178 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1179 if (v && !strcmp(v, "close"))
1183 hres->version = "1.1";
1187 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1188 assoc->state = ASSOC_DEAD;
1193 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1195 if (alive && isdigit(*alive))
1199 if (t < 0 || t > 3600)
1201 iochan_settimeout(assoc->client_chan,t);
1202 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1204 process_gdu_response(assoc, req, p);
1207 static void process_gdu_request(association *assoc, request *req)
1209 if (req->gdu_request->which == Z_GDU_Z3950)
1212 req->apdu_request = req->gdu_request->u.z3950;
1213 if (process_z_request(assoc, req, &msg) < 0)
1214 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1216 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1217 process_http_request(assoc, req);
1220 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1225 * Initiate request processing.
1227 static int process_z_request(association *assoc, request *req, char **msg)
1233 *msg = "Unknown Error";
1234 assert(req && req->state == REQUEST_IDLE);
1235 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1237 *msg = "Missing InitRequest";
1240 switch (req->apdu_request->which)
1242 case Z_APDU_initRequest:
1243 iochan_settimeout(assoc->client_chan,
1244 statserv_getcontrol()->idle_timeout * 60);
1245 res = process_initRequest(assoc, req); break;
1246 case Z_APDU_searchRequest:
1247 res = process_searchRequest(assoc, req, &fd); break;
1248 case Z_APDU_presentRequest:
1249 res = process_presentRequest(assoc, req, &fd); break;
1250 case Z_APDU_scanRequest:
1251 if (assoc->init->bend_scan)
1252 res = process_scanRequest(assoc, req, &fd);
1255 *msg = "Cannot handle Scan APDU";
1259 case Z_APDU_extendedServicesRequest:
1260 if (assoc->init->bend_esrequest)
1261 res = process_ESRequest(assoc, req, &fd);
1264 *msg = "Cannot handle Extended Services APDU";
1268 case Z_APDU_sortRequest:
1269 if (assoc->init->bend_sort)
1270 res = process_sortRequest(assoc, req, &fd);
1273 *msg = "Cannot handle Sort APDU";
1278 process_close(assoc, req);
1280 case Z_APDU_deleteResultSetRequest:
1281 if (assoc->init->bend_delete)
1282 res = process_deleteRequest(assoc, req, &fd);
1285 *msg = "Cannot handle Delete APDU";
1289 case Z_APDU_segmentRequest:
1290 if (assoc->init->bend_segment)
1292 res = process_segmentRequest (assoc, req);
1296 *msg = "Cannot handle Segment APDU";
1301 *msg = "Bad APDU received";
1306 yaz_log(LOG_DEBUG, " result immediately available");
1307 retval = process_z_response(assoc, req, res);
1311 yaz_log(LOG_DEBUG, " result unavailble");
1314 else /* no result yet - one will be provided later */
1318 /* Set up an I/O handler for the fd supplied by the backend */
1320 yaz_log(LOG_DEBUG, " establishing handler for result");
1321 req->state = REQUEST_PENDING;
1322 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1324 iochan_setdata(chan, assoc);
1331 * Handle message from the backend.
1333 void backend_response(IOCHAN i, int event)
1335 association *assoc = (association *)iochan_getdata(i);
1336 request *req = request_head(&assoc->incoming);
1340 yaz_log(LOG_DEBUG, "backend_response");
1341 assert(assoc && req && req->state != REQUEST_IDLE);
1342 /* determine what it is we're waiting for */
1343 switch (req->apdu_request->which)
1345 case Z_APDU_searchRequest:
1346 res = response_searchRequest(assoc, req, 0, &fd); break;
1348 case Z_APDU_presentRequest:
1349 res = response_presentRequest(assoc, req, 0, &fd); break;
1350 case Z_APDU_scanRequest:
1351 res = response_scanRequest(assoc, req, 0, &fd); break;
1354 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1357 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1359 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1360 do_close(assoc, Z_Close_systemProblem, 0);
1364 else if (!res) /* no result yet - try again later */
1366 yaz_log(LOG_DEBUG, " no result yet");
1367 iochan_setfd(i, fd); /* in case fd has changed */
1372 * Encode response, and transfer the request structure to the outgoing queue.
1374 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1376 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1378 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1380 yaz_log(LOG_WARN, "ODR print error: %s",
1381 odr_errmsg(odr_geterror(assoc->print)));
1382 odr_reset(assoc->print);
1384 if (!z_GDU(assoc->encode, &res, 0, 0))
1386 yaz_log(LOG_WARN, "ODR error when decoding PDU: %s [element %s]",
1387 odr_errmsg(odr_geterror(assoc->decode)),
1388 odr_getelement(assoc->decode));
1391 req->response = odr_getbuf(assoc->encode, &req->len_response,
1392 &req->size_response);
1393 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1394 odr_reset(assoc->encode);
1395 req->state = REQUEST_IDLE;
1396 request_enq(&assoc->outgoing, req);
1397 /* turn the work over to the ir_session handler */
1398 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1399 assoc->cs_put_mask = EVENT_OUTPUT;
1400 /* Is there more work to be done? give that to the input handler too */
1402 if (request_head(&assoc->incoming))
1404 yaz_log (LOG_DEBUG, "more work to be done");
1405 iochan_setevent(assoc->client_chan, EVENT_WORK);
1412 * Encode response, and transfer the request structure to the outgoing queue.
1414 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1416 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1417 gres->which = Z_GDU_Z3950;
1418 gres->u.z3950 = res;
1420 return process_gdu_response(assoc, req, gres);
1425 * Handle init request.
1426 * At the moment, we don't check the options
1427 * anywhere else in the code - we just try not to do anything that would
1428 * break a naive client. We'll toss 'em into the association block when
1429 * we need them there.
1431 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1433 statserv_options_block *cb = statserv_getcontrol();
1434 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1435 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1436 Z_InitResponse *resp = apdu->u.initResponse;
1437 bend_initresult *binitres;
1441 yaz_log(LOG_LOG, "Got initRequest");
1442 if (req->implementationId)
1443 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1444 if (req->implementationName)
1445 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1446 if (req->implementationVersion)
1447 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1449 assoc_init_reset(assoc);
1451 assoc->init->auth = req->idAuthentication;
1452 assoc->init->referenceId = req->referenceId;
1454 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1456 Z_CharSetandLanguageNegotiation *negotiation =
1457 yaz_get_charneg_record (req->otherInfo);
1458 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1459 assoc->init->charneg_request = negotiation;
1462 if (!(binitres = (*cb->bend_init)(assoc->init)))
1464 yaz_log(LOG_WARN, "Bad response from backend.");
1468 assoc->backend = binitres->handle;
1469 if ((assoc->init->bend_sort))
1470 yaz_log (LOG_DEBUG, "Sort handler installed");
1471 if ((assoc->init->bend_search))
1472 yaz_log (LOG_DEBUG, "Search handler installed");
1473 if ((assoc->init->bend_present))
1474 yaz_log (LOG_DEBUG, "Present handler installed");
1475 if ((assoc->init->bend_esrequest))
1476 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1477 if ((assoc->init->bend_delete))
1478 yaz_log (LOG_DEBUG, "Delete handler installed");
1479 if ((assoc->init->bend_scan))
1480 yaz_log (LOG_DEBUG, "Scan handler installed");
1481 if ((assoc->init->bend_segment))
1482 yaz_log (LOG_DEBUG, "Segment handler installed");
1484 resp->referenceId = req->referenceId;
1486 /* let's tell the client what we can do */
1487 if (ODR_MASK_GET(req->options, Z_Options_search))
1489 ODR_MASK_SET(resp->options, Z_Options_search);
1490 strcat(options, "srch");
1492 if (ODR_MASK_GET(req->options, Z_Options_present))
1494 ODR_MASK_SET(resp->options, Z_Options_present);
1495 strcat(options, " prst");
1497 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1498 assoc->init->bend_delete)
1500 ODR_MASK_SET(resp->options, Z_Options_delSet);
1501 strcat(options, " del");
1503 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1504 assoc->init->bend_esrequest)
1506 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1507 strcat (options, " extendedServices");
1509 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1511 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1512 strcat(options, " namedresults");
1514 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1516 ODR_MASK_SET(resp->options, Z_Options_scan);
1517 strcat(options, " scan");
1519 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1521 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1522 strcat(options, " concurrop");
1524 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1526 ODR_MASK_SET(resp->options, Z_Options_sort);
1527 strcat(options, " sort");
1530 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1531 && assoc->init->charneg_response)
1533 Z_OtherInformation **p;
1534 Z_OtherInformationUnit *p0;
1536 yaz_oi_APDU(apdu, &p);
1538 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1539 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1541 p0->which = Z_OtherInfo_externallyDefinedInfo;
1542 p0->information.externallyDefinedInfo =
1543 assoc->init->charneg_response;
1545 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1546 strcat(options, " negotiation");
1549 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1551 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1552 assoc->version = 2; /* 1 & 2 are equivalent */
1554 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1556 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1559 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1561 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1565 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1566 assoc->maximumRecordSize = *req->maximumRecordSize;
1567 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1568 assoc->maximumRecordSize = control_block->maxrecordsize;
1569 assoc->preferredMessageSize = *req->preferredMessageSize;
1570 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1571 assoc->preferredMessageSize = assoc->maximumRecordSize;
1573 resp->preferredMessageSize = &assoc->preferredMessageSize;
1574 resp->maximumRecordSize = &assoc->maximumRecordSize;
1576 resp->implementationName = "GFS/YAZ";
1578 if (assoc->init->implementation_id)
1581 odr_malloc (assoc->encode,
1582 strlen(assoc->init->implementation_id) + 10 +
1583 strlen(resp->implementationId));
1584 sprintf (nv, "%s / %s",
1585 resp->implementationId, assoc->init->implementation_id);
1586 resp->implementationId = nv;
1588 if (assoc->init->implementation_name)
1591 odr_malloc (assoc->encode,
1592 strlen(assoc->init->implementation_name) + 10 +
1593 strlen(resp->implementationName));
1594 sprintf (nv, "%s / %s",
1595 resp->implementationName, assoc->init->implementation_name);
1596 resp->implementationName = nv;
1598 if (assoc->init->implementation_version)
1601 odr_malloc (assoc->encode,
1602 strlen(assoc->init->implementation_version) + 10 +
1603 strlen(resp->implementationVersion));
1604 sprintf (nv, "YAZ %s / %s",
1605 resp->implementationVersion,
1606 assoc->init->implementation_version);
1607 resp->implementationVersion = nv;
1610 if (binitres->errcode)
1612 yaz_log(LOG_LOG, "Connection rejected by backend.");
1614 assoc->state = ASSOC_DEAD;
1617 assoc->state = ASSOC_UP;
1622 * These functions should be merged.
1625 static void set_addinfo (Z_DefaultDiagFormat *dr, char *addinfo, ODR odr)
1627 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1628 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1632 * nonsurrogate diagnostic record.
1634 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1636 Z_Records *rec = (Z_Records *)
1637 odr_malloc (assoc->encode, sizeof(*rec));
1638 int *err = odr_intdup(assoc->encode, error);
1639 Z_DiagRec *drec = (Z_DiagRec *)
1640 odr_malloc (assoc->encode, sizeof(*drec));
1641 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1642 odr_malloc (assoc->encode, sizeof(*dr));
1644 yaz_log(LOG_LOG, "[%d] %s %s%s", error, diagbib1_str(error),
1645 addinfo ? " -- " : "", addinfo ? addinfo : "");
1646 rec->which = Z_Records_NSD;
1647 rec->u.nonSurrogateDiagnostic = dr;
1648 dr->diagnosticSetId =
1649 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1650 dr->condition = err;
1651 set_addinfo (dr, addinfo, assoc->encode);
1656 * surrogate diagnostic.
1658 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1659 int error, char *addinfo)
1661 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1662 odr_malloc (assoc->encode, sizeof(*rec));
1663 int *err = odr_intdup(assoc->encode, error);
1664 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1665 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1666 odr_malloc (assoc->encode, sizeof(*dr));
1668 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1669 rec->databaseName = dbname;
1670 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1671 rec->u.surrogateDiagnostic = drec;
1672 drec->which = Z_DiagRec_defaultFormat;
1673 drec->u.defaultFormat = dr;
1674 dr->diagnosticSetId =
1675 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1676 dr->condition = err;
1677 set_addinfo (dr, addinfo, assoc->encode);
1683 * multiple nonsurrogate diagnostics.
1685 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1687 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1688 int *err = odr_intdup(assoc->encode, error);
1689 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1690 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1691 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1692 odr_malloc (assoc->encode, sizeof(*rec));
1694 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1696 recs->num_diagRecs = 1;
1697 recs->diagRecs = recp;
1699 drec->which = Z_DiagRec_defaultFormat;
1700 drec->u.defaultFormat = rec;
1702 rec->diagnosticSetId =
1703 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1704 rec->condition = err;
1706 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1707 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1711 static Z_Records *pack_records(association *a, char *setname, int start,
1712 int *num, Z_RecordComposition *comp,
1713 int *next, int *pres, oid_value format,
1714 Z_ReferenceId *referenceId,
1717 int recno, total_length = 0, toget = *num, dumped_records = 0;
1718 Z_Records *records =
1719 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1720 Z_NamePlusRecordList *reclist =
1721 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1722 Z_NamePlusRecord **list =
1723 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1725 records->which = Z_Records_DBOSD;
1726 records->u.databaseOrSurDiagnostics = reclist;
1727 reclist->num_records = 0;
1728 reclist->records = list;
1729 *pres = Z_PRES_SUCCESS;
1733 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1734 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1735 a->maximumRecordSize);
1736 for (recno = start; reclist->num_records < toget; recno++)
1739 Z_NamePlusRecord *thisrec;
1740 int this_length = 0;
1742 * we get the number of bytes allocated on the stream before any
1743 * allocation done by the backend - this should give us a reasonable
1744 * idea of the total size of the data so far.
1746 total_length = odr_total(a->encode) - dumped_records;
1752 freq.last_in_set = 0;
1753 freq.setname = setname;
1754 freq.surrogate_flag = 0;
1755 freq.number = recno;
1757 freq.request_format = format;
1758 freq.request_format_raw = oid;
1759 freq.output_format = format;
1760 freq.output_format_raw = 0;
1761 freq.stream = a->encode;
1762 freq.print = a->print;
1763 freq.referenceId = referenceId;
1765 (*a->init->bend_fetch)(a->backend, &freq);
1766 /* backend should be able to signal whether error is system-wide
1767 or only pertaining to current record */
1770 if (!freq.surrogate_flag)
1773 *pres = Z_PRES_FAILURE;
1774 /* for 'present request out of range',
1775 set addinfo to record position if not set */
1776 if (freq.errcode == 13 && freq.errstring == 0)
1778 sprintf (s, "%d", recno);
1781 return diagrec(a, freq.errcode, freq.errstring);
1783 reclist->records[reclist->num_records] =
1784 surrogatediagrec(a, freq.basename, freq.errcode,
1786 reclist->num_records++;
1787 *next = freq.last_in_set ? 0 : recno + 1;
1791 this_length = freq.len;
1793 this_length = odr_total(a->encode) - total_length;
1794 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d",
1795 this_length, total_length);
1796 if (this_length + total_length > a->preferredMessageSize)
1798 /* record is small enough, really */
1799 if (this_length <= a->preferredMessageSize)
1801 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1802 *pres = Z_PRES_PARTIAL_2;
1805 /* record can only be fetched by itself */
1806 if (this_length < a->maximumRecordSize)
1808 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1811 yaz_log(LOG_DEBUG, " Dropped it");
1812 reclist->records[reclist->num_records] =
1813 surrogatediagrec(a, freq.basename, 16, 0);
1814 reclist->num_records++;
1815 *next = freq.last_in_set ? 0 : recno + 1;
1816 dumped_records += this_length;
1820 else /* too big entirely */
1822 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1823 reclist->records[reclist->num_records] =
1824 surrogatediagrec(a, freq.basename, 17, 0);
1825 reclist->num_records++;
1826 *next = freq.last_in_set ? 0 : recno + 1;
1827 dumped_records += this_length;
1832 if (!(thisrec = (Z_NamePlusRecord *)
1833 odr_malloc(a->encode, sizeof(*thisrec))))
1835 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1836 strlen(freq.basename) + 1)))
1838 strcpy(thisrec->databaseName, freq.basename);
1839 thisrec->which = Z_NamePlusRecord_databaseRecord;
1841 if (freq.output_format_raw)
1843 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1844 freq.output_format = ident->value;
1846 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1847 freq.record, freq.len);
1848 if (!thisrec->u.databaseRecord)
1850 reclist->records[reclist->num_records] = thisrec;
1851 reclist->num_records++;
1852 *next = freq.last_in_set ? 0 : recno + 1;
1854 *num = reclist->num_records;
1858 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1861 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1862 bend_search_rr *bsrr =
1863 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1865 yaz_log(LOG_LOG, "Got SearchRequest.");
1867 bsrr->request = reqb;
1868 bsrr->association = assoc;
1869 bsrr->referenceId = req->referenceId;
1870 save_referenceId (reqb, bsrr->referenceId);
1872 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1873 if (req->databaseNames)
1876 for (i = 0; i < req->num_databaseNames; i++)
1877 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1879 yaz_log_zquery(req->query);
1881 if (assoc->init->bend_search)
1883 bsrr->setname = req->resultSetName;
1884 bsrr->replace_set = *req->replaceIndicator;
1885 bsrr->num_bases = req->num_databaseNames;
1886 bsrr->basenames = req->databaseNames;
1887 bsrr->query = req->query;
1888 bsrr->stream = assoc->encode;
1889 bsrr->decode = assoc->decode;
1890 bsrr->print = assoc->print;
1893 bsrr->errstring = NULL;
1894 bsrr->search_info = NULL;
1895 (assoc->init->bend_search)(assoc->backend, bsrr);
1899 return response_searchRequest(assoc, reqb, bsrr, fd);
1902 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1905 * Prepare a searchresponse based on the backend results. We probably want
1906 * to look at making the fetching of records nonblocking as well, but
1907 * so far, we'll keep things simple.
1908 * If bsrt is null, that means we're called in response to a communications
1909 * event, and we'll have to get the response for ourselves.
1911 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1912 bend_search_rr *bsrt, int *fd)
1914 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1915 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1916 Z_SearchResponse *resp = (Z_SearchResponse *)
1917 odr_malloc (assoc->encode, sizeof(*resp));
1918 int *nulint = odr_intdup (assoc->encode, 0);
1919 bool_t *sr = odr_intdup(assoc->encode, 1);
1920 int *next = odr_intdup(assoc->encode, 0);
1921 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1923 apdu->which = Z_APDU_searchResponse;
1924 apdu->u.searchResponse = resp;
1925 resp->referenceId = req->referenceId;
1926 resp->additionalSearchInfo = 0;
1927 resp->otherInfo = 0;
1929 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1931 yaz_log(LOG_FATAL, "Bad result from backend");
1934 else if (bsrt->errcode)
1936 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1937 resp->resultCount = nulint;
1938 resp->numberOfRecordsReturned = nulint;
1939 resp->nextResultSetPosition = nulint;
1940 resp->searchStatus = nulint;
1941 resp->resultSetStatus = none;
1942 resp->presentStatus = 0;
1946 int *toget = odr_intdup(assoc->encode, 0);
1947 int *presst = odr_intdup(assoc->encode, 0);
1948 Z_RecordComposition comp, *compp = 0;
1950 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1953 resp->resultCount = &bsrt->hits;
1955 comp.which = Z_RecordComp_simple;
1956 /* how many records does the user agent want, then? */
1957 if (bsrt->hits <= *req->smallSetUpperBound)
1959 *toget = bsrt->hits;
1960 if ((comp.u.simple = req->smallSetElementSetNames))
1963 else if (bsrt->hits < *req->largeSetLowerBound)
1965 *toget = *req->mediumSetPresentNumber;
1966 if (*toget > bsrt->hits)
1967 *toget = bsrt->hits;
1968 if ((comp.u.simple = req->mediumSetElementSetNames))
1974 if (*toget && !resp->records)
1979 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1982 form = prefformat->value;
1983 resp->records = pack_records(assoc, req->resultSetName, 1,
1984 toget, compp, next, presst, form, req->referenceId,
1985 req->preferredRecordSyntax);
1988 resp->numberOfRecordsReturned = toget;
1989 resp->nextResultSetPosition = next;
1990 resp->searchStatus = sr;
1991 resp->resultSetStatus = 0;
1992 resp->presentStatus = presst;
1996 if (*resp->resultCount)
1998 resp->numberOfRecordsReturned = nulint;
1999 resp->nextResultSetPosition = next;
2000 resp->searchStatus = sr;
2001 resp->resultSetStatus = 0;
2002 resp->presentStatus = 0;
2005 resp->additionalSearchInfo = bsrt->search_info;
2010 * Maybe we got a little over-friendly when we designed bend_fetch to
2011 * get only one record at a time. Some backends can optimise multiple-record
2012 * fetches, and at any rate, there is some overhead involved in
2013 * all that selecting and hopping around. Problem is, of course, that the
2014 * frontend can't know ahead of time how many records it'll need to
2015 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2016 * is downright lousy as a bulk data transfer protocol.
2018 * To start with, we'll do the fetching of records from the backend
2019 * in one operation: To save some trips in and out of the event-handler,
2020 * and to simplify the interface to pack_records. At any rate, asynch
2021 * operation is more fun in operations that have an unpredictable execution
2022 * speed - which is normally more true for search than for present.
2024 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2027 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2031 Z_PresentResponse *resp;
2035 yaz_log(LOG_LOG, "Got PresentRequest.");
2037 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2040 form = prefformat->value;
2041 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2043 resp->presentStatus = odr_intdup(assoc->encode, 0);
2044 if (assoc->init->bend_present)
2046 bend_present_rr *bprr = (bend_present_rr *)
2047 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2048 bprr->setname = req->resultSetId;
2049 bprr->start = *req->resultSetStartPoint;
2050 bprr->number = *req->numberOfRecordsRequested;
2051 bprr->format = form;
2052 bprr->comp = req->recordComposition;
2053 bprr->referenceId = req->referenceId;
2054 bprr->stream = assoc->encode;
2055 bprr->print = assoc->print;
2056 bprr->request = reqb;
2057 bprr->association = assoc;
2059 bprr->errstring = NULL;
2060 (*assoc->init->bend_present)(assoc->backend, bprr);
2066 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2067 *resp->presentStatus = Z_PRES_FAILURE;
2070 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2071 next = odr_intdup(assoc->encode, 0);
2072 num = odr_intdup(assoc->encode, 0);
2074 apdu->which = Z_APDU_presentResponse;
2075 apdu->u.presentResponse = resp;
2076 resp->referenceId = req->referenceId;
2077 resp->otherInfo = 0;
2081 *num = *req->numberOfRecordsRequested;
2083 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2084 num, req->recordComposition, next, resp->presentStatus,
2085 form, req->referenceId, req->preferredRecordSyntax);
2089 resp->numberOfRecordsReturned = num;
2090 resp->nextResultSetPosition = next;
2096 * Scan was implemented rather in a hurry, and with support for only the basic
2097 * elements of the service in the backend API. Suggestions are welcome.
2099 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2101 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2102 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2103 Z_ScanResponse *res = (Z_ScanResponse *)
2104 odr_malloc (assoc->encode, sizeof(*res));
2105 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2106 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2107 Z_ListEntries *ents = (Z_ListEntries *)
2108 odr_malloc (assoc->encode, sizeof(*ents));
2109 Z_DiagRecs *diagrecs_p = NULL;
2111 bend_scan_rr *bsrr = (bend_scan_rr *)
2112 odr_malloc (assoc->encode, sizeof(*bsrr));
2113 struct scan_entry *save_entries;
2115 yaz_log(LOG_LOG, "Got ScanRequest");
2117 apdu->which = Z_APDU_scanResponse;
2118 apdu->u.scanResponse = res;
2119 res->referenceId = req->referenceId;
2121 /* if step is absent, set it to 0 */
2122 res->stepSize = odr_intdup(assoc->encode, 0);
2124 *res->stepSize = *req->stepSize;
2126 res->scanStatus = scanStatus;
2127 res->numberOfEntriesReturned = numberOfEntriesReturned;
2128 res->positionOfTerm = 0;
2129 res->entries = ents;
2130 ents->num_entries = 0;
2131 ents->entries = NULL;
2132 ents->num_nonsurrogateDiagnostics = 0;
2133 ents->nonsurrogateDiagnostics = NULL;
2134 res->attributeSet = 0;
2137 if (req->databaseNames)
2140 for (i = 0; i < req->num_databaseNames; i++)
2141 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2143 bsrr->num_bases = req->num_databaseNames;
2144 bsrr->basenames = req->databaseNames;
2145 bsrr->num_entries = *req->numberOfTermsRequested;
2146 bsrr->term = req->termListAndStartPoint;
2147 bsrr->referenceId = req->referenceId;
2148 bsrr->stream = assoc->encode;
2149 bsrr->print = assoc->print;
2150 bsrr->step_size = res->stepSize;
2152 /* Note that version 2.0 of YAZ and older did not set entries ..
2153 We do now. And when we do it's easier to extend the scan entry
2154 We know that if the scan handler did set entries, it will
2155 not know of new member display_term.
2157 if (bsrr->num_entries > 0)
2160 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2162 for (i = 0; i<bsrr->num_entries; i++)
2164 bsrr->entries[i].term = 0;
2165 bsrr->entries[i].occurrences = 0;
2166 bsrr->entries[i].errcode = 0;
2167 bsrr->entries[i].errstring = 0;
2168 bsrr->entries[i].display_term = 0;
2171 save_entries = bsrr->entries; /* save it so we can compare later */
2173 if (req->attributeSet &&
2174 (attset = oid_getentbyoid(req->attributeSet)) &&
2175 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2176 bsrr->attributeset = attset->value;
2178 bsrr->attributeset = VAL_NONE;
2179 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2180 bsrr->term_position = req->preferredPositionInResponse ?
2181 *req->preferredPositionInResponse : 1;
2182 ((int (*)(void *, bend_scan_rr *))
2183 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2185 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2189 Z_Entry **tab = (Z_Entry **)
2190 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2192 if (bsrr->status == BEND_SCAN_PARTIAL)
2193 *scanStatus = Z_Scan_partial_5;
2195 *scanStatus = Z_Scan_success;
2196 ents->entries = tab;
2197 ents->num_entries = bsrr->num_entries;
2198 res->numberOfEntriesReturned = &ents->num_entries;
2199 res->positionOfTerm = &bsrr->term_position;
2200 for (i = 0; i < bsrr->num_entries; i++)
2206 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2207 if (bsrr->entries[i].occurrences >= 0)
2209 e->which = Z_Entry_termInfo;
2210 e->u.termInfo = t = (Z_TermInfo *)
2211 odr_malloc(assoc->encode, sizeof(*t));
2212 t->suggestedAttributes = 0;
2214 if (save_entries == bsrr->entries &&
2215 bsrr->entries[i].display_term)
2217 /* the entries was NOT set by the handler. So it's
2218 safe to test for new member display_term. It is
2221 t->displayTerm = odr_strdup(assoc->encode,
2222 bsrr->entries[i].display_term);
2224 t->alternativeTerm = 0;
2225 t->byAttributes = 0;
2226 t->otherTermInfo = 0;
2227 t->globalOccurrences = &bsrr->entries[i].occurrences;
2228 t->term = (Z_Term *)
2229 odr_malloc(assoc->encode, sizeof(*t->term));
2230 t->term->which = Z_Term_general;
2231 t->term->u.general = o =
2232 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2233 o->buf = (unsigned char *)
2234 odr_malloc(assoc->encode, o->len = o->size =
2235 strlen(bsrr->entries[i].term));
2236 memcpy(o->buf, bsrr->entries[i].term, o->len);
2237 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2238 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2242 Z_DiagRecs *drecs = diagrecs (assoc,
2243 bsrr->entries[i].errcode,
2244 bsrr->entries[i].errstring);
2245 assert (drecs->num_diagRecs == 1);
2246 e->which = Z_Entry_surrogateDiagnostic;
2247 assert (drecs->diagRecs[0]);
2248 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2254 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2255 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2260 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2263 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2264 Z_SortResponse *res = (Z_SortResponse *)
2265 odr_malloc (assoc->encode, sizeof(*res));
2266 bend_sort_rr *bsrr = (bend_sort_rr *)
2267 odr_malloc (assoc->encode, sizeof(*bsrr));
2269 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2271 yaz_log(LOG_LOG, "Got SortRequest.");
2273 bsrr->num_input_setnames = req->num_inputResultSetNames;
2274 bsrr->input_setnames = req->inputResultSetNames;
2275 bsrr->referenceId = req->referenceId;
2276 bsrr->output_setname = req->sortedResultSetName;
2277 bsrr->sort_sequence = req->sortSequence;
2278 bsrr->stream = assoc->encode;
2279 bsrr->print = assoc->print;
2281 bsrr->sort_status = Z_SortStatus_failure;
2283 bsrr->errstring = 0;
2285 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2287 res->referenceId = bsrr->referenceId;
2288 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2289 res->resultSetStatus = 0;
2292 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2293 res->diagnostics = dr->diagRecs;
2294 res->num_diagnostics = dr->num_diagRecs;
2298 res->num_diagnostics = 0;
2299 res->diagnostics = 0;
2303 apdu->which = Z_APDU_sortResponse;
2304 apdu->u.sortResponse = res;
2308 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2311 Z_DeleteResultSetRequest *req =
2312 reqb->apdu_request->u.deleteResultSetRequest;
2313 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2314 odr_malloc (assoc->encode, sizeof(*res));
2315 bend_delete_rr *bdrr = (bend_delete_rr *)
2316 odr_malloc (assoc->encode, sizeof(*bdrr));
2317 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2319 yaz_log(LOG_LOG, "Got DeleteRequest.");
2321 bdrr->num_setnames = req->num_resultSetList;
2322 bdrr->setnames = req->resultSetList;
2323 bdrr->stream = assoc->encode;
2324 bdrr->print = assoc->print;
2325 bdrr->function = *req->deleteFunction;
2326 bdrr->referenceId = req->referenceId;
2328 if (bdrr->num_setnames > 0)
2331 bdrr->statuses = (int*)
2332 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2333 bdrr->num_setnames);
2334 for (i = 0; i < bdrr->num_setnames; i++)
2335 bdrr->statuses[i] = 0;
2337 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2339 res->referenceId = req->referenceId;
2341 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2343 res->deleteListStatuses = 0;
2344 if (bdrr->num_setnames > 0)
2347 res->deleteListStatuses = (Z_ListStatuses *)
2348 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2349 res->deleteListStatuses->num = bdrr->num_setnames;
2350 res->deleteListStatuses->elements =
2352 odr_malloc (assoc->encode,
2353 sizeof(*res->deleteListStatuses->elements) *
2354 bdrr->num_setnames);
2355 for (i = 0; i<bdrr->num_setnames; i++)
2357 res->deleteListStatuses->elements[i] =
2359 odr_malloc (assoc->encode,
2360 sizeof(**res->deleteListStatuses->elements));
2361 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2362 res->deleteListStatuses->elements[i]->id =
2363 odr_strdup (assoc->encode, bdrr->setnames[i]);
2367 res->numberNotDeleted = 0;
2368 res->bulkStatuses = 0;
2369 res->deleteMessage = 0;
2372 apdu->which = Z_APDU_deleteResultSetResponse;
2373 apdu->u.deleteResultSetResponse = res;
2377 static void process_close(association *assoc, request *reqb)
2379 Z_Close *req = reqb->apdu_request->u.close;
2380 static char *reasons[] =
2387 "securityViolation",
2394 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2395 reasons[*req->closeReason], req->diagnosticInformation ?
2396 req->diagnosticInformation : "NULL");
2397 if (assoc->version < 3) /* to make do_force respond with close */
2399 do_close_req(assoc, Z_Close_finished,
2400 "Association terminated by client", reqb);
2403 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2407 reqb->len_refid = refid->len;
2408 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2409 memcpy (reqb->refid, refid->buf, refid->len);
2413 reqb->len_refid = 0;
2418 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2420 process_z_response (a, req, res);
2423 bend_request bend_request_mk (bend_association a)
2425 request *nreq = request_get (&a->outgoing);
2426 nreq->request_mem = nmem_create ();
2430 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2435 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2436 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2437 id->len = id->size = req->len_refid;
2438 memcpy (id->buf, req->refid, req->len_refid);
2442 void bend_request_destroy (bend_request *req)
2444 nmem_destroy((*req)->request_mem);
2445 request_release(*req);
2449 int bend_backend_respond (bend_association a, bend_request req)
2453 r = process_z_request (a, req, &msg);
2455 yaz_log (LOG_WARN, "%s", msg);
2459 void bend_request_setdata(bend_request r, void *p)
2464 void *bend_request_getdata(bend_request r)
2466 return r->clientData;
2469 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2471 bend_segment_rr req;
2473 req.segment = reqb->apdu_request->u.segmentRequest;
2474 req.stream = assoc->encode;
2475 req.decode = assoc->decode;
2476 req.print = assoc->print;
2477 req.association = assoc;
2479 (*assoc->init->bend_segment)(assoc->backend, &req);
2484 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2486 bend_esrequest_rr esrequest;
2488 Z_ExtendedServicesRequest *req =
2489 reqb->apdu_request->u.extendedServicesRequest;
2490 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2492 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2494 yaz_log(LOG_DEBUG,"inside Process esRequest");
2496 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2497 esrequest.stream = assoc->encode;
2498 esrequest.decode = assoc->decode;
2499 esrequest.print = assoc->print;
2500 esrequest.errcode = 0;
2501 esrequest.errstring = NULL;
2502 esrequest.request = reqb;
2503 esrequest.association = assoc;
2504 esrequest.taskPackage = 0;
2505 esrequest.referenceId = req->referenceId;
2507 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2509 /* If the response is being delayed, return NULL */
2510 if (esrequest.request == NULL)
2513 resp->referenceId = req->referenceId;
2515 if (esrequest.errcode == -1)
2517 /* Backend service indicates request will be processed */
2518 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2519 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2521 else if (esrequest.errcode == 0)
2523 /* Backend service indicates request will be processed */
2524 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2525 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2529 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2530 esrequest.errstring);
2532 /* Backend indicates error, request will not be processed */
2533 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2534 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2535 resp->num_diagnostics = diagRecs->num_diagRecs;
2536 resp->diagnostics = diagRecs->diagRecs;
2538 /* Do something with the members of bend_extendedservice */
2539 if (esrequest.taskPackage)
2540 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2541 (const char *) esrequest.taskPackage,
2543 yaz_log(LOG_DEBUG,"Send the result apdu");