Added peer_name member for bend_init handler. Changed the YAZ
[yaz-moved-to-github.git] / server / seshigh.c
1 /*
2  * Copyright (c) 1995-2000, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Log: seshigh.c,v $
6  * Revision 1.109  2000-10-02 11:07:44  adam
7  * Added peer_name member for bend_init handler. Changed the YAZ
8  * client so that tcp: can be avoided in target spec.
9  *
10  * Revision 1.108  2000/09/04 08:58:15  adam
11  * Added prefix yaz_ for most logging utility functions.
12  *
13  * Revision 1.107  2000/08/31 10:20:12  adam
14  * Added member request_format and output_format for backend fetch method.
15  *
16  * Revision 1.106  2000/08/31 09:51:25  adam
17  * Added record_syntax member for fetch method (raw OID).
18  *
19  * Revision 1.105  2000/07/06 10:38:47  adam
20  * Enhanced option --enable-tcpd.
21  *
22  * Revision 1.104  2000/04/05 07:39:55  adam
23  * Added shared library support (libtool).
24  *
25  * Revision 1.103  2000/03/20 19:06:25  adam
26  * Added Segment request for fronend server. Work on admin for client.
27  *
28  * Revision 1.102  2000/03/15 12:59:49  adam
29  * Added handle member to statserv_control.
30  *
31  * Revision 1.101  2000/01/12 14:36:07  adam
32  * Added printing stream (ODR) for backend functions.
33  *
34  * Revision 1.100  1999/12/16 23:36:19  adam
35  * Implemented ILL protocol. Minor updates ASN.1 compiler.
36  *
37  * Revision 1.99  1999/11/30 13:47:12  adam
38  * Improved installation. Moved header files to include/yaz.
39  *
40  * Revision 1.98  1999/11/29 15:12:27  adam
41  * Changed the way implementationName - and version is set.
42  *
43  * Revision 1.96  1999/11/04 14:58:44  adam
44  * Added status elements for backend delete result set handler.
45  * Updated delete result result set command for client.
46  *
47  * Revision 1.95  1999/10/11 10:01:24  adam
48  * Implemented bend_sort_rr handler for frontend server.
49  *
50  * Revision 1.94  1999/08/27 09:40:32  adam
51  * Renamed logf function to yaz_log. Removed VC++ project files.
52  *
53  * Revision 1.93  1999/07/06 12:17:15  adam
54  * Added option -1 that runs server once (for profiling purposes).
55  *
56  * Revision 1.92  1999/06/17 10:54:45  adam
57  * Added facility to specify implementation version - and name
58  * for server.
59  *
60  * Revision 1.91  1999/06/01 14:29:12  adam
61  * Work on Extended Services.
62  *
63  * Revision 1.90  1999/05/27 13:02:20  adam
64  * Assigned OID for old DB Update (VAL_DBUPDATE0).
65  *
66  * Revision 1.89  1999/05/26 15:24:26  adam
67  * Fixed minor bugs regarding DB Update (introduced by previous commit).
68  *
69  * Revision 1.88  1999/04/20 09:56:48  adam
70  * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
71  * Modified all encoders/decoders to reflect this change.
72  *
73  * Revision 1.87  1999/03/31 11:18:25  adam
74  * Implemented odr_strdup. Added Reference ID to backend server API.
75  *
76  * Revision 1.86  1999/02/02 13:57:38  adam
77  * Uses preprocessor define WIN32 instead of WINDOWS to build code
78  * for Microsoft WIN32.
79  *
80  * Revision 1.85  1998/11/17 09:52:59  adam
81  * Fixed minor bug (introduced by previous commit).
82  *
83  * Revision 1.84  1998/11/16 16:02:32  adam
84  * Added loggin utilies, log_rpn_query and log_scan_term. These used
85  * to be part of Zebra.
86  *
87  * Revision 1.83  1998/11/03 10:09:36  adam
88  * Fixed bug regarding YC.
89  *
90  * Revision 1.82  1998/10/20 14:00:30  quinn
91  * Fixed Scan
92  *
93  * Revision 1.81  1998/10/13 16:12:24  adam
94  * Added support for Surrogate Diagnostics for Scan Term entries.
95  *
96  * Revision 1.80  1998/09/02 12:41:53  adam
97  * Added decode stream in bend search structures.
98  *
99  * Revision 1.79  1998/08/19 16:10:08  adam
100  * Changed som member names of DeleteResultSetRequest/Response.
101  *
102  * Revision 1.78  1998/08/03 10:23:55  adam
103  * Fixed bug regarding Options for Sort.
104  *
105  * Revision 1.77  1998/07/20 12:38:42  adam
106  * Implemented delete result set service to server API.
107  *
108  * Revision 1.76  1998/05/27 16:57:07  adam
109  * Support for surrogate diagnostic records added for bend_fetch.
110  *
111  * Revision 1.75  1998/05/18 10:13:07  adam
112  * Fixed call to es_request handler - extra argument was passed.
113  *
114  * Revision 1.74  1998/03/31 15:13:20  adam
115  * Development towards compiled ASN.1.
116  *
117  * Revision 1.73  1998/03/31 11:07:45  adam
118  * Furhter work on UNIverse resource report.
119  * Added Extended Services handling in frontend server.
120  *
121  * Revision 1.72  1998/02/11 11:53:35  adam
122  * Changed code so that it compiles as C++.
123  *
124  * Revision 1.71  1998/02/10 11:03:57  adam
125  * Added support for extended handlers in backend server interface.
126  *
127  * Revision 1.70  1998/01/29 13:15:35  adam
128  * Implemented sort for the backend interface.
129  *
130  * Revision 1.69  1997/09/30 11:48:12  adam
131  * Fixed bug introduced by previous commit.
132  *
133  * Revision 1.68  1997/09/29 13:18:59  adam
134  * Added function, oid_ent_to_oid, to replace the function
135  * oid_getoidbyent, which is not thread safe.
136  *
137  * Revision 1.67  1997/09/17 12:10:40  adam
138  * YAZ version 1.4.
139  *
140  * Revision 1.66  1997/09/05 15:26:44  adam
141  * Added ODR encode in search and scen bend request structures.
142  * Fixed a few enums that caused trouble with C++.
143  *
144  * Revision 1.65  1997/09/01 08:53:01  adam
145  * New windows NT/95 port using MSV5.0. The test server 'ztest' was
146  * moved a separate directory. MSV5.0 project server.dsp created.
147  * As an option, the server can now operate as an NT service.
148  *
149  * Revision 1.64  1997/04/30 08:52:11  quinn
150  * Null
151  *
152  * Revision 1.63  1996/10/11  11:57:26  quinn
153  * Smallish
154  *
155  * Revision 1.62  1996/07/06  19:58:35  quinn
156  * System headerfiles gathered in yconfig
157  *
158  * Revision 1.61  1996/06/10  08:56:16  quinn
159  * Work on Summary.
160  *
161  * Revision 1.60  1996/05/30  11:03:10  quinn
162  * Fixed NextresultSetPosition bug fixed.
163  *
164  * Revision 1.59  1996/05/14  09:26:46  quinn
165  * Added attribute set to scan backend
166  *
167  * Revision 1.58  1996/02/20  12:53:04  quinn
168  * Chanes to SCAN
169  *
170  * Revision 1.57  1996/01/02  08:57:47  quinn
171  * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
172  *
173  * Revision 1.56  1995/12/14  11:09:57  quinn
174  * Work on Explain
175  *
176  * Revision 1.55  1995/11/08  17:41:37  quinn
177  * Smallish.
178  *
179  * Revision 1.54  1995/11/08  15:11:29  quinn
180  * Log of close transmit.
181  *
182  * Revision 1.53  1995/11/01  13:54:58  quinn
183  * Minor adjustments
184  *
185  * Revision 1.52  1995/11/01  12:19:13  quinn
186  * Second attempt to fix same bug.
187  *
188  * Revision 1.50  1995/10/25  16:58:32  quinn
189  * Simple.
190  *
191  * Revision 1.49  1995/10/16  13:51:53  quinn
192  * Changes to provide Especs to the backend.
193  *
194  * Revision 1.48  1995/10/06  08:51:20  quinn
195  * Added Write-buffer.
196  *
197  * Revision 1.47  1995/08/29  14:24:16  quinn
198  * Added second half of close-handshake
199  *
200  * Revision 1.46  1995/08/29  11:17:58  quinn
201  * Added code to receive close
202  *
203  * Revision 1.45  1995/08/21  09:11:00  quinn
204  * Smallish fixes to suppport new formats.
205  *
206  * Revision 1.44  1995/08/17  12:45:25  quinn
207  * Fixed minor problems with GRS-1. Added support in c&s.
208  *
209  * Revision 1.43  1995/08/15  12:00:31  quinn
210  * Updated External
211  *
212  * Revision 1.42  1995/08/15  11:16:50  quinn
213  *
214  * Revision 1.41  1995/08/02  10:23:06  quinn
215  * Smallish
216  *
217  * Revision 1.40  1995/07/31  14:34:26  quinn
218  * Fixed bug in process_searchResponse (numberOfRecordsReturned).
219  *
220  * Revision 1.39  1995/06/27  13:21:00  quinn
221  * SUTRS support
222  *
223  * Revision 1.38  1995/06/19  12:39:11  quinn
224  * Fixed bug in timeout code. Added BER dumper.
225  *
226  * Revision 1.37  1995/06/16  13:16:14  quinn
227  * Fixed Defaultdiagformat.
228  *
229  * Revision 1.36  1995/06/16  10:31:36  quinn
230  * Added session timeout.
231  *
232  * Revision 1.35  1995/06/15  07:45:14  quinn
233  * Moving to v3.
234  *
235  * Revision 1.34  1995/06/14  15:26:46  quinn
236  * *** empty log message ***
237  *
238  * Revision 1.33  1995/06/06  14:57:05  quinn
239  * Better diagnostics.
240  *
241  * Revision 1.32  1995/06/06  08:41:44  quinn
242  * Better diagnostics.
243  *
244  * Revision 1.31  1995/06/06  08:15:37  quinn
245  * Cosmetic.
246  *
247  * Revision 1.30  1995/06/05  10:53:32  quinn
248  * Added a better SCAN.
249  *
250  * Revision 1.29  1995/06/01  11:25:03  quinn
251  * Smallish.
252  *
253  * Revision 1.28  1995/06/01  11:21:01  quinn
254  * Attempting to fix a bug in pack-records. replaced break with continue
255  * for large records, according to standard.
256  *
257  * Revision 1.27  1995/05/29  08:12:06  quinn
258  * Moved oid to util
259  *
260  * Revision 1.26  1995/05/18  13:02:12  quinn
261  * Smallish.
262  *
263  * Revision 1.25  1995/05/17  08:42:26  quinn
264  * Transfer auth info to backend. Allow backend to reject init gracefully.
265  *
266  * Revision 1.24  1995/05/16  08:51:04  quinn
267  * License, documentation, and memory fixes
268  *
269  * Revision 1.23  1995/05/15  13:25:10  quinn
270  * Fixed memory bug.
271  *
272  * Revision 1.22  1995/05/15  11:56:39  quinn
273  * Asynchronous facilities. Restructuring of seshigh code.
274  *
275  * Revision 1.21  1995/05/02  08:53:19  quinn
276  * Trying in vain to fix comm with ISODE
277  *
278  * Revision 1.20  1995/04/20  15:13:00  quinn
279  * Cosmetic
280  *
281  * Revision 1.19  1995/04/18  08:15:34  quinn
282  * Added dynamic memory allocation on encoding (whew). Code is now somewhat
283  * neater. We'll make the same change for decoding one day.
284  *
285  * Revision 1.18  1995/04/17  11:28:25  quinn
286  * Smallish
287  *
288  * Revision 1.17  1995/04/10  10:23:36  quinn
289  * Some work to add scan and other things.
290  *
291  * Revision 1.16  1995/03/31  09:18:55  quinn
292  * Added logging.
293  *
294  * Revision 1.15  1995/03/30  14:03:23  quinn
295  * Added RFC1006 as separate library
296  *
297  * Revision 1.14  1995/03/30  12:18:17  quinn
298  * Fixed bug.
299  *
300  * Revision 1.13  1995/03/30  09:09:24  quinn
301  * Added state-handle and some support for asynchronous activities.
302  *
303  * Revision 1.12  1995/03/29  15:40:16  quinn
304  * Ongoing work. Statserv is now dynamic by default
305  *
306  * Revision 1.11  1995/03/28  09:16:21  quinn
307  * Added record packing to the search request
308  *
309  * Revision 1.10  1995/03/27  08:34:24  quinn
310  * Added dynamic server functionality.
311  * Released bindings to session.c (is now redundant)
312  *
313  * Revision 1.9  1995/03/22  15:01:26  quinn
314  * Adjusting record packing.
315  *
316  * Revision 1.8  1995/03/22  10:13:21  quinn
317  * Working on record packer
318  *
319  * Revision 1.7  1995/03/21  15:53:31  quinn
320  * Little changes.
321  *
322  * Revision 1.6  1995/03/21  12:30:09  quinn
323  * Beginning to add support for record packing.
324  *
325  * Revision 1.5  1995/03/17  10:44:13  quinn
326  * Added catch of null-string in makediagrec
327  *
328  * Revision 1.4  1995/03/17  10:18:08  quinn
329  * Added memory management.
330  *
331  * Revision 1.3  1995/03/16  17:42:39  quinn
332  * Little changes
333  *
334  * Revision 1.2  1995/03/16  13:29:01  quinn
335  * Partitioned server.
336  *
337  * Revision 1.1  1995/03/15  16:02:10  quinn
338  * Modded session.c to seshigh.c
339  *
340  */
341
342 /*
343  * Frontend server logic.
344  *
345  * This code receives incoming APDUs, and handles client requests by means
346  * of the backend API.
347  *
348  * Some of the code is getting quite involved, compared to simpler servers -
349  * primarily because it is asynchronous both in the communication with
350  * the user and the backend. We think the complexity will pay off in
351  * the form of greater flexibility when more asynchronous facilities
352  * are implemented.
353  *
354  * Memory management has become somewhat involved. In the simple case, where
355  * only one PDU is pending at a time, it will simply reuse the same memory,
356  * once it has found its working size. When we enable multiple concurrent
357  * operations, perhaps even with multiple parallel calls to the backend, it
358  * will maintain a pool of buffers for encoding and decoding, trying to
359  * minimize memory allocation/deallocation during normal operation.
360  *
361  * TODOs include (and will be done in order of public interest):
362  * 
363  * Support for EXPLAIN - provide simple meta-database system.
364  * Support for access control.
365  * Support for resource control.
366  * Support for extended services - primarily Item Order.
367  * Rest of Z39.50-1994
368  *
369  */
370
371 #include <stdlib.h>
372 #include <stdio.h>
373 #ifdef WIN32
374 #include <process.h>
375 #else
376 #include <unistd.h>
377 #endif
378 #include <assert.h>
379
380 #include <yaz/yconfig.h>
381 #include <yaz/xmalloc.h>
382 #include <yaz/comstack.h>
383 #include "eventl.h"
384 #include "session.h"
385 #include <yaz/proto.h>
386 #include <yaz/oid.h>
387 #include <yaz/log.h>
388 #include <yaz/logrpn.h>
389 #include <yaz/statserv.h>
390
391 #include <yaz/backend.h>
392
393 static int process_request(association *assoc, request *req, char **msg);
394 void backend_response(IOCHAN i, int event);
395 static int process_response(association *assoc, request *req, Z_APDU *res);
396 static Z_APDU *process_initRequest(association *assoc, request *reqb);
397 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
398     int *fd);
399 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
400     bend_search_rr *bsrr, int *fd);
401 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
402     int *fd);
403 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
404 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
405 static void process_close(association *assoc, request *reqb);
406 void save_referenceId (request *reqb, Z_ReferenceId *refid);
407 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
408     int *fd);
409 static Z_APDU *process_segmentRequest (association *assoc, request *reqb);
410
411 static FILE *apduf = 0; /* for use in static mode */
412 static statserv_options_block *control_block = 0;
413
414 /* Chas: Added in from DALI */
415 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
416 /* Chas: End of addition from DALI */
417
418 /*
419  * Create and initialize a new association-handle.
420  *  channel  : iochannel for the current line.
421  *  link     : communications channel.
422  * Returns: 0 or a new association handle.
423  */
424 association *create_association(IOCHAN channel, COMSTACK link)
425 {
426     association *anew;
427
428     if (!control_block)
429         control_block = statserv_getcontrol();
430     if (!(anew = (association *)xmalloc(sizeof(*anew))))
431         return 0;
432     anew->init = 0;
433     anew->client_chan = channel;
434     anew->client_link = link;
435     if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
436         !(anew->encode = odr_createmem(ODR_ENCODE)))
437         return 0;
438     if (*control_block->apdufile)
439     {
440         char filename[256];
441         FILE *f;
442
443         strcpy(filename, control_block->apdufile);
444         if (!(anew->print = odr_createmem(ODR_PRINT)))
445             return 0;
446         if (*control_block->apdufile != '-')
447         {
448             strcpy(filename, control_block->apdufile);
449             if (!control_block->dynamic)
450             {
451                 if (!apduf)
452                 {
453                     if (!(apduf = fopen(filename, "w")))
454                     {
455                         yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
456                         return 0;
457                     }
458                     setvbuf(apduf, 0, _IONBF, 0);
459                 }
460                 f = apduf;
461             }
462             else 
463             {
464                 sprintf(filename + strlen(filename), ".%d", getpid());
465                 if (!(f = fopen(filename, "w")))
466                 {
467                     yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
468                     return 0;
469                 }
470                 setvbuf(f, 0, _IONBF, 0);
471             }
472             odr_setprint(anew->print, f);
473         }
474     }
475     else
476         anew->print = 0;
477     anew->input_buffer = 0;
478     anew->input_buffer_len = 0;
479     anew->backend = 0;
480     anew->state = ASSOC_NEW;
481     request_initq(&anew->incoming);
482     request_initq(&anew->outgoing);
483     anew->proto = cs_getproto(link);
484     return anew;
485 }
486
487 /*
488  * Free association and release resources.
489  */
490 void destroy_association(association *h)
491 {
492     statserv_options_block *cb = statserv_getcontrol();
493
494     xfree(h->init);
495     odr_destroy(h->decode);
496     odr_destroy(h->encode);
497     if (h->print)
498         odr_destroy(h->print);
499     if (h->input_buffer)
500     xfree(h->input_buffer);
501     if (h->backend)
502         (*cb->bend_close)(h->backend);
503     while (request_deq(&h->incoming));
504     while (request_deq(&h->outgoing));
505     request_delq(&h->incoming);
506     request_delq(&h->outgoing);
507     xfree(h);
508     if (control_block && control_block->one_shot)
509         exit (0);
510 }
511
512 static void do_close_req(association *a, int reason, char *message,
513                          request *req)
514 {
515     Z_APDU apdu;
516     Z_Close *cls = zget_Close(a->encode);
517     
518     /* Purge request queue */
519     while (request_deq(&a->incoming));
520     while (request_deq(&a->outgoing));
521     if (a->version >= 3)
522     {
523         yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
524             reason, message ? message : "none");
525         apdu.which = Z_APDU_close;
526         apdu.u.close = cls;
527         *cls->closeReason = reason;
528         cls->diagnosticInformation = message;
529         process_response(a, req, &apdu);
530         iochan_settimeout(a->client_chan, 60);
531     }
532     else
533     {
534         yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
535         iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
536     }
537     a->state = ASSOC_DEAD;
538 }
539
540 static void do_close(association *a, int reason, char *message)
541 {
542     do_close_req (a, reason, message, request_get(&a->outgoing));
543 }
544
545 /*
546  * This is where PDUs from the client are read and the further
547  * processing is initiated. Flow of control moves down through the
548  * various process_* functions below, until the encoded result comes back up
549  * to the output handler in here.
550  * 
551  *  h     : the I/O channel that has an outstanding event.
552  *  event : the current outstanding event.
553  */
554 void ir_session(IOCHAN h, int event)
555 {
556     int res;
557     association *assoc = (association *)iochan_getdata(h);
558     COMSTACK conn = assoc->client_link;
559     request *req;
560
561     assert(h && conn && assoc);
562     if (event == EVENT_TIMEOUT)
563     {
564         if (assoc->state != ASSOC_UP)
565         {
566             yaz_log(LOG_LOG, "Final timeout - closing connection.");
567             cs_close(conn);
568             destroy_association(assoc);
569             iochan_destroy(h);
570         }
571         else
572         {
573             yaz_log(LOG_LOG, "Session idle too long. Sending close.");
574             do_close(assoc, Z_Close_lackOfActivity, 0);
575         }
576         return;
577     }
578     if (event & EVENT_INPUT || event & EVENT_WORK) /* input */
579     {
580         if (event & EVENT_INPUT)
581         {
582             yaz_log(LOG_DEBUG, "ir_session (input)");
583             assert(assoc && conn);
584             /* We aren't speaking to this fellow */
585             if (assoc->state == ASSOC_DEAD)
586             {
587                 yaz_log(LOG_LOG, "Closed connection after reject");
588                 cs_close(conn);
589                 destroy_association(assoc);
590                 iochan_destroy(h);
591                 return;
592             }
593             if ((res = cs_get(conn, &assoc->input_buffer,
594                 &assoc->input_buffer_len)) <= 0)
595             {
596                 yaz_log(LOG_LOG, "Connection closed by client");
597                 cs_close(conn);
598                 destroy_association(assoc);
599                 iochan_destroy(h);
600                 return;
601             }
602             else if (res == 1) /* incomplete read - wait for more  */
603                 return;
604             if (cs_more(conn)) /* more stuff - call us again later, please */
605                 iochan_setevent(h, EVENT_INPUT);
606                 
607             /* we got a complete PDU. Let's decode it */
608             yaz_log(LOG_DEBUG, "Got PDU, %d bytes", res);
609             req = request_get(&assoc->incoming); /* get a new request structure */
610             odr_reset(assoc->decode);
611             odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
612             if (!z_APDU(assoc->decode, &req->request, 0, 0))
613             {
614                 yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ",
615                     odr_errmsg(odr_geterror(assoc->decode)),
616                     odr_offset(assoc->decode));
617                 yaz_log(LOG_LOG, "PDU dump:");
618                 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
619                 do_close(assoc, Z_Close_protocolError, "Malformed package");
620                 return;
621             }
622             req->request_mem = odr_extract_mem(assoc->decode);
623             if (assoc->print && !z_APDU(assoc->print, &req->request, 0, 0))
624             {
625                 yaz_log(LOG_WARN, "ODR print error: %s", 
626                     odr_errmsg(odr_geterror(assoc->print)));
627                 odr_reset(assoc->print);
628             }
629             request_enq(&assoc->incoming, req);
630         }
631
632         /* can we do something yet? */
633         req = request_head(&assoc->incoming);
634         if (req->state == REQUEST_IDLE)
635         {
636             char *msg;
637             request_deq(&assoc->incoming);
638             if (process_request(assoc, req, &msg) < 0)
639                 do_close_req(assoc, Z_Close_systemProblem, msg, req);
640         }
641     }
642     if (event & EVENT_OUTPUT)
643     {
644         request *req = request_head(&assoc->outgoing);
645
646         yaz_log(LOG_DEBUG, "ir_session (output)");
647         req->state = REQUEST_PENDING;
648         switch (res = cs_put(conn, req->response, req->len_response))
649         {
650             case -1:
651                 yaz_log(LOG_LOG, "Connection closed by client");
652                 cs_close(conn);
653                 destroy_association(assoc);
654                 iochan_destroy(h);
655                 break;
656             case 0: /* all sent - release the request structure */
657                 yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
658                 nmem_destroy(req->request_mem);
659                 request_deq(&assoc->outgoing);
660                 request_release(req);
661                 if (!request_head(&assoc->outgoing))
662                     iochan_clearflag(h, EVENT_OUTPUT);
663                 break;
664             /* value of 1 -- partial send -- is simply ignored */
665         }
666     }
667     if (event & EVENT_EXCEPT)
668     {
669         yaz_log(LOG_DEBUG, "ir_session (exception)");
670         cs_close(conn);
671         destroy_association(assoc);
672         iochan_destroy(h);
673     }
674 }
675
676 /*
677  * Initiate request processing.
678  */
679 static int process_request(association *assoc, request *req, char **msg)
680 {
681     int fd = -1;
682     Z_APDU *res;
683     int retval;
684     
685     *msg = "Unknown Error";
686     assert(req && req->state == REQUEST_IDLE);
687     if (req->request->which != Z_APDU_initRequest && !assoc->init)
688     {
689         *msg = "Missing InitRequest";
690         return -1;
691     }
692     switch (req->request->which)
693     {
694     case Z_APDU_initRequest:
695         res = process_initRequest(assoc, req); break;
696     case Z_APDU_searchRequest:
697         res = process_searchRequest(assoc, req, &fd); break;
698     case Z_APDU_presentRequest:
699         res = process_presentRequest(assoc, req, &fd); break;
700     case Z_APDU_scanRequest:
701         if (assoc->init->bend_scan)
702             res = process_scanRequest(assoc, req, &fd);
703         else
704         {
705             *msg = "Cannot handle Scan APDU";
706             return -1;
707         }
708         break;
709     case Z_APDU_extendedServicesRequest:
710         if (assoc->init->bend_esrequest)
711             res = process_ESRequest(assoc, req, &fd);
712         else
713         {
714             *msg = "Cannot handle Extended Services APDU";
715             return -1;
716         }
717         break;
718     case Z_APDU_sortRequest:
719         if (assoc->init->bend_sort)
720             res = process_sortRequest(assoc, req, &fd);
721         else
722         {
723             *msg = "Cannot handle Sort APDU";
724             return -1;
725         }
726         break;
727     case Z_APDU_close:
728         process_close(assoc, req);
729         return 0;
730     case Z_APDU_deleteResultSetRequest:
731         if (assoc->init->bend_delete)
732             res = process_deleteRequest(assoc, req, &fd);
733         else
734         {
735             *msg = "Cannot handle Delete APDU";
736             return -1;
737         }
738         break;
739     case Z_APDU_segmentRequest:
740         if (assoc->init->bend_segment)
741         {
742             res = process_segmentRequest (assoc, req);
743         }
744         else
745         {
746             *msg = "Cannot handle Segment APDU";
747             return -1;
748         }
749         break;
750     default:
751         *msg = "Bad APDU received";
752         return -1;
753     }
754     if (res)
755     {
756         yaz_log(LOG_DEBUG, "  result immediately available");
757         retval = process_response(assoc, req, res);
758     }
759     else if (fd < 0)
760     {
761         yaz_log(LOG_DEBUG, "  result unavailble");
762         retval = 0;
763     }
764     else /* no result yet - one will be provided later */
765     {
766         IOCHAN chan;
767
768         /* Set up an I/O handler for the fd supplied by the backend */
769
770         yaz_log(LOG_DEBUG, "   establishing handler for result");
771         req->state = REQUEST_PENDING;
772         if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
773             abort();
774         iochan_setdata(chan, assoc);
775         retval = 0;
776     }
777     return retval;
778 }
779
780 /*
781  * Handle message from the backend.
782  */
783 void backend_response(IOCHAN i, int event)
784 {
785     association *assoc = (association *)iochan_getdata(i);
786     request *req = request_head(&assoc->incoming);
787     Z_APDU *res;
788     int fd;
789
790     yaz_log(LOG_DEBUG, "backend_response");
791     assert(assoc && req && req->state != REQUEST_IDLE);
792     /* determine what it is we're waiting for */
793     switch (req->request->which)
794     {
795         case Z_APDU_searchRequest:
796             res = response_searchRequest(assoc, req, 0, &fd); break;
797 #if 0
798         case Z_APDU_presentRequest:
799             res = response_presentRequest(assoc, req, 0, &fd); break;
800         case Z_APDU_scanRequest:
801             res = response_scanRequest(assoc, req, 0, &fd); break;
802 #endif
803         default:
804             yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
805             abort();
806     }
807     if ((res && process_response(assoc, req, res) < 0) || fd < 0)
808     {
809         yaz_log(LOG_LOG, "Fatal error when talking to backend");
810         do_close(assoc, Z_Close_systemProblem, 0);
811         iochan_destroy(i);
812         return;
813     }
814     else if (!res) /* no result yet - try again later */
815     {
816         yaz_log(LOG_DEBUG, "   no result yet");
817         iochan_setfd(i, fd); /* in case fd has changed */
818     }
819 }
820
821 /*
822  * Encode response, and transfer the request structure to the outgoing queue.
823  */
824 static int process_response(association *assoc, request *req, Z_APDU *res)
825 {
826     odr_setbuf(assoc->encode, req->response, req->size_response, 1);
827     if (!z_APDU(assoc->encode, &res, 0, 0))
828     {
829         yaz_log(LOG_WARN, "ODR error when encoding response: %s",
830             odr_errmsg(odr_geterror(assoc->decode)));
831         odr_reset(assoc->encode);
832         return -1;
833     }
834     req->response = odr_getbuf(assoc->encode, &req->len_response,
835         &req->size_response);
836     odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
837     if (assoc->print && !z_APDU(assoc->print, &res, 0, 0))
838     {
839         yaz_log(LOG_WARN, "ODR print error: %s", 
840             odr_errmsg(odr_geterror(assoc->print)));
841         odr_reset(assoc->print);
842     }
843     odr_reset(assoc->encode);
844     req->state = REQUEST_IDLE;
845     request_enq(&assoc->outgoing, req);
846     /* turn the work over to the ir_session handler */
847     iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
848     /* Is there more work to be done? give that to the input handler too */
849 #if 1
850     if (request_head(&assoc->incoming))
851     {
852         yaz_log (LOG_DEBUG, "more work to be done");
853         iochan_setevent(assoc->client_chan, EVENT_WORK);
854     }
855 #endif
856     return 0;
857 }
858
859 /*
860  * Handle init request.
861  * At the moment, we don't check the options
862  * anywhere else in the code - we just try not to do anything that would
863  * break a naive client. We'll toss 'em into the association block when
864  * we need them there.
865  */
866 static Z_APDU *process_initRequest(association *assoc, request *reqb)
867 {
868     statserv_options_block *cb = statserv_getcontrol();
869     Z_InitRequest *req = reqb->request->u.initRequest;
870     Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
871     Z_InitResponse *resp = apdu->u.initResponse;
872     bend_initresult *binitres;
873     char options[100];
874
875     xfree (assoc->init);
876     assoc->init = xmalloc (sizeof(*assoc->init));
877
878     yaz_log(LOG_LOG, "Got initRequest");
879     if (req->implementationId)
880         yaz_log(LOG_LOG, "Id:        %s", req->implementationId);
881     if (req->implementationName)
882         yaz_log(LOG_LOG, "Name:      %s", req->implementationName);
883     if (req->implementationVersion)
884         yaz_log(LOG_LOG, "Version:   %s", req->implementationVersion);
885
886     assoc->init->stream = assoc->encode;
887     assoc->init->print = assoc->print;
888     assoc->init->auth = req->idAuthentication;
889     assoc->init->referenceId = req->referenceId;
890     assoc->init->implementation_version = 0;
891     assoc->init->implementation_name = 0;
892     assoc->init->bend_sort = NULL;
893     assoc->init->bend_search = NULL;
894     assoc->init->bend_present = NULL;
895     assoc->init->bend_esrequest = NULL;
896     assoc->init->bend_delete = NULL;
897     assoc->init->bend_scan = NULL;
898     assoc->init->bend_segment = NULL;
899     assoc->init->bend_fetch = NULL;
900     
901     assoc->init->peer_name =
902         odr_strdup (assoc->decode, cs_addrstr(assoc->client_link));
903     if (!(binitres = (*cb->bend_init)(assoc->init)))
904     {
905         yaz_log(LOG_WARN, "Bad response from backend.");
906         return 0;
907     }
908
909     assoc->backend = binitres->handle;
910     if ((assoc->init->bend_sort))
911         yaz_log (LOG_DEBUG, "Sort handler installed");
912     if ((assoc->init->bend_search))
913         yaz_log (LOG_DEBUG, "Search handler installed");
914     if ((assoc->init->bend_present))
915         yaz_log (LOG_DEBUG, "Present handler installed");   
916     if ((assoc->init->bend_esrequest))
917         yaz_log (LOG_DEBUG, "ESRequest handler installed");   
918     if ((assoc->init->bend_delete))
919         yaz_log (LOG_DEBUG, "Delete handler installed");   
920     if ((assoc->init->bend_scan))
921         yaz_log (LOG_DEBUG, "Scan handler installed");   
922     if ((assoc->init->bend_segment))
923         yaz_log (LOG_DEBUG, "Segment handler installed");   
924     
925     resp->referenceId = req->referenceId;
926     *options = '\0';
927     /* let's tell the client what we can do */
928     if (ODR_MASK_GET(req->options, Z_Options_search))
929     {
930         ODR_MASK_SET(resp->options, Z_Options_search);
931         strcat(options, "srch");
932     }
933     if (ODR_MASK_GET(req->options, Z_Options_present))
934     {
935         ODR_MASK_SET(resp->options, Z_Options_present);
936         strcat(options, " prst");
937     }
938     if (ODR_MASK_GET(req->options, Z_Options_delSet) &&
939         assoc->init->bend_delete)
940     {
941         ODR_MASK_SET(resp->options, Z_Options_delSet);
942         strcat(options, " del");
943     }
944     if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
945         assoc->init->bend_esrequest)
946     {
947         ODR_MASK_SET(resp->options, Z_Options_extendedServices);
948         strcat (options, " extendedServices");
949     }
950     if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
951     {
952         ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
953         strcat(options, " namedresults");
954     }
955     if (ODR_MASK_GET(req->options, Z_Options_scan) && assoc->init->bend_scan)
956     {
957         ODR_MASK_SET(resp->options, Z_Options_scan);
958         strcat(options, " scan");
959     }
960     if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
961     {
962         ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
963         strcat(options, " concurop");
964     }
965     if (ODR_MASK_GET(req->options, Z_Options_sort) && assoc->init->bend_sort)
966     {
967         ODR_MASK_SET(resp->options, Z_Options_sort);
968         strcat(options, " sort");
969     }
970     if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
971     {
972         ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
973         assoc->version = 2; /* 1 & 2 are equivalent */
974     }
975     if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
976     {
977         ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
978         assoc->version = 2;
979     }
980     if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
981     {
982         ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
983         assoc->version = 3;
984     }
985     yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
986     assoc->maximumRecordSize = *req->maximumRecordSize;
987     if (assoc->maximumRecordSize > control_block->maxrecordsize)
988         assoc->maximumRecordSize = control_block->maxrecordsize;
989     assoc->preferredMessageSize = *req->preferredMessageSize;
990     if (assoc->preferredMessageSize > assoc->maximumRecordSize)
991         assoc->preferredMessageSize = assoc->maximumRecordSize;
992     resp->preferredMessageSize = &assoc->preferredMessageSize;
993     resp->maximumRecordSize = &assoc->maximumRecordSize;
994
995     resp->implementationName = "GFS";
996
997     if (assoc->init->implementation_name)
998     {
999         char *nv = (char *)
1000             odr_malloc (assoc->encode,
1001                         strlen(assoc->init->implementation_name) + 10 + 
1002                                strlen(resp->implementationName));
1003         sprintf (nv, "%s / %s",
1004                  resp->implementationName, assoc->init->implementation_name);
1005         resp->implementationName = nv;
1006     }
1007     if (assoc->init->implementation_version)
1008     {
1009         char *nv = (char *)
1010             odr_malloc (assoc->encode,
1011                         strlen(assoc->init->implementation_version) + 10 + 
1012                                strlen(resp->implementationVersion));
1013         sprintf (nv, "YAZ %s / %s",
1014                  resp->implementationVersion,
1015                  assoc->init->implementation_version);
1016         resp->implementationVersion = nv;
1017     }
1018
1019     if (binitres->errcode)
1020     {
1021         yaz_log(LOG_LOG, "Connection rejected by backend.");
1022         *resp->result = 0;
1023         assoc->state = ASSOC_DEAD;
1024     }
1025     else
1026         assoc->state = ASSOC_UP;
1027     return apdu;
1028 }
1029
1030 /*
1031  * These functions should be merged.
1032  */
1033
1034 static void set_addinfo (Z_DefaultDiagFormat *dr, char *addinfo)
1035 {
1036 #if ASN_COMPILED
1037     dr->which = Z_DefaultDiagFormat_v2Addinfo;
1038     dr->u.v2Addinfo = addinfo ? addinfo : "";
1039 #else
1040     dr->which = Z_DiagForm_v2AddInfo;
1041     dr->addinfo = addinfo ? addinfo : "";
1042 #endif
1043 }
1044
1045 /*
1046  * nonsurrogate diagnostic record.
1047  */
1048 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
1049 {
1050     int oid[OID_SIZE];
1051     Z_Records *rec = (Z_Records *)
1052         odr_malloc (assoc->encode, sizeof(*rec));
1053     oident bib1;
1054     int *err = (int *)
1055         odr_malloc (assoc->encode, sizeof(*err));
1056     Z_DiagRec *drec = (Z_DiagRec *)
1057         odr_malloc (assoc->encode, sizeof(*drec));
1058     Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1059         odr_malloc (assoc->encode, sizeof(*dr));
1060
1061     bib1.proto = assoc->proto;
1062     bib1.oclass = CLASS_DIAGSET;
1063     bib1.value = VAL_BIB1;
1064
1065     yaz_log(LOG_DEBUG, "Diagnostic: %d -- %s", error, addinfo ? addinfo :
1066         "NULL");
1067     *err = error;
1068     rec->which = Z_Records_NSD;
1069 #if ASN_COMPILED
1070     rec->u.nonSurrogateDiagnostic = dr;
1071 #else
1072     rec->u.nonSurrogateDiagnostic = drec;
1073     drec->which = Z_DiagRec_defaultFormat;
1074     drec->u.defaultFormat = dr;
1075 #endif
1076     dr->diagnosticSetId =
1077         odr_oiddup (assoc->encode, oid_ent_to_oid(&bib1, oid));
1078     dr->condition = err;
1079     set_addinfo (dr, addinfo);
1080     return rec;
1081 }
1082
1083 /*
1084  * surrogate diagnostic.
1085  */
1086 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
1087                                           int error, char *addinfo)
1088 {
1089     int oid[OID_SIZE];
1090     Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
1091         odr_malloc (assoc->encode, sizeof(*rec));
1092     int *err = (int *)odr_malloc (assoc->encode, sizeof(*err));
1093     oident bib1;
1094     Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1095     Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
1096         odr_malloc (assoc->encode, sizeof(*dr));
1097     
1098     bib1.proto = assoc->proto;
1099     bib1.oclass = CLASS_DIAGSET;
1100     bib1.value = VAL_BIB1;
1101
1102     yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
1103     *err = error;
1104     rec->databaseName = dbname;
1105     rec->which = Z_NamePlusRecord_surrogateDiagnostic;
1106     rec->u.surrogateDiagnostic = drec;
1107     drec->which = Z_DiagRec_defaultFormat;
1108     drec->u.defaultFormat = dr;
1109     dr->diagnosticSetId = odr_oiddup (assoc->encode,
1110                                       oid_ent_to_oid(&bib1, oid));
1111     dr->condition = err;
1112     set_addinfo (dr, addinfo);
1113
1114     return rec;
1115 }
1116
1117 /*
1118  * multiple nonsurrogate diagnostics.
1119  */
1120 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
1121 {
1122     int oid[OID_SIZE];
1123     Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
1124     int *err = (int *)odr_malloc (assoc->encode, sizeof(*err));
1125     oident bib1;
1126     Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
1127     Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
1128     Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)odr_malloc (assoc->encode, sizeof(*rec));
1129
1130     yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
1131     bib1.proto = assoc->proto;
1132     bib1.oclass = CLASS_DIAGSET;
1133     bib1.value = VAL_BIB1;
1134
1135     *err = error;
1136     recs->num_diagRecs = 1;
1137     recs->diagRecs = recp;
1138     recp[0] = drec;
1139     drec->which = Z_DiagRec_defaultFormat;
1140     drec->u.defaultFormat = rec;
1141
1142     rec->diagnosticSetId = odr_oiddup (assoc->encode,
1143                                       oid_ent_to_oid(&bib1, oid));
1144     rec->condition = err;
1145
1146 #ifdef ASN_COMPILED
1147     rec->which = Z_DefaultDiagFormat_v2Addinfo;
1148     rec->u.v2Addinfo = addinfo ? addinfo : "";
1149 #else
1150     rec->which = Z_DiagForm_v2AddInfo;
1151     rec->addinfo = addinfo ? addinfo : "";
1152 #endif
1153     return recs;
1154 }
1155
1156 static Z_Records *pack_records(association *a, char *setname, int start,
1157                                int *num, Z_RecordComposition *comp,
1158                                int *next, int *pres, oid_value format,
1159                                Z_ReferenceId *referenceId,
1160                                int *oid)
1161 {
1162     int recno, total_length = 0, toget = *num, dumped_records = 0;
1163     Z_Records *records =
1164         (Z_Records *) odr_malloc (a->encode, sizeof(*records));
1165     Z_NamePlusRecordList *reclist =
1166         (Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
1167     Z_NamePlusRecord **list =
1168         (Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
1169
1170     records->which = Z_Records_DBOSD;
1171     records->u.databaseOrSurDiagnostics = reclist;
1172     reclist->num_records = 0;
1173     reclist->records = list;
1174     *pres = Z_PRES_SUCCESS;
1175     *num = 0;
1176     *next = 0;
1177
1178     yaz_log(LOG_LOG, "Request to pack %d+%d", start, toget);
1179     yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
1180         a->maximumRecordSize);
1181     for (recno = start; reclist->num_records < toget; recno++)
1182     {
1183         bend_fetch_rr freq;
1184         Z_NamePlusRecord *thisrec;
1185         int this_length = 0;
1186         /*
1187          * we get the number of bytes allocated on the stream before any
1188          * allocation done by the backend - this should give us a reasonable
1189          * idea of the total size of the data so far.
1190          */
1191         total_length = odr_total(a->encode) - dumped_records;
1192         freq.errcode = 0;
1193         freq.errstring = 0;
1194         freq.basename = 0;
1195         freq.len = 0;
1196         freq.record = 0;
1197         freq.last_in_set = 0;
1198         freq.setname = setname;
1199         freq.surrogate_flag = 0;
1200         freq.number = recno;
1201         freq.comp = comp;
1202         freq.request_format = format;
1203         freq.request_format_raw = oid;
1204         freq.output_format = format;
1205         freq.output_format_raw = 0;
1206         freq.stream = a->encode;
1207         freq.print = a->print;
1208         freq.surrogate_flag = 0;
1209         freq.referenceId = referenceId;
1210         (*a->init->bend_fetch)(a->backend, &freq);
1211         /* backend should be able to signal whether error is system-wide
1212            or only pertaining to current record */
1213         if (freq.errcode)
1214         {
1215             if (!freq.surrogate_flag)
1216             {
1217                 *pres = Z_PRES_FAILURE;
1218                 return diagrec(a, freq.errcode, freq.errstring);
1219             }
1220             reclist->records[reclist->num_records] =
1221                 surrogatediagrec(a, freq.basename, freq.errcode,
1222                                  freq.errstring);
1223             reclist->num_records++;
1224             *next = freq.last_in_set ? 0 : recno + 1;
1225             continue;
1226         }
1227         if (freq.len >= 0)
1228             this_length = freq.len;
1229         else
1230             this_length = odr_total(a->encode) - total_length;
1231         yaz_log(LOG_DEBUG, "  fetched record, len=%d, total=%d",
1232             this_length, total_length);
1233         if (this_length + total_length > a->preferredMessageSize)
1234         {
1235             /* record is small enough, really */
1236             if (this_length <= a->preferredMessageSize)
1237             {
1238                 yaz_log(LOG_DEBUG, "  Dropped last normal-sized record");
1239                 *pres = Z_PRES_PARTIAL_2;
1240                 break;
1241             }
1242             /* record can only be fetched by itself */
1243             if (this_length < a->maximumRecordSize)
1244             {
1245                 yaz_log(LOG_DEBUG, "  Record > prefmsgsz");
1246                 if (toget > 1)
1247                 {
1248                     yaz_log(LOG_DEBUG, "  Dropped it");
1249                     reclist->records[reclist->num_records] =
1250                          surrogatediagrec(a, freq.basename, 16, 0);
1251                     reclist->num_records++;
1252                     *next = freq.last_in_set ? 0 : recno + 1;
1253                     dumped_records += this_length;
1254                     continue;
1255                 }
1256             }
1257             else /* too big entirely */
1258             {
1259                 yaz_log(LOG_DEBUG, "Record > maxrcdsz");
1260                 reclist->records[reclist->num_records] =
1261                     surrogatediagrec(a, freq.basename, 17, 0);
1262                 reclist->num_records++;
1263                 *next = freq.last_in_set ? 0 : recno + 1;
1264                 dumped_records += this_length;
1265                 continue;
1266             }
1267         }
1268
1269         if (!(thisrec = (Z_NamePlusRecord *)
1270               odr_malloc(a->encode, sizeof(*thisrec))))
1271             return 0;
1272         if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
1273             strlen(freq.basename) + 1)))
1274             return 0;
1275         strcpy(thisrec->databaseName, freq.basename);
1276         thisrec->which = Z_NamePlusRecord_databaseRecord;
1277
1278         if (freq.output_format_raw)
1279         {
1280             struct oident *ident = oid_getentbyoid(freq.output_format_raw);
1281             freq.output_format = ident->value;
1282         }
1283         thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
1284                                                  freq.record, freq.len);
1285         if (!thisrec->u.databaseRecord)
1286             return 0;
1287         reclist->records[reclist->num_records] = thisrec;
1288         reclist->num_records++;
1289         *next = freq.last_in_set ? 0 : recno + 1;
1290     }
1291     *num = reclist->num_records;
1292     return records;
1293 }
1294
1295 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
1296     int *fd)
1297 {
1298     Z_SearchRequest *req = reqb->request->u.searchRequest;
1299     bend_search_rr *bsrr = 
1300         (bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
1301     
1302     yaz_log(LOG_LOG, "Got SearchRequest.");
1303     bsrr->fd = fd;
1304     bsrr->request = reqb;
1305     bsrr->association = assoc;
1306     bsrr->referenceId = req->referenceId;
1307     save_referenceId (reqb, bsrr->referenceId);
1308
1309     yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
1310     if (req->databaseNames)
1311     {
1312         int i;
1313         for (i = 0; i < req->num_databaseNames; i++)
1314             yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1315     }
1316     switch (req->query->which)
1317     {
1318     case Z_Query_type_1: case Z_Query_type_101:
1319         log_rpn_query (req->query->u.type_1);
1320     }
1321     if (assoc->init->bend_search)
1322     {
1323         bsrr->setname = req->resultSetName;
1324         bsrr->replace_set = *req->replaceIndicator;
1325         bsrr->num_bases = req->num_databaseNames;
1326         bsrr->basenames = req->databaseNames;
1327         bsrr->query = req->query;
1328         bsrr->stream = assoc->encode;
1329         bsrr->decode = assoc->decode;
1330         bsrr->print = assoc->print;
1331         bsrr->errcode = 0;
1332         bsrr->hits = 0;
1333         bsrr->errstring = NULL;
1334         (assoc->init->bend_search)(assoc->backend, bsrr);
1335         if (!bsrr->request)
1336             return 0;
1337     }
1338 #if 0
1339     else
1340     {
1341         bend_searchrequest bsrq;
1342         bend_searchresult *bsrt;
1343
1344         bsrq.setname = req->resultSetName;
1345         bsrq.replace_set = *req->replaceIndicator;
1346         bsrq.num_bases = req->num_databaseNames;
1347         bsrq.basenames = req->databaseNames;
1348         bsrq.query = req->query;
1349         bsrq.referenceId = req->referenceId;
1350         bsrq.stream = assoc->encode;
1351         bsrq.decode = assoc->decode;
1352         bsrq.print = assoc->print;
1353         if (!(bsrt = bend_search (assoc->backend, &bsrq, fd)))
1354             return 0;
1355         bsrr->hits = bsrt->hits;
1356         bsrr->errcode = bsrt->errcode;
1357         bsrr->errstring = bsrt->errstring;
1358     }
1359 #endif
1360     return response_searchRequest(assoc, reqb, bsrr, fd);
1361 }
1362
1363 int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
1364
1365 /*
1366  * Prepare a searchresponse based on the backend results. We probably want
1367  * to look at making the fetching of records nonblocking as well, but
1368  * so far, we'll keep things simple.
1369  * If bsrt is null, that means we're called in response to a communications
1370  * event, and we'll have to get the response for ourselves.
1371  */
1372 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
1373     bend_search_rr *bsrt, int *fd)
1374 {
1375     Z_SearchRequest *req = reqb->request->u.searchRequest;
1376     Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1377     Z_SearchResponse *resp = (Z_SearchResponse *)
1378         odr_malloc (assoc->encode, sizeof(*resp));
1379     int *nulint = (int *)odr_malloc (assoc->encode, sizeof(*nulint));
1380     bool_t *sr = (bool_t *)odr_malloc (assoc->encode, sizeof(*sr));
1381     int *next = (int *)odr_malloc (assoc->encode, sizeof(*next));
1382     int *none = (int *)odr_malloc (assoc->encode, sizeof(*none));
1383
1384     *nulint = 0;
1385     *sr = 1;
1386     *next = 0;
1387     *none = Z_RES_NONE;
1388
1389     apdu->which = Z_APDU_searchResponse;
1390     apdu->u.searchResponse = resp;
1391     resp->referenceId = req->referenceId;
1392     resp->additionalSearchInfo = 0;
1393     resp->otherInfo = 0;
1394     *fd = -1;
1395     if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
1396     {
1397         yaz_log(LOG_FATAL, "Bad result from backend");
1398         return 0;
1399     }
1400     else if (bsrt->errcode)
1401     {
1402         resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
1403         resp->resultCount = nulint;
1404         resp->numberOfRecordsReturned = nulint;
1405         resp->nextResultSetPosition = nulint;
1406         resp->searchStatus = nulint;
1407         resp->resultSetStatus = none;
1408         resp->presentStatus = 0;
1409     }
1410     else
1411     {
1412         int *toget = (int *)odr_malloc (assoc->encode, sizeof(*toget));
1413         int *presst = (int *)odr_malloc (assoc->encode, sizeof(*presst));
1414         Z_RecordComposition comp, *compp = 0;
1415
1416         *toget = 0;
1417         *presst = 0;
1418         resp->records = 0;
1419         resp->resultCount = &bsrt->hits;
1420
1421         comp.which = Z_RecordComp_simple;
1422         /* how many records does the user agent want, then? */
1423         if (bsrt->hits <= *req->smallSetUpperBound)
1424         {
1425             *toget = bsrt->hits;
1426             if ((comp.u.simple = req->smallSetElementSetNames))
1427                 compp = &comp;
1428         }
1429         else if (bsrt->hits < *req->largeSetLowerBound)
1430         {
1431             *toget = *req->mediumSetPresentNumber;
1432             if (*toget > bsrt->hits)
1433                 *toget = bsrt->hits;
1434             if ((comp.u.simple = req->mediumSetElementSetNames))
1435                 compp = &comp;
1436         }
1437         else
1438             *toget = 0;
1439
1440         if (*toget && !resp->records)
1441         {
1442             oident *prefformat;
1443             oid_value form;
1444
1445             if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
1446                 prefformat->oclass != CLASS_RECSYN)
1447                 form = VAL_NONE;
1448             else
1449                 form = prefformat->value;
1450             resp->records = pack_records(assoc, req->resultSetName, 1,
1451                 toget, compp, next, presst, form, req->referenceId,
1452                                          req->preferredRecordSyntax);
1453             if (!resp->records)
1454                 return 0;
1455             resp->numberOfRecordsReturned = toget;
1456             resp->nextResultSetPosition = next;
1457             resp->searchStatus = sr;
1458             resp->resultSetStatus = 0;
1459             resp->presentStatus = presst;
1460         }
1461         else
1462         {
1463             if (*resp->resultCount)
1464                 *next = 1;
1465             resp->numberOfRecordsReturned = nulint;
1466             resp->nextResultSetPosition = next;
1467             resp->searchStatus = sr;
1468             resp->resultSetStatus = 0;
1469             resp->presentStatus = 0;
1470         }
1471     }
1472     return apdu;
1473 }
1474
1475 /*
1476  * Maybe we got a little over-friendly when we designed bend_fetch to
1477  * get only one record at a time. Some backends can optimise multiple-record
1478  * fetches, and at any rate, there is some overhead involved in
1479  * all that selecting and hopping around. Problem is, of course, that the
1480  * frontend can't know ahead of time how many records it'll need to
1481  * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
1482  * is downright lousy as a bulk data transfer protocol.
1483  *
1484  * To start with, we'll do the fetching of records from the backend
1485  * in one operation: To save some trips in and out of the event-handler,
1486  * and to simplify the interface to pack_records. At any rate, asynch
1487  * operation is more fun in operations that have an unpredictable execution
1488  * speed - which is normally more true for search than for present.
1489  */
1490 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
1491                                       int *fd)
1492 {
1493     Z_PresentRequest *req = reqb->request->u.presentRequest;
1494     oident *prefformat;
1495     oid_value form;
1496     Z_APDU *apdu;
1497     Z_PresentResponse *resp;
1498     int *presst;
1499     int *next;
1500     int *num;
1501
1502     yaz_log(LOG_LOG, "Got PresentRequest.");
1503
1504     if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
1505         prefformat->oclass != CLASS_RECSYN)
1506         form = VAL_NONE;
1507     else
1508         form = prefformat->value;
1509     if (assoc->init->bend_present)
1510     {
1511         bend_present_rr *bprr = (bend_present_rr *)
1512             nmem_malloc (reqb->request_mem, sizeof(*bprr));
1513         bprr->setname = req->resultSetId;
1514         bprr->start = *req->resultSetStartPoint;
1515         bprr->number = *req->numberOfRecordsRequested;
1516         bprr->format = form;
1517         bprr->comp = req->recordComposition;
1518         bprr->referenceId = req->referenceId;
1519         bprr->stream = assoc->encode;
1520         bprr->print = assoc->print;
1521         bprr->request = reqb;
1522         bprr->association = assoc;
1523         bprr->errcode = 0;
1524         bprr->errstring = NULL;
1525         (*assoc->init->bend_present)(assoc->backend, bprr);
1526         
1527         if (!bprr->request)
1528             return 0;
1529     }
1530     apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1531     resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
1532     presst = (int *)odr_malloc (assoc->encode, sizeof(*presst));
1533     next = (int *)odr_malloc (assoc->encode, sizeof(*next));
1534     num = (int *)odr_malloc (assoc->encode, sizeof(*num));
1535     *presst = 0;
1536     *next = 0;
1537     *num = *req->numberOfRecordsRequested;
1538     
1539     apdu->which = Z_APDU_presentResponse;
1540     apdu->u.presentResponse = resp;
1541     resp->referenceId = req->referenceId;
1542     resp->otherInfo = 0;
1543     
1544     resp->records =
1545         pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
1546                      num, req->recordComposition, next, presst, form,
1547                      req->referenceId, req->preferredRecordSyntax);
1548     if (!resp->records)
1549         return 0;
1550     resp->numberOfRecordsReturned = num;
1551     resp->presentStatus = presst;
1552     resp->nextResultSetPosition = next;
1553     
1554     return apdu;
1555 }
1556
1557 #if 0
1558 static int bend_default_scan (void *handle, bend_scan_rr *rr)
1559 {
1560     bend_scanrequest srq;
1561     bend_scanresult *srs;
1562
1563     srq.num_bases = rr->num_bases;
1564     srq.basenames = rr->basenames;
1565     srq.attributeset = rr->attributeset;
1566     srq.referenceId = rr->referenceId;
1567     srq.term = rr->term;
1568     srq.term_position = rr->term_position;
1569     srq.num_entries = rr->num_entries;
1570     srq.stream = rr->stream;
1571     srq.print = rr->print;
1572     
1573     srs = bend_scan(handle, &srq, 0);
1574
1575     rr->term_position = srs->term_position;
1576     rr->num_entries = srs->num_entries;
1577     rr->entries = srs->entries;
1578     rr->status = srs->status;
1579     rr->errcode = srs->errcode;
1580     rr->errstring = srs->errstring;
1581     return 0;
1582 }
1583 #endif
1584
1585 /*
1586  * Scan was implemented rather in a hurry, and with support for only the basic
1587  * elements of the service in the backend API. Suggestions are welcome.
1588  */
1589 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
1590 {
1591     Z_ScanRequest *req = reqb->request->u.scanRequest;
1592     Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1593     Z_ScanResponse *res = (Z_ScanResponse *)
1594         odr_malloc (assoc->encode, sizeof(*res));
1595     int *scanStatus = (int *)
1596         odr_malloc (assoc->encode, sizeof(*scanStatus));
1597     int *numberOfEntriesReturned = (int *)
1598         odr_malloc (assoc->encode, sizeof(*numberOfEntriesReturned));
1599     Z_ListEntries *ents = (Z_ListEntries *)
1600         odr_malloc (assoc->encode, sizeof(*ents));
1601     Z_DiagRecs *diagrecs_p = NULL;
1602     oident *attent;
1603     oident *attset;
1604
1605     yaz_log(LOG_LOG, "Got ScanRequest");
1606     *scanStatus = Z_Scan_failure;
1607     *numberOfEntriesReturned = 0;
1608
1609     apdu->which = Z_APDU_scanResponse;
1610     apdu->u.scanResponse = res;
1611     res->referenceId = req->referenceId;
1612     res->stepSize = 0;
1613     res->scanStatus = scanStatus;
1614     res->numberOfEntriesReturned = numberOfEntriesReturned;
1615     res->positionOfTerm = 0;
1616     res->entries = ents;
1617     ents->num_entries = 0;
1618     ents->entries = NULL;
1619     ents->num_nonsurrogateDiagnostics = 0;
1620     ents->nonsurrogateDiagnostics = NULL;
1621     res->attributeSet = 0;
1622     res->otherInfo = 0;
1623
1624     if (req->attributeSet && (!(attent = oid_getentbyoid(req->attributeSet)) ||
1625                               attent->oclass != CLASS_ATTSET
1626                               || attent->value != VAL_BIB1))
1627         diagrecs_p = diagrecs(assoc, 121, 0);
1628     else if (req->stepSize && *req->stepSize > 0)
1629         diagrecs_p = diagrecs(assoc, 205, 0);
1630     else
1631     {
1632         bend_scan_rr *bsrr = (bend_scan_rr *)
1633             odr_malloc (assoc->encode, sizeof(*bsrr));
1634         if (req->databaseNames)
1635         {
1636             int i;
1637             for (i = 0; i < req->num_databaseNames; i++)
1638                 yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
1639         }
1640         bsrr->num_bases = req->num_databaseNames;
1641         bsrr->basenames = req->databaseNames;
1642         bsrr->num_entries = *req->numberOfTermsRequested;
1643         bsrr->term = req->termListAndStartPoint;
1644         bsrr->referenceId = req->referenceId;
1645         bsrr->stream = assoc->encode;
1646         bsrr->print = assoc->print;
1647         if (!(attset = oid_getentbyoid(req->attributeSet)) ||
1648             attset->oclass != CLASS_RECSYN)
1649             bsrr->attributeset = VAL_NONE;
1650         else
1651             bsrr->attributeset = attset->value;
1652         log_scan_term (req->termListAndStartPoint, attset->value);
1653         bsrr->term_position = req->preferredPositionInResponse ?
1654             *req->preferredPositionInResponse : 1;
1655         ((int (*)(void *, bend_scan_rr *))
1656          (*assoc->init->bend_scan))(assoc->backend, bsrr);
1657         if (bsrr->errcode)
1658             diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
1659         else
1660         {
1661             int i;
1662             Z_Entry **tab = (Z_Entry **)
1663                 odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
1664             
1665             if (bsrr->status == BEND_SCAN_PARTIAL)
1666                 *scanStatus = Z_Scan_partial_5;
1667             else
1668                 *scanStatus = Z_Scan_success;
1669             ents->entries = tab;
1670             ents->num_entries = bsrr->num_entries;
1671             res->numberOfEntriesReturned = &ents->num_entries;      
1672             res->positionOfTerm = &bsrr->term_position;
1673             for (i = 0; i < bsrr->num_entries; i++)
1674             {
1675                 Z_Entry *e;
1676                 Z_TermInfo *t;
1677                 Odr_oct *o;
1678                 
1679                 tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
1680                 if (bsrr->entries[i].occurrences >= 0)
1681                 {
1682                     e->which = Z_Entry_termInfo;
1683                     e->u.termInfo = t = (Z_TermInfo *)
1684                         odr_malloc(assoc->encode, sizeof(*t));
1685                     t->suggestedAttributes = 0;
1686                     t->displayTerm = 0;
1687                     t->alternativeTerm = 0;
1688                     t->byAttributes = 0;
1689                     t->otherTermInfo = 0;
1690                     t->globalOccurrences = &bsrr->entries[i].occurrences;
1691                     t->term = (Z_Term *)
1692                         odr_malloc(assoc->encode, sizeof(*t->term));
1693                     t->term->which = Z_Term_general;
1694                     t->term->u.general = o =
1695                         (Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
1696                     o->buf = (unsigned char *)
1697                         odr_malloc(assoc->encode, o->len = o->size =
1698                                    strlen(bsrr->entries[i].term));
1699                     memcpy(o->buf, bsrr->entries[i].term, o->len);
1700                     yaz_log(LOG_DEBUG, "  term #%d: '%s' (%d)", i,
1701                          bsrr->entries[i].term, bsrr->entries[i].occurrences);
1702                 }
1703                 else
1704                 {
1705                     Z_DiagRecs *drecs = diagrecs (assoc,
1706                                                   bsrr->entries[i].errcode,
1707                                                   bsrr->entries[i].errstring);
1708                     assert (drecs->num_diagRecs == 1);
1709                     e->which = Z_Entry_surrogateDiagnostic;
1710                     assert (drecs->diagRecs[0]);
1711                     e->u.surrogateDiagnostic = drecs->diagRecs[0];
1712                 }
1713             }
1714         }
1715     }
1716     if (diagrecs_p)
1717     {
1718         ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
1719         ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
1720     }
1721     return apdu;
1722 }
1723
1724 static Z_APDU *process_sortRequest(association *assoc, request *reqb,
1725     int *fd)
1726 {
1727     Z_SortRequest *req = reqb->request->u.sortRequest;
1728     Z_SortResponse *res = (Z_SortResponse *)
1729         odr_malloc (assoc->encode, sizeof(*res));
1730     bend_sort_rr *bsrr = (bend_sort_rr *)
1731         odr_malloc (assoc->encode, sizeof(*bsrr));
1732
1733     Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1734
1735     yaz_log(LOG_LOG, "Got SortRequest.");
1736
1737 #ifdef ASN_COMPILED
1738     bsrr->num_input_setnames = req->num_inputResultSetNames;
1739     bsrr->input_setnames = req->inputResultSetNames;
1740 #else
1741     bsrr->num_input_setnames = req->inputResultSetNames->num_strings;
1742     bsrr->input_setnames = req->inputResultSetNames->strings;
1743 #endif
1744     bsrr->referenceId = req->referenceId;
1745     bsrr->output_setname = req->sortedResultSetName;
1746     bsrr->sort_sequence = req->sortSequence;
1747     bsrr->stream = assoc->encode;
1748     bsrr->print = assoc->print;
1749
1750     bsrr->sort_status = Z_SortStatus_failure;
1751     bsrr->errcode = 0;
1752     bsrr->errstring = 0;
1753     
1754     (*assoc->init->bend_sort)(assoc->backend, bsrr);
1755     
1756     res->referenceId = bsrr->referenceId;
1757     res->sortStatus = (int *)
1758         odr_malloc (assoc->encode, sizeof(*res->sortStatus));
1759     *res->sortStatus = bsrr->sort_status;
1760     res->resultSetStatus = 0;
1761     if (bsrr->errcode)
1762     {
1763         Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
1764 #ifdef ASN_COMPILED
1765         res->diagnostics = dr->diagRecs;
1766         res->num_diagnostics = dr->num_diagRecs;
1767 #else
1768         res->diagnostics = dr;
1769 #endif
1770     }
1771     else
1772     {
1773 #ifdef ASN_COMPILED
1774         res->num_diagnostics = 0;
1775 #endif
1776         res->diagnostics = 0;
1777     }
1778     res->otherInfo = 0;
1779
1780     apdu->which = Z_APDU_sortResponse;
1781     apdu->u.sortResponse = res;
1782     return apdu;
1783 }
1784
1785 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
1786     int *fd)
1787 {
1788     Z_DeleteResultSetRequest *req = reqb->request->u.deleteResultSetRequest;
1789     Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
1790         odr_malloc (assoc->encode, sizeof(*res));
1791     bend_delete_rr *bdrr = (bend_delete_rr *)
1792         odr_malloc (assoc->encode, sizeof(*bdrr));
1793     Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
1794
1795     yaz_log(LOG_LOG, "Got DeleteRequest.");
1796
1797     bdrr->num_setnames = req->num_resultSetList;
1798     bdrr->setnames = req->resultSetList;
1799     bdrr->stream = assoc->encode;
1800     bdrr->print = assoc->print;
1801     bdrr->function = *req->deleteFunction;
1802     bdrr->referenceId = req->referenceId;
1803     bdrr->statuses = 0;
1804     if (bdrr->num_setnames > 0)
1805     {
1806         int i;
1807         bdrr->statuses = odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
1808                                     bdrr->num_setnames);
1809         for (i = 0; i < bdrr->num_setnames; i++)
1810             bdrr->statuses[i] = 0;
1811     }
1812     (*assoc->init->bend_delete)(assoc->backend, bdrr);
1813     
1814     res->referenceId = req->referenceId;
1815
1816     res->deleteOperationStatus = (int *)
1817         odr_malloc (assoc->encode, sizeof(*res->deleteOperationStatus));
1818     *res->deleteOperationStatus = bdrr->delete_status;
1819
1820     res->deleteListStatuses = 0;
1821     if (bdrr->num_setnames > 0)
1822     {
1823         int i;
1824         res->deleteListStatuses = odr_malloc(assoc->encode,
1825                                              sizeof(*res->deleteListStatuses));
1826         res->deleteListStatuses->num = bdrr->num_setnames;
1827         res->deleteListStatuses->elements =
1828             odr_malloc (assoc->encode,
1829                         sizeof(*res->deleteListStatuses->elements) *
1830                         bdrr->num_setnames);
1831         for (i = 0; i<bdrr->num_setnames; i++)
1832         {
1833             res->deleteListStatuses->elements[i] =
1834                 odr_malloc (assoc->encode,
1835                             sizeof(**res->deleteListStatuses->elements));
1836             res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
1837             res->deleteListStatuses->elements[i]->id =
1838                 odr_strdup (assoc->encode, bdrr->setnames[i]);
1839             
1840         }
1841     }
1842     res->numberNotDeleted = 0;
1843     res->bulkStatuses = 0;
1844     res->deleteMessage = 0;
1845     res->otherInfo = 0;
1846
1847     apdu->which = Z_APDU_deleteResultSetResponse;
1848     apdu->u.deleteResultSetResponse = res;
1849     return apdu;
1850 }
1851
1852 static void process_close(association *assoc, request *reqb)
1853 {
1854     Z_Close *req = reqb->request->u.close;
1855     static char *reasons[] =
1856     {
1857         "finished",
1858         "shutdown",
1859         "systemProblem",
1860         "costLimit",
1861         "resources",
1862         "securityViolation",
1863         "protocolError",
1864         "lackOfActivity",
1865         "peerAbort",
1866         "unspecified"
1867     };
1868
1869     yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
1870         reasons[*req->closeReason], req->diagnosticInformation ?
1871         req->diagnosticInformation : "NULL");
1872     if (assoc->version < 3) /* to make do_force respond with close */
1873         assoc->version = 3;
1874     do_close_req(assoc, Z_Close_finished,
1875                  "Association terminated by client", reqb);
1876 }
1877
1878 void save_referenceId (request *reqb, Z_ReferenceId *refid)
1879 {
1880     if (refid)
1881     {
1882         reqb->len_refid = refid->len;
1883         reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
1884         memcpy (reqb->refid, refid->buf, refid->len);
1885     }
1886     else
1887     {
1888         reqb->len_refid = 0;
1889         reqb->refid = NULL;
1890     }
1891 }
1892
1893 void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
1894 {
1895     process_response (a, req, res);
1896 }
1897
1898 bend_request bend_request_mk (bend_association a)
1899 {
1900     request *nreq = request_get (&a->outgoing);
1901     nreq->request_mem = nmem_create ();
1902     return nreq;
1903 }
1904
1905 Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
1906 {
1907     Z_ReferenceId *id;
1908     if (!req->refid)
1909         return 0;
1910     id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
1911     id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
1912     id->len = id->size = req->len_refid;
1913     memcpy (id->buf, req->refid, req->len_refid);
1914     return id;
1915 }
1916
1917 void bend_request_destroy (bend_request *req)
1918 {
1919     nmem_destroy((*req)->request_mem);
1920     request_release(*req);
1921     *req = NULL;
1922 }
1923
1924 int bend_backend_respond (bend_association a, bend_request req)
1925 {
1926     char *msg;
1927     int r;
1928     r = process_request (a, req, &msg);
1929     if (r < 0)
1930         logf (LOG_WARN, "%s", msg);
1931     return r;
1932 }
1933
1934 void bend_request_setdata(bend_request r, void *p)
1935 {
1936     r->clientData = p;
1937 }
1938
1939 void *bend_request_getdata(bend_request r)
1940 {
1941     return r->clientData;
1942 }
1943
1944 static Z_APDU *process_segmentRequest (association *assoc, request *reqb)
1945 {
1946     bend_segment_rr request;
1947
1948     request.segment = reqb->request->u.segmentRequest;
1949     request.stream = assoc->encode;
1950     request.decode = assoc->decode;
1951     request.print = assoc->print;
1952     request.association = assoc;
1953     
1954     (*assoc->init->bend_segment)(assoc->backend, &request);
1955
1956     return 0;
1957 }
1958
1959 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
1960 {
1961     bend_esrequest_rr esrequest;
1962
1963     Z_ExtendedServicesRequest *req = reqb->request->u.extendedServicesRequest;
1964     Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
1965
1966     Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
1967
1968     yaz_log(LOG_DEBUG,"inside Process esRequest");
1969
1970     esrequest.esr = reqb->request->u.extendedServicesRequest;
1971     esrequest.stream = assoc->encode;
1972     esrequest.decode = assoc->decode;
1973     esrequest.print = assoc->print;
1974     esrequest.errcode = 0;
1975     esrequest.errstring = NULL;
1976     esrequest.request = reqb;
1977     esrequest.association = assoc;
1978     esrequest.referenceId = req->referenceId;
1979     
1980     (*assoc->init->bend_esrequest)(assoc->backend, &esrequest);
1981     
1982     /* If the response is being delayed, return NULL */
1983     if (esrequest.request == NULL)
1984         return(NULL);
1985
1986     resp->referenceId = req->referenceId;
1987
1988     if (esrequest.errcode == -1)
1989     {
1990         /* Backend service indicates request will be processed */
1991         yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
1992         *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
1993     }
1994     else if (esrequest.errcode == 0)
1995     {
1996         /* Backend service indicates request will be processed */
1997         yaz_log(LOG_DEBUG,"Request could be processed...Done !");
1998         *resp->operationStatus = Z_ExtendedServicesResponse_done;
1999     }
2000     else
2001     {
2002         Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
2003                                          esrequest.errstring);
2004
2005         /* Backend indicates error, request will not be processed */
2006         yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
2007         *resp->operationStatus = Z_ExtendedServicesResponse_failure;
2008         resp->num_diagnostics = diagRecs->num_diagRecs;
2009         resp->diagnostics = diagRecs->diagRecs;
2010     }
2011     /* Do something with the members of bend_extendedservice */
2012
2013     yaz_log(LOG_DEBUG,"Send the result apdu");
2014     return apdu;
2015 }