1 /*
2   Copyright (c) Fabasoft R&D Software GmbH & Co KG, 2003
3   oss@fabasoft.com
4   Author: Bernhard Penz <bernhard.penz@fabasoft.com>
5 
6   Redistribution and use in source and binary forms, with or without
7   modification, are permitted provided that the following conditions are met:
8 
9   *  Redistributions of source code must retain the above copyright notice,
10      this list of conditions and the following disclaimer.
11 
12   *  Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15 
16   *  The name of Fabasoft R&D Software GmbH & Co KG or any of its subsidiaries,
17      brand or product names may not be used to endorse or promote products
18      derived from this software without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY
21   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
24   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29   OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 #ifdef WIN32
34 
35 #include <net-snmp/net-snmp-config.h>
36 #include <net-snmp/types.h>
37 #include <net-snmp/library/snmp_assert.h>
38 #include <net-snmp/library/winpipe.h>
39 #include <io.h>
40 
InitUPDSocket(SOCKET * sock,struct sockaddr_in * socketaddress)41 static int InitUPDSocket(SOCKET *sock, struct sockaddr_in *socketaddress)
42 {
43 	*sock = 0;
44 	memset(socketaddress, 0, sizeof(struct sockaddr_in));
45 
46 	if( (*sock = socket(AF_INET, SOCK_DGRAM, 0)) == SOCKET_ERROR)
47 	{
48 		netsnmp_assert(GetLastError() != WSANOTINITIALISED);
49 		return -1;
50 	}
51 	socketaddress->sin_family = AF_INET;
52 	socketaddress->sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK);
53 	socketaddress->sin_port = 0;
54 
55 	if(bind(*sock, (struct sockaddr *) socketaddress, sizeof(struct sockaddr)) == SOCKET_ERROR)
56 	{
57 		return -1;
58 	}
59 
60 	return 0;
61 }
62 
ConnectUDPSocket(SOCKET * sock,struct sockaddr_in * socketaddress,SOCKET * remotesocket)63 static int ConnectUDPSocket(SOCKET *sock, struct sockaddr_in *socketaddress, SOCKET *remotesocket)
64 {
65 	int size = sizeof(struct sockaddr);
66 	if (getsockname(*sock, (struct sockaddr *) socketaddress, &size) == SOCKET_ERROR)
67 	{
68 		return -1;
69 	}
70 
71 	if(size != sizeof(struct sockaddr))
72 	{
73 		return -1;
74 	}
75 
76 	if (connect(*remotesocket, (struct sockaddr *) socketaddress, sizeof(struct sockaddr)) == SOCKET_ERROR)
77 	{
78 		return -1;
79 	}
80 
81 	return 0;
82 }
83 
TestUDPSend(SOCKET * sock,struct sockaddr_in * socketaddress)84 static int TestUDPSend(SOCKET *sock, struct sockaddr_in *socketaddress)
85 {
86 	unsigned short port = socketaddress->sin_port;
87 
88 	int bytessent = sendto(*sock, (char *) &port, sizeof(port), 0, NULL, 0);
89 	if(bytessent != sizeof(port))
90 	{
91 		return -1;
92 	}
93 
94 	return 0;
95 }
96 
TestUDPReceive(SOCKET * sock,SOCKET * remotesocket,struct sockaddr_in * remotesocketaddress)97 static int TestUDPReceive(SOCKET *sock, SOCKET *remotesocket, struct sockaddr_in *remotesocketaddress)
98 {
99 	struct sockaddr_in recvfromaddress;
100 	unsigned short readbuffer[2];
101 	int size = sizeof(struct sockaddr);
102 
103 	int bytesreceived = recvfrom(*sock,(char *) &readbuffer, sizeof(readbuffer), 0, (struct sockaddr *) &recvfromaddress, &size) ;
104 	if(bytesreceived != sizeof(unsigned short) || size != sizeof(struct sockaddr) || readbuffer[0] != (unsigned short) remotesocketaddress->sin_port || recvfromaddress.sin_family != remotesocketaddress->sin_family || recvfromaddress.sin_addr.S_un.S_addr != remotesocketaddress->sin_addr.S_un.S_addr || recvfromaddress.sin_port != remotesocketaddress->sin_port)
105 	{
106 		return -1;
107 	}
108 
109 	return 0;
110 }
111 
CloseUDPSocketPair(SOCKET * socketpair)112 static void CloseUDPSocketPair(SOCKET *socketpair)
113 {
114 	if(socketpair[0] != INVALID_SOCKET)
115 	{
116 		closesocket(socketpair[0]);
117 	}
118 	if(socketpair[1] != INVALID_SOCKET)
119 	{
120 		closesocket(socketpair[1]);
121 	}
122 }
123 
124 /*
125 	Windows unnamed pipe emulation, used to enable select()
126 	on a Windows machine for the CALLBACK (pipe-based) transport domain.
127 */
create_winpipe_transport(int * pipefds)128 int create_winpipe_transport(int *pipefds)
129 {
130 	SOCKET socketpair[2];
131 	struct sockaddr_in socketaddress[2];
132 
133 	NETSNMP_SELECT_TIMEVAL waittime = {0, 200000};
134 	fd_set readset;
135 
136 	if (InitUPDSocket(&socketpair[0], &socketaddress[0]))
137 	{
138 		CloseUDPSocketPair(socketpair);
139 		return -1;
140 	}
141 	if (InitUPDSocket(&socketpair[1], &socketaddress[1]))
142 	{
143 		CloseUDPSocketPair(socketpair);
144 		return -1;
145 	}
146 
147 	/*
148 		I have two UDP sockets - now lets connect them to each other.
149 	*/
150 
151 	if (ConnectUDPSocket(&socketpair[0], &socketaddress[0], &socketpair[1]))
152 	{
153 		CloseUDPSocketPair(socketpair);
154 		return -1;
155 	}
156 	if(ConnectUDPSocket(&socketpair[1], &socketaddress[1], &socketpair[0]))
157 	{
158 		CloseUDPSocketPair(socketpair);
159 		return -1;
160 	}
161 
162 	/*
163 		The two sockets are connected to each other, now lets test the connection
164 		by sending the own port number.
165 	*/
166 	if(TestUDPSend(&socketpair[0], &socketaddress[0]))
167 	{
168 		CloseUDPSocketPair(socketpair);
169 		return -1;
170 	}
171 	if(TestUDPSend(&socketpair[1], &socketaddress[1]))
172 	{
173 		CloseUDPSocketPair(socketpair);
174 		return -1;
175 	}
176 
177 	/*
178 		Port numbers sent, now lets select() on the socketpair and check that
179 		both messages got through
180 	*/
181 	FD_ZERO(&readset);
182 	FD_SET(socketpair[0], &readset);
183 	FD_SET(socketpair[1], &readset);
184 
185 	/*
186 		For some unknown reason the timeout setting in the select call does not have
187 		the desired effect, and for yet another unknown reason a Sleep(1) solves this
188 		problem.
189 	*/
190 	Sleep(1);
191 	if(select(0, &readset, NULL, NULL, &waittime) != 2 || !FD_ISSET(socketpair[0], &readset) || !FD_ISSET(socketpair[1], &readset))
192 	{
193 		CloseUDPSocketPair(socketpair);
194 		return -1;
195 	}
196 
197 	/*
198 		Check if the packets I receive were really sent by me, and nobody else
199 		tried to sneak.
200 	*/
201     if(TestUDPReceive(&socketpair[0], &socketpair[1], &socketaddress[1]))
202 	{
203 		CloseUDPSocketPair(socketpair);
204 		return -1;
205 	}
206 	if(TestUDPReceive(&socketpair[1], &socketpair[0], &socketaddress[0]))
207 	{
208 		CloseUDPSocketPair(socketpair);
209 		return -1;
210 	}
211 
212 	/*
213 		All sanity checks passed, I can return a "UDP pipe"
214 	*/
215 	pipefds[0] = (int) socketpair[0];
216 	pipefds[1] = (int) socketpair[1];
217 
218 	return 0;
219 }
220 
221 #endif /* WIN32 */
222 
223