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