2 * Copyright (c) 1998-1999, Index Data.
3 * See the file LICENSE for details.
4 * Sebastian Hammer, Adam Dickmeiss
6 * $Log: yaz-proxy.cpp,v $
7 * Revision 1.9 1999-09-13 12:53:44 adam
8 * Proxy removes OtherInfo Proxy Address and Session ID. Other
9 * Otherinfo remains untouched.
11 * Revision 1.8 1999/05/04 10:53:00 adam
12 * Changed the way the PROXY behaves when lost cookie is received.
14 * Revision 1.7 1999/04/28 13:31:17 adam
15 * Better result set optimisation for proxy.
17 * Revision 1.6 1999/04/27 07:52:13 adam
18 * Improved proxy; added query match for result set re-use.
20 * Revision 1.5 1999/04/21 12:09:01 adam
21 * Many improvements. Modified to proxy server to work with "sessions"
24 * Revision 1.4 1999/04/20 10:30:05 adam
25 * Implemented various stuff for client and proxy. Updated calls
26 * to ODR to reflect new name parameter.
28 * Revision 1.3 1999/04/09 11:46:57 adam
29 * Added object Yaz_Z_Assoc. Much more functional client.
31 * Revision 1.2 1999/01/28 13:08:46 adam
32 * Yaz_PDU_Assoc better encapsulated. Memory leak fix in
33 * yaz-socket-manager.cc.
35 * Revision 1.1.1.1 1999/01/28 09:41:07 adam
36 * First implementation of YAZ++.
44 #include <yaz-proxy.h>
46 Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable) :
47 Yaz_Z_Assoc(the_PDU_Observable)
49 m_PDU_Observable = the_PDU_Observable;
57 Yaz_Proxy::~Yaz_Proxy()
61 IYaz_PDU_Observer *Yaz_Proxy::clone(IYaz_PDU_Observable
64 Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable);
65 new_proxy->m_parent = this;
66 new_proxy->timeout(120);
70 char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
73 Z_OtherInformationUnit *oi;
75 ent.proto = PROTO_Z3950;
76 ent.oclass = CLASS_USERINFO;
77 ent.value = (oid_value) VAL_COOKIE;
78 assert (oid_ent_to_oid (&ent, oid));
80 if (oid_ent_to_oid (&ent, oid) &&
81 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
82 oi->which == Z_OtherInfo_characterInfo)
83 return oi->information.characterInfo;
87 char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
90 Z_OtherInformationUnit *oi;
92 ent.proto = PROTO_Z3950;
93 ent.oclass = CLASS_USERINFO;
94 ent.value = (oid_value) VAL_PROXY;
95 if (oid_ent_to_oid (&ent, oid) &&
96 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
97 oi->which == Z_OtherInfo_characterInfo)
98 return oi->information.characterInfo;
102 Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu)
105 Yaz_Proxy *parent = m_parent;
106 Z_OtherInformation **oi;
107 Yaz_ProxyClient *c = m_client;
109 get_otherInfoAPDU(apdu, &oi);
110 char *cookie = get_cookie(oi);
111 logf (LOG_LOG, "Yaz_Proxy::get_client cookie=%s", cookie ? cookie :
115 for (c = parent->m_clientPool; c; c = c->m_next)
118 assert (*c->m_prev == c);
119 if (!strcmp(cookie,c->m_cookie))
121 logf (LOG_LOG, "Yaz_Proxy::get_client cached");
129 logf (LOG_LOG, "Yaz_Proxy::get_client creating new");
130 c = new Yaz_ProxyClient(m_PDU_Observable->clone());
131 c->m_next = parent->m_clientPool;
133 c->m_next->m_prev = &c->m_next;
134 parent->m_clientPool = c;
135 c->m_prev = &parent->m_clientPool;
137 sprintf (c->m_cookie, "%d", parent->m_seqno);
140 if (apdu->which == Z_APDU_initRequest)
142 logf (LOG_LOG, "got InitRequest");
144 char *proxy_host = get_proxy(&apdu->u.initRequest->otherInfo);
146 c->client(proxy_host);
148 c->client("localhost:9999");
155 Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
157 if (apdu->which != Z_APDU_searchRequest)
159 Z_SearchRequest *sr = apdu->u.searchRequest;
160 Yaz_Z_Query *this_query = new Yaz_Z_Query;
162 this_query->set_Z_Query(sr->query);
164 if (m_client->m_last_query &&
165 m_client->m_last_query->match(this_query))
168 if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
169 m_client->m_last_resultCount < *sr->largeSetLowerBound)
172 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
173 Z_PresentRequest *pr = new_apdu->u.presentRequest;
174 pr->referenceId = sr->referenceId;
175 pr->resultSetId = sr->resultSetName;
176 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
177 *pr->numberOfRecordsRequested = *sr->mediumSetPresentNumber;
178 if (sr->mediumSetElementSetNames)
180 pr->recordComposition = (Z_RecordComposition *)
181 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
182 pr->recordComposition->which = Z_RecordComp_simple;
183 pr->recordComposition->u.simple = sr->mediumSetElementSetNames;
185 m_client->m_sr_transform = 1;
188 else if (m_client->m_last_resultCount >= *sr->largeSetLowerBound ||
189 m_client->m_last_resultCount == 0)
192 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
193 new_apdu->u.searchResponse->referenceId = sr->referenceId;
194 new_apdu->u.searchResponse->resultCount =
195 &m_client->m_last_resultCount;
196 send_Z_PDU(new_apdu);
202 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
203 Z_PresentRequest *pr = new_apdu->u.presentRequest;
204 pr->referenceId = sr->referenceId;
205 pr->resultSetId = sr->resultSetName;
206 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
207 *pr->numberOfRecordsRequested = m_client->m_last_resultCount;
208 if (sr->smallSetElementSetNames)
210 pr->recordComposition = (Z_RecordComposition *)
211 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
212 pr->recordComposition->which = Z_RecordComp_simple;
213 pr->recordComposition->u.simple = sr->smallSetElementSetNames;
215 m_client->m_sr_transform = 1;
221 logf (LOG_LOG, "query doesn't match");
222 delete m_client->m_last_query;
223 m_client->m_last_query = this_query;
228 void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu)
230 logf (LOG_LOG, "Yaz_Proxy::recv_Z_PDU");
231 // Determine our client.
232 m_client = get_client(apdu);
238 m_client->m_server = this;
241 Z_OtherInformation **oi;
242 get_otherInfoAPDU(apdu, &oi);
246 if (apdu->which == Z_APDU_initRequest)
248 if (m_client->m_init_flag)
250 Z_APDU *apdu = create_Z_PDU(Z_APDU_initResponse);
251 if (m_client->m_cookie)
252 set_otherInformationString(apdu, VAL_COOKIE, 1,
257 m_client->m_init_flag = 1;
259 apdu = result_set_optimize(apdu);
263 logf (LOG_LOG, "Yaz_ProxyClient::send_Z_PDU");
264 if (m_client->send_Z_PDU(apdu) < 0)
271 void Yaz_Proxy::failNotify()
273 logf (LOG_LOG, "failNotity server");
276 // Tell client (if any) that no server connection is there..
278 m_client->m_server = 0;
287 void Yaz_ProxyClient::failNotify()
289 logf (LOG_LOG, "failNotity client");
294 IYaz_PDU_Observer *Yaz_ProxyClient::clone(IYaz_PDU_Observable
297 return new Yaz_ProxyClient(the_PDU_Observable);
300 Yaz_ProxyClient::~Yaz_ProxyClient()
306 m_next->m_prev = m_prev;
311 void Yaz_Proxy::timeoutNotify()
316 void Yaz_ProxyClient::timeoutNotify()
321 Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable) :
322 Yaz_Z_Assoc (the_PDU_Observable)
329 m_last_resultCount = 0;
333 void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu)
335 logf (LOG_LOG, "Yaz_ProxyClient::recv_Z_PDU");
336 if (apdu->which == Z_APDU_searchResponse)
337 m_last_resultCount = *apdu->u.searchResponse->resultCount;
338 if (apdu->which == Z_APDU_presentResponse && m_sr_transform)
341 Z_PresentResponse *pr = apdu->u.presentResponse;
342 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
343 Z_SearchResponse *sr = new_apdu->u.searchResponse;
344 sr->referenceId = pr->referenceId;
345 *sr->resultCount = m_last_resultCount;
346 sr->records = pr->records;
347 sr->nextResultSetPosition = pr->nextResultSetPosition;
348 sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
352 set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
355 logf (LOG_LOG, "Yaz_Proxy::send_Z_PDU");
356 m_server->send_Z_PDU(apdu);