/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_event_server.c,v $ $Revision: 1.5.2.4 $ * $Source: /home/interpeak/CVSRoot/ipike/src/ipike_event_server.c,v $ * $Author: zan $ $Date: 2013-07-31 08:17:04 $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Erik Dahlberg ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* IKE event receiver (client) and server implementation. The event server * will send event messages to each registered receiver. All communication * relies on IKE channels */ /* **************************************************************************** * 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_event.h" #include "ipike_event_server.h" #include "ipike_event_receiver.h" #include "ipike_channel.h" /* **************************************************************************** * 4 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 5 DEFINES **************************************************************************** */ /* Retry time period for an IKE event receiver */ #define IPIKE_EVENT_RECEIVER_RETRY_TIME_SEC 1 /* Process name */ #define IPIKE_EVENT_RECEIVER_PROC_NAME "tIKEEventReceiver" /* Channel address */ #if defined(IPCOM_USE_INET) #define IPIKE_EVENT_CHANNEL_IP "127.0.0.1" #else #define IPIKE_EVENT_CHANNEL_IP "::1" #endif /* Channel port */ #define IPIKE_EVENT_CHANNEL_PORT "50150" /* Full channel address */ #define IPIKE_EVENT_CHANNEL_ADDRESS \ IPIKE_EVENT_CHANNEL_IP "@" IPIKE_EVENT_CHANNEL_PORT /* **************************************************************************** * 6 TYPES **************************************************************************** */ /* Event receiver context */ typedef struct Ipike_event_receiver_ctx_struct { /* Semaphore for synchronized termination */ Ipcom_sem sem; Ipcom_mutex mutex; /* Variables protected by mutex - start */ Ipike_event_receiver_cb event_cb; Ipike_channel *channel; /* variables protected by mutex - end */ } Ipike_event_receiver_ctx; /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* Event receiver context, use one static global for now */ IP_STATIC Ipike_event_receiver_ctx ctx_store; IP_STATIC Ipike_event_receiver_ctx * libctx; /* String representation of events, must be aligned with the event table */ IP_STATIC const char * Ipike_event_strings[] = { "SOFT_LIFE_SIZE_EXPIRED", "SOFT_LIFE_TIME_EXPIRED", "HARD_LIFE_SIZE_EXPIRED", "HARD_LIFE_TIME_EXPIRED", "IKE_PACKET_DISCARD", "IKE_PHASE_I_FAIL", "IKE_PHASE_I_SUCCESS", "IKE_PHASE_II_FAIL", "IKE_PHASE_II_SUCCESS", "IPSEC_PACKET_DISCARD", "SEQUENCE_NUM_OVERFLOW", "SPD_PACKET_DISCARD" }; /* String representation of event reasons, must be aligned with * the event reason table */ IP_STATIC const char * Ipike_event_reason_strings[] = { "UNDEFINED", "AUTHENTICATION_ERROR", "DECRYPTION_ERROR", "ENCRYPTION_ERROR", "EXPLICIT_DISCARD_POLICY", "INVALID_SPI_ERROR", "NEGOTIATION_TIMEOUT", "NO_POLICY", "NO_PROTECTION_SUITE", "POLICY_ERROR", "REPLAY_ERROR", "INTERNAL_ERROR", "ISAKMP_PACKET_ERROR", "PROPOSAL_MISMATCH", "PSK_MISMATCH", "FLOW_MISMATCH", "IKE_INTERNAL_ERROR", "IKE_SA_OVERFLOW", "IPSEC_SA_OVERFLOW" }; /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_event_receiver_callback_set *=========================================================================== */ IP_STATIC void ipike_event_receiver_callback_set( Ipike_event_receiver_ctx * ctx, Ipike_event_receiver_cb event_cb) { ip_assert(ctx != IP_NULL); ipcom_mutex_lock(ctx->mutex); ctx->event_cb = event_cb; ipcom_mutex_unlock(ctx->mutex); } /* *=========================================================================== * ipike_event_receiver_callback_get *=========================================================================== */ IP_STATIC Ipike_event_receiver_cb ipike_event_receiver_callback_get( Ipike_event_receiver_ctx * ctx) { Ipike_event_receiver_cb cb; ip_assert(ctx != IP_NULL); ipcom_mutex_lock(ctx->mutex); cb = ctx->event_cb; ipcom_mutex_unlock(ctx->mutex); return cb; } /* *=========================================================================== * ipike_event_receiver_process_msg *=========================================================================== */ IP_STATIC int ipike_event_receiver_process_msg( Ipike_event_receiver_ctx * ctx, Ipike_channel_msg * msg) { Ipike_event_msg * emsg = (Ipike_event_msg *) msg; Ipike_event_receiver_cb cb = IP_NULL; cb = ipike_event_receiver_callback_get(ctx); emsg->event.spi = ip_ntohl(emsg->event.spi); emsg->event.reason = ip_ntohs(emsg->event.reason); emsg->event.type = ip_ntohs(emsg->event.type); emsg->event.src_port = ip_ntohs(emsg->event.src_port); emsg->event.dst_port = ip_ntohs(emsg->event.dst_port); if ( cb ) return cb(&emsg->event); return -1; } /* *=========================================================================== * ipike_event_receiver_proc *=========================================================================== */ IP_STATIC IPCOM_PROCESS(ipike_event_receiver_proc) { Ipike_channel_addr * caddr = IP_NULL; Ipike_channel_msg * msg = IP_NULL; Ipike_channel * channel = IP_NULL; Ipike_event_msg emsg; Ipike_channel_status ret; ip_assert(libctx != IP_NULL); /* Register process */ ipcom_proc_init(); /* Register log in ipike facility */ ipcom_openlog("ipike", 0, IPCOM_LOG_IPIKE); /* Get IKE daemon's channel address */ caddr = ipike_channel_addr_create(IPIKE_EVENT_CHANNEL_ADDRESS); if ( caddr == IP_NULL ) { IPCOM_LOG0(ERR, "ipike_event_receiver_proc() :: "\ "failed to create address"); goto errout; } /* Try keep us connected as long we have callback */ while ( ipike_event_receiver_callback_get(libctx) ) { IPCOM_LOG1(DEBUG2, "ipike_event_receiver_proc() ::"\ " opening channel, retrying in %d seconds", IPIKE_EVENT_RECEIVER_RETRY_TIME_SEC); /* We are reestablishing an existing channel */ if ( channel != IP_NULL ) { ipcom_mutex_lock(libctx->mutex); libctx->channel = IP_NULL; ipcom_mutex_unlock(libctx->mutex); /* Destroy channel */ ipike_channel_destroy(channel); } /* Open channel to IKE daemon */ channel = ipike_channel_open(caddr); if ( channel == IP_NULL ) { IPCOM_LOG1(DEBUG2, "ipike_event_receiver_proc() :: failed to"\ " open channel, retrying in %d seconds", IPIKE_EVENT_RECEIVER_RETRY_TIME_SEC); ipcom_sleep(IPIKE_EVENT_RECEIVER_RETRY_TIME_SEC); continue; } ipcom_mutex_lock(libctx->mutex); libctx->channel = channel; ipcom_mutex_unlock(libctx->mutex); /* Loop forever and process channel messages */ for (;;) { IPIKE_CHANNEL_MSG_INIT_STATIC(msg, emsg); /* Block until we get a message */ ret = ipike_channel_receive_msg(channel, &msg); if ( ret != IPIKE_CHANNEL_OK ) { IPCOM_LOG0(DEBUG, "ipike_event_receiver_proc() :: "\ "closing channel"); /* Something is wrong with the channel, break and * reestablish the channel */ break; } /* We got a message, process it */ if ( ipike_event_receiver_process_msg(libctx, msg) < 0 ) { IPCOM_LOG0(DEBUG, "ipike_event_receiver_proc() :: "\ "user callback signaled stop"); goto errout; } } } errout: IPCOM_LOG0(DEBUG, "ipike_event_receiver_proc() :: cleaning up before exit"); ipcom_mutex_lock(libctx->mutex); if (libctx->channel) { ipike_channel_destroy(libctx->channel); libctx->channel = IP_NULL; } ipcom_mutex_unlock(libctx->mutex); if (caddr) ipike_channel_addr_destroy(caddr); ipcom_closelog(); /* Notify exit */ ipcom_sem_post(libctx->sem); /* Not allowed to reference libctx from now */ ipcom_proc_exit(); } /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_event_server_log *=========================================================================== */ IP_GLOBAL void ipike_event_server_log( int type, int reason, union Ip_sockaddr_union * src_ip, union Ip_sockaddr_union * dst_ip, int protocol, Ip_u8 spi[4]) { Ipike_event_msg emsg; Ipike_channel_msg * msg; Ipike_event * event; event = &emsg.event; if ( ipike.event_server != IP_NULL ) { /* Set channel message header */ IPIKE_CHANNEL_MSG_INIT_STATIC(msg, emsg); /* Set event data */ event->type = ip_htons((Ip_u16) type); event->reason = ip_htons((Ip_u16) reason); event->protocol = (Ip_u8) protocol; if ( src_ip != IP_NULL ) (void)ipike_addr_copy(&event->src_ip, src_ip); if ( dst_ip != IP_NULL ) (void)ipike_addr_copy(&event->dst_ip, dst_ip); if ( spi != IP_NULL ) ipcom_memcpy(&event->spi, spi, 4); IPCOM_LOG1(DEBUG2, "ipike_event_server_log() :: broadcasting event (%s) "\ "on all channels", ipike_event_type_str((Ip_u16) type)); ipike_channel_server_broadcast_msg(ipike.event_server, (Ipike_channel_msg *) &emsg); } } /* *=========================================================================== * ipike_event_server_relay *=========================================================================== */ IP_GLOBAL void ipike_event_server_relay(Ipike_event_msg *emsg) { if ( ipike.event_server ) { IPCOM_LOG0(DEBUG2, "ipike_event_relay() :: relaying event "\ "message on all channels"); ipike_channel_server_broadcast_msg(ipike.event_server, (Ipike_channel_msg *) emsg); } } /* *=========================================================================== * ipike_event_server_startup *=========================================================================== */ IP_GLOBAL Ipike_error ipike_event_server_startup(void) { Ipike_channel_addr * caddr; /* Create IKE daemon's channel address */ caddr = ipike_channel_addr_create(IPIKE_EVENT_CHANNEL_ADDRESS); if ( caddr == IP_NULL ) return IPIKE_FAILED; /* Create a channel server */ ipike.event_server = ipike_channel_server_create(caddr, IP_NULL, IP_NULL, IP_NULL); /* We only needed the channel address to create the channel server */ ipike_channel_addr_destroy(caddr); if ( ipike.event_server == IP_NULL ) { IPCOM_LOG0(ERR, "ipike_event_server_startup() :: "\ "failed to create event server"); return IPIKE_FAILED; } IPCOM_LOG0(DEBUG2, "ipike_event_server_startup() :: "\ "event channel server is running started"); return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_event_server_shutdown *=========================================================================== */ IP_GLOBAL void ipike_event_server_shutdown(void) { if ( ipike.event_server != IP_NULL ) { ipike_channel_server_destroy(ipike.event_server); ipike.event_server = IP_NULL; } } /* *=========================================================================== * ipike_event_server_add_fds *=========================================================================== */ IP_GLOBAL int ipike_event_server_add_fds( Ip_fd_set * read_fds, Ip_fd_set * write_fds) { return ipike_channel_server_add_fds(ipike.event_server, read_fds, write_fds); } /* *=========================================================================== * ipike_event_server_process *=========================================================================== */ IP_GLOBAL int ipike_event_server_process( Ip_fd_set * read_fds, Ip_fd_set * write_fds) { return ipike_channel_server_process(ipike.event_server, read_fds, write_fds); } /* *=========================================================================== * ipike_event_type_str *=========================================================================== */ IP_GLOBAL const char * ipike_event_type_str( Ip_u16 type) { if ( type >= IPIKE_EVENT_MAX ) return "TYPE_UNKNOWN"; return Ipike_event_strings[type]; } /* *=========================================================================== * ipike_event_type_str *=========================================================================== */ IP_GLOBAL const char * ipike_event_reason_str( Ip_u16 type) { if ( type >= IPIKE_REASON_MAX ) return "REASON_UNKNOWN"; return Ipike_event_reason_strings[type]; } /* **************************************************************************** * Event receiver (client) functionality **************************************************************************** */ /* *=========================================================================== * ipike_event_receiver_init *=========================================================================== */ IP_PUBLIC int ipike_event_receiver_init( Ipike_event_receiver_cb event_cb) { Ipcom_proc_attr proc_attr; Ip_err err; /* Make sure that library isn't initialized yet */ if ( libctx != IP_NULL ) return -1; /* Get context, (replace with malloc to allow multiple instances */ libctx = &ctx_store; ipcom_memset(libctx, 0, sizeof(Ipike_event_receiver_ctx)); /* Create mutex */ if ( ipcom_mutex_create(&libctx->mutex) != IPCOM_SUCCESS ) goto errout; /* Create mutex */ if ( ipcom_sem_create(&libctx->sem, 0) != IPCOM_SUCCESS ) { ipcom_mutex_delete(&libctx->mutex); goto errout; } ipike_event_receiver_callback_set(libctx, event_cb); ipcom_proc_attr_init(&proc_attr); proc_attr.flags |= IPCOM_PROC_FLAG_FP; proc_attr.stacksize = IPCOM_PROC_STACK_DEFAULT; /* Spawn a new task/thread for handling events */ err = ipcom_proc_acreate(IPIKE_EVENT_RECEIVER_PROC_NAME, (Ipcom_proc_func) ipike_event_receiver_proc, &proc_attr, IP_NULL); if ( err != IPCOM_SUCCESS ) { ipcom_mutex_delete(&libctx->mutex); ipcom_sem_delete(&libctx->sem); goto errout; } return 0; errout: libctx = IP_NULL; return -1; } /* *=========================================================================== * ipike_event_receiver_destroy *=========================================================================== */ IP_PUBLIC void ipike_event_receiver_destroy(void) { /* Make sure we are initialized */ if ( libctx == IP_NULL ) return; /* Protect shared data */ ipcom_mutex_lock(libctx->mutex); libctx->event_cb = IP_NULL; if ( libctx->channel != IP_NULL ) { /* This will wake up the receiver task/thread */ ipike_channel_close(libctx->channel); } ipcom_mutex_unlock(libctx->mutex); /* Wait for the receiver thread to finish */ ipcom_sem_wait(libctx->sem); /* Receiver thread has finished, do clean up */ ipcom_mutex_delete(&libctx->mutex); ipcom_sem_delete(&libctx->sem); ipcom_memset(libctx, 0, sizeof(Ipike_event_receiver_ctx)); libctx = IP_NULL; } #else int ipike_channel_empty_file = 0; #endif /* IPIKE_USE_EVENT_LOG */ /* **************************************************************************** * END OF FILE **************************************************************************** */