win32: call olsr_exit() instead of exit()
[olsrd.git] / src / win32 / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon (olsrd)
4  * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
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 #ifdef _WIN32
43
44 #if defined WINCE
45 #include <sys/types.h>          // for time_t
46 #endif /* defined WINCE */
47
48 #define WIN32_LEAN_AND_MEAN
49 #include <windows.h>
50 #include <winsock2.h>
51 #include <ws2tcpip.h>
52 #include <iphlpapi.h>
53 #undef interface
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include "defs.h"
58 #include "net_os.h"
59 #include "net_olsr.h"
60 #include "ipcalc.h"
61 #include "olsr.h"
62
63 #if defined WINCE
64 #define WIDE_STRING(s) L##s
65 #else /* defined WINCE */
66 #define WIDE_STRING(s) TEXT(s)
67 #endif /* defined WINCE */
68
69 void WinSockPError(const char *Str);
70 void PError(const char *);
71
72 void DisableIcmpRedirects(void);
73
74 int
75 gethemusocket(struct sockaddr_in *pin)
76 {
77   int sock;
78
79   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
80
81   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
82     perror("hcsocket");
83     return (-1);
84   }
85
86   /* connect to PORT on HOST */
87   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
88     printf("FAILED\n");
89     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
90     printf("connection refused\n");
91     closesocket(sock);
92     return (-1);
93   }
94
95   printf("OK\n");
96
97   /* Keep TCP socket blocking */
98   return (sock);
99 }
100
101 int
102 getsocket(int bufspace, struct interface_olsr *ifp __attribute__ ((unused)))
103 {
104   struct sockaddr_in Addr;
105   int On = 1;
106   unsigned long Len;
107   int Sock = socket(AF_INET, SOCK_DGRAM, 0);
108   if (Sock < 0) {
109     WinSockPError("getsocket/socket()");
110     return -1;
111   }
112
113   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
114     WinSockPError("getsocket/setsockopt(SO_BROADCAST)");
115     closesocket(Sock);
116     return -1;
117   }
118
119   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
120     WinSockPError("getsocket/setsockopt(SO_REUSEADDR)");
121     closesocket(Sock);
122     return -1;
123   }
124
125   while (bufspace > 8192) {
126     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
127       break;
128
129     bufspace -= 1024;
130   }
131
132   if (bufspace <= 8192) {
133     OLSR_PRINTF(1, "Cannot set IPv4 socket receive buffer.\n");
134   }
135   memset(&Addr, 0, sizeof(Addr));
136   Addr.sin_family = AF_INET;
137   Addr.sin_port = htons(olsr_cnf->olsrport);
138
139   if(bufspace <= 0) {
140     Addr.sin_addr.s_addr = ifp->int_addr.sin_addr.s_addr;
141   }
142
143   if (bind(Sock, (struct sockaddr *)&Addr, sizeof(Addr)) < 0) {
144     WinSockPError("getsocket/bind()");
145     closesocket(Sock);
146     return -1;
147   }
148
149   if (WSAIoctl(Sock, FIONBIO, &On, sizeof(On), NULL, 0, &Len, NULL, NULL) < 0) {
150     WinSockPError("WSAIoctl");
151     closesocket(Sock);
152     return -1;
153   }
154
155   return Sock;
156 }
157
158 int
159 getsocket6(int bufspace, struct interface_olsr *ifp __attribute__ ((unused)))
160 {
161   struct sockaddr_in6 Addr6;
162   int On = 1;
163   int Sock = socket(AF_INET6, SOCK_DGRAM, 0);
164   if (Sock < 0) {
165     WinSockPError("getsocket6/socket()");
166     return -1;
167   }
168
169   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
170     WinSockPError("getsocket6/setsockopt(SO_BROADCAST)");
171     closesocket(Sock);
172     return -1;
173   }
174
175   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
176     WinSockPError("getsocket6/setsockopt(SO_REUSEADDR)");
177     closesocket(Sock);
178     return -1;
179   }
180
181   while (bufspace > 8192) {
182     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
183       break;
184
185     bufspace -= 1024;
186   }
187
188   if (bufspace <= 8192)
189     fprintf(stderr, "Cannot set IPv6 socket receive buffer.\n");
190
191   memset(&Addr6, 0, sizeof(Addr6));
192   Addr6.sin6_family = AF_INET6;
193   Addr6.sin6_port = htons(olsr_cnf->olsrport);
194
195   if(bufspace <= 0) {
196     memcpy(&Addr6.sin6_addr, &ifp->int6_addr.sin6_addr, sizeof(struct in6_addr));
197   }
198
199   if (bind(Sock, (struct sockaddr *)&Addr6, sizeof(Addr6)) < 0) {
200     WinSockPError("getsocket6/bind()");
201     closesocket(Sock);
202     return -1;
203   }
204
205   return Sock;
206 }
207
208 static OVERLAPPED RouterOver;
209
210 void net_os_set_global_ifoptions(void)
211 {
212   HMODULE Lib;
213   unsigned int __stdcall(*enable_router)(HANDLE *, OVERLAPPED *);
214   HANDLE Hand;
215
216   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
217
218   if (Lib == NULL)
219     return;
220
221   enable_router = (unsigned int __stdcall(*)(HANDLE *, OVERLAPPED *))GetProcAddress(Lib, WIDE_STRING("EnableRouter"));
222
223   if (enable_router == NULL)
224     return;
225
226   memset(&RouterOver, 0, sizeof(OVERLAPPED));
227
228   RouterOver.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
229
230   if (RouterOver.hEvent == NULL) {
231     PError("CreateEvent()");
232     return;
233   }
234
235   if (enable_router(&Hand, &RouterOver) != ERROR_IO_PENDING) {
236     PError("EnableRouter()");
237     return;
238   }
239
240   OLSR_PRINTF(3, "Routing enabled.\n");
241
242   return;
243 }
244
245 static int
246 disable_ip_forwarding(int Ver)
247 {
248   HMODULE Lib;
249   unsigned int __stdcall(*unenable_router)(OVERLAPPED *, unsigned int *);
250   unsigned int Count;
251
252   Ver = Ver;
253
254   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
255
256   if (Lib == NULL)
257     return 0;
258
259   unenable_router = (unsigned int __stdcall(*)(OVERLAPPED *, unsigned int *))GetProcAddress(Lib, WIDE_STRING("UnenableRouter"));
260
261   if (unenable_router == NULL)
262     return 0;
263
264   if (unenable_router(&RouterOver, &Count) != NO_ERROR) {
265     PError("UnenableRouter()");
266     return -1;
267   }
268
269   OLSR_PRINTF(3, "Routing disabled, count = %u.\n", Count);
270
271   return 0;
272 }
273
274
275 int
276 net_os_restore_ifoptions(void)
277 {
278   disable_ip_forwarding(olsr_cnf->ip_version);
279
280   return 0;
281 }
282
283 static int
284 SetEnableRedirKey(unsigned long New)
285 {
286 #if !defined WINCE
287   HKEY Key;
288   unsigned long Type;
289   unsigned long Len;
290   unsigned long Old;
291
292   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ | KEY_WRITE, &Key) !=
293       ERROR_SUCCESS)
294     return -1;
295
296   Len = sizeof(Old);
297
298   if (RegQueryValueEx(Key, "EnableICMPRedirect", NULL, &Type, (unsigned char *)&Old, &Len) != ERROR_SUCCESS || Type != REG_DWORD)
299     Old = 1;
300
301   if (RegSetValueEx(Key, "EnableICMPRedirect", 0, REG_DWORD, (unsigned char *)&New, sizeof(New))) {
302     RegCloseKey(Key);
303     return -1;
304   }
305
306   RegCloseKey(Key);
307   return Old;
308 #else /* !defined WINCE */
309   return 0;
310 #endif /* !defined WINCE */
311 }
312
313 void
314 DisableIcmpRedirects(void)
315 {
316   int Res;
317
318   Res = SetEnableRedirKey(0);
319
320   if (Res != 1)
321     return;
322
323   fprintf(stderr, "\n*** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT ***\n\n");
324
325   fprintf(stderr, "I have disabled ICMP redirect processing in the registry for you.\n");
326   fprintf(stderr, "REBOOT NOW, so that these changes take effect. Exiting...\n\n");
327
328   olsr_exit(NULL, 0);
329 }
330
331 int
332 join_mcast(struct interface_olsr *Nic, int Sock)
333 {
334   /* See linux/in6.h */
335   struct ipaddr_str buf;
336   struct ipv6_mreq McastReq;
337
338   McastReq.ipv6mr_multiaddr = Nic->int6_multaddr.sin6_addr;
339   McastReq.ipv6mr_interface = Nic->if_index;
340
341   OLSR_PRINTF(3, "Interface %s joining multicast %s...", Nic->int_name,
342               olsr_ip_to_string(&buf, (union olsr_ip_addr *)&Nic->int6_multaddr.sin6_addr));
343   /* Send multicast */
344   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq)) < 0) {
345     perror("Join multicast");
346     return -1;
347   }
348
349   /* Old libc fix */
350 #ifdef IPV6_JOIN_GROUP
351   /* Join receiver group */
352   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&McastReq, sizeof(struct ipv6_mreq)) < 0)
353 #else /* IPV6_JOIN_GROUP */
354   /* Join receiver group */
355   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq)) < 0)
356 #endif /* IPV6_JOIN_GROUP */
357   {
358     perror("Join multicast send");
359     return -1;
360   }
361
362   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&McastReq.ipv6mr_interface, sizeof(McastReq.ipv6mr_interface)) < 0) {
363     perror("Set multicast if");
364     return -1;
365   }
366
367   OLSR_PRINTF(3, "OK\n");
368   return 0;
369 }
370
371 /**
372  * Wrapper for sendto(2)
373  */
374
375 ssize_t
376 olsr_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr * to, socklen_t tolen)
377 {
378   return sendto(s, buf, len, flags, to, tolen);
379 }
380
381 /**
382  * Wrapper for recvfrom(2)
383  */
384
385 ssize_t
386 olsr_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), struct sockaddr * from, socklen_t * fromlen)
387 {
388   return recvfrom(s, buf, len, 0, from, fromlen);
389 }
390
391 /**
392  * Wrapper for select(2)
393  */
394
395 int
396 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
397 {
398 #ifdef _WIN32
399   if (nfds == 0) {
400     if (timeout) {
401       Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
402     }
403     return 0;
404   }
405   else {
406     return select(nfds, readfds, writefds, exceptfds, timeout);
407   }
408 #else /* _WIN32 */
409   return select(nfds, readfds, writefds, exceptfds, timeout);
410 #endif /* _WIN32 */
411 }
412
413 #endif /* _WIN32 */
414
415 /*
416  * Local Variables:
417  * c-basic-offset: 2
418  * indent-tabs-mode: nil
419  * End:
420  */