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