2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.31 2004-09-30 21:51:59 adam Exp $
9 * Frontend server logic.
11 * This code receives incoming APDUs, and handles client requests by means
14 * Some of the code is getting quite involved, compared to simpler servers -
15 * primarily because it is asynchronous both in the communication with
16 * the user and the backend. We think the complexity will pay off in
17 * the form of greater flexibility when more asynchronous facilities
20 * Memory management has become somewhat involved. In the simple case, where
21 * only one PDU is pending at a time, it will simply reuse the same memory,
22 * once it has found its working size. When we enable multiple concurrent
23 * operations, perhaps even with multiple parallel calls to the backend, it
24 * will maintain a pool of buffers for encoding and decoding, trying to
25 * minimize memory allocation/deallocation during normal operation.
31 #include <sys/types.h>
34 #define S_ISREG(x) (x & _S_IFREG)
44 #include <yaz/yconfig.h>
45 #include <yaz/xmalloc.h>
46 #include <yaz/comstack.h>
49 #include <yaz/proto.h>
52 #include <yaz/logrpn.h>
53 #include <yaz/statserv.h>
54 #include <yaz/diagbib1.h>
55 #include <yaz/charneg.h>
56 #include <yaz/otherinfo.h>
57 #include <yaz/yaz-util.h>
58 #include <yaz/pquery.h>
61 #include <yaz/backend.h>
63 static void process_gdu_request(association *assoc, request *req);
64 static int process_z_request(association *assoc, request *req, char **msg);
65 void backend_response(IOCHAN i, int event);
66 static int process_gdu_response(association *assoc, request *req, Z_GDU *res);
67 static int process_z_response(association *assoc, request *req, Z_APDU *res);
68 static Z_APDU *process_initRequest(association *assoc, request *reqb);
69 static Z_External *init_diagnostics(ODR odr, int errcode, char *errstring);
70 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
72 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
73 bend_search_rr *bsrr, int *fd);
74 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
76 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
77 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
78 static void process_close(association *assoc, request *reqb);
79 void save_referenceId (request *reqb, Z_ReferenceId *refid);
80 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
82 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
84 static FILE *apduf = 0; /* for use in static mode */
85 static statserv_options_block *control_block = 0;
87 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
90 * Create and initialize a new association-handle.
91 * channel : iochannel for the current line.
92 * link : communications channel.
93 * Returns: 0 or a new association handle.
95 association *create_association(IOCHAN channel, COMSTACK link)
100 control_block = statserv_getcontrol();
101 if (!(anew = (association *)xmalloc(sizeof(*anew))))
105 anew->client_chan = channel;
106 anew->client_link = link;
107 anew->cs_get_mask = 0;
108 anew->cs_put_mask = 0;
109 anew->cs_accept_mask = 0;
110 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
111 !(anew->encode = odr_createmem(ODR_ENCODE)))
113 if (*control_block->apdufile)
118 strcpy(filename, control_block->apdufile);
119 if (!(anew->print = odr_createmem(ODR_PRINT)))
121 if (*control_block->apdufile == '@')
123 odr_setprint(anew->print, yaz_log_file());
125 else if (*control_block->apdufile != '-')
127 strcpy(filename, control_block->apdufile);
128 if (!control_block->dynamic)
132 if (!(apduf = fopen(filename, "w")))
134 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
137 setvbuf(apduf, 0, _IONBF, 0);
143 sprintf(filename + strlen(filename), ".%d", getpid());
144 if (!(f = fopen(filename, "w")))
146 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
149 setvbuf(f, 0, _IONBF, 0);
151 odr_setprint(anew->print, f);
156 anew->input_buffer = 0;
157 anew->input_buffer_len = 0;
159 anew->state = ASSOC_NEW;
160 request_initq(&anew->incoming);
161 request_initq(&anew->outgoing);
162 anew->proto = cs_getproto(link);
167 * Free association and release resources.
169 void destroy_association(association *h)
171 statserv_options_block *cb = statserv_getcontrol();
175 odr_destroy(h->decode);
176 odr_destroy(h->encode);
178 odr_destroy(h->print);
180 xfree(h->input_buffer);
182 (*cb->bend_close)(h->backend);
183 while ((req = request_deq(&h->incoming)))
184 request_release(req);
185 while ((req = request_deq(&h->outgoing)))
186 request_release(req);
187 request_delq(&h->incoming);
188 request_delq(&h->outgoing);
190 xmalloc_trav("session closed");
191 if (control_block && control_block->one_shot)
197 static void do_close_req(association *a, int reason, char *message,
201 Z_Close *cls = zget_Close(a->encode);
203 /* Purge request queue */
204 while (request_deq(&a->incoming));
205 while (request_deq(&a->outgoing));
208 yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
209 reason, message ? message : "none");
210 apdu.which = Z_APDU_close;
212 *cls->closeReason = reason;
213 cls->diagnosticInformation = message;
214 process_z_response(a, req, &apdu);
215 iochan_settimeout(a->client_chan, 20);
219 request_release(req);
220 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
221 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
223 a->state = ASSOC_DEAD;
226 static void do_close(association *a, int reason, char *message)
228 request *req = request_get(&a->outgoing);
229 do_close_req (a, reason, message, req);
233 * This is where PDUs from the client are read and the further
234 * processing is initiated. Flow of control moves down through the
235 * various process_* functions below, until the encoded result comes back up
236 * to the output handler in here.
238 * h : the I/O channel that has an outstanding event.
239 * event : the current outstanding event.
241 void ir_session(IOCHAN h, int event)
244 association *assoc = (association *)iochan_getdata(h);
245 COMSTACK conn = assoc->client_link;
248 assert(h && conn && assoc);
249 if (event == EVENT_TIMEOUT)
251 if (assoc->state != ASSOC_UP)
253 yaz_log(LOG_LOG, "Final timeout - closing connection.");
255 destroy_association(assoc);
260 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
261 do_close(assoc, Z_Close_lackOfActivity, 0);
265 if (event & assoc->cs_accept_mask)
267 yaz_log (LOG_DEBUG, "ir_session (accept)");
268 if (!cs_accept (conn))
270 yaz_log (LOG_LOG, "accept failed");
271 destroy_association(assoc);
274 iochan_clearflag (h, EVENT_OUTPUT);
275 if (conn->io_pending)
276 { /* cs_accept didn't complete */
277 assoc->cs_accept_mask =
278 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
279 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
281 iochan_setflag (h, assoc->cs_accept_mask);
284 { /* cs_accept completed. Prepare for reading (cs_get) */
285 assoc->cs_accept_mask = 0;
286 assoc->cs_get_mask = EVENT_INPUT;
287 iochan_setflag (h, assoc->cs_get_mask);
291 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
293 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
295 yaz_log(LOG_DEBUG, "ir_session (input)");
296 /* We aren't speaking to this fellow */
297 if (assoc->state == ASSOC_DEAD)
299 yaz_log(LOG_LOG, "Connection closed - end of session");
301 destroy_association(assoc);
305 assoc->cs_get_mask = EVENT_INPUT;
306 if ((res = cs_get(conn, &assoc->input_buffer,
307 &assoc->input_buffer_len)) <= 0)
309 yaz_log(LOG_LOG, "Connection closed by client");
311 destroy_association(assoc);
315 else if (res == 1) /* incomplete read - wait for more */
317 if (conn->io_pending & CS_WANT_WRITE)
318 assoc->cs_get_mask |= EVENT_OUTPUT;
319 iochan_setflag(h, assoc->cs_get_mask);
322 if (cs_more(conn)) /* more stuff - call us again later, please */
323 iochan_setevent(h, EVENT_INPUT);
325 /* we got a complete PDU. Let's decode it */
326 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
327 assoc->input_buffer[0] & 0xff,
328 assoc->input_buffer[1] & 0xff,
329 assoc->input_buffer[2] & 0xff);
330 req = request_get(&assoc->incoming); /* get a new request */
331 odr_reset(assoc->decode);
332 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
333 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
335 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
337 odr_errmsg(odr_geterror(assoc->decode)),
338 odr_getelement(assoc->decode),
339 odr_offset(assoc->decode));
340 if (assoc->decode->error != OHTTP)
342 yaz_log(LOG_LOG, "PDU dump:");
343 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
344 request_release(req);
345 do_close(assoc, Z_Close_protocolError,"Malformed package");
349 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
350 assoc->state = ASSOC_DEAD;
351 process_gdu_response(assoc, req, p);
355 req->request_mem = odr_extract_mem(assoc->decode);
358 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
359 yaz_log(LOG_WARN, "ODR print error: %s",
360 odr_errmsg(odr_geterror(assoc->print)));
361 odr_reset(assoc->print);
363 request_enq(&assoc->incoming, req);
366 /* can we do something yet? */
367 req = request_head(&assoc->incoming);
368 if (req->state == REQUEST_IDLE)
370 request_deq(&assoc->incoming);
371 process_gdu_request(assoc, req);
374 if (event & assoc->cs_put_mask)
376 request *req = request_head(&assoc->outgoing);
378 assoc->cs_put_mask = 0;
379 yaz_log(LOG_DEBUG, "ir_session (output)");
380 req->state = REQUEST_PENDING;
381 switch (res = cs_put(conn, req->response, req->len_response))
384 yaz_log(LOG_LOG, "Connection closed by client");
386 destroy_association(assoc);
389 case 0: /* all sent - release the request structure */
390 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
392 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
395 nmem_destroy(req->request_mem);
396 request_deq(&assoc->outgoing);
397 request_release(req);
398 if (!request_head(&assoc->outgoing))
399 { /* restore mask for cs_get operation ... */
400 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
401 iochan_setflag(h, assoc->cs_get_mask);
402 if (assoc->state == ASSOC_DEAD)
403 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
407 assoc->cs_put_mask = EVENT_OUTPUT;
411 if (conn->io_pending & CS_WANT_WRITE)
412 assoc->cs_put_mask |= EVENT_OUTPUT;
413 if (conn->io_pending & CS_WANT_READ)
414 assoc->cs_put_mask |= EVENT_INPUT;
415 iochan_setflag(h, assoc->cs_put_mask);
418 if (event & EVENT_EXCEPT)
420 yaz_log(LOG_LOG, "ir_session (exception)");
422 destroy_association(assoc);
427 static int process_z_request(association *assoc, request *req, char **msg);
429 static void assoc_init_reset(association *assoc)
432 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
434 assoc->init->stream = assoc->encode;
435 assoc->init->print = assoc->print;
436 assoc->init->auth = 0;
437 assoc->init->referenceId = 0;
438 assoc->init->implementation_version = 0;
439 assoc->init->implementation_id = 0;
440 assoc->init->implementation_name = 0;
441 assoc->init->bend_sort = NULL;
442 assoc->init->bend_search = NULL;
443 assoc->init->bend_present = NULL;
444 assoc->init->bend_esrequest = NULL;
445 assoc->init->bend_delete = NULL;
446 assoc->init->bend_scan = NULL;
447 assoc->init->bend_segment = NULL;
448 assoc->init->bend_fetch = NULL;
449 assoc->init->bend_explain = NULL;
451 assoc->init->charneg_request = NULL;
452 assoc->init->charneg_response = NULL;
454 assoc->init->decode = assoc->decode;
455 assoc->init->peer_name =
456 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
459 static int srw_bend_init(association *assoc)
461 const char *encoding = "UTF-8";
463 bend_initresult *binitres;
464 statserv_options_block *cb = statserv_getcontrol();
466 assoc_init_reset(assoc);
468 assoc->maximumRecordSize = 3000000;
469 assoc->preferredMessageSize = 3000000;
471 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
472 assoc->init->charneg_request = ce->u.charNeg3;
475 if (!(binitres = (*cb->bend_init)(assoc->init)))
477 yaz_log(LOG_WARN, "Bad response from backend.");
480 assoc->backend = binitres->handle;
484 static int srw_bend_fetch(association *assoc, int pos,
485 Z_SRW_searchRetrieveRequest *srw_req,
486 Z_SRW_record *record)
489 ODR o = assoc->encode;
491 rr.setname = "default";
494 rr.request_format = VAL_TEXT_XML;
495 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
498 rr.comp = (Z_RecordComposition *)
499 odr_malloc(assoc->decode, sizeof(*rr.comp));
500 rr.comp->which = Z_RecordComp_complex;
501 rr.comp->u.complex = (Z_CompSpec *)
502 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
503 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
504 odr_malloc(assoc->encode, sizeof(bool_t));
505 *rr.comp->u.complex->selectAlternativeSyntax = 0;
506 rr.comp->u.complex->num_dbSpecific = 0;
507 rr.comp->u.complex->dbSpecific = 0;
508 rr.comp->u.complex->num_recordSyntax = 0;
509 rr.comp->u.complex->recordSyntax = 0;
511 rr.comp->u.complex->generic = (Z_Specification *)
512 odr_malloc(assoc->decode, sizeof(Z_Specification));
514 /* schema uri = recordSchema (or NULL if recordSchema is not given) */
515 rr.comp->u.complex->generic->which = Z_Schema_uri;
516 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
518 /* ESN = recordSchema if recordSchema is present */
519 rr.comp->u.complex->generic->elementSpec = 0;
520 if (srw_req->recordSchema)
522 rr.comp->u.complex->generic->elementSpec =
523 (Z_ElementSpec *) odr_malloc(assoc->encode, sizeof(Z_ElementSpec));
524 rr.comp->u.complex->generic->elementSpec->which =
525 Z_ElementSpec_elementSetName;
526 rr.comp->u.complex->generic->elementSpec->u.elementSetName =
527 srw_req->recordSchema;
530 rr.stream = assoc->encode;
531 rr.print = assoc->print;
537 rr.output_format = VAL_TEXT_XML;
538 rr.output_format_raw = 0;
541 rr.surrogate_flag = 0;
542 rr.schema = srw_req->recordSchema;
544 if (!assoc->init->bend_fetch)
547 (*assoc->init->bend_fetch)(assoc->backend, &rr);
549 if (rr.errcode && rr.surrogate_flag)
551 int code = yaz_diag_bib1_to_srw(rr.errcode);
552 const char *message = yaz_diag_srw_str(code);
555 len += strlen(message);
557 len += strlen(rr.errstring);
559 record->recordData_buf = odr_malloc(o, len);
561 sprintf(record->recordData_buf, "<diagnostic>\n"
562 " <uri>info:srw/diagnostic/1/%d</uri>\n", code);
564 sprintf(record->recordData_buf + strlen(record->recordData_buf),
565 " <details>%s</details>\n", rr.errstring);
567 sprintf(record->recordData_buf + strlen(record->recordData_buf),
568 " <message>%s</message>\n", message);
569 sprintf(record->recordData_buf + strlen(record->recordData_buf),
571 record->recordData_len = strlen(record->recordData_buf);
572 record->recordPosition = odr_intdup(o, pos);
573 record->recordSchema = "info:srw/schema/1/diagnostics-v1.1";
576 else if (rr.len >= 0)
578 record->recordData_buf = rr.record;
579 record->recordData_len = rr.len;
580 record->recordPosition = odr_intdup(o, pos);
582 record->recordSchema = odr_strdup(o, rr.schema);
584 record->recordSchema = 0;
589 static void srw_bend_search(association *assoc, request *req,
590 Z_SRW_searchRetrieveRequest *srw_req,
591 Z_SRW_searchRetrieveResponse *srw_res,
599 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
600 yaz_log(LOG_DEBUG, "srw_bend_search");
603 yaz_log(LOG_DEBUG, "srw_bend_init");
604 if (!srw_bend_init(assoc))
606 srw_error = 3; /* assume Authentication error */
608 yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
609 &srw_res->num_diagnostics, 1, 0);
614 rr.setname = "default";
617 rr.basenames = &srw_req->database;
620 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
622 if (srw_req->query_type == Z_SRW_query_type_cql)
624 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
625 ext->direct_reference = odr_getoidbystr(assoc->decode,
626 "1.2.840.10003.16.2");
627 ext->indirect_reference = 0;
629 ext->which = Z_External_CQL;
630 ext->u.cql = srw_req->query.cql;
632 rr.query->which = Z_Query_type_104;
633 rr.query->u.type_104 = ext;
635 else if (srw_req->query_type == Z_SRW_query_type_pqf)
637 Z_RPNQuery *RPNquery;
638 YAZ_PQF_Parser pqf_parser;
640 pqf_parser = yaz_pqf_create ();
642 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
648 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
650 yaz_log(LOG_LOG, "%*s^\n", (int)off+4, "");
651 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
656 rr.query->which = Z_Query_type_1;
657 rr.query->u.type_1 = RPNquery;
659 yaz_pqf_destroy (pqf_parser);
664 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
667 if (!srw_error && !assoc->init->bend_search)
672 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
673 srw_res->num_diagnostics = 1;
674 srw_res->diagnostics = (Z_SRW_diagnostic *)
675 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
676 yaz_mk_std_diagnostic(assoc->encode,
677 srw_res->diagnostics, srw_error, 0);
681 rr.stream = assoc->encode;
682 rr.decode = assoc->decode;
683 rr.print = assoc->print;
685 rr.association = assoc;
691 yaz_log_zquery(rr.query);
692 (assoc->init->bend_search)(assoc->backend, &rr);
695 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
696 if (rr.errcode == 109) /* database unavailable */
701 srw_res->num_diagnostics = 1;
702 srw_res->diagnostics = (Z_SRW_diagnostic *)
703 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
704 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
705 yaz_diag_bib1_to_srw (rr.errcode),
707 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %s",
708 srw_res->diagnostics[0].uri);
712 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
713 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
715 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
716 start, number, rr.hits);
718 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
725 srw_res->num_diagnostics = 1;
726 srw_res->diagnostics = (Z_SRW_diagnostic *)
727 odr_malloc(assoc->encode,
728 sizeof(*srw_res->diagnostics));
729 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
735 int packing = Z_SRW_recordPacking_string;
736 if (start + number > rr.hits)
737 number = rr.hits - start + 1;
738 if (srw_req->recordPacking &&
739 !strcmp(srw_req->recordPacking, "xml"))
740 packing = Z_SRW_recordPacking_XML;
741 srw_res->records = (Z_SRW_record *)
742 odr_malloc(assoc->encode,
743 number * sizeof(*srw_res->records));
744 for (i = 0; i<number; i++)
748 srw_res->records[j].recordPacking = packing;
749 srw_res->records[j].recordData_buf = 0;
750 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
751 errcode = srw_bend_fetch(assoc, i+start, srw_req,
752 srw_res->records + j);
755 srw_res->num_diagnostics = 1;
756 srw_res->diagnostics = (Z_SRW_diagnostic *)
757 odr_malloc(assoc->encode,
758 sizeof(*srw_res->diagnostics));
760 yaz_mk_std_diagnostic(assoc->encode,
761 srw_res->diagnostics,
762 yaz_diag_bib1_to_srw (errcode),
766 if (srw_res->records[j].recordData_buf)
769 srw_res->num_records = j;
771 srw_res->records = 0;
777 static void srw_bend_explain(association *assoc, request *req,
778 Z_SRW_explainRequest *srw_req,
779 Z_SRW_explainResponse *srw_res,
782 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
786 yaz_log(LOG_DEBUG, "srw_bend_init");
787 if (!srw_bend_init(assoc))
792 if (assoc->init && assoc->init->bend_explain)
796 rr.stream = assoc->encode;
797 rr.decode = assoc->decode;
798 rr.print = assoc->print;
800 rr.database = srw_req->database;
801 rr.schema = "http://explain.z3950.org/dtd/2.0/";
802 (*assoc->init->bend_explain)(assoc->backend, &rr);
805 int packing = Z_SRW_recordPacking_string;
806 if (srw_req->recordPacking &&
807 !strcmp(srw_req->recordPacking, "xml"))
808 packing = Z_SRW_recordPacking_XML;
809 srw_res->record.recordSchema = rr.schema;
810 srw_res->record.recordPacking = packing;
811 srw_res->record.recordData_buf = rr.explain_buf;
812 srw_res->record.recordData_len = strlen(rr.explain_buf);
813 srw_res->record.recordPosition = 0;
819 static void process_http_request(association *assoc, request *req)
821 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
822 ODR o = assoc->encode;
823 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
825 Z_SOAP *soap_package = 0;
828 Z_HTTP_Response *hres = 0;
830 char *stylesheet = 0;
831 Z_SRW_diagnostic *diagnostic = 0;
832 int num_diagnostic = 0;
834 if (!strcmp(hreq->path, "/test"))
836 p = z_get_HTTP_Response(o, 200);
837 hres = p->u.HTTP_Response;
838 hres->content_buf = "1234567890\n";
839 hres->content_len = strlen(hres->content_buf);
844 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
845 yaz_log(LOG_DEBUG, "yaz_srw_decode returned %d", r);
847 if (r == 2) /* not taken */
849 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
850 &diagnostic, &num_diagnostic);
851 yaz_log(LOG_DEBUG, "yaz_sru_decode returned %d", r);
853 if (r == 0) /* decode SRW/SRU OK .. */
856 if (sr->which == Z_SRW_searchRetrieve_request)
859 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
861 stylesheet = sr->u.request->stylesheet;
864 res->u.response->diagnostics = diagnostic;
865 res->u.response->num_diagnostics = num_diagnostic;
869 srw_bend_search(assoc, req, sr->u.request, res->u.response,
872 if (http_code == 200)
873 soap_package->u.generic->p = res;
875 else if (sr->which == Z_SRW_explain_request)
877 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
878 stylesheet = sr->u.explain_request->stylesheet;
881 res->u.explain_response->diagnostics = diagnostic;
882 res->u.explain_response->num_diagnostics = num_diagnostic;
884 srw_bend_explain(assoc, req, sr->u.explain_request,
885 res->u.explain_response, &http_code);
886 if (http_code == 200)
887 soap_package->u.generic->p = res;
889 else if (sr->which == Z_SRW_scan_request)
891 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
892 stylesheet = sr->u.scan_request->stylesheet;
895 res->u.scan_response->diagnostics = diagnostic;
896 res->u.scan_response->num_diagnostics = num_diagnostic;
898 yaz_add_srw_diagnostic(o,
899 &res->u.scan_response->diagnostics,
900 &res->u.scan_response->num_diagnostics,
902 if (http_code == 200)
903 soap_package->u.generic->p = res;
907 yaz_log(LOG_LOG, "generate soap error");
909 z_soap_error(assoc->encode, soap_package,
910 "SOAP-ENV:Client", "Bad method", 0);
912 if (http_code == 200 || http_code == 500)
914 static Z_SOAP_Handler soap_handlers[3] = {
916 {"http://www.loc.gov/zing/srw/", 0,
917 (Z_SOAP_fun) yaz_srw_codec},
918 {"http://www.loc.gov/zing/srw/v1.0/", 0,
919 (Z_SOAP_fun) yaz_srw_codec},
925 p = z_get_HTTP_Response(o, 200);
926 hres = p->u.HTTP_Response;
927 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
928 &hres->content_buf, &hres->content_len,
929 soap_handlers, charset, stylesheet);
930 hres->code = http_code;
932 strcpy(ctype, "text/xml");
935 strcat(ctype, "; charset=");
936 strcat(ctype, charset);
938 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
941 p = z_get_HTTP_Response(o, http_code);
945 p = z_get_HTTP_Response(o, 500);
946 hres = p->u.HTTP_Response;
947 if (!strcmp(hreq->version, "1.0"))
949 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
950 if (v && !strcmp(v, "Keep-Alive"))
954 hres->version = "1.0";
958 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
959 if (v && !strcmp(v, "close"))
963 hres->version = "1.1";
967 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
968 assoc->state = ASSOC_DEAD;
969 assoc->cs_get_mask = 0;
974 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
976 if (alive && isdigit(*alive))
980 if (t < 0 || t > 3600)
982 iochan_settimeout(assoc->client_chan,t);
983 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
985 process_gdu_response(assoc, req, p);
988 static void process_gdu_request(association *assoc, request *req)
990 if (req->gdu_request->which == Z_GDU_Z3950)
993 req->apdu_request = req->gdu_request->u.z3950;
994 if (process_z_request(assoc, req, &msg) < 0)
995 do_close_req(assoc, Z_Close_systemProblem, msg, req);
997 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
998 process_http_request(assoc, req);
1001 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1006 * Initiate request processing.
1008 static int process_z_request(association *assoc, request *req, char **msg)
1014 *msg = "Unknown Error";
1015 assert(req && req->state == REQUEST_IDLE);
1016 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1018 *msg = "Missing InitRequest";
1021 switch (req->apdu_request->which)
1023 case Z_APDU_initRequest:
1024 iochan_settimeout(assoc->client_chan,
1025 statserv_getcontrol()->idle_timeout * 60);
1026 res = process_initRequest(assoc, req); break;
1027 case Z_APDU_searchRequest:
1028 res = process_searchRequest(assoc, req, &fd); break;
1029 case Z_APDU_presentRequest:
1030 res = process_presentRequest(assoc, req, &fd); break;
1031 case Z_APDU_scanRequest:
1032 if (assoc->init->bend_scan)
1033 res = process_scanRequest(assoc, req, &fd);
1036 *msg = "Cannot handle Scan APDU";
1040 case Z_APDU_extendedServicesRequest:
1041 if (assoc->init->bend_esrequest)
1042 res = process_ESRequest(assoc, req, &fd);
1045 *msg = "Cannot handle Extended Services APDU";
1049 case Z_APDU_sortRequest:
1050 if (assoc->init->bend_sort)
1051 res = process_sortRequest(assoc, req, &fd);
1054 *msg = "Cannot handle Sort APDU";
1059 process_close(assoc, req);
1061 case Z_APDU_deleteResultSetRequest:
1062 if (assoc->init->bend_delete)
1063 res = process_deleteRequest(assoc, req, &fd);
1066 *msg = "Cannot handle Delete APDU";
1070 case Z_APDU_segmentRequest:
1071 if (assoc->init->bend_segment)
1073 res = process_segmentRequest (assoc, req);
1077 *msg = "Cannot handle Segment APDU";
1081 case Z_APDU_triggerResourceControlRequest:
1084 *msg = "Bad APDU received";
1089 yaz_log(LOG_DEBUG, " result immediately available");
1090 retval = process_z_response(assoc, req, res);
1094 yaz_log(LOG_DEBUG, " result unavailble");
1097 else /* no result yet - one will be provided later */
1101 /* Set up an I/O handler for the fd supplied by the backend */
1103 yaz_log(LOG_DEBUG, " establishing handler for result");
1104 req->state = REQUEST_PENDING;
1105 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1107 iochan_setdata(chan, assoc);
1114 * Handle message from the backend.
1116 void backend_response(IOCHAN i, int event)
1118 association *assoc = (association *)iochan_getdata(i);
1119 request *req = request_head(&assoc->incoming);
1123 yaz_log(LOG_DEBUG, "backend_response");
1124 assert(assoc && req && req->state != REQUEST_IDLE);
1125 /* determine what it is we're waiting for */
1126 switch (req->apdu_request->which)
1128 case Z_APDU_searchRequest:
1129 res = response_searchRequest(assoc, req, 0, &fd); break;
1131 case Z_APDU_presentRequest:
1132 res = response_presentRequest(assoc, req, 0, &fd); break;
1133 case Z_APDU_scanRequest:
1134 res = response_scanRequest(assoc, req, 0, &fd); break;
1137 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1140 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1142 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1143 do_close(assoc, Z_Close_systemProblem, 0);
1147 else if (!res) /* no result yet - try again later */
1149 yaz_log(LOG_DEBUG, " no result yet");
1150 iochan_setfd(i, fd); /* in case fd has changed */
1155 * Encode response, and transfer the request structure to the outgoing queue.
1157 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1159 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1163 if (!z_GDU(assoc->print, &res, 0, 0))
1164 yaz_log(LOG_WARN, "ODR print error: %s",
1165 odr_errmsg(odr_geterror(assoc->print)));
1166 odr_reset(assoc->print);
1168 if (!z_GDU(assoc->encode, &res, 0, 0))
1170 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1171 odr_errmsg(odr_geterror(assoc->decode)),
1172 odr_getelement(assoc->decode));
1173 request_release(req);
1176 req->response = odr_getbuf(assoc->encode, &req->len_response,
1177 &req->size_response);
1178 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1179 odr_reset(assoc->encode);
1180 req->state = REQUEST_IDLE;
1181 request_enq(&assoc->outgoing, req);
1182 /* turn the work over to the ir_session handler */
1183 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1184 assoc->cs_put_mask = EVENT_OUTPUT;
1185 /* Is there more work to be done? give that to the input handler too */
1187 if (request_head(&assoc->incoming))
1189 yaz_log (LOG_DEBUG, "more work to be done");
1190 iochan_setevent(assoc->client_chan, EVENT_WORK);
1197 * Encode response, and transfer the request structure to the outgoing queue.
1199 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1201 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1202 gres->which = Z_GDU_Z3950;
1203 gres->u.z3950 = res;
1205 return process_gdu_response(assoc, req, gres);
1210 * Handle init request.
1211 * At the moment, we don't check the options
1212 * anywhere else in the code - we just try not to do anything that would
1213 * break a naive client. We'll toss 'em into the association block when
1214 * we need them there.
1216 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1218 statserv_options_block *cb = statserv_getcontrol();
1219 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1220 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1221 Z_InitResponse *resp = apdu->u.initResponse;
1222 bend_initresult *binitres;
1226 yaz_log(LOG_LOG, "Got initRequest");
1227 if (req->implementationId)
1228 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1229 if (req->implementationName)
1230 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1231 if (req->implementationVersion)
1232 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1234 assoc_init_reset(assoc);
1236 assoc->init->auth = req->idAuthentication;
1237 assoc->init->referenceId = req->referenceId;
1239 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1241 Z_CharSetandLanguageNegotiation *negotiation =
1242 yaz_get_charneg_record (req->otherInfo);
1244 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1245 assoc->init->charneg_request = negotiation;
1249 if (!(binitres = (*cb->bend_init)(assoc->init)))
1251 yaz_log(LOG_WARN, "Bad response from backend.");
1255 assoc->backend = binitres->handle;
1256 if ((assoc->init->bend_sort))
1257 yaz_log (LOG_DEBUG, "Sort handler installed");
1258 if ((assoc->init->bend_search))
1259 yaz_log (LOG_DEBUG, "Search handler installed");
1260 if ((assoc->init->bend_present))
1261 yaz_log (LOG_DEBUG, "Present handler installed");
1262 if ((assoc->init->bend_esrequest))
1263 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1264 if ((assoc->init->bend_delete))
1265 yaz_log (LOG_DEBUG, "Delete handler installed");
1266 if ((assoc->init->bend_scan))
1267 yaz_log (LOG_DEBUG, "Scan handler installed");
1268 if ((assoc->init->bend_segment))
1269 yaz_log (LOG_DEBUG, "Segment handler installed");
1271 resp->referenceId = req->referenceId;
1273 /* let's tell the client what we can do */
1274 if (ODR_MASK_GET(req->options, Z_Options_search))
1276 ODR_MASK_SET(resp->options, Z_Options_search);
1277 strcat(options, "srch");
1279 if (ODR_MASK_GET(req->options, Z_Options_present))
1281 ODR_MASK_SET(resp->options, Z_Options_present);
1282 strcat(options, " prst");
1284 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1285 assoc->init->bend_delete)
1287 ODR_MASK_SET(resp->options, Z_Options_delSet);
1288 strcat(options, " del");
1290 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1291 assoc->init->bend_esrequest)
1293 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1294 strcat (options, " extendedServices");
1296 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1298 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1299 strcat(options, " namedresults");
1301 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1303 ODR_MASK_SET(resp->options, Z_Options_scan);
1304 strcat(options, " scan");
1306 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1308 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1309 strcat(options, " concurrop");
1311 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1313 ODR_MASK_SET(resp->options, Z_Options_sort);
1314 strcat(options, " sort");
1317 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1318 && assoc->init->charneg_response)
1320 Z_OtherInformation **p;
1321 Z_OtherInformationUnit *p0;
1323 yaz_oi_APDU(apdu, &p);
1325 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1326 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1328 p0->which = Z_OtherInfo_externallyDefinedInfo;
1329 p0->information.externallyDefinedInfo =
1330 assoc->init->charneg_response;
1332 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1333 strcat(options, " negotiation");
1336 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1338 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1340 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1341 assoc->version = 1; /* 1 & 2 are equivalent */
1343 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1345 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1348 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1350 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1354 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1355 assoc->maximumRecordSize = *req->maximumRecordSize;
1356 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1357 assoc->maximumRecordSize = control_block->maxrecordsize;
1358 assoc->preferredMessageSize = *req->preferredMessageSize;
1359 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1360 assoc->preferredMessageSize = assoc->maximumRecordSize;
1362 resp->preferredMessageSize = &assoc->preferredMessageSize;
1363 resp->maximumRecordSize = &assoc->maximumRecordSize;
1365 resp->implementationId = odr_prepend(assoc->encode,
1366 assoc->init->implementation_id,
1367 resp->implementationId);
1369 resp->implementationName = odr_prepend(assoc->encode,
1370 assoc->init->implementation_name,
1371 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1373 version = odr_strdup(assoc->encode, "$Revision: 1.31 $");
1374 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1375 version[strlen(version)-2] = '\0';
1376 resp->implementationVersion = odr_prepend(assoc->encode,
1377 assoc->init->implementation_version,
1378 odr_prepend(assoc->encode, &version[11],
1379 resp->implementationVersion));
1381 if (binitres->errcode)
1383 yaz_log(LOG_LOG, "Connection rejected by backend.");
1385 assoc->state = ASSOC_DEAD;
1386 resp->userInformationField = init_diagnostics(assoc->encode,
1388 binitres->errstring);
1391 assoc->state = ASSOC_UP;
1396 * Diagnostic in default format, to be returned as either a surrogate
1397 * or non-surrogate diagnostic in the context of an open session, or
1398 * as User-information when an Init is refused.
1400 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1402 int *err = odr_intdup(odr, error);
1403 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1404 odr_malloc (odr, sizeof(*dr));
1406 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1407 addinfo ? " -- " : "", addinfo ? addinfo : "");
1409 dr->diagnosticSetId =
1410 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1411 dr->condition = err;
1412 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1413 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1418 * Set the specified `errcode' and `errstring' into a UserInfo-1
1419 * external to be returned to the client in accordance with Z35.90
1420 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1421 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1423 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1427 Z_OtherInformation *u;
1428 Z_OtherInformationUnit *l;
1429 Z_DiagnosticFormat *d;
1430 Z_DiagnosticFormat_s *e;
1432 x = (Z_External*) odr_malloc(odr, sizeof *x);
1434 x->indirect_reference = 0;
1435 oid.proto = PROTO_Z3950;
1436 oid.oclass = CLASS_USERINFO;
1437 oid.value = VAL_USERINFO1;
1438 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1439 x->which = Z_External_userInfo1;
1441 u = odr_malloc(odr, sizeof *u);
1443 u->num_elements = 1;
1444 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1445 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1448 l->which = Z_OtherInfo_externallyDefinedInfo;
1450 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1451 l->information.externallyDefinedInfo = x2;
1453 x2->indirect_reference = 0;
1454 oid.oclass = CLASS_DIAGSET;
1455 oid.value = VAL_DIAG1;
1456 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1457 x2->which = Z_External_diag1;
1459 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1462 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1463 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1466 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1467 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1473 * nonsurrogate diagnostic record.
1475 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1477 Z_Records *rec = (Z_Records *)
1478 odr_malloc (assoc->encode, sizeof(*rec));
1479 rec->which = Z_Records_NSD;
1480 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1485 * surrogate diagnostic.
1487 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1488 int error, char *addinfo)
1490 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1491 odr_malloc (assoc->encode, sizeof(*rec));
1492 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1494 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1495 rec->databaseName = dbname;
1496 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1497 rec->u.surrogateDiagnostic = drec;
1498 drec->which = Z_DiagRec_defaultFormat;
1499 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1505 * multiple nonsurrogate diagnostics.
1507 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1509 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1510 int *err = odr_intdup(assoc->encode, error);
1511 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1512 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1513 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1514 odr_malloc (assoc->encode, sizeof(*rec));
1516 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1518 recs->num_diagRecs = 1;
1519 recs->diagRecs = recp;
1521 drec->which = Z_DiagRec_defaultFormat;
1522 drec->u.defaultFormat = rec;
1524 rec->diagnosticSetId =
1525 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1526 rec->condition = err;
1528 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1529 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1533 static Z_Records *pack_records(association *a, char *setname, int start,
1534 int *num, Z_RecordComposition *comp,
1535 int *next, int *pres, oid_value format,
1536 Z_ReferenceId *referenceId,
1539 int recno, total_length = 0, toget = *num, dumped_records = 0;
1540 Z_Records *records =
1541 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1542 Z_NamePlusRecordList *reclist =
1543 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1544 Z_NamePlusRecord **list =
1545 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1547 records->which = Z_Records_DBOSD;
1548 records->u.databaseOrSurDiagnostics = reclist;
1549 reclist->num_records = 0;
1550 reclist->records = list;
1551 *pres = Z_PresentStatus_success;
1555 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1556 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1557 a->maximumRecordSize);
1558 for (recno = start; reclist->num_records < toget; recno++)
1561 Z_NamePlusRecord *thisrec;
1562 int this_length = 0;
1564 * we get the number of bytes allocated on the stream before any
1565 * allocation done by the backend - this should give us a reasonable
1566 * idea of the total size of the data so far.
1568 total_length = odr_total(a->encode) - dumped_records;
1574 freq.last_in_set = 0;
1575 freq.setname = setname;
1576 freq.surrogate_flag = 0;
1577 freq.number = recno;
1579 freq.request_format = format;
1580 freq.request_format_raw = oid;
1581 freq.output_format = format;
1582 freq.output_format_raw = 0;
1583 freq.stream = a->encode;
1584 freq.print = a->print;
1585 freq.referenceId = referenceId;
1587 (*a->init->bend_fetch)(a->backend, &freq);
1588 /* backend should be able to signal whether error is system-wide
1589 or only pertaining to current record */
1592 if (!freq.surrogate_flag)
1595 *pres = Z_PresentStatus_failure;
1596 /* for 'present request out of range',
1597 set addinfo to record position if not set */
1598 if (freq.errcode == 13 && freq.errstring == 0)
1600 sprintf (s, "%d", recno);
1603 return diagrec(a, freq.errcode, freq.errstring);
1605 reclist->records[reclist->num_records] =
1606 surrogatediagrec(a, freq.basename, freq.errcode,
1608 reclist->num_records++;
1609 *next = freq.last_in_set ? 0 : recno + 1;
1613 this_length = freq.len;
1615 this_length = odr_total(a->encode) - total_length - dumped_records;
1616 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1617 this_length, total_length, dumped_records);
1618 if (a->preferredMessageSize > 0 &&
1619 this_length + total_length > a->preferredMessageSize)
1621 /* record is small enough, really */
1622 if (this_length <= a->preferredMessageSize && recno > start)
1624 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1625 *pres = Z_PresentStatus_partial_2;
1628 /* record can only be fetched by itself */
1629 if (this_length < a->maximumRecordSize)
1631 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1634 yaz_log(LOG_DEBUG, " Dropped it");
1635 reclist->records[reclist->num_records] =
1636 surrogatediagrec(a, freq.basename, 16, 0);
1637 reclist->num_records++;
1638 *next = freq.last_in_set ? 0 : recno + 1;
1639 dumped_records += this_length;
1643 else /* too big entirely */
1645 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1646 reclist->records[reclist->num_records] =
1647 surrogatediagrec(a, freq.basename, 17, 0);
1648 reclist->num_records++;
1649 *next = freq.last_in_set ? 0 : recno + 1;
1650 dumped_records += this_length;
1655 if (!(thisrec = (Z_NamePlusRecord *)
1656 odr_malloc(a->encode, sizeof(*thisrec))))
1658 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1659 strlen(freq.basename) + 1)))
1661 strcpy(thisrec->databaseName, freq.basename);
1662 thisrec->which = Z_NamePlusRecord_databaseRecord;
1664 if (freq.output_format_raw)
1666 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1667 freq.output_format = ident->value;
1669 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1670 freq.record, freq.len);
1671 if (!thisrec->u.databaseRecord)
1673 reclist->records[reclist->num_records] = thisrec;
1674 reclist->num_records++;
1675 *next = freq.last_in_set ? 0 : recno + 1;
1677 *num = reclist->num_records;
1681 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1684 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1685 bend_search_rr *bsrr =
1686 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1688 yaz_log(LOG_LOG, "Got SearchRequest.");
1690 bsrr->request = reqb;
1691 bsrr->association = assoc;
1692 bsrr->referenceId = req->referenceId;
1693 save_referenceId (reqb, bsrr->referenceId);
1695 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1696 if (req->databaseNames)
1699 for (i = 0; i < req->num_databaseNames; i++)
1700 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1702 yaz_log_zquery(req->query);
1704 if (assoc->init->bend_search)
1706 bsrr->setname = req->resultSetName;
1707 bsrr->replace_set = *req->replaceIndicator;
1708 bsrr->num_bases = req->num_databaseNames;
1709 bsrr->basenames = req->databaseNames;
1710 bsrr->query = req->query;
1711 bsrr->stream = assoc->encode;
1712 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1713 bsrr->decode = assoc->decode;
1714 bsrr->print = assoc->print;
1717 bsrr->errstring = NULL;
1718 bsrr->search_info = NULL;
1719 (assoc->init->bend_search)(assoc->backend, bsrr);
1723 return response_searchRequest(assoc, reqb, bsrr, fd);
1726 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1729 * Prepare a searchresponse based on the backend results. We probably want
1730 * to look at making the fetching of records nonblocking as well, but
1731 * so far, we'll keep things simple.
1732 * If bsrt is null, that means we're called in response to a communications
1733 * event, and we'll have to get the response for ourselves.
1735 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1736 bend_search_rr *bsrt, int *fd)
1738 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1739 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1740 Z_SearchResponse *resp = (Z_SearchResponse *)
1741 odr_malloc (assoc->encode, sizeof(*resp));
1742 int *nulint = odr_intdup (assoc->encode, 0);
1743 bool_t *sr = odr_intdup(assoc->encode, 1);
1744 int *next = odr_intdup(assoc->encode, 0);
1745 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1747 apdu->which = Z_APDU_searchResponse;
1748 apdu->u.searchResponse = resp;
1749 resp->referenceId = req->referenceId;
1750 resp->additionalSearchInfo = 0;
1751 resp->otherInfo = 0;
1753 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1755 yaz_log(LOG_FATAL, "Bad result from backend");
1758 else if (bsrt->errcode)
1760 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1761 resp->resultCount = nulint;
1762 resp->numberOfRecordsReturned = nulint;
1763 resp->nextResultSetPosition = nulint;
1764 resp->searchStatus = nulint;
1765 resp->resultSetStatus = none;
1766 resp->presentStatus = 0;
1770 int *toget = odr_intdup(assoc->encode, 0);
1771 int *presst = odr_intdup(assoc->encode, 0);
1772 Z_RecordComposition comp, *compp = 0;
1774 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1777 resp->resultCount = &bsrt->hits;
1779 comp.which = Z_RecordComp_simple;
1780 /* how many records does the user agent want, then? */
1781 if (bsrt->hits <= *req->smallSetUpperBound)
1783 *toget = bsrt->hits;
1784 if ((comp.u.simple = req->smallSetElementSetNames))
1787 else if (bsrt->hits < *req->largeSetLowerBound)
1789 *toget = *req->mediumSetPresentNumber;
1790 if (*toget > bsrt->hits)
1791 *toget = bsrt->hits;
1792 if ((comp.u.simple = req->mediumSetElementSetNames))
1798 if (*toget && !resp->records)
1803 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1806 form = prefformat->value;
1807 resp->records = pack_records(assoc, req->resultSetName, 1,
1808 toget, compp, next, presst, form, req->referenceId,
1809 req->preferredRecordSyntax);
1812 resp->numberOfRecordsReturned = toget;
1813 resp->nextResultSetPosition = next;
1814 resp->searchStatus = sr;
1815 resp->resultSetStatus = 0;
1816 resp->presentStatus = presst;
1820 if (*resp->resultCount)
1822 resp->numberOfRecordsReturned = nulint;
1823 resp->nextResultSetPosition = next;
1824 resp->searchStatus = sr;
1825 resp->resultSetStatus = 0;
1826 resp->presentStatus = 0;
1829 resp->additionalSearchInfo = bsrt->search_info;
1834 * Maybe we got a little over-friendly when we designed bend_fetch to
1835 * get only one record at a time. Some backends can optimise multiple-record
1836 * fetches, and at any rate, there is some overhead involved in
1837 * all that selecting and hopping around. Problem is, of course, that the
1838 * frontend can't know ahead of time how many records it'll need to
1839 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1840 * is downright lousy as a bulk data transfer protocol.
1842 * To start with, we'll do the fetching of records from the backend
1843 * in one operation: To save some trips in and out of the event-handler,
1844 * and to simplify the interface to pack_records. At any rate, asynch
1845 * operation is more fun in operations that have an unpredictable execution
1846 * speed - which is normally more true for search than for present.
1848 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1851 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1855 Z_PresentResponse *resp;
1859 yaz_log(LOG_LOG, "Got PresentRequest.");
1861 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1864 form = prefformat->value;
1865 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1867 resp->presentStatus = odr_intdup(assoc->encode, 0);
1868 if (assoc->init->bend_present)
1870 bend_present_rr *bprr = (bend_present_rr *)
1871 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1872 bprr->setname = req->resultSetId;
1873 bprr->start = *req->resultSetStartPoint;
1874 bprr->number = *req->numberOfRecordsRequested;
1875 bprr->format = form;
1876 bprr->comp = req->recordComposition;
1877 bprr->referenceId = req->referenceId;
1878 bprr->stream = assoc->encode;
1879 bprr->print = assoc->print;
1880 bprr->request = reqb;
1881 bprr->association = assoc;
1883 bprr->errstring = NULL;
1884 (*assoc->init->bend_present)(assoc->backend, bprr);
1890 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1891 *resp->presentStatus = Z_PresentStatus_failure;
1894 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1895 next = odr_intdup(assoc->encode, 0);
1896 num = odr_intdup(assoc->encode, 0);
1898 apdu->which = Z_APDU_presentResponse;
1899 apdu->u.presentResponse = resp;
1900 resp->referenceId = req->referenceId;
1901 resp->otherInfo = 0;
1905 *num = *req->numberOfRecordsRequested;
1907 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1908 num, req->recordComposition, next, resp->presentStatus,
1909 form, req->referenceId, req->preferredRecordSyntax);
1913 resp->numberOfRecordsReturned = num;
1914 resp->nextResultSetPosition = next;
1920 * Scan was implemented rather in a hurry, and with support for only the basic
1921 * elements of the service in the backend API. Suggestions are welcome.
1923 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1925 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1926 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1927 Z_ScanResponse *res = (Z_ScanResponse *)
1928 odr_malloc (assoc->encode, sizeof(*res));
1929 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1930 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1931 Z_ListEntries *ents = (Z_ListEntries *)
1932 odr_malloc (assoc->encode, sizeof(*ents));
1933 Z_DiagRecs *diagrecs_p = NULL;
1935 bend_scan_rr *bsrr = (bend_scan_rr *)
1936 odr_malloc (assoc->encode, sizeof(*bsrr));
1937 struct scan_entry *save_entries;
1939 yaz_log(LOG_LOG, "Got ScanRequest");
1941 apdu->which = Z_APDU_scanResponse;
1942 apdu->u.scanResponse = res;
1943 res->referenceId = req->referenceId;
1945 /* if step is absent, set it to 0 */
1946 res->stepSize = odr_intdup(assoc->encode, 0);
1948 *res->stepSize = *req->stepSize;
1950 res->scanStatus = scanStatus;
1951 res->numberOfEntriesReturned = numberOfEntriesReturned;
1952 res->positionOfTerm = 0;
1953 res->entries = ents;
1954 ents->num_entries = 0;
1955 ents->entries = NULL;
1956 ents->num_nonsurrogateDiagnostics = 0;
1957 ents->nonsurrogateDiagnostics = NULL;
1958 res->attributeSet = 0;
1961 if (req->databaseNames)
1964 for (i = 0; i < req->num_databaseNames; i++)
1965 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1967 bsrr->num_bases = req->num_databaseNames;
1968 bsrr->basenames = req->databaseNames;
1969 bsrr->num_entries = *req->numberOfTermsRequested;
1970 bsrr->term = req->termListAndStartPoint;
1971 bsrr->referenceId = req->referenceId;
1972 bsrr->stream = assoc->encode;
1973 bsrr->print = assoc->print;
1974 bsrr->step_size = res->stepSize;
1976 /* Note that version 2.0 of YAZ and older did not set entries ..
1977 We do now. And when we do it's easier to extend the scan entry
1978 We know that if the scan handler did set entries, it will
1979 not know of new member display_term.
1981 if (bsrr->num_entries > 0)
1984 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1986 for (i = 0; i<bsrr->num_entries; i++)
1988 bsrr->entries[i].term = 0;
1989 bsrr->entries[i].occurrences = 0;
1990 bsrr->entries[i].errcode = 0;
1991 bsrr->entries[i].errstring = 0;
1992 bsrr->entries[i].display_term = 0;
1995 save_entries = bsrr->entries; /* save it so we can compare later */
1997 if (req->attributeSet &&
1998 (attset = oid_getentbyoid(req->attributeSet)) &&
1999 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2000 bsrr->attributeset = attset->value;
2002 bsrr->attributeset = VAL_NONE;
2003 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2004 bsrr->term_position = req->preferredPositionInResponse ?
2005 *req->preferredPositionInResponse : 1;
2006 ((int (*)(void *, bend_scan_rr *))
2007 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2009 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2013 Z_Entry **tab = (Z_Entry **)
2014 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2016 if (bsrr->status == BEND_SCAN_PARTIAL)
2017 *scanStatus = Z_Scan_partial_5;
2019 *scanStatus = Z_Scan_success;
2020 ents->entries = tab;
2021 ents->num_entries = bsrr->num_entries;
2022 res->numberOfEntriesReturned = &ents->num_entries;
2023 res->positionOfTerm = &bsrr->term_position;
2024 for (i = 0; i < bsrr->num_entries; i++)
2030 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2031 if (bsrr->entries[i].occurrences >= 0)
2033 e->which = Z_Entry_termInfo;
2034 e->u.termInfo = t = (Z_TermInfo *)
2035 odr_malloc(assoc->encode, sizeof(*t));
2036 t->suggestedAttributes = 0;
2038 if (save_entries == bsrr->entries &&
2039 bsrr->entries[i].display_term)
2041 /* the entries was NOT set by the handler. So it's
2042 safe to test for new member display_term. It is
2045 t->displayTerm = odr_strdup(assoc->encode,
2046 bsrr->entries[i].display_term);
2048 t->alternativeTerm = 0;
2049 t->byAttributes = 0;
2050 t->otherTermInfo = 0;
2051 t->globalOccurrences = &bsrr->entries[i].occurrences;
2052 t->term = (Z_Term *)
2053 odr_malloc(assoc->encode, sizeof(*t->term));
2054 t->term->which = Z_Term_general;
2055 t->term->u.general = o =
2056 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2057 o->buf = (unsigned char *)
2058 odr_malloc(assoc->encode, o->len = o->size =
2059 strlen(bsrr->entries[i].term));
2060 memcpy(o->buf, bsrr->entries[i].term, o->len);
2061 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2062 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2066 Z_DiagRecs *drecs = diagrecs (assoc,
2067 bsrr->entries[i].errcode,
2068 bsrr->entries[i].errstring);
2069 assert (drecs->num_diagRecs == 1);
2070 e->which = Z_Entry_surrogateDiagnostic;
2071 assert (drecs->diagRecs[0]);
2072 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2078 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2079 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2084 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2087 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2088 Z_SortResponse *res = (Z_SortResponse *)
2089 odr_malloc (assoc->encode, sizeof(*res));
2090 bend_sort_rr *bsrr = (bend_sort_rr *)
2091 odr_malloc (assoc->encode, sizeof(*bsrr));
2093 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2095 yaz_log(LOG_LOG, "Got SortRequest.");
2097 bsrr->num_input_setnames = req->num_inputResultSetNames;
2098 bsrr->input_setnames = req->inputResultSetNames;
2099 bsrr->referenceId = req->referenceId;
2100 bsrr->output_setname = req->sortedResultSetName;
2101 bsrr->sort_sequence = req->sortSequence;
2102 bsrr->stream = assoc->encode;
2103 bsrr->print = assoc->print;
2105 bsrr->sort_status = Z_SortResponse_failure;
2107 bsrr->errstring = 0;
2109 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2111 res->referenceId = bsrr->referenceId;
2112 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2113 res->resultSetStatus = 0;
2116 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2117 res->diagnostics = dr->diagRecs;
2118 res->num_diagnostics = dr->num_diagRecs;
2122 res->num_diagnostics = 0;
2123 res->diagnostics = 0;
2125 res->resultCount = 0;
2128 apdu->which = Z_APDU_sortResponse;
2129 apdu->u.sortResponse = res;
2133 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2136 Z_DeleteResultSetRequest *req =
2137 reqb->apdu_request->u.deleteResultSetRequest;
2138 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2139 odr_malloc (assoc->encode, sizeof(*res));
2140 bend_delete_rr *bdrr = (bend_delete_rr *)
2141 odr_malloc (assoc->encode, sizeof(*bdrr));
2142 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2144 yaz_log(LOG_LOG, "Got DeleteRequest.");
2146 bdrr->num_setnames = req->num_resultSetList;
2147 bdrr->setnames = req->resultSetList;
2148 bdrr->stream = assoc->encode;
2149 bdrr->print = assoc->print;
2150 bdrr->function = *req->deleteFunction;
2151 bdrr->referenceId = req->referenceId;
2153 if (bdrr->num_setnames > 0)
2156 bdrr->statuses = (int*)
2157 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2158 bdrr->num_setnames);
2159 for (i = 0; i < bdrr->num_setnames; i++)
2160 bdrr->statuses[i] = 0;
2162 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2164 res->referenceId = req->referenceId;
2166 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2168 res->deleteListStatuses = 0;
2169 if (bdrr->num_setnames > 0)
2172 res->deleteListStatuses = (Z_ListStatuses *)
2173 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2174 res->deleteListStatuses->num = bdrr->num_setnames;
2175 res->deleteListStatuses->elements =
2177 odr_malloc (assoc->encode,
2178 sizeof(*res->deleteListStatuses->elements) *
2179 bdrr->num_setnames);
2180 for (i = 0; i<bdrr->num_setnames; i++)
2182 res->deleteListStatuses->elements[i] =
2184 odr_malloc (assoc->encode,
2185 sizeof(**res->deleteListStatuses->elements));
2186 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2187 res->deleteListStatuses->elements[i]->id =
2188 odr_strdup (assoc->encode, bdrr->setnames[i]);
2192 res->numberNotDeleted = 0;
2193 res->bulkStatuses = 0;
2194 res->deleteMessage = 0;
2197 apdu->which = Z_APDU_deleteResultSetResponse;
2198 apdu->u.deleteResultSetResponse = res;
2202 static void process_close(association *assoc, request *reqb)
2204 Z_Close *req = reqb->apdu_request->u.close;
2205 static char *reasons[] =
2212 "securityViolation",
2219 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2220 reasons[*req->closeReason], req->diagnosticInformation ?
2221 req->diagnosticInformation : "NULL");
2222 if (assoc->version < 3) /* to make do_force respond with close */
2224 do_close_req(assoc, Z_Close_finished,
2225 "Association terminated by client", reqb);
2228 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2232 reqb->len_refid = refid->len;
2233 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2234 memcpy (reqb->refid, refid->buf, refid->len);
2238 reqb->len_refid = 0;
2243 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2245 process_z_response (a, req, res);
2248 bend_request bend_request_mk (bend_association a)
2250 request *nreq = request_get (&a->outgoing);
2251 nreq->request_mem = nmem_create ();
2255 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2260 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2261 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2262 id->len = id->size = req->len_refid;
2263 memcpy (id->buf, req->refid, req->len_refid);
2267 void bend_request_destroy (bend_request *req)
2269 nmem_destroy((*req)->request_mem);
2270 request_release(*req);
2274 int bend_backend_respond (bend_association a, bend_request req)
2278 r = process_z_request (a, req, &msg);
2280 yaz_log (LOG_WARN, "%s", msg);
2284 void bend_request_setdata(bend_request r, void *p)
2289 void *bend_request_getdata(bend_request r)
2291 return r->clientData;
2294 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2296 bend_segment_rr req;
2298 req.segment = reqb->apdu_request->u.segmentRequest;
2299 req.stream = assoc->encode;
2300 req.decode = assoc->decode;
2301 req.print = assoc->print;
2302 req.association = assoc;
2304 (*assoc->init->bend_segment)(assoc->backend, &req);
2309 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2311 bend_esrequest_rr esrequest;
2313 Z_ExtendedServicesRequest *req =
2314 reqb->apdu_request->u.extendedServicesRequest;
2315 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2317 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2319 yaz_log(LOG_DEBUG,"inside Process esRequest");
2321 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2322 esrequest.stream = assoc->encode;
2323 esrequest.decode = assoc->decode;
2324 esrequest.print = assoc->print;
2325 esrequest.errcode = 0;
2326 esrequest.errstring = NULL;
2327 esrequest.request = reqb;
2328 esrequest.association = assoc;
2329 esrequest.taskPackage = 0;
2330 esrequest.referenceId = req->referenceId;
2332 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2334 /* If the response is being delayed, return NULL */
2335 if (esrequest.request == NULL)
2338 resp->referenceId = req->referenceId;
2340 if (esrequest.errcode == -1)
2342 /* Backend service indicates request will be processed */
2343 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2344 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2346 else if (esrequest.errcode == 0)
2348 /* Backend service indicates request will be processed */
2349 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2350 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2354 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2355 esrequest.errstring);
2357 /* Backend indicates error, request will not be processed */
2358 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2359 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2360 resp->num_diagnostics = diagRecs->num_diagRecs;
2361 resp->diagnostics = diagRecs->diagRecs;
2363 /* Do something with the members of bend_extendedservice */
2364 if (esrequest.taskPackage)
2365 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2366 (const char *) esrequest.taskPackage,
2368 yaz_log(LOG_DEBUG,"Send the result apdu");