]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 3125] NTPD doesn't fully start when ntp.conf entries are out of order using...
authorJuergen Perlinger <perlinger@ntp.org>
Tue, 4 Oct 2016 06:36:17 +0000 (08:36 +0200)
committerJuergen Perlinger <perlinger@ntp.org>
Tue, 4 Oct 2016 06:36:17 +0000 (08:36 +0200)
bk: 57f34de1Cp_P0NidT2Ym9FzsbNLtCA

ChangeLog
ports/winnt/include/ntp_iocompletionport.h
ports/winnt/include/termios.h
ports/winnt/libntp/termios.c
ports/winnt/ntpd/ntp_iocompletionport.c
ports/winnt/ntpd/ntp_iocpltypes.c

index 43e74b4c7730aa7d583860a14ef3ce82194701b3..cf8174374a8e03be3f3fffa047583847c364cc7c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,8 @@
 * [Sec 3072] Attack on interface selection <perlinger@ntp.org>
   - implemented Miroslav Lichvars <mlichvar@redhat.com> suggestion
     to skip interface updates based on incoming packets
+* [Bug 3125] NTPD doesn't fully start when ntp.conf entries are out of order
+  using the loopback-ppsapi-provider.dll <perlinger@ntp.org>
 * [Bug 3116] unit tests for NTP time stamp expansion. <perlinger@ntp.org>
 * [Bug 3100] ntpq can't retrieve daemon_version <perlinger@ntp.org>
   - fixed extended sysvar lookup (bug introduced with bug 3008 fix)
index a5558a0b8b729884e08cf290f6817fed3d476ef9..b75c421c18c504a334e52ed7bc39ddf3a94c6b4f 100644 (file)
@@ -21,7 +21,7 @@ extern        void    io_completion_port_remove_interface(struct interface*);
 extern BOOL    io_completion_port_add_socket(SOCKET fd, struct interface *, BOOL bcast);
 extern void    io_completion_port_remove_socket(SOCKET fd, struct interface*);
 
-extern int     io_completion_port_sendto(struct interface*, SOCKET, void *, size_t, sockaddr_u *);
+extern int     io_completion_port_sendto(endpt*, SOCKET, void *, size_t, sockaddr_u *);
 
 extern BOOL    io_completion_port_add_clock_io(struct refclockio *rio);
 extern void    io_completion_port_remove_clock_io(struct refclockio *rio);
index 94331afca57e7801f5dfc66964f2eae63554ca6c..2ed34208903c09b0a927dfe882dd1ba6b518dd2e 100644 (file)
@@ -211,4 +211,7 @@ extern      int     tcgetattr       (int, struct termios *);
 extern int     tcflush         (int, int);
 extern int     isserialhandle  (HANDLE);
 
+typedef struct DeviceContext DevCtx_t;
+extern DevCtx_t*       serial_devctx(HANDLE);
+
 #endif /* NTP_WIN_TERMIOS_H */
index 9596593b7575a4de19def4fc86433a09b2ecef91..22b06b4718179aa1313bee3cdd54d9c6720f2062 100644 (file)
 #include "ntp_assert.h"
 #include "win32_io.h"
 
+#include "ntp_iocplmem.h"
+#include "ntp_iocpltypes.h"
+
+/* -------------------------------------------------------------------
+ * COM port management
+ *
+ * com port handling needs some special functionality, especially for
+ * PPS support. There are things that are shared by the Windows Kernel
+ * on device level, not handle level. These include IOCPL membership,
+ * event wait slot, ... It's also no so simple to open a device a
+ * second time, and so we must manage the handles on open com ports
+ * in userland. Well, partially.
+ */
 #define MAX_SERIAL 255 /* COM1: - COM255: */
+#define MAX_COMDUP 8   /* max. allowed number of dupes per device */
 
 typedef struct comhandles_tag {
-       HANDLE          h;
-       size_t          opens;
-       HANDLE *        dupes;
+       uint16_t        unit;   /* COMPORT number               */
+       uint16_t        nhnd;   /* number of open handles       */
+       char *          comName;/* windows device name          */
+       DevCtx_t *      devCtx; /* shared device context        */
+       HANDLE          htab[MAX_COMDUP];       /* OS handles   */
 } comhandles;
 
-comhandles *   hnds;   /* handle/dupes array */
-size_t         c_hnds; /* current array size */
+comhandles **  tab_comh;       /* device data table            */
+size_t         num_comh;       /* current used array size      */
+size_t         max_comh;       /* current allocated array size */
+
+/* lookup a COM unit by a handle
+ * Scans all used units for a matching handle. Returns the slot
+ * or NULL on failure.
+ *
+ * If 'phidx' is given, the index in the slots handle table that
+ * holds the handle is also returned.
+ *
+ * This a simple 2d table scan. But since we don't expect to have
+ * hundreds of com ports open, this should be no problem.
+ */
+static comhandles*
+lookup_com_handle(
+       HANDLE          h,
+       size_t *        phidx
+       )
+{
+       size_t          tidx, hidx;
+       comhandles *    slot;
+       for (tidx = 0; tidx < num_comh; ++tidx) {
+               slot = tab_comh[tidx];
+               for (hidx = 0; hidx < slot->nhnd; ++hidx) {
+                       if (slot->htab[hidx] == h) {
+                               if (phidx != NULL)
+                                       *phidx = hidx;
+                               return slot;
+                       }
+               }
+       }
+       return NULL;
+}
+
+/* lookup the list of COM units by unit number. This will always return
+ * a valid location -- eventually the table gets expanded, and a new
+ * entry is returned. In that case, the structure is set up with all
+ * entries valid and *no* file handles yet.
+ */
+static comhandles*
+insert_com_unit(
+       uint16_t unit
+)
+{
+       size_t          tidx;
+       comhandles *    slot;
+
+       /* search for matching entry and return if found */
+       for (tidx = 0; tidx < num_comh; ++tidx)
+               if (tab_comh[tidx]->unit == unit)
+                       return tab_comh[tidx];
+
+       /* search failed. make sure we can add a new slot */
+       if (num_comh >= max_comh) {
+               /* round up to next multiple of 4 */
+               max_comh = (num_comh + 4) & ~(size_t)3;
+               tab_comh = erealloc(tab_comh, max_comh * sizeof(tab_comh[0]));
+       }
+
+       /* create a new slot and populate it. */
+       slot = emalloc_zero(sizeof(comhandles));
+       LIB_GETBUF(slot->comName);
+       snprintf(slot->comName, LIB_BUFLENGTH, "\\\\.\\COM%d", unit);
+       slot->comName = estrdup(slot->comName);
+       slot->devCtx  = DevCtxAlloc();
+       slot->unit    = unit;
+
+       /* plug it into table and return it */
+       tab_comh[num_comh++] = slot;
+       return slot;
+}
+
+/* remove a COM slot from the table and destroy it. */
+static void
+remove_com_slot(
+       comhandles *    slot    /* must be valid! */
+       )
+{
+       size_t  tidx;
+       for (tidx = 0; tidx < num_comh; ++tidx)
+               if (tab_comh[tidx] == slot) {
+                       tab_comh[tidx] = tab_comh[--num_comh];
+                       break;
+               }
+
+       DevCtxDetach(slot->devCtx);
+       free(slot->comName);
+       free(slot);
+}
+
+/* fetch the stored device context block.
+ * This does NOT step the reference counter!
+ */
+DevCtx_t*
+serial_devctx(
+       HANDLE  h
+       )
+{
+       comhandles * slot = NULL;
+       if (INVALID_HANDLE_VALUE != h && NULL != h)
+               slot = lookup_com_handle(h, NULL);
+       return (NULL != slot) ? slot->devCtx : NULL;
+}
+
 
 /*
  * common_serial_open ensures duplicate opens of the same port
@@ -30,16 +149,13 @@ size_t             c_hnds; /* current array size */
 HANDLE
 common_serial_open(
        const char *    dev,
-       char **         pwindev
+       const char **   pwindev
        )
 {
-       char *          windev;
        HANDLE          handle;
        size_t          unit;
-       size_t          prev_c_hnds;
-       size_t          opens;
        const char *    pch;
-       u_int           uibuf;
+       comhandles *    slot;
 
        /*
         * This is odd, but we'll take any unix device path
@@ -55,147 +171,105 @@ common_serial_open(
 
        TRACE(1, ("common_serial_open given %s\n", dev));
 
+       handle = INVALID_HANDLE_VALUE;
+
        pch = NULL;
        if ('/' == dev[0]) {
-               pch = dev + strlen(dev) - 1;
-
-               if (isdigit(pch[0])) {
-                       while (isdigit(pch[0])) {
-                               pch--;
-                       }
-                       pch++;
-               }
+               pch = dev + strlen(dev);
+               while (isdigit((u_char)pch[-1]))
+                       --pch;
                TRACE(1, ("common_serial_open skipped to ending digits leaving %s\n", pch));
-       } else if ('c' == tolower(dev[0])
-                  && 'o' == tolower(dev[1])
-                  && 'm' == tolower(dev[2])) {
+       } else if (0 == _strnicmp("COM", dev, 3)) {
                pch = dev + 3;
                TRACE(1, ("common_serial_open skipped COM leaving %s\n", pch));
        }
 
-       if (!pch || !isdigit(pch[0])) {
+       if (!pch || !isdigit((u_char)pch[0])) {
                TRACE(1, ("not a digit: %s\n", pch ? pch : "[NULL]"));
                return INVALID_HANDLE_VALUE;
        }
 
-       if (1 != sscanf(pch, "%u", &uibuf) 
-           || (unit = uibuf) > MAX_SERIAL) {
-               TRACE(1, ("sscanf failure of %s\n", pch));
+       unit = strtoul(pch, (char**)&pch, 10);
+       if (*pch || unit > MAX_SERIAL) {
+               TRACE(1, ("conversion failure: unit=%u at '%s'\n", pch));
                return INVALID_HANDLE_VALUE;
        }
 
-
-       if (c_hnds < unit + 1) {
-               prev_c_hnds = c_hnds;
-               c_hnds = unit + 1;
-               /* round up to closest multiple of 4 to avoid churn */
-               c_hnds = (c_hnds + 3) & ~3;
-               hnds = erealloc_zero(hnds, c_hnds * sizeof(hnds[0]),
-                                    prev_c_hnds * sizeof(hnds[0]));
-       }
-
-       if (NULL == hnds[unit].h) {
-               INSIST(0 == hnds[unit].opens);
-               LIB_GETBUF(windev);
-               snprintf(windev, LIB_BUFLENGTH, "\\\\.\\COM%d", unit);
-               TRACE(1, ("windows device %s\n", windev));
-               *pwindev = windev;
-               hnds[unit].h =
-                   CreateFile(
-                       windev,
+       /* Now.... find the COM slot, and either create a new file
+        * (if there is no handle yet) or duplicate one of the existing
+        * handles. Unless the dup table for one com port would overflow,
+        * but that's an indication of a programming error somewhere.
+        */
+       slot = insert_com_unit(unit);
+       if (slot->nhnd == 0) {
+               TRACE(1, ("windows device %s\n", slot->comName));
+               slot->htab[0] = CreateFileA(
+                               slot->comName,
                        GENERIC_READ | GENERIC_WRITE,
                        0, /* sharing prohibited */
                        NULL, /* default security */
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
                        NULL);
-               if (INVALID_HANDLE_VALUE == hnds[unit].h)
-                       hnds[unit].h = NULL;
-       }
-
-       if (NULL != hnds[unit].h) {
-               /* think handle = dup(hnds[unit].h); */
-               DuplicateHandle(
-                       GetCurrentProcess(),
-                       hnds[unit].h,
-                       GetCurrentProcess(),
-                       &handle,
-                       0,
-                       FALSE,
-                       DUPLICATE_SAME_ACCESS
-                       );
-               hnds[unit].opens++;
-               opens = hnds[unit].opens;
-               hnds[unit].dupes = erealloc(hnds[unit].dupes, opens *
-                                           sizeof(hnds[unit].dupes[0]));
-               hnds[unit].dupes[opens - 1] = handle;
-               return handle;
+               if (INVALID_HANDLE_VALUE != slot->htab[0]) {
+                       slot->nhnd     = 1;
+                       handle         = slot->htab[0];
+                       *pwindev       = slot->comName;
+               }
+       } else if (slot->nhnd >= MAX_COMDUP) {
+               SetLastError(ERROR_TOO_MANY_OPEN_FILES);
+       } else if (DuplicateHandle(GetCurrentProcess(), slot->htab[0],
+                                  GetCurrentProcess(), &slot->htab[slot->nhnd],
+                                  0, FALSE, DUPLICATE_SAME_ACCESS))
+       {
+               handle = slot->htab[slot->nhnd++];
+               *pwindev = slot->comName;
        }
 
-       return INVALID_HANDLE_VALUE;
+       return handle;
 }
 
-
 /*
  * closeserial() is used in place of close by ntpd refclock I/O for ttys
  */
 int
-closeserial(int fd)
+closeserial(
+       int     fd
+       )
 {
        HANDLE  h;
-       BOOL    found;
-       size_t  u;
-       size_t  d;
+       size_t  hidx;
+       comhandles *    slot;
 
        h = (HANDLE)_get_osfhandle(fd);
-       if (INVALID_HANDLE_VALUE == h) {
-               errno = EBADF;
-               return -1;
-       }
+       if (INVALID_HANDLE_VALUE == h)
+               goto onerror;
 
-       d = 0;          /* silence potent. uninit. warning */
-       found = FALSE;
-       for (u = 0; u < c_hnds; u++) {
-               for (d = 0; d < hnds[u].opens; d++) {
-                       if (hnds[u].dupes[d] == h) {
-                               found = TRUE;
-                               break;
-                       }
-               }
-               if (found)
-                       break;
-       }
-       if (found) {
-               hnds[u].opens--;
-               if (d < hnds[u].opens)
-                       memmove(&hnds[u].dupes[d],
-                               &hnds[u].dupes[d + 1],
-                               hnds[u].opens - d *
-                                   sizeof(hnds[u].dupes[d]));
-               if (0 == hnds[u].opens) {
-                       CloseHandle(hnds[u].h);
-                       hnds[u].h = NULL;
-               }
-       }
+       slot = lookup_com_handle(h, &hidx);
+       if (NULL == slot)
+               goto onerror;
+
+       slot->htab[hidx] = slot->htab[--slot->nhnd];
+       if (slot->nhnd == 0)
+               remove_com_slot(slot);
+
+       return close(fd); /* closes system handle, too! */
 
-       return close(fd);
+onerror:
+       errno = EBADF;
+       return -1;
 }
 
 /*
  * isserialhandle() -- check if a handle is a COM port handle
  */
-int isserialhandle(
+int/*BOOL*/
+isserialhandle(
        HANDLE h
        )
 {
-       size_t  u;
-       size_t  d;
-
-
-       for (u = 0; u < c_hnds; u++)
-               for (d = 0; d < hnds[u].opens; d++)
-                       if (hnds[u].dupes[d] == h)
-                               return TRUE;
+       if (INVALID_HANDLE_VALUE != h && NULL != h)
+               return lookup_com_handle(h, NULL) != NULL;
        return FALSE;
 }
 
@@ -206,23 +280,21 @@ int isserialhandle(
  * This routine opens a serial port for and returns the 
  * file descriptor if success and -1 if failure.
  */
-int tty_open(
+int
+tty_open(
        const char *dev,        /* device name pointer */
        int access,             /* O_RDWR */
        int mode                /* unused */
        )
 {
-       HANDLE  Handle;
-       char *  windev;
+       HANDLE          Handle;
+       const char *    windev;
 
        /*
         * open communication port handle
         */
-       windev = NULL;
+       windev = dev;
        Handle = common_serial_open(dev, &windev);
-       windev = (windev)
-                    ? windev
-                    : dev;
 
        if (Handle == INVALID_HANDLE_VALUE) {  
                msyslog(LOG_ERR, "tty_open: device %s CreateFile error: %m", windev);
@@ -230,7 +302,7 @@ int tty_open(
                return -1;
        }
 
-       return (int)_open_osfhandle((intptr_t)Handle, _O_TEXT);
+       return _open_osfhandle((intptr_t)Handle, _O_TEXT);
 }
 
 
@@ -247,7 +319,7 @@ refclock_open(
        u_int           flags   /* line discipline flags */
        )
 {
-       char *          windev;
+       const char *    windev;
        HANDLE          h;
        COMMTIMEOUTS    timeouts;
        DCB             dcb;
@@ -258,9 +330,8 @@ refclock_open(
        /*
         * open communication port handle
         */
-       windev = NULL;
+       windev = dev;
        h = common_serial_open(dev, &windev);
-       windev = (windev) ? windev : dev;
 
        if (INVALID_HANDLE_VALUE == h) {
                SAVE_ERRNO(
index 08f3c4e3729b622c5d8b2ceaa335b65ed93bdd78..90bdd99e18d999ef93f96764bb80b928b2db6060 100644 (file)
@@ -71,6 +71,11 @@ Juergen Perlinger (perlinger@ntp.org) Feb 2012
 #define CONTAINEROF(p, type, member) \
        ((type *)((char *)(p) - offsetof(type, member)))
 
+enum io_packet_handling {
+       PKT_OK,
+       PKT_DROP,
+       PKT_SOCKET_ERROR
+};
 
 /*
  * local function definitions
@@ -110,7 +115,7 @@ static      HANDLE  hMainThread;
 static BOOL    DoPPShack;
 
 DWORD  ActiveWaitHandles;
-HANDLE WaitHandles[16];
+HANDLE WaitHandles[4];
 
 
 /*
@@ -474,6 +479,8 @@ IoResultCheck(
        const char *    msg
        )
 {
+       DPRINTF(6, ("in IoResultCheck err = %d\n", err));
+
        switch (err) {
                /* The first ones are no real errors. */
        case ERROR_SUCCESS:     /* all is good */
@@ -557,8 +564,7 @@ getRioFromIoCtx(
 static endpt*
 getEndptFromIoCtx(
        IoCtx_t *       ctx,
-       ULONG_PTR       key,
-       const char *    msg
+       ULONG_PTR       key
        )
 {
        /* Make sure the key matches the context info in the shared
@@ -570,7 +576,6 @@ getEndptFromIoCtx(
         * LSB is not used in the reverse-link check. Hence we shift
         * it out in both the input key and the registered source.
         */
-       int             oval, olen; /* getsockopt params */
        endpt *         ep    = NULL;
        SharedLock_t *  slock = slAttachShared(ctx->slock);
        if (slock != NULL) {
@@ -581,7 +586,25 @@ getEndptFromIoCtx(
                        ep = NULL;
                slDetachShared(slock);
        }
-       if (ep != NULL) switch (ctx->errCode) {
+       if (ep == NULL)
+               IoCtxRelease(ctx);
+       return ep;
+}
+
+
+static int
+socketErrorCheck(
+       IoCtx_t *       ctx,
+       const char *    msg
+       )
+{
+       int oval, olen; /* getsockopt params */
+       int retCode;
+
+       switch (ctx->errCode) {
+       case ERROR_SUCCESS:             /* all is good */
+               retCode = PKT_OK;
+               break;
        case ERROR_UNEXP_NET_ERR:
                if (hMainThread)
                        QueueUserAPC(apcOnUnexpectedNetworkError,
@@ -589,9 +612,7 @@ getEndptFromIoCtx(
        case ERROR_INVALID_PARAMETER:   /* handle already closed (clock?)*/
        case ERROR_OPERATION_ABORTED:   /* handle closed while wait      */
        case WSAENOTSOCK            :   /* handle already closed (sock)  */
-               ctx->errCode = ERROR_SUCCESS;
-               ep = NULL;
-       case ERROR_SUCCESS:             /* all is good */
+               retCode = PKT_SOCKET_ERROR;
                break;
 
        /* [Bug 3019] is hard to squash.
@@ -609,33 +630,35 @@ getEndptFromIoCtx(
                oval = 0;
                olen = sizeof(oval);
                getsockopt(ctx->io.sfd, SOL_SOCKET, SO_ERROR, (char*)&oval, &olen);
-               ctx->errCode = ERROR_SUCCESS;
+               retCode = PKT_DROP;
                break;
 
        /* [Bug 3110] On POSIX systems, reading UDP data into too small
         * a buffers silently truncates the message. Under Windows the
         * data is also truncated, but it blarts loudly about that.
         * Just pretend all is well, and all will be well.
+        *
+        * Note: We accept the truncated packet -- this is consistent with the
+        * POSIX / UNIX case where we have no notification about this at all.
         */
-       case ERROR_MORE_DATA:
-       case WSAEMSGSIZE    :
-               ctx->errCode = ERROR_SUCCESS;
+       case ERROR_MORE_DATA:           /* Too Much data for Buffer      */
+       case WSAEMSGSIZE:
+               retCode = PKT_OK; /* or PKT_DROP ??? */
                break;
 
-       /* For any other error, log the error, clear the byt count, but
-        * but return the endpoint. This prevents processing the packet
-        * and keeps the read-chain running -- otherwise NTPD will play
+       /* For any other error, log the error, clear the byte count, but
+        * return the endpoint. This prevents processing the packet and
+        * keeps the read-chain running -- otherwise NTPD will play
         * dead duck!
         */
        default:
                LogIoError(msg, ctx->io.hnd, ctx->errCode);
-               ctx->byteCount = 0;
+               retCode = PKT_DROP;
                break;
        }
-       if (NULL == ep)
-               IoCtxRelease(ctx);
-       return ep;
+       return retCode;
 }
+
 /*
  * -------------------------------------------------------------------
  * Serial IO stuff
@@ -909,8 +932,8 @@ wait_again:
  */
 static DWORD WINAPI
 OnSerialReadWorker(
-void * ctx
-)
+       void *  ctx
+       )
 {
        IoCtx_t *       lpo;
        SharedLock_t *  slock;
@@ -1182,58 +1205,16 @@ OnSerialWriteComplete(
  * -------------------------------------------------------------------
  */
 
-/* The dummy read procedure is used for getting the device context
- * into the IO completion thread, using the IO completion queue for
- * transport. There are other ways to accomplish what we need here,
- * but using the IO machine is handy and avoids a lot of trouble.
- */
-static void
-OnPpsDummyRead(
-       ULONG_PTR       key,
-       IoCtx_t *       lpo
-       )
-{
-       RIO_t * rio;
-
-       rio = (RIO_t *)key;
-       lpo->devCtx = DevCtxAttach(rio->device_ctx);
-       SetEvent(lpo->ppswake);
-}
-
 __declspec(dllexport) void* __stdcall
 ntp_pps_attach_device(
        HANDLE  hndIo
        )
 {
-       IoCtx_t         myIoCtx;
-       HANDLE          myEvt;
-       DevCtx_t *      dev;
-       DWORD           rc;
+       DevCtx_t *      dev = NULL;
 
-       if (!isserialhandle(hndIo)) {
+       dev = DevCtxAttach(serial_devctx(hndIo));
+       if ( NULL == dev)
                SetLastError(ERROR_INVALID_HANDLE);
-               return NULL;
-       }
-
-       ZERO(myIoCtx);
-       dev   = NULL;
-       myEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
-       if (myEvt == NULL)
-               goto done;
-
-       myIoCtx.ppswake   = myEvt;
-       myIoCtx.onIoDone  = OnPpsDummyRead;
-       rc = ReadFile(hndIo, &myIoCtx.byteCount, 0,
-                       &myIoCtx.byteCount, &myIoCtx.ol);
-       if (!rc && (GetLastError() != ERROR_IO_PENDING))
-               goto done;
-       if (WaitForSingleObject(myEvt, INFINITE) == WAIT_OBJECT_0)
-               if (NULL == (dev = myIoCtx.devCtx))
-                       SetLastError(ERROR_INVALID_HANDLE);
-done:
-       rc = GetLastError();
-       CloseHandle(myEvt);
-       SetLastError(rc);
        return dev;
 }
 
@@ -1332,7 +1313,7 @@ io_completion_port_add_clock_io(
        slock->riofd      = rio->fd;
        slock->rsrc.rio   = rio;
 
-       if ( ! (rio->device_ctx = DevCtxAlloc())) {
+       if (!(rio->device_ctx = DevCtxAttach(serial_devctx(h)))) {
                msyslog(LOG_ERR, "%s: Failed to allocate device context",
                        msgh);
                goto fail;
@@ -1435,9 +1416,13 @@ OnSocketRecv(
 
        recvbuf_t *     buff    = NULL;
        SharedLock_t *  slock   = NULL;
+       BOOL epOK = TRUE;
+       int retCode = PKT_OK;
 
        /* Make sure this endpoint is not closed. */
-       endpt * ep = getEndptFromIoCtx(lpo, key, msg);
+       endpt * ep = getEndptFromIoCtx(lpo, key);
+       retCode = socketErrorCheck(lpo, msg);
+
        if (ep == NULL)
                return;
 
@@ -1448,7 +1433,7 @@ OnSocketRecv(
         * We also need an extra hold to the SLOCK structure.
         */
        slock = slAttach(lpo->slock);
-       if (lpo->errCode == ERROR_SUCCESS && lpo->byteCount > 0) {
+       if (retCode == PKT_OK && lpo->byteCount > 0) {
                /* keep input buffer, create new one for IO */
                buff              = lpo->recv_buf;
                lpo->recv_buf     = get_free_recv_buffer_alloc();
@@ -1457,7 +1442,13 @@ OnSocketRecv(
                buff->recv_length = (int)lpo->byteCount;
 
        } /* Note: else we use the current buffer again */
-       IoCtxStartLocked(lpo, QueueSocketRecv, lpo->recv_buf);
+
+       if (retCode != PKT_SOCKET_ERROR) {
+               IoCtxStartLocked(lpo, QueueSocketRecv, lpo->recv_buf);
+       }  else {
+               freerecvbuf(lpo->recv_buf);
+               IoCtxFree(lpo);
+       }
        /* below this, any usage of 'lpo' is invalid! */
 
        /* If we have a buffer, do some bookkeeping and other chores,
@@ -1474,19 +1465,19 @@ OnSocketRecv(
                        get_packet_mode(buff)));
 
                if (slAttachShared(slock)) {
-                       BOOL epOK = slEndPointOK(slock);
-                       if (epOK)
-                               InterlockedIncrement(&slock->rsrc.ept->received);
-                       slDetachShared(slock);
-                       if (epOK) {
+                       if (slEndPointOK(slock)) {
+                               InterlockedIncrement(&ep->received);
+                               slDetachShared(slock);
                                InterlockedIncrement(&packets_received);
                                InterlockedIncrement(&handler_pkts);
+                       } else {
+                               slDetachShared(slock);
                        }
                }
 
-               DPRINTF(2, ("Received %d bytes fd %d in buffer %p from %s\n",
+               DPRINTF(2, ("Received %d bytes fd %d in buffer %p from %s, state = %s\n",
                        buff->recv_length, (int)buff->fd, buff,
-                       stoa(&buff->recv_srcadr)));
+                       stoa(&buff->recv_srcadr), epOK? "Accepted" : "Ignored"));
                slQueueLocked(slock, slEndPointOK, buff);
        }
        slDetach(slock);
@@ -1501,26 +1492,27 @@ OnSocketSend(
 {
        /* this is somewhat easier: */
        static const char * const msg =
-               "OnSocketRecv: send to socket failed";
+               "OnSocketSend: send to socket failed";
 
        SharedLock_t *  slock = NULL;
-       endpt *         ep    = getEndptFromIoCtx(lpo, key, msg);
+       endpt *         ep = getEndptFromIoCtx(lpo, key);
+       int             retCode = socketErrorCheck(lpo, msg);
        /* Make sure this endpoint is not closed. */
        if (ep == NULL)
                return;
 
-       if (lpo->errCode != ERROR_SUCCESS)
+       if (retCode != PKT_OK) {
                slock = slAttachShared(lpo->slock);
-       if (slock) {
-               BOOL epOK = slEndPointOK(slock);
-               if (epOK) {
-                       InterlockedIncrement(&slock->rsrc.ept->notsent);
-                       InterlockedDecrement(&slock->rsrc.ept->sent);
-               }
-               slDetachShared(slock);
-               if (epOK) {
-                       InterlockedIncrement(&packets_notsent);
-                       InterlockedDecrement(&packets_sent);
+               if (slock) {
+                       if (slEndPointOK(slock)) {
+                               InterlockedIncrement(&ep->notsent);
+                               InterlockedDecrement(&ep->sent);
+                               slDetachShared(slock);
+                               InterlockedIncrement(&packets_notsent);
+                               InterlockedDecrement(&packets_sent);
+                       } else {
+                               slDetachShared(slock);
+                       }
                }
        }
        IoCtxRelease(lpo);
@@ -1721,7 +1713,10 @@ GetReceivedBuffers(void)
 {
        DWORD   index;
        HANDLE  ready;
-       int     have_packet;
+       int     errcode;
+       BOOL    dynbuf;
+       BOOL    have_packet;
+       char *  msgbuf;
 
        have_packet = FALSE;
        while (!have_packet) {
@@ -1748,20 +1743,18 @@ GetReceivedBuffers(void)
 
                case WAIT_TIMEOUT:
                        msyslog(LOG_ERR,
-                               "WaitForMultipleObjects INFINITE timed out.");
-                       exit(1);
+                               "WaitForMultipleObjectsEx INFINITE timed out.");
                        break;
 
                case WAIT_FAILED:
-               {
-                       BOOL   dynbuf = FALSE;
-                       char * msgbuf = NTstrerror(GetLastError(), &dynbuf);
+                       dynbuf = FALSE;
+                       errcode = GetLastError();
+                       msgbuf = NTstrerror(errcode, &dynbuf);
                        msyslog(LOG_ERR,
-                               "WaitForMultipleObjects Failed: Error: %s", msgbuf);
+                               "WaitForMultipleObjectsEx Failed: Errcode = %n, msg = %s", errcode, msgbuf);
                        if (dynbuf)
                                LocalFree(msgbuf);
                        exit(1);
-               }
                break;
 
                default:
index bd12f2881bb69e73a220b25664e3696ef9938187..538217a7b826dc3313c04797350da14ba513d3c2 100644 (file)
@@ -211,10 +211,10 @@ DevCtxAlloc(void)
        /* allocate struct and tag all slots as invalid */
        devCtx = (DevCtx_t *)IOCPLPoolAlloc(sizeof(DevCtx_t), "DEV ctx");
        if (devCtx != NULL) {
+               devCtx->ref_count = 1;  /* already owned! */
                /* The initial COV values make sure there is no busy
                * loop on unused/empty slots.
                */
-               devCtx->cov_count = 1;  /* already owned! */
                for (slot = 0; slot < PPS_QUEUE_LEN; slot++)
                        devCtx->pps_buff[slot].cov_count = ~slot;
        }
@@ -299,7 +299,7 @@ IoCtxRelease(
        )
 {
        static const char *const dmsg =
-               "overlapped IO data buffer";
+               "Release overlapped IO data buffer";
 
        if (ctx) {
                if (ctx->flRawMem)