1 /* This file implements i/o calls that are specific to Windows */
2 
3 #include <config.h>
4 #include <stdio.h>
5 #include "ntp_fp.h"
6 #include "ntp_net.h"
7 #include "ntp_stdlib.h"
8 #include "ntp_syslog.h"
9 #include "win32_io.h"
10 #include <isc/win32os.h>
11 
12 /*
13  * Define this macro to control the behavior of connection
14  * resets on UDP sockets.  See Microsoft KnowledgeBase Article Q263823
15  * for details.
16  * Based on that article, it is surprising that a much newer winsock2.h
17  * does not define SIO_UDP_CONNRESET (the one that comes with VS 2008).
18  * NOTE: This requires that Windows 2000 systems install Service Pack 2
19  * or later.
20  */
21 #ifndef SIO_UDP_CONNRESET
22 #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
23 #endif
24 
25 void
InitSockets(void)26 InitSockets(
27 	void
28 	)
29 {
30 	WORD wVersionRequested;
31 	WSADATA wsaData;
32 	int err;
33 
34 	/* Need Winsock 2.0 or better */
35 	wVersionRequested = MAKEWORD(2, 0);
36 
37 	err = WSAStartup(wVersionRequested, &wsaData);
38 	if ( err != 0 ) {
39 		SetLastError(err);
40 		mfprintf(stderr, "No usable winsock: %m\n");
41 		SetLastError(err);
42 		msyslog(LOG_ERR, "No usable winsock: %m");
43 		exit(1);
44 	}
45 }
46 
47 /*
48  * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom
49  * to not work correctly, returning a WSACONNRESET error when a WSASendTo
50  * fails with an "ICMP port unreachable" response and preventing the
51  * socket from using the WSARecvFrom in subsequent operations.
52  * The function below fixes this, but requires that Windows 2000
53  * Service Pack 2 or later be installed on the system.  NT 4.0
54  * systems are not affected by this and work correctly.
55  * See Microsoft Knowledge Base Article Q263823 for details of this.
56  */
57 void
connection_reset_fix(SOCKET fd,sockaddr_u * addr)58 connection_reset_fix(
59 	SOCKET		fd,
60 	sockaddr_u *	addr
61 	)
62 {
63 	DWORD dw;
64 	BOOL  bNewBehavior = FALSE;
65 	DWORD status;
66 
67 	/*
68 	 * disable bad behavior using IOCTL: SIO_UDP_CONNRESET
69 	 * NT 4.0 has no problem
70 	 */
71 	if (isc_win32os_majorversion() >= 5) {
72 		status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
73 				  sizeof(bNewBehavior), NULL, 0,
74 				  &dw, NULL, NULL);
75 		if (SOCKET_ERROR == status)
76 			msyslog(LOG_ERR,
77 				"connection_reset_fix() failed for address %s: %m",
78 				stoa(addr));
79 	}
80 }
81 
82