]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 873] Windows serial refclock proper TTY line discipline emulation
authorDave Hart <hart@ntp.org>
Fri, 20 Mar 2009 01:46:15 +0000 (01:46 +0000)
committerDave Hart <hart@ntp.org>
Fri, 20 Mar 2009 01:46:15 +0000 (01:46 +0000)
bk: 49c2f5678DEw6aEZpBKhp5W2nC2xsQ

ChangeLog
ntpd/ntp_io.c
ntpd/ntpd.c
ntpd/refclock_dumbclock.c
ntpd/refclock_hopfser.c
ntpd/refclock_nmea.c
ntpd/refclock_palisade.c
ports/winnt/include/ntp_iocompletionport.h
ports/winnt/ntpd/ntp_iocompletionport.c
ports/winnt/ntpd/win32_io.c

index f26fece5e6cf9e644f616d7c735e7dd7c3b852bd..acdd4e3c180eba097e01ef3db7b34dc4c617626e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,5 @@
+* [Bug 873] Windows serial refclock proper TTY line discipline emulation
+
 ---
 (4.2.4p6) 2009/01/08 Released by Harlan Stenn <stenn@ntp.org>
 
index faa46461f484e2f34b1329dc3d953ca1b41acfcb..0062436ca1dfbe5a2e93b8650d5effc7032b0bec 100644 (file)
@@ -477,6 +477,8 @@ void
 init_io(void)
 {
 #ifdef SYS_WINNT
+       init_io_completion_port();
+
        if (!Win32InitSockets())
        {
                netsyslog(LOG_ERR, "No useable winsock.dll: %m");
@@ -1184,7 +1186,7 @@ update_interfaces(
                scan_ipv6 = ISC_TRUE;
 #if defined(DEBUG)
        else
-               if(debug)
+               if (debug)
                        netsyslog(LOG_ERR, "no IPv6 interfaces found");
 #endif
 #endif
@@ -1192,7 +1194,7 @@ update_interfaces(
                scan_ipv6 = ISC_TRUE;
 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(DEBUG)
        else
-               if(debug)
+               if (debug)
                        netsyslog(LOG_ERR, "no IPv6 interfaces found");
 #endif
 
@@ -1508,13 +1510,14 @@ create_interface(
  */
 static void
 set_reuseaddr(int flag) {
-        struct interface *interf;
+       struct interface *interf;
 
        for (interf = ISC_LIST_HEAD(inter_list);
             interf != NULL;
             interf = ISC_LIST_NEXT(interf, link)) {
-               if (interf->flags & INT_WILDCARD)
-                       continue;
+
+               if (interf->flags & INT_WILDCARD)
+                       continue;
          
                /*
                 * if interf->fd  is INVALID_SOCKET, we might have a adapter
@@ -1691,7 +1694,7 @@ enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr)
        case AF_INET6:
 #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
                if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
-                   &iface->scopeid, sizeof(iface->scopeid)) == -1) {
+                   (char *) &iface->scopeid, sizeof(iface->scopeid)) == -1) {
                        netsyslog(LOG_ERR,
                        "setsockopt IPV6_MULTICAST_IF failure: %m on socket %d, addr %s, scope %d for multicast address %s",
                        iface->fd, stoa(&iface->sin), iface->scopeid,
@@ -1703,7 +1706,7 @@ enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr)
                 * Don't send back to itself, but allow it to fail to set it
                 */
                if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
-                      &off, sizeof(off)) == -1) {
+                      (char *) &off, sizeof(off)) == -1) {
                        netsyslog(LOG_ERR,
                        "setsockopt IP_MULTICAST_LOOP failure: %m on socket %d, addr %s for multicast address %s",
                        iface->fd, stoa(&iface->sin), stoa(maddr));
@@ -1981,7 +1984,10 @@ io_multicast_add(
        )
 {
 #ifdef MCAST
-        struct interface *interface, *iface;
+       struct interface *interface;
+#ifndef MULTICAST_NONEWSOCKET
+       struct interface *iface;
+#endif
        int lscope = 0;
        
        /*
@@ -2496,9 +2502,6 @@ sendpkt(
        )
 {
        int cc, slot;
-#ifdef SYS_WINNT
-       DWORD err;
-#endif /* SYS_WINNT */
 
        /*
         * Send error caches. Empty slots have port == 0
@@ -2618,8 +2621,8 @@ sendpkt(
 #endif /* INCLUDE_IPV6_SUPPORT */
 
 #if defined(HAVE_IO_COMPLETION_PORT)
-        err = io_completion_port_sendto(inter, pkt, len, dest);
-       if (err != ERROR_SUCCESS)
+        cc = io_completion_port_sendto(inter, pkt, len, dest);
+       if (cc != ERROR_SUCCESS)
 #else
 #ifdef SIM
         cc = srvr_rply(&ntp_node,  dest, inter, pkt);
@@ -2632,9 +2635,9 @@ sendpkt(
        {
                inter->notsent++;
                packets_notsent++;
+
 #if defined(HAVE_IO_COMPLETION_PORT)
-               err = WSAGetLastError();
-               if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0)
+               if (cc != WSAEWOULDBLOCK && cc != WSAENOBUFS && slot < 0)
 #else
                if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0)
 #endif
@@ -2659,13 +2662,13 @@ sendpkt(
                        case AF_INET6 :
 
                                for (slot = ERRORCACHESIZE; --slot >= 0; )
-                                       if (badaddrs6[slot].port == 0)
-                                       {
-                                               badaddrs6[slot].port = SRCPORT(dest);
-                                               badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr;
-                                               break;
-                                       }
-                               break;
+                                       if (badaddrs6[slot].port == 0)
+                                       {
+                                               badaddrs6[slot].port = SRCPORT(dest);
+                                               badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr;
+                                               break;
+                                       }
+                               break;
 #endif /* INCLUDE_IPV6_SUPPORT */
                        default:  /* don't care if not supported */
                                break;
@@ -3207,7 +3210,7 @@ findlocalinterface(
        struct interface *iface;
 
        DPRINTF(4, ("Finding interface for addr %s in list of addresses\n",
-                   stoa(addr));)
+                   stoa(addr)));
 
        memset(&saddr, 0, sizeof(saddr));
        saddr.ss_family = addr->ss_family;
index 04e0d07f94c90b71a7d65e3d9e3a5175ce67ff34..02a5198b087f34b15fe4528251ffd32db1b815a6 100644 (file)
 # include <sys/stat.h>
 #endif
 #include <stdio.h>
-#ifndef SYS_WINNT
-# if !defined(VMS)     /*wjm*/
-#  ifdef HAVE_SYS_PARAM_H
-#   include <sys/param.h>
-#  endif
-# endif /* VMS */
-# ifdef HAVE_SYS_SIGNAL_H
-#  include <sys/signal.h>
-# else
-#  include <signal.h>
+#if !defined(VMS)      /*wjm*/
+# ifdef HAVE_SYS_PARAM_H
+#  include <sys/param.h>
 # endif
-# ifdef HAVE_SYS_IOCTL_H
-#  include <sys/ioctl.h>
-# endif /* HAVE_SYS_IOCTL_H */
-# ifdef HAVE_SYS_RESOURCE_H
-#  include <sys/resource.h>
-# endif /* HAVE_SYS_RESOURCE_H */
+#endif /* VMS */
+#ifdef HAVE_SYS_SIGNAL_H
+# include <sys/signal.h>
 #else
 # include <signal.h>
-# include <process.h>
-# include <io.h>
-# include <clockstuff.h>
-#include "ntp_iocompletionport.h"
-#endif /* SYS_WINNT */
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif /* HAVE_SYS_IOCTL_H */
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
 #if defined(HAVE_RTPRIO)
 # ifdef HAVE_SYS_RESOURCE_H
 #  include <sys/resource.h>
@@ -821,9 +813,6 @@ ntpdmain(
        init_restrict();
        init_mon();
        init_timer();
-#if defined (HAVE_IO_COMPLETION_PORT)
-       init_io_completion_port();
-#endif
        init_lib();
        init_request();
        init_control();
@@ -993,7 +982,7 @@ getgroup:
 #if defined(HAVE_IO_COMPLETION_PORT)
 
        for (;;) {
-               int tot_full_recvbufs = GetReceivedBuffers();
+               GetReceivedBuffers();
 #else /* normal I/O */
 
        BLOCK_IO_AND_ALARM();
index 2788649ac3a7872e242e3f2eb415adf0a7ac8233..10ff2cfe893b18bf0fbaff2db4a30e5bfe311077 100644 (file)
 #include <config.h>
 #endif
 
-#if defined(SYS_WINNT)
-#undef close
-#define close closesocket
-#endif
-
 #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK)
 
 #include "ntpd.h"
 #include <stdio.h>
 #include <ctype.h>
 
+#ifdef SYS_WINNT
+extern int async_write(int, const void *, unsigned int);
+#undef write
+#define write(fd, data, octets)        async_write(fd, data, octets)
+#endif
+
 /*
  * This driver supports a generic dumb clock that only outputs hh:mm:ss,
  * in local time, no less.
index 94b660be236e6b3db772215fef6c76c112b9cd1f..9037d4a9222ad8e5dd23839f10dccb2d9c828301 100644 (file)
 # include "config.h"
 #endif
 
-#if defined(SYS_WINNT)
-#undef close
-#define close closesocket
-#endif
-
 #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
 
 #include "ntpd.h"
 # include <sys/ioctl.h>
 #endif
 
+#ifdef SYS_WINNT
+extern int async_write(int, const void *, unsigned int);
+#undef write
+#define write(fd, data, octets)        async_write(fd, data, octets)
+#endif
+
 /*
  * clock definitions
  */
index 5b124cb0c3f4637647eca852f45cd08e5b84b2cc..a176ee86c139daeec45ca18557779fc74fc18c49 100644 (file)
@@ -7,11 +7,6 @@
 #include <config.h>
 #endif
 
-#if defined(SYS_WINNT)
-#undef close
-#define close closesocket
-#endif
-
 #if defined(REFCLOCK) && defined(CLOCK_NMEA)
 
 #include <stdio.h>
 # include "ppsapi_timepps.h"
 #endif /* HAVE_PPSAPI */
 
+#ifdef SYS_WINNT
+extern int async_write(int, const void *, unsigned int);
+#undef write
+#define write(fd, data, octets)        async_write(fd, data, octets)
+#endif
+
 /*
  * This driver supports the NMEA GPS Receiver with
  *
index 217ec104dcf986677b52db9fb53906efa3a61d20..adb4659f97bbb1712fe5b9e28cb23e2f1166a1f7 100644 (file)
 #include "config.h"
 #endif
 
-#if defined(SYS_WINNT)
-#undef close
-#define close closesocket
-#endif
-
 #if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE))
 
+#ifdef SYS_WINNT
+extern int async_write(int, const void *, unsigned int);
+#undef write
+#define write(fd, data, octets)        async_write(fd, data, octets)
+#endif
+
 #include "refclock_palisade.h"
 /* Table to get from month to day of the year */
 const int days_of_year [12] = {
index dafc5606ee41385e8241c90f577a8b3f7c8e45fd..6e7b92b2c75585e9d8eb76c1bfaebebb91a6f046 100644 (file)
@@ -3,26 +3,25 @@
 
 #include "ntp_fp.h"
 #include "ntp.h"
+#include "clockstuff.h"
 
 # if defined(HAVE_IO_COMPLETION_PORT)
 
-struct refclockio;
-
-
 extern void    init_io_completion_port (void);
 extern void    uninit_io_completion_port (void);
 
-extern int     io_completion_port_add_clock_io (struct refclockio * /*rio */);
-
 extern int     io_completion_port_add_socket (SOCKET fd, struct interface *);
 
-extern DWORD   io_completion_port_sendto (struct interface *, struct pkt *, int, struct sockaddr_storage*);
+struct refclockio; /* in ntp_refclock.h but inclusion here triggers problems */
+extern int     io_completion_port_add_clock_io (struct refclockio *rio);
+
+extern int     io_completion_port_sendto (struct interface *, struct pkt *, int, struct sockaddr_storage*);
 
-extern HANDLE get_io_event (void);
+extern HANDLE  get_io_event (void);
 
-extern HANDLE get_exit_event(void);            /* Handle of the exit event */
+extern HANDLE  get_exit_event (void);          /* Handle of the exit event */
 
-int GetReceivedBuffers(void);
+extern int     GetReceivedBuffers (void);
 
 # endif
 
index 099623879e80d4d623879dd2d5bd9f7ed0146bb4..7c7ec3b6787afcd6dbe1fd24e7f16e0b9d4c54a2 100644 (file)
@@ -25,8 +25,9 @@
 enum {
        SOCK_RECV,
        SOCK_SEND,
-       CLOCK_READ,
-       CLOCK_WRITE
+       SERIAL_WAIT,
+       SERIAL_READ,
+       SERIAL_WRITE
 };
 
 
@@ -42,16 +43,31 @@ typedef struct IoCompletionInfo {
 #define        recv_buf        buff_space.rbuf
 #define        trans_buf       buff_space.tbuf
 
+#if !defined( _W64 )
+  /*
+   * if ULONG_PTR needs to be defined then the build environment
+   * is pure 32 bit Windows. Since ULONG_PTR and DWORD have 
+   * the same size in 32 bit Windows we can safely define
+   * a replacement.
+   */
+  typedef DWORD ULONG_PTR;
+#endif
+
 /*
  * local function definitions
  */
-static int QueueIORead( struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo);
+static int QueueSerialWait(struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp);
 
-static int OnSocketRecv(DWORD, IoCompletionInfo *, DWORD, int);
-static int OnIoReadComplete(DWORD, IoCompletionInfo *, DWORD, int);
-static int OnWriteComplete(DWORD, IoCompletionInfo *, DWORD, int);
+static int OnSocketRecv(ULONG_PTR, IoCompletionInfo *, DWORD, int);
+static int OnSerialWaitComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
+static int OnSerialReadComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
+static int OnWriteComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
 
+/* #define USE_HEAP */
+
+#ifdef USE_HEAP
 static HANDLE hHeapHandle = NULL;
+#endif
 
 static HANDLE hIoCompletionPort = NULL;
 
@@ -61,8 +77,6 @@ static HANDLE WaitableExitEventHandle = NULL;
 #define MAXHANDLES 3
 HANDLE WaitHandles[MAXHANDLES] = { NULL, NULL, NULL };
 
-#define USE_HEAP
-
 IoCompletionInfo *
 GetHeapAlloc(char *fromfunc)
 {
@@ -73,25 +87,17 @@ GetHeapAlloc(char *fromfunc)
                             HEAP_ZERO_MEMORY,
                             sizeof(IoCompletionInfo));
 #else
-       lpo = (IoCompletionInfo *) calloc(1, sizeof(IoCompletionInfo));
-#endif
-#ifdef DEBUG
-       if (debug > 3) {
-               printf("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo);
-       }
+       lpo = (IoCompletionInfo *) calloc(1, sizeof(*lpo));
 #endif
+       DPRINTF(3, ("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo));
+
        return (lpo);
 }
 
 void
 FreeHeap(IoCompletionInfo *lpo, char *fromfunc)
 {
-#ifdef DEBUG
-       if (debug > 3)
-       {
-               printf("Freeing memory for %s, ptr %x\n", fromfunc, lpo);
-       }
-#endif
+       DPRINTF(3, ("Freeing memory for %s, ptr %x\n", fromfunc, lpo));
 
 #ifdef USE_HEAP
        HeapFree(hHeapHandle, 0, lpo);
@@ -103,7 +109,7 @@ FreeHeap(IoCompletionInfo *lpo, char *fromfunc)
 transmitbuf_t *
 get_trans_buf()
 {
-       transmitbuf_t *tb  = calloc(sizeof(transmitbuf_t), 1);
+       transmitbuf_t *tb  = (transmitbuf_t *) emalloc(sizeof(transmitbuf_t));
        tb->wsabuf.len = 0;
        tb->wsabuf.buf = (char *) &tb->pkt;
        return (tb);
@@ -133,19 +139,21 @@ static void
 signal_io_completion_port_exit()
 {
        if (!PostQueuedCompletionStatus(hIoCompletionPort, 0, 0, 0)) {
-               msyslog(LOG_ERR, "Can't request service thread to exit: %m");
-               exit(1);
+               DPRINTF(1, ("Can't request IO thread to exit: %d\n", GetLastError()));
        }
 }
 
-static void
+static unsigned WINAPI
 iocompletionthread(void *NotUsed)
 {
        BOOL bSuccess = FALSE;
        int errstatus = 0;
        DWORD BytesTransferred = 0;
-       DWORD Key = 0;
+       ULONG_PTR Key = 0;
        IoCompletionInfo * lpo = NULL;
+       u_long time_next_ifscan_after_error = 0;
+
+       /* UNUSED_ARG(NotUsed); */
 
        /*      Set the thread priority high enough so I/O will
         *      preempt normal recv packet processing, but not
@@ -156,39 +164,48 @@ iocompletionthread(void *NotUsed)
        }
 
        while (TRUE) {
-               bSuccess = GetQueuedCompletionStatus(hIoCompletionPort, 
-                                         &BytesTransferred, 
-                                         &Key, 
-                                         & (LPOVERLAPPED) lpo, 
-                                         INFINITE);
+               bSuccess = GetQueuedCompletionStatus(
+                                       hIoCompletionPort, 
+                                       &BytesTransferred, 
+                                       &Key, 
+                                       (LPOVERLAPPED *) &lpo, 
+                                       INFINITE);
                if (lpo == NULL)
                {
-#ifdef DEBUG
-                       if (debug > 2) {
-                               printf("Overlapped IO Thread Exits: \n");
-                       }
-#endif
+                       DPRINTF(2, ("Overlapped IO Thread Exiting\n"));
                        break; /* fail */
                }
                
                /*
                 * Deal with errors
                 */
-               errstatus = 0;
-               if (!bSuccess)
+               if (bSuccess)
+                       errstatus = 0;
+               else
                {
                        errstatus = GetLastError();
-                       if (BytesTransferred == 0 && errstatus == WSA_OPERATION_ABORTED)
+                       if (BytesTransferred == 0)
                        {
-#ifdef DEBUG
-                               if (debug > 2) {
-                                       printf("Transfer Operation aborted\n");
+                               if (WSA_OPERATION_ABORTED == errstatus) {
+                                       DPRINTF(4, ("Transfer Operation aborted\n"));
+                               } else if (ERROR_UNEXP_NET_ERR == errstatus) {
+                                       /*
+                                        * We get this error when trying to send an the network
+                                        * interface is gone or has lost link.  Rescan interfaces
+                                        * to catch on sooner, but no more than once per minute.
+                                        * Once ntp is able to detect changes without polling
+                                        * this should be unneccessary
+                                        */
+                                       if (time_next_ifscan_after_error < current_time) {
+                                               time_next_ifscan_after_error = current_time + 60;
+                                               timer_interfacetimeout(current_time);
+                                       }
+                                       DPRINTF(4, ("sendto unexpected network error, interface may be down\n"));
                                }
-#endif
                        }
                        else
                        {
-                               msyslog(LOG_ERR, "Error transferring packet after %d bytes: %m", BytesTransferred);
+                               msyslog(LOG_ERR, "sendto error after %d bytes: %m", BytesTransferred);
                        }
                }
 
@@ -198,26 +215,27 @@ iocompletionthread(void *NotUsed)
                 */
                switch(lpo->request_type)
                {
-               case CLOCK_READ:
-                       OnIoReadComplete(Key, lpo, BytesTransferred, errstatus);
+               case SERIAL_WAIT:
+                       OnSerialWaitComplete(Key, lpo, BytesTransferred, errstatus);
+                       break;
+               case SERIAL_READ:
+                       OnSerialReadComplete(Key, lpo, BytesTransferred, errstatus);
                        break;
                case SOCK_RECV:
                        OnSocketRecv(Key, lpo, BytesTransferred, errstatus);
                        break;
                case SOCK_SEND:
-               case CLOCK_WRITE:
+               case SERIAL_WRITE:
                        OnWriteComplete(Key, lpo, BytesTransferred, errstatus);
                        break;
                default:
-#if DEBUG
-                       if (debug > 2) {
-                               printf("Unknown request type %d found in completion port\n",
-                                       lpo->request_type);
-                       }
-#endif
+                       DPRINTF(1, ("Unknown request type %d found in completion port\n",
+                                   lpo->request_type));
                        break;
                }
        }
+
+       return 0;
 }
 
 /*  Create/initialise the I/O creation port
@@ -227,7 +245,10 @@ init_io_completion_port(
        void
        )
 {
+       unsigned tid;
+       HANDLE thread;
 
+#ifdef USE_HEAP
        /*
         * Create a handle to the Heap
         */
@@ -237,33 +258,29 @@ init_io_completion_port(
                msyslog(LOG_ERR, "Can't initialize Heap: %m");
                exit(1);
        }
-
+#endif
 
        /* Create the event used to signal an IO event
         */
-       WaitableIoEventHandle = CreateEvent(NULL, FALSE, FALSE, "WaitableIoEventHandle");
-       if (WaitableIoEventHandle == NULL) {
-               msyslog(LOG_ERR,
-               "Can't create I/O event handle: %m - another process may be running - EXITING");
-               exit(1);
-       }
+       WaitableIoEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
+
        /* Create the event used to signal an exit event
         */
-       WaitableExitEventHandle = CreateEvent(NULL, FALSE, FALSE, "WaitableExitEventHandle");
-       if (WaitableExitEventHandle == NULL) {
-               msyslog(LOG_ERR,
-               "Can't create exit event handle: %m - another process may be running - EXITING");
-               exit(1);
-       }
+       WaitableExitEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
 
        /* Create the IO completion port
         */
        hIoCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
-       if (hIoCompletionPort == NULL) {
-               msyslog(LOG_ERR, "Can't create I/O completion port: %m");
+
+#ifdef DEBUG
+       if (NULL == WaitableExitEventHandle || 
+           NULL == WaitableIoEventHandle ||
+           NULL == hIoCompletionPort) {
+               DPRINTF(1, ("init_io_completion_port: Can't create event or port\n"));
                exit(1);
        }
-       
+#endif
+
        /*
         * Initialize the Wait Handles
         */
@@ -274,7 +291,15 @@ init_io_completion_port(
        /* Have one thread servicing I/O - there were 4, but this would 
         * somehow cause NTP to stop replying to ntpq requests; TODO
         */
-       _beginthread(iocompletionthread, 0, NULL);
+       thread = (HANDLE)_beginthreadex(
+               NULL, 
+               0, 
+               iocompletionthread, 
+               NULL, 
+               CREATE_SUSPENDED, 
+               &tid);
+       ResumeThread(thread);
+       CloseHandle(thread);
 }
        
 
@@ -291,25 +316,18 @@ uninit_io_completion_port(
 }
 
 
-static int QueueIORead( struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo) {
-
-       lpo->request_type = CLOCK_READ;
+static int QueueSerialWait(struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp)
+{
+       lpo->request_type = SERIAL_WAIT;
        lpo->recv_buf = buff;
 
-       buff->fd = rio->fd;
-       if (!ReadFile((HANDLE) buff->fd, buff->wsabuff.buf, buff->wsabuff.len, NULL, (LPOVERLAPPED) lpo)) {
-               DWORD Result = GetLastError();
-               switch (Result) {                               
-               case NO_ERROR :
-               case ERROR_HANDLE_EOF :
-               case ERROR_IO_PENDING :
-                       break ;
+       if (clear_timestamp)
+               memset(&buff->recv_time, 0, sizeof(buff->recv_time));
 
-               /*
-                * Something bad happened
-                */
-               default:
-                       msyslog(LOG_ERR, "Can't read from Refclock: %m");
+       buff->fd = _get_osfhandle(rio->fd);
+       if (!WaitCommEvent((HANDLE) buff->fd, (DWORD *)&buff->recv_buffer, (LPOVERLAPPED) lpo)) {
+               if (ERROR_IO_PENDING != GetLastError()) {
+                       msyslog(LOG_ERR, "Can't wait on Refclock: %m");
                        freerecvbuf(buff);
                        return 0;
                }
@@ -318,60 +336,135 @@ static int QueueIORead( struct refclockio *rio, recvbuf_t *buff, IoCompletionInf
 }
 
 
-
-/* Return 1 on Successful Read */
 static int 
-OnIoReadComplete(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
+OnSerialWaitComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 {
        recvbuf_t *buff;
-       recvbuf_t *newbuff;
        struct refclockio * rio = (struct refclockio *) i;
+       struct peer *pp;
        l_fp arrival_time;
+       DWORD comm_mask;
+       DWORD modem_status;
+       static const l_fp zero_time = { 0 };
+       DWORD dwBytesReturned;
+       BOOL rc;
 
        get_systime(&arrival_time);
 
        /*
         * Get the recvbuf pointer from the overlapped buffer.
         */
-       buff = (recvbuf_t *) lpo->recv_buf;
-       /*
-        * Get a new recv buffer for the next packet
-        */
-       newbuff = get_free_recv_buffer_alloc();
-       if (newbuff == NULL) {
-               /*
-                * recv buffers not available so we drop the packet
-                * and reuse the buffer.
-                */
-               newbuff = buff;
-       }
-       else 
-       {
-               /*
-                * ignore 0 bytes read due to timeout's and closure on fd
-                */
-               if (Bytes > 0 && errstatus != WSA_OPERATION_ABORTED) {
-                       memcpy(&buff->recv_time, &arrival_time, sizeof(arrival_time));  
-                       buff->recv_length = (int) Bytes;
-                       buff->receiver = rio->clock_recv;
-                       buff->dstadr = NULL;
-                       buff->recv_srcclock = rio->srcclock;
-                       add_full_recv_buffer(buff);
-                       if( !SetEvent( WaitableIoEventHandle ) ) {
+       buff = lpo->recv_buf;
+       comm_mask = (*(DWORD *)&buff->recv_buffer);
 #ifdef DEBUG
-                               if (debug > 3) {
-                                       printf( "Error %d setting IoEventHandle\n", GetLastError() );
-                               }
+               if (errstatus || comm_mask & ~(EV_RXFLAG | EV_RLSD)) {
+                       msyslog(LOG_ERR, "WaitCommEvent returned unexpected mask %x errstatus %d",
+                               comm_mask, errstatus);
+                       exit(-1);
+               }
 #endif
+               if (comm_mask & EV_RLSD) { 
+                       modem_status = 0;
+                       GetCommModemStatus((HANDLE)buff->fd, &modem_status);
+                       if (modem_status & MS_RLSD_ON) {
+                               /*
+                                * Use the timestamp from this PPS CD not
+                                * the later end of line.
+                                */
+                               buff->recv_time = arrival_time;
+                       }
+
+                       if (!(comm_mask & EV_RXFLAG)) {
+                               /*
+                                * if we didn't see an end of line yet
+                                * issue another wait for it.
+                                */
+                               QueueSerialWait(rio, buff, lpo, FALSE);
+                               return 1;
                        }
                }
-               else
-               {
+
+               /*
+                * We've detected the end of line of serial input.
+                * Use this timestamp unless we already have a CD PPS
+                * timestamp in buff->recv_time.
+                */
+               if (memcmp(&buff->recv_time, &zero_time, sizeof buff->recv_time)) {
+                       /*
+                        * We will first see a user PPS timestamp here on either
+                        * the first or second line of text.  Log a one-time
+                        * message while processing the second line.
+                        */
+                       if (1 == rio->recvcount) {
+                               pp = (struct peer *)rio->srcclock;
+                               msyslog(LOG_NOTICE, "Using user-mode PPS timestamp for %s",
+                                       refnumtoa(&pp->srcadr));
+                       }
+               } else {
+                       buff->recv_time = arrival_time;
+               }
+
+               /*
+                * Now that we have a complete line waiting, read it.
+                * There is still a race here, but we're likely to win.
+                */
+
+               lpo->request_type = SERIAL_READ;
+
+               rc = ReadFile(
+                       (HANDLE)buff->fd,
+                       buff->wsabuff.buf,
+                       buff->wsabuff.len,
+                       &buff->wsabuff.len,
+                       (LPOVERLAPPED) lpo);
+
+               if (!rc && ERROR_IO_PENDING != GetLastError()) {
+                       msyslog(LOG_ERR, "Can't read from Refclock: %m");
                        freerecvbuf(buff);
+                       return 0;
+               }
+
+       return 1;
+}
+
+/* Return 1 on Successful Read */
+static int 
+OnSerialReadComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
+{
+       recvbuf_t *buff;
+       struct refclockio * rio = (struct refclockio *) i;
+
+       /*
+        * Get the recvbuf pointer from the overlapped buffer.
+        */
+       buff = lpo->recv_buf;
+
+       /*
+        * ignore 0 bytes read due to timeout's and closure on fd
+        */
+       if (!errstatus && Bytes) {
+               buff->recv_length = (int) Bytes;
+               buff->receiver = rio->clock_recv;
+               buff->dstadr = NULL;
+               buff->recv_srcclock = rio->srcclock;
+               packets_received++;
+               /*
+                * Eat the first line of input as it's possibly
+                * partial and if a PPS is present, it may not 
+                * have fired since the port was opened.
+                */
+               if (rio->recvcount++) {
+                       add_full_recv_buffer(buff);
+                       /*
+                        * Now signal we have something to process
+                        */
+                       SetEvent(WaitableIoEventHandle);
+                       buff = get_free_recv_buffer_alloc();
                }
        }
 
-       QueueIORead( rio, newbuff, lpo );
+       QueueSerialWait(rio, buff, lpo, TRUE);
+
        return 1;
 }
 
@@ -386,7 +479,7 @@ io_completion_port_add_clock_io(
        IoCompletionInfo *lpo;
        recvbuf_t *buff;
 
-       if (NULL == CreateIoCompletionPort((HANDLE) rio->fd, hIoCompletionPort, (DWORD) rio, 0)) {
+       if (NULL == CreateIoCompletionPort((HANDLE)_get_osfhandle(rio->fd), hIoCompletionPort, (ULONG_PTR) rio, 0)) {
                msyslog(LOG_ERR, "Can't add COM port to i/o completion port: %m");
                return 1;
        }
@@ -399,19 +492,16 @@ io_completion_port_add_clock_io(
        }
 
        buff = get_free_recv_buffer_alloc();
-
-       if (buff == NULL)
-       {
-               msyslog(LOG_ERR, "Can't allocate memory for clock socket: %m");
-               FreeHeap(lpo, "io_completion_port_add_clock_io");
-               return 1;
-       }
-       QueueIORead( rio, buff, lpo );
+       QueueSerialWait(rio, buff, lpo, TRUE);
        return 0;
 }
 
-/* Queue a receiver on a socket. Returns 0 if no buffer can be queued */
-
+/*
+ * Queue a receiver on a socket. Returns 0 if no buffer can be queued 
+ *
+ *  Note: As per the winsock documentation, we use WSARecvFrom. Using
+ *        ReadFile() is less efficient.
+ */
 static unsigned long QueueSocketRecv(SOCKET s, recvbuf_t *buff, IoCompletionInfo *lpo) {
        
        int AddrLen;
@@ -433,8 +523,6 @@ static unsigned long QueueSocketRecv(SOCKET s, recvbuf_t *buff, IoCompletionInfo
                        DWORD Result = WSAGetLastError();
                        switch (Result) {
                                case NO_ERROR :
-                               case WSA_IO_INCOMPLETE :
-                               case WSA_WAIT_IO_COMPLETION :
                                case WSA_IO_PENDING :
                                        break ;
 
@@ -465,7 +553,7 @@ static unsigned long QueueSocketRecv(SOCKET s, recvbuf_t *buff, IoCompletionInfo
 
 /* Returns 0 if any Error */
 static int 
-OnSocketRecv(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
+OnSocketRecv(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 {
        struct recvbuf *buff = NULL;
        recvbuf_t *newbuff;
@@ -473,7 +561,7 @@ OnSocketRecv(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
        l_fp arrival_time;
        struct interface * inter = (struct interface *) i;
        
-       get_systime(&arrival_time);     
+       get_systime(&arrival_time);
 
        /*  Convert the overlapped pointer back to a recvbuf pointer.
        */
@@ -505,65 +593,49 @@ OnSocketRecv(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 
 
        /*
-        * Get a new recv buffer for the next packet
+        * Get a new recv buffer for the replacement socket receive
         */
        newbuff = get_free_recv_buffer_alloc();
-       if (newbuff == NULL) {
-               /*
-                * recv buffers not available so we drop the packet
-                * and reuse the buffer.
-                */
-               newbuff = buff;
-       }
-       else 
-       {
-               ignore_this = inter->ignore_packets;
+       QueueSocketRecv(inter->fd, newbuff, lpo);
 
-               /*
-                * If we keep it add some info to the structure
-                */
-               if (Bytes > 0 && ignore_this == ISC_FALSE) {
-                       memcpy(&buff->recv_time, &arrival_time, sizeof(arrival_time));  
-                       buff->recv_length = (int) Bytes;
-                       buff->receiver = receive; 
-                       buff->dstadr = inter;
-#ifdef DEBUG
-                       if (debug > 1)
-                               printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr));
-#endif
-                       add_full_recv_buffer(buff);
-                       /*
-                        * Now signal we have something to process
-                        */
-                       if( !SetEvent( WaitableIoEventHandle ) ) {
+       ignore_this = inter->ignore_packets;
+
+       /*
+        * If we keep it add some info to the structure
+        */
+       if (Bytes > 0 && ignore_this == ISC_FALSE) {
+               memcpy(&buff->recv_time, &arrival_time, sizeof buff->recv_time);        
+               buff->recv_length = (int) Bytes;
+               buff->receiver = receive; 
+               buff->dstadr = inter;
 #ifdef DEBUG
-                               if (debug > 1) {
-                                       printf( "Error %d setting IoEventHandle\n", GetLastError() );
-                               }
+               if (debug > 1)
+                       printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr));
 #endif
-                       }
-               }
-               else {
-                       freerecvbuf(buff);
-               }
+               packets_received++;
+               inter->received++;
+               add_full_recv_buffer(buff);
+               /*
+                * Now signal we have something to process
+                */
+               SetEvent(WaitableIoEventHandle);
        }
-       if (newbuff != NULL)
-               QueueSocketRecv(inter->fd, newbuff, lpo);
+       else
+               freerecvbuf(buff);
+
        return 1;
 }
 
 
-/*  Add a socket handle to the I/O completion port, and send an I/O
- *  read request to the kernel.
- *
- *  Note: As per the winsock documentation, we use WSARecvFrom. Using
- *        ReadFile() is less efficient.
+/*  Add a socket handle to the I/O completion port, and send 
+ *  NTP_RECVS_PER_SOCKET recv requests to the kernel.
  */
 extern int
 io_completion_port_add_socket(SOCKET fd, struct interface *inter)
 {
        IoCompletionInfo *lpo;
        recvbuf_t *buff;
+       int n;
 
        if (fd != INVALID_SOCKET) {
                if (NULL == CreateIoCompletionPort((HANDLE) fd, hIoCompletionPort,
@@ -573,37 +645,50 @@ io_completion_port_add_socket(SOCKET fd, struct interface *inter)
                }
        }
 
-       lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket");
-       if (lpo == NULL)
-       {
-               msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
-               return 1;
-       }
+#define WINDOWS_RECVS_PER_SOCKET 4
 
-       buff = get_free_recv_buffer_alloc();
+       for (n = 0; n < WINDOWS_RECVS_PER_SOCKET; n++) {
 
-       if (buff == NULL)
-       {
-               msyslog(LOG_ERR, "Can't allocate memory for network socket: %m");
-               FreeHeap(lpo, "io_completion_port_add_socket");
-               return 1;
-       }
+               buff = get_free_recv_buffer_alloc();
+               lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket");
+               if (lpo == NULL)
+               {
+                       msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
+                       return 1;
+               }
+
+               QueueSocketRecv(fd, buff, lpo);
 
-       QueueSocketRecv(fd, buff, lpo);
+       }
        return 0;
 }
 
 static int 
-OnWriteComplete(DWORD Key, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
+OnWriteComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 {
        transmitbuf_t *buff;
-       (void) Bytes;
-       (void) Key;
+       struct interface *inter;
+
+       /* UNUSED_ARG(Bytes); */
 
        buff = lpo->trans_buf;
 
        free_trans_buf(buff);
 
+       if (SOCK_SEND == lpo->request_type) {
+               switch (errstatus) {
+               case WSA_OPERATION_ABORTED:
+               case NO_ERROR:
+                       break;
+
+               default:
+                       inter = (struct interface *)i;
+                       packets_notsent++;
+                       inter->notsent++;
+                       break;
+               }
+       }
+
        if (errstatus == WSA_OPERATION_ABORTED)
                FreeHeap(lpo, "OnWriteComplete: Socket Closed");
        else
@@ -612,7 +697,12 @@ OnWriteComplete(DWORD Key, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 }
 
 
-DWORD  
+/*
+ * Return value is really GetLastError-style error code
+ * which is a DWORD but using int, which is large enough,
+ * decreases #ifdef forest in ntp_io.c harmlessly.
+ */
+int    
 io_completion_port_sendto(
        struct interface *inter,        
        struct pkt *pkt,        
@@ -659,8 +749,6 @@ io_completion_port_sendto(
                        switch (errval) {
 
                        case NO_ERROR :
-                       case WSA_IO_INCOMPLETE :
-                       case WSA_WAIT_IO_COMPLETION :
                        case WSA_IO_PENDING :
                                Result = ERROR_SUCCESS;
                                break ;
@@ -691,72 +779,66 @@ io_completion_port_sendto(
 
 
 /*
- * Async IO Write
+ * async_write, clone of write(), used by some reflock drivers
  */
-DWORD  
-io_completion_port_write(
-       HANDLE fd,      
-       char *pkt,      
-       int len)
+int    
+async_write(
+       int fd,
+       const void *data,
+       unsigned int count)
 {
-       DWORD errval;
-       transmitbuf_t *buff = NULL;
-       DWORD lpNumberOfBytesWritten;
-       DWORD Result = ERROR_INSUFFICIENT_BUFFER;
+       transmitbuf_t *buff;
        IoCompletionInfo *lpo;
+       DWORD BytesWritten;
 
-       lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_write");
+       if (count > sizeof buff->pkt) {
+#ifdef DEBUG
+               if (debug) {
+                       printf("async_write: %d bytes too large, limit is %d\n",
+                               count, sizeof buff->pkt);
+                       exit(-1);
+               }
+#endif
+               errno = ENOMEM;
+               return -1;
+       }
 
-       if (lpo == NULL)
-               return ERROR_OUTOFMEMORY;
+       buff = get_trans_buf();
+       lpo = (IoCompletionInfo *) GetHeapAlloc("async_write");
 
-       if (len <= sizeof(buff->pkt)) {
-               buff = get_trans_buf();
-               if (buff == NULL) {
+       if (! buff || ! lpo) {
+               if (buff) {
+                       free_trans_buf(buff);
+#ifdef DEBUG
+                       if (debug)
+                               printf("async_write: out of memory, \n");
+#endif
+               } else {
                        msyslog(LOG_ERR, "No more transmit buffers left - data discarded");
-                       FreeHeap(lpo, "io_completion_port_write");
                }
 
-               lpo->request_type = CLOCK_WRITE;
-               lpo->trans_buf = buff;
-               memcpy(&buff->pkt, pkt, len);
+               errno = ENOMEM;
+               return -1;
+       }
 
-               Result = WriteFile(fd, buff->pkt, len, &lpNumberOfBytesWritten, (LPOVERLAPPED) lpo);
+       lpo->request_type = SERIAL_WRITE;
+       lpo->trans_buf = buff;
+       memcpy(&buff->pkt, data, count);
 
-               if(Result == SOCKET_ERROR)
-               {
-                       errval = WSAGetLastError();
-                       switch (errval) {
+       if (! WriteFile((HANDLE)_get_osfhandle(fd), buff->pkt, count, &BytesWritten, (LPOVERLAPPED) lpo) &&
+               ERROR_IO_PENDING != GetLastError()) {
 
-                       case NO_ERROR :
-                       case WSA_IO_INCOMPLETE :
-                       case WSA_WAIT_IO_COMPLETION :
-                       case WSA_IO_PENDING :
-                               Result = ERROR_SUCCESS;
-                               break ;
-
-                       default :
-                               netsyslog(LOG_ERR, "WriteFile - error sending message: %m");
-                               free_trans_buf(buff);
-                               FreeHeap(lpo, "io_completion_port_write");
-                               break;
-                       }
-               }
-#ifdef DEBUG
-                       if (debug > 2) {
-                               printf("WriteFile - %d bytes %d\n", len, Result);
-                       }
-#endif
-                       if (Result) return len;
+               msyslog(LOG_ERR, "async_write - error %m");
+               free_trans_buf(buff);
+               FreeHeap(lpo, "async_write");
+               errno = EBADF;
+               return -1;
        }
-       else {
-#ifdef DEBUG
-               if (debug) printf("Packet too large: %d Bytes\n", len);
-#endif
-       }
-       return Result;
+
+       return count;
 }
 
+
 /*
  * GetReceivedBuffers
  * Note that this is in effect the main loop for processing requests
index c4a7407032706c581a8128d87d33164fa21b1c7b..20aa6dc890d3b9ea4898013d336fd61bba6f2a19 100644 (file)
@@ -1,19 +1,18 @@
-/* This file implementes system calls that are not compatible with UNIX */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
+/* This file implements system calls that are not compatible with UNIX */
 
+#include <config.h>
 #include <stdio.h>
 #include "ntp_machine.h"
 #include "ntp_stdlib.h"
 #include "ntp_syslog.h"
+#include "ntp_debug.h"
 #include "ntp_fp.h"
 #include "ntp.h"
 #include "ntp_refclock.h"
 #include "win32_io.h"
 
+#define MAX_SERIAL 16  /* COM1-COM16 */
+
 
 int NT_set_process_priority(void)
 {
@@ -26,14 +25,100 @@ int NT_set_process_priority(void)
                return 1;
 }
 
+
+/*
+ * common_serial_open ensures duplicate opens of the same port
+ * work by duplicating the handle for the 2nd open, allowing
+ * refclock_atom to share a GPS refclock's comm port.
+ *
+ */
+
+HANDLE common_serial_open(
+       char *dev
+       )
+{
+       static HANDLE SerialHandles[MAX_SERIAL+1] = {0};
+       HANDLE RetHandle;
+       int unit;
+
+       if (1 != sscanf(dev, "COM%d:", &unit) || unit > MAX_SERIAL)
+               return INVALID_HANDLE_VALUE;
+
+       if (!SerialHandles[unit])
+               SerialHandles[unit] = CreateFile(
+                                       dev,
+                                       GENERIC_READ | GENERIC_WRITE,
+                                       0, /* sharing prohibited */
+                                       NULL, /* default security */
+                                       OPEN_EXISTING,
+                                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+                                       NULL);
+
+       if (INVALID_HANDLE_VALUE == SerialHandles[unit]) {
+               SerialHandles[unit] = 0;
+               return INVALID_HANDLE_VALUE;
+       }
+
+       DuplicateHandle(
+               GetCurrentProcess(),
+               SerialHandles[unit],
+               GetCurrentProcess(),
+               &RetHandle,
+               0,
+               FALSE,
+               DUPLICATE_SAME_ACCESS
+               );
+
+       return RetHandle;
+}
+
+/*
+ * pps_open - open serial port for PPS
+ *
+ * This routine opens a serial port for and returns the 
+ * file descriptor if success and -1 if failure.
+ */
+int pps_open(
+       char *dev,              /* device name pointer */
+       int access,             /* O_RDWR */
+       int mode                /* unused */
+       )
+{
+       HANDLE Handle;
+       char windev[3 + 20 + 1 + 1];
+       int unit;
+
+       if (1 != sscanf(dev, "/dev/pps%d", &unit)) {
+               errno = ENOENT;
+               return -1;
+       }
+       /*
+        * there never is a COM0: but this is the ntp convention
+        */
+       _snprintf(windev, sizeof(windev)-1, "COM%d:", unit);
+       windev[sizeof(windev)-1] = 0; 
+
+       /*
+        * open communication port handle
+        */
+       Handle = common_serial_open(windev);
+
+       if (Handle == INVALID_HANDLE_VALUE) {  
+               msyslog(LOG_ERR, "pps_open: Device %s CreateFile error: %m", windev);
+               errno = EMFILE; /* lie, lacking conversion from GetLastError() */
+               return -1;
+       }
+
+       return (int) _open_osfhandle((int)Handle, _O_TEXT);
+}
+
 /*
  * refclock_open - open serial port for reference clock
  *
  * This routine opens a serial port for I/O and sets default options. It
  * returns the file descriptor if success and zero if failure.
  */
-int
-refclock_open(
+int refclock_open(
        char *dev,              /* device name pointer */
        u_int speed,            /* serial port speed (code) */
        u_int flags             /* line discipline flags */
@@ -41,35 +126,30 @@ refclock_open(
 {
        HANDLE Handle = INVALID_HANDLE_VALUE;
        COMMTIMEOUTS timeouts;
-       DCB dcb = {0};
-
-       //
-       // open communication port handle
-       //
-       Handle = CreateFile(dev,
-               GENERIC_READ | GENERIC_WRITE,
-               0, // no sharing
-               NULL, // no security
-               OPEN_EXISTING,
-               FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
-               NULL); // not template
+       DCB dcb;
+
+       /*
+        * open communication port handle
+        */
+       Handle = common_serial_open(dev);
+
        if (Handle == INVALID_HANDLE_VALUE) {  
                 
-               msyslog(LOG_ERR, "NT_COM: Device %s: CreateFile error: %m", dev);
+               msyslog(LOG_ERR, "NT_COM: Device %s CreateFile error: %m", dev);
                return -1;
        }
 
        /*  Change the input/output buffers to be large.
        */
        if (!SetupComm( Handle, 1024, 1024)) {
-               msyslog(LOG_ERR, "NT_COM: Device %s: SetupComm error: %m", dev);
+               msyslog(LOG_ERR, "NT_COM: Device %s SetupComm error: %m", dev);
                return -1;
        }
 
        dcb.DCBlength = sizeof(dcb);
        if (!GetCommState(Handle, &dcb)) {
                // Error getting current DCB settings
-               msyslog(LOG_ERR, "NT_COM: Device %s: GetCommState error: %m", dev);
+               msyslog(LOG_ERR, "NT_COM: Device %s GetCommState error: %m", dev);
                return -1;
        }
 
@@ -81,20 +161,21 @@ refclock_open(
          case B9600 :  dcb.BaudRate = 9600; break;
          case B19200 : dcb.BaudRate = 19200; break;
          case B38400 : dcb.BaudRate = 38400; break;
+         case B57600 : dcb.BaudRate = 57600; break;
+         case B115200 : dcb.BaudRate = 115200; break;
          default :
-               msyslog(LOG_ERR, "NT_COM: Device %s: unsupported baud rate", dev);
+               msyslog(LOG_ERR, "NT_COM: Device %s unsupported baud rate", dev);
                return -1;
        }
 
 
-       dcb.ByteSize = 8;
        dcb.fBinary = TRUE;
        dcb.fParity = TRUE;
        dcb.fOutxCtsFlow = 0;
        dcb.fOutxDsrFlow = 0;
        dcb.fDtrControl = DTR_CONTROL_DISABLE;
        dcb.fDsrSensitivity = 0;
-       dcb.fTXContinueOnXoff = FALSE;
+       dcb.fTXContinueOnXoff = TRUE;
        dcb.fOutX = 0; 
        dcb.fInX = 0;
        dcb.fErrorChar = 0;
@@ -105,41 +186,56 @@ refclock_open(
        dcb.StopBits = ONESTOPBIT;
        dcb.Parity = NOPARITY;
        dcb.ErrorChar = 0;
-       dcb.EvtChar = 0;
+       dcb.EvtChar = 13; /* CR */
        dcb.EofChar = 0;
 
        if (!SetCommState(Handle, &dcb)) {
-               msyslog(LOG_ERR, "NT_COM: Device %s: SetCommState error: %m", dev);
+               msyslog(LOG_ERR, "NT_COM: Device %s SetCommState error: %m", dev);
+               return -1;
+       }
+
+       /* watch out for CR (dcb.EvtChar) as well as the CD line */
+       if (!SetCommMask(Handle, EV_RXFLAG | EV_RLSD)) {
+               msyslog(LOG_ERR, "NT_COM: Device %s SetCommMask error: %m", dev);
                return -1;
        }
 
-       timeouts.ReadIntervalTimeout = 20; 
+       /* configure the handle to never block */
+       timeouts.ReadIntervalTimeout = MAXDWORD;
        timeouts.ReadTotalTimeoutMultiplier = 0;
-       timeouts.ReadTotalTimeoutConstant = 5000;
+       timeouts.ReadTotalTimeoutConstant = 0;
        timeouts.WriteTotalTimeoutMultiplier = 0;
-       timeouts.WriteTotalTimeoutConstant = 5000;
+       timeouts.WriteTotalTimeoutConstant = 0;
 
-          // Error setting time-outs.
        if (!SetCommTimeouts(Handle, &timeouts)) {
-               msyslog(LOG_ERR, "NT_COM: Device %s: SetCommTimeouts error: %m", dev);
+               msyslog(LOG_ERR, "NT_COM: Device %s SetCommTimeouts error: %m", dev);
                return -1;
        }
 
-       return (int) Handle;
+       return (int) _open_osfhandle((int)Handle, _O_TEXT);
 }
 
-
 int 
 ioctl(int fd,
-         int cmd,
-         int *x) {
+       int cmd,
+       int *x)
+{
+       HANDLE h = (HANDLE) _get_osfhandle(fd);
 
        if ((cmd == TIOCMSET) && (*x & TIOCM_RTS)) {
-               if (!EscapeCommFunction((HANDLE) fd, SETRTS)) 
+               if (!EscapeCommFunction(h, SETRTS)) 
                        return -1;
        }
        else if ((cmd == TIOCMSET) && !(*x & TIOCM_RTS)){
-               if (!EscapeCommFunction((HANDLE) fd, CLRRTS)) 
+               if (!EscapeCommFunction(h, CLRRTS)) 
+                       return -1;
+       }
+       if ((cmd == TIOCMSET) && (*x & TIOCM_DTR)) {
+               if (!EscapeCommFunction(h, SETDTR)) 
+                       return -1;
+       }
+       else if ((cmd == TIOCMSET) && !(*x & TIOCM_DTR)){
+               if (!EscapeCommFunction(h, CLRDTR)) 
                        return -1;
        }
 
@@ -154,7 +250,7 @@ tcsetattr(
        const struct termios * s)
 {
        DCB dcb = { 0 };
-       HANDLE Handle = (HANDLE) fd;
+       HANDLE Handle = (HANDLE) _get_osfhandle(fd);
        dcb.DCBlength = sizeof(dcb);
        if (!GetCommState(Handle, &dcb)) {
                // Error getting current DCB settings
@@ -170,6 +266,8 @@ tcsetattr(
                case B9600 :  dcb.BaudRate = 9600; break;
                case B19200 : dcb.BaudRate = 19200; break;
                case B38400 : dcb.BaudRate = 38400; break;
+               case B57600 : dcb.BaudRate = 57600; break;
+               case B115200 : dcb.BaudRate = 115200; break;
                default :
                        msyslog(LOG_ERR, "NT_COM: unsupported baud rate");
                        return FALSE;
@@ -198,24 +296,15 @@ tcsetattr(
                dcb.fParity = FALSE;
                dcb.Parity = NOPARITY;
        }
-
-
-       dcb.fOutxCtsFlow = 0;
-       dcb.fOutxDsrFlow = 0;
-       dcb.fDtrControl = DTR_CONTROL_DISABLE;
-       dcb.fDsrSensitivity = 0;
-       dcb.fOutX = 0; 
-       dcb.fInX = 0;
-       dcb.fErrorChar = 0;
-       dcb.fNull = 0;
-       dcb.fRtsControl = RTS_CONTROL_DISABLE;
-       dcb.fAbortOnError = 0;
-       dcb.ErrorChar = 0;
-       dcb.EvtChar = 0;
-       dcb.EofChar = 0;
+       if (s->c_cflag & CSTOPB ) {
+               dcb.StopBits = TWOSTOPBITS;
+       }
+       else {
+               dcb.StopBits = ONESTOPBIT;
+       }
 
        if (!SetCommState(Handle, &dcb)) {
-               msyslog(LOG_ERR, "NT_COM: SetCommState error: %m");
+               msyslog(LOG_ERR, "NT_COM: SetCommState error 2: %m");
                return FALSE;
        }
        return TRUE;
@@ -225,11 +314,11 @@ extern    int
 tcgetattr(
        int fd, struct termios *s)
 {
-       DCB dcb = { 0 };
-       HANDLE Handle = (HANDLE) fd;
+       DCB dcb;
+       HANDLE Handle = (HANDLE) _get_osfhandle(fd);
+
        dcb.DCBlength = sizeof(dcb);
        if (!GetCommState(Handle, &dcb)) {
-               // Error getting current DCB settings
                msyslog(LOG_ERR, "NT_COM: GetCommState error: %m");
                return FALSE;
        }
@@ -244,6 +333,8 @@ tcgetattr(
                case 9600 : s->c_ispeed = s->c_ospeed = B9600; break;
                case 19200 : s->c_ispeed = s->c_ospeed = B19200; break;
                case 38400 : s->c_ispeed = s->c_ospeed = B38400; break;
+               case 57600 : s->c_ispeed = s->c_ospeed = B57600; break;
+               case 115200 : s->c_ispeed = s->c_ospeed = B115200; break;
                default : s->c_ispeed = s->c_ospeed = B9600;
        }
        
@@ -265,6 +356,11 @@ tcgetattr(
                case ODDPARITY : s->c_cflag |= PARODD; break;
                case SPACEPARITY : break;
        }
+       switch (dcb.StopBits) {
+               case ONESTOPBIT : break;
+               case ONE5STOPBITS : break;
+               case TWOSTOPBITS : s->c_cflag |= CSTOPB; break;
+       }
 
        s->c_iflag = 0;
        s->c_lflag = 0;
@@ -276,22 +372,32 @@ tcgetattr(
 
 
 extern int tcflush(int fd, int mode) {
-
-
-
-
-return 0;
-
+       int Result = 0;
+       HANDLE h = (HANDLE) _get_osfhandle(fd);
+       switch ( mode ) {
+       case TCIFLUSH:
+               Result = PurgeComm(h, PURGE_RXCLEAR);
+               break;
+       case TCOFLUSH:
+               Result = PurgeComm(h, PURGE_TXABORT);
+               break;
+       case TCIOFLUSH:
+               Result = PurgeComm(h, PURGE_RXCLEAR | PURGE_TXABORT);
+               break;
+       }
+       if ( Result == 0 ) return -1;   /* failed */
+       else return 0;                                  /* successful */
 }
 
+
 extern int cfsetispeed(struct termios *tio, int speed) {
-               
+
 return 0;              
 };     
 
 
 extern int cfsetospeed(struct termios *tio, int speed) {
-               
+
 return 0;              
 };