2 * Copyright (c) 1995-2004, Index Data
3 * See the file LICENSE for details.
5 * $Id: seshigh.c,v 1.33 2004-10-15 00:19:00 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, char *errstring);
72 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
74 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
75 bend_search_rr *bsrr, int *fd);
76 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
78 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
79 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
80 static void process_close(association *assoc, request *reqb);
81 void save_referenceId (request *reqb, Z_ReferenceId *refid);
82 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
84 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
86 static FILE *apduf = 0; /* for use in static mode */
87 static statserv_options_block *control_block = 0;
89 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
92 * Create and initialize a new association-handle.
93 * channel : iochannel for the current line.
94 * link : communications channel.
95 * Returns: 0 or a new association handle.
97 association *create_association(IOCHAN channel, COMSTACK link)
102 control_block = statserv_getcontrol();
103 if (!(anew = (association *)xmalloc(sizeof(*anew))))
107 anew->client_chan = channel;
108 anew->client_link = link;
109 anew->cs_get_mask = 0;
110 anew->cs_put_mask = 0;
111 anew->cs_accept_mask = 0;
112 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
113 !(anew->encode = odr_createmem(ODR_ENCODE)))
115 if (*control_block->apdufile)
120 strcpy(filename, control_block->apdufile);
121 if (!(anew->print = odr_createmem(ODR_PRINT)))
123 if (*control_block->apdufile == '@')
125 odr_setprint(anew->print, yaz_log_file());
127 else if (*control_block->apdufile != '-')
129 strcpy(filename, control_block->apdufile);
130 if (!control_block->dynamic)
134 if (!(apduf = fopen(filename, "w")))
136 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
139 setvbuf(apduf, 0, _IONBF, 0);
145 sprintf(filename + strlen(filename), ".%d", getpid());
146 if (!(f = fopen(filename, "w")))
148 yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
151 setvbuf(f, 0, _IONBF, 0);
153 odr_setprint(anew->print, f);
158 anew->input_buffer = 0;
159 anew->input_buffer_len = 0;
161 anew->state = ASSOC_NEW;
162 request_initq(&anew->incoming);
163 request_initq(&anew->outgoing);
164 anew->proto = cs_getproto(link);
169 * Free association and release resources.
171 void destroy_association(association *h)
173 statserv_options_block *cb = statserv_getcontrol();
177 odr_destroy(h->decode);
178 odr_destroy(h->encode);
180 odr_destroy(h->print);
182 xfree(h->input_buffer);
184 (*cb->bend_close)(h->backend);
185 while ((req = request_deq(&h->incoming)))
186 request_release(req);
187 while ((req = request_deq(&h->outgoing)))
188 request_release(req);
189 request_delq(&h->incoming);
190 request_delq(&h->outgoing);
192 xmalloc_trav("session closed");
193 if (control_block && control_block->one_shot)
199 static void do_close_req(association *a, int reason, char *message,
203 Z_Close *cls = zget_Close(a->encode);
205 /* Purge request queue */
206 while (request_deq(&a->incoming));
207 while (request_deq(&a->outgoing));
210 yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
211 reason, message ? message : "none");
212 apdu.which = Z_APDU_close;
214 *cls->closeReason = reason;
215 cls->diagnosticInformation = message;
216 process_z_response(a, req, &apdu);
217 iochan_settimeout(a->client_chan, 20);
221 request_release(req);
222 yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
223 iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
225 a->state = ASSOC_DEAD;
228 static void do_close(association *a, int reason, char *message)
230 request *req = request_get(&a->outgoing);
231 do_close_req (a, reason, message, req);
235 * This is where PDUs from the client are read and the further
236 * processing is initiated. Flow of control moves down through the
237 * various process_* functions below, until the encoded result comes back up
238 * to the output handler in here.
240 * h : the I/O channel that has an outstanding event.
241 * event : the current outstanding event.
243 void ir_session(IOCHAN h, int event)
246 association *assoc = (association *)iochan_getdata(h);
247 COMSTACK conn = assoc->client_link;
250 assert(h && conn && assoc);
251 if (event == EVENT_TIMEOUT)
253 if (assoc->state != ASSOC_UP)
255 yaz_log(LOG_LOG, "Final timeout - closing connection.");
257 destroy_association(assoc);
262 yaz_log(LOG_LOG, "Session idle too long. Sending close.");
263 do_close(assoc, Z_Close_lackOfActivity, 0);
267 if (event & assoc->cs_accept_mask)
269 yaz_log (LOG_DEBUG, "ir_session (accept)");
270 if (!cs_accept (conn))
272 yaz_log (LOG_LOG, "accept failed");
273 destroy_association(assoc);
276 iochan_clearflag (h, EVENT_OUTPUT);
277 if (conn->io_pending)
278 { /* cs_accept didn't complete */
279 assoc->cs_accept_mask =
280 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
281 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
283 iochan_setflag (h, assoc->cs_accept_mask);
286 { /* cs_accept completed. Prepare for reading (cs_get) */
287 assoc->cs_accept_mask = 0;
288 assoc->cs_get_mask = EVENT_INPUT;
289 iochan_setflag (h, assoc->cs_get_mask);
293 if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
295 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
297 yaz_log(LOG_DEBUG, "ir_session (input)");
298 /* We aren't speaking to this fellow */
299 if (assoc->state == ASSOC_DEAD)
301 yaz_log(LOG_LOG, "Connection closed - end of session");
303 destroy_association(assoc);
307 assoc->cs_get_mask = EVENT_INPUT;
308 if ((res = cs_get(conn, &assoc->input_buffer,
309 &assoc->input_buffer_len)) <= 0)
311 yaz_log(LOG_LOG, "Connection closed by client");
313 destroy_association(assoc);
317 else if (res == 1) /* incomplete read - wait for more */
319 if (conn->io_pending & CS_WANT_WRITE)
320 assoc->cs_get_mask |= EVENT_OUTPUT;
321 iochan_setflag(h, assoc->cs_get_mask);
324 if (cs_more(conn)) /* more stuff - call us again later, please */
325 iochan_setevent(h, EVENT_INPUT);
327 /* we got a complete PDU. Let's decode it */
328 yaz_log(LOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
329 assoc->input_buffer[0] & 0xff,
330 assoc->input_buffer[1] & 0xff,
331 assoc->input_buffer[2] & 0xff);
332 req = request_get(&assoc->incoming); /* get a new request */
333 odr_reset(assoc->decode);
334 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
335 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
337 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [element %s] "
339 odr_errmsg(odr_geterror(assoc->decode)),
340 odr_getelement(assoc->decode),
341 odr_offset(assoc->decode));
342 if (assoc->decode->error != OHTTP)
344 yaz_log(LOG_LOG, "PDU dump:");
345 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
346 request_release(req);
347 do_close(assoc, Z_Close_protocolError,"Malformed package");
351 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
352 assoc->state = ASSOC_DEAD;
353 process_gdu_response(assoc, req, p);
357 req->request_mem = odr_extract_mem(assoc->decode);
360 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
361 yaz_log(LOG_WARN, "ODR print error: %s",
362 odr_errmsg(odr_geterror(assoc->print)));
363 odr_reset(assoc->print);
365 request_enq(&assoc->incoming, req);
368 /* can we do something yet? */
369 req = request_head(&assoc->incoming);
370 if (req->state == REQUEST_IDLE)
372 request_deq(&assoc->incoming);
373 process_gdu_request(assoc, req);
376 if (event & assoc->cs_put_mask)
378 request *req = request_head(&assoc->outgoing);
380 assoc->cs_put_mask = 0;
381 yaz_log(LOG_DEBUG, "ir_session (output)");
382 req->state = REQUEST_PENDING;
383 switch (res = cs_put(conn, req->response, req->len_response))
386 yaz_log(LOG_LOG, "Connection closed by client");
388 destroy_association(assoc);
391 case 0: /* all sent - release the request structure */
392 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
394 yaz_log(LOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
397 nmem_destroy(req->request_mem);
398 request_deq(&assoc->outgoing);
399 request_release(req);
400 if (!request_head(&assoc->outgoing))
401 { /* restore mask for cs_get operation ... */
402 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
403 iochan_setflag(h, assoc->cs_get_mask);
404 if (assoc->state == ASSOC_DEAD)
405 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
409 assoc->cs_put_mask = EVENT_OUTPUT;
413 if (conn->io_pending & CS_WANT_WRITE)
414 assoc->cs_put_mask |= EVENT_OUTPUT;
415 if (conn->io_pending & CS_WANT_READ)
416 assoc->cs_put_mask |= EVENT_INPUT;
417 iochan_setflag(h, assoc->cs_put_mask);
420 if (event & EVENT_EXCEPT)
422 yaz_log(LOG_LOG, "ir_session (exception)");
424 destroy_association(assoc);
429 static int process_z_request(association *assoc, request *req, char **msg);
431 static void assoc_init_reset(association *assoc)
434 assoc->init = (bend_initrequest *) xmalloc (sizeof(*assoc->init));
436 assoc->init->stream = assoc->encode;
437 assoc->init->print = assoc->print;
438 assoc->init->auth = 0;
439 assoc->init->referenceId = 0;
440 assoc->init->implementation_version = 0;
441 assoc->init->implementation_id = 0;
442 assoc->init->implementation_name = 0;
443 assoc->init->bend_sort = NULL;
444 assoc->init->bend_search = NULL;
445 assoc->init->bend_present = NULL;
446 assoc->init->bend_esrequest = NULL;
447 assoc->init->bend_delete = NULL;
448 assoc->init->bend_scan = NULL;
449 assoc->init->bend_segment = NULL;
450 assoc->init->bend_fetch = NULL;
451 assoc->init->bend_explain = NULL;
453 assoc->init->charneg_request = NULL;
454 assoc->init->charneg_response = NULL;
456 assoc->init->decode = assoc->decode;
457 assoc->init->peer_name =
458 odr_strdup (assoc->encode, cs_addrstr(assoc->client_link));
461 static int srw_bend_init(association *assoc)
463 const char *encoding = "UTF-8";
465 bend_initresult *binitres;
466 statserv_options_block *cb = statserv_getcontrol();
468 assoc_init_reset(assoc);
470 assoc->maximumRecordSize = 3000000;
471 assoc->preferredMessageSize = 3000000;
473 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
474 assoc->init->charneg_request = ce->u.charNeg3;
477 if (!(binitres = (*cb->bend_init)(assoc->init)))
479 yaz_log(LOG_WARN, "Bad response from backend.");
482 assoc->backend = binitres->handle;
486 static int srw_bend_fetch(association *assoc, int pos,
487 Z_SRW_searchRetrieveRequest *srw_req,
488 Z_SRW_record *record)
491 ODR o = assoc->encode;
493 rr.setname = "default";
496 rr.request_format = VAL_TEXT_XML;
497 rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
500 rr.comp = (Z_RecordComposition *)
501 odr_malloc(assoc->decode, sizeof(*rr.comp));
502 rr.comp->which = Z_RecordComp_complex;
503 rr.comp->u.complex = (Z_CompSpec *)
504 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
505 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
506 odr_malloc(assoc->encode, sizeof(bool_t));
507 *rr.comp->u.complex->selectAlternativeSyntax = 0;
508 rr.comp->u.complex->num_dbSpecific = 0;
509 rr.comp->u.complex->dbSpecific = 0;
510 rr.comp->u.complex->num_recordSyntax = 0;
511 rr.comp->u.complex->recordSyntax = 0;
513 rr.comp->u.complex->generic = (Z_Specification *)
514 odr_malloc(assoc->decode, sizeof(Z_Specification));
516 /* schema uri = recordSchema (or NULL if recordSchema is not given) */
517 rr.comp->u.complex->generic->which = Z_Schema_uri;
518 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
520 /* ESN = recordSchema if recordSchema is present */
521 rr.comp->u.complex->generic->elementSpec = 0;
522 if (srw_req->recordSchema)
524 rr.comp->u.complex->generic->elementSpec =
525 (Z_ElementSpec *) odr_malloc(assoc->encode, sizeof(Z_ElementSpec));
526 rr.comp->u.complex->generic->elementSpec->which =
527 Z_ElementSpec_elementSetName;
528 rr.comp->u.complex->generic->elementSpec->u.elementSetName =
529 srw_req->recordSchema;
532 rr.stream = assoc->encode;
533 rr.print = assoc->print;
539 rr.output_format = VAL_TEXT_XML;
540 rr.output_format_raw = 0;
543 rr.surrogate_flag = 0;
544 rr.schema = srw_req->recordSchema;
546 if (!assoc->init->bend_fetch)
549 (*assoc->init->bend_fetch)(assoc->backend, &rr);
551 if (rr.errcode && rr.surrogate_flag)
553 int code = yaz_diag_bib1_to_srw(rr.errcode);
554 const char *message = yaz_diag_srw_str(code);
557 len += strlen(message);
559 len += strlen(rr.errstring);
561 record->recordData_buf = odr_malloc(o, len);
563 sprintf(record->recordData_buf, "<diagnostic "
564 "xmlns=\"http://www.loc.gov/zing/srw/diagnostic/\">\n"
565 " <uri>info:srw/diagnostic/1/%d</uri>\n", code);
567 sprintf(record->recordData_buf + strlen(record->recordData_buf),
568 " <details>%s</details>\n", rr.errstring);
570 sprintf(record->recordData_buf + strlen(record->recordData_buf),
571 " <message>%s</message>\n", message);
572 sprintf(record->recordData_buf + strlen(record->recordData_buf),
574 record->recordData_len = strlen(record->recordData_buf);
575 record->recordPosition = odr_intdup(o, pos);
576 record->recordSchema = "info:srw/schema/1/diagnostics-v1.1";
579 else if (rr.len >= 0)
581 record->recordData_buf = rr.record;
582 record->recordData_len = rr.len;
583 record->recordPosition = odr_intdup(o, pos);
585 record->recordSchema = odr_strdup(o, rr.schema);
587 record->recordSchema = 0;
592 static void srw_bend_search(association *assoc, request *req,
593 Z_SRW_searchRetrieveRequest *srw_req,
594 Z_SRW_searchRetrieveResponse *srw_res,
602 yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
603 yaz_log(LOG_DEBUG, "srw_bend_search");
606 yaz_log(LOG_DEBUG, "srw_bend_init");
607 if (!srw_bend_init(assoc))
609 srw_error = 3; /* assume Authentication error */
611 yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
612 &srw_res->num_diagnostics, 1, 0);
617 rr.setname = "default";
620 rr.basenames = &srw_req->database;
623 rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query));
625 if (srw_req->query_type == Z_SRW_query_type_cql)
627 ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
628 ext->direct_reference = odr_getoidbystr(assoc->decode,
629 "1.2.840.10003.16.2");
630 ext->indirect_reference = 0;
632 ext->which = Z_External_CQL;
633 ext->u.cql = srw_req->query.cql;
635 rr.query->which = Z_Query_type_104;
636 rr.query->u.type_104 = ext;
638 else if (srw_req->query_type == Z_SRW_query_type_pqf)
640 Z_RPNQuery *RPNquery;
641 YAZ_PQF_Parser pqf_parser;
643 pqf_parser = yaz_pqf_create ();
645 RPNquery = yaz_pqf_parse (pqf_parser, assoc->decode,
651 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
653 yaz_log(LOG_LOG, "%*s^\n", (int)off+4, "");
654 yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
659 rr.query->which = Z_Query_type_1;
660 rr.query->u.type_1 = RPNquery;
662 yaz_pqf_destroy (pqf_parser);
667 if (!srw_error && srw_req->sort_type != Z_SRW_sort_type_none)
670 if (!srw_error && !assoc->init->bend_search)
675 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d", srw_error);
676 srw_res->num_diagnostics = 1;
677 srw_res->diagnostics = (Z_SRW_diagnostic *)
678 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
679 yaz_mk_std_diagnostic(assoc->encode,
680 srw_res->diagnostics, srw_error, 0);
684 rr.stream = assoc->encode;
685 rr.decode = assoc->decode;
686 rr.print = assoc->print;
688 rr.association = assoc;
694 yaz_log_zquery(rr.query);
695 (assoc->init->bend_search)(assoc->backend, &rr);
698 yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
699 if (rr.errcode == 109) /* database unavailable */
704 srw_res->num_diagnostics = 1;
705 srw_res->diagnostics = (Z_SRW_diagnostic *)
706 odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
707 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
708 yaz_diag_bib1_to_srw (rr.errcode),
710 yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %s",
711 srw_res->diagnostics[0].uri);
715 int number = srw_req->maximumRecords ? *srw_req->maximumRecords : 0;
716 int start = srw_req->startRecord ? *srw_req->startRecord : 1;
718 yaz_log(LOG_LOG, "Request to pack %d+%d out of %d",
719 start, number, rr.hits);
721 srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
728 srw_res->num_diagnostics = 1;
729 srw_res->diagnostics = (Z_SRW_diagnostic *)
730 odr_malloc(assoc->encode,
731 sizeof(*srw_res->diagnostics));
732 yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
738 int packing = Z_SRW_recordPacking_string;
739 if (start + number > rr.hits)
740 number = rr.hits - start + 1;
741 if (srw_req->recordPacking &&
742 !strcmp(srw_req->recordPacking, "xml"))
743 packing = Z_SRW_recordPacking_XML;
744 srw_res->records = (Z_SRW_record *)
745 odr_malloc(assoc->encode,
746 number * sizeof(*srw_res->records));
747 for (i = 0; i<number; i++)
751 srw_res->records[j].recordPacking = packing;
752 srw_res->records[j].recordData_buf = 0;
753 yaz_log(LOG_DEBUG, "srw_bend_fetch %d", i+start);
754 errcode = srw_bend_fetch(assoc, i+start, srw_req,
755 srw_res->records + j);
758 srw_res->num_diagnostics = 1;
759 srw_res->diagnostics = (Z_SRW_diagnostic *)
760 odr_malloc(assoc->encode,
761 sizeof(*srw_res->diagnostics));
763 yaz_mk_std_diagnostic(assoc->encode,
764 srw_res->diagnostics,
765 yaz_diag_bib1_to_srw (errcode),
769 if (srw_res->records[j].recordData_buf)
772 srw_res->num_records = j;
774 srw_res->records = 0;
780 static void srw_bend_explain(association *assoc, request *req,
781 Z_SRW_explainRequest *srw_req,
782 Z_SRW_explainResponse *srw_res,
785 yaz_log(LOG_LOG, "Got SRW ExplainRequest");
789 yaz_log(LOG_DEBUG, "srw_bend_init");
790 if (!srw_bend_init(assoc))
795 if (assoc->init && assoc->init->bend_explain)
799 rr.stream = assoc->encode;
800 rr.decode = assoc->decode;
801 rr.print = assoc->print;
803 rr.database = srw_req->database;
804 rr.schema = "http://explain.z3950.org/dtd/2.0/";
805 (*assoc->init->bend_explain)(assoc->backend, &rr);
808 int packing = Z_SRW_recordPacking_string;
809 if (srw_req->recordPacking &&
810 !strcmp(srw_req->recordPacking, "xml"))
811 packing = Z_SRW_recordPacking_XML;
812 srw_res->record.recordSchema = rr.schema;
813 srw_res->record.recordPacking = packing;
814 srw_res->record.recordData_buf = rr.explain_buf;
815 srw_res->record.recordData_len = strlen(rr.explain_buf);
816 srw_res->record.recordPosition = 0;
822 static void process_http_request(association *assoc, request *req)
824 Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
825 ODR o = assoc->encode;
826 int r = 2; /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
828 Z_SOAP *soap_package = 0;
831 Z_HTTP_Response *hres = 0;
833 char *stylesheet = 0;
834 Z_SRW_diagnostic *diagnostic = 0;
835 int num_diagnostic = 0;
837 if (!strcmp(hreq->path, "/test"))
839 p = z_get_HTTP_Response(o, 200);
840 hres = p->u.HTTP_Response;
841 hres->content_buf = "1234567890\n";
842 hres->content_len = strlen(hres->content_buf);
847 r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
848 yaz_log(LOG_DEBUG, "yaz_srw_decode returned %d", r);
850 if (r == 2) /* not taken */
852 r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
853 &diagnostic, &num_diagnostic);
854 yaz_log(LOG_DEBUG, "yaz_sru_decode returned %d", r);
856 if (r == 0) /* decode SRW/SRU OK .. */
859 if (sr->which == Z_SRW_searchRetrieve_request)
862 yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
864 stylesheet = sr->u.request->stylesheet;
867 res->u.response->diagnostics = diagnostic;
868 res->u.response->num_diagnostics = num_diagnostic;
872 srw_bend_search(assoc, req, sr->u.request, res->u.response,
875 if (http_code == 200)
876 soap_package->u.generic->p = res;
878 else if (sr->which == Z_SRW_explain_request)
880 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
881 stylesheet = sr->u.explain_request->stylesheet;
884 res->u.explain_response->diagnostics = diagnostic;
885 res->u.explain_response->num_diagnostics = num_diagnostic;
887 srw_bend_explain(assoc, req, sr->u.explain_request,
888 res->u.explain_response, &http_code);
889 if (http_code == 200)
890 soap_package->u.generic->p = res;
892 else if (sr->which == Z_SRW_scan_request)
894 Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
895 stylesheet = sr->u.scan_request->stylesheet;
898 res->u.scan_response->diagnostics = diagnostic;
899 res->u.scan_response->num_diagnostics = num_diagnostic;
901 yaz_add_srw_diagnostic(o,
902 &res->u.scan_response->diagnostics,
903 &res->u.scan_response->num_diagnostics,
905 if (http_code == 200)
906 soap_package->u.generic->p = res;
910 yaz_log(LOG_LOG, "generate soap error");
912 z_soap_error(assoc->encode, soap_package,
913 "SOAP-ENV:Client", "Bad method", 0);
915 if (http_code == 200 || http_code == 500)
917 static Z_SOAP_Handler soap_handlers[3] = {
919 {"http://www.loc.gov/zing/srw/", 0,
920 (Z_SOAP_fun) yaz_srw_codec},
921 {"http://www.loc.gov/zing/srw/v1.0/", 0,
922 (Z_SOAP_fun) yaz_srw_codec},
928 p = z_get_HTTP_Response(o, 200);
929 hres = p->u.HTTP_Response;
930 ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
931 &hres->content_buf, &hres->content_len,
932 soap_handlers, charset, stylesheet);
933 hres->code = http_code;
935 strcpy(ctype, "text/xml");
938 strcat(ctype, "; charset=");
939 strcat(ctype, charset);
941 z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
944 p = z_get_HTTP_Response(o, http_code);
948 p = z_get_HTTP_Response(o, 500);
949 hres = p->u.HTTP_Response;
950 if (!strcmp(hreq->version, "1.0"))
952 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
953 if (v && !strcmp(v, "Keep-Alive"))
957 hres->version = "1.0";
961 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
962 if (v && !strcmp(v, "close"))
966 hres->version = "1.1";
970 z_HTTP_header_add(o, &hres->headers, "Connection", "close");
971 assoc->state = ASSOC_DEAD;
972 assoc->cs_get_mask = 0;
977 const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
979 if (alive && isdigit(*alive))
983 if (t < 0 || t > 3600)
985 iochan_settimeout(assoc->client_chan,t);
986 z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
988 process_gdu_response(assoc, req, p);
991 static void process_gdu_request(association *assoc, request *req)
993 if (req->gdu_request->which == Z_GDU_Z3950)
996 req->apdu_request = req->gdu_request->u.z3950;
997 if (process_z_request(assoc, req, &msg) < 0)
998 do_close_req(assoc, Z_Close_systemProblem, msg, req);
1000 else if (req->gdu_request->which == Z_GDU_HTTP_Request)
1001 process_http_request(assoc, req);
1004 do_close_req(assoc, Z_Close_systemProblem, "bad protocol packet", req);
1009 * Initiate request processing.
1011 static int process_z_request(association *assoc, request *req, char **msg)
1017 *msg = "Unknown Error";
1018 assert(req && req->state == REQUEST_IDLE);
1019 if (req->apdu_request->which != Z_APDU_initRequest && !assoc->init)
1021 *msg = "Missing InitRequest";
1024 switch (req->apdu_request->which)
1026 case Z_APDU_initRequest:
1027 iochan_settimeout(assoc->client_chan,
1028 statserv_getcontrol()->idle_timeout * 60);
1029 res = process_initRequest(assoc, req); break;
1030 case Z_APDU_searchRequest:
1031 res = process_searchRequest(assoc, req, &fd); break;
1032 case Z_APDU_presentRequest:
1033 res = process_presentRequest(assoc, req, &fd); break;
1034 case Z_APDU_scanRequest:
1035 if (assoc->init->bend_scan)
1036 res = process_scanRequest(assoc, req, &fd);
1039 *msg = "Cannot handle Scan APDU";
1043 case Z_APDU_extendedServicesRequest:
1044 if (assoc->init->bend_esrequest)
1045 res = process_ESRequest(assoc, req, &fd);
1048 *msg = "Cannot handle Extended Services APDU";
1052 case Z_APDU_sortRequest:
1053 if (assoc->init->bend_sort)
1054 res = process_sortRequest(assoc, req, &fd);
1057 *msg = "Cannot handle Sort APDU";
1062 process_close(assoc, req);
1064 case Z_APDU_deleteResultSetRequest:
1065 if (assoc->init->bend_delete)
1066 res = process_deleteRequest(assoc, req, &fd);
1069 *msg = "Cannot handle Delete APDU";
1073 case Z_APDU_segmentRequest:
1074 if (assoc->init->bend_segment)
1076 res = process_segmentRequest (assoc, req);
1080 *msg = "Cannot handle Segment APDU";
1084 case Z_APDU_triggerResourceControlRequest:
1087 *msg = "Bad APDU received";
1092 yaz_log(LOG_DEBUG, " result immediately available");
1093 retval = process_z_response(assoc, req, res);
1097 yaz_log(LOG_DEBUG, " result unavailble");
1100 else /* no result yet - one will be provided later */
1104 /* Set up an I/O handler for the fd supplied by the backend */
1106 yaz_log(LOG_DEBUG, " establishing handler for result");
1107 req->state = REQUEST_PENDING;
1108 if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
1110 iochan_setdata(chan, assoc);
1117 * Handle message from the backend.
1119 void backend_response(IOCHAN i, int event)
1121 association *assoc = (association *)iochan_getdata(i);
1122 request *req = request_head(&assoc->incoming);
1126 yaz_log(LOG_DEBUG, "backend_response");
1127 assert(assoc && req && req->state != REQUEST_IDLE);
1128 /* determine what it is we're waiting for */
1129 switch (req->apdu_request->which)
1131 case Z_APDU_searchRequest:
1132 res = response_searchRequest(assoc, req, 0, &fd); break;
1134 case Z_APDU_presentRequest:
1135 res = response_presentRequest(assoc, req, 0, &fd); break;
1136 case Z_APDU_scanRequest:
1137 res = response_scanRequest(assoc, req, 0, &fd); break;
1140 yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
1143 if ((res && process_z_response(assoc, req, res) < 0) || fd < 0)
1145 yaz_log(LOG_LOG, "Fatal error when talking to backend");
1146 do_close(assoc, Z_Close_systemProblem, 0);
1150 else if (!res) /* no result yet - try again later */
1152 yaz_log(LOG_DEBUG, " no result yet");
1153 iochan_setfd(i, fd); /* in case fd has changed */
1158 * Encode response, and transfer the request structure to the outgoing queue.
1160 static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
1162 odr_setbuf(assoc->encode, req->response, req->size_response, 1);
1166 if (!z_GDU(assoc->print, &res, 0, 0))
1167 yaz_log(LOG_WARN, "ODR print error: %s",
1168 odr_errmsg(odr_geterror(assoc->print)));
1169 odr_reset(assoc->print);
1171 if (!z_GDU(assoc->encode, &res, 0, 0))
1173 yaz_log(LOG_WARN, "ODR error when encoding PDU: %s [element %s]",
1174 odr_errmsg(odr_geterror(assoc->decode)),
1175 odr_getelement(assoc->decode));
1176 request_release(req);
1179 req->response = odr_getbuf(assoc->encode, &req->len_response,
1180 &req->size_response);
1181 odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
1182 odr_reset(assoc->encode);
1183 req->state = REQUEST_IDLE;
1184 request_enq(&assoc->outgoing, req);
1185 /* turn the work over to the ir_session handler */
1186 iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
1187 assoc->cs_put_mask = EVENT_OUTPUT;
1188 /* Is there more work to be done? give that to the input handler too */
1190 if (request_head(&assoc->incoming))
1192 yaz_log (LOG_DEBUG, "more work to be done");
1193 iochan_setevent(assoc->client_chan, EVENT_WORK);
1200 * Encode response, and transfer the request structure to the outgoing queue.
1202 static int process_z_response(association *assoc, request *req, Z_APDU *res)
1204 Z_GDU *gres = (Z_GDU *) odr_malloc(assoc->encode, sizeof(*res));
1205 gres->which = Z_GDU_Z3950;
1206 gres->u.z3950 = res;
1208 return process_gdu_response(assoc, req, gres);
1213 * Handle init request.
1214 * At the moment, we don't check the options
1215 * anywhere else in the code - we just try not to do anything that would
1216 * break a naive client. We'll toss 'em into the association block when
1217 * we need them there.
1219 static Z_APDU *process_initRequest(association *assoc, request *reqb)
1221 statserv_options_block *cb = statserv_getcontrol();
1222 Z_InitRequest *req = reqb->apdu_request->u.initRequest;
1223 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
1224 Z_InitResponse *resp = apdu->u.initResponse;
1225 bend_initresult *binitres;
1229 yaz_log(LOG_LOG, "Got initRequest");
1230 if (req->implementationId)
1231 yaz_log(LOG_LOG, "Id: %s", req->implementationId);
1232 if (req->implementationName)
1233 yaz_log(LOG_LOG, "Name: %s", req->implementationName);
1234 if (req->implementationVersion)
1235 yaz_log(LOG_LOG, "Version: %s", req->implementationVersion);
1237 assoc_init_reset(assoc);
1239 assoc->init->auth = req->idAuthentication;
1240 assoc->init->referenceId = req->referenceId;
1242 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel))
1244 Z_CharSetandLanguageNegotiation *negotiation =
1245 yaz_get_charneg_record (req->otherInfo);
1247 negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
1248 assoc->init->charneg_request = negotiation;
1252 if (!(binitres = (*cb->bend_init)(assoc->init)))
1254 yaz_log(LOG_WARN, "Bad response from backend.");
1258 assoc->backend = binitres->handle;
1259 if ((assoc->init->bend_sort))
1260 yaz_log (LOG_DEBUG, "Sort handler installed");
1261 if ((assoc->init->bend_search))
1262 yaz_log (LOG_DEBUG, "Search handler installed");
1263 if ((assoc->init->bend_present))
1264 yaz_log (LOG_DEBUG, "Present handler installed");
1265 if ((assoc->init->bend_esrequest))
1266 yaz_log (LOG_DEBUG, "ESRequest handler installed");
1267 if ((assoc->init->bend_delete))
1268 yaz_log (LOG_DEBUG, "Delete handler installed");
1269 if ((assoc->init->bend_scan))
1270 yaz_log (LOG_DEBUG, "Scan handler installed");
1271 if ((assoc->init->bend_segment))
1272 yaz_log (LOG_DEBUG, "Segment handler installed");
1274 resp->referenceId = req->referenceId;
1276 /* let's tell the client what we can do */
1277 if (ODR_MASK_GET(req->options, Z_Options_search))
1279 ODR_MASK_SET(resp->options, Z_Options_search);
1280 strcat(options, "srch");
1282 if (ODR_MASK_GET(req->options, Z_Options_present))
1284 ODR_MASK_SET(resp->options, Z_Options_present);
1285 strcat(options, " prst");
1287 if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
1288 assoc->init->bend_delete)
1290 ODR_MASK_SET(resp->options, Z_Options_delSet);
1291 strcat(options, " del");
1293 if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
1294 assoc->init->bend_esrequest)
1296 ODR_MASK_SET(resp->options, Z_Options_extendedServices);
1297 strcat (options, " extendedServices");
1299 if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
1301 ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
1302 strcat(options, " namedresults");
1304 if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
1306 ODR_MASK_SET(resp->options, Z_Options_scan);
1307 strcat(options, " scan");
1309 if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
1311 ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
1312 strcat(options, " concurrop");
1314 if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
1316 ODR_MASK_SET(resp->options, Z_Options_sort);
1317 strcat(options, " sort");
1320 if (ODR_MASK_GET(req->options, Z_Options_negotiationModel)
1321 && assoc->init->charneg_response)
1323 Z_OtherInformation **p;
1324 Z_OtherInformationUnit *p0;
1326 yaz_oi_APDU(apdu, &p);
1328 if ((p0=yaz_oi_update(p, assoc->encode, NULL, 0, 0))) {
1329 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1331 p0->which = Z_OtherInfo_externallyDefinedInfo;
1332 p0->information.externallyDefinedInfo =
1333 assoc->init->charneg_response;
1335 ODR_MASK_SET(resp->options, Z_Options_negotiationModel);
1336 strcat(options, " negotiation");
1339 ODR_MASK_SET(resp->options, Z_Options_triggerResourceCtrl);
1341 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
1343 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
1344 assoc->version = 1; /* 1 & 2 are equivalent */
1346 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
1348 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
1351 if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
1353 ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
1357 yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
1358 assoc->maximumRecordSize = *req->maximumRecordSize;
1359 if (assoc->maximumRecordSize > control_block->maxrecordsize)
1360 assoc->maximumRecordSize = control_block->maxrecordsize;
1361 assoc->preferredMessageSize = *req->preferredMessageSize;
1362 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
1363 assoc->preferredMessageSize = assoc->maximumRecordSize;
1365 resp->preferredMessageSize = &assoc->preferredMessageSize;
1366 resp->maximumRecordSize = &assoc->maximumRecordSize;
1368 resp->implementationId = odr_prepend(assoc->encode,
1369 assoc->init->implementation_id,
1370 resp->implementationId);
1372 resp->implementationName = odr_prepend(assoc->encode,
1373 assoc->init->implementation_name,
1374 odr_prepend(assoc->encode, "GFS", resp->implementationName));
1376 version = odr_strdup(assoc->encode, "$Revision: 1.33 $");
1377 if (strlen(version) > 10) /* check for unexpanded CVS strings */
1378 version[strlen(version)-2] = '\0';
1379 resp->implementationVersion = odr_prepend(assoc->encode,
1380 assoc->init->implementation_version,
1381 odr_prepend(assoc->encode, &version[11],
1382 resp->implementationVersion));
1384 if (binitres->errcode)
1386 yaz_log(LOG_LOG, "Connection rejected by backend.");
1388 assoc->state = ASSOC_DEAD;
1389 resp->userInformationField = init_diagnostics(assoc->encode,
1391 binitres->errstring);
1394 assoc->state = ASSOC_UP;
1399 * Diagnostic in default format, to be returned as either a surrogate
1400 * or non-surrogate diagnostic in the context of an open session, or
1401 * as User-information when an Init is refused.
1403 static Z_DefaultDiagFormat *justdiag(ODR odr, int error, char *addinfo)
1405 int *err = odr_intdup(odr, error);
1406 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1407 odr_malloc (odr, sizeof(*dr));
1409 yaz_log(LOG_LOG, "[%d] %s%s%s", error, diagbib1_str(error),
1410 addinfo ? " -- " : "", addinfo ? addinfo : "");
1412 dr->diagnosticSetId =
1413 yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
1414 dr->condition = err;
1415 dr->which = Z_DefaultDiagFormat_v2Addinfo;
1416 dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
1421 * Set the specified `errcode' and `errstring' into a UserInfo-1
1422 * external to be returned to the client in accordance with Z35.90
1423 * Implementor Agreement 5 (Returning diagnostics in an InitResponse):
1424 * http://lcweb.loc.gov/z3950/agency/agree/initdiag.html
1426 static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
1430 Z_OtherInformation *u;
1431 Z_OtherInformationUnit *l;
1432 Z_DiagnosticFormat *d;
1433 Z_DiagnosticFormat_s *e;
1435 x = (Z_External*) odr_malloc(odr, sizeof *x);
1437 x->indirect_reference = 0;
1438 oid.proto = PROTO_Z3950;
1439 oid.oclass = CLASS_USERINFO;
1440 oid.value = VAL_USERINFO1;
1441 x->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1442 x->which = Z_External_userInfo1;
1444 u = odr_malloc(odr, sizeof *u);
1446 u->num_elements = 1;
1447 u->list = (Z_OtherInformationUnit**) odr_malloc(odr, sizeof *u->list);
1448 u->list[0] = (Z_OtherInformationUnit*) odr_malloc(odr, sizeof *u->list[0]);
1451 l->which = Z_OtherInfo_externallyDefinedInfo;
1453 x2 = (Z_External*) odr_malloc(odr, sizeof *x);
1454 l->information.externallyDefinedInfo = x2;
1456 x2->indirect_reference = 0;
1457 oid.oclass = CLASS_DIAGSET;
1458 oid.value = VAL_DIAG1;
1459 x2->direct_reference = odr_oiddup(odr, oid_getoidbyent(&oid));
1460 x2->which = Z_External_diag1;
1462 d = (Z_DiagnosticFormat*) odr_malloc(odr, sizeof *d);
1465 d->elements = (Z_DiagnosticFormat_s**) odr_malloc (odr, sizeof *d->elements);
1466 d->elements[0] = (Z_DiagnosticFormat_s*) odr_malloc (odr, sizeof *d->elements[0]);
1469 e->which = Z_DiagnosticFormat_s_defaultDiagRec;
1470 e->u.defaultDiagRec = justdiag(odr, error, addinfo);
1476 * nonsurrogate diagnostic record.
1478 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1480 Z_Records *rec = (Z_Records *)
1481 odr_malloc (assoc->encode, sizeof(*rec));
1482 rec->which = Z_Records_NSD;
1483 rec->u.nonSurrogateDiagnostic = justdiag(assoc->encode, error, addinfo);
1488 * surrogate diagnostic.
1490 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1491 int error, char *addinfo)
1493 Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1494 odr_malloc (assoc->encode, sizeof(*rec));
1495 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1497 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1498 rec->databaseName = dbname;
1499 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1500 rec->u.surrogateDiagnostic = drec;
1501 drec->which = Z_DiagRec_defaultFormat;
1502 drec->u.defaultFormat = justdiag(assoc->encode, error, addinfo);
1508 * multiple nonsurrogate diagnostics.
1510 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1512 Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1513 int *err = odr_intdup(assoc->encode, error);
1514 Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1515 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1516 Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)
1517 odr_malloc (assoc->encode, sizeof(*rec));
1519 yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1521 recs->num_diagRecs = 1;
1522 recs->diagRecs = recp;
1524 drec->which = Z_DiagRec_defaultFormat;
1525 drec->u.defaultFormat = rec;
1527 rec->diagnosticSetId =
1528 yaz_oidval_to_z3950oid (assoc->encode, CLASS_DIAGSET, VAL_BIB1);
1529 rec->condition = err;
1531 rec->which = Z_DefaultDiagFormat_v2Addinfo;
1532 rec->u.v2Addinfo = odr_strdup (assoc->encode, addinfo ? addinfo : "");
1536 static Z_Records *pack_records(association *a, char *setname, int start,
1537 int *num, Z_RecordComposition *comp,
1538 int *next, int *pres, oid_value format,
1539 Z_ReferenceId *referenceId,
1542 int recno, total_length = 0, toget = *num, dumped_records = 0;
1543 Z_Records *records =
1544 (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1545 Z_NamePlusRecordList *reclist =
1546 (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1547 Z_NamePlusRecord **list =
1548 (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1550 records->which = Z_Records_DBOSD;
1551 records->u.databaseOrSurDiagnostics = reclist;
1552 reclist->num_records = 0;
1553 reclist->records = list;
1554 *pres = Z_PresentStatus_success;
1558 yaz_log(LOG_LOG, "Request to pack %d+%d+%s", start, toget, setname);
1559 yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1560 a->maximumRecordSize);
1561 for (recno = start; reclist->num_records < toget; recno++)
1564 Z_NamePlusRecord *thisrec;
1565 int this_length = 0;
1567 * we get the number of bytes allocated on the stream before any
1568 * allocation done by the backend - this should give us a reasonable
1569 * idea of the total size of the data so far.
1571 total_length = odr_total(a->encode) - dumped_records;
1577 freq.last_in_set = 0;
1578 freq.setname = setname;
1579 freq.surrogate_flag = 0;
1580 freq.number = recno;
1582 freq.request_format = format;
1583 freq.request_format_raw = oid;
1584 freq.output_format = format;
1585 freq.output_format_raw = 0;
1586 freq.stream = a->encode;
1587 freq.print = a->print;
1588 freq.referenceId = referenceId;
1590 (*a->init->bend_fetch)(a->backend, &freq);
1591 /* backend should be able to signal whether error is system-wide
1592 or only pertaining to current record */
1595 if (!freq.surrogate_flag)
1598 *pres = Z_PresentStatus_failure;
1599 /* for 'present request out of range',
1600 set addinfo to record position if not set */
1601 if (freq.errcode == 13 && freq.errstring == 0)
1603 sprintf (s, "%d", recno);
1606 return diagrec(a, freq.errcode, freq.errstring);
1608 reclist->records[reclist->num_records] =
1609 surrogatediagrec(a, freq.basename, freq.errcode,
1611 reclist->num_records++;
1612 *next = freq.last_in_set ? 0 : recno + 1;
1616 this_length = freq.len;
1618 this_length = odr_total(a->encode) - total_length - dumped_records;
1619 yaz_log(LOG_DEBUG, " fetched record, len=%d, total=%d dumped=%d",
1620 this_length, total_length, dumped_records);
1621 if (a->preferredMessageSize > 0 &&
1622 this_length + total_length > a->preferredMessageSize)
1624 /* record is small enough, really */
1625 if (this_length <= a->preferredMessageSize && recno > start)
1627 yaz_log(LOG_DEBUG, " Dropped last normal-sized record");
1628 *pres = Z_PresentStatus_partial_2;
1631 /* record can only be fetched by itself */
1632 if (this_length < a->maximumRecordSize)
1634 yaz_log(LOG_DEBUG, " Record > prefmsgsz");
1637 yaz_log(LOG_DEBUG, " Dropped it");
1638 reclist->records[reclist->num_records] =
1639 surrogatediagrec(a, freq.basename, 16, 0);
1640 reclist->num_records++;
1641 *next = freq.last_in_set ? 0 : recno + 1;
1642 dumped_records += this_length;
1646 else /* too big entirely */
1648 yaz_log(LOG_LOG, "Record > maxrcdsz this=%d max=%d", this_length, a->maximumRecordSize);
1649 reclist->records[reclist->num_records] =
1650 surrogatediagrec(a, freq.basename, 17, 0);
1651 reclist->num_records++;
1652 *next = freq.last_in_set ? 0 : recno + 1;
1653 dumped_records += this_length;
1658 if (!(thisrec = (Z_NamePlusRecord *)
1659 odr_malloc(a->encode, sizeof(*thisrec))))
1661 if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1662 strlen(freq.basename) + 1)))
1664 strcpy(thisrec->databaseName, freq.basename);
1665 thisrec->which = Z_NamePlusRecord_databaseRecord;
1667 if (freq.output_format_raw)
1669 struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1670 freq.output_format = ident->value;
1672 thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1673 freq.record, freq.len);
1674 if (!thisrec->u.databaseRecord)
1676 reclist->records[reclist->num_records] = thisrec;
1677 reclist->num_records++;
1678 *next = freq.last_in_set ? 0 : recno + 1;
1680 *num = reclist->num_records;
1684 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1687 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1688 bend_search_rr *bsrr =
1689 (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1691 yaz_log(LOG_LOG, "Got SearchRequest.");
1693 bsrr->request = reqb;
1694 bsrr->association = assoc;
1695 bsrr->referenceId = req->referenceId;
1696 save_referenceId (reqb, bsrr->referenceId);
1698 yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1699 if (req->databaseNames)
1702 for (i = 0; i < req->num_databaseNames; i++)
1703 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1705 yaz_log_zquery(req->query);
1707 if (assoc->init->bend_search)
1709 bsrr->setname = req->resultSetName;
1710 bsrr->replace_set = *req->replaceIndicator;
1711 bsrr->num_bases = req->num_databaseNames;
1712 bsrr->basenames = req->databaseNames;
1713 bsrr->query = req->query;
1714 bsrr->stream = assoc->encode;
1715 nmem_transfer(bsrr->stream->mem, reqb->request_mem);
1716 bsrr->decode = assoc->decode;
1717 bsrr->print = assoc->print;
1720 bsrr->errstring = NULL;
1721 bsrr->search_info = NULL;
1722 (assoc->init->bend_search)(assoc->backend, bsrr);
1726 return response_searchRequest(assoc, reqb, bsrr, fd);
1729 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1732 * Prepare a searchresponse based on the backend results. We probably want
1733 * to look at making the fetching of records nonblocking as well, but
1734 * so far, we'll keep things simple.
1735 * If bsrt is null, that means we're called in response to a communications
1736 * event, and we'll have to get the response for ourselves.
1738 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1739 bend_search_rr *bsrt, int *fd)
1741 Z_SearchRequest *req = reqb->apdu_request->u.searchRequest;
1742 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1743 Z_SearchResponse *resp = (Z_SearchResponse *)
1744 odr_malloc (assoc->encode, sizeof(*resp));
1745 int *nulint = odr_intdup (assoc->encode, 0);
1746 bool_t *sr = odr_intdup(assoc->encode, 1);
1747 int *next = odr_intdup(assoc->encode, 0);
1748 int *none = odr_intdup(assoc->encode, Z_SearchResponse_none);
1750 apdu->which = Z_APDU_searchResponse;
1751 apdu->u.searchResponse = resp;
1752 resp->referenceId = req->referenceId;
1753 resp->additionalSearchInfo = 0;
1754 resp->otherInfo = 0;
1756 if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1758 yaz_log(LOG_FATAL, "Bad result from backend");
1761 else if (bsrt->errcode)
1763 resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1764 resp->resultCount = nulint;
1765 resp->numberOfRecordsReturned = nulint;
1766 resp->nextResultSetPosition = nulint;
1767 resp->searchStatus = nulint;
1768 resp->resultSetStatus = none;
1769 resp->presentStatus = 0;
1773 int *toget = odr_intdup(assoc->encode, 0);
1774 int *presst = odr_intdup(assoc->encode, 0);
1775 Z_RecordComposition comp, *compp = 0;
1777 yaz_log (LOG_LOG, "resultCount: %d", bsrt->hits);
1780 resp->resultCount = &bsrt->hits;
1782 comp.which = Z_RecordComp_simple;
1783 /* how many records does the user agent want, then? */
1784 if (bsrt->hits <= *req->smallSetUpperBound)
1786 *toget = bsrt->hits;
1787 if ((comp.u.simple = req->smallSetElementSetNames))
1790 else if (bsrt->hits < *req->largeSetLowerBound)
1792 *toget = *req->mediumSetPresentNumber;
1793 if (*toget > bsrt->hits)
1794 *toget = bsrt->hits;
1795 if ((comp.u.simple = req->mediumSetElementSetNames))
1801 if (*toget && !resp->records)
1806 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1809 form = prefformat->value;
1810 resp->records = pack_records(assoc, req->resultSetName, 1,
1811 toget, compp, next, presst, form, req->referenceId,
1812 req->preferredRecordSyntax);
1815 resp->numberOfRecordsReturned = toget;
1816 resp->nextResultSetPosition = next;
1817 resp->searchStatus = sr;
1818 resp->resultSetStatus = 0;
1819 resp->presentStatus = presst;
1823 if (*resp->resultCount)
1825 resp->numberOfRecordsReturned = nulint;
1826 resp->nextResultSetPosition = next;
1827 resp->searchStatus = sr;
1828 resp->resultSetStatus = 0;
1829 resp->presentStatus = 0;
1832 resp->additionalSearchInfo = bsrt->search_info;
1837 * Maybe we got a little over-friendly when we designed bend_fetch to
1838 * get only one record at a time. Some backends can optimise multiple-record
1839 * fetches, and at any rate, there is some overhead involved in
1840 * all that selecting and hopping around. Problem is, of course, that the
1841 * frontend can't know ahead of time how many records it'll need to
1842 * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1843 * is downright lousy as a bulk data transfer protocol.
1845 * To start with, we'll do the fetching of records from the backend
1846 * in one operation: To save some trips in and out of the event-handler,
1847 * and to simplify the interface to pack_records. At any rate, asynch
1848 * operation is more fun in operations that have an unpredictable execution
1849 * speed - which is normally more true for search than for present.
1851 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1854 Z_PresentRequest *req = reqb->apdu_request->u.presentRequest;
1858 Z_PresentResponse *resp;
1862 yaz_log(LOG_LOG, "Got PresentRequest.");
1864 if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)))
1867 form = prefformat->value;
1868 resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1870 resp->presentStatus = odr_intdup(assoc->encode, 0);
1871 if (assoc->init->bend_present)
1873 bend_present_rr *bprr = (bend_present_rr *)
1874 nmem_malloc (reqb->request_mem, sizeof(*bprr));
1875 bprr->setname = req->resultSetId;
1876 bprr->start = *req->resultSetStartPoint;
1877 bprr->number = *req->numberOfRecordsRequested;
1878 bprr->format = form;
1879 bprr->comp = req->recordComposition;
1880 bprr->referenceId = req->referenceId;
1881 bprr->stream = assoc->encode;
1882 bprr->print = assoc->print;
1883 bprr->request = reqb;
1884 bprr->association = assoc;
1886 bprr->errstring = NULL;
1887 (*assoc->init->bend_present)(assoc->backend, bprr);
1893 resp->records = diagrec(assoc, bprr->errcode, bprr->errstring);
1894 *resp->presentStatus = Z_PresentStatus_failure;
1897 apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1898 next = odr_intdup(assoc->encode, 0);
1899 num = odr_intdup(assoc->encode, 0);
1901 apdu->which = Z_APDU_presentResponse;
1902 apdu->u.presentResponse = resp;
1903 resp->referenceId = req->referenceId;
1904 resp->otherInfo = 0;
1908 *num = *req->numberOfRecordsRequested;
1910 pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1911 num, req->recordComposition, next, resp->presentStatus,
1912 form, req->referenceId, req->preferredRecordSyntax);
1916 resp->numberOfRecordsReturned = num;
1917 resp->nextResultSetPosition = next;
1923 * Scan was implemented rather in a hurry, and with support for only the basic
1924 * elements of the service in the backend API. Suggestions are welcome.
1926 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1928 Z_ScanRequest *req = reqb->apdu_request->u.scanRequest;
1929 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1930 Z_ScanResponse *res = (Z_ScanResponse *)
1931 odr_malloc (assoc->encode, sizeof(*res));
1932 int *scanStatus = odr_intdup(assoc->encode, Z_Scan_failure);
1933 int *numberOfEntriesReturned = odr_intdup(assoc->encode, 0);
1934 Z_ListEntries *ents = (Z_ListEntries *)
1935 odr_malloc (assoc->encode, sizeof(*ents));
1936 Z_DiagRecs *diagrecs_p = NULL;
1938 bend_scan_rr *bsrr = (bend_scan_rr *)
1939 odr_malloc (assoc->encode, sizeof(*bsrr));
1940 struct scan_entry *save_entries;
1942 yaz_log(LOG_LOG, "Got ScanRequest");
1944 apdu->which = Z_APDU_scanResponse;
1945 apdu->u.scanResponse = res;
1946 res->referenceId = req->referenceId;
1948 /* if step is absent, set it to 0 */
1949 res->stepSize = odr_intdup(assoc->encode, 0);
1951 *res->stepSize = *req->stepSize;
1953 res->scanStatus = scanStatus;
1954 res->numberOfEntriesReturned = numberOfEntriesReturned;
1955 res->positionOfTerm = 0;
1956 res->entries = ents;
1957 ents->num_entries = 0;
1958 ents->entries = NULL;
1959 ents->num_nonsurrogateDiagnostics = 0;
1960 ents->nonsurrogateDiagnostics = NULL;
1961 res->attributeSet = 0;
1964 if (req->databaseNames)
1967 for (i = 0; i < req->num_databaseNames; i++)
1968 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1970 bsrr->num_bases = req->num_databaseNames;
1971 bsrr->basenames = req->databaseNames;
1972 bsrr->num_entries = *req->numberOfTermsRequested;
1973 bsrr->term = req->termListAndStartPoint;
1974 bsrr->referenceId = req->referenceId;
1975 bsrr->stream = assoc->encode;
1976 bsrr->print = assoc->print;
1977 bsrr->step_size = res->stepSize;
1979 /* Note that version 2.0 of YAZ and older did not set entries ..
1980 We do now. And when we do it's easier to extend the scan entry
1981 We know that if the scan handler did set entries, it will
1982 not know of new member display_term.
1984 if (bsrr->num_entries > 0)
1987 bsrr->entries = odr_malloc(assoc->decode, sizeof(*bsrr->entries) *
1989 for (i = 0; i<bsrr->num_entries; i++)
1991 bsrr->entries[i].term = 0;
1992 bsrr->entries[i].occurrences = 0;
1993 bsrr->entries[i].errcode = 0;
1994 bsrr->entries[i].errstring = 0;
1995 bsrr->entries[i].display_term = 0;
1998 save_entries = bsrr->entries; /* save it so we can compare later */
2000 if (req->attributeSet &&
2001 (attset = oid_getentbyoid(req->attributeSet)) &&
2002 (attset->oclass == CLASS_ATTSET || attset->oclass == CLASS_GENERAL))
2003 bsrr->attributeset = attset->value;
2005 bsrr->attributeset = VAL_NONE;
2006 log_scan_term (req->termListAndStartPoint, bsrr->attributeset);
2007 bsrr->term_position = req->preferredPositionInResponse ?
2008 *req->preferredPositionInResponse : 1;
2009 ((int (*)(void *, bend_scan_rr *))
2010 (*assoc->init->bend_scan))(assoc->backend, bsrr);
2012 diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
2016 Z_Entry **tab = (Z_Entry **)
2017 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
2019 if (bsrr->status == BEND_SCAN_PARTIAL)
2020 *scanStatus = Z_Scan_partial_5;
2022 *scanStatus = Z_Scan_success;
2023 ents->entries = tab;
2024 ents->num_entries = bsrr->num_entries;
2025 res->numberOfEntriesReturned = &ents->num_entries;
2026 res->positionOfTerm = &bsrr->term_position;
2027 for (i = 0; i < bsrr->num_entries; i++)
2033 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
2034 if (bsrr->entries[i].occurrences >= 0)
2036 e->which = Z_Entry_termInfo;
2037 e->u.termInfo = t = (Z_TermInfo *)
2038 odr_malloc(assoc->encode, sizeof(*t));
2039 t->suggestedAttributes = 0;
2041 if (save_entries == bsrr->entries &&
2042 bsrr->entries[i].display_term)
2044 /* the entries was NOT set by the handler. So it's
2045 safe to test for new member display_term. It is
2048 t->displayTerm = odr_strdup(assoc->encode,
2049 bsrr->entries[i].display_term);
2051 t->alternativeTerm = 0;
2052 t->byAttributes = 0;
2053 t->otherTermInfo = 0;
2054 t->globalOccurrences = &bsrr->entries[i].occurrences;
2055 t->term = (Z_Term *)
2056 odr_malloc(assoc->encode, sizeof(*t->term));
2057 t->term->which = Z_Term_general;
2058 t->term->u.general = o =
2059 (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
2060 o->buf = (unsigned char *)
2061 odr_malloc(assoc->encode, o->len = o->size =
2062 strlen(bsrr->entries[i].term));
2063 memcpy(o->buf, bsrr->entries[i].term, o->len);
2064 yaz_log(LOG_DEBUG, " term #%d: '%s' (%d)", i,
2065 bsrr->entries[i].term, bsrr->entries[i].occurrences);
2069 Z_DiagRecs *drecs = diagrecs (assoc,
2070 bsrr->entries[i].errcode,
2071 bsrr->entries[i].errstring);
2072 assert (drecs->num_diagRecs == 1);
2073 e->which = Z_Entry_surrogateDiagnostic;
2074 assert (drecs->diagRecs[0]);
2075 e->u.surrogateDiagnostic = drecs->diagRecs[0];
2081 ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
2082 ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
2087 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
2090 Z_SortRequest *req = reqb->apdu_request->u.sortRequest;
2091 Z_SortResponse *res = (Z_SortResponse *)
2092 odr_malloc (assoc->encode, sizeof(*res));
2093 bend_sort_rr *bsrr = (bend_sort_rr *)
2094 odr_malloc (assoc->encode, sizeof(*bsrr));
2096 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2098 yaz_log(LOG_LOG, "Got SortRequest.");
2100 bsrr->num_input_setnames = req->num_inputResultSetNames;
2101 bsrr->input_setnames = req->inputResultSetNames;
2102 bsrr->referenceId = req->referenceId;
2103 bsrr->output_setname = req->sortedResultSetName;
2104 bsrr->sort_sequence = req->sortSequence;
2105 bsrr->stream = assoc->encode;
2106 bsrr->print = assoc->print;
2108 bsrr->sort_status = Z_SortResponse_failure;
2110 bsrr->errstring = 0;
2112 (*assoc->init->bend_sort)(assoc->backend, bsrr);
2114 res->referenceId = bsrr->referenceId;
2115 res->sortStatus = odr_intdup(assoc->encode, bsrr->sort_status);
2116 res->resultSetStatus = 0;
2119 Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
2120 res->diagnostics = dr->diagRecs;
2121 res->num_diagnostics = dr->num_diagRecs;
2125 res->num_diagnostics = 0;
2126 res->diagnostics = 0;
2128 res->resultCount = 0;
2131 apdu->which = Z_APDU_sortResponse;
2132 apdu->u.sortResponse = res;
2136 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
2139 Z_DeleteResultSetRequest *req =
2140 reqb->apdu_request->u.deleteResultSetRequest;
2141 Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
2142 odr_malloc (assoc->encode, sizeof(*res));
2143 bend_delete_rr *bdrr = (bend_delete_rr *)
2144 odr_malloc (assoc->encode, sizeof(*bdrr));
2145 Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
2147 yaz_log(LOG_LOG, "Got DeleteRequest.");
2149 bdrr->num_setnames = req->num_resultSetList;
2150 bdrr->setnames = req->resultSetList;
2151 bdrr->stream = assoc->encode;
2152 bdrr->print = assoc->print;
2153 bdrr->function = *req->deleteFunction;
2154 bdrr->referenceId = req->referenceId;
2156 if (bdrr->num_setnames > 0)
2159 bdrr->statuses = (int*)
2160 odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
2161 bdrr->num_setnames);
2162 for (i = 0; i < bdrr->num_setnames; i++)
2163 bdrr->statuses[i] = 0;
2165 (*assoc->init->bend_delete)(assoc->backend, bdrr);
2167 res->referenceId = req->referenceId;
2169 res->deleteOperationStatus = odr_intdup(assoc->encode,bdrr->delete_status);
2171 res->deleteListStatuses = 0;
2172 if (bdrr->num_setnames > 0)
2175 res->deleteListStatuses = (Z_ListStatuses *)
2176 odr_malloc(assoc->encode, sizeof(*res->deleteListStatuses));
2177 res->deleteListStatuses->num = bdrr->num_setnames;
2178 res->deleteListStatuses->elements =
2180 odr_malloc (assoc->encode,
2181 sizeof(*res->deleteListStatuses->elements) *
2182 bdrr->num_setnames);
2183 for (i = 0; i<bdrr->num_setnames; i++)
2185 res->deleteListStatuses->elements[i] =
2187 odr_malloc (assoc->encode,
2188 sizeof(**res->deleteListStatuses->elements));
2189 res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
2190 res->deleteListStatuses->elements[i]->id =
2191 odr_strdup (assoc->encode, bdrr->setnames[i]);
2195 res->numberNotDeleted = 0;
2196 res->bulkStatuses = 0;
2197 res->deleteMessage = 0;
2200 apdu->which = Z_APDU_deleteResultSetResponse;
2201 apdu->u.deleteResultSetResponse = res;
2205 static void process_close(association *assoc, request *reqb)
2207 Z_Close *req = reqb->apdu_request->u.close;
2208 static char *reasons[] =
2215 "securityViolation",
2222 yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
2223 reasons[*req->closeReason], req->diagnosticInformation ?
2224 req->diagnosticInformation : "NULL");
2225 if (assoc->version < 3) /* to make do_force respond with close */
2227 do_close_req(assoc, Z_Close_finished,
2228 "Association terminated by client", reqb);
2231 void save_referenceId (request *reqb, Z_ReferenceId *refid)
2235 reqb->len_refid = refid->len;
2236 reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
2237 memcpy (reqb->refid, refid->buf, refid->len);
2241 reqb->len_refid = 0;
2246 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
2248 process_z_response (a, req, res);
2251 bend_request bend_request_mk (bend_association a)
2253 request *nreq = request_get (&a->outgoing);
2254 nreq->request_mem = nmem_create ();
2258 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
2263 id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
2264 id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
2265 id->len = id->size = req->len_refid;
2266 memcpy (id->buf, req->refid, req->len_refid);
2270 void bend_request_destroy (bend_request *req)
2272 nmem_destroy((*req)->request_mem);
2273 request_release(*req);
2277 int bend_backend_respond (bend_association a, bend_request req)
2281 r = process_z_request (a, req, &msg);
2283 yaz_log (LOG_WARN, "%s", msg);
2287 void bend_request_setdata(bend_request r, void *p)
2292 void *bend_request_getdata(bend_request r)
2294 return r->clientData;
2297 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
2299 bend_segment_rr req;
2301 req.segment = reqb->apdu_request->u.segmentRequest;
2302 req.stream = assoc->encode;
2303 req.decode = assoc->decode;
2304 req.print = assoc->print;
2305 req.association = assoc;
2307 (*assoc->init->bend_segment)(assoc->backend, &req);
2312 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
2314 bend_esrequest_rr esrequest;
2316 Z_ExtendedServicesRequest *req =
2317 reqb->apdu_request->u.extendedServicesRequest;
2318 Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
2320 Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
2322 yaz_log(LOG_DEBUG,"inside Process esRequest");
2324 esrequest.esr = reqb->apdu_request->u.extendedServicesRequest;
2325 esrequest.stream = assoc->encode;
2326 esrequest.decode = assoc->decode;
2327 esrequest.print = assoc->print;
2328 esrequest.errcode = 0;
2329 esrequest.errstring = NULL;
2330 esrequest.request = reqb;
2331 esrequest.association = assoc;
2332 esrequest.taskPackage = 0;
2333 esrequest.referenceId = req->referenceId;
2335 (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
2337 /* If the response is being delayed, return NULL */
2338 if (esrequest.request == NULL)
2341 resp->referenceId = req->referenceId;
2343 if (esrequest.errcode == -1)
2345 /* Backend service indicates request will be processed */
2346 yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
2347 *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
2349 else if (esrequest.errcode == 0)
2351 /* Backend service indicates request will be processed */
2352 yaz_log(LOG_DEBUG,"Request could be processed...Done !");
2353 *resp->operationStatus = Z_ExtendedServicesResponse_done;
2357 Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2358 esrequest.errstring);
2360 /* Backend indicates error, request will not be processed */
2361 yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2362 *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2363 resp->num_diagnostics = diagRecs->num_diagRecs;
2364 resp->diagnostics = diagRecs->diagRecs;
2366 /* Do something with the members of bend_extendedservice */
2367 if (esrequest.taskPackage)
2368 resp->taskPackage = z_ext_record (assoc->encode, VAL_EXTENDED,
2369 (const char *) esrequest.taskPackage,
2371 yaz_log(LOG_DEBUG,"Send the result apdu");