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