More cleanup of OS-specific interface, this times with win32
[olsrd.git] / src / win32 / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #if defined WINCE
43 #include <sys/types.h>          // for time_t
44 #endif
45
46 #define WIN32_LEAN_AND_MEAN
47 #include <windows.h>
48 #include <winsock2.h>
49 #include <ws2tcpip.h>
50 #include <iphlpapi.h>
51 #undef interface
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <errno.h>
56
57 #include "defs.h"
58 #include "os_net.h"
59 #include "net_olsr.h"
60 #include "ipcalc.h"
61 #include "olsr_logging.h"
62 #include "win32/compat.h"
63 #if defined WINCE
64 #define WIDE_STRING(s) L##s
65 #else
66 #define WIDE_STRING(s) s
67 #endif
68
69 void WinSockPError(const char *Str);
70 void PError(const char *);
71
72 static void DisableIcmpRedirects(void);
73
74 int
75 os_socket_set_nonblocking(int fd)
76 {
77   /* make the fd non-blocking */
78   unsigned long flags = 1;
79   if (ioctlsocket(fd, FIONBIO, &flags) != 0) {
80     OLSR_WARN(LOG_NETWORKING, "Cannot set the socket flags: %s", StrError(WSAGetLastError()));
81     return -1;
82   }
83   return 0;
84 }
85
86 int
87 os_getsocket4(int bufspace, struct interface *ifp, bool bind_to_unicast, uint16_t port)
88 {
89   struct sockaddr_in Addr;
90   int On = 1;
91   unsigned long Len;
92   int Sock = socket(AF_INET, SOCK_DGRAM, 0);
93   if (Sock < 0) {
94     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
95     olsr_exit(EXIT_FAILURE);
96   }
97
98   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
99     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
100     CLOSESOCKET(Sock);
101     olsr_exit(EXIT_FAILURE);
102   }
103
104   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
105     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
106     CLOSESOCKET(Sock);
107     olsr_exit(EXIT_FAILURE);
108   }
109
110   while (bufspace > 8192) {
111     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
112       break;
113
114     bufspace -= 1024;
115   }
116
117   if (bufspace <= 8192)
118     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv4 socket receive buffer.\n");
119
120   memset(&Addr, 0, sizeof(Addr));
121   Addr.sin_family = AF_INET;
122   Addr.sin_port = htons(port);
123
124   if(bind_to_unicast) {
125     Addr.sin_addr.s_addr = ifp->int_src.v4.sin_addr.s_addr;
126   }
127   else {
128     Addr.sin_addr.s_addr = INADDR_ANY;
129   }
130
131   if (bind(Sock, (struct sockaddr *)&Addr, sizeof(Addr)) < 0) {
132     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
133     CLOSESOCKET(Sock);
134     olsr_exit(EXIT_FAILURE);
135   }
136
137   if (WSAIoctl(Sock, FIONBIO, &On, sizeof(On), NULL, 0, &Len, NULL, NULL) < 0) {
138     OLSR_ERROR(LOG_NETWORKING, "WSAIoctl");
139     CLOSESOCKET(Sock);
140     olsr_exit(EXIT_FAILURE);
141   }
142
143   return Sock;
144 }
145
146 int
147 os_getsocket6(int bufspace, struct interface *ifp, bool bind_to_unicast, uint16_t port)
148 {
149   struct sockaddr_in6 Addr6;
150   int On = 1;
151   int Sock = socket(AF_INET6, SOCK_DGRAM, 0);
152   if (Sock < 0) {
153     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
154     olsr_exit(EXIT_FAILURE);
155   }
156
157   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
158     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
159     CLOSESOCKET(Sock);
160     olsr_exit(EXIT_FAILURE);
161   }
162
163   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
164     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
165     CLOSESOCKET(Sock);
166     olsr_exit(EXIT_FAILURE);
167   }
168
169   while (bufspace > 8192) {
170     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
171       break;
172
173     bufspace -= 1024;
174   }
175
176   if (bufspace <= 8192)
177     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv6 socket receive buffer.\n");
178
179   memset(&Addr6, 0, sizeof(Addr6));
180   Addr6.sin6_family = AF_INET6;
181   Addr6.sin6_port = htons(port);
182
183   if(bind_to_unicast) {
184     memcpy(&Addr6.sin6_addr, &ifp->int_src.v6.sin6_addr, sizeof(struct in6_addr));
185   }
186
187   if (bind(Sock, (struct sockaddr *)&Addr6, sizeof(Addr6)) < 0) {
188     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
189     CLOSESOCKET(Sock);
190     olsr_exit(EXIT_FAILURE);
191   }
192
193   return Sock;
194 }
195
196 void
197 os_socket_set_olsr_options(int sock __attribute__ ((unused))) {
198 }
199
200 static int
201 SetEnableRedirKey(unsigned long New)
202 {
203 #if !defined WINCE
204   HKEY Key;
205   unsigned long Type;
206   unsigned long Len;
207   unsigned long Old;
208
209   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
210                    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ | KEY_WRITE, &Key) != ERROR_SUCCESS)
211     return -1;
212
213   Len = sizeof(Old);
214
215   if (RegQueryValueEx(Key, "EnableICMPRedirect", NULL, &Type, (unsigned char *)&Old, &Len) != ERROR_SUCCESS || Type != REG_DWORD)
216     Old = 1;
217
218   if (RegSetValueEx(Key, "EnableICMPRedirect", 0, REG_DWORD, (unsigned char *)&New, sizeof(New))) {
219     RegCloseKey(Key);
220     return -1;
221   }
222
223   RegCloseKey(Key);
224   return Old;
225 #else
226   return 0;
227 #endif
228 }
229
230 static void
231 DisableIcmpRedirects(void)
232 {
233   int Res;
234
235   Res = SetEnableRedirKey(0);
236
237   if (Res != 1)
238     return;
239
240   OLSR_ERROR(LOG_NETWORKING, "\n*** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT ***\n\n");
241
242 #if 0
243   if (Res < 0) {
244     OLSR_ERROR(LOG_NETWORKING, "Cannot disable ICMP redirect processing in the registry.\n");
245     OLSR_ERROR(LOG_NETWORKING, "Please disable it manually. Continuing in 3 seconds...\n");
246     Sleep(3000);
247
248     return;
249   }
250 #endif
251
252   OLSR_ERROR(LOG_NETWORKING, "I have disabled ICMP redirect processing in the registry for you.\n");
253   OLSR_ERROR(LOG_NETWORKING, "REBOOT NOW, so that these changes take effect. Exiting...\n\n");
254
255   exit(0);
256 }
257
258 static OVERLAPPED RouterOver;
259
260 void os_init_global_ifoptions(void)
261 {
262   HMODULE Lib;
263   unsigned int __stdcall(*EnableRouterFunc) (HANDLE * Hand, OVERLAPPED * Over);
264   HANDLE Hand;
265
266   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
267
268   if (Lib == NULL)
269     return;
270
271   EnableRouterFunc = (unsigned int __stdcall(*)(HANDLE *, OVERLAPPED *))
272     GetProcAddress(Lib, WIDE_STRING("EnableRouter"));
273
274   if (EnableRouterFunc == NULL)
275     return;
276
277   memset(&RouterOver, 0, sizeof(OVERLAPPED));
278
279   RouterOver.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
280
281   if (RouterOver.hEvent == NULL) {
282     OLSR_WARN(LOG_NETWORKING, "CreateEvent()");
283     return;
284   }
285
286   if (EnableRouterFunc(&Hand, &RouterOver) != ERROR_IO_PENDING) {
287     OLSR_WARN(LOG_NETWORKING, "EnableRouter()");
288     return;
289   }
290
291   OLSR_DEBUG(LOG_NETWORKING, "Routing enabled.\n");
292
293   DisableIcmpRedirects();
294
295   return;
296 }
297
298 static int
299 disable_ip_forwarding(void)
300 {
301   HMODULE Lib;
302   unsigned int __stdcall(*UnenableRouterFunc) (OVERLAPPED * Over, unsigned int *Count);
303   unsigned int Count;
304
305   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
306
307   if (Lib == NULL)
308     return 0;
309
310   UnenableRouterFunc = (unsigned int __stdcall(*)(OVERLAPPED *, unsigned int *))
311     GetProcAddress(Lib, WIDE_STRING("UnenableRouter"));
312
313   if (UnenableRouterFunc == NULL)
314     return 0;
315
316   if (UnenableRouterFunc(&RouterOver, &Count) != NO_ERROR) {
317     OLSR_WARN(LOG_NETWORKING, "UnenableRouter()");
318     return -1;
319   }
320
321   OLSR_DEBUG(LOG_NETWORKING, "Routing disabled, count = %u.\n", Count);
322
323   return 0;
324 }
325
326 int os_cleanup_global_ifoptions(void) {
327   disable_ip_forwarding();
328
329   return 0;
330 }
331
332 /**
333  * Wrapper for sendto(2)
334  */
335
336 ssize_t
337 os_sendto(int s, const void *buf, size_t len, int flags, const union olsr_sockaddr *sock)
338 {
339   return sendto(s, buf, len, flags, &sock->std, sizeof(*sock));
340 }
341
342
343 /**
344  * Wrapper for recvfrom(2)
345  */
346
347 ssize_t
348 os_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), union olsr_sockaddr *sock, socklen_t * fromlen)
349 {
350   return recvfrom(s, buf, len, 0, &sock->std, fromlen);
351 }
352
353 /**
354  * Wrapper for select(2)
355  */
356
357 int
358 os_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
359 {
360   return select(nfds, readfds, writefds, exceptfds, timeout);
361 }
362
363 /*
364  * Local Variables:
365  * c-basic-offset: 2
366  * indent-tabs-mode: nil
367  * End:
368  */