Using USEMARCON 3 API.
[yazproxy-moved-to-github.git] / src / yaz-proxy.cpp
index 5707846..926d5b4 100644 (file)
@@ -1,5 +1,5 @@
-/* $Id: yaz-proxy.cpp,v 1.73 2007-04-12 18:18:42 adam Exp $
-   Copyright (c) 1998-2007, Index Data.
+/* $Id: yaz-proxy.cpp,v 1.78 2008-02-21 09:33:23 adam Exp $
+   Copyright (c) 1998-2008, Index Data.
 
 This file is part of the yazproxy.
 
@@ -220,6 +220,7 @@ Yaz_Proxy::Yaz_Proxy(IPDU_Observable *the_PDU_Observable,
     m_seed = time(0);
     m_client_idletime = 600;
     m_target_idletime = 600;
+    m_max_sockets = 1024;
     m_optimize = xstrdup ("1");
     strcpy(m_session_str, "0 ");
     m_session_no = 0;
@@ -399,7 +400,6 @@ Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
     if (m_reconfig_flag)
     {
         yaz_log(YLOG_LOG, "reconfigure");
-        yaz_log_reopen();
         if (m_config_fname && cfg)
         {
             yaz_log(YLOG_LOG, "reconfigure config %s", m_config_fname);
@@ -484,25 +484,20 @@ IPDU_Observer *Yaz_Proxy::sessionNotify(IPDU_Observable
 
 char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
 {
-    Z_OtherInformationUnit *oi;
-    const int *oid = yaz_string_to_oid(yaz_oid_std(),
-                                       CLASS_USERINFO, OID_STR_COOKIE);
+    Z_OtherInformationUnit *oi =
+        update_otherInformation(otherInfo, 0, yaz_oid_userinfo_cookie, 1, 1);
     
-    if (oid &&
-        (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
-        oi->which == Z_OtherInfo_characterInfo)
+    if (oi && oi->which == Z_OtherInfo_characterInfo)
         return oi->information.characterInfo;
     return 0;
 }
 
 char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
 {
-    Z_OtherInformationUnit *oi;
-    const int *oid = yaz_string_to_oid(yaz_oid_std(),
-                                       CLASS_USERINFO, OID_STR_COOKIE);
-    if (oid &&
-        (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
-        oi->which == Z_OtherInfo_characterInfo)
+    Z_OtherInformationUnit *oi =
+        update_otherInformation(otherInfo, 0, yaz_oid_userinfo_proxy, 1, 1);
+    
+    if (oi && oi->which == Z_OtherInfo_characterInfo)
         return oi->information.characterInfo;
     return 0;
 }
@@ -552,8 +547,27 @@ const char *Yaz_Proxy::load_balance(const char **url)
     return ret_min;
 }
 
+int Yaz_Proxy::get_number_of_connections()
+{
+    int no_connections = 0;
+    Yaz_ProxyClient *c;
+
+    for (c = m_parent->m_clientPool; c; c = c->m_next)
+    {
+        assert(c->m_prev);
+        assert(*c->m_prev == c);
+        if (!strcmp(m_proxyTarget, c->get_hostname()))
+        {
+            no_connections++;
+        }
+    }
+    yaz_log (YLOG_LOG, "%sExisting %s connections: %d", m_session_str, m_proxyTarget,
+        no_connections);
+    return no_connections;
+}
+
 Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
-                                       const char *proxy_host)
+                                       const char *proxy_host, int *http_code)
 {
     assert (m_parent);
     Yaz_Proxy *parent = m_parent;
@@ -590,6 +604,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
                                  &m_pdu_max, &m_max_record_retrieve,
                                  &m_search_max,
                                  &m_target_idletime, &client_idletime,
+                                 &m_max_sockets,
                                  &parent->m_max_clients,
                                  &m_keepalive_limit_bw,
                                  &m_keepalive_limit_pdu,
@@ -685,7 +700,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
         {
             assert(c->m_prev);
             assert(*c->m_prev == c);
-            if (c->m_server == 0 && c->m_cookie == 0 &&  c->m_waiting == 0 
+            if (c->m_server == 0 && c->m_cookie == 0 && c->m_waiting == 0 
                 && c->compare_idAuthentication(apdu)
                 && c->compare_charset(apdu)
                 && !strcmp(m_proxyTarget, c->get_hostname()))
@@ -716,6 +731,16 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
         if (apdu->which != Z_APDU_initRequest)
         {
             yaz_log (YLOG_LOG, "%sno init request as first PDU", m_session_str);
+            *http_code = 500;
+            return 0;
+        }
+
+        int no_in_use = get_number_of_connections();
+        if (no_in_use >= m_max_sockets)
+        {
+            yaz_log (YLOG_LOG, "%smax sockets reached %d", m_session_str,
+                m_max_sockets);
+            *http_code = 500;
             return 0;
         }
         // go through list of clients - and find the lowest/oldest one.
@@ -775,6 +800,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
         }
         else
         {
+
             yaz_log (YLOG_LOG, "%sNEW %d %s",
                      m_session_str, parent->m_seqno, m_proxyTarget);
             c = new Yaz_ProxyClient(m_PDU_Observable->clone(), parent);
@@ -893,11 +919,9 @@ void Yaz_Proxy::convert_xsl_delay()
                 xmlChar *out_buf;
                 int out_len;
                 xmlDocDumpFormatMemory (res, &out_buf, &out_len, 1);
-                const int *oid = yaz_string_to_oid(yaz_oid_std(),
-                                                   CLASS_RECSYN, OID_STR_XML);
                 m_stylesheet_nprl->records[m_stylesheet_offset]->
                     u.databaseRecord =
-                    z_ext_record_oid(odr_encode(), oid,
+                    z_ext_record_oid(odr_encode(), yaz_oid_recsyn_xml,
                                      (char*) out_buf, out_len);
                 xmlFree(out_buf);
                 xmlFreeDoc(res);
@@ -937,53 +961,30 @@ void Yaz_Proxy::convert_to_frontend_type(Z_NamePlusRecordList *p)
                 Z_External *r = npr->u.databaseRecord;
                 if (r->which == Z_External_octet)
                 {
-#if HAVE_USEMARCON
+#if !HAVE_USEMARCON
                     if (m_usemarcon_ini_stage1 && *m_usemarcon_ini_stage1)
+                        yaz_log (YLOG_LOG, "%sError: USEMARCON requested but not available",
+                            m_session_str);
+#endif
+#if HAVE_USEMARCON
+                    yaz_log (YLOG_DEBUG, "%sUSEMARCON stage1=%s stage2=%s",
+                        m_session_str,
+                        m_usemarcon_ini_stage1 ? m_usemarcon_ini_stage1 : "(none)",
+                        m_usemarcon_ini_stage2 ? m_usemarcon_ini_stage2 : "(none)");
+                    char *converted;
+                    int convlen;
+                    if (m_usemarcon->convert(m_usemarcon_ini_stage1, m_usemarcon_ini_stage2,
+                        (char*) r->u.octet_aligned->buf, r->u.octet_aligned->len,
+                        &converted, &convlen))
                     {
-                        if (!m_usemarcon->m_stage1)
-                        {
-                            m_usemarcon->m_stage1 = new CDetails();
-                        }
-                        m_usemarcon->m_stage1->SetIniFileName(m_usemarcon_ini_stage1);
-                        m_usemarcon->m_stage1->SetMarcRecord((char*) r->u.octet_aligned->buf, r->u.octet_aligned->len);
-                        int res = m_usemarcon->m_stage1->Start();
-                        if (res == 0)
-                        {
-                            char *converted;
-                            int convlen;
-                            m_usemarcon->m_stage1->GetMarcRecord(converted, convlen);
-                            if (m_usemarcon_ini_stage2 && *m_usemarcon_ini_stage2)
-                            {
-                                if (!m_usemarcon->m_stage2)
-                                {
-                                    m_usemarcon->m_stage2 = new CDetails();
-                                }
-                                m_usemarcon->m_stage2->SetIniFileName(m_usemarcon_ini_stage2);
-                                m_usemarcon->m_stage2->SetMarcRecord(converted, convlen);
-                                res = m_usemarcon->m_stage2->Start();
-                                if (res == 0)
-                                {
-                                    free(converted);
-                                    m_usemarcon->m_stage2->GetMarcRecord(converted, convlen);
-                                }
-                                else
-                                {
-                                    yaz_log(YLOG_LOG, "%sUSEMARCON stage 2 error %d", m_session_str, res);
-                                }
-                            }
-                            npr->u.databaseRecord =
-                                z_ext_record_oid(odr_encode(),
-                                                 m_frontend_type,
-                                                 converted,
-                                                 strlen(converted));
-                            free(converted);
-                        }
-                        else
-                        {
-                            yaz_log(YLOG_LOG, "%sUSEMARCON stage 1 error %d", m_session_str, res);
-                        }
-                        continue;
+                        npr->u.databaseRecord =
+                            z_ext_record_oid(odr_encode(),
+                                             m_frontend_type,
+                                             converted,
+                                             strlen(converted));
+                        free(converted);
                     }
+                    else
 #endif
 /* HAVE_USEMARCON */
                     npr->u.databaseRecord =
@@ -1018,16 +1019,11 @@ void Yaz_Proxy::convert_records_charset(Z_NamePlusRecordList *p,
             if (npr->which == Z_NamePlusRecord_databaseRecord)
             {
                 Z_External *r = npr->u.databaseRecord;
-                const int *oid = r->direct_reference;
+                const Odr_oid *oid = r->direct_reference;
                 if (!oid)
                     continue;
 
-                char oid_name_str[OID_STR_MAX];
-                int oclass;
-                const char *oid_name = yaz_oid_to_string_buf(
-                    oid, &oclass, oid_name_str);
-
-                if (oid_name && !strcmp(oid_name, OID_STR_SUTRS))
+                if (!oid_oidcmp(oid, yaz_oid_recsyn_sutrs))
                 {
                     WRBUF w = wrbuf_alloc();
 
@@ -1038,7 +1034,7 @@ void Yaz_Proxy::convert_records_charset(Z_NamePlusRecordList *p,
                                          wrbuf_len(w));
                     wrbuf_destroy(w);
                 }
-                else if (oid_name && !strcmp(oid_name, OID_STR_XML))
+                else if (!oid_oidcmp(oid, yaz_oid_recsyn_xml))
                 {
                     ;
                 }
@@ -1080,9 +1076,6 @@ void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
         Z_NamePlusRecord *npr = p->records[i];
         if (npr->which == Z_NamePlusRecord_databaseRecord)
         {
-            const int *xml_oid = yaz_string_to_oid(yaz_oid_std(),
-                                                   CLASS_RECSYN,
-                                                   OID_STR_XML);
             Z_External *r = npr->u.databaseRecord;
             if (r->which == Z_External_OPAC)
             {
@@ -1090,7 +1083,7 @@ void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
 
                 yaz_opac_decode_wrbuf(mt, r->u.opac, w);
                 npr->u.databaseRecord = z_ext_record_oid(
-                    odr_encode(), xml_oid,
+                    odr_encode(), yaz_oid_recsyn_xml,
                     wrbuf_buf(w), wrbuf_len(w));
                 wrbuf_destroy(w);
             }
@@ -1103,7 +1096,8 @@ void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
                                         &result, &rlen))
                 {
                     npr->u.databaseRecord =
-                        z_ext_record_oid(odr_encode(), xml_oid, result, rlen);
+                        z_ext_record_oid(odr_encode(), yaz_oid_recsyn_xml,
+                                         result, rlen);
                 }
             }
         }
@@ -1268,10 +1262,8 @@ int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start)
             }
             Z_External *r = npr->u.databaseRecord;
 
-            const int *xml_oid = yaz_string_to_oid(
-                yaz_oid_std(), CLASS_RECSYN, OID_STR_XML);
             if (r->which == Z_External_octet 
-                && !oid_oidcmp(r->direct_reference, xml_oid))
+                && !oid_oidcmp(r->direct_reference, yaz_oid_recsyn_xml))
             {
                 srw_res->records[i].recordSchema = m_schema;
                 srw_res->records[i].recordPacking = m_s2z_packing;
@@ -2283,8 +2275,7 @@ Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
     *err = error;
     rec->which = Z_Records_NSD;
     rec->u.nonSurrogateDiagnostic = dr;
-    dr->diagnosticSetId =
-        yaz_string_to_oid_odr(yaz_oid_std(), CLASS_DIAGSET, OID_STR_BIB1, odr);
+    dr->diagnosticSetId = odr_oiddup(odr, yaz_oid_diagset_bib_1);
     dr->condition = err;
     dr->which = Z_DefaultDiagFormat_v2Addinfo;
     dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
@@ -2516,7 +2507,7 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
             sr->preferredRecordSyntax =
                 yaz_string_to_oid_odr(
                     yaz_oid_std(), CLASS_RECSYN,
-                    m_backend_type ? m_backend_type : OID_STR_USMARC, 
+                    m_backend_type ? m_backend_type : "usmarc", 
                     odr_encode());
         }
         else if (err)
@@ -2584,7 +2575,7 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
             pr->preferredRecordSyntax =
                 yaz_string_to_oid_odr(
                     yaz_oid_std(), CLASS_RECSYN,
-                    m_backend_type ? m_backend_type : OID_STR_USMARC, 
+                    m_backend_type ? m_backend_type : "usmarc", 
                     odr_encode());
         }
         else if (err)
@@ -2782,24 +2773,49 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
         m_s2z_present_apdu = 0;
 
         m_s2z_stylesheet = 0;
-
+        
         Z_IdAuthentication *auth = NULL;
-        if (*authorization_str)
+        if (srw_pdu->username && srw_pdu->password)
         {
+            yaz_log(YLOG_LOG, "username/password: %s/%s\n",
+                    srw_pdu->username, srw_pdu->password);
             auth = (Z_IdAuthentication *) odr_malloc(m_s2z_odr_init, sizeof(Z_IdAuthentication));
             auth->which = Z_IdAuthentication_idPass;
             auth->u.idPass = (Z_IdPass *) odr_malloc(m_s2z_odr_init, sizeof(Z_IdPass));
             auth->u.idPass->groupId = NULL;
-            char *p = strchr(authorization_str, ':');
-            if (p)
+            auth->u.idPass->password = odr_strdup(m_s2z_odr_init, srw_pdu->password);
+            auth->u.idPass->userId = odr_strdup(m_s2z_odr_init, srw_pdu->username);
+        }
+        else
+        {
+            if (*authorization_str)
             {
-                *p = '\0';
-                p++;
-                auth->u.idPass->password = odr_strdup(m_s2z_odr_init, p);
+                yaz_log(YLOG_LOG, "authorization_str present: %s\n", authorization_str);
+                auth = (Z_IdAuthentication *) odr_malloc(m_s2z_odr_init, sizeof(Z_IdAuthentication));
+                auth->which = Z_IdAuthentication_idPass;
+                auth->u.idPass = (Z_IdPass *) odr_malloc(m_s2z_odr_init, sizeof(Z_IdPass));
+                auth->u.idPass->groupId = NULL;
+                char *p = strchr(authorization_str, ':');
+                if (p)
+                {
+                    *p = '\0';
+                    p++;
+                    auth->u.idPass->password = odr_strdup(m_s2z_odr_init, p);
+                }
+                auth->u.idPass->userId = odr_strdup(m_s2z_odr_init, authorization_str);
             }
-            auth->u.idPass->userId = odr_strdup(m_s2z_odr_init, authorization_str);
-        }
-
+            else
+            {
+                // Use _client_ IP as shown in the log entries...!
+                auth = (Z_IdAuthentication *) odr_malloc(m_s2z_odr_init, sizeof(Z_IdAuthentication));
+                   auth->which = Z_IdAuthentication_idPass;
+                   auth->u.idPass = (Z_IdPass *) odr_malloc(m_s2z_odr_init, sizeof(Z_IdPass));
+                   auth->u.idPass->groupId  = NULL;
+                   auth->u.idPass->password = NULL;
+                   auth->u.idPass->userId   = odr_strdup(m_s2z_odr_init, m_peername);
+            }
+        }              
+        
         if (srw_pdu->which == Z_SRW_searchRetrieve_request)
         {
 
@@ -2930,9 +2946,7 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
                     *z_searchRequest->largeSetLowerBound = 2000000000; // 2e9
 
                     z_searchRequest->preferredRecordSyntax =
-                        yaz_string_to_oid_odr(yaz_oid_std(),
-                                              CLASS_RECSYN, OID_STR_XML,
-                                              m_s2z_odr_search);
+                        odr_oiddup(m_s2z_odr_search, yaz_oid_recsyn_xml);
 
                     if (srw_req->recordSchema)
                     {
@@ -2952,10 +2966,7 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
                     *z_presentRequest->numberOfRecordsRequested = max;
 
                     z_presentRequest->preferredRecordSyntax =
-                        yaz_string_to_oid_odr(yaz_oid_std(),
-                                              CLASS_RECSYN, OID_STR_XML,
-                                              m_s2z_odr_search);
-
+                        odr_oiddup(m_s2z_odr_search, yaz_oid_recsyn_xml);
                     if (srw_req->recordSchema)
                     {
                         z_presentRequest->recordComposition =
@@ -3160,8 +3171,8 @@ void Yaz_Proxy::handle_init(Z_APDU *apdu)
             Z_APDU *apdu2 = m_client->m_initResponse;
             apdu2->u.initResponse->otherInfo = 0;
             if (m_client->m_cookie && *m_client->m_cookie)
-                set_otherInformationString(apdu2, OID_STR_COOKIE, 1,
-                                           m_client->m_cookie);
+                set_otherInformationString(apdu2, yaz_oid_userinfo_cookie, 
+                                           1, m_client->m_cookie);
             apdu2->u.initResponse->referenceId =
                 apdu->u.initRequest->referenceId;
             apdu2->u.initResponse->options = m_client->m_initResponse_options;
@@ -3245,12 +3256,13 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
     // Determine our client.
     Z_OtherInformation **oi;
     get_otherInfoAPDU(apdu, &oi);
-    m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
+    int http_code = 404;
+    m_client = get_client(apdu, get_cookie(oi), get_proxy(oi), &http_code);
     if (!m_client)
     {
         if (m_http_version)
         {   // HTTP. Send not found
-            send_http_response(404);
+            send_http_response(http_code);
             return;
         }
         else
@@ -3504,6 +3516,7 @@ void Yaz_Proxy::pre_init()
     const char *zurl_in_use[MAX_ZURL_PLEX];
     int limit_bw, limit_pdu, limit_req, limit_search;
     int target_idletime, client_idletime;
+    int max_sockets;
     int max_clients;
     int keepalive_limit_bw, keepalive_limit_pdu;
     int pre_init;
@@ -3525,6 +3538,7 @@ void Yaz_Proxy::pre_init()
                                           &limit_bw, &limit_pdu, &limit_req,
                                           &limit_search,
                                           &target_idletime, &client_idletime,
+                                          &max_sockets,
                                           &max_clients,
                                           &keepalive_limit_bw,
                                           &keepalive_limit_pdu,
@@ -3568,7 +3582,8 @@ void Yaz_Proxy::pre_init()
                         "sparew=%d preinit=%d",m_session_str,
                         name, zurl_in_use[j], in_use, other,
                         spare, spare_waiting, pre_init);
-                if (spare + spare_waiting < pre_init)
+                if (spare + spare_waiting < pre_init
+                    && in_use + spare + spare_waiting + other < max_sockets)
                 {
                     c = new Yaz_ProxyClient(m_PDU_Observable->clone(), this);
                     c->m_next = m_clientPool;
@@ -3825,7 +3840,7 @@ void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
         }
     }
     if (m_cookie)
-        set_otherInformationString (apdu, OID_STR_COOKIE, 1, m_cookie);
+        set_otherInformationString(apdu, yaz_oid_userinfo_cookie, 1, m_cookie);
 
     Yaz_Proxy *server = m_server; // save it. send_to_client may destroy us