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