2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.39 2004-12-20 23:38:03 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), ".%d", 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, "Search %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 code %d", rr.errcode);
741 if (rr.errcode == 109) /* database unavailable */
746 srw_res->num_diagnostics = 1;
747 srw_res->diagnostics = (Z_SRW_diagnostic *)
748 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
749 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
750 yaz_diag_bib1_to_srw (rr.errcode),
752 yaz_log(log_request, "srw_bend_search returned SRW error %s",
753 srw_res->diagnostics[0].uri);
757 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
758 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
760 yaz_log(log_requestdetail, "Request to pack %d+%d out of %d",
761 start, number, rr.hits);
763 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
770 srw_res->num_diagnostics = 1;
771 srw_res->diagnostics = (Z_SRW_diagnostic *)
772 odr_malloc(assoc->encode,
773 sizeof(*srw_res->diagnostics));
774 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
780 int packing = Z_SRW_recordPacking_string;
781 if (start + number > rr.hits)
782 number = rr.hits - start + 1;
783 if (srw_req->recordPacking &&
784 !strcmp(srw_req->recordPacking, "xml"))
785 packing = Z_SRW_recordPacking_XML;
786 srw_res->records = (Z_SRW_record *)
787 odr_malloc(assoc->encode,
788 number * sizeof(*srw_res->records));
789 for (i = 0; i<number; i++)
793 srw_res->records[j].recordPacking = packing;
794 srw_res->records[j].recordData_buf = 0;
795 yaz_log(YLOG_DEBUG, "srw_bend_fetch %d", i+start);
796 errcode = srw_bend_fetch(assoc, i+start, srw_req,
797 srw_res->records + j);
800 srw_res->num_diagnostics = 1;
801 srw_res->diagnostics = (Z_SRW_diagnostic *)
802 odr_malloc(assoc->encode,
803 sizeof(*srw_res->diagnostics));
805 yaz_mk_std_diagnostic(assoc->encode,
806 srw_res->diagnostics,
807 yaz_diag_bib1_to_srw (errcode),
811 if (srw_res->records[j].recordData_buf)
814 srw_res->num_records = j;
816 srw_res->records = 0;
822 WRBUF wr=wrbuf_alloc();
823 wrbuf_printf(wr,"SRW: %s", querystr);
825 wrbuf_printf(wr," ERROR %d ", srw_error);
828 wrbuf_printf(wr," OK:%d hits ", rr.hits);
829 if (srw_res->num_records)
830 wrbuf_printf(wr," Returned %d records", srw_res->num_records);
832 yaz_log(log_request, "Search %s", wrbuf_buf(wr) );
837 static void srw_bend_explain(association *assoc, request *req,
838 Z_SRW_explainRequest *srw_req,
839 Z_SRW_explainResponse *srw_res,
842 yaz_log(log_requestdetail, "Got SRW ExplainRequest");
846 yaz_log(YLOG_DEBUG, "srw_bend_init");
847 if (!srw_bend_init(assoc))
852 if (assoc->init && assoc->init->bend_explain)
856 rr.stream = assoc->encode;
857 rr.decode = assoc->decode;
858 rr.print = assoc->print;
860 rr.database = srw_req->database;
861 rr.schema = "http://explain.z3950.org/dtd/2.0/";
862 (*assoc->init->bend_explain)(assoc->backend, &rr);
865 int packing = Z_SRW_recordPacking_string;
866 if (srw_req->recordPacking &&
867 !strcmp(srw_req->recordPacking, "xml"))
868 packing = Z_SRW_recordPacking_XML;
869 srw_res->record.recordSchema = rr.schema;
870 srw_res->record.recordPacking = packing;
871 srw_res->record.recordData_buf = rr.explain_buf;
872 srw_res->record.recordData_len = strlen(rr.explain_buf);
873 srw_res->record.recordPosition = 0;
879 static void process_http_request(association *assoc, request *req)
881 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
882 ODR o = assoc->encode;
883 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
885 Z_SOAP *soap_package = 0;
888 Z_HTTP_Response *hres = 0;
890 char *stylesheet = 0;
891 Z_SRW_diagnostic *diagnostic = 0;
892 int num_diagnostic = 0;
894 if (!strcmp(hreq->path, "/test"))
896 p = z_get_HTTP_Response(o, 200);
897 hres = p->u.HTTP_Response;
898 hres->content_buf = "1234567890\n";
899 hres->content_len = strlen(hres->content_buf);
904 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
905 yaz_log(YLOG_DEBUG, "yaz_srw_decode returned %d", r);
907 if (r == 2) /* not taken */
909 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
910 &diagnostic, &num_diagnostic);
911 yaz_log(YLOG_DEBUG, "yaz_sru_decode returned %d", r);
913 if (r == 0) /* decode SRW/SRU OK .. */
916 if (sr->which == Z_SRW_searchRetrieve_request)
919 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
921 stylesheet = sr->u.request->stylesheet;
924 res->u.response->diagnostics = diagnostic;
925 res->u.response->num_diagnostics = num_diagnostic;
929 srw_bend_search(assoc, req, sr->u.request, res->u.response,
932 if (http_code == 200)
933 soap_package->u.generic->p = res;
935 else if (sr->which == Z_SRW_explain_request)
937 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
938 stylesheet = sr->u.explain_request->stylesheet;
941 res->u.explain_response->diagnostics = diagnostic;
942 res->u.explain_response->num_diagnostics = num_diagnostic;
944 srw_bend_explain(assoc, req, sr->u.explain_request,
945 res->u.explain_response, &http_code);
946 if (http_code == 200)
947 soap_package->u.generic->p = res;
949 else if (sr->which == Z_SRW_scan_request)
951 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
952 stylesheet = sr->u.scan_request->stylesheet;
955 res->u.scan_response->diagnostics = diagnostic;
956 res->u.scan_response->num_diagnostics = num_diagnostic;
958 yaz_add_srw_diagnostic(o,
959 &res->u.scan_response->diagnostics,
960 &res->u.scan_response->num_diagnostics,
962 if (http_code == 200)
963 soap_package->u.generic->p = res;
967 yaz_log(log_request, "generate soap error");
968 /* FIXME - what error, what query */
970 z_soap_error(assoc->encode, soap_package,
971 "SOAP-ENV:Client", "Bad method", 0);
973 if (http_code == 200 || http_code == 500)
975 static Z_SOAP_Handler soap_handlers[3] = {
977 {"http://www.loc.gov/zing/srw/", 0,
978 (Z_SOAP_fun) yaz_srw_codec},
979 {"http://www.loc.gov/zing/srw/v1.0/", 0,
980 (Z_SOAP_fun) yaz_srw_codec},
986 p = z_get_HTTP_Response(o, 200);
987 hres = p->u.HTTP_Response;
988 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
989 &hres->content_buf, &hres->content_len,
990 soap_handlers, charset, stylesheet);
991 hres->code = http_code;
993 strcpy(ctype, "text/xml");
996 strcat(ctype, "; charset=");
997 strcat(ctype, charset);
999 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
1002 p = z_get_HTTP_Response(o, http_code);
1006 p = z_get_HTTP_Response(o, 500);
1007 hres = p->u.HTTP_Response;
1008 if (!strcmp(hreq->version, "1.0"))
1010 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1011 if (v && !strcmp(v, "Keep-Alive"))
1015 hres->version = "1.0";
1019 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
1020 if (v && !strcmp(v, "close"))
1024 hres->version = "1.1";
1028 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
1029 assoc->state = ASSOC_DEAD;
1030 assoc->cs_get_mask = 0;
1035 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
1037 if (alive && isdigit(*alive))
1041 if (t < 0 || t > 3600)
1043 iochan_settimeout(assoc->client_chan,t);
1044 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
1046 process_gdu_response(assoc, req, p);
1049 static void process_gdu_request(association *assoc, request *req)
1051 if (req->gdu_request->which == Z_GDU_Z3950)
1054 req->apdu_request = req->gdu_request->u.z3950;
1055 if (process_z_request(assoc, req, &msg) < 0)
1056 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1058 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1059 process_http_request(assoc, req);
1062 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1067 * Initiate request processing.
1069 static int process_z_request(association *assoc, request *req, char **msg)
1075 *msg = "Unknown Error";
1076 assert(req && req->state == REQUEST_IDLE);
1077 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1079 *msg = "Missing InitRequest";
1082 switch (req->apdu_request->which)
1084 case Z_APDU_initRequest:
1085 iochan_settimeout(assoc->client_chan,
1086 statserv_getcontrol()->idle_timeout * 60);
1087 res = process_initRequest(assoc, req); break;
1088 case Z_APDU_searchRequest:
1089 res = process_searchRequest(assoc, req, &fd); break;
1090 case Z_APDU_presentRequest:
1091 res = process_presentRequest(assoc, req, &fd); break;
1092 case Z_APDU_scanRequest:
1093 if (assoc->init->bend_scan)
1094 res = process_scanRequest(assoc, req, &fd);
1097 *msg = "Cannot handle Scan APDU";
1101 case Z_APDU_extendedServicesRequest:
1102 if (assoc->init->bend_esrequest)
1103 res = process_ESRequest(assoc, req, &fd);
1106 *msg = "Cannot handle Extended Services APDU";
1110 case Z_APDU_sortRequest:
1111 if (assoc->init->bend_sort)
1112 res = process_sortRequest(assoc, req, &fd);
1115 *msg = "Cannot handle Sort APDU";
1120 process_close(assoc, req);
1122 case Z_APDU_deleteResultSetRequest:
1123 if (assoc->init->bend_delete)
1124 res = process_deleteRequest(assoc, req, &fd);
1127 *msg = "Cannot handle Delete APDU";
1131 case Z_APDU_segmentRequest:
1132 if (assoc->init->bend_segment)
1134 res = process_segmentRequest (assoc, req);
1138 *msg = "Cannot handle Segment APDU";
1142 case Z_APDU_triggerResourceControlRequest:
1145 *msg = "Bad APDU received";
1150 yaz_log(YLOG_DEBUG, " result immediately available");
1151 retval = process_z_response(assoc, req, res);
1155 yaz_log(YLOG_DEBUG, " result unavailble");
1158 else /* no result yet - one will be provided later */
1162 /* Set up an I/O handler for the fd supplied by the backend */
1164 yaz_log(YLOG_DEBUG, " establishing handler for result");
1165 req->state = REQUEST_PENDING;
1166 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1168 iochan_setdata(chan, assoc);
1175 * Handle message from the backend.
1177 void backend_response(IOCHAN i, int event)
1179 association *assoc = (association *)iochan_getdata(i);
1180 request *req = request_head(&assoc->incoming);
1184 yaz_log(YLOG_DEBUG, "backend_response");
1185 assert(assoc && req && req->state != REQUEST_IDLE);
1186 /* determine what it is we're waiting for */
1187 switch (req->apdu_request->which)
1189 case Z_APDU_searchRequest:
1190 res = response_searchRequest(assoc, req, 0, &fd); break;
1192 case Z_APDU_presentRequest:
1193 res = response_presentRequest(assoc, req, 0, &fd); break;
1194 case Z_APDU_scanRequest:
1195 res = response_scanRequest(assoc, req, 0, &fd); break;
1198 yaz_log(YLOG_FATAL, "Serious programmer's lapse or bug");
1201 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1203 yaz_log(YLOG_WARN, "Fatal error when talking to backend");
1204 do_close(assoc, Z_Close_systemProblem, 0);
1208 else if (!res) /* no result yet - try again later */
1210 yaz_log(YLOG_DEBUG, " no result yet");
1211 iochan_setfd(i, fd); /* in case fd has changed */
1216 * Encode response, and transfer the request structure to the outgoing queue.
1218 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1220 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1224 if (!z_GDU(assoc->print, &res, 0, 0))
1225 yaz_log(YLOG_WARN, "ODR print error: %s",
1226 odr_errmsg(odr_geterror(assoc->print)));
1227 odr_reset(assoc->print);
1229 if (!z_GDU(assoc->encode, &res, 0, 0))
1231 yaz_log(YLOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1232 odr_errmsg(odr_geterror(assoc->decode)),
1233 odr_getelement(assoc->decode));
1236 req->response = odr_getbuf(assoc->encode, &req->len_response,
1237 &req->size_response);
1238 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1239 odr_reset(assoc->encode);
1240 req->state = REQUEST_IDLE;
1241 request_enq(&assoc->outgoing, req);
1242 /* turn the work over to the ir_session handler */
1243 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1244 assoc->cs_put_mask = EVENT_OUTPUT;
1245 /* Is there more work to be done? give that to the input handler too */
1247 if (request_head(&assoc->incoming))
1249 yaz_log (YLOG_DEBUG, "more work to be done");
1250 iochan_setevent(assoc->client_chan, EVENT_WORK);
1257 * Encode response, and transfer the request structure to the outgoing queue.
1259 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1261 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1262 gres->which = Z_GDU_Z3950;
1263 gres->u.z3950 = res;
1265 return process_gdu_response(assoc, req, gres);
1270 * Handle init request.
1271 * At the moment, we don't check the options
1272 * anywhere else in the code - we just try not to do anything that would
1273 * break a naive client. We'll toss 'em into the association block when
1274 * we need them there.
1276 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1278 statserv_options_block *cb = statserv_getcontrol();
1279 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1280 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1281 Z_InitResponse *resp = apdu->u.initResponse;
1282 bend_initresult *binitres;
1286 yaz_log(log_requestdetail, "Got initRequest");
1287 if (req->implementationId)
1288 yaz_log(log_requestdetail, "Id: %s", req->implementationId);
1289 if (req->implementationName)
1290 yaz_log(log_requestdetail, "Name: %s", req->implementationName);
1291 if (req->implementationVersion)
1292 yaz_log(log_requestdetail, "Version: %s", req->implementationVersion);
1294 assoc_init_reset(assoc);
1296 assoc->init->auth = req->idAuthentication;
1297 assoc->init->referenceId = req->referenceId;
1299 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1301 Z_CharSetandLanguageNegotiation *negotiation =
1302 yaz_get_charneg_record (req->otherInfo);
1304 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1305 assoc->init->charneg_request = negotiation;
1309 if (!(binitres = (*cb->bend_init)(assoc->init)))
1311 yaz_log(YLOG_WARN, "Bad response from backend.");
1315 assoc->backend = binitres->handle;
1316 if ((assoc->init->bend_sort))
1317 yaz_log (YLOG_DEBUG, "Sort handler installed");
1318 if ((assoc->init->bend_search))
1319 yaz_log (YLOG_DEBUG, "Search handler installed");
1320 if ((assoc->init->bend_present))
1321 yaz_log (YLOG_DEBUG, "Present handler installed");
1322 if ((assoc->init->bend_esrequest))
1323 yaz_log (YLOG_DEBUG, "ESRequest handler installed");
1324 if ((assoc->init->bend_delete))
1325 yaz_log (YLOG_DEBUG, "Delete handler installed");
1326 if ((assoc->init->bend_scan))
1327 yaz_log (YLOG_DEBUG, "Scan handler installed");
1328 if ((assoc->init->bend_segment))
1329 yaz_log (YLOG_DEBUG, "Segment handler installed");
1331 resp->referenceId = req->referenceId;
1333 /* let's tell the client what we can do */
1334 if (ODR_MASK_GET(req->options, Z_Options_search))
1336 ODR_MASK_SET(resp->options, Z_Options_search);
1337 strcat(options, "srch");
1339 if (ODR_MASK_GET(req->options, Z_Options_present))
1341 ODR_MASK_SET(resp->options, Z_Options_present);
1342 strcat(options, " prst");
1344 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1345 assoc->init->bend_delete)
1347 ODR_MASK_SET(resp->options, Z_Options_delSet);
1348 strcat(options, " del");
1350 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1351 assoc->init->bend_esrequest)
1353 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1354 strcat (options, " extendedServices");
1356 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1358 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1359 strcat(options, " namedresults");
1361 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1363 ODR_MASK_SET(resp->options, Z_Options_scan);
1364 strcat(options, " scan");
1366 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1368 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1369 strcat(options, " concurrop");
1371 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1373 ODR_MASK_SET(resp->options, Z_Options_sort);
1374 strcat(options, " sort");
1377 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1378 && assoc->init->charneg_response)
1380 Z_OtherInformation **p;
1381 Z_OtherInformationUnit *p0;
1383 yaz_oi_APDU(apdu, &p);
1385 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1386 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1388 p0->which = Z_OtherInfo_externallyDefinedInfo;
1389 p0->information.externallyDefinedInfo =
1390 assoc->init->charneg_response;
1392 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1393 strcat(options, " negotiation");
1396 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1398 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1400 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1401 assoc->version = 1; /* 1 & 2 are equivalent */
1403 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1405 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1408 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1410 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1414 yaz_log(log_requestdetail, "Negotiated to v%d: %s", assoc->version, options);
1415 assoc->maximumRecordSize = *req->maximumRecordSize;
1416 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1417 assoc->maximumRecordSize = control_block->maxrecordsize;
1418 assoc->preferredMessageSize = *req->preferredMessageSize;
1419 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1420 assoc->preferredMessageSize = assoc->maximumRecordSize;
1422 resp->preferredMessageSize = &assoc->preferredMessageSize;
1423 resp->maximumRecordSize = &assoc->maximumRecordSize;
1425 resp->implementationId = odr_prepend(assoc->encode,
1426 assoc->init->implementation_id,
1427 resp->implementationId);
1429 resp->implementationName = odr_prepend(assoc->encode,
1430 assoc->init->implementation_name,
1431 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1433 version = odr_strdup(assoc->encode, "$Revision: 1.39 $");
1434 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1435 version[strlen(version)-2] = '\0';
1436 resp->implementationVersion = odr_prepend(assoc->encode,
1437 assoc->init->implementation_version,
1438 odr_prepend(assoc->encode, &version[11],
1439 resp->implementationVersion));
1441 if (binitres->errcode)
1443 WRBUF wr = wrbuf_alloc();
1445 assoc->state = ASSOC_DEAD;
1446 resp->userInformationField =
1447 init_diagnostics(assoc->encode, binitres->errcode,
1448 binitres->errstring);
1449 wr_diag(wr, binitres->errcode, binitres->errstring);
1450 yaz_log(log_request, "Init from '%s' (%s) (ver %s) %s",
1451 req->implementationName ? req->implementationName :"??",
1452 req->implementationId ? req->implementationId :"?",
1453 req->implementationVersion ? req->implementationVersion: "?",
1459 assoc->state = ASSOC_UP;
1460 yaz_log(log_request, "Init from '%s' (%s) (ver %s) OK",
1461 req->implementationName ? req->implementationName :"??",
1462 req->implementationId ? req->implementationId :"?",
1463 req->implementationVersion ? req->implementationVersion: "?");
1470 * Set the specified `errcode' and `errstring' into a UserInfo-1
1471 * external to be returned to the client in accordance with Z35.90
1472 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1473 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1475 static Z_External *init_diagnostics(ODR odr, int error, const char *addinfo)
1477 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1478 addinfo ? " -- " : "", addinfo ? addinfo : "");
1479 return zget_init_diagnostics(odr, error, addinfo);
1483 * nonsurrogate diagnostic record.
1485 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1487 Z_Records *rec = (Z_Records *) odr_malloc (assoc->encode, sizeof(*rec));
1489 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1490 addinfo ? " -- " : "", addinfo ? addinfo : "");
1492 rec->which = Z_Records_NSD;
1493 rec->u.nonSurrogateDiagnostic = zget_DefaultDiagFormat(assoc->encode,
1499 * surrogate diagnostic.
1501 static Z_NamePlusRecord *surrogatediagrec(association *assoc,
1503 int error, const char *addinfo)
1505 yaz_log(log_requestdetail, "[%d] %s%s%s", error, diagbib1_str(error),
1506 addinfo ? " -- " : "", addinfo ? addinfo : "");
1507 return zget_surrogateDiagRec(assoc->encode, dbname, error, addinfo);
1510 static Z_Records *pack_records(association *a, char *setname, int start,
1511 int *num, Z_RecordComposition *comp,
1512 int *next, int *pres, oid_value format,
1513 Z_ReferenceId *referenceId,
1514 int *oid, int *errcode)
1516 int recno, total_length = 0, toget = *num, dumped_records = 0;
1517 Z_Records *records =
1518 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1519 Z_NamePlusRecordList *reclist =
1520 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1521 Z_NamePlusRecord **list =
1522 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1524 records->which = Z_Records_DBOSD;
1525 records->u.databaseOrSurDiagnostics = reclist;
1526 reclist->num_records = 0;
1527 reclist->records = list;
1528 *pres = Z_PresentStatus_success;
1532 yaz_log(log_requestdetail, "Request to pack %d+%d %s", start, toget, setname);
1533 yaz_log(log_requestdetail, "pms=%d, mrs=%d", a->preferredMessageSize,
1534 a->maximumRecordSize);
1535 for (recno = start; reclist->num_records < toget; recno++)
1538 Z_NamePlusRecord *thisrec;
1539 int this_length = 0;
1541 * we get the number of bytes allocated on the stream before any
1542 * allocation done by the backend - this should give us a reasonable
1543 * idea of the total size of the data so far.
1545 total_length = odr_total(a->encode) - dumped_records;
1551 freq.last_in_set = 0;
1552 freq.setname = setname;
1553 freq.surrogate_flag = 0;
1554 freq.number = recno;
1556 freq.request_format = format;
1557 freq.request_format_raw = oid;
1558 freq.output_format = format;
1559 freq.output_format_raw = 0;
1560 freq.stream = a->encode;
1561 freq.print = a->print;
1562 freq.referenceId = referenceId;
1564 (*a->init->bend_fetch)(a->backend, &freq);
1565 /* backend should be able to signal whether error is system-wide
1566 or only pertaining to current record */
1569 if (!freq.surrogate_flag)
1572 *pres = Z_PresentStatus_failure;
1573 /* for 'present request out of range',
1574 set addinfo to record position if not set */
1575 if (freq.errcode == 13 && freq.errstring == 0)
1577 sprintf (s, "%d", recno);
1581 *errcode = freq.errcode;
1582 return diagrec(a, freq.errcode, freq.errstring);
1584 reclist->records[reclist->num_records] =
1585 surrogatediagrec(a, freq.basename, freq.errcode,
1587 reclist->num_records++;
1588 *next = freq.last_in_set ? 0 : recno + 1;
1592 this_length = freq.len;
1594 this_length = odr_total(a->encode) - total_length - dumped_records;
1595 yaz_log(YLOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1596 this_length, total_length, dumped_records);
1597 if (a->preferredMessageSize > 0 &&
1598 this_length + total_length > a->preferredMessageSize)
1600 /* record is small enough, really */
1601 if (this_length <= a->preferredMessageSize && recno > start)
1603 yaz_log(log_requestdetail, " Dropped last normal-sized record");
1604 *pres = Z_PresentStatus_partial_2;
1607 /* record can only be fetched by itself */
1608 if (this_length < a->maximumRecordSize)
1610 yaz_log(log_requestdetail, " Record > prefmsgsz");
1613 yaz_log(YLOG_DEBUG, " Dropped it");
1614 reclist->records[reclist->num_records] =
1615 surrogatediagrec(a, freq.basename, 16, 0);
1616 reclist->num_records++;
1617 *next = freq.last_in_set ? 0 : recno + 1;
1618 dumped_records += this_length;
1622 else /* too big entirely */
1624 yaz_log(log_requestdetail, "Record > maxrcdsz this=%d max=%d",
1625 this_length, a->maximumRecordSize);
1626 reclist->records[reclist->num_records] =
1627 surrogatediagrec(a, freq.basename, 17, 0);
1628 reclist->num_records++;
1629 *next = freq.last_in_set ? 0 : recno + 1;
1630 dumped_records += this_length;
1635 if (!(thisrec = (Z_NamePlusRecord *)
1636 odr_malloc(a->encode, sizeof(*thisrec))))
1638 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1639 strlen(freq.basename) + 1)))
1641 strcpy(thisrec->databaseName, freq.basename);
1642 thisrec->which = Z_NamePlusRecord_databaseRecord;
1644 if (freq.output_format_raw)
1646 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1647 freq.output_format = ident->value;
1649 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1650 freq.record, freq.len);
1651 if (!thisrec->u.databaseRecord)
1653 reclist->records[reclist->num_records] = thisrec;
1654 reclist->num_records++;
1655 *next = freq.last_in_set ? 0 : recno + 1;
1657 *num = reclist->num_records;
1661 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1664 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1665 bend_search_rr *bsrr =
1666 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1668 yaz_log(log_requestdetail, "Got SearchRequest.");
1670 bsrr->request = reqb;
1671 bsrr->association = assoc;
1672 bsrr->referenceId = req->referenceId;
1673 save_referenceId (reqb, bsrr->referenceId);
1675 yaz_log (log_requestdetail, "ResultSet '%s'", req->resultSetName);
1676 if (req->databaseNames)
1679 for (i = 0; i < req->num_databaseNames; i++)
1680 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
1683 yaz_log_zquery_level(log_requestdetail,req->query);
1685 if (assoc->init->bend_search)
1687 bsrr->setname = req->resultSetName;
1688 bsrr->replace_set = *req->replaceIndicator;
1689 bsrr->num_bases = req->num_databaseNames;
1690 bsrr->basenames = req->databaseNames;
1691 bsrr->query = req->query;
1692 bsrr->stream = assoc->encode;
1693 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1694 bsrr->decode = assoc->decode;
1695 bsrr->print = assoc->print;
1698 bsrr->errstring = NULL;
1699 bsrr->search_info = NULL;
1700 (assoc->init->bend_search)(assoc->backend, bsrr);
1701 if (!bsrr->request) /* backend not ready with the search response */
1702 return 0; /* should not be used any more */
1706 /* FIXME - make a diagnostic for it */
1707 yaz_log(YLOG_WARN,"Search not supported ?!?!");
1709 return response_searchRequest(assoc, reqb, bsrr, fd);
1712 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1715 * Prepare a searchresponse based on the backend results. We probably want
1716 * to look at making the fetching of records nonblocking as well, but
1717 * so far, we'll keep things simple.
1718 * If bsrt is null, that means we're called in response to a communications
1719 * event, and we'll have to get the response for ourselves.
1721 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1722 bend_search_rr *bsrt, int *fd)
1724 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1725 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1726 Z_SearchResponse *resp = (Z_SearchResponse *)
1727 odr_malloc (assoc->encode, sizeof(*resp));
1728 int *nulint = odr_intdup (assoc->encode, 0);
1729 bool_t *sr = odr_intdup(assoc->encode, 1);
1730 int *next = odr_intdup(assoc->encode, 0);
1731 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1734 apdu->which = Z_APDU_searchResponse;
1735 apdu->u.searchResponse = resp;
1736 resp->referenceId = req->referenceId;
1737 resp->additionalSearchInfo = 0;
1738 resp->otherInfo = 0;
1740 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1742 yaz_log(YLOG_FATAL, "Bad result from backend");
1745 else if (bsrt->errcode)
1747 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1748 resp->resultCount = nulint;
1749 resp->numberOfRecordsReturned = nulint;
1750 resp->nextResultSetPosition = nulint;
1751 resp->searchStatus = nulint;
1752 resp->resultSetStatus = none;
1753 resp->presentStatus = 0;
1757 int *toget = odr_intdup(assoc->encode, 0);
1758 int *presst = odr_intdup(assoc->encode, 0);
1759 Z_RecordComposition comp, *compp = 0;
1761 yaz_log (log_requestdetail, "resultCount: %d", bsrt->hits);
1764 resp->resultCount = &bsrt->hits;
1766 comp.which = Z_RecordComp_simple;
1767 /* how many records does the user agent want, then? */
1768 if (bsrt->hits <= *req->smallSetUpperBound)
1770 *toget = bsrt->hits;
1771 if ((comp.u.simple = req->smallSetElementSetNames))
1774 else if (bsrt->hits < *req->largeSetLowerBound)
1776 *toget = *req->mediumSetPresentNumber;
1777 if (*toget > bsrt->hits)
1778 *toget = bsrt->hits;
1779 if ((comp.u.simple = req->mediumSetElementSetNames))
1785 if (*toget && !resp->records)
1790 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1793 form = prefformat->value;
1794 resp->records = pack_records(assoc, req->resultSetName, 1,
1795 toget, compp, next, presst, form, req->referenceId,
1796 req->preferredRecordSyntax, NULL);
1799 resp->numberOfRecordsReturned = toget;
1800 returnedrecs = *toget;
1801 resp->nextResultSetPosition = next;
1802 resp->searchStatus = sr;
1803 resp->resultSetStatus = 0;
1804 resp->presentStatus = presst;
1808 if (*resp->resultCount)
1810 resp->numberOfRecordsReturned = nulint;
1811 resp->nextResultSetPosition = next;
1812 resp->searchStatus = sr;
1813 resp->resultSetStatus = 0;
1814 resp->presentStatus = 0;
1817 resp->additionalSearchInfo = bsrt->search_info;
1821 WRBUF wr=wrbuf_alloc();
1822 wrbuf_put_zquery(wr, req->query);
1824 wr_diag(wr, bsrt->errcode, bsrt->errstring);
1827 wrbuf_printf(wr," OK:%d hits ", bsrt->hits);
1829 wrbuf_printf(wr," %d records returned", returnedrecs);
1831 yaz_log(log_request, "Search %s %s", req->resultSetName,
1839 * Maybe we got a little over-friendly when we designed bend_fetch to
1840 * get only one record at a time. Some backends can optimise multiple-record
1841 * fetches, and at any rate, there is some overhead involved in
1842 * all that selecting and hopping around. Problem is, of course, that the
1843 * frontend can't know ahead of time how many records it'll need to
1844 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1845 * is downright lousy as a bulk data transfer protocol.
1847 * To start with, we'll do the fetching of records from the backend
1848 * in one operation: To save some trips in and out of the event-handler,
1849 * and to simplify the interface to pack_records. At any rate, asynch
1850 * operation is more fun in operations that have an unpredictable execution
1851 * speed - which is normally more true for search than for present.
1853 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1856 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1860 Z_PresentResponse *resp;
1864 const char *errstring = 0;
1866 yaz_log(log_requestdetail, "Got PresentRequest.");
1868 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1871 form = prefformat->value;
1872 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1874 resp->presentStatus = odr_intdup(assoc->encode, 0);
1875 if (assoc->init->bend_present)
1877 bend_present_rr *bprr = (bend_present_rr *)
1878 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1879 bprr->setname = req->resultSetId;
1880 bprr->start = *req->resultSetStartPoint;
1881 bprr->number = *req->numberOfRecordsRequested;
1882 bprr->format = form;
1883 bprr->comp = req->recordComposition;
1884 bprr->referenceId = req->referenceId;
1885 bprr->stream = assoc->encode;
1886 bprr->print = assoc->print;
1887 bprr->request = reqb;
1888 bprr->association = assoc;
1890 bprr->errstring = NULL;
1891 (*assoc->init->bend_present)(assoc->backend, bprr);
1894 return 0; /* should not happen */
1897 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1898 *resp->presentStatus = Z_PresentStatus_failure;
1899 errcode = bprr->errcode;
1900 errstring = bprr->errstring;
1903 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1904 next = odr_intdup(assoc->encode, 0);
1905 num = odr_intdup(assoc->encode, 0);
1907 apdu->which = Z_APDU_presentResponse;
1908 apdu->u.presentResponse = resp;
1909 resp->referenceId = req->referenceId;
1910 resp->otherInfo = 0;
1914 *num = *req->numberOfRecordsRequested;
1916 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1917 num, req->recordComposition, next,
1918 resp->presentStatus,
1919 form, req->referenceId, req->preferredRecordSyntax,
1924 WRBUF wr = wrbuf_alloc();
1925 wrbuf_printf(wr, "Present %s %d+%d ",
1926 req->resultSetId, *req->resultSetStartPoint,
1927 *req->numberOfRecordsRequested);
1928 if (*resp->presentStatus == Z_PresentStatus_failure)
1929 wr_diag(wr, errcode, errstring);
1930 else if (*resp->presentStatus == Z_PresentStatus_success)
1931 wrbuf_printf(wr," OK %d records returned ", *num);
1933 wrbuf_printf(wr," Partial (%d) OK %d records returned ",
1934 *resp->presentStatus, *num);
1935 yaz_log(log_request, "%s", wrbuf_buf(wr) );
1940 resp->numberOfRecordsReturned = num;
1941 resp->nextResultSetPosition = next;
1947 * Scan was implemented rather in a hurry, and with support for only the basic
1948 * elements of the service in the backend API. Suggestions are welcome.
1950 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1952 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1953 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1954 Z_ScanResponse *res = (Z_ScanResponse *)
1955 odr_malloc (assoc->encode, sizeof(*res));
1956 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1957 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1958 Z_ListEntries *ents = (Z_ListEntries *)
1959 odr_malloc (assoc->encode, sizeof(*ents));
1960 Z_DiagRecs *diagrecs_p = NULL;
1962 bend_scan_rr *bsrr = (bend_scan_rr *)
1963 odr_malloc (assoc->encode, sizeof(*bsrr));
1964 struct scan_entry *save_entries;
1966 yaz_log(log_requestdetail, "Got ScanRequest");
1968 apdu->which = Z_APDU_scanResponse;
1969 apdu->u.scanResponse = res;
1970 res->referenceId = req->referenceId;
1972 /* if step is absent, set it to 0 */
1973 res->stepSize = odr_intdup(assoc->encode, 0);
1975 *res->stepSize = *req->stepSize;
1977 res->scanStatus = scanStatus;
1978 res->numberOfEntriesReturned = numberOfEntriesReturned;
1979 res->positionOfTerm = 0;
1980 res->entries = ents;
1981 ents->num_entries = 0;
1982 ents->entries = NULL;
1983 ents->num_nonsurrogateDiagnostics = 0;
1984 ents->nonsurrogateDiagnostics = NULL;
1985 res->attributeSet = 0;
1988 if (req->databaseNames)
1991 for (i = 0; i < req->num_databaseNames; i++)
1992 yaz_log (log_requestdetail, "Database '%s'", req->databaseNames[i]);
1994 yaz_log(log_requestdetail, "pos %d step %d entries %d",
1995 *req->preferredPositionInResponse, *res->stepSize,
1996 *req->numberOfTermsRequested);
1997 bsrr->num_bases = req->num_databaseNames;
1998 bsrr->basenames = req->databaseNames;
1999 bsrr->num_entries = *req->numberOfTermsRequested;
2000 bsrr->term = req->termListAndStartPoint;
2001 bsrr->referenceId = req->referenceId;
2002 bsrr->stream = assoc->encode;
2003 bsrr->print = assoc->print;
2004 bsrr->step_size = res->stepSize;
2006 /* Note that version 2.0 of YAZ and older did not set entries ..
2007 We do now. And when we do it's easier to extend the scan entry
2008 We know that if the scan handler did set entries, it will
2009 not know of new member display_term.
2011 if (bsrr->num_entries > 0)
2014 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
2016 for (i = 0; i<bsrr->num_entries; i++)
2018 bsrr->entries[i].term = 0;
2019 bsrr->entries[i].occurrences = 0;
2020 bsrr->entries[i].errcode = 0;
2021 bsrr->entries[i].errstring = 0;
2022 bsrr->entries[i].display_term = 0;
2025 save_entries = bsrr->entries; /* save it so we can compare later */
2027 if (req->attributeSet &&
2028 (attset = oid_getentbyoid(req->attributeSet)) &&
2029 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2030 bsrr->attributeset = attset->value;
2032 bsrr->attributeset = VAL_NONE;
2033 log_scan_term_level (log_requestdetail, req->termListAndStartPoint,
2034 bsrr->attributeset);
2035 bsrr->term_position = req->preferredPositionInResponse ?
2036 *req->preferredPositionInResponse : 1;
2038 ((int (*)(void *, bend_scan_rr *))
2039 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2042 diagrecs_p = zget_DiagRecs(assoc->encode,
2043 bsrr->errcode, bsrr->errstring);
2047 Z_Entry **tab = (Z_Entry **)
2048 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2050 if (bsrr->status == BEND_SCAN_PARTIAL)
2051 *scanStatus = Z_Scan_partial_5;
2053 *scanStatus = Z_Scan_success;
2054 ents->entries = tab;
2055 ents->num_entries = bsrr->num_entries;
2056 res->numberOfEntriesReturned = &ents->num_entries;
2057 res->positionOfTerm = &bsrr->term_position;
2058 for (i = 0; i < bsrr->num_entries; i++)
2064 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2065 if (bsrr->entries[i].occurrences >= 0)
2067 e->which = Z_Entry_termInfo;
2068 e->u.termInfo = t = (Z_TermInfo *)
2069 odr_malloc(assoc->encode, sizeof(*t));
2070 t->suggestedAttributes = 0;
2072 if (save_entries == bsrr->entries &&
2073 bsrr->entries[i].display_term)
2075 /* the entries was NOT set by the handler. So it's
2076 safe to test for new member display_term. It is
2079 t->displayTerm = odr_strdup(assoc->encode,
2080 bsrr->entries[i].display_term);
2082 t->alternativeTerm = 0;
2083 t->byAttributes = 0;
2084 t->otherTermInfo = 0;
2085 t->globalOccurrences = &bsrr->entries[i].occurrences;
2086 t->term = (Z_Term *)
2087 odr_malloc(assoc->encode, sizeof(*t->term));
2088 t->term->which = Z_Term_general;
2089 t->term->u.general = o =
2090 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2091 o->buf = (unsigned char *)
2092 odr_malloc(assoc->encode, o->len = o->size =
2093 strlen(bsrr->entries[i].term));
2094 memcpy(o->buf, bsrr->entries[i].term, o->len);
2095 yaz_log(YLOG_DEBUG, " term #%d: '%s' (%d)", i,
2096 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2100 Z_DiagRecs *drecs = zget_DiagRecs(assoc->encode,
2101 bsrr->entries[i].errcode,
2102 bsrr->entries[i].errstring);
2103 assert (drecs->num_diagRecs == 1);
2104 e->which = Z_Entry_surrogateDiagnostic;
2105 assert (drecs->diagRecs[0]);
2106 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2112 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2113 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2117 WRBUF wr=wrbuf_alloc();
2118 wrbuf_printf(wr, "Scan %d@%d ",
2119 *req->preferredPositionInResponse,
2120 *req->numberOfTermsRequested);
2122 wrbuf_printf(wr, "(step %d) ",*res->stepSize);
2123 wrbuf_scan_term(wr, req->termListAndStartPoint,
2124 bsrr->attributeset);
2126 if (*res->scanStatus == Z_Scan_success)
2128 wrbuf_printf(wr," OK");
2131 wrbuf_printf(wr," Error");
2132 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2138 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2142 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2143 Z_SortResponse *res = (Z_SortResponse *)
2144 odr_malloc (assoc->encode, sizeof(*res));
2145 bend_sort_rr *bsrr = (bend_sort_rr *)
2146 odr_malloc (assoc->encode, sizeof(*bsrr));
2148 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2150 yaz_log(log_requestdetail, "Got SortRequest.");
2152 bsrr->num_input_setnames = req->num_inputResultSetNames;
2153 for (i=0;i<req->num_inputResultSetNames;i++)
2154 yaz_log(log_requestdetail, "Input resultset: '%s'",
2155 req->inputResultSetNames[i]);
2156 bsrr->input_setnames = req->inputResultSetNames;
2157 bsrr->referenceId = req->referenceId;
2158 bsrr->output_setname = req->sortedResultSetName;
2159 yaz_log(log_requestdetail, "Output resultset: '%s'",
2160 req->sortedResultSetName);
2161 bsrr->sort_sequence = req->sortSequence;
2162 /*FIXME - dump those sequences too */
2163 bsrr->stream = assoc->encode;
2164 bsrr->print = assoc->print;
2166 bsrr->sort_status = Z_SortResponse_failure;
2168 bsrr->errstring = 0;
2170 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2172 res->referenceId = bsrr->referenceId;
2173 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2174 res->resultSetStatus = 0;
2177 Z_DiagRecs *dr = zget_DiagRecs(assoc->encode,
2178 bsrr->errcode, bsrr->errstring);
2179 res->diagnostics = dr->diagRecs;
2180 res->num_diagnostics = dr->num_diagRecs;
2184 res->num_diagnostics = 0;
2185 res->diagnostics = 0;
2187 res->resultCount = 0;
2190 apdu->which = Z_APDU_sortResponse;
2191 apdu->u.sortResponse = res;
2194 WRBUF wr=wrbuf_alloc();
2195 wrbuf_printf(wr, "Sort (");
2196 for (i=0;i<req->num_inputResultSetNames;i++)
2199 wrbuf_printf(wr,",");
2200 wrbuf_printf(wr, req->inputResultSetNames[i]);
2202 wrbuf_printf(wr,")->%s ",req->sortedResultSetName);
2204 /* FIXME - dump also the sort sequence */
2206 wrbuf_diags(wr, res->num_diagnostics, res->diagnostics);
2208 wrbuf_printf(wr," OK");
2209 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2215 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2219 Z_DeleteResultSetRequest *req =
2220 reqb->apdu_request->u.deleteResultSetRequest;
2221 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2222 odr_malloc (assoc->encode, sizeof(*res));
2223 bend_delete_rr *bdrr = (bend_delete_rr *)
2224 odr_malloc (assoc->encode, sizeof(*bdrr));
2225 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2227 yaz_log(log_requestdetail, "Got DeleteRequest.");
2229 bdrr->num_setnames = req->num_resultSetList;
2230 bdrr->setnames = req->resultSetList;
2231 for (i = 0; i<req->num_resultSetList; i++)
2232 yaz_log(log_requestdetail, "resultset: '%s'",
2233 req->resultSetList[i]);
2234 bdrr->stream = assoc->encode;
2235 bdrr->print = assoc->print;
2236 bdrr->function = *req->deleteFunction;
2237 bdrr->referenceId = req->referenceId;
2239 if (bdrr->num_setnames > 0)
2241 bdrr->statuses = (int*)
2242 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2243 bdrr->num_setnames);
2244 for (i = 0; i < bdrr->num_setnames; i++)
2245 bdrr->statuses[i] = 0;
2247 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2249 res->referenceId = req->referenceId;
2251 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2253 res->deleteListStatuses = 0;
2254 if (bdrr->num_setnames > 0)
2257 res->deleteListStatuses = (Z_ListStatuses *)
2258 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2259 res->deleteListStatuses->num = bdrr->num_setnames;
2260 res->deleteListStatuses->elements =
2262 odr_malloc (assoc->encode,
2263 sizeof(*res->deleteListStatuses->elements) *
2264 bdrr->num_setnames);
2265 for (i = 0; i<bdrr->num_setnames; i++)
2267 res->deleteListStatuses->elements[i] =
2269 odr_malloc (assoc->encode,
2270 sizeof(**res->deleteListStatuses->elements));
2271 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2272 res->deleteListStatuses->elements[i]->id =
2273 odr_strdup (assoc->encode, bdrr->setnames[i]);
2276 res->numberNotDeleted = 0;
2277 res->bulkStatuses = 0;
2278 res->deleteMessage = 0;
2281 apdu->which = Z_APDU_deleteResultSetResponse;
2282 apdu->u.deleteResultSetResponse = res;
2285 WRBUF wr=wrbuf_alloc();
2286 wrbuf_printf(wr, "Delete ");
2287 for (i = 0; i<req->num_resultSetList; i++)
2288 wrbuf_printf(wr, " '%s' ", req->resultSetList[i]);
2289 if (bdrr->delete_status)
2290 wrbuf_printf(wr," ERROR %d", bdrr->delete_status);
2292 wrbuf_printf(wr,"OK");
2293 yaz_log(log_request, "%s", wrbuf_buf(wr) );
2299 static void process_close(association *assoc, request *reqb)
2301 Z_Close *req = reqb->apdu_request->u.close;
2302 static char *reasons[] =
2309 "securityViolation",
2316 yaz_log(log_requestdetail, "Got Close, reason %s, message %s",
2317 reasons[*req->closeReason], req->diagnosticInformation ?
2318 req->diagnosticInformation : "NULL");
2319 if (assoc->version < 3) /* to make do_force respond with close */
2321 do_close_req(assoc, Z_Close_finished,
2322 "Association terminated by client", reqb);
2323 yaz_log(log_request,"Close OK");
2326 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2330 reqb->len_refid = refid->len;
2331 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2332 memcpy (reqb->refid, refid->buf, refid->len);
2336 reqb->len_refid = 0;
2341 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2343 process_z_response (a, req, res);
2346 bend_request bend_request_mk (bend_association a)
2348 request *nreq = request_get (&a->outgoing);
2349 nreq->request_mem = nmem_create ();
2353 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2358 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2359 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2360 id->len = id->size = req->len_refid;
2361 memcpy (id->buf, req->refid, req->len_refid);
2365 void bend_request_destroy (bend_request *req)
2367 nmem_destroy((*req)->request_mem);
2368 request_release(*req);
2372 int bend_backend_respond (bend_association a, bend_request req)
2376 r = process_z_request (a, req, &msg);
2378 yaz_log (YLOG_WARN, "%s", msg);
2382 void bend_request_setdata(bend_request r, void *p)
2387 void *bend_request_getdata(bend_request r)
2389 return r->clientData;
2392 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2394 bend_segment_rr req;
2396 req.segment = reqb->apdu_request->u.segmentRequest;
2397 req.stream = assoc->encode;
2398 req.decode = assoc->decode;
2399 req.print = assoc->print;
2400 req.association = assoc;
2402 (*assoc->init->bend_segment)(assoc->backend, &req);
2407 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2409 bend_esrequest_rr esrequest;
2411 Z_ExtendedServicesRequest *req =
2412 reqb->apdu_request->u.extendedServicesRequest;
2413 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2415 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2417 yaz_log(log_requestdetail,"Got EsRequest");
2419 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2420 esrequest.stream = assoc->encode;
2421 esrequest.decode = assoc->decode;
2422 esrequest.print = assoc->print;
2423 esrequest.errcode = 0;
2424 esrequest.errstring = NULL;
2425 esrequest.request = reqb;
2426 esrequest.association = assoc;
2427 esrequest.taskPackage = 0;
2428 esrequest.referenceId = req->referenceId;
2430 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2432 /* If the response is being delayed, return NULL */
2433 if (esrequest.request == NULL)
2436 resp->referenceId = req->referenceId;
2438 if (esrequest.errcode == -1)
2440 /* Backend service indicates request will be processed */
2441 yaz_log(log_request,"EsRequest OK: Accepted !");
2442 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2444 else if (esrequest.errcode == 0)
2446 /* Backend service indicates request will be processed */
2447 yaz_log(log_request,"EsRequest OK: Done !");
2448 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2452 Z_DiagRecs *diagRecs =
2453 zget_DiagRecs(assoc->encode, esrequest.errcode,
2454 esrequest.errstring);
2455 /* Backend indicates error, request will not be processed */
2456 yaz_log(YLOG_DEBUG,"Request could not be processed...failure !");
2457 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2458 resp->num_diagnostics = diagRecs->num_diagRecs;
2459 resp->diagnostics = diagRecs->diagRecs;
2462 WRBUF wr=wrbuf_alloc();
2463 wrbuf_diags(wr, resp->num_diagnostics, resp->diagnostics);
2464 yaz_log(log_request, "EsRequest %s", wrbuf_buf(wr) );
2469 /* Do something with the members of bend_extendedservice */
2470 if (esrequest.taskPackage)
2471 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2472 (const char *) esrequest.taskPackage,
2474 yaz_log(YLOG_DEBUG,"Send the result apdu");