42
44
#define recv_buf buff_space.rbuf
43
45
#define trans_buf buff_space.tbuf
50
* if ULONG_PTR needs to be defined then the build environment
51
* is pure 32 bit Windows. Since ULONG_PTR and DWORD have
52
* the same size in 32 bit Windows we can safely define
55
typedef DWORD ULONG_PTR;
46
59
* local function definitions
48
static int QueueIORead( struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo);
50
static int OnSocketRecv(DWORD, IoCompletionInfo *, DWORD, int);
51
static int OnIoReadComplete(DWORD, IoCompletionInfo *, DWORD, int);
52
static int OnWriteComplete(DWORD, IoCompletionInfo *, DWORD, int);
61
static int QueueSerialWait(struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp);
63
static int OnSocketRecv(ULONG_PTR, IoCompletionInfo *, DWORD, int);
64
static int OnSerialWaitComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
65
static int OnSerialReadComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
66
static int OnWriteComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
68
/* #define USE_HEAP */
54
71
static HANDLE hHeapHandle = NULL;
56
74
static HANDLE hIoCompletionPort = NULL;
58
76
static HANDLE WaitableIoEventHandle = NULL;
59
77
static HANDLE WaitableExitEventHandle = NULL;
79
#ifdef NTPNEEDNAMEDHANDLE
80
#define WAITABLEIOEVENTHANDLE "WaitableIoEventHandle"
82
#define WAITABLEIOEVENTHANDLE NULL
61
85
#define MAXHANDLES 3
62
86
HANDLE WaitHandles[MAXHANDLES] = { NULL, NULL, NULL };
67
89
GetHeapAlloc(char *fromfunc)
74
96
sizeof(IoCompletionInfo));
76
lpo = (IoCompletionInfo *) calloc(1, sizeof(IoCompletionInfo));
80
printf("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo);
98
lpo = (IoCompletionInfo *) calloc(1, sizeof(*lpo));
100
DPRINTF(3, ("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo));
87
106
FreeHeap(IoCompletionInfo *lpo, char *fromfunc)
92
printf("Freeing memory for %s, ptr %x\n", fromfunc, lpo);
108
DPRINTF(3, ("Freeing memory for %s, ptr %x\n", fromfunc, lpo));
97
111
HeapFree(hHeapHandle, 0, lpo);
159
bSuccess = GetQueuedCompletionStatus(hIoCompletionPort,
162
& (LPOVERLAPPED) lpo,
185
bSuccess = GetQueuedCompletionStatus(
189
(LPOVERLAPPED *) &lpo,
168
printf("Overlapped IO Thread Exits: \n");
193
DPRINTF(2, ("Overlapped IO Thread Exiting\n"));
171
194
break; /* fail */
175
198
* Deal with errors
180
204
errstatus = GetLastError();
181
if (BytesTransferred == 0 && errstatus == WSA_OPERATION_ABORTED)
205
if (BytesTransferred == 0)
185
printf("Transfer Operation aborted\n");
207
if (WSA_OPERATION_ABORTED == errstatus) {
208
DPRINTF(4, ("Transfer Operation aborted\n"));
209
} else if (ERROR_UNEXP_NET_ERR == errstatus) {
211
* We get this error when trying to send an the network
212
* interface is gone or has lost link. Rescan interfaces
213
* to catch on sooner, but no more than once per minute.
214
* Once ntp is able to detect changes without polling
215
* this should be unneccessary
217
if (time_next_ifscan_after_error < current_time) {
218
time_next_ifscan_after_error = current_time + 60;
219
timer_interfacetimeout(current_time);
221
DPRINTF(4, ("sendto unexpected network error, interface may be down\n"));
191
msyslog(LOG_ERR, "Error transferring packet after %d bytes: %m", BytesTransferred);
226
msyslog(LOG_ERR, "sendto error after %d bytes: %m", BytesTransferred);
199
234
switch(lpo->request_type)
202
OnIoReadComplete(Key, lpo, BytesTransferred, errstatus);
237
OnSerialWaitComplete(Key, lpo, BytesTransferred, errstatus);
240
OnSerialReadComplete(Key, lpo, BytesTransferred, errstatus);
205
243
OnSocketRecv(Key, lpo, BytesTransferred, errstatus);
209
247
OnWriteComplete(Key, lpo, BytesTransferred, errstatus);
214
printf("Unknown request type %d found in completion port\n",
250
DPRINTF(1, ("Unknown request type %d found in completion port\n",
223
259
/* Create/initialise the I/O creation port
294
static int QueueIORead( struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo) {
296
lpo->request_type = CLOCK_READ;
341
static int QueueSerialWait(struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp)
343
lpo->request_type = SERIAL_WAIT;
297
344
lpo->recv_buf = buff;
300
if (!ReadFile((HANDLE) buff->fd, buff->wsabuff.buf, buff->wsabuff.len, NULL, (LPOVERLAPPED) lpo)) {
301
DWORD Result = GetLastError();
304
case ERROR_HANDLE_EOF :
305
case ERROR_IO_PENDING :
309
* Something bad happened
347
memset(&buff->recv_time, 0, sizeof(buff->recv_time));
349
buff->fd = _get_osfhandle(rio->fd);
350
if (!WaitCommEvent((HANDLE) buff->fd, (DWORD *)&buff->recv_buffer, (LPOVERLAPPED) lpo)) {
351
if (ERROR_IO_PENDING != GetLastError()) {
352
msyslog(LOG_ERR, "Can't wait on Refclock: %m");
362
OnSerialWaitComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
365
struct refclockio * rio = (struct refclockio *) i;
370
static const l_fp zero_time = { 0 };
371
DWORD dwBytesReturned;
374
get_systime(&arrival_time);
377
* Get the recvbuf pointer from the overlapped buffer.
379
buff = lpo->recv_buf;
380
comm_mask = (*(DWORD *)&buff->recv_buffer);
382
if (errstatus || comm_mask & ~(EV_RXFLAG | EV_RLSD)) {
383
msyslog(LOG_ERR, "WaitCommEvent returned unexpected mask %x errstatus %d",
384
comm_mask, errstatus);
388
if (comm_mask & EV_RLSD) {
390
GetCommModemStatus((HANDLE)buff->fd, &modem_status);
391
if (modem_status & MS_RLSD_ON) {
393
* Use the timestamp from this PPS CD not
394
* the later end of line.
396
buff->recv_time = arrival_time;
399
if (!(comm_mask & EV_RXFLAG)) {
401
* if we didn't see an end of line yet
402
* issue another wait for it.
404
QueueSerialWait(rio, buff, lpo, FALSE);
410
* We've detected the end of line of serial input.
411
* Use this timestamp unless we already have a CD PPS
412
* timestamp in buff->recv_time.
414
if (memcmp(&buff->recv_time, &zero_time, sizeof buff->recv_time)) {
416
* We will first see a user PPS timestamp here on either
417
* the first or second line of text. Log a one-time
418
* message while processing the second line.
420
if (1 == rio->recvcount) {
421
pp = (struct peer *)rio->srcclock;
422
msyslog(LOG_NOTICE, "Using user-mode PPS timestamp for %s",
423
refnumtoa(&pp->srcadr));
426
buff->recv_time = arrival_time;
430
* Now that we have a complete line waiting, read it.
431
* There is still a race here, but we're likely to win.
434
lpo->request_type = SERIAL_READ;
443
if (!rc && ERROR_IO_PENDING != GetLastError()) {
312
444
msyslog(LOG_ERR, "Can't read from Refclock: %m");
313
445
freerecvbuf(buff);
322
452
/* Return 1 on Successful Read */
324
OnIoReadComplete(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
454
OnSerialReadComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
328
457
struct refclockio * rio = (struct refclockio *) i;
331
get_systime(&arrival_time);
334
460
* Get the recvbuf pointer from the overlapped buffer.
336
buff = (recvbuf_t *) lpo->recv_buf;
462
buff = lpo->recv_buf;
338
* Get a new recv buffer for the next packet
465
* ignore 0 bytes read due to timeout's and closure on fd
340
newbuff = get_free_recv_buffer_alloc();
341
if (newbuff == NULL) {
343
* recv buffers not available so we drop the packet
344
* and reuse the buffer.
351
* ignore 0 bytes read due to timeout's and closure on fd
353
if (Bytes > 0 && errstatus != WSA_OPERATION_ABORTED) {
354
memcpy(&buff->recv_time, &arrival_time, sizeof(arrival_time));
355
buff->recv_length = (int) Bytes;
356
buff->receiver = rio->clock_recv;
358
buff->recv_srcclock = rio->srcclock;
467
if (!errstatus && Bytes) {
468
buff->recv_length = (int) Bytes;
469
buff->receiver = rio->clock_recv;
471
buff->recv_srcclock = rio->srcclock;
474
* Eat the first line of input as it's possibly
475
* partial and if a PPS is present, it may not
476
* have fired since the port was opened.
478
if (rio->recvcount++) {
359
479
add_full_recv_buffer(buff);
360
if( !SetEvent( WaitableIoEventHandle ) ) {
363
printf( "Error %d setting IoEventHandle\n", GetLastError() );
481
* Now signal we have something to process
483
SetEvent(WaitableIoEventHandle);
484
buff = get_free_recv_buffer_alloc();
374
QueueIORead( rio, newbuff, lpo );
488
QueueSerialWait(rio, buff, lpo, TRUE);
508
* Get a new recv buffer for the next packet
618
* Get a new recv buffer for the replacement socket receive
510
620
newbuff = get_free_recv_buffer_alloc();
511
if (newbuff == NULL) {
513
* recv buffers not available so we drop the packet
514
* and reuse the buffer.
520
ignore_this = inter->ignore_packets;
523
* If we keep it add some info to the structure
525
if (Bytes > 0 && ignore_this == ISC_FALSE) {
526
memcpy(&buff->recv_time, &arrival_time, sizeof(arrival_time));
527
buff->recv_length = (int) Bytes;
528
buff->receiver = receive;
529
buff->dstadr = inter;
532
printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr));
534
add_full_recv_buffer(buff);
536
* Now signal we have something to process
538
if( !SetEvent( WaitableIoEventHandle ) ) {
541
printf( "Error %d setting IoEventHandle\n", GetLastError() );
551
QueueSocketRecv(inter->fd, newbuff, lpo);
621
QueueSocketRecv(inter->fd, newbuff, lpo);
623
ignore_this = inter->ignore_packets;
626
* If we keep it add some info to the structure
628
if (Bytes > 0 && ignore_this == ISC_FALSE) {
629
memcpy(&buff->recv_time, &arrival_time, sizeof buff->recv_time);
630
buff->recv_length = (int) Bytes;
631
buff->receiver = receive;
632
buff->dstadr = inter;
635
printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr));
639
add_full_recv_buffer(buff);
641
* Now signal we have something to process
643
SetEvent(WaitableIoEventHandle);
556
/* Add a socket handle to the I/O completion port, and send an I/O
557
* read request to the kernel.
559
* Note: As per the winsock documentation, we use WSARecvFrom. Using
560
* ReadFile() is less efficient.
652
/* Add a socket handle to the I/O completion port, and send
653
* NTP_RECVS_PER_SOCKET recv requests to the kernel.
563
656
io_completion_port_add_socket(SOCKET fd, struct interface *inter)
565
658
IoCompletionInfo *lpo;
568
662
if (fd != INVALID_SOCKET) {
569
663
if (NULL == CreateIoCompletionPort((HANDLE) fd, hIoCompletionPort,
576
lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket");
579
msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
583
buff = get_free_recv_buffer_alloc();
587
msyslog(LOG_ERR, "Can't allocate memory for network socket: %m");
588
FreeHeap(lpo, "io_completion_port_add_socket");
592
QueueSocketRecv(fd, buff, lpo);
671
* Windows 2000 bluescreens with bugcheck 0x76
672
* PROCESS_HAS_LOCKED_PAGES at ntpd process
673
* termination when using more than one pending
674
* receive per socket. A runtime version test
675
* would allow using more on newer versions
679
#define WINDOWS_RECVS_PER_SOCKET 1
681
for (n = 0; n < WINDOWS_RECVS_PER_SOCKET; n++) {
683
buff = get_free_recv_buffer_alloc();
684
lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket");
687
msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
691
QueueSocketRecv(fd, buff, lpo);
597
OnWriteComplete(DWORD Key, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
698
OnWriteComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
599
700
transmitbuf_t *buff;
701
struct interface *inter;
703
/* UNUSED_ARG(Bytes); */
603
705
buff = lpo->trans_buf;
605
707
free_trans_buf(buff);
709
if (SOCK_SEND == lpo->request_type) {
711
case WSA_OPERATION_ABORTED:
716
inter = (struct interface *)i;
607
723
if (errstatus == WSA_OPERATION_ABORTED)
608
724
FreeHeap(lpo, "OnWriteComplete: Socket Closed");
813
* async_write, clone of write(), used by some reflock drivers
697
io_completion_port_write(
703
transmitbuf_t *buff = NULL;
704
DWORD lpNumberOfBytesWritten;
705
DWORD Result = ERROR_INSUFFICIENT_BUFFER;
706
822
IoCompletionInfo *lpo;
708
lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_write");
711
return ERROR_OUTOFMEMORY;
713
if (len <= sizeof(buff->pkt)) {
714
buff = get_trans_buf();
825
if (count > sizeof buff->pkt) {
828
printf("async_write: %d bytes too large, limit is %d\n",
829
count, sizeof buff->pkt);
837
buff = get_trans_buf();
838
lpo = (IoCompletionInfo *) GetHeapAlloc("async_write");
840
if (! buff || ! lpo) {
842
free_trans_buf(buff);
845
printf("async_write: out of memory, \n");
716
848
msyslog(LOG_ERR, "No more transmit buffers left - data discarded");
717
FreeHeap(lpo, "io_completion_port_write");
720
lpo->request_type = CLOCK_WRITE;
721
lpo->trans_buf = buff;
722
memcpy(&buff->pkt, pkt, len);
724
Result = WriteFile(fd, buff->pkt, len, &lpNumberOfBytesWritten, (LPOVERLAPPED) lpo);
726
if(Result == SOCKET_ERROR)
728
errval = WSAGetLastError();
732
case WSA_IO_INCOMPLETE :
733
case WSA_WAIT_IO_COMPLETION :
734
case WSA_IO_PENDING :
735
Result = ERROR_SUCCESS;
739
netsyslog(LOG_ERR, "WriteFile - error sending message: %m");
740
free_trans_buf(buff);
741
FreeHeap(lpo, "io_completion_port_write");
747
printf("WriteFile - %d bytes %d\n", len, Result);
750
if (Result) return len;
754
if (debug) printf("Packet too large: %d Bytes\n", len);
855
lpo->request_type = SERIAL_WRITE;
856
lpo->trans_buf = buff;
857
memcpy(&buff->pkt, data, count);
859
if (! WriteFile((HANDLE)_get_osfhandle(fd), buff->pkt, count, &BytesWritten, (LPOVERLAPPED) lpo) &&
860
ERROR_IO_PENDING != GetLastError()) {
862
msyslog(LOG_ERR, "async_write - error %m");
863
free_trans_buf(buff);
864
FreeHeap(lpo, "async_write");
761
874
* GetReceivedBuffers
762
875
* Note that this is in effect the main loop for processing requests