New windows NT/95 port using MSV5.0. The test server 'ztest' was
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 1 Sep 1997 08:52:58 +0000 (08:52 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 1 Sep 1997 08:52:58 +0000 (08:52 +0000)
moved a separate directory. MSV5.0 project server.dsp created.
As an option, the server can now operate as an NT service.

server/Makefile
server/eventl.c
server/requestq.c
server/server.dsp [new file with mode: 0644]
server/seshigh.c
server/session.h
server/statserv.c

index abdb1e0..c222307 100644 (file)
@@ -1,7 +1,7 @@
-# Copyright (C) 1994, Index Data I/S 
+# Copyright (C) 1994-1997, Index Data I/S 
 # All rights reserved.
 # Sebastian Hammer, Adam Dickmeiss
-# $Id: Makefile,v 1.31 1996-10-08 10:45:05 quinn Exp $
+# $Id: Makefile,v 1.32 1997-09-01 08:52:58 adam Exp $
 
 LIBDIR=../lib
 
@@ -16,16 +16,9 @@ LIBS=$(LIBDIR)/libserver.a $(LIBDIR)/libasn.a $(LIBDIR)/libodr.a \
 $(LIBDIR)/libcomstack.a $(LIBMOSI) $(LIBDIR)/libutil.a $(ELIBS)
 PO = eventl.o seshigh.o statserv.o requestq.o
 CPP=$(CC) -E
-PROG=ztest
-PROGO=ztest.o read-grs.o
 RANLIB=ranlib
 
-all: $(LIBDIR) $(LIB) $(PROG)
-
-$(PROG): $(LIB) $(PROGO) 
-       $(CC) $(CFLAGS) $(LIBINCLUDE) -o $(PROG) $(PROGO) $(LIBS)
-
-alll:
+all: $(LIBDIR) $(LIB) 
 
 $(LIB): $(PO)
        rm -f $(LIB)
index cd5aa48..c4120fb 100644 (file)
@@ -4,7 +4,12 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: eventl.c,v $
- * Revision 1.22  1996-07-06 19:58:35  quinn
+ * Revision 1.23  1997-09-01 08:52:59  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.22  1996/07/06 19:58:35  quinn
  * System headerfiles gathered in yconfig
  *
  * Revision 1.21  1996/02/21  12:55:51  quinn
 #include <yconfig.h>
 #include <stdio.h>
 #include <assert.h>
+#ifdef WINDOWS
+#include <winsock.h>
+#else
 #include <unistd.h>
+#endif
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
 
-#include <eventl.h>
-
+#include "eventl.h"
+#include "log.h"
+#include "comstack.h"
+#include "session.h"
+#include "statserv.h"
 #include <xmalloc.h>
 
+#ifndef WINDOWS
+
 static IOCHAN iochans = 0;
 
 IOCHAN iochan_getchan(void)
@@ -92,113 +106,140 @@ IOCHAN iochan_getchan(void)
     return iochans;
 }
 
+#endif /* WINDOWS */
+
 IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags)
 {
-    IOCHAN new;
+    IOCHAN new_iochan;
 
-    if (!(new = xmalloc(sizeof(*new))))
+    if (!(new_iochan = xmalloc(sizeof(*new_iochan))))
        return 0;
-    new->destroyed = 0;
-    new->fd = fd;
-    new->flags = flags;
-    new->fun = cb;
-    new->next = iochans;
-    new->force_event = 0;
-    new->last_event = new->max_idle = 0;
-    iochans = new;
-    return new;
+    new_iochan->destroyed = 0;
+    new_iochan->fd = fd;
+    new_iochan->flags = flags;
+    new_iochan->fun = cb;
+    new_iochan->force_event = 0;
+    new_iochan->last_event = new_iochan->max_idle = 0;
+
+#ifdef WINDOWS
+    /* For windows we don't have a linklist of iochans */
+    new_iochan->next = NULL;
+#else /* WINDOWS */
+    new_iochan->next = iochans;
+    iochans = new_iochan;
+#endif  /* WINDOWS */
+
+    return new_iochan;
 }
 
-int event_loop()
+/* Event loop now takes an iochan as a parameter */
+#ifdef WINDOWS
+int __stdcall event_loop(IOCHAN iochans)
+#else
+int event_loop(IOCHAN dummylistener)
+#endif
 {
     do /* loop as long as there are active associations to process */
     {
        IOCHAN p, nextp;
-       fd_set in, out, except;
-       int res, max;
-       static struct timeval nullto = {0, 0}, to;
-       struct timeval *timeout;
-
-       FD_ZERO(&in);
-       FD_ZERO(&out);
-       FD_ZERO(&except);
-       timeout = &to; /* hang on select */
-       to.tv_sec = 5*60;
-       to.tv_usec = 0;
-       max = 0;
-       for (p = iochans; p; p = p->next)
-       {
-           if (p->force_event)
-               timeout = &nullto;        /* polling select */
-           if (p->flags & EVENT_INPUT)
-               FD_SET(p->fd, &in);
-           if (p->flags & EVENT_OUTPUT)
-               FD_SET(p->fd, &out);
-           if (p->flags & EVENT_EXCEPT)
-               FD_SET(p->fd, &except);
-           if (p->fd > max)
-               max = p->fd;
-       }
-       if ((res = select(max + 1, &in, &out, &except, timeout)) < 0)
-       {
-           if (errno == EINTR)
-               continue;
-           return 1;
-       }
+           fd_set in, out, except;
+           int res, max;
+           static struct timeval nullto = {0, 0}, to;
+           struct timeval *timeout;
+
+           FD_ZERO(&in);
+           FD_ZERO(&out);
+           FD_ZERO(&except);
+           timeout = &to; /* hang on select */
+           to.tv_sec = 5*60;
+           to.tv_usec = 0;
+           max = 0;
        for (p = iochans; p; p = p->next)
        {
-           int force_event = p->force_event;
-           time_t now = time(0);
-
-           p->force_event = 0;
-           if (!p->destroyed && (FD_ISSET(p->fd, &in) || force_event ==
-               EVENT_INPUT))
-           {
-               p->last_event = now;
-               (*p->fun)(p, EVENT_INPUT);
+               if (p->force_event)
+                   timeout = &nullto;        /* polling select */
+               if (p->flags & EVENT_INPUT)
+                   FD_SET(p->fd, &in);
+               if (p->flags & EVENT_OUTPUT)
+                   FD_SET(p->fd, &out);
+               if (p->flags & EVENT_EXCEPT)
+                   FD_SET(p->fd, &except);
+               if (p->fd > max)
+                   max = p->fd;
            }
-           if (!p->destroyed && (FD_ISSET(p->fd, &out) ||
-               force_event == EVENT_OUTPUT))
+           if ((res = select(max + 1, &in, &out, &except, timeout)) < 0)
            {
-               p->last_event = now;
-               (*p->fun)(p, EVENT_OUTPUT);
+               if (errno == EINTR)
+                   continue;
+            else
+            {
+                /* Destroy the first member in the chain, and try again */
+                association *assoc = iochan_getdata(iochans);
+                COMSTACK conn = assoc->client_link;
+
+                cs_close(conn);
+                   destroy_association(assoc);
+                   iochan_destroy(iochans);
+                logf(LOG_DEBUG, "error while selecting, destroying iochan %p", iochans);
+            }
            }
-           if (!p->destroyed && (FD_ISSET(p->fd, &except) ||
-               force_event == EVENT_EXCEPT))
-           {
-               p->last_event = now;
-               (*p->fun)(p, EVENT_EXCEPT);
+       for (p = iochans; p; p = p->next)
+       {
+               int force_event = p->force_event;
+               time_t now = time(0);
+
+               p->force_event = 0;
+               if (!p->destroyed && (FD_ISSET(p->fd, &in) || force_event == EVENT_INPUT))
+               {
+                   p->last_event = now;
+                   (*p->fun)(p, EVENT_INPUT);
+               }
+               if (!p->destroyed && (FD_ISSET(p->fd, &out) ||
+                       force_event == EVENT_OUTPUT))
+               {
+                   p->last_event = now;
+                   (*p->fun)(p, EVENT_OUTPUT);
+               }
+               if (!p->destroyed && (FD_ISSET(p->fd, &except) ||
+                   force_event == EVENT_EXCEPT))
+               {
+                       p->last_event = now;
+                   (*p->fun)(p, EVENT_EXCEPT);
+               }
+               if (!p->destroyed && ((p->max_idle && now - p->last_event >
+                   p->max_idle) || force_event == EVENT_TIMEOUT))
+               {
+                   p->last_event = now;
+                   (*p->fun)(p, EVENT_TIMEOUT);
+               }
            }
-           if (!p->destroyed && ((p->max_idle && now - p->last_event >
-               p->max_idle) || force_event == EVENT_TIMEOUT))
+           for (p = iochans; p; p = nextp)
            {
-               p->last_event = now;
-               (*p->fun)(p, EVENT_TIMEOUT);
-           }
-       }
-       for (p = iochans; p; p = nextp)
-       {
-           nextp = p->next;
+               nextp = p->next;
 
-           if (p->destroyed)
-           {
-               IOCHAN tmp = p, pr;
-
-               if (p == iochans)
-                   iochans = p->next;
-               else
-               {
-                   for (pr = iochans; pr; pr = pr->next)
-                       if (pr->next == p)
-                           break;
-                   assert(pr); /* grave error if it weren't there */
-                   pr->next = p->next;
-               }
-               if (nextp == p)
-                   nextp = p->next;
-               xfree(tmp);
+               if (p->destroyed)
+               {
+                   IOCHAN tmp = p, pr;
+
+                /* We need to inform the threadlist that this channel has been destroyed */
+                statserv_remove(p);
+
+                   /* Now reset the pointers */
+                if (p == iochans)
+                           iochans = p->next;
+                       else
+                       {
+                           for (pr = iochans; pr; pr = pr->next)
+                               if (pr->next == p)
+                                   break;
+                           assert(pr); /* grave error if it weren't there */
+                           pr->next = p->next;
+                       }
+                       if (nextp == p)
+                           nextp = p->next;
+                       xfree(tmp);
+               }
            }
-       }
     }
     while (iochans);
     return 0;
index d9a3a34..80fe7e8 100644 (file)
@@ -4,7 +4,12 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: requestq.c,v $
- * Revision 1.2  1995-11-01 13:54:57  quinn
+ * Revision 1.3  1997-09-01 08:53:00  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.2  1995/11/01 13:54:57  quinn
  * Minor adjustments
  *
  * Revision 1.1  1995/05/15  12:12:22  quinn
@@ -23,9 +28,7 @@
 #include <stdlib.h>
 
 #include <xmalloc.h>
-#include <session.h>
-
-static request *request_list = 0;  /* global freelist for requests */
+#include "session.h"
 
 void request_enq(request_q *q, request *r)
 {
@@ -57,16 +60,27 @@ request *request_deq(request_q *q)
 
 void request_initq(request_q *q)
 {
-    q->head = q->tail = 0;
+    q->head = q->tail = q->list = 0;
     q->num = 0;
 }
 
-request *request_get(void)
+void request_delq(request_q *q)
+{
+    request *r1, *r = q->list;
+    while (r)
+    {
+        r1 = r;
+        r = r->next;
+        xfree (r1);
+    }
+}
+
+request *request_get(request_q *q)
 {
-    request *r = request_list;
+    request *r = q->list;
 
     if (r)
-       request_list = r->next;
+       q->list = r->next;
     else
     {
        if (!(r = xmalloc(sizeof(*r))))
@@ -74,6 +88,7 @@ request *request_get(void)
        r->response = 0;
        r->size_response = 0;
     }
+    r->q = q;
     r->len_refid = 0;
     r->request = 0;
     r->request_mem = 0;
@@ -85,6 +100,7 @@ request *request_get(void)
 
 void request_release(request *r)
 {
-    r->next = request_list;
-    request_list = r;
+    request_q *q = r->q;
+    r->next = q->list;
+    q->list = r;
 }
diff --git a/server/server.dsp b/server/server.dsp
new file mode 100644 (file)
index 0000000..66295ac
--- /dev/null
@@ -0,0 +1,116 @@
+# Microsoft Developer Studio Project File - Name="server" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 5.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=server - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "server.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "server.mak" CFG="server - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "server - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "server - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+\r
+!IF  "$(CFG)" == "server - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WINDOWS" /FD /c\r
+# SUBTRACT CPP /YX\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+# Begin Special Build Tool\r
+OutDir=.\Release\r
+ProjDir=.\r
+TargetName=server\r
+SOURCE=$(InputPath)\r
+PostBuild_Desc=Copy lib\r
+PostBuild_Cmds=copy $(OutDir)\$(TargetName).lib $(ProjDir)\..\lib\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "server - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WINDOWS" /FR /FD /c\r
+# SUBTRACT CPP /YX\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+# Begin Special Build Tool\r
+OutDir=.\Debug\r
+ProjDir=.\r
+TargetName=server\r
+SOURCE=$(InputPath)\r
+PostBuild_Desc=Copy lib\r
+PostBuild_Cmds=copy $(OutDir)\$(TargetName).lib $(ProjDir)\..\lib\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "server - Win32 Release"\r
+# Name "server - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=.\eventl.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\requestq.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seshigh.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\session.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\statserv.c\r
+# End Source File\r
+# End Target\r
+# End Project\r
index 586af65..94c4d45 100644 (file)
@@ -4,7 +4,12 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: seshigh.c,v $
- * Revision 1.64  1997-04-30 08:52:11  quinn
+ * Revision 1.65  1997-09-01 08:53:01  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.64  1997/04/30 08:52:11  quinn
  * Null
  *
  * Revision 1.63  1996/10/11  11:57:26  quinn
 #include <yconfig.h>
 #include <stdlib.h>
 #include <stdio.h>
+#ifdef WINDOWS
+#include <process.h>
+#else
 #include <unistd.h>
+#endif
 #include <assert.h>
 
 #include <xmalloc.h>
 #include <comstack.h>
-#include <eventl.h>
-#include <session.h>
+#include "eventl.h"
+#include "session.h"
 #include <proto.h>
 #include <oid.h>
 #include <log.h>
@@ -342,14 +351,16 @@ void destroy_association(association *h)
        bend_close(h->backend);
     while (request_deq(&h->incoming));
     while (request_deq(&h->outgoing));
-   xfree(h);
+    request_delq(&h->incoming);
+    request_delq(&h->outgoing);
+    xfree(h);
 }
 
 static void do_close(association *a, int reason, char *message)
 {
     Z_APDU apdu;
     Z_Close *cls = zget_Close(a->encode);
-    request *req = request_get();
+    request *req = request_get(&a->outgoing);
 
     /* Purge request queue */
     while (request_deq(&a->incoming));
@@ -437,13 +448,13 @@ void ir_session(IOCHAN h, int event)
                
            /* we got a complete PDU. Let's decode it */
            logf(LOG_DEBUG, "Got PDU, %d bytes", res);
-           req = request_get(); /* get a new request structure */
+           req = request_get(&assoc->incoming); /* get a new request structure */
            odr_reset(assoc->decode);
            odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
            if (!z_APDU(assoc->decode, &req->request, 0))
            {
                logf(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ",
-                   odr_errlist[odr_geterror(assoc->decode)],
+                   odr_errmsg(odr_geterror(assoc->decode)),
                    odr_offset(assoc->decode));
                logf(LOG_LOG, "PDU dump:");
                odr_dumpBER(log_file(), assoc->input_buffer, res);
@@ -454,7 +465,7 @@ void ir_session(IOCHAN h, int event)
            if (assoc->print && !z_APDU(assoc->print, &req->request, 0))
            {
                logf(LOG_WARN, "ODR print error: %s", 
-                   odr_errlist[odr_geterror(assoc->print)]);
+                   odr_errmsg(odr_geterror(assoc->print)));
                odr_reset(assoc->print);
            }
            request_enq(&assoc->incoming, req);
@@ -602,7 +613,7 @@ static int process_response(association *assoc, request *req, Z_APDU *res)
     if (!z_APDU(assoc->encode, &res, 0))
     {
        logf(LOG_WARN, "ODR error when encoding response: %s",
-           odr_errlist[odr_geterror(assoc->decode)]);
+           odr_errmsg(odr_geterror(assoc->decode)));
        odr_reset(assoc->encode);
        return -1;
     }
@@ -613,7 +624,7 @@ static int process_response(association *assoc, request *req, Z_APDU *res)
     if (assoc->print && !z_APDU(assoc->print, &res, 0))
     {
        logf(LOG_WARN, "ODR print error: %s", 
-           odr_errlist[odr_geterror(assoc->print)]);
+           odr_errmsg(odr_geterror(assoc->print)));
        odr_reset(assoc->print);
     }
     /* change this when we make the backend reentrant */
@@ -743,131 +754,111 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
 /*
  * nonsurrogate diagnostic record.
  */
-static Z_Records *diagrec(oid_proto proto, int error, char *addinfo)
+static Z_Records *diagrec(association *assoc, int error, char *addinfo)
 {
-    static Z_Records rec;
+    Z_Records *rec = odr_malloc (assoc->encode, sizeof(*rec));
     oident bib1;
-    static int err;
-#ifdef Z_95
-    static Z_DiagRec drec;
-    static Z_DefaultDiagFormat dr;
-#else
-    static Z_DiagRec dr;
-#endif
+    int *err = odr_malloc (assoc->encode, sizeof(*err));
+    Z_DiagRec *drec = odr_malloc (assoc->encode, sizeof(*drec));
+    Z_DefaultDiagFormat *dr = odr_malloc (assoc->encode, sizeof(*dr));
 
-    bib1.proto = proto;
+    bib1.proto = assoc->proto;
     bib1.oclass = CLASS_DIAGSET;
     bib1.value = VAL_BIB1;
 
     logf(LOG_DEBUG, "Diagnostic: %d -- %s", error, addinfo ? addinfo :
        "NULL");
-    err = error;
-    rec.which = Z_Records_NSD;
+    *err = error;
+    rec->which = Z_Records_NSD;
 #ifdef Z_95
-    rec.u.nonSurrogateDiagnostic = &drec;
-    drec.which = Z_DiagRec_defaultFormat;
-    drec.u.defaultFormat = &dr;
+    rec->u.nonSurrogateDiagnostic = drec;
+    drec->which = Z_DiagRec_defaultFormat;
+    drec->u.defaultFormat = dr;
 #else
-    rec.u.nonSurrogateDiagnostic = &dr;
+    rec->u.nonSurrogateDiagnostic = dr;
 #endif
-    dr.diagnosticSetId = oid_getoidbyent(&bib1);
-    dr.condition = &err;
-    dr.which = Z_DiagForm_v2AddInfo;
-    dr.addinfo = addinfo ? addinfo : "";
-    return &rec;
+    dr->diagnosticSetId = oid_getoidbyent(&bib1);
+    dr->condition = err;
+    dr->which = Z_DiagForm_v2AddInfo;
+    dr->addinfo = addinfo ? addinfo : "";
+    return rec;
 }
 
 /*
  * surrogate diagnostic.
  */
-static Z_NamePlusRecord *surrogatediagrec(oid_proto proto, char *dbname,
+static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
                                            int error, char *addinfo)
 {
-    static Z_NamePlusRecord rec;
-    static int err;
+    Z_NamePlusRecord *rec = odr_malloc (assoc->encode, sizeof(*rec));
+    int *err = odr_malloc (assoc->encode, sizeof(*err));
     oident bib1;
-#ifdef Z_95
-    static Z_DiagRec drec;
-    static Z_DefaultDiagFormat dr;
-#else
-    static Z_DiagRec dr;
-#endif
+    Z_DiagRec *drec = odr_malloc (assoc->encode, sizeof(*drec));
+    Z_DefaultDiagFormat *dr = odr_malloc (assoc->encode, sizeof(*dr));
 
-    bib1.proto = proto;
+    bib1.proto = assoc->proto;
     bib1.oclass = CLASS_DIAGSET;
     bib1.value = VAL_BIB1;
 
     logf(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
-    err = error;
-    rec.databaseName = dbname;
-    rec.which = Z_NamePlusRecord_surrogateDiagnostic;
-#ifdef Z_95
-    rec.u.surrogateDiagnostic = &drec;
-    drec.which = Z_DiagRec_defaultFormat;
-    drec.u.defaultFormat = &dr;
-#else
-    rec.u.surrogateDiagnostic = &dr;
-#endif
-    dr.diagnosticSetId = oid_getoidbyent(&bib1);
-    dr.condition = &err;
-    dr.which = Z_DiagForm_v2AddInfo;
-    dr.addinfo = addinfo ? addinfo : "";
-    return &rec;
+    *err = error;
+    rec->databaseName = dbname;
+    rec->which = Z_NamePlusRecord_surrogateDiagnostic;
+    rec->u.surrogateDiagnostic = drec;
+    drec->which = Z_DiagRec_defaultFormat;
+    drec->u.defaultFormat = dr;
+    dr->diagnosticSetId = oid_getoidbyent(&bib1);
+    dr->condition = err;
+    dr->which = Z_DiagForm_v2AddInfo;
+    dr->addinfo = addinfo ? addinfo : "";
+    return rec;
 }
 
 /*
  * multiple nonsurrogate diagnostics.
  */
-static Z_DiagRecs *diagrecs(oid_proto proto, int error, char *addinfo)
+static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
 {
-    static Z_DiagRecs recs;
-    static int err;
+    Z_DiagRecs *recs = odr_malloc (assoc->encode, sizeof(*recs));
+    int *err = odr_malloc (assoc->encode, sizeof(*err));
     oident bib1;
-#ifdef Z_95
-    static Z_DiagRec *recp[1], drec;
-    static Z_DefaultDiagFormat rec;
-#else
-    static Z_DiagRec *recp[1], rec;
-#endif
+    Z_DiagRec **recp = odr_malloc (assoc->encode, sizeof(*recp));
+    Z_DiagRec *drec = odr_malloc (assoc->encode, sizeof(*drec));
+    Z_DefaultDiagFormat *rec = odr_malloc (assoc->encode, sizeof(*rec));
 
     logf(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo);
-    bib1.proto = proto;
+    bib1.proto = assoc->proto;
     bib1.oclass = CLASS_DIAGSET;
     bib1.value = VAL_BIB1;
 
-    err = error;
-    recs.num_diagRecs = 1;
-    recs.diagRecs = recp;
-#ifdef Z_95
-    recp[0] = &drec;
-    drec.which = Z_DiagRec_defaultFormat;
-    drec.u.defaultFormat = &rec;
-#else
-    recp[0] = &rec;
-#endif
-    rec.diagnosticSetId = oid_getoidbyent(&bib1);
-    rec.condition = &err;
-    rec.which = Z_DiagForm_v2AddInfo;
-    rec.addinfo = addinfo ? addinfo : "";
-    return &recs;
+    *err = error;
+    recs->num_diagRecs = 1;
+    recs->diagRecs = recp;
+    recp[0] = drec;
+    drec->which = Z_DiagRec_defaultFormat;
+    drec->u.defaultFormat = rec;
+
+    rec->diagnosticSetId = oid_getoidbyent(&bib1);
+    rec->condition = err;
+    rec->which = Z_DiagForm_v2AddInfo;
+    rec->addinfo = addinfo ? addinfo : "";
+    return recs;
 }
 
-#define MAX_RECORDS 256
-
 static Z_Records *pack_records(association *a, char *setname, int start,
                                int *num, Z_RecordComposition *comp,
                                int *next, int *pres, oid_value format)
 {
     int recno, total_length = 0, toget = *num, dumped_records = 0;
-    static Z_Records records;
-    static Z_NamePlusRecordList reclist;
-    static Z_NamePlusRecord *list[MAX_RECORDS];
+    Z_Records *records = odr_malloc (a->encode, sizeof(*records));
+    Z_NamePlusRecordList *reclist = odr_malloc (a->encode, sizeof(*reclist));
+    Z_NamePlusRecord **list = odr_malloc (a->encode, sizeof(*list) * toget);
     oident recform;
 
-    records.which = Z_Records_DBOSD;
-    records.u.databaseOrSurDiagnostics = &reclist;
-    reclist.num_records = 0;
-    reclist.records = list;
+    records->which = Z_Records_DBOSD;
+    records->u.databaseOrSurDiagnostics = reclist;
+    reclist->num_records = 0;
+    reclist->records = list;
     *pres = Z_PRES_SUCCESS;
     *num = 0;
     *next = 0;
@@ -875,7 +866,7 @@ static Z_Records *pack_records(association *a, char *setname, int start,
     logf(LOG_DEBUG, "Request to pack %d+%d", start, toget);
     logf(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
        a->maximumRecordSize);
-    for (recno = start; reclist.num_records < toget; recno++)
+    for (recno = start; reclist->num_records < toget; recno++)
     {
        bend_fetchrequest freq;
        bend_fetchresult *fres;
@@ -889,11 +880,6 @@ static Z_Records *pack_records(association *a, char *setname, int start,
         * idea of the total size of the data so far.
         */
        total_length = odr_total(a->encode) - dumped_records;
-       if (reclist.num_records == MAX_RECORDS - 1)
-       {
-           *pres = Z_PRES_PARTIAL_2;
-           break;
-       }
        freq.setname = setname;
        freq.number = recno;
        freq.comp = comp;
@@ -902,14 +888,14 @@ static Z_Records *pack_records(association *a, char *setname, int start,
        if (!(fres = bend_fetch(a->backend, &freq, 0)))
        {
            *pres = Z_PRES_FAILURE;
-           return diagrec(a->proto, 2, "Backend interface problem");
+           return diagrec(a, 2, "Backend interface problem");
        }
        /* backend should be able to signal whether error is system-wide
           or only pertaining to current record */
        if (fres->errcode)
        {
            *pres = Z_PRES_FAILURE;
-           return diagrec(a->proto, fres->errcode, fres->errstring);
+           return diagrec(a, fres->errcode, fres->errstring);
        }
        if (fres->len >= 0)
            this_length = fres->len;
@@ -933,9 +919,9 @@ static Z_Records *pack_records(association *a, char *setname, int start,
                if (toget > 1)
                {
                    logf(LOG_DEBUG, "  Dropped it");
-                   reclist.records[reclist.num_records] =
-                        surrogatediagrec(a->proto, fres->basename, 16, 0);
-                   reclist.num_records++;
+                   reclist->records[reclist->num_records] =
+                        surrogatediagrec(a, fres->basename, 16, 0);
+                   reclist->num_records++;
                    *next = fres->last_in_set ? 0 : recno + 1;
                    dumped_records += this_length;
                    continue;
@@ -944,9 +930,9 @@ static Z_Records *pack_records(association *a, char *setname, int start,
            else /* too big entirely */
            {
                logf(LOG_DEBUG, "Record > maxrcdsz");
-               reclist.records[reclist.num_records] =
-                   surrogatediagrec(a->proto, fres->basename, 17, 0);
-               reclist.num_records++;
+               reclist->records[reclist->num_records] =
+                   surrogatediagrec(a, fres->basename, 17, 0);
+               reclist->num_records++;
                *next = fres->last_in_set ? 0 : recno + 1;
                dumped_records += this_length;
                continue;
@@ -1016,12 +1002,12 @@ static Z_Records *pack_records(association *a, char *setname, int start,
            thisext->u.octet_aligned->len = thisext->u.octet_aligned->size =
                fres->len;
        }
-       reclist.records[reclist.num_records] = thisrec;
-       reclist.num_records++;
+       reclist->records[reclist->num_records] = thisrec;
+       reclist->num_records++;
        *next = fres->last_in_set ? 0 : recno + 1;
     }
-    *num = reclist.num_records;
-    return &records;
+    *num = reclist->num_records;
+    return records;
 }
 
 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
@@ -1057,20 +1043,23 @@ static Z_APDU *response_searchRequest(association *assoc, request *reqb,
     bend_searchresult *bsrt, int *fd)
 {
     Z_SearchRequest *req = reqb->request->u.searchRequest;
-    static Z_APDU apdu;
-    static Z_SearchResponse resp;
-    static int nulint = 0;
-    static bool_t sr = 1;
-    static int next = 0;
-    static int none = Z_RES_NONE;
-
-    apdu.which = Z_APDU_searchResponse;
-    apdu.u.searchResponse = &resp;
-    resp.referenceId = req->referenceId;
-#ifdef Z_95
-    resp.additionalSearchInfo = 0;
-    resp.otherInfo = 0;
-#endif
+    Z_APDU *apdu = odr_malloc (assoc->encode, sizeof(*apdu));
+    Z_SearchResponse *resp = odr_malloc (assoc->encode, sizeof(*resp));
+    int *nulint = odr_malloc (assoc->encode, sizeof(*nulint));
+    bool_t *sr = odr_malloc (assoc->encode, sizeof(*sr));
+    int *next = odr_malloc (assoc->encode, sizeof(*next));
+    int *none = odr_malloc (assoc->encode, sizeof(*none));
+
+    *nulint = 0;
+    *sr = 1;
+    *next = 0;
+    *none = Z_RES_NONE;
+
+    apdu->which = Z_APDU_searchResponse;
+    apdu->u.searchResponse = resp;
+    resp->referenceId = req->referenceId;
+    resp->additionalSearchInfo = 0;
+    resp->otherInfo = 0;
     *fd = -1;
     if (!bsrt && !(bsrt = bend_searchresponse(assoc->backend)))
     {
@@ -1079,44 +1068,45 @@ static Z_APDU *response_searchRequest(association *assoc, request *reqb,
     }
     else if (bsrt->errcode)
     {
-       resp.records = diagrec(assoc->proto, bsrt->errcode,
-           bsrt->errstring);
-       resp.resultCount = &nulint;
-       resp.numberOfRecordsReturned = &nulint;
-       resp.nextResultSetPosition = &nulint;
-       resp.searchStatus = &nulint;
-       resp.resultSetStatus = &none;
-       resp.presentStatus = 0;
+       resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
+       resp->resultCount = nulint;
+       resp->numberOfRecordsReturned = nulint;
+       resp->nextResultSetPosition = nulint;
+       resp->searchStatus = nulint;
+       resp->resultSetStatus = none;
+       resp->presentStatus = 0;
     }
     else
     {
-       static int toget;
+       int *toget = odr_malloc (assoc->encode, sizeof(*toget));
+        int *presst = odr_malloc (assoc->encode, sizeof(*presst));
        Z_RecordComposition comp, *compp = 0;
-       static int presst = 0;
 
-       resp.records = 0;
-       resp.resultCount = &bsrt->hits;
+        *toget = 0;
+        *presst = 0;
+       resp->records = 0;
+       resp->resultCount = &bsrt->hits;
 
        comp.which = Z_RecordComp_simple;
        /* how many records does the user agent want, then? */
        if (bsrt->hits <= *req->smallSetUpperBound)
        {
-           toget = bsrt->hits;
+           *toget = bsrt->hits;
            if ((comp.u.simple = req->smallSetElementSetNames))
                compp = &comp;
        }
        else if (bsrt->hits < *req->largeSetLowerBound)
        {
-           toget = *req->mediumSetPresentNumber;
-           if (toget > bsrt->hits)
-               toget = bsrt->hits;
+           *toget = *req->mediumSetPresentNumber;
+           if (*toget > bsrt->hits)
+               *toget = bsrt->hits;
            if ((comp.u.simple = req->mediumSetElementSetNames))
                compp = &comp;
        }
        else
-           toget = 0;
+           *toget = 0;
 
-       if (toget && !resp.records)
+       if (*toget && !resp->records)
        {
            oident *prefformat;
            oid_value form;
@@ -1126,28 +1116,28 @@ static Z_APDU *response_searchRequest(association *assoc, request *reqb,
                form = VAL_NONE;
            else
                form = prefformat->value;
-           resp.records = pack_records(assoc, req->resultSetName, 1,
-               &toget, compp, &next, &presst, form);
-           if (!resp.records)
+           resp->records = pack_records(assoc, req->resultSetName, 1,
+               toget, compp, next, presst, form);
+           if (!resp->records)
                return 0;
-           resp.numberOfRecordsReturned = &toget;
-           resp.nextResultSetPosition = &next;
-           resp.searchStatus = &sr;
-           resp.resultSetStatus = 0;
-           resp.presentStatus = &presst;
+           resp->numberOfRecordsReturned = toget;
+           resp->nextResultSetPosition = next;
+           resp->searchStatus = sr;
+           resp->resultSetStatus = 0;
+           resp->presentStatus = presst;
        }
        else
        {
-           if (*resp.resultCount)
-               next = 1;
-           resp.numberOfRecordsReturned = &nulint;
-           resp.nextResultSetPosition = &next;
-           resp.searchStatus = &sr;
-           resp.resultSetStatus = 0;
-           resp.presentStatus = 0;
+           if (*resp->resultCount)
+               *next = 1;
+           resp->numberOfRecordsReturned = nulint;
+           resp->nextResultSetPosition = next;
+           resp->searchStatus = sr;
+           resp->resultSetStatus = 0;
+           resp->presentStatus = 0;
        }
     }
-    return &apdu;
+    return apdu;
 }
 
 /*
@@ -1169,37 +1159,40 @@ static Z_APDU *process_presentRequest(association *assoc, request *reqb,
     int *fd)
 {
     Z_PresentRequest *req = reqb->request->u.presentRequest;
-    static Z_APDU apdu;
-    static Z_PresentResponse resp;
-    static int presst, next, num;
+    Z_APDU *apdu = odr_malloc (assoc->encode, sizeof(*apdu));
+    Z_PresentResponse *resp = odr_malloc (assoc->encode, sizeof(*resp));
+    int *presst = odr_malloc (assoc->encode, sizeof(*presst));
+    int *next = odr_malloc (assoc->encode, sizeof(*next));
+    int *num = odr_malloc (assoc->encode, sizeof(*num));
     oident *prefformat;
     oid_value form;
 
-
     logf(LOG_LOG, "Got PresentRequest.");
-    apdu.which = Z_APDU_presentResponse;
-    apdu.u.presentResponse = &resp;
-    resp.referenceId = req->referenceId;
-#ifdef Z_95
-    resp.otherInfo = 0;
-#endif
+    *presst = 0;
+    *next = 0;
+    *num = 0;
+
+    apdu->which = Z_APDU_presentResponse;
+    apdu->u.presentResponse = resp;
+    resp->referenceId = req->referenceId;
+    resp->otherInfo = 0;
 
     if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
        prefformat->oclass != CLASS_RECSYN)
        form = VAL_NONE;
     else
        form = prefformat->value;
-    num = *req->numberOfRecordsRequested;
-    resp.records = pack_records(assoc, req->resultSetId,
-       *req->resultSetStartPoint, &num, req->recordComposition, &next,
-       &presst, form);
-    if (!resp.records)
+    *num = *req->numberOfRecordsRequested;
+    resp->records = pack_records(assoc, req->resultSetId,
+       *req->resultSetStartPoint, num, req->recordComposition, next,
+       presst, form);
+    if (!resp->records)
        return 0;
-    resp.numberOfRecordsReturned = &num;
-    resp.presentStatus = &presst;
-    resp.nextResultSetPosition = &next;
+    resp->numberOfRecordsReturned = num;
+    resp->presentStatus = presst;
+    resp->nextResultSetPosition = next;
 
-    return &apdu;
+    return apdu;
 }
 
 /*
@@ -1209,38 +1202,38 @@ static Z_APDU *process_presentRequest(association *assoc, request *reqb,
 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
 {
     Z_ScanRequest *req = reqb->request->u.scanRequest;
-    static Z_APDU apdu;
-    static Z_ScanResponse res;
-    static int scanStatus = Z_Scan_failure;
-    static int numberOfEntriesReturned = 0;
+    Z_APDU *apdu = odr_malloc (assoc->encode, sizeof(*apdu));
+    Z_ScanResponse *res = odr_malloc (assoc->encode, sizeof(*res));
+    int *scanStatus = odr_malloc (assoc->encode, sizeof(*scanStatus));
+    int *numberOfEntriesReturned =
+         odr_malloc (assoc->encode, sizeof(*numberOfEntriesReturned));
+    Z_ListEntries *ents = odr_malloc (assoc->encode, sizeof(*ents));
     oident *attent;
-    static Z_ListEntries ents;
-#define SCAN_MAX_ENTRIES 200
-    static Z_Entry *tab[SCAN_MAX_ENTRIES];
     bend_scanrequest srq;
     bend_scanresult *srs;
     oident *attset;
 
     logf(LOG_LOG, "Got scanrequest");
-    apdu.which = Z_APDU_scanResponse;
-    apdu.u.scanResponse = &res;
-    res.referenceId = req->referenceId;
-    res.stepSize = 0;
-    res.scanStatus = &scanStatus;
-    res.numberOfEntriesReturned = &numberOfEntriesReturned;
-    res.positionOfTerm = 0;
-    res.entries = &ents;
-    ents.which = Z_ListEntries_nonSurrogateDiagnostics;
-    res.attributeSet = 0;
-#ifdef Z_95
-    res.otherInfo = 0;
-#endif
+    *scanStatus = Z_Scan_failure;
+    *numberOfEntriesReturned = 0;
+
+    apdu->which = Z_APDU_scanResponse;
+    apdu->u.scanResponse = res;
+    res->referenceId = req->referenceId;
+    res->stepSize = 0;
+    res->scanStatus = scanStatus;
+    res->numberOfEntriesReturned = numberOfEntriesReturned;
+    res->positionOfTerm = 0;
+    res->entries = ents;
+    ents->which = Z_ListEntries_nonSurrogateDiagnostics;
+    res->attributeSet = 0;
+    res->otherInfo = 0;
 
     if (req->attributeSet && (!(attent = oid_getentbyoid(req->attributeSet)) ||
        attent->oclass != CLASS_ATTSET || attent->value != VAL_BIB1))
-       ents.u.nonSurrogateDiagnostics = diagrecs(assoc->proto, 121, 0);
+       ents->u.nonSurrogateDiagnostics = diagrecs(assoc, 121, 0);
     else if (req->stepSize && *req->stepSize > 0)
-       ents.u.nonSurrogateDiagnostics = diagrecs(assoc->proto, 205, 0);
+       ents->u.nonSurrogateDiagnostics = diagrecs(assoc, 205, 0);
     else
     {
        if (req->termListAndStartPoint->term->which == Z_Term_general)
@@ -1259,34 +1252,31 @@ static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
        srq.term_position = req->preferredPositionInResponse ?
            *req->preferredPositionInResponse : 1;
        if (!(srs = bend_scan(assoc->backend, &srq, 0)))
-           ents.u.nonSurrogateDiagnostics = diagrecs(assoc->proto, 2, 0);
+           ents->u.nonSurrogateDiagnostics = diagrecs(assoc, 2, 0);
        else if (srs->errcode)
-           ents.u.nonSurrogateDiagnostics = diagrecs(assoc->proto,
+           ents->u.nonSurrogateDiagnostics = diagrecs(assoc,
                srs->errcode, srs->errstring);
        else
        {
            int i;
-           static Z_Entries list;
+           Z_Entries *list = odr_malloc (assoc->encode, sizeof(*list));
+            Z_Entry **tab = odr_malloc (assoc->encode,
+                                        sizeof(*tab) * srs->num_entries);
 
            if (srs->status == BEND_SCAN_PARTIAL)
-               scanStatus = Z_Scan_partial_5;
+               *scanStatus = Z_Scan_partial_5;
            else
-               scanStatus = Z_Scan_success;
-           ents.which = Z_ListEntries_entries;
-           ents.u.entries = &list;
-           list.entries = tab;
+               *scanStatus = Z_Scan_success;
+           ents->which = Z_ListEntries_entries;
+           ents->u.entries = list;
+           list->entries = tab;
            for (i = 0; i < srs->num_entries; i++)
            {
                Z_Entry *e;
                Z_TermInfo *t;
                Odr_oct *o;
 
-               if (i >= SCAN_MAX_ENTRIES)
-               {
-                   scanStatus = Z_Scan_partial_4;
-                   break;
-               }
-               list.entries[i] = e = odr_malloc(assoc->encode, sizeof(*e));
+               list->entries[i] = e = odr_malloc(assoc->encode, sizeof(*e));
                e->which = Z_Entry_termInfo;
                e->u.termInfo = t = odr_malloc(assoc->encode, sizeof(*t));
                t->suggestedAttributes = 0;
@@ -1305,13 +1295,13 @@ static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
                logf(LOG_DEBUG, "  term #%d: '%s' (%d)", i,
                    srs->entries[i].term, srs->entries[i].occurrences);
            }
-           list.num_entries = i;
-           res.numberOfEntriesReturned = &list.num_entries;
-           res.positionOfTerm = &srs->term_position;
+           list->num_entries = i;
+           res->numberOfEntriesReturned = &list->num_entries;
+           res->positionOfTerm = &srs->term_position;
        }
     }
 
-    return &apdu;
+    return apdu;
 }
 
 static void process_close(association *assoc, request *reqb)
index ab63da3..aefe3da 100644 (file)
@@ -4,7 +4,12 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: session.h,v $
- * Revision 1.11  1995-11-08 17:41:40  quinn
+ * Revision 1.12  1997-09-01 08:53:01  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.11  1995/11/08 17:41:40  quinn
  * Smallish.
  *
  * Revision 1.10  1995/08/29  11:18:01  quinn
@@ -49,7 +54,7 @@
 #include <oid.h>
 #include <proto.h>
 #include <sys/types.h>
-#include <eventl.h>
+#include "eventl.h"
 
 typedef struct request
 {
@@ -69,12 +74,14 @@ typedef struct request
     char *response;        /* encoded data waiting for transmission */
 
     struct request *next;
+    struct request_q *q; 
 } request;
 
 typedef struct request_q
 {
     request *head;
     request *tail;
+    request *list;
     int num;
 } request_q;
 
@@ -118,7 +125,8 @@ void request_enq(request_q *q, request *r);
 request *request_head(request_q *q);
 request *request_deq(request_q *q);
 void request_initq(request_q *q);
-request *request_get(void);
+void request_delq(request_q *q);
+request *request_get(request_q *q);
 void request_release(request *r);
 
 #endif
index 3f86861..a09ba6b 100644 (file)
@@ -4,7 +4,12 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: statserv.c,v $
- * Revision 1.36  1996-07-06 19:58:36  quinn
+ * Revision 1.37  1997-09-01 08:53:01  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.36  1996/07/06 19:58:36  quinn
  * System headerfiles gathered in yconfig
  *
  * Revision 1.35  1996/05/29  10:03:28  quinn
 
 #include <yconfig.h>
 #include <stdio.h>
+#ifdef WINDOWS
+#include <process.h>
+#include <winsock.h>
+#include <direct.h>
+#else
 #include <unistd.h>
+#include <pwd.h>
+#endif
 #include <fcntl.h>
 #include <signal.h>
 #include <errno.h>
-#include <pwd.h>
 
 #include <options.h>
-#include <eventl.h>
-#include <session.h>
-#include <eventl.h>
+#include "eventl.h"
+#include "session.h"
 #include <comstack.h>
 #include <tcpip.h>
 #ifdef USE_XTIMOSI
 #include <log.h>
 #include <statserv.h>
 
+static IOCHAN pListener;
+
 static char *me = "statserver";
 /*
  * default behavior.
@@ -164,6 +176,249 @@ static statserv_options_block control_block = {
  * doing all of the listening and accepting in the parent - it's
  * safer that way.
  */
+#ifdef WINDOWS
+
+typedef struct _ThreadList ThreadList;
+
+typedef struct _ThreadList
+{
+    HANDLE hThread;
+    IOCHAN pIOChannel;
+    ThreadList *pNext;
+} ThreadList;
+
+static ThreadList *pFirstThread;
+static CRITICAL_SECTION Thread_CritSect;
+static BOOL bInitialized = FALSE;
+
+static void ThreadList_Initialize()
+{
+    /* Initialize the critical Sections */
+     InitializeCriticalSection(&Thread_CritSect);
+
+     /* Set the first thraed */
+     pFirstThread = NULL;
+
+     /* we have been initialized */
+     bInitialized = TRUE;
+}
+
+static void statserv_add(HANDLE hThread, IOCHAN pIOChannel)
+{
+    /* Only one thread can go through this section at a time */
+    EnterCriticalSection(&Thread_CritSect);
+
+    {
+        /* Lets create our new object */
+        ThreadList *pNewThread = (ThreadList *)malloc(sizeof(ThreadList));
+        pNewThread->hThread = hThread;
+        pNewThread->pIOChannel = pIOChannel;
+        pNewThread->pNext = pFirstThread;
+        pFirstThread = pNewThread;
+
+        /* Lets let somebody else create a new object now */
+        LeaveCriticalSection(&Thread_CritSect);
+    }
+}
+
+void statserv_remove(IOCHAN pIOChannel)
+{
+    /* Only one thread can go through this section at a time */
+    EnterCriticalSection(&Thread_CritSect);
+
+    {
+        ThreadList *pCurrentThread = pFirstThread;
+        ThreadList *pNextThread;
+        ThreadList *pPrevThread =NULL;
+
+        /* Step through alll the threads */
+        for (; pCurrentThread != NULL; pCurrentThread = pNextThread)
+        {
+            /* We only need to compare on the IO Channel */
+            if (pCurrentThread->pIOChannel == pIOChannel)
+            {
+                /* We have found the thread we want to delete */
+                /* First of all reset the next pointers */
+                if (pPrevThread == NULL)
+                    pFirstThread = pCurrentThread->pNext;
+                else
+                    pPrevThread->pNext = pCurrentThread->pNext;
+
+                /* All we need todo now is delete the memory */
+                free(pCurrentThread);
+
+                /* No need to look at any more threads */
+                pNextThread = NULL;
+            }
+            else
+            {
+                /* We need to look at another thread */
+                pNextThread = pCurrentThread->pNext;
+            }
+        }
+
+        /* Lets let somebody else remove an object now */
+        LeaveCriticalSection(&Thread_CritSect);
+    }
+}
+
+void statserv_closedown()
+{
+    /* Shouldn't do anything if we are not initialized */
+    if (bInitialized)
+    {
+        int iHandles = 0;
+        HANDLE *pThreadHandles = NULL;
+
+        /* We need to stop threads adding and removing while we start the closedown process */
+        EnterCriticalSection(&Thread_CritSect);
+
+        {
+            /* We have exclusive access to the thread stuff now */
+            /* Y didn't i use a semaphore - Oh well never mind */
+            ThreadList *pCurrentThread = pFirstThread;
+
+            /* Before we do anything else, we need to shutdown the listener */
+            if (pListener != NULL)
+                iochan_destroy(pListener);
+
+            for (; pCurrentThread != NULL; pCurrentThread = pCurrentThread->pNext)
+            {
+                /* Just destroy the IOCHAN, that should do the trick */
+                iochan_destroy(pCurrentThread->pIOChannel);
+
+                /* Keep a running count of our handles */
+                iHandles++;
+            }
+
+            if (iHandles > 0)
+            {
+                HANDLE *pCurrentHandle ;
+
+                /* Allocate the thread handle array */
+                pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles);
+                pCurrentHandle = pThreadHandles; 
+
+                for (pCurrentThread = pFirstThread;
+                     pCurrentThread != NULL;
+                     pCurrentThread = pCurrentThread->pNext, pCurrentHandle++)
+                {
+                    /* Just the handle */
+                    *pCurrentHandle = pCurrentThread->hThread;
+                }
+            }
+
+            /* We can now leave the critical section */
+            LeaveCriticalSection(&Thread_CritSect);
+        }
+
+        /* Now we can really do something */
+        if (iHandles > 0)
+        {
+            /* This will now wait, until all the threads close */
+            WaitForMultipleObjects(iHandles, pThreadHandles, TRUE, INFINITE);
+
+            /* Free the memory we allocated for the handle array */
+            free(pThreadHandles);
+        }
+
+        /* No longer require the critical section, since all threads are dead */
+        DeleteCriticalSection(&Thread_CritSect);
+    }
+}
+
+static void listener(IOCHAN h, int event)
+{
+    COMSTACK line = (COMSTACK) iochan_getdata(h);
+    association *newas;
+    int res;
+    HANDLE NewHandle;
+
+    if (event == EVENT_INPUT)
+    {
+        if ((res = cs_listen(line, 0, 0)) < 0)
+        {
+               logf(LOG_FATAL, "cs_listen failed.");
+           return;
+        }
+        else if (res == 1)
+               return;
+        logf(LOG_DEBUG, "listen ok");
+        iochan_setevent(h, EVENT_OUTPUT);
+        iochan_setflags(h, EVENT_OUTPUT | EVENT_EXCEPT); /* set up for acpt */
+    }
+    else if (event == EVENT_OUTPUT)
+    {
+       COMSTACK new_line;
+       IOCHAN new_chan;
+           char *a;
+        DWORD ThreadId;
+
+           if (!(new_line = cs_accept(line)))
+           {
+               logf(LOG_FATAL, "Accept failed.");
+               iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+               return;
+           }
+           logf(LOG_DEBUG, "accept ok");
+
+           if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, EVENT_INPUT)))
+           {
+               logf(LOG_FATAL, "Failed to create iochan");
+            iochan_destroy(h);
+            return;
+           }
+           if (!(newas = create_association(new_chan, new_line)))
+           {
+               logf(LOG_FATAL, "Failed to create new assoc.");
+            iochan_destroy(h);
+            return;
+           }
+           iochan_setdata(new_chan, newas);
+           iochan_settimeout(new_chan, control_block.idle_timeout * 60);
+           a = cs_addrstr(new_line);
+           logf(LOG_LOG, "Accepted connection from %s", a ? a : "[Unknown]");
+
+        /* Now what we need todo is create a new thread with this iochan as the parameter */
+/*        if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)event_loop, new_chan, 0, &ThreadId) == NULL)
+*/
+        /* Somehow, somewhere we need to store this thread id, otherwise we won't be able to close cleanly */
+        NewHandle = (HANDLE)_beginthreadex(NULL, 0, event_loop, new_chan, 0, &ThreadId);
+        if (NewHandle == (HANDLE)-1)
+           {
+               logf(LOG_FATAL, "Failed to create new thread.");
+            iochan_destroy(h);
+            return;
+           }
+
+        /* We successfully created the thread, so add it to the list */
+        statserv_add(NewHandle, new_chan);
+
+        logf(LOG_DEBUG, "Created new thread, iochan %p", new_chan);
+        iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+    }
+    else
+    {
+       logf(LOG_FATAL, "Bad event on listener.");
+        iochan_destroy(h);
+        return;
+    }
+}
+
+#else /* WINDOWS */
+
+/* To save having an #ifdef in event_loop we need to define this empty function */
+void statserv_remove(IOCHAN pIOChannel)
+{
+}
+
+void statserv_closedown()
+{
+    /* We don't need todoanything here - or do we */
+    if (pListener != NULL)
+        iochan_destroy(pListener);
+}
+
 static void listener(IOCHAN h, int event)
 {
     COMSTACK line = (COMSTACK) iochan_getdata(h);
@@ -181,12 +436,14 @@ static void listener(IOCHAN h, int event)
            if (pipe(hand) < 0)
            {
                logf(LOG_FATAL|LOG_ERRNO, "pipe");
-               exit(1);
+                iochan_destroy(h);
+                return;
            }
            if ((res = fork()) < 0)
            {
                logf(LOG_FATAL|LOG_ERRNO, "fork");
-               exit(1);
+                iochan_destroy(h);
+                return;
            }
            else if (res == 0) /* child */
            {
@@ -219,7 +476,7 @@ static void listener(IOCHAN h, int event)
                    if ((res = read(hand[0], dummy, 1)) < 0 && errno != EINTR)
                    {
                        logf(LOG_FATAL|LOG_ERRNO, "handshake read");
-                       exit(1);
+                        return;
                    }
                    else if (res >= 0)
                        break;
@@ -275,12 +532,14 @@ static void listener(IOCHAN h, int event)
            EVENT_INPUT)))
        {
            logf(LOG_FATAL, "Failed to create iochan");
-           exit(1);
+            iochan_destroy(h);
+            return;
        }
        if (!(newas = create_association(new_chan, new_line)))
        {
            logf(LOG_FATAL, "Failed to create new assoc.");
-           exit(1);
+            iochan_destroy(h);
+            return;
        }
        iochan_setdata(new_chan, newas);
        iochan_settimeout(new_chan, control_block.idle_timeout * 60);
@@ -290,10 +549,13 @@ static void listener(IOCHAN h, int event)
     else
     {
        logf(LOG_FATAL, "Bad event on listener.");
-       exit(1);
+        iochan_destroy(h);
+        return;
     }
 }
 
+#endif /* WINDOWS */
+
 static void inetd_connection(int what)
 {
     COMSTACK line;
@@ -301,25 +563,31 @@ static void inetd_connection(int what)
     association *assoc;
     char *addr;
 
-    if (!(line = cs_createbysocket(0, tcpip_type, 0, what)))
+    if ((line = cs_createbysocket(0, tcpip_type, 0, what)))
     {
-       logf(LOG_ERRNO|LOG_FATAL, "Failed to create comstack on socket 0");
-       exit(1);
-    }
-    if (!(chan = iochan_create(cs_fileno(line), ir_session, EVENT_INPUT)))
-    {
-       logf(LOG_FATAL, "Failed to create iochan");
-       exit(1);
+        if ((chan = iochan_create(cs_fileno(line), ir_session, EVENT_INPUT)))
+        {
+            if ((assoc = create_association(chan, line)))
+            {
+                iochan_setdata(chan, assoc);
+                iochan_settimeout(chan, control_block.idle_timeout * 60);
+                addr = cs_addrstr(line);
+                logf(LOG_LOG, "Inetd association from %s", addr ? addr : "[UNKNOWN]");
+            }
+            else
+            {
+               logf(LOG_FATAL, "Failed to create association structure");
+            }
+        }
+        else
+        {
+            logf(LOG_FATAL, "Failed to create iochan");
+        }
     }
-    if (!(assoc = create_association(chan, line)))
+    else
     {
-       logf(LOG_FATAL, "Failed to create association structure");
-       exit(1);
+       logf(LOG_ERRNO|LOG_FATAL, "Failed to create comstack on socket 0");
     }
-    iochan_setdata(chan, assoc);
-    iochan_settimeout(chan, control_block.idle_timeout * 60);
-    addr = cs_addrstr(line);
-    logf(LOG_LOG, "Inetd association from %s", addr ? addr : "[UNKNOWN]");
 }
 
 /*
@@ -331,20 +599,18 @@ static void add_listener(char *where, int what)
     CS_TYPE type;
     char mode[100], addr[100];
     void *ap;
-    IOCHAN lst;
+    IOCHAN lst = NULL;
 
     if (!where || sscanf(where, "%[^:]:%s", mode, addr) != 2)
     {
        fprintf(stderr, "%s: Address format: ('tcp'|'osi')':'<address>.\n",
            me);
-       exit(1);
     }
     if (!strcmp(mode, "tcp"))
     {
        if (!(ap = tcpip_strtoaddr(addr)))
        {
            fprintf(stderr, "Address resolution failed for TCP.\n");
-           exit(1);
        }
        type = tcpip_type;
     }
@@ -354,18 +620,15 @@ static void add_listener(char *where, int what)
        if (!(ap = mosi_strtoaddr(addr)))
        {
            fprintf(stderr, "Address resolution failed for TCP.\n");
-           exit(1);
        }
        type = mosi_type;
 #else
        fprintf(stderr, "OSI Transport not allowed by configuration.\n");
-       exit(1);
 #endif
     }
     else
     {
        fprintf(stderr, "You must specify either 'osi:' or 'tcp:'.\n");
-       exit(1);
     }
     logf(LOG_LOG, "Adding %s %s listener on %s",
         control_block.dynamic ? "dynamic" : "static",
@@ -373,28 +636,32 @@ static void add_listener(char *where, int what)
     if (!(l = cs_create(type, 0, what)))
     {
        logf(LOG_FATAL|LOG_ERRNO, "Failed to create listener");
-       exit(1);
     }
     if (cs_bind(l, ap, CS_SERVER) < 0)
     {
        logf(LOG_FATAL|LOG_ERRNO, "Failed to bind to %s", where);
-       exit(1);
     }
     if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT |
         EVENT_EXCEPT)))
     {
        logf(LOG_FATAL|LOG_ERRNO, "Failed to create IOCHAN-type");
-       exit(1);
     }
     iochan_setdata(lst, l);
+
+    /* Ensure our listener chain is setup properly */
+    lst->next = pListener;
+    pListener = lst;
 }
 
+#ifndef WINDOWS
+/* For windows we don't need to catch the signals */
 static void catchchld(int num)
 {
     while (waitpid(-1, 0, WNOHANG) > 0)
        ;
     signal(SIGCHLD, catchchld);
 }
+#endif /* WINDOWS */
 
 statserv_options_block *statserv_getcontrol(void)
 {
@@ -415,14 +682,19 @@ int statserv_main(int argc, char **argv)
     char *arg;
     int protocol = control_block.default_proto;
 
+#ifdef WINDOWS
+    /* We need to initialize the thread list */
+    ThreadList_Initialize();
+#endif /* WINDOWS */
+
     me = argv[0];
     while ((ret = options("a:iszSl:v:u:c:w:t:k:", argv, argc, &arg)) != -2)
     {
        switch (ret)
        {
            case 0:
-               add_listener(arg, protocol);
-               listeners++;
+                   add_listener(arg, protocol);
+                   listeners++;
                break;
            case 'z': protocol = PROTO_Z3950; break;
            case 's': protocol = PROTO_SR; break;
@@ -446,7 +718,7 @@ int statserv_main(int argc, char **argv)
                {
                    fprintf(stderr, "%s: Specify positive timeout for -t.\n",
                        me);
-                   exit(1);
+                   return(1);
                }
                control_block.idle_timeout = r;
                break;
@@ -455,7 +727,7 @@ int statserv_main(int argc, char **argv)
                {
                    fprintf(stderr, "%s: Specify positive timeout for -t.\n",
                        me);
-                   exit(1);
+                   return(1);
                }
                control_block.maxrecordsize = r * 1024;
                break;
@@ -465,7 +737,8 @@ int statserv_main(int argc, char **argv)
                if (chdir(arg))
                {
                    perror(arg);
-                   exit(1);
+
+                   return(1);
                }
                break;
            default:
@@ -473,17 +746,24 @@ int statserv_main(int argc, char **argv)
                         " -l <logfile> -u <user> -c <config> -t <minutes>"
                        " -k <kilobytes>"
                         " -zsS <listener-addr> -w <directory> ... ]\n", me);
-               exit(1);
+               return(1);
             }
     }
+
+#ifdef WINDOWS
+    log_init(control_block.loglevel, NULL, control_block.logfile);
+#endif /* WINDOWS */
+
+    if ((pListener == NULL) && *control_block.default_listen)
+           add_listener(control_block.default_listen, protocol);
+
+#ifndef WINDOWS
     if (inetd)
        inetd_connection(protocol);
     else
     {
        if (control_block.dynamic)
            signal(SIGCHLD, catchchld);
-       if (!listeners && *control_block.default_listen)
-           add_listener(control_block.default_listen, protocol);
     }
     if (*control_block.setuid)
     {
@@ -492,7 +772,7 @@ int statserv_main(int argc, char **argv)
        if (!(pw = getpwnam(control_block.setuid)))
        {
            logf(LOG_FATAL, "%s: Unknown user", control_block.setuid);
-           exit(1);
+           return(1);
        }
        if (setuid(pw->pw_uid) < 0)
        {
@@ -500,7 +780,12 @@ int statserv_main(int argc, char **argv)
            exit(1);
        }
     }
+#endif /* WINDOWS */
+
     logf(LOG_LOG, "Entering event loop.");
-           
-    return event_loop();
+       
+    if (pListener == NULL)
+        return(1);
+    else
+        return event_loop(pListener);
 }