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