2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.38 2004-12-13 14:21:55 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));
1225 req->response = odr_getbuf(assoc->encode, &req->len_response,
1226 &req->size_response);
1227 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1228 odr_reset(assoc->encode);
1229 req->state = REQUEST_IDLE;
1230 request_enq(&assoc->outgoing, req);
1231 /* turn the work over to the ir_session handler */
1232 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1233 assoc->cs_put_mask = EVENT_OUTPUT;
1234 /* Is there more work to be done? give that to the input handler too */
1236 if (request_head(&assoc->incoming))
1238 yaz_log (YLOG_DEBUG, "more work to be done");
1239 iochan_setevent(assoc->client_chan, EVENT_WORK);
1246 * Encode response, and transfer the request structure to the outgoing queue.
1248 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1250 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1251 gres->which = Z_GDU_Z3950;
1252 gres->u.z3950 = res;
1254 return process_gdu_response(assoc, req, gres);
1259 * Handle init request.
1260 * At the moment, we don't check the options
1261 * anywhere else in the code - we just try not to do anything that would
1262 * break a naive client. We'll toss 'em into the association block when
1263 * we need them there.
1265 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1267 statserv_options_block *cb = statserv_getcontrol();
1268 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1269 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1270 Z_InitResponse *resp = apdu->u.initResponse;
1271 bend_initresult *binitres;
1275 yaz_log(log_requestdetail, "Got initRequest");
1276 if (req->implementationId)
1277 yaz_log(log_requestdetail, "Id: %s", req->implementationId);
1278 if (req->implementationName)
1279 yaz_log(log_requestdetail, "Name: %s", req->implementationName);
1280 if (req->implementationVersion)
1281 yaz_log(log_requestdetail, "Version: %s", req->implementationVersion);
1283 assoc_init_reset(assoc);
1285 assoc->init->auth = req->idAuthentication;
1286 assoc->init->referenceId = req->referenceId;
1288 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1290 Z_CharSetandLanguageNegotiation *negotiation =
1291 yaz_get_charneg_record (req->otherInfo);
1293 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1294 assoc->init->charneg_request = negotiation;
1298 if (!(binitres = (*cb->bend_init)(assoc->init)))
1300 yaz_log(YLOG_WARN, "Bad response from backend.");
1304 assoc->backend = binitres->handle;
1305 if ((assoc->init->bend_sort))
1306 yaz_log (YLOG_DEBUG, "Sort handler installed");
1307 if ((assoc->init->bend_search))
1308 yaz_log (YLOG_DEBUG, "Search handler installed");
1309 if ((assoc->init->bend_present))
1310 yaz_log (YLOG_DEBUG, "Present handler installed");
1311 if ((assoc->init->bend_esrequest))
1312 yaz_log (YLOG_DEBUG, "ESRequest handler installed");
1313 if ((assoc->init->bend_delete))
1314 yaz_log (YLOG_DEBUG, "Delete handler installed");
1315 if ((assoc->init->bend_scan))
1316 yaz_log (YLOG_DEBUG, "Scan handler installed");
1317 if ((assoc->init->bend_segment))
1318 yaz_log (YLOG_DEBUG, "Segment handler installed");
1320 resp->referenceId = req->referenceId;
1322 /* let's tell the client what we can do */
1323 if (ODR_MASK_GET(req->options, Z_Options_search))
1325 ODR_MASK_SET(resp->options, Z_Options_search);
1326 strcat(options, "srch");
1328 if (ODR_MASK_GET(req->options, Z_Options_present))
1330 ODR_MASK_SET(resp->options, Z_Options_present);
1331 strcat(options, " prst");
1333 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1334 assoc->init->bend_delete)
1336 ODR_MASK_SET(resp->options, Z_Options_delSet);
1337 strcat(options, " del");
1339 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1340 assoc->init->bend_esrequest)
1342 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1343 strcat (options, " extendedServices");
1345 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1347 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1348 strcat(options, " namedresults");
1350 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1352 ODR_MASK_SET(resp->options, Z_Options_scan);
1353 strcat(options, " scan");
1355 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1357 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1358 strcat(options, " concurrop");
1360 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1362 ODR_MASK_SET(resp->options, Z_Options_sort);
1363 strcat(options, " sort");
1366 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1367 && assoc->init->charneg_response)
1369 Z_OtherInformation **p;
1370 Z_OtherInformationUnit *p0;
1372 yaz_oi_APDU(apdu, &p);
1374 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1375 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1377 p0->which = Z_OtherInfo_externallyDefinedInfo;
1378 p0->information.externallyDefinedInfo =
1379 assoc->init->charneg_response;
1381 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1382 strcat(options, " negotiation");
1385 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1387 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1389 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1390 assoc->version = 1; /* 1 & 2 are equivalent */
1392 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1394 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1397 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1399 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1403 yaz_log(log_requestdetail, "Negotiated to v%d: %s", assoc->version, options);
1404 assoc->maximumRecordSize = *req->maximumRecordSize;
1405 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1406 assoc->maximumRecordSize = control_block->maxrecordsize;
1407 assoc->preferredMessageSize = *req->preferredMessageSize;
1408 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1409 assoc->preferredMessageSize = assoc->maximumRecordSize;
1411 resp->preferredMessageSize = &assoc->preferredMessageSize;
1412 resp->maximumRecordSize = &assoc->maximumRecordSize;
1414 resp->implementationId = odr_prepend(assoc->encode,
1415 assoc->init->implementation_id,
1416 resp->implementationId);
1418 resp->implementationName = odr_prepend(assoc->encode,
1419 assoc->init->implementation_name,
1420 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1422 version = odr_strdup(assoc->encode, "$Revision: 1.38 $");
1423 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1424 version[strlen(version)-2] = '\0';
1425 resp->implementationVersion = odr_prepend(assoc->encode,
1426 assoc->init->implementation_version,
1427 odr_prepend(assoc->encode, &version[11],
1428 resp->implementationVersion));
1430 if (binitres->errcode)
1432 yaz_log(YLOG_DEBUG, "Connection rejected by backend.");
1434 assoc->state = ASSOC_DEAD;
1435 resp->userInformationField = init_diagnostics(assoc->encode,
1437 binitres->errstring);
1438 yaz_log(log_request,"Init from '%s' (%s) (ver %s) Error %d %s",
1439 req->implementationName ? req->implementationName :"??",
1440 req->implementationId ? req->implementationId :"?",
1441 req->implementationVersion ? req->implementationVersion: "?",
1442 binitres->errcode,binitres->errstring );
1446 assoc->state = ASSOC_UP;
1447 yaz_log(log_request,"Init from '%s' (%s) (ver %s) OK",
1448 req->implementationName ? req->implementationName :"??",
1449 req->implementationId ? req->implementationId :"?",
1450 req->implementationVersion ? req->implementationVersion: "?");
1457 * Diagnostic in default format, to be returned as either a surrogate
1458 * or non-surrogate diagnostic in the context of an open session, or
1459 * as User-information when an Init is refused.
1461 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1463 int *err = odr_intdup(odr, error);
1464 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1465 odr_malloc (odr, sizeof(*dr));
1467 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1468 addinfo ? " -- " : "", addinfo ? addinfo : "");
1470 dr->diagnosticSetId =
1471 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1472 dr->condition = err;
1473 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1474 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1479 * Set the specified `errcode' and `errstring' into a UserInfo-1
1480 * external to be returned to the client in accordance with Z35.90
1481 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1482 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1484 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1488 Z_OtherInformation *u;
1489 Z_OtherInformationUnit *l;
1490 Z_DiagnosticFormat *d;
1491 Z_DiagnosticFormat_s *e;
1493 x = (Z_External*) odr_malloc(odr, sizeof *x);
1495 x->indirect_reference = 0;
1496 oid.proto = PROTO_Z3950;
1497 oid.oclass = CLASS_USERINFO;
1498 oid.value = VAL_USERINFO1;
1499 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1500 x->which = Z_External_userInfo1;
1502 u = odr_malloc(odr, sizeof *u);
1504 u->num_elements = 1;
1505 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1506 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1509 l->which = Z_OtherInfo_externallyDefinedInfo;
1511 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1512 l->information.externallyDefinedInfo = x2;
1514 x2->indirect_reference = 0;
1515 oid.oclass = CLASS_DIAGSET;
1516 oid.value = VAL_DIAG1;
1517 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1518 x2->which = Z_External_diag1;
1520 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1523 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1524 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1527 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1528 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1534 * nonsurrogate diagnostic record.
1536 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1538 Z_Records *rec = (Z_Records *)
1539 odr_malloc (assoc->encode, sizeof(*rec));
1540 rec->which = Z_Records_NSD;
1541 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1546 * surrogate diagnostic.
1548 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1549 int error, char *addinfo)
1551 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1552 odr_malloc (assoc->encode, sizeof(*rec));
1553 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1555 yaz_log(YLOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1556 rec->databaseName = dbname;
1557 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1558 rec->u.surrogateDiagnostic = drec;
1559 drec->which = Z_DiagRec_defaultFormat;
1560 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1566 * multiple nonsurrogate diagnostics.
1568 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1570 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1571 int *err = odr_intdup(assoc->encode, error);
1572 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1573 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1574 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1575 odr_malloc (assoc->encode, sizeof(*rec));
1577 yaz_log(YLOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1579 recs->num_diagRecs = 1;
1580 recs->diagRecs = recp;
1582 drec->which = Z_DiagRec_defaultFormat;
1583 drec->u.defaultFormat = rec;
1585 rec->diagnosticSetId =
1586 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1587 rec->condition = err;
1589 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1590 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1594 static Z_Records *pack_records(association *a, char *setname, int start,
1595 int *num, Z_RecordComposition *comp,
1596 int *next, int *pres, oid_value format,
1597 Z_ReferenceId *referenceId,
1598 int *oid, int *errcode)
1600 int recno, total_length = 0, toget = *num, dumped_records = 0;
1601 Z_Records *records =
1602 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1603 Z_NamePlusRecordList *reclist =
1604 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1605 Z_NamePlusRecord **list =
1606 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1609 records->which = Z_Records_DBOSD;
1610 records->u.databaseOrSurDiagnostics = reclist;
1611 reclist->num_records = 0;
1612 reclist->records = list;
1613 *pres = Z_PresentStatus_success;
1617 yaz_log(log_requestdetail, "Request to pack %d+%d %s", start, toget, setname);
1618 yaz_log(log_requestdetail, "pms=%d, mrs=%d", a->preferredMessageSize,
1619 a->maximumRecordSize);
1620 for (recno = start; reclist->num_records < toget; recno++)
1623 Z_NamePlusRecord *thisrec;
1624 int this_length = 0;
1626 * we get the number of bytes allocated on the stream before any
1627 * allocation done by the backend - this should give us a reasonable
1628 * idea of the total size of the data so far.
1630 total_length = odr_total(a->encode) - dumped_records;
1636 freq.last_in_set = 0;
1637 freq.setname = setname;
1638 freq.surrogate_flag = 0;
1639 freq.number = recno;
1641 freq.request_format = format;
1642 freq.request_format_raw = oid;
1643 freq.output_format = format;
1644 freq.output_format_raw = 0;
1645 freq.stream = a->encode;
1646 freq.print = a->print;
1647 freq.referenceId = referenceId;
1649 (*a->init->bend_fetch)(a->backend, &freq);
1650 /* backend should be able to signal whether error is system-wide
1651 or only pertaining to current record */
1654 if (!freq.surrogate_flag)
1657 *pres = Z_PresentStatus_failure;
1658 /* for 'present request out of range',
1659 set addinfo to record position if not set */
1660 if (freq.errcode == 13 && freq.errstring == 0)
1662 sprintf (s, "%d", recno);
1666 *errcode=freq.errcode;
1667 return diagrec(a, freq.errcode, freq.errstring);
1669 reclist->records[reclist->num_records] =
1670 surrogatediagrec(a, freq.basename, freq.errcode,
1672 reclist->num_records++;
1673 *next = freq.last_in_set ? 0 : recno + 1;
1677 this_length = freq.len;
1679 this_length = odr_total(a->encode) - total_length - dumped_records;
1680 yaz_log(YLOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1681 this_length, total_length, dumped_records);
1682 if (a->preferredMessageSize > 0 &&
1683 this_length + total_length > a->preferredMessageSize)
1685 /* record is small enough, really */
1686 if (this_length <= a->preferredMessageSize && recno > start)
1688 yaz_log(log_requestdetail, " Dropped last normal-sized record");
1689 *pres = Z_PresentStatus_partial_2;
1692 /* record can only be fetched by itself */
1693 if (this_length < a->maximumRecordSize)
1695 yaz_log(log_requestdetail, " Record > prefmsgsz");
1698 yaz_log(YLOG_DEBUG, " Dropped it");
1699 reclist->records[reclist->num_records] =
1700 surrogatediagrec(a, freq.basename, 16, 0);
1701 reclist->num_records++;
1702 *next = freq.last_in_set ? 0 : recno + 1;
1703 dumped_records += this_length;
1707 else /* too big entirely */
1709 yaz_log(log_requestdetail, "Record > maxrcdsz this=%d max=%d",
1710 this_length, a->maximumRecordSize);
1711 reclist->records[reclist->num_records] =
1712 surrogatediagrec(a, freq.basename, 17, 0);
1713 reclist->num_records++;
1714 *next = freq.last_in_set ? 0 : recno + 1;
1715 dumped_records += this_length;
1720 if (!(thisrec = (Z_NamePlusRecord *)
1721 odr_malloc(a->encode, sizeof(*thisrec))))
1723 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1724 strlen(freq.basename) + 1)))
1726 strcpy(thisrec->databaseName, freq.basename);
1727 thisrec->which = Z_NamePlusRecord_databaseRecord;
1729 if (freq.output_format_raw)
1731 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1732 freq.output_format = ident->value;
1734 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1735 freq.record, freq.len);
1736 if (!thisrec->u.databaseRecord)
1738 reclist->records[reclist->num_records] = thisrec;
1739 reclist->num_records++;
1740 *next = freq.last_in_set ? 0 : recno + 1;
1742 *num = reclist->num_records;
1746 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1749 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1750 bend_search_rr *bsrr =
1751 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1753 yaz_log(log_requestdetail, "Got SearchRequest.");
1755 bsrr->request = reqb;
1756 bsrr->association = assoc;
1757 bsrr->referenceId = req->referenceId;
1758 save_referenceId (reqb, bsrr->referenceId);
1760 yaz_log (log_requestdetail, "ResultSet '%s'", req->resultSetName);
1761 if (req->databaseNames)
1764 for (i = 0; i < req->num_databaseNames; i++)
1765 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
1768 yaz_log_zquery_level(log_requestdetail,req->query);
1770 if (assoc->init->bend_search)
1772 bsrr->setname = req->resultSetName;
1773 bsrr->replace_set = *req->replaceIndicator;
1774 bsrr->num_bases = req->num_databaseNames;
1775 bsrr->basenames = req->databaseNames;
1776 bsrr->query = req->query;
1777 bsrr->stream = assoc->encode;
1778 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1779 bsrr->decode = assoc->decode;
1780 bsrr->print = assoc->print;
1783 bsrr->errstring = NULL;
1784 bsrr->search_info = NULL;
1785 (assoc->init->bend_search)(assoc->backend, bsrr);
1786 if (!bsrr->request) /* backend not ready with the search response */
1787 return 0; /* should not be used any more */
1791 /* FIXME - make a diagnostic for it */
1792 yaz_log(YLOG_WARN,"Search not supported ?!?!");
1794 return response_searchRequest(assoc, reqb, bsrr, fd);
1797 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1800 * Prepare a searchresponse based on the backend results. We probably want
1801 * to look at making the fetching of records nonblocking as well, but
1802 * so far, we'll keep things simple.
1803 * If bsrt is null, that means we're called in response to a communications
1804 * event, and we'll have to get the response for ourselves.
1806 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1807 bend_search_rr *bsrt, int *fd)
1809 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1810 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1811 Z_SearchResponse *resp = (Z_SearchResponse *)
1812 odr_malloc (assoc->encode, sizeof(*resp));
1813 int *nulint = odr_intdup (assoc->encode, 0);
1814 bool_t *sr = odr_intdup(assoc->encode, 1);
1815 int *next = odr_intdup(assoc->encode, 0);
1816 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1819 apdu->which = Z_APDU_searchResponse;
1820 apdu->u.searchResponse = resp;
1821 resp->referenceId = req->referenceId;
1822 resp->additionalSearchInfo = 0;
1823 resp->otherInfo = 0;
1825 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1827 yaz_log(YLOG_FATAL, "Bad result from backend");
1830 else if (bsrt->errcode)
1832 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1833 resp->resultCount = nulint;
1834 resp->numberOfRecordsReturned = nulint;
1835 resp->nextResultSetPosition = nulint;
1836 resp->searchStatus = nulint;
1837 resp->resultSetStatus = none;
1838 resp->presentStatus = 0;
1842 int *toget = odr_intdup(assoc->encode, 0);
1843 int *presst = odr_intdup(assoc->encode, 0);
1844 Z_RecordComposition comp, *compp = 0;
1846 yaz_log (log_requestdetail, "resultCount: %d", bsrt->hits);
1849 resp->resultCount = &bsrt->hits;
1851 comp.which = Z_RecordComp_simple;
1852 /* how many records does the user agent want, then? */
1853 if (bsrt->hits <= *req->smallSetUpperBound)
1855 *toget = bsrt->hits;
1856 if ((comp.u.simple = req->smallSetElementSetNames))
1859 else if (bsrt->hits < *req->largeSetLowerBound)
1861 *toget = *req->mediumSetPresentNumber;
1862 if (*toget > bsrt->hits)
1863 *toget = bsrt->hits;
1864 if ((comp.u.simple = req->mediumSetElementSetNames))
1870 if (*toget && !resp->records)
1875 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1878 form = prefformat->value;
1879 resp->records = pack_records(assoc, req->resultSetName, 1,
1880 toget, compp, next, presst, form, req->referenceId,
1881 req->preferredRecordSyntax, NULL);
1884 resp->numberOfRecordsReturned = toget;
1885 returnedrecs=*toget;
1886 resp->nextResultSetPosition = next;
1887 resp->searchStatus = sr;
1888 resp->resultSetStatus = 0;
1889 resp->presentStatus = presst;
1893 if (*resp->resultCount)
1895 resp->numberOfRecordsReturned = nulint;
1896 resp->nextResultSetPosition = next;
1897 resp->searchStatus = sr;
1898 resp->resultSetStatus = 0;
1899 resp->presentStatus = 0;
1902 resp->additionalSearchInfo = bsrt->search_info;
1906 WRBUF wr=wrbuf_alloc();
1907 wrbuf_put_zquery(wr, req->query);
1909 wrbuf_printf(wr," ERROR %d %s", bsrt->errcode, bsrt->errstring);
1912 wrbuf_printf(wr," OK:%d hits ",bsrt->hits);
1914 wrbuf_printf(wr," Returned %d records", returnedrecs);
1916 yaz_log(log_request, "Search %s", wrbuf_buf(wr) );
1923 * Maybe we got a little over-friendly when we designed bend_fetch to
1924 * get only one record at a time. Some backends can optimise multiple-record
1925 * fetches, and at any rate, there is some overhead involved in
1926 * all that selecting and hopping around. Problem is, of course, that the
1927 * frontend can't know ahead of time how many records it'll need to
1928 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1929 * is downright lousy as a bulk data transfer protocol.
1931 * To start with, we'll do the fetching of records from the backend
1932 * in one operation: To save some trips in and out of the event-handler,
1933 * and to simplify the interface to pack_records. At any rate, asynch
1934 * operation is more fun in operations that have an unpredictable execution
1935 * speed - which is normally more true for search than for present.
1937 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1940 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1944 Z_PresentResponse *resp;
1949 yaz_log(log_requestdetail, "Got PresentRequest.");
1951 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1954 form = prefformat->value;
1955 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1957 resp->presentStatus = odr_intdup(assoc->encode, 0);
1958 if (assoc->init->bend_present)
1960 bend_present_rr *bprr = (bend_present_rr *)
1961 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1962 bprr->setname = req->resultSetId;
1963 bprr->start = *req->resultSetStartPoint;
1964 bprr->number = *req->numberOfRecordsRequested;
1965 bprr->format = form;
1966 bprr->comp = req->recordComposition;
1967 bprr->referenceId = req->referenceId;
1968 bprr->stream = assoc->encode;
1969 bprr->print = assoc->print;
1970 bprr->request = reqb;
1971 bprr->association = assoc;
1973 bprr->errstring = NULL;
1974 (*assoc->init->bend_present)(assoc->backend, bprr);
1977 return 0; /* should not happen */
1980 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1981 *resp->presentStatus = Z_PresentStatus_failure;
1982 errcode=bprr->errcode;
1985 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1986 next = odr_intdup(assoc->encode, 0);
1987 num = odr_intdup(assoc->encode, 0);
1989 apdu->which = Z_APDU_presentResponse;
1990 apdu->u.presentResponse = resp;
1991 resp->referenceId = req->referenceId;
1992 resp->otherInfo = 0;
1996 *num = *req->numberOfRecordsRequested;
1998 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1999 num, req->recordComposition, next, resp->presentStatus,
2000 form, req->referenceId, req->preferredRecordSyntax,
2005 resp->numberOfRecordsReturned = num;
2006 resp->nextResultSetPosition = next;
2009 WRBUF wr=wrbuf_alloc();
2010 wrbuf_printf(wr, "Present: [%s] %d+%d ",
2011 req->resultSetId, *req->resultSetStartPoint,
2012 *req->numberOfRecordsRequested);
2013 if (*resp->presentStatus == Z_PresentStatus_failure)
2015 wrbuf_printf(wr," ERROR %d ", errcode);
2017 else if (*resp->presentStatus == Z_PresentStatus_success)
2018 wrbuf_printf(wr," OK %d records returned ", *num);
2020 wrbuf_printf(wr," Partial (%d) OK %d records returned ",
2021 *resp->presentStatus, *num);
2022 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2030 * Scan was implemented rather in a hurry, and with support for only the basic
2031 * elements of the service in the backend API. Suggestions are welcome.
2033 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
2035 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
2036 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2037 Z_ScanResponse *res = (Z_ScanResponse *)
2038 odr_malloc (assoc->encode, sizeof(*res));
2039 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
2040 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
2041 Z_ListEntries *ents = (Z_ListEntries *)
2042 odr_malloc (assoc->encode, sizeof(*ents));
2043 Z_DiagRecs *diagrecs_p = NULL;
2045 bend_scan_rr *bsrr = (bend_scan_rr *)
2046 odr_malloc (assoc->encode, sizeof(*bsrr));
2047 struct scan_entry *save_entries;
2049 yaz_log(log_requestdetail, "Got ScanRequest");
2051 apdu->which = Z_APDU_scanResponse;
2052 apdu->u.scanResponse = res;
2053 res->referenceId = req->referenceId;
2055 /* if step is absent, set it to 0 */
2056 res->stepSize = odr_intdup(assoc->encode, 0);
2058 *res->stepSize = *req->stepSize;
2060 res->scanStatus = scanStatus;
2061 res->numberOfEntriesReturned = numberOfEntriesReturned;
2062 res->positionOfTerm = 0;
2063 res->entries = ents;
2064 ents->num_entries = 0;
2065 ents->entries = NULL;
2066 ents->num_nonsurrogateDiagnostics = 0;
2067 ents->nonsurrogateDiagnostics = NULL;
2068 res->attributeSet = 0;
2071 if (req->databaseNames)
2074 for (i = 0; i < req->num_databaseNames; i++)
2075 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
2077 yaz_log(log_requestdetail, "pos %d step %d entries %d",
2078 *req->preferredPositionInResponse, *res->stepSize,
2079 *req->numberOfTermsRequested);
2080 bsrr->num_bases = req->num_databaseNames;
2081 bsrr->basenames = req->databaseNames;
2082 bsrr->num_entries = *req->numberOfTermsRequested;
2083 bsrr->term = req->termListAndStartPoint;
2084 bsrr->referenceId = req->referenceId;
2085 bsrr->stream = assoc->encode;
2086 bsrr->print = assoc->print;
2087 bsrr->step_size = res->stepSize;
2089 /* Note that version 2.0 of YAZ and older did not set entries ..
2090 We do now. And when we do it's easier to extend the scan entry
2091 We know that if the scan handler did set entries, it will
2092 not know of new member display_term.
2094 if (bsrr->num_entries > 0)
2097 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2099 for (i = 0; i<bsrr->num_entries; i++)
2101 bsrr->entries[i].term = 0;
2102 bsrr->entries[i].occurrences = 0;
2103 bsrr->entries[i].errcode = 0;
2104 bsrr->entries[i].errstring = 0;
2105 bsrr->entries[i].display_term = 0;
2108 save_entries = bsrr->entries; /* save it so we can compare later */
2110 if (req->attributeSet &&
2111 (attset = oid_getentbyoid(req->attributeSet)) &&
2112 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2113 bsrr->attributeset = attset->value;
2115 bsrr->attributeset = VAL_NONE;
2116 log_scan_term_level (log_requestdetail, req->termListAndStartPoint,
2117 bsrr->attributeset);
2118 bsrr->term_position = req->preferredPositionInResponse ?
2119 *req->preferredPositionInResponse : 1;
2121 ((int (*)(void *, bend_scan_rr *))
2122 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2125 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2129 Z_Entry **tab = (Z_Entry **)
2130 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2132 if (bsrr->status == BEND_SCAN_PARTIAL)
2133 *scanStatus = Z_Scan_partial_5;
2135 *scanStatus = Z_Scan_success;
2136 ents->entries = tab;
2137 ents->num_entries = bsrr->num_entries;
2138 res->numberOfEntriesReturned = &ents->num_entries;
2139 res->positionOfTerm = &bsrr->term_position;
2140 for (i = 0; i < bsrr->num_entries; i++)
2146 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2147 if (bsrr->entries[i].occurrences >= 0)
2149 e->which = Z_Entry_termInfo;
2150 e->u.termInfo = t = (Z_TermInfo *)
2151 odr_malloc(assoc->encode, sizeof(*t));
2152 t->suggestedAttributes = 0;
2154 if (save_entries == bsrr->entries &&
2155 bsrr->entries[i].display_term)
2157 /* the entries was NOT set by the handler. So it's
2158 safe to test for new member display_term. It is
2161 t->displayTerm = odr_strdup(assoc->encode,
2162 bsrr->entries[i].display_term);
2164 t->alternativeTerm = 0;
2165 t->byAttributes = 0;
2166 t->otherTermInfo = 0;
2167 t->globalOccurrences = &bsrr->entries[i].occurrences;
2168 t->term = (Z_Term *)
2169 odr_malloc(assoc->encode, sizeof(*t->term));
2170 t->term->which = Z_Term_general;
2171 t->term->u.general = o =
2172 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2173 o->buf = (unsigned char *)
2174 odr_malloc(assoc->encode, o->len = o->size =
2175 strlen(bsrr->entries[i].term));
2176 memcpy(o->buf, bsrr->entries[i].term, o->len);
2177 yaz_log(YLOG_DEBUG, " term #%d: '%s' (%d)", i,
2178 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2182 Z_DiagRecs *drecs = diagrecs (assoc,
2183 bsrr->entries[i].errcode,
2184 bsrr->entries[i].errstring);
2185 assert (drecs->num_diagRecs == 1);
2186 e->which = Z_Entry_surrogateDiagnostic;
2187 assert (drecs->diagRecs[0]);
2188 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2194 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2195 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2199 WRBUF wr=wrbuf_alloc();
2200 wrbuf_printf(wr, "Scan %d@%d ",
2201 *req->preferredPositionInResponse,
2202 *req->numberOfTermsRequested);
2204 wrbuf_printf(wr, "(step %d) ",*res->stepSize);
2205 wrbuf_scan_term(wr, req->termListAndStartPoint,
2206 bsrr->attributeset);
2208 if (*res->scanStatus == Z_Scan_success)
2210 wrbuf_printf(wr," OK");
2213 wrbuf_printf(wr," Error");
2214 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2220 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2224 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2225 Z_SortResponse *res = (Z_SortResponse *)
2226 odr_malloc (assoc->encode, sizeof(*res));
2227 bend_sort_rr *bsrr = (bend_sort_rr *)
2228 odr_malloc (assoc->encode, sizeof(*bsrr));
2230 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2232 yaz_log(log_requestdetail, "Got SortRequest.");
2234 bsrr->num_input_setnames = req->num_inputResultSetNames;
2235 for (i=0;i<req->num_inputResultSetNames;i++)
2236 yaz_log(log_requestdetail, "Input resultset: '%s'",
2237 req->inputResultSetNames[i]);
2238 bsrr->input_setnames = req->inputResultSetNames;
2239 bsrr->referenceId = req->referenceId;
2240 bsrr->output_setname = req->sortedResultSetName;
2241 yaz_log(log_requestdetail, "Output resultset: '%s'",
2242 req->sortedResultSetName);
2243 bsrr->sort_sequence = req->sortSequence;
2244 /*FIXME - dump those sequences too */
2245 bsrr->stream = assoc->encode;
2246 bsrr->print = assoc->print;
2248 bsrr->sort_status = Z_SortResponse_failure;
2250 bsrr->errstring = 0;
2252 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2254 res->referenceId = bsrr->referenceId;
2255 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2256 res->resultSetStatus = 0;
2259 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2260 res->diagnostics = dr->diagRecs;
2261 res->num_diagnostics = dr->num_diagRecs;
2265 res->num_diagnostics = 0;
2266 res->diagnostics = 0;
2268 res->resultCount = 0;
2271 apdu->which = Z_APDU_sortResponse;
2272 apdu->u.sortResponse = res;
2275 WRBUF wr=wrbuf_alloc();
2276 wrbuf_printf(wr, "Sort (");
2277 for (i=0;i<req->num_inputResultSetNames;i++)
2280 wrbuf_printf(wr,",");
2281 wrbuf_printf(wr, req->inputResultSetNames[i]);
2283 wrbuf_printf(wr,")->%s ",req->sortedResultSetName);
2285 /* FIXME - dump also the sort sequence */
2287 wrbuf_diags(wr, res->num_diagnostics, res->diagnostics);
2289 wrbuf_printf(wr," OK");
2290 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2296 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2300 Z_DeleteResultSetRequest *req =
2301 reqb->apdu_request->u.deleteResultSetRequest;
2302 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2303 odr_malloc (assoc->encode, sizeof(*res));
2304 bend_delete_rr *bdrr = (bend_delete_rr *)
2305 odr_malloc (assoc->encode, sizeof(*bdrr));
2306 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2308 yaz_log(log_requestdetail, "Got DeleteRequest.");
2310 bdrr->num_setnames = req->num_resultSetList;
2311 bdrr->setnames = req->resultSetList;
2312 for (i=0;i<req->num_resultSetList;i++)
2313 yaz_log(log_requestdetail, "resultset: '%s'",
2314 req->resultSetList[i]);
2315 bdrr->stream = assoc->encode;
2316 bdrr->print = assoc->print;
2317 bdrr->function = *req->deleteFunction;
2318 bdrr->referenceId = req->referenceId;
2320 if (bdrr->num_setnames > 0)
2322 bdrr->statuses = (int*)
2323 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2324 bdrr->num_setnames);
2325 for (i = 0; i < bdrr->num_setnames; i++)
2326 bdrr->statuses[i] = 0;
2328 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2330 res->referenceId = req->referenceId;
2332 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2334 res->deleteListStatuses = 0;
2335 if (bdrr->num_setnames > 0)
2338 res->deleteListStatuses = (Z_ListStatuses *)
2339 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2340 res->deleteListStatuses->num = bdrr->num_setnames;
2341 res->deleteListStatuses->elements =
2343 odr_malloc (assoc->encode,
2344 sizeof(*res->deleteListStatuses->elements) *
2345 bdrr->num_setnames);
2346 for (i = 0; i<bdrr->num_setnames; i++)
2348 res->deleteListStatuses->elements[i] =
2350 odr_malloc (assoc->encode,
2351 sizeof(**res->deleteListStatuses->elements));
2352 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2353 res->deleteListStatuses->elements[i]->id =
2354 odr_strdup (assoc->encode, bdrr->setnames[i]);
2358 res->numberNotDeleted = 0;
2359 res->bulkStatuses = 0;
2360 res->deleteMessage = 0;
2363 apdu->which = Z_APDU_deleteResultSetResponse;
2364 apdu->u.deleteResultSetResponse = res;
2367 WRBUF wr=wrbuf_alloc();
2368 wrbuf_printf(wr, "Delete ");
2369 for (i=0;i<req->num_resultSetList;i++)
2370 wrbuf_printf(wr, " '%s' ", req->resultSetList[i]);
2371 if (bdrr->delete_status)
2372 wrbuf_printf(wr," ERROR %d", bdrr->delete_status);
2374 wrbuf_printf(wr,"OK");
2375 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2381 static void process_close(association *assoc, request *reqb)
2383 Z_Close *req = reqb->apdu_request->u.close;
2384 static char *reasons[] =
2391 "securityViolation",
2398 yaz_log(log_requestdetail, "Got Close, reason %s, message %s",
2399 reasons[*req->closeReason], req->diagnosticInformation ?
2400 req->diagnosticInformation : "NULL");
2401 if (assoc->version < 3) /* to make do_force respond with close */
2403 do_close_req(assoc, Z_Close_finished,
2404 "Association terminated by client", reqb);
2405 yaz_log(log_request,"Close OK");
2408 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2412 reqb->len_refid = refid->len;
2413 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2414 memcpy (reqb->refid, refid->buf, refid->len);
2418 reqb->len_refid = 0;
2423 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2425 process_z_response (a, req, res);
2428 bend_request bend_request_mk (bend_association a)
2430 request *nreq = request_get (&a->outgoing);
2431 nreq->request_mem = nmem_create ();
2435 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2440 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2441 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2442 id->len = id->size = req->len_refid;
2443 memcpy (id->buf, req->refid, req->len_refid);
2447 void bend_request_destroy (bend_request *req)
2449 nmem_destroy((*req)->request_mem);
2450 request_release(*req);
2454 int bend_backend_respond (bend_association a, bend_request req)
2458 r = process_z_request (a, req, &msg);
2460 yaz_log (YLOG_WARN, "%s", msg);
2464 void bend_request_setdata(bend_request r, void *p)
2469 void *bend_request_getdata(bend_request r)
2471 return r->clientData;
2474 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2476 bend_segment_rr req;
2478 req.segment = reqb->apdu_request->u.segmentRequest;
2479 req.stream = assoc->encode;
2480 req.decode = assoc->decode;
2481 req.print = assoc->print;
2482 req.association = assoc;
2484 (*assoc->init->bend_segment)(assoc->backend, &req);
2489 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2491 bend_esrequest_rr esrequest;
2493 Z_ExtendedServicesRequest *req =
2494 reqb->apdu_request->u.extendedServicesRequest;
2495 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2497 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2499 yaz_log(log_requestdetail,"Got EsRequest");
2501 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2502 esrequest.stream = assoc->encode;
2503 esrequest.decode = assoc->decode;
2504 esrequest.print = assoc->print;
2505 esrequest.errcode = 0;
2506 esrequest.errstring = NULL;
2507 esrequest.request = reqb;
2508 esrequest.association = assoc;
2509 esrequest.taskPackage = 0;
2510 esrequest.referenceId = req->referenceId;
2512 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2514 /* If the response is being delayed, return NULL */
2515 if (esrequest.request == NULL)
2518 resp->referenceId = req->referenceId;
2520 if (esrequest.errcode == -1)
2522 /* Backend service indicates request will be processed */
2523 yaz_log(log_request,"EsRequest OK: Accepted !");
2524 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2526 else if (esrequest.errcode == 0)
2528 /* Backend service indicates request will be processed */
2529 yaz_log(log_request,"EsRequest OK: Done !");
2530 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2534 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2535 esrequest.errstring);
2537 /* Backend indicates error, request will not be processed */
2538 yaz_log(YLOG_DEBUG,"Request could not be processed...failure !");
2539 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2540 resp->num_diagnostics = diagRecs->num_diagRecs;
2541 resp->diagnostics = diagRecs->diagRecs;
2544 WRBUF wr=wrbuf_alloc();
2545 wrbuf_diags(wr, resp->num_diagnostics, resp->diagnostics);
2546 yaz_log(log_request, "EsRequest %s", wrbuf_buf(wr) );
2551 /* Do something with the members of bend_extendedservice */
2552 if (esrequest.taskPackage)
2553 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2554 (const char *) esrequest.taskPackage,
2556 yaz_log(YLOG_DEBUG,"Send the result apdu");