2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.36 2004-11-18 15:18:13 heikki Exp $
9 * \brief Implements GFS session logic.
11 * Frontend server logic.
13 * This code receives incoming APDUs, and handles client requests by means
16 * Some of the code is getting quite involved, compared to simpler servers -
17 * primarily because it is asynchronous both in the communication with
18 * the user and the backend. We think the complexity will pay off in
19 * the form of greater flexibility when more asynchronous facilities
22 * Memory management has become somewhat involved. In the simple case, where
23 * only one PDU is pending at a time, it will simply reuse the same memory,
24 * once it has found its working size. When we enable multiple concurrent
25 * operations, perhaps even with multiple parallel calls to the backend, it
26 * will maintain a pool of buffers for encoding and decoding, trying to
27 * minimize memory allocation/deallocation during normal operation.
33 #include <sys/types.h>
36 #define S_ISREG(x) (x & _S_IFREG)
46 #include <yaz/yconfig.h>
47 #include <yaz/xmalloc.h>
48 #include <yaz/comstack.h>
51 #include <yaz/proto.h>
54 #include <yaz/logrpn.h>
55 #include <yaz/statserv.h>
56 #include <yaz/diagbib1.h>
57 #include <yaz/charneg.h>
58 #include <yaz/otherinfo.h>
59 #include <yaz/yaz-util.h>
60 #include <yaz/pquery.h>
63 #include <yaz/backend.h>
65 static void process_gdu_request(association *assoc, request *req);
66 static int process_z_request(association *assoc, request *req, char **msg);
67 void backend_response(IOCHAN i, int event);
68 static int process_gdu_response(association *assoc, request *req, Z_GDU *res);
69 static int process_z_response(association *assoc, request *req, Z_APDU *res);
70 static Z_APDU *process_initRequest(association *assoc, request *reqb);
71 static Z_External *init_diagnostics(ODR odr, int errcode, char *errstring);
72 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
74 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
75 bend_search_rr *bsrr, int *fd);
76 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
78 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
79 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
80 static void process_close(association *assoc, request *reqb);
81 void save_referenceId (request *reqb, Z_ReferenceId *refid);
82 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
84 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
86 static FILE *apduf = 0; /* for use in static mode */
87 static statserv_options_block *control_block = 0;
89 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
91 /* dynamic logging levels */
92 static int logbits_set=0;
93 static int log_session=0;
94 static int log_request=0; /* one-line logs for requests */
95 static int log_requestdetail=0; /* more detailed stuff */
97 /** get_logbits sets global loglevel bits */
98 static void get_logbits()
99 { /* needs to be called after parsing cmd-line args that can set loglevels!*/
103 log_session=yaz_log_module_level("session");
104 log_request=yaz_log_module_level("request");
105 log_requestdetail=yaz_log_module_level("requestdetail");
110 * Create and initialize a new association-handle.
111 * channel : iochannel for the current line.
112 * link : communications channel.
113 * Returns: 0 or a new association handle.
115 association *create_association(IOCHAN channel, COMSTACK link)
122 control_block = statserv_getcontrol();
123 if (!(anew = (association *)xmalloc(sizeof(*anew))))
127 anew->client_chan = channel;
128 anew->client_link = link;
129 anew->cs_get_mask = 0;
130 anew->cs_put_mask = 0;
131 anew->cs_accept_mask = 0;
132 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
133 !(anew->encode = odr_createmem(ODR_ENCODE)))
135 if (*control_block->apdufile)
140 strcpy(filename, control_block->apdufile);
141 if (!(anew->print = odr_createmem(ODR_PRINT)))
143 if (*control_block->apdufile == '@')
145 odr_setprint(anew->print, yaz_log_file());
147 else if (*control_block->apdufile != '-')
149 strcpy(filename, control_block->apdufile);
150 if (!control_block->dynamic)
154 if (!(apduf = fopen(filename, "w")))
156 yaz_log(YLOG_WARN|YLOG_ERRNO, "can't open apdu dump %s", filename);
159 setvbuf(apduf, 0, _IONBF, 0);
165 sprintf(filename + strlen(filename), ".%d", getpid());
166 if (!(f = fopen(filename, "w")))
168 yaz_log(YLOG_WARN|YLOG_ERRNO, "%s", filename);
171 setvbuf(f, 0, _IONBF, 0);
173 odr_setprint(anew->print, f);
178 anew->input_buffer = 0;
179 anew->input_buffer_len = 0;
181 anew->state = ASSOC_NEW;
182 request_initq(&anew->incoming);
183 request_initq(&anew->outgoing);
184 anew->proto = cs_getproto(link);
189 * Free association and release resources.
191 void destroy_association(association *h)
193 statserv_options_block *cb = statserv_getcontrol();
197 odr_destroy(h->decode);
198 odr_destroy(h->encode);
200 odr_destroy(h->print);
202 xfree(h->input_buffer);
204 (*cb->bend_close)(h->backend);
205 while ((req = request_deq(&h->incoming)))
206 request_release(req);
207 while ((req = request_deq(&h->outgoing)))
208 request_release(req);
209 request_delq(&h->incoming);
210 request_delq(&h->outgoing);
212 xmalloc_trav("session closed");
213 if (control_block && control_block->one_shot)
219 static void do_close_req(association *a, int reason, char *message,
223 Z_Close *cls = zget_Close(a->encode);
225 /* Purge request queue */
226 while (request_deq(&a->incoming));
227 while (request_deq(&a->outgoing));
230 yaz_log(log_requestdetail, "Sending Close PDU, reason=%d, message=%s",
231 reason, message ? message : "none");
232 apdu.which = Z_APDU_close;
234 *cls->closeReason = reason;
235 cls->diagnosticInformation = message;
236 process_z_response(a, req, &apdu);
237 iochan_settimeout(a->client_chan, 20);
241 request_release(req);
242 yaz_log(log_requestdetail, "v2 client. No Close PDU");
243 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
245 a->state = ASSOC_DEAD;
248 static void do_close(association *a, int reason, char *message)
250 request *req = request_get(&a->outgoing);
251 do_close_req (a, reason, message, req);
255 * This is where PDUs from the client are read and the further
256 * processing is initiated. Flow of control moves down through the
257 * various process_* functions below, until the encoded result comes back up
258 * to the output handler in here.
260 * h : the I/O channel that has an outstanding event.
261 * event : the current outstanding event.
263 void ir_session(IOCHAN h, int event)
266 association *assoc = (association *)iochan_getdata(h);
267 COMSTACK conn = assoc->client_link;
270 assert(h && conn && assoc);
271 if (event == EVENT_TIMEOUT)
273 if (assoc->state != ASSOC_UP)
275 yaz_log(YLOG_DEBUG, "Final timeout - closing connection.");
276 /* do we need to lod this at all */
278 destroy_association(assoc);
283 yaz_log(log_session, "Session idle too long. Sending close.");
284 do_close(assoc, Z_Close_lackOfActivity, 0);
288 if (event & assoc->cs_accept_mask)
290 yaz_log (log_session, "ir_session (accept)");
291 if (!cs_accept (conn))
293 yaz_log (YLOG_WARN, "accept failed");
294 destroy_association(assoc);
297 iochan_clearflag (h, EVENT_OUTPUT);
298 if (conn->io_pending)
299 { /* cs_accept didn't complete */
300 assoc->cs_accept_mask =
301 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
302 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
304 iochan_setflag (h, assoc->cs_accept_mask);
307 { /* cs_accept completed. Prepare for reading (cs_get) */
308 assoc->cs_accept_mask = 0;
309 assoc->cs_get_mask = EVENT_INPUT;
310 iochan_setflag (h, assoc->cs_get_mask);
314 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
316 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
318 yaz_log(YLOG_DEBUG, "ir_session (input)");
319 /* We aren't speaking to this fellow */
320 if (assoc->state == ASSOC_DEAD)
322 yaz_log(log_session, "Connection closed - end of session");
324 destroy_association(assoc);
328 assoc->cs_get_mask = EVENT_INPUT;
329 if ((res = cs_get(conn, &assoc->input_buffer,
330 &assoc->input_buffer_len)) <= 0)
332 yaz_log(log_session, "Connection closed by client");
334 destroy_association(assoc);
338 else if (res == 1) /* incomplete read - wait for more */
340 if (conn->io_pending & CS_WANT_WRITE)
341 assoc->cs_get_mask |= EVENT_OUTPUT;
342 iochan_setflag(h, assoc->cs_get_mask);
345 if (cs_more(conn)) /* more stuff - call us again later, please */
346 iochan_setevent(h, EVENT_INPUT);
348 /* we got a complete PDU. Let's decode it */
349 yaz_log(YLOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
350 assoc->input_buffer[0] & 0xff,
351 assoc->input_buffer[1] & 0xff,
352 assoc->input_buffer[2] & 0xff);
353 req = request_get(&assoc->incoming); /* get a new request */
354 odr_reset(assoc->decode);
355 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
356 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
358 yaz_log(YLOG_WARN, "ODR error on incoming PDU: %s [element %s] "
360 odr_errmsg(odr_geterror(assoc->decode)),
361 odr_getelement(assoc->decode),
362 odr_offset(assoc->decode));
363 if (assoc->decode->error != OHTTP)
365 yaz_log(YLOG_WARN, "PDU dump:");
366 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
367 request_release(req);
368 do_close(assoc, Z_Close_protocolError,"Malformed package");
372 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
373 assoc->state = ASSOC_DEAD;
374 process_gdu_response(assoc, req, p);
378 req->request_mem = odr_extract_mem(assoc->decode);
381 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
382 yaz_log(YLOG_WARN, "ODR print error: %s",
383 odr_errmsg(odr_geterror(assoc->print)));
384 odr_reset(assoc->print);
386 request_enq(&assoc->incoming, req);
389 /* can we do something yet? */
390 req = request_head(&assoc->incoming);
391 if (req->state == REQUEST_IDLE)
393 request_deq(&assoc->incoming);
394 process_gdu_request(assoc, req);
397 if (event & assoc->cs_put_mask)
399 request *req = request_head(&assoc->outgoing);
401 assoc->cs_put_mask = 0;
402 yaz_log(YLOG_DEBUG, "ir_session (output)");
403 req->state = REQUEST_PENDING;
404 switch (res = cs_put(conn, req->response, req->len_response))
407 yaz_log(log_session, "Connection closed by client");
409 destroy_association(assoc);
412 case 0: /* all sent - release the request structure */
413 yaz_log(YLOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
415 yaz_log(YLOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
418 nmem_destroy(req->request_mem);
419 request_deq(&assoc->outgoing);
420 request_release(req);
421 if (!request_head(&assoc->outgoing))
422 { /* restore mask for cs_get operation ... */
423 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
424 iochan_setflag(h, assoc->cs_get_mask);
425 if (assoc->state == ASSOC_DEAD)
426 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
430 assoc->cs_put_mask = EVENT_OUTPUT;
434 if (conn->io_pending & CS_WANT_WRITE)
435 assoc->cs_put_mask |= EVENT_OUTPUT;
436 if (conn->io_pending & CS_WANT_READ)
437 assoc->cs_put_mask |= EVENT_INPUT;
438 iochan_setflag(h, assoc->cs_put_mask);
441 if (event & EVENT_EXCEPT)
443 yaz_log(YLOG_WARN, "ir_session (exception)");
445 destroy_association(assoc);
450 static int process_z_request(association *assoc, request *req, char **msg);
452 static void assoc_init_reset(association *assoc)
455 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
457 assoc->init->stream = assoc->encode;
458 assoc->init->print = assoc->print;
459 assoc->init->auth = 0;
460 assoc->init->referenceId = 0;
461 assoc->init->implementation_version = 0;
462 assoc->init->implementation_id = 0;
463 assoc->init->implementation_name = 0;
464 assoc->init->bend_sort = NULL;
465 assoc->init->bend_search = NULL;
466 assoc->init->bend_present = NULL;
467 assoc->init->bend_esrequest = NULL;
468 assoc->init->bend_delete = NULL;
469 assoc->init->bend_scan = NULL;
470 assoc->init->bend_segment = NULL;
471 assoc->init->bend_fetch = NULL;
472 assoc->init->bend_explain = NULL;
474 assoc->init->charneg_request = NULL;
475 assoc->init->charneg_response = NULL;
477 assoc->init->decode = assoc->decode;
478 assoc->init->peer_name =
479 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
482 static int srw_bend_init(association *assoc)
484 const char *encoding = "UTF-8";
486 bend_initresult *binitres;
487 statserv_options_block *cb = statserv_getcontrol();
489 assoc_init_reset(assoc);
491 assoc->maximumRecordSize = 3000000;
492 assoc->preferredMessageSize = 3000000;
494 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
495 assoc->init->charneg_request = ce->u.charNeg3;
498 if (!(binitres = (*cb->bend_init)(assoc->init)))
500 yaz_log(YLOG_WARN, "Bad response from backend.");
503 assoc->backend = binitres->handle;
507 static int srw_bend_fetch(association *assoc, int pos,
508 Z_SRW_searchRetrieveRequest *srw_req,
509 Z_SRW_record *record)
512 ODR o = assoc->encode;
514 rr.setname = "default";
517 rr.request_format = VAL_TEXT_XML;
518 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
521 rr.comp = (Z_RecordComposition *)
522 odr_malloc(assoc->decode, sizeof(*rr.comp));
523 rr.comp->which = Z_RecordComp_complex;
524 rr.comp->u.complex = (Z_CompSpec *)
525 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
526 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
527 odr_malloc(assoc->encode, sizeof(bool_t));
528 *rr.comp->u.complex->selectAlternativeSyntax = 0;
529 rr.comp->u.complex->num_dbSpecific = 0;
530 rr.comp->u.complex->dbSpecific = 0;
531 rr.comp->u.complex->num_recordSyntax = 0;
532 rr.comp->u.complex->recordSyntax = 0;
534 rr.comp->u.complex->generic = (Z_Specification *)
535 odr_malloc(assoc->decode, sizeof(Z_Specification));
537 /* schema uri = recordSchema (or NULL if recordSchema is not given) */
538 rr.comp->u.complex->generic->which = Z_Schema_uri;
539 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
541 /* ESN = recordSchema if recordSchema is present */
542 rr.comp->u.complex->generic->elementSpec = 0;
543 if (srw_req->recordSchema)
545 rr.comp->u.complex->generic->elementSpec =
546 (Z_ElementSpec *) odr_malloc(assoc->encode, sizeof(Z_ElementSpec));
547 rr.comp->u.complex->generic->elementSpec->which =
548 Z_ElementSpec_elementSetName;
549 rr.comp->u.complex->generic->elementSpec->u.elementSetName =
550 srw_req->recordSchema;
553 rr.stream = assoc->encode;
554 rr.print = assoc->print;
560 rr.output_format = VAL_TEXT_XML;
561 rr.output_format_raw = 0;
564 rr.surrogate_flag = 0;
565 rr.schema = srw_req->recordSchema;
567 if (!assoc->init->bend_fetch)
570 (*assoc->init->bend_fetch)(assoc->backend, &rr);
572 if (rr.errcode && rr.surrogate_flag)
574 int code = yaz_diag_bib1_to_srw(rr.errcode);
575 const char *message = yaz_diag_srw_str(code);
578 len += strlen(message);
580 len += strlen(rr.errstring);
582 record->recordData_buf = odr_malloc(o, len);
584 sprintf(record->recordData_buf, "<diagnostic "
585 "xmlns=\"http://www.loc.gov/zing/srw/diagnostic/\">\n"
586 " <uri>info:srw/diagnostic/1/%d</uri>\n", code);
588 sprintf(record->recordData_buf + strlen(record->recordData_buf),
589 " <details>%s</details>\n", rr.errstring);
591 sprintf(record->recordData_buf + strlen(record->recordData_buf),
592 " <message>%s</message>\n", message);
593 sprintf(record->recordData_buf + strlen(record->recordData_buf),
595 record->recordData_len = strlen(record->recordData_buf);
596 record->recordPosition = odr_intdup(o, pos);
597 record->recordSchema = "info:srw/schema/1/diagnostics-v1.1";
600 else if (rr.len >= 0)
602 record->recordData_buf = rr.record;
603 record->recordData_len = rr.len;
604 record->recordPosition = odr_intdup(o, pos);
606 record->recordSchema = odr_strdup(o, rr.schema);
608 record->recordSchema = 0;
613 static void srw_bend_search(association *assoc, request *req,
614 Z_SRW_searchRetrieveRequest *srw_req,
615 Z_SRW_searchRetrieveResponse *srw_res,
624 yaz_log(log_requestdetail, "Got SRW SearchRetrieveRequest");
625 yaz_log(YLOG_DEBUG, "srw_bend_search");
628 yaz_log(YLOG_DEBUG, "srw_bend_init");
629 if (!srw_bend_init(assoc))
631 srw_error = 3; /* assume Authentication error */
633 yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
634 &srw_res->num_diagnostics, 1, 0);
635 yaz_log(log_request,"Search SRW: backend init failed");
640 rr.setname = "default";
643 rr.basenames = &srw_req->database;
646 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
648 if (srw_req->query_type == Z_SRW_query_type_cql)
650 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
651 ext->direct_reference = odr_getoidbystr(assoc->decode,
652 "1.2.840.10003.16.2");
653 ext->indirect_reference = 0;
655 ext->which = Z_External_CQL;
656 ext->u.cql = srw_req->query.cql;
657 querystr=srw_req->query.cql;
659 rr.query->which = Z_Query_type_104;
660 rr.query->u.type_104 = ext;
662 else if (srw_req->query_type == Z_SRW_query_type_pqf)
664 Z_RPNQuery *RPNquery;
665 YAZ_PQF_Parser pqf_parser;
667 pqf_parser = yaz_pqf_create ();
669 querystr=srw_req->query.pqf;
670 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
676 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
677 yaz_log(log_requestdetail, "Parse error %d %s near offset %d",
682 rr.query->which = Z_Query_type_1;
683 rr.query->u.type_1 = RPNquery;
685 yaz_pqf_destroy (pqf_parser);
690 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
693 if (!srw_error && !assoc->init->bend_search)
700 WRBUF wr=wrbuf_alloc();
701 wrbuf_printf(wr, "Search: SRW: %s ",querystr);
702 wrbuf_printf(wr," ERROR %d ", srw_error);
703 yaz_log(log_request, "Search %s", wrbuf_buf(wr) );
706 srw_res->num_diagnostics = 1;
707 srw_res->diagnostics = (Z_SRW_diagnostic *)
708 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
709 yaz_mk_std_diagnostic(assoc->encode,
710 srw_res->diagnostics, srw_error, 0);
714 rr.stream = assoc->encode;
715 rr.decode = assoc->decode;
716 rr.print = assoc->print;
718 rr.association = assoc;
724 yaz_log_zquery_level(log_requestdetail,rr.query);
726 (assoc->init->bend_search)(assoc->backend, &rr);
729 yaz_log(log_request, "bend_search returned Bib-1 code %d", rr.errcode);
730 if (rr.errcode == 109) /* database unavailable */
735 srw_res->num_diagnostics = 1;
736 srw_res->diagnostics = (Z_SRW_diagnostic *)
737 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
738 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
739 yaz_diag_bib1_to_srw (rr.errcode),
741 yaz_log(log_request, "srw_bend_search returned SRW error %s",
742 srw_res->diagnostics[0].uri);
746 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
747 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
749 yaz_log(log_requestdetail, "Request to pack %d+%d out of %d",
750 start, number, rr.hits);
752 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
759 srw_res->num_diagnostics = 1;
760 srw_res->diagnostics = (Z_SRW_diagnostic *)
761 odr_malloc(assoc->encode,
762 sizeof(*srw_res->diagnostics));
763 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
769 int packing = Z_SRW_recordPacking_string;
770 if (start + number > rr.hits)
771 number = rr.hits - start + 1;
772 if (srw_req->recordPacking &&
773 !strcmp(srw_req->recordPacking, "xml"))
774 packing = Z_SRW_recordPacking_XML;
775 srw_res->records = (Z_SRW_record *)
776 odr_malloc(assoc->encode,
777 number * sizeof(*srw_res->records));
778 for (i = 0; i<number; i++)
782 srw_res->records[j].recordPacking = packing;
783 srw_res->records[j].recordData_buf = 0;
784 yaz_log(YLOG_DEBUG, "srw_bend_fetch %d", i+start);
785 errcode = srw_bend_fetch(assoc, i+start, srw_req,
786 srw_res->records + j);
789 srw_res->num_diagnostics = 1;
790 srw_res->diagnostics = (Z_SRW_diagnostic *)
791 odr_malloc(assoc->encode,
792 sizeof(*srw_res->diagnostics));
794 yaz_mk_std_diagnostic(assoc->encode,
795 srw_res->diagnostics,
796 yaz_diag_bib1_to_srw (errcode),
800 if (srw_res->records[j].recordData_buf)
803 srw_res->num_records = j;
805 srw_res->records = 0;
811 WRBUF wr=wrbuf_alloc();
812 wrbuf_printf(wr,"SRW: %s",querystr );
814 wrbuf_printf(wr," ERROR %d ", srw_error);
817 wrbuf_printf(wr," OK:%d hits ",rr.hits);
818 if (srw_res->num_records)
819 wrbuf_printf(wr," Returned %d records", srw_res->num_records);
821 yaz_log(log_request, "Search %s", wrbuf_buf(wr) );
826 static void srw_bend_explain(association *assoc, request *req,
827 Z_SRW_explainRequest *srw_req,
828 Z_SRW_explainResponse *srw_res,
831 yaz_log(log_requestdetail, "Got SRW ExplainRequest");
835 yaz_log(YLOG_DEBUG, "srw_bend_init");
836 if (!srw_bend_init(assoc))
841 if (assoc->init && assoc->init->bend_explain)
845 rr.stream = assoc->encode;
846 rr.decode = assoc->decode;
847 rr.print = assoc->print;
849 rr.database = srw_req->database;
850 rr.schema = "http://explain.z3950.org/dtd/2.0/";
851 (*assoc->init->bend_explain)(assoc->backend, &rr);
854 int packing = Z_SRW_recordPacking_string;
855 if (srw_req->recordPacking &&
856 !strcmp(srw_req->recordPacking, "xml"))
857 packing = Z_SRW_recordPacking_XML;
858 srw_res->record.recordSchema = rr.schema;
859 srw_res->record.recordPacking = packing;
860 srw_res->record.recordData_buf = rr.explain_buf;
861 srw_res->record.recordData_len = strlen(rr.explain_buf);
862 srw_res->record.recordPosition = 0;
868 static void process_http_request(association *assoc, request *req)
870 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
871 ODR o = assoc->encode;
872 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
874 Z_SOAP *soap_package = 0;
877 Z_HTTP_Response *hres = 0;
879 char *stylesheet = 0;
880 Z_SRW_diagnostic *diagnostic = 0;
881 int num_diagnostic = 0;
883 if (!strcmp(hreq->path, "/test"))
885 p = z_get_HTTP_Response(o, 200);
886 hres = p->u.HTTP_Response;
887 hres->content_buf = "1234567890\n";
888 hres->content_len = strlen(hres->content_buf);
893 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
894 yaz_log(YLOG_DEBUG, "yaz_srw_decode returned %d", r);
896 if (r == 2) /* not taken */
898 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
899 &diagnostic, &num_diagnostic);
900 yaz_log(YLOG_DEBUG, "yaz_sru_decode returned %d", r);
902 if (r == 0) /* decode SRW/SRU OK .. */
905 if (sr->which == Z_SRW_searchRetrieve_request)
908 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
910 stylesheet = sr->u.request->stylesheet;
913 res->u.response->diagnostics = diagnostic;
914 res->u.response->num_diagnostics = num_diagnostic;
918 srw_bend_search(assoc, req, sr->u.request, res->u.response,
921 if (http_code == 200)
922 soap_package->u.generic->p = res;
924 else if (sr->which == Z_SRW_explain_request)
926 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
927 stylesheet = sr->u.explain_request->stylesheet;
930 res->u.explain_response->diagnostics = diagnostic;
931 res->u.explain_response->num_diagnostics = num_diagnostic;
933 srw_bend_explain(assoc, req, sr->u.explain_request,
934 res->u.explain_response, &http_code);
935 if (http_code == 200)
936 soap_package->u.generic->p = res;
938 else if (sr->which == Z_SRW_scan_request)
940 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
941 stylesheet = sr->u.scan_request->stylesheet;
944 res->u.scan_response->diagnostics = diagnostic;
945 res->u.scan_response->num_diagnostics = num_diagnostic;
947 yaz_add_srw_diagnostic(o,
948 &res->u.scan_response->diagnostics,
949 &res->u.scan_response->num_diagnostics,
951 if (http_code == 200)
952 soap_package->u.generic->p = res;
956 yaz_log(log_request, "generate soap error");
957 /* FIXME - what error, what query */
959 z_soap_error(assoc->encode, soap_package,
960 "SOAP-ENV:Client", "Bad method", 0);
962 if (http_code == 200 || http_code == 500)
964 static Z_SOAP_Handler soap_handlers[3] = {
966 {"http://www.loc.gov/zing/srw/", 0,
967 (Z_SOAP_fun) yaz_srw_codec},
968 {"http://www.loc.gov/zing/srw/v1.0/", 0,
969 (Z_SOAP_fun) yaz_srw_codec},
975 p = z_get_HTTP_Response(o, 200);
976 hres = p->u.HTTP_Response;
977 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
978 &hres->content_buf, &hres->content_len,
979 soap_handlers, charset, stylesheet);
980 hres->code = http_code;
982 strcpy(ctype, "text/xml");
985 strcat(ctype, "; charset=");
986 strcat(ctype, charset);
988 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
991 p = z_get_HTTP_Response(o, http_code);
995 p = z_get_HTTP_Response(o, 500);
996 hres = p->u.HTTP_Response;
997 if (!strcmp(hreq->version, "1.0"))
999 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1000 if (v && !strcmp(v, "Keep-Alive"))
1004 hres->version = "1.0";
1008 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1009 if (v && !strcmp(v, "close"))
1013 hres->version = "1.1";
1017 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1018 assoc->state = ASSOC_DEAD;
1019 assoc->cs_get_mask = 0;
1024 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1026 if (alive && isdigit(*alive))
1030 if (t < 0 || t > 3600)
1032 iochan_settimeout(assoc->client_chan,t);
1033 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1035 process_gdu_response(assoc, req, p);
1038 static void process_gdu_request(association *assoc, request *req)
1040 if (req->gdu_request->which == Z_GDU_Z3950)
1043 req->apdu_request = req->gdu_request->u.z3950;
1044 if (process_z_request(assoc, req, &msg) < 0)
1045 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1047 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1048 process_http_request(assoc, req);
1051 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1056 * Initiate request processing.
1058 static int process_z_request(association *assoc, request *req, char **msg)
1064 *msg = "Unknown Error";
1065 assert(req && req->state == REQUEST_IDLE);
1066 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1068 *msg = "Missing InitRequest";
1071 switch (req->apdu_request->which)
1073 case Z_APDU_initRequest:
1074 iochan_settimeout(assoc->client_chan,
1075 statserv_getcontrol()->idle_timeout * 60);
1076 res = process_initRequest(assoc, req); break;
1077 case Z_APDU_searchRequest:
1078 res = process_searchRequest(assoc, req, &fd); break;
1079 case Z_APDU_presentRequest:
1080 res = process_presentRequest(assoc, req, &fd); break;
1081 case Z_APDU_scanRequest:
1082 if (assoc->init->bend_scan)
1083 res = process_scanRequest(assoc, req, &fd);
1086 *msg = "Cannot handle Scan APDU";
1090 case Z_APDU_extendedServicesRequest:
1091 if (assoc->init->bend_esrequest)
1092 res = process_ESRequest(assoc, req, &fd);
1095 *msg = "Cannot handle Extended Services APDU";
1099 case Z_APDU_sortRequest:
1100 if (assoc->init->bend_sort)
1101 res = process_sortRequest(assoc, req, &fd);
1104 *msg = "Cannot handle Sort APDU";
1109 process_close(assoc, req);
1111 case Z_APDU_deleteResultSetRequest:
1112 if (assoc->init->bend_delete)
1113 res = process_deleteRequest(assoc, req, &fd);
1116 *msg = "Cannot handle Delete APDU";
1120 case Z_APDU_segmentRequest:
1121 if (assoc->init->bend_segment)
1123 res = process_segmentRequest (assoc, req);
1127 *msg = "Cannot handle Segment APDU";
1131 case Z_APDU_triggerResourceControlRequest:
1134 *msg = "Bad APDU received";
1139 yaz_log(YLOG_DEBUG, " result immediately available");
1140 retval = process_z_response(assoc, req, res);
1144 yaz_log(YLOG_DEBUG, " result unavailble");
1147 else /* no result yet - one will be provided later */
1151 /* Set up an I/O handler for the fd supplied by the backend */
1153 yaz_log(YLOG_DEBUG, " establishing handler for result");
1154 req->state = REQUEST_PENDING;
1155 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1157 iochan_setdata(chan, assoc);
1164 * Handle message from the backend.
1166 void backend_response(IOCHAN i, int event)
1168 association *assoc = (association *)iochan_getdata(i);
1169 request *req = request_head(&assoc->incoming);
1173 yaz_log(YLOG_DEBUG, "backend_response");
1174 assert(assoc && req && req->state != REQUEST_IDLE);
1175 /* determine what it is we're waiting for */
1176 switch (req->apdu_request->which)
1178 case Z_APDU_searchRequest:
1179 res = response_searchRequest(assoc, req, 0, &fd); break;
1181 case Z_APDU_presentRequest:
1182 res = response_presentRequest(assoc, req, 0, &fd); break;
1183 case Z_APDU_scanRequest:
1184 res = response_scanRequest(assoc, req, 0, &fd); break;
1187 yaz_log(YLOG_FATAL, "Serious programmer's lapse or bug");
1190 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1192 yaz_log(YLOG_WARN, "Fatal error when talking to backend");
1193 do_close(assoc, Z_Close_systemProblem, 0);
1197 else if (!res) /* no result yet - try again later */
1199 yaz_log(YLOG_DEBUG, " no result yet");
1200 iochan_setfd(i, fd); /* in case fd has changed */
1205 * Encode response, and transfer the request structure to the outgoing queue.
1207 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1209 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1213 if (!z_GDU(assoc->print, &res, 0, 0))
1214 yaz_log(YLOG_WARN, "ODR print error: %s",
1215 odr_errmsg(odr_geterror(assoc->print)));
1216 odr_reset(assoc->print);
1218 if (!z_GDU(assoc->encode, &res, 0, 0))
1220 yaz_log(YLOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1221 odr_errmsg(odr_geterror(assoc->decode)),
1222 odr_getelement(assoc->decode));
1223 request_release(req);
1226 req->response = odr_getbuf(assoc->encode, &req->len_response,
1227 &req->size_response);
1228 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1229 odr_reset(assoc->encode);
1230 req->state = REQUEST_IDLE;
1231 request_enq(&assoc->outgoing, req);
1232 /* turn the work over to the ir_session handler */
1233 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1234 assoc->cs_put_mask = EVENT_OUTPUT;
1235 /* Is there more work to be done? give that to the input handler too */
1237 if (request_head(&assoc->incoming))
1239 yaz_log (YLOG_DEBUG, "more work to be done");
1240 iochan_setevent(assoc->client_chan, EVENT_WORK);
1247 * Encode response, and transfer the request structure to the outgoing queue.
1249 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1251 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1252 gres->which = Z_GDU_Z3950;
1253 gres->u.z3950 = res;
1255 return process_gdu_response(assoc, req, gres);
1260 * Handle init request.
1261 * At the moment, we don't check the options
1262 * anywhere else in the code - we just try not to do anything that would
1263 * break a naive client. We'll toss 'em into the association block when
1264 * we need them there.
1266 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1268 statserv_options_block *cb = statserv_getcontrol();
1269 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1270 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1271 Z_InitResponse *resp = apdu->u.initResponse;
1272 bend_initresult *binitres;
1276 yaz_log(log_requestdetail, "Got initRequest");
1277 if (req->implementationId)
1278 yaz_log(log_requestdetail, "Id: %s", req->implementationId);
1279 if (req->implementationName)
1280 yaz_log(log_requestdetail, "Name: %s", req->implementationName);
1281 if (req->implementationVersion)
1282 yaz_log(log_requestdetail, "Version: %s", req->implementationVersion);
1284 assoc_init_reset(assoc);
1286 assoc->init->auth = req->idAuthentication;
1287 assoc->init->referenceId = req->referenceId;
1289 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1291 Z_CharSetandLanguageNegotiation *negotiation =
1292 yaz_get_charneg_record (req->otherInfo);
1294 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1295 assoc->init->charneg_request = negotiation;
1299 if (!(binitres = (*cb->bend_init)(assoc->init)))
1301 yaz_log(YLOG_WARN, "Bad response from backend.");
1305 assoc->backend = binitres->handle;
1306 if ((assoc->init->bend_sort))
1307 yaz_log (YLOG_DEBUG, "Sort handler installed");
1308 if ((assoc->init->bend_search))
1309 yaz_log (YLOG_DEBUG, "Search handler installed");
1310 if ((assoc->init->bend_present))
1311 yaz_log (YLOG_DEBUG, "Present handler installed");
1312 if ((assoc->init->bend_esrequest))
1313 yaz_log (YLOG_DEBUG, "ESRequest handler installed");
1314 if ((assoc->init->bend_delete))
1315 yaz_log (YLOG_DEBUG, "Delete handler installed");
1316 if ((assoc->init->bend_scan))
1317 yaz_log (YLOG_DEBUG, "Scan handler installed");
1318 if ((assoc->init->bend_segment))
1319 yaz_log (YLOG_DEBUG, "Segment handler installed");
1321 resp->referenceId = req->referenceId;
1323 /* let's tell the client what we can do */
1324 if (ODR_MASK_GET(req->options, Z_Options_search))
1326 ODR_MASK_SET(resp->options, Z_Options_search);
1327 strcat(options, "srch");
1329 if (ODR_MASK_GET(req->options, Z_Options_present))
1331 ODR_MASK_SET(resp->options, Z_Options_present);
1332 strcat(options, " prst");
1334 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1335 assoc->init->bend_delete)
1337 ODR_MASK_SET(resp->options, Z_Options_delSet);
1338 strcat(options, " del");
1340 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1341 assoc->init->bend_esrequest)
1343 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1344 strcat (options, " extendedServices");
1346 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1348 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1349 strcat(options, " namedresults");
1351 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1353 ODR_MASK_SET(resp->options, Z_Options_scan);
1354 strcat(options, " scan");
1356 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1358 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1359 strcat(options, " concurrop");
1361 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1363 ODR_MASK_SET(resp->options, Z_Options_sort);
1364 strcat(options, " sort");
1367 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1368 && assoc->init->charneg_response)
1370 Z_OtherInformation **p;
1371 Z_OtherInformationUnit *p0;
1373 yaz_oi_APDU(apdu, &p);
1375 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1376 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1378 p0->which = Z_OtherInfo_externallyDefinedInfo;
1379 p0->information.externallyDefinedInfo =
1380 assoc->init->charneg_response;
1382 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1383 strcat(options, " negotiation");
1386 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1388 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1390 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1391 assoc->version = 1; /* 1 & 2 are equivalent */
1393 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1395 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1398 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1400 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1404 yaz_log(log_requestdetail, "Negotiated to v%d: %s", assoc->version, options);
1405 assoc->maximumRecordSize = *req->maximumRecordSize;
1406 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1407 assoc->maximumRecordSize = control_block->maxrecordsize;
1408 assoc->preferredMessageSize = *req->preferredMessageSize;
1409 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1410 assoc->preferredMessageSize = assoc->maximumRecordSize;
1412 resp->preferredMessageSize = &assoc->preferredMessageSize;
1413 resp->maximumRecordSize = &assoc->maximumRecordSize;
1415 resp->implementationId = odr_prepend(assoc->encode,
1416 assoc->init->implementation_id,
1417 resp->implementationId);
1419 resp->implementationName = odr_prepend(assoc->encode,
1420 assoc->init->implementation_name,
1421 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1423 version = odr_strdup(assoc->encode, "$Revision: 1.36 $");
1424 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1425 version[strlen(version)-2] = '\0';
1426 resp->implementationVersion = odr_prepend(assoc->encode,
1427 assoc->init->implementation_version,
1428 odr_prepend(assoc->encode, &version[11],
1429 resp->implementationVersion));
1431 if (binitres->errcode)
1433 yaz_log(YLOG_DEBUG, "Connection rejected by backend.");
1435 assoc->state = ASSOC_DEAD;
1436 resp->userInformationField = init_diagnostics(assoc->encode,
1438 binitres->errstring);
1439 yaz_log(log_request,"Init from '%s' (%s) (ver %s) Error %d %s",
1440 req->implementationName ? req->implementationName :"??",
1441 req->implementationId ? req->implementationId :"?",
1442 req->implementationVersion ? req->implementationVersion: "?",
1443 binitres->errcode,binitres->errstring );
1447 assoc->state = ASSOC_UP;
1448 yaz_log(log_request,"Init from '%s' (%s) (ver %s) OK",
1449 req->implementationName ? req->implementationName :"??",
1450 req->implementationId ? req->implementationId :"?",
1451 req->implementationVersion ? req->implementationVersion: "?");
1458 * Diagnostic in default format, to be returned as either a surrogate
1459 * or non-surrogate diagnostic in the context of an open session, or
1460 * as User-information when an Init is refused.
1462 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1464 int *err = odr_intdup(odr, error);
1465 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1466 odr_malloc (odr, sizeof(*dr));
1468 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1469 addinfo ? " -- " : "", addinfo ? addinfo : "");
1471 dr->diagnosticSetId =
1472 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1473 dr->condition = err;
1474 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1475 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1480 * Set the specified `errcode' and `errstring' into a UserInfo-1
1481 * external to be returned to the client in accordance with Z35.90
1482 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1483 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1485 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1489 Z_OtherInformation *u;
1490 Z_OtherInformationUnit *l;
1491 Z_DiagnosticFormat *d;
1492 Z_DiagnosticFormat_s *e;
1494 x = (Z_External*) odr_malloc(odr, sizeof *x);
1496 x->indirect_reference = 0;
1497 oid.proto = PROTO_Z3950;
1498 oid.oclass = CLASS_USERINFO;
1499 oid.value = VAL_USERINFO1;
1500 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1501 x->which = Z_External_userInfo1;
1503 u = odr_malloc(odr, sizeof *u);
1505 u->num_elements = 1;
1506 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1507 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1510 l->which = Z_OtherInfo_externallyDefinedInfo;
1512 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1513 l->information.externallyDefinedInfo = x2;
1515 x2->indirect_reference = 0;
1516 oid.oclass = CLASS_DIAGSET;
1517 oid.value = VAL_DIAG1;
1518 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1519 x2->which = Z_External_diag1;
1521 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1524 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1525 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1528 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1529 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1535 * nonsurrogate diagnostic record.
1537 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1539 Z_Records *rec = (Z_Records *)
1540 odr_malloc (assoc->encode, sizeof(*rec));
1541 rec->which = Z_Records_NSD;
1542 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1547 * surrogate diagnostic.
1549 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1550 int error, char *addinfo)
1552 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1553 odr_malloc (assoc->encode, sizeof(*rec));
1554 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1556 yaz_log(YLOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1557 rec->databaseName = dbname;
1558 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1559 rec->u.surrogateDiagnostic = drec;
1560 drec->which = Z_DiagRec_defaultFormat;
1561 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1567 * multiple nonsurrogate diagnostics.
1569 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1571 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1572 int *err = odr_intdup(assoc->encode, error);
1573 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1574 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1575 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1576 odr_malloc (assoc->encode, sizeof(*rec));
1578 yaz_log(YLOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1580 recs->num_diagRecs = 1;
1581 recs->diagRecs = recp;
1583 drec->which = Z_DiagRec_defaultFormat;
1584 drec->u.defaultFormat = rec;
1586 rec->diagnosticSetId =
1587 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1588 rec->condition = err;
1590 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1591 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1595 static Z_Records *pack_records(association *a, char *setname, int start,
1596 int *num, Z_RecordComposition *comp,
1597 int *next, int *pres, oid_value format,
1598 Z_ReferenceId *referenceId,
1599 int *oid, int *errcode)
1601 int recno, total_length = 0, toget = *num, dumped_records = 0;
1602 Z_Records *records =
1603 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1604 Z_NamePlusRecordList *reclist =
1605 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1606 Z_NamePlusRecord **list =
1607 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1610 records->which = Z_Records_DBOSD;
1611 records->u.databaseOrSurDiagnostics = reclist;
1612 reclist->num_records = 0;
1613 reclist->records = list;
1614 *pres = Z_PresentStatus_success;
1618 yaz_log(log_requestdetail, "Request to pack %d+%d %s", start, toget, setname);
1619 yaz_log(log_requestdetail, "pms=%d, mrs=%d", a->preferredMessageSize,
1620 a->maximumRecordSize);
1621 for (recno = start; reclist->num_records < toget; recno++)
1624 Z_NamePlusRecord *thisrec;
1625 int this_length = 0;
1627 * we get the number of bytes allocated on the stream before any
1628 * allocation done by the backend - this should give us a reasonable
1629 * idea of the total size of the data so far.
1631 total_length = odr_total(a->encode) - dumped_records;
1637 freq.last_in_set = 0;
1638 freq.setname = setname;
1639 freq.surrogate_flag = 0;
1640 freq.number = recno;
1642 freq.request_format = format;
1643 freq.request_format_raw = oid;
1644 freq.output_format = format;
1645 freq.output_format_raw = 0;
1646 freq.stream = a->encode;
1647 freq.print = a->print;
1648 freq.referenceId = referenceId;
1650 (*a->init->bend_fetch)(a->backend, &freq);
1651 /* backend should be able to signal whether error is system-wide
1652 or only pertaining to current record */
1655 if (!freq.surrogate_flag)
1658 *pres = Z_PresentStatus_failure;
1659 /* for 'present request out of range',
1660 set addinfo to record position if not set */
1661 if (freq.errcode == 13 && freq.errstring == 0)
1663 sprintf (s, "%d", recno);
1667 *errcode=freq.errcode;
1668 return diagrec(a, freq.errcode, freq.errstring);
1670 reclist->records[reclist->num_records] =
1671 surrogatediagrec(a, freq.basename, freq.errcode,
1673 reclist->num_records++;
1674 *next = freq.last_in_set ? 0 : recno + 1;
1678 this_length = freq.len;
1680 this_length = odr_total(a->encode) - total_length - dumped_records;
1681 yaz_log(YLOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1682 this_length, total_length, dumped_records);
1683 if (a->preferredMessageSize > 0 &&
1684 this_length + total_length > a->preferredMessageSize)
1686 /* record is small enough, really */
1687 if (this_length <= a->preferredMessageSize && recno > start)
1689 yaz_log(log_requestdetail, " Dropped last normal-sized record");
1690 *pres = Z_PresentStatus_partial_2;
1693 /* record can only be fetched by itself */
1694 if (this_length < a->maximumRecordSize)
1696 yaz_log(log_requestdetail, " Record > prefmsgsz");
1699 yaz_log(YLOG_DEBUG, " Dropped it");
1700 reclist->records[reclist->num_records] =
1701 surrogatediagrec(a, freq.basename, 16, 0);
1702 reclist->num_records++;
1703 *next = freq.last_in_set ? 0 : recno + 1;
1704 dumped_records += this_length;
1708 else /* too big entirely */
1710 yaz_log(log_requestdetail, "Record > maxrcdsz this=%d max=%d",
1711 this_length, a->maximumRecordSize);
1712 reclist->records[reclist->num_records] =
1713 surrogatediagrec(a, freq.basename, 17, 0);
1714 reclist->num_records++;
1715 *next = freq.last_in_set ? 0 : recno + 1;
1716 dumped_records += this_length;
1721 if (!(thisrec = (Z_NamePlusRecord *)
1722 odr_malloc(a->encode, sizeof(*thisrec))))
1724 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1725 strlen(freq.basename) + 1)))
1727 strcpy(thisrec->databaseName, freq.basename);
1728 thisrec->which = Z_NamePlusRecord_databaseRecord;
1730 if (freq.output_format_raw)
1732 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1733 freq.output_format = ident->value;
1735 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1736 freq.record, freq.len);
1737 if (!thisrec->u.databaseRecord)
1739 reclist->records[reclist->num_records] = thisrec;
1740 reclist->num_records++;
1741 *next = freq.last_in_set ? 0 : recno + 1;
1743 *num = reclist->num_records;
1747 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1750 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1751 bend_search_rr *bsrr =
1752 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1754 yaz_log(log_requestdetail, "Got SearchRequest.");
1756 bsrr->request = reqb;
1757 bsrr->association = assoc;
1758 bsrr->referenceId = req->referenceId;
1759 save_referenceId (reqb, bsrr->referenceId);
1761 yaz_log (log_requestdetail, "ResultSet '%s'", req->resultSetName);
1762 if (req->databaseNames)
1765 for (i = 0; i < req->num_databaseNames; i++)
1766 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
1769 yaz_log_zquery_level(log_requestdetail,req->query);
1771 if (assoc->init->bend_search)
1773 bsrr->setname = req->resultSetName;
1774 bsrr->replace_set = *req->replaceIndicator;
1775 bsrr->num_bases = req->num_databaseNames;
1776 bsrr->basenames = req->databaseNames;
1777 bsrr->query = req->query;
1778 bsrr->stream = assoc->encode;
1779 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1780 bsrr->decode = assoc->decode;
1781 bsrr->print = assoc->print;
1784 bsrr->errstring = NULL;
1785 bsrr->search_info = NULL;
1786 (assoc->init->bend_search)(assoc->backend, bsrr);
1787 if (!bsrr->request) /* backend not ready with the search response */
1788 return 0; /* should not be used any more */
1792 /* FIXME - make a diagnostic for it */
1793 yaz_log(YLOG_WARN,"Search not supported ?!?!");
1795 return response_searchRequest(assoc, reqb, bsrr, fd);
1798 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1801 * Prepare a searchresponse based on the backend results. We probably want
1802 * to look at making the fetching of records nonblocking as well, but
1803 * so far, we'll keep things simple.
1804 * If bsrt is null, that means we're called in response to a communications
1805 * event, and we'll have to get the response for ourselves.
1807 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1808 bend_search_rr *bsrt, int *fd)
1810 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1811 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1812 Z_SearchResponse *resp = (Z_SearchResponse *)
1813 odr_malloc (assoc->encode, sizeof(*resp));
1814 int *nulint = odr_intdup (assoc->encode, 0);
1815 bool_t *sr = odr_intdup(assoc->encode, 1);
1816 int *next = odr_intdup(assoc->encode, 0);
1817 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1820 apdu->which = Z_APDU_searchResponse;
1821 apdu->u.searchResponse = resp;
1822 resp->referenceId = req->referenceId;
1823 resp->additionalSearchInfo = 0;
1824 resp->otherInfo = 0;
1826 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1828 yaz_log(YLOG_FATAL, "Bad result from backend");
1831 else if (bsrt->errcode)
1833 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1834 resp->resultCount = nulint;
1835 resp->numberOfRecordsReturned = nulint;
1836 resp->nextResultSetPosition = nulint;
1837 resp->searchStatus = nulint;
1838 resp->resultSetStatus = none;
1839 resp->presentStatus = 0;
1843 int *toget = odr_intdup(assoc->encode, 0);
1844 int *presst = odr_intdup(assoc->encode, 0);
1845 Z_RecordComposition comp, *compp = 0;
1847 yaz_log (log_requestdetail, "resultCount: %d", bsrt->hits);
1850 resp->resultCount = &bsrt->hits;
1852 comp.which = Z_RecordComp_simple;
1853 /* how many records does the user agent want, then? */
1854 if (bsrt->hits <= *req->smallSetUpperBound)
1856 *toget = bsrt->hits;
1857 if ((comp.u.simple = req->smallSetElementSetNames))
1860 else if (bsrt->hits < *req->largeSetLowerBound)
1862 *toget = *req->mediumSetPresentNumber;
1863 if (*toget > bsrt->hits)
1864 *toget = bsrt->hits;
1865 if ((comp.u.simple = req->mediumSetElementSetNames))
1871 if (*toget && !resp->records)
1876 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1879 form = prefformat->value;
1880 resp->records = pack_records(assoc, req->resultSetName, 1,
1881 toget, compp, next, presst, form, req->referenceId,
1882 req->preferredRecordSyntax, NULL);
1885 resp->numberOfRecordsReturned = toget;
1886 returnedrecs=*toget;
1887 resp->nextResultSetPosition = next;
1888 resp->searchStatus = sr;
1889 resp->resultSetStatus = 0;
1890 resp->presentStatus = presst;
1894 if (*resp->resultCount)
1896 resp->numberOfRecordsReturned = nulint;
1897 resp->nextResultSetPosition = next;
1898 resp->searchStatus = sr;
1899 resp->resultSetStatus = 0;
1900 resp->presentStatus = 0;
1903 resp->additionalSearchInfo = bsrt->search_info;
1907 WRBUF wr=wrbuf_alloc();
1908 wrbuf_put_zquery(wr, req->query);
1910 wrbuf_printf(wr," ERROR %d %s", bsrt->errcode, bsrt->errstring);
1913 wrbuf_printf(wr," OK:%d hits ",bsrt->hits);
1915 wrbuf_printf(wr," Returned %d records", returnedrecs);
1917 yaz_log(log_request, "Search %s", wrbuf_buf(wr) );
1924 * Maybe we got a little over-friendly when we designed bend_fetch to
1925 * get only one record at a time. Some backends can optimise multiple-record
1926 * fetches, and at any rate, there is some overhead involved in
1927 * all that selecting and hopping around. Problem is, of course, that the
1928 * frontend can't know ahead of time how many records it'll need to
1929 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1930 * is downright lousy as a bulk data transfer protocol.
1932 * To start with, we'll do the fetching of records from the backend
1933 * in one operation: To save some trips in and out of the event-handler,
1934 * and to simplify the interface to pack_records. At any rate, asynch
1935 * operation is more fun in operations that have an unpredictable execution
1936 * speed - which is normally more true for search than for present.
1938 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1941 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1945 Z_PresentResponse *resp;
1950 yaz_log(log_requestdetail, "Got PresentRequest.");
1952 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1955 form = prefformat->value;
1956 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1958 resp->presentStatus = odr_intdup(assoc->encode, 0);
1959 if (assoc->init->bend_present)
1961 bend_present_rr *bprr = (bend_present_rr *)
1962 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1963 bprr->setname = req->resultSetId;
1964 bprr->start = *req->resultSetStartPoint;
1965 bprr->number = *req->numberOfRecordsRequested;
1966 bprr->format = form;
1967 bprr->comp = req->recordComposition;
1968 bprr->referenceId = req->referenceId;
1969 bprr->stream = assoc->encode;
1970 bprr->print = assoc->print;
1971 bprr->request = reqb;
1972 bprr->association = assoc;
1974 bprr->errstring = NULL;
1975 (*assoc->init->bend_present)(assoc->backend, bprr);
1978 return 0; /* should not happen */
1981 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1982 *resp->presentStatus = Z_PresentStatus_failure;
1983 errcode=bprr->errcode;
1986 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1987 next = odr_intdup(assoc->encode, 0);
1988 num = odr_intdup(assoc->encode, 0);
1990 apdu->which = Z_APDU_presentResponse;
1991 apdu->u.presentResponse = resp;
1992 resp->referenceId = req->referenceId;
1993 resp->otherInfo = 0;
1997 *num = *req->numberOfRecordsRequested;
1999 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
2000 num, req->recordComposition, next, resp->presentStatus,
2001 form, req->referenceId, req->preferredRecordSyntax,
2006 resp->numberOfRecordsReturned = num;
2007 resp->nextResultSetPosition = next;
2010 WRBUF wr=wrbuf_alloc();
2011 wrbuf_printf(wr, "Present: [%s] %d+%d ",
2012 req->resultSetId, *req->resultSetStartPoint,
2013 *req->numberOfRecordsRequested);
2014 if (*resp->presentStatus == Z_PresentStatus_failure)
2016 wrbuf_printf(wr," ERROR %d ", errcode);
2018 else if (*resp->presentStatus == Z_PresentStatus_success)
2019 wrbuf_printf(wr," OK %d records returned ", *num);
2021 wrbuf_printf(wr," Partial (%d) OK %d records returned ",
2022 *resp->presentStatus, *num);
2023 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2031 * Scan was implemented rather in a hurry, and with support for only the basic
2032 * elements of the service in the backend API. Suggestions are welcome.
2034 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2036 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2037 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2038 Z_ScanResponse *res = (Z_ScanResponse *)
2039 odr_malloc (assoc->encode, sizeof(*res));
2040 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2041 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2042 Z_ListEntries *ents = (Z_ListEntries *)
2043 odr_malloc (assoc->encode, sizeof(*ents));
2044 Z_DiagRecs *diagrecs_p = NULL;
2046 bend_scan_rr *bsrr = (bend_scan_rr *)
2047 odr_malloc (assoc->encode, sizeof(*bsrr));
2048 struct scan_entry *save_entries;
2050 yaz_log(log_requestdetail, "Got ScanRequest");
2052 apdu->which = Z_APDU_scanResponse;
2053 apdu->u.scanResponse = res;
2054 res->referenceId = req->referenceId;
2056 /* if step is absent, set it to 0 */
2057 res->stepSize = odr_intdup(assoc->encode, 0);
2059 *res->stepSize = *req->stepSize;
2061 res->scanStatus = scanStatus;
2062 res->numberOfEntriesReturned = numberOfEntriesReturned;
2063 res->positionOfTerm = 0;
2064 res->entries = ents;
2065 ents->num_entries = 0;
2066 ents->entries = NULL;
2067 ents->num_nonsurrogateDiagnostics = 0;
2068 ents->nonsurrogateDiagnostics = NULL;
2069 res->attributeSet = 0;
2072 if (req->databaseNames)
2075 for (i = 0; i < req->num_databaseNames; i++)
2076 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
2078 yaz_log(log_requestdetail, "pos %d step %d entries %d",
2079 *req->preferredPositionInResponse, *res->stepSize,
2080 *req->numberOfTermsRequested);
2081 bsrr->num_bases = req->num_databaseNames;
2082 bsrr->basenames = req->databaseNames;
2083 bsrr->num_entries = *req->numberOfTermsRequested;
2084 bsrr->term = req->termListAndStartPoint;
2085 bsrr->referenceId = req->referenceId;
2086 bsrr->stream = assoc->encode;
2087 bsrr->print = assoc->print;
2088 bsrr->step_size = res->stepSize;
2090 /* Note that version 2.0 of YAZ and older did not set entries ..
2091 We do now. And when we do it's easier to extend the scan entry
2092 We know that if the scan handler did set entries, it will
2093 not know of new member display_term.
2095 if (bsrr->num_entries > 0)
2098 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2100 for (i = 0; i<bsrr->num_entries; i++)
2102 bsrr->entries[i].term = 0;
2103 bsrr->entries[i].occurrences = 0;
2104 bsrr->entries[i].errcode = 0;
2105 bsrr->entries[i].errstring = 0;
2106 bsrr->entries[i].display_term = 0;
2109 save_entries = bsrr->entries; /* save it so we can compare later */
2111 if (req->attributeSet &&
2112 (attset = oid_getentbyoid(req->attributeSet)) &&
2113 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2114 bsrr->attributeset = attset->value;
2116 bsrr->attributeset = VAL_NONE;
2117 log_scan_term_level (log_requestdetail, req->termListAndStartPoint,
2118 bsrr->attributeset);
2119 bsrr->term_position = req->preferredPositionInResponse ?
2120 *req->preferredPositionInResponse : 1;
2122 ((int (*)(void *, bend_scan_rr *))
2123 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2126 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2130 Z_Entry **tab = (Z_Entry **)
2131 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2133 if (bsrr->status == BEND_SCAN_PARTIAL)
2134 *scanStatus = Z_Scan_partial_5;
2136 *scanStatus = Z_Scan_success;
2137 ents->entries = tab;
2138 ents->num_entries = bsrr->num_entries;
2139 res->numberOfEntriesReturned = &ents->num_entries;
2140 res->positionOfTerm = &bsrr->term_position;
2141 for (i = 0; i < bsrr->num_entries; i++)
2147 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2148 if (bsrr->entries[i].occurrences >= 0)
2150 e->which = Z_Entry_termInfo;
2151 e->u.termInfo = t = (Z_TermInfo *)
2152 odr_malloc(assoc->encode, sizeof(*t));
2153 t->suggestedAttributes = 0;
2155 if (save_entries == bsrr->entries &&
2156 bsrr->entries[i].display_term)
2158 /* the entries was NOT set by the handler. So it's
2159 safe to test for new member display_term. It is
2162 t->displayTerm = odr_strdup(assoc->encode,
2163 bsrr->entries[i].display_term);
2165 t->alternativeTerm = 0;
2166 t->byAttributes = 0;
2167 t->otherTermInfo = 0;
2168 t->globalOccurrences = &bsrr->entries[i].occurrences;
2169 t->term = (Z_Term *)
2170 odr_malloc(assoc->encode, sizeof(*t->term));
2171 t->term->which = Z_Term_general;
2172 t->term->u.general = o =
2173 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2174 o->buf = (unsigned char *)
2175 odr_malloc(assoc->encode, o->len = o->size =
2176 strlen(bsrr->entries[i].term));
2177 memcpy(o->buf, bsrr->entries[i].term, o->len);
2178 yaz_log(YLOG_DEBUG, " term #%d: '%s' (%d)", i,
2179 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2183 Z_DiagRecs *drecs = diagrecs (assoc,
2184 bsrr->entries[i].errcode,
2185 bsrr->entries[i].errstring);
2186 assert (drecs->num_diagRecs == 1);
2187 e->which = Z_Entry_surrogateDiagnostic;
2188 assert (drecs->diagRecs[0]);
2189 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2195 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2196 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2200 WRBUF wr=wrbuf_alloc();
2201 wrbuf_printf(wr, "Scan %d@%d ",
2202 *req->preferredPositionInResponse,
2203 *req->numberOfTermsRequested);
2205 wrbuf_printf(wr, "(step %d) ",*res->stepSize);
2206 wrbuf_scan_term(wr, req->termListAndStartPoint,
2207 bsrr->attributeset);
2209 if (*res->scanStatus == Z_Scan_success)
2211 wrbuf_printf(wr," OK");
2214 wrbuf_printf(wr," Error");
2215 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2221 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2225 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2226 Z_SortResponse *res = (Z_SortResponse *)
2227 odr_malloc (assoc->encode, sizeof(*res));
2228 bend_sort_rr *bsrr = (bend_sort_rr *)
2229 odr_malloc (assoc->encode, sizeof(*bsrr));
2231 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2233 yaz_log(log_requestdetail, "Got SortRequest.");
2235 bsrr->num_input_setnames = req->num_inputResultSetNames;
2236 for (i=0;i<req->num_inputResultSetNames;i++)
2237 yaz_log(log_requestdetail, "Input resultset: '%s'",
2238 req->inputResultSetNames[i]);
2239 bsrr->input_setnames = req->inputResultSetNames;
2240 bsrr->referenceId = req->referenceId;
2241 bsrr->output_setname = req->sortedResultSetName;
2242 yaz_log(log_requestdetail, "Output resultset: '%s'",
2243 req->sortedResultSetName);
2244 bsrr->sort_sequence = req->sortSequence;
2245 /*FIXME - dump those sequences too */
2246 bsrr->stream = assoc->encode;
2247 bsrr->print = assoc->print;
2249 bsrr->sort_status = Z_SortResponse_failure;
2251 bsrr->errstring = 0;
2253 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2255 res->referenceId = bsrr->referenceId;
2256 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2257 res->resultSetStatus = 0;
2260 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2261 res->diagnostics = dr->diagRecs;
2262 res->num_diagnostics = dr->num_diagRecs;
2266 res->num_diagnostics = 0;
2267 res->diagnostics = 0;
2269 res->resultCount = 0;
2272 apdu->which = Z_APDU_sortResponse;
2273 apdu->u.sortResponse = res;
2276 WRBUF wr=wrbuf_alloc();
2277 wrbuf_printf(wr, "Sort (");
2278 for (i=0;i<req->num_inputResultSetNames;i++)
2281 wrbuf_printf(wr,",");
2282 wrbuf_printf(wr, req->inputResultSetNames[i]);
2284 wrbuf_printf(wr,")->%s ",req->sortedResultSetName);
2286 /* FIXME - dump also the sort sequence */
2288 wrbuf_diags(wr, res->num_diagnostics, res->diagnostics);
2290 wrbuf_printf(wr," OK");
2291 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2297 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2301 Z_DeleteResultSetRequest *req =
2302 reqb->apdu_request->u.deleteResultSetRequest;
2303 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2304 odr_malloc (assoc->encode, sizeof(*res));
2305 bend_delete_rr *bdrr = (bend_delete_rr *)
2306 odr_malloc (assoc->encode, sizeof(*bdrr));
2307 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2309 yaz_log(log_requestdetail, "Got DeleteRequest.");
2311 bdrr->num_setnames = req->num_resultSetList;
2312 bdrr->setnames = req->resultSetList;
2313 for (i=0;i<req->num_resultSetList;i++)
2314 yaz_log(log_requestdetail, "resultset: '%s'",
2315 req->resultSetList[i]);
2316 bdrr->stream = assoc->encode;
2317 bdrr->print = assoc->print;
2318 bdrr->function = *req->deleteFunction;
2319 bdrr->referenceId = req->referenceId;
2321 if (bdrr->num_setnames > 0)
2323 bdrr->statuses = (int*)
2324 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2325 bdrr->num_setnames);
2326 for (i = 0; i < bdrr->num_setnames; i++)
2327 bdrr->statuses[i] = 0;
2329 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2331 res->referenceId = req->referenceId;
2333 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2335 res->deleteListStatuses = 0;
2336 if (bdrr->num_setnames > 0)
2339 res->deleteListStatuses = (Z_ListStatuses *)
2340 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2341 res->deleteListStatuses->num = bdrr->num_setnames;
2342 res->deleteListStatuses->elements =
2344 odr_malloc (assoc->encode,
2345 sizeof(*res->deleteListStatuses->elements) *
2346 bdrr->num_setnames);
2347 for (i = 0; i<bdrr->num_setnames; i++)
2349 res->deleteListStatuses->elements[i] =
2351 odr_malloc (assoc->encode,
2352 sizeof(**res->deleteListStatuses->elements));
2353 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2354 res->deleteListStatuses->elements[i]->id =
2355 odr_strdup (assoc->encode, bdrr->setnames[i]);
2359 res->numberNotDeleted = 0;
2360 res->bulkStatuses = 0;
2361 res->deleteMessage = 0;
2364 apdu->which = Z_APDU_deleteResultSetResponse;
2365 apdu->u.deleteResultSetResponse = res;
2368 WRBUF wr=wrbuf_alloc();
2369 wrbuf_printf(wr, "Delete ");
2370 for (i=0;i<req->num_resultSetList;i++)
2371 wrbuf_printf(wr, " '%s' ", req->resultSetList[i]);
2372 if (bdrr->delete_status)
2373 wrbuf_printf(wr," ERROR %d", bdrr->delete_status);
2375 wrbuf_printf(wr,"OK");
2376 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2382 static void process_close(association *assoc, request *reqb)
2384 Z_Close *req = reqb->apdu_request->u.close;
2385 static char *reasons[] =
2392 "securityViolation",
2399 yaz_log(log_requestdetail, "Got Close, reason %s, message %s",
2400 reasons[*req->closeReason], req->diagnosticInformation ?
2401 req->diagnosticInformation : "NULL");
2402 if (assoc->version < 3) /* to make do_force respond with close */
2404 do_close_req(assoc, Z_Close_finished,
2405 "Association terminated by client", reqb);
2406 yaz_log(log_request,"Close OK");
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 (YLOG_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_requestdetail,"Got 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_request,"EsRequest OK: 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_request,"EsRequest OK: 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(YLOG_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;
2545 WRBUF wr=wrbuf_alloc();
2546 wrbuf_diags(wr, resp->num_diagnostics, resp->diagnostics);
2547 yaz_log(log_request, "EsRequest %s", wrbuf_buf(wr) );
2552 /* Do something with the members of bend_extendedservice */
2553 if (esrequest.taskPackage)
2554 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2555 (const char *) esrequest.taskPackage,
2557 yaz_log(YLOG_DEBUG,"Send the result apdu");