2 * Copyright (c) 2000, Index Data.
3 * See the file LICENSE for details.
5 * $Log: yaz-z-server.cpp,v $
6 * Revision 1.3 2000-09-21 21:43:20 adam
7 * Better high-level server API.
9 * Revision 1.2 2000/09/12 12:09:53 adam
10 * More work on high-level server.
12 * Revision 1.1 2000/09/08 10:23:42 adam
13 * Added skeleton of yaz-z-server.
18 #include <yaz-z-server.h>
21 Yaz_Z_Server::Yaz_Z_Server(IYaz_PDU_Observable *the_PDU_Observable)
22 : Yaz_Z_Assoc(the_PDU_Observable)
29 void Yaz_Z_Server::create_databaseRecord (
30 Z_NamePlusRecord *rec, const char *dbname, int format, const void *buf, int len)
32 rec->databaseName = dbname ? odr_strdup (odr_encode(), dbname) : 0;
33 rec->which = Z_NamePlusRecord_databaseRecord;
34 rec->u.databaseRecord = z_ext_record (odr_encode(), format,
35 (const char *) buf, len);
39 * surrogate diagnostic.
41 void Yaz_Z_Server::create_surrogateDiagnostics(
42 Z_NamePlusRecord *rec, const char *dbname, int error, char *const addinfo)
45 int *err = (int *)odr_malloc (odr_encode(), sizeof(*err));
47 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (odr_encode(), sizeof(*drec));
48 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
49 odr_malloc (odr_encode(), sizeof(*dr));
51 bib1.proto = PROTO_Z3950;
52 bib1.oclass = CLASS_DIAGSET;
53 bib1.value = VAL_BIB1;
55 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
57 rec->databaseName = dbname ? odr_strdup (odr_encode(), dbname) : 0;
58 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
59 rec->u.surrogateDiagnostic = drec;
60 drec->which = Z_DiagRec_defaultFormat;
61 drec->u.defaultFormat = dr;
62 dr->diagnosticSetId = odr_oiddup (odr_encode(),
63 oid_ent_to_oid(&bib1, oid));
65 dr->which = Z_DefaultDiagFormat_v2Addinfo;
66 dr->u.v2Addinfo = odr_strdup (odr_encode(), addinfo ? addinfo : "");
69 Z_Records *Yaz_Z_Server::create_nonSurrogateDiagnostics (
70 int error, const char *addinfo)
73 Z_Records *rec = (Z_Records *)
74 odr_malloc (odr_encode(), sizeof(*rec));
77 odr_malloc (odr_encode(), sizeof(*err));
78 Z_DiagRec *drec = (Z_DiagRec *)
79 odr_malloc (odr_encode(), sizeof(*drec));
80 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
81 odr_malloc (odr_encode(), sizeof(*dr));
83 bib1.proto = PROTO_Z3950;
84 bib1.oclass = CLASS_DIAGSET;
85 bib1.value = VAL_BIB1;
88 rec->which = Z_Records_NSD;
89 rec->u.nonSurrogateDiagnostic = dr;
91 odr_oiddup (odr_encode(), oid_ent_to_oid(&bib1, oid));
93 dr->which = Z_DefaultDiagFormat_v2Addinfo;
94 dr->u.v2Addinfo = odr_strdup (odr_encode(), addinfo ? addinfo : "");
98 Z_Records *Yaz_Z_Server::pack_records (const char *resultSetName,
100 Z_RecordComposition *comp,
101 int *next, int *pres,
104 int recno, total_length = 0, toget = xnum, dumped_records = 0;
106 (Z_Records *) odr_malloc (odr_encode(), sizeof(*records));
107 Z_NamePlusRecordList *reclist =
108 (Z_NamePlusRecordList *) odr_malloc (odr_encode(), sizeof(*reclist));
109 Z_NamePlusRecord **list =
110 (Z_NamePlusRecord **) odr_malloc (odr_encode(), sizeof(*list) * toget);
112 records->which = Z_Records_DBOSD;
113 records->u.databaseOrSurDiagnostics = reclist;
114 reclist->num_records = 0;
115 reclist->records = list;
116 *pres = Z_PRES_SUCCESS;
119 yaz_log(LOG_LOG, "Request to pack %d+%d", start, toget);
120 yaz_log(LOG_LOG, "pms=%d, mrs=%d", m_preferredMessageSize,
121 m_maximumRecordSize);
122 for (recno = start; reclist->num_records < toget; recno++)
124 Z_NamePlusRecord *this_rec =
125 (Z_NamePlusRecord *) odr_malloc (odr_encode(), sizeof(*this_rec));
126 this_rec->databaseName = 0;
127 this_rec->which = Z_NamePlusRecord_databaseRecord;
128 this_rec->u.databaseRecord = 0;
132 recv_Z_record (resultSetName, recno, format, comp, this_rec, records);
134 if (records->which != Z_Records_DBOSD)
136 *pres = Z_PRES_FAILURE;
140 if (this_rec->which == Z_NamePlusRecord_databaseRecord &&
141 this_rec->u.databaseRecord == 0)
142 { // handler did not return a record..
143 create_surrogateDiagnostics(this_rec, 0, 14, 0);
146 * we get the number of bytes allocated on the stream before any
147 * allocation done by the backend - this should give us a reasonable
148 * idea of the total size of the data so far.
150 total_length = odr_total(odr_encode()) - dumped_records;
151 this_length = odr_total(odr_encode()) - total_length;
152 yaz_log(LOG_LOG, " fetched record, len=%d, total=%d",
153 this_length, total_length);
154 if (this_length + total_length > m_preferredMessageSize)
156 /* record is small enough, really */
157 if (this_length <= m_preferredMessageSize)
159 yaz_log(LOG_LOG, " Dropped last normal-sized record");
160 *pres = Z_PRES_PARTIAL_2;
163 if (this_length >= m_maximumRecordSize)
164 { /* too big entirely */
165 yaz_log(LOG_LOG, "Record > maxrcdsz");
166 reclist->records[reclist->num_records] = this_rec;
167 create_surrogateDiagnostics(this_rec,
168 this_rec->databaseName, 17, 0);
169 reclist->num_records++;
171 dumped_records += this_length;
174 else /* record can only be fetched by itself */
176 yaz_log(LOG_LOG, " Record > prefmsgsz");
179 yaz_log(LOG_DEBUG, " Dropped it");
180 reclist->records[reclist->num_records] = this_rec;
181 create_surrogateDiagnostics(this_rec,
182 this_rec->databaseName,
184 reclist->num_records++;
185 // *next = freq.last_in_set ? 0 : recno + 1;
187 dumped_records += this_length;
192 reclist->records[reclist->num_records] = this_rec;
193 reclist->num_records++;
199 void Yaz_Z_Server::fetch_via_piggyback (Z_SearchRequest *req,
200 Z_SearchResponse *res)
202 bool_t *sr = (bool_t *)odr_malloc (odr_encode(), sizeof(*sr));
207 Z_RecordComposition comp, *compp = 0;
208 int hits = *res->resultCount;
210 int *nulint = (int *)odr_malloc (odr_encode(), sizeof(*nulint));
213 comp.which = Z_RecordComp_simple;
214 /* how many records does the user agent want, then? */
215 if (hits <= *req->smallSetUpperBound)
218 if ((comp.u.simple = req->smallSetElementSetNames))
221 else if (hits < *req->largeSetLowerBound)
223 toget = *req->mediumSetPresentNumber;
226 if ((comp.u.simple = req->mediumSetElementSetNames))
230 if (toget && !res->records)
232 res->presentStatus = (int *) odr_malloc (odr_encode(), sizeof(int));
233 *res->presentStatus = Z_PRES_SUCCESS;
235 pack_records(req->resultSetName, 1, toget, compp,
236 res->nextResultSetPosition,
238 req->preferredRecordSyntax);
241 if (res->records->which == Z_Records_DBOSD)
242 *res->numberOfRecordsReturned =
243 res->records->u.databaseOrSurDiagnostics->num_records;
244 res->searchStatus = sr;
245 res->resultSetStatus = 0;
250 *res->nextResultSetPosition = 1;
251 res->numberOfRecordsReturned = nulint;
252 res->searchStatus = sr;
253 res->resultSetStatus = 0;
254 res->presentStatus = 0;
258 void Yaz_Z_Server::fetch_via_present (Z_PresentRequest *req,
259 Z_PresentResponse *res)
261 res->records = pack_records (req->resultSetId,*req->resultSetStartPoint,
262 *req->numberOfRecordsRequested,
263 req->recordComposition,
264 res->nextResultSetPosition,
266 req->preferredRecordSyntax);
267 if (res->records->which == Z_Records_DBOSD)
268 *res->numberOfRecordsReturned =
269 res->records->u.databaseOrSurDiagnostics->num_records;
272 void Yaz_Z_Server::recv_Z_PDU (Z_APDU *apdu_request)
274 Z_APDU *apdu_response;
275 switch (apdu_request->which)
277 case Z_APDU_initRequest:
278 logf (LOG_LOG, "got InitRequest");
279 apdu_response = create_Z_PDU(Z_APDU_initResponse);
280 recv_Z_init (apdu_request->u.initRequest,
281 apdu_response->u.initResponse);
282 m_preferredMessageSize =
283 *apdu_request->u.initRequest->preferredMessageSize;
284 m_maximumRecordSize =
285 *apdu_request->u.initRequest->maximumRecordSize;
286 send_Z_PDU(apdu_response);
288 case Z_APDU_searchRequest:
289 logf (LOG_LOG, "got SearchRequest");
290 apdu_response = create_Z_PDU(Z_APDU_searchResponse);
291 recv_Z_search (apdu_request->u.searchRequest,
292 apdu_response->u.searchResponse);
293 if (!apdu_response->u.searchResponse->records)
295 fetch_via_piggyback(apdu_request->u.searchRequest,
296 apdu_response->u.searchResponse);
298 send_Z_PDU(apdu_response);
300 case Z_APDU_presentRequest:
301 logf (LOG_LOG, "got PresentRequest");
302 apdu_response = create_Z_PDU(Z_APDU_presentResponse);
303 recv_Z_present (apdu_request->u.presentRequest,
304 apdu_response->u.presentResponse);
305 if (!apdu_response->u.presentResponse->records)
306 fetch_via_present(apdu_request->u.presentRequest,
307 apdu_response->u.presentResponse);
308 send_Z_PDU(apdu_response);