2 * Copyright (c) 1995-2003, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.9 2003-12-29 14:54:33 adam Exp $
9 * Frontend server logic.
11 * This code receives incoming APDUs, and handles client requests by means
14 * Some of the code is getting quite involved, compared to simpler servers -
15 * primarily because it is asynchronous both in the communication with
16 * the user and the backend. We think the complexity will pay off in
17 * the form of greater flexibility when more asynchronous facilities
20 * Memory management has become somewhat involved. In the simple case, where
21 * only one PDU is pending at a time, it will simply reuse the same memory,
22 * once it has found its working size. When we enable multiple concurrent
23 * operations, perhaps even with multiple parallel calls to the backend, it
24 * will maintain a pool of buffers for encoding and decoding, trying to
25 * minimize memory allocation/deallocation during normal operation.
31 #include <sys/types.h>
34 #define S_ISREG(x) (x & _S_IFREG)
44 #include <yaz/yconfig.h>
45 #include <yaz/xmalloc.h>
46 #include <yaz/comstack.h>
49 #include <yaz/proto.h>
52 #include <yaz/logrpn.h>
53 #include <yaz/statserv.h>
54 #include <yaz/diagbib1.h>
55 #include <yaz/charneg.h>
56 #include <yaz/otherinfo.h>
57 #include <yaz/yaz-util.h>
58 #include <yaz/pquery.h>
61 #include <yaz/backend.h>
63 static void process_gdu_request(association *assoc, request *req);
64 static int process_z_request(association *assoc, request *req, char **msg);
65 void backend_response(IOCHAN i, int event);
66 static int process_gdu_response(association *assoc, request *req, Z_GDU *res);
67 static int process_z_response(association *assoc, request *req, Z_APDU *res);
68 static Z_APDU *process_initRequest(association *assoc, request *reqb);
69 static Z_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[2] = {
1033 {"http://www.loc.gov/zing/srw/", 0,
1034 (Z_SOAP_fun) yaz_srw_codec},
1038 if ((charset_p = strstr(content_type, "; charset=")))
1042 while (i < 20 && charset_p[i] &&
1043 !strchr("; \n\r", charset_p[i]))
1045 charset = odr_malloc(assoc->encode, i+1);
1046 memcpy(charset, charset_p, i);
1048 yaz_log(LOG_LOG, "SOAP encoding %s", charset);
1050 ret = z_soap_codec(assoc->decode, &soap_package,
1051 &hreq->content_buf, &hreq->content_len,
1054 if (!ret && soap_package->which == Z_SOAP_generic &&
1055 soap_package->u.generic->no == 0)
1058 char *db = "Default";
1059 const char *p0 = hreq->path, *p1;
1060 Z_SRW_PDU *sr = soap_package->u.generic->p;
1064 p1 = strchr(p0, '?');
1066 p1 = p0 + strlen(p0);
1069 db = (char*) odr_malloc(assoc->decode, p1 - p0 + 1);
1070 memcpy (db, p0, p1 - p0);
1074 if (sr->which == Z_SRW_searchRetrieve_request)
1077 yaz_srw_get(assoc->encode,
1078 Z_SRW_searchRetrieve_response);
1080 if (!sr->u.request->database)
1081 sr->u.request->database = db;
1083 srw_bend_search(assoc, req, sr->u.request,
1084 res->u.response, &http_code);
1086 soap_package->u.generic->p = res;
1088 else if (sr->which == Z_SRW_explain_request)
1091 yaz_srw_get(assoc->encode, Z_SRW_explain_response);
1092 sr->u.explain_request->database = db;
1094 srw_bend_explain(assoc, req, sr->u.explain_request,
1095 res->u.explain_response, &http_code);
1096 if (http_code == 200)
1097 soap_package->u.generic->p = res;
1101 z_soap_error(assoc->encode, soap_package,
1102 "SOAP-ENV:Client", "Bad method", 0);
1106 if (http_code == 200 || http_code == 500)
1108 p = z_get_HTTP_Response(o, 200);
1109 hres = p->u.HTTP_Response;
1110 ret = z_soap_codec_enc(assoc->encode, &soap_package,
1111 &hres->content_buf, &hres->content_len,
1112 soap_handlers, charset);
1113 hres->code = http_code;
1115 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
1119 strcpy(ctype, "text/xml; charset=");
1120 strcat(ctype, charset);
1121 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1125 p = z_get_HTTP_Response(o, http_code);
1127 if (!p) /* still no response ? */
1128 p = z_get_HTTP_Response(o, 500);
1132 p = z_get_HTTP_Response(o, 405);
1133 hres = p->u.HTTP_Response;
1135 z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
1137 hres = p->u.HTTP_Response;
1138 if (!strcmp(hreq->version, "1.0"))
1140 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1141 if (v && !strcmp(v, "Keep-Alive"))
1145 hres->version = "1.0";
1149 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1150 if (v && !strcmp(v, "close"))
1154 hres->version = "1.1";
1158 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1159 assoc->state = ASSOC_DEAD;
1164 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1166 if (alive && isdigit(*alive))
1170 if (t < 0 || t > 3600)
1172 iochan_settimeout(assoc->client_chan,t);
1173 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1175 process_gdu_response(assoc, req, p);
1178 static void process_gdu_request(association *assoc, request *req)
1180 if (req->gdu_request->which == Z_GDU_Z3950)
1183 req->apdu_request = req->gdu_request->u.z3950;
1184 if (process_z_request(assoc, req, &msg) < 0)
1185 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1187 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1188 process_http_request(assoc, req);
1191 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1196 * Initiate request processing.
1198 static int process_z_request(association *assoc, request *req, char **msg)
1204 *msg = "Unknown Error";
1205 assert(req && req->state == REQUEST_IDLE);
1206 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1208 *msg = "Missing InitRequest";
1211 switch (req->apdu_request->which)
1213 case Z_APDU_initRequest:
1214 iochan_settimeout(assoc->client_chan,
1215 statserv_getcontrol()->idle_timeout * 60);
1216 res = process_initRequest(assoc, req); break;
1217 case Z_APDU_searchRequest:
1218 res = process_searchRequest(assoc, req, &fd); break;
1219 case Z_APDU_presentRequest:
1220 res = process_presentRequest(assoc, req, &fd); break;
1221 case Z_APDU_scanRequest:
1222 if (assoc->init->bend_scan)
1223 res = process_scanRequest(assoc, req, &fd);
1226 *msg = "Cannot handle Scan APDU";
1230 case Z_APDU_extendedServicesRequest:
1231 if (assoc->init->bend_esrequest)
1232 res = process_ESRequest(assoc, req, &fd);
1235 *msg = "Cannot handle Extended Services APDU";
1239 case Z_APDU_sortRequest:
1240 if (assoc->init->bend_sort)
1241 res = process_sortRequest(assoc, req, &fd);
1244 *msg = "Cannot handle Sort APDU";
1249 process_close(assoc, req);
1251 case Z_APDU_deleteResultSetRequest:
1252 if (assoc->init->bend_delete)
1253 res = process_deleteRequest(assoc, req, &fd);
1256 *msg = "Cannot handle Delete APDU";
1260 case Z_APDU_segmentRequest:
1261 if (assoc->init->bend_segment)
1263 res = process_segmentRequest (assoc, req);
1267 *msg = "Cannot handle Segment APDU";
1272 *msg = "Bad APDU received";
1277 yaz_log(LOG_DEBUG, " result immediately available");
1278 retval = process_z_response(assoc, req, res);
1282 yaz_log(LOG_DEBUG, " result unavailble");
1285 else /* no result yet - one will be provided later */
1289 /* Set up an I/O handler for the fd supplied by the backend */
1291 yaz_log(LOG_DEBUG, " establishing handler for result");
1292 req->state = REQUEST_PENDING;
1293 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1295 iochan_setdata(chan, assoc);
1302 * Handle message from the backend.
1304 void backend_response(IOCHAN i, int event)
1306 association *assoc = (association *)iochan_getdata(i);
1307 request *req = request_head(&assoc->incoming);
1311 yaz_log(LOG_DEBUG, "backend_response");
1312 assert(assoc && req && req->state != REQUEST_IDLE);
1313 /* determine what it is we're waiting for */
1314 switch (req->apdu_request->which)
1316 case Z_APDU_searchRequest:
1317 res = response_searchRequest(assoc, req, 0, &fd); break;
1319 case Z_APDU_presentRequest:
1320 res = response_presentRequest(assoc, req, 0, &fd); break;
1321 case Z_APDU_scanRequest:
1322 res = response_scanRequest(assoc, req, 0, &fd); break;
1325 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1328 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1330 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1331 do_close(assoc, Z_Close_systemProblem, 0);
1335 else if (!res) /* no result yet - try again later */
1337 yaz_log(LOG_DEBUG, " no result yet");
1338 iochan_setfd(i, fd); /* in case fd has changed */
1343 * Encode response, and transfer the request structure to the outgoing queue.
1345 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1347 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1349 if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
1351 yaz_log(LOG_WARN, "ODR print error: %s",
1352 odr_errmsg(odr_geterror(assoc->print)));
1353 odr_reset(assoc->print);
1355 if (!z_GDU(assoc->encode, &res, 0, 0))
1357 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1358 odr_errmsg(odr_geterror(assoc->decode)),
1359 odr_getelement(assoc->decode));
1360 request_release(req);
1363 req->response = odr_getbuf(assoc->encode, &req->len_response,
1364 &req->size_response);
1365 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1366 odr_reset(assoc->encode);
1367 req->state = REQUEST_IDLE;
1368 request_enq(&assoc->outgoing, req);
1369 /* turn the work over to the ir_session handler */
1370 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1371 assoc->cs_put_mask = EVENT_OUTPUT;
1372 /* Is there more work to be done? give that to the input handler too */
1374 if (request_head(&assoc->incoming))
1376 yaz_log (LOG_DEBUG, "more work to be done");
1377 iochan_setevent(assoc->client_chan, EVENT_WORK);
1384 * Encode response, and transfer the request structure to the outgoing queue.
1386 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1388 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1389 gres->which = Z_GDU_Z3950;
1390 gres->u.z3950 = res;
1392 return process_gdu_response(assoc, req, gres);
1397 * Handle init request.
1398 * At the moment, we don't check the options
1399 * anywhere else in the code - we just try not to do anything that would
1400 * break a naive client. We'll toss 'em into the association block when
1401 * we need them there.
1403 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1405 statserv_options_block *cb = statserv_getcontrol();
1406 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1407 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1408 Z_InitResponse *resp = apdu->u.initResponse;
1409 bend_initresult *binitres;
1413 yaz_log(LOG_LOG, "Got initRequest");
1414 if (req->implementationId)
1415 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1416 if (req->implementationName)
1417 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1418 if (req->implementationVersion)
1419 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1421 assoc_init_reset(assoc);
1423 assoc->init->auth = req->idAuthentication;
1424 assoc->init->referenceId = req->referenceId;
1426 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1428 Z_CharSetandLanguageNegotiation *negotiation =
1429 yaz_get_charneg_record (req->otherInfo);
1430 if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1431 assoc->init->charneg_request = negotiation;
1434 if (!(binitres = (*cb->bend_init)(assoc->init)))
1436 yaz_log(LOG_WARN, "Bad response from backend.");
1440 assoc->backend = binitres->handle;
1441 if ((assoc->init->bend_sort))
1442 yaz_log (LOG_DEBUG, "Sort handler installed");
1443 if ((assoc->init->bend_search))
1444 yaz_log (LOG_DEBUG, "Search handler installed");
1445 if ((assoc->init->bend_present))
1446 yaz_log (LOG_DEBUG, "Present handler installed");
1447 if ((assoc->init->bend_esrequest))
1448 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1449 if ((assoc->init->bend_delete))
1450 yaz_log (LOG_DEBUG, "Delete handler installed");
1451 if ((assoc->init->bend_scan))
1452 yaz_log (LOG_DEBUG, "Scan handler installed");
1453 if ((assoc->init->bend_segment))
1454 yaz_log (LOG_DEBUG, "Segment handler installed");
1456 resp->referenceId = req->referenceId;
1458 /* let's tell the client what we can do */
1459 if (ODR_MASK_GET(req->options, Z_Options_search))
1461 ODR_MASK_SET(resp->options, Z_Options_search);
1462 strcat(options, "srch");
1464 if (ODR_MASK_GET(req->options, Z_Options_present))
1466 ODR_MASK_SET(resp->options, Z_Options_present);
1467 strcat(options, " prst");
1469 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1470 assoc->init->bend_delete)
1472 ODR_MASK_SET(resp->options, Z_Options_delSet);
1473 strcat(options, " del");
1475 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1476 assoc->init->bend_esrequest)
1478 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1479 strcat (options, " extendedServices");
1481 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1483 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1484 strcat(options, " namedresults");
1486 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1488 ODR_MASK_SET(resp->options, Z_Options_scan);
1489 strcat(options, " scan");
1491 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1493 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1494 strcat(options, " concurrop");
1496 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1498 ODR_MASK_SET(resp->options, Z_Options_sort);
1499 strcat(options, " sort");
1502 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1503 && assoc->init->charneg_response)
1505 Z_OtherInformation **p;
1506 Z_OtherInformationUnit *p0;
1508 yaz_oi_APDU(apdu, &p);
1510 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1511 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1513 p0->which = Z_OtherInfo_externallyDefinedInfo;
1514 p0->information.externallyDefinedInfo =
1515 assoc->init->charneg_response;
1517 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1518 strcat(options, " negotiation");
1521 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1523 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1524 assoc->version = 2; /* 1 & 2 are equivalent */
1526 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1528 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1531 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1533 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1537 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1538 assoc->maximumRecordSize = *req->maximumRecordSize;
1539 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1540 assoc->maximumRecordSize = control_block->maxrecordsize;
1541 assoc->preferredMessageSize = *req->preferredMessageSize;
1542 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1543 assoc->preferredMessageSize = assoc->maximumRecordSize;
1545 resp->preferredMessageSize = &assoc->preferredMessageSize;
1546 resp->maximumRecordSize = &assoc->maximumRecordSize;
1548 resp->implementationId = odr_prepend(assoc->encode,
1549 assoc->init->implementation_id,
1550 resp->implementationId);
1552 resp->implementationName = odr_prepend(assoc->encode,
1553 assoc->init->implementation_name,
1554 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1556 version = odr_strdup(assoc->encode, "$Revision: 1.9 $");
1557 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1558 version[strlen(version)-2] = '\0';
1559 resp->implementationVersion = odr_prepend(assoc->encode,
1560 assoc->init->implementation_version,
1561 odr_prepend(assoc->encode, &version[11],
1562 resp->implementationVersion));
1564 if (binitres->errcode)
1566 yaz_log(LOG_LOG, "Connection rejected by backend.");
1568 assoc->state = ASSOC_DEAD;
1569 resp->userInformationField = init_diagnostics(assoc->encode,
1571 binitres->errstring);
1574 assoc->state = ASSOC_UP;
1579 * Diagnostic in default format, to be returned as either a surrogate
1580 * or non-surrogate diagnostic in the context of an open session, or
1581 * as User-information when an Init is refused.
1583 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1585 int *err = odr_intdup(odr, error);
1586 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1587 odr_malloc (odr, sizeof(*dr));
1589 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1590 addinfo ? " -- " : "", addinfo ? addinfo : "");
1592 dr->diagnosticSetId =
1593 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1594 dr->condition = err;
1595 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1596 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1601 * Set the specified `errcode' and `errstring' into a UserInfo-1
1602 * external to be returned to the client in accordance with Z35.90
1603 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1604 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1606 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1610 Z_OtherInformation *u;
1611 Z_OtherInformationUnit *l;
1612 Z_DiagnosticFormat *d;
1613 Z_DiagnosticFormat_s *e;
1615 x = (Z_External*) odr_malloc(odr, sizeof *x);
1617 x->indirect_reference = 0;
1618 oid.proto = PROTO_Z3950;
1619 oid.oclass = CLASS_USERINFO;
1620 oid.value = VAL_USERINFO1;
1621 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1622 x->which = Z_External_userInfo1;
1624 u = odr_malloc(odr, sizeof *u);
1626 u->num_elements = 1;
1627 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1628 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1631 l->which = Z_OtherInfo_externallyDefinedInfo;
1633 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1634 l->information.externallyDefinedInfo = x2;
1636 x2->indirect_reference = 0;
1637 oid.oclass = CLASS_DIAGSET;
1638 oid.value = VAL_DIAG1;
1639 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1640 x2->which = Z_External_diag1;
1642 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1645 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1646 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1649 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1650 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1655 * nonsurrogate diagnostic record.
1657 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1659 Z_Records *rec = (Z_Records *)
1660 odr_malloc (assoc->encode, sizeof(*rec));
1661 rec->which = Z_Records_NSD;
1662 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1667 * surrogate diagnostic.
1669 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1670 int error, char *addinfo)
1672 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1673 odr_malloc (assoc->encode, sizeof(*rec));
1674 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1676 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1677 rec->databaseName = dbname;
1678 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1679 rec->u.surrogateDiagnostic = drec;
1680 drec->which = Z_DiagRec_defaultFormat;
1681 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1687 * multiple nonsurrogate diagnostics.
1689 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1691 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1692 int *err = odr_intdup(assoc->encode, error);
1693 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1694 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1695 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1696 odr_malloc (assoc->encode, sizeof(*rec));
1698 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1700 recs->num_diagRecs = 1;
1701 recs->diagRecs = recp;
1703 drec->which = Z_DiagRec_defaultFormat;
1704 drec->u.defaultFormat = rec;
1706 rec->diagnosticSetId =
1707 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1708 rec->condition = err;
1710 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1711 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1715 static Z_Records *pack_records(association *a, char *setname, int start,
1716 int *num, Z_RecordComposition *comp,
1717 int *next, int *pres, oid_value format,
1718 Z_ReferenceId *referenceId,
1721 int recno, total_length = 0, toget = *num, dumped_records = 0;
1722 Z_Records *records =
1723 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1724 Z_NamePlusRecordList *reclist =
1725 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1726 Z_NamePlusRecord **list =
1727 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1729 records->which = Z_Records_DBOSD;
1730 records->u.databaseOrSurDiagnostics = reclist;
1731 reclist->num_records = 0;
1732 reclist->records = list;
1733 *pres = Z_PRES_SUCCESS;
1737 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1738 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1739 a->maximumRecordSize);
1740 for (recno = start; reclist->num_records < toget; recno++)
1743 Z_NamePlusRecord *thisrec;
1744 int this_length = 0;
1746 * we get the number of bytes allocated on the stream before any
1747 * allocation done by the backend - this should give us a reasonable
1748 * idea of the total size of the data so far.
1750 total_length = odr_total(a->encode) - dumped_records;
1756 freq.last_in_set = 0;
1757 freq.setname = setname;
1758 freq.surrogate_flag = 0;
1759 freq.number = recno;
1761 freq.request_format = format;
1762 freq.request_format_raw = oid;
1763 freq.output_format = format;
1764 freq.output_format_raw = 0;
1765 freq.stream = a->encode;
1766 freq.print = a->print;
1767 freq.referenceId = referenceId;
1769 (*a->init->bend_fetch)(a->backend, &freq);
1770 /* backend should be able to signal whether error is system-wide
1771 or only pertaining to current record */
1774 if (!freq.surrogate_flag)
1777 *pres = Z_PRES_FAILURE;
1778 /* for 'present request out of range',
1779 set addinfo to record position if not set */
1780 if (freq.errcode == 13 && freq.errstring == 0)
1782 sprintf (s, "%d", recno);
1785 return diagrec(a, freq.errcode, freq.errstring);
1787 reclist->records[reclist->num_records] =
1788 surrogatediagrec(a, freq.basename, freq.errcode,
1790 reclist->num_records++;
1791 *next = freq.last_in_set ? 0 : recno + 1;
1795 this_length = freq.len;
1797 this_length = odr_total(a->encode) - total_length - dumped_records;
1798 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1799 this_length, total_length, dumped_records);
1800 if (this_length + total_length > a->preferredMessageSize)
1802 /* record is small enough, really */
1803 if (this_length <= a->preferredMessageSize && recno > start)
1805 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1806 *pres = Z_PRES_PARTIAL_2;
1809 /* record can only be fetched by itself */
1810 if (this_length < a->maximumRecordSize)
1812 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1815 yaz_log(LOG_DEBUG, " Dropped it");
1816 reclist->records[reclist->num_records] =
1817 surrogatediagrec(a, freq.basename, 16, 0);
1818 reclist->num_records++;
1819 *next = freq.last_in_set ? 0 : recno + 1;
1820 dumped_records += this_length;
1824 else /* too big entirely */
1826 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1827 reclist->records[reclist->num_records] =
1828 surrogatediagrec(a, freq.basename, 17, 0);
1829 reclist->num_records++;
1830 *next = freq.last_in_set ? 0 : recno + 1;
1831 dumped_records += this_length;
1836 if (!(thisrec = (Z_NamePlusRecord *)
1837 odr_malloc(a->encode, sizeof(*thisrec))))
1839 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1840 strlen(freq.basename) + 1)))
1842 strcpy(thisrec->databaseName, freq.basename);
1843 thisrec->which = Z_NamePlusRecord_databaseRecord;
1845 if (freq.output_format_raw)
1847 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1848 freq.output_format = ident->value;
1850 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1851 freq.record, freq.len);
1852 if (!thisrec->u.databaseRecord)
1854 reclist->records[reclist->num_records] = thisrec;
1855 reclist->num_records++;
1856 *next = freq.last_in_set ? 0 : recno + 1;
1858 *num = reclist->num_records;
1862 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1865 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1866 bend_search_rr *bsrr =
1867 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1869 yaz_log(LOG_LOG, "Got SearchRequest.");
1871 bsrr->request = reqb;
1872 bsrr->association = assoc;
1873 bsrr->referenceId = req->referenceId;
1874 save_referenceId (reqb, bsrr->referenceId);
1876 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1877 if (req->databaseNames)
1880 for (i = 0; i < req->num_databaseNames; i++)
1881 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1883 yaz_log_zquery(req->query);
1885 if (assoc->init->bend_search)
1887 bsrr->setname = req->resultSetName;
1888 bsrr->replace_set = *req->replaceIndicator;
1889 bsrr->num_bases = req->num_databaseNames;
1890 bsrr->basenames = req->databaseNames;
1891 bsrr->query = req->query;
1892 bsrr->stream = assoc->encode;
1893 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1894 bsrr->decode = assoc->decode;
1895 bsrr->print = assoc->print;
1898 bsrr->errstring = NULL;
1899 bsrr->search_info = NULL;
1900 (assoc->init->bend_search)(assoc->backend, bsrr);
1904 return response_searchRequest(assoc, reqb, bsrr, fd);
1907 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1910 * Prepare a searchresponse based on the backend results. We probably want
1911 * to look at making the fetching of records nonblocking as well, but
1912 * so far, we'll keep things simple.
1913 * If bsrt is null, that means we're called in response to a communications
1914 * event, and we'll have to get the response for ourselves.
1916 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1917 bend_search_rr *bsrt, int *fd)
1919 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1920 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1921 Z_SearchResponse *resp = (Z_SearchResponse *)
1922 odr_malloc (assoc->encode, sizeof(*resp));
1923 int *nulint = odr_intdup (assoc->encode, 0);
1924 bool_t *sr = odr_intdup(assoc->encode, 1);
1925 int *next = odr_intdup(assoc->encode, 0);
1926 int *none = odr_intdup(assoc->encode, Z_RES_NONE);
1928 apdu->which = Z_APDU_searchResponse;
1929 apdu->u.searchResponse = resp;
1930 resp->referenceId = req->referenceId;
1931 resp->additionalSearchInfo = 0;
1932 resp->otherInfo = 0;
1934 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1936 yaz_log(LOG_FATAL, "Bad result from backend");
1939 else if (bsrt->errcode)
1941 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1942 resp->resultCount = nulint;
1943 resp->numberOfRecordsReturned = nulint;
1944 resp->nextResultSetPosition = nulint;
1945 resp->searchStatus = nulint;
1946 resp->resultSetStatus = none;
1947 resp->presentStatus = 0;
1951 int *toget = odr_intdup(assoc->encode, 0);
1952 int *presst = odr_intdup(assoc->encode, 0);
1953 Z_RecordComposition comp, *compp = 0;
1955 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1958 resp->resultCount = &bsrt->hits;
1960 comp.which = Z_RecordComp_simple;
1961 /* how many records does the user agent want, then? */
1962 if (bsrt->hits <= *req->smallSetUpperBound)
1964 *toget = bsrt->hits;
1965 if ((comp.u.simple = req->smallSetElementSetNames))
1968 else if (bsrt->hits < *req->largeSetLowerBound)
1970 *toget = *req->mediumSetPresentNumber;
1971 if (*toget > bsrt->hits)
1972 *toget = bsrt->hits;
1973 if ((comp.u.simple = req->mediumSetElementSetNames))
1979 if (*toget && !resp->records)
1984 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1987 form = prefformat->value;
1988 resp->records = pack_records(assoc, req->resultSetName, 1,
1989 toget, compp, next, presst, form, req->referenceId,
1990 req->preferredRecordSyntax);
1993 resp->numberOfRecordsReturned = toget;
1994 resp->nextResultSetPosition = next;
1995 resp->searchStatus = sr;
1996 resp->resultSetStatus = 0;
1997 resp->presentStatus = presst;
2001 if (*resp->resultCount)
2003 resp->numberOfRecordsReturned = nulint;
2004 resp->nextResultSetPosition = next;
2005 resp->searchStatus = sr;
2006 resp->resultSetStatus = 0;
2007 resp->presentStatus = 0;
2010 resp->additionalSearchInfo = bsrt->search_info;
2015 * Maybe we got a little over-friendly when we designed bend_fetch to
2016 * get only one record at a time. Some backends can optimise multiple-record
2017 * fetches, and at any rate, there is some overhead involved in
2018 * all that selecting and hopping around. Problem is, of course, that the
2019 * frontend can't know ahead of time how many records it'll need to
2020 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
2021 * is downright lousy as a bulk data transfer protocol.
2023 * To start with, we'll do the fetching of records from the backend
2024 * in one operation: To save some trips in and out of the event-handler,
2025 * and to simplify the interface to pack_records. At any rate, asynch
2026 * operation is more fun in operations that have an unpredictable execution
2027 * speed - which is normally more true for search than for present.
2029 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
2032 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
2036 Z_PresentResponse *resp;
2040 yaz_log(LOG_LOG, "Got PresentRequest.");
2042 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
2045 form = prefformat->value;
2046 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
2048 resp->presentStatus = odr_intdup(assoc->encode, 0);
2049 if (assoc->init->bend_present)
2051 bend_present_rr *bprr = (bend_present_rr *)
2052 nmem_malloc (reqb->request_mem, sizeof(*bprr));
2053 bprr->setname = req->resultSetId;
2054 bprr->start = *req->resultSetStartPoint;
2055 bprr->number = *req->numberOfRecordsRequested;
2056 bprr->format = form;
2057 bprr->comp = req->recordComposition;
2058 bprr->referenceId = req->referenceId;
2059 bprr->stream = assoc->encode;
2060 bprr->print = assoc->print;
2061 bprr->request = reqb;
2062 bprr->association = assoc;
2064 bprr->errstring = NULL;
2065 (*assoc->init->bend_present)(assoc->backend, bprr);
2071 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
2072 *resp->presentStatus = Z_PRES_FAILURE;
2075 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2076 next = odr_intdup(assoc->encode, 0);
2077 num = odr_intdup(assoc->encode, 0);
2079 apdu->which = Z_APDU_presentResponse;
2080 apdu->u.presentResponse = resp;
2081 resp->referenceId = req->referenceId;
2082 resp->otherInfo = 0;
2086 *num = *req->numberOfRecordsRequested;
2088 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2089 num, req->recordComposition, next, resp->presentStatus,
2090 form, req->referenceId, req->preferredRecordSyntax);
2094 resp->numberOfRecordsReturned = num;
2095 resp->nextResultSetPosition = next;
2101 * Scan was implemented rather in a hurry, and with support for only the basic
2102 * elements of the service in the backend API. Suggestions are welcome.
2104 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2106 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2107 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2108 Z_ScanResponse *res = (Z_ScanResponse *)
2109 odr_malloc (assoc->encode, sizeof(*res));
2110 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2111 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2112 Z_ListEntries *ents = (Z_ListEntries *)
2113 odr_malloc (assoc->encode, sizeof(*ents));
2114 Z_DiagRecs *diagrecs_p = NULL;
2116 bend_scan_rr *bsrr = (bend_scan_rr *)
2117 odr_malloc (assoc->encode, sizeof(*bsrr));
2118 struct scan_entry *save_entries;
2120 yaz_log(LOG_LOG, "Got ScanRequest");
2122 apdu->which = Z_APDU_scanResponse;
2123 apdu->u.scanResponse = res;
2124 res->referenceId = req->referenceId;
2126 /* if step is absent, set it to 0 */
2127 res->stepSize = odr_intdup(assoc->encode, 0);
2129 *res->stepSize = *req->stepSize;
2131 res->scanStatus = scanStatus;
2132 res->numberOfEntriesReturned = numberOfEntriesReturned;
2133 res->positionOfTerm = 0;
2134 res->entries = ents;
2135 ents->num_entries = 0;
2136 ents->entries = NULL;
2137 ents->num_nonsurrogateDiagnostics = 0;
2138 ents->nonsurrogateDiagnostics = NULL;
2139 res->attributeSet = 0;
2142 if (req->databaseNames)
2145 for (i = 0; i < req->num_databaseNames; i++)
2146 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
2148 bsrr->num_bases = req->num_databaseNames;
2149 bsrr->basenames = req->databaseNames;
2150 bsrr->num_entries = *req->numberOfTermsRequested;
2151 bsrr->term = req->termListAndStartPoint;
2152 bsrr->referenceId = req->referenceId;
2153 bsrr->stream = assoc->encode;
2154 bsrr->print = assoc->print;
2155 bsrr->step_size = res->stepSize;
2157 /* Note that version 2.0 of YAZ and older did not set entries ..
2158 We do now. And when we do it's easier to extend the scan entry
2159 We know that if the scan handler did set entries, it will
2160 not know of new member display_term.
2162 if (bsrr->num_entries > 0)
2165 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2167 for (i = 0; i<bsrr->num_entries; i++)
2169 bsrr->entries[i].term = 0;
2170 bsrr->entries[i].occurrences = 0;
2171 bsrr->entries[i].errcode = 0;
2172 bsrr->entries[i].errstring = 0;
2173 bsrr->entries[i].display_term = 0;
2176 save_entries = bsrr->entries; /* save it so we can compare later */
2178 if (req->attributeSet &&
2179 (attset = oid_getentbyoid(req->attributeSet)) &&
2180 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2181 bsrr->attributeset = attset->value;
2183 bsrr->attributeset = VAL_NONE;
2184 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2185 bsrr->term_position = req->preferredPositionInResponse ?
2186 *req->preferredPositionInResponse : 1;
2187 ((int (*)(void *, bend_scan_rr *))
2188 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2190 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2194 Z_Entry **tab = (Z_Entry **)
2195 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2197 if (bsrr->status == BEND_SCAN_PARTIAL)
2198 *scanStatus = Z_Scan_partial_5;
2200 *scanStatus = Z_Scan_success;
2201 ents->entries = tab;
2202 ents->num_entries = bsrr->num_entries;
2203 res->numberOfEntriesReturned = &ents->num_entries;
2204 res->positionOfTerm = &bsrr->term_position;
2205 for (i = 0; i < bsrr->num_entries; i++)
2211 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2212 if (bsrr->entries[i].occurrences >= 0)
2214 e->which = Z_Entry_termInfo;
2215 e->u.termInfo = t = (Z_TermInfo *)
2216 odr_malloc(assoc->encode, sizeof(*t));
2217 t->suggestedAttributes = 0;
2219 if (save_entries == bsrr->entries &&
2220 bsrr->entries[i].display_term)
2222 /* the entries was NOT set by the handler. So it's
2223 safe to test for new member display_term. It is
2226 t->displayTerm = odr_strdup(assoc->encode,
2227 bsrr->entries[i].display_term);
2229 t->alternativeTerm = 0;
2230 t->byAttributes = 0;
2231 t->otherTermInfo = 0;
2232 t->globalOccurrences = &bsrr->entries[i].occurrences;
2233 t->term = (Z_Term *)
2234 odr_malloc(assoc->encode, sizeof(*t->term));
2235 t->term->which = Z_Term_general;
2236 t->term->u.general = o =
2237 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2238 o->buf = (unsigned char *)
2239 odr_malloc(assoc->encode, o->len = o->size =
2240 strlen(bsrr->entries[i].term));
2241 memcpy(o->buf, bsrr->entries[i].term, o->len);
2242 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2243 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2247 Z_DiagRecs *drecs = diagrecs (assoc,
2248 bsrr->entries[i].errcode,
2249 bsrr->entries[i].errstring);
2250 assert (drecs->num_diagRecs == 1);
2251 e->which = Z_Entry_surrogateDiagnostic;
2252 assert (drecs->diagRecs[0]);
2253 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2259 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2260 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2265 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2268 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2269 Z_SortResponse *res = (Z_SortResponse *)
2270 odr_malloc (assoc->encode, sizeof(*res));
2271 bend_sort_rr *bsrr = (bend_sort_rr *)
2272 odr_malloc (assoc->encode, sizeof(*bsrr));
2274 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2276 yaz_log(LOG_LOG, "Got SortRequest.");
2278 bsrr->num_input_setnames = req->num_inputResultSetNames;
2279 bsrr->input_setnames = req->inputResultSetNames;
2280 bsrr->referenceId = req->referenceId;
2281 bsrr->output_setname = req->sortedResultSetName;
2282 bsrr->sort_sequence = req->sortSequence;
2283 bsrr->stream = assoc->encode;
2284 bsrr->print = assoc->print;
2286 bsrr->sort_status = Z_SortStatus_failure;
2288 bsrr->errstring = 0;
2290 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2292 res->referenceId = bsrr->referenceId;
2293 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2294 res->resultSetStatus = 0;
2297 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2298 res->diagnostics = dr->diagRecs;
2299 res->num_diagnostics = dr->num_diagRecs;
2303 res->num_diagnostics = 0;
2304 res->diagnostics = 0;
2306 res->resultCount = 0;
2309 apdu->which = Z_APDU_sortResponse;
2310 apdu->u.sortResponse = res;
2314 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2317 Z_DeleteResultSetRequest *req =
2318 reqb->apdu_request->u.deleteResultSetRequest;
2319 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2320 odr_malloc (assoc->encode, sizeof(*res));
2321 bend_delete_rr *bdrr = (bend_delete_rr *)
2322 odr_malloc (assoc->encode, sizeof(*bdrr));
2323 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2325 yaz_log(LOG_LOG, "Got DeleteRequest.");
2327 bdrr->num_setnames = req->num_resultSetList;
2328 bdrr->setnames = req->resultSetList;
2329 bdrr->stream = assoc->encode;
2330 bdrr->print = assoc->print;
2331 bdrr->function = *req->deleteFunction;
2332 bdrr->referenceId = req->referenceId;
2334 if (bdrr->num_setnames > 0)
2337 bdrr->statuses = (int*)
2338 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2339 bdrr->num_setnames);
2340 for (i = 0; i < bdrr->num_setnames; i++)
2341 bdrr->statuses[i] = 0;
2343 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2345 res->referenceId = req->referenceId;
2347 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2349 res->deleteListStatuses = 0;
2350 if (bdrr->num_setnames > 0)
2353 res->deleteListStatuses = (Z_ListStatuses *)
2354 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2355 res->deleteListStatuses->num = bdrr->num_setnames;
2356 res->deleteListStatuses->elements =
2358 odr_malloc (assoc->encode,
2359 sizeof(*res->deleteListStatuses->elements) *
2360 bdrr->num_setnames);
2361 for (i = 0; i<bdrr->num_setnames; i++)
2363 res->deleteListStatuses->elements[i] =
2365 odr_malloc (assoc->encode,
2366 sizeof(**res->deleteListStatuses->elements));
2367 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2368 res->deleteListStatuses->elements[i]->id =
2369 odr_strdup (assoc->encode, bdrr->setnames[i]);
2373 res->numberNotDeleted = 0;
2374 res->bulkStatuses = 0;
2375 res->deleteMessage = 0;
2378 apdu->which = Z_APDU_deleteResultSetResponse;
2379 apdu->u.deleteResultSetResponse = res;
2383 static void process_close(association *assoc, request *reqb)
2385 Z_Close *req = reqb->apdu_request->u.close;
2386 static char *reasons[] =
2393 "securityViolation",
2400 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2401 reasons[*req->closeReason], req->diagnosticInformation ?
2402 req->diagnosticInformation : "NULL");
2403 if (assoc->version < 3) /* to make do_force respond with close */
2405 do_close_req(assoc, Z_Close_finished,
2406 "Association terminated by client", reqb);
2409 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2413 reqb->len_refid = refid->len;
2414 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2415 memcpy (reqb->refid, refid->buf, refid->len);
2419 reqb->len_refid = 0;
2424 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2426 process_z_response (a, req, res);
2429 bend_request bend_request_mk (bend_association a)
2431 request *nreq = request_get (&a->outgoing);
2432 nreq->request_mem = nmem_create ();
2436 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2441 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2442 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2443 id->len = id->size = req->len_refid;
2444 memcpy (id->buf, req->refid, req->len_refid);
2448 void bend_request_destroy (bend_request *req)
2450 nmem_destroy((*req)->request_mem);
2451 request_release(*req);
2455 int bend_backend_respond (bend_association a, bend_request req)
2459 r = process_z_request (a, req, &msg);
2461 yaz_log (LOG_WARN, "%s", msg);
2465 void bend_request_setdata(bend_request r, void *p)
2470 void *bend_request_getdata(bend_request r)
2472 return r->clientData;
2475 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2477 bend_segment_rr req;
2479 req.segment = reqb->apdu_request->u.segmentRequest;
2480 req.stream = assoc->encode;
2481 req.decode = assoc->decode;
2482 req.print = assoc->print;
2483 req.association = assoc;
2485 (*assoc->init->bend_segment)(assoc->backend, &req);
2490 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2492 bend_esrequest_rr esrequest;
2494 Z_ExtendedServicesRequest *req =
2495 reqb->apdu_request->u.extendedServicesRequest;
2496 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2498 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2500 yaz_log(LOG_DEBUG,"inside Process esRequest");
2502 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2503 esrequest.stream = assoc->encode;
2504 esrequest.decode = assoc->decode;
2505 esrequest.print = assoc->print;
2506 esrequest.errcode = 0;
2507 esrequest.errstring = NULL;
2508 esrequest.request = reqb;
2509 esrequest.association = assoc;
2510 esrequest.taskPackage = 0;
2511 esrequest.referenceId = req->referenceId;
2513 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2515 /* If the response is being delayed, return NULL */
2516 if (esrequest.request == NULL)
2519 resp->referenceId = req->referenceId;
2521 if (esrequest.errcode == -1)
2523 /* Backend service indicates request will be processed */
2524 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2525 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2527 else if (esrequest.errcode == 0)
2529 /* Backend service indicates request will be processed */
2530 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2531 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2535 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2536 esrequest.errstring);
2538 /* Backend indicates error, request will not be processed */
2539 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2540 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2541 resp->num_diagnostics = diagRecs->num_diagRecs;
2542 resp->diagnostics = diagRecs->diagRecs;
2544 /* Do something with the members of bend_extendedservice */
2545 if (esrequest.taskPackage)
2546 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2547 (const char *) esrequest.taskPackage,
2549 yaz_log(LOG_DEBUG,"Send the result apdu");