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