2 * Copyright (C) 1994, Index Data I/S
4 * Sebastian Hammer, Adam Dickmeiss
7 * Revision 1.9 1995-03-22 15:01:26 quinn
8 * Adjusting record packing.
10 * Revision 1.8 1995/03/22 10:13:21 quinn
11 * Working on record packer
13 * Revision 1.7 1995/03/21 15:53:31 quinn
16 * Revision 1.6 1995/03/21 12:30:09 quinn
17 * Beginning to add support for record packing.
19 * Revision 1.5 1995/03/17 10:44:13 quinn
20 * Added catch of null-string in makediagrec
22 * Revision 1.4 1995/03/17 10:18:08 quinn
23 * Added memory management.
25 * Revision 1.3 1995/03/16 17:42:39 quinn
28 * Revision 1.2 1995/03/16 13:29:01 quinn
31 * Revision 1.1 1995/03/15 16:02:10 quinn
32 * Modded session.c to seshigh.c
48 #define ENCODE_BUFFER_SIZE 10000
50 static int process_apdu(IOCHAN chan);
51 static int process_initRequest(IOCHAN client, Z_InitRequest *req);
52 static int process_searchRequest(IOCHAN client, Z_SearchRequest *req);
53 static int process_presentRequest(IOCHAN client, Z_PresentRequest *req);
55 association *create_association(IOCHAN channel, COMSTACK link)
59 if (!(new = malloc(sizeof(*new))))
61 new->client_chan = channel;
62 new->client_link = link;
63 if (!(new->decode = odr_createmem(ODR_DECODE)) ||
64 !(new->encode = odr_createmem(ODR_ENCODE)))
66 if (!(new->encode_buffer = malloc(ENCODE_BUFFER_SIZE)))
68 odr_setbuf(new->encode, new->encode_buffer, ENCODE_BUFFER_SIZE);
69 new->state = ASSOC_UNINIT;
70 new->input_buffer = 0;
71 new->input_buffer_len = 0;
75 void destroy_association(association *h)
77 odr_destroy(h->decode);
78 odr_destroy(h->encode);
79 free(h->encode_buffer);
81 free(h->input_buffer);
85 void ir_session(IOCHAN h, int event)
88 association *assoc = iochan_getdata(h);
89 COMSTACK conn = assoc->client_link;
91 if (event == EVENT_INPUT)
93 assert(assoc && conn);
94 res = cs_get(conn, &assoc->input_buffer, &assoc->input_buffer_len);
97 case 0: case -1: /* connection closed by peer */
98 fprintf(stderr, "Closed connection\n");
100 destroy_association(assoc);
103 case 1: /* incomplete read */
106 assoc->input_apdu_len = res;
107 if (process_apdu(h) < 0)
109 fprintf(stderr, "Operation failed\n");
111 destroy_association(assoc);
114 else if (cs_more(conn)) /* arrange to be called again */
115 iochan_setevent(h, EVENT_INPUT);
118 else if (event == EVENT_OUTPUT)
120 switch (res = cs_put(conn, assoc->encode_buffer, assoc->encoded_len))
123 fprintf(stderr, "Closed connection\n");
125 destroy_association(assoc);
127 case 0: /* all sent */
128 iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset */
130 case 1: /* partial send */
131 break; /* we'll get called again */
134 else if (event == EVENT_EXCEPT)
136 fprintf(stderr, "Exception on line\n");
138 destroy_association(assoc);
143 static int process_apdu(IOCHAN chan)
147 association *assoc = iochan_getdata(chan);
149 odr_setbuf(assoc->decode, assoc->input_buffer, assoc->input_apdu_len);
150 if (!z_APDU(assoc->decode, &apdu, 0))
152 odr_perror(assoc->decode, "Incoming APDU");
157 case Z_APDU_initRequest:
158 res = process_initRequest(chan, apdu->u.initRequest); break;
159 case Z_APDU_searchRequest:
160 res = process_searchRequest(chan, apdu->u.searchRequest); break;
161 case Z_APDU_presentRequest:
162 res = process_presentRequest(chan, apdu->u.presentRequest); break;
164 fprintf(stderr, "Bad APDU\n");
167 odr_reset(assoc->decode); /* release incopming APDU */
168 odr_reset(assoc->encode); /* release stuff alloced before encoding */
172 static int process_initRequest(IOCHAN client, Z_InitRequest *req)
177 association *assoc = iochan_getdata(client);
178 bend_initrequest binitreq;
179 bend_initresult *binitres;
181 fprintf(stderr, "Got initRequest.\n");
182 if (req->implementationId)
183 fprintf(stderr, "Id: %s\n", req->implementationId);
184 if (req->implementationName)
185 fprintf(stderr, "Name: %s\n", req->implementationName);
186 if (req->implementationVersion)
187 fprintf(stderr, "Version: %s\n", req->implementationVersion);
189 binitreq.configname = "default-config";
190 if (!(binitres = bend_init(&binitreq)) || binitres->errcode)
192 fprintf(stderr, "Bad response from backend\n");
197 apdu.which = Z_APDU_initResponse;
198 apdu.u.initResponse = &resp;
199 resp.referenceId = req->referenceId;
200 resp.options = req->options; /* should check these */
201 resp.protocolVersion = req->protocolVersion;
202 assoc->maximumRecordSize = *req->maximumRecordSize;
204 * This is not so hot. The big todo for ODR is dynamic memory allocation
207 if (assoc->maximumRecordSize > ENCODE_BUFFER_SIZE - 1000)
208 assoc->maximumRecordSize = ENCODE_BUFFER_SIZE - 1000;
209 assoc->preferredMessageSize = *req->preferredMessageSize;
210 if (assoc->preferredMessageSize > assoc->maximumRecordSize)
211 assoc->preferredMessageSize = assoc->maximumRecordSize;
212 resp.preferredMessageSize = &assoc->preferredMessageSize;
213 resp.maximumRecordSize = &assoc->maximumRecordSize;
214 resp.result = &result;
215 resp.implementationId = "YAZ";
216 resp.implementationName = "YAZ/Simple asynchronous test server";
217 resp.implementationVersion = "$Revision: 1.9 $";
218 resp.userInformationField = 0;
219 if (!z_APDU(assoc->encode, &apdup, 0))
221 odr_perror(assoc->encode, "Encode initres");
224 odr_getbuf(assoc->encode, &assoc->encoded_len);
225 odr_reset(assoc->encode);
226 iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);
230 static Z_Records *diagrec(int error, char *addinfo)
232 static Z_Records rec;
233 static Odr_oid bib1[] = { 1, 2, 3, 4, 5, -1 };
237 fprintf(stderr, "Diagnostic: %d -- %s\n", error, addinfo ? addinfo :
240 rec.which = Z_Records_NSD;
241 rec.u.nonSurrogateDiagnostic = &dr;
242 dr.diagnosticSetId = bib1;
244 dr.addinfo = addinfo ? addinfo : "";
248 static Z_NamePlusRecord *surrogatediagrec(char *dbname, int error,
251 static Z_NamePlusRecord rec;
253 static Odr_oid bib1[] = { 1, 2, 3, 4, 5, -1 };
256 fprintf(stderr, "SurrogateDiagnotic: %d -- %s\n", error, addinfo);
258 rec.databaseName = dbname;
259 rec.which = Z_NamePlusRecord_surrogateDiagnostic;
260 rec.u.surrogateDiagnostic = &dr;
261 dr.diagnosticSetId = bib1;
263 dr.addinfo = addinfo ? addinfo : "";
267 #define MAX_RECORDS 256
269 static Z_Records *pack_records(association *a, char *setname, int start,
270 int *num, Z_ElementSetNames *esn,
271 int *next, int *pres)
273 int recno, total_length = 0, toget = *num;
274 static Z_Records records;
275 static Z_NamePlusRecordList reclist;
276 static Z_NamePlusRecord *list[MAX_RECORDS];
278 records.which = Z_Records_DBOSD;
279 records.u.databaseOrSurDiagnostics = &reclist;
280 reclist.num_records = 0;
281 reclist.records = list;
282 *pres = Z_PRES_SUCCESS;
286 fprintf(stderr, "Request to pack %d+%d\n", start, toget);
287 fprintf(stderr, "pms=%d, mrs=%d\n", a->preferredMessageSize,
288 a->maximumRecordSize);
289 for (recno = start; reclist.num_records < toget; recno++)
291 bend_fetchrequest freq;
292 bend_fetchresult *fres;
293 Z_NamePlusRecord *thisrec;
294 Z_DatabaseRecord *thisext;
296 if (reclist.num_records == MAX_RECORDS - 1)
298 *pres = Z_PRES_PARTIAL_2;
301 freq.setname = setname;
303 if (!(fres = bend_fetch(&freq)))
305 *pres = Z_PRES_FAILURE;
306 return diagrec(2, "Backend interface problem");
308 /* backend should be able to signal whether error is system-wide
309 or only pertaining to current record */
312 *pres = Z_PRES_FAILURE;
313 return diagrec(fres->errcode, fres->errstring);
315 fprintf(stderr, " Got record, len=%d, total=%d\n",
316 fres->len, total_length);
317 if (fres->len + total_length > a->preferredMessageSize)
319 fprintf(stderr, " In drop-zone\n");
320 /* record is small enough, really */
321 if (fres->len <= a->preferredMessageSize)
323 fprintf(stderr, " Dropped last normal-sized record\n");
324 *pres = Z_PRES_PARTIAL_2;
327 /* record can only be fetched by itself */
328 if (fres->len < a->maximumRecordSize)
330 fprintf(stderr, " Record > prefmsgsz\n");
333 fprintf(stderr, " Dropped it\n");
334 reclist.records[reclist.num_records] =
335 surrogatediagrec(fres->basename, 16, 0);
336 reclist.num_records++;
337 *pres = Z_PRES_PARTIAL_2;
341 else /* too big entirely */
343 fprintf(stderr, "Record > maxrcdsz\n");
344 reclist.records[reclist.num_records] =
345 surrogatediagrec(fres->basename,
347 reclist.num_records++;
348 *pres = Z_PRES_PARTIAL_2;
352 if (!(thisrec = odr_malloc(a->encode, sizeof(*thisrec))))
354 if (!(thisrec->databaseName = odr_malloc(a->encode,
355 strlen(fres->basename) + 1)))
357 strcpy(thisrec->databaseName, fres->basename);
358 thisrec->which = Z_NamePlusRecord_databaseRecord;
359 if (!(thisrec->u.databaseRecord = thisext = odr_malloc(a->encode,
360 sizeof(Z_DatabaseRecord))))
362 thisext->direct_reference = 0; /* should be OID for current MARC */
363 thisext->indirect_reference = 0;
364 thisext->descriptor = 0;
365 thisext->which = ODR_EXTERNAL_octet;
366 if (!(thisext->u.octet_aligned = odr_malloc(a->encode,
369 if (!(thisext->u.octet_aligned->buf = odr_malloc(a->encode, fres->len)))
371 memcpy(thisext->u.octet_aligned->buf, fres->record, fres->len);
372 thisext->u.octet_aligned->len = thisext->u.octet_aligned->size =
374 reclist.records[reclist.num_records] = thisrec;
375 reclist.num_records++;
376 total_length += fres->len;
378 *next = fres->last_in_set ? 0 : recno + 1;
383 static int process_searchRequest(IOCHAN client, Z_SearchRequest *req)
386 Z_SearchResponse resp;
387 association *assoc = iochan_getdata(client);
391 bend_searchrequest bsrq;
392 bend_searchresult *bsrt;
394 fprintf(stderr, "Got SearchRequest.\n");
396 apdu.which = Z_APDU_searchResponse;
397 apdu.u.searchResponse = &resp;
398 resp.referenceId = req->referenceId;
400 bsrq.setname = req->resultSetName;
401 bsrq.replace_set = *req->replaceIndicator;
402 bsrq.num_bases = req->num_databaseNames;
403 bsrq.basenames = req->databaseNames;
404 bsrq.query = req->query;
406 if (!(bsrt = bend_search(&bsrq)))
408 else if (bsrt->errcode)
409 resp.records = diagrec(bsrt->errcode, bsrt->errstring);
413 resp.resultCount = &bsrt->hits;
414 resp.numberOfRecordsReturned = &nulint;
415 nrp = bsrt->hits ? 1 : 0;
416 resp.nextResultSetPosition = &nrp;
417 resp.searchStatus = &sr;
418 resp.resultSetStatus = &sr;
419 resp.presentStatus = 0;
421 if (!z_APDU(assoc->encode, &apdup, 0))
423 odr_perror(assoc->encode, "Encode searchres");
426 odr_getbuf(assoc->encode, &assoc->encoded_len);
427 odr_reset(assoc->encode);
428 iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);
432 static int process_presentRequest(IOCHAN client, Z_PresentRequest *req)
435 Z_PresentResponse resp;
436 association *assoc = iochan_getdata(client);
437 int presst, next, num;
439 fprintf(stderr, "Got PresentRequest.\n");
441 apdu.which = Z_APDU_presentResponse;
442 apdu.u.presentResponse = &resp;
443 resp.referenceId = req->referenceId;
445 num = *req->numberOfRecordsRequested;
446 resp.records = pack_records(assoc, req->resultSetId,
447 *req->resultSetStartPoint, &num, req->elementSetNames, &next, &presst);
450 resp.numberOfRecordsReturned = #
451 resp.presentStatus = &presst;
452 resp.nextResultSetPosition = &next;
454 if (!z_APDU(assoc->encode, &apdup, 0))
456 odr_perror(assoc->encode, "Encode presentres");
459 odr_getbuf(assoc->encode, &assoc->encoded_len);
460 odr_reset(assoc->encode);
461 iochan_setflags(client, EVENT_OUTPUT | EVENT_EXCEPT);