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