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