More work on high-level server.
[yazpp-moved-to-github.git] / src / yaz-z-server.cpp
1 /*
2  * Copyright (c) 2000, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Log: yaz-z-server.cpp,v $
6  * Revision 1.2  2000-09-12 12:09:53  adam
7  * More work on high-level server.
8  *
9  * Revision 1.1  2000/09/08 10:23:42  adam
10  * Added skeleton of yaz-z-server.
11  *
12  */
13
14 #include <yaz/log.h>
15 #include <yaz-z-server.h>
16
17
18 Yaz_Z_Server::Yaz_Z_Server(IYaz_PDU_Observable *the_PDU_Observable)
19     : Yaz_Z_Assoc(the_PDU_Observable)
20 {
21 }
22
23 Z_Records *Yaz_Z_Server::pack_records (const char *resultSetName,
24                                        int start, int *num,
25                                        Z_RecordComposition *comp,
26                                        int *next, int *pres,
27                                        int *format)
28 {
29 #if 0
30     int recno, total_length = 0, toget = *num, dumped_records = 0;
31     Z_Records *records =
32         (Z_Records *) odr_malloc (odr_encode(), sizeof(*records));
33     Z_NamePlusRecordList *reclist =
34         (Z_NamePlusRecordList *) odr_malloc (odr_encode(), sizeof(*reclist));
35     Z_NamePlusRecord **list =
36         (Z_NamePlusRecord **) odr_malloc (odr_encode(), sizeof(*list) * toget);
37
38     records->which = Z_Records_DBOSD;
39     records->u.databaseOrSurDiagnostics = reclist;
40     reclist->num_records = 0;
41     reclist->records = list;
42     *pres = Z_PRES_SUCCESS;
43     *num = 0;
44     *next = 0;
45
46     yaz_log(LOG_LOG, "Request to pack %d+%d", start, toget);
47     yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", m_preferredMessageSize,
48         m_maximumRecordSize);
49     for (recno = start; reclist->num_records < toget; recno++)
50     {
51         Z_NamePlusRecord *rec =
52             (Z_NamePlusRecord *) odr_malloc (odr_encode(), sizeof(*rec));
53         rec->databaseName = 0;
54         rec->which = Z_NamePlusRecord_databaseRecord;
55         rec->u.databaseRecord = 0;
56
57         Z_DefaultDiagFormat *diagnostics = (Z_DefaultDiagFormat *)
58             odr_malloc (odr_encode(), sizeof(*diagnostics));
59         diagnostics->diagnosticSetId = 0;
60         diagnostics->condition = 0;
61         diagnostics->which = Z_DefaultDiagFormat_v2Addinfo;
62         
63         recv_Z_record (resultSetName, recno, format, comp, rec, diagnostics);
64
65         bend_fetch_rr freq;
66         Z_NamePlusRecord *thisrec;
67         int this_length = 0;
68         /*
69          * we get the number of bytes allocated on the stream before any
70          * allocation done by the backend - this should give us a reasonable
71          * idea of the total size of the data so far.
72          */
73         total_length = odr_total(a->encode) - dumped_records;
74         freq.errcode = 0;
75         freq.errstring = 0;
76         freq.basename = 0;
77         freq.len = 0;
78         freq.record = 0;
79         freq.last_in_set = 0;
80         freq.setname = setname;
81         freq.surrogate_flag = 0;
82         freq.number = recno;
83         freq.comp = comp;
84         freq.request_format = format;
85         freq.request_format_raw = oid;
86         freq.output_format = format;
87         freq.output_format_raw = 0;
88         freq.stream = a->encode;
89         freq.print = a->print;
90         freq.surrogate_flag = 0;
91         freq.referenceId = referenceId;
92         (*a->init->bend_fetch)(a->backend, &freq);
93         /* backend should be able to signal whether error is system-wide
94            or only pertaining to current record */
95         if (freq.errcode)
96         {
97             if (!freq.surrogate_flag)
98             {
99                 *pres = Z_PRES_FAILURE;
100                 return diagrec(a, freq.errcode, freq.errstring);
101             }
102             reclist->records[reclist->num_records] =
103                 surrogatediagrec(a, freq.basename, freq.errcode,
104                                  freq.errstring);
105             reclist->num_records++;
106             *next = freq.last_in_set ? 0 : recno + 1;
107             continue;
108         }
109         if (freq.len >= 0)
110             this_length = freq.len;
111         else
112             this_length = odr_total(a->encode) - total_length;
113         yaz_log(LOG_DEBUG, "  fetched record, len=%d, total=%d",
114             this_length, total_length);
115         if (this_length + total_length > a->preferredMessageSize)
116         {
117             /* record is small enough, really */
118             if (this_length <= a->preferredMessageSize)
119             {
120                 yaz_log(LOG_DEBUG, "  Dropped last normal-sized record");
121                 *pres = Z_PRES_PARTIAL_2;
122                 break;
123             }
124             /* record can only be fetched by itself */
125             if (this_length < a->maximumRecordSize)
126             {
127                 yaz_log(LOG_DEBUG, "  Record > prefmsgsz");
128                 if (toget > 1)
129                 {
130                     yaz_log(LOG_DEBUG, "  Dropped it");
131                     reclist->records[reclist->num_records] =
132                          surrogatediagrec(a, freq.basename, 16, 0);
133                     reclist->num_records++;
134                     *next = freq.last_in_set ? 0 : recno + 1;
135                     dumped_records += this_length;
136                     continue;
137                 }
138             }
139             else /* too big entirely */
140             {
141                 yaz_log(LOG_DEBUG, "Record > maxrcdsz");
142                 reclist->records[reclist->num_records] =
143                     surrogatediagrec(a, freq.basename, 17, 0);
144                 reclist->num_records++;
145                 *next = freq.last_in_set ? 0 : recno + 1;
146                 dumped_records += this_length;
147                 continue;
148             }
149         }
150
151         if (!(thisrec = (Z_NamePlusRecord *)
152               odr_malloc(a->encode, sizeof(*thisrec))))
153             return 0;
154         if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
155             strlen(freq.basename) + 1)))
156             return 0;
157         strcpy(thisrec->databaseName, freq.basename);
158         thisrec->which = Z_NamePlusRecord_databaseRecord;
159
160         if (freq.output_format_raw)
161         {
162             struct oident *ident = oid_getentbyoid(freq.output_format_raw);
163             freq.output_format = ident->value;
164         }
165         thisrec->u.databaseRecord = z_ext_record(a->encode, freq.output_format,
166                                                  freq.record, freq.len);
167         if (!thisrec->u.databaseRecord)
168             return 0;
169         reclist->records[reclist->num_records] = thisrec;
170         reclist->num_records++;
171         *next = freq.last_in_set ? 0 : recno + 1;
172     }
173     *num = reclist->num_records;
174     return records;
175 #endif
176     return 0;
177 }
178
179 void Yaz_Z_Server::piggyback (Z_SearchRequest *req,
180                               Z_SearchResponse *res)
181 {
182     bool_t *sr = (bool_t *)odr_malloc (odr_encode(), sizeof(*sr));
183     *sr = 1;
184     
185     int *next = (int *)odr_malloc (odr_encode(), sizeof(*next));
186     *next = 0;
187     
188     int *toget = (int *)odr_malloc (odr_encode(), sizeof(*toget));
189     *toget = 0;
190     
191     int *presst = (int *)odr_malloc (odr_encode(), sizeof(*presst));
192     *presst = 0;
193     
194     Z_RecordComposition comp, *compp = 0;
195     int hits = *res->resultCount;
196     
197     int *nulint = (int *)odr_malloc (odr_encode(), sizeof(*nulint));
198     *nulint = 0;
199     
200     res->records = 0;
201     
202     comp.which = Z_RecordComp_simple;
203     /* how many records does the user agent want, then? */
204     if (hits <= *req->smallSetUpperBound)
205     {
206         *toget = hits;
207         if ((comp.u.simple = req->smallSetElementSetNames))
208             compp = &comp;
209     }
210     else if (hits < *req->largeSetLowerBound)
211     {
212         *toget = *req->mediumSetPresentNumber;
213         if (*toget > hits)
214             *toget = hits;
215         if ((comp.u.simple = req->mediumSetElementSetNames))
216             compp = &comp;
217     }
218     else
219         *toget = 0;
220     
221     if (*toget && !res->records)
222     {
223         res->records =
224             pack_records(req->resultSetName, 1,
225                          toget, compp, next, presst,
226                          req->preferredRecordSyntax);
227         if (!res->records)
228             return;
229         res->numberOfRecordsReturned = toget;
230         res->nextResultSetPosition = next;
231         res->searchStatus = sr;
232         res->resultSetStatus = 0;
233         res->presentStatus = presst;
234     }
235     else
236     {
237         if (hits)
238             *next = 1;
239         res->numberOfRecordsReturned = nulint;
240         res->nextResultSetPosition = next;
241         res->searchStatus = sr;
242         res->resultSetStatus = 0;
243         res->presentStatus = 0;
244     }
245 }
246
247 void Yaz_Z_Server::recv_Z_PDU (Z_APDU *apdu_request)
248 {   
249     Z_APDU *apdu_response;
250     switch (apdu_request->which)
251     {
252     case Z_APDU_initRequest:
253         logf (LOG_LOG, "got InitRequest");
254         apdu_response = create_Z_PDU(Z_APDU_initResponse);
255         recv_Z_init (apdu_request->u.initRequest,
256                      apdu_response->u.initResponse);
257         send_Z_PDU(apdu_response);
258         break;
259     case Z_APDU_searchRequest:
260         logf (LOG_LOG, "got SearchRequest");
261         apdu_response = create_Z_PDU(Z_APDU_searchResponse);
262         recv_Z_search (apdu_request->u.searchRequest,
263                        apdu_response->u.searchResponse);
264         if (!apdu_response->u.searchResponse->records)
265         {
266             piggyback(apdu_request->u.searchRequest,
267                       apdu_response->u.searchResponse);
268         }
269         send_Z_PDU(apdu_response);
270         break;
271     case Z_APDU_presentRequest:
272         logf (LOG_LOG, "got PresentRequest");
273         apdu_response = create_Z_PDU(Z_APDU_presentResponse);
274         recv_Z_present (apdu_request->u.presentRequest,
275                         apdu_response->u.presentResponse);
276         send_Z_PDU(apdu_response);
277         break;
278     }
279 }
280