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