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