Win32 fixes: use CLOSESOCKET to close sockets
[olsrd.git] / src / olsr_switch / main.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2005, Andreas Tonnesen(andreto@olsr.org)
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 /* olsrd host-switch daemon */
43
44 #include "olsr_host_switch.h"
45 #include "link_rules.h"
46 #include "ohs_cmd.h"
47 #include "ipcalc.h"
48
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <errno.h>
52 #include <signal.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <unistd.h>
59 #include <time.h>
60
61 #ifdef WIN32
62 #undef errno
63 #define errno WSAGetLastError()
64 #undef strerror
65 #define strerror(x) StrError(x)
66 #else
67 #include <sys/wait.h>
68 #endif
69
70 static int srv_socket;
71
72 #define OHS_BUFSIZE 1500
73 static uint8_t data_buffer[OHS_BUFSIZE];
74
75 struct ohs_connection *ohs_conns;
76
77 //static int ip_version;
78 //int ipsize;
79 static struct olsrd_config olsr_cnf_data;
80 struct olsrd_config *olsr_cnf = &olsr_cnf_data;
81
82 uint32_t logbits;
83
84 /* local functions */
85 static int
86 ohs_init_new_connection(int);
87
88 static int
89 ohs_route_data(struct ohs_connection *);
90
91 static int
92 ohs_init_connect_sockets(void);
93
94 static int
95 ohs_configure(void);
96
97 #if !defined WIN32
98 static void
99 ohs_listen_loop(void) __attribute__((noreturn));
100 #else
101 static void
102 ohs_listen_loop(void);
103 #endif
104
105 #ifdef WIN32
106 int __stdcall
107 ohs_close(unsigned long signo __attribute__((unused)))
108 #else
109 void
110 ohs_close(int signo __attribute__((unused)))
111 #endif
112 {
113   printf("OHS: exit\n");
114
115   CLOSESOCKET(srv_socket);
116
117   exit(0);
118 }
119
120 struct ohs_connection *
121 get_client_by_addr(const union olsr_ip_addr *adr)
122 {
123   struct ohs_connection *oc;
124   for (oc = ohs_conns; oc != NULL; oc = oc->next) {
125     if (ipequal(adr, &oc->ip_addr)) {
126         return oc;
127     }
128   }
129   return NULL;
130 }
131
132
133 static int
134 ohs_init_new_connection(int s)
135 {
136   struct ohs_connection *oc;
137   int i;
138
139   if(logbits & LOG_CONNECT) {
140     printf("ohs_init_new_connection\n");
141   }
142   /* Create new client node */
143   oc = calloc(1, sizeof(struct ohs_connection));
144   if (!oc) {
145     OHS_OUT_OF_MEMORY("New connection");
146   }
147
148   oc->socket = s;
149   oc->links = NULL;
150   oc->rx = 0;
151   oc->tx = 0;
152   oc->linkcnt = 0;
153
154   // hack alert: WSAEventSelect makes sockets non-blocking, so the
155   // recv() may return without having read anything on Windows; hence
156   // re-try for 2 seconds on Windows; shouldn't harm Linux et al.
157
158   /* Get "fake IP" */
159   for (i = 0; i < 20; i++) {
160     /* Win32 needs that cast. */
161       if (recv(oc->socket, (void *)&oc->ip_addr, olsr_cnf->ipsize, 0) == (int)olsr_cnf->ipsize) {
162       break;
163     }
164 #if defined WIN32
165     Sleep(100);
166 #endif
167   }
168
169   if (i == 20) {
170     printf("Failed to fetch IP address! (%s)\n", strerror(errno));
171     return -1;
172   }
173
174   if (logbits & LOG_CONNECT) {
175     struct ipaddr_str addrstr;
176     printf("IP: %s\n", olsr_ip_to_string(&addrstr, &oc->ip_addr));
177   }
178   if (get_client_by_addr(&oc->ip_addr)) {
179     if (logbits & LOG_CONNECT) {
180       struct ipaddr_str addrstr;
181       printf("IP: %s DUPLICATE! Disconecting client!\n", olsr_ip_to_string(&addrstr, &oc->ip_addr));
182     }
183     CLOSESOCKET(s);
184     free(oc);
185     return -1;
186   }
187
188   /* Queue */
189   oc->next = ohs_conns;
190   ohs_conns = oc;
191   return 1;
192 }
193
194 int
195 ohs_delete_connection(struct ohs_connection *oc)
196 {
197   if (!oc) {
198     return -1;
199   }
200   /* Close the socket */
201   CLOSESOCKET(oc->socket);
202
203   if(logbits & LOG_CONNECT) {
204     struct ipaddr_str addrstr;
205     printf("Removing entry %s\n", olsr_ip_to_string(&addrstr, &oc->ip_addr));
206   }
207   /* De-queue */
208   if(oc == ohs_conns) {
209     ohs_conns = ohs_conns->next;
210   } else {
211     struct ohs_connection *curr_entry = ohs_conns->next;
212     struct ohs_connection *prev_entry = ohs_conns;
213
214     while (curr_entry != NULL) {
215       if(curr_entry == oc) {
216         prev_entry->next = curr_entry->next;
217         break;
218       }
219       prev_entry = curr_entry;
220       curr_entry = curr_entry->next;
221     }
222   }
223   ohs_delete_all_related_links(oc);
224
225   free(oc);
226   return 0;
227 }
228
229 static int
230 ohs_route_data(struct ohs_connection *oc)
231 {
232   struct ohs_connection *ohs_cs;
233   ssize_t len;
234   int cnt = 0;
235
236   oc->tx++;
237   /* Read data */
238   if((len = recv(oc->socket, data_buffer, OHS_BUFSIZE, 0)) <= 0)
239     return -1;
240
241   if(logbits & LOG_FORWARD) {
242     struct ipaddr_str addrstr;
243     printf("Received %ld bytes from %s\n", (long)len, olsr_ip_to_string(&addrstr, &oc->ip_addr));
244   }
245   /* Loop trough clients */
246   for(ohs_cs = ohs_conns; ohs_cs; ohs_cs = ohs_cs->next) {
247     /* Check that the link is active open */
248     if(ohs_check_link(oc, &ohs_cs->ip_addr) &&
249        oc->socket != ohs_cs->socket) {
250       ssize_t sent;
251
252       /* Send link addr */
253       if (send(ohs_cs->socket, (const void *)&oc->ip_addr, olsr_cnf->ipsize, 0) != (int)olsr_cnf->ipsize) {
254           printf("Error sending link address!\n");
255       }
256       /* Send data */
257       if (logbits & LOG_FORWARD) {
258           struct ipaddr_str addrstr, addrstr2;
259           printf("Sending %d bytes %s=>%s\n",
260                  (int)len,
261                  olsr_ip_to_string(&addrstr, &oc->ip_addr),
262                  olsr_ip_to_string(&addrstr2, &ohs_cs->ip_addr));
263       }
264
265       sent = send(ohs_cs->socket, data_buffer, len, 0);
266       if(sent != len) {
267         printf("Error sending(buf %d != sent %d)\n", (int)len, (int)sent);
268       }
269       ohs_cs->rx++;
270       cnt++;
271     }
272   }
273   return cnt;
274 }
275
276 static int
277 ohs_init_connect_sockets(void)
278 {
279   uint32_t yes = 1;
280   struct sockaddr_in sin4;
281
282   printf("Initiating socket TCP port %d\n", OHS_TCP_PORT);
283
284   if((srv_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
285     {
286       printf("Could not initialize socket(%d): %s\n", srv_socket, strerror(errno));
287       exit(0);
288     }
289
290   if(setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR,
291                 (char *)&yes, sizeof(yes)) < 0)
292     {
293       printf("SO_REUSEADDR failed for socket: %s\n", strerror(errno));
294       CLOSESOCKET(srv_socket);
295       exit(0);
296     }
297
298   /* complete the socket structure */
299   memset(&sin4, 0, sizeof(sin4));
300   sin4.sin_family = AF_INET;
301   sin4.sin_addr.s_addr = INADDR_ANY;
302   sin4.sin_port = htons(OHS_TCP_PORT);
303
304   /* bind the socket to the port number */
305   if (bind(srv_socket, (struct sockaddr *) &sin4, sizeof(sin4)) == -1)
306     {
307       printf("bind failed for socket: %s\n", strerror(errno));
308       CLOSESOCKET(srv_socket);
309       exit(0);
310     }
311
312   /* show that we are willing to listen */
313   if (listen(srv_socket, 5) == -1)
314     {
315       printf("listen failed for socket: %s\n", strerror(errno));
316       CLOSESOCKET(srv_socket);
317       exit(0);
318     }
319   return 1;
320 }
321
322
323 static int
324 ohs_configure(void)
325 {
326
327   return 1;
328 }
329
330 static void accept_handler(void)
331 {
332   struct sockaddr_in pin;
333   socklen_t addrlen = sizeof(pin);
334   int s;
335
336   memset(&pin, 0 , sizeof(pin));
337
338   if((s = accept(srv_socket, (struct sockaddr *)&pin, &addrlen)) < 0)
339     {
340       printf("accept failed socket: %s\n", strerror(errno));
341     }
342   else
343     {
344       /* Create new node */
345       ohs_init_new_connection(s);
346     }
347 }
348
349 static void stdin_handler(void)
350 {
351   ohs_parse_command();
352 }
353
354 static void read_handler(struct ohs_connection *con)
355 {
356   if (ohs_route_data(con) < 0)
357     ohs_delete_connection(con);
358 }
359
360 static void
361 ohs_listen_loop(void)
362 {
363 #if !defined WIN32
364   int n;
365   fd_set ibits;
366   int fn_stdin = fileno(stdin);
367
368   while(1)
369     {
370       int high;
371
372       struct ohs_connection *ohs_cs;
373
374       high = 0;
375       FD_ZERO(&ibits);
376
377       /* Add server socket */
378       high = srv_socket;
379       FD_SET(srv_socket, &ibits);
380
381       if(fn_stdin > high)
382         high = fn_stdin;
383
384       FD_SET(fn_stdin, &ibits);
385
386       /* Add clients */
387       for(ohs_cs = ohs_conns; ohs_cs; ohs_cs = ohs_cs->next)
388         {
389           if(ohs_cs->socket > high)
390             high = ohs_cs->socket;
391
392           FD_SET(ohs_cs->socket, &ibits);
393         }
394
395       /* block */
396       n = select(high + 1, &ibits, 0, 0, NULL);
397
398       if(n == 0)
399         continue;
400
401       /* Did somethig go wrong? */
402       if (n < 0)
403         {
404           if(errno == EINTR)
405             continue;
406
407           printf("Error select: %s", strerror(errno));
408           continue;
409         }
410
411       /* Check server socket */
412       if(FD_ISSET(srv_socket, &ibits))
413         accept_handler();
414
415       /* Loop trough clients */
416       ohs_cs = ohs_conns;
417       while(ohs_cs)
418         {
419           struct ohs_connection *ohs_tmp = ohs_cs;
420           ohs_cs = ohs_cs->next;
421
422           if(FD_ISSET(ohs_tmp->socket, &ibits))
423             read_handler(ohs_tmp);
424         }
425
426       if(FD_ISSET(fn_stdin, &ibits))
427         stdin_handler();
428
429     }
430 #else
431   HANDLE Objects[2];
432   WSANETWORKEVENTS NetEvents;
433   struct ohs_connection *Walker, *TmpWalker;
434   unsigned int Res;
435
436   Objects[0] = GetStdHandle(STD_INPUT_HANDLE);
437   Objects[1] = WSACreateEvent();
438
439   if (WSAEventSelect(srv_socket, Objects[1], FD_ACCEPT) == SOCKET_ERROR)
440   {
441     fprintf(stderr, "WSAEventSelect failed (1): %s\n", strerror(errno));
442     return;
443   }
444
445   while (1)
446   {
447     for (Walker = ohs_conns; Walker != NULL; Walker = Walker->next)
448     {
449       if (WSAEventSelect(Walker->socket, Objects[1], FD_READ | FD_CLOSE) == SOCKET_ERROR)
450       {
451         fprintf(stderr, "WSAEventSelect failed (2): %s\n", strerror(errno));
452         Sleep(1000);
453         continue;
454       }
455     }
456
457     Res = WaitForMultipleObjects(2, Objects, FALSE, INFINITE);
458
459     if (Res == WAIT_FAILED)
460     {
461       fprintf(stderr, "WaitForMultipleObjects failed: %s\n", strerror(GetLastError()));
462       Sleep(1000);
463       continue;
464     }
465
466     if (Res == WAIT_OBJECT_0)
467       stdin_handler();
468
469     else if (Res == WAIT_OBJECT_0 + 1)
470     {
471       if (WSAEnumNetworkEvents(srv_socket, Objects[1], &NetEvents) == SOCKET_ERROR)
472         fprintf(stderr, "WSAEnumNetworkEvents failed (1): %s\n", strerror(errno));
473
474       else
475       {
476         if ((NetEvents.lNetworkEvents & FD_ACCEPT) != 0)
477           accept_handler();
478       }
479
480       for (Walker = ohs_conns; Walker != NULL; Walker = TmpWalker)
481       {
482         TmpWalker = Walker->next;
483
484         if (WSAEnumNetworkEvents(Walker->socket, Objects[1], &NetEvents) == SOCKET_ERROR)
485           fprintf(stderr, "WSAEnumNetworkEvents failed (2): %s\n", strerror(errno));
486
487         else
488         {
489           if ((NetEvents.lNetworkEvents & (FD_READ | FD_CLOSE)) != 0)
490             read_handler(Walker);
491         }
492       }
493     }
494   }
495
496 #endif
497 }
498
499 int
500 main(void)
501 {
502
503 #ifdef WIN32
504   WSADATA WsaData;
505
506   if (WSAStartup(0x0202, &WsaData))
507     {
508       fprintf(stderr, "Could not initialize WinSock.\n");
509       exit(EXIT_FAILURE);
510     }
511
512   SetConsoleCtrlHandler(ohs_close, true);
513
514 #else
515   signal(SIGINT, ohs_close);
516   signal(SIGTERM, ohs_close);
517
518   /* Avoid zombie children */
519   signal(SIGCHLD, SIG_IGN);
520 #endif
521
522   printf("olsrd host-switch daemon version %s starting\n", OHS_VERSION);
523
524   logbits = LOG_DEFAULT;
525   olsr_cnf->ip_version = AF_INET;
526   olsr_cnf->ipsize = sizeof(struct in_addr);
527
528   srand((unsigned int)time(NULL));
529
530   ohs_set_olsrd_path(OHS_DEFAULT_OLSRD_PATH);
531
532   ohs_init_connect_sockets();
533
534   ohs_configure();
535
536   printf("OHS command interpreter reading from STDIN\n");
537   printf("\n> ");
538   fflush(stdout);
539
540   ohs_listen_loop();
541
542   ohs_close(0);
543
544   return 1;
545 }
546
547 /*
548  * Local Variables:
549  * c-basic-offset: 2
550  * indent-tabs-mode: nil
551  * End:
552  */