Added some commands
[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.4 2005/05/30 19:57:49 kattemat Exp $
41  */
42
43 /* olsrd host-switch daemon */
44
45 #ifdef WIN32
46 #define close(x) closesocket(x)
47 int __stdcall SignalHandler(unsigned long signal);
48 #else
49 void
50 olsr_shutdown(int);
51 #endif
52
53 #include "olsr_host_switch.h"
54 #include "link_rules.h"
55 #include "ohs_cmd.h"
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <errno.h>
59 #include <signal.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <string.h>
65 #include <unistd.h>
66
67 static int srv_socket;
68
69 #define OHS_BUFSIZE 1500
70 static olsr_u8_t data_buffer[OHS_BUFSIZE];
71
72 struct ohs_connection *ohs_conns;
73
74
75 static int ip_version;
76 int ipsize;
77 static char ipv6_buf[100]; /* for address coversion */
78
79 olsr_u32_t logbits;
80
81 char *
82 olsr_ip_to_string(union olsr_ip_addr *addr)
83 {
84   static int index = 0;
85   static char buff[4][100];
86   char *ret;
87   struct in_addr in;
88   
89   if(ip_version == AF_INET)
90     {
91       in.s_addr=addr->v4;
92       ret = inet_ntoa(in);
93     }
94   else
95     {
96       /* IPv6 */
97       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
98     }
99
100   strncpy(buff[index], ret, 100);
101
102   ret = buff[index];
103
104   index = (index + 1) & 3;
105
106   return ret;
107 }
108
109
110 #ifdef WIN32
111 int __stdcall
112 SignalHandler(unsigned long signal)
113 #else
114 void
115 ohs_close(int signal)
116 #endif
117 {
118   printf("OHS: exit\n");
119
120   close(srv_socket);
121
122   exit(0);
123 }
124
125
126 int
127 ohs_init_new_connection(int s)
128 {
129   struct ohs_connection *oc;
130   olsr_u8_t new_addr[4];
131
132   if(logbits & LOG_CONNECT)
133     printf("ohs_init_new_connection\n");
134
135   /* Create new client node */
136   oc = malloc(sizeof(struct ohs_connection));
137   if(!oc)
138     OHS_OUT_OF_MEMORY("New connection");
139
140   memset(oc, 0, sizeof(oc));
141
142   oc->socket = s;
143
144   oc->links = NULL;
145
146   /* Queue */
147   oc->next = ohs_conns;
148   ohs_conns = oc;
149
150   /* Get "fake IP" */
151   if(recv(oc->socket, new_addr, 4, 0) != 4)
152     {
153       printf("Failed to fetch IP address!\n");
154       return -1;
155     }
156   memcpy(&oc->ip_addr, new_addr, 4);
157   oc->ip_addr.v4 = ntohl(oc->ip_addr.v4);
158   if(logbits & LOG_CONNECT)
159     printf("IP: %s\n", olsr_ip_to_string(&oc->ip_addr));
160
161   return 1;
162 }
163
164 int
165 ohs_delete_connection(struct ohs_connection *oc)
166 {
167
168   /* Close the socket */
169   close(oc->socket);
170
171   if(logbits & LOG_CONNECT)
172     printf("Removing entry %s\n", olsr_ip_to_string(&oc->ip_addr));
173   /* De-queue */
174   if(oc == ohs_conns)
175     {
176       ohs_conns = ohs_conns->next;
177     }
178   else
179     {
180       struct ohs_connection *curr_entry, *prev_entry;
181       curr_entry = ohs_conns->next;
182       prev_entry = ohs_conns;
183       
184       while(curr_entry)
185         {
186           if(curr_entry == oc)
187             {
188               prev_entry->next = curr_entry->next;
189               break;
190             }
191           prev_entry = curr_entry;
192           curr_entry = curr_entry->next;
193         }
194     }
195   /* Free */
196   free(oc);
197
198   return 0;
199 }
200
201 int
202 ohs_route_data(struct ohs_connection *oc)
203 {
204   struct ohs_connection *ohs_cs;
205   ssize_t len;
206   int cnt = 0;
207
208   /* Read data */
209   if((len = recv(oc->socket, data_buffer, OHS_BUFSIZE, 0)) <= 0)
210     return -1;
211
212   if(logbits & LOG_FORWARD)
213     printf("Received %d bytes from %s\n", len, olsr_ip_to_string(&oc->ip_addr));
214
215   /* Loop trough clients */
216   for(ohs_cs = ohs_conns; ohs_cs; ohs_cs = ohs_cs->next)
217     {
218       /* Check that the link is active open */
219       if(ohs_check_link(oc, &ohs_cs->ip_addr) &&
220          oc->socket != ohs_cs->socket)
221         {
222           ssize_t sent;
223
224           /* Send link addr */
225           if(send(ohs_cs->socket, oc->ip_addr.v6.s6_addr, ipsize, 0) != ipsize)
226             {
227               printf("Error sending link address!\n");
228             }
229           /* Send data */
230           if(logbits & LOG_FORWARD)
231             printf("Sending %d bytes %s=>%s\n", len, 
232                    olsr_ip_to_string(&oc->ip_addr),
233                    olsr_ip_to_string(&ohs_cs->ip_addr));
234
235           if((sent = send(ohs_cs->socket, data_buffer, len, 0)) != len)
236             {
237               printf("Error sending(buf %d != sent %d)\n", len, sent);
238             }
239           cnt++;
240         }
241     }
242
243   return cnt;
244 }
245
246 int
247 ohs_init_connect_sockets()
248 {
249   olsr_u32_t yes = 1;
250   struct sockaddr_in sin;
251
252   printf("Initiating socket TCP port %d\n", OHS_TCP_PORT);
253
254   if((srv_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
255     {
256       printf("Could not initialize socket: %s\n", strerror(errno));
257       exit(0);
258     }
259
260   if(setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR, 
261                 (char *)&yes, sizeof(yes)) < 0) 
262     {
263       printf("SO_REUSEADDR failed for socket: %s\n", strerror(errno));
264       close(srv_socket);
265       exit(0);
266     }
267
268   /* complete the socket structure */
269   memset(&sin, 0, sizeof(sin));
270   sin.sin_family = AF_INET;
271   sin.sin_addr.s_addr = INADDR_ANY;
272   sin.sin_port = htons(OHS_TCP_PORT);
273   
274   /* bind the socket to the port number */
275   if (bind(srv_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
276     {
277       printf("bind failed for socket: %s\n", strerror(errno));
278       exit(0);
279     }
280   
281   /* show that we are willing to listen */
282   if (listen(srv_socket, 5) == -1) 
283     {
284       printf("listen failed for socket: %s\n", strerror(errno));
285       exit(0);
286     }
287   return 1;
288 }
289
290
291 int
292 ohs_configure()
293 {
294
295   return 1;
296 }
297
298 void
299 ohs_listen_loop()
300 {
301   int n;
302   fd_set ibits;
303   int fn_stdin = fileno(stdin);
304
305
306   printf("OHS command interper reading from STDIN\n");
307   printf("\n> ");
308   fflush(stdout);
309
310   while(1)
311     {
312       int high;
313
314       struct ohs_connection *ohs_cs;
315
316       high = 0;
317       FD_ZERO(&ibits);
318
319       /* Add server socket */
320       high = srv_socket;
321       FD_SET(srv_socket, &ibits);
322
323
324       if(fn_stdin > high) 
325         high = fn_stdin;
326
327       FD_SET(fn_stdin, &ibits);
328
329       /* Add clients */
330       for(ohs_cs = ohs_conns; ohs_cs; ohs_cs = ohs_cs->next)
331         {
332           if(ohs_cs->socket > high)
333             high = ohs_cs->socket;
334       
335           FD_SET(ohs_cs->socket, &ibits);
336         }
337
338       /* block */
339       n = select(high + 1, &ibits, 0, 0, NULL);
340       
341       if(n == 0)
342         continue;
343
344       /* Did somethig go wrong? */
345       if (n < 0) 
346         {
347           if(errno == EINTR)
348             continue;
349           
350           printf("Error select: %s", strerror(errno));
351           continue;
352         }
353       
354       /* Check server socket */
355       if(FD_ISSET(srv_socket, &ibits))
356         {
357           struct sockaddr_in pin;
358           socklen_t addrlen = sizeof(pin);
359           int s;
360           
361           memset(&pin, 0 , sizeof(pin));
362
363           if((s = accept(srv_socket, (struct sockaddr *)&pin, &addrlen)) < 0)
364             {
365               printf("accept failed socket: %s\n", strerror(errno));
366             }
367           else
368             {
369               /* Create new node */
370               ohs_init_new_connection(s);
371             }
372         }
373       /* Loop trough clients */
374       ohs_cs = ohs_conns;
375       while(ohs_cs)
376         {
377           struct ohs_connection *ohs_tmp = ohs_cs;
378           ohs_cs = ohs_cs->next;
379
380           if(FD_ISSET(ohs_tmp->socket, &ibits))
381             {
382               if(ohs_route_data(ohs_tmp) < 0)
383                   ohs_delete_connection(ohs_tmp);
384             }
385         }
386
387       if(FD_ISSET(fn_stdin, &ibits))
388         {
389           ohs_parse_command(stdin);
390           printf("\n> ");
391           fflush(stdout);
392         }      
393     }
394 }
395
396
397 int
398 main(int argc, char *argv[])
399 {
400
401   printf("olsrd host-switch daemon version %s starting\n", OHS_VERSION);
402
403   logbits = LOG_DEFAULT;
404   ip_version = AF_INET;
405   ipsize = 4;
406
407   ohs_init_connect_sockets();
408 #ifdef WIN32
409   SetConsoleCtrlHandler(SignalHandler, OLSR_TRUE);
410 #else
411   signal(SIGINT, ohs_close);  
412   signal(SIGTERM, ohs_close);  
413 #endif
414
415   ohs_configure();
416
417   ohs_listen_loop();
418
419   ohs_close(0);
420
421   return 1;
422 }