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