+void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
+{
+ int i;
+ for (i = 0; i<num; i++)
+ {
+ oident *ent;
+ Z_DefaultDiagFormat *r;
+ Z_DiagRec *p = pp[i];
+ if (p->which != Z_DiagRec_defaultFormat)
+ {
+ yaz_log(LOG_LOG, "%s Error no diagnostics", m_session_str);
+ return;
+ }
+ else
+ r = p->u.defaultFormat;
+ if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
+ ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
+ yaz_log(LOG_LOG, "%s Error unknown diagnostic set", m_session_str);
+ switch (r->which)
+ {
+ case Z_DefaultDiagFormat_v2Addinfo:
+ yaz_log(LOG_LOG, "%s Error %d %s:%s",
+ m_session_str,
+ *r->condition, diagbib1_str(*r->condition),
+ r->u.v2Addinfo);
+ break;
+ case Z_DefaultDiagFormat_v3Addinfo:
+ yaz_log(LOG_LOG, "%s Error %d %s:%s",
+ m_session_str,
+ *r->condition, diagbib1_str(*r->condition),
+ r->u.v3Addinfo);
+ break;
+ }
+ }
+}
+
+int Yaz_Proxy::send_to_client(Z_APDU *apdu)
+{
+ int len = 0;
+ if (apdu->which == Z_APDU_searchResponse)
+ {
+ Z_SearchResponse *sr = apdu->u.searchResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+
+ display_diagrecs(&dr_p, 1);
+ }
+ else
+ {
+ if (sr->resultCount)
+ yaz_log(LOG_LOG, "%s %d hits", m_session_str,
+ *sr->resultCount);
+ }
+ }
+ else if (apdu->which == Z_APDU_presentResponse)
+ {
+ Z_PresentResponse *sr = apdu->u.presentResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+
+ display_diagrecs(&dr_p, 1);
+ }
+ }
+ int r = send_Z_PDU(apdu, &len);
+ yaz_log (LOG_LOG, "%s Sending %s to client %d bytes", m_session_str,
+ apdu_name(apdu), len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ return r;
+}
+
+int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
+{
+ int len = 0;
+ int r = send_Z_PDU(apdu, &len);
+ yaz_log (LOG_LOG, "%s Sending %s to %s %d bytes",
+ get_session_str(),
+ apdu_name(apdu), get_hostname(), len);
+ m_bytes_sent += len;
+ return r;
+}
+
+Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
+{
+ if (*m_parent->m_optimize == '0')
+ return apdu; // don't optimize result sets..
+ if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ Z_NamePlusRecordList *npr;
+ int toget = *pr->numberOfRecordsRequested;
+ int start = *pr->resultSetStartPoint;
+
+ if (m_client->m_last_resultSetId &&
+ !strcmp(m_client->m_last_resultSetId, pr->resultSetId))
+ {
+ if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget,
+ pr->preferredRecordSyntax,
+ pr->recordComposition))
+ {
+ yaz_log (LOG_LOG, "%s Returned cache records for present request",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+ new_apdu->u.presentResponse->referenceId = pr->referenceId;
+
+ new_apdu->u.presentResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.presentResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.presentResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.presentResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.presentResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), start+toget);
+
+ send_to_client(new_apdu);
+ return 0;
+ }
+ }
+ }
+
+ if (apdu->which != Z_APDU_searchRequest)
+ return apdu;
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ Yaz_Z_Query *this_query = new Yaz_Z_Query;
+ Yaz_Z_Databases this_databases;
+
+ this_databases.set(sr->num_databaseNames, (const char **)
+ sr->databaseNames);
+
+ this_query->set_Z_Query(sr->query);
+
+ char query_str[80];
+ this_query->print(query_str, sizeof(query_str)-1);
+ yaz_log(LOG_LOG, "%s Query %s", m_session_str, query_str);
+
+ if (m_client->m_last_ok && m_client->m_last_query &&
+ m_client->m_last_query->match(this_query) &&
+ !strcmp(m_client->m_last_resultSetId, sr->resultSetName) &&
+ m_client->m_last_databases.match(this_databases))
+ {
+ delete this_query;
+ if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
+ m_client->m_last_resultCount < *sr->largeSetLowerBound)
+ {
+ Z_NamePlusRecordList *npr;
+ int toget = *sr->mediumSetPresentNumber;
+ Z_RecordComposition *comp = 0;
+
+ if (toget > m_client->m_last_resultCount)
+ toget = m_client->m_last_resultCount;
+
+ if (sr->mediumSetElementSetNames)
+ {
+ comp = (Z_RecordComposition *)
+ odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
+ comp->which = Z_RecordComp_simple;
+ comp->u.simple = sr->mediumSetElementSetNames;
+ }
+
+ if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
+ sr->preferredRecordSyntax, comp))
+ {
+ yaz_log (LOG_LOG, "%s Returned cache records for medium set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+
+ new_apdu->u.searchResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.searchResponse->presentStatus =
+ odr_intdup(odr_encode(), Z_PresentStatus_success);
+ new_apdu->u.searchResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.searchResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), toget+1);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ // medium Set
+ // send present request (medium size)
+ yaz_log (LOG_LOG, "%s Optimizing search for medium set",
+ m_session_str);
+
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
+ Z_PresentRequest *pr = new_apdu->u.presentRequest;
+ pr->referenceId = sr->referenceId;
+ pr->resultSetId = sr->resultSetName;
+ pr->preferredRecordSyntax = sr->preferredRecordSyntax;
+ *pr->numberOfRecordsRequested = toget;
+ pr->recordComposition = comp;
+ m_client->m_sr_transform = 1;
+ return new_apdu;
+ }
+ }
+ else if (m_client->m_last_resultCount >= *sr->largeSetLowerBound ||
+ m_client->m_last_resultCount <= 0)
+ {
+ // large set. Return pseudo-search response immediately
+ yaz_log (LOG_LOG, "%s Optimizing search for large set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ Z_NamePlusRecordList *npr;
+ int toget = m_client->m_last_resultCount;
+ Z_RecordComposition *comp = 0;
+ // small set
+ // send a present request (small set)
+
+ if (sr->smallSetElementSetNames)
+ {
+ comp = (Z_RecordComposition *)
+ odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
+ comp->which = Z_RecordComp_simple;
+ comp->u.simple = sr->smallSetElementSetNames;
+ }
+
+ if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
+ sr->preferredRecordSyntax, comp))
+ {
+ yaz_log (LOG_LOG, "%s Returned cache records for small set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+
+ new_apdu->u.searchResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.searchResponse->presentStatus =
+ odr_intdup(odr_encode(), Z_PresentStatus_success);
+ new_apdu->u.searchResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.searchResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), toget+1);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%s Optimizing search for small set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
+ Z_PresentRequest *pr = new_apdu->u.presentRequest;
+ pr->referenceId = sr->referenceId;
+ pr->resultSetId = sr->resultSetName;
+ pr->preferredRecordSyntax = sr->preferredRecordSyntax;
+ *pr->numberOfRecordsRequested = toget;
+ pr->recordComposition = comp;
+ m_client->m_sr_transform = 1;
+ return new_apdu;
+ }
+ }
+ }
+ else
+ {
+ delete m_client->m_last_query;
+ m_client->m_last_query = this_query;
+ m_client->m_last_ok = 0;
+ m_client->m_cache.clear();
+ m_client->m_resultSetStartPoint = 0;
+
+ xfree (m_client->m_last_resultSetId);
+ m_client->m_last_resultSetId = xstrdup (sr->resultSetName);
+
+ m_client->m_last_databases.set(sr->num_databaseNames,
+ (const char **) sr->databaseNames);
+ }
+ return apdu;
+}
+
+
+void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu, int len)
+{
+ int reduce = 0;
+ m_bytes_recv += len;
+
+ yaz_log (LOG_LOG, "%s Receiving %s from client %d bytes", m_session_str,
+ apdu_name(apdu), len);
+
+ if (m_bw_hold_PDU) // double incoming PDU. shutdown now.
+ shutdown();
+
+ m_bw_stat.add_bytes(len);
+ m_pdu_stat.add_bytes(1);
+
+ int bw_total = m_bw_stat.get_total();
+ int pdu_total = m_pdu_stat.get_total();
+
+ yaz_log(LOG_LOG, "%s stat bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+ m_session_str, bw_total, pdu_total, m_bw_max, m_pdu_max);
+ if (m_bw_max)
+ {
+ if (bw_total > m_bw_max)
+ {
+ reduce = (bw_total/m_bw_max);
+ }
+ }
+ if (m_pdu_max)
+ {
+ if (pdu_total > m_pdu_max)
+ {
+ int nreduce = (60/m_pdu_max);
+ reduce = (reduce > nreduce) ? reduce : nreduce;
+ }
+ }
+ if (reduce)
+ {
+ yaz_log(LOG_LOG, "%s Limit delay=%d", m_session_str, reduce);
+ m_bw_hold_PDU = apdu; // save PDU and signal "on hold"
+ timeout(reduce); // call us reduce seconds later
+ }
+ else
+ recv_Z_PDU_0(apdu); // all fine. Proceed receive PDU as usual
+}
+
+void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)