Annotation of embedaddon/ntp/ports/winnt/ntpd/ntp_iocompletionport.c, revision 1.1

1.1     ! misho       1: #ifdef HAVE_CONFIG_H
        !             2: # include <config.h>
        !             3: #endif
        !             4: 
        !             5: #if defined (HAVE_IO_COMPLETION_PORT)
        !             6: 
        !             7: #include <stddef.h>
        !             8: #include <stdio.h>
        !             9: #include <process.h>
        !            10: #include <syslog.h>
        !            11: 
        !            12: #include "ntp_stdlib.h"
        !            13: #include "ntp_machine.h"
        !            14: #include "ntp_fp.h"
        !            15: #include "ntp.h"
        !            16: #include "ntpd.h"
        !            17: #include "ntp_refclock.h"
        !            18: #include "ntp_iocompletionport.h"
        !            19: #include "transmitbuff.h"
        !            20: #include "ntp_request.h"
        !            21: #include "ntp_assert.h"
        !            22: #include "clockstuff.h"
        !            23: #include "ntp_io.h"
        !            24: #include "ntp_lists.h"
        !            25: #include "clockstuff.h"
        !            26: 
        !            27: /*
        !            28:  * Request types
        !            29:  */
        !            30: enum {
        !            31:        SOCK_RECV,
        !            32:        SOCK_SEND,
        !            33:        SERIAL_WAIT,
        !            34:        SERIAL_READ,
        !            35:        SERIAL_WRITE
        !            36: };
        !            37: 
        !            38: #ifdef _MSC_VER
        !            39: # pragma warning(push)
        !            40: # pragma warning(disable: 201)         /* nonstd extension nameless union */
        !            41: #endif
        !            42: 
        !            43: typedef struct IoCompletionInfo {
        !            44:        OVERLAPPED              overlapped;     /* must be first */
        !            45:        int                     request_type;
        !            46:        union {
        !            47:                recvbuf_t *     recv_buf;
        !            48:                transmitbuf_t * trans_buf;
        !            49:        };
        !            50: #ifdef DEBUG
        !            51:        struct IoCompletionInfo *link;
        !            52: #endif
        !            53: } IoCompletionInfo;
        !            54: 
        !            55: #ifdef _MSC_VER
        !            56: # pragma warning(pop)
        !            57: #endif
        !            58: 
        !            59: /*
        !            60:  * local function definitions
        !            61:  */
        !            62: static int QueueSerialWait(struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp);
        !            63: 
        !            64: static int OnSocketRecv(ULONG_PTR, IoCompletionInfo *, DWORD, int);
        !            65: static int OnSerialWaitComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
        !            66: static int OnSerialReadComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
        !            67: static int OnWriteComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int);
        !            68: 
        !            69: /* keep a list to traverse to free memory on debug builds */
        !            70: #ifdef DEBUG
        !            71: static void free_io_completion_port_mem(void);
        !            72: IoCompletionInfo *     compl_info_list;
        !            73: CRITICAL_SECTION       compl_info_lock;
        !            74: #define LOCK_COMPL()   EnterCriticalSection(&compl_info_lock);
        !            75: #define UNLOCK_COMPL() LeaveCriticalSection(&compl_info_lock);
        !            76: #endif
        !            77: 
        !            78: /* #define USE_HEAP */
        !            79: 
        !            80: #ifdef USE_HEAP
        !            81: static HANDLE hHeapHandle = NULL;
        !            82: #endif
        !            83: 
        !            84: static HANDLE hIoCompletionPort = NULL;
        !            85: 
        !            86: static HANDLE WaitableIoEventHandle = NULL;
        !            87: static HANDLE WaitableExitEventHandle = NULL;
        !            88: 
        !            89: #ifdef NTPNEEDNAMEDHANDLE
        !            90: #define WAITABLEIOEVENTHANDLE "WaitableIoEventHandle"
        !            91: #else
        !            92: #define WAITABLEIOEVENTHANDLE NULL
        !            93: #endif
        !            94: 
        !            95: #define MAXHANDLES 3
        !            96: HANDLE WaitHandles[MAXHANDLES] = { NULL, NULL, NULL };
        !            97: 
        !            98: IoCompletionInfo *
        !            99: GetHeapAlloc(char *fromfunc)
        !           100: {
        !           101:        IoCompletionInfo *lpo;
        !           102: 
        !           103: #ifdef USE_HEAP
        !           104:        lpo = HeapAlloc(hHeapHandle,
        !           105:                        HEAP_ZERO_MEMORY,
        !           106:                        sizeof(IoCompletionInfo));
        !           107: #else
        !           108:        lpo = emalloc(sizeof(*lpo));
        !           109:        memset(lpo, 0, sizeof(*lpo));
        !           110: #endif
        !           111:        DPRINTF(3, ("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo));
        !           112: 
        !           113: #ifdef DEBUG
        !           114:        LOCK_COMPL();
        !           115:        LINK_SLIST(compl_info_list, lpo, link);
        !           116:        UNLOCK_COMPL();
        !           117: #endif
        !           118: 
        !           119:        return (lpo);
        !           120: }
        !           121: 
        !           122: void
        !           123: FreeHeap(IoCompletionInfo *lpo, char *fromfunc)
        !           124: {
        !           125: #ifdef DEBUG
        !           126:        IoCompletionInfo *unlinked;
        !           127: 
        !           128:        DPRINTF(3, ("Freeing memory for %s, ptr %x\n", fromfunc, lpo));
        !           129: 
        !           130:        LOCK_COMPL();
        !           131:        UNLINK_SLIST(unlinked, compl_info_list, lpo, link,
        !           132:            IoCompletionInfo);
        !           133:        UNLOCK_COMPL();
        !           134: #endif
        !           135: 
        !           136: #ifdef USE_HEAP
        !           137:        HeapFree(hHeapHandle, 0, lpo);
        !           138: #else
        !           139:        free(lpo);
        !           140: #endif
        !           141: }
        !           142: 
        !           143: transmitbuf_t *
        !           144: get_trans_buf()
        !           145: {
        !           146:        transmitbuf_t *tb  = emalloc(sizeof(*tb));
        !           147:        return (tb);
        !           148: }
        !           149: 
        !           150: void
        !           151: free_trans_buf(transmitbuf_t *tb)
        !           152: {
        !           153:        free(tb);
        !           154: }
        !           155: 
        !           156: HANDLE
        !           157: get_io_event()
        !           158: {
        !           159:        return( WaitableIoEventHandle );
        !           160: }
        !           161: HANDLE
        !           162: get_exit_event()
        !           163: {
        !           164:        return( WaitableExitEventHandle );
        !           165: }
        !           166: 
        !           167: /*  This function will add an entry to the I/O completion port
        !           168:  *  that will signal the I/O thread to exit (gracefully)
        !           169:  */
        !           170: static void
        !           171: signal_io_completion_port_exit()
        !           172: {
        !           173:        if (!PostQueuedCompletionStatus(hIoCompletionPort, 0, 0, 0)) {
        !           174:                msyslog(LOG_ERR, "Can't request service thread to exit: %m");
        !           175:                exit(1);
        !           176:        }
        !           177: }
        !           178: 
        !           179: static unsigned WINAPI
        !           180: iocompletionthread(void *NotUsed)
        !           181: {
        !           182:        BOOL bSuccess = FALSE;
        !           183:        int errstatus = 0;
        !           184:        DWORD BytesTransferred = 0;
        !           185:        ULONG_PTR Key = 0;
        !           186:        IoCompletionInfo * lpo = NULL;
        !           187:        u_long time_next_ifscan_after_error = 0;
        !           188: 
        !           189:        UNUSED_ARG(NotUsed);
        !           190: 
        !           191:        /*
        !           192:         *      socket and refclock receive call gettimeofday()
        !           193:         *      so the I/O thread needs to be on the same 
        !           194:         *      processor as the main and timing threads
        !           195:         *      to ensure consistent QueryPerformanceCounter()
        !           196:         *      results.
        !           197:         */
        !           198:        lock_thread_to_processor(GetCurrentThread());
        !           199: 
        !           200:        /*      Set the thread priority high enough so I/O will
        !           201:         *      preempt normal recv packet processing, but not
        !           202:         *      higher than the timer sync thread.
        !           203:         */
        !           204:        if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL)) {
        !           205:                msyslog(LOG_ERR, "Can't set thread priority: %m");
        !           206:        }
        !           207: 
        !           208:        while (TRUE) {
        !           209:                bSuccess = GetQueuedCompletionStatus(
        !           210:                                        hIoCompletionPort, 
        !           211:                                        &BytesTransferred, 
        !           212:                                        &Key, 
        !           213:                                        (LPOVERLAPPED *) &lpo, 
        !           214:                                        INFINITE);
        !           215:                if (lpo == NULL)
        !           216:                {
        !           217:                        DPRINTF(2, ("Overlapped IO Thread Exiting\n"));
        !           218:                        break; /* fail */
        !           219:                }
        !           220:                
        !           221:                /*
        !           222:                 * Deal with errors
        !           223:                 */
        !           224:                if (bSuccess)
        !           225:                        errstatus = 0;
        !           226:                else
        !           227:                {
        !           228:                        errstatus = GetLastError();
        !           229:                        if (BytesTransferred == 0)
        !           230:                        {
        !           231:                                if (WSA_OPERATION_ABORTED == errstatus) {
        !           232:                                        DPRINTF(4, ("Transfer Operation aborted\n"));
        !           233:                                } else if (ERROR_UNEXP_NET_ERR == errstatus) {
        !           234:                                        /*
        !           235:                                         * We get this error when trying to send an the network
        !           236:                                         * interface is gone or has lost link.  Rescan interfaces
        !           237:                                         * to catch on sooner, but no more than once per minute.
        !           238:                                         * Once ntp is able to detect changes without polling
        !           239:                                         * this should be unneccessary
        !           240:                                         */
        !           241:                                        if (time_next_ifscan_after_error < current_time) {
        !           242:                                                time_next_ifscan_after_error = current_time + 60;
        !           243:                                                timer_interfacetimeout(current_time);
        !           244:                                        }
        !           245:                                        DPRINTF(4, ("sendto unexpected network error, interface may be down\n"));
        !           246:                                }
        !           247:                        }
        !           248:                        else
        !           249:                        {
        !           250:                                msyslog(LOG_ERR, "sendto error after %d bytes: %m", BytesTransferred);
        !           251:                        }
        !           252:                }
        !           253: 
        !           254:                /*
        !           255:                 * Invoke the appropriate function based on
        !           256:                 * the value of the request_type
        !           257:                 */
        !           258:                switch(lpo->request_type)
        !           259:                {
        !           260:                case SERIAL_WAIT:
        !           261:                        OnSerialWaitComplete(Key, lpo, BytesTransferred, errstatus);
        !           262:                        break;
        !           263:                case SERIAL_READ:
        !           264:                        OnSerialReadComplete(Key, lpo, BytesTransferred, errstatus);
        !           265:                        break;
        !           266:                case SOCK_RECV:
        !           267:                        OnSocketRecv(Key, lpo, BytesTransferred, errstatus);
        !           268:                        break;
        !           269:                case SOCK_SEND:
        !           270:                case SERIAL_WRITE:
        !           271:                        OnWriteComplete(Key, lpo, BytesTransferred, errstatus);
        !           272:                        break;
        !           273:                default:
        !           274:                        DPRINTF(1, ("Unknown request type %d found in completion port\n",
        !           275:                                    lpo->request_type));
        !           276:                        break;
        !           277:                }
        !           278:        }
        !           279: 
        !           280:        return 0;
        !           281: }
        !           282: 
        !           283: /*  Create/initialise the I/O creation port
        !           284:  */
        !           285: void
        !           286: init_io_completion_port(
        !           287:        void
        !           288:        )
        !           289: {
        !           290:        unsigned tid;
        !           291:        HANDLE thread;
        !           292: 
        !           293: #ifdef DEBUG
        !           294:        InitializeCriticalSection(&compl_info_lock);
        !           295:        atexit(&free_io_completion_port_mem);
        !           296: #endif
        !           297: 
        !           298: #ifdef USE_HEAP
        !           299:        /*
        !           300:         * Create a handle to the Heap
        !           301:         */
        !           302:        hHeapHandle = HeapCreate(0, 20*sizeof(IoCompletionInfo), 0);
        !           303:        if (hHeapHandle == NULL)
        !           304:        {
        !           305:                msyslog(LOG_ERR, "Can't initialize Heap: %m");
        !           306:                exit(1);
        !           307:        }
        !           308: #endif
        !           309: 
        !           310: #if 0  /* transmitbuff.c unused, no need to initialize it */
        !           311:        init_transmitbuff();
        !           312: #endif
        !           313: 
        !           314:        /* Create the event used to signal an IO event
        !           315:         */
        !           316:        WaitableIoEventHandle = CreateEvent(NULL, FALSE, FALSE, WAITABLEIOEVENTHANDLE);
        !           317:        if (WaitableIoEventHandle == NULL) {
        !           318:                msyslog(LOG_ERR,
        !           319:                "Can't create I/O event handle: %m - another process may be running - EXITING");
        !           320:                exit(1);
        !           321:        }
        !           322:        /* Create the event used to signal an exit event
        !           323:         */
        !           324:        WaitableExitEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
        !           325:        if (WaitableExitEventHandle == NULL) {
        !           326:                msyslog(LOG_ERR,
        !           327:                "Can't create exit event handle: %m - EXITING");
        !           328:                exit(1);
        !           329:        }
        !           330: 
        !           331:        /* Create the IO completion port
        !           332:         */
        !           333:        hIoCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
        !           334:        if (hIoCompletionPort == NULL) {
        !           335:                msyslog(LOG_ERR, "Can't create I/O completion port: %m");
        !           336:                exit(1);
        !           337:        }
        !           338: 
        !           339:        /*
        !           340:         * Initialize the Wait Handles
        !           341:         */
        !           342:        WaitHandles[0] = WaitableIoEventHandle;
        !           343:        WaitHandles[1] = WaitableExitEventHandle; /* exit request */
        !           344:        WaitHandles[2] = get_timer_handle();
        !           345: 
        !           346:        /* Have one thread servicing I/O - there were 4, but this would 
        !           347:         * somehow cause NTP to stop replying to ntpq requests; TODO
        !           348:         */
        !           349:        thread = (HANDLE)_beginthreadex(
        !           350:                NULL, 
        !           351:                0, 
        !           352:                iocompletionthread, 
        !           353:                NULL, 
        !           354:                CREATE_SUSPENDED, 
        !           355:                &tid);
        !           356:        ResumeThread(thread);
        !           357:        CloseHandle(thread);
        !           358: }
        !           359:        
        !           360: 
        !           361: #ifdef DEBUG
        !           362: static void
        !           363: free_io_completion_port_mem(
        !           364:        void
        !           365:        )
        !           366: {
        !           367:        IoCompletionInfo *      pci;
        !           368: 
        !           369: #if defined(_MSC_VER) && defined (_DEBUG)
        !           370:        _CrtCheckMemory();
        !           371: #endif
        !           372:        LOCK_COMPL();
        !           373:        while ((pci = compl_info_list) != NULL) {
        !           374: 
        !           375: #if 0  /* sockaddr with received-from address in recvbuf */
        !           376:        /* is sometimes modified by system after we free it  */
        !           377:        /* triggering heap corruption warning -- find a */
        !           378:        /* better way to free it after I/O is surely done */
        !           379:                /* this handles both xmit and recv buffs */
        !           380:                if (pci->recv_buf != NULL) {
        !           381:                        DPRINTF(1, ("freeing xmit/recv buff %p\n", pci->recv_buf));
        !           382:                        free(pci->recv_buf);
        !           383:                }
        !           384: #endif
        !           385: 
        !           386:                FreeHeap(pci, "free_io_completion_port_mem");
        !           387:                /* FreeHeap() removed this item from compl_info_list */
        !           388:        }
        !           389:        UNLOCK_COMPL()
        !           390: 
        !           391: #if defined(_MSC_VER) && defined (_DEBUG)
        !           392:        _CrtCheckMemory();
        !           393: #endif
        !           394: }
        !           395: #endif /* DEBUG */
        !           396: 
        !           397: 
        !           398: void
        !           399: uninit_io_completion_port(
        !           400:        void
        !           401:        )
        !           402: {
        !           403:        if (hIoCompletionPort != NULL) {
        !           404:                /*  Get each of the service threads to exit
        !           405:                */
        !           406:                signal_io_completion_port_exit();
        !           407:        }
        !           408: }
        !           409: 
        !           410: 
        !           411: static int
        !           412: QueueSerialWait(
        !           413:        struct refclockio *     rio,
        !           414:        recvbuf_t *             buff,
        !           415:        IoCompletionInfo *      lpo,
        !           416:        BOOL                    clear_timestamp
        !           417:        )
        !           418: {
        !           419:        lpo->request_type = SERIAL_WAIT;
        !           420:        lpo->recv_buf = buff;
        !           421: 
        !           422:        if (clear_timestamp)
        !           423:                memset(&buff->recv_time, 0, sizeof(buff->recv_time));
        !           424: 
        !           425:        buff->fd = _get_osfhandle(rio->fd);
        !           426:        if (!WaitCommEvent((HANDLE) buff->fd, (DWORD *)&buff->recv_buffer, (LPOVERLAPPED) lpo)) {
        !           427:                if (ERROR_IO_PENDING != GetLastError()) {
        !           428:                        msyslog(LOG_ERR, "Can't wait on Refclock: %m");
        !           429:                        freerecvbuf(buff);
        !           430:                        return 0;
        !           431:                }
        !           432:        }
        !           433:        return 1;
        !           434: }
        !           435: 
        !           436: 
        !           437: static int 
        !           438: OnSerialWaitComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
        !           439: {
        !           440:        recvbuf_t *buff;
        !           441:        struct refclockio * rio = (struct refclockio *) i;
        !           442:        struct peer *pp;
        !           443:        l_fp arrival_time;
        !           444:        DWORD comm_mask;
        !           445:        DWORD modem_status;
        !           446:        static const l_fp zero_time = { 0 };
        !           447:        BOOL rc;
        !           448: 
        !           449:        get_systime(&arrival_time);
        !           450: 
        !           451:        /*
        !           452:         * Get the recvbuf pointer from the overlapped buffer.
        !           453:         */
        !           454:        buff = lpo->recv_buf;
        !           455:        comm_mask = (*(DWORD *)&buff->recv_buffer);
        !           456: #ifdef DEBUG
        !           457:                if (errstatus || comm_mask & ~(EV_RXFLAG | EV_RLSD)) {
        !           458:                        msyslog(LOG_ERR, "WaitCommEvent returned unexpected mask %x errstatus %d",
        !           459:                                comm_mask, errstatus);
        !           460:                        exit(-1);
        !           461:                }
        !           462: #endif
        !           463:                if (comm_mask & EV_RLSD) { 
        !           464:                        modem_status = 0;
        !           465:                        GetCommModemStatus((HANDLE)buff->fd, &modem_status);
        !           466:                        if (modem_status & MS_RLSD_ON) {
        !           467:                                /*
        !           468:                                 * Use the timestamp from this PPS CD not
        !           469:                                 * the later end of line.
        !           470:                                 */
        !           471:                                buff->recv_time = arrival_time;
        !           472:                        }
        !           473: 
        !           474:                        if (!(comm_mask & EV_RXFLAG)) {
        !           475:                                /*
        !           476:                                 * if we didn't see an end of line yet
        !           477:                                 * issue another wait for it.
        !           478:                                 */
        !           479:                                QueueSerialWait(rio, buff, lpo, FALSE);
        !           480:                                return 1;
        !           481:                        }
        !           482:                }
        !           483: 
        !           484:                /*
        !           485:                 * We've detected the end of line of serial input.
        !           486:                 * Use this timestamp unless we already have a CD PPS
        !           487:                 * timestamp in buff->recv_time.
        !           488:                 */
        !           489:                if (memcmp(&buff->recv_time, &zero_time, sizeof buff->recv_time)) {
        !           490:                        /*
        !           491:                         * We will first see a user PPS timestamp here on either
        !           492:                         * the first or second line of text.  Log a one-time
        !           493:                         * message while processing the second line.
        !           494:                         */
        !           495:                        if (1 == rio->recvcount) {
        !           496:                                pp = (struct peer *)rio->srcclock;
        !           497:                                msyslog(LOG_NOTICE, "Using user-mode PPS timestamp for %s",
        !           498:                                        refnumtoa(&pp->srcadr));
        !           499:                        }
        !           500:                } else {
        !           501:                        buff->recv_time = arrival_time;
        !           502:                }
        !           503: 
        !           504:                /*
        !           505:                 * Now that we have a complete line waiting, read it.
        !           506:                 * There is still a race here, but we're likely to win.
        !           507:                 */
        !           508: 
        !           509:                lpo->request_type = SERIAL_READ;
        !           510: 
        !           511:                rc = ReadFile(
        !           512:                        (HANDLE)buff->fd,
        !           513:                        buff->recv_buffer,
        !           514:                        sizeof(buff->recv_buffer),
        !           515:                        NULL,
        !           516:                        (LPOVERLAPPED)lpo);
        !           517: 
        !           518:                if (!rc && ERROR_IO_PENDING != GetLastError()) {
        !           519:                        msyslog(LOG_ERR, "Can't read from Refclock: %m");
        !           520:                        freerecvbuf(buff);
        !           521:                        return 0;
        !           522:                }
        !           523: 
        !           524:        return 1;
        !           525: }
        !           526: 
        !           527: /* Return 1 on Successful Read */
        !           528: static int 
        !           529: OnSerialReadComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
        !           530: {
        !           531:        recvbuf_t *             buff;
        !           532:        l_fp                    cr_time;
        !           533:        struct refclockio *     rio;
        !           534: 
        !           535:        rio = (struct refclockio *)i;
        !           536:        /*
        !           537:         * Get the recvbuf pointer from the overlapped buffer.
        !           538:         */
        !           539:        buff = lpo->recv_buf;
        !           540: 
        !           541:        /*
        !           542:         * ignore 0 bytes read due to timeout's and closure on fd
        !           543:         */
        !           544:        if (!errstatus && Bytes) {
        !           545:                buff->recv_length = (int) Bytes;
        !           546:                buff->receiver = rio->clock_recv;
        !           547:                buff->dstadr = NULL;
        !           548:                buff->recv_srcclock = rio->srcclock;
        !           549:                packets_received++;
        !           550:                /*
        !           551:                 * Eat the first line of input as it's possibly
        !           552:                 * partial and if a PPS is present, it may not 
        !           553:                 * have fired since the port was opened.
        !           554:                 */
        !           555:                if (rio->recvcount++) {
        !           556:                        cr_time = buff->recv_time;
        !           557:                        add_full_recv_buffer(buff);
        !           558:                        /*
        !           559:                         * Mimic Unix line discipline and assume CR/LF
        !           560:                         * line termination.  On Unix the CR terminates
        !           561:                         * the line containing the timecode, and
        !           562:                         * immediately after the LF terminates an empty
        !           563:                         * line.  So synthesize the empty LF-terminated
        !           564:                         * line using the same CR timestamp.  Both CR
        !           565:                         * and LF are stripped by refclock_gtlin().
        !           566:                         */
        !           567:                        buff = get_free_recv_buffer_alloc();
        !           568:                        buff->recv_time = cr_time;
        !           569:                        buff->recv_length = 0;
        !           570:                        buff->fd = _get_osfhandle(rio->fd);
        !           571:                        buff->receiver = rio->clock_recv;
        !           572:                        buff->dstadr = NULL;
        !           573:                        buff->recv_srcclock = rio->srcclock;
        !           574:                        add_full_recv_buffer(buff);
        !           575:                        /*
        !           576:                         * Now signal we have something to process
        !           577:                         */
        !           578:                        SetEvent(WaitableIoEventHandle);
        !           579:                        buff = get_free_recv_buffer_alloc();
        !           580:                }
        !           581:        }
        !           582: 
        !           583:        QueueSerialWait(rio, buff, lpo, TRUE);
        !           584: 
        !           585:        return 1;
        !           586: }
        !           587: 
        !           588: /*  Add a reference clock data structures I/O handles to
        !           589:  *  the I/O completion port. Return 1 if any error.
        !           590:  */  
        !           591: int
        !           592: io_completion_port_add_clock_io(
        !           593:        struct refclockio *rio
        !           594:        )
        !           595: {
        !           596:        IoCompletionInfo *lpo;
        !           597:        recvbuf_t *buff;
        !           598: 
        !           599:        if (NULL == CreateIoCompletionPort(
        !           600:                        (HANDLE)_get_osfhandle(rio->fd), 
        !           601:                        hIoCompletionPort, 
        !           602:                        (ULONG_PTR)rio,
        !           603:                        0)) {
        !           604:                msyslog(LOG_ERR, "Can't add COM port to i/o completion port: %m");
        !           605:                return 1;
        !           606:        }
        !           607: 
        !           608:        lpo = GetHeapAlloc("io_completion_port_add_clock_io");
        !           609:        if (NULL == lpo) {
        !           610:                msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
        !           611:                return 1;
        !           612:        }
        !           613: 
        !           614:        buff = get_free_recv_buffer_alloc();
        !           615:        QueueSerialWait(rio, buff, lpo, TRUE);
        !           616:        return 0;
        !           617: }
        !           618: 
        !           619: /*
        !           620:  * Queue a receiver on a socket. Returns 0 if no buffer can be queued 
        !           621:  *
        !           622:  *  Note: As per the winsock documentation, we use WSARecvFrom. Using
        !           623:  *       ReadFile() is less efficient.
        !           624:  */
        !           625: static unsigned long 
        !           626: QueueSocketRecv(
        !           627:        SOCKET s,
        !           628:        recvbuf_t *buff,
        !           629:        IoCompletionInfo *lpo
        !           630:        )
        !           631: {
        !           632:        WSABUF wsabuf;
        !           633:        DWORD Flags;
        !           634:        DWORD Result;
        !           635: 
        !           636:        lpo->request_type = SOCK_RECV;
        !           637:        lpo->recv_buf = buff;
        !           638: 
        !           639:        if (buff != NULL) {
        !           640:                Flags = 0;
        !           641:                buff->fd = s;
        !           642:                buff->recv_srcadr_len = sizeof(buff->recv_srcadr);
        !           643:                wsabuf.buf = (char *)buff->recv_buffer;
        !           644:                wsabuf.len = sizeof(buff->recv_buffer);
        !           645: 
        !           646:                if (SOCKET_ERROR == WSARecvFrom(buff->fd, &wsabuf, 1, 
        !           647:                                                NULL, &Flags, 
        !           648:                                                &buff->recv_srcadr.sa, 
        !           649:                                                &buff->recv_srcadr_len, 
        !           650:                                                (LPOVERLAPPED)lpo, NULL)) {
        !           651:                        Result = GetLastError();
        !           652:                        switch (Result) {
        !           653:                                case NO_ERROR :
        !           654:                                case WSA_IO_PENDING :
        !           655:                                        break ;
        !           656: 
        !           657:                                case WSAENOTSOCK :
        !           658:                                        msyslog(LOG_ERR, "Can't read from non-socket fd %d: %m", (int)buff->fd);
        !           659:                                        /* return the buffer */
        !           660:                                        freerecvbuf(buff);
        !           661:                                        return 0;
        !           662:                                        break;
        !           663: 
        !           664:                                case WSAEFAULT :
        !           665:                                        msyslog(LOG_ERR, "The buffers parameter is incorrect: %m");
        !           666:                                        /* return the buffer */
        !           667:                                        freerecvbuf(buff);
        !           668:                                        return 0;
        !           669:                                break;
        !           670: 
        !           671:                                default :
        !           672:                                  /* nop */ ;
        !           673:                        }
        !           674:                }
        !           675:        }
        !           676:        else 
        !           677:                return 0;
        !           678:        return 1;
        !           679: }
        !           680: 
        !           681: 
        !           682: /* Returns 0 if any Error */
        !           683: static int 
        !           684: OnSocketRecv(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
        !           685: {
        !           686:        struct recvbuf *buff = NULL;
        !           687:        recvbuf_t *newbuff;
        !           688:        l_fp arrival_time;
        !           689:        struct interface * inter = (struct interface *) i;
        !           690:        
        !           691:        get_systime(&arrival_time);
        !           692: 
        !           693:        NTP_REQUIRE(NULL != lpo);
        !           694:        NTP_REQUIRE(NULL != lpo->recv_buf);
        !           695: 
        !           696:        /*
        !           697:         * Convert the overlapped pointer back to a recvbuf pointer.
        !           698:         */
        !           699:        buff = lpo->recv_buf;
        !           700: 
        !           701:        /*
        !           702:         * If the socket is closed we get an Operation Aborted error
        !           703:         * Just clean up
        !           704:         */
        !           705:        if (errstatus == WSA_OPERATION_ABORTED)
        !           706:        {
        !           707:                freerecvbuf(buff);
        !           708:                lpo->recv_buf = NULL;
        !           709:                FreeHeap(lpo, "OnSocketRecv: Socket Closed");
        !           710:                return (1);
        !           711:        }
        !           712: 
        !           713:        /*
        !           714:         * Get a new recv buffer for the replacement socket receive
        !           715:         */
        !           716:        newbuff = get_free_recv_buffer_alloc();
        !           717:        QueueSocketRecv(inter->fd, newbuff, lpo);
        !           718: 
        !           719:        DPRINTF(4, ("%sfd %d %s recv packet mode is %d\n", 
        !           720:                    (MODE_BROADCAST == get_packet_mode(buff))
        !           721:                        ? " **** Broadcast "
        !           722:                        : "",
        !           723:                    (int)buff->fd, stoa(&buff->recv_srcadr),
        !           724:                    get_packet_mode(buff)));
        !           725: 
        !           726:        /*
        !           727:         * If we keep it add some info to the structure
        !           728:         */
        !           729:        if (Bytes && !inter->ignore_packets) {
        !           730:                memcpy(&buff->recv_time, &arrival_time, sizeof buff->recv_time);        
        !           731:                buff->recv_length = (int) Bytes;
        !           732:                buff->receiver = receive; 
        !           733:                buff->dstadr = inter;
        !           734: 
        !           735:                DPRINTF(2, ("Received %d bytes fd %d in buffer %p from %s\n", 
        !           736:                            Bytes, (int)buff->fd, buff, stoa(&buff->recv_srcadr)));
        !           737: 
        !           738:                packets_received++;
        !           739:                inter->received++;
        !           740:                add_full_recv_buffer(buff);
        !           741:                /*
        !           742:                 * Now signal we have something to process
        !           743:                 */
        !           744:                SetEvent(WaitableIoEventHandle);
        !           745:        } else
        !           746:                freerecvbuf(buff);
        !           747: 
        !           748:        return 1;
        !           749: }
        !           750: 
        !           751: 
        !           752: /*  Add a socket handle to the I/O completion port, and send 
        !           753:  *  NTP_RECVS_PER_SOCKET recv requests to the kernel.
        !           754:  */
        !           755: extern int
        !           756: io_completion_port_add_socket(SOCKET fd, struct interface *inter)
        !           757: {
        !           758:        IoCompletionInfo *lpo;
        !           759:        recvbuf_t *buff;
        !           760:        int n;
        !           761: 
        !           762:        if (fd != INVALID_SOCKET) {
        !           763:                if (NULL == CreateIoCompletionPort((HANDLE)fd, 
        !           764:                    hIoCompletionPort, (ULONG_PTR)inter, 0)) {
        !           765:                        msyslog(LOG_ERR, "Can't add socket to i/o completion port: %m");
        !           766:                        return 1;
        !           767:                }
        !           768:        }
        !           769: 
        !           770:        /*
        !           771:         * Windows 2000 bluescreens with bugcheck 0x76
        !           772:         * PROCESS_HAS_LOCKED_PAGES at ntpd process
        !           773:         * termination when using more than one pending
        !           774:         * receive per socket.  A runtime version test
        !           775:         * would allow using more on newer versions
        !           776:         * of Windows.
        !           777:         */
        !           778: 
        !           779: #define WINDOWS_RECVS_PER_SOCKET 1
        !           780: 
        !           781:        for (n = 0; n < WINDOWS_RECVS_PER_SOCKET; n++) {
        !           782: 
        !           783:                buff = get_free_recv_buffer_alloc();
        !           784:                lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket");
        !           785:                if (lpo == NULL)
        !           786:                {
        !           787:                        msyslog(LOG_ERR, "Can't allocate heap for completion port: %m");
        !           788:                        return 1;
        !           789:                }
        !           790: 
        !           791:                QueueSocketRecv(fd, buff, lpo);
        !           792: 
        !           793:        }
        !           794:        return 0;
        !           795: }
        !           796: 
        !           797: static int 
        !           798: OnWriteComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
        !           799: {
        !           800:        transmitbuf_t *buff;
        !           801:        struct interface *inter;
        !           802: 
        !           803:        UNUSED_ARG(Bytes);
        !           804: 
        !           805:        buff = lpo->trans_buf;
        !           806: 
        !           807:        free_trans_buf(buff);
        !           808:        lpo->trans_buf = NULL;
        !           809: 
        !           810:        if (SOCK_SEND == lpo->request_type) {
        !           811:                switch (errstatus) {
        !           812:                case WSA_OPERATION_ABORTED:
        !           813:                case NO_ERROR:
        !           814:                        break;
        !           815: 
        !           816:                default:
        !           817:                        inter = (struct interface *)i;
        !           818:                        packets_notsent++;
        !           819:                        inter->notsent++;
        !           820:                        break;
        !           821:                }
        !           822:        }
        !           823: 
        !           824:        if (errstatus == WSA_OPERATION_ABORTED)
        !           825:                FreeHeap(lpo, "OnWriteComplete: Socket Closed");
        !           826:        else
        !           827:                FreeHeap(lpo, "OnWriteComplete");
        !           828:        return 1;
        !           829: }
        !           830: 
        !           831: 
        !           832: /*
        !           833:  * mimic sendto() interface
        !           834:  */
        !           835: int
        !           836: io_completion_port_sendto(
        !           837:        int             fd,
        !           838:        void  *         pkt,
        !           839:        size_t          len,
        !           840:        sockaddr_u *    dest
        !           841:        )
        !           842: {
        !           843:        WSABUF                  wsabuf;
        !           844:        transmitbuf_t *         buff;
        !           845:        DWORD                   Result;
        !           846:        int                     errval;
        !           847:        int                     AddrLen;
        !           848:        IoCompletionInfo *      lpo;
        !           849:        DWORD                   Flags;
        !           850: 
        !           851:        Result = ERROR_SUCCESS;
        !           852:        lpo = (IoCompletionInfo *)GetHeapAlloc("io_completion_port_sendto");
        !           853:        if (lpo == NULL) {
        !           854:                SetLastError(ERROR_OUTOFMEMORY);
        !           855:                return -1;
        !           856:        }
        !           857: 
        !           858:        if (len <= sizeof(buff->pkt)) {
        !           859:                buff = get_trans_buf();
        !           860: 
        !           861:                if (buff == NULL) {
        !           862:                        msyslog(LOG_ERR, "No more transmit buffers left - data discarded");
        !           863:                        FreeHeap(lpo, "io_completion_port_sendto");
        !           864:                        SetLastError(ERROR_OUTOFMEMORY);
        !           865:                        return -1;
        !           866:                }
        !           867: 
        !           868:                memcpy(&buff->pkt, pkt, len);
        !           869:                wsabuf.buf = buff->pkt;
        !           870:                wsabuf.len = len;
        !           871: 
        !           872:                AddrLen = SOCKLEN(dest);
        !           873:                lpo->request_type = SOCK_SEND;
        !           874:                lpo->trans_buf = buff;
        !           875:                Flags = 0;
        !           876: 
        !           877:                Result = WSASendTo(fd, &wsabuf, 1, NULL, Flags,
        !           878:                                   &dest->sa, AddrLen,
        !           879:                                   (LPOVERLAPPED)lpo, NULL);
        !           880:                if (Result == SOCKET_ERROR) {
        !           881:                        errval = WSAGetLastError();
        !           882:                        switch (errval) {
        !           883: 
        !           884:                        case NO_ERROR :
        !           885:                        case WSA_IO_PENDING :
        !           886:                                Result = ERROR_SUCCESS;
        !           887:                                break ;
        !           888: 
        !           889:                        /*
        !           890:                         * Something bad happened
        !           891:                         */
        !           892:                        default :
        !           893:                                msyslog(LOG_ERR,
        !           894:                                        "WSASendTo(%s) error %d: %s",
        !           895:                                        stoa(dest), errval, strerror(errval));
        !           896:                                free_trans_buf(buff);
        !           897:                                lpo->trans_buf = NULL;
        !           898:                                FreeHeap(lpo, "io_completion_port_sendto");
        !           899:                                break;
        !           900:                        }
        !           901:                }
        !           902: #ifdef DEBUG
        !           903:                if (debug > 3)
        !           904:                        printf("WSASendTo - %d bytes to %s : %d\n", len, stoa(dest), Result);
        !           905: #endif
        !           906:                if (ERROR_SUCCESS == Result)
        !           907:                        return len;
        !           908:                SetLastError(Result);
        !           909:                return -1;
        !           910:        } else {
        !           911: #ifdef DEBUG
        !           912:                if (debug) printf("Packet too large: %d Bytes\n", len);
        !           913: #endif
        !           914:                SetLastError(ERROR_INSUFFICIENT_BUFFER);
        !           915:                return -1;
        !           916:        }
        !           917: }
        !           918: 
        !           919: 
        !           920: /*
        !           921:  * async_write, clone of write(), used by some reflock drivers
        !           922:  */
        !           923: int    
        !           924: async_write(
        !           925:        int fd,
        !           926:        const void *data,
        !           927:        unsigned int count
        !           928:        )
        !           929: {
        !           930:        transmitbuf_t *buff;
        !           931:        IoCompletionInfo *lpo;
        !           932:        DWORD BytesWritten;
        !           933: 
        !           934:        if (count > sizeof buff->pkt) {
        !           935: #ifdef DEBUG
        !           936:                if (debug) {
        !           937:                        printf("async_write: %d bytes too large, limit is %d\n",
        !           938:                                count, sizeof buff->pkt);
        !           939:                        exit(-1);
        !           940:                }
        !           941: #endif
        !           942:                errno = ENOMEM;
        !           943:                return -1;
        !           944:        }
        !           945: 
        !           946:        buff = get_trans_buf();
        !           947:        lpo = (IoCompletionInfo *) GetHeapAlloc("async_write");
        !           948: 
        !           949:        if (! buff || ! lpo) {
        !           950:                if (buff) {
        !           951:                        free_trans_buf(buff);
        !           952:                        DPRINTF(1, ("async_write: out of memory\n"));
        !           953:                } else
        !           954:                        msyslog(LOG_ERR, "No more transmit buffers left - data discarded");
        !           955: 
        !           956:                errno = ENOMEM;
        !           957:                return -1;
        !           958:        }
        !           959: 
        !           960:        lpo->request_type = SERIAL_WRITE;
        !           961:        lpo->trans_buf = buff;
        !           962:        memcpy(&buff->pkt, data, count);
        !           963: 
        !           964:        if (!WriteFile((HANDLE)_get_osfhandle(fd), buff->pkt, count,
        !           965:                &BytesWritten, (LPOVERLAPPED)lpo)
        !           966:                && ERROR_IO_PENDING != GetLastError()) {
        !           967: 
        !           968:                msyslog(LOG_ERR, "async_write - error %m");
        !           969:                free_trans_buf(buff);
        !           970:                lpo->trans_buf = NULL;
        !           971:                FreeHeap(lpo, "async_write");
        !           972:                errno = EBADF;
        !           973:                return -1;
        !           974:        }
        !           975: 
        !           976:        return count;
        !           977: }
        !           978: 
        !           979: 
        !           980: /*
        !           981:  * GetReceivedBuffers
        !           982:  * Note that this is in effect the main loop for processing requests
        !           983:  * both send and receive. This should be reimplemented
        !           984:  */
        !           985: int GetReceivedBuffers()
        !           986: {
        !           987:        isc_boolean_t have_packet = ISC_FALSE;
        !           988:        while (!have_packet) {
        !           989:                DWORD Index = WaitForMultipleObjects(MAXHANDLES, WaitHandles, FALSE, INFINITE);
        !           990:                switch (Index) {
        !           991:                case WAIT_OBJECT_0 + 0 : /* Io event */
        !           992: # ifdef DEBUG
        !           993:                        if ( debug > 3 )
        !           994:                        {
        !           995:                                printf( "IoEvent occurred\n" );
        !           996:                        }
        !           997: # endif
        !           998:                        have_packet = ISC_TRUE;
        !           999:                        break;
        !          1000:                case WAIT_OBJECT_0 + 1 : /* exit request */
        !          1001:                        exit(0);
        !          1002:                        break;
        !          1003:                case WAIT_OBJECT_0 + 2 : /* timer */
        !          1004:                        timer();
        !          1005:                        break;
        !          1006:                case WAIT_IO_COMPLETION : /* loop */
        !          1007:                case WAIT_TIMEOUT :
        !          1008:                        break;
        !          1009:                case WAIT_FAILED:
        !          1010:                        msyslog(LOG_ERR, "ntpd: WaitForMultipleObjects Failed: Error: %m");
        !          1011:                        break;
        !          1012: 
        !          1013:                        /* For now do nothing if not expected */
        !          1014:                default:
        !          1015:                        break;          
        !          1016:                                
        !          1017:                } /* switch */
        !          1018:        }
        !          1019: 
        !          1020:        return (full_recvbuffs());      /* get received buffers */
        !          1021: }
        !          1022: 
        !          1023: #else
        !          1024:   static int NonEmptyCompilationUnit;
        !          1025: #endif
        !          1026: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>