0d7b4ae293b0fcc0fca4aba0f219352f7b66ad71
[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.39 2007/11/11 22:59:29 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 #include "net_olsr.h"
57
58 #ifdef WIN32
59 #define close(x) closesocket(x)
60 #define perror(x) WinSockPError(x)
61 void 
62 WinSockPError(char *);
63 #endif
64
65 #ifndef linux
66 #define MSG_NOSIGNAL 0
67 #endif
68
69 static int ipc_sock = -1;
70 static int ipc_conn = -1;
71 static int ipc_active = OLSR_FALSE;
72
73 static int
74 ipc_send_all_routes(int fd);
75
76 static int
77 ipc_send_net_info(int fd);
78
79
80 /**
81  *Create the socket to use for IPC to the
82  *GUI front-end
83  *
84  *@return the socket FD
85  */
86 int
87 ipc_init(void)
88 {
89   //int flags;
90   struct   sockaddr_in sin;
91   int yes = 1;
92
93   /* Add parser function */
94   olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS, 0);
95
96   /* get an internet domain socket */
97   if ((ipc_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
98     {
99       perror("IPC socket");
100       olsr_exit("IPC socket", EXIT_FAILURE);
101     }
102
103   if(setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
104     {
105       perror("SO_REUSEADDR failed");
106       return 0;
107     }
108
109   /* complete the socket structure */
110   memset(&sin, 0, sizeof(sin));
111   sin.sin_family = AF_INET;
112   sin.sin_addr.s_addr = INADDR_ANY;
113   sin.sin_port = htons(IPC_PORT);
114
115   /* bind the socket to the port number */
116   if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
117     {
118       perror("IPC bind");
119       OLSR_PRINTF(1, "Will retry in 10 seconds...\n");
120       sleep(10);
121       if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
122         {
123           perror("IPC bind");
124           olsr_exit("IPC bind", EXIT_FAILURE);
125         }
126       OLSR_PRINTF(1, "OK\n");
127     }
128
129   /* show that we are willing to listen */
130   if(listen(ipc_sock, olsr_cnf->ipc_connections) == -1) 
131     {
132       perror("IPC listen");
133       olsr_exit("IPC listen", EXIT_FAILURE);
134     }
135
136   /* Register the socket with the socket parser */
137   add_olsr_socket(ipc_sock, &ipc_accept);
138
139   return ipc_sock;
140 }
141
142
143 void
144 ipc_accept(int fd)
145 {
146   socklen_t addrlen;
147   struct sockaddr_in pin;
148   char *addr;  
149
150
151   addrlen = sizeof (struct sockaddr_in);
152   
153   if ((ipc_conn = accept(fd, (struct sockaddr *)  &pin, &addrlen)) == -1)
154     {
155       perror("IPC accept");
156       olsr_exit("IPC accept", EXIT_FAILURE);
157     }
158   else
159     {
160       OLSR_PRINTF(1, "Front end connected\n");
161       addr = inet_ntoa(pin.sin_addr);
162       if(ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr))
163         {
164           ipc_active = OLSR_TRUE;
165           ipc_send_net_info(ipc_conn);
166           ipc_send_all_routes(ipc_conn);
167           OLSR_PRINTF(1, "Connection from %s\n",addr);
168         }
169       else
170         {
171           OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
172           olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
173           CLOSE(ipc_conn);
174         }
175     }
176
177 }
178
179 olsr_bool
180 ipc_check_allowed_ip(const union olsr_ip_addr *addr)
181 {
182   struct ipc_host *ipch = olsr_cnf->ipc_hosts;
183   struct ipc_net *ipcn = olsr_cnf->ipc_nets;
184
185   if(addr->v4.s_addr == ntohl(INADDR_LOOPBACK))
186     return OLSR_TRUE;
187
188   /* check hosts */
189   while(ipch)
190     {
191         if(ipequal(addr, &ipch->host))
192         return OLSR_TRUE;
193       ipch = ipch->next;
194     }
195
196   /* check nets */
197   while(ipcn)
198     {
199       if((addr->v4.s_addr & ipcn->mask.v4.s_addr) == (ipcn->net.v4.s_addr & ipcn->mask.v4.s_addr))
200         return OLSR_TRUE;
201       ipcn = ipcn->next;
202     }
203
204   return OLSR_FALSE;
205 }
206
207 #if 0
208 /**
209  *Read input from the IPC socket. Not in use.
210  *
211  *@todo for future use
212  *@param sock the IPC socket
213  *@return 1
214  */
215 int
216 ipc_input(int sock __attribute__((unused)))
217 {
218   union 
219   {
220     char        buf[MAXPACKETSIZE+1];
221     struct olsr olsr;
222   } inbuf;
223
224
225   if (recv(sock, dir, sizeof(dir), 0) == -1) 
226     {
227       perror("recv");
228       exit(1);
229     }
230   return 1;
231 }
232 #endif
233
234 /**
235  *Sends a olsr packet on the IPC socket.
236  *
237  *@param olsr the olsr struct representing the packet
238  *
239  *@return negative on error
240  */
241 void
242 frontend_msgparser(union olsr_message *msg, struct interface *in_if __attribute__((unused)), union olsr_ip_addr *from_addr __attribute__((unused)))
243 {
244   int size;
245
246   if(!ipc_active)
247     return;
248   
249   if(olsr_cnf->ip_version == AF_INET)
250     size = ntohs(msg->v4.olsr_msgsize);
251   else
252     size = ntohs(msg->v6.olsr_msgsize);
253   
254   if (send(ipc_conn, (void *)msg, size, MSG_NOSIGNAL) < 0) 
255     {
256       OLSR_PRINTF(1, "(OUTPUT)IPC connection lost!\n");
257       CLOSE(ipc_conn);
258       //olsr_cnf->open_ipc = 0;
259       ipc_active = OLSR_FALSE;
260     }
261 }
262
263
264 /**
265  *Send a route table update to the front-end.
266  *
267  *@param kernel_route a rtentry describing the route update
268  *@param add 1 if the route is to be added 0 if it is to be deleted
269  *@param int_name the name of the interface the route is set to go by
270  *
271  *@return negative on error
272  */
273 int
274 ipc_route_send_rtentry(const union olsr_ip_addr *dst,
275                        const union olsr_ip_addr *gw,
276                        int met,
277                        int add,
278                        const char *int_name)
279 {
280   struct ipcmsg packet;
281   char *tmp;
282
283   if(!olsr_cnf->open_ipc) {
284     return -1;
285   }
286
287   if(!ipc_active)
288     return 0;
289
290   memset(&packet, 0, sizeof(struct ipcmsg));
291   packet.size = htons(IPC_PACK_SIZE);
292   packet.msgtype = ROUTE_IPC;
293
294   //COPY_IP(&packet.target_addr, dst);
295   packet.target_addr = *dst;
296
297   packet.add = add;
298   if(add && gw)
299     {
300       packet.metric = met;
301       //COPY_IP(&packet.gateway_addr, gw);
302       packet.gateway_addr = *gw;
303     }
304
305   if(int_name != NULL)
306     memcpy(&packet.device[0], int_name, 4);
307   else
308     memset(&packet.device[0], 0, 4);
309
310
311   tmp = (char *) &packet;
312   /*
313   x = 0;
314   for(i = 0; i < IPC_PACK_SIZE;i++)
315     {
316       if(x == 4)
317         {
318           x = 0;
319           printf("\n\t");
320         }
321       x++;
322       printf(" %03i", (u_char) tmp[i]);
323     }
324   
325   printf("\n");
326   */
327   
328   if (send(ipc_conn, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
329     {
330       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
331       CLOSE(ipc_conn);
332
333       //olsr_cnf->open_ipc = 0;
334       ipc_active = OLSR_FALSE;
335       return -1;
336     }
337
338   return 1;
339 }
340
341
342
343 static int
344 ipc_send_all_routes(int fd)
345 {
346   struct rt_entry  *rt;
347   struct ipcmsg packet;
348   char *tmp;
349   
350
351   if(!ipc_active)
352     return 0;
353   
354   OLSR_FOR_ALL_RT_ENTRIES(rt) {
355
356     memset(&packet, 0, sizeof(struct ipcmsg));
357     packet.size = htons(IPC_PACK_SIZE);
358     packet.msgtype = ROUTE_IPC;
359           
360     //COPY_IP(&packet.target_addr, &rt->rt_dst.prefix);
361     packet.target_addr = rt->rt_dst.prefix;
362
363     packet.add = 1;
364     packet.metric = (olsr_u8_t)(rt->rt_best->rtp_metric.hops);
365
366     //COPY_IP(&packet.gateway_addr, &rt->rt_nexthop.gateway);
367     packet.gateway_addr = rt->rt_nexthop.gateway;
368
369     memcpy(&packet.device[0], if_ifwithindex_name(rt->rt_nexthop.iif_index), 4);
370
371     tmp = (char *) &packet;
372   
373     /* MSG_NOSIGNAL to avoid sigpipe */
374     if (send(fd, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) {
375       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
376       CLOSE(ipc_conn);
377       ipc_active = OLSR_FALSE;
378       return -1;
379     }
380   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
381   return 1;
382 }
383
384
385
386 /**
387  *Sends OLSR info to the front-end. This info consists of
388  *the different time intervals and holding times, number
389  *of interfaces, HNA routes and main address.
390  *
391  *@return negative on error
392  */
393 static int
394 ipc_send_net_info(int fd)
395 {
396   struct ipc_net_msg *net_msg;
397   //int x, i;
398   char *msg;
399   
400
401   net_msg = olsr_malloc(sizeof(struct ipc_net_msg), "send net info");
402
403   msg = (char *)net_msg;
404
405   OLSR_PRINTF(1, "Sending net-info to front end...\n");
406   
407   memset(net_msg, 0, sizeof(struct ipc_net_msg));
408   
409   /* Message size */
410   net_msg->size = htons(sizeof(struct ipc_net_msg));
411   /* Message type */
412   net_msg->msgtype = NET_IPC;
413   
414   /* MIDs */
415   /* XXX fix IPC MIDcnt */
416   net_msg->mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
417   
418   /* HNAs */
419   net_msg->hnas = olsr_cnf->hna_entries == NULL ? 0 : 1;
420
421   /* Different values */
422   /* Temporary fixes */
423   /* XXX fix IPC intervals */
424   net_msg->hello_int = 0;//htons((olsr_u16_t)hello_int);
425   net_msg->hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
426   net_msg->tc_int = 0;//htons((olsr_u16_t)tc_int);
427   net_msg->neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
428   net_msg->topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
429
430   net_msg->ipv6 = olsr_cnf->ip_version == AF_INET ? 0 : 1;
431  
432   /* Main addr */
433   //COPY_IP(&net_msg->main_addr, &olsr_cnf->main_addr);
434   net_msg->main_addr = olsr_cnf->main_addr;
435
436   /*
437   printf("\t");
438   x = 0;
439   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
440     {
441       if(x == 4)
442         {
443           x = 0;
444           printf("\n\t");
445         }
446       x++;
447       printf(" %03i", (u_char) msg[i]);
448     }
449   
450   printf("\n");
451   */
452
453
454   if (send(fd, (char *)net_msg, sizeof(struct ipc_net_msg), MSG_NOSIGNAL) < 0) 
455     {
456       OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n");
457       CLOSE(ipc_conn);
458       //olsr_cnf->open_ipc = 0;
459       return -1;
460     }
461
462   free(net_msg);
463   return 0;
464 }
465
466
467
468 int
469 shutdown_ipc(void)
470 {
471   OLSR_PRINTF(1, "Shutting down IPC...\n");
472   CLOSE(ipc_sock);
473   CLOSE(ipc_conn);
474   
475   return 1;
476 }
477
478 /*
479  * Local Variables:
480  * c-basic-offset: 2
481  * End:
482  */