Added memory management.
[yaz-moved-to-github.git] / server / seshigh.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: seshigh.c,v $
7  * Revision 1.4  1995-03-17 10:18:08  quinn
8  * Added memory management.
9  *
10  * Revision 1.3  1995/03/16  17:42:39  quinn
11  * Little changes
12  *
13  * Revision 1.2  1995/03/16  13:29:01  quinn
14  * Partitioned server.
15  *
16  * Revision 1.1  1995/03/15  16:02:10  quinn
17  * Modded session.c seshigh.c
18  *
19  * Revision 1.10  1995/03/15  15:18:51  quinn
20  * Little changes to better support nonblocking I/O
21  * Added backend.h
22  *
23  * Revision 1.9  1995/03/15  13:20:23  adam
24  * Yet another bug fix in very dummy_database...
25  *
26  * Revision 1.8  1995/03/15  11:18:17  quinn
27  * Smallish changes.
28  *
29  * Revision 1.7  1995/03/15  09:40:15  adam
30  * Bug fixes in dummy_database_...
31  *
32  * Revision 1.6  1995/03/15  09:08:30  adam
33  * Take care of preferredMessageSize.
34  *
35  * Revision 1.5  1995/03/15  08:37:44  quinn
36  * Now we're pretty much set for nonblocking I/O.
37  *
38  * Revision 1.4  1995/03/15  08:27:20  adam
39  * PresentRequest changed to return MARC records from file 'dummy-records'.
40  *
41  * Revision 1.3  1995/03/14  16:59:48  quinn
42  * Bug-fixes
43  *
44  * Revision 1.2  1995/03/14  11:30:14  quinn
45  * Works better now.
46  *
47  * Revision 1.1  1995/03/14  10:28:01  quinn
48  * More work on demo server.
49  *
50  *
51  */
52
53 #include <stdlib.h>
54 #include <assert.h>
55
56 #include <comstack.h>
57 #include <eventl.h>
58 #include <session.h>
59 #include <proto.h>
60
61 #include <backend.h>
62
63 #include <iso2709.h>
64
65 #define ENCODE_BUFFER_SIZE 10000
66
67 static int process_apdu(IOCHAN chan);
68 static int process_initRequest(IOCHAN client, Z_InitRequest *req);
69 static int process_searchRequest(IOCHAN client, Z_SearchRequest *req);
70 static int process_presentRequest(IOCHAN client, Z_PresentRequest *req);
71
72 association *create_association(IOCHAN channel, COMSTACK link)
73 {
74     association *new;
75
76     if (!(new = malloc(sizeof(*new))))
77         return 0;
78     new->client_chan = channel;
79     new->client_link = link;
80     if (!(new->decode = odr_createmem(ODR_DECODE)) ||
81         !(new->encode = odr_createmem(ODR_ENCODE)))
82         return 0;
83     if (!(new->encode_buffer = malloc(ENCODE_BUFFER_SIZE)))
84         return 0;
85     odr_setbuf(new->encode, new->encode_buffer, ENCODE_BUFFER_SIZE);
86     new->state = ASSOC_UNINIT;
87     new->input_buffer = 0;
88     new->input_buffer_len = 0;
89     return new;
90 }
91
92 void destroy_association(association *h)
93 {
94     odr_destroy(h->decode);
95     odr_destroy(h->encode);
96     free(h->encode_buffer);
97     if (h->input_buffer)
98         free(h->input_buffer);
99     free(h);
100 }
101
102 void ir_session(IOCHAN h, int event)
103 {
104     int res;
105     association *assoc = iochan_getdata(h);
106     COMSTACK conn = assoc->client_link;
107
108     if (event == EVENT_INPUT)
109     {
110         assert(assoc && conn);
111         res = cs_get(conn, &assoc->input_buffer, &assoc->input_buffer_len);
112         switch (res)
113         {
114             case 0: case -1: /* connection closed by peer */
115                 fprintf(stderr, "Closed connection\n");
116                 cs_close(conn);
117                 destroy_association(assoc);
118                 iochan_destroy(h);
119                 return;
120             case 1:  /* incomplete read */
121                 return;
122             default: /* data! */
123                 assoc->input_apdu_len = res;
124                 if (process_apdu(h) < 0)
125                 {
126                     fprintf(stderr, "Operation failed\n");
127                     cs_close(conn);
128                     destroy_association(assoc);
129                     iochan_destroy(h);
130                 }
131                 else if (cs_more(conn)) /* arrange to be called again */
132                     iochan_setevent(h, EVENT_INPUT);
133         }
134     }
135     else if (event == EVENT_OUTPUT)
136     {
137         switch (res = cs_put(conn, assoc->encode_buffer, assoc->encoded_len))
138         {
139             case -1:
140                 fprintf(stderr, "Closed connection\n");
141                 cs_close(conn);
142                 destroy_association(assoc);
143                 iochan_destroy(h);
144             case 0: /* all sent */
145                 iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset */
146                 break;
147             case 1: /* partial send */
148                 break; /* we'll get called again */
149         }
150     }
151     else if (event == EVENT_EXCEPT)
152     {
153         fprintf(stderr, "Exception on line\n");
154         cs_close(conn);
155         destroy_association(assoc);
156         iochan_destroy(h);
157     }
158 }
159
160 static int process_apdu(IOCHAN chan)
161 {
162     Z_APDU *apdu;
163     int res;
164     association *assoc = iochan_getdata(chan);
165
166     odr_setbuf(assoc->decode, assoc->input_buffer, assoc->input_apdu_len);
167     if (!z_APDU(assoc->decode, &apdu, 0))
168     {
169         odr_perror(assoc->decode, "Incoming APDU");
170         return -1;
171     }
172     switch (apdu->which)
173     {
174         case Z_APDU_initRequest:
175             res = process_initRequest(chan, apdu->u.initRequest); break;
176         case Z_APDU_searchRequest:
177             res = process_searchRequest(chan, apdu->u.searchRequest); break;
178         case Z_APDU_presentRequest:
179             res = process_presentRequest(chan, apdu->u.presentRequest); break;
180         default:
181             fprintf(stderr, "Bad APDU\n");
182             return -1;
183     }
184     odr_reset(assoc->decode);
185     return res;
186 }
187
188 static int process_initRequest(IOCHAN client, Z_InitRequest *req)
189 {
190     Z_APDU apdu, *apdup;
191     Z_InitResponse resp;
192     bool_t result = 1;
193     association *assoc = iochan_getdata(client);
194     bend_initrequest binitreq;
195     bend_initresult *binitres;
196
197     fprintf(stderr, "Got initRequest.\n");
198     if (req->implementationId)
199         fprintf(stderr, "Id:        %s\n", req->implementationId);
200     if (req->implementationName)
201         fprintf(stderr, "Name:      %s\n", req->implementationName);
202     if (req->implementationVersion)
203         fprintf(stderr, "Version:   %s\n", req->implementationVersion);
204
205     binitreq.configname = "default-config";
206     if (!(binitres = bend_init(&binitreq)) || binitres->errcode)
207     {
208         fprintf(stderr, "Bad response from backend\n");
209         return -1;
210     }
211
212     apdup = &apdu;
213     apdu.which = Z_APDU_initResponse;
214     apdu.u.initResponse = &resp;
215     resp.referenceId = req->referenceId;
216     resp.options = req->options; /* should check these */
217     resp.protocolVersion = req->protocolVersion;
218     assoc->maximumRecordSize = *req->maximumRecordSize;
219     if (assoc->maximumRecordSize > ENCODE_BUFFER_SIZE - 500)
220         assoc->maximumRecordSize = ENCODE_BUFFER_SIZE - 500;
221     assoc->preferredMessageSize = *req->preferredMessageSize;
222     if (assoc->preferredMessageSize > assoc->maximumRecordSize)
223         assoc->preferredMessageSize = assoc->maximumRecordSize;
224     resp.preferredMessageSize = &assoc->preferredMessageSize;
225     resp.maximumRecordSize = &assoc->maximumRecordSize;
226     resp.result = &result;
227     resp.implementationId = "YAZ";
228     resp.implementationName = "YAZ/Simple asynchronous test server";
229     resp.implementationVersion = "$Revision: 1.4 $";
230     resp.userInformationField = 0;
231     if (!z_APDU(assoc->encode, &apdup, 0))
232     {
233         odr_perror(assoc->encode, "Encode initres");
234         return -1;
235     }
236     odr_getbuf(assoc->encode, &assoc->encoded_len);
237     odr_reset(assoc->encode);
238     iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);
239     return 0;
240 }
241
242 static Z_Records *diagrec(int error, char *addinfo)
243 {
244     static Z_Records rec;
245     static Odr_oid bib1[] = { 1, 2, 3, 4, 5, -1 };
246     static Z_DiagRec dr;
247     static int err;
248
249     fprintf(stderr, "Diagnostic: %d -- %s\n", error, addinfo);
250     err = error;
251     rec.which = Z_Records_NSD;
252     rec.u.nonSurrogateDiagnostic = &dr;
253     dr.diagnosticSetId = bib1;
254     dr.condition = &err;
255     dr.addinfo = addinfo;
256     return &rec;
257 }
258
259 static int process_searchRequest(IOCHAN client, Z_SearchRequest *req)
260 {
261     Z_APDU apdu, *apdup;
262     Z_SearchResponse resp;
263     association *assoc = iochan_getdata(client);
264     int nulint = 0;
265     bool_t sr = 1;
266     int nrp;
267     bend_searchrequest bsrq;
268     bend_searchresult *bsrt;
269
270     fprintf(stderr, "Got SearchRequest.\n");
271     apdup = &apdu;
272     apdu.which = Z_APDU_searchResponse;
273     apdu.u.searchResponse = &resp;
274     resp.referenceId = req->referenceId;
275
276     bsrq.setname = req->resultSetName;
277     bsrq.replace_set = *req->replaceIndicator;
278     bsrq.num_bases = req->num_databaseNames;
279     bsrq.basenames = req->databaseNames;
280     bsrq.query = req->query;
281
282     if (!(bsrt = bend_search(&bsrq)))
283         return -1;
284     else if (bsrt->errcode)
285         resp.records = diagrec(bsrt->errcode, bsrt->errstring);
286     else
287         resp.records = 0;
288
289     resp.resultCount = &bsrt->hits;
290     resp.numberOfRecordsReturned = &nulint;
291     nrp = bsrt->hits ? 1 : 0;
292     resp.nextResultSetPosition = &nrp;
293     resp.searchStatus = &sr;
294     resp.resultSetStatus = &sr;
295     resp.presentStatus = 0;
296
297     if (!z_APDU(assoc->encode, &apdup, 0))
298     {
299         odr_perror(assoc->encode, "Encode searchres");
300         return -1;
301     }
302     odr_getbuf(assoc->encode, &assoc->encoded_len);
303     odr_reset(assoc->encode);
304     iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);
305     return 0;
306 }
307
308 static int process_presentRequest(IOCHAN client, Z_PresentRequest *req)
309 {
310     Z_APDU apdu, *apdup;
311     Z_PresentResponse resp;
312     association *assoc = iochan_getdata(client);
313     int nrr = 1;
314
315     fprintf(stderr, "Got PresentRequest.\n");
316     apdup = &apdu;
317     apdu.which = Z_APDU_presentResponse;
318     apdu.u.presentResponse = &resp;
319     resp.referenceId = req->referenceId;
320
321     resp.numberOfRecordsReturned = &nrr;
322     resp.nextResultSetPosition = &nrr;
323     resp.presentStatus = &nrr;
324
325     resp.records = diagrec(1, "No records yet.");
326
327     if (!z_APDU(assoc->encode, &apdup, 0))
328     {
329         odr_perror(assoc->encode, "Encode presentres");
330         return -1;
331     }
332     odr_getbuf(assoc->encode, &assoc->encoded_len);
333     odr_reset(assoc->encode);
334     iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);
335     return 0;
336 }