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