Files
m241Neelima/components/ip_net2-6.9/ipike/src/ipike_channel.c
T
2026-07-30 11:19:44 +05:30

867 lines
24 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_channel.c,v $ $Revision: 1.6.2.6 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_channel.c,v $
* $Author: zan $ $Date: 2013-08-02 07:52:29 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Erik Dahlberg <erik.dahlberg@windriver.com>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/* A message channel framework */
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include "ipike_config.h"
#ifdef IPIKE_USE_EVENT_LOG
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipike_h.h"
#include "ipike_channel.h"
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
#define IPIKE_CHANNEL_ADDRESS_MAX_LEN 32
#define IPIKE_CHANNEL_USE_TCP
#define for_each_channel_in_server(_chan, _server) \
for (_chan = (Ipike_channel *) ipcom_list_first(&_server->channel_list);\
_chan != IP_NULL; \
_chan = (Ipike_channel *) ipcom_list_next(&_chan->list) )
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
typedef enum Ipike_channel_state_enum
{
IPIKE_CHANNEL_STATE_CLOSED = 0,
IPIKE_CHANNEL_STATE_LISTEN = 1,
IPIKE_CHANNEL_STATE_OPEN = 2,
} Ipike_channel_state;
struct Ipike_channel_struct
{
Ipcom_list list;
Ip_fd fd;
Ipike_channel_state state;
Ipcom_mutex mutex;
};
struct Ipike_channel_server_struct
{
Ipcom_list channel_list;
Ipike_channel_server_cb on_open_cb;
Ipike_channel_server_cb on_close_cb;
Ipike_channel_server_receive_cb on_receive_cb;
};
enum Ipike_channel_msg_type_enum
{
IPIKE_CHANNEL_REGISTER = 0,
IPIKE_CHANNEL_UNREGISTER = 1,
IPIKE_CHANNEL_MESSAGE = 2,
};
#define MSG_HDR(_msg) ((Ipike_channel_msg_header *)_msg - 1);
struct Ipike_channel_addr_struct
{
union Ip_sockaddr_union addr;
};
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_channel_set_state
*===========================================================================
*/
IP_INLINE void
ipike_channel_set_state(
Ipike_channel * channel,
Ipike_channel_state state)
{
channel->state = state;
}
/*
*===========================================================================
* ipike_channel_is_open
*===========================================================================
*/
IP_INLINE Ip_bool
ipike_channel_is_open(
const Ipike_channel * channel)
{
return (channel->state == IPIKE_CHANNEL_STATE_OPEN);
}
/*
*===========================================================================
* ipike_channel_lock
*===========================================================================
*/
IP_INLINE void
ipike_channel_lock(
const Ipike_channel * channel)
{
IPCOM_LOG1(DEBUG2, "locking channel %p", channel);
ipcom_mutex_lock(channel->mutex);
}
/*
*===========================================================================
* ipike_channel_unlock
*===========================================================================
*/
IP_INLINE void
ipike_channel_unlock(
const Ipike_channel * channel)
{
IPCOM_LOG1(DEBUG2, "Unlocking channel %p", channel);
ipcom_mutex_unlock(channel->mutex);
}
/*
*===========================================================================
* ipike_channel_destroy
*===========================================================================
*/
IP_PUBLIC void
ipike_channel_destroy(
Ipike_channel * channel)
{
ip_assert(channel != IP_NULL);
IPCOM_LOG1(DEBUG2, "Destroying channel %p", channel);
ipike_channel_close(channel);
(void)ipcom_mutex_delete(&channel->mutex);
ipcom_free(channel);
}
/*
*===========================================================================
* ipike_channel_server_destroy
*===========================================================================
*/
IP_GLOBAL void
ipike_channel_server_destroy(
Ipike_channel_server * cserver)
{
Ipike_channel * channel;
ip_assert(cserver != IP_NULL);
IPCOM_LOG1(DEBUG2, "Destroying channel server %p", cserver);
for ( channel = (Ipike_channel *) ipcom_list_first(&cserver->channel_list);
channel != IP_NULL;
channel = (Ipike_channel *) ipcom_list_first(&cserver->channel_list))
{
ipcom_list_remove(&channel->list);
ipike_channel_destroy(channel);
}
ipcom_free(cserver);
}
/*
*===========================================================================
* ipike_channel_create
*===========================================================================
*/
IP_STATIC Ipike_channel *
ipike_channel_create()
{
Ipike_channel *channel;
channel = ipcom_malloc(sizeof(Ipike_channel));
if ( IP_NULL == channel )
return IP_NULL;
ipcom_memset(channel, 0, sizeof(Ipike_channel));
channel->fd = IP_INVALID_SOCKET;
ipike_channel_set_state(channel, IPIKE_CHANNEL_STATE_CLOSED);
/* Create channel mutex */
if ( ipcom_mutex_create(&channel->mutex) != IPCOM_SUCCESS )
{
ipcom_free(channel);
return IP_NULL;
}
return channel;
}
/*
*===========================================================================
* ipike_channel_server_accept_new_channel
*===========================================================================
*/
IP_STATIC Ipike_channel_status
ipike_channel_server_accept_new_channel(
Ipike_channel_server * cserver,
Ipike_channel * channel)
{
Ipike_channel * new_channel;
Ip_fd fd;
ip_assert(channel->state == IPIKE_CHANNEL_STATE_LISTEN);
IPCOM_LOG0(DEBUG2, "ipike_channel_server_accept_new_channel() :: "\
"received new connection attempt");
fd = ipcom_accept(channel->fd, IP_NULL, 0 );
if ( fd < 0 )
{
IPCOM_LOG1(ERR, "ipike_channel_server_accept_new_channel() :: "\
"failed to accept new connection (%s)",
ipcom_strerror(ipcom_errno));
return IPIKE_CHANNEL_ERROR;
}
/* Create a new channel */
new_channel = ipike_channel_create();
if ( new_channel == NULL )
{
IP_PANIC();
return IPIKE_CHANNEL_ERROR;
}
/* Set channel state and add it to the channel list */
new_channel->fd = fd;
ipike_channel_set_state(new_channel, IPIKE_CHANNEL_STATE_OPEN);
ipcom_list_insert_last(&cserver->channel_list, &new_channel->list);
/* Notify user with the new channel */
if ( cserver->on_open_cb )
cserver->on_open_cb(new_channel);
IPCOM_LOG0(DEBUG, "ipike_channel_server_accept_new_channel() :: "\
"new channel established");
return IPIKE_CHANNEL_OK;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_channel_addr_create
*===========================================================================
*/
IP_GLOBAL Ipike_channel_addr *
ipike_channel_addr_create(
const char * caddr_str)
{
Ipike_channel_addr * caddr;
char tmp[IPIKE_CHANNEL_ADDRESS_MAX_LEN];
char * ip_str;
char * port_str;
Ip_u16 port;
caddr = ipcom_malloc(sizeof(Ipike_channel_addr));
if ( caddr == IP_NULL )
return IP_NULL;
ipcom_memset(caddr, 0, sizeof(Ipike_channel_addr));
ipcom_memset(tmp, 0, sizeof(tmp));
ipcom_strncpy(tmp, caddr_str, sizeof(tmp) - 1);
port_str = ipcom_strchr(tmp, '@');
if ( port_str == IP_NULL )
{
ipcom_free(caddr);
return IP_NULL;
}
ip_str = tmp;
*port_str = '\0';
port_str++;
port = (Ip_u16)ipcom_atoi(port_str);
#ifdef IPCOM_USE_INET
if ( 1 == ipcom_inet_pton(IP_AF_INET,
ip_str,
&caddr->addr.sin.sin_addr))
{
caddr->addr.sa.sa_family = IP_AF_INET;
caddr->addr.sin.sin_port = ip_htons(port);
IPCOM_SA_LEN_SET(&caddr->addr.sa, sizeof(struct Ip_sockaddr_in));
return caddr;
}
#endif
#ifdef IPCOM_USE_INET6
if ( 1 == ipcom_inet_pton(IP_AF_INET6,
ip_str,
&caddr->addr.sin6.sin6_addr) )
{
caddr->addr.sa.sa_family = IP_AF_INET6;
caddr->addr.sin6.sin6_port = ip_htons(port);
IPCOM_SA_LEN_SET(&caddr->addr.sa, sizeof(struct Ip_sockaddr_in6));
return caddr;
}
#endif
return caddr;
}
/*
*===========================================================================
* ipike_channel_addr_destroy
*===========================================================================
*/
IP_GLOBAL void
ipike_channel_addr_destroy(
Ipike_channel_addr * caddr)
{
ipcom_free(caddr);
}
/*
*===========================================================================
* ipike_channel_msg_create
*===========================================================================
*/
IP_GLOBAL Ipike_channel_msg *
ipike_channel_msg_create(Ip_u16 len)
{
Ipike_channel_msg * msg;
Ip_size_t msg_len;
msg_len = sizeof(Ipike_channel_msg) + len;
msg = ipcom_malloc(msg_len);
if ( msg == IP_NULL )
return IP_NULL;
ipcom_memset(msg, 0, msg_len);
msg->type = IPIKE_CHANNEL_MESSAGE;
msg->len = (Ip_u16)msg_len;
return msg;
}
/*
*===========================================================================
* ike_channel_msg_destroy(
*===========================================================================
*/
IP_GLOBAL void
ipike_channel_msg_destroy(
Ipike_channel_msg *msg)
{
ip_assert(msg);
ipcom_free(msg);
}
/*
*===========================================================================
* ipike_channel_server_add_fds
*===========================================================================
*/
IP_GLOBAL int
ipike_channel_server_add_fds(
Ipike_channel_server * cserver,
Ip_fd_set * read_fds,
Ip_fd_set * write_fds)
{
Ipike_channel * channel;
int max = -1;
IPCOM_UNUSED_ARG(write_fds);
for_each_channel_in_server(channel, cserver)
{
switch (channel->state)
{
case IPIKE_CHANNEL_STATE_LISTEN:
case IPIKE_CHANNEL_STATE_OPEN:
IP_FD_SET(channel->fd, read_fds);
break;
default:
IPCOM_LOG1(ERR, "ipike_channel_server_add_fds() :: "\
"invalid fd state (%u)",
channel->state);
break;
}
max = IP_MAX(channel->fd, max);
}
return max;
}
/*
*===========================================================================
* ipike_channel_server_broadcast_msg
*===========================================================================
*/
IP_GLOBAL void
ipike_channel_server_broadcast_msg(
Ipike_channel_server * channel_server,
Ipike_channel_msg * msg)
{
Ipike_channel *channel;
/* Broadcast message on all open channels */
for_each_channel_in_server(channel, channel_server)
{
if ( ipike_channel_is_open(channel) )
{
ipike_channel_send_msg(channel, msg);
}
}
}
/*
*===========================================================================
* ipike_channel_server_create
*===========================================================================
*/
IP_GLOBAL Ipike_channel_server *
ipike_channel_server_create(
Ipike_channel_addr * caddr,
Ipike_channel_server_cb on_open_cb,
Ipike_channel_server_cb on_close_cb,
Ipike_channel_server_receive_cb on_receive_cb)
{
Ipike_channel_server * cserver;
Ipike_channel * channel;
cserver = ipcom_malloc(sizeof(Ipike_channel_server));
if ( IP_NULL == cserver )
return IP_NULL;
ipcom_memset(cserver, 0, sizeof(Ipike_channel_server));
ipcom_list_init(&cserver->channel_list);
/* Set user callbacks */
cserver->on_open_cb = on_open_cb;
cserver->on_close_cb = on_close_cb;
cserver->on_receive_cb = on_receive_cb;
channel = ipike_channel_create();
if ( channel == IP_NULL )
goto errout;
ipcom_list_insert_last(&cserver->channel_list, &channel->list);
/* Open socket */
#if defined(IPCOM_USE_INET)
channel->fd = ipcom_socket(IP_AF_INET, IP_SOCK_STREAM, IP_IPPROTO_TCP);
#elif defined(IPCOM_USE_INET6)
channel->fd = ipcom_socket(IP_AF_INET6, IP_SOCK_STREAM, IP_IPPROTO_TCP);
#endif
if ( channel->fd < 0 )
goto errout;
/* Bind channel server */
if ( ipcom_bind(channel->fd,
(struct Ip_sockaddr *) &caddr->addr,
IPCOM_SA_LEN_GET(&caddr->addr)) < 0 )
goto errout;
/* Start listen for new connections */
if (ipcom_listen(channel->fd, 1) != 0)
{
IPCOM_LOG1(WARNING, "ipike_event_channel_bind() :: failed to set socket to"\
" listen state (%s)",
ipcom_strerror(ipcom_errno));
goto errout;
}
/* The channel is listen state */
ipike_channel_set_state(channel, IPIKE_CHANNEL_STATE_LISTEN);
return cserver;
errout:
if ( cserver )
ipike_channel_server_destroy(cserver);
return IP_NULL;
}
/*
*===========================================================================
* ipike_channel_open
*===========================================================================
*/
IP_GLOBAL Ipike_channel *
ipike_channel_open(
Ipike_channel_addr * caddr)
{
Ipike_channel * channel;
/* Create channel */
channel = ipike_channel_create();
if ( channel == IP_NULL )
goto errout;
/* Open socket */
#if defined(IPCOM_USE_INET)
channel->fd = ipcom_socket(IP_AF_INET, IP_SOCK_STREAM, IP_IPPROTO_TCP);
#elif defined(IPCOM_USE_INET6)
channel->fd = ipcom_socket(IP_AF_INET6, IP_SOCK_STREAM, IP_IPPROTO_TCP);
#endif
if ( channel->fd < 0 )
goto errout;
/* Connect to IKE Daemon */
if ( ipcom_connect(channel->fd,
(struct Ip_sockaddr *) &caddr->addr,
IPCOM_SA_LEN_GET(&caddr->addr)) < 0 )
goto errout;
/* The channel is established */
ipike_channel_set_state(channel, IPIKE_CHANNEL_STATE_OPEN);
return channel;
errout:
if (channel)
ipike_channel_destroy(channel);
return IP_NULL;
}
/*
*===========================================================================
* ipike_channel_close
*===========================================================================
*/
IP_GLOBAL void
ipike_channel_close(
Ipike_channel * channel)
{
ipike_channel_lock(channel);
/* Close channel socket */
if ( channel->fd != IP_INVALID_SOCKET )
{
(void)ipcom_socketclose(channel->fd);
channel->fd = IP_INVALID_SOCKET;
}
ipike_channel_set_state(channel, IPIKE_CHANNEL_STATE_CLOSED);
ipike_channel_unlock(channel);
}
/*
*===========================================================================
* ipike_channel_receive_msg
*===========================================================================
*/
IP_GLOBAL Ipike_channel_status
ipike_channel_receive_msg(
Ipike_channel * channel,
Ipike_channel_msg ** msg)
{
Ipike_channel_msg hdr;
Ipike_channel_msg * msg_out = IP_NULL;
Ipike_channel_status err = IPIKE_CHANNEL_ERROR;
Ip_ssize_t ret = 0;
Ip_size_t len;
Ip_fd fd;
ipike_channel_lock(channel);
fd = channel->fd;
ipike_channel_unlock(channel);
/* Read header information */
ret = ipcom_recv(fd, &hdr, sizeof(hdr), 0);
/* Receive error */
if ( ret < 0 )
{
IPCOM_LOG2(DEBUG, "ipike_channel_receive_msg() :: "\
"failed to receive (%ld) (%s)",
ret,
ipcom_strerror(ipcom_errno));
goto errout;
}
/* Socket closed */
if ( ret == 0 )
{
IPCOM_LOG0(DEBUG, "ipike_channel_receive_msg() :: channel closed");
err = IPIKE_CHANNEL_CLOSED;
goto errout;
}
/* Expect the same size as specified in header */
if ( (Ip_ssize_t) ret != sizeof(hdr) )
{
IPCOM_LOG2(DEBUG, "ipike_channel_receive_msg() :: "\
"bad message, got %ld , expected %ld",
hdr.len, sizeof(hdr));
goto errout;
}
IPCOM_LOG1(DEBUG2, "ipike_channel_receive_msg() :: "\
"received message header of length %d\n", hdr.len);
/* If no message buffer was provided, create one dynamically */
if ( *msg == IP_NULL )
{
/* Allocate message space */
/* packet is sent by target itself, it is not vulnerable to attack */
/* coverity[tainted_data] : INTENTIONAL */
msg_out = ipike_channel_msg_create(hdr.len);
if ( msg_out == IP_NULL )
{
IP_PANIC();
goto errout;
}
*msg = msg_out;
}
else
{
/* Make sure the provided buffer has enough space for this message */
if ( (*msg)->len < hdr.len )
{
IPCOM_LOG0(DEBUG, "ipike_channel_receive_msg() :: "
"not enough memory in provided message");
goto errout;
}
}
/* Set message length to the size of the received message */
(*msg)->len = hdr.len;
/* Read the rest of the message */
len = (*msg)->len - sizeof(Ipike_channel_msg);
ret = ipcom_recv(fd, (*msg) + 1, len , 0);
if ( ret == 0 )
{
IPCOM_LOG0(DEBUG, "ipike_channel_receive_msg() :: channel closed");
err = IPIKE_CHANNEL_CLOSED;
goto errout;
}
if ( ret != (Ip_ssize_t) len )
{
IPCOM_LOG2(DEBUG, "ipike_channel_receive_msg() :: "\
"failed to receive message (%ld) (%s)",
ret,
ipcom_strerror(ipcom_errno));
goto errout;
}
IPCOM_LOG1(DEBUG, "ipike_channel_receive_msg() :: "\
"Successfully received message (%d)",
hdr.len);
return IPIKE_CHANNEL_OK;
errout:
if ( msg_out )
ipike_channel_msg_destroy(msg_out);
return err;
}
/*
*===========================================================================
* ipike_channel_send_msg
*===========================================================================
*/
IP_GLOBAL Ipike_channel_status
ipike_channel_send_msg(
Ipike_channel * channel,
Ipike_channel_msg * msg)
{
ip_assert(channel);
ip_assert(msg);
/* We need an open channel */
if ( !ipike_channel_is_open(channel) )
{
IPCOM_LOG0(DEBUG, "ipike_channel_send_msg() :: "\
"channel is not open");
return IPIKE_CHANNEL_CLOSED;
}
/* Send message */
if ( ipcom_send(channel->fd, (void *) msg, msg->len, 0) != msg->len )
{
IPCOM_LOG1(ERR, "ipike_channel_send_msg() :: "\
"failed to send message (%s)",
ipcom_strerror(ipcom_errno));
return IPIKE_CHANNEL_ERROR;
}
/* Message has been sent */
return IPIKE_CHANNEL_OK;
}
/*
*===========================================================================
* ipike_channel_server_process
*===========================================================================
*/
IP_GLOBAL int
ipike_channel_server_process(
Ipike_channel_server * cserver,
Ip_fd_set * read_fds,
Ip_fd_set * write_fds)
{
Ipike_channel * channel;
Ipike_channel * next;
int num_processed = 0;
IPCOM_UNUSED_ARG(write_fds);
/* Get first channel */
channel = (Ipike_channel * )ipcom_list_first(&cserver->channel_list);
if (channel==IP_NULL)
{
return 0;
}
/* This is the master channel where new connection can arrive on */
if ( IP_FD_ISSET(channel->fd, read_fds) )
{
/* Accept new channel connection */
(void)ipike_channel_server_accept_new_channel(cserver, channel);
num_processed++;
}
/* Continue to check if there are messages on other channels */
channel = (Ipike_channel *) ipcom_list_next(&channel->list);
while ( channel )
{
/* Receive data */
Ipike_channel_msg * msg = IP_NULL;
/* Store next pointer so we can remote the channel object if is needed */
next = (Ipike_channel *) ipcom_list_next(&channel->list);
if ( IP_FD_ISSET(channel->fd, read_fds) )
{
/* Receive message */
if ( ipike_channel_receive_msg(channel, &msg) != IPIKE_CHANNEL_OK )
{
IPCOM_LOG0(DEBUG, "ipike_channel_server_process():: "\
"closing channel");
ipcom_list_remove(&channel->list);
/* Notify user that channel is closed */
if ( cserver->on_close_cb )
cserver->on_close_cb(channel);
/* Destroy the channel on errors */
ipike_channel_destroy(channel);
}
else
{
/* Send message to user receive callback */
if (cserver->on_receive_cb)
cserver->on_receive_cb(channel, msg);
/* Destroy message */
ipike_channel_msg_destroy(msg);
}
num_processed++;
}
channel = next;
}
return num_processed;
}
#else
int ipike_channel_empty_file = 0;
#endif /* IPIKE_USE_EVENT_LOG */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/