* [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)
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);
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 */
#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
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
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;
}
* 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);
return -1;
}
- return (int)_open_osfhandle((intptr_t)Handle, _O_TEXT);
+ return _open_osfhandle((intptr_t)Handle, _O_TEXT);
}
u_int flags /* line discipline flags */
)
{
- char * windev;
+ const char * windev;
HANDLE h;
COMMTIMEOUTS timeouts;
DCB dcb;
/*
* 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(
#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
static BOOL DoPPShack;
DWORD ActiveWaitHandles;
-HANDLE WaitHandles[16];
+HANDLE WaitHandles[4];
/*
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 */
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
* 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) {
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,
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.
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
*/
static DWORD WINAPI
OnSerialReadWorker(
-void * ctx
-)
+ void * ctx
+ )
{
IoCtx_t * lpo;
SharedLock_t * slock;
* -------------------------------------------------------------------
*/
-/* 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;
}
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;
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;
* 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();
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,
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);
{
/* 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);
{
DWORD index;
HANDLE ready;
- int have_packet;
+ int errcode;
+ BOOL dynbuf;
+ BOOL have_packet;
+ char * msgbuf;
have_packet = FALSE;
while (!have_packet) {
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:
/* 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;
}
)
{
static const char *const dmsg =
- "overlapped IO data buffer";
+ "Release overlapped IO data buffer";
if (ctx) {
if (ctx->flRawMem)