Some hackish stuff to allow quick restart of olsrd using IPC
[olsrd.git] / src / ipc_frontend.c
1 /*
2  * OLSR ad-hoc routing table management protocol
3  * Copyright (C) 2003 Andreas T√łnnesen (andreto@ifi.uio.no)
4  *
5  * This file is part of the olsr.org OLSR daemon.
6  *
7  * olsr.org is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * olsr.org is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with olsr.org; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  * 
21  * 
22  * $Id: ipc_frontend.c,v 1.20 2004/11/20 21:42:23 kattemat Exp $
23  *
24  */
25
26 /*
27  *Andreas T√łnnesen (andreto@ifi.uio.no)
28  *
29  *IPC - interprocess communication
30  *for the OLSRD - GUI front-end
31  *
32  */
33
34 #include "ipc_frontend.h"
35 #include "link_set.h"
36 #include "olsr.h"
37 #include "parser.h"
38 #include "socket_parser.h"
39 #include "local_hna_set.h"
40
41 #ifdef WIN32
42 #define close(x) closesocket(x)
43 #define perror(x) WinSockPError(x)
44 void 
45 WinSockPError(char *);
46 #endif
47
48 #ifndef linux
49 #define MSG_NOSIGNAL 0
50 #endif
51
52 /**
53  *Create the socket to use for IPC to the
54  *GUI front-end
55  *
56  *@return the socket FD
57  */
58 int
59 ipc_init()
60 {
61   //int flags;
62   struct   sockaddr_in sin;
63   int yes = 1;
64
65   /* Add parser function */
66   olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS, 0);
67
68   /* get an internet domain socket */
69   if ((ipc_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
70     {
71       perror("IPC socket");
72       olsr_exit("IPC socket", EXIT_FAILURE);
73     }
74
75   if(setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
76     {
77       perror("SO_REUSEADDR failed");
78       return 0;
79     }
80
81   /* complete the socket structure */
82   memset(&sin, 0, sizeof(sin));
83   sin.sin_family = AF_INET;
84   sin.sin_addr.s_addr = INADDR_ANY;
85   sin.sin_port = htons(IPC_PORT);
86
87   /* bind the socket to the port number */
88   if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
89     {
90       perror("IPC bind");
91       olsr_printf(1, "Will retry in 10 seconds...\n");
92       sleep(10);
93       if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
94         {
95           perror("IPC bind");
96           olsr_exit("IPC bind", EXIT_FAILURE);
97         }
98       olsr_printf(1, "OK\n");
99     }
100
101   /* show that we are willing to listen */
102   if(listen(ipc_sock, olsr_cnf->ipc_connections) == -1) 
103     {
104       perror("IPC listen");
105       olsr_exit("IPC listen", EXIT_FAILURE);
106     }
107
108   /* Register the socket with the socket parser */
109   add_olsr_socket(ipc_sock, &ipc_accept);
110
111   return ipc_sock;
112 }
113
114
115 void
116 ipc_accept(int fd)
117 {
118   int                addrlen;
119   struct sockaddr_in pin;
120   char *addr;  
121
122
123   addrlen = sizeof (struct sockaddr_in);
124   
125   if ((ipc_connection = accept(ipc_sock, (struct sockaddr *)  &pin, &addrlen)) == -1)
126     {
127       perror("IPC accept");
128       olsr_exit("IPC accept", EXIT_FAILURE);
129     }
130   else
131     {
132       olsr_printf(1, "Front end connected\n");
133       addr = inet_ntoa(pin.sin_addr);
134       if(ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr))
135         {
136           ipc_active = OLSR_TRUE;
137           ipc_send_net_info();
138           ipc_send_all_routes();
139           olsr_printf(1, "Connection from %s\n",addr);
140         }
141       else
142         {
143           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
144           olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
145           close(ipc_connection);
146         }
147     }
148
149 }
150
151 olsr_bool
152 ipc_check_allowed_ip(union olsr_ip_addr *addr)
153 {
154   struct ipc_host *ipch = olsr_cnf->ipc_hosts;
155   struct ipc_net *ipcn = olsr_cnf->ipc_nets;
156
157   if(addr->v4 == ntohl(INADDR_LOOPBACK))
158     return OLSR_TRUE;
159
160   /* check hosts */
161   while(ipch)
162     {
163       if(addr->v4 == ipch->host.v4)
164         return OLSR_TRUE;
165       ipch = ipch->next;
166     }
167
168   /* check nets */
169   while(ipcn)
170     {
171       if((addr->v4 & ipcn->mask.v4) == (ipcn->net.v4 & ipcn->mask.v4))
172         return OLSR_TRUE;
173       ipcn = ipcn->next;
174     }
175
176   return OLSR_FALSE;
177 }
178
179 /**
180  *Read input from the IPC socket. Not in use.
181  *
182  *@todo for future use
183  *@param sock the IPC socket
184  *@return 1
185  */
186 int
187 ipc_input(int sock)
188 {
189   /*
190   union 
191   {
192     char        buf[MAXPACKETSIZE+1];
193     struct      olsr olsr;
194   } inbuf;
195
196
197   if (recv(sock, dir, sizeof(dir), 0) == -1) 
198     {
199       perror("recv");
200       exit(1);
201     }
202 */
203   return 1;
204 }
205
206
207 /**
208  *Sends a olsr packet on the IPC socket.
209  *
210  *@param olsr the olsr struct representing the packet
211  *
212  *@return negative on error
213  */
214 void
215 frontend_msgparser(union olsr_message *msg, struct interface *in_if, union olsr_ip_addr *from_addr)
216 {
217   int size;
218
219   if(!ipc_active)
220     return;
221   
222   if(olsr_cnf->ip_version == AF_INET)
223     size = ntohs(msg->v4.olsr_msgsize);
224   else
225     size = ntohs(msg->v6.olsr_msgsize);
226   
227   if (send(ipc_connection, (void *)msg, size, MSG_NOSIGNAL) < 0) 
228     {
229       olsr_printf(1, "(OUTPUT)IPC connection lost!\n");
230       close(ipc_connection);
231       //olsr_cnf->open_ipc = 0;
232       ipc_active = OLSR_FALSE;
233       return;
234     }
235   
236   return;
237 }
238
239
240 /**
241  *Send a route table update to the front-end.
242  *
243  *@param kernel_route a rtentry describing the route update
244  *@param add 1 if the route is to be added 0 if it is to be deleted
245  *@param int_name the name of the interface the route is set to go by
246  *
247  *@return negative on error
248  */
249 int
250 ipc_route_send_rtentry(union olsr_ip_addr *dst, union olsr_ip_addr *gw, int met, int add, char *int_name)
251 {
252   struct ipcmsg packet;
253   //int i, x;
254   char *tmp;
255
256   if(!ipc_active)
257     return 0;
258
259   memset(&packet, 0, sizeof(struct ipcmsg));
260   packet.size = htons(IPC_PACK_SIZE);
261   packet.msgtype = ROUTE_IPC;
262
263   COPY_IP(&packet.target_addr, dst);
264
265   packet.add = add;
266   if(add && gw)
267     {
268       packet.metric = met;
269       COPY_IP(&packet.gateway_addr, gw);
270     }
271
272   if(int_name != NULL)
273     memcpy(&packet.device[0], int_name, 4);
274   else
275     memset(&packet.device[0], 0, 4);
276
277
278   tmp = (char *) &packet;
279   /*
280   x = 0;
281   for(i = 0; i < IPC_PACK_SIZE;i++)
282     {
283       if(x == 4)
284         {
285           x = 0;
286           printf("\n\t");
287         }
288       x++;
289       printf(" %03i", (u_char) tmp[i]);
290     }
291   
292   printf("\n");
293   */
294   
295   if (send(ipc_connection, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
296     {
297       olsr_printf(1, "(RT_ENTRY)IPC connection lost!\n");
298       close(ipc_connection);
299       //olsr_cnf->open_ipc = 0;
300       ipc_active = OLSR_FALSE;
301       return -1;
302     }
303
304   return 1;
305 }
306
307
308
309 int
310 ipc_send_all_routes()
311 {
312   struct rt_entry  *destination;
313   struct interface *ifn;
314   olsr_u8_t        index;
315   struct ipcmsg packet;
316   char *tmp;
317   
318
319   if(!ipc_active)
320     return 0;
321   
322   for(index=0;index<HASHSIZE;index++)
323     {
324       for(destination = routingtable[index].next;
325           destination != &routingtable[index];
326           destination = destination->next)
327         {
328           ifn = get_interface_link_set(&destination->rt_router);
329           
330
331           memset(&packet, 0, sizeof(struct ipcmsg));
332           packet.size = htons(IPC_PACK_SIZE);
333           packet.msgtype = ROUTE_IPC;
334           
335           COPY_IP(&packet.target_addr, &destination->rt_dst);
336           
337           packet.add = 1;
338
339           if(olsr_cnf->ip_version == AF_INET)
340             {
341               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
342             }
343           else
344             {
345               packet.metric = (olsr_u8_t)destination->rt_metric;
346             }
347           COPY_IP(&packet.gateway_addr, &destination->rt_router);
348
349           if(ifn)
350             memcpy(&packet.device[0], ifn->int_name, 4);
351           else
352             memset(&packet.device[0], 0, 4);
353
354
355           tmp = (char *) &packet;
356   
357           if (send(ipc_connection, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
358             {
359               olsr_printf(1, "(RT_ENTRY)IPC connection lost!\n");
360               close(ipc_connection);
361               //olsr_cnf->open_ipc = 0;
362               ipc_active = OLSR_FALSE;
363               return -1;
364             }
365
366         }
367     }
368
369   for(index=0;index<HASHSIZE;index++)
370     {
371       for(destination = hna_routes[index].next;
372           destination != &hna_routes[index];
373           destination = destination->next)
374         {
375           ifn = get_interface_link_set(&destination->rt_router);
376
377           packet.size = htons(IPC_PACK_SIZE);
378           packet.msgtype = ROUTE_IPC;
379           
380           COPY_IP(&packet.target_addr, &destination->rt_dst);
381           
382           packet.add = 1;
383
384           if(olsr_cnf->ip_version == AF_INET)
385             {
386               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
387             }
388           else
389             {
390               packet.metric = (olsr_u8_t)destination->rt_metric;
391             }
392           COPY_IP(&packet.gateway_addr, &destination->rt_router);
393
394           if(ifn)
395             memcpy(&packet.device[0], ifn->int_name, 4);
396           else
397             memset(&packet.device[0], 0, 4);
398
399
400           tmp = (char *) &packet;
401   
402           if (send(ipc_connection, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
403             {
404               olsr_printf(1, "(RT_ENTRY)IPC connection lost!\n");
405               close(ipc_connection);
406               //olsr_cnf->open_ipc = 0;
407               ipc_active = OLSR_FALSE;
408               return -1;
409             }
410
411         }
412     }
413
414
415   return 1;
416 }
417
418
419
420 /**
421  *Sends OLSR info to the front-end. This info consists of
422  *the different time intervals and holding times, number
423  *of interfaces, HNA routes and main address.
424  *
425  *@return negative on error
426  */
427 int
428 ipc_send_net_info()
429 {
430   struct ipc_net_msg *net_msg;
431   //int x, i;
432   char *msg;
433   
434
435   net_msg = olsr_malloc(sizeof(struct ipc_net_msg), "send net info");
436
437   msg = (char *)net_msg;
438
439   olsr_printf(1, "Sending net-info to front end...\n");
440   
441   memset(net_msg, 0, sizeof(struct ipc_net_msg));
442   
443   /* Message size */
444   net_msg->size = htons(sizeof(struct ipc_net_msg));
445   /* Message type */
446   net_msg->msgtype = NET_IPC;
447   
448   /* MIDs */
449 #warning fix IPC MIDcnt
450   net_msg->mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
451   
452   /* HNAs */
453   if(olsr_cnf->ip_version == AF_INET6)
454     {
455       if(olsr_cnf->hna6_entries == NULL)
456         net_msg->hnas = 0;
457       else
458         net_msg->hnas = 1;
459     }
460
461   if(olsr_cnf->ip_version == AF_INET)
462     {
463       if(olsr_cnf->hna4_entries == NULL)
464         net_msg->hnas = 0;
465       else
466         net_msg->hnas = 1;
467     }
468
469   /* Different values */
470   /* Temporary fixes */
471 #warning fix IPC intervals
472   net_msg->hello_int = 0;//htons((olsr_u16_t)hello_int);
473   net_msg->hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
474   net_msg->tc_int = 0;//htons((olsr_u16_t)tc_int);
475   net_msg->neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
476   net_msg->topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
477
478   if(olsr_cnf->ip_version == AF_INET)
479     net_msg->ipv6 = 0;
480   else
481     net_msg->ipv6 = 1;
482  
483   /* Main addr */
484   COPY_IP(&net_msg->main_addr, &main_addr);
485
486
487   /*
488   printf("\t");
489   x = 0;
490   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
491     {
492       if(x == 4)
493         {
494           x = 0;
495           printf("\n\t");
496         }
497       x++;
498       printf(" %03i", (u_char) msg[i]);
499     }
500   
501   printf("\n");
502   */
503
504
505   if (send(ipc_connection, (char *)net_msg, sizeof(struct ipc_net_msg), MSG_NOSIGNAL) < 0) 
506     {
507       olsr_printf(1, "(NETINFO)IPC connection lost!\n");
508       close(ipc_connection);
509       //olsr_cnf->open_ipc = 0;
510       return -1;
511     }
512
513   free(net_msg);
514   return 0;
515 }
516
517
518
519 int
520 shutdown_ipc()
521 {
522   olsr_printf(1, "Shutting down IPC...\n");
523   close(ipc_sock);
524   close(ipc_connection);
525   
526   return 1;
527 }