Dear Gustaf,
        Thank you as always for all your work.

About Windows I cannot really talk about MinGW nor Cygwin. I'm just using
Visual Studio 2015 with 64 bit as target.
With this configuration I tried to modify the file sockaddr.c (to make it
compile), but I'm not sure about the changes I made.
I also had to modify the file nswin32.c as I could not find anywhere the
function "NsSockGetPort".
Well the resulting system compiles... but nothing works.
I need much more time to do a proper testing/tuning and I can't do that at
the moment.
As soon as I discover more, I'll let you know.

Back to your delivery of the 16th of February.

Once again thank you,
Maurizio


-----Original Message-----
From: Gustaf Neumann [mailto:neum...@wu.ac.at] 
Sent: 24 February 2016 14:01
To: Navidevel <naviserver-devel@lists.sourceforge.net>
Subject: [naviserver-devel] IPv6 for NaviServer

Dear all,

over the last week, i've worked on IPv6 support for NaviServer.
For this task, i took the following path:
1) build a version of NaviServer for IPv6
2) build a single code source for compiling either for IPv4 or IPv6
3) let the IPv6 version run the setup-files for IPv4 in the IPv6 version
4) Run regression test suite under IPv4 and/IPv6
5) Allow mixed mode (handle IPv4 and IPv6 by the same binary)
    (requires some interface changes to handle generic sockaddrs)

Everything seems to work fine, one can work with the same config files as
before, and everything works as expected, but one can as well listen on IPv6
addresses (e.g.
the IPv6 unspecified address "::"). IPv4->6 mapping is activated, or the
kernel allows to deliver as well
IPv4 traffic to the IPv6 interface, then one can talk also multiple
protocols. The mileage may vary depending on the OS and kernel.

It is as well possible to deactivate IPv6 support at compile time via
--disable-ipv6.

Here is a summary of the necessary changes:
- Added a amall Abstraction API for IP-version agnostic calls:
   Ns_LogSockaddr(), Ns_SockaddrGetPort(),
   Ns_SockaddrGetSockLen(), Ns_SockaddrMask(), Ns_SockaddrMaskBits(),
   Ns_SockaddrSetPort(), ns_inet_ntop(), ns_inet_pton()

- Replaced in interface more places where "sockaddr_in" (the IPv4
   version of the sockaddr) with the generic (version agnostic)
   sockaddr (also in IPv4 code to obtain API consistency when no IPv6
   is available): Ns_BindSock(), Ns_ConnSetPeer(), Ns_GetSockAddr(),
   Ns_SockBind(), Ns_SockBindUdp()

- The Ns_Sock structure contained sockaddr_in, which is not sufficient
   to store IPv6 addresses. Therefore it was necessary to change
   that to "sockaddr_storage" which guarantees to be large enough
   to keep all kind of addresses. This affects as well driver modules
   which communicate via the NaviServer managed sockets. Old drivers
   might crash with the new structure. Therefore, I've bumped
   NS_DRIVER_VERSION to 3 such that driver modules (also binaries)
   can communicate that they support IPv6. In IPv6 mode, NaviServer
   refuses to work with versions <3.

- Replaced all usages of ns_inet_ntoa() by ns_intet_ntop()
   (except for legacy an minimal library support)

- Added log file warnings on various places, where NaviServer
   was ignoring error states in socket communications silently.

- Transformed hash table for open listen ports to string keys
   (the old code used 32bit IPv4-addresses as keys in hash tables)
- added test for ns_listencallback

- Ns_HttpParseHost: new abstraction for parsing host and port number.
   Reason: IPv6 literal notation contains many colons, parsing
   IP-literal notation according to RFC 3986 section 3.2.2 is necessary
   (removed places where code was searching for ':' to expect the port)

- Added [ns_info ipv6] to obtain information whether the binary
   supports IPv6 or not

- Added configure flag --disable-ipv6 to build NaviServer just with
   IPv4 support.

- provide defines for core differences between IPv4 and IPv6 #ifdef
HAVE_IPV6
# define NS_IP_LOOPBACK     "::1"
# define NS_IP_UNSPECIFIED  "::"
# define NS_SOCKADDR_IN     sockaddr_storage
# define NS_IPADDR_SIZE     INET6_ADDRSTRLEN
#else
# define NS_IP_LOOPBACK     "127.0.0.1"
# define NS_IP_UNSPECIFIED  "0.0.0.0"
# define NS_SOCKADDR_IN     sockaddr_in
# define NS_IPADDR_SIZE     INET_ADDRSTRLEN
#endif

  - nsperm:
   * Aligned implementation with the documentation
     (hosts.allow/deny have comma-separated entries)
   * Added submask specification in the form /xxx
     (e.g. ::1/64)
   * Use binary IPv4 and IPv6 values for hash and mask lookup
   * Generalizing masking functions
   * Refactor code to avoid memory leaks
   * Updated documentation

- modules:
   * nsudp and nsssl are now IPv6 aware/compliant

TODOs:
- more platform testing
   (probably changes for Windows necessary, help is appreciated)
- remove commented out debug statements

- make more modules IPv6 compliant
- documentation updates

I've tested the generic and IPv4 only version via regression test and random
browsing on Mac OS X and Linux. If you have other platforms, testing would
be appreciated. There are some adjustments for windows probably necessary
(in the absence of "configure", one has to add manually "HAVE_IPV4" to the
compile flags). Any help is welcome.

best regards
-gustaf neumann


----------------------------------------------------------------------------
--
Site24x7 APM Insight: Get Deep Visibility into Application Performance APM +
Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor
end-to-end web transactions and take corrective actions now Troubleshoot
faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
naviserver-devel mailing list
naviserver-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/naviserver-devel
/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://mozilla.org/.
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is AOLserver Code and related documentation
 * distributed by AOL.
 *
 * The Initial Developer of the Original Code is America Online,
 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
 * Inc. All Rights Reserved.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU General Public License (the "GPL"), in which case the
 * provisions of GPL are applicable instead of those above.  If you wish
 * to allow use of your version of this file only under the terms of the
 * GPL and not to allow others to use your version of this file under the
 * License, indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by the GPL.
 * If you do not delete the provisions above, a recipient may use your
 * version of this file under either the License or the GPL.
 */

#include "nsd.h"

/*
 * sockaddr.c --
 *
 *      Generic Interface for IPv4 and IPv6
 */


#if defined(__APPLE__) || defined(__darwin__)
/* OSX seems not to define these. */
# ifndef s6_addr16
#  define s6_addr16 __u6_addr.__u6_addr16
# endif
# ifndef s6_addr32
#  define s6_addr32 __u6_addr.__u6_addr32
# endif
#endif


/*
 *----------------------------------------------------------------------
 *
 * Ns_SockaddrMask --
 *
 *      Compute from and address and a mask a masked address in a generic way
 *      (for IPv4 and IPv6 addresses).
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      The last argument (maskedAddr) is updated.
 *
 *----------------------------------------------------------------------
 */
void
Ns_SockaddrMask(struct sockaddr *addr, struct sockaddr *mask, struct sockaddr 
*maskedAddr)
{
    NS_NONNULL_ASSERT(addr != NULL);
    NS_NONNULL_ASSERT(mask != NULL);
    NS_NONNULL_ASSERT(maskedAddr != NULL);

    /*
     * Copy the full content to maskedAddr in case it is not identical.
     */
    if (addr != maskedAddr) {
        memcpy(maskedAddr, addr, sizeof(struct NS_SOCKADDR_STORAGE));
    }

    if (addr->sa_family == AF_INET6 && mask->sa_family == AF_INET6) {
        struct in6_addr *addrBits   = &(((struct sockaddr_in6 
*)addr)->sin6_addr);
        struct in6_addr *maskBits   = &(((struct sockaddr_in6 
*)mask)->sin6_addr);
        struct in6_addr *maskedBits = &(((struct sockaddr_in6 
*)maskedAddr)->sin6_addr);
        int i;

        /*
         * Perform bitwise masking over the full array. Maybe we need
         * something special for IN6_IS_ADDR_V4MAPPED.
         */
        for (i = 0; i < 16; i++) {

                        /* maskedBits->s6_addr32[i] = addrBits->s6_addr32[i] & 
maskBits->s6_addr32[i]; */
                        maskedBits-> u.Byte[i] = addrBits->u.Byte[i] & 
maskBits->u.Byte[i];
        }
        /*
          fprintf(stderr, "#### addr   %s\n",ns_inet_ntoa(addr));
          fprintf(stderr, "#### mask   %s\n",ns_inet_ntoa(mask));
          fprintf(stderr, "#### masked %s\n",ns_inet_ntoa(maskedAddr));
        */
    } else if (addr->sa_family == AF_INET && mask->sa_family == AF_INET) {
        ((struct sockaddr_in *)maskedAddr)->sin_addr.s_addr =
            ((struct sockaddr_in *)addr)->sin_addr.s_addr &
            ((struct sockaddr_in *)mask)->sin_addr.s_addr;
    } else if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) {
        Ns_Log(Error, "nsperm: invalid address family %d detected 
(Ns_SockaddrMask addr)", addr->sa_family);
    } else if (mask->sa_family != AF_INET && mask->sa_family != AF_INET6) {
        Ns_Log(Error, "nsperm: invalid address family %d detected 
(Ns_SockaddrMask mask)", mask->sa_family);
    }
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_SockaddrMaskBits --
 *
 *      Build a mask with the given bits in a IPv4 or IPv6 sockaddr
 *
 * Results:
 *      Mask computed in 1 arg.
 *
 * Side effects:
 *      The first argument is updated.
 *
 *----------------------------------------------------------------------
 */
void
Ns_SockaddrMaskBits(struct sockaddr *mask, unsigned int nrBits)
{
    NS_NONNULL_ASSERT(mask != NULL);

    if (mask->sa_family == AF_INET6) {
        struct in6_addr *addr = &(((struct sockaddr_in6 *)mask)->sin6_addr);
        int i;

        if (nrBits > 128) {
            Ns_Log(Warning, "Invalid bitmask /%d: can be most 128 bits", 
nrBits);
            nrBits = 128;
        }
        /*
         * Set the mask bits in the leading 32 bit ints to 1.
         */
        for (i = 0; i < 16 && nrBits >= 32; i++, nrBits -= 8) {
            addr->u.Byte[i] = (~0u);
        }
        /*
         * Set the partial mask.
         */
        if (i < 16 && nrBits > 0) {
            addr->u.Byte[i] = htonl((~0u) << (8 - nrBits));
            i++;
        }
        /*
         * Clear trailing 32 bit ints.
         */
        for (; i < 16; i++) {
            addr->u.Byte[i] = 0u;
        }
        /*fprintf(stderr, "#### FINAL mask %s\n",ns_inet_ntoa(mask));*/
    } else if (mask->sa_family == AF_INET) {
        if (nrBits > 32) {
            Ns_Log(Warning, "Invalid bitmask /%d: can be most 32 bits", nrBits);
            nrBits = 32;
        }
        ((struct sockaddr_in *)mask)->sin_addr.s_addr = htonl((~0u) << (32 - 
nrBits));
    } else {
        Ns_Log(Error, "nsperm: invalid address family %d detected 
(Ns_SockaddrMaskBits)", mask->sa_family);
    }
}


/*
 *----------------------------------------------------------------------
 *
 * ns_inet_ntop --
 *
 *    This function is a version of inet_ntop() which is agnostic to IPv4 and 
IPv6.
 *
 * Results:
 *    String pointing to printable ip address.
 *
 * Side effects:
 *    Update provided buffer with resulting character string.
 *
 *----------------------------------------------------------------------
 */
const char *
ns_inet_ntop(const struct sockaddr *saPtr, char *buffer, size_t size) {
    const char *result;

    NS_NONNULL_ASSERT(saPtr != NULL);
    NS_NONNULL_ASSERT(buffer != NULL);

    if (saPtr->sa_family == AF_INET6) {
        result = inet_ntop(AF_INET6, &((struct sockaddr_in6 
*)saPtr)->sin6_addr, buffer, size);
    } else {
        result = inet_ntop(AF_INET, &((struct sockaddr_in *)saPtr)->sin_addr, 
buffer, size);
    }
    
    return result;
}


/*
 *----------------------------------------------------------------------
 *
 * ns_inet_pton --
 *
 *  Convert an IPv4/IPv6 address in textual form to a binary IPv6
 *  form. IPV4 addresses are converted to "mapped IPv4 addresses".
 *
 * Results:
 *  >0  = Success.
 *  <=0 = Error:
 *   <0 = Invalid address family. As this routine hardcodes the AF,
 *        this result should not occur.
 *    0 = Parse error.
 *
 * Side effects:
 *  None.
 *
 *----------------------------------------------------------------------
 */
int
ns_inet_pton(struct sockaddr *saPtr, const char *addr) {
    int r;

    NS_NONNULL_ASSERT(saPtr != NULL);
    NS_NONNULL_ASSERT(addr != NULL);

    /*
     * First try whether the address parses as an IPv4 address
     */
    r = inet_pton(AF_INET, addr, &((struct sockaddr_in *)saPtr)->sin_addr);
    if (r > 0) {
        saPtr->sa_family = AF_INET;
        /*Ns_LogSockaddr(Notice, "ns_inet_pton returns IPv4 address", saPtr);*/
    } else {
#ifdef HAVE_IPV6
        /*
         * No IPv4 address, try to parse as IPv6 address
         */
        r = inet_pton(AF_INET6, addr, &((struct sockaddr_in6 
*)saPtr)->sin6_addr);
        saPtr->sa_family = AF_INET6;

        /*Ns_LogSockaddr(Notice, "ns_inet_pton returns IPv6 address", saPtr);*/
#endif
    }
    return r;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_GetSockAddr --
 *
 *      Take a host/port and fill in a NS_SOCKADDR_STORAGE structure
 *      appropriately. Host may be an IP address or a DNS name.
 *
 * Results:
 *      NS_OK/NS_ERROR
 *
 * Side effects:
 *      May perform DNS query.
 *
 *----------------------------------------------------------------------
 */
int
Ns_GetSockAddr(struct sockaddr *saPtr, const char *host, int port)
{
    NS_NONNULL_ASSERT(saPtr != NULL);

    //fprintf(stderr, "# GetSockAddr host '%s' port %d\n", host, port);
    
    memset(saPtr, 0, sizeof(struct NS_SOCKADDR_STORAGE));
    
#ifdef HAVE_IPV6
    if (host == NULL) {
        saPtr->sa_family = AF_INET6;
        ((struct sockaddr_in6 *)saPtr)->sin6_addr = in6addr_any;
    } else {
        int r;

        r = ns_inet_pton((struct sockaddr *)saPtr, host);
        if (r <= 0) {
            Ns_DString ds;

            Ns_DStringInit(&ds);
            //fprintf(stderr, "# GetSockAddr ... calls Ns_GetAddrByHost\n");
            if (Ns_GetAddrByHost(&ds, host) == NS_TRUE) {
                //fprintf(stderr, "# GetAddrByHost returns <%s>\n", ds.string);
                r = ns_inet_pton((struct sockaddr *)saPtr, ds.string);
            }
            Ns_DStringFree(&ds);
            if (r <= 0) {
                //fprintf(stderr, "# GetSockAddr ... fails\n");
                return NS_ERROR;
            }
        }
    }

#else
    saPtr->sa_family = AF_INET;

    if (host == NULL) {
        ((struct sockaddr_in *)saPtr)->sin_addr.s_addr = htonl(INADDR_ANY);
    } else {
        ((struct sockaddr_in *)saPtr)->sin_addr.s_addr = inet_addr(host);
        if (((struct sockaddr_in *)saPtr)->sin_addr.s_addr == INADDR_NONE) {
            Ns_DString ds;

            Ns_DStringInit(&ds);
            if (Ns_GetAddrByHost(&ds, host) == NS_TRUE) {
                ((struct sockaddr_in *)saPtr)->sin_addr.s_addr = 
inet_addr(ds.string);
            }
            Ns_DStringFree(&ds);
            if (((struct sockaddr_in *)saPtr)->sin_addr.s_addr == INADDR_NONE) {
                return NS_ERROR;
            }
        }
    }
#endif

    Ns_SockaddrSetPort((struct sockaddr *)saPtr, port);
    /*Ns_LogSockaddr(Notice, "Ns_GetSockAddr returns", (const struct sockaddr 
*)saPtr);*/

    return NS_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Ns_SockaddrGetPort --
 *
 *      Generic function to obtain port from an IPv4 or IPv6 sock addr.
 *
 * Results:
 *      Port number
 *
 * Side effects:
 *      None
 *
 *----------------------------------------------------------------------
 */
unsigned short
Ns_SockaddrGetPort(const struct sockaddr *saPtr)
{
    unsigned int port;
    
    NS_NONNULL_ASSERT(saPtr != NULL);
    
#ifdef HAVE_IPV6
    if (saPtr->sa_family == AF_INET6) {
        port = ((struct sockaddr_in6 *)saPtr)->sin6_port;
    } else {
        port = ((struct sockaddr_in *)saPtr)->sin_port;
    }
#else
    port = ((struct sockaddr_in *)saPtr)->sin_port;
#endif
    
    return htons(port);
}

/*
 *----------------------------------------------------------------------
 *
 * Ns_SockaddrSetPort --
 *
 *      Generic function to set port in an IPv4 or IPv6 sock addr.
 *
 * Results:
 *      Port number
 *
 * Side effects:
 *      None
 *
 *----------------------------------------------------------------------
 */
void
Ns_SockaddrSetPort(struct sockaddr *saPtr, unsigned short port)
{
    NS_NONNULL_ASSERT(saPtr != NULL);
    
#ifdef HAVE_IPV6
    if (saPtr->sa_family == AF_INET6) {
        ((struct sockaddr_in6 *)saPtr)->sin6_port = ntohs(port);
    } else {
        ((struct sockaddr_in *)saPtr)->sin_port = ntohs(port);
    }
#else
    ((struct sockaddr_in *)saPtr)->sin_port = ntohs(port);
#endif

}

/*
 *----------------------------------------------------------------------
 *
 * Ns_SockaddrGetSockLen --
 *
 *      Generic function to obtain socklen from an IPv4 or IPv6 sockaddr.
 *
 * Results:
 *      socklen.
 *
 * Side effects:
 *      None
 *
 *----------------------------------------------------------------------
 */
socklen_t
Ns_SockaddrGetSockLen(const struct sockaddr *saPtr)
{
    size_t socklen;
    
    NS_NONNULL_ASSERT(saPtr != NULL);
    
#ifdef HAVE_IPV6
    socklen = (saPtr->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : 
sizeof(struct sockaddr_in);
#else
    socklen = sizeof(struct sockaddr_in);
#endif
    
    return (socklen_t)socklen;
}

/*
 *----------------------------------------------------------------------
 *
 * Ns_LogSockSockaddr --
 *
 *      Function to log generic SockAddr.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Entry in log file.
 *
 *----------------------------------------------------------------------
 */
void
Ns_LogSockaddr(Ns_LogSeverity severity, const char *prefix, const struct 
sockaddr *saPtr)
{
    const char *family;
    char        ipString[NS_IPADDR_SIZE], *ipStrPtr = ipString;
    
    NS_NONNULL_ASSERT(prefix != NULL);
    NS_NONNULL_ASSERT(saPtr != NULL);

    family = (saPtr->sa_family == AF_INET6) ? "AF_INET6" :
        (saPtr->sa_family == AF_INET) ? "AF_INET" : "UNKOWN";

    ns_inet_ntop(saPtr, ipString, NS_IPADDR_SIZE);
    
    Ns_Log(severity, "%s: SockAddr %p, family %s, ip %s, port %d",
           prefix, (void*)saPtr, family, ipStrPtr, Ns_SockaddrGetPort(saPtr));
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * indent-tabs-mode: nil
 * End:
 */
/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/.
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is AOLserver Code and related documentation
 * distributed by AOL.
 *
 * The Initial Developer of the Original Code is America Online,
 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
 * Inc. All Rights Reserved.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU General Public License (the "GPL"), in which case the
 * provisions of GPL are applicable instead of those above.  If you wish
 * to allow use of your version of this file only under the terms of the
 * GPL and not to allow others to use your version of this file under the
 * License, indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by the GPL.
 * If you do not delete the provisions above, a recipient may use your
 * version of this file under either the License or the GPL.
 */

#ifdef _WIN32

/*
 * win32.c --
 *
 *  Win32 specific routines.
 */

#include "nsd.h"
#include <share.h>

static Ns_ThreadProc ServiceTicker;
static void StopTicker(void);
static void StartTicker(DWORD pending);
static VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
static VOID WINAPI ServiceHandler(DWORD code);
static BOOL WINAPI ConsoleHandler(DWORD code);
static void ReportStatus(DWORD state, DWORD code, DWORD hint);
static char *GetServiceName(Ns_DString *dsPtr, char *service);

/*
 * Static variables used in this file
 */

static Ns_Mutex lock;
static Ns_Cond cond;
static Ns_Thread tickThread;
static SERVICE_STATUS_HANDLE hStatus = 0;
static SERVICE_STATUS curStatus;
static Ns_Tls tls;
static int serviceRunning = 0;
static int tick = 0;
static unsigned int sigpending = 0u;
static int serviceFailed = 0;

#define SysErrMsg() (NsWin32ErrMsg(GetLastError()))


/*
 *----------------------------------------------------------------------
 *
 * NsBlockSignal --
 *
 *      Mask one specific signal.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

void
NsBlockSignal(int UNUSED(sig))
{
    return;
}


/*
 *----------------------------------------------------------------------
 *
 * NsUnblockSignal --
 *
 *      Restores one specific signal.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Signal will be unblock.
 *
 *----------------------------------------------------------------------
 */

void
NsUnblockSignal(int UNUSED(sig))
{
    return;
}

int
Ns_SetGroup(const char *UNUSED(group))
{
    return -1;
}

int
Ns_SetUser(const char *UNUSED(user))
{
    return -1;
}


/*
 *----------------------------------------------------------------------
 *
 * DllMain --
 *
 *      Init routine for the nsd.dll which setups TLS for Win32 errors
 *      disables thread attach/detach calls.
 *
 * Results:
 *      TRUE or FALSE.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

BOOL APIENTRY
DllMain(HANDLE hModule, DWORD why, LPVOID UNUSED(lpReserved))
{
    WSADATA wsd;

    if (why == (DWORD)DLL_PROCESS_ATTACH) {
        Ns_TlsAlloc(&tls, ns_free);
        if (WSAStartup((WORD)MAKEWORD(1, 1), &wsd) != 0) {
            return FALSE;
        }
        DisableThreadLibraryCalls(hModule);
        Nsd_LibInit();
    } else if (why == (DWORD)DLL_PROCESS_DETACH) {
        WSACleanup();
    }

    return TRUE;
}


/*
 *----------------------------------------------------------------------
 *
 * NsWin32ErrMsg --
 *
 *      Get a string message for an error code in either the kernel or
 *      wsock dll's.
 *
 * Results:
 *      Pointer to per-thread LocalAlloc'ed memory.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

char *
NsWin32ErrMsg(DWORD err)
{
    char  *msg;
    size_t len;

    msg = Ns_TlsGet(&tls);
    if (msg == NULL) {
        msg = ns_malloc(1000u);
        Ns_TlsSet(&tls, msg);
    }
    snprintf(msg, 1000u, "win32 error code: %lu: ", err);
    len = strlen(msg);
    
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
                  msg+len, (DWORD)(1000u - len), NULL);

    return msg;
}


/*
 *----------------------------------------------------------------------
 *
 * NsConnectService --
 *
 *      Attach to the service control manager at startup.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Service control manager will create a new thread running
 *      ServiceMain().
 *
 *----------------------------------------------------------------------
 */

int
NsConnectService(void)
{
    SERVICE_TABLE_ENTRY table[2];
    BOOL   ok;
    HANDLE fi;

    /*
     * Close all opened streams at this point
     */

    _fcloseall();

    /*
     * Re-route std streams to null because they will be
     * handled separately, i.e. re-routed to log file in
     * the LogReOpen() function. The stdin remains bound
     * to nul: device forever.
     */

    freopen(DEVNULL, "rt", stdin);
    freopen(DEVNULL, "wt", stdout);
    freopen(DEVNULL, "wt", stderr);

    /*
     * Ensure that stdio handles are correctly set.
     * Fail to do this will result in Tcl library
     * thinking that no stdio handles are defined.
     */

    fi = (HANDLE) _get_osfhandle(_fileno(stdin));
    if (fi != INVALID_HANDLE_VALUE) {
        SetStdHandle(STD_INPUT_HANDLE, fi);
    }
    fi = (HANDLE) _get_osfhandle(_fileno(stdout));
    if (fi != INVALID_HANDLE_VALUE) {
        SetStdHandle(STD_OUTPUT_HANDLE, fi);
    }
    fi = (HANDLE) _get_osfhandle(_fileno(stderr));
    if (fi != INVALID_HANDLE_VALUE) {
        SetStdHandle(STD_ERROR_HANDLE, fi);
    }

    Ns_Log(Notice, "nswin32: connecting to service control manager");

    serviceRunning = 1;

    table[0].lpServiceName = PACKAGE_NAME;
    table[0].lpServiceProc = ServiceMain;
    table[1].lpServiceName = NULL;
    table[1].lpServiceProc = NULL;

    ok = StartServiceCtrlDispatcher(table);

    if (ok == 0) {
        Ns_Log(Error, "nswin32: StartServiceCtrlDispatcher(): '%s'",
               SysErrMsg());
    }

    return ((ok != 0) ? NS_OK : NS_ERROR);
}


/*
 *----------------------------------------------------------------------
 *
 * NsRemoveService --
 *
 *      Remove a previously installed service.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Service should stop and then disappear from the list in the
 *      services control panel.
 *
 *----------------------------------------------------------------------
 */

int
NsRemoveService(char *service)
{
    SC_HANDLE hmgr;
    SERVICE_STATUS status;
    Ns_DString name;
    BOOL ok;

    Ns_DStringInit(&name);
    (void) GetServiceName(&name, service);
    ok = FALSE;
    hmgr = OpenSCManager(NULL, NULL, (DWORD)SC_MANAGER_ALL_ACCESS);
    if (hmgr != NULL) {
        SC_HANDLE hsrv = OpenService(hmgr, name.string, 
(DWORD)SERVICE_ALL_ACCESS);
        if (hsrv != NULL) {
            ControlService(hsrv, (DWORD)SERVICE_CONTROL_STOP, &status);
            ok = DeleteService(hsrv);
            CloseServiceHandle(hsrv);
        }
        CloseServiceHandle(hmgr);
    }
    if (ok != 0) {
        Ns_Log(Notice, "nswin32: removed service: %s", name.string);
    } else {
        Ns_Log(Error, "nswin32: failed to remove %s service: %s",
               name.string, SysErrMsg());
    }
    Ns_DStringFree(&name);

    return ((ok != 0) ? NS_OK : NS_ERROR);
}


/*
 *----------------------------------------------------------------------
 *
 * NsInstallService --
 *
 *      Install as an NT service.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Service should appear in the list in the services control panel.
 *
 *----------------------------------------------------------------------
 */

int
NsInstallService(char *service)
{
    SC_HANDLE hmgr, hsrv;
    bool ok = FALSE;
    char nsd[PATH_MAX], config[PATH_MAX];
    Ns_DString name, cmd;

    if (_fullpath(config, nsconf.config, sizeof(config)) == NULL) {
        Ns_Log(Error, "nswin32: invalid config path '%s'", nsconf.config);
    } else if (GetModuleFileName(NULL, nsd, sizeof(nsd)) == 0u) {
        Ns_Log(Error, "nswin32: failed to find nsd.exe: '%s'", SysErrMsg());
    } else {
        Ns_DStringInit(&name);
        Ns_DStringInit(&cmd);
        Ns_DStringVarAppend(&cmd, "\"", nsd, "\"",
                            " -S -s ", service, " -t \"", config, "\"", NULL);
        (void) GetServiceName(&name, service);
        hmgr = OpenSCManager(NULL, NULL, (DWORD)SC_MANAGER_ALL_ACCESS);
        if (hmgr != NULL) {
            hsrv = CreateService(hmgr, name.string, name.string,
                                 (DWORD)SERVICE_ALL_ACCESS,  
                                 (DWORD)SERVICE_WIN32_OWN_PROCESS,
                                 (DWORD)SERVICE_AUTO_START, 
                                 (DWORD)SERVICE_ERROR_NORMAL,
                                 cmd.string, NULL, NULL, "TcpIp\0", NULL, NULL);
            if (hsrv != NULL) {
                CloseServiceHandle(hsrv);
                ok = TRUE;
            } else {
                Ns_Log(Error, "nswin32: failed to install service '%s': '%s'",
                       name.string, SysErrMsg());
            }
            CloseServiceHandle(hmgr);
        } else {
            Ns_Log(Error, "nswin32: failed to connect to service manager: %s", 
SysErrMsg());
        }
        Ns_DStringFree(&name);
        Ns_DStringFree(&cmd);
    }

    return ((ok != 0) ? NS_OK : NS_ERROR);
}


/*
 *----------------------------------------------------------------------
 * NsRestoreSignals --
 *
 *      Noop to avoid ifdefs and make symetrical to Unix part
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

void
NsRestoreSignals(void)
{
    return;
}


/*
 *----------------------------------------------------------------------
 *
 * NsHandleSignals --
 *
 *      Loop endlessly, processing HUP signals until a TERM
 *      signal arrives
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

int
NsHandleSignals(void)
{
    unsigned int sig;

    /*
     * If running as a service, stop the ticker thread and report
     * startup complete. Otherwise, register a handler which will
     * initiate an orderly shutdown on Ctrl-C.
     */

    if (serviceRunning == 0) {
        SetConsoleCtrlHandler(ConsoleHandler, TRUE);
    } else {
        StopTicker();
        ReportStatus((DWORD)SERVICE_RUNNING, NO_ERROR, 0u);
    }
    Ns_MutexSetName2(&lock, "ns", "signal");
    do {
        Ns_MutexLock(&lock);
        while (sigpending == 0u) {
            Ns_CondWait(&cond, &lock);
        }
        sig = sigpending;
        sigpending = 0u;
        if ((sig & (unsigned int)(1u << NS_SIGINT)) != 0u) {

           /*
            * Signalize the Service Control Manager
            * to restart the service.
            */

            serviceFailed = 1;
        }
        Ns_MutexUnlock(&lock);
        if ((sig & (unsigned int)(1u << NS_SIGHUP)) != 0u) {
            NsRunSignalProcs();
        }
    } while ((sig & (unsigned int)(1u << NS_SIGHUP)) != 0u);

    /*
     * If running as a service, startup the ticker thread again
     * to keep updating status until shutdown is complete.
     */

    if (serviceRunning != 0) {
        StartTicker((DWORD)SERVICE_STOP_PENDING);
    }

    return (int)sig;
}


/*
 *----------------------------------------------------------------------
 *
 * NsSendSignal --
 *
 *      Send a signal to wakeup NsHandleSignals. As on Unix, a signal
 *      sent multiple times is only received once.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Main thread will wakeup.
 *
 *----------------------------------------------------------------------
 */

void
NsSendSignal(int sig)
{
    switch (sig) {
    case NS_SIGTERM:
    case NS_SIGINT:
    case NS_SIGHUP:
        Ns_MutexLock(&lock);
        sigpending |= (1u << sig);
        Ns_CondSignal(&cond);
        Ns_MutexUnlock(&lock);
        break;
    default:
        Ns_Fatal("nswin32: invalid signal: %d", sig);
        break;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * NsMemMap --
 *
 *      Maps a file to memory.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

int
NsMemMap(const char *path, size_t size, int mode, FileMap *mapPtr)
{
    HANDLE hndl, mobj;
    LPCVOID addr;
    char name[256];

    switch (mode) {
    case NS_MMAP_WRITE:
        hndl = CreateFile(path,
                          (DWORD)(GENERIC_READ|GENERIC_WRITE),
                          (DWORD)(FILE_SHARE_READ|FILE_SHARE_WRITE),
                          NULL,
                          (DWORD)OPEN_EXISTING,
                          (DWORD)FILE_FLAG_WRITE_THROUGH,
                          NULL);
        break;
    case NS_MMAP_READ:
        hndl = CreateFile(path,
                          GENERIC_READ,
                          (DWORD)FILE_SHARE_READ,
                          NULL,
                          (DWORD)OPEN_EXISTING,
                          0u,
                          NULL);
        break;
    default:
        return NS_ERROR;
    }

    if (hndl == NULL || hndl == INVALID_HANDLE_VALUE) {
        Ns_Log(Error, "CreateFile(%s): %ld", path, GetLastError());
        return NS_ERROR;
    }

    snprintf(name, sizeof(name), "MapObj-%s", Ns_ThreadGetName());

    mobj = CreateFileMapping(hndl,
                             NULL,
                             mode == NS_MMAP_WRITE ? (DWORD)PAGE_READWRITE : 
(DWORD)PAGE_READONLY,
                             0u,
                             0u,
                             name);

    if (mobj == NULL || mobj == INVALID_HANDLE_VALUE) {
        Ns_Log(Error, "CreateFileMapping(%s): %ld", path, GetLastError());
        CloseHandle(hndl);
        return NS_ERROR;
    }

    addr = MapViewOfFile(mobj,
                         mode == NS_MMAP_WRITE ? (DWORD)FILE_MAP_WRITE : 
(DWORD)FILE_MAP_READ,
                         0u,
                         0u,
                         size);

    if (addr == NULL) {
        Ns_Log(Warning, "MapViewOfFile(%s): %ld", path, GetLastError());
        CloseHandle(mobj);
        CloseHandle(hndl);
        return NS_ERROR;
    }

    mapPtr->mapobj = (void *) mobj;
    mapPtr->handle = (int) hndl;
    mapPtr->addr   = (void *) addr;
    mapPtr->size   = size;

    return NS_OK;
}


/*
 *----------------------------------------------------------------------
 *
 * NsMemUmap --
 *
 *      Unmaps a file.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

void
NsMemUmap(const FileMap *mapPtr)
{
    UnmapViewOfFile((LPCVOID)mapPtr->addr);
    CloseHandle((HANDLE)mapPtr->mapobj);
    CloseHandle((HANDLE)mapPtr->handle);
}


/*
 *----------------------------------------------------------------------
 *
 * ns_socknbclose --
 *
 *      Perform a non-blocking socket close via the socket callback
 *      thread.
 *      This is only called by a timeout in Ns_SockTimedConnect.
 *
 * Results:
 *      0 or SOCKET_ERROR.
 *
 * Side effects:
 *      Socket will be closed when writable.
 *
 *----------------------------------------------------------------------
 */

int
ns_socknbclose(NS_SOCKET sock)
{
    if (Ns_SockCloseLater(sock) != NS_OK) {
        return SOCKET_ERROR;
    }

    return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * ns_sockdup --
 *
 *      Duplicate a socket. This is used in the old ns_sock Tcl cmds.
 *
 * Results:
 *      New handle to underlying socket.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

NS_SOCKET
ns_sockdup(NS_SOCKET sock)
{
    HANDLE hp, src, dup;

    src = (HANDLE) sock;
    hp = GetCurrentProcess();
    if (DuplicateHandle(hp, src, hp, &dup, 0u, FALSE, 
(DWORD)DUPLICATE_SAME_ACCESS) == 0) {
        return NS_INVALID_SOCKET;
    }

    return (NS_SOCKET) dup;
}


/*
 *----------------------------------------------------------------------
 * ns_sock_set_blocking --
 *
 *      Set a channel blocking or non-blocking
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Change blocking state of a channel
 *
 *----------------------------------------------------------------------
 */

int
ns_sock_set_blocking(NS_SOCKET sock, bool blocking) 
{
    u_long state = (blocking == NS_FALSE) ? 1u : 0u;

    return ioctlsocket(sock, (long)FIONBIO, &state);
}


/*
 *----------------------------------------------------------------------
 *
 * ns_pipe --
 *
 *      Create a pipe marked close-on-exec.
 *
 * Results:
 *      0 if ok, -1 on error.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

int
ns_pipe(int *fds)
{
    return _pipe(fds, 4096u, _O_NOINHERIT|_O_BINARY);
}


/*
 *----------------------------------------------------------------------
 *
 * ns_mkstemp --
 *
 *      Create a temporary file based on the provided character template and
 *      return its fd.  This is a cheap replacement for mkstemp() under
 *      unix-like systems.
 *
 * Results:
 *      fd if ok, NS_INVALID_FD on error.
 *
 * Side effects:
 *      Opens a temporary file.
 *
 *----------------------------------------------------------------------
 */

int
ns_mkstemp(char *charTemplate) 
{
    int err, fd = NS_INVALID_FD;

    err = _mktemp_s(charTemplate, strlen(charTemplate));

    if (err == 0) {
        err = _sopen_s(&fd, charTemplate, 
                       O_RDWR | O_CREAT |_O_TEMPORARY | O_EXCL, 
                       _SH_DENYRW,
                       _S_IREAD | _S_IWRITE);
    }

    if (err != 0) {
        return -1;
    }

    return fd;
}

const char *
inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
    return InetNtop(af, src, dst, size);
}


/*
 *----------------------------------------------------------------------
 *
 * SockAddrEqual --
 *
 *      Compare two sockaddr structures. This is just 
 *      a helper for ns_sockpair
 *
 * Results:
 *      NS_TRUE if the two structures are equal
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static bool
SockAddrEqual(struct sockaddr *saPtr1, struct sockaddr *saPtr2)
{
#ifdef HAVE_IPV6
    if (saPtr1->sa_family != saPtr2->sa_family) {
        return NS_FALSE;
    }
    if (saPtr1->sa_family == AF_INET) {
        if (((struct sockaddr_in *)saPtr1)->sin_addr.s_addr !=
            ((struct sockaddr_in *)saPtr2)->sin_addr.s_addr) {
            return NS_FALSE;
        }
    } else if (saPtr1->sa_family == AF_INET6) {
        struct in6_addr *sa1Bits = &(((struct sockaddr_in6 
*)saPtr1)->sin6_addr);
        struct in6_addr *sa2Bits = &(((struct sockaddr_in6 
*)saPtr2)->sin6_addr);
        int i;
        
        for (i = 0; i < 4; i++) {
            if (sa1Bits->s6_addr32[i] != sa2Bits->s6_addr32[i]) {
                return NS_FALSE;
            }
        }
    } else {
        return NS_FALSE;
    }
#else
    if (((struct sockaddr_in *)saPtr1)->sin_addr.s_addr !=
        ((struct sockaddr_in *)saPtr2)->sin_addr.s_addr) {
        return NS_FALSE;
    }
#endif
    return NS_TRUE;
}


/*
 *----------------------------------------------------------------------
 *
 * ns_sockpair --
 *
 *      Create a pair of connected sockets via brute force.
 *      Sock pairs are used as trigger pipes in various subsystems.
 *
 * Results:
 *      0 if ok, -1 on error.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

int
ns_sockpair(NS_SOCKET socks[2])
{
    NS_SOCKET sock;
    struct NS_SOCKADDR_STORAGE ia[2];
    int size;

    size = (int)sizeof(struct NS_SOCKADDR_STORAGE);
    sock = Ns_SockListen(NS_IP_LOOPBACK, 0);
    if (sock == NS_INVALID_SOCKET ||
        getsockname(sock, (struct sockaddr *) &ia[0], &size) != 0) {
        return -1;
    }
    size = (int)sizeof(struct NS_SOCKADDR_STORAGE);
    /* socks[1] = Ns_SockConnect(NS_IP_LOOPBACK, (int) NsSockGetPort((struct 
sockaddr *)&ia[0])); */
        socks[1] = Ns_SockConnect(NS_IP_LOOPBACK, (int)ntohs(ia[0].sin_port));
    if (socks[1] == NS_INVALID_SOCKET ||
        getsockname(socks[1], (struct sockaddr *) &ia[1], &size) != 0) {
        ns_sockclose(sock);
        return -1;
    }
    size = (int)sizeof(struct NS_SOCKADDR_STORAGE);
    socks[0] = accept(sock, (struct sockaddr *) &ia[0], &size);
    ns_sockclose(sock);
    if (socks[0] == NS_INVALID_SOCKET) {
        ns_sockclose(socks[1]);
        return -1;
    }
    if (!(SockAddrEqual((struct sockaddr *)&ia[0], (struct sockaddr *)&ia[1])) 
||
        Ns_SockaddrGetPort((struct sockaddr *)&ia[0]) != 
Ns_SockaddrGetPort((struct sockaddr *)&ia[1])) {
        ns_sockclose(socks[0]);
        ns_sockclose(socks[1]);
        return -1;
    }

    return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_SockListen --
 *
 *      Simple socket listen implementation for Win32 without
 *      privileged port issues.
 *
 * Results:
 *      Socket descriptor or NS_INVALID_SOCKET on error.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

NS_SOCKET
Ns_SockListenEx(const char *address, int port, int backlog)
{
    NS_SOCKET sock;
    struct sockaddr_in sa;

    if (Ns_GetSockAddr(&sa, address, port) != NS_OK) {
        return NS_INVALID_SOCKET;
    }
    sock = Ns_SockBind(&sa);
    if (sock != NS_INVALID_SOCKET && listen(sock, backlog) != 0) {
        ns_sockclose(sock);
        sock = NS_INVALID_SOCKET;
    }

    return sock;
}


/*
 *----------------------------------------------------------------------
 *
 * ConsoleHandler --
 *
 *      Callback when the Ctrl-C is pressed.
 *
 * Results:
 *      TRUE.
 *
 * Side effects:
 *      Shutdown is initiated.
 *
 *----------------------------------------------------------------------
 */

static BOOL WINAPI
ConsoleHandler(DWORD UNUSED(code))
{
    SetConsoleCtrlHandler(ConsoleHandler, FALSE);
    NsSendSignal(NS_SIGTERM);

    return TRUE;
}


/*
 *----------------------------------------------------------------------
 *
 * GetServiceName --
 *
 *      Construct the service name for the corresponding service.
 *
 * Results:
 *      Pointer to given dstring string.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static char *
GetServiceName(Ns_DString *dsPtr, char *service)
{
    Ns_DStringVarAppend(dsPtr, PACKAGE_NAME, "-", service, NULL);
    return dsPtr->string;
}


/*
 *----------------------------------------------------------------------
 *
 * StartTicker, StopTicker --
 *
 *      Start and stop the background ticker thread which keeps the
 *      service control manager informed of during startup and
 *      shutdown.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Thread is created or signalled to stop and joined.
 *
 *----------------------------------------------------------------------
 */

static void
StartTicker(DWORD pending)
{
    Ns_MutexLock(&lock);
    tick = 1;
    Ns_MutexUnlock(&lock);
    Ns_ThreadCreate(ServiceTicker, (void *) pending, 0, &tickThread);
}

static void
StopTicker(void)
{
    Ns_MutexLock(&lock);
    tick = 0;
    Ns_CondBroadcast(&cond);
    Ns_MutexUnlock(&lock);
    Ns_ThreadJoin(&tickThread, NULL);
}


/*
 *----------------------------------------------------------------------
 *
 * ServiceTicker --
 *
 *      Background ticker created by StartTicker which does nothing
 *      but send the message repeatedly until signaled to stop.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Service control manager is kept informed of progress.
 *
 *----------------------------------------------------------------------
 */

static void
ServiceTicker(void *arg)
{
    Ns_Time timeout;
    DWORD pending = (DWORD) arg;

    Ns_ThreadSetName("-ticker-");

    Ns_MutexLock(&lock);
    do {
        ReportStatus(pending, NO_ERROR, 2000u);
        Ns_GetTime(&timeout);
        Ns_IncrTime(&timeout, 1, 0);
        (void) Ns_CondTimedWait(&cond, &lock, &timeout);
    } while (tick);
    Ns_MutexUnlock(&lock);
}


/*
 *----------------------------------------------------------------------
 *
 * ServiceMain --
 *
 *      Startup routine created by the service control manager.
 *      This routine initializes the structure for reporting status,
 *      starts the ticker, and then re-enters Ns_Main() where it
 *      was left off when NsServiceConnect() was called.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Server startup continues.
 *
 *----------------------------------------------------------------------
 */

static VOID WINAPI
ServiceMain(DWORD argc, LPTSTR *argv)
{
    hStatus = RegisterServiceCtrlHandler(argv[0], ServiceHandler);
    if (hStatus == 0) {
        Ns_Fatal("nswin32: RegisterServiceCtrlHandler() failed: '%s'",
                 SysErrMsg());
    }
    curStatus.dwServiceType = (DWORD)SERVICE_WIN32_OWN_PROCESS;
    curStatus.dwServiceSpecificExitCode = 0u;
    StartTicker((DWORD)SERVICE_START_PENDING);
    (void) Ns_Main((int)argc, argv, NULL);
    StopTicker();
    ReportStatus((DWORD)SERVICE_STOP_PENDING, NO_ERROR, 100u);
    if (serviceFailed == 0) {
        Ns_Log(Notice, "nswin32: noitifying SCM about exit");
        ReportStatus((DWORD)SERVICE_STOPPED, 0u, 0u);
    }
    Ns_Log(Notice, "nswin32: service exiting");
    if(serviceFailed) {
        exit(-1);
    }
}


/*
 *----------------------------------------------------------------------
 *
 * ServiceHandler --
 *
 *      Callback when the service control manager wants to signal the
 *      server (i.e., when service is stopped via services control
 *      panel).
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Signal may be sent.
 *
 *----------------------------------------------------------------------
 */

static VOID WINAPI
ServiceHandler(DWORD code)
{
    if (code == (DWORD)SERVICE_CONTROL_STOP || code == 
(DWORD)SERVICE_CONTROL_SHUTDOWN) {
        NsSendSignal(NS_SIGTERM);
    } else {
        ReportStatus(code, NO_ERROR, 0u);
    }
}


/*
 *----------------------------------------------------------------------
 *
 * ReportStatus --
 *
 *      Update the service control manager with the current state.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static void
ReportStatus(DWORD state, DWORD code, DWORD hint)
{
    if (state == (DWORD)SERVICE_START_PENDING) {
        curStatus.dwControlsAccepted = 0u;
    } else {
        curStatus.dwControlsAccepted =
            (DWORD)SERVICE_ACCEPT_STOP | (DWORD)SERVICE_ACCEPT_SHUTDOWN;
    }
    curStatus.dwCurrentState = state;
    curStatus.dwWin32ExitCode = code;
    if (code == (DWORD)ERROR_SERVICE_SPECIFIC_ERROR) {
        curStatus.dwServiceSpecificExitCode = code;
    }
    curStatus.dwWaitHint = hint;
    if (state == (DWORD)SERVICE_RUNNING || state == (DWORD)SERVICE_STOPPED) {
        curStatus.dwCheckPoint = 0u;
    } else {
        static DWORD check = 1u;
        curStatus.dwCheckPoint = check++;
    }
    if (hStatus != 0 && SetServiceStatus(hStatus, &curStatus) != TRUE) {
        Ns_Fatal("nswin32: SetServiceStatus(%ld) failed: '%s'", state,
                 SysErrMsg());
    }
}
/*
 * -----------------------------------------------------------------
 *  Copyright 1994 University of Washington
 *
 *  Permission is hereby granted to copy this software, and to
 *  use and redistribute it, except that this notice may not be
 *  removed.  The University of Washington does not guarantee
 *  that this software is suitable for any purpose and will not
 *  be held liable for any damage it may cause.
 * -----------------------------------------------------------------
 *
 *  Modified to work properly on Darwin 10.2 or less.
 *  Also, heavily reformatted to be more readable.
 */

int
ns_poll(struct pollfd *fds, NS_POLL_NFDS_TYPE nfds, int timo)
{
    struct timeval timeout, *toPtr;
    fd_set ifds, ofds, efds;
    unsigned long int i;
    NS_SOCKET n = NS_INVALID_SOCKET;
    int rc;

    FD_ZERO(&ifds);
    FD_ZERO(&ofds);
    FD_ZERO(&efds);

    for (i = 0u; i < nfds; ++i) {
        if (fds[i].fd == NS_INVALID_SOCKET) {
            continue;
        }
#ifndef _MSC_VER
        /* winsock ignores the first argument of select() */
        if (fds[i].fd > n) {
            n = fds[i].fd;
        }
#endif
        if ((fds[i].events & POLLIN)) {
            FD_SET(fds[i].fd, &ifds);
        }
        if ((fds[i].events & POLLOUT)) {
            FD_SET(fds[i].fd, &ofds);
        }
        if ((fds[i].events & POLLPRI)) {
            FD_SET(fds[i].fd, &efds);
        }
    }
    if (timo < 0) {
        toPtr = NULL;
    } else {
        toPtr = &timeout;
        timeout.tv_sec = timo / 1000;
        timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000;
    }
    rc = select((int)++n, &ifds, &ofds, &efds, toPtr);
    if (rc <= 0) {
        return rc;
    }
    for (i = 0u; i < nfds; ++i) {
        fds[i].revents = 0;
        if (fds[i].fd == NS_INVALID_SOCKET) {
            continue;
        }
        if (FD_ISSET(fds[i].fd, &ifds)) {
            fds[i].revents |= POLLIN;
        }
        if (FD_ISSET(fds[i].fd, &ofds)) {
            fds[i].revents |= POLLOUT;
        }
        if (FD_ISSET(fds[i].fd, &efds)) {
            fds[i].revents |= POLLPRI;
        }
    }

    return rc;
}

/*
 *----------------------------------------------------------------------
 *
 * ns_open, ns_close, ns_write, ns_read, ns_lseek, ns_dup, ns_dup2  --
 *
 *      Elementary operations on file descriptors. The interfaces are the same
 *      as in a Unix environment.
 *
 *      These functions are implemented in C due to slightly different
 *      interfaces under windows, but most prominently, to link the _* system
 *      calls to the main .dll file, such that external modules (such as
 *      e.g. nslog) do link against these instead of their own version.
 *
 * Results:
 *      For details, see MSDN
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

int
ns_open(const char *path, int oflag, int mode) 
{
    return _open(path, oflag, mode);
}

int
ns_close(int fildes) 
{
    return _close(fildes);
}

ssize_t
ns_write(int fildes, const void *buf, size_t nbyte)
{
    return _write(fildes, buf, (unsigned int)nbyte);
}

ssize_t
ns_read(int fildes, void *buf, size_t nbyte) 
{
    return _read(fildes, buf, (unsigned int)nbyte);
}

off_t
ns_lseek(int fildes, off_t offset, int whence)
{
    return (off_t)_lseek(fildes, (long)offset, whence);
}

int 
ns_dup(int fildes) 
{
    return _dup(fildes);
}

int     
ns_dup2(int fildes, int fildes2)
{
    return _dup2(fildes, fildes2);
}

/*
 *----------------------------------------------------------------------
 *
 * ns_recv, ns_send  --
 *
 *      Elementary operations on sockets. The interfaces are the same
 *      as in a Unix environment.
 *
 *      These functions are implemented in C due to slightly different
 *      interfaces under windows.
 *
 * Results:
 *      For details, see MSDN
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */
ssize_t
ns_recv(NS_SOCKET socket, void *buffer, size_t length, int flags)
{
    return recv(socket, buffer, (int)length, flags);
}

ssize_t
ns_send(NS_SOCKET socket, const void *buffer, size_t length, int flags)
{
    return send(socket, buffer, (int)length, flags);
}

#else
/* avoid empty translation unit */
   typedef void empty; 
#endif

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * indent-tabs-mode: nil
 * End:
 */
------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
naviserver-devel mailing list
naviserver-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/naviserver-devel

Reply via email to