From: Dave Hart Date: Fri, 20 Mar 2009 01:46:15 +0000 (+0000) Subject: [Bug 873] Windows serial refclock proper TTY line discipline emulation X-Git-Tag: NTP_4_2_4P7_RC1~8^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5447b6d3f6b559da9d622885c3d7498a7e6d21ae;p=thirdparty%2Fntp.git [Bug 873] Windows serial refclock proper TTY line discipline emulation bk: 49c2f5678DEw6aEZpBKhp5W2nC2xsQ --- diff --git a/ChangeLog b/ChangeLog index f26fece5e..acdd4e3c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +* [Bug 873] Windows serial refclock proper TTY line discipline emulation + --- (4.2.4p6) 2009/01/08 Released by Harlan Stenn diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index faa46461f..0062436ca 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -477,6 +477,8 @@ void init_io(void) { #ifdef SYS_WINNT + init_io_completion_port(); + if (!Win32InitSockets()) { netsyslog(LOG_ERR, "No useable winsock.dll: %m"); @@ -1184,7 +1186,7 @@ update_interfaces( scan_ipv6 = ISC_TRUE; #if defined(DEBUG) else - if(debug) + if (debug) netsyslog(LOG_ERR, "no IPv6 interfaces found"); #endif #endif @@ -1192,7 +1194,7 @@ update_interfaces( scan_ipv6 = ISC_TRUE; #if defined(ISC_PLATFORM_HAVEIPV6) && defined(DEBUG) else - if(debug) + if (debug) netsyslog(LOG_ERR, "no IPv6 interfaces found"); #endif @@ -1508,13 +1510,14 @@ create_interface( */ static void set_reuseaddr(int flag) { - struct interface *interf; + struct interface *interf; for (interf = ISC_LIST_HEAD(inter_list); interf != NULL; interf = ISC_LIST_NEXT(interf, link)) { - if (interf->flags & INT_WILDCARD) - continue; + + if (interf->flags & INT_WILDCARD) + continue; /* * if interf->fd is INVALID_SOCKET, we might have a adapter @@ -1691,7 +1694,7 @@ enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr) case AF_INET6: #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, - &iface->scopeid, sizeof(iface->scopeid)) == -1) { + (char *) &iface->scopeid, sizeof(iface->scopeid)) == -1) { netsyslog(LOG_ERR, "setsockopt IPV6_MULTICAST_IF failure: %m on socket %d, addr %s, scope %d for multicast address %s", iface->fd, stoa(&iface->sin), iface->scopeid, @@ -1703,7 +1706,7 @@ enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr) * Don't send back to itself, but allow it to fail to set it */ if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, - &off, sizeof(off)) == -1) { + (char *) &off, sizeof(off)) == -1) { netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_LOOP failure: %m on socket %d, addr %s for multicast address %s", iface->fd, stoa(&iface->sin), stoa(maddr)); @@ -1981,7 +1984,10 @@ io_multicast_add( ) { #ifdef MCAST - struct interface *interface, *iface; + struct interface *interface; +#ifndef MULTICAST_NONEWSOCKET + struct interface *iface; +#endif int lscope = 0; /* @@ -2496,9 +2502,6 @@ sendpkt( ) { int cc, slot; -#ifdef SYS_WINNT - DWORD err; -#endif /* SYS_WINNT */ /* * Send error caches. Empty slots have port == 0 @@ -2618,8 +2621,8 @@ sendpkt( #endif /* INCLUDE_IPV6_SUPPORT */ #if defined(HAVE_IO_COMPLETION_PORT) - err = io_completion_port_sendto(inter, pkt, len, dest); - if (err != ERROR_SUCCESS) + cc = io_completion_port_sendto(inter, pkt, len, dest); + if (cc != ERROR_SUCCESS) #else #ifdef SIM cc = srvr_rply(&ntp_node, dest, inter, pkt); @@ -2632,9 +2635,9 @@ sendpkt( { inter->notsent++; packets_notsent++; + #if defined(HAVE_IO_COMPLETION_PORT) - err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0) + if (cc != WSAEWOULDBLOCK && cc != WSAENOBUFS && slot < 0) #else if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) #endif @@ -2659,13 +2662,13 @@ sendpkt( case AF_INET6 : for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs6[slot].port == 0) - { - badaddrs6[slot].port = SRCPORT(dest); - badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr; - break; - } - break; + if (badaddrs6[slot].port == 0) + { + badaddrs6[slot].port = SRCPORT(dest); + badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr; + break; + } + break; #endif /* INCLUDE_IPV6_SUPPORT */ default: /* don't care if not supported */ break; @@ -3207,7 +3210,7 @@ findlocalinterface( struct interface *iface; DPRINTF(4, ("Finding interface for addr %s in list of addresses\n", - stoa(addr));) + stoa(addr))); memset(&saddr, 0, sizeof(saddr)); saddr.ss_family = addr->ss_family; diff --git a/ntpd/ntpd.c b/ntpd/ntpd.c index 04e0d07f9..02a5198b0 100644 --- a/ntpd/ntpd.c +++ b/ntpd/ntpd.c @@ -26,30 +26,22 @@ # include #endif #include -#ifndef SYS_WINNT -# if !defined(VMS) /*wjm*/ -# ifdef HAVE_SYS_PARAM_H -# include -# endif -# endif /* VMS */ -# ifdef HAVE_SYS_SIGNAL_H -# include -# else -# include +#if !defined(VMS) /*wjm*/ +# ifdef HAVE_SYS_PARAM_H +# include # endif -# ifdef HAVE_SYS_IOCTL_H -# include -# endif /* HAVE_SYS_IOCTL_H */ -# ifdef HAVE_SYS_RESOURCE_H -# include -# endif /* HAVE_SYS_RESOURCE_H */ +#endif /* VMS */ +#ifdef HAVE_SYS_SIGNAL_H +# include #else # include -# include -# include -# include -#include "ntp_iocompletionport.h" -#endif /* SYS_WINNT */ +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif /* HAVE_SYS_IOCTL_H */ +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif /* HAVE_SYS_RESOURCE_H */ #if defined(HAVE_RTPRIO) # ifdef HAVE_SYS_RESOURCE_H # include @@ -821,9 +813,6 @@ ntpdmain( init_restrict(); init_mon(); init_timer(); -#if defined (HAVE_IO_COMPLETION_PORT) - init_io_completion_port(); -#endif init_lib(); init_request(); init_control(); @@ -993,7 +982,7 @@ getgroup: #if defined(HAVE_IO_COMPLETION_PORT) for (;;) { - int tot_full_recvbufs = GetReceivedBuffers(); + GetReceivedBuffers(); #else /* normal I/O */ BLOCK_IO_AND_ALARM(); diff --git a/ntpd/refclock_dumbclock.c b/ntpd/refclock_dumbclock.c index 2788649ac..10ff2cfe8 100644 --- a/ntpd/refclock_dumbclock.c +++ b/ntpd/refclock_dumbclock.c @@ -12,11 +12,6 @@ #include #endif -#if defined(SYS_WINNT) -#undef close -#define close closesocket -#endif - #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) #include "ntpd.h" @@ -28,6 +23,12 @@ #include #include +#ifdef SYS_WINNT +extern int async_write(int, const void *, unsigned int); +#undef write +#define write(fd, data, octets) async_write(fd, data, octets) +#endif + /* * This driver supports a generic dumb clock that only outputs hh:mm:ss, * in local time, no less. diff --git a/ntpd/refclock_hopfser.c b/ntpd/refclock_hopfser.c index 94b660be2..9037d4a92 100644 --- a/ntpd/refclock_hopfser.c +++ b/ntpd/refclock_hopfser.c @@ -14,11 +14,6 @@ # include "config.h" #endif -#if defined(SYS_WINNT) -#undef close -#define close closesocket -#endif - #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL)) #include "ntpd.h" @@ -51,6 +46,12 @@ # include #endif +#ifdef SYS_WINNT +extern int async_write(int, const void *, unsigned int); +#undef write +#define write(fd, data, octets) async_write(fd, data, octets) +#endif + /* * clock definitions */ diff --git a/ntpd/refclock_nmea.c b/ntpd/refclock_nmea.c index 5b124cb0c..a176ee86c 100644 --- a/ntpd/refclock_nmea.c +++ b/ntpd/refclock_nmea.c @@ -7,11 +7,6 @@ #include #endif -#if defined(SYS_WINNT) -#undef close -#define close closesocket -#endif - #if defined(REFCLOCK) && defined(CLOCK_NMEA) #include @@ -27,6 +22,12 @@ # include "ppsapi_timepps.h" #endif /* HAVE_PPSAPI */ +#ifdef SYS_WINNT +extern int async_write(int, const void *, unsigned int); +#undef write +#define write(fd, data, octets) async_write(fd, data, octets) +#endif + /* * This driver supports the NMEA GPS Receiver with * diff --git a/ntpd/refclock_palisade.c b/ntpd/refclock_palisade.c index 217ec104d..adb4659f9 100644 --- a/ntpd/refclock_palisade.c +++ b/ntpd/refclock_palisade.c @@ -56,13 +56,14 @@ #include "config.h" #endif -#if defined(SYS_WINNT) -#undef close -#define close closesocket -#endif - #if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE)) +#ifdef SYS_WINNT +extern int async_write(int, const void *, unsigned int); +#undef write +#define write(fd, data, octets) async_write(fd, data, octets) +#endif + #include "refclock_palisade.h" /* Table to get from month to day of the year */ const int days_of_year [12] = { diff --git a/ports/winnt/include/ntp_iocompletionport.h b/ports/winnt/include/ntp_iocompletionport.h index dafc5606e..6e7b92b2c 100644 --- a/ports/winnt/include/ntp_iocompletionport.h +++ b/ports/winnt/include/ntp_iocompletionport.h @@ -3,26 +3,25 @@ #include "ntp_fp.h" #include "ntp.h" +#include "clockstuff.h" # if defined(HAVE_IO_COMPLETION_PORT) -struct refclockio; - - extern void init_io_completion_port (void); extern void uninit_io_completion_port (void); -extern int io_completion_port_add_clock_io (struct refclockio * /*rio */); - extern int io_completion_port_add_socket (SOCKET fd, struct interface *); -extern DWORD io_completion_port_sendto (struct interface *, struct pkt *, int, struct sockaddr_storage*); +struct refclockio; /* in ntp_refclock.h but inclusion here triggers problems */ +extern int io_completion_port_add_clock_io (struct refclockio *rio); + +extern int io_completion_port_sendto (struct interface *, struct pkt *, int, struct sockaddr_storage*); -extern HANDLE get_io_event (void); +extern HANDLE get_io_event (void); -extern HANDLE get_exit_event(void); /* Handle of the exit event */ +extern HANDLE get_exit_event (void); /* Handle of the exit event */ -int GetReceivedBuffers(void); +extern int GetReceivedBuffers (void); # endif diff --git a/ports/winnt/ntpd/ntp_iocompletionport.c b/ports/winnt/ntpd/ntp_iocompletionport.c index 099623879..7c7ec3b67 100644 --- a/ports/winnt/ntpd/ntp_iocompletionport.c +++ b/ports/winnt/ntpd/ntp_iocompletionport.c @@ -25,8 +25,9 @@ enum { SOCK_RECV, SOCK_SEND, - CLOCK_READ, - CLOCK_WRITE + SERIAL_WAIT, + SERIAL_READ, + SERIAL_WRITE }; @@ -42,16 +43,31 @@ typedef struct IoCompletionInfo { #define recv_buf buff_space.rbuf #define trans_buf buff_space.tbuf +#if !defined( _W64 ) + /* + * if ULONG_PTR needs to be defined then the build environment + * is pure 32 bit Windows. Since ULONG_PTR and DWORD have + * the same size in 32 bit Windows we can safely define + * a replacement. + */ + typedef DWORD ULONG_PTR; +#endif + /* * local function definitions */ -static int QueueIORead( struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo); +static int QueueSerialWait(struct refclockio *, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp); -static int OnSocketRecv(DWORD, IoCompletionInfo *, DWORD, int); -static int OnIoReadComplete(DWORD, IoCompletionInfo *, DWORD, int); -static int OnWriteComplete(DWORD, IoCompletionInfo *, DWORD, int); +static int OnSocketRecv(ULONG_PTR, IoCompletionInfo *, DWORD, int); +static int OnSerialWaitComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int); +static int OnSerialReadComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int); +static int OnWriteComplete(ULONG_PTR, IoCompletionInfo *, DWORD, int); +/* #define USE_HEAP */ + +#ifdef USE_HEAP static HANDLE hHeapHandle = NULL; +#endif static HANDLE hIoCompletionPort = NULL; @@ -61,8 +77,6 @@ static HANDLE WaitableExitEventHandle = NULL; #define MAXHANDLES 3 HANDLE WaitHandles[MAXHANDLES] = { NULL, NULL, NULL }; -#define USE_HEAP - IoCompletionInfo * GetHeapAlloc(char *fromfunc) { @@ -73,25 +87,17 @@ GetHeapAlloc(char *fromfunc) HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo)); #else - lpo = (IoCompletionInfo *) calloc(1, sizeof(IoCompletionInfo)); -#endif -#ifdef DEBUG - if (debug > 3) { - printf("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo); - } + lpo = (IoCompletionInfo *) calloc(1, sizeof(*lpo)); #endif + DPRINTF(3, ("Allocation %d memory for %s, ptr %x\n", sizeof(IoCompletionInfo), fromfunc, lpo)); + return (lpo); } void FreeHeap(IoCompletionInfo *lpo, char *fromfunc) { -#ifdef DEBUG - if (debug > 3) - { - printf("Freeing memory for %s, ptr %x\n", fromfunc, lpo); - } -#endif + DPRINTF(3, ("Freeing memory for %s, ptr %x\n", fromfunc, lpo)); #ifdef USE_HEAP HeapFree(hHeapHandle, 0, lpo); @@ -103,7 +109,7 @@ FreeHeap(IoCompletionInfo *lpo, char *fromfunc) transmitbuf_t * get_trans_buf() { - transmitbuf_t *tb = calloc(sizeof(transmitbuf_t), 1); + transmitbuf_t *tb = (transmitbuf_t *) emalloc(sizeof(transmitbuf_t)); tb->wsabuf.len = 0; tb->wsabuf.buf = (char *) &tb->pkt; return (tb); @@ -133,19 +139,21 @@ static void signal_io_completion_port_exit() { if (!PostQueuedCompletionStatus(hIoCompletionPort, 0, 0, 0)) { - msyslog(LOG_ERR, "Can't request service thread to exit: %m"); - exit(1); + DPRINTF(1, ("Can't request IO thread to exit: %d\n", GetLastError())); } } -static void +static unsigned WINAPI iocompletionthread(void *NotUsed) { BOOL bSuccess = FALSE; int errstatus = 0; DWORD BytesTransferred = 0; - DWORD Key = 0; + ULONG_PTR Key = 0; IoCompletionInfo * lpo = NULL; + u_long time_next_ifscan_after_error = 0; + + /* UNUSED_ARG(NotUsed); */ /* Set the thread priority high enough so I/O will * preempt normal recv packet processing, but not @@ -156,39 +164,48 @@ iocompletionthread(void *NotUsed) } while (TRUE) { - bSuccess = GetQueuedCompletionStatus(hIoCompletionPort, - &BytesTransferred, - &Key, - & (LPOVERLAPPED) lpo, - INFINITE); + bSuccess = GetQueuedCompletionStatus( + hIoCompletionPort, + &BytesTransferred, + &Key, + (LPOVERLAPPED *) &lpo, + INFINITE); if (lpo == NULL) { -#ifdef DEBUG - if (debug > 2) { - printf("Overlapped IO Thread Exits: \n"); - } -#endif + DPRINTF(2, ("Overlapped IO Thread Exiting\n")); break; /* fail */ } /* * Deal with errors */ - errstatus = 0; - if (!bSuccess) + if (bSuccess) + errstatus = 0; + else { errstatus = GetLastError(); - if (BytesTransferred == 0 && errstatus == WSA_OPERATION_ABORTED) + if (BytesTransferred == 0) { -#ifdef DEBUG - if (debug > 2) { - printf("Transfer Operation aborted\n"); + if (WSA_OPERATION_ABORTED == errstatus) { + DPRINTF(4, ("Transfer Operation aborted\n")); + } else if (ERROR_UNEXP_NET_ERR == errstatus) { + /* + * We get this error when trying to send an the network + * interface is gone or has lost link. Rescan interfaces + * to catch on sooner, but no more than once per minute. + * Once ntp is able to detect changes without polling + * this should be unneccessary + */ + if (time_next_ifscan_after_error < current_time) { + time_next_ifscan_after_error = current_time + 60; + timer_interfacetimeout(current_time); + } + DPRINTF(4, ("sendto unexpected network error, interface may be down\n")); } -#endif } else { - msyslog(LOG_ERR, "Error transferring packet after %d bytes: %m", BytesTransferred); + msyslog(LOG_ERR, "sendto error after %d bytes: %m", BytesTransferred); } } @@ -198,26 +215,27 @@ iocompletionthread(void *NotUsed) */ switch(lpo->request_type) { - case CLOCK_READ: - OnIoReadComplete(Key, lpo, BytesTransferred, errstatus); + case SERIAL_WAIT: + OnSerialWaitComplete(Key, lpo, BytesTransferred, errstatus); + break; + case SERIAL_READ: + OnSerialReadComplete(Key, lpo, BytesTransferred, errstatus); break; case SOCK_RECV: OnSocketRecv(Key, lpo, BytesTransferred, errstatus); break; case SOCK_SEND: - case CLOCK_WRITE: + case SERIAL_WRITE: OnWriteComplete(Key, lpo, BytesTransferred, errstatus); break; default: -#if DEBUG - if (debug > 2) { - printf("Unknown request type %d found in completion port\n", - lpo->request_type); - } -#endif + DPRINTF(1, ("Unknown request type %d found in completion port\n", + lpo->request_type)); break; } } + + return 0; } /* Create/initialise the I/O creation port @@ -227,7 +245,10 @@ init_io_completion_port( void ) { + unsigned tid; + HANDLE thread; +#ifdef USE_HEAP /* * Create a handle to the Heap */ @@ -237,33 +258,29 @@ init_io_completion_port( msyslog(LOG_ERR, "Can't initialize Heap: %m"); exit(1); } - +#endif /* Create the event used to signal an IO event */ - WaitableIoEventHandle = CreateEvent(NULL, FALSE, FALSE, "WaitableIoEventHandle"); - if (WaitableIoEventHandle == NULL) { - msyslog(LOG_ERR, - "Can't create I/O event handle: %m - another process may be running - EXITING"); - exit(1); - } + WaitableIoEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL); + /* Create the event used to signal an exit event */ - WaitableExitEventHandle = CreateEvent(NULL, FALSE, FALSE, "WaitableExitEventHandle"); - if (WaitableExitEventHandle == NULL) { - msyslog(LOG_ERR, - "Can't create exit event handle: %m - another process may be running - EXITING"); - exit(1); - } + WaitableExitEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL); /* Create the IO completion port */ hIoCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); - if (hIoCompletionPort == NULL) { - msyslog(LOG_ERR, "Can't create I/O completion port: %m"); + +#ifdef DEBUG + if (NULL == WaitableExitEventHandle || + NULL == WaitableIoEventHandle || + NULL == hIoCompletionPort) { + DPRINTF(1, ("init_io_completion_port: Can't create event or port\n")); exit(1); } - +#endif + /* * Initialize the Wait Handles */ @@ -274,7 +291,15 @@ init_io_completion_port( /* Have one thread servicing I/O - there were 4, but this would * somehow cause NTP to stop replying to ntpq requests; TODO */ - _beginthread(iocompletionthread, 0, NULL); + thread = (HANDLE)_beginthreadex( + NULL, + 0, + iocompletionthread, + NULL, + CREATE_SUSPENDED, + &tid); + ResumeThread(thread); + CloseHandle(thread); } @@ -291,25 +316,18 @@ uninit_io_completion_port( } -static int QueueIORead( struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo) { - - lpo->request_type = CLOCK_READ; +static int QueueSerialWait(struct refclockio *rio, recvbuf_t *buff, IoCompletionInfo *lpo, BOOL clear_timestamp) +{ + lpo->request_type = SERIAL_WAIT; lpo->recv_buf = buff; - buff->fd = rio->fd; - if (!ReadFile((HANDLE) buff->fd, buff->wsabuff.buf, buff->wsabuff.len, NULL, (LPOVERLAPPED) lpo)) { - DWORD Result = GetLastError(); - switch (Result) { - case NO_ERROR : - case ERROR_HANDLE_EOF : - case ERROR_IO_PENDING : - break ; + if (clear_timestamp) + memset(&buff->recv_time, 0, sizeof(buff->recv_time)); - /* - * Something bad happened - */ - default: - msyslog(LOG_ERR, "Can't read from Refclock: %m"); + buff->fd = _get_osfhandle(rio->fd); + if (!WaitCommEvent((HANDLE) buff->fd, (DWORD *)&buff->recv_buffer, (LPOVERLAPPED) lpo)) { + if (ERROR_IO_PENDING != GetLastError()) { + msyslog(LOG_ERR, "Can't wait on Refclock: %m"); freerecvbuf(buff); return 0; } @@ -318,60 +336,135 @@ static int QueueIORead( struct refclockio *rio, recvbuf_t *buff, IoCompletionInf } - -/* Return 1 on Successful Read */ static int -OnIoReadComplete(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) +OnSerialWaitComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) { recvbuf_t *buff; - recvbuf_t *newbuff; struct refclockio * rio = (struct refclockio *) i; + struct peer *pp; l_fp arrival_time; + DWORD comm_mask; + DWORD modem_status; + static const l_fp zero_time = { 0 }; + DWORD dwBytesReturned; + BOOL rc; get_systime(&arrival_time); /* * Get the recvbuf pointer from the overlapped buffer. */ - buff = (recvbuf_t *) lpo->recv_buf; - /* - * Get a new recv buffer for the next packet - */ - newbuff = get_free_recv_buffer_alloc(); - if (newbuff == NULL) { - /* - * recv buffers not available so we drop the packet - * and reuse the buffer. - */ - newbuff = buff; - } - else - { - /* - * ignore 0 bytes read due to timeout's and closure on fd - */ - if (Bytes > 0 && errstatus != WSA_OPERATION_ABORTED) { - memcpy(&buff->recv_time, &arrival_time, sizeof(arrival_time)); - buff->recv_length = (int) Bytes; - buff->receiver = rio->clock_recv; - buff->dstadr = NULL; - buff->recv_srcclock = rio->srcclock; - add_full_recv_buffer(buff); - if( !SetEvent( WaitableIoEventHandle ) ) { + buff = lpo->recv_buf; + comm_mask = (*(DWORD *)&buff->recv_buffer); #ifdef DEBUG - if (debug > 3) { - printf( "Error %d setting IoEventHandle\n", GetLastError() ); - } + if (errstatus || comm_mask & ~(EV_RXFLAG | EV_RLSD)) { + msyslog(LOG_ERR, "WaitCommEvent returned unexpected mask %x errstatus %d", + comm_mask, errstatus); + exit(-1); + } #endif + if (comm_mask & EV_RLSD) { + modem_status = 0; + GetCommModemStatus((HANDLE)buff->fd, &modem_status); + if (modem_status & MS_RLSD_ON) { + /* + * Use the timestamp from this PPS CD not + * the later end of line. + */ + buff->recv_time = arrival_time; + } + + if (!(comm_mask & EV_RXFLAG)) { + /* + * if we didn't see an end of line yet + * issue another wait for it. + */ + QueueSerialWait(rio, buff, lpo, FALSE); + return 1; } } - else - { + + /* + * We've detected the end of line of serial input. + * Use this timestamp unless we already have a CD PPS + * timestamp in buff->recv_time. + */ + if (memcmp(&buff->recv_time, &zero_time, sizeof buff->recv_time)) { + /* + * We will first see a user PPS timestamp here on either + * the first or second line of text. Log a one-time + * message while processing the second line. + */ + if (1 == rio->recvcount) { + pp = (struct peer *)rio->srcclock; + msyslog(LOG_NOTICE, "Using user-mode PPS timestamp for %s", + refnumtoa(&pp->srcadr)); + } + } else { + buff->recv_time = arrival_time; + } + + /* + * Now that we have a complete line waiting, read it. + * There is still a race here, but we're likely to win. + */ + + lpo->request_type = SERIAL_READ; + + rc = ReadFile( + (HANDLE)buff->fd, + buff->wsabuff.buf, + buff->wsabuff.len, + &buff->wsabuff.len, + (LPOVERLAPPED) lpo); + + if (!rc && ERROR_IO_PENDING != GetLastError()) { + msyslog(LOG_ERR, "Can't read from Refclock: %m"); freerecvbuf(buff); + return 0; + } + + return 1; +} + +/* Return 1 on Successful Read */ +static int +OnSerialReadComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) +{ + recvbuf_t *buff; + struct refclockio * rio = (struct refclockio *) i; + + /* + * Get the recvbuf pointer from the overlapped buffer. + */ + buff = lpo->recv_buf; + + /* + * ignore 0 bytes read due to timeout's and closure on fd + */ + if (!errstatus && Bytes) { + buff->recv_length = (int) Bytes; + buff->receiver = rio->clock_recv; + buff->dstadr = NULL; + buff->recv_srcclock = rio->srcclock; + packets_received++; + /* + * Eat the first line of input as it's possibly + * partial and if a PPS is present, it may not + * have fired since the port was opened. + */ + if (rio->recvcount++) { + add_full_recv_buffer(buff); + /* + * Now signal we have something to process + */ + SetEvent(WaitableIoEventHandle); + buff = get_free_recv_buffer_alloc(); } } - QueueIORead( rio, newbuff, lpo ); + QueueSerialWait(rio, buff, lpo, TRUE); + return 1; } @@ -386,7 +479,7 @@ io_completion_port_add_clock_io( IoCompletionInfo *lpo; recvbuf_t *buff; - if (NULL == CreateIoCompletionPort((HANDLE) rio->fd, hIoCompletionPort, (DWORD) rio, 0)) { + if (NULL == CreateIoCompletionPort((HANDLE)_get_osfhandle(rio->fd), hIoCompletionPort, (ULONG_PTR) rio, 0)) { msyslog(LOG_ERR, "Can't add COM port to i/o completion port: %m"); return 1; } @@ -399,19 +492,16 @@ io_completion_port_add_clock_io( } buff = get_free_recv_buffer_alloc(); - - if (buff == NULL) - { - msyslog(LOG_ERR, "Can't allocate memory for clock socket: %m"); - FreeHeap(lpo, "io_completion_port_add_clock_io"); - return 1; - } - QueueIORead( rio, buff, lpo ); + QueueSerialWait(rio, buff, lpo, TRUE); return 0; } -/* Queue a receiver on a socket. Returns 0 if no buffer can be queued */ - +/* + * Queue a receiver on a socket. Returns 0 if no buffer can be queued + * + * Note: As per the winsock documentation, we use WSARecvFrom. Using + * ReadFile() is less efficient. + */ static unsigned long QueueSocketRecv(SOCKET s, recvbuf_t *buff, IoCompletionInfo *lpo) { int AddrLen; @@ -433,8 +523,6 @@ static unsigned long QueueSocketRecv(SOCKET s, recvbuf_t *buff, IoCompletionInfo DWORD Result = WSAGetLastError(); switch (Result) { case NO_ERROR : - case WSA_IO_INCOMPLETE : - case WSA_WAIT_IO_COMPLETION : case WSA_IO_PENDING : break ; @@ -465,7 +553,7 @@ static unsigned long QueueSocketRecv(SOCKET s, recvbuf_t *buff, IoCompletionInfo /* Returns 0 if any Error */ static int -OnSocketRecv(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) +OnSocketRecv(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) { struct recvbuf *buff = NULL; recvbuf_t *newbuff; @@ -473,7 +561,7 @@ OnSocketRecv(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) l_fp arrival_time; struct interface * inter = (struct interface *) i; - get_systime(&arrival_time); + get_systime(&arrival_time); /* Convert the overlapped pointer back to a recvbuf pointer. */ @@ -505,65 +593,49 @@ OnSocketRecv(DWORD i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) /* - * Get a new recv buffer for the next packet + * Get a new recv buffer for the replacement socket receive */ newbuff = get_free_recv_buffer_alloc(); - if (newbuff == NULL) { - /* - * recv buffers not available so we drop the packet - * and reuse the buffer. - */ - newbuff = buff; - } - else - { - ignore_this = inter->ignore_packets; + QueueSocketRecv(inter->fd, newbuff, lpo); - /* - * If we keep it add some info to the structure - */ - if (Bytes > 0 && ignore_this == ISC_FALSE) { - memcpy(&buff->recv_time, &arrival_time, sizeof(arrival_time)); - buff->recv_length = (int) Bytes; - buff->receiver = receive; - buff->dstadr = inter; -#ifdef DEBUG - if (debug > 1) - printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr)); -#endif - add_full_recv_buffer(buff); - /* - * Now signal we have something to process - */ - if( !SetEvent( WaitableIoEventHandle ) ) { + ignore_this = inter->ignore_packets; + + /* + * If we keep it add some info to the structure + */ + if (Bytes > 0 && ignore_this == ISC_FALSE) { + memcpy(&buff->recv_time, &arrival_time, sizeof buff->recv_time); + buff->recv_length = (int) Bytes; + buff->receiver = receive; + buff->dstadr = inter; #ifdef DEBUG - if (debug > 1) { - printf( "Error %d setting IoEventHandle\n", GetLastError() ); - } + if (debug > 1) + printf("Received %d bytes of fd %d in buffer %x from %s\n", Bytes, buff->fd, buff, stoa(&buff->recv_srcadr)); #endif - } - } - else { - freerecvbuf(buff); - } + packets_received++; + inter->received++; + add_full_recv_buffer(buff); + /* + * Now signal we have something to process + */ + SetEvent(WaitableIoEventHandle); } - if (newbuff != NULL) - QueueSocketRecv(inter->fd, newbuff, lpo); + else + freerecvbuf(buff); + return 1; } -/* Add a socket handle to the I/O completion port, and send an I/O - * read request to the kernel. - * - * Note: As per the winsock documentation, we use WSARecvFrom. Using - * ReadFile() is less efficient. +/* Add a socket handle to the I/O completion port, and send + * NTP_RECVS_PER_SOCKET recv requests to the kernel. */ extern int io_completion_port_add_socket(SOCKET fd, struct interface *inter) { IoCompletionInfo *lpo; recvbuf_t *buff; + int n; if (fd != INVALID_SOCKET) { if (NULL == CreateIoCompletionPort((HANDLE) fd, hIoCompletionPort, @@ -573,37 +645,50 @@ io_completion_port_add_socket(SOCKET fd, struct interface *inter) } } - lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket"); - if (lpo == NULL) - { - msyslog(LOG_ERR, "Can't allocate heap for completion port: %m"); - return 1; - } +#define WINDOWS_RECVS_PER_SOCKET 4 - buff = get_free_recv_buffer_alloc(); + for (n = 0; n < WINDOWS_RECVS_PER_SOCKET; n++) { - if (buff == NULL) - { - msyslog(LOG_ERR, "Can't allocate memory for network socket: %m"); - FreeHeap(lpo, "io_completion_port_add_socket"); - return 1; - } + buff = get_free_recv_buffer_alloc(); + lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_add_socket"); + if (lpo == NULL) + { + msyslog(LOG_ERR, "Can't allocate heap for completion port: %m"); + return 1; + } + + QueueSocketRecv(fd, buff, lpo); - QueueSocketRecv(fd, buff, lpo); + } return 0; } static int -OnWriteComplete(DWORD Key, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) +OnWriteComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) { transmitbuf_t *buff; - (void) Bytes; - (void) Key; + struct interface *inter; + + /* UNUSED_ARG(Bytes); */ buff = lpo->trans_buf; free_trans_buf(buff); + if (SOCK_SEND == lpo->request_type) { + switch (errstatus) { + case WSA_OPERATION_ABORTED: + case NO_ERROR: + break; + + default: + inter = (struct interface *)i; + packets_notsent++; + inter->notsent++; + break; + } + } + if (errstatus == WSA_OPERATION_ABORTED) FreeHeap(lpo, "OnWriteComplete: Socket Closed"); else @@ -612,7 +697,12 @@ OnWriteComplete(DWORD Key, IoCompletionInfo *lpo, DWORD Bytes, int errstatus) } -DWORD +/* + * Return value is really GetLastError-style error code + * which is a DWORD but using int, which is large enough, + * decreases #ifdef forest in ntp_io.c harmlessly. + */ +int io_completion_port_sendto( struct interface *inter, struct pkt *pkt, @@ -659,8 +749,6 @@ io_completion_port_sendto( switch (errval) { case NO_ERROR : - case WSA_IO_INCOMPLETE : - case WSA_WAIT_IO_COMPLETION : case WSA_IO_PENDING : Result = ERROR_SUCCESS; break ; @@ -691,72 +779,66 @@ io_completion_port_sendto( /* - * Async IO Write + * async_write, clone of write(), used by some reflock drivers */ -DWORD -io_completion_port_write( - HANDLE fd, - char *pkt, - int len) +int +async_write( + int fd, + const void *data, + unsigned int count) { - DWORD errval; - transmitbuf_t *buff = NULL; - DWORD lpNumberOfBytesWritten; - DWORD Result = ERROR_INSUFFICIENT_BUFFER; + transmitbuf_t *buff; IoCompletionInfo *lpo; + DWORD BytesWritten; - lpo = (IoCompletionInfo *) GetHeapAlloc("io_completion_port_write"); + if (count > sizeof buff->pkt) { +#ifdef DEBUG + if (debug) { + printf("async_write: %d bytes too large, limit is %d\n", + count, sizeof buff->pkt); + exit(-1); + } +#endif + errno = ENOMEM; + return -1; + } - if (lpo == NULL) - return ERROR_OUTOFMEMORY; + buff = get_trans_buf(); + lpo = (IoCompletionInfo *) GetHeapAlloc("async_write"); - if (len <= sizeof(buff->pkt)) { - buff = get_trans_buf(); - if (buff == NULL) { + if (! buff || ! lpo) { + if (buff) { + free_trans_buf(buff); +#ifdef DEBUG + if (debug) + printf("async_write: out of memory, \n"); +#endif + } else { msyslog(LOG_ERR, "No more transmit buffers left - data discarded"); - FreeHeap(lpo, "io_completion_port_write"); } - lpo->request_type = CLOCK_WRITE; - lpo->trans_buf = buff; - memcpy(&buff->pkt, pkt, len); + errno = ENOMEM; + return -1; + } - Result = WriteFile(fd, buff->pkt, len, &lpNumberOfBytesWritten, (LPOVERLAPPED) lpo); + lpo->request_type = SERIAL_WRITE; + lpo->trans_buf = buff; + memcpy(&buff->pkt, data, count); - if(Result == SOCKET_ERROR) - { - errval = WSAGetLastError(); - switch (errval) { + if (! WriteFile((HANDLE)_get_osfhandle(fd), buff->pkt, count, &BytesWritten, (LPOVERLAPPED) lpo) && + ERROR_IO_PENDING != GetLastError()) { - case NO_ERROR : - case WSA_IO_INCOMPLETE : - case WSA_WAIT_IO_COMPLETION : - case WSA_IO_PENDING : - Result = ERROR_SUCCESS; - break ; - - default : - netsyslog(LOG_ERR, "WriteFile - error sending message: %m"); - free_trans_buf(buff); - FreeHeap(lpo, "io_completion_port_write"); - break; - } - } -#ifdef DEBUG - if (debug > 2) { - printf("WriteFile - %d bytes %d\n", len, Result); - } -#endif - if (Result) return len; + msyslog(LOG_ERR, "async_write - error %m"); + free_trans_buf(buff); + FreeHeap(lpo, "async_write"); + errno = EBADF; + return -1; } - else { -#ifdef DEBUG - if (debug) printf("Packet too large: %d Bytes\n", len); -#endif - } - return Result; + + return count; } + /* * GetReceivedBuffers * Note that this is in effect the main loop for processing requests diff --git a/ports/winnt/ntpd/win32_io.c b/ports/winnt/ntpd/win32_io.c index c4a740703..20aa6dc89 100644 --- a/ports/winnt/ntpd/win32_io.c +++ b/ports/winnt/ntpd/win32_io.c @@ -1,19 +1,18 @@ -/* This file implementes system calls that are not compatible with UNIX */ - -#ifdef HAVE_CONFIG_H -# include -#endif - +/* This file implements system calls that are not compatible with UNIX */ +#include #include #include "ntp_machine.h" #include "ntp_stdlib.h" #include "ntp_syslog.h" +#include "ntp_debug.h" #include "ntp_fp.h" #include "ntp.h" #include "ntp_refclock.h" #include "win32_io.h" +#define MAX_SERIAL 16 /* COM1-COM16 */ + int NT_set_process_priority(void) { @@ -26,14 +25,100 @@ int NT_set_process_priority(void) return 1; } + +/* + * common_serial_open ensures duplicate opens of the same port + * work by duplicating the handle for the 2nd open, allowing + * refclock_atom to share a GPS refclock's comm port. + * + */ + +HANDLE common_serial_open( + char *dev + ) +{ + static HANDLE SerialHandles[MAX_SERIAL+1] = {0}; + HANDLE RetHandle; + int unit; + + if (1 != sscanf(dev, "COM%d:", &unit) || unit > MAX_SERIAL) + return INVALID_HANDLE_VALUE; + + if (!SerialHandles[unit]) + SerialHandles[unit] = CreateFile( + dev, + GENERIC_READ | GENERIC_WRITE, + 0, /* sharing prohibited */ + NULL, /* default security */ + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + + if (INVALID_HANDLE_VALUE == SerialHandles[unit]) { + SerialHandles[unit] = 0; + return INVALID_HANDLE_VALUE; + } + + DuplicateHandle( + GetCurrentProcess(), + SerialHandles[unit], + GetCurrentProcess(), + &RetHandle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS + ); + + return RetHandle; +} + +/* + * pps_open - open serial port for PPS + * + * This routine opens a serial port for and returns the + * file descriptor if success and -1 if failure. + */ +int pps_open( + char *dev, /* device name pointer */ + int access, /* O_RDWR */ + int mode /* unused */ + ) +{ + HANDLE Handle; + char windev[3 + 20 + 1 + 1]; + int unit; + + if (1 != sscanf(dev, "/dev/pps%d", &unit)) { + errno = ENOENT; + return -1; + } + /* + * there never is a COM0: but this is the ntp convention + */ + _snprintf(windev, sizeof(windev)-1, "COM%d:", unit); + windev[sizeof(windev)-1] = 0; + + /* + * open communication port handle + */ + Handle = common_serial_open(windev); + + if (Handle == INVALID_HANDLE_VALUE) { + msyslog(LOG_ERR, "pps_open: Device %s CreateFile error: %m", windev); + errno = EMFILE; /* lie, lacking conversion from GetLastError() */ + return -1; + } + + return (int) _open_osfhandle((int)Handle, _O_TEXT); +} + /* * refclock_open - open serial port for reference clock * * This routine opens a serial port for I/O and sets default options. It * returns the file descriptor if success and zero if failure. */ -int -refclock_open( +int refclock_open( char *dev, /* device name pointer */ u_int speed, /* serial port speed (code) */ u_int flags /* line discipline flags */ @@ -41,35 +126,30 @@ refclock_open( { HANDLE Handle = INVALID_HANDLE_VALUE; COMMTIMEOUTS timeouts; - DCB dcb = {0}; - - // - // open communication port handle - // - Handle = CreateFile(dev, - GENERIC_READ | GENERIC_WRITE, - 0, // no sharing - NULL, // no security - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - NULL); // not template + DCB dcb; + + /* + * open communication port handle + */ + Handle = common_serial_open(dev); + if (Handle == INVALID_HANDLE_VALUE) { - msyslog(LOG_ERR, "NT_COM: Device %s: CreateFile error: %m", dev); + msyslog(LOG_ERR, "NT_COM: Device %s CreateFile error: %m", dev); return -1; } /* Change the input/output buffers to be large. */ if (!SetupComm( Handle, 1024, 1024)) { - msyslog(LOG_ERR, "NT_COM: Device %s: SetupComm error: %m", dev); + msyslog(LOG_ERR, "NT_COM: Device %s SetupComm error: %m", dev); return -1; } dcb.DCBlength = sizeof(dcb); if (!GetCommState(Handle, &dcb)) { // Error getting current DCB settings - msyslog(LOG_ERR, "NT_COM: Device %s: GetCommState error: %m", dev); + msyslog(LOG_ERR, "NT_COM: Device %s GetCommState error: %m", dev); return -1; } @@ -81,20 +161,21 @@ refclock_open( case B9600 : dcb.BaudRate = 9600; break; case B19200 : dcb.BaudRate = 19200; break; case B38400 : dcb.BaudRate = 38400; break; + case B57600 : dcb.BaudRate = 57600; break; + case B115200 : dcb.BaudRate = 115200; break; default : - msyslog(LOG_ERR, "NT_COM: Device %s: unsupported baud rate", dev); + msyslog(LOG_ERR, "NT_COM: Device %s unsupported baud rate", dev); return -1; } - dcb.ByteSize = 8; dcb.fBinary = TRUE; dcb.fParity = TRUE; dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fDsrSensitivity = 0; - dcb.fTXContinueOnXoff = FALSE; + dcb.fTXContinueOnXoff = TRUE; dcb.fOutX = 0; dcb.fInX = 0; dcb.fErrorChar = 0; @@ -105,41 +186,56 @@ refclock_open( dcb.StopBits = ONESTOPBIT; dcb.Parity = NOPARITY; dcb.ErrorChar = 0; - dcb.EvtChar = 0; + dcb.EvtChar = 13; /* CR */ dcb.EofChar = 0; if (!SetCommState(Handle, &dcb)) { - msyslog(LOG_ERR, "NT_COM: Device %s: SetCommState error: %m", dev); + msyslog(LOG_ERR, "NT_COM: Device %s SetCommState error: %m", dev); + return -1; + } + + /* watch out for CR (dcb.EvtChar) as well as the CD line */ + if (!SetCommMask(Handle, EV_RXFLAG | EV_RLSD)) { + msyslog(LOG_ERR, "NT_COM: Device %s SetCommMask error: %m", dev); return -1; } - timeouts.ReadIntervalTimeout = 20; + /* configure the handle to never block */ + timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.ReadTotalTimeoutConstant = 5000; + timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 5000; + timeouts.WriteTotalTimeoutConstant = 0; - // Error setting time-outs. if (!SetCommTimeouts(Handle, &timeouts)) { - msyslog(LOG_ERR, "NT_COM: Device %s: SetCommTimeouts error: %m", dev); + msyslog(LOG_ERR, "NT_COM: Device %s SetCommTimeouts error: %m", dev); return -1; } - return (int) Handle; + return (int) _open_osfhandle((int)Handle, _O_TEXT); } - int ioctl(int fd, - int cmd, - int *x) { + int cmd, + int *x) +{ + HANDLE h = (HANDLE) _get_osfhandle(fd); if ((cmd == TIOCMSET) && (*x & TIOCM_RTS)) { - if (!EscapeCommFunction((HANDLE) fd, SETRTS)) + if (!EscapeCommFunction(h, SETRTS)) return -1; } else if ((cmd == TIOCMSET) && !(*x & TIOCM_RTS)){ - if (!EscapeCommFunction((HANDLE) fd, CLRRTS)) + if (!EscapeCommFunction(h, CLRRTS)) + return -1; + } + if ((cmd == TIOCMSET) && (*x & TIOCM_DTR)) { + if (!EscapeCommFunction(h, SETDTR)) + return -1; + } + else if ((cmd == TIOCMSET) && !(*x & TIOCM_DTR)){ + if (!EscapeCommFunction(h, CLRDTR)) return -1; } @@ -154,7 +250,7 @@ tcsetattr( const struct termios * s) { DCB dcb = { 0 }; - HANDLE Handle = (HANDLE) fd; + HANDLE Handle = (HANDLE) _get_osfhandle(fd); dcb.DCBlength = sizeof(dcb); if (!GetCommState(Handle, &dcb)) { // Error getting current DCB settings @@ -170,6 +266,8 @@ tcsetattr( case B9600 : dcb.BaudRate = 9600; break; case B19200 : dcb.BaudRate = 19200; break; case B38400 : dcb.BaudRate = 38400; break; + case B57600 : dcb.BaudRate = 57600; break; + case B115200 : dcb.BaudRate = 115200; break; default : msyslog(LOG_ERR, "NT_COM: unsupported baud rate"); return FALSE; @@ -198,24 +296,15 @@ tcsetattr( dcb.fParity = FALSE; dcb.Parity = NOPARITY; } - - - dcb.fOutxCtsFlow = 0; - dcb.fOutxDsrFlow = 0; - dcb.fDtrControl = DTR_CONTROL_DISABLE; - dcb.fDsrSensitivity = 0; - dcb.fOutX = 0; - dcb.fInX = 0; - dcb.fErrorChar = 0; - dcb.fNull = 0; - dcb.fRtsControl = RTS_CONTROL_DISABLE; - dcb.fAbortOnError = 0; - dcb.ErrorChar = 0; - dcb.EvtChar = 0; - dcb.EofChar = 0; + if (s->c_cflag & CSTOPB ) { + dcb.StopBits = TWOSTOPBITS; + } + else { + dcb.StopBits = ONESTOPBIT; + } if (!SetCommState(Handle, &dcb)) { - msyslog(LOG_ERR, "NT_COM: SetCommState error: %m"); + msyslog(LOG_ERR, "NT_COM: SetCommState error 2: %m"); return FALSE; } return TRUE; @@ -225,11 +314,11 @@ extern int tcgetattr( int fd, struct termios *s) { - DCB dcb = { 0 }; - HANDLE Handle = (HANDLE) fd; + DCB dcb; + HANDLE Handle = (HANDLE) _get_osfhandle(fd); + dcb.DCBlength = sizeof(dcb); if (!GetCommState(Handle, &dcb)) { - // Error getting current DCB settings msyslog(LOG_ERR, "NT_COM: GetCommState error: %m"); return FALSE; } @@ -244,6 +333,8 @@ tcgetattr( case 9600 : s->c_ispeed = s->c_ospeed = B9600; break; case 19200 : s->c_ispeed = s->c_ospeed = B19200; break; case 38400 : s->c_ispeed = s->c_ospeed = B38400; break; + case 57600 : s->c_ispeed = s->c_ospeed = B57600; break; + case 115200 : s->c_ispeed = s->c_ospeed = B115200; break; default : s->c_ispeed = s->c_ospeed = B9600; } @@ -265,6 +356,11 @@ tcgetattr( case ODDPARITY : s->c_cflag |= PARODD; break; case SPACEPARITY : break; } + switch (dcb.StopBits) { + case ONESTOPBIT : break; + case ONE5STOPBITS : break; + case TWOSTOPBITS : s->c_cflag |= CSTOPB; break; + } s->c_iflag = 0; s->c_lflag = 0; @@ -276,22 +372,32 @@ tcgetattr( extern int tcflush(int fd, int mode) { - - - - -return 0; - + int Result = 0; + HANDLE h = (HANDLE) _get_osfhandle(fd); + switch ( mode ) { + case TCIFLUSH: + Result = PurgeComm(h, PURGE_RXCLEAR); + break; + case TCOFLUSH: + Result = PurgeComm(h, PURGE_TXABORT); + break; + case TCIOFLUSH: + Result = PurgeComm(h, PURGE_RXCLEAR | PURGE_TXABORT); + break; + } + if ( Result == 0 ) return -1; /* failed */ + else return 0; /* successful */ } + extern int cfsetispeed(struct termios *tio, int speed) { - + return 0; }; extern int cfsetospeed(struct termios *tio, int speed) { - + return 0; };