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