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