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