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