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