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