2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.42 2004-12-30 00:25:33 adam 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,
72 const char *errstring);
73 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
75 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
76 bend_search_rr *bsrr, int *fd);
77 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
79 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
80 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
81 static void process_close(association *assoc, request *reqb);
82 void save_referenceId (request *reqb, Z_ReferenceId *refid);
83 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
85 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
87 static FILE *apduf = 0; /* for use in static mode */
88 static statserv_options_block *control_block = 0;
90 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
92 /* dynamic logging levels */
93 static int logbits_set=0;
94 static int log_session=0;
95 static int log_request=0; /* one-line logs for requests */
96 static int log_requestdetail=0; /* more detailed stuff */
98 /** get_logbits sets global loglevel bits */
99 static void get_logbits()
100 { /* needs to be called after parsing cmd-line args that can set loglevels!*/
104 log_session=yaz_log_module_level("session");
105 log_request=yaz_log_module_level("request");
106 log_requestdetail=yaz_log_module_level("requestdetail");
110 static void wr_diag(WRBUF w, int error, const char *addinfo)
112 wrbuf_printf(w, "ERROR [%d] %s%s%s",
113 error, diagbib1_str(error),
114 addinfo ? "--" : "", addinfo ? addinfo : "");
119 * Create and initialize a new association-handle.
120 * channel : iochannel for the current line.
121 * link : communications channel.
122 * Returns: 0 or a new association handle.
124 association *create_association(IOCHAN channel, COMSTACK link)
131 control_block = statserv_getcontrol();
132 if (!(anew = (association *)xmalloc(sizeof(*anew))))
136 anew->client_chan = channel;
137 anew->client_link = link;
138 anew->cs_get_mask = 0;
139 anew->cs_put_mask = 0;
140 anew->cs_accept_mask = 0;
141 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
142 !(anew->encode = odr_createmem(ODR_ENCODE)))
144 if (*control_block->apdufile)
149 strcpy(filename, control_block->apdufile);
150 if (!(anew->print = odr_createmem(ODR_PRINT)))
152 if (*control_block->apdufile == '@')
154 odr_setprint(anew->print, yaz_log_file());
156 else if (*control_block->apdufile != '-')
158 strcpy(filename, control_block->apdufile);
159 if (!control_block->dynamic)
163 if (!(apduf = fopen(filename, "w")))
165 yaz_log(YLOG_WARN|YLOG_ERRNO, "can't open apdu dump %s", filename);
168 setvbuf(apduf, 0, _IONBF, 0);
174 sprintf(filename + strlen(filename), ".%ld", (long)getpid());
175 if (!(f = fopen(filename, "w")))
177 yaz_log(YLOG_WARN|YLOG_ERRNO, "%s", filename);
180 setvbuf(f, 0, _IONBF, 0);
182 odr_setprint(anew->print, f);
187 anew->input_buffer = 0;
188 anew->input_buffer_len = 0;
190 anew->state = ASSOC_NEW;
191 request_initq(&anew->incoming);
192 request_initq(&anew->outgoing);
193 anew->proto = cs_getproto(link);
198 * Free association and release resources.
200 void destroy_association(association *h)
202 statserv_options_block *cb = statserv_getcontrol();
206 odr_destroy(h->decode);
207 odr_destroy(h->encode);
209 odr_destroy(h->print);
211 xfree(h->input_buffer);
213 (*cb->bend_close)(h->backend);
214 while ((req = request_deq(&h->incoming)))
215 request_release(req);
216 while ((req = request_deq(&h->outgoing)))
217 request_release(req);
218 request_delq(&h->incoming);
219 request_delq(&h->outgoing);
221 xmalloc_trav("session closed");
222 if (control_block && control_block->one_shot)
228 static void do_close_req(association *a, int reason, char *message,
232 Z_Close *cls = zget_Close(a->encode);
234 /* Purge request queue */
235 while (request_deq(&a->incoming));
236 while (request_deq(&a->outgoing));
239 yaz_log(log_requestdetail, "Sending Close PDU, reason=%d, message=%s",
240 reason, message ? message : "none");
241 apdu.which = Z_APDU_close;
243 *cls->closeReason = reason;
244 cls->diagnosticInformation = message;
245 process_z_response(a, req, &apdu);
246 iochan_settimeout(a->client_chan, 20);
250 request_release(req);
251 yaz_log(log_requestdetail, "v2 client. No Close PDU");
252 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
254 a->state = ASSOC_DEAD;
257 static void do_close(association *a, int reason, char *message)
259 request *req = request_get(&a->outgoing);
260 do_close_req (a, reason, message, req);
264 * This is where PDUs from the client are read and the further
265 * processing is initiated. Flow of control moves down through the
266 * various process_* functions below, until the encoded result comes back up
267 * to the output handler in here.
269 * h : the I/O channel that has an outstanding event.
270 * event : the current outstanding event.
272 void ir_session(IOCHAN h, int event)
275 association *assoc = (association *)iochan_getdata(h);
276 COMSTACK conn = assoc->client_link;
279 assert(h && conn && assoc);
280 if (event == EVENT_TIMEOUT)
282 if (assoc->state != ASSOC_UP)
284 yaz_log(YLOG_DEBUG, "Final timeout - closing connection.");
285 /* do we need to lod this at all */
287 destroy_association(assoc);
292 yaz_log(log_session, "Session idle too long. Sending close.");
293 do_close(assoc, Z_Close_lackOfActivity, 0);
297 if (event & assoc->cs_accept_mask)
299 if (!cs_accept (conn))
301 yaz_log (YLOG_WARN, "accept failed");
302 destroy_association(assoc);
305 iochan_clearflag (h, EVENT_OUTPUT);
306 if (conn->io_pending)
307 { /* cs_accept didn't complete */
308 assoc->cs_accept_mask =
309 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
310 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
312 iochan_setflag (h, assoc->cs_accept_mask);
315 { /* cs_accept completed. Prepare for reading (cs_get) */
316 assoc->cs_accept_mask = 0;
317 assoc->cs_get_mask = EVENT_INPUT;
318 iochan_setflag (h, assoc->cs_get_mask);
322 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
324 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
326 yaz_log(YLOG_DEBUG, "ir_session (input)");
327 /* We aren't speaking to this fellow */
328 if (assoc->state == ASSOC_DEAD)
330 yaz_log(log_session, "Connection closed - end of session");
332 destroy_association(assoc);
336 assoc->cs_get_mask = EVENT_INPUT;
337 if ((res = cs_get(conn, &assoc->input_buffer,
338 &assoc->input_buffer_len)) <= 0)
340 yaz_log(log_session, "Connection closed by client");
342 destroy_association(assoc);
346 else if (res == 1) /* incomplete read - wait for more */
348 if (conn->io_pending & CS_WANT_WRITE)
349 assoc->cs_get_mask |= EVENT_OUTPUT;
350 iochan_setflag(h, assoc->cs_get_mask);
353 if (cs_more(conn)) /* more stuff - call us again later, please */
354 iochan_setevent(h, EVENT_INPUT);
356 /* we got a complete PDU. Let's decode it */
357 yaz_log(YLOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
358 assoc->input_buffer[0] & 0xff,
359 assoc->input_buffer[1] & 0xff,
360 assoc->input_buffer[2] & 0xff);
361 req = request_get(&assoc->incoming); /* get a new request */
362 odr_reset(assoc->decode);
363 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
364 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
366 yaz_log(YLOG_WARN, "ODR error on incoming PDU: %s [element %s] "
368 odr_errmsg(odr_geterror(assoc->decode)),
369 odr_getelement(assoc->decode),
370 odr_offset(assoc->decode));
371 if (assoc->decode->error != OHTTP)
373 yaz_log(YLOG_WARN, "PDU dump:");
374 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
375 request_release(req);
376 do_close(assoc, Z_Close_protocolError,"Malformed package");
380 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
381 assoc->state = ASSOC_DEAD;
382 process_gdu_response(assoc, req, p);
386 req->request_mem = odr_extract_mem(assoc->decode);
389 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
390 yaz_log(YLOG_WARN, "ODR print error: %s",
391 odr_errmsg(odr_geterror(assoc->print)));
392 odr_reset(assoc->print);
394 request_enq(&assoc->incoming, req);
397 /* can we do something yet? */
398 req = request_head(&assoc->incoming);
399 if (req->state == REQUEST_IDLE)
401 request_deq(&assoc->incoming);
402 process_gdu_request(assoc, req);
405 if (event & assoc->cs_put_mask)
407 request *req = request_head(&assoc->outgoing);
409 assoc->cs_put_mask = 0;
410 yaz_log(YLOG_DEBUG, "ir_session (output)");
411 req->state = REQUEST_PENDING;
412 switch (res = cs_put(conn, req->response, req->len_response))
415 yaz_log(log_session, "Connection closed by client");
417 destroy_association(assoc);
420 case 0: /* all sent - release the request structure */
421 yaz_log(YLOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
423 yaz_log(YLOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
426 nmem_destroy(req->request_mem);
427 request_deq(&assoc->outgoing);
428 request_release(req);
429 if (!request_head(&assoc->outgoing))
430 { /* restore mask for cs_get operation ... */
431 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
432 iochan_setflag(h, assoc->cs_get_mask);
433 if (assoc->state == ASSOC_DEAD)
434 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
438 assoc->cs_put_mask = EVENT_OUTPUT;
442 if (conn->io_pending & CS_WANT_WRITE)
443 assoc->cs_put_mask |= EVENT_OUTPUT;
444 if (conn->io_pending & CS_WANT_READ)
445 assoc->cs_put_mask |= EVENT_INPUT;
446 iochan_setflag(h, assoc->cs_put_mask);
449 if (event & EVENT_EXCEPT)
451 yaz_log(YLOG_WARN, "ir_session (exception)");
453 destroy_association(assoc);
458 static int process_z_request(association *assoc, request *req, char **msg);
460 static void assoc_init_reset(association *assoc)
463 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
465 assoc->init->stream = assoc->encode;
466 assoc->init->print = assoc->print;
467 assoc->init->auth = 0;
468 assoc->init->referenceId = 0;
469 assoc->init->implementation_version = 0;
470 assoc->init->implementation_id = 0;
471 assoc->init->implementation_name = 0;
472 assoc->init->bend_sort = NULL;
473 assoc->init->bend_search = NULL;
474 assoc->init->bend_present = NULL;
475 assoc->init->bend_esrequest = NULL;
476 assoc->init->bend_delete = NULL;
477 assoc->init->bend_scan = NULL;
478 assoc->init->bend_segment = NULL;
479 assoc->init->bend_fetch = NULL;
480 assoc->init->bend_explain = NULL;
482 assoc->init->charneg_request = NULL;
483 assoc->init->charneg_response = NULL;
485 assoc->init->decode = assoc->decode;
486 assoc->init->peer_name =
487 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
490 static int srw_bend_init(association *assoc)
492 const char *encoding = "UTF-8";
494 bend_initresult *binitres;
495 statserv_options_block *cb = statserv_getcontrol();
497 assoc_init_reset(assoc);
499 assoc->maximumRecordSize = 3000000;
500 assoc->preferredMessageSize = 3000000;
502 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
503 assoc->init->charneg_request = ce->u.charNeg3;
506 if (!(binitres = (*cb->bend_init)(assoc->init)))
508 yaz_log(YLOG_WARN, "Bad response from backend.");
511 assoc->backend = binitres->handle;
515 static int srw_bend_fetch(association *assoc, int pos,
516 Z_SRW_searchRetrieveRequest *srw_req,
517 Z_SRW_record *record)
520 ODR o = assoc->encode;
522 rr.setname = "default";
525 rr.request_format = VAL_TEXT_XML;
526 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
529 rr.comp = (Z_RecordComposition *)
530 odr_malloc(assoc->decode, sizeof(*rr.comp));
531 rr.comp->which = Z_RecordComp_complex;
532 rr.comp->u.complex = (Z_CompSpec *)
533 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
534 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
535 odr_malloc(assoc->encode, sizeof(bool_t));
536 *rr.comp->u.complex->selectAlternativeSyntax = 0;
537 rr.comp->u.complex->num_dbSpecific = 0;
538 rr.comp->u.complex->dbSpecific = 0;
539 rr.comp->u.complex->num_recordSyntax = 0;
540 rr.comp->u.complex->recordSyntax = 0;
542 rr.comp->u.complex->generic = (Z_Specification *)
543 odr_malloc(assoc->decode, sizeof(Z_Specification));
545 /* schema uri = recordSchema (or NULL if recordSchema is not given) */
546 rr.comp->u.complex->generic->which = Z_Schema_uri;
547 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
549 /* ESN = recordSchema if recordSchema is present */
550 rr.comp->u.complex->generic->elementSpec = 0;
551 if (srw_req->recordSchema)
553 rr.comp->u.complex->generic->elementSpec =
554 (Z_ElementSpec *) odr_malloc(assoc->encode, sizeof(Z_ElementSpec));
555 rr.comp->u.complex->generic->elementSpec->which =
556 Z_ElementSpec_elementSetName;
557 rr.comp->u.complex->generic->elementSpec->u.elementSetName =
558 srw_req->recordSchema;
561 rr.stream = assoc->encode;
562 rr.print = assoc->print;
568 rr.output_format = VAL_TEXT_XML;
569 rr.output_format_raw = 0;
572 rr.surrogate_flag = 0;
573 rr.schema = srw_req->recordSchema;
575 if (!assoc->init->bend_fetch)
578 (*assoc->init->bend_fetch)(assoc->backend, &rr);
580 if (rr.errcode && rr.surrogate_flag)
582 int code = yaz_diag_bib1_to_srw(rr.errcode);
583 const char *message = yaz_diag_srw_str(code);
586 len += strlen(message);
588 len += strlen(rr.errstring);
590 record->recordData_buf = odr_malloc(o, len);
592 sprintf(record->recordData_buf, "<diagnostic "
593 "xmlns=\"http://www.loc.gov/zing/srw/diagnostic/\">\n"
594 " <uri>info:srw/diagnostic/1/%d</uri>\n", code);
596 sprintf(record->recordData_buf + strlen(record->recordData_buf),
597 " <details>%s</details>\n", rr.errstring);
599 sprintf(record->recordData_buf + strlen(record->recordData_buf),
600 " <message>%s</message>\n", message);
601 sprintf(record->recordData_buf + strlen(record->recordData_buf),
603 record->recordData_len = strlen(record->recordData_buf);
604 record->recordPosition = odr_intdup(o, pos);
605 record->recordSchema = "info:srw/schema/1/diagnostics-v1.1";
608 else if (rr.len >= 0)
610 record->recordData_buf = rr.record;
611 record->recordData_len = rr.len;
612 record->recordPosition = odr_intdup(o, pos);
614 record->recordSchema = odr_strdup(o, rr.schema);
616 record->recordSchema = 0;
621 static void srw_bend_search(association *assoc, request *req,
622 Z_SRW_searchRetrieveRequest *srw_req,
623 Z_SRW_searchRetrieveResponse *srw_res,
629 const char *querystr = 0;
630 const char *querytype = 0;
633 yaz_log(log_requestdetail, "Got SRW SearchRetrieveRequest");
634 yaz_log(YLOG_DEBUG, "srw_bend_search");
637 yaz_log(YLOG_DEBUG, "srw_bend_init");
638 if (!srw_bend_init(assoc))
640 srw_error = 3; /* assume Authentication error */
642 yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
643 &srw_res->num_diagnostics, 1, 0);
644 yaz_log(log_request, "Search SRW: backend init failed");
649 rr.setname = "default";
652 rr.basenames = &srw_req->database;
655 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
657 if (srw_req->query_type == Z_SRW_query_type_cql)
659 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
660 ext->direct_reference = odr_getoidbystr(assoc->decode,
661 "1.2.840.10003.16.2");
662 ext->indirect_reference = 0;
664 ext->which = Z_External_CQL;
665 ext->u.cql = srw_req->query.cql;
666 querystr = srw_req->query.cql;
669 rr.query->which = Z_Query_type_104;
670 rr.query->u.type_104 = ext;
672 else if (srw_req->query_type == Z_SRW_query_type_pqf)
674 Z_RPNQuery *RPNquery;
675 YAZ_PQF_Parser pqf_parser;
677 pqf_parser = yaz_pqf_create ();
679 querystr = srw_req->query.pqf;
681 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
687 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
688 yaz_log(log_requestdetail, "Parse error %d %s near offset %d",
693 rr.query->which = Z_Query_type_1;
694 rr.query->u.type_1 = RPNquery;
696 yaz_pqf_destroy (pqf_parser);
701 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
704 if (!srw_error && !assoc->init->bend_search)
711 WRBUF wr = wrbuf_alloc();
712 wrbuf_printf(wr, "Search: %s: %s ", querytype, querystr);
713 wrbuf_printf(wr, " ERROR %d ", srw_error);
714 yaz_log(log_request, "%s", wrbuf_buf(wr) );
717 srw_res->num_diagnostics = 1;
718 srw_res->diagnostics = (Z_SRW_diagnostic *)
719 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
720 yaz_mk_std_diagnostic(assoc->encode,
721 srw_res->diagnostics, srw_error, 0);
725 rr.stream = assoc->encode;
726 rr.decode = assoc->decode;
727 rr.print = assoc->print;
729 rr.association = assoc;
735 yaz_log_zquery_level(log_requestdetail,rr.query);
737 (assoc->init->bend_search)(assoc->backend, &rr);
740 yaz_log(log_request, "bend_search returned Bib-1 diagnostic %d",
742 if (rr.errcode == 109) /* database unavailable */
747 srw_error = yaz_diag_bib1_to_srw (rr.errcode);
748 srw_res->num_diagnostics = 1;
749 srw_res->diagnostics = (Z_SRW_diagnostic *)
750 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
751 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
752 srw_error, rr.errstring);
756 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
757 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
759 yaz_log(log_requestdetail, "Request to pack %d+%d out of %d",
760 start, number, rr.hits);
762 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
769 srw_res->num_diagnostics = 1;
770 srw_res->diagnostics = (Z_SRW_diagnostic *)
771 odr_malloc(assoc->encode,
772 sizeof(*srw_res->diagnostics));
773 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
779 int packing = Z_SRW_recordPacking_string;
780 if (start + number > rr.hits)
781 number = rr.hits - start + 1;
782 if (srw_req->recordPacking &&
783 !strcmp(srw_req->recordPacking, "xml"))
784 packing = Z_SRW_recordPacking_XML;
785 srw_res->records = (Z_SRW_record *)
786 odr_malloc(assoc->encode,
787 number * sizeof(*srw_res->records));
788 for (i = 0; i<number; i++)
792 srw_res->records[j].recordPacking = packing;
793 srw_res->records[j].recordData_buf = 0;
794 yaz_log(YLOG_DEBUG, "srw_bend_fetch %d", i+start);
795 errcode = srw_bend_fetch(assoc, i+start, srw_req,
796 srw_res->records + j);
799 srw_res->num_diagnostics = 1;
800 srw_res->diagnostics = (Z_SRW_diagnostic *)
801 odr_malloc(assoc->encode,
802 sizeof(*srw_res->diagnostics));
804 yaz_mk_std_diagnostic(assoc->encode,
805 srw_res->diagnostics,
806 yaz_diag_bib1_to_srw (errcode),
810 if (srw_res->records[j].recordData_buf)
813 srw_res->num_records = j;
815 srw_res->records = 0;
821 WRBUF wr=wrbuf_alloc();
822 wrbuf_printf(wr,"Search %s: %s", querytype, querystr);
824 wrbuf_printf(wr, " ERROR %d", srw_error);
827 wrbuf_printf(wr, " OK:%d hits", rr.hits);
828 if (srw_res->num_records)
829 wrbuf_printf(wr, " %d records returned", srw_res->num_records);
831 yaz_log(log_request, "%s", wrbuf_buf(wr) );
836 static void srw_bend_explain(association *assoc, request *req,
837 Z_SRW_explainRequest *srw_req,
838 Z_SRW_explainResponse *srw_res,
841 yaz_log(log_requestdetail, "Got SRW ExplainRequest");
845 yaz_log(YLOG_DEBUG, "srw_bend_init");
846 if (!srw_bend_init(assoc))
851 if (assoc->init && assoc->init->bend_explain)
855 rr.stream = assoc->encode;
856 rr.decode = assoc->decode;
857 rr.print = assoc->print;
859 rr.database = srw_req->database;
860 rr.schema = "http://explain.z3950.org/dtd/2.0/";
861 (*assoc->init->bend_explain)(assoc->backend, &rr);
864 int packing = Z_SRW_recordPacking_string;
865 if (srw_req->recordPacking &&
866 !strcmp(srw_req->recordPacking, "xml"))
867 packing = Z_SRW_recordPacking_XML;
868 srw_res->record.recordSchema = rr.schema;
869 srw_res->record.recordPacking = packing;
870 srw_res->record.recordData_buf = rr.explain_buf;
871 srw_res->record.recordData_len = strlen(rr.explain_buf);
872 srw_res->record.recordPosition = 0;
878 static void process_http_request(association *assoc, request *req)
880 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
881 ODR o = assoc->encode;
882 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
884 Z_SOAP *soap_package = 0;
887 Z_HTTP_Response *hres = 0;
889 char *stylesheet = 0;
890 Z_SRW_diagnostic *diagnostic = 0;
891 int num_diagnostic = 0;
893 if (!strcmp(hreq->path, "/test"))
895 p = z_get_HTTP_Response(o, 200);
896 hres = p->u.HTTP_Response;
897 hres->content_buf = "1234567890\n";
898 hres->content_len = strlen(hres->content_buf);
903 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
904 yaz_log(YLOG_DEBUG, "yaz_srw_decode returned %d", r);
906 if (r == 2) /* not taken */
908 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
909 &diagnostic, &num_diagnostic);
910 yaz_log(YLOG_DEBUG, "yaz_sru_decode returned %d", r);
912 if (r == 0) /* decode SRW/SRU OK .. */
915 if (sr->which == Z_SRW_searchRetrieve_request)
918 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
920 stylesheet = sr->u.request->stylesheet;
923 res->u.response->diagnostics = diagnostic;
924 res->u.response->num_diagnostics = num_diagnostic;
928 srw_bend_search(assoc, req, sr->u.request, res->u.response,
931 if (http_code == 200)
932 soap_package->u.generic->p = res;
934 else if (sr->which == Z_SRW_explain_request)
936 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
937 stylesheet = sr->u.explain_request->stylesheet;
940 res->u.explain_response->diagnostics = diagnostic;
941 res->u.explain_response->num_diagnostics = num_diagnostic;
943 srw_bend_explain(assoc, req, sr->u.explain_request,
944 res->u.explain_response, &http_code);
945 if (http_code == 200)
946 soap_package->u.generic->p = res;
948 else if (sr->which == Z_SRW_scan_request)
950 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
951 stylesheet = sr->u.scan_request->stylesheet;
954 res->u.scan_response->diagnostics = diagnostic;
955 res->u.scan_response->num_diagnostics = num_diagnostic;
957 yaz_add_srw_diagnostic(o,
958 &res->u.scan_response->diagnostics,
959 &res->u.scan_response->num_diagnostics,
961 if (http_code == 200)
962 soap_package->u.generic->p = res;
966 yaz_log(log_request, "generate soap error");
967 /* FIXME - what error, what query */
969 z_soap_error(assoc->encode, soap_package,
970 "SOAP-ENV:Client", "Bad method", 0);
972 if (http_code == 200 || http_code == 500)
974 static Z_SOAP_Handler soap_handlers[3] = {
976 {"http://www.loc.gov/zing/srw/", 0,
977 (Z_SOAP_fun) yaz_srw_codec},
978 {"http://www.loc.gov/zing/srw/v1.0/", 0,
979 (Z_SOAP_fun) yaz_srw_codec},
985 p = z_get_HTTP_Response(o, 200);
986 hres = p->u.HTTP_Response;
987 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
988 &hres->content_buf, &hres->content_len,
989 soap_handlers, charset, stylesheet);
990 hres->code = http_code;
992 strcpy(ctype, "text/xml");
995 strcat(ctype, "; charset=");
996 strcat(ctype, charset);
998 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1001 p = z_get_HTTP_Response(o, http_code);
1005 p = z_get_HTTP_Response(o, 500);
1006 hres = p->u.HTTP_Response;
1007 if (!strcmp(hreq->version, "1.0"))
1009 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1010 if (v && !strcmp(v, "Keep-Alive"))
1014 hres->version = "1.0";
1018 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1019 if (v && !strcmp(v, "close"))
1023 hres->version = "1.1";
1027 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1028 assoc->state = ASSOC_DEAD;
1029 assoc->cs_get_mask = 0;
1034 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1036 if (alive && isdigit(*(const unsigned char *) alive))
1040 if (t < 0 || t > 3600)
1042 iochan_settimeout(assoc->client_chan,t);
1043 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1045 process_gdu_response(assoc, req, p);
1048 static void process_gdu_request(association *assoc, request *req)
1050 if (req->gdu_request->which == Z_GDU_Z3950)
1053 req->apdu_request = req->gdu_request->u.z3950;
1054 if (process_z_request(assoc, req, &msg) < 0)
1055 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1057 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1058 process_http_request(assoc, req);
1061 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1066 * Initiate request processing.
1068 static int process_z_request(association *assoc, request *req, char **msg)
1074 *msg = "Unknown Error";
1075 assert(req && req->state == REQUEST_IDLE);
1076 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1078 *msg = "Missing InitRequest";
1081 switch (req->apdu_request->which)
1083 case Z_APDU_initRequest:
1084 iochan_settimeout(assoc->client_chan,
1085 statserv_getcontrol()->idle_timeout * 60);
1086 res = process_initRequest(assoc, req); break;
1087 case Z_APDU_searchRequest:
1088 res = process_searchRequest(assoc, req, &fd); break;
1089 case Z_APDU_presentRequest:
1090 res = process_presentRequest(assoc, req, &fd); break;
1091 case Z_APDU_scanRequest:
1092 if (assoc->init->bend_scan)
1093 res = process_scanRequest(assoc, req, &fd);
1096 *msg = "Cannot handle Scan APDU";
1100 case Z_APDU_extendedServicesRequest:
1101 if (assoc->init->bend_esrequest)
1102 res = process_ESRequest(assoc, req, &fd);
1105 *msg = "Cannot handle Extended Services APDU";
1109 case Z_APDU_sortRequest:
1110 if (assoc->init->bend_sort)
1111 res = process_sortRequest(assoc, req, &fd);
1114 *msg = "Cannot handle Sort APDU";
1119 process_close(assoc, req);
1121 case Z_APDU_deleteResultSetRequest:
1122 if (assoc->init->bend_delete)
1123 res = process_deleteRequest(assoc, req, &fd);
1126 *msg = "Cannot handle Delete APDU";
1130 case Z_APDU_segmentRequest:
1131 if (assoc->init->bend_segment)
1133 res = process_segmentRequest (assoc, req);
1137 *msg = "Cannot handle Segment APDU";
1141 case Z_APDU_triggerResourceControlRequest:
1144 *msg = "Bad APDU received";
1149 yaz_log(YLOG_DEBUG, " result immediately available");
1150 retval = process_z_response(assoc, req, res);
1154 yaz_log(YLOG_DEBUG, " result unavailble");
1157 else /* no result yet - one will be provided later */
1161 /* Set up an I/O handler for the fd supplied by the backend */
1163 yaz_log(YLOG_DEBUG, " establishing handler for result");
1164 req->state = REQUEST_PENDING;
1165 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1167 iochan_setdata(chan, assoc);
1174 * Handle message from the backend.
1176 void backend_response(IOCHAN i, int event)
1178 association *assoc = (association *)iochan_getdata(i);
1179 request *req = request_head(&assoc->incoming);
1183 yaz_log(YLOG_DEBUG, "backend_response");
1184 assert(assoc && req && req->state != REQUEST_IDLE);
1185 /* determine what it is we're waiting for */
1186 switch (req->apdu_request->which)
1188 case Z_APDU_searchRequest:
1189 res = response_searchRequest(assoc, req, 0, &fd); break;
1191 case Z_APDU_presentRequest:
1192 res = response_presentRequest(assoc, req, 0, &fd); break;
1193 case Z_APDU_scanRequest:
1194 res = response_scanRequest(assoc, req, 0, &fd); break;
1197 yaz_log(YLOG_FATAL, "Serious programmer's lapse or bug");
1200 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1202 yaz_log(YLOG_WARN, "Fatal error when talking to backend");
1203 do_close(assoc, Z_Close_systemProblem, 0);
1207 else if (!res) /* no result yet - try again later */
1209 yaz_log(YLOG_DEBUG, " no result yet");
1210 iochan_setfd(i, fd); /* in case fd has changed */
1215 * Encode response, and transfer the request structure to the outgoing queue.
1217 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1219 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1223 if (!z_GDU(assoc->print, &res, 0, 0))
1224 yaz_log(YLOG_WARN, "ODR print error: %s",
1225 odr_errmsg(odr_geterror(assoc->print)));
1226 odr_reset(assoc->print);
1228 if (!z_GDU(assoc->encode, &res, 0, 0))
1230 yaz_log(YLOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1231 odr_errmsg(odr_geterror(assoc->decode)),
1232 odr_getelement(assoc->decode));
1235 req->response = odr_getbuf(assoc->encode, &req->len_response,
1236 &req->size_response);
1237 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1238 odr_reset(assoc->encode);
1239 req->state = REQUEST_IDLE;
1240 request_enq(&assoc->outgoing, req);
1241 /* turn the work over to the ir_session handler */
1242 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1243 assoc->cs_put_mask = EVENT_OUTPUT;
1244 /* Is there more work to be done? give that to the input handler too */
1246 if (request_head(&assoc->incoming))
1248 yaz_log (YLOG_DEBUG, "more work to be done");
1249 iochan_setevent(assoc->client_chan, EVENT_WORK);
1256 * Encode response, and transfer the request structure to the outgoing queue.
1258 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1260 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1261 gres->which = Z_GDU_Z3950;
1262 gres->u.z3950 = res;
1264 return process_gdu_response(assoc, req, gres);
1269 * Handle init request.
1270 * At the moment, we don't check the options
1271 * anywhere else in the code - we just try not to do anything that would
1272 * break a naive client. We'll toss 'em into the association block when
1273 * we need them there.
1275 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1277 statserv_options_block *cb = statserv_getcontrol();
1278 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1279 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1280 Z_InitResponse *resp = apdu->u.initResponse;
1281 bend_initresult *binitres;
1285 yaz_log(log_requestdetail, "Got initRequest");
1286 if (req->implementationId)
1287 yaz_log(log_requestdetail, "Id: %s", req->implementationId);
1288 if (req->implementationName)
1289 yaz_log(log_requestdetail, "Name: %s", req->implementationName);
1290 if (req->implementationVersion)
1291 yaz_log(log_requestdetail, "Version: %s", req->implementationVersion);
1293 assoc_init_reset(assoc);
1295 assoc->init->auth = req->idAuthentication;
1296 assoc->init->referenceId = req->referenceId;
1298 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1300 Z_CharSetandLanguageNegotiation *negotiation =
1301 yaz_get_charneg_record (req->otherInfo);
1303 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1304 assoc->init->charneg_request = negotiation;
1308 if (!(binitres = (*cb->bend_init)(assoc->init)))
1310 yaz_log(YLOG_WARN, "Bad response from backend.");
1314 assoc->backend = binitres->handle;
1315 if ((assoc->init->bend_sort))
1316 yaz_log (YLOG_DEBUG, "Sort handler installed");
1317 if ((assoc->init->bend_search))
1318 yaz_log (YLOG_DEBUG, "Search handler installed");
1319 if ((assoc->init->bend_present))
1320 yaz_log (YLOG_DEBUG, "Present handler installed");
1321 if ((assoc->init->bend_esrequest))
1322 yaz_log (YLOG_DEBUG, "ESRequest handler installed");
1323 if ((assoc->init->bend_delete))
1324 yaz_log (YLOG_DEBUG, "Delete handler installed");
1325 if ((assoc->init->bend_scan))
1326 yaz_log (YLOG_DEBUG, "Scan handler installed");
1327 if ((assoc->init->bend_segment))
1328 yaz_log (YLOG_DEBUG, "Segment handler installed");
1330 resp->referenceId = req->referenceId;
1332 /* let's tell the client what we can do */
1333 if (ODR_MASK_GET(req->options, Z_Options_search))
1335 ODR_MASK_SET(resp->options, Z_Options_search);
1336 strcat(options, "srch");
1338 if (ODR_MASK_GET(req->options, Z_Options_present))
1340 ODR_MASK_SET(resp->options, Z_Options_present);
1341 strcat(options, " prst");
1343 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1344 assoc->init->bend_delete)
1346 ODR_MASK_SET(resp->options, Z_Options_delSet);
1347 strcat(options, " del");
1349 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1350 assoc->init->bend_esrequest)
1352 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1353 strcat (options, " extendedServices");
1355 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1357 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1358 strcat(options, " namedresults");
1360 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1362 ODR_MASK_SET(resp->options, Z_Options_scan);
1363 strcat(options, " scan");
1365 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1367 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1368 strcat(options, " concurrop");
1370 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1372 ODR_MASK_SET(resp->options, Z_Options_sort);
1373 strcat(options, " sort");
1376 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1377 && assoc->init->charneg_response)
1379 Z_OtherInformation **p;
1380 Z_OtherInformationUnit *p0;
1382 yaz_oi_APDU(apdu, &p);
1384 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1385 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1387 p0->which = Z_OtherInfo_externallyDefinedInfo;
1388 p0->information.externallyDefinedInfo =
1389 assoc->init->charneg_response;
1391 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1392 strcat(options, " negotiation");
1395 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1397 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1399 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1400 assoc->version = 1; /* 1 & 2 are equivalent */
1402 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1404 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1407 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1409 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1413 yaz_log(log_requestdetail, "Negotiated to v%d: %s", assoc->version, options);
1414 assoc->maximumRecordSize = *req->maximumRecordSize;
1415 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1416 assoc->maximumRecordSize = control_block->maxrecordsize;
1417 assoc->preferredMessageSize = *req->preferredMessageSize;
1418 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1419 assoc->preferredMessageSize = assoc->maximumRecordSize;
1421 resp->preferredMessageSize = &assoc->preferredMessageSize;
1422 resp->maximumRecordSize = &assoc->maximumRecordSize;
1424 resp->implementationId = odr_prepend(assoc->encode,
1425 assoc->init->implementation_id,
1426 resp->implementationId);
1428 resp->implementationName = odr_prepend(assoc->encode,
1429 assoc->init->implementation_name,
1430 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1432 version = odr_strdup(assoc->encode, "$Revision: 1.42 $");
1433 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1434 version[strlen(version)-2] = '\0';
1435 resp->implementationVersion = odr_prepend(assoc->encode,
1436 assoc->init->implementation_version,
1437 odr_prepend(assoc->encode, &version[11],
1438 resp->implementationVersion));
1440 if (binitres->errcode)
1442 WRBUF wr = wrbuf_alloc();
1444 assoc->state = ASSOC_DEAD;
1445 resp->userInformationField =
1446 init_diagnostics(assoc->encode, binitres->errcode,
1447 binitres->errstring);
1448 wr_diag(wr, binitres->errcode, binitres->errstring);
1449 yaz_log(log_request, "Init from '%s' (%s) (ver %s) %s",
1450 req->implementationName ? req->implementationName :"??",
1451 req->implementationId ? req->implementationId :"?",
1452 req->implementationVersion ? req->implementationVersion: "?",
1458 assoc->state = ASSOC_UP;
1459 yaz_log(log_request, "Init from '%s' (%s) (ver %s) OK",
1460 req->implementationName ? req->implementationName :"??",
1461 req->implementationId ? req->implementationId :"?",
1462 req->implementationVersion ? req->implementationVersion: "?");
1469 * Set the specified `errcode' and `errstring' into a UserInfo-1
1470 * external to be returned to the client in accordance with Z35.90
1471 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1472 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1474 static Z_External *init_diagnostics(ODR odr, int error, const char *addinfo)
1476 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1477 addinfo ? " -- " : "", addinfo ? addinfo : "");
1478 return zget_init_diagnostics(odr, error, addinfo);
1482 * nonsurrogate diagnostic record.
1484 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1486 Z_Records *rec = (Z_Records *) odr_malloc (assoc->encode, sizeof(*rec));
1488 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1489 addinfo ? " -- " : "", addinfo ? addinfo : "");
1491 rec->which = Z_Records_NSD;
1492 rec->u.nonSurrogateDiagnostic = zget_DefaultDiagFormat(assoc->encode,
1498 * surrogate diagnostic.
1500 static Z_NamePlusRecord *surrogatediagrec(association *assoc,
1502 int error, const char *addinfo)
1504 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1505 addinfo ? " -- " : "", addinfo ? addinfo : "");
1506 return zget_surrogateDiagRec(assoc->encode, dbname, error, addinfo);
1509 static Z_Records *pack_records(association *a, char *setname, int start,
1510 int *num, Z_RecordComposition *comp,
1511 int *next, int *pres, oid_value format,
1512 Z_ReferenceId *referenceId,
1513 int *oid, int *errcode)
1515 int recno, total_length = 0, toget = *num, dumped_records = 0;
1516 Z_Records *records =
1517 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1518 Z_NamePlusRecordList *reclist =
1519 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1520 Z_NamePlusRecord **list =
1521 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1523 records->which = Z_Records_DBOSD;
1524 records->u.databaseOrSurDiagnostics = reclist;
1525 reclist->num_records = 0;
1526 reclist->records = list;
1527 *pres = Z_PresentStatus_success;
1531 yaz_log(log_requestdetail, "Request to pack %d+%d %s", start, toget, setname);
1532 yaz_log(log_requestdetail, "pms=%d, mrs=%d", a->preferredMessageSize,
1533 a->maximumRecordSize);
1534 for (recno = start; reclist->num_records < toget; recno++)
1537 Z_NamePlusRecord *thisrec;
1538 int this_length = 0;
1540 * we get the number of bytes allocated on the stream before any
1541 * allocation done by the backend - this should give us a reasonable
1542 * idea of the total size of the data so far.
1544 total_length = odr_total(a->encode) - dumped_records;
1550 freq.last_in_set = 0;
1551 freq.setname = setname;
1552 freq.surrogate_flag = 0;
1553 freq.number = recno;
1555 freq.request_format = format;
1556 freq.request_format_raw = oid;
1557 freq.output_format = format;
1558 freq.output_format_raw = 0;
1559 freq.stream = a->encode;
1560 freq.print = a->print;
1561 freq.referenceId = referenceId;
1563 (*a->init->bend_fetch)(a->backend, &freq);
1564 /* backend should be able to signal whether error is system-wide
1565 or only pertaining to current record */
1568 if (!freq.surrogate_flag)
1571 *pres = Z_PresentStatus_failure;
1572 /* for 'present request out of range',
1573 set addinfo to record position if not set */
1574 if (freq.errcode == 13 && freq.errstring == 0)
1576 sprintf (s, "%d", recno);
1580 *errcode = freq.errcode;
1581 return diagrec(a, freq.errcode, freq.errstring);
1583 reclist->records[reclist->num_records] =
1584 surrogatediagrec(a, freq.basename, freq.errcode,
1586 reclist->num_records++;
1587 *next = freq.last_in_set ? 0 : recno + 1;
1591 this_length = freq.len;
1593 this_length = odr_total(a->encode) - total_length - dumped_records;
1594 yaz_log(YLOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1595 this_length, total_length, dumped_records);
1596 if (a->preferredMessageSize > 0 &&
1597 this_length + total_length > a->preferredMessageSize)
1599 /* record is small enough, really */
1600 if (this_length <= a->preferredMessageSize && recno > start)
1602 yaz_log(log_requestdetail, " Dropped last normal-sized record");
1603 *pres = Z_PresentStatus_partial_2;
1606 /* record can only be fetched by itself */
1607 if (this_length < a->maximumRecordSize)
1609 yaz_log(log_requestdetail, " Record > prefmsgsz");
1612 yaz_log(YLOG_DEBUG, " Dropped it");
1613 reclist->records[reclist->num_records] =
1614 surrogatediagrec(a, freq.basename, 16, 0);
1615 reclist->num_records++;
1616 *next = freq.last_in_set ? 0 : recno + 1;
1617 dumped_records += this_length;
1621 else /* too big entirely */
1623 yaz_log(log_requestdetail, "Record > maxrcdsz this=%d max=%d",
1624 this_length, a->maximumRecordSize);
1625 reclist->records[reclist->num_records] =
1626 surrogatediagrec(a, freq.basename, 17, 0);
1627 reclist->num_records++;
1628 *next = freq.last_in_set ? 0 : recno + 1;
1629 dumped_records += this_length;
1634 if (!(thisrec = (Z_NamePlusRecord *)
1635 odr_malloc(a->encode, sizeof(*thisrec))))
1637 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1638 strlen(freq.basename) + 1)))
1640 strcpy(thisrec->databaseName, freq.basename);
1641 thisrec->which = Z_NamePlusRecord_databaseRecord;
1643 if (freq.output_format_raw)
1645 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1646 freq.output_format = ident->value;
1648 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1649 freq.record, freq.len);
1650 if (!thisrec->u.databaseRecord)
1652 reclist->records[reclist->num_records] = thisrec;
1653 reclist->num_records++;
1654 *next = freq.last_in_set ? 0 : recno + 1;
1656 *num = reclist->num_records;
1660 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1663 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1664 bend_search_rr *bsrr =
1665 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1667 yaz_log(log_requestdetail, "Got SearchRequest.");
1669 bsrr->request = reqb;
1670 bsrr->association = assoc;
1671 bsrr->referenceId = req->referenceId;
1672 save_referenceId (reqb, bsrr->referenceId);
1674 yaz_log (log_requestdetail, "ResultSet '%s'", req->resultSetName);
1675 if (req->databaseNames)
1678 for (i = 0; i < req->num_databaseNames; i++)
1679 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
1682 yaz_log_zquery_level(log_requestdetail,req->query);
1684 if (assoc->init->bend_search)
1686 bsrr->setname = req->resultSetName;
1687 bsrr->replace_set = *req->replaceIndicator;
1688 bsrr->num_bases = req->num_databaseNames;
1689 bsrr->basenames = req->databaseNames;
1690 bsrr->query = req->query;
1691 bsrr->stream = assoc->encode;
1692 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1693 bsrr->decode = assoc->decode;
1694 bsrr->print = assoc->print;
1697 bsrr->errstring = NULL;
1698 bsrr->search_info = NULL;
1699 (assoc->init->bend_search)(assoc->backend, bsrr);
1700 if (!bsrr->request) /* backend not ready with the search response */
1701 return 0; /* should not be used any more */
1705 /* FIXME - make a diagnostic for it */
1706 yaz_log(YLOG_WARN,"Search not supported ?!?!");
1708 return response_searchRequest(assoc, reqb, bsrr, fd);
1711 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1714 * Prepare a searchresponse based on the backend results. We probably want
1715 * to look at making the fetching of records nonblocking as well, but
1716 * so far, we'll keep things simple.
1717 * If bsrt is null, that means we're called in response to a communications
1718 * event, and we'll have to get the response for ourselves.
1720 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1721 bend_search_rr *bsrt, int *fd)
1723 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1724 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1725 Z_SearchResponse *resp = (Z_SearchResponse *)
1726 odr_malloc (assoc->encode, sizeof(*resp));
1727 int *nulint = odr_intdup (assoc->encode, 0);
1728 bool_t *sr = odr_intdup(assoc->encode, 1);
1729 int *next = odr_intdup(assoc->encode, 0);
1730 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1733 apdu->which = Z_APDU_searchResponse;
1734 apdu->u.searchResponse = resp;
1735 resp->referenceId = req->referenceId;
1736 resp->additionalSearchInfo = 0;
1737 resp->otherInfo = 0;
1739 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1741 yaz_log(YLOG_FATAL, "Bad result from backend");
1744 else if (bsrt->errcode)
1746 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1747 resp->resultCount = nulint;
1748 resp->numberOfRecordsReturned = nulint;
1749 resp->nextResultSetPosition = nulint;
1750 resp->searchStatus = nulint;
1751 resp->resultSetStatus = none;
1752 resp->presentStatus = 0;
1756 int *toget = odr_intdup(assoc->encode, 0);
1757 int *presst = odr_intdup(assoc->encode, 0);
1758 Z_RecordComposition comp, *compp = 0;
1760 yaz_log (log_requestdetail, "resultCount: %d", bsrt->hits);
1763 resp->resultCount = &bsrt->hits;
1765 comp.which = Z_RecordComp_simple;
1766 /* how many records does the user agent want, then? */
1767 if (bsrt->hits <= *req->smallSetUpperBound)
1769 *toget = bsrt->hits;
1770 if ((comp.u.simple = req->smallSetElementSetNames))
1773 else if (bsrt->hits < *req->largeSetLowerBound)
1775 *toget = *req->mediumSetPresentNumber;
1776 if (*toget > bsrt->hits)
1777 *toget = bsrt->hits;
1778 if ((comp.u.simple = req->mediumSetElementSetNames))
1784 if (*toget && !resp->records)
1789 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1792 form = prefformat->value;
1793 resp->records = pack_records(assoc, req->resultSetName, 1,
1794 toget, compp, next, presst, form, req->referenceId,
1795 req->preferredRecordSyntax, NULL);
1798 resp->numberOfRecordsReturned = toget;
1799 returnedrecs = *toget;
1800 resp->nextResultSetPosition = next;
1801 resp->searchStatus = sr;
1802 resp->resultSetStatus = 0;
1803 resp->presentStatus = presst;
1807 if (*resp->resultCount)
1809 resp->numberOfRecordsReturned = nulint;
1810 resp->nextResultSetPosition = next;
1811 resp->searchStatus = sr;
1812 resp->resultSetStatus = 0;
1813 resp->presentStatus = 0;
1816 resp->additionalSearchInfo = bsrt->search_info;
1820 WRBUF wr=wrbuf_alloc();
1821 wrbuf_put_zquery(wr, req->query);
1823 wr_diag(wr, bsrt->errcode, bsrt->errstring);
1826 wrbuf_printf(wr," OK:%d hits", bsrt->hits);
1828 wrbuf_printf(wr, " %d records returned", returnedrecs);
1830 yaz_log(log_request, "Search %s %s", req->resultSetName,
1838 * Maybe we got a little over-friendly when we designed bend_fetch to
1839 * get only one record at a time. Some backends can optimise multiple-record
1840 * fetches, and at any rate, there is some overhead involved in
1841 * all that selecting and hopping around. Problem is, of course, that the
1842 * frontend can't know ahead of time how many records it'll need to
1843 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1844 * is downright lousy as a bulk data transfer protocol.
1846 * To start with, we'll do the fetching of records from the backend
1847 * in one operation: To save some trips in and out of the event-handler,
1848 * and to simplify the interface to pack_records. At any rate, asynch
1849 * operation is more fun in operations that have an unpredictable execution
1850 * speed - which is normally more true for search than for present.
1852 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1855 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1859 Z_PresentResponse *resp;
1863 const char *errstring = 0;
1865 yaz_log(log_requestdetail, "Got PresentRequest.");
1867 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1870 form = prefformat->value;
1871 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1873 resp->presentStatus = odr_intdup(assoc->encode, 0);
1874 if (assoc->init->bend_present)
1876 bend_present_rr *bprr = (bend_present_rr *)
1877 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1878 bprr->setname = req->resultSetId;
1879 bprr->start = *req->resultSetStartPoint;
1880 bprr->number = *req->numberOfRecordsRequested;
1881 bprr->format = form;
1882 bprr->comp = req->recordComposition;
1883 bprr->referenceId = req->referenceId;
1884 bprr->stream = assoc->encode;
1885 bprr->print = assoc->print;
1886 bprr->request = reqb;
1887 bprr->association = assoc;
1889 bprr->errstring = NULL;
1890 (*assoc->init->bend_present)(assoc->backend, bprr);
1893 return 0; /* should not happen */
1896 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1897 *resp->presentStatus = Z_PresentStatus_failure;
1898 errcode = bprr->errcode;
1899 errstring = bprr->errstring;
1902 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1903 next = odr_intdup(assoc->encode, 0);
1904 num = odr_intdup(assoc->encode, 0);
1906 apdu->which = Z_APDU_presentResponse;
1907 apdu->u.presentResponse = resp;
1908 resp->referenceId = req->referenceId;
1909 resp->otherInfo = 0;
1913 *num = *req->numberOfRecordsRequested;
1915 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1916 num, req->recordComposition, next,
1917 resp->presentStatus,
1918 form, req->referenceId, req->preferredRecordSyntax,
1923 WRBUF wr = wrbuf_alloc();
1924 wrbuf_printf(wr, "Present %s %d+%d ",
1925 req->resultSetId, *req->resultSetStartPoint,
1926 *req->numberOfRecordsRequested);
1927 if (*resp->presentStatus == Z_PresentStatus_failure)
1928 wr_diag(wr, errcode, errstring);
1929 else if (*resp->presentStatus == Z_PresentStatus_success)
1930 wrbuf_printf(wr,"OK %d records returned ", *num);
1932 wrbuf_printf(wr,"Partial (%d) OK %d records returned ",
1933 *resp->presentStatus, *num);
1934 yaz_log(log_request, "%s", wrbuf_buf(wr) );
1939 resp->numberOfRecordsReturned = num;
1940 resp->nextResultSetPosition = next;
1946 * Scan was implemented rather in a hurry, and with support for only the basic
1947 * elements of the service in the backend API. Suggestions are welcome.
1949 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1951 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1952 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1953 Z_ScanResponse *res = (Z_ScanResponse *)
1954 odr_malloc (assoc->encode, sizeof(*res));
1955 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1956 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1957 Z_ListEntries *ents = (Z_ListEntries *)
1958 odr_malloc (assoc->encode, sizeof(*ents));
1959 Z_DiagRecs *diagrecs_p = NULL;
1961 bend_scan_rr *bsrr = (bend_scan_rr *)
1962 odr_malloc (assoc->encode, sizeof(*bsrr));
1963 struct scan_entry *save_entries;
1965 yaz_log(log_requestdetail, "Got ScanRequest");
1967 apdu->which = Z_APDU_scanResponse;
1968 apdu->u.scanResponse = res;
1969 res->referenceId = req->referenceId;
1971 /* if step is absent, set it to 0 */
1972 res->stepSize = odr_intdup(assoc->encode, 0);
1974 *res->stepSize = *req->stepSize;
1976 res->scanStatus = scanStatus;
1977 res->numberOfEntriesReturned = numberOfEntriesReturned;
1978 res->positionOfTerm = 0;
1979 res->entries = ents;
1980 ents->num_entries = 0;
1981 ents->entries = NULL;
1982 ents->num_nonsurrogateDiagnostics = 0;
1983 ents->nonsurrogateDiagnostics = NULL;
1984 res->attributeSet = 0;
1987 if (req->databaseNames)
1990 for (i = 0; i < req->num_databaseNames; i++)
1991 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
1993 yaz_log(log_requestdetail, "pos %d step %d entries %d",
1994 *req->preferredPositionInResponse, *res->stepSize,
1995 *req->numberOfTermsRequested);
1996 bsrr->num_bases = req->num_databaseNames;
1997 bsrr->basenames = req->databaseNames;
1998 bsrr->num_entries = *req->numberOfTermsRequested;
1999 bsrr->term = req->termListAndStartPoint;
2000 bsrr->referenceId = req->referenceId;
2001 bsrr->stream = assoc->encode;
2002 bsrr->print = assoc->print;
2003 bsrr->step_size = res->stepSize;
2005 /* Note that version 2.0 of YAZ and older did not set entries ..
2006 We do now. And when we do it's easier to extend the scan entry
2007 We know that if the scan handler did set entries, it will
2008 not know of new member display_term.
2010 if (bsrr->num_entries > 0)
2013 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2015 for (i = 0; i<bsrr->num_entries; i++)
2017 bsrr->entries[i].term = 0;
2018 bsrr->entries[i].occurrences = 0;
2019 bsrr->entries[i].errcode = 0;
2020 bsrr->entries[i].errstring = 0;
2021 bsrr->entries[i].display_term = 0;
2024 save_entries = bsrr->entries; /* save it so we can compare later */
2026 if (req->attributeSet &&
2027 (attset = oid_getentbyoid(req->attributeSet)) &&
2028 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2029 bsrr->attributeset = attset->value;
2031 bsrr->attributeset = VAL_NONE;
2032 log_scan_term_level (log_requestdetail, req->termListAndStartPoint,
2033 bsrr->attributeset);
2034 bsrr->term_position = req->preferredPositionInResponse ?
2035 *req->preferredPositionInResponse : 1;
2037 ((int (*)(void *, bend_scan_rr *))
2038 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2041 diagrecs_p = zget_DiagRecs(assoc->encode,
2042 bsrr->errcode, bsrr->errstring);
2046 Z_Entry **tab = (Z_Entry **)
2047 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2049 if (bsrr->status == BEND_SCAN_PARTIAL)
2050 *scanStatus = Z_Scan_partial_5;
2052 *scanStatus = Z_Scan_success;
2053 ents->entries = tab;
2054 ents->num_entries = bsrr->num_entries;
2055 res->numberOfEntriesReturned = &ents->num_entries;
2056 res->positionOfTerm = &bsrr->term_position;
2057 for (i = 0; i < bsrr->num_entries; i++)
2063 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2064 if (bsrr->entries[i].occurrences >= 0)
2066 e->which = Z_Entry_termInfo;
2067 e->u.termInfo = t = (Z_TermInfo *)
2068 odr_malloc(assoc->encode, sizeof(*t));
2069 t->suggestedAttributes = 0;
2071 if (save_entries == bsrr->entries &&
2072 bsrr->entries[i].display_term)
2074 /* the entries was NOT set by the handler. So it's
2075 safe to test for new member display_term. It is
2078 t->displayTerm = odr_strdup(assoc->encode,
2079 bsrr->entries[i].display_term);
2081 t->alternativeTerm = 0;
2082 t->byAttributes = 0;
2083 t->otherTermInfo = 0;
2084 t->globalOccurrences = &bsrr->entries[i].occurrences;
2085 t->term = (Z_Term *)
2086 odr_malloc(assoc->encode, sizeof(*t->term));
2087 t->term->which = Z_Term_general;
2088 t->term->u.general = o =
2089 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2090 o->buf = (unsigned char *)
2091 odr_malloc(assoc->encode, o->len = o->size =
2092 strlen(bsrr->entries[i].term));
2093 memcpy(o->buf, bsrr->entries[i].term, o->len);
2094 yaz_log(YLOG_DEBUG, " term #%d: '%s' (%d)", i,
2095 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2099 Z_DiagRecs *drecs = zget_DiagRecs(assoc->encode,
2100 bsrr->entries[i].errcode,
2101 bsrr->entries[i].errstring);
2102 assert (drecs->num_diagRecs == 1);
2103 e->which = Z_Entry_surrogateDiagnostic;
2104 assert (drecs->diagRecs[0]);
2105 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2111 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2112 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2116 WRBUF wr=wrbuf_alloc();
2117 wrbuf_printf(wr, "Scan %d@%d ",
2118 *req->preferredPositionInResponse,
2119 *req->numberOfTermsRequested);
2121 wrbuf_printf(wr, "(step %d) ",*res->stepSize);
2122 wrbuf_scan_term(wr, req->termListAndStartPoint,
2123 bsrr->attributeset);
2125 if (*res->scanStatus == Z_Scan_success)
2127 wrbuf_printf(wr," OK");
2130 wrbuf_printf(wr," Error");
2131 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2137 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2141 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2142 Z_SortResponse *res = (Z_SortResponse *)
2143 odr_malloc (assoc->encode, sizeof(*res));
2144 bend_sort_rr *bsrr = (bend_sort_rr *)
2145 odr_malloc (assoc->encode, sizeof(*bsrr));
2147 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2149 yaz_log(log_requestdetail, "Got SortRequest.");
2151 bsrr->num_input_setnames = req->num_inputResultSetNames;
2152 for (i=0;i<req->num_inputResultSetNames;i++)
2153 yaz_log(log_requestdetail, "Input resultset: '%s'",
2154 req->inputResultSetNames[i]);
2155 bsrr->input_setnames = req->inputResultSetNames;
2156 bsrr->referenceId = req->referenceId;
2157 bsrr->output_setname = req->sortedResultSetName;
2158 yaz_log(log_requestdetail, "Output resultset: '%s'",
2159 req->sortedResultSetName);
2160 bsrr->sort_sequence = req->sortSequence;
2161 /*FIXME - dump those sequences too */
2162 bsrr->stream = assoc->encode;
2163 bsrr->print = assoc->print;
2165 bsrr->sort_status = Z_SortResponse_failure;
2167 bsrr->errstring = 0;
2169 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2171 res->referenceId = bsrr->referenceId;
2172 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2173 res->resultSetStatus = 0;
2176 Z_DiagRecs *dr = zget_DiagRecs(assoc->encode,
2177 bsrr->errcode, bsrr->errstring);
2178 res->diagnostics = dr->diagRecs;
2179 res->num_diagnostics = dr->num_diagRecs;
2183 res->num_diagnostics = 0;
2184 res->diagnostics = 0;
2186 res->resultCount = 0;
2189 apdu->which = Z_APDU_sortResponse;
2190 apdu->u.sortResponse = res;
2193 WRBUF wr=wrbuf_alloc();
2194 wrbuf_printf(wr, "Sort (");
2195 for (i=0;i<req->num_inputResultSetNames;i++)
2198 wrbuf_printf(wr,",");
2199 wrbuf_printf(wr, req->inputResultSetNames[i]);
2201 wrbuf_printf(wr,")->%s ",req->sortedResultSetName);
2203 /* FIXME - dump also the sort sequence */
2205 wrbuf_diags(wr, res->num_diagnostics, res->diagnostics);
2207 wrbuf_printf(wr," OK");
2208 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2214 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2218 Z_DeleteResultSetRequest *req =
2219 reqb->apdu_request->u.deleteResultSetRequest;
2220 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2221 odr_malloc (assoc->encode, sizeof(*res));
2222 bend_delete_rr *bdrr = (bend_delete_rr *)
2223 odr_malloc (assoc->encode, sizeof(*bdrr));
2224 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2226 yaz_log(log_requestdetail, "Got DeleteRequest.");
2228 bdrr->num_setnames = req->num_resultSetList;
2229 bdrr->setnames = req->resultSetList;
2230 for (i = 0; i<req->num_resultSetList; i++)
2231 yaz_log(log_requestdetail, "resultset: '%s'",
2232 req->resultSetList[i]);
2233 bdrr->stream = assoc->encode;
2234 bdrr->print = assoc->print;
2235 bdrr->function = *req->deleteFunction;
2236 bdrr->referenceId = req->referenceId;
2238 if (bdrr->num_setnames > 0)
2240 bdrr->statuses = (int*)
2241 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2242 bdrr->num_setnames);
2243 for (i = 0; i < bdrr->num_setnames; i++)
2244 bdrr->statuses[i] = 0;
2246 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2248 res->referenceId = req->referenceId;
2250 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2252 res->deleteListStatuses = 0;
2253 if (bdrr->num_setnames > 0)
2256 res->deleteListStatuses = (Z_ListStatuses *)
2257 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2258 res->deleteListStatuses->num = bdrr->num_setnames;
2259 res->deleteListStatuses->elements =
2261 odr_malloc (assoc->encode,
2262 sizeof(*res->deleteListStatuses->elements) *
2263 bdrr->num_setnames);
2264 for (i = 0; i<bdrr->num_setnames; i++)
2266 res->deleteListStatuses->elements[i] =
2268 odr_malloc (assoc->encode,
2269 sizeof(**res->deleteListStatuses->elements));
2270 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2271 res->deleteListStatuses->elements[i]->id =
2272 odr_strdup (assoc->encode, bdrr->setnames[i]);
2275 res->numberNotDeleted = 0;
2276 res->bulkStatuses = 0;
2277 res->deleteMessage = 0;
2280 apdu->which = Z_APDU_deleteResultSetResponse;
2281 apdu->u.deleteResultSetResponse = res;
2284 WRBUF wr=wrbuf_alloc();
2285 wrbuf_printf(wr, "Delete ");
2286 for (i = 0; i<req->num_resultSetList; i++)
2287 wrbuf_printf(wr, " '%s' ", req->resultSetList[i]);
2288 if (bdrr->delete_status)
2289 wrbuf_printf(wr," ERROR %d", bdrr->delete_status);
2291 wrbuf_printf(wr,"OK");
2292 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2298 static void process_close(association *assoc, request *reqb)
2300 Z_Close *req = reqb->apdu_request->u.close;
2301 static char *reasons[] =
2308 "securityViolation",
2315 yaz_log(log_requestdetail, "Got Close, reason %s, message %s",
2316 reasons[*req->closeReason], req->diagnosticInformation ?
2317 req->diagnosticInformation : "NULL");
2318 if (assoc->version < 3) /* to make do_force respond with close */
2320 do_close_req(assoc, Z_Close_finished,
2321 "Association terminated by client", reqb);
2322 yaz_log(log_request,"Close OK");
2325 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2329 reqb->len_refid = refid->len;
2330 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2331 memcpy (reqb->refid, refid->buf, refid->len);
2335 reqb->len_refid = 0;
2340 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2342 process_z_response (a, req, res);
2345 bend_request bend_request_mk (bend_association a)
2347 request *nreq = request_get (&a->outgoing);
2348 nreq->request_mem = nmem_create ();
2352 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2357 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2358 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2359 id->len = id->size = req->len_refid;
2360 memcpy (id->buf, req->refid, req->len_refid);
2364 void bend_request_destroy (bend_request *req)
2366 nmem_destroy((*req)->request_mem);
2367 request_release(*req);
2371 int bend_backend_respond (bend_association a, bend_request req)
2375 r = process_z_request (a, req, &msg);
2377 yaz_log (YLOG_WARN, "%s", msg);
2381 void bend_request_setdata(bend_request r, void *p)
2386 void *bend_request_getdata(bend_request r)
2388 return r->clientData;
2391 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2393 bend_segment_rr req;
2395 req.segment = reqb->apdu_request->u.segmentRequest;
2396 req.stream = assoc->encode;
2397 req.decode = assoc->decode;
2398 req.print = assoc->print;
2399 req.association = assoc;
2401 (*assoc->init->bend_segment)(assoc->backend, &req);
2406 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2408 bend_esrequest_rr esrequest;
2410 Z_ExtendedServicesRequest *req =
2411 reqb->apdu_request->u.extendedServicesRequest;
2412 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2414 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2416 yaz_log(log_requestdetail,"Got EsRequest");
2418 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2419 esrequest.stream = assoc->encode;
2420 esrequest.decode = assoc->decode;
2421 esrequest.print = assoc->print;
2422 esrequest.errcode = 0;
2423 esrequest.errstring = NULL;
2424 esrequest.request = reqb;
2425 esrequest.association = assoc;
2426 esrequest.taskPackage = 0;
2427 esrequest.referenceId = req->referenceId;
2429 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2431 /* If the response is being delayed, return NULL */
2432 if (esrequest.request == NULL)
2435 resp->referenceId = req->referenceId;
2437 if (esrequest.errcode == -1)
2439 /* Backend service indicates request will be processed */
2440 yaz_log(log_request,"EsRequest OK: Accepted !");
2441 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2443 else if (esrequest.errcode == 0)
2445 /* Backend service indicates request will be processed */
2446 yaz_log(log_request,"EsRequest OK: Done !");
2447 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2451 Z_DiagRecs *diagRecs =
2452 zget_DiagRecs(assoc->encode, esrequest.errcode,
2453 esrequest.errstring);
2454 /* Backend indicates error, request will not be processed */
2455 yaz_log(YLOG_DEBUG,"Request could not be processed...failure !");
2456 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2457 resp->num_diagnostics = diagRecs->num_diagRecs;
2458 resp->diagnostics = diagRecs->diagRecs;
2461 WRBUF wr=wrbuf_alloc();
2462 wrbuf_diags(wr, resp->num_diagnostics, resp->diagnostics);
2463 yaz_log(log_request, "EsRequest %s", wrbuf_buf(wr) );
2468 /* Do something with the members of bend_extendedservice */
2469 if (esrequest.taskPackage)
2470 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2471 (const char *) esrequest.taskPackage,
2473 yaz_log(YLOG_DEBUG,"Send the result apdu");