2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.10 2003-12-30 00:13:05 adam Exp $
9 * Frontend server logic.
11 * This code receives incoming APDUs, and handles client requests by means
14 * Some of the code is getting quite involved, compared to simpler servers -
15 * primarily because it is asynchronous both in the communication with
16 * the user and the backend. We think the complexity will pay off in
17 * the form of greater flexibility when more asynchronous facilities
20 * Memory management has become somewhat involved. In the simple case, where
21 * only one PDU is pending at a time, it will simply reuse the same memory,
22 * once it has found its working size. When we enable multiple concurrent
23 * operations, perhaps even with multiple parallel calls to the backend, it
24 * will maintain a pool of buffers for encoding and decoding, trying to
25 * minimize memory allocation/deallocation during normal operation.
31 #include <sys/types.h>
34 #define S_ISREG(x) (x & _S_IFREG)
44 #include <yaz/yconfig.h>
45 #include <yaz/xmalloc.h>
46 #include <yaz/comstack.h>
49 #include <yaz/proto.h>
52 #include <yaz/logrpn.h>
53 #include <yaz/statserv.h>
54 #include <yaz/diagbib1.h>
55 #include <yaz/charneg.h>
56 #include <yaz/otherinfo.h>
57 #include <yaz/yaz-util.h>
58 #include <yaz/pquery.h>
61 #include <yaz/backend.h>
63 static void process_gdu_request(association *assoc, request *req);
64 static int process_z_request(association *assoc, request *req, char **msg);
65 void backend_response(IOCHAN i, int event);
66 static int process_gdu_response(association *assoc, request *req, Z_GDU *res);
67 static int process_z_response(association *assoc, request *req, Z_APDU *res);
68 static Z_APDU *process_initRequest(association *assoc, request *reqb);
69 static Z_External *init_diagnostics(ODR odr, int errcode, char *errstring);
70 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
72 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
73 bend_search_rr *bsrr, int *fd);
74 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
76 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
77 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
78 static void process_close(association *assoc, request *reqb);
79 void save_referenceId (request *reqb, Z_ReferenceId *refid);
80 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
82 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
84 static FILE *apduf = 0; /* for use in static mode */
85 static statserv_options_block *control_block = 0;
87 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
90 * Create and initialize a new association-handle.
91 * channel : iochannel for the current line.
92 * link : communications channel.
93 * Returns: 0 or a new association handle.
95 association *create_association(IOCHAN channel, COMSTACK link)
100 control_block = statserv_getcontrol();
101 if (!(anew = (association *)xmalloc(sizeof(*anew))))
105 anew->client_chan = channel;
106 anew->client_link = link;
107 anew->cs_get_mask = 0;
108 anew->cs_put_mask = 0;
109 anew->cs_accept_mask = 0;
110 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
111 !(anew->encode = odr_createmem(ODR_ENCODE)))
113 if (*control_block->apdufile)
118 strcpy(filename, control_block->apdufile);
119 if (!(anew->print = odr_createmem(ODR_PRINT)))
121 if (*control_block->apdufile == '@')
123 odr_setprint(anew->print, yaz_log_file());
125 else if (*control_block->apdufile != '-')
127 strcpy(filename, control_block->apdufile);
128 if (!control_block->dynamic)
132 if (!(apduf = fopen(filename, "w")))
134 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
137 setvbuf(apduf, 0, _IONBF, 0);
143 sprintf(filename + strlen(filename), ".%d", getpid());
144 if (!(f = fopen(filename, "w")))
146 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
149 setvbuf(f, 0, _IONBF, 0);
151 odr_setprint(anew->print, f);
156 anew->input_buffer = 0;
157 anew->input_buffer_len = 0;
159 anew->state = ASSOC_NEW;
160 request_initq(&anew->incoming);
161 request_initq(&anew->outgoing);
162 anew->proto = cs_getproto(link);
167 * Free association and release resources.
169 void destroy_association(association *h)
171 statserv_options_block *cb = statserv_getcontrol();
175 odr_destroy(h->decode);
176 odr_destroy(h->encode);
178 odr_destroy(h->print);
180 xfree(h->input_buffer);
182 (*cb->bend_close)(h->backend);
183 while ((req = request_deq(&h->incoming)))
184 request_release(req);
185 while ((req = request_deq(&h->outgoing)))
186 request_release(req);
187 request_delq(&h->incoming);
188 request_delq(&h->outgoing);
190 xmalloc_trav("session closed");
191 if (control_block && control_block->one_shot)
197 static void do_close_req(association *a, int reason, char *message,
201 Z_Close *cls = zget_Close(a->encode);
203 /* Purge request queue */
204 while (request_deq(&a->incoming));
205 while (request_deq(&a->outgoing));
208 yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
209 reason, message ? message : "none");
210 apdu.which = Z_APDU_close;
212 *cls->closeReason = reason;
213 cls->diagnosticInformation = message;
214 process_z_response(a, req, &apdu);
215 iochan_settimeout(a->client_chan, 20);
219 request_release(req);
220 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
221 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
223 a->state = ASSOC_DEAD;
226 static void do_close(association *a, int reason, char *message)
228 request *req = request_get(&a->outgoing);
229 do_close_req (a, reason, message, req);
233 * This is where PDUs from the client are read and the further
234 * processing is initiated. Flow of control moves down through the
235 * various process_* functions below, until the encoded result comes back up
236 * to the output handler in here.
238 * h : the I/O channel that has an outstanding event.
239 * event : the current outstanding event.
241 void ir_session(IOCHAN h, int event)
244 association *assoc = (association *)iochan_getdata(h);
245 COMSTACK conn = assoc->client_link;
248 assert(h && conn && assoc);
249 if (event == EVENT_TIMEOUT)
251 if (assoc->state != ASSOC_UP)
253 yaz_log(LOG_LOG, "Final timeout - closing connection.");
255 destroy_association(assoc);
260 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
261 do_close(assoc, Z_Close_lackOfActivity, 0);
265 if (event & assoc->cs_accept_mask)
267 yaz_log (LOG_DEBUG, "ir_session (accept)");
268 if (!cs_accept (conn))
270 yaz_log (LOG_LOG, "accept failed");
271 destroy_association(assoc);
274 iochan_clearflag (h, EVENT_OUTPUT|EVENT_OUTPUT);
275 if (conn->io_pending)
276 { /* cs_accept didn't complete */
277 assoc->cs_accept_mask =
278 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
279 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
281 iochan_setflag (h, assoc->cs_accept_mask);
284 { /* cs_accept completed. Prepare for reading (cs_get) */
285 assoc->cs_accept_mask = 0;
286 assoc->cs_get_mask = EVENT_INPUT;
287 iochan_setflag (h, assoc->cs_get_mask);
291 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
293 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
295 yaz_log(LOG_DEBUG, "ir_session (input)");
296 /* We aren't speaking to this fellow */
297 if (assoc->state == ASSOC_DEAD)
299 yaz_log(LOG_LOG, "Connection closed - end of session");
301 destroy_association(assoc);
305 assoc->cs_get_mask = EVENT_INPUT;
306 if ((res = cs_get(conn, &assoc->input_buffer,
307 &assoc->input_buffer_len)) <= 0)
309 yaz_log(LOG_LOG, "Connection closed by client");
311 destroy_association(assoc);
315 else if (res == 1) /* incomplete read - wait for more */
317 if (conn->io_pending & CS_WANT_WRITE)
318 assoc->cs_get_mask |= EVENT_OUTPUT;
319 iochan_setflag(h, assoc->cs_get_mask);
322 if (cs_more(conn)) /* more stuff - call us again later, please */
323 iochan_setevent(h, EVENT_INPUT);
325 /* we got a complete PDU. Let's decode it */
326 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
327 assoc->input_buffer[0] & 0xff,
328 assoc->input_buffer[1] & 0xff,
329 assoc->input_buffer[2] & 0xff);
330 req = request_get(&assoc->incoming); /* get a new request */
331 odr_reset(assoc->decode);
332 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
333 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
335 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
337 odr_errmsg(odr_geterror(assoc->decode)),
338 odr_getelement(assoc->decode),
339 odr_offset(assoc->decode));
340 if (assoc->decode->error != OHTTP)
342 yaz_log(LOG_LOG, "PDU dump:");
343 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
344 request_release(req);
345 do_close(assoc, Z_Close_protocolError,"Malformed package");
349 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
350 assoc->state = ASSOC_DEAD;
351 process_gdu_response(assoc, req, p);
355 req->request_mem = odr_extract_mem(assoc->decode);
356 if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
358 yaz_log(LOG_WARN, "ODR print error: %s",
359 odr_errmsg(odr_geterror(assoc->print)));
360 odr_reset(assoc->print);
362 request_enq(&assoc->incoming, req);
365 /* can we do something yet? */
366 req = request_head(&assoc->incoming);
367 if (req->state == REQUEST_IDLE)
369 request_deq(&assoc->incoming);
370 process_gdu_request(assoc, req);
373 if (event & assoc->cs_put_mask)
375 request *req = request_head(&assoc->outgoing);
377 assoc->cs_put_mask = 0;
378 yaz_log(LOG_DEBUG, "ir_session (output)");
379 req->state = REQUEST_PENDING;
380 switch (res = cs_put(conn, req->response, req->len_response))
383 yaz_log(LOG_LOG, "Connection closed by client");
385 destroy_association(assoc);
388 case 0: /* all sent - release the request structure */
389 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
391 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
394 nmem_destroy(req->request_mem);
395 request_deq(&assoc->outgoing);
396 request_release(req);
397 if (!request_head(&assoc->outgoing))
398 { /* restore mask for cs_get operation ... */
399 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
400 iochan_setflag(h, assoc->cs_get_mask);
401 if (assoc->state == ASSOC_DEAD)
402 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
406 assoc->cs_put_mask = EVENT_OUTPUT;
410 if (conn->io_pending & CS_WANT_WRITE)
411 assoc->cs_put_mask |= EVENT_OUTPUT;
412 if (conn->io_pending & CS_WANT_READ)
413 assoc->cs_put_mask |= EVENT_INPUT;
414 iochan_setflag(h, assoc->cs_put_mask);
417 if (event & EVENT_EXCEPT)
419 yaz_log(LOG_LOG, "ir_session (exception)");
421 destroy_association(assoc);
426 static int process_z_request(association *assoc, request *req, char **msg);
428 static void assoc_init_reset(association *assoc)
431 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
433 assoc->init->stream = assoc->encode;
434 assoc->init->print = assoc->print;
435 assoc->init->auth = 0;
436 assoc->init->referenceId = 0;
437 assoc->init->implementation_version = 0;
438 assoc->init->implementation_id = 0;
439 assoc->init->implementation_name = 0;
440 assoc->init->bend_sort = NULL;
441 assoc->init->bend_search = NULL;
442 assoc->init->bend_present = NULL;
443 assoc->init->bend_esrequest = NULL;
444 assoc->init->bend_delete = NULL;
445 assoc->init->bend_scan = NULL;
446 assoc->init->bend_segment = NULL;
447 assoc->init->bend_fetch = NULL;
448 assoc->init->bend_explain = NULL;
450 assoc->init->charneg_request = NULL;
451 assoc->init->charneg_response = NULL;
453 assoc->init->decode = assoc->decode;
454 assoc->init->peer_name =
455 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
458 static int srw_bend_init(association *assoc)
460 const char *encoding = "UTF-8";
462 bend_initresult *binitres;
463 statserv_options_block *cb = statserv_getcontrol();
465 assoc_init_reset(assoc);
467 assoc->maximumRecordSize = 3000000;
468 assoc->preferredMessageSize = 3000000;
470 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
471 assoc->init->charneg_request = ce->u.charNeg3;
473 if (!(binitres = (*cb->bend_init)(assoc->init)))
475 yaz_log(LOG_WARN, "Bad response from backend.");
478 assoc->backend = binitres->handle;
482 static int srw_bend_fetch(association *assoc, int pos,
483 Z_SRW_searchRetrieveRequest *srw_req,
484 Z_SRW_record *record)
487 ODR o = assoc->encode;
489 rr.setname = "default";
492 rr.request_format = VAL_TEXT_XML;
493 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
496 rr.comp = (Z_RecordComposition *)
497 odr_malloc(assoc->decode, sizeof(*rr.comp));
498 rr.comp->which = Z_RecordComp_complex;
499 rr.comp->u.complex = (Z_CompSpec *)
500 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
501 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
502 odr_malloc(assoc->encode, sizeof(bool_t));
503 *rr.comp->u.complex->selectAlternativeSyntax = 0;
504 rr.comp->u.complex->num_dbSpecific = 0;
505 rr.comp->u.complex->dbSpecific = 0;
506 rr.comp->u.complex->num_recordSyntax = 0;
507 rr.comp->u.complex->recordSyntax = 0;
509 rr.comp->u.complex->generic = (Z_Specification *)
510 odr_malloc(assoc->decode, sizeof(Z_Specification));
511 rr.comp->u.complex->generic->which = Z_Schema_uri;
512 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
513 rr.comp->u.complex->generic->elementSpec = 0;
515 rr.stream = assoc->encode;
516 rr.print = assoc->print;
522 rr.output_format = VAL_TEXT_XML;
523 rr.output_format_raw = 0;
526 rr.surrogate_flag = 0;
527 rr.schema = srw_req->recordSchema;
529 if (!assoc->init->bend_fetch)
532 (*assoc->init->bend_fetch)(assoc->backend, &rr);
536 record->recordData_buf = rr.record;
537 record->recordData_len = rr.len;
538 record->recordPosition = odr_intdup(o, pos);
540 record->recordSchema = odr_strdup(o, rr.schema);
542 record->recordSchema = 0;
547 static void srw_bend_search(association *assoc, request *req,
548 Z_SRW_searchRetrieveRequest *srw_req,
549 Z_SRW_searchRetrieveResponse *srw_res,
557 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
558 yaz_log(LOG_DEBUG, "srw_bend_search");
561 yaz_log(LOG_DEBUG, "srw_bend_init");
562 if (!srw_bend_init(assoc))
564 srw_error = 3; /* assume Authentication error */
566 srw_res->num_diagnostics = 1;
567 srw_res->diagnostics = (Z_SRW_diagnostic *)
568 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
569 srw_res->diagnostics[0].code =
570 odr_intdup(assoc->encode, srw_error);
571 srw_res->diagnostics[0].details = 0;
576 rr.setname = "default";
579 rr.basenames = &srw_req->database;
582 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
584 if (srw_req->query_type == Z_SRW_query_type_cql)
586 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
587 ext->direct_reference = odr_getoidbystr(assoc->decode,
588 "1.2.840.10003.16.2");
589 ext->indirect_reference = 0;
591 ext->which = Z_External_CQL;
592 ext->u.cql = srw_req->query.cql;
594 rr.query->which = Z_Query_type_104;
595 rr.query->u.type_104 = ext;
597 else if (srw_req->query_type == Z_SRW_query_type_pqf)
599 Z_RPNQuery *RPNquery;
600 YAZ_PQF_Parser pqf_parser;
602 pqf_parser = yaz_pqf_create ();
604 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
610 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
611 yaz_log(LOG_LOG, "%*s^\n", off+4, "");
612 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
617 rr.query->which = Z_Query_type_1;
618 rr.query->u.type_1 = RPNquery;
620 yaz_pqf_destroy (pqf_parser);
625 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
628 if (!srw_error && !assoc->init->bend_search)
633 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
634 srw_res->num_diagnostics = 1;
635 srw_res->diagnostics = (Z_SRW_diagnostic *)
636 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
637 srw_res->diagnostics[0].code =
638 odr_intdup(assoc->encode, srw_error);
639 srw_res->diagnostics[0].details = 0;
643 rr.stream = assoc->encode;
644 rr.decode = assoc->decode;
645 rr.print = assoc->print;
647 rr.association = assoc;
653 yaz_log_zquery(rr.query);
654 (assoc->init->bend_search)(assoc->backend, &rr);
655 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
658 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
659 if (rr.errcode == 109) /* database unavailable */
664 srw_res->num_diagnostics = 1;
665 srw_res->diagnostics = (Z_SRW_diagnostic *)
666 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
667 srw_res->diagnostics[0].code =
668 odr_intdup(assoc->encode,
669 yaz_diag_bib1_to_srw (rr.errcode));
670 srw_res->diagnostics[0].details = rr.errstring;
671 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
672 *srw_res->diagnostics[0].code);
677 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
678 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
680 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
681 start, number, rr.hits);
683 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
690 yaz_log(LOG_LOG, "Request out or range");
695 int packing = Z_SRW_recordPacking_string;
696 if (start + number > rr.hits)
697 number = rr.hits - start + 1;
698 if (srw_req->recordPacking &&
699 !strcmp(srw_req->recordPacking, "xml"))
700 packing = Z_SRW_recordPacking_XML;
701 srw_res->records = (Z_SRW_record *)
702 odr_malloc(assoc->encode,
703 number * sizeof(*srw_res->records));
704 for (i = 0; i<number; i++)
708 srw_res->records[j].recordPacking = packing;
709 srw_res->records[j].recordData_buf = 0;
710 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
711 errcode = srw_bend_fetch(assoc, i+start, srw_req,
712 srw_res->records + j);
715 srw_res->num_diagnostics = 1;
716 srw_res->diagnostics = (Z_SRW_diagnostic *)
717 odr_malloc(assoc->encode,
718 sizeof(*srw_res->diagnostics));
719 srw_res->diagnostics[0].code =
720 odr_intdup(assoc->encode,
721 yaz_diag_bib1_to_srw (errcode));
722 srw_res->diagnostics[0].details = rr.errstring;
725 if (srw_res->records[j].recordData_buf)
728 srw_res->num_records = j;
730 srw_res->records = 0;
736 static void srw_bend_explain(association *assoc, request *req,
737 Z_SRW_explainRequest *srw_req,
738 Z_SRW_explainResponse *srw_res,
741 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
745 yaz_log(LOG_DEBUG, "srw_bend_init");
746 if (!srw_bend_init(assoc))
751 if (assoc->init && assoc->init->bend_explain)
755 rr.stream = assoc->encode;
756 rr.decode = assoc->decode;
757 rr.print = assoc->print;
759 rr.database = srw_req->database;
760 (*assoc->init->bend_explain)(assoc->backend, &rr);
763 int packing = Z_SRW_recordPacking_string;
764 if (srw_req->recordPacking &&
765 !strcmp(srw_req->recordPacking, "xml"))
766 packing = Z_SRW_recordPacking_XML;
767 srw_res->record.recordSchema = 0;
768 srw_res->record.recordPacking = packing;
769 srw_res->record.recordData_buf = rr.explain_buf;
770 srw_res->record.recordData_len = strlen(rr.explain_buf);
771 srw_res->record.recordPosition = 0;
777 static void process_http_request(association *assoc, request *req)
779 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
780 ODR o = assoc->encode;
782 Z_HTTP_Response *hres = 0;
785 if (!strcmp(hreq->method, "GET"))
787 char *db = "Default";
788 const char *p0 = hreq->path, *p1;
789 const char *operation = 0;
793 Z_SOAP *soap_package = 0;
794 static Z_SOAP_Handler soap_handlers[2] = {
795 {"http://www.loc.gov/zing/srw/", 0,
796 (Z_SOAP_fun) yaz_srw_codec},
802 p1 = strchr(p0, '?');
804 p1 = p0 + strlen(p0);
807 db = odr_malloc(assoc->decode, p1 - p0 + 1);
808 memcpy (db, p0, p1 - p0);
812 operation = yaz_uri_val(p1, "operation", o);
814 operation = "explain";
816 if (p1 && !strcmp(operation, "searchRetrieve"))
818 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
819 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
820 char *query = yaz_uri_val(p1, "query", o);
821 char *pQuery = yaz_uri_val(p1, "pQuery", o);
822 char *sortKeys = yaz_uri_val(p1, "sortKeys", o);
827 sr->u.request->query_type = Z_SRW_query_type_cql;
828 sr->u.request->query.cql = query;
832 sr->u.request->query_type = Z_SRW_query_type_pqf;
833 sr->u.request->query.pqf = pQuery;
837 sr->u.request->sort_type = Z_SRW_sort_type_sort;
838 sr->u.request->sort.sortKeys = sortKeys;
840 sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", o);
841 sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", o);
842 if (!sr->u.request->recordPacking)
843 sr->u.request->recordPacking = "xml";
844 yaz_uri_val_int(p1, "maximumRecords", o,
845 &sr->u.request->maximumRecords);
846 yaz_uri_val_int(p1, "startRecord", o,
847 &sr->u.request->startRecord);
848 sr->u.request->database = db;
849 srw_bend_search(assoc, req, sr->u.request, res->u.response,
852 soap_package = odr_malloc(o, sizeof(*soap_package));
853 soap_package->which = Z_SOAP_generic;
855 soap_package->u.generic =
856 odr_malloc(o, sizeof(*soap_package->u.generic));
858 soap_package->u.generic->p = res;
859 soap_package->u.generic->ns = soap_handlers[0].ns;
860 soap_package->u.generic->no = 0;
862 soap_package->ns = "SRU";
864 p = z_get_HTTP_Response(o, http_code);
865 if (http_code == 200)
867 hres = p->u.HTTP_Response;
869 ret = z_soap_codec_enc(assoc->encode, &soap_package,
870 &hres->content_buf, &hres->content_len,
871 soap_handlers, charset);
873 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
877 strcpy(ctype, "text/xml; charset=");
878 strcat(ctype, charset);
879 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
883 else if (p1 && !strcmp(operation, "explain"))
885 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
886 Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
889 sr->u.explain_request->database = db;
890 sr->u.explain_request->recordPacking =
891 yaz_uri_val(p1, "recordPacking", o);
892 if (!sr->u.explain_request->recordPacking)
893 sr->u.explain_request->recordPacking = "xml";
895 srw_bend_explain(assoc, req, sr->u.explain_request,
896 res->u.explain_response, &http_code);
898 if (res->u.explain_response->record.recordData_buf)
900 soap_package = odr_malloc(o, sizeof(*soap_package));
901 soap_package->which = Z_SOAP_generic;
903 soap_package->u.generic =
904 odr_malloc(o, sizeof(*soap_package->u.generic));
906 soap_package->u.generic->p = res;
907 soap_package->u.generic->ns = soap_handlers[0].ns;
908 soap_package->u.generic->no = 0;
910 soap_package->ns = "SRU";
912 p = z_get_HTTP_Response(o, 200);
913 hres = p->u.HTTP_Response;
915 ret = z_soap_codec_enc(assoc->encode, &soap_package,
916 &hres->content_buf, &hres->content_len,
917 soap_handlers, charset);
919 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
923 strcpy(ctype, "text/xml; charset=");
924 strcat(ctype, charset);
925 z_HTTP_header_add(o, &hres->headers, "Content-Type",
932 if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
933 !memcmp(hreq->path, "/doc/", 5))
938 strcpy(fpath, DOCDIR);
939 strcat(fpath, hreq->path+4);
940 f = fopen(fpath, "rb");
943 if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
952 fseek(f, 0L, SEEK_END);
954 if (sz >= 0 && sz < 500000)
956 const char *ctype = "application/octet-stream";
959 p = z_get_HTTP_Response(o, 200);
960 hres = p->u.HTTP_Response;
961 hres->content_buf = (char *) odr_malloc(o, sz + 1);
962 hres->content_len = sz;
963 fseek(f, 0L, SEEK_SET);
964 fread(hres->content_buf, 1, sz, f);
965 if ((cp = strrchr(fpath, '.'))) {
967 if (!strcmp(cp, "png"))
969 else if (!strcmp(cp, "gif"))
971 else if (!strcmp(cp, "xml"))
973 else if (!strcmp(cp, "html"))
976 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
984 if (!strcmp(hreq->path, "/"))
989 const char *doclink = "";
990 p = z_get_HTTP_Response(o, 200);
991 hres = p->u.HTTP_Response;
992 hres->content_buf = (char *) odr_malloc(o, 400);
994 if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
995 doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
997 sprintf (hres->content_buf,
998 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
1001 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
1004 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
1005 YAZ_VERSION "</P>\n"
1008 "</HTML>\n", doclink);
1009 hres->content_len = strlen(hres->content_buf);
1010 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
1016 p = z_get_HTTP_Response(o, 404);
1019 else if (!strcmp(hreq->method, "POST"))
1021 const char *content_type = z_HTTP_header_lookup(hreq->headers,
1023 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
1025 Z_SOAP *soap_package = 0;
1027 int http_code = 500;
1028 const char *charset_p = 0;
1031 static Z_SOAP_Handler soap_handlers[3] = {
1033 {"http://www.loc.gov/zing/srw/", 0,
1034 (Z_SOAP_fun) yaz_srw_codec},
1035 {"http://www.loc.gov/zing/srw/v1.0/", 0,
1036 (Z_SOAP_fun) yaz_srw_codec},
1040 if ((charset_p = strstr(content_type, "; charset=")))
1044 while (i < 20 && charset_p[i] &&
1045 !strchr("; \n\r", charset_p[i]))
1047 charset = odr_malloc(assoc->encode, i+1);
1048 memcpy(charset, charset_p, i);
1050 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1052 ret = z_soap_codec(assoc->decode, &soap_package,
1053 &hreq->content_buf, &hreq->content_len,
1056 if (!ret && soap_package->which == Z_SOAP_generic)
1059 char *db = "Default";
1060 char *srw_version = 0;
1061 const char *p0 = hreq->path, *p1;
1062 Z_SRW_PDU *sr = soap_package->u.generic->p;
1066 p1 = strchr(p0, '?');
1068 p1 = p0 + strlen(p0);
1071 db = (char*) odr_malloc(assoc->decode, p1 - p0 + 1);
1072 memcpy (db, p0, p1 - p0);
1076 if (sr->which == Z_SRW_searchRetrieve_request)
1079 yaz_srw_get(assoc->encode,
1080 Z_SRW_searchRetrieve_response);
1082 if (!sr->u.request->database)
1083 sr->u.request->database = db;
1085 if (soap_package->u.generic->no == 1) /* SRW 1.0 */
1086 res->srw_version = 0;
1088 srw_bend_search(assoc, req, sr->u.request,
1089 res->u.response, &http_code);
1091 soap_package->u.generic->p = res;
1093 else if (sr->which == Z_SRW_explain_request)
1096 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1097 sr->u.explain_request->database = db;
1099 if (soap_package->u.generic->no == 1) /* SRW 1.0 */
1100 res->srw_version = 0;
1102 srw_bend_explain(assoc, req, sr->u.explain_request,
1103 res->u.explain_response, &http_code);
1104 if (http_code == 200)
1105 soap_package->u.generic->p = res;
1109 z_soap_error(assoc->encode, soap_package,
1110 "SOAP-ENV:Client", "Bad method", 0);
1115 if (http_code == 200 || http_code == 500)
1117 p = z_get_HTTP_Response(o, 200);
1118 hres = p->u.HTTP_Response;
1119 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1120 &hres->content_buf, &hres->content_len,
1121 soap_handlers, charset);
1122 hres->code = http_code;
1124 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1128 strcpy(ctype, "text/xml; charset=");
1129 strcat(ctype, charset);
1130 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1134 p = z_get_HTTP_Response(o, http_code);
1136 if (!p) /* still no response ? */
1137 p = z_get_HTTP_Response(o, 500);
1141 p = z_get_HTTP_Response(o, 405);
1142 hres = p->u.HTTP_Response;
1144 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1146 hres = p->u.HTTP_Response;
1147 if (!strcmp(hreq->version, "1.0"))
1149 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1150 if (v && !strcmp(v, "Keep-Alive"))
1154 hres->version = "1.0";
1158 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1159 if (v && !strcmp(v, "close"))
1163 hres->version = "1.1";
1167 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1168 assoc->state = ASSOC_DEAD;
1173 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1175 if (alive && isdigit(*alive))
1179 if (t < 0 || t > 3600)
1181 iochan_settimeout(assoc->client_chan,t);
1182 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1184 process_gdu_response(assoc, req, p);
1187 static void process_gdu_request(association *assoc, request *req)
1189 if (req->gdu_request->which == Z_GDU_Z3950)
1192 req->apdu_request = req->gdu_request->u.z3950;
1193 if (process_z_request(assoc, req, &msg) < 0)
1194 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1196 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1197 process_http_request(assoc, req);
1200 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1205 * Initiate request processing.
1207 static int process_z_request(association *assoc, request *req, char **msg)
1213 *msg = "Unknown Error";
1214 assert(req && req->state == REQUEST_IDLE);
1215 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1217 *msg = "Missing InitRequest";
1220 switch (req->apdu_request->which)
1222 case Z_APDU_initRequest:
1223 iochan_settimeout(assoc->client_chan,
1224 statserv_getcontrol()->idle_timeout * 60);
1225 res = process_initRequest(assoc, req); break;
1226 case Z_APDU_searchRequest:
1227 res = process_searchRequest(assoc, req, &fd); break;
1228 case Z_APDU_presentRequest:
1229 res = process_presentRequest(assoc, req, &fd); break;
1230 case Z_APDU_scanRequest:
1231 if (assoc->init->bend_scan)
1232 res = process_scanRequest(assoc, req, &fd);
1235 *msg = "Cannot handle Scan APDU";
1239 case Z_APDU_extendedServicesRequest:
1240 if (assoc->init->bend_esrequest)
1241 res = process_ESRequest(assoc, req, &fd);
1244 *msg = "Cannot handle Extended Services APDU";
1248 case Z_APDU_sortRequest:
1249 if (assoc->init->bend_sort)
1250 res = process_sortRequest(assoc, req, &fd);
1253 *msg = "Cannot handle Sort APDU";
1258 process_close(assoc, req);
1260 case Z_APDU_deleteResultSetRequest:
1261 if (assoc->init->bend_delete)
1262 res = process_deleteRequest(assoc, req, &fd);
1265 *msg = "Cannot handle Delete APDU";
1269 case Z_APDU_segmentRequest:
1270 if (assoc->init->bend_segment)
1272 res = process_segmentRequest (assoc, req);
1276 *msg = "Cannot handle Segment APDU";
1281 *msg = "Bad APDU received";
1286 yaz_log(LOG_DEBUG, " result immediately available");
1287 retval = process_z_response(assoc, req, res);
1291 yaz_log(LOG_DEBUG, " result unavailble");
1294 else /* no result yet - one will be provided later */
1298 /* Set up an I/O handler for the fd supplied by the backend */
1300 yaz_log(LOG_DEBUG, " establishing handler for result");
1301 req->state = REQUEST_PENDING;
1302 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1304 iochan_setdata(chan, assoc);
1311 * Handle message from the backend.
1313 void backend_response(IOCHAN i, int event)
1315 association *assoc = (association *)iochan_getdata(i);
1316 request *req = request_head(&assoc->incoming);
1320 yaz_log(LOG_DEBUG, "backend_response");
1321 assert(assoc && req && req->state != REQUEST_IDLE);
1322 /* determine what it is we're waiting for */
1323 switch (req->apdu_request->which)
1325 case Z_APDU_searchRequest:
1326 res = response_searchRequest(assoc, req, 0, &fd); break;
1328 case Z_APDU_presentRequest:
1329 res = response_presentRequest(assoc, req, 0, &fd); break;
1330 case Z_APDU_scanRequest:
1331 res = response_scanRequest(assoc, req, 0, &fd); break;
1334 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1337 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1339 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1340 do_close(assoc, Z_Close_systemProblem, 0);
1344 else if (!res) /* no result yet - try again later */
1346 yaz_log(LOG_DEBUG, " no result yet");
1347 iochan_setfd(i, fd); /* in case fd has changed */
1352 * Encode response, and transfer the request structure to the outgoing queue.
1354 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1356 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1358 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1360 yaz_log(LOG_WARN, "ODR print error: %s",
1361 odr_errmsg(odr_geterror(assoc->print)));
1362 odr_reset(assoc->print);
1364 if (!z_GDU(assoc->encode, &res, 0, 0))
1366 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1367 odr_errmsg(odr_geterror(assoc->decode)),
1368 odr_getelement(assoc->decode));
1369 request_release(req);
1372 req->response = odr_getbuf(assoc->encode, &req->len_response,
1373 &req->size_response);
1374 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1375 odr_reset(assoc->encode);
1376 req->state = REQUEST_IDLE;
1377 request_enq(&assoc->outgoing, req);
1378 /* turn the work over to the ir_session handler */
1379 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1380 assoc->cs_put_mask = EVENT_OUTPUT;
1381 /* Is there more work to be done? give that to the input handler too */
1383 if (request_head(&assoc->incoming))
1385 yaz_log (LOG_DEBUG, "more work to be done");
1386 iochan_setevent(assoc->client_chan, EVENT_WORK);
1393 * Encode response, and transfer the request structure to the outgoing queue.
1395 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1397 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1398 gres->which = Z_GDU_Z3950;
1399 gres->u.z3950 = res;
1401 return process_gdu_response(assoc, req, gres);
1406 * Handle init request.
1407 * At the moment, we don't check the options
1408 * anywhere else in the code - we just try not to do anything that would
1409 * break a naive client. We'll toss 'em into the association block when
1410 * we need them there.
1412 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1414 statserv_options_block *cb = statserv_getcontrol();
1415 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1416 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1417 Z_InitResponse *resp = apdu->u.initResponse;
1418 bend_initresult *binitres;
1422 yaz_log(LOG_LOG, "Got initRequest");
1423 if (req->implementationId)
1424 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1425 if (req->implementationName)
1426 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1427 if (req->implementationVersion)
1428 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1430 assoc_init_reset(assoc);
1432 assoc->init->auth = req->idAuthentication;
1433 assoc->init->referenceId = req->referenceId;
1435 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1437 Z_CharSetandLanguageNegotiation *negotiation =
1438 yaz_get_charneg_record (req->otherInfo);
1439 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1440 assoc->init->charneg_request = negotiation;
1443 if (!(binitres = (*cb->bend_init)(assoc->init)))
1445 yaz_log(LOG_WARN, "Bad response from backend.");
1449 assoc->backend = binitres->handle;
1450 if ((assoc->init->bend_sort))
1451 yaz_log (LOG_DEBUG, "Sort handler installed");
1452 if ((assoc->init->bend_search))
1453 yaz_log (LOG_DEBUG, "Search handler installed");
1454 if ((assoc->init->bend_present))
1455 yaz_log (LOG_DEBUG, "Present handler installed");
1456 if ((assoc->init->bend_esrequest))
1457 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1458 if ((assoc->init->bend_delete))
1459 yaz_log (LOG_DEBUG, "Delete handler installed");
1460 if ((assoc->init->bend_scan))
1461 yaz_log (LOG_DEBUG, "Scan handler installed");
1462 if ((assoc->init->bend_segment))
1463 yaz_log (LOG_DEBUG, "Segment handler installed");
1465 resp->referenceId = req->referenceId;
1467 /* let's tell the client what we can do */
1468 if (ODR_MASK_GET(req->options, Z_Options_search))
1470 ODR_MASK_SET(resp->options, Z_Options_search);
1471 strcat(options, "srch");
1473 if (ODR_MASK_GET(req->options, Z_Options_present))
1475 ODR_MASK_SET(resp->options, Z_Options_present);
1476 strcat(options, " prst");
1478 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1479 assoc->init->bend_delete)
1481 ODR_MASK_SET(resp->options, Z_Options_delSet);
1482 strcat(options, " del");
1484 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1485 assoc->init->bend_esrequest)
1487 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1488 strcat (options, " extendedServices");
1490 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1492 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1493 strcat(options, " namedresults");
1495 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1497 ODR_MASK_SET(resp->options, Z_Options_scan);
1498 strcat(options, " scan");
1500 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1502 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1503 strcat(options, " concurrop");
1505 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1507 ODR_MASK_SET(resp->options, Z_Options_sort);
1508 strcat(options, " sort");
1511 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1512 && assoc->init->charneg_response)
1514 Z_OtherInformation **p;
1515 Z_OtherInformationUnit *p0;
1517 yaz_oi_APDU(apdu, &p);
1519 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1520 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1522 p0->which = Z_OtherInfo_externallyDefinedInfo;
1523 p0->information.externallyDefinedInfo =
1524 assoc->init->charneg_response;
1526 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1527 strcat(options, " negotiation");
1530 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1532 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1533 assoc->version = 2; /* 1 & 2 are equivalent */
1535 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1537 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1540 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1542 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1546 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1547 assoc->maximumRecordSize = *req->maximumRecordSize;
1548 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1549 assoc->maximumRecordSize = control_block->maxrecordsize;
1550 assoc->preferredMessageSize = *req->preferredMessageSize;
1551 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1552 assoc->preferredMessageSize = assoc->maximumRecordSize;
1554 resp->preferredMessageSize = &assoc->preferredMessageSize;
1555 resp->maximumRecordSize = &assoc->maximumRecordSize;
1557 resp->implementationId = odr_prepend(assoc->encode,
1558 assoc->init->implementation_id,
1559 resp->implementationId);
1561 resp->implementationName = odr_prepend(assoc->encode,
1562 assoc->init->implementation_name,
1563 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1565 version = odr_strdup(assoc->encode, "$Revision: 1.10 $");
1566 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1567 version[strlen(version)-2] = '\0';
1568 resp->implementationVersion = odr_prepend(assoc->encode,
1569 assoc->init->implementation_version,
1570 odr_prepend(assoc->encode, &version[11],
1571 resp->implementationVersion));
1573 if (binitres->errcode)
1575 yaz_log(LOG_LOG, "Connection rejected by backend.");
1577 assoc->state = ASSOC_DEAD;
1578 resp->userInformationField = init_diagnostics(assoc->encode,
1580 binitres->errstring);
1583 assoc->state = ASSOC_UP;
1588 * Diagnostic in default format, to be returned as either a surrogate
1589 * or non-surrogate diagnostic in the context of an open session, or
1590 * as User-information when an Init is refused.
1592 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1594 int *err = odr_intdup(odr, error);
1595 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1596 odr_malloc (odr, sizeof(*dr));
1598 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1599 addinfo ? " -- " : "", addinfo ? addinfo : "");
1601 dr->diagnosticSetId =
1602 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1603 dr->condition = err;
1604 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1605 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1610 * Set the specified `errcode' and `errstring' into a UserInfo-1
1611 * external to be returned to the client in accordance with Z35.90
1612 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1613 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1615 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1619 Z_OtherInformation *u;
1620 Z_OtherInformationUnit *l;
1621 Z_DiagnosticFormat *d;
1622 Z_DiagnosticFormat_s *e;
1624 x = (Z_External*) odr_malloc(odr, sizeof *x);
1626 x->indirect_reference = 0;
1627 oid.proto = PROTO_Z3950;
1628 oid.oclass = CLASS_USERINFO;
1629 oid.value = VAL_USERINFO1;
1630 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1631 x->which = Z_External_userInfo1;
1633 u = odr_malloc(odr, sizeof *u);
1635 u->num_elements = 1;
1636 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1637 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1640 l->which = Z_OtherInfo_externallyDefinedInfo;
1642 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1643 l->information.externallyDefinedInfo = x2;
1645 x2->indirect_reference = 0;
1646 oid.oclass = CLASS_DIAGSET;
1647 oid.value = VAL_DIAG1;
1648 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1649 x2->which = Z_External_diag1;
1651 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1654 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1655 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1658 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1659 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1664 * nonsurrogate diagnostic record.
1666 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1668 Z_Records *rec = (Z_Records *)
1669 odr_malloc (assoc->encode, sizeof(*rec));
1670 rec->which = Z_Records_NSD;
1671 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1676 * surrogate diagnostic.
1678 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1679 int error, char *addinfo)
1681 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1682 odr_malloc (assoc->encode, sizeof(*rec));
1683 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1685 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1686 rec->databaseName = dbname;
1687 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1688 rec->u.surrogateDiagnostic = drec;
1689 drec->which = Z_DiagRec_defaultFormat;
1690 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1696 * multiple nonsurrogate diagnostics.
1698 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1700 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1701 int *err = odr_intdup(assoc->encode, error);
1702 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1703 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1704 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1705 odr_malloc (assoc->encode, sizeof(*rec));
1707 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1709 recs->num_diagRecs = 1;
1710 recs->diagRecs = recp;
1712 drec->which = Z_DiagRec_defaultFormat;
1713 drec->u.defaultFormat = rec;
1715 rec->diagnosticSetId =
1716 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1717 rec->condition = err;
1719 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1720 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1724 static Z_Records *pack_records(association *a, char *setname, int start,
1725 int *num, Z_RecordComposition *comp,
1726 int *next, int *pres, oid_value format,
1727 Z_ReferenceId *referenceId,
1730 int recno, total_length = 0, toget = *num, dumped_records = 0;
1731 Z_Records *records =
1732 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1733 Z_NamePlusRecordList *reclist =
1734 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1735 Z_NamePlusRecord **list =
1736 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1738 records->which = Z_Records_DBOSD;
1739 records->u.databaseOrSurDiagnostics = reclist;
1740 reclist->num_records = 0;
1741 reclist->records = list;
1742 *pres = Z_PRES_SUCCESS;
1746 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1747 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1748 a->maximumRecordSize);
1749 for (recno = start; reclist->num_records < toget; recno++)
1752 Z_NamePlusRecord *thisrec;
1753 int this_length = 0;
1755 * we get the number of bytes allocated on the stream before any
1756 * allocation done by the backend - this should give us a reasonable
1757 * idea of the total size of the data so far.
1759 total_length = odr_total(a->encode) - dumped_records;
1765 freq.last_in_set = 0;
1766 freq.setname = setname;
1767 freq.surrogate_flag = 0;
1768 freq.number = recno;
1770 freq.request_format = format;
1771 freq.request_format_raw = oid;
1772 freq.output_format = format;
1773 freq.output_format_raw = 0;
1774 freq.stream = a->encode;
1775 freq.print = a->print;
1776 freq.referenceId = referenceId;
1778 (*a->init->bend_fetch)(a->backend, &freq);
1779 /* backend should be able to signal whether error is system-wide
1780 or only pertaining to current record */
1783 if (!freq.surrogate_flag)
1786 *pres = Z_PRES_FAILURE;
1787 /* for 'present request out of range',
1788 set addinfo to record position if not set */
1789 if (freq.errcode == 13 && freq.errstring == 0)
1791 sprintf (s, "%d", recno);
1794 return diagrec(a, freq.errcode, freq.errstring);
1796 reclist->records[reclist->num_records] =
1797 surrogatediagrec(a, freq.basename, freq.errcode,
1799 reclist->num_records++;
1800 *next = freq.last_in_set ? 0 : recno + 1;
1804 this_length = freq.len;
1806 this_length = odr_total(a->encode) - total_length - dumped_records;
1807 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1808 this_length, total_length, dumped_records);
1809 if (this_length + total_length > a->preferredMessageSize)
1811 /* record is small enough, really */
1812 if (this_length <= a->preferredMessageSize && recno > start)
1814 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1815 *pres = Z_PRES_PARTIAL_2;
1818 /* record can only be fetched by itself */
1819 if (this_length < a->maximumRecordSize)
1821 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1824 yaz_log(LOG_DEBUG, " Dropped it");
1825 reclist->records[reclist->num_records] =
1826 surrogatediagrec(a, freq.basename, 16, 0);
1827 reclist->num_records++;
1828 *next = freq.last_in_set ? 0 : recno + 1;
1829 dumped_records += this_length;
1833 else /* too big entirely */
1835 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1836 reclist->records[reclist->num_records] =
1837 surrogatediagrec(a, freq.basename, 17, 0);
1838 reclist->num_records++;
1839 *next = freq.last_in_set ? 0 : recno + 1;
1840 dumped_records += this_length;
1845 if (!(thisrec = (Z_NamePlusRecord *)
1846 odr_malloc(a->encode, sizeof(*thisrec))))
1848 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1849 strlen(freq.basename) + 1)))
1851 strcpy(thisrec->databaseName, freq.basename);
1852 thisrec->which = Z_NamePlusRecord_databaseRecord;
1854 if (freq.output_format_raw)
1856 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1857 freq.output_format = ident->value;
1859 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1860 freq.record, freq.len);
1861 if (!thisrec->u.databaseRecord)
1863 reclist->records[reclist->num_records] = thisrec;
1864 reclist->num_records++;
1865 *next = freq.last_in_set ? 0 : recno + 1;
1867 *num = reclist->num_records;
1871 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1874 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1875 bend_search_rr *bsrr =
1876 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1878 yaz_log(LOG_LOG, "Got SearchRequest.");
1880 bsrr->request = reqb;
1881 bsrr->association = assoc;
1882 bsrr->referenceId = req->referenceId;
1883 save_referenceId (reqb, bsrr->referenceId);
1885 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1886 if (req->databaseNames)
1889 for (i = 0; i < req->num_databaseNames; i++)
1890 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1892 yaz_log_zquery(req->query);
1894 if (assoc->init->bend_search)
1896 bsrr->setname = req->resultSetName;
1897 bsrr->replace_set = *req->replaceIndicator;
1898 bsrr->num_bases = req->num_databaseNames;
1899 bsrr->basenames = req->databaseNames;
1900 bsrr->query = req->query;
1901 bsrr->stream = assoc->encode;
1902 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1903 bsrr->decode = assoc->decode;
1904 bsrr->print = assoc->print;
1907 bsrr->errstring = NULL;
1908 bsrr->search_info = NULL;
1909 (assoc->init->bend_search)(assoc->backend, bsrr);
1913 return response_searchRequest(assoc, reqb, bsrr, fd);
1916 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1919 * Prepare a searchresponse based on the backend results. We probably want
1920 * to look at making the fetching of records nonblocking as well, but
1921 * so far, we'll keep things simple.
1922 * If bsrt is null, that means we're called in response to a communications
1923 * event, and we'll have to get the response for ourselves.
1925 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1926 bend_search_rr *bsrt, int *fd)
1928 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1929 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1930 Z_SearchResponse *resp = (Z_SearchResponse *)
1931 odr_malloc (assoc->encode, sizeof(*resp));
1932 int *nulint = odr_intdup (assoc->encode, 0);
1933 bool_t *sr = odr_intdup(assoc->encode, 1);
1934 int *next = odr_intdup(assoc->encode, 0);
1935 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1937 apdu->which = Z_APDU_searchResponse;
1938 apdu->u.searchResponse = resp;
1939 resp->referenceId = req->referenceId;
1940 resp->additionalSearchInfo = 0;
1941 resp->otherInfo = 0;
1943 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1945 yaz_log(LOG_FATAL, "Bad result from backend");
1948 else if (bsrt->errcode)
1950 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1951 resp->resultCount = nulint;
1952 resp->numberOfRecordsReturned = nulint;
1953 resp->nextResultSetPosition = nulint;
1954 resp->searchStatus = nulint;
1955 resp->resultSetStatus = none;
1956 resp->presentStatus = 0;
1960 int *toget = odr_intdup(assoc->encode, 0);
1961 int *presst = odr_intdup(assoc->encode, 0);
1962 Z_RecordComposition comp, *compp = 0;
1964 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1967 resp->resultCount = &bsrt->hits;
1969 comp.which = Z_RecordComp_simple;
1970 /* how many records does the user agent want, then? */
1971 if (bsrt->hits <= *req->smallSetUpperBound)
1973 *toget = bsrt->hits;
1974 if ((comp.u.simple = req->smallSetElementSetNames))
1977 else if (bsrt->hits < *req->largeSetLowerBound)
1979 *toget = *req->mediumSetPresentNumber;
1980 if (*toget > bsrt->hits)
1981 *toget = bsrt->hits;
1982 if ((comp.u.simple = req->mediumSetElementSetNames))
1988 if (*toget && !resp->records)
1993 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1996 form = prefformat->value;
1997 resp->records = pack_records(assoc, req->resultSetName, 1,
1998 toget, compp, next, presst, form, req->referenceId,
1999 req->preferredRecordSyntax);
2002 resp->numberOfRecordsReturned = toget;
2003 resp->nextResultSetPosition = next;
2004 resp->searchStatus = sr;
2005 resp->resultSetStatus = 0;
2006 resp->presentStatus = presst;
2010 if (*resp->resultCount)
2012 resp->numberOfRecordsReturned = nulint;
2013 resp->nextResultSetPosition = next;
2014 resp->searchStatus = sr;
2015 resp->resultSetStatus = 0;
2016 resp->presentStatus = 0;
2019 resp->additionalSearchInfo = bsrt->search_info;
2024 * Maybe we got a little over-friendly when we designed bend_fetch to
2025 * get only one record at a time. Some backends can optimise multiple-record
2026 * fetches, and at any rate, there is some overhead involved in
2027 * all that selecting and hopping around. Problem is, of course, that the
2028 * frontend can't know ahead of time how many records it'll need to
2029 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2030 * is downright lousy as a bulk data transfer protocol.
2032 * To start with, we'll do the fetching of records from the backend
2033 * in one operation: To save some trips in and out of the event-handler,
2034 * and to simplify the interface to pack_records. At any rate, asynch
2035 * operation is more fun in operations that have an unpredictable execution
2036 * speed - which is normally more true for search than for present.
2038 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2041 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2045 Z_PresentResponse *resp;
2049 yaz_log(LOG_LOG, "Got PresentRequest.");
2051 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2054 form = prefformat->value;
2055 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2057 resp->presentStatus = odr_intdup(assoc->encode, 0);
2058 if (assoc->init->bend_present)
2060 bend_present_rr *bprr = (bend_present_rr *)
2061 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2062 bprr->setname = req->resultSetId;
2063 bprr->start = *req->resultSetStartPoint;
2064 bprr->number = *req->numberOfRecordsRequested;
2065 bprr->format = form;
2066 bprr->comp = req->recordComposition;
2067 bprr->referenceId = req->referenceId;
2068 bprr->stream = assoc->encode;
2069 bprr->print = assoc->print;
2070 bprr->request = reqb;
2071 bprr->association = assoc;
2073 bprr->errstring = NULL;
2074 (*assoc->init->bend_present)(assoc->backend, bprr);
2080 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2081 *resp->presentStatus = Z_PRES_FAILURE;
2084 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2085 next = odr_intdup(assoc->encode, 0);
2086 num = odr_intdup(assoc->encode, 0);
2088 apdu->which = Z_APDU_presentResponse;
2089 apdu->u.presentResponse = resp;
2090 resp->referenceId = req->referenceId;
2091 resp->otherInfo = 0;
2095 *num = *req->numberOfRecordsRequested;
2097 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2098 num, req->recordComposition, next, resp->presentStatus,
2099 form, req->referenceId, req->preferredRecordSyntax);
2103 resp->numberOfRecordsReturned = num;
2104 resp->nextResultSetPosition = next;
2110 * Scan was implemented rather in a hurry, and with support for only the basic
2111 * elements of the service in the backend API. Suggestions are welcome.
2113 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2115 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2116 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2117 Z_ScanResponse *res = (Z_ScanResponse *)
2118 odr_malloc (assoc->encode, sizeof(*res));
2119 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2120 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2121 Z_ListEntries *ents = (Z_ListEntries *)
2122 odr_malloc (assoc->encode, sizeof(*ents));
2123 Z_DiagRecs *diagrecs_p = NULL;
2125 bend_scan_rr *bsrr = (bend_scan_rr *)
2126 odr_malloc (assoc->encode, sizeof(*bsrr));
2127 struct scan_entry *save_entries;
2129 yaz_log(LOG_LOG, "Got ScanRequest");
2131 apdu->which = Z_APDU_scanResponse;
2132 apdu->u.scanResponse = res;
2133 res->referenceId = req->referenceId;
2135 /* if step is absent, set it to 0 */
2136 res->stepSize = odr_intdup(assoc->encode, 0);
2138 *res->stepSize = *req->stepSize;
2140 res->scanStatus = scanStatus;
2141 res->numberOfEntriesReturned = numberOfEntriesReturned;
2142 res->positionOfTerm = 0;
2143 res->entries = ents;
2144 ents->num_entries = 0;
2145 ents->entries = NULL;
2146 ents->num_nonsurrogateDiagnostics = 0;
2147 ents->nonsurrogateDiagnostics = NULL;
2148 res->attributeSet = 0;
2151 if (req->databaseNames)
2154 for (i = 0; i < req->num_databaseNames; i++)
2155 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2157 bsrr->num_bases = req->num_databaseNames;
2158 bsrr->basenames = req->databaseNames;
2159 bsrr->num_entries = *req->numberOfTermsRequested;
2160 bsrr->term = req->termListAndStartPoint;
2161 bsrr->referenceId = req->referenceId;
2162 bsrr->stream = assoc->encode;
2163 bsrr->print = assoc->print;
2164 bsrr->step_size = res->stepSize;
2166 /* Note that version 2.0 of YAZ and older did not set entries ..
2167 We do now. And when we do it's easier to extend the scan entry
2168 We know that if the scan handler did set entries, it will
2169 not know of new member display_term.
2171 if (bsrr->num_entries > 0)
2174 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2176 for (i = 0; i<bsrr->num_entries; i++)
2178 bsrr->entries[i].term = 0;
2179 bsrr->entries[i].occurrences = 0;
2180 bsrr->entries[i].errcode = 0;
2181 bsrr->entries[i].errstring = 0;
2182 bsrr->entries[i].display_term = 0;
2185 save_entries = bsrr->entries; /* save it so we can compare later */
2187 if (req->attributeSet &&
2188 (attset = oid_getentbyoid(req->attributeSet)) &&
2189 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2190 bsrr->attributeset = attset->value;
2192 bsrr->attributeset = VAL_NONE;
2193 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2194 bsrr->term_position = req->preferredPositionInResponse ?
2195 *req->preferredPositionInResponse : 1;
2196 ((int (*)(void *, bend_scan_rr *))
2197 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2199 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2203 Z_Entry **tab = (Z_Entry **)
2204 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2206 if (bsrr->status == BEND_SCAN_PARTIAL)
2207 *scanStatus = Z_Scan_partial_5;
2209 *scanStatus = Z_Scan_success;
2210 ents->entries = tab;
2211 ents->num_entries = bsrr->num_entries;
2212 res->numberOfEntriesReturned = &ents->num_entries;
2213 res->positionOfTerm = &bsrr->term_position;
2214 for (i = 0; i < bsrr->num_entries; i++)
2220 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2221 if (bsrr->entries[i].occurrences >= 0)
2223 e->which = Z_Entry_termInfo;
2224 e->u.termInfo = t = (Z_TermInfo *)
2225 odr_malloc(assoc->encode, sizeof(*t));
2226 t->suggestedAttributes = 0;
2228 if (save_entries == bsrr->entries &&
2229 bsrr->entries[i].display_term)
2231 /* the entries was NOT set by the handler. So it's
2232 safe to test for new member display_term. It is
2235 t->displayTerm = odr_strdup(assoc->encode,
2236 bsrr->entries[i].display_term);
2238 t->alternativeTerm = 0;
2239 t->byAttributes = 0;
2240 t->otherTermInfo = 0;
2241 t->globalOccurrences = &bsrr->entries[i].occurrences;
2242 t->term = (Z_Term *)
2243 odr_malloc(assoc->encode, sizeof(*t->term));
2244 t->term->which = Z_Term_general;
2245 t->term->u.general = o =
2246 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2247 o->buf = (unsigned char *)
2248 odr_malloc(assoc->encode, o->len = o->size =
2249 strlen(bsrr->entries[i].term));
2250 memcpy(o->buf, bsrr->entries[i].term, o->len);
2251 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2252 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2256 Z_DiagRecs *drecs = diagrecs (assoc,
2257 bsrr->entries[i].errcode,
2258 bsrr->entries[i].errstring);
2259 assert (drecs->num_diagRecs == 1);
2260 e->which = Z_Entry_surrogateDiagnostic;
2261 assert (drecs->diagRecs[0]);
2262 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2268 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2269 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2274 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2277 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2278 Z_SortResponse *res = (Z_SortResponse *)
2279 odr_malloc (assoc->encode, sizeof(*res));
2280 bend_sort_rr *bsrr = (bend_sort_rr *)
2281 odr_malloc (assoc->encode, sizeof(*bsrr));
2283 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2285 yaz_log(LOG_LOG, "Got SortRequest.");
2287 bsrr->num_input_setnames = req->num_inputResultSetNames;
2288 bsrr->input_setnames = req->inputResultSetNames;
2289 bsrr->referenceId = req->referenceId;
2290 bsrr->output_setname = req->sortedResultSetName;
2291 bsrr->sort_sequence = req->sortSequence;
2292 bsrr->stream = assoc->encode;
2293 bsrr->print = assoc->print;
2295 bsrr->sort_status = Z_SortStatus_failure;
2297 bsrr->errstring = 0;
2299 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2301 res->referenceId = bsrr->referenceId;
2302 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2303 res->resultSetStatus = 0;
2306 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2307 res->diagnostics = dr->diagRecs;
2308 res->num_diagnostics = dr->num_diagRecs;
2312 res->num_diagnostics = 0;
2313 res->diagnostics = 0;
2315 res->resultCount = 0;
2318 apdu->which = Z_APDU_sortResponse;
2319 apdu->u.sortResponse = res;
2323 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2326 Z_DeleteResultSetRequest *req =
2327 reqb->apdu_request->u.deleteResultSetRequest;
2328 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2329 odr_malloc (assoc->encode, sizeof(*res));
2330 bend_delete_rr *bdrr = (bend_delete_rr *)
2331 odr_malloc (assoc->encode, sizeof(*bdrr));
2332 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2334 yaz_log(LOG_LOG, "Got DeleteRequest.");
2336 bdrr->num_setnames = req->num_resultSetList;
2337 bdrr->setnames = req->resultSetList;
2338 bdrr->stream = assoc->encode;
2339 bdrr->print = assoc->print;
2340 bdrr->function = *req->deleteFunction;
2341 bdrr->referenceId = req->referenceId;
2343 if (bdrr->num_setnames > 0)
2346 bdrr->statuses = (int*)
2347 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2348 bdrr->num_setnames);
2349 for (i = 0; i < bdrr->num_setnames; i++)
2350 bdrr->statuses[i] = 0;
2352 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2354 res->referenceId = req->referenceId;
2356 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2358 res->deleteListStatuses = 0;
2359 if (bdrr->num_setnames > 0)
2362 res->deleteListStatuses = (Z_ListStatuses *)
2363 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2364 res->deleteListStatuses->num = bdrr->num_setnames;
2365 res->deleteListStatuses->elements =
2367 odr_malloc (assoc->encode,
2368 sizeof(*res->deleteListStatuses->elements) *
2369 bdrr->num_setnames);
2370 for (i = 0; i<bdrr->num_setnames; i++)
2372 res->deleteListStatuses->elements[i] =
2374 odr_malloc (assoc->encode,
2375 sizeof(**res->deleteListStatuses->elements));
2376 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2377 res->deleteListStatuses->elements[i]->id =
2378 odr_strdup (assoc->encode, bdrr->setnames[i]);
2382 res->numberNotDeleted = 0;
2383 res->bulkStatuses = 0;
2384 res->deleteMessage = 0;
2387 apdu->which = Z_APDU_deleteResultSetResponse;
2388 apdu->u.deleteResultSetResponse = res;
2392 static void process_close(association *assoc, request *reqb)
2394 Z_Close *req = reqb->apdu_request->u.close;
2395 static char *reasons[] =
2402 "securityViolation",
2409 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2410 reasons[*req->closeReason], req->diagnosticInformation ?
2411 req->diagnosticInformation : "NULL");
2412 if (assoc->version < 3) /* to make do_force respond with close */
2414 do_close_req(assoc, Z_Close_finished,
2415 "Association terminated by client", reqb);
2418 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2422 reqb->len_refid = refid->len;
2423 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2424 memcpy (reqb->refid, refid->buf, refid->len);
2428 reqb->len_refid = 0;
2433 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2435 process_z_response (a, req, res);
2438 bend_request bend_request_mk (bend_association a)
2440 request *nreq = request_get (&a->outgoing);
2441 nreq->request_mem = nmem_create ();
2445 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2450 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2451 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2452 id->len = id->size = req->len_refid;
2453 memcpy (id->buf, req->refid, req->len_refid);
2457 void bend_request_destroy (bend_request *req)
2459 nmem_destroy((*req)->request_mem);
2460 request_release(*req);
2464 int bend_backend_respond (bend_association a, bend_request req)
2468 r = process_z_request (a, req, &msg);
2470 yaz_log (LOG_WARN, "%s", msg);
2474 void bend_request_setdata(bend_request r, void *p)
2479 void *bend_request_getdata(bend_request r)
2481 return r->clientData;
2484 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2486 bend_segment_rr req;
2488 req.segment = reqb->apdu_request->u.segmentRequest;
2489 req.stream = assoc->encode;
2490 req.decode = assoc->decode;
2491 req.print = assoc->print;
2492 req.association = assoc;
2494 (*assoc->init->bend_segment)(assoc->backend, &req);
2499 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2501 bend_esrequest_rr esrequest;
2503 Z_ExtendedServicesRequest *req =
2504 reqb->apdu_request->u.extendedServicesRequest;
2505 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2507 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2509 yaz_log(LOG_DEBUG,"inside Process esRequest");
2511 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2512 esrequest.stream = assoc->encode;
2513 esrequest.decode = assoc->decode;
2514 esrequest.print = assoc->print;
2515 esrequest.errcode = 0;
2516 esrequest.errstring = NULL;
2517 esrequest.request = reqb;
2518 esrequest.association = assoc;
2519 esrequest.taskPackage = 0;
2520 esrequest.referenceId = req->referenceId;
2522 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2524 /* If the response is being delayed, return NULL */
2525 if (esrequest.request == NULL)
2528 resp->referenceId = req->referenceId;
2530 if (esrequest.errcode == -1)
2532 /* Backend service indicates request will be processed */
2533 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2534 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2536 else if (esrequest.errcode == 0)
2538 /* Backend service indicates request will be processed */
2539 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2540 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2544 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2545 esrequest.errstring);
2547 /* Backend indicates error, request will not be processed */
2548 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2549 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2550 resp->num_diagnostics = diagRecs->num_diagRecs;
2551 resp->diagnostics = diagRecs->diagRecs;
2553 /* Do something with the members of bend_extendedservice */
2554 if (esrequest.taskPackage)
2555 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2556 (const char *) esrequest.taskPackage,
2558 yaz_log(LOG_DEBUG,"Send the result apdu");