1fc404a853c71213955dd7e76c228145bf1c736b
[olsrd.git] / src / ipc_frontend.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  * $Id: ipc_frontend.c,v 1.29 2007/04/20 13:46:04 bernd67 Exp $
40  */
41
42 /*
43  *
44  *IPC - interprocess communication
45  *for the OLSRD - GUI front-end
46  *
47  */
48
49 #include "ipc_frontend.h"
50 #include "link_set.h"
51 #include "olsr.h"
52 #include "log.h"
53 #include "parser.h"
54 #include "socket_parser.h"
55 #include "local_hna_set.h"
56
57 #ifdef WIN32
58 #define close(x) closesocket(x)
59 #define perror(x) WinSockPError(x)
60 void 
61 WinSockPError(char *);
62 #endif
63
64 #ifndef linux
65 #define MSG_NOSIGNAL 0
66 #endif
67
68 static int ipc_sock = -1;
69 static int ipc_conn = -1;
70
71 static int
72 ipc_send_all_routes(int fd);
73
74 static int
75 ipc_send_net_info(int fd);
76
77
78 /**
79  *Create the socket to use for IPC to the
80  *GUI front-end
81  *
82  *@return the socket FD
83  */
84 int
85 ipc_init(void)
86 {
87   //int flags;
88   struct   sockaddr_in sin;
89   int yes = 1;
90
91   /* Add parser function */
92   olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS, 0);
93
94   /* get an internet domain socket */
95   if ((ipc_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
96     {
97       perror("IPC socket");
98       olsr_exit("IPC socket", EXIT_FAILURE);
99     }
100
101   if(setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
102     {
103       perror("SO_REUSEADDR failed");
104       return 0;
105     }
106
107   /* complete the socket structure */
108   memset(&sin, 0, sizeof(sin));
109   sin.sin_family = AF_INET;
110   sin.sin_addr.s_addr = INADDR_ANY;
111   sin.sin_port = htons(IPC_PORT);
112
113   /* bind the socket to the port number */
114   if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
115     {
116       perror("IPC bind");
117       OLSR_PRINTF(1, "Will retry in 10 seconds...\n")
118       sleep(10);
119       if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
120         {
121           perror("IPC bind");
122           olsr_exit("IPC bind", EXIT_FAILURE);
123         }
124       OLSR_PRINTF(1, "OK\n")
125     }
126
127   /* show that we are willing to listen */
128   if(listen(ipc_sock, olsr_cnf->ipc_connections) == -1) 
129     {
130       perror("IPC listen");
131       olsr_exit("IPC listen", EXIT_FAILURE);
132     }
133
134   /* Register the socket with the socket parser */
135   add_olsr_socket(ipc_sock, &ipc_accept);
136
137   return ipc_sock;
138 }
139
140
141 void
142 ipc_accept(int fd)
143 {
144   socklen_t addrlen;
145   struct sockaddr_in pin;
146   char *addr;  
147
148
149   addrlen = sizeof (struct sockaddr_in);
150   
151   if ((ipc_conn = accept(fd, (struct sockaddr *)  &pin, &addrlen)) == -1)
152     {
153       perror("IPC accept");
154       olsr_exit("IPC accept", EXIT_FAILURE);
155     }
156   else
157     {
158       OLSR_PRINTF(1, "Front end connected\n")
159       addr = inet_ntoa(pin.sin_addr);
160       if(ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr))
161         {
162           ipc_active = OLSR_TRUE;
163           ipc_send_net_info(ipc_conn);
164           ipc_send_all_routes(ipc_conn);
165           OLSR_PRINTF(1, "Connection from %s\n",addr)
166         }
167       else
168         {
169           OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr)
170           olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
171           CLOSE(ipc_conn);
172         }
173     }
174
175 }
176
177 olsr_bool
178 ipc_check_allowed_ip(union olsr_ip_addr *addr)
179 {
180   struct ipc_host *ipch = olsr_cnf->ipc_hosts;
181   struct ipc_net *ipcn = olsr_cnf->ipc_nets;
182
183   if(addr->v4 == ntohl(INADDR_LOOPBACK))
184     return OLSR_TRUE;
185
186   /* check hosts */
187   while(ipch)
188     {
189       if(addr->v4 == ipch->host.v4)
190         return OLSR_TRUE;
191       ipch = ipch->next;
192     }
193
194   /* check nets */
195   while(ipcn)
196     {
197       if((addr->v4 & ipcn->mask.v4) == (ipcn->net.v4 & ipcn->mask.v4))
198         return OLSR_TRUE;
199       ipcn = ipcn->next;
200     }
201
202   return OLSR_FALSE;
203 }
204
205 /**
206  *Read input from the IPC socket. Not in use.
207  *
208  *@todo for future use
209  *@param sock the IPC socket
210  *@return 1
211  */
212 int
213 ipc_input(int sock __attribute__((unused)))
214 {
215   /*
216   union 
217   {
218     char        buf[MAXPACKETSIZE+1];
219     struct      olsr olsr;
220   } inbuf;
221
222
223   if (recv(sock, dir, sizeof(dir), 0) == -1) 
224     {
225       perror("recv");
226       exit(1);
227     }
228 */
229   return 1;
230 }
231
232
233 /**
234  *Sends a olsr packet on the IPC socket.
235  *
236  *@param olsr the olsr struct representing the packet
237  *
238  *@return negative on error
239  */
240 void
241 frontend_msgparser(union olsr_message *msg, struct interface *in_if __attribute__((unused)), union olsr_ip_addr *from_addr __attribute__((unused)))
242 {
243   int size;
244
245   if(!ipc_active)
246     return;
247   
248   if(olsr_cnf->ip_version == AF_INET)
249     size = ntohs(msg->v4.olsr_msgsize);
250   else
251     size = ntohs(msg->v6.olsr_msgsize);
252   
253   if (send(ipc_conn, (void *)msg, size, MSG_NOSIGNAL) < 0) 
254     {
255       OLSR_PRINTF(1, "(OUTPUT)IPC connection lost!\n")
256       CLOSE(ipc_conn);
257       //olsr_cnf->open_ipc = 0;
258       ipc_active = OLSR_FALSE;
259       return;
260     }
261   
262   return;
263 }
264
265
266 /**
267  *Send a route table update to the front-end.
268  *
269  *@param kernel_route a rtentry describing the route update
270  *@param add 1 if the route is to be added 0 if it is to be deleted
271  *@param int_name the name of the interface the route is set to go by
272  *
273  *@return negative on error
274  */
275 int
276 ipc_route_send_rtentry(union olsr_ip_addr *dst, union olsr_ip_addr *gw, int met, int add, char *int_name)
277 {
278   struct ipcmsg packet;
279   //int i, x;
280   char *tmp;
281
282   if(!ipc_active)
283     return 0;
284
285   memset(&packet, 0, sizeof(struct ipcmsg));
286   packet.size = htons(IPC_PACK_SIZE);
287   packet.msgtype = ROUTE_IPC;
288
289   COPY_IP(&packet.target_addr, dst);
290
291   packet.add = add;
292   if(add && gw)
293     {
294       packet.metric = met;
295       COPY_IP(&packet.gateway_addr, gw);
296     }
297
298   if(int_name != NULL)
299     memcpy(&packet.device[0], int_name, 4);
300   else
301     memset(&packet.device[0], 0, 4);
302
303
304   tmp = (char *) &packet;
305   /*
306   x = 0;
307   for(i = 0; i < IPC_PACK_SIZE;i++)
308     {
309       if(x == 4)
310         {
311           x = 0;
312           printf("\n\t");
313         }
314       x++;
315       printf(" %03i", (u_char) tmp[i]);
316     }
317   
318   printf("\n");
319   */
320   
321   if (send(ipc_conn, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
322     {
323       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n")
324       CLOSE(ipc_conn);
325       //olsr_cnf->open_ipc = 0;
326       ipc_active = OLSR_FALSE;
327       return -1;
328     }
329
330   return 1;
331 }
332
333
334
335 static int
336 ipc_send_all_routes(int fd)
337 {
338   struct rt_entry  *destination;
339   struct interface *ifn;
340   olsr_u8_t        index;
341   struct ipcmsg packet;
342   char *tmp;
343   
344
345   if(!ipc_active)
346     return 0;
347   
348   for(index=0;index<HASHSIZE;index++)
349     {
350       for(destination = routingtable[index].next;
351           destination != &routingtable[index];
352           destination = destination->next)
353         {
354           ifn = destination->rt_if;
355           
356
357           memset(&packet, 0, sizeof(struct ipcmsg));
358           packet.size = htons(IPC_PACK_SIZE);
359           packet.msgtype = ROUTE_IPC;
360           
361           COPY_IP(&packet.target_addr, &destination->rt_dst);
362           
363           packet.add = 1;
364
365           if(olsr_cnf->ip_version == AF_INET)
366             {
367               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
368             }
369           else
370             {
371               packet.metric = (olsr_u8_t)destination->rt_metric;
372             }
373           COPY_IP(&packet.gateway_addr, &destination->rt_router);
374
375           if(ifn)
376             memcpy(&packet.device[0], ifn->int_name, 4);
377           else
378             memset(&packet.device[0], 0, 4);
379
380
381           tmp = (char *) &packet;
382   
383           if (send(fd, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
384             {
385               OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n")
386               CLOSE(ipc_conn);
387               //olsr_cnf->open_ipc = 0;
388               ipc_active = OLSR_FALSE;
389               return -1;
390             }
391
392         }
393     }
394
395   for(index=0;index<HASHSIZE;index++)
396     {
397       for(destination = hna_routes[index].next;
398           destination != &hna_routes[index];
399           destination = destination->next)
400         {
401           ifn = destination->rt_if;
402
403           packet.size = htons(IPC_PACK_SIZE);
404           packet.msgtype = ROUTE_IPC;
405           
406           COPY_IP(&packet.target_addr, &destination->rt_dst);
407           
408           packet.add = 1;
409
410           if(olsr_cnf->ip_version == AF_INET)
411             {
412               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
413             }
414           else
415             {
416               packet.metric = (olsr_u8_t)destination->rt_metric;
417             }
418           COPY_IP(&packet.gateway_addr, &destination->rt_router);
419
420           if(ifn)
421             memcpy(&packet.device[0], ifn->int_name, 4);
422           else
423             memset(&packet.device[0], 0, 4);
424
425
426           tmp = (char *) &packet;
427   
428           if (send(ipc_conn, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
429             {
430               OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n")
431               CLOSE(ipc_conn);
432               //olsr_cnf->open_ipc = 0;
433               ipc_active = OLSR_FALSE;
434               return -1;
435             }
436
437         }
438     }
439
440
441   return 1;
442 }
443
444
445
446 /**
447  *Sends OLSR info to the front-end. This info consists of
448  *the different time intervals and holding times, number
449  *of interfaces, HNA routes and main address.
450  *
451  *@return negative on error
452  */
453 static int
454 ipc_send_net_info(int fd)
455 {
456   struct ipc_net_msg *net_msg;
457   //int x, i;
458   char *msg;
459   
460
461   net_msg = olsr_malloc(sizeof(struct ipc_net_msg), "send net info");
462
463   msg = (char *)net_msg;
464
465   OLSR_PRINTF(1, "Sending net-info to front end...\n")
466   
467   memset(net_msg, 0, sizeof(struct ipc_net_msg));
468   
469   /* Message size */
470   net_msg->size = htons(sizeof(struct ipc_net_msg));
471   /* Message type */
472   net_msg->msgtype = NET_IPC;
473   
474   /* MIDs */
475   /* XXX fix IPC MIDcnt */
476   net_msg->mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
477   
478   /* HNAs */
479   if(olsr_cnf->ip_version == AF_INET6)
480     {
481       if(olsr_cnf->hna6_entries == NULL)
482         net_msg->hnas = 0;
483       else
484         net_msg->hnas = 1;
485     }
486
487   if(olsr_cnf->ip_version == AF_INET)
488     {
489       if(olsr_cnf->hna4_entries == NULL)
490         net_msg->hnas = 0;
491       else
492         net_msg->hnas = 1;
493     }
494
495   /* Different values */
496   /* Temporary fixes */
497   /* XXX fix IPC intervals */
498   net_msg->hello_int = 0;//htons((olsr_u16_t)hello_int);
499   net_msg->hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
500   net_msg->tc_int = 0;//htons((olsr_u16_t)tc_int);
501   net_msg->neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
502   net_msg->topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
503
504   if(olsr_cnf->ip_version == AF_INET)
505     net_msg->ipv6 = 0;
506   else
507     net_msg->ipv6 = 1;
508  
509   /* Main addr */
510   COPY_IP(&net_msg->main_addr, &olsr_cnf->main_addr);
511
512
513   /*
514   printf("\t");
515   x = 0;
516   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
517     {
518       if(x == 4)
519         {
520           x = 0;
521           printf("\n\t");
522         }
523       x++;
524       printf(" %03i", (u_char) msg[i]);
525     }
526   
527   printf("\n");
528   */
529
530
531   if (send(fd, (char *)net_msg, sizeof(struct ipc_net_msg), MSG_NOSIGNAL) < 0) 
532     {
533       OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n")
534       CLOSE(ipc_conn);
535       //olsr_cnf->open_ipc = 0;
536       return -1;
537     }
538
539   free(net_msg);
540   return 0;
541 }
542
543
544
545 int
546 shutdown_ipc(void)
547 {
548   OLSR_PRINTF(1, "Shutting down IPC...\n")
549   CLOSE(ipc_sock);
550   CLOSE(ipc_conn);
551   
552   return 1;
553 }