2 * Copyright (c) 2000, Index Data.
3 * See the file LICENSE for details.
5 * $Log: yaz-z-server.cpp,v $
6 * Revision 1.6 2001-01-29 11:18:24 adam
7 * Server sets OPTIONS search and present.
9 * Revision 1.5 2000/10/24 12:29:57 adam
10 * Fixed bug in proxy where a Yaz_ProxyClient could be owned by
11 * two Yaz_Proxy's (fatal).
13 * Revision 1.4 2000/10/11 11:58:17 adam
14 * Moved header files to include/yaz++. Switched to libtool and automake.
15 * Configure script creates yaz++-config script.
17 * Revision 1.3 2000/09/21 21:43:20 adam
18 * Better high-level server API.
20 * Revision 1.2 2000/09/12 12:09:53 adam
21 * More work on high-level server.
23 * Revision 1.1 2000/09/08 10:23:42 adam
24 * Added skeleton of yaz-z-server.
29 #include <yaz++/yaz-z-server.h>
32 Yaz_Z_Server::Yaz_Z_Server(IYaz_PDU_Observable *the_PDU_Observable)
33 : Yaz_Z_Assoc(the_PDU_Observable)
40 void Yaz_Z_Server::create_databaseRecord (
41 Z_NamePlusRecord *rec, const char *dbname, int format, const void *buf, int len)
43 rec->databaseName = dbname ? odr_strdup (odr_encode(), dbname) : 0;
44 rec->which = Z_NamePlusRecord_databaseRecord;
45 rec->u.databaseRecord = z_ext_record (odr_encode(), format,
46 (const char *) buf, len);
50 * surrogate diagnostic.
52 void Yaz_Z_Server::create_surrogateDiagnostics(
53 Z_NamePlusRecord *rec, const char *dbname, int error, char *const addinfo)
56 int *err = (int *)odr_malloc (odr_encode(), sizeof(*err));
58 Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (odr_encode(), sizeof(*drec));
59 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
60 odr_malloc (odr_encode(), sizeof(*dr));
62 bib1.proto = PROTO_Z3950;
63 bib1.oclass = CLASS_DIAGSET;
64 bib1.value = VAL_BIB1;
66 yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
68 rec->databaseName = dbname ? odr_strdup (odr_encode(), dbname) : 0;
69 rec->which = Z_NamePlusRecord_surrogateDiagnostic;
70 rec->u.surrogateDiagnostic = drec;
71 drec->which = Z_DiagRec_defaultFormat;
72 drec->u.defaultFormat = dr;
73 dr->diagnosticSetId = odr_oiddup (odr_encode(),
74 oid_ent_to_oid(&bib1, oid));
76 dr->which = Z_DefaultDiagFormat_v2Addinfo;
77 dr->u.v2Addinfo = odr_strdup (odr_encode(), addinfo ? addinfo : "");
80 Z_Records *Yaz_Z_Server::create_nonSurrogateDiagnostics (
81 int error, const char *addinfo)
84 Z_Records *rec = (Z_Records *)
85 odr_malloc (odr_encode(), sizeof(*rec));
88 odr_malloc (odr_encode(), sizeof(*err));
89 Z_DiagRec *drec = (Z_DiagRec *)
90 odr_malloc (odr_encode(), sizeof(*drec));
91 Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
92 odr_malloc (odr_encode(), sizeof(*dr));
94 bib1.proto = PROTO_Z3950;
95 bib1.oclass = CLASS_DIAGSET;
96 bib1.value = VAL_BIB1;
99 rec->which = Z_Records_NSD;
100 rec->u.nonSurrogateDiagnostic = dr;
101 dr->diagnosticSetId =
102 odr_oiddup (odr_encode(), oid_ent_to_oid(&bib1, oid));
104 dr->which = Z_DefaultDiagFormat_v2Addinfo;
105 dr->u.v2Addinfo = odr_strdup (odr_encode(), addinfo ? addinfo : "");
109 Z_Records *Yaz_Z_Server::pack_records (const char *resultSetName,
111 Z_RecordComposition *comp,
112 int *next, int *pres,
115 int recno, total_length = 0, toget = xnum, dumped_records = 0;
117 (Z_Records *) odr_malloc (odr_encode(), sizeof(*records));
118 Z_NamePlusRecordList *reclist =
119 (Z_NamePlusRecordList *) odr_malloc (odr_encode(), sizeof(*reclist));
120 Z_NamePlusRecord **list =
121 (Z_NamePlusRecord **) odr_malloc (odr_encode(), sizeof(*list) * toget);
123 records->which = Z_Records_DBOSD;
124 records->u.databaseOrSurDiagnostics = reclist;
125 reclist->num_records = 0;
126 reclist->records = list;
127 *pres = Z_PRES_SUCCESS;
130 yaz_log(LOG_LOG, "Request to pack %d+%d", start, toget);
131 yaz_log(LOG_LOG, "pms=%d, mrs=%d", m_preferredMessageSize,
132 m_maximumRecordSize);
133 for (recno = start; reclist->num_records < toget; recno++)
135 Z_NamePlusRecord *this_rec =
136 (Z_NamePlusRecord *) odr_malloc (odr_encode(), sizeof(*this_rec));
137 this_rec->databaseName = 0;
138 this_rec->which = Z_NamePlusRecord_databaseRecord;
139 this_rec->u.databaseRecord = 0;
143 recv_Z_record (resultSetName, recno, format, comp, this_rec, records);
145 if (records->which != Z_Records_DBOSD)
147 *pres = Z_PRES_FAILURE;
151 if (this_rec->which == Z_NamePlusRecord_databaseRecord &&
152 this_rec->u.databaseRecord == 0)
153 { // handler did not return a record..
154 create_surrogateDiagnostics(this_rec, 0, 14, 0);
157 * we get the number of bytes allocated on the stream before any
158 * allocation done by the backend - this should give us a reasonable
159 * idea of the total size of the data so far.
161 total_length = odr_total(odr_encode()) - dumped_records;
162 this_length = odr_total(odr_encode()) - total_length;
163 yaz_log(LOG_LOG, " fetched record, len=%d, total=%d",
164 this_length, total_length);
165 if (this_length + total_length > m_preferredMessageSize)
167 /* record is small enough, really */
168 if (this_length <= m_preferredMessageSize)
170 yaz_log(LOG_LOG, " Dropped last normal-sized record");
171 *pres = Z_PRES_PARTIAL_2;
174 if (this_length >= m_maximumRecordSize)
175 { /* too big entirely */
176 yaz_log(LOG_LOG, "Record > maxrcdsz");
177 reclist->records[reclist->num_records] = this_rec;
178 create_surrogateDiagnostics(this_rec,
179 this_rec->databaseName, 17, 0);
180 reclist->num_records++;
182 dumped_records += this_length;
185 else /* record can only be fetched by itself */
187 yaz_log(LOG_LOG, " Record > prefmsgsz");
190 yaz_log(LOG_DEBUG, " Dropped it");
191 reclist->records[reclist->num_records] = this_rec;
192 create_surrogateDiagnostics(this_rec,
193 this_rec->databaseName,
195 reclist->num_records++;
196 // *next = freq.last_in_set ? 0 : recno + 1;
198 dumped_records += this_length;
203 reclist->records[reclist->num_records] = this_rec;
204 reclist->num_records++;
210 void Yaz_Z_Server::fetch_via_piggyback (Z_SearchRequest *req,
211 Z_SearchResponse *res)
213 bool_t *sr = (bool_t *)odr_malloc (odr_encode(), sizeof(*sr));
218 Z_RecordComposition comp, *compp = 0;
219 int hits = *res->resultCount;
221 int *nulint = (int *)odr_malloc (odr_encode(), sizeof(*nulint));
224 comp.which = Z_RecordComp_simple;
225 /* how many records does the user agent want, then? */
226 if (hits <= *req->smallSetUpperBound)
229 if ((comp.u.simple = req->smallSetElementSetNames))
232 else if (hits < *req->largeSetLowerBound)
234 toget = *req->mediumSetPresentNumber;
237 if ((comp.u.simple = req->mediumSetElementSetNames))
241 if (toget && !res->records)
243 res->presentStatus = (int *) odr_malloc (odr_encode(), sizeof(int));
244 *res->presentStatus = Z_PRES_SUCCESS;
246 pack_records(req->resultSetName, 1, toget, compp,
247 res->nextResultSetPosition,
249 req->preferredRecordSyntax);
252 if (res->records->which == Z_Records_DBOSD)
253 *res->numberOfRecordsReturned =
254 res->records->u.databaseOrSurDiagnostics->num_records;
255 res->searchStatus = sr;
256 res->resultSetStatus = 0;
261 *res->nextResultSetPosition = 1;
262 res->numberOfRecordsReturned = nulint;
263 res->searchStatus = sr;
264 res->resultSetStatus = 0;
265 res->presentStatus = 0;
269 void Yaz_Z_Server::fetch_via_present (Z_PresentRequest *req,
270 Z_PresentResponse *res)
272 res->records = pack_records (req->resultSetId,*req->resultSetStartPoint,
273 *req->numberOfRecordsRequested,
274 req->recordComposition,
275 res->nextResultSetPosition,
277 req->preferredRecordSyntax);
278 if (res->records->which == Z_Records_DBOSD)
279 *res->numberOfRecordsReturned =
280 res->records->u.databaseOrSurDiagnostics->num_records;
283 void Yaz_Z_Server::recv_Z_PDU (Z_APDU *apdu_request)
285 Z_Options *req, *res;
286 Z_APDU *apdu_response;
287 switch (apdu_request->which)
289 case Z_APDU_initRequest:
290 logf (LOG_LOG, "got InitRequest p=%p", this);
291 apdu_response = create_Z_PDU(Z_APDU_initResponse);
292 req = apdu_request->u.initRequest->options;
293 res = apdu_response->u.initResponse->options;
295 if (ODR_MASK_GET(req, Z_Options_search))
296 ODR_MASK_SET(res, Z_Options_search);
297 if (ODR_MASK_GET(req, Z_Options_present))
298 ODR_MASK_SET(res, Z_Options_present);
299 recv_Z_init (apdu_request->u.initRequest,
300 apdu_response->u.initResponse);
301 m_preferredMessageSize =
302 *apdu_request->u.initRequest->preferredMessageSize;
303 m_maximumRecordSize =
304 *apdu_request->u.initRequest->maximumRecordSize;
305 send_Z_PDU(apdu_response);
307 case Z_APDU_searchRequest:
308 logf (LOG_LOG, "got SearchRequest p=%p", this);
309 apdu_response = create_Z_PDU(Z_APDU_searchResponse);
310 recv_Z_search (apdu_request->u.searchRequest,
311 apdu_response->u.searchResponse);
312 if (!apdu_response->u.searchResponse->records)
314 fetch_via_piggyback(apdu_request->u.searchRequest,
315 apdu_response->u.searchResponse);
317 send_Z_PDU(apdu_response);
319 case Z_APDU_presentRequest:
320 logf (LOG_LOG, "got PresentRequest p=%p", this);
321 apdu_response = create_Z_PDU(Z_APDU_presentResponse);
322 recv_Z_present (apdu_request->u.presentRequest,
323 apdu_response->u.presentResponse);
324 if (!apdu_response->u.presentResponse->records)
325 fetch_via_present(apdu_request->u.presentRequest,
326 apdu_response->u.presentResponse);
327 send_Z_PDU(apdu_response);