2 * Copyright (c) 1998-2000, Index Data.
3 * See the file LICENSE for details.
4 * Sebastian Hammer, Adam Dickmeiss
6 * $Log: yaz-proxy.cpp,v $
7 * Revision 1.14 2000-08-10 08:42:42 adam
8 * Fixes for {set,get}_APDU_log.
10 * Revision 1.13 2000/08/07 14:19:59 adam
11 * Fixed serious bug regarding timeouts. Improved logging for proxy.
13 * Revision 1.12 2000/07/04 13:48:49 adam
14 * Implemented upper-limit on proxy-to-target sessions.
16 * Revision 1.11 1999/12/06 13:52:45 adam
17 * Modified for new location of YAZ header files. Experimental threaded
20 * Revision 1.10 1999/11/10 10:02:34 adam
23 * Revision 1.9 1999/09/13 12:53:44 adam
24 * Proxy removes OtherInfo Proxy Address and Session ID. Other
25 * Otherinfo remains untouched.
27 * Revision 1.8 1999/05/04 10:53:00 adam
28 * Changed the way the PROXY behaves when lost cookie is received.
30 * Revision 1.7 1999/04/28 13:31:17 adam
31 * Better result set optimisation for proxy.
33 * Revision 1.6 1999/04/27 07:52:13 adam
34 * Improved proxy; added query match for result set re-use.
36 * Revision 1.5 1999/04/21 12:09:01 adam
37 * Many improvements. Modified to proxy server to work with "sessions"
40 * Revision 1.4 1999/04/20 10:30:05 adam
41 * Implemented various stuff for client and proxy. Updated calls
42 * to ODR to reflect new name parameter.
44 * Revision 1.3 1999/04/09 11:46:57 adam
45 * Added object Yaz_Z_Assoc. Much more functional client.
47 * Revision 1.2 1999/01/28 13:08:46 adam
48 * Yaz_PDU_Assoc better encapsulated. Memory leak fix in
49 * yaz-socket-manager.cc.
51 * Revision 1.1.1.1 1999/01/28 09:41:07 adam
52 * First implementation of YAZ++.
60 #include <yaz-proxy.h>
62 Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable) :
63 Yaz_Z_Assoc(the_PDU_Observable)
65 m_PDU_Observable = the_PDU_Observable;
76 Yaz_Proxy::~Yaz_Proxy()
78 xfree (m_proxyTarget);
81 void Yaz_Proxy::set_proxyTarget(const char *target)
83 xfree (m_proxyTarget);
86 m_proxyTarget = (char *) xstrdup (target);
89 IYaz_PDU_Observer *Yaz_Proxy::clone(IYaz_PDU_Observable
92 Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable);
93 new_proxy->m_parent = this;
94 new_proxy->timeout(120);
95 new_proxy->set_proxyTarget(m_proxyTarget);
96 new_proxy->set_APDU_log(get_APDU_log());
100 char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
103 Z_OtherInformationUnit *oi;
105 ent.proto = PROTO_Z3950;
106 ent.oclass = CLASS_USERINFO;
107 ent.value = (oid_value) VAL_COOKIE;
108 assert (oid_ent_to_oid (&ent, oid));
110 if (oid_ent_to_oid (&ent, oid) &&
111 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
112 oi->which == Z_OtherInfo_characterInfo)
113 return oi->information.characterInfo;
117 char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
120 Z_OtherInformationUnit *oi;
122 ent.proto = PROTO_Z3950;
123 ent.oclass = CLASS_USERINFO;
124 ent.value = (oid_value) VAL_PROXY;
125 if (oid_ent_to_oid (&ent, oid) &&
126 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
127 oi->which == Z_OtherInfo_characterInfo)
128 return oi->information.characterInfo;
132 Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu)
135 Yaz_Proxy *parent = m_parent;
136 Z_OtherInformation **oi;
137 Yaz_ProxyClient *c = m_client;
139 get_otherInfoAPDU(apdu, &oi);
140 char *cookie = get_cookie(oi);
141 logf (LOG_LOG, "Yaz_Proxy::get_client cookie=%s", cookie ? cookie :
145 for (c = parent->m_clientPool; c; c = c->m_next)
148 assert (*c->m_prev == c);
149 if (!strcmp(cookie,c->m_cookie))
151 logf (LOG_LOG, "Yaz_Proxy::get_client cached %s",
153 c->m_seqno = parent->m_seqno;
160 if (apdu->which == Z_APDU_initRequest)
162 logf (LOG_LOG, "got InitRequest");
164 const char *proxy_host =
165 get_proxy(&apdu->u.initRequest->otherInfo);
167 set_proxyTarget(proxy_host);
168 logf (LOG_LOG, "proxy_host = %s", m_proxyTarget ?
169 m_proxyTarget:"none");
173 logf (LOG_LOG, "no first INIT!");
179 Yaz_ProxyClient *c_min = 0;
181 int no_of_clients = 0;
182 for (c = parent->m_clientPool; c; c = c->m_next)
185 logf (LOG_LOG, "found seqno = %d", c->m_seqno);
186 if (min_seq < 0 || c->m_seqno < min_seq)
188 min_seq = c->m_seqno;
192 if (no_of_clients >= parent->m_max_clients)
195 logf (LOG_LOG, "Yaz_Proxy::get_client re-using session %d",
203 logf (LOG_LOG, "Yaz_Proxy::get_client making session %d",
205 c = new Yaz_ProxyClient(m_PDU_Observable->clone());
206 c->m_next = parent->m_clientPool;
208 c->m_next->m_prev = &c->m_next;
209 parent->m_clientPool = c;
210 c->m_prev = &parent->m_clientPool;
212 sprintf (c->m_cookie, "%lx.%d", m_seed, parent->m_seqno);
213 logf (LOG_LOG, "Yaz_Proxy::get_client connect to %s", m_proxyTarget);
214 c->m_seqno = parent->m_seqno;
215 c->client(m_proxyTarget);
218 delete c->m_last_query;
220 c->m_last_resultCount = 0;
221 c->m_sr_transform = 0;
230 Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
232 if (apdu->which != Z_APDU_searchRequest)
234 Z_SearchRequest *sr = apdu->u.searchRequest;
235 Yaz_Z_Query *this_query = new Yaz_Z_Query;
237 this_query->set_Z_Query(sr->query);
239 if (m_client->m_last_query &&
240 m_client->m_last_query->match(this_query))
243 if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
244 m_client->m_last_resultCount < *sr->largeSetLowerBound)
247 logf (LOG_LOG, "Yaz_Proxy::result_set_optimize medium set");
248 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
249 Z_PresentRequest *pr = new_apdu->u.presentRequest;
250 pr->referenceId = sr->referenceId;
251 pr->resultSetId = sr->resultSetName;
252 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
253 *pr->numberOfRecordsRequested = *sr->mediumSetPresentNumber;
254 if (sr->mediumSetElementSetNames)
256 pr->recordComposition = (Z_RecordComposition *)
257 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
258 pr->recordComposition->which = Z_RecordComp_simple;
259 pr->recordComposition->u.simple = sr->mediumSetElementSetNames;
261 m_client->m_sr_transform = 1;
264 else if (m_client->m_last_resultCount > *sr->largeSetLowerBound ||
265 m_client->m_last_resultCount == 0)
268 logf (LOG_LOG, "Yaz_Proxy::result_set_optimize large set");
269 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
270 new_apdu->u.searchResponse->referenceId = sr->referenceId;
271 new_apdu->u.searchResponse->resultCount =
272 &m_client->m_last_resultCount;
273 send_Z_PDU(new_apdu);
279 logf (LOG_LOG, "Yaz_Proxy::result_set_optimize small set");
280 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
281 Z_PresentRequest *pr = new_apdu->u.presentRequest;
282 pr->referenceId = sr->referenceId;
283 pr->resultSetId = sr->resultSetName;
284 pr->preferredRecordSyntax = sr->preferredRecordSyntax;
285 *pr->numberOfRecordsRequested = m_client->m_last_resultCount;
286 if (sr->smallSetElementSetNames)
288 pr->recordComposition = (Z_RecordComposition *)
289 odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
290 pr->recordComposition->which = Z_RecordComp_simple;
291 pr->recordComposition->u.simple = sr->smallSetElementSetNames;
293 m_client->m_sr_transform = 1;
299 logf (LOG_LOG, "Yaz_Proxy::result_set_optimize new set");
300 delete m_client->m_last_query;
301 m_client->m_last_query = this_query;
306 void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu)
308 logf (LOG_LOG, "Yaz_Proxy::recv_Z_PDU");
309 // Determine our client.
310 m_client = get_client(apdu);
316 m_client->m_server = this;
319 Z_OtherInformation **oi;
320 get_otherInfoAPDU(apdu, &oi);
324 if (apdu->which == Z_APDU_initRequest)
326 if (m_client->m_init_flag)
328 Z_APDU *apdu = create_Z_PDU(Z_APDU_initResponse);
329 if (m_client->m_cookie)
330 set_otherInformationString(apdu, VAL_COOKIE, 1,
335 m_client->m_init_flag = 1;
337 apdu = result_set_optimize(apdu);
341 logf (LOG_LOG, "Yaz_ProxyClient::send_Z_PDU %s", m_client->get_hostname());
342 if (m_client->send_Z_PDU(apdu) < 0)
349 void Yaz_Proxy::connectNotify()
353 void Yaz_Proxy::shutdown()
355 logf (LOG_LOG, "shutdown (client to proxy)");
358 // Tell client (if any) that no server connection is there..
360 m_client->m_server = 0;
369 void Yaz_ProxyClient::shutdown()
371 logf (LOG_LOG, "shutdown (proxy to server) %s", get_hostname());
376 void Yaz_Proxy::failNotify()
378 logf (LOG_LOG, "connection closed by client");
382 void Yaz_ProxyClient::failNotify()
384 logf (LOG_LOG, "Yaz_ProxyClient connection closed by %s", get_hostname());
388 void Yaz_ProxyClient::connectNotify()
390 logf (LOG_LOG, "Yaz_ProxyClient connection accept by %s", get_hostname());
393 IYaz_PDU_Observer *Yaz_ProxyClient::clone(IYaz_PDU_Observable
396 return new Yaz_ProxyClient(the_PDU_Observable);
399 Yaz_ProxyClient::~Yaz_ProxyClient()
405 m_next->m_prev = m_prev;
410 void Yaz_Proxy::timeoutNotify()
412 logf (LOG_LOG, "timeout (client to proxy)");
416 void Yaz_ProxyClient::timeoutNotify()
418 logf (LOG_LOG, "timeout (proxy to target) %s", get_hostname());
422 Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable) :
423 Yaz_Z_Assoc (the_PDU_Observable)
430 m_last_resultCount = 0;
434 void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu)
436 logf (LOG_LOG, "Yaz_ProxyClient::recv_Z_PDU %s", get_hostname());
437 if (apdu->which == Z_APDU_searchResponse)
438 m_last_resultCount = *apdu->u.searchResponse->resultCount;
439 if (apdu->which == Z_APDU_presentResponse && m_sr_transform)
442 Z_PresentResponse *pr = apdu->u.presentResponse;
443 Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
444 Z_SearchResponse *sr = new_apdu->u.searchResponse;
445 sr->referenceId = pr->referenceId;
446 *sr->resultCount = m_last_resultCount;
447 sr->records = pr->records;
448 sr->nextResultSetPosition = pr->nextResultSetPosition;
449 sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
453 set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
456 logf (LOG_LOG, "Yaz_Proxy::send_Z_PDU");
457 m_server->send_Z_PDU(apdu);