8f5b6561353ce8fd894722a7d7186958d4b6fd21
[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.13 2004/11/11 21:14:17 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 "local_hna_set.h"
39
40 #ifdef WIN32
41 #define close(x) closesocket(x)
42 #define perror(x) WinSockPError(x)
43 void 
44 WinSockPError(char *);
45 #endif
46
47 #ifndef linux
48 #define MSG_NOSIGNAL 0
49 #endif
50
51 pthread_t accept_thread;
52
53 /**
54  *Create the socket to use for IPC to the
55  *GUI front-end
56  *
57  *@return the socket FD
58  */
59 int
60 ipc_init()
61 {
62   //int flags;
63   struct   sockaddr_in sin;
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   /* complete the socket structure */
76   memset(&sin, 0, sizeof(sin));
77   sin.sin_family = AF_INET;
78   sin.sin_addr.s_addr = INADDR_ANY;
79   sin.sin_port = htons(IPC_PORT);
80
81   /* bind the socket to the port number */
82   if (bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
83     {
84       perror("IPC bind");
85       olsr_exit("IPC bind", EXIT_FAILURE);
86     }
87
88   /* show that we are willing to listen */
89   if (listen(ipc_sock, 5) == -1) 
90     {
91       perror("IPC listen");
92       olsr_exit("IPC listen", EXIT_FAILURE);
93     }
94
95
96   /* Start the accept thread */
97
98   pthread_create(&accept_thread, NULL, (void *)&ipc_accept_thread, NULL);
99
100   return ipc_sock;
101 }
102
103
104 /*
105  * XXX - the socket should just be registered with the socket parser.
106  * Should NOT spawn this listen thread!
107  */
108 void
109 ipc_accept_thread()
110 {
111   int                addrlen;
112   struct sockaddr_in pin;
113   char *addr;  
114
115   while(olsr_cnf->open_ipc)
116     {
117       olsr_printf(2, "\nFront-end accept thread initiated(socket %d)\n\n", ipc_sock);
118
119       addrlen = sizeof (struct sockaddr_in);
120
121       if ((ipc_connection = accept(ipc_sock, (struct sockaddr *)  &pin, &addrlen)) == -1)
122         {
123           perror("IPC accept");
124           olsr_exit("IPC accept", EXIT_FAILURE);
125         }
126       else
127         {
128           olsr_printf(1, "Front end connected\n");
129           addr = inet_ntoa(pin.sin_addr);
130           if(ntohl(pin.sin_addr.s_addr) != INADDR_LOOPBACK)
131             {
132               olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
133               olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
134               close(ipc_connection);
135             }
136           else
137             {
138               ipc_active = OLSR_TRUE;
139               ipc_send_net_info();
140               ipc_send_all_routes();
141               olsr_printf(1, "Connection from %s\n",addr);
142             }
143         }
144
145       sleep(2);
146     }
147 }
148
149
150
151 /**
152  *Read input from the IPC socket. Not in use.
153  *
154  *@todo for future use
155  *@param sock the IPC socket
156  *@return 1
157  */
158 int
159 ipc_input(int sock)
160 {
161   /*
162   union 
163   {
164     char        buf[MAXPACKETSIZE+1];
165     struct      olsr olsr;
166   } inbuf;
167
168
169   if (recv(sock, dir, sizeof(dir), 0) == -1) 
170     {
171       perror("recv");
172       exit(1);
173     }
174 */
175   return 1;
176 }
177
178
179 /**
180  *Sends a olsr packet on the IPC socket.
181  *
182  *@param olsr the olsr struct representing the packet
183  *
184  *@return negative on error
185  */
186 void
187 frontend_msgparser(union olsr_message *msg, struct interface *in_if, union olsr_ip_addr *from_addr)
188 {
189   int size;
190
191   if(!ipc_active)
192     return;
193   
194   if(olsr_cnf->ip_version == AF_INET)
195     size = ntohs(msg->v4.olsr_msgsize);
196   else
197     size = ntohs(msg->v6.olsr_msgsize);
198   
199   if (send(ipc_connection, (void *)msg, size, MSG_NOSIGNAL) < 0) 
200     {
201       olsr_printf(1, "(OUTPUT)IPC connection lost!\n");
202       close(ipc_connection);
203       //olsr_cnf->open_ipc = 0;
204       ipc_active = OLSR_FALSE;
205       return;
206     }
207   
208   return;
209 }
210
211
212 /**
213  *Send a route table update to the front-end.
214  *
215  *@param kernel_route a rtentry describing the route update
216  *@param add 1 if the route is to be added 0 if it is to be deleted
217  *@param int_name the name of the interface the route is set to go by
218  *
219  *@return negative on error
220  */
221 int
222 ipc_route_send_rtentry(union olsr_kernel_route *kernel_route, int add, char *int_name)
223 {
224   struct ipcmsg packet;
225   //int i, x;
226   char *tmp;
227
228   if(!ipc_active)
229     return 0;
230
231   packet.size = htons(IPC_PACK_SIZE);
232   packet.msgtype = ROUTE_IPC;
233
234   if(olsr_cnf->ip_version == AF_INET)
235     COPY_IP(&packet.target_addr, &((struct sockaddr_in *)&kernel_route->v4.rt_dst)->sin_addr.s_addr);
236   else
237     COPY_IP(&packet.target_addr, &kernel_route->v6.rtmsg_dst);
238
239   packet.add = add;
240   if(add)
241     {
242       if(olsr_cnf->ip_version == AF_INET)
243         {
244           packet.metric = kernel_route->v4.rt_metric - 1;
245           COPY_IP(&packet.gateway_addr, &((struct sockaddr_in *)&kernel_route->v4.rt_gateway)->sin_addr.s_addr);
246         }
247       else
248         {
249           packet.metric = kernel_route->v6.rtmsg_metric;
250           COPY_IP(&packet.gateway_addr, &kernel_route->v6.rtmsg_gateway);
251         }
252
253       if(int_name != NULL)
254         memcpy(&packet.device[0], int_name, 4);
255       else
256         memset(&packet.device[0], 0, 4);
257     }
258   else
259     {
260       memset(&packet.metric, 0, 1);
261       memset(&packet.gateway_addr, 0, 4);
262       memset(&packet.device[0], 0, 4);
263     }
264
265
266   tmp = (char *) &packet;
267   /*
268   x = 0;
269   for(i = 0; i < IPC_PACK_SIZE;i++)
270     {
271       if(x == 4)
272         {
273           x = 0;
274           printf("\n\t");
275         }
276       x++;
277       printf(" %03i", (u_char) tmp[i]);
278     }
279   
280   printf("\n");
281   */
282   
283   if (send(ipc_connection, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
284     {
285       olsr_printf(1, "(RT_ENTRY)IPC connection lost!\n");
286       close(ipc_connection);
287       //olsr_cnf->open_ipc = 0;
288       ipc_active = OLSR_FALSE;
289       return -1;
290     }
291
292   return 1;
293 }
294
295
296
297 int
298 ipc_send_all_routes()
299 {
300   struct rt_entry  *destination;
301   struct interface *ifn;
302   olsr_u8_t        index;
303   struct ipcmsg packet;
304   char *tmp;
305   
306
307   if(!ipc_active)
308     return 0;
309   
310   for(index=0;index<HASHSIZE;index++)
311     {
312       for(destination = routingtable[index].next;
313           destination != &routingtable[index];
314           destination = destination->next)
315         {
316           ifn = get_interface_link_set(&destination->rt_router);
317           
318
319           
320           packet.size = htons(IPC_PACK_SIZE);
321           packet.msgtype = ROUTE_IPC;
322           
323           COPY_IP(&packet.target_addr, &destination->rt_dst);
324           
325           packet.add = 1;
326
327           if(olsr_cnf->ip_version == AF_INET)
328             {
329               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
330             }
331           else
332             {
333               packet.metric = (olsr_u8_t)destination->rt_metric;
334             }
335           COPY_IP(&packet.gateway_addr, &destination->rt_router);
336
337           if(ifn)
338             memcpy(&packet.device[0], ifn->int_name, 4);
339           else
340             memset(&packet.device[0], 0, 4);
341
342
343           tmp = (char *) &packet;
344   
345           if (send(ipc_connection, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
346             {
347               olsr_printf(1, "(RT_ENTRY)IPC connection lost!\n");
348               close(ipc_connection);
349               //olsr_cnf->open_ipc = 0;
350               ipc_active = OLSR_FALSE;
351               return -1;
352             }
353
354         }
355     }
356
357   for(index=0;index<HASHSIZE;index++)
358     {
359       for(destination = hna_routes[index].next;
360           destination != &hna_routes[index];
361           destination = destination->next)
362         {
363           ifn = get_interface_link_set(&destination->rt_router);
364
365           packet.size = htons(IPC_PACK_SIZE);
366           packet.msgtype = ROUTE_IPC;
367           
368           COPY_IP(&packet.target_addr, &destination->rt_dst);
369           
370           packet.add = 1;
371
372           if(olsr_cnf->ip_version == AF_INET)
373             {
374               packet.metric = (olsr_u8_t)(destination->rt_metric - 1);
375             }
376           else
377             {
378               packet.metric = (olsr_u8_t)destination->rt_metric;
379             }
380           COPY_IP(&packet.gateway_addr, &destination->rt_router);
381
382           if(ifn)
383             memcpy(&packet.device[0], ifn->int_name, 4);
384           else
385             memset(&packet.device[0], 0, 4);
386
387
388           tmp = (char *) &packet;
389   
390           if (send(ipc_connection, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
391             {
392               olsr_printf(1, "(RT_ENTRY)IPC connection lost!\n");
393               close(ipc_connection);
394               //olsr_cnf->open_ipc = 0;
395               ipc_active = OLSR_FALSE;
396               return -1;
397             }
398
399         }
400     }
401
402
403   return 1;
404 }
405
406
407
408 /**
409  *Sends OLSR info to the front-end. This info consists of
410  *the different time intervals and holding times, number
411  *of interfaces, HNA routes and main address.
412  *
413  *@return negative on error
414  */
415 int
416 ipc_send_net_info()
417 {
418   struct ipc_net_msg *net_msg;
419   //int x, i;
420   char *msg;
421   
422
423   net_msg = olsr_malloc(sizeof(struct ipc_net_msg), "send net info");
424
425   msg = (char *)net_msg;
426
427   olsr_printf(1, "Sending net-info to front end...\n");
428   
429   memset(net_msg, 0, sizeof(struct ipc_net_msg));
430   
431   /* Message size */
432   net_msg->size = htons(sizeof(struct ipc_net_msg));
433   /* Message type */
434   net_msg->msgtype = NET_IPC;
435   
436   /* MIDs */
437 #warning fix IPC MIDcnt
438   net_msg->mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
439   
440   /* HNAs */
441   if(olsr_cnf->ip_version == AF_INET6)
442     {
443       if(olsr_cnf->hna6_entries == NULL)
444         net_msg->hnas = 0;
445       else
446         net_msg->hnas = 1;
447     }
448
449   if(olsr_cnf->ip_version == AF_INET)
450     {
451       if(olsr_cnf->hna4_entries == NULL)
452         net_msg->hnas = 0;
453       else
454         net_msg->hnas = 1;
455     }
456
457   /* Different values */
458   /* Temporary fixes */
459 #warning fix IPC intervals
460   net_msg->hello_int = 0;//htons((olsr_u16_t)hello_int);
461   net_msg->hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
462   net_msg->tc_int = 0;//htons((olsr_u16_t)tc_int);
463   net_msg->neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
464   net_msg->topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
465
466   if(olsr_cnf->ip_version == AF_INET)
467     net_msg->ipv6 = 0;
468   else
469     net_msg->ipv6 = 1;
470  
471   /* Main addr */
472   COPY_IP(&net_msg->main_addr, &main_addr);
473
474
475   /*
476   printf("\t");
477   x = 0;
478   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
479     {
480       if(x == 4)
481         {
482           x = 0;
483           printf("\n\t");
484         }
485       x++;
486       printf(" %03i", (u_char) msg[i]);
487     }
488   
489   printf("\n");
490   */
491
492
493   if (send(ipc_connection, (char *)net_msg, sizeof(struct ipc_net_msg), MSG_NOSIGNAL) < 0) 
494     {
495       olsr_printf(1, "(NETINFO)IPC connection lost!\n");
496       close(ipc_connection);
497       //olsr_cnf->open_ipc = 0;
498       return -1;
499     }
500
501   free(net_msg);
502   return 0;
503 }
504
505
506
507 int
508 shutdown_ipc()
509 {
510
511   pthread_kill(accept_thread, SIGTERM);
512   close(ipc_sock);
513   
514   if(ipc_active)
515     close(ipc_connection);
516   
517   return 1;
518 }