/*
* The olsr.org Optimized Link-State Routing daemon(olsrd)
* Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of olsr.org, olsrd nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Visit http://www.olsr.org for more information.
*
* If you find this software useful feel free to make a donation
* to the project. For more information see the website or contact
* the copyright holders.
*
* $Id: ipc_frontend.c,v 1.36 2007/10/13 12:31:04 bernd67 Exp $
*/
/*
*
*IPC - interprocess communication
*for the OLSRD - GUI front-end
*
*/
#include "ipc_frontend.h"
#include "link_set.h"
#include "olsr.h"
#include "log.h"
#include "parser.h"
#include "socket_parser.h"
#include "local_hna_set.h"
#ifdef WIN32
#define close(x) closesocket(x)
#define perror(x) WinSockPError(x)
void
WinSockPError(char *);
#endif
#ifndef linux
#define MSG_NOSIGNAL 0
#endif
static int ipc_sock = -1;
static int ipc_conn = -1;
static int ipc_active = OLSR_FALSE;
static int
ipc_send_all_routes(int fd);
static int
ipc_send_net_info(int fd);
/**
*Create the socket to use for IPC to the
*GUI front-end
*
*@return the socket FD
*/
int
ipc_init(void)
{
//int flags;
struct sockaddr_in sin;
int yes = 1;
/* Add parser function */
olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS, 0);
/* get an internet domain socket */
if ((ipc_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("IPC socket");
olsr_exit("IPC socket", EXIT_FAILURE);
}
if(setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)
{
perror("SO_REUSEADDR failed");
return 0;
}
/* complete the socket structure */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(IPC_PORT);
/* bind the socket to the port number */
if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1)
{
perror("IPC bind");
OLSR_PRINTF(1, "Will retry in 10 seconds...\n");
sleep(10);
if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1)
{
perror("IPC bind");
olsr_exit("IPC bind", EXIT_FAILURE);
}
OLSR_PRINTF(1, "OK\n");
}
/* show that we are willing to listen */
if(listen(ipc_sock, olsr_cnf->ipc_connections) == -1)
{
perror("IPC listen");
olsr_exit("IPC listen", EXIT_FAILURE);
}
/* Register the socket with the socket parser */
add_olsr_socket(ipc_sock, &ipc_accept);
return ipc_sock;
}
void
ipc_accept(int fd)
{
socklen_t addrlen;
struct sockaddr_in pin;
char *addr;
addrlen = sizeof (struct sockaddr_in);
if ((ipc_conn = accept(fd, (struct sockaddr *) &pin, &addrlen)) == -1)
{
perror("IPC accept");
olsr_exit("IPC accept", EXIT_FAILURE);
}
else
{
OLSR_PRINTF(1, "Front end connected\n");
addr = inet_ntoa(pin.sin_addr);
if(ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr))
{
ipc_active = OLSR_TRUE;
ipc_send_net_info(ipc_conn);
ipc_send_all_routes(ipc_conn);
OLSR_PRINTF(1, "Connection from %s\n",addr);
}
else
{
OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
CLOSE(ipc_conn);
}
}
}
olsr_bool
ipc_check_allowed_ip(union olsr_ip_addr *addr)
{
struct ipc_host *ipch = olsr_cnf->ipc_hosts;
struct ipc_net *ipcn = olsr_cnf->ipc_nets;
if(addr->v4 == ntohl(INADDR_LOOPBACK))
return OLSR_TRUE;
/* check hosts */
while(ipch)
{
if(addr->v4 == ipch->host.v4)
return OLSR_TRUE;
ipch = ipch->next;
}
/* check nets */
while(ipcn)
{
if((addr->v4 & ipcn->mask.v4) == (ipcn->net.v4 & ipcn->mask.v4))
return OLSR_TRUE;
ipcn = ipcn->next;
}
return OLSR_FALSE;
}
#if 0
/**
*Read input from the IPC socket. Not in use.
*
*@todo for future use
*@param sock the IPC socket
*@return 1
*/
int
ipc_input(int sock __attribute__((unused)))
{
union
{
char buf[MAXPACKETSIZE+1];
struct olsr olsr;
} inbuf;
if (recv(sock, dir, sizeof(dir), 0) == -1)
{
perror("recv");
exit(1);
}
return 1;
}
#endif
/**
*Sends a olsr packet on the IPC socket.
*
*@param olsr the olsr struct representing the packet
*
*@return negative on error
*/
void
frontend_msgparser(union olsr_message *msg, struct interface *in_if __attribute__((unused)), union olsr_ip_addr *from_addr __attribute__((unused)))
{
int size;
if(!ipc_active)
return;
if(olsr_cnf->ip_version == AF_INET)
size = ntohs(msg->v4.olsr_msgsize);
else
size = ntohs(msg->v6.olsr_msgsize);
if (send(ipc_conn, (void *)msg, size, MSG_NOSIGNAL) < 0)
{
OLSR_PRINTF(1, "(OUTPUT)IPC connection lost!\n");
CLOSE(ipc_conn);
//olsr_cnf->open_ipc = 0;
ipc_active = OLSR_FALSE;
}
}
/**
*Send a route table update to the front-end.
*
*@param kernel_route a rtentry describing the route update
*@param add 1 if the route is to be added 0 if it is to be deleted
*@param int_name the name of the interface the route is set to go by
*
*@return negative on error
*/
int
ipc_route_send_rtentry(union olsr_ip_addr *dst, union olsr_ip_addr *gw,
int met, int add, const char *int_name)
{
struct ipcmsg packet;
char *tmp;
if(!olsr_cnf->open_ipc) {
return -1;
}
if(!ipc_active)
return 0;
memset(&packet, 0, sizeof(struct ipcmsg));
packet.size = htons(IPC_PACK_SIZE);
packet.msgtype = ROUTE_IPC;
COPY_IP(&packet.target_addr, dst);
packet.add = add;
if(add && gw)
{
packet.metric = met;
COPY_IP(&packet.gateway_addr, gw);
}
if(int_name != NULL)
memcpy(&packet.device[0], int_name, 4);
else
memset(&packet.device[0], 0, 4);
tmp = (char *) &packet;
/*
x = 0;
for(i = 0; i < IPC_PACK_SIZE;i++)
{
if(x == 4)
{
x = 0;
printf("\n\t");
}
x++;
printf(" %03i", (u_char) tmp[i]);
}
printf("\n");
*/
if (send(ipc_conn, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) // MSG_NOSIGNAL to avoid sigpipe
{
OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
CLOSE(ipc_conn);
//olsr_cnf->open_ipc = 0;
ipc_active = OLSR_FALSE;
return -1;
}
return 1;
}
static int
ipc_send_all_routes(int fd)
{
struct rt_entry *rt;
struct ipcmsg packet;
char *tmp;
if(!ipc_active)
return 0;
OLSR_FOR_ALL_RT_ENTRIES(rt) {
memset(&packet, 0, sizeof(struct ipcmsg));
packet.size = htons(IPC_PACK_SIZE);
packet.msgtype = ROUTE_IPC;
COPY_IP(&packet.target_addr, &rt->rt_dst.prefix);
packet.add = 1;
packet.metric = (olsr_u8_t)(rt->rt_best->rtp_metric.hops);
COPY_IP(&packet.gateway_addr, &rt->rt_nexthop.gateway);
memcpy(&packet.device[0], if_ifwithindex_name(rt->rt_nexthop.iif_index), 4);
tmp = (char *) &packet;
/* MSG_NOSIGNAL to avoid sigpipe */
if (send(fd, tmp, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) {
OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
CLOSE(ipc_conn);
ipc_active = OLSR_FALSE;
return -1;
}
} OLSR_FOR_ALL_RT_ENTRIES_END(rt);
return 1;
}
/**
*Sends OLSR info to the front-end. This info consists of
*the different time intervals and holding times, number
*of interfaces, HNA routes and main address.
*
*@return negative on error
*/
static int
ipc_send_net_info(int fd)
{
struct ipc_net_msg *net_msg;
//int x, i;
char *msg;
net_msg = olsr_malloc(sizeof(struct ipc_net_msg), "send net info");
msg = (char *)net_msg;
OLSR_PRINTF(1, "Sending net-info to front end...\n");
memset(net_msg, 0, sizeof(struct ipc_net_msg));
/* Message size */
net_msg->size = htons(sizeof(struct ipc_net_msg));
/* Message type */
net_msg->msgtype = NET_IPC;
/* MIDs */
/* XXX fix IPC MIDcnt */
net_msg->mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
/* HNAs */
if(olsr_cnf->ip_version == AF_INET6)
{
if(olsr_cnf->hna6_entries == NULL)
net_msg->hnas = 0;
else
net_msg->hnas = 1;
}
if(olsr_cnf->ip_version == AF_INET)
{
if(olsr_cnf->hna4_entries == NULL)
net_msg->hnas = 0;
else
net_msg->hnas = 1;
}
/* Different values */
/* Temporary fixes */
/* XXX fix IPC intervals */
net_msg->hello_int = 0;//htons((olsr_u16_t)hello_int);
net_msg->hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
net_msg->tc_int = 0;//htons((olsr_u16_t)tc_int);
net_msg->neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
net_msg->topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
if(olsr_cnf->ip_version == AF_INET)
net_msg->ipv6 = 0;
else
net_msg->ipv6 = 1;
/* Main addr */
COPY_IP(&net_msg->main_addr, &olsr_cnf->main_addr);
/*
printf("\t");
x = 0;
for(i = 0; i < sizeof(struct ipc_net_msg);i++)
{
if(x == 4)
{
x = 0;
printf("\n\t");
}
x++;
printf(" %03i", (u_char) msg[i]);
}
printf("\n");
*/
if (send(fd, (char *)net_msg, sizeof(struct ipc_net_msg), MSG_NOSIGNAL) < 0)
{
OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n");
CLOSE(ipc_conn);
//olsr_cnf->open_ipc = 0;
return -1;
}
free(net_msg);
return 0;
}
int
shutdown_ipc(void)
{
OLSR_PRINTF(1, "Shutting down IPC...\n");
CLOSE(ipc_sock);
CLOSE(ipc_conn);
return 1;
}
/*
* Local Variables:
* c-basic-offset: 2
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1