* OLSR_PRINTF() is now a real C expression
[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.30 2007/04/25 22:08:08 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     }
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   olsr_u8_t        index;
339   struct ipcmsg packet;
340   char *tmp;
341   
342
343   if(!ipc_active)
344     return 0;
345   
346   for(index=0;index<HASHSIZE;index++)
347     {
348       for(destination = routingtable[index].next;
349           destination != &routingtable[index];
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(index=0;index<HASHSIZE;index++)
394     {
395       for(destination = hna_routes[index].next;
396           destination != &hna_routes[index];
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 }