Added the olsrd command
[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.16 2005/06/04 21:07:33 kattemat 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 <sys/wait.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 EINTR
63 #define EINTR WSAEINTR
64 #undef errno
65 #define errno WSAGetLastError()
66 #undef strerror
67 #define strerror(x) StrError(x)
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 inline 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
164   if(logbits & LOG_CONNECT)
165     printf("ohs_init_new_connection\n");
166
167   /* Create new client node */
168   oc = malloc(sizeof(struct ohs_connection));
169   if(!oc)
170     OHS_OUT_OF_MEMORY("New connection");
171
172   memset(oc, 0, sizeof(oc));
173
174   oc->socket = s;
175
176   oc->links = NULL;
177   oc->rx = 0;
178   oc->tx = 0;
179   oc->linkcnt = 0;
180
181   /* Get "fake IP" */
182   if(recv(oc->socket, new_addr, 4, 0) != 4)
183     {
184       printf("Failed to fetch IP address!\n");
185       return -1;
186     }
187   memcpy(&oc->ip_addr, new_addr, 4);
188   oc->ip_addr.v4 = ntohl(oc->ip_addr.v4);
189   if(logbits & LOG_CONNECT)
190     printf("IP: %s\n", olsr_ip_to_string(&oc->ip_addr));
191
192   if(get_client_by_addr(&oc->ip_addr))
193     {
194       if(logbits & LOG_CONNECT)
195         printf("IP: %s DUPLICATE! Disconecting client!\n", olsr_ip_to_string(&oc->ip_addr));
196
197       close(s);
198       return -1;
199     }
200
201   /* Queue */
202   oc->next = ohs_conns;
203   ohs_conns = oc;
204
205   return 1;
206 }
207
208 int
209 ohs_delete_connection(struct ohs_connection *oc)
210 {
211
212   if(!oc)
213     return -1;
214
215   /* Close the socket */
216   close(oc->socket);
217
218   if(logbits & LOG_CONNECT)
219     printf("Removing entry %s\n", olsr_ip_to_string(&oc->ip_addr));
220   /* De-queue */
221   if(oc == ohs_conns)
222     {
223       ohs_conns = ohs_conns->next;
224     }
225   else
226     {
227       struct ohs_connection *curr_entry, *prev_entry;
228       curr_entry = ohs_conns->next;
229       prev_entry = ohs_conns;
230       
231       while(curr_entry)
232         {
233           if(curr_entry == oc)
234             {
235               prev_entry->next = curr_entry->next;
236               break;
237             }
238           prev_entry = curr_entry;
239           curr_entry = curr_entry->next;
240         }
241     }
242
243   ohs_delete_all_related_links(oc);
244   /* Free */
245   free(oc);
246
247   return 0;
248 }
249
250 inline static int
251 ohs_route_data(struct ohs_connection *oc)
252 {
253   struct ohs_connection *ohs_cs;
254   ssize_t len;
255   int cnt = 0;
256
257   oc->tx++;
258   /* Read data */
259   if((len = recv(oc->socket, data_buffer, OHS_BUFSIZE, 0)) <= 0)
260     return -1;
261
262   if(logbits & LOG_FORWARD)
263     printf("Received %d bytes from %s\n", (int)len, olsr_ip_to_string(&oc->ip_addr));
264
265   /* Loop trough clients */
266   for(ohs_cs = ohs_conns; ohs_cs; ohs_cs = ohs_cs->next)
267     {
268       /* Check that the link is active open */
269       if(ohs_check_link(oc, &ohs_cs->ip_addr) &&
270          oc->socket != ohs_cs->socket)
271         {
272           ssize_t sent;
273
274           /* Send link addr */
275           if(send(ohs_cs->socket, oc->ip_addr.v6.s6_addr, ipsize, 0) != ipsize)
276             {
277               printf("Error sending link address!\n");
278             }
279           /* Send data */
280           if(logbits & LOG_FORWARD)
281             printf("Sending %d bytes %s=>%s\n", (int)len, 
282                    olsr_ip_to_string(&oc->ip_addr),
283                    olsr_ip_to_string(&ohs_cs->ip_addr));
284
285           if((sent = send(ohs_cs->socket, data_buffer, len, 0)) != len)
286             {
287               printf("Error sending(buf %d != sent %d)\n", (int)len, (int)sent);
288             }
289           ohs_cs->rx++;
290           cnt++;
291         }
292     }
293
294   return cnt;
295 }
296
297 static int
298 ohs_init_connect_sockets()
299 {
300   olsr_u32_t yes = 1;
301   struct sockaddr_in sin;
302
303   printf("Initiating socket TCP port %d\n", OHS_TCP_PORT);
304
305   if((srv_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
306     {
307       printf("Could not initialize socket(%d): %s\n", srv_socket, strerror(errno));
308       exit(0);
309     }
310
311   if(setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR, 
312                 (char *)&yes, sizeof(yes)) < 0) 
313     {
314       printf("SO_REUSEADDR failed for socket: %s\n", strerror(errno));
315       close(srv_socket);
316       exit(0);
317     }
318
319   /* complete the socket structure */
320   memset(&sin, 0, sizeof(sin));
321   sin.sin_family = AF_INET;
322   sin.sin_addr.s_addr = INADDR_ANY;
323   sin.sin_port = htons(OHS_TCP_PORT);
324   
325   /* bind the socket to the port number */
326   if (bind(srv_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
327     {
328       printf("bind failed for socket: %s\n", strerror(errno));
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       exit(0);
337     }
338   return 1;
339 }
340
341
342 static int
343 ohs_configure()
344 {
345
346   return 1;
347 }
348
349 static void
350 ohs_listen_loop()
351 {
352   int n;
353   fd_set ibits;
354   int fn_stdin = fileno(stdin);
355
356
357   printf("OHS command interpreter reading from STDIN\n");
358   printf("\n> ");
359   fflush(stdout);
360
361   while(1)
362     {
363       int high;
364
365       struct ohs_connection *ohs_cs;
366
367       high = 0;
368       FD_ZERO(&ibits);
369
370       /* Add server socket */
371       high = srv_socket;
372       FD_SET(srv_socket, &ibits);
373
374
375       if(fn_stdin > high) 
376         high = fn_stdin;
377
378       FD_SET(fn_stdin, &ibits);
379
380       /* Add clients */
381       for(ohs_cs = ohs_conns; ohs_cs; ohs_cs = ohs_cs->next)
382         {
383           if(ohs_cs->socket > high)
384             high = ohs_cs->socket;
385       
386           FD_SET(ohs_cs->socket, &ibits);
387         }
388
389       /* block */
390       n = select(high + 1, &ibits, 0, 0, NULL);
391       
392       if(n == 0)
393         continue;
394
395       /* Did somethig go wrong? */
396       if (n < 0) 
397         {
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         {
408           struct sockaddr_in pin;
409           socklen_t addrlen = sizeof(pin);
410           int s;
411           
412           memset(&pin, 0 , sizeof(pin));
413
414           if((s = accept(srv_socket, (struct sockaddr *)&pin, &addrlen)) < 0)
415             {
416               printf("accept failed socket: %s\n", strerror(errno));
417             }
418           else
419             {
420               /* Create new node */
421               ohs_init_new_connection(s);
422             }
423         }
424       /* Loop trough clients */
425       ohs_cs = ohs_conns;
426       while(ohs_cs)
427         {
428           struct ohs_connection *ohs_tmp = ohs_cs;
429           ohs_cs = ohs_cs->next;
430
431           if(FD_ISSET(ohs_tmp->socket, &ibits))
432             {
433               if(ohs_route_data(ohs_tmp) < 0)
434                   ohs_delete_connection(ohs_tmp);
435             }
436         }
437
438       if(FD_ISSET(fn_stdin, &ibits))
439         {
440           ohs_parse_command(stdin);
441           printf("\n> ");
442           fflush(stdout);
443         }      
444     }
445 }
446
447 int
448 main(int argc, char *argv[])
449 {
450
451 #ifdef WIN32
452   WSADATA WsaData;
453
454   if (WSAStartup(0x0202, &WsaData))
455     {
456       fprintf(stderr, "Could not initialize WinSock.\n");
457       exit(EXIT_FAILURE);
458     }
459   SetConsoleCtrlHandler(ohs_close, OLSR_TRUE);
460 #else
461   signal(SIGINT, ohs_close);  
462   signal(SIGTERM, ohs_close);  
463
464   /* Avoid zombie children */
465   signal(SIGCHLD, SIG_IGN);
466 #endif
467
468   printf("olsrd host-switch daemon version %s starting\n", OHS_VERSION);
469
470   logbits = LOG_DEFAULT;
471   ip_version = AF_INET;
472   ipsize = 4;
473
474   srand((unsigned int)time(NULL));
475
476   ohs_set_olsrd_path(OHS_DEFAULT_OLSRD_PATH);
477
478   ohs_init_connect_sockets();
479
480   ohs_configure();
481
482   ohs_listen_loop();
483
484   ohs_close(0);
485
486   return 1;
487 }