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