* Copyright (c) 1998-2003, Index Data.
* See the file LICENSE for details.
*
- * $Id: yaz-proxy.cpp,v 1.48 2003-10-01 13:13:51 adam Exp $
+ * $Id: yaz-proxy.cpp,v 1.53 2003-10-08 09:49:05 adam Exp $
*/
#include <assert.h>
return "other";
}
-
Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable) :
Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
{
return 0;
}
+const char *Yaz_Proxy::load_balance(const char **url)
+{
+ int zurl_in_use[MAX_ZURL_PLEX];
+ Yaz_ProxyClient *c;
+ int i;
+
+ for (i = 0; i<MAX_ZURL_PLEX; i++)
+ zurl_in_use[i] = 0;
+ for (c = m_parent->m_clientPool; c; c = c->m_next)
+ {
+ for (i = 0; url[i]; i++)
+ if (!strcmp(url[i], c->get_hostname()))
+ zurl_in_use[i]++;
+ }
+ int min = 100000;
+ const char *ret = 0;
+ for (i = 0; url[i]; i++)
+ {
+ yaz_log(LOG_DEBUG, "%s zurl=%s use=%d",
+ m_session_str, url[i], zurl_in_use[i]);
+ if (min > zurl_in_use[i])
+ {
+ ret = url[i];
+ min = zurl_in_use[i];
+ }
+ }
+ return ret;
+}
+
Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu)
{
assert (m_parent);
if (!m_proxyTarget)
{
+ const char *url[MAX_ZURL_PLEX];
const char *proxy_host = get_proxy(oi);
- if (!proxy_host)
+ if (proxy_host)
+ {
+ xfree(m_default_target);
+ m_default_target = xstrdup(proxy_host);
proxy_host = m_default_target;
+ }
- const char *url = 0;
- m_config.get_target_info(proxy_host, &url, &m_keepalive, &m_bw_max,
- &m_pdu_max, &m_max_record_retrieve);
-
- if (!url)
+ int client_idletime = -1;
+ m_config.get_target_info(proxy_host, url, &m_keepalive, &m_bw_max,
+ &m_pdu_max, &m_max_record_retrieve,
+ &m_target_idletime, &client_idletime,
+ &parent->m_max_clients);
+ if (client_idletime != -1)
+ {
+ m_client_idletime = client_idletime;
+ timeout(m_client_idletime);
+ }
+ if (!url[0])
{
yaz_log(LOG_LOG, "%s No default target", m_session_str);
return 0;
}
- m_proxyTarget = (char*) xstrdup(url);
+ // we don't handle multiplexing for cookie session, so we just
+ // pick the first one in this case (anonymous users will be able
+ // to use any backend)
+ if (cookie && *cookie)
+ m_proxyTarget = (char*) xstrdup(url[0]);
+ else
+ m_proxyTarget = (char*) xstrdup(load_balance(url));
}
if (cookie && *cookie)
{
int min_seq = -1;
int no_of_clients = 0;
if (parent->m_clientPool)
- yaz_log (LOG_LOG, "Existing sessions");
+ yaz_log (LOG_DEBUG, "Existing sessions");
for (c = parent->m_clientPool; c; c = c->m_next)
{
- yaz_log (LOG_LOG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
+ yaz_log (LOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
c->m_waiting, c->get_hostname(),
c->m_cookie ? c->m_cookie : "");
no_of_clients++;
}
}
}
- else
+ else // query doesn't match
{
delete m_client->m_last_query;
m_client->m_last_query = this_query;
}
}
+Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
+ int error,
+ const char *addinfo)
+{
+ Z_Records *rec = (Z_Records *)
+ odr_malloc (odr, sizeof(*rec));
+ int *err = (int *)
+ odr_malloc (odr, sizeof(*err));
+ Z_DiagRec *drec = (Z_DiagRec *)
+ odr_malloc (odr, sizeof(*drec));
+ Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
+ odr_malloc (odr, sizeof(*dr));
+ *err = error;
+ rec->which = Z_Records_NSD;
+ rec->u.nonSurrogateDiagnostic = dr;
+ dr->diagnosticSetId =
+ yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
+ dr->condition = err;
+ dr->which = Z_DefaultDiagFormat_v2Addinfo;
+ dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
+ return rec;
+}
+
+Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_searchRequest)
+ {
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ int err;
+ char *addinfo = 0;
+ err = m_config.check_query(odr_encode(), m_default_target, sr->query,
+ &addinfo);
+ if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ return apdu;
+}
+
+Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_searchRequest)
+ {
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ if (*sr->smallSetUpperBound > 0 || *sr->largeSetLowerBound > 1)
+ {
+ int err;
+ char *addinfo = 0;
+ err = m_config.check_syntax(odr_encode(), m_default_target,
+ sr->preferredRecordSyntax,
+ &addinfo);
+ if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ }
+ else if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ int err;
+ char *addinfo = 0;
+ err = m_config.check_syntax(odr_encode(), m_default_target,
+ pr->preferredRecordSyntax,
+ &addinfo);
+ if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+
+ new_apdu->u.presentResponse->referenceId = pr->referenceId;
+ new_apdu->u.presentResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.presentResponse->presentStatus =
+ Z_PresentStatus_failure;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ return apdu;
+}
+
void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu)
{
// Determine our client.
if (apdu->which == Z_APDU_initRequest)
{
+ if (apdu->u.initRequest->implementationId)
+ yaz_log(LOG_LOG, "%s implementationId: %s",
+ m_session_str, apdu->u.initRequest->implementationId);
+ if (apdu->u.initRequest->implementationName)
+ yaz_log(LOG_LOG, "%s implementationName: %s",
+ m_session_str, apdu->u.initRequest->implementationName);
+ if (apdu->u.initRequest->implementationVersion)
+ yaz_log(LOG_LOG, "%s implementationVersion: %s",
+ m_session_str, apdu->u.initRequest->implementationVersion);
if (m_client->m_init_flag)
{
Z_APDU *apdu = m_client->m_initResponse;
}
handle_max_record_retrieve(apdu);
- apdu = result_set_optimize(apdu);
+ if (apdu)
+ apdu = handle_syntax_validation(apdu);
+
+ if (apdu)
+ apdu = handle_query_validation(apdu);
+
+ if (apdu)
+ apdu = result_set_optimize(apdu);
if (!apdu)
+ {
+ m_client->timeout(m_target_idletime); // mark it active even
+ // though we didn't use it
return;
+ }
// delete other info part from PDU before sending to target
Z_OtherInformation **oi;
odr_reset (m_init_odr);
nmem_transfer (m_init_odr->mem, nmem);
m_initResponse = apdu;
+
+ Z_InitResponse *ir = apdu->u.initResponse;
+ char *im0 = ir->implementationName;
+
+ char *im1 = (char*)
+ odr_malloc(m_init_odr, 20 + (im0 ? strlen(im0) : 0));
+ *im1 = '\0';
+ if (im0)
+ {
+ strcat(im1, im0);
+ strcat(im1, " ");
+ }
+ strcat(im1, "(YAZ Proxy)");
+ ir->implementationName = im1;
+
nmem_destroy (nmem);
}
if (apdu->which == Z_APDU_searchResponse)
sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
apdu = new_apdu;
}
- if (pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
+ if (pr->records &&
+ pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
{
m_cache.add(odr_decode(),
pr->records->u.databaseOrSurDiagnostics,