Added support for threaded authentication modules. See
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 30 May 2005 20:09:20 +0000 (20:09 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 30 May 2005 20:09:20 +0000 (20:09 +0000)
etc/config-modules.xml + mod_sample.cpp for an example.

NEWS
etc/config-modules.xml
include/yazproxy/module.h
include/yazproxy/proxy.h
src/Makefile.am
src/modules.cpp [new file with mode: 0644]
src/yaz-proxy-config.cpp
src/yaz-proxy-main.cpp
src/yaz-proxy.cpp

diff --git a/NEWS b/NEWS
index 140c67b..821fb59 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+
+Added support for threaded authentication modules. See
+etc/config-modules.xml + mod_sample.cpp for an example.
+
 Added support for Z39.50 character set negotiation. This allows
 the proxy to act as a Z39.50 server supporting character set negotiation
 for backends not supporting it. New config element target-charset
index fc10e04..9804cd5 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!-- $Id: config-modules.xml,v 1.1 2005-03-14 13:10:08 adam Exp $ -->
+<!-- $Id: config-modules.xml,v 1.2 2005-05-30 20:09:20 adam Exp $ -->
 <!-- 
    Config that uses modules 
 -->
     <preinit>0</preinit>
     <xi:include href="explain.xml"/>
     <cql2rpn>pqf.properties</cql2rpn>
-    <target-authentication type="open">my/bad</target-authentication>
     <client-authentication module="sample" args="authenticate.pl"/>
-    <negotiation-charset>iso-8859-1</negotiation-charset>
-    <negotiation-lang>US</negotiation-lang>
   </target>
   <max-clients>50</max-clients>
   <log>client-requests server-requests</log>
index 7afbff5..d701209 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: module.h,v 1.2 2005-02-21 14:27:31 adam Exp $
+/* $Id: module.h,v 1.3 2005-05-30 20:09:20 adam Exp $
    Copyright (c) 1998-2005, Index Data.
 
 This file is part of the yaz-proxy.
@@ -50,4 +50,22 @@ struct Yaz_ProxyModule_int0 {
     );
 };
 
+class Yaz_ProxyModule;
+
+class Yaz_ProxyModules {
+    friend class Proxy_Msg;
+ public:
+    Yaz_ProxyModules();
+    ~Yaz_ProxyModules();
+    int authenticate(const char *module_name,
+                    const char *target_name, void *element_ptr,
+                    const char *user,
+                    const char *group,
+                    const char *password);
+    int add_module(const char *fname);
+    void unload_modules();
+ private:
+    Yaz_ProxyModule *m_list;
+};
+
 #endif
index 854191c..7482f52 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: proxy.h,v 1.16 2005-05-18 20:15:22 adam Exp $
+/* $Id: proxy.h,v 1.17 2005-05-30 20:09:20 adam Exp $
    Copyright (c) 1998-2005, Index Data.
 
 This file is part of the yaz-proxy.
@@ -22,6 +22,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #ifndef YAZ_PROXY_H_INCLUDED
 #define YAZ_PROXY_H_INCLUDED
 
+#include <yaz++/socket-observer.h>
 #include <yaz++/z-assoc.h>
 #include <yaz++/z-query.h>
 #include <yaz++/z-databases.h>
@@ -48,8 +49,11 @@ enum YAZ_Proxy_MARCXML_mode {
     marcxml,
 };
 
+class Msg_Thread;
+
 /// Information Retrieval Proxy Server.
 class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
+    friend class Proxy_Msg;
  private:
     char *get_cookie(Z_OtherInformation **otherInfo);
     char *get_proxy(Z_OtherInformation **otherInfo);
@@ -63,6 +67,7 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
     void releaseClient();    
     Yaz_ProxyClient *m_client;
     IYaz_PDU_Observable *m_PDU_Observable;
+    IYazSocketObservable *m_socket_observable;
     Yaz_ProxyClient *m_clientPool;
     Yaz_Proxy *m_parent;
     int m_seqno;
@@ -92,7 +97,6 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
     Z_GDU *m_bw_hold_PDU;
     int m_max_record_retrieve;
     void handle_max_record_retrieve(Z_APDU *apdu);
-    int handle_authentication(Z_APDU *apdu);
     void display_diagrecs(Z_DiagRec **pp, int num);
     Z_Records *create_nonSurrogateDiagnostics(ODR o, int error,
                                              const char *addinfo);
@@ -165,6 +169,7 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
     Z_ElementSetNames *mk_esn_from_schema(ODR o, const char *schema);
     Z_ReferenceId *m_referenceId;
     NMEM m_referenceId_mem;
+    
 #define NO_SPARE_SOLARIS_FD 10
     int m_lo_fd[NO_SPARE_SOLARIS_FD];
     void low_socket_open();
@@ -175,12 +180,17 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
     Yaz_CharsetConverter *m_charset_converter;
  public:
     Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
+             IYazSocketObservable *the_socket_observable,
              Yaz_Proxy *parent = 0);
     ~Yaz_Proxy();
+    int handle_authentication(Z_APDU *apdu);
+    void result_authentication(Z_APDU *apdu, int ret);
+    void handle_init(Z_APDU *apdu);
     void inc_request_no();
     void recv_GDU(Z_GDU *apdu, int len);
     void handle_incoming_HTTP(Z_HTTP_Request *req);
     void handle_incoming_Z_PDU(Z_APDU *apdu);
+    void handle_incoming_Z_PDU_2(Z_APDU *apdu);
     IYaz_PDU_Observer* sessionNotify
        (IYaz_PDU_Observable *the_PDU_Observable, int fd);
     void failNotify();
@@ -205,6 +215,7 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
     int get_log_mask() { return m_log_mask; };
     int handle_init_response_for_invalid_session(Z_APDU *apdu);
     void set_debug_mode(int mode);
+    Msg_Thread *m_my_thread;
 };
 
 #endif
index 1b8a5ca..95c84ca 100644 (file)
@@ -1,4 +1,4 @@
-## $Id: Makefile.am,v 1.7 2005-05-19 21:29:58 adam Exp $
+## $Id: Makefile.am,v 1.8 2005-05-30 20:09:21 adam Exp $
 
 AM_CXXFLAGS = $(YAZPPINC) -I$(srcdir)/../include $(XSLT_CFLAGS) $(USEMARCONINC)
 
@@ -6,7 +6,8 @@ lib_LTLIBRARIES = libyazproxy.la
 libyazproxy_la_LDFLAGS=-version-info 1:0:0
 
 libyazproxy_la_SOURCES= yaz-proxy.cpp yaz-proxy-config.cpp yaz-bw.cpp \
- proxyp.h yaz-usemarcon.cpp charset-converter.cpp
+ proxyp.h yaz-usemarcon.cpp charset-converter.cpp msg-thread.cpp msg-thread.h \
+ modules.cpp
 
 bin_PROGRAMS = yazproxy
 check_PROGRAMS = cdetails
diff --git a/src/modules.cpp b/src/modules.cpp
new file mode 100644 (file)
index 0000000..4e7f473
--- /dev/null
@@ -0,0 +1,178 @@
+/* $Id: modules.cpp,v 1.1 2005-05-30 20:09:21 adam Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <string.h>
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <yaz/nmem.h>
+#include <yazproxy/module.h>
+
+class Yaz_ProxyModule {
+    friend class Proxy_Msg;
+private:
+    void *m_dl_handle;                /* dlopen/close handle */
+    Yaz_ProxyModule_entry *m_entry;
+    Yaz_ProxyModule *m_next; 
+    void *m_user_handle;              /* user handle */
+public:
+    Yaz_ProxyModule(void *dl_handle, Yaz_ProxyModule_entry *ent,
+                   Yaz_ProxyModule *next);
+    ~Yaz_ProxyModule();
+    
+    Yaz_ProxyModule *get_next() { return m_next; };
+    int is_module(const char *name);
+    int authenticate(const char *target_name, void *element_ptr,
+                    const char *user, const char *group, const char *password);
+};
+
+int Yaz_ProxyModule::is_module(const char *name)
+{
+    if (!name || !strcmp(m_entry->module_name, name))
+       return 1;
+    return 0;
+}
+
+Yaz_ProxyModule::Yaz_ProxyModule(void *dl_handle, Yaz_ProxyModule_entry *ent,
+                                Yaz_ProxyModule *next)
+{
+    m_dl_handle = dl_handle;
+    m_entry = ent;
+    m_next = next;
+    m_user_handle = 0;
+    if (m_entry->int_version == 0)
+    {
+       struct Yaz_ProxyModule_int0 *int0 =
+           reinterpret_cast<Yaz_ProxyModule_int0 *>(m_entry->fl);
+       if (int0->init)
+           m_user_handle = (*int0->init)();
+    }
+}
+
+Yaz_ProxyModule::~Yaz_ProxyModule()
+{
+    if (m_entry->int_version == 0)
+    {
+       struct Yaz_ProxyModule_int0 *int0 =
+           reinterpret_cast<Yaz_ProxyModule_int0 *>(m_entry->fl);
+       if (int0->destroy)
+           (*int0->destroy)(m_user_handle);
+    }
+#if HAVE_DLFCN_H
+    dlclose(m_dl_handle);
+#endif
+}
+
+int Yaz_ProxyModule::authenticate(const char *name,
+                                 void *element_ptr,
+                                 const char *user, const char *group,
+                                 const char *password)
+{
+    if (m_entry->int_version == 0)
+    {
+       struct Yaz_ProxyModule_int0 *int0 =
+           reinterpret_cast<Yaz_ProxyModule_int0 *>(m_entry->fl);
+       
+       if (!int0->authenticate)
+           return YAZPROXY_RET_NOT_ME;
+       return (*int0->authenticate)(m_user_handle, name, element_ptr,
+                                    user, group, password);
+    }
+    return YAZPROXY_RET_NOT_ME;
+}
+
+Yaz_ProxyModules::Yaz_ProxyModules()
+{
+    m_list = 0;
+}
+
+
+Yaz_ProxyModules::~Yaz_ProxyModules()
+{
+    unload_modules();
+}
+
+void Yaz_ProxyModules::unload_modules()
+{
+    Yaz_ProxyModule *m = m_list;
+    while (m)
+    {
+       Yaz_ProxyModule *m_next = m->get_next();
+       delete m;
+       m = m_next;
+    }
+    m_list = 0;
+}
+
+
+int Yaz_ProxyModules::authenticate(const char *module_name,
+                                  const char *target_name, void *element_ptr,
+                                  const char *user,
+                                  const char *group,
+                                  const char *password)
+{
+    int ret = YAZPROXY_RET_NOT_ME;
+    Yaz_ProxyModule *m = m_list;
+    for (; m; m = m->get_next())
+    {
+       if (m->is_module(module_name))
+       {
+           ret = m->authenticate(target_name, element_ptr,
+                                      user, group, password);
+           if (ret != YAZPROXY_RET_NOT_ME)
+               break;
+       }
+    }
+    return ret;
+}
+
+int Yaz_ProxyModules::add_module(const char *fname)
+{
+#if HAVE_DLFCN_H
+    void *dl_handle = dlopen(fname, RTLD_NOW|RTLD_GLOBAL);
+    if (dl_handle)
+    {
+       Yaz_ProxyModule_entry *fl_ptr = 0;
+       fl_ptr = reinterpret_cast<Yaz_ProxyModule_entry *> 
+           (dlsym(dl_handle, "yazproxy_module"));
+       if (fl_ptr)
+       {
+           Yaz_ProxyModule *m = new Yaz_ProxyModule(dl_handle,
+                                                    fl_ptr,
+                                                    m_list);
+           m_list = m;
+
+           return 0;
+       }
+       else
+       {
+           return -1;
+           dlclose(dl_handle);
+       }
+    }
+    else
+       return -1;
+#else
+    return -1;
+#endif
+}
+
index 76259cf..6a5b313 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: yaz-proxy-config.cpp,v 1.19 2005-05-18 20:15:22 adam Exp $
+/* $Id: yaz-proxy-config.cpp,v 1.20 2005-05-30 20:09:21 adam Exp $
    Copyright (c) 1998-2005, Index Data.
 
 This file is part of the yaz-proxy.
@@ -21,97 +21,18 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include <ctype.h>
 
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
 #include <yaz/log.h>
 #include "proxyp.h"
 
-
-class Yaz_ProxyModule {
-private:
-    void *m_dl_handle;                /* dlopen/close handle */
-    Yaz_ProxyModule_entry *m_entry;
-    Yaz_ProxyModule *m_next; 
-    void *m_user_handle;              /* user handle */
-public:
-    Yaz_ProxyModule(void *dl_handle, Yaz_ProxyModule_entry *ent,
-                   Yaz_ProxyModule *next);
-    ~Yaz_ProxyModule();
-    
-    Yaz_ProxyModule *get_next() { return m_next; };
-    int is_module(const char *name);
-    int authenticate(const char *target_name, void *element_ptr,
-                    const char *user, const char *group, const char *password);
-};
-
-int Yaz_ProxyModule::is_module(const char *type)
-{
-    if (!type || !strcmp(m_entry->module_name, type))
-       return 1;
-    return 0;
-}
-
-Yaz_ProxyModule::Yaz_ProxyModule(void *dl_handle, Yaz_ProxyModule_entry *ent,
-                                Yaz_ProxyModule *next)
-{
-    m_dl_handle = dl_handle;
-    m_entry = ent;
-    m_next = next;
-    m_user_handle = 0;
-    if (m_entry->int_version == 0)
-    {
-       struct Yaz_ProxyModule_int0 *int0 =
-           reinterpret_cast<Yaz_ProxyModule_int0 *>(m_entry->fl);
-       if (int0->init)
-           m_user_handle = (*int0->init)();
-    }
-}
-
-Yaz_ProxyModule::~Yaz_ProxyModule()
-{
-    if (m_entry->int_version == 0)
-    {
-       struct Yaz_ProxyModule_int0 *int0 =
-           reinterpret_cast<Yaz_ProxyModule_int0 *>(m_entry->fl);
-       if (int0->destroy)
-           (*int0->destroy)(m_user_handle);
-    }
-#if HAVE_DLFCN_H
-    dlclose(m_dl_handle);
-#endif
-}
-
-int Yaz_ProxyModule::authenticate(const char *name,
-                                 void *element_ptr,
-                                 const char *user, const char *group,
-                                 const char *password)
-{
-    if (m_entry->int_version == 0)
-    {
-       struct Yaz_ProxyModule_int0 *int0 =
-           reinterpret_cast<Yaz_ProxyModule_int0 *>(m_entry->fl);
-       
-       if (!int0->authenticate)
-           return YAZPROXY_RET_NOT_ME;
-       return (*int0->authenticate)(m_user_handle, name, element_ptr,
-                                    user, group, password);
-    }
-    return YAZPROXY_RET_NOT_ME;
-}
-
 class Yaz_ProxyConfigP {
     friend class Yaz_ProxyConfig;
 
-    Yaz_ProxyModule *m_modules;
-
+    Yaz_ProxyModules m_modules;
     int mycmp(const char *hay, const char *item, size_t len);
     int match_list(int v, const char *m);
     int atoi_l(const char **cp);
 #if HAVE_XSLT
     void load_modules(void);
-    void unload_modules(void);
     int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
                     const char *schema_identifier);
     xmlDocPtr m_docPtr;
@@ -143,13 +64,12 @@ class Yaz_ProxyConfigP {
     ~Yaz_ProxyConfigP();
 };
 
-Yaz_ProxyConfigP::Yaz_ProxyConfigP()
+Yaz_ProxyConfigP::Yaz_ProxyConfigP()  : m_modules()
 {
 #if HAVE_XSLT
     m_docPtr = 0;
     m_proxyPtr = 0;
 #endif
-    m_modules = 0;
 }
 
 Yaz_ProxyConfigP::~Yaz_ProxyConfigP()
@@ -162,7 +82,7 @@ Yaz_ProxyConfigP::~Yaz_ProxyConfigP()
 
 Yaz_ProxyConfig::Yaz_ProxyConfig()
 {
-    m_cp = new Yaz_ProxyConfigP;
+    m_cp = new Yaz_ProxyConfigP();
 }
 
 Yaz_ProxyConfig::~Yaz_ProxyConfig()
@@ -171,20 +91,6 @@ Yaz_ProxyConfig::~Yaz_ProxyConfig()
 }
 
 #if HAVE_XSLT
-void Yaz_ProxyConfigP::unload_modules()
-{
-    Yaz_ProxyModule *m = m_modules;
-    while (m)
-    {
-       Yaz_ProxyModule *m_next = m->get_next();
-       delete m;
-       m = m_next;
-    }
-    m_modules = 0;
-}
-#endif
-
-#if HAVE_XSLT
 void Yaz_ProxyConfigP::load_modules()
 {
     if (!m_proxyPtr)
@@ -197,32 +103,7 @@ void Yaz_ProxyConfigP::load_modules()
            && !strcmp((const char *) ptr->name, "module")
            && (fname = get_text(ptr)))
        {
-#if HAVE_DLFCN_H
-           void *dl_handle = dlopen(fname, RTLD_NOW|RTLD_GLOBAL);
-           if (dl_handle)
-           {
-               Yaz_ProxyModule_entry *fl_ptr = 0;
-               fl_ptr = reinterpret_cast<Yaz_ProxyModule_entry *> 
-                   (dlsym(dl_handle, "yazproxy_module"));
-               if (fl_ptr)
-               {
-                   Yaz_ProxyModule *m = new Yaz_ProxyModule(dl_handle,
-                                                            fl_ptr,
-                                                            m_modules);
-                   m_modules = m;
-                   yaz_log(YLOG_LOG, "Loading %s OK", fname);
-               }
-               else
-               {
-                   yaz_log(YLOG_WARN, "Loading %s FAIL: missing yazproxy_module symbol", fname);
-                   dlclose(dl_handle);
-               }
-           }
-           else
-               yaz_log(YLOG_WARN, "Loading %s FAIL: dlopen failed", fname);
-#else
-           yaz_log(YLOG_WARN, "Loading &s FAIL: dl unsupported", fname);
-#endif
+           m_modules.add_module(fname);
        }
     }
 }
@@ -257,7 +138,7 @@ int Yaz_ProxyConfig::read_xml(const char *fname)
        xmlFreeDoc(m_cp->m_docPtr);
     m_cp->m_docPtr = ndoc;
 
-    m_cp->unload_modules();
+    m_cp->m_modules.unload_modules();
     m_cp->load_modules();
     return 0;
 #else
@@ -742,16 +623,11 @@ int Yaz_ProxyConfig::client_authentication(const char *name,
                    attr->children && attr->children->type == XML_TEXT_NODE)
                    module_name = (const char *) attr->children->content;
            }
-           Yaz_ProxyModule *m = m_cp->m_modules;
-           for (; m; m = m->get_next())
-           {
-               if (m->is_module(module_name))
-               {
-                   ret = m->authenticate(name, ptr, user, group, password);
-                   if (ret != YAZPROXY_RET_NOT_ME)
-                       break;
-               }
-           }
+           ret = m_cp->m_modules.authenticate(module_name,
+                                              name, ptr,
+                                              user, group, password);
+           if (ret != YAZPROXY_RET_NOT_ME)
+               break;
        }
 #endif
     if (ret == YAZPROXY_RET_PERM)
index f40c64a..4257c79 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: yaz-proxy-main.cpp,v 1.12 2005-02-21 14:27:32 adam Exp $
+/* $Id: yaz-proxy-main.cpp,v 1.13 2005-05-30 20:09:21 adam Exp $
    Copyright (c) 1998-2005, Index Data.
 
 This file is part of the yaz-proxy.
@@ -283,7 +283,7 @@ int main(int argc, char **argv)
     int cont = 1;
     int run = 1;
     Yaz_SocketManager mySocketManager;
-    Yaz_Proxy proxy(new Yaz_PDU_Assoc(&mySocketManager));
+    Yaz_Proxy proxy(new Yaz_PDU_Assoc(&mySocketManager), &mySocketManager);
 
     static_yaz_proxy = &proxy;
 
index e59613e..6aae564 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: yaz-proxy.cpp,v 1.27 2005-05-27 18:07:49 adam Exp $
+/* $Id: yaz-proxy.cpp,v 1.28 2005-05-30 20:09:21 adam Exp $
    Copyright (c) 1998-2005, Index Data.
 
 This file is part of the yaz-proxy.
@@ -51,7 +51,45 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include <yaz/pquery.h>
 #include <yaz/otherinfo.h>
 #include <yaz/charneg.h>
+#include "msg-thread.h"
 
+class Auth_Msg : public IMsg_Thread {
+public:
+    int m_ret;
+    void destroy();
+    IMsg_Thread *handle();
+    void result();
+    Yaz_Proxy *m_proxy;
+    Z_APDU *m_apdu;
+};
+
+IMsg_Thread *Auth_Msg::handle()
+{
+    yaz_log(YLOG_LOG, "Auth_Msg:handle begin");
+    m_ret = m_proxy->handle_authentication(m_apdu);
+    yaz_log(YLOG_LOG, "Auth_Msg:handle end");
+    return this;
+}
+
+void Yaz_Proxy::result_authentication(Z_APDU *apdu, int ret)
+{
+    if (ret == 0)
+    {
+       Z_APDU *apdu_reject = zget_APDU(odr_encode(), Z_APDU_initResponse);
+       *apdu_reject->u.initResponse->result = 0;
+       send_to_client(apdu_reject);
+       shutdown();
+    }
+    else
+       handle_incoming_Z_PDU_2(apdu);
+}
+
+void Auth_Msg::result()
+{
+    yaz_log(YLOG_LOG, "Auth_Msg:result");
+    m_proxy->result_authentication(m_apdu, m_ret);
+    delete this;
+}
 
 static const char *apdu_name(Z_APDU *apdu)
 {
@@ -104,11 +142,15 @@ static const char *gdu_name(Z_GDU *gdu)
     }
     return "Unknown request/response";
 }
+
 Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
-                    Yaz_Proxy *parent) :
+                    IYazSocketObservable *the_socket_observable,
+                    Yaz_Proxy *parent) 
+    :
     Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
 {
     m_PDU_Observable = the_PDU_Observable;
+    m_socket_observable = the_socket_observable;
     m_client = 0;
     m_parent = parent;
     m_clientPool = 0;
@@ -127,7 +169,7 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
     m_target_idletime = 600;
     m_optimize = xstrdup ("1");
     strcpy(m_session_str, "0 ");
-    m_session_no=0;
+    m_session_no = 0;
     m_bytes_sent = 0;
     m_bytes_recv = 0;
     m_bw_hold_PDU = 0;
@@ -185,6 +227,7 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
     m_usemarcon = new Yaz_usemarcon();
     if (!m_parent)
        low_socket_open();
+    m_my_thread = 0;
 }
 
 Yaz_Proxy::~Yaz_Proxy()
@@ -220,6 +263,8 @@ Yaz_Proxy::~Yaz_Proxy()
        odr_destroy(m_s2z_odr_search);
     if (!m_parent)
        low_socket_close();
+    if (!m_parent)
+       delete m_my_thread;
     delete m_config;
 }
 
@@ -295,7 +340,8 @@ IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
                                            *the_PDU_Observable, int fd)
 {
     check_reconfigure();
-    Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable, this);
+    Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable,
+                                        m_socket_observable, this);
     new_proxy->m_config = 0;
     new_proxy->m_config_fname = 0;
     new_proxy->timeout(m_client_idletime);
@@ -314,6 +360,10 @@ IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
             the_PDU_Observable->getpeername());
     new_proxy->set_proxy_negotiation(m_proxy_negotiation_charset,
        m_proxy_negotiation_lang);
+    // create thread object the first time we get an incoming connection
+    if (!m_my_thread)
+       m_my_thread = new Msg_Thread(m_socket_observable);
+    new_proxy->m_my_thread = m_my_thread;
     return new_proxy;
 }
 
@@ -658,6 +708,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
     yaz_log (YLOG_DEBUG, "get_client 3 %p %p", this, c);
     return c;
 }
+
 void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
 {
     int i;
@@ -2601,6 +2652,123 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
     send_http_response(400);
 }
 
+void Yaz_Proxy::handle_init(Z_APDU *apdu)
+{
+    Z_OtherInformation **oi;
+    get_otherInfoAPDU(apdu, &oi);
+
+    if (apdu->u.initRequest->implementationId)
+       yaz_log(YLOG_LOG, "%simplementationId: %s",
+               m_session_str, apdu->u.initRequest->implementationId);
+    if (apdu->u.initRequest->implementationName)
+       yaz_log(YLOG_LOG, "%simplementationName: %s",
+               m_session_str, apdu->u.initRequest->implementationName);
+    if (apdu->u.initRequest->implementationVersion)
+       yaz_log(YLOG_LOG, "%simplementationVersion: %s",
+               m_session_str, apdu->u.initRequest->implementationVersion);
+    if (m_initRequest_apdu == 0)
+    {
+       if (m_initRequest_mem)
+           nmem_destroy(m_initRequest_mem);
+       
+       m_initRequest_apdu = apdu;
+       m_initRequest_mem = odr_extract_mem(odr_decode());
+       
+       m_initRequest_preferredMessageSize = *apdu->u.initRequest->
+           preferredMessageSize;
+       *apdu->u.initRequest->preferredMessageSize = 1024*1024;
+       m_initRequest_maximumRecordSize = *apdu->u.initRequest->
+           maximumRecordSize;
+       *apdu->u.initRequest->maximumRecordSize = 1024*1024;
+       
+       // Save proposal charsets and langs.
+       if (ODR_MASK_GET(apdu->u.initRequest->options,
+                        Z_Options_negotiationModel))
+       {
+           Z_CharSetandLanguageNegotiation *charSetandLangRecord =
+               yaz_get_charneg_record(*oi);
+           
+           yaz_get_proposal_charneg(m_referenceId_mem,
+                                    charSetandLangRecord,
+                                    &m_initRequest_oi_negotiation_charsets,
+                                    &m_initRequest_oi_negotiation_num_charsets,
+                                    &m_initRequest_oi_negotiation_langs,
+                                    &m_initRequest_oi_negotiation_num_langs,
+                                    &m_initRequest_oi_negotiation_selected);
+           
+           for (int i = 0; i<m_initRequest_oi_negotiation_num_charsets; i++)
+           {
+               yaz_log(YLOG_LOG, "%scharacters set proposal: %s",
+                       m_session_str,(m_initRequest_oi_negotiation_charsets[i])?
+                       m_initRequest_oi_negotiation_charsets[i]:"none");
+           }
+           for (int i=0; i<m_initRequest_oi_negotiation_num_langs; i++)
+           {
+               yaz_log(YLOG_LOG, "%slanguages proposal: %s",
+                       m_session_str, (m_initRequest_oi_negotiation_langs[i])?
+                       m_initRequest_oi_negotiation_langs[i]:"none");
+           }
+           yaz_log(YLOG_LOG, "%sselected proposal: %d (boolean)",
+                   m_session_str, m_initRequest_oi_negotiation_selected);
+       }       
+       // save init options for the response..
+       m_initRequest_options = apdu->u.initRequest->options;
+       
+       apdu->u.initRequest->options = 
+           (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
+                                      sizeof(Odr_bitmask));
+       ODR_MASK_ZERO(apdu->u.initRequest->options);
+       int i;
+       for (i = 0; i<= 24; i++)
+           ODR_MASK_SET(apdu->u.initRequest->options, i);
+       // check negotiation option
+       if (!ODR_MASK_GET(m_initRequest_options,
+                         Z_Options_negotiationModel))
+       {
+           ODR_MASK_CLEAR(apdu->u.initRequest->options,
+                          Z_Options_negotiationModel);
+       }
+       ODR_MASK_CLEAR(apdu->u.initRequest->options,
+                      Z_Options_concurrentOperations);
+       // make new version
+       m_initRequest_version = apdu->u.initRequest->protocolVersion;
+       apdu->u.initRequest->protocolVersion = 
+           (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
+                                      sizeof(Odr_bitmask));
+       ODR_MASK_ZERO(apdu->u.initRequest->protocolVersion);
+       
+       for (i = 0; i<= 8; i++)
+           ODR_MASK_SET(apdu->u.initRequest->protocolVersion, i);
+    }
+    if (m_client->m_init_flag)
+    {
+       if (handle_init_response_for_invalid_session(apdu))
+           return;
+       if (m_client->m_initResponse)
+       {
+           Z_APDU *apdu2 = m_client->m_initResponse;
+           apdu2->u.initResponse->otherInfo = 0;
+           if (m_client->m_cookie && *m_client->m_cookie)
+               set_otherInformationString(apdu2, VAL_COOKIE, 1,
+                                          m_client->m_cookie);
+           apdu2->u.initResponse->referenceId =
+               apdu->u.initRequest->referenceId;
+           apdu2->u.initResponse->options = m_client->m_initResponse_options;
+           apdu2->u.initResponse->protocolVersion = 
+               m_client->m_initResponse_version;
+           
+           send_to_client(apdu2);
+           return;
+       }
+    }
+    m_client->m_init_flag = 1;
+    
+    Auth_Msg *m = new Auth_Msg;
+    m->m_apdu = apdu;
+    m->m_proxy = this;
+    m_my_thread->put(m);
+}
+
 void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
 {
     Z_ReferenceId **refid = get_referenceIdP(apdu);
@@ -2645,126 +2813,15 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
     m_client->m_server = this;
 
     if (apdu->which == Z_APDU_initRequest)
-    {
-       if (apdu->u.initRequest->implementationId)
-           yaz_log(YLOG_LOG, "%simplementationId: %s",
-                   m_session_str, apdu->u.initRequest->implementationId);
-       if (apdu->u.initRequest->implementationName)
-           yaz_log(YLOG_LOG, "%simplementationName: %s",
-                   m_session_str, apdu->u.initRequest->implementationName);
-       if (apdu->u.initRequest->implementationVersion)
-           yaz_log(YLOG_LOG, "%simplementationVersion: %s",
-                   m_session_str, apdu->u.initRequest->implementationVersion);
-       if (m_initRequest_apdu == 0)
-       {
-           if (m_initRequest_mem)
-               nmem_destroy(m_initRequest_mem);
-
-           m_initRequest_apdu = apdu;
-           m_initRequest_mem = odr_extract_mem(odr_decode());
-
-           m_initRequest_preferredMessageSize = *apdu->u.initRequest->
-               preferredMessageSize;
-           *apdu->u.initRequest->preferredMessageSize = 1024*1024;
-           m_initRequest_maximumRecordSize = *apdu->u.initRequest->
-               maximumRecordSize;
-           *apdu->u.initRequest->maximumRecordSize = 1024*1024;
-                   
-           // Save proposal charsets and langs.
-           if (ODR_MASK_GET(apdu->u.initRequest->options,
-               Z_Options_negotiationModel))
-           {
-               Z_CharSetandLanguageNegotiation *charSetandLangRecord =
-                   yaz_get_charneg_record(*oi);
-    
-               yaz_get_proposal_charneg(m_referenceId_mem,
-                   charSetandLangRecord,
-                   &m_initRequest_oi_negotiation_charsets,
-                   &m_initRequest_oi_negotiation_num_charsets,
-                   &m_initRequest_oi_negotiation_langs,
-                   &m_initRequest_oi_negotiation_num_langs,
-                   &m_initRequest_oi_negotiation_selected);
-       
-               for (int i=0; i<m_initRequest_oi_negotiation_num_charsets; i++)
-               {
-                   yaz_log(YLOG_LOG, "%scharacters set proposal: %s",
-                       m_session_str,(m_initRequest_oi_negotiation_charsets[i])?
-                       m_initRequest_oi_negotiation_charsets[i]:"none");
-               }
-               for (int i=0; i<m_initRequest_oi_negotiation_num_langs; i++)
-               {
-                   yaz_log(YLOG_LOG, "%slanguages proposal: %s",
-                       m_session_str, (m_initRequest_oi_negotiation_langs[i])?
-                       m_initRequest_oi_negotiation_langs[i]:"none");
-               }
-               yaz_log(YLOG_LOG, "%sselected proposal: %d (boolean)",
-                   m_session_str, m_initRequest_oi_negotiation_selected);
-           }   
-           // save init options for the response..
-           m_initRequest_options = apdu->u.initRequest->options;
-           
-           apdu->u.initRequest->options = 
-               (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
-                                          sizeof(Odr_bitmask));
-           ODR_MASK_ZERO(apdu->u.initRequest->options);
-           int i;
-           for (i = 0; i<= 24; i++)
-               ODR_MASK_SET(apdu->u.initRequest->options, i);
-           // check negotiation option
-           if (!ODR_MASK_GET(m_initRequest_options,
-               Z_Options_negotiationModel))
-           {
-               ODR_MASK_CLEAR(apdu->u.initRequest->options,
-                   Z_Options_negotiationModel);
-           }
-           ODR_MASK_CLEAR(apdu->u.initRequest->options,
-               Z_Options_concurrentOperations);
-           // make new version
-           m_initRequest_version = apdu->u.initRequest->protocolVersion;
-           apdu->u.initRequest->protocolVersion = 
-               (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
-                                          sizeof(Odr_bitmask));
-           ODR_MASK_ZERO(apdu->u.initRequest->protocolVersion);
-
-           for (i = 0; i<= 8; i++)
-               ODR_MASK_SET(apdu->u.initRequest->protocolVersion, i);
-       }
-       if (m_client->m_init_flag)
-       {
-           if (handle_init_response_for_invalid_session(apdu))
-               return;
-           if (m_client->m_initResponse)
-           {
-               Z_APDU *apdu2 = m_client->m_initResponse;
-               apdu2->u.initResponse->otherInfo = 0;
-               if (m_client->m_cookie && *m_client->m_cookie)
-                   set_otherInformationString(apdu2, VAL_COOKIE, 1,
-                                              m_client->m_cookie);
-               apdu2->u.initResponse->referenceId =
-                   apdu->u.initRequest->referenceId;
-               apdu2->u.initResponse->options = m_client->m_initResponse_options;
-               apdu2->u.initResponse->protocolVersion = 
-                   m_client->m_initResponse_version;
-               
-               send_to_client(apdu2);
-               return;
-           }
-       }
-       m_client->m_init_flag = 1;
-    }
-    
-    if (!handle_authentication(apdu))
-    {
-       Z_APDU *apdu_reject = zget_APDU(odr_encode(), Z_APDU_initResponse);
-       *apdu_reject->u.initResponse->result = 0;
-       send_to_client(apdu_reject);
-
-       shutdown();
-       return;
-    }
+       handle_init(apdu);
+    else
+       handle_incoming_Z_PDU_2(apdu);
+}
 
+void Yaz_Proxy::handle_incoming_Z_PDU_2(Z_APDU *apdu)
+{
     handle_max_record_retrieve(apdu);
-
+    
     if (apdu)
        apdu = handle_syntax_validation(apdu);
 
@@ -2787,11 +2844,12 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
        return;
     }
     // Add otherInformation entry in APDU if
-    // negotiatoin in use.
+    // negotiation is in use.
     if (apdu)
        handle_charset_lang_negotiation(apdu);
 
     // delete other info construct completely if 0 elements
+    Z_OtherInformation **oi;
     get_otherInfoAPDU(apdu, &oi);
     if (oi && *oi && (*oi)->num_elements == 0)
         *oi = 0;