~ubuntu-branches/debian/squeeze/ntp/squeeze-201010051545

« back to all changes in this revision

Viewing changes to ports/winnt/ntpd/ntp_iocompletionport.c

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2009-11-26 22:16:37 UTC
  • mfrom: (1.2.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20091126221637-lbtdp0ax1yg9t0bx
Tags: 1:4.2.4p7+dfsg-4
* Use uname -s instead of dpkg-architecture to found the kernel we're
  running on.  dpkg-architecture is part of dpkg-dev. (Closes: #558145)
* Make the package fail to build on hurd since it does not provided
  the needed system calls for ntpd to work.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
#include "transmitbuff.h"
19
19
#include "ntp_request.h"
20
20
#include "ntp_io.h"
 
21
#include "clockstuff.h"
21
22
 
22
23
/*
23
24
 * Request types
25
26
enum {
26
27
        SOCK_RECV,
27
28
        SOCK_SEND,
28
 
        CLOCK_READ,
29
 
        CLOCK_WRITE
 
29
        SERIAL_WAIT,
 
30
        SERIAL_READ,
 
31
        SERIAL_WRITE
30
32
};
31
33
 
32
34
 
42
44
#define recv_buf        buff_space.rbuf
43
45
#define trans_buf       buff_space.tbuf
44
46
 
 
47
 
 
48
#if !defined( _W64 )
 
49
  /*
 
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
 
53
   * a replacement.
 
54
   */
 
55
  typedef DWORD ULONG_PTR;
 
56
#endif
 
57
 
45
58
/*
46
59
 * local function definitions
47
60
 */
48
 
static int QueueIORead( struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo);
49
 
 
50
 
static int OnSocketRecv(DWORD, IoCompletionInfo *, DWORD, int);
51
 
static int OnIoReadComplete(DWORD, IoCompletionInfo *, DWORD, int);
52
 
static int OnWriteComplete(DWORD, IoCompletionInfo *, DWORD, int);
53
 
 
 
61
static int QueueSerialWait(struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp);
 
62
 
 
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);
 
67
 
 
68
/* #define USE_HEAP */
 
69
 
 
70
#ifdef USE_HEAP
54
71
static HANDLE hHeapHandle = NULL;
 
72
#endif
55
73
 
56
74
static HANDLE hIoCompletionPort = NULL;
57
75
 
58
76
static HANDLE WaitableIoEventHandle = NULL;
59
77
static HANDLE WaitableExitEventHandle = NULL;
60
78
 
 
79
#ifdef NTPNEEDNAMEDHANDLE
 
80
#define WAITABLEIOEVENTHANDLE "WaitableIoEventHandle"
 
81
#else
 
82
#define WAITABLEIOEVENTHANDLE NULL
 
83
#endif
 
84
 
61
85
#define MAXHANDLES 3
62
86
HANDLE WaitHandles[MAXHANDLES] = { NULL, NULL, NULL };
63
87
 
64
 
#define USE_HEAP
65
 
 
66
88
IoCompletionInfo *
67
89
GetHeapAlloc(char *fromfunc)
68
90
{
73
95
                             HEAP_ZERO_MEMORY,
74
96
                             sizeof(IoCompletionInfo));
75
97
#else
76
 
        lpo = (IoCompletionInfo *) calloc(1, sizeof(IoCompletionInfo));
77
 
#endif
78
 
#ifdef DEBUG
79
 
        if (debug > 3) {
80
 
                printf("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo);
81
 
        }
82
 
#endif
 
98
        lpo = (IoCompletionInfo *) calloc(1, sizeof(*lpo));
 
99
#endif
 
100
        DPRINTF(3, ("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo));
 
101
 
83
102
        return (lpo);
84
103
}
85
104
 
86
105
void
87
106
FreeHeap(IoCompletionInfo *lpo, char *fromfunc)
88
107
{
89
 
#ifdef DEBUG
90
 
        if (debug > 3)
91
 
        {
92
 
                printf("Freeing memory for %s, ptr %x\n", fromfunc, lpo);
93
 
        }
94
 
#endif
 
108
        DPRINTF(3, ("Freeing memory for %s, ptr %x\n", fromfunc, lpo));
95
109
 
96
110
#ifdef USE_HEAP
97
111
        HeapFree(hHeapHandle, 0, lpo);
103
117
transmitbuf_t *
104
118
get_trans_buf()
105
119
{
106
 
        transmitbuf_t *tb  = calloc(sizeof(transmitbuf_t), 1);
 
120
        transmitbuf_t *tb  = (transmitbuf_t *) emalloc(sizeof(transmitbuf_t));
107
121
        tb->wsabuf.len = 0;
108
122
        tb->wsabuf.buf = (char *) &tb->pkt;
109
123
        return (tb);
138
152
        }
139
153
}
140
154
 
141
 
static void
 
155
static unsigned WINAPI
142
156
iocompletionthread(void *NotUsed)
143
157
{
144
158
        BOOL bSuccess = FALSE;
145
159
        int errstatus = 0;
146
160
        DWORD BytesTransferred = 0;
147
 
        DWORD Key = 0;
 
161
        ULONG_PTR Key = 0;
148
162
        IoCompletionInfo * lpo = NULL;
 
163
        u_long time_next_ifscan_after_error = 0;
 
164
 
 
165
        /* UNUSED_ARG(NotUsed); */
 
166
 
 
167
        /*
 
168
         *      socket and refclock receive call gettimeofday()
 
169
         *      so the I/O thread needs to be on the same 
 
170
         *      processor as the main and timing threads
 
171
         *      to ensure consistent QueryPerformanceCounter()
 
172
         *      results.
 
173
         */
 
174
        lock_thread_to_processor(GetCurrentThread());
149
175
 
150
176
        /*      Set the thread priority high enough so I/O will
151
177
         *      preempt normal recv packet processing, but not
156
182
        }
157
183
 
158
184
        while (TRUE) {
159
 
                bSuccess = GetQueuedCompletionStatus(hIoCompletionPort, 
160
 
                                          &BytesTransferred, 
161
 
                                          &Key, 
162
 
                                          & (LPOVERLAPPED) lpo, 
163
 
                                          INFINITE);
 
185
                bSuccess = GetQueuedCompletionStatus(
 
186
                                        hIoCompletionPort, 
 
187
                                        &BytesTransferred, 
 
188
                                        &Key, 
 
189
                                        (LPOVERLAPPED *) &lpo, 
 
190
                                        INFINITE);
164
191
                if (lpo == NULL)
165
192
                {
166
 
#ifdef DEBUG
167
 
                        if (debug > 2) {
168
 
                                printf("Overlapped IO Thread Exits: \n");
169
 
                        }
170
 
#endif
 
193
                        DPRINTF(2, ("Overlapped IO Thread Exiting\n"));
171
194
                        break; /* fail */
172
195
                }
173
196
                
174
197
                /*
175
198
                 * Deal with errors
176
199
                 */
177
 
                errstatus = 0;
178
 
                if (!bSuccess)
 
200
                if (bSuccess)
 
201
                        errstatus = 0;
 
202
                else
179
203
                {
180
204
                        errstatus = GetLastError();
181
 
                        if (BytesTransferred == 0 && errstatus == WSA_OPERATION_ABORTED)
 
205
                        if (BytesTransferred == 0)
182
206
                        {
183
 
#ifdef DEBUG
184
 
                                if (debug > 2) {
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) {
 
210
                                        /*
 
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
 
216
                                         */
 
217
                                        if (time_next_ifscan_after_error < current_time) {
 
218
                                                time_next_ifscan_after_error = current_time + 60;
 
219
                                                timer_interfacetimeout(current_time);
 
220
                                        }
 
221
                                        DPRINTF(4, ("sendto unexpected network error, interface may be down\n"));
186
222
                                }
187
 
#endif
188
223
                        }
189
224
                        else
190
225
                        {
191
 
                                msyslog(LOG_ERR, "Error transferring packet after %d bytes: %m", BytesTransferred);
 
226
                                msyslog(LOG_ERR, "sendto error after %d bytes: %m", BytesTransferred);
192
227
                        }
193
228
                }
194
229
 
198
233
                 */
199
234
                switch(lpo->request_type)
200
235
                {
201
 
                case CLOCK_READ:
202
 
                        OnIoReadComplete(Key, lpo, BytesTransferred, errstatus);
 
236
                case SERIAL_WAIT:
 
237
                        OnSerialWaitComplete(Key, lpo, BytesTransferred, errstatus);
 
238
                        break;
 
239
                case SERIAL_READ:
 
240
                        OnSerialReadComplete(Key, lpo, BytesTransferred, errstatus);
203
241
                        break;
204
242
                case SOCK_RECV:
205
243
                        OnSocketRecv(Key, lpo, BytesTransferred, errstatus);
206
244
                        break;
207
245
                case SOCK_SEND:
208
 
                case CLOCK_WRITE:
 
246
                case SERIAL_WRITE:
209
247
                        OnWriteComplete(Key, lpo, BytesTransferred, errstatus);
210
248
                        break;
211
249
                default:
212
 
#if DEBUG
213
 
                        if (debug > 2) {
214
 
                                printf("Unknown request type %d found in completion port\n",
215
 
                                        lpo->request_type);
216
 
                        }
217
 
#endif
 
250
                        DPRINTF(1, ("Unknown request type %d found in completion port\n",
 
251
                                    lpo->request_type));
218
252
                        break;
219
253
                }
220
254
        }
 
255
 
 
256
        return 0;
221
257
}
222
258
 
223
259
/*  Create/initialise the I/O creation port
227
263
        void
228
264
        )
229
265
{
 
266
        unsigned tid;
 
267
        HANDLE thread;
230
268
 
 
269
#ifdef USE_HEAP
231
270
        /*
232
271
         * Create a handle to the Heap
233
272
         */
237
276
                msyslog(LOG_ERR, "Can't initialize Heap: %m");
238
277
                exit(1);
239
278
        }
240
 
 
 
279
#endif
241
280
 
242
281
        /* Create the event used to signal an IO event
243
282
         */
244
 
        WaitableIoEventHandle = CreateEvent(NULL, FALSE, FALSE, "WaitableIoEventHandle");
 
283
        WaitableIoEventHandle = CreateEvent(NULL, FALSE, FALSE, WAITABLEIOEVENTHANDLE);
245
284
        if (WaitableIoEventHandle == NULL) {
246
285
                msyslog(LOG_ERR,
247
286
                "Can't create I/O event handle: %m - another process may be running - EXITING");
249
288
        }
250
289
        /* Create the event used to signal an exit event
251
290
         */
252
 
        WaitableExitEventHandle = CreateEvent(NULL, FALSE, FALSE, "WaitableExitEventHandle");
 
291
        WaitableExitEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
253
292
        if (WaitableExitEventHandle == NULL) {
254
293
                msyslog(LOG_ERR,
255
 
                "Can't create exit event handle: %m - another process may be running - EXITING");
 
294
                "Can't create exit event handle: %m - EXITING");
256
295
                exit(1);
257
296
        }
258
297
 
263
302
                msyslog(LOG_ERR, "Can't create I/O completion port: %m");
264
303
                exit(1);
265
304
        }
266
 
        
 
305
 
267
306
        /*
268
307
         * Initialize the Wait Handles
269
308
         */
274
313
        /* Have one thread servicing I/O - there were 4, but this would 
275
314
         * somehow cause NTP to stop replying to ntpq requests; TODO
276
315
         */
277
 
        _beginthread(iocompletionthread, 0, NULL);
 
316
        thread = (HANDLE)_beginthreadex(
 
317
                NULL, 
 
318
                0, 
 
319
                iocompletionthread, 
 
320
                NULL, 
 
321
                CREATE_SUSPENDED, 
 
322
                &tid);
 
323
        ResumeThread(thread);
 
324
        CloseHandle(thread);
278
325
}
279
326
        
280
327
 
291
338
}
292
339
 
293
340
 
294
 
static int QueueIORead( struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo) {
295
 
 
296
 
        lpo->request_type = CLOCK_READ;
 
341
static int QueueSerialWait(struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp)
 
342
{
 
343
        lpo->request_type = SERIAL_WAIT;
297
344
        lpo->recv_buf = buff;
298
345
 
299
 
        buff->fd = rio->fd;
300
 
        if (!ReadFile((HANDLE) buff->fd, buff->wsabuff.buf, buff->wsabuff.len, NULL, (LPOVERLAPPED) lpo)) {
301
 
                DWORD Result = GetLastError();
302
 
                switch (Result) {                               
303
 
                case NO_ERROR :
304
 
                case ERROR_HANDLE_EOF :
305
 
                case ERROR_IO_PENDING :
306
 
                        break ;
307
 
 
308
 
                /*
309
 
                 * Something bad happened
310
 
                 */
311
 
                default:
 
346
        if (clear_timestamp)
 
347
                memset(&buff->recv_time, 0, sizeof(buff->recv_time));
 
348
 
 
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");
 
353
                        freerecvbuf(buff);
 
354
                        return 0;
 
355
                }
 
356
        }
 
357
        return 1;
 
358
}
 
359
 
 
360
 
 
361
static int 
 
362
OnSerialWaitComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 
363
{
 
364
        recvbuf_t *buff;
 
365
        struct refclockio * rio = (struct refclockio *) i;
 
366
        struct peer *pp;
 
367
        l_fp arrival_time;
 
368
        DWORD comm_mask;
 
369
        DWORD modem_status;
 
370
        static const l_fp zero_time = { 0 };
 
371
        DWORD dwBytesReturned;
 
372
        BOOL rc;
 
373
 
 
374
        get_systime(&arrival_time);
 
375
 
 
376
        /*
 
377
         * Get the recvbuf pointer from the overlapped buffer.
 
378
         */
 
379
        buff = lpo->recv_buf;
 
380
        comm_mask = (*(DWORD *)&buff->recv_buffer);
 
381
#ifdef DEBUG
 
382
                if (errstatus || comm_mask & ~(EV_RXFLAG | EV_RLSD)) {
 
383
                        msyslog(LOG_ERR, "WaitCommEvent returned unexpected mask %x errstatus %d",
 
384
                                comm_mask, errstatus);
 
385
                        exit(-1);
 
386
                }
 
387
#endif
 
388
                if (comm_mask & EV_RLSD) { 
 
389
                        modem_status = 0;
 
390
                        GetCommModemStatus((HANDLE)buff->fd, &modem_status);
 
391
                        if (modem_status & MS_RLSD_ON) {
 
392
                                /*
 
393
                                 * Use the timestamp from this PPS CD not
 
394
                                 * the later end of line.
 
395
                                 */
 
396
                                buff->recv_time = arrival_time;
 
397
                        }
 
398
 
 
399
                        if (!(comm_mask & EV_RXFLAG)) {
 
400
                                /*
 
401
                                 * if we didn't see an end of line yet
 
402
                                 * issue another wait for it.
 
403
                                 */
 
404
                                QueueSerialWait(rio, buff, lpo, FALSE);
 
405
                                return 1;
 
406
                        }
 
407
                }
 
408
 
 
409
                /*
 
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.
 
413
                 */
 
414
                if (memcmp(&buff->recv_time, &zero_time, sizeof buff->recv_time)) {
 
415
                        /*
 
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.
 
419
                         */
 
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));
 
424
                        }
 
425
                } else {
 
426
                        buff->recv_time = arrival_time;
 
427
                }
 
428
 
 
429
                /*
 
430
                 * Now that we have a complete line waiting, read it.
 
431
                 * There is still a race here, but we're likely to win.
 
432
                 */
 
433
 
 
434
                lpo->request_type = SERIAL_READ;
 
435
 
 
436
                rc = ReadFile(
 
437
                        (HANDLE)buff->fd,
 
438
                        buff->wsabuff.buf,
 
439
                        buff->wsabuff.len,
 
440
                        &buff->wsabuff.len,
 
441
                        (LPOVERLAPPED) lpo);
 
442
 
 
443
                if (!rc && ERROR_IO_PENDING != GetLastError()) {
312
444
                        msyslog(LOG_ERR, "Can't read from Refclock: %m");
313
445
                        freerecvbuf(buff);
314
446
                        return 0;
315
447
                }
316
 
        }
 
448
 
317
449
        return 1;
318
450
}
319
451
 
320
 
 
321
 
 
322
452
/* Return 1 on Successful Read */
323
453
static int 
324
 
OnIoReadComplete(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 
454
OnSerialReadComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
325
455
{
326
456
        recvbuf_t *buff;
327
 
        recvbuf_t *newbuff;
328
457
        struct refclockio * rio = (struct refclockio *) i;
329
 
        l_fp arrival_time;
330
 
 
331
 
        get_systime(&arrival_time);
332
458
 
333
459
        /*
334
460
         * Get the recvbuf pointer from the overlapped buffer.
335
461
         */
336
 
        buff = (recvbuf_t *) lpo->recv_buf;
 
462
        buff = lpo->recv_buf;
 
463
 
337
464
        /*
338
 
         * Get a new recv buffer for the next packet
 
465
         * ignore 0 bytes read due to timeout's and closure on fd
339
466
         */
340
 
        newbuff = get_free_recv_buffer_alloc();
341
 
        if (newbuff == NULL) {
342
 
                /*
343
 
                 * recv buffers not available so we drop the packet
344
 
                 * and reuse the buffer.
345
 
                 */
346
 
                newbuff = buff;
347
 
        }
348
 
        else 
349
 
        {
350
 
                /*
351
 
                 * ignore 0 bytes read due to timeout's and closure on fd
352
 
                 */
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;
357
 
                        buff->dstadr = NULL;
358
 
                        buff->recv_srcclock = rio->srcclock;
 
467
        if (!errstatus && Bytes) {
 
468
                buff->recv_length = (int) Bytes;
 
469
                buff->receiver = rio->clock_recv;
 
470
                buff->dstadr = NULL;
 
471
                buff->recv_srcclock = rio->srcclock;
 
472
                packets_received++;
 
473
                /*
 
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.
 
477
                 */
 
478
                if (rio->recvcount++) {
359
479
                        add_full_recv_buffer(buff);
360
 
                        if( !SetEvent( WaitableIoEventHandle ) ) {
361
 
#ifdef DEBUG
362
 
                                if (debug > 3) {
363
 
                                        printf( "Error %d setting IoEventHandle\n", GetLastError() );
364
 
                                }
365
 
#endif
366
 
                        }
367
 
                }
368
 
                else
369
 
                {
370
 
                        freerecvbuf(buff);
 
480
                        /*
 
481
                         * Now signal we have something to process
 
482
                         */
 
483
                        SetEvent(WaitableIoEventHandle);
 
484
                        buff = get_free_recv_buffer_alloc();
371
485
                }
372
486
        }
373
487
 
374
 
        QueueIORead( rio, newbuff, lpo );
 
488
        QueueSerialWait(rio, buff, lpo, TRUE);
 
489
 
375
490
        return 1;
376
491
}
377
492
 
386
501
        IoCompletionInfo *lpo;
387
502
        recvbuf_t *buff;
388
503
 
389
 
        if (NULL == CreateIoCompletionPort((HANDLE) rio->fd, hIoCompletionPort, (DWORD) rio, 0)) {
 
504
        if (NULL == CreateIoCompletionPort((HANDLE)_get_osfhandle(rio->fd), hIoCompletionPort, (ULONG_PTR) rio, 0)) {
390
505
                msyslog(LOG_ERR, "Can't add COM port to i/o completion port: %m");
391
506
                return 1;
392
507
        }
399
514
        }
400
515
 
401
516
        buff = get_free_recv_buffer_alloc();
402
 
 
403
 
        if (buff == NULL)
404
 
        {
405
 
                msyslog(LOG_ERR, "Can't allocate memory for clock socket: %m");
406
 
                FreeHeap(lpo, "io_completion_port_add_clock_io");
407
 
                return 1;
408
 
        }
409
 
        QueueIORead( rio, buff, lpo );
 
517
        QueueSerialWait(rio, buff, lpo, TRUE);
410
518
        return 0;
411
519
}
412
520
 
413
 
/* Queue a receiver on a socket. Returns 0 if no buffer can be queued */
414
 
 
 
521
/*
 
522
 * Queue a receiver on a socket. Returns 0 if no buffer can be queued 
 
523
 *
 
524
 *  Note: As per the winsock documentation, we use WSARecvFrom. Using
 
525
 *        ReadFile() is less efficient.
 
526
 */
415
527
static unsigned long QueueSocketRecv(SOCKET s, recvbuf_t *buff, IoCompletionInfo *lpo) {
416
528
        
417
529
        int AddrLen;
433
545
                        DWORD Result = WSAGetLastError();
434
546
                        switch (Result) {
435
547
                                case NO_ERROR :
436
 
                                case WSA_IO_INCOMPLETE :
437
 
                                case WSA_WAIT_IO_COMPLETION :
438
548
                                case WSA_IO_PENDING :
439
549
                                        break ;
440
550
 
465
575
 
466
576
/* Returns 0 if any Error */
467
577
static int 
468
 
OnSocketRecv(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 
578
OnSocketRecv(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
469
579
{
470
580
        struct recvbuf *buff = NULL;
471
581
        recvbuf_t *newbuff;
473
583
        l_fp arrival_time;
474
584
        struct interface * inter = (struct interface *) i;
475
585
        
476
 
        get_systime(&arrival_time);     
 
586
        get_systime(&arrival_time);
477
587
 
478
588
        /*  Convert the overlapped pointer back to a recvbuf pointer.
479
589
        */
505
615
 
506
616
 
507
617
        /*
508
 
         * Get a new recv buffer for the next packet
 
618
         * Get a new recv buffer for the replacement socket receive
509
619
         */
510
620
        newbuff = get_free_recv_buffer_alloc();
511
 
        if (newbuff == NULL) {
512
 
                /*
513
 
                 * recv buffers not available so we drop the packet
514
 
                 * and reuse the buffer.
515
 
                 */
516
 
                newbuff = buff;
517
 
        }
518
 
        else 
519
 
        {
520
 
                ignore_this = inter->ignore_packets;
521
 
 
522
 
                /*
523
 
                 * If we keep it add some info to the structure
524
 
                 */
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;
530
 
#ifdef DEBUG
531
 
                        if (debug > 1)
532
 
                                printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr));
533
 
#endif
534
 
                        add_full_recv_buffer(buff);
535
 
                        /*
536
 
                         * Now signal we have something to process
537
 
                         */
538
 
                        if( !SetEvent( WaitableIoEventHandle ) ) {
539
 
#ifdef DEBUG
540
 
                                if (debug > 1) {
541
 
                                        printf( "Error %d setting IoEventHandle\n", GetLastError() );
542
 
                                }
543
 
#endif
544
 
                        }
545
 
                }
546
 
                else {
547
 
                        freerecvbuf(buff);
548
 
                }
549
 
        }
550
 
        if (newbuff != NULL)
551
 
                QueueSocketRecv(inter->fd, newbuff, lpo);
 
621
        QueueSocketRecv(inter->fd, newbuff, lpo);
 
622
 
 
623
        ignore_this = inter->ignore_packets;
 
624
 
 
625
        /*
 
626
         * If we keep it add some info to the structure
 
627
         */
 
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;
 
633
#ifdef DEBUG
 
634
                if (debug > 1)
 
635
                        printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr));
 
636
#endif
 
637
                packets_received++;
 
638
                inter->received++;
 
639
                add_full_recv_buffer(buff);
 
640
                /*
 
641
                 * Now signal we have something to process
 
642
                 */
 
643
                SetEvent(WaitableIoEventHandle);
 
644
        }
 
645
        else
 
646
                freerecvbuf(buff);
 
647
 
552
648
        return 1;
553
649
}
554
650
 
555
651
 
556
 
/*  Add a socket handle to the I/O completion port, and send an I/O
557
 
 *  read request to the kernel.
558
 
 *
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.
561
654
 */
562
655
extern int
563
656
io_completion_port_add_socket(SOCKET fd, struct interface *inter)
564
657
{
565
658
        IoCompletionInfo *lpo;
566
659
        recvbuf_t *buff;
 
660
        int n;
567
661
 
568
662
        if (fd != INVALID_SOCKET) {
569
663
                if (NULL == CreateIoCompletionPort((HANDLE) fd, hIoCompletionPort,
573
667
                }
574
668
        }
575
669
 
576
 
        lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket");
577
 
        if (lpo == NULL)
578
 
        {
579
 
                msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
580
 
                return 1;
581
 
        }
582
 
 
583
 
        buff = get_free_recv_buffer_alloc();
584
 
 
585
 
        if (buff == NULL)
586
 
        {
587
 
                msyslog(LOG_ERR, "Can't allocate memory for network socket: %m");
588
 
                FreeHeap(lpo, "io_completion_port_add_socket");
589
 
                return 1;
590
 
        }
591
 
 
592
 
        QueueSocketRecv(fd, buff, lpo);
 
670
        /*
 
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
 
676
         * of Windows.
 
677
         */
 
678
 
 
679
#define WINDOWS_RECVS_PER_SOCKET 1
 
680
 
 
681
        for (n = 0; n < WINDOWS_RECVS_PER_SOCKET; n++) {
 
682
 
 
683
                buff = get_free_recv_buffer_alloc();
 
684
                lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket");
 
685
                if (lpo == NULL)
 
686
                {
 
687
                        msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
 
688
                        return 1;
 
689
                }
 
690
 
 
691
                QueueSocketRecv(fd, buff, lpo);
 
692
 
 
693
        }
593
694
        return 0;
594
695
}
595
696
 
596
697
static int 
597
 
OnWriteComplete(DWORD Key, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 
698
OnWriteComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
598
699
{
599
700
        transmitbuf_t *buff;
600
 
        (void) Bytes;
601
 
        (void) Key;
 
701
        struct interface *inter;
 
702
 
 
703
        /* UNUSED_ARG(Bytes); */
602
704
 
603
705
        buff = lpo->trans_buf;
604
706
 
605
707
        free_trans_buf(buff);
606
708
 
 
709
        if (SOCK_SEND == lpo->request_type) {
 
710
                switch (errstatus) {
 
711
                case WSA_OPERATION_ABORTED:
 
712
                case NO_ERROR:
 
713
                        break;
 
714
 
 
715
                default:
 
716
                        inter = (struct interface *)i;
 
717
                        packets_notsent++;
 
718
                        inter->notsent++;
 
719
                        break;
 
720
                }
 
721
        }
 
722
 
607
723
        if (errstatus == WSA_OPERATION_ABORTED)
608
724
                FreeHeap(lpo, "OnWriteComplete: Socket Closed");
609
725
        else
612
728
}
613
729
 
614
730
 
615
 
DWORD   
 
731
/*
 
732
 * Return value is really GetLastError-style error code
 
733
 * which is a DWORD but using int, which is large enough,
 
734
 * decreases #ifdef forest in ntp_io.c harmlessly.
 
735
 */
 
736
int     
616
737
io_completion_port_sendto(
617
738
        struct interface *inter,        
618
739
        struct pkt *pkt,        
659
780
                        switch (errval) {
660
781
 
661
782
                        case NO_ERROR :
662
 
                        case WSA_IO_INCOMPLETE :
663
 
                        case WSA_WAIT_IO_COMPLETION :
664
783
                        case WSA_IO_PENDING :
665
784
                                Result = ERROR_SUCCESS;
666
785
                                break ;
691
810
 
692
811
 
693
812
/*
694
 
 * Async IO Write
 
813
 * async_write, clone of write(), used by some reflock drivers
695
814
 */
696
 
DWORD   
697
 
io_completion_port_write(
698
 
        HANDLE fd,      
699
 
        char *pkt,      
700
 
        int len)
 
815
int     
 
816
async_write(
 
817
        int fd,
 
818
        const void *data,
 
819
        unsigned int count)
701
820
{
702
 
        DWORD errval;
703
 
        transmitbuf_t *buff = NULL;
704
 
        DWORD lpNumberOfBytesWritten;
705
 
        DWORD Result = ERROR_INSUFFICIENT_BUFFER;
 
821
        transmitbuf_t *buff;
706
822
        IoCompletionInfo *lpo;
707
 
 
708
 
        lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_write");
709
 
 
710
 
        if (lpo == NULL)
711
 
                return ERROR_OUTOFMEMORY;
712
 
 
713
 
        if (len <= sizeof(buff->pkt)) {
714
 
                buff = get_trans_buf();
715
 
                if (buff == NULL) {
 
823
        DWORD BytesWritten;
 
824
 
 
825
        if (count > sizeof buff->pkt) {
 
826
#ifdef DEBUG
 
827
                if (debug) {
 
828
                        printf("async_write: %d bytes too large, limit is %d\n",
 
829
                                count, sizeof buff->pkt);
 
830
                        exit(-1);
 
831
                }
 
832
#endif
 
833
                errno = ENOMEM;
 
834
                return -1;
 
835
        }
 
836
 
 
837
        buff = get_trans_buf();
 
838
        lpo = (IoCompletionInfo *) GetHeapAlloc("async_write");
 
839
 
 
840
        if (! buff || ! lpo) {
 
841
                if (buff) {
 
842
                        free_trans_buf(buff);
 
843
#ifdef DEBUG
 
844
                        if (debug)
 
845
                                printf("async_write: out of memory, \n");
 
846
#endif
 
847
                } else {
716
848
                        msyslog(LOG_ERR, "No more transmit buffers left - data discarded");
717
 
                        FreeHeap(lpo, "io_completion_port_write");
718
 
                }
719
 
 
720
 
                lpo->request_type = CLOCK_WRITE;
721
 
                lpo->trans_buf = buff;
722
 
                memcpy(&buff->pkt, pkt, len);
723
 
 
724
 
                Result = WriteFile(fd, buff->pkt, len, &lpNumberOfBytesWritten, (LPOVERLAPPED) lpo);
725
 
 
726
 
                if(Result == SOCKET_ERROR)
727
 
                {
728
 
                        errval = WSAGetLastError();
729
 
                        switch (errval) {
730
 
 
731
 
                        case NO_ERROR :
732
 
                        case WSA_IO_INCOMPLETE :
733
 
                        case WSA_WAIT_IO_COMPLETION :
734
 
                        case WSA_IO_PENDING :
735
 
                                Result = ERROR_SUCCESS;
736
 
                                break ;
737
 
 
738
 
                        default :
739
 
                                netsyslog(LOG_ERR, "WriteFile - error sending message: %m");
740
 
                                free_trans_buf(buff);
741
 
                                FreeHeap(lpo, "io_completion_port_write");
742
 
                                break;
743
 
                        }
744
 
                }
745
 
#ifdef DEBUG
746
 
                        if (debug > 2) {
747
 
                                printf("WriteFile - %d bytes %d\n", len, Result);
748
 
                        }
749
 
#endif
750
 
                        if (Result) return len;
751
 
        }
752
 
        else {
753
 
#ifdef DEBUG
754
 
                if (debug) printf("Packet too large: %d Bytes\n", len);
755
 
#endif
756
 
        }
757
 
        return Result;
 
849
                }
 
850
 
 
851
                errno = ENOMEM;
 
852
                return -1;
 
853
        }
 
854
 
 
855
        lpo->request_type = SERIAL_WRITE;
 
856
        lpo->trans_buf = buff;
 
857
        memcpy(&buff->pkt, data, count);
 
858
 
 
859
        if (! WriteFile((HANDLE)_get_osfhandle(fd), buff->pkt, count, &BytesWritten, (LPOVERLAPPED) lpo) &&
 
860
                ERROR_IO_PENDING != GetLastError()) {
 
861
 
 
862
                msyslog(LOG_ERR, "async_write - error %m");
 
863
                free_trans_buf(buff);
 
864
                FreeHeap(lpo, "async_write");
 
865
                errno = EBADF;
 
866
                return -1;
 
867
        }
 
868
 
 
869
        return count;
758
870
}
759
871
 
 
872
 
760
873
/*
761
874
 * GetReceivedBuffers
762
875
 * Note that this is in effect the main loop for processing requests