2 * Copyright (C) 1994, Index Data I/S
4 * Sebastian Hammer, Adam Dickmeiss
7 * Revision 1.8 1995-03-22 10:13:21 quinn
8 * Working on record packer
10 * Revision 1.7 1995/03/21 15:53:31 quinn
13 * Revision 1.6 1995/03/21 12:30:09 quinn
14 * Beginning to add support for record packing.
16 * Revision 1.5 1995/03/17 10:44:13 quinn
17 * Added catch of null-string in makediagrec
19 * Revision 1.4 1995/03/17 10:18:08 quinn
20 * Added memory management.
22 * Revision 1.3 1995/03/16 17:42:39 quinn
25 * Revision 1.2 1995/03/16 13:29:01 quinn
28 * Revision 1.1 1995/03/15 16:02:10 quinn
29 * Modded session.c seshigh.c
31 * Revision 1.10 1995/03/15 15:18:51 quinn
32 * Little changes to better support nonblocking I/O
35 * Revision 1.9 1995/03/15 13:20:23 adam
36 * Yet another bug fix in very dummy_database...
38 * Revision 1.8 1995/03/15 11:18:17 quinn
41 * Revision 1.7 1995/03/15 09:40:15 adam
42 * Bug fixes in dummy_database_...
44 * Revision 1.6 1995/03/15 09:08:30 adam
45 * Take care of preferredMessageSize.
47 * Revision 1.5 1995/03/15 08:37:44 quinn
48 * Now we're pretty much set for nonblocking I/O.
50 * Revision 1.4 1995/03/15 08:27:20 adam
51 * PresentRequest changed to return MARC records from file 'dummy-records'.
53 * Revision 1.3 1995/03/14 16:59:48 quinn
56 * Revision 1.2 1995/03/14 11:30:14 quinn
59 * Revision 1.1 1995/03/14 10:28:01 quinn
60 * More work on demo server.
77 #define ENCODE_BUFFER_SIZE 10000
79 static int process_apdu(IOCHAN chan);
80 static int process_initRequest(IOCHAN client, Z_InitRequest *req);
81 static int process_searchRequest(IOCHAN client, Z_SearchRequest *req);
82 static int process_presentRequest(IOCHAN client, Z_PresentRequest *req);
84 association *create_association(IOCHAN channel, COMSTACK link)
88 if (!(new = malloc(sizeof(*new))))
90 new->client_chan = channel;
91 new->client_link = link;
92 if (!(new->decode = odr_createmem(ODR_DECODE)) ||
93 !(new->encode = odr_createmem(ODR_ENCODE)))
95 if (!(new->encode_buffer = malloc(ENCODE_BUFFER_SIZE)))
97 odr_setbuf(new->encode, new->encode_buffer, ENCODE_BUFFER_SIZE);
98 new->state = ASSOC_UNINIT;
99 new->input_buffer = 0;
100 new->input_buffer_len = 0;
104 void destroy_association(association *h)
106 odr_destroy(h->decode);
107 odr_destroy(h->encode);
108 free(h->encode_buffer);
110 free(h->input_buffer);
114 void ir_session(IOCHAN h, int event)
117 association *assoc = iochan_getdata(h);
118 COMSTACK conn = assoc->client_link;
120 if (event == EVENT_INPUT)
122 assert(assoc && conn);
123 res = cs_get(conn, &assoc->input_buffer, &assoc->input_buffer_len);
126 case 0: case -1: /* connection closed by peer */
127 fprintf(stderr, "Closed connection\n");
129 destroy_association(assoc);
132 case 1: /* incomplete read */
135 assoc->input_apdu_len = res;
136 if (process_apdu(h) < 0)
138 fprintf(stderr, "Operation failed\n");
140 destroy_association(assoc);
143 else if (cs_more(conn)) /* arrange to be called again */
144 iochan_setevent(h, EVENT_INPUT);
147 else if (event == EVENT_OUTPUT)
149 switch (res = cs_put(conn, assoc->encode_buffer, assoc->encoded_len))
152 fprintf(stderr, "Closed connection\n");
154 destroy_association(assoc);
156 case 0: /* all sent */
157 iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset */
159 case 1: /* partial send */
160 break; /* we'll get called again */
163 else if (event == EVENT_EXCEPT)
165 fprintf(stderr, "Exception on line\n");
167 destroy_association(assoc);
172 static int process_apdu(IOCHAN chan)
176 association *assoc = iochan_getdata(chan);
178 odr_setbuf(assoc->decode, assoc->input_buffer, assoc->input_apdu_len);
179 if (!z_APDU(assoc->decode, &apdu, 0))
181 odr_perror(assoc->decode, "Incoming APDU");
186 case Z_APDU_initRequest:
187 res = process_initRequest(chan, apdu->u.initRequest); break;
188 case Z_APDU_searchRequest:
189 res = process_searchRequest(chan, apdu->u.searchRequest); break;
190 case Z_APDU_presentRequest:
191 res = process_presentRequest(chan, apdu->u.presentRequest); break;
193 fprintf(stderr, "Bad APDU\n");
196 odr_reset(assoc->decode);
200 static int process_initRequest(IOCHAN client, Z_InitRequest *req)
205 association *assoc = iochan_getdata(client);
206 bend_initrequest binitreq;
207 bend_initresult *binitres;
209 fprintf(stderr, "Got initRequest.\n");
210 if (req->implementationId)
211 fprintf(stderr, "Id: %s\n", req->implementationId);
212 if (req->implementationName)
213 fprintf(stderr, "Name: %s\n", req->implementationName);
214 if (req->implementationVersion)
215 fprintf(stderr, "Version: %s\n", req->implementationVersion);
217 binitreq.configname = "default-config";
218 if (!(binitres = bend_init(&binitreq)) || binitres->errcode)
220 fprintf(stderr, "Bad response from backend\n");
225 apdu.which = Z_APDU_initResponse;
226 apdu.u.initResponse = &resp;
227 resp.referenceId = req->referenceId;
228 resp.options = req->options; /* should check these */
229 resp.protocolVersion = req->protocolVersion;
230 assoc->maximumRecordSize = *req->maximumRecordSize;
231 if (assoc->maximumRecordSize > ENCODE_BUFFER_SIZE - 500)
232 assoc->maximumRecordSize = ENCODE_BUFFER_SIZE - 500;
233 assoc->preferredMessageSize = *req->preferredMessageSize;
234 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
235 assoc->preferredMessageSize = assoc->maximumRecordSize;
236 resp.preferredMessageSize = &assoc->preferredMessageSize;
237 resp.maximumRecordSize = &assoc->maximumRecordSize;
238 resp.result = &result;
239 resp.implementationId = "YAZ";
240 resp.implementationName = "YAZ/Simple asynchronous test server";
241 resp.implementationVersion = "$Revision: 1.8 $";
242 resp.userInformationField = 0;
243 if (!z_APDU(assoc->encode, &apdup, 0))
245 odr_perror(assoc->encode, "Encode initres");
248 odr_getbuf(assoc->encode, &assoc->encoded_len);
249 odr_reset(assoc->encode);
250 iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);
254 static Z_Records *diagrec(int error, char *addinfo)
256 static Z_Records rec;
257 static Odr_oid bib1[] = { 1, 2, 3, 4, 5, -1 };
261 fprintf(stderr, "Diagnostic: %d -- %s\n", error, addinfo ? addinfo :
264 rec.which = Z_Records_NSD;
265 rec.u.nonSurrogateDiagnostic = &dr;
266 dr.diagnosticSetId = bib1;
268 dr.addinfo = addinfo ? addinfo : "";
272 static Z_NamePlusRecord *surrogatediagrec(char *dbname, int error,
275 static Z_NamePlusRecord rec;
277 static Odr_oid bib1[] = { 1, 2, 3, 4, 5, -1 };
280 fprintf(stderr, "SurrogateDiagnotic: %d -- %s\n", error, addinfo);
281 rec.databaseName = dbname;
282 rec.which = Z_NamePlusRecord_surrogateDiagnostic;
283 rec.u.surrogateDiagnostic = &dr;
284 dr.diagnosticSetId = bib1;
286 dr.addinfo = addinfo ? addinfo : "";
290 #define MAX_RECORDS 50
292 static Z_Records *pack_records(association *a, char *setname, int start,
293 int *num, Z_ElementSetNames *esn,
294 int *next, int *pres)
296 int recno, total_length = 0, toget = *num;
297 static Z_Records records;
298 static Z_NamePlusRecordList reclist;
299 static Z_NamePlusRecord *list[MAX_RECORDS];
301 records.which = Z_Records_DBOSD;
302 records.u.databaseOrSurDiagnostics = &reclist;
303 reclist.num_records = 0;
304 reclist.records = list;
305 *pres = Z_PRES_SUCCESS;
309 for (recno = start; recno < toget; recno++)
311 bend_fetchrequest freq;
312 bend_fetchresult *fres;
313 Z_NamePlusRecord *thisrec;
314 Z_DatabaseRecord *thisext;
316 if (reclist.num_records == MAX_RECORDS - 1)
318 *pres = Z_PRES_PARTIAL_2;
321 freq.setname = setname;
323 if (!(fres = bend_fetch(&freq)))
325 *pres = Z_PRES_FAILURE;
326 return diagrec(2, "Backend interface problem");
328 /* backend should be able to signal whether error is system-wide
329 or only pertaining to current record */
332 *pres = Z_PRES_FAILURE;
333 return diagrec(fres->errcode, fres->errstring);
335 if (fres->len + total_length > a->preferredMessageSize)
337 /* record is small enough, really */
338 if (fres->len <= a->preferredMessageSize)
340 *pres = Z_PRES_PARTIAL_2;
343 /* record canonly be fetched by itself */
344 if (fres->len < a->maximumRecordSize)
348 reclist.records[reclist.num_records] =
349 surrogatediagrec(fres->basename, 16, 0);
350 reclist.num_records++;
351 *pres = Z_PRES_PARTIAL_2;
354 else /* too big entirely */
356 reclist.records[reclist.num_records] =
357 surrogatediagrec(fres->basename,
359 reclist.num_records++;
360 *pres = Z_PRES_PARTIAL_2;
363 if (!(thisrec = odr_malloc(a->encode, sizeof(*thisrec))))
365 if (!(thisrec->databaseName = odr_malloc(a->encode,
366 strlen(fres->basename) + 1)))
368 strcpy(thisrec->databaseName, fres->basename);
369 thisrec->which = Z_NamePlusRecord_databaseRecord;
370 if (!(thisrec->u.databaseRecord = thisext = odr_malloc(a->encode,
371 sizeof(Z_DatabaseRecord))))
373 thisext->direct_reference = 0; /* should be OID for current MARC */
374 thisext->indirect_reference = 0;
375 thisext->descriptor = 0;
376 thisext->which = ODR_EXTERNAL_octet;
377 if (!(thisext->u.octet_aligned = odr_malloc(a->encode,
380 if (!(thisext->u.octet_aligned->buf = odr_malloc(a->encode, fres->len)))
382 memcpy(thisext->u.octet_aligned->buf, fres->record, fres->len);
383 thisext->u.octet_aligned->len = thisext->u.octet_aligned->size =
385 reclist.records[reclist.num_records] = thisrec;
386 reclist.num_records++;
387 total_length = fres->len;
389 *next = fres->last_in_set ? 0 : recno + 1;
394 static int process_searchRequest(IOCHAN client, Z_SearchRequest *req)
397 Z_SearchResponse resp;
398 association *assoc = iochan_getdata(client);
402 bend_searchrequest bsrq;
403 bend_searchresult *bsrt;
405 fprintf(stderr, "Got SearchRequest.\n");
407 apdu.which = Z_APDU_searchResponse;
408 apdu.u.searchResponse = &resp;
409 resp.referenceId = req->referenceId;
411 bsrq.setname = req->resultSetName;
412 bsrq.replace_set = *req->replaceIndicator;
413 bsrq.num_bases = req->num_databaseNames;
414 bsrq.basenames = req->databaseNames;
415 bsrq.query = req->query;
417 if (!(bsrt = bend_search(&bsrq)))
419 else if (bsrt->errcode)
420 resp.records = diagrec(bsrt->errcode, bsrt->errstring);
424 resp.resultCount = &bsrt->hits;
425 resp.numberOfRecordsReturned = &nulint;
426 nrp = bsrt->hits ? 1 : 0;
427 resp.nextResultSetPosition = &nrp;
428 resp.searchStatus = &sr;
429 resp.resultSetStatus = &sr;
430 resp.presentStatus = 0;
432 if (!z_APDU(assoc->encode, &apdup, 0))
434 odr_perror(assoc->encode, "Encode searchres");
437 odr_getbuf(assoc->encode, &assoc->encoded_len);
438 odr_reset(assoc->encode);
439 iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);
443 static int process_presentRequest(IOCHAN client, Z_PresentRequest *req)
446 Z_PresentResponse resp;
447 association *assoc = iochan_getdata(client);
448 int presst, next, num;
450 fprintf(stderr, "Got PresentRequest.\n");
452 apdu.which = Z_APDU_presentResponse;
453 apdu.u.presentResponse = &resp;
454 resp.referenceId = req->referenceId;
456 num = *req->numberOfRecordsRequested;
457 resp.records = pack_records(assoc, req->resultSetId,
458 *req->resultSetStartPoint, &num, req->elementSetNames, &next, &presst);
461 resp.numberOfRecordsReturned = #
462 resp.presentStatus = &presst;
463 resp.nextResultSetPosition = &next;
465 if (!z_APDU(assoc->encode, &apdup, 0))
467 odr_perror(assoc->encode, "Encode presentres");
470 odr_getbuf(assoc->encode, &assoc->encoded_len);
471 odr_reset(assoc->encode);
472 iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);