aae0e10d83e9360f7b1ea0fc35a9a5c0540a7645
[olsrd.git] / src / ipc_frontend.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /*
43  *
44  *IPC - interprocess communication
45  *for the OLSRD - GUI front-end
46  *
47  */
48
49 #include "ipc_frontend.h"
50 #include "link_set.h"
51 #include "olsr.h"
52 #include "log.h"
53 #include "parser.h"
54 #include "scheduler.h"
55 #include "net_olsr.h"
56 #include "ipcalc.h"
57
58 #ifdef _WIN32
59 #define close(x) closesocket(x)
60 #define perror(x) WinSockPError(x)
61 void WinSockPError(const char *);
62 #endif /* _WIN32 */
63
64 #ifndef MSG_NOSIGNAL
65 #define MSG_NOSIGNAL 0
66 #endif /* MSG_NOSIGNAL */
67
68 static int ipc_sock = -1;
69 static int ipc_conn = -1;
70 static int ipc_active = false;
71
72 static int ipc_send_all_routes(int fd);
73
74 static int ipc_send_net_info(int fd);
75
76 /**
77  *Create the socket to use for IPC to the
78  *GUI front-end
79  *
80  *@return -1 if an error happened, 0 otherwise
81  */
82 int
83 ipc_init(void)
84 {
85   //int flags;
86   struct sockaddr_in sin;
87   int yes = 1;
88
89   /* Add parser function */
90   olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS);
91
92   /* get an internet domain socket */
93   if ((ipc_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
94     perror("IPC socket");
95     return -1;
96   }
97
98   if (setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
99     perror("SO_REUSEADDR failed");
100     close(ipc_sock);
101     return -1;
102   }
103
104   /* complete the socket structure */
105   memset(&sin, 0, sizeof(sin));
106   sin.sin_family = AF_INET;
107   sin.sin_addr.s_addr = INADDR_ANY;
108   sin.sin_port = htons(IPC_PORT);
109
110   /* bind the socket to the port number */
111   if (bind(ipc_sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
112     perror("IPC bind");
113     OLSR_PRINTF(1, "Will retry in 10 seconds...\n");
114     sleep(10);
115     if (bind(ipc_sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
116       perror("IPC bind");
117       close(ipc_sock);
118       return -1;
119     }
120     OLSR_PRINTF(1, "OK\n");
121   }
122
123   /* show that we are willing to listen */
124   if (listen(ipc_sock, olsr_cnf->ipc_connections) == -1) {
125     perror("IPC listen");
126     close(ipc_sock);
127     return -1;
128   }
129
130   /* Register the socket with the socket parser */
131   add_olsr_socket(ipc_sock, &ipc_accept, NULL, NULL, SP_PR_READ);
132
133   return 0;
134 }
135
136
137 void
138 ipc_accept(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
139 {
140   socklen_t addrlen;
141   struct sockaddr_in pin;
142   char *addr;
143
144   addrlen = sizeof(struct sockaddr_in);
145
146   if ((ipc_conn = accept(fd, (struct sockaddr *)&pin, &addrlen)) == -1) {
147     char buf[1024];
148     snprintf(buf, sizeof(buf), "IPC accept error: %s", strerror(errno));
149     olsr_exit(buf, EXIT_FAILURE);
150   } else {
151     OLSR_PRINTF(1, "Front end connected\n");
152     addr = inet_ntoa(pin.sin_addr);
153     if (ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
154       ipc_active = true;
155       ipc_send_net_info(ipc_conn);
156       ipc_send_all_routes(ipc_conn);
157       OLSR_PRINTF(1, "Connection from %s\n", addr);
158     } else {
159       OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
160       olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
161       CLOSE(ipc_conn);
162     }
163   }
164
165 }
166
167 bool
168 ipc_check_allowed_ip(const union olsr_ip_addr *addr)
169 {
170   struct ip_prefix_list *ipcn;
171
172   if (addr->v4.s_addr == ntohl(INADDR_LOOPBACK)) {
173     return true;
174   }
175
176   /* check nets */
177   for (ipcn = olsr_cnf->ipc_nets; ipcn != NULL; ipcn = ipcn->next) {
178     if (ip_in_net(addr, &ipcn->net)) {
179       return true;
180     }
181   }
182
183   return false;
184 }
185
186 /**
187  *Sends a olsr packet on the IPC socket.
188  *
189  *@param msg the olsr struct representing the packet
190  *@param in_if the incoming interface
191  *@param from_addr the sender address
192  *
193  *@return true for not preventing forwarding
194  */
195 bool
196 frontend_msgparser(union olsr_message * msg, struct interface_olsr * in_if __attribute__ ((unused)), union olsr_ip_addr * from_addr
197                    __attribute__ ((unused)))
198 {
199   int size;
200
201   if (!ipc_active)
202     return true;
203
204   if (olsr_cnf->ip_version == AF_INET)
205     size = ntohs(msg->v4.olsr_msgsize);
206   else
207     size = ntohs(msg->v6.olsr_msgsize);
208
209   if (send(ipc_conn, (void *)msg, size, MSG_NOSIGNAL) < 0) {
210     OLSR_PRINTF(1, "(OUTPUT)IPC connection lost!\n");
211     CLOSE(ipc_conn);
212     ipc_active = false;
213   }
214   return true;
215 }
216
217 /**
218  *Send a route table update to the front-end.
219  *
220  *@param dst the destination of the route
221  *@param gw the gateway for the route
222  *@param met the metric for the route
223  *@param add 1 if the route is to be added 0 if it is to be deleted
224  *@param int_name the name of the interface the route is set to go by
225  *
226  *@return negative on error
227  */
228 int
229 ipc_route_send_rtentry(const union olsr_ip_addr *dst, const union olsr_ip_addr *gw, int met, int add, const char *int_name)
230 {
231   struct ipcmsg packet;
232   char *tmp;
233
234   if (olsr_cnf->ipc_connections <= 0) {
235     return -1;
236   }
237
238   if (!ipc_active) {
239     return 0;
240   }
241   memset(&packet, 0, sizeof(struct ipcmsg));
242   packet.size = htons(IPC_PACK_SIZE);
243   packet.msgtype = ROUTE_IPC;
244
245   packet.target_addr = *dst;
246
247   packet.add = add;
248   if (add && gw) {
249     packet.metric = met;
250     packet.gateway_addr = *gw;
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   tmp = (char *)&packet;
259   /*
260      x = 0;
261      for(i = 0; i < IPC_PACK_SIZE;i++)
262      {
263      if(x == 4)
264      {
265      x = 0;
266      printf("\n\t");
267      }
268      x++;
269      printf(" %03i", (u_char) tmp[i]);
270      }
271
272      printf("\n");
273    */
274
275   if (send(ipc_conn, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0)     // MSG_NOSIGNAL to avoid sigpipe
276   {
277     OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
278     CLOSE(ipc_conn);
279
280     ipc_active = false;
281     return -1;
282   }
283
284   return 1;
285 }
286
287 static int
288 ipc_send_all_routes(int fd)
289 {
290   struct rt_entry *rt;
291   struct ipcmsg packet;
292   char *tmp;
293
294   if (!ipc_active)
295     return 0;
296
297   OLSR_FOR_ALL_RT_ENTRIES(rt) {
298
299     memset(&packet, 0, sizeof(struct ipcmsg));
300     packet.size = htons(IPC_PACK_SIZE);
301     packet.msgtype = ROUTE_IPC;
302
303     packet.target_addr = rt->rt_dst.prefix;
304
305     packet.add = 1;
306     packet.metric = (uint8_t) (rt->rt_best->rtp_metric.hops);
307
308     packet.gateway_addr = rt->rt_nexthop.gateway;
309
310     memcpy(&packet.device[0], if_ifwithindex_name(rt->rt_nexthop.iif_index), 4);
311
312     tmp = (char *)&packet;
313
314     /* MSG_NOSIGNAL to avoid sigpipe */
315     if (send(fd, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) {
316       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
317       CLOSE(ipc_conn);
318       ipc_active = false;
319       return -1;
320     }
321   }
322   OLSR_FOR_ALL_RT_ENTRIES_END(rt);
323   return 1;
324 }
325
326 /**
327  *Sends OLSR info to the front-end. This info consists of
328  *the different time intervals and holding times, number
329  *of interfaces, HNA routes and main address.
330  *
331  *@return negative on error
332  */
333 static int
334 ipc_send_net_info(int fd)
335 {
336   struct ipc_net_msg net_msg;
337
338   memset(&net_msg, 0, sizeof(net_msg));
339
340   OLSR_PRINTF(1, "Sending net-info to front end...\n");
341
342   /* Message size */
343   net_msg.size = htons(sizeof(struct ipc_net_msg));
344   /* Message type */
345   net_msg.msgtype = NET_IPC;
346
347   /* MIDs */
348   /* XXX fix IPC MIDcnt */
349   net_msg.mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
350
351   /* HNAs */
352   net_msg.hnas = olsr_cnf->hna_entries == NULL ? 0 : 1;
353
354   /* Different values */
355   /* Temporary fixes */
356   /* XXX fix IPC intervals */
357   net_msg.hello_int = 0;       //htons((uint16_t)hello_int);
358   net_msg.hello_lan_int = 0;   //htons((uint16_t)hello_int_nw);
359   net_msg.tc_int = 0;          //htons((uint16_t)tc_int);
360   net_msg.neigh_hold = 0;      //htons((uint16_t)neighbor_hold_time);
361   net_msg.topology_hold = 0;   //htons((uint16_t)topology_hold_time);
362
363   net_msg.ipv6 = olsr_cnf->ip_version == AF_INET ? 0 : 1;
364
365   /* Main addr */
366   net_msg.main_addr = olsr_cnf->main_addr;
367
368   /*
369   {
370      unsigned int x, i;
371
372      printf("\t");
373      for(i = 0; i < sizeof(struct ipc_net_msg);i++)
374      {
375      if(x == 4)
376      {
377      x = 0;
378      printf("\n\t");
379      }
380      x++;
381      printf(" %03i", ((u_char *)net_msg)[i]);
382      }
383
384      printf("\n");
385   }
386   */
387
388   if (send(fd, (char *)&net_msg, sizeof(struct ipc_net_msg), MSG_NOSIGNAL) < 0) {
389     OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n");
390     CLOSE(ipc_conn);
391     return -1;
392   }
393
394   return 0;
395 }
396
397 int
398 shutdown_ipc(void)
399 {
400   OLSR_PRINTF(1, "Shutting down IPC...\n");
401   CLOSE(ipc_sock);
402   CLOSE(ipc_conn);
403
404   return 1;
405 }
406
407 /*
408  * Local Variables:
409  * c-basic-offset: 2
410  * indent-tabs-mode: nil
411  * End:
412  */