Make the socket parser more general
[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  */
40
41 /*
42  *
43  *IPC - interprocess communication
44  *for the OLSRD - GUI front-end
45  *
46  */
47
48 #include "ipc_frontend.h"
49 #include "link_set.h"
50 #include "olsr.h"
51 #include "log.h"
52 #include "parser.h"
53 #include "socket_parser.h"
54 #include "net_olsr.h"
55 #include "ipcalc.h"
56
57 #include <unistd.h>
58 #include <stdlib.h>
59
60 #ifdef WIN32
61 #define close(x) closesocket(x)
62 #define perror(x) WinSockPError(x)
63 void 
64 WinSockPError(const char *);
65 #endif
66
67 #ifndef MSG_NOSIGNAL
68 #define MSG_NOSIGNAL 0
69 #endif
70
71 /*
72  *IPC message sent to the front-end
73  *at every route update. Both delete
74  *and add
75  */
76 struct ipcmsg 
77 {
78   olsr_u8_t          msgtype;
79   olsr_u16_t         size;
80   olsr_u8_t          metric;
81   olsr_u8_t          add;
82   union olsr_ip_addr target_addr;
83   union olsr_ip_addr gateway_addr;
84   char               device[4];
85 };
86
87
88 struct ipc_net_msg
89 {
90   olsr_u8_t            msgtype;
91   olsr_u16_t           size;
92   olsr_u8_t            mids; /* No. of extra interfaces */
93   olsr_u8_t            hnas; /* No. of HNA nets */
94   olsr_u8_t            unused1;
95   olsr_u16_t           hello_int;
96   olsr_u16_t           hello_lan_int;
97   olsr_u16_t           tc_int;
98   olsr_u16_t           neigh_hold;
99   olsr_u16_t           topology_hold;
100   olsr_u8_t            ipv6;
101   union olsr_ip_addr   main_addr;
102 };
103
104 static int ipc_sock = -1;
105 static int ipc_conn = -1;
106
107 static int
108 ipc_send_all_routes(int fd);
109
110 static int
111 ipc_send_net_info(int fd);
112
113 static void
114 ipc_accept(int, void *, unsigned int);
115
116 #if 0
117 static int
118 ipc_input(int);
119 #endif
120
121 static olsr_bool
122 ipc_check_allowed_ip(const union olsr_ip_addr *);
123
124 static void
125 frontend_msgparser(union olsr_message *, struct interface *, union olsr_ip_addr *);
126
127
128 /**
129  *Create the socket to use for IPC to the
130  *GUI front-end
131  *
132  *@return the socket FD
133  */
134 int
135 ipc_init(void)
136 {
137   //int flags;
138   struct   sockaddr_in sin;
139   int yes = 1;
140
141   /* Add parser function */
142   olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS, 0);
143
144   /* get an internet domain socket */
145   ipc_sock = socket(AF_INET, SOCK_STREAM, 0);
146   if (ipc_sock == -1) {
147     perror("IPC socket");
148     olsr_exit("IPC socket", EXIT_FAILURE);
149   }
150
151   if (setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
152     perror("SO_REUSEADDR failed");
153     return 0;
154   }
155
156   /* complete the socket structure */
157   memset(&sin, 0, sizeof(sin));
158   sin.sin_family = AF_INET;
159   sin.sin_addr.s_addr = INADDR_ANY;
160   sin.sin_port = htons(IPC_PORT);
161
162   /* bind the socket to the port number */
163   if (bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
164     perror("IPC bind");
165     OLSR_PRINTF(1, "Will retry in 10 seconds...\n");
166     sleep(10);
167     if (bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
168       perror("IPC bind");
169       olsr_exit("IPC bind", EXIT_FAILURE);
170     }
171     OLSR_PRINTF(1, "OK\n");
172   }
173
174   /* show that we are willing to listen */
175   if (listen(ipc_sock, olsr_cnf->ipc_connections) == -1) {
176     perror("IPC listen");
177     olsr_exit("IPC listen", EXIT_FAILURE);
178   }
179
180   /* Register the socket with the socket parser */
181   add_olsr_socket(ipc_sock, &ipc_accept, NULL, NULL, SP_PR_READ);
182
183   return ipc_sock;
184 }
185
186 static olsr_bool
187 ipc_check_allowed_ip(const union olsr_ip_addr *addr)
188 {
189   struct ip_prefix_list *ipcn;
190
191   if (addr->v4.s_addr == ntohl(INADDR_LOOPBACK)) {
192     return OLSR_TRUE;
193   }
194
195   /* check nets */
196   for (ipcn = olsr_cnf->ipc_nets; ipcn != NULL; ipcn = ipcn->next) {
197     if (ip_in_net(addr, &ipcn->net)) { 
198       return OLSR_TRUE;
199     }
200   }
201
202   return OLSR_FALSE;
203 }
204
205 static void
206 ipc_accept(int fd, void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
207 {
208   struct sockaddr_in pin;
209   char *addr;  
210   socklen_t addrlen = sizeof (struct sockaddr_in);
211
212   ipc_conn = accept(fd, (struct sockaddr *)&pin, &addrlen);
213   if (ipc_conn == -1)
214     {
215       perror("IPC accept");
216       olsr_exit("IPC accept", EXIT_FAILURE);
217     }
218   else
219     {
220       OLSR_PRINTF(1, "Front end connected\n");
221       addr = inet_ntoa(pin.sin_addr);
222       if (ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr))
223         {
224           ipc_send_net_info(ipc_conn);
225           ipc_send_all_routes(ipc_conn);
226           OLSR_PRINTF(1, "Connection from %s\n",addr);
227         }
228       else
229         {
230           OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
231           olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
232           CLOSE(ipc_conn);
233         }
234     }
235
236 }
237
238 #if 0
239 /**
240  *Read input from the IPC socket. Not in use.
241  *
242  *@todo for future use
243  *@param sock the IPC socket
244  *@return 1
245  */
246 static int
247 ipc_input(int sock __attribute__((unused)))
248 {
249   union 
250   {
251     char        buf[MAXPACKETSIZE+1];
252     struct olsr olsr;
253   } inbuf;
254
255
256   if (recv(sock, dir, sizeof(dir), 0) == -1) 
257     {
258       perror("recv");
259       exit(1);
260     }
261   return 1;
262 }
263 #endif
264
265 /**
266  *Sends a olsr packet on the IPC socket.
267  *
268  *@param olsr the olsr struct representing the packet
269  *
270  *@return negative on error
271  */
272 static void
273 frontend_msgparser(union olsr_message *msg, struct interface *in_if __attribute__((unused)), union olsr_ip_addr *from_addr __attribute__((unused)))
274 {
275   int size;
276
277   if (ipc_conn < 0) {
278     return;
279   }
280
281   size = olsr_cnf->ip_version == AF_INET ? ntohs(msg->v4.olsr_msgsize) : ntohs(msg->v6.olsr_msgsize);
282   
283   if (send(ipc_conn, (void *)msg, size, MSG_NOSIGNAL) < 0) {
284     OLSR_PRINTF(1, "(OUTPUT)IPC connection lost!\n");
285     CLOSE(ipc_conn);
286   }
287 }
288
289
290 /**
291  *Send a route table update to the front-end.
292  *
293  *@param kernel_route a rtentry describing the route update
294  *@param add 1 if the route is to be added 0 if it is to be deleted
295  *@param int_name the name of the interface the route is set to go by
296  *
297  *@return negative on error
298  */
299 int
300 ipc_route_send_rtentry(const union olsr_ip_addr *dst,
301                        const union olsr_ip_addr *gw,
302                        int met,
303                        int add,
304                        const char *int_name)
305 {
306   struct ipcmsg packet;
307
308   if (olsr_cnf->ipc_connections <= 0) {
309     return -1;
310   }
311
312   if (ipc_conn < 0) {
313     return 0;
314   }
315   memset(&packet, 0, sizeof(struct ipcmsg));
316   packet.size = htons(IPC_PACK_SIZE);
317   packet.msgtype = ROUTE_IPC;
318
319   packet.target_addr = *dst;
320
321   packet.add = add;
322   if (add && gw) {
323     packet.metric = met;
324     packet.gateway_addr = *gw;
325   }
326
327   if (int_name != NULL) {
328     memcpy(&packet.device[0], int_name, 4);
329   } else {
330     memset(&packet.device[0], 0, 4);
331   }
332
333   /*
334   x = 0;
335   for(i = 0; i < IPC_PACK_SIZE;i++)
336     {
337       if (x == 4)
338         {
339           x = 0;
340           printf("\n\t");
341         }
342       x++;
343       printf(" %03i", (u_char) tmp[i]);
344     }
345   
346   printf("\n");
347   */
348   
349   if (send(ipc_conn, (void *) &packet, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) { // MSG_NOSIGNAL to avoid sigpipe
350     OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
351     CLOSE(ipc_conn);
352     return -1;
353   }
354
355   return 1;
356 }
357
358
359
360 static int
361 ipc_send_all_routes(int fd)
362 {
363   struct rt_entry  *rt;
364
365   if (ipc_conn < 0) {
366     return 0;
367   }
368
369   OLSR_FOR_ALL_RT_ENTRIES(rt) {
370     struct ipcmsg packet;
371
372     memset(&packet, 0, sizeof(packet));
373     packet.size = htons(IPC_PACK_SIZE);
374     packet.msgtype = ROUTE_IPC;
375           
376     packet.target_addr = rt->rt_dst.prefix;
377
378     packet.add = 1;
379     packet.metric = (olsr_u8_t)(rt->rt_best->rtp_metric.hops);
380
381     packet.gateway_addr = rt->rt_nexthop.gateway;
382
383     memcpy(&packet.device[0], if_ifwithindex_name(rt->rt_nexthop.iif_index), 4);
384
385     /* MSG_NOSIGNAL to avoid sigpipe */
386     if (send(fd, (void *)&packet, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) {
387       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
388       CLOSE(ipc_conn);
389       return -1;
390     }
391   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
392   return 1;
393 }
394
395
396
397 /**
398  *Sends OLSR info to the front-end. This info consists of
399  *the different time intervals and holding times, number
400  *of interfaces, HNA routes and main address.
401  *
402  *@return negative on error
403  */
404 static int
405 ipc_send_net_info(int fd)
406 {
407   //int x, i;
408   struct ipc_net_msg net_msg;
409
410   OLSR_PRINTF(1, "Sending net-info to front end...\n");
411   
412   memset(&net_msg, 0, sizeof(net_msg));
413   
414   /* Message size */
415   net_msg.size = htons(sizeof(net_msg));
416   /* Message type */
417   net_msg.msgtype = NET_IPC;
418   
419   /* MIDs */
420   /* XXX fix IPC MIDcnt */
421   net_msg.mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
422   
423   /* HNAs */
424   net_msg.hnas = olsr_cnf->hna_entries == NULL ? 0 : 1;
425
426   /* Different values */
427   /* Temporary fixes */
428   /* XXX fix IPC intervals */
429   net_msg.hello_int = 0;//htons((olsr_u16_t)hello_int);
430   net_msg.hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
431   net_msg.tc_int = 0;//htons((olsr_u16_t)tc_int);
432   net_msg.neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
433   net_msg.topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
434
435   net_msg.ipv6 = olsr_cnf->ip_version == AF_INET ? 0 : 1;
436  
437   /* Main addr */
438   net_msg.main_addr = olsr_cnf->main_addr;
439
440   /*
441   printf("\t");
442   x = 0;
443   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
444     {
445       if (x == 4)
446         {
447           x = 0;
448           printf("\n\t");
449         }
450       x++;
451       printf(" %03i", (u_char) msg[i]);
452     }
453   
454   printf("\n");
455   */
456
457   if (send(fd, (void *)&net_msg, sizeof(net_msg), MSG_NOSIGNAL) < 0) {
458     OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n");
459     CLOSE(ipc_conn);
460     return -1;
461   }
462   return 0;
463 }
464
465
466
467 void
468 shutdown_ipc(void)
469 {
470   OLSR_PRINTF(1, "Shutting down IPC...\n");
471   CLOSE(ipc_sock);
472   CLOSE(ipc_conn);
473 }
474
475 /*
476  * Local Variables:
477  * c-basic-offset: 2
478  * End:
479  */