www.pudn.com > hipl.1.0.1.rar > connhipd.c
/*
HIP Agent
License: GNU/GPL
Authors: Antti Partanen
*/
/******************************************************************************/
/* INCLUDES */
#include "connhipd.h"
/******************************************************************************/
/* VARIABLES */
/** This socket is used for communication between agent and HIP daemon. */
int hip_agent_sock = 0;
/** This is just for waiting the connection thread to start properly. */
int hip_agent_thread_started = 0;
/** Connection pthread holder. */
pthread_t connhipd_pthread;
/** Determine whether we are connected to daemon or not. */
int hip_agent_connected = 0;
/******************************************************************************/
/* FUNCTIONS */
/******************************************************************************/
/**
Initialize connection to hip daemon.
@return 0 on success, -1 on errors.
*/
int connhipd_init(void)
{
/* Variables. */
int err = 0, n, len;
struct sockaddr_un agent_addr;
struct hip_common *msg = NULL;
socklen_t alen;
/* Allocate message. */
HIP_IFE(((msg = hip_msg_alloc()) == NULL), -1);
/* Create and bind daemon socket. */
hip_agent_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
HIP_IFEL(hip_agent_sock < 0, -1, "Failed to create socket.\n");
bzero(&agent_addr, sizeof(agent_addr));
agent_addr.sun_family = AF_LOCAL;
strcpy(agent_addr.sun_path, tmpnam(NULL));
HIP_IFEL(bind(hip_agent_sock, (struct sockaddr *)&agent_addr,
sizeof(agent_addr)), -1, "Bind failed.\n");
/* bzero(&agent_addr, sizeof(agent_addr));
alen = sizeof(agent_addr);
n = recvfrom(hip_agent_sock, msg, sizeof(struct hip_common), 0,
(struct sockaddr *)&agent_addr, &alen);
HIP_IFEL(n < 0, -1, "Did not receive ping reply from daemon.\n");
/* Start thread for connection handling. */
/* HIP_DEBUG("Received %d bytes of ping reply message from daemon.\n"
"Starting thread for HIP daemon connection handling\n", n);*/
pthread_create(&connhipd_pthread, NULL, connhipd_thread, msg);
hip_agent_thread_started = 0;
while (hip_agent_thread_started == 0) usleep(100 * 1000);
usleep(100 * 1000);
return (0);
out_err:
if (hip_agent_sock) close(hip_agent_sock);
if (msg != NULL) HIP_FREE(msg);
return err;
}
/* END OF FUNCTION */
/******************************************************************************/
/** Send packet to HIP daemon. */
int connhipd_sendto_hipd(char *msg, size_t len)
{
/* Variables. */
struct sockaddr_un agent_addr;
int n, alen;
bzero(&agent_addr, sizeof(agent_addr));
agent_addr.sun_family = AF_LOCAL;
strcpy(agent_addr.sun_path, HIP_AGENTADDR_PATH);
alen = sizeof(agent_addr);
n = sendto(hip_agent_sock, msg, len, 0, (struct sockaddr *)&agent_addr, alen);
return (n);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Handle message from agent socket.
*/
int connhipd_handle_msg(struct hip_common *msg,
struct sockaddr_un *addr)
{
/* Variables. */
struct hip_tlv_common *param = NULL, *param2 = NULL;
hip_hdr_type_t type;
HIT_Remote hit, *r;
HIT_Local *l;
socklen_t alen;
struct in6_addr *lhit, *rhit;
int err = 0, ret, n, direction, check;
char chit[128], *type_s;
type = hip_get_msg_type(msg);
if (type == HIP_I1 || type == HIP_I2 || type == HIP_R1 || type == HIP_R2)
{
/* Find out, which of the HITs in the message is local HIT. */
l = hit_db_find_local(NULL, &msg->hits);
if (!l)
{
l = hit_db_find_local(NULL, &msg->hitr);
if (l)
{
memcpy(&hit.hit, &msg->hits, sizeof(hit.hit));
direction = CONNHIPD_IN;
}
}
else
{
memcpy(&hit.hit, &msg->hitr, sizeof(hit.hit));
direction = CONNHIPD_OUT;
}
}
if (type == HIP_AGENT_PING_REPLY)
{
term_print("Received ping reply from daemon. Connection to daemon established.\n");
gui_set_info("Connection do daemon established.");
hip_agent_connected = 1;
}
else if (type == HIP_DAEMON_QUIT)
{
term_print("Daemon quit. Waiting daemon to wake up again...\n");
gui_set_info("Connection do daemon lost.");
hip_agent_connected = 0;
}
else if (type == HIP_ADD_DB_HI)
{
HIP_DEBUG("Message received successfully from daemon with type"
" HIP_ADD_DB_HI (%d).\n", type);
n = 0;
while((param = hip_get_next_param(msg, param)))
{
if (hip_get_param_type(param) == HIP_PARAM_HIT)
{
lhit = hip_get_param_contents_direct(param);
HIP_HEXDUMP("Adding local HIT:", lhit, 16);
print_hit_to_buffer(chit, lhit);
hit_db_add_local(chit, lhit);
n++;
}
}
}
else if (type == HIP_UPDATE_HIU)
{
n = 0;
gui_clear_hiu();
while((param = hip_get_next_param(msg, param)))
{
/*param2 = hip_get_next_param(msg, param);
if (param2 == NULL) break;*/
if (hip_get_param_type(param) == HIP_PARAM_HIT)/* &&
hip_get_param_type(param2) == HIP_PARAM_HIT)*/
{
rhit = hip_get_param_contents_direct(param);
//lhit = hip_get_param_contents_direct(param2);
r = hit_db_find(NULL, rhit);
if (r)
{
gui_add_hiu(r);
n++;
}
}
}
gui_set_nof_hiu(n);
}
else if ((type == HIP_I1 || type == HIP_R2) && direction == CONNHIPD_OUT)
{
NAMECPY(hit.name, "NewHIT");
URLCPY(hit.url, "");
URLCPY(hit.port, "");
HIP_DEBUG("Received %s %s from daemon.\n",
direction == CONNHIPD_IN ? "incoming" : "outgoing",
type == HIP_I1 ? "I1" : "R2 ");
/* Check the remote HIT from database. */
if (l)
{
ret = check_hit(&hit, direction);
/* Reset local HIT, if outgoing I1. */
HIP_HEXDUMP("Old local HIT: ", &msg->hits, 16);
HIP_HEXDUMP("New local HIT: ", &hit.g->l->lhit, 16);
HIP_HEXDUMP("Old remote HIT: ", &msg->hitr, 16);
HIP_HEXDUMP("New remote HIT: ", &hit.hit, 16);
if (direction == CONNHIPD_OUT)
{
//memcpy(&msg->hits, &hit.g->l->lhit, sizeof(msg->hits));
}
}
/* If neither HIT in message was local HIT, then drop the packet! */
else
{
HIP_DEBUG("Failed to find local HIT from database for packet."
" Rejecting packet automatically.\n");
HIP_HEXDUMP("msg->hits: ", &msg->hits, 16);
HIP_HEXDUMP("msg->hitr: ", &msg->hits, 16);
ret = -1;
}
/*
Now either reject or accept the packet,
according to previous results.
*/
if (ret == 0)
{
HIP_DEBUG("Message accepted, sending back to daemon.\n");
n = connhipd_sendto_hipd(msg, hip_get_msg_total_len(msg));
HIP_IFEL(n < 0, -1, "Could not send message back to daemon"
" (%d: %s).\n", errno, strerror(errno));
HIP_DEBUG("Reply sent successfully\n");
term_print("* %s: %s\n",
type == HIP_I1 ? "I1" : "R2",
direction == CONNHIPD_OUT ? "sent" : "received");
}
else
{
HIP_DEBUG("Message rejected, sending reply to daemon.\n");
hip_set_msg_type(msg, HIP_I1_REJECT);
n = connhipd_sendto_hipd(msg, hip_get_msg_total_len(msg));
HIP_IFEL(n < 0, -1, "Could not send message back to daemon.\n");
HIP_DEBUG("Rejection sent successfully\n");
term_print("* %s: %s, rejected\n",
type == HIP_I1 ? "I1" : "R2",
direction == CONNHIPD_OUT ? "outgoing" : "incoming");
}
}
else
{
check = 0;
switch (type)
{
case HIP_I1:
type_s = "I1";
break;
case HIP_R1:
type_s = "R1";
break;
case HIP_I2:
type_s = "I2";
break;
case HIP_R2:
type_s = "R2";
break;
default:
type_s = "packet";
break;
}
if (check)
{
HIP_DEBUG("Received %s %s from daemon (type code %d).\n",
direction == CONNHIPD_IN ? "incoming" : "outgoing", type_s, type);
/* Check the remote HIT from database. */
if (l) r = hit_db_find(NULL, &hit.hit);
/* If neither HIT in message was local HIT, then drop the packet! */
else
{
HIP_DEBUG("Failed to find local HIT from database for packet.\n"
" Rejecting packet automatically.");
ret = -1;
}
HIP_HEXDUMP("Source HIT: ", &msg->hits, 16);
HIP_HEXDUMP("Destination HIT: ", &msg->hitr, 16);
if (r) ret = (r->g->type == HIT_DB_TYPE_ACCEPT) ? 0 : -1;
else ret = -1;
}
else ret = 0;
/*
Now either reject or accept the packet,
according to previous results.
*/
if (ret == 0)
{
HIP_DEBUG("Message accepted, sending back to daemon.\n");
n = connhipd_sendto_hipd(msg, hip_get_msg_total_len(msg));
HIP_IFEL(n < 0, -1, "Could not send message back to daemon"
" (%d: %s).\n", errno, strerror(errno));
HIP_DEBUG("Reply sent successfully\n");
term_print("* %s: %s\n", type_s, (direction == CONNHIPD_OUT) ? "sent" : "received");
}
else
{
HIP_DEBUG("Message rejected, sending reply to daemon.\n");
n = connhipd_sendto_hipd("no", 2);
HIP_IFEL(n < 0, -1, "Could not send message back to daemon.\n");
HIP_DEBUG("Rejection sent successfully\n");
term_print("* %s: %s, rejected\n", type_s, (direction == CONNHIPD_OUT) ? "outgoing" : "incoming");
}
}
out_err:
// HIP_DEBUG("Message handled.\n");
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
This thread keeps the HIP daemon connection alive.
*/
int connhipd_thread(void *data)
{
/* Variables. */
int err = 0, n, len, ret, max_fd;
struct sockaddr_un agent_addr;
struct hip_common *msg = (struct hip_common *)data;
socklen_t alen;
fd_set read_fdset;
struct timeval tv;
HIP_DEBUG("Waiting messages...\n");
/* Start handling. */
hip_agent_thread_started = 1;
while (hip_agent_thread_started)
{
FD_ZERO(&read_fdset);
FD_SET(hip_agent_sock, &read_fdset);
max_fd = hip_agent_sock;
tv.tv_sec = 1;
tv.tv_usec = 0;
if (hip_agent_connected < 1)
{
/* Test connection. */
//HIP_IFEL(hip_agent_connected < -60, -1, "Could not connect to daemon.\n");
//HIP_DEBUG("Pinging daemon...\n");
hip_build_user_hdr(msg, HIP_AGENT_PING, 0);
n = connhipd_sendto_hipd(msg, sizeof(struct hip_common));
//if (n < 0) HIP_DEBUG("Could not send ping to daemon, waiting.\n");
hip_agent_connected--;
}
/* Wait for incoming packets. */
if (select(max_fd + 1, &read_fdset, NULL,NULL, &tv) == -1)
{
HIP_ERROR("select() error: %s.\n", strerror(errno));
err = -1;
goto out_err;
}
if (!hip_agent_thread_started) continue;
if (!FD_ISSET(hip_agent_sock, &read_fdset)) continue;
bzero(&agent_addr, sizeof(agent_addr));
alen = sizeof(agent_addr);
n = recvfrom(hip_agent_sock, msg, sizeof(struct hip_common), MSG_PEEK,
(struct sockaddr *)&agent_addr, &alen);
if (n < 0)
{
HIP_ERROR("Error receiving message header from daemon.\n");
err = -1;
goto out_err;
}
// HIP_DEBUG("Header received successfully\n");
alen = sizeof(agent_addr);
len = hip_get_msg_total_len(msg);
// HIP_DEBUG("Receiving message (%d bytes)\n", len);
n = recvfrom(hip_agent_sock, msg, len, 0,
(struct sockaddr *)&agent_addr, &alen);
if (n < 0)
{
HIP_ERROR("Error receiving message parameters from daemon.\n");
err = -1;
goto out_err;
}
HIP_ASSERT(n == len);
connhipd_handle_msg(msg, &agent_addr);
}
out_err:
/* Send quit message to daemon. */
hip_build_user_hdr(msg, HIP_AGENT_QUIT, 0);
n = connhipd_sendto_hipd(msg, hip_get_msg_total_len(msg));
if (n < 0) HIP_ERROR("Could not send quit message to daemon.\n");
if (hip_agent_sock) close(hip_agent_sock);
if (msg != NULL) HIP_FREE(msg);
hip_agent_thread_started = 0;
agent_exit();
HIP_DEBUG("Connection thread exit.\n");
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Quits connection thread. Function agent_exit() should be called before
calling this.
*/
void connhipd_quit(void)
{
if (!hip_agent_thread_started) return;
HIP_DEBUG("Stopping connection thread...\n");
hip_agent_thread_started = 0;
pthread_join(connhipd_pthread, NULL);
}
/* END OF FUNCTION */
/* END OF SOURCE FILE */
/******************************************************************************/