c66dfad8ad8fa8fffcc20cf891117d3319616cf9
[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.33 2007/08/02 22:07:19 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 static int ipc_active = OLSR_FALSE;
71
72 static int
73 ipc_send_all_routes(int fd);
74
75 static int
76 ipc_send_net_info(int fd);
77
78
79 /**
80  *Create the socket to use for IPC to the
81  *GUI front-end
82  *
83  *@return the socket FD
84  */
85 int
86 ipc_init(void)
87 {
88   //int flags;
89   struct   sockaddr_in sin;
90   int yes = 1;
91
92   /* Add parser function */
93   olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS, 0);
94
95   /* get an internet domain socket */
96   if ((ipc_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
97     {
98       perror("IPC socket");
99       olsr_exit("IPC socket", EXIT_FAILURE);
100     }
101
102   if(setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
103     {
104       perror("SO_REUSEADDR failed");
105       return 0;
106     }
107
108   /* complete the socket structure */
109   memset(&sin, 0, sizeof(sin));
110   sin.sin_family = AF_INET;
111   sin.sin_addr.s_addr = INADDR_ANY;
112   sin.sin_port = htons(IPC_PORT);
113
114   /* bind the socket to the port number */
115   if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
116     {
117       perror("IPC bind");
118       OLSR_PRINTF(1, "Will retry in 10 seconds...\n");
119       sleep(10);
120       if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
121         {
122           perror("IPC bind");
123           olsr_exit("IPC bind", EXIT_FAILURE);
124         }
125       OLSR_PRINTF(1, "OK\n");
126     }
127
128   /* show that we are willing to listen */
129   if(listen(ipc_sock, olsr_cnf->ipc_connections) == -1) 
130     {
131       perror("IPC listen");
132       olsr_exit("IPC listen", EXIT_FAILURE);
133     }
134
135   /* Register the socket with the socket parser */
136   add_olsr_socket(ipc_sock, &ipc_accept);
137
138   return ipc_sock;
139 }
140
141
142 void
143 ipc_accept(int fd)
144 {
145   socklen_t addrlen;
146   struct sockaddr_in pin;
147   char *addr;  
148
149
150   addrlen = sizeof (struct sockaddr_in);
151   
152   if ((ipc_conn = accept(fd, (struct sockaddr *)  &pin, &addrlen)) == -1)
153     {
154       perror("IPC accept");
155       olsr_exit("IPC accept", EXIT_FAILURE);
156     }
157   else
158     {
159       OLSR_PRINTF(1, "Front end connected\n");
160       addr = inet_ntoa(pin.sin_addr);
161       if(ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr))
162         {
163           ipc_active = OLSR_TRUE;
164           ipc_send_net_info(ipc_conn);
165           ipc_send_all_routes(ipc_conn);
166           OLSR_PRINTF(1, "Connection from %s\n",addr);
167         }
168       else
169         {
170           OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
171           olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
172           CLOSE(ipc_conn);
173         }
174     }
175
176 }
177
178 olsr_bool
179 ipc_check_allowed_ip(union olsr_ip_addr *addr)
180 {
181   struct ipc_host *ipch = olsr_cnf->ipc_hosts;
182   struct ipc_net *ipcn = olsr_cnf->ipc_nets;
183
184   if(addr->v4 == ntohl(INADDR_LOOPBACK))
185     return OLSR_TRUE;
186
187   /* check hosts */
188   while(ipch)
189     {
190       if(addr->v4 == ipch->host.v4)
191         return OLSR_TRUE;
192       ipch = ipch->next;
193     }
194
195   /* check nets */
196   while(ipcn)
197     {
198       if((addr->v4 & ipcn->mask.v4) == (ipcn->net.v4 & ipcn->mask.v4))
199         return OLSR_TRUE;
200       ipcn = ipcn->next;
201     }
202
203   return OLSR_FALSE;
204 }
205
206 #if 0
207 /**
208  *Read input from the IPC socket. Not in use.
209  *
210  *@todo for future use
211  *@param sock the IPC socket
212  *@return 1
213  */
214 int
215 ipc_input(int sock __attribute__((unused)))
216 {
217   union 
218   {
219     char        buf[MAXPACKETSIZE+1];
220     struct      olsr olsr;
221   } inbuf;
222
223
224   if (recv(sock, dir, sizeof(dir), 0) == -1) 
225     {
226       perror("recv");
227       exit(1);
228     }
229   return 1;
230 }
231 #endif
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     }
260 }
261
262
263 /**
264  *Send a route table update to the front-end.
265  *
266  *@param kernel_route a rtentry describing the route update
267  *@param add 1 if the route is to be added 0 if it is to be deleted
268  *@param int_name the name of the interface the route is set to go by
269  *
270  *@return negative on error
271  */
272 int
273 ipc_route_send_rtentry(union olsr_ip_addr *dst, union olsr_ip_addr *gw, int met, int add, char *int_name)
274 {
275   struct ipcmsg packet;
276   //int i, x;
277   char *tmp;
278
279   if(!ipc_active)
280     return 0;
281
282   memset(&packet, 0, sizeof(struct ipcmsg));
283   packet.size = htons(IPC_PACK_SIZE);
284   packet.msgtype = ROUTE_IPC;
285
286   COPY_IP(&packet.target_addr, dst);
287
288   packet.add = add;
289   if(add && gw)
290     {
291       packet.metric = met;
292       COPY_IP(&packet.gateway_addr, gw);
293     }
294
295   if(int_name != NULL)
296     memcpy(&packet.device[0], int_name, 4);
297   else
298     memset(&packet.device[0], 0, 4);
299
300
301   tmp = (char *) &packet;
302   /*
303   x = 0;
304   for(i = 0; i < IPC_PACK_SIZE;i++)
305     {
306       if(x == 4)
307         {
308           x = 0;
309           printf("\n\t");
310         }
311       x++;
312       printf(" %03i", (u_char) tmp[i]);
313     }
314   
315   printf("\n");
316   */
317   
318   if (send(ipc_conn, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
319     {
320       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
321       CLOSE(ipc_conn);
322
323       //olsr_cnf->open_ipc = 0;
324       ipc_active = OLSR_FALSE;
325       return -1;
326     }
327
328   return 1;
329 }
330
331
332
333 static int
334 ipc_send_all_routes(int fd)
335 {
336   struct rt_entry  *destination;
337   struct interface *ifn;
338   int               idx;
339   struct ipcmsg packet;
340   char *tmp;
341   
342
343   if(!ipc_active)
344     return 0;
345   
346   for(idx=0;idx<HASHSIZE;idx++)
347     {
348       for(destination = routingtable[idx].next;
349           destination != &routingtable[idx];
350           destination = destination->next)
351         {
352           ifn = destination->rt_if;
353           
354
355           memset(&packet, 0, sizeof(struct ipcmsg));
356           packet.size = htons(IPC_PACK_SIZE);
357           packet.msgtype = ROUTE_IPC;
358           
359           COPY_IP(&packet.target_addr, &destination->rt_dst);
360           
361           packet.add = 1;
362
363           if(olsr_cnf->ip_version == AF_INET)
364             {
365               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
366             }
367           else
368             {
369               packet.metric = (olsr_u8_t)destination->rt_metric;
370             }
371           COPY_IP(&packet.gateway_addr, &destination->rt_router);
372
373           if(ifn)
374             memcpy(&packet.device[0], ifn->int_name, 4);
375           else
376             memset(&packet.device[0], 0, 4);
377
378
379           tmp = (char *) &packet;
380   
381           if (send(fd, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
382             {
383               OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
384               CLOSE(ipc_conn);
385               //olsr_cnf->open_ipc = 0;
386               ipc_active = OLSR_FALSE;
387               return -1;
388             }
389
390         }
391     }
392
393   for(idx=0;idx<HASHSIZE;idx++)
394     {
395       for(destination = hna_routes[idx].next;
396           destination != &hna_routes[idx];
397           destination = destination->next)
398         {
399           ifn = destination->rt_if;
400
401           packet.size = htons(IPC_PACK_SIZE);
402           packet.msgtype = ROUTE_IPC;
403           
404           COPY_IP(&packet.target_addr, &destination->rt_dst);
405           
406           packet.add = 1;
407
408           if(olsr_cnf->ip_version == AF_INET)
409             {
410               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
411             }
412           else
413             {
414               packet.metric = (olsr_u8_t)destination->rt_metric;
415             }
416           COPY_IP(&packet.gateway_addr, &destination->rt_router);
417
418           if(ifn)
419             memcpy(&packet.device[0], ifn->int_name, 4);
420           else
421             memset(&packet.device[0], 0, 4);
422
423
424           tmp = (char *) &packet;
425   
426           if (send(ipc_conn, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
427             {
428               OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
429               CLOSE(ipc_conn);
430               //olsr_cnf->open_ipc = 0;
431               ipc_active = OLSR_FALSE;
432               return -1;
433             }
434
435         }
436     }
437
438
439   return 1;
440 }
441
442
443
444 /**
445  *Sends OLSR info to the front-end. This info consists of
446  *the different time intervals and holding times, number
447  *of interfaces, HNA routes and main address.
448  *
449  *@return negative on error
450  */
451 static int
452 ipc_send_net_info(int fd)
453 {
454   struct ipc_net_msg *net_msg;
455   //int x, i;
456   char *msg;
457   
458
459   net_msg = olsr_malloc(sizeof(struct ipc_net_msg), "send net info");
460
461   msg = (char *)net_msg;
462
463   OLSR_PRINTF(1, "Sending net-info to front end...\n");
464   
465   memset(net_msg, 0, sizeof(struct ipc_net_msg));
466   
467   /* Message size */
468   net_msg->size = htons(sizeof(struct ipc_net_msg));
469   /* Message type */
470   net_msg->msgtype = NET_IPC;
471   
472   /* MIDs */
473   /* XXX fix IPC MIDcnt */
474   net_msg->mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
475   
476   /* HNAs */
477   if(olsr_cnf->ip_version == AF_INET6)
478     {
479       if(olsr_cnf->hna6_entries == NULL)
480         net_msg->hnas = 0;
481       else
482         net_msg->hnas = 1;
483     }
484
485   if(olsr_cnf->ip_version == AF_INET)
486     {
487       if(olsr_cnf->hna4_entries == NULL)
488         net_msg->hnas = 0;
489       else
490         net_msg->hnas = 1;
491     }
492
493   /* Different values */
494   /* Temporary fixes */
495   /* XXX fix IPC intervals */
496   net_msg->hello_int = 0;//htons((olsr_u16_t)hello_int);
497   net_msg->hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
498   net_msg->tc_int = 0;//htons((olsr_u16_t)tc_int);
499   net_msg->neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
500   net_msg->topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
501
502   if(olsr_cnf->ip_version == AF_INET)
503     net_msg->ipv6 = 0;
504   else
505     net_msg->ipv6 = 1;
506  
507   /* Main addr */
508   COPY_IP(&net_msg->main_addr, &olsr_cnf->main_addr);
509
510
511   /*
512   printf("\t");
513   x = 0;
514   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
515     {
516       if(x == 4)
517         {
518           x = 0;
519           printf("\n\t");
520         }
521       x++;
522       printf(" %03i", (u_char) msg[i]);
523     }
524   
525   printf("\n");
526   */
527
528
529   if (send(fd, (char *)net_msg, sizeof(struct ipc_net_msg), MSG_NOSIGNAL) < 0) 
530     {
531       OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n");
532       CLOSE(ipc_conn);
533       //olsr_cnf->open_ipc = 0;
534       return -1;
535     }
536
537   free(net_msg);
538   return 0;
539 }
540
541
542
543 int
544 shutdown_ipc(void)
545 {
546   OLSR_PRINTF(1, "Shutting down IPC...\n");
547   CLOSE(ipc_sock);
548   CLOSE(ipc_conn);
549   
550   return 1;
551 }