From d986aeb99fa33967374290bf7ce75eab76c6d446 Mon Sep 17 00:00:00 2001 From: Dmitri Pal Date: Mon, 23 Feb 2009 10:38:06 -0500 Subject: Initial commit. --- dispatcher/elapi_dispatcher.c | 688 +++++++++++++++++++++++++++++++++++++++ dispatcher/elapi_dispatcher.h | 68 ++++ dispatcher/elapi_dispatcher_ut.c | 201 ++++++++++++ 3 files changed, 957 insertions(+) create mode 100644 dispatcher/elapi_dispatcher.c create mode 100644 dispatcher/elapi_dispatcher.h create mode 100644 dispatcher/elapi_dispatcher_ut.c (limited to 'dispatcher') diff --git a/dispatcher/elapi_dispatcher.c b/dispatcher/elapi_dispatcher.c new file mode 100644 index 0000000..cecf5bf --- /dev/null +++ b/dispatcher/elapi_dispatcher.c @@ -0,0 +1,688 @@ +/* Copyright */ + +#include +#include +#include +#include +#include +#include +#include "elapi_debug.h" +#include "elapi_dispatcher.h" +#include "elapi_collection.h" +#include "elapi_sink.h" + +#define SINK_COLLECTION "sinks" + +char def_application_name[] = "unknown"; + +char *default_sinks[] = { "ipa","kernel","syslog","file","stderr", NULL }; + + +/* Structure to pass data from logging function to sinks */ +struct sink_context { + struct collection_item *event; + struct dispatcher_handle *handle; + char *previous; + int previous_status; +}; + +/* The structure to hold a command and a result of the command execution */ +struct get_sink { + int action; + int found; +}; + + +#ifdef ELAPI_LOG_DEBUG +#define DEBUG_SINK(sink_data) print_sink(sink_data); +#else +#define DEBUG_SINK(sink_data) ; +#endif + +/* Debug function */ +static void print_sink(struct sink_descriptor *sink_data) +{ + DEBUG_NUMBER("SINK data address",sink_data); + DEBUG_NUMBER("SINK data DBLOCK address",&(sink_data->dblock)); + DEBUG_NUMBER("SINK data DBLOCK internals",(&(sink_data->dblock))->internal_data); +} + + +static void init_sink(struct sink_descriptor *sink_data, int status) +{ + int error; + struct timeval tv; + + DEBUG_STRING("init_sink","Entry"); + DEBUG_STRING("In init_sink application name:",sink_data->dblock.appname); + + /* Pass in the data block storage */ + error = (sink_data->sink_cpb_block).init_cb(&(sink_data->dblock)); + DEBUG_NUMBER("DBLOCK in init_sink",&(sink_data->dblock)); + if(error != EOK) { + DEBUG_NUMBER("Failed to initialize the sink:",error); + (void)gettimeofday(&tv,NULL); + sink_data->suspended = ELAPI_SINK_SUSPENDED; + sink_data->lasttry = tv.tv_sec; + } + else { + DEBUG_NUMBER("Initialized the sink. Status set to:",status); + sink_data->suspended = status; + sink_data->lasttry = 0; + } + DEBUG_SINK(sink_data); + DEBUG_STRING("init_sink","Exit"); +} + +static void wash_sink(struct sink_descriptor *sink_data) +{ + int error; + struct timeval tv; + + DEBUG_STRING("wash_sink","Entry"); + DEBUG_NUMBER("Descriptor",sink_data); + DEBUG_NUMBER("Capability",&(sink_data->sink_cpb_block)); + DEBUG_NUMBER("Callback",(sink_data->sink_cpb_block).close_cb); + DEBUG_NUMBER("DBLOCK in wash",&(sink_data->dblock)); + + /* Pass in the data block storage */ + (sink_data->sink_cpb_block).close_cb(&(sink_data->dblock)); + + DEBUG_STRING("wash_sink","Exit"); +} + + +/* Function to load sink library */ +static int load_sink(struct sink_descriptor *sink_data,char *sink_name) +{ + char sink_lib_name[SINK_LIB_NAME_SIZE]; + capability_fn get_lib_info; + void *lib_handle; + char *lib_error; + int error = EOK; + + DEBUG_STRING("load_sink","Entry"); + + sprintf(sink_lib_name,SINK_NAME_TEMPLATE,sink_name); + DEBUG_STRING("Name of the library to load",sink_lib_name); + + /* Load library */ + sink_data->lib_handle = dlopen (sink_lib_name, RTLD_LAZY); + if (!(sink_data->lib_handle)) { + DEBUG_STRING("Dlopen returned error",dlerror()); + return ELIBACC; + } + + /* Clear any existing error */ + dlerror(); + /* Get addres to the main entry point */ + get_lib_info = (capability_fn)(dlsym(sink_data->lib_handle, SINK_ENTRY_POINT)); + if ((lib_error = dlerror()) != NULL) { + DEBUG_STRING("Dlsym returned error",lib_error); + return ELIBACC; + } + + /* Init data */ + get_lib_info(&(sink_data->sink_cpb_block)); + + /* Call library initialization function */ + init_sink(sink_data,ELAPI_SINK_OK); + + /* If we return ELIBACC it would indicate that the desired library is missing */ + + DEBUG_STRING("load_sink","Returning Success"); + return EOK; +} + + +/* Function to add a sink in the list */ +static int add_sink_to_list(struct collection_item *sink_list, + char *sink, + char *appname) +{ + int error = EOK; + int found = 0; + struct sink_descriptor sink_data; + + DEBUG_STRING("add_sink_to_list","Entry"); + error = is_item_in_collection(sink_list, + sink, + ELAPI_TYPE_ANY, + ELAPI_TRAVERSE_DEFAULT, + &found); + if(error) { + DEBUG_NUMBER("Search returned error",error); + return error; + } + + /* Check if it was found */ + if(found) { + DEBUG_STRING("Attempt to add an exiting sink.",""); + return EINVAL; + } + + /* Save the pointer to application name into the sink's data block */ + sink_data.dblock.appname = appname; + DEBUG_STRING("add_sink_to_list - saving appname:",sink_data.dblock.appname); + + /* Try to load the sink library */ + error = load_sink(&sink_data,sink); + if(error != 0) { + DEBUG_NUMBER("Failed to load sink",error); + return error; + } + + /* We got a valid sink so add it to the collection */ + error=add_binary_property(sink_list,NULL, + sink,(void *)(&sink_data), + sizeof(struct sink_descriptor)); + if(error != 0) { + DEBUG_NUMBER("Failed to add sink data as property",error); + return error; + } + + DEBUG_NUMBER("add_sink_to_list returning",error); + return error; +} + +/* Handler to change the sink status data */ +static int update_sink_handle(char *sink, + int sink_len, + int type, + void *data, + int length, + void *passed_data, + int *stop) +{ + int error = EOK; + struct sink_descriptor *sink_data; + struct get_sink *get_sink_op; + + DEBUG_STRING("update_sink_handler","Entry."); + + sink_data = (struct sink_descriptor *)(data); + get_sink_op = (struct get_sink *)(passed_data); + + switch(get_sink_op->action) { + case ELAPI_SINK_ACTION_DISABLE: + DEBUG_STRING("Disabling sink:",sink); + wash_sink(sink_data); + sink_data->suspended = ELAPI_SINK_DISABLED; + break; + case ELAPI_SINK_ACTION_ENABLE: + DEBUG_STRING("Enabling sink:",sink); + wash_sink(sink_data); + /* Init sink will set the correct status */ + init_sink(sink_data,ELAPI_SINK_OK); + break; + case ELAPI_SINK_ACTION_PULSE: + DEBUG_STRING("Pulsing sink:",sink); + wash_sink(sink_data); + init_sink(sink_data,ELAPI_SINK_PULSE); + break; + default: + DEBUG_STRING("update_sink_handler","ERROR Invalid argument"); + return EINVAL; + } + + *stop = 1; + /* Indicate that we found item */ + get_sink_op->found = 1; + + DEBUG_STRING("update_sink_handler","Return."); + return EOK; +} + +/* Handler to clean sinks at the end */ +static int close_sink_handler(char *sink, + int sink_len, + int type, + void *data, + int length, + void *passed_data, + int *stop) +{ + int error = EOK; + struct sink_descriptor *sink_data; + + DEBUG_STRING("close_sink_handler","Entry."); + DEBUG_STRING("Sink:",sink); + + if(type == ELAPI_TYPE_COLLECTION) return EOK; + + sink_data = (struct sink_descriptor *)(data); + + wash_sink(sink_data); + + if(sink_data->lib_handle != NULL) { + DEBUG_STRING("Closing lib handle",""); + dlclose(sink_data->lib_handle); + sink_data->lib_handle = NULL; + } + + DEBUG_STRING("close_sink_handler","Return."); + return EOK; +} + + +/* Handler for logging through the sinks */ +static int sink_handler(char *sink, + int sink_len, + int type, + void *data, + int length, + void *passed_data, + int *stop) +{ + struct sink_context *sink_env; + struct sink_descriptor *sink_data; + int status = 0; + int error = EOK; + struct timeval tv; + + DEBUG_STRING("sink_handler","Entry."); + DEBUG_STRING("Sink:",sink); + + sink_env = (struct sink_context *)(passed_data); + sink_data = (struct sink_descriptor *)(data); + + /* When porcessing header just initialize and continue */ + if(type == ELAPI_TYPE_COLLECTION) { + sink_env->previous = NULL; + sink_env->previous_status = 0; + return error; + } + + /* Check if the sink is healthy to use */ + if(sink_data->suspended!= ELAPI_SINK_OK) { + DEBUG_NUMBER("Sink is suspended:",sink_data->suspended); + if(sink_data->suspended == ELAPI_SINK_DISABLED) { + DEBUG_STRING("Sink is suspended by caller. Skipping sink.",sink); + return EOK; + } + if(sink_data->suspended == ELAPI_SINK_PULSE) { + DEBUG_STRING("Sink is suspended by caller for one time. Skipping sink but resetting to Ok.",sink); + sink_data->suspended = ELAPI_SINK_OK; + return EOK; + } + if(sink_data->suspended == ELAPI_SINK_SUSPENDED) { + DEBUG_STRING("Sink is suspended is it time to retry.",sink); + /* Is the sink permanently suspended ? */ + if((sink_data->sink_cpb_block).retry_interval == SINK_NEVER_RETRY) { + DEBUG_STRING("Sink is suspended forever since the sink tells not to retry.",sink); + /* For future: should we delete the sink ?*/ + /* IMO we should not becuase the calling + * application can potentially do something to fix the issue and + * explicitely re-enable the sink after it. */ + return EOK; + } + /* Check interval */ + (void)gettimeofday(&tv,NULL); + if(difftime(tv.tv_sec,sink_data->lasttry + (sink_data->sink_cpb_block).retry_interval) < 0) { + DEBUG_STRING("Sink is suspended is it not time to retry.",sink); + return EOK; + } + + /* Time to retry a suspended sink */ + init_sink(sink_data,ELAPI_SINK_OK); + if(sink_data->suspended == ELAPI_SINK_SUSPENDED) { + DEBUG_STRING("Sink is still suspended. Problem still exists.",sink); + return EOK; + } + + } + else { + DEBUG_STRING("Status is invalid for sink.",sink); + return EINVAL; + } + } + + + /* Call router function */ + status = (sink_env->handle)->router(sink, + sink_env->previous, + sink_env->previous_status, + sink_env->event, + sink_data, + (sink_env->handle)->custom_data, + &error); + /* Check the status */ + switch(status) { + case ELAPI_DISPATCHER_SKIP: /* Ignore current sink as if it is abcent */ + DEBUG_STRING("Ignoring sink.",sink); + /* Do not change suspended status */ + /* Do not change previous fields */ + break; + case ELAPI_DISPATCHER_DONE: /* Sink is done with this event */ + DEBUG_STRING("Done with this event.",sink); + *stop = 1; + sink_data->suspended = ELAPI_SINK_OK; + break; + case ELAPI_DISPATCHER_NEXT: /* Sink thinks somone else would want to log this event */ + DEBUG_STRING("Go to the next sink.",sink); + sink_env->previous = sink; + sink_env->previous_status = status; + sink_data->suspended = ELAPI_SINK_OK; + break; + case ELAPI_DISPATCHER_ERROR: /* An error occured */ + DEBUG_NUMBER("Go to the next sink due to error.",error); + + /* FIXME: In future may be store the error and log it later + * when the sink recovers from failure. + * Alternatively may be log it into another sink. */ + + /* Record the fact that the sink returned error */ + sink_env->previous = sink; + sink_env->previous_status = status; + + /* Suspend this sink */ + sink_data->suspended = ELAPI_SINK_SUSPENDED; + sink_data->lasttry=tv.tv_sec; + wash_sink(sink_data); + break; + + default: /* This should not happen - codding error */ + DEBUG_STRING("Status is invalid for sink.",sink); + return EINVAL; + } + + DEBUG_STRING("sink_handler","Success Exit."); + + return EOK; +} + + +/* Router function returns status not error */ +static int default_router(char *sink, + char *previous_sink, + int previous_status, + struct collection_item *event, + struct sink_descriptor *sink_data, + void *custom_data, + int *error) +{ + DEBUG_STRING("default_router","Entry"); + + /* FIXME + * default implementation of the routing function: + * Log every event into every facility regardless + * of the outcome. + */ + + + *error = log_event_to_sink(sink_data,event,custom_data); + + + + DEBUG_STRING("default_router","Returning"); + return ELAPI_DISPATCHER_NEXT; +} + + + +/* ================== SINK LIST MANAGEMENT ======================== */ + +/* Function to create a list of sinks */ +static int construct_sink_list(struct dispatcher_handle *handle) +{ + int error = EOK; + char **current_sink; + + DEBUG_STRING("construct_sink_list","Entry"); + + /* Allocate collection to store sinks */ + error=create_collection(&(handle->sink_list),SINK_COLLECTION); + if(error != 0) { + DEBUG_NUMBER("Failed to create sink collection. Error",error); + /* No cleanup here. + * The calling function will call a cleanup + * of the dispatcher as a whole.*/ + return error; + } + + current_sink = handle->sinks; + handle->sink_counter = 0; + + /* Add sinks as properties to the sink collection */ + while (*current_sink != NULL) { + + DEBUG_STRING("Current sink",*current_sink); + DEBUG_STRING("Will use appname:",handle->appname); + + /* Load sink */ + error = add_sink_to_list(handle->sink_list,*current_sink,handle->appname); + if((error != 0) && (error != ELIBACC)) { + DEBUG_NUMBER("Failed to add sink",error); + /* No cleanup here. */ + return error; + } + + handle->sink_counter++; + current_sink++; + } + + /* Check if we have any sinks available */ + if(handle->sink_counter == 0) { + DEBUG_NUMBER("No sinks",""); + /* No cleanup here. */ + /* Return "Cannot access a needed shared library" */ + return ELIBACC; + } + + DEBUG_STRING("construct_sink_list","Returning success"); + return EOK; +} + +/* Function to delete sink list collection */ +static void delete_sink_list(struct dispatcher_handle *handle) +{ + DEBUG_STRING("delete_sink_list","Entry point"); + if(handle->sink_list != (struct collection_item *)(NULL)) { + DEBUG_STRING("delete_sink_list","Deleting sink collection"); + destroy_collection(handle->sink_list); + } + DEBUG_STRING("delete_sink_list","Exit"); +} + + +/* ========================= MAIN INTERFACE FUNCTIONS ============================ */ + +/* Function to create an audit dispatcher */ +int create_audit_dispatcher(struct dispatcher_handle **dispatcher, + const char *appname, + char **desired_sinks, + event_router_fn desired_router, + void *custom_data) +{ + struct dispatcher_handle *handle; + int error = EOK; + + DEBUG_STRING("create_audit_dispatcher","Entry point"); + + /* Make sure the memory for handle is passed in */ + if(dispatcher == (struct dispatcher_handle **)(NULL)) { + DEBUG_STRING("create_audit_dispatcher","Invalid parameter."); + return EINVAL; + } + + /* Allocate memory */ + handle = (struct dispatcher_handle *) malloc(sizeof(struct dispatcher_handle)); + if(handle == (struct dispatcher_handle *)(NULL)) { + error = errno; + DEBUG_NUMBER("Memory allocation failed. Error",error); + return error; + } + + /* Save application name in the handle */ + if(appname != NULL) handle->appname = strdup(appname); + else handle->appname = strdup(def_application_name); + + DEBUG_STRING("Application name:",handle->appname); + + /* Check error */ + if(handle->appname == NULL) { + error = errno; + DEBUG_NUMBER("Memory allocation failed. Error",error); + return error; + } + + /* Check if there is no desired sinks provided */ + if(desired_sinks != (char **)(NULL)) handle->sinks = desired_sinks; + else handle->sinks = default_sinks; + + /* Check the router. If it is empty use the default router */ + if(desired_router != (event_router_fn)(NULL)) handle->router = desired_router; + else handle->router = default_router; + + handle->custom_data = custom_data; + + /* Create the list of sinks */ + error = construct_sink_list(handle); + if(error != EOK) { + DEBUG_NUMBER("Failed to create sink list. Error",error); + destroy_audit_dispatcher(handle); + return error; + } + + *dispatcher = handle; + + DEBUG_STRING("create_audit_dispatcher","Returning Success."); + return EOK; +} + +/* Function to clean memory associated with the audit dispatcher */ +void destroy_audit_dispatcher(struct dispatcher_handle *dispatcher) +{ + DEBUG_STRING("destroy_audit_dispatcher","Entry"); + if(dispatcher != (struct dispatcher_handle *)(NULL)) { + /* Offload libs */ + (void)traverse_collection(dispatcher->sink_list,ELAPI_TRAVERSE_ONELEVEL,close_sink_handler,(void *)(NULL)); + DEBUG_STRING("Deleting sink list.",""); + delete_sink_list(dispatcher); + DEBUG_STRING("Freeing application name.",""); + free((void *)(dispatcher->appname)); + DEBUG_STRING("Freeing dispatcher.",""); + free((void *)(dispatcher)); + } + DEBUG_STRING("destroy_audit_dispatcher","Exit"); +} + + + +/* Log evento into a specific sink */ +int log_event_to_sink(struct sink_descriptor *sink_data, + struct collection_item *event, + void *custom_data) +{ + int error = EOK; + struct sink_capability *sink_cpb; + + DEBUG_STRING("log_event_to_sink","Entry"); + + sink_cpb = &(sink_data->sink_cpb_block); + + DEBUG_NUMBER("DBLOCK in dispatcher",&(sink_data->dblock)); + DEBUG_NUMBER("internal data in dispatcher",(&(sink_data->dblock))->internal_data); + DEBUG_SINK(sink_data); + + /* Format (serialize the event) */ + error = sink_cpb->format_cb(&(sink_data->dblock),event); + if(error != EOK) { + DEBUG_NUMBER("Format function returned error",error); + return error; + } + + /* Submit the event */ + error = sink_cpb->submit_cb(&(sink_data->dblock)); + DEBUG_NUMBER("Format function returned error",error); + + /* Clean internal per event data in any case */ + sink_cpb->cleanup_cb(&(sink_data->dblock)); + + DEBUG_STRING("log_event_to_sink","Return"); + return error; + +} + + +/* Function to clean memory associated with the audit dispatcher */ +void log_audit_event(struct dispatcher_handle *dispatcher, struct collection_item *event) +{ + struct sink_context sink_env; + + DEBUG_STRING("log_audit_event","Entry"); + if((dispatcher == (struct dispatcher_handle *)(NULL)) || + (event == (struct collection_item *)(NULL))) { + DEBUG_STRING("log_audit_event","ERROR Invalid argument"); + DEBUG_NUMBER("Dispatcher",dispatcher); + DEBUG_NUMBER("Event",event); + DEBUG_STRING("log_audit_event","ERROR Return"); + return; + } + + sink_env.handle = dispatcher; + sink_env.event = event; + + /* Logging an event is just iterating through the sinks and calling the sink_handler */ + (void)traverse_collection(dispatcher->sink_list,ELAPI_TRAVERSE_ONELEVEL,sink_handler,(void *)(&sink_env)); + + DEBUG_STRING("log_audit_event","Return"); +} + +/* Managing the sink collection */ +int alter_audit_dispatcher(struct dispatcher_handle *dispatcher, + char *sink, + int action) +{ + int error; + struct get_sink get_sink_op; + + DEBUG_STRING("alter_audit_dispatcher","Entry"); + if((dispatcher == (struct dispatcher_handle *)(NULL)) || + (sink == (char *)(NULL))) { + DEBUG_STRING("log_audit_event","ERROR Invalid argument"); + DEBUG_NUMBER("Dispatcher",dispatcher); + DEBUG_NUMBER("Sink",sink); + DEBUG_STRING("log_audit_event","ERROR Return"); + return EINVAL; + } + + switch(action) { + case ELAPI_SINK_ACTION_ADD: + /* Try to add it and return whatever the attmpt returned */ + error = add_sink_to_list(dispatcher->sink_list,sink,dispatcher->appname); + DEBUG_NUMBER("alter_audit_dispatcher ADD returning",error); + return error; + case ELAPI_SINK_ACTION_DELETE: + /* Try to delete the sink */ + error = delete_property(dispatcher->sink_list, + sink, + ELAPI_TYPE_ANY, + ELAPI_TRAVERSE_DEFAULT); + DEBUG_NUMBER("alter_audit_dispatcher DELETE returning",error); + return error; + case ELAPI_SINK_ACTION_DISABLE: + case ELAPI_SINK_ACTION_ENABLE: + case ELAPI_SINK_ACTION_PULSE: + /* Try to modify the sink */ + get_sink_op.action = action; + get_sink_op.found = 0; + error = get_item_and_do(dispatcher->sink_list, + sink, + ELAPI_TYPE_ANY, + ELAPI_TRAVERSE_DEFAULT, + update_sink_handle, + (void *)(&get_sink_op)); + if(get_sink_op.found == 0) { + DEBUG_STRING("alter_audit_dispatcher DISABLE/ENABLE/PULSE sink not found",""); + return EINVAL; + } + DEBUG_NUMBER("alter_audit_dispatcher DISABLE/ENABLE/PULSE returning",error); + return error; + default: + DEBUG_STRING("alter_audit_dispatcher","Invalid action"); + return EINVAL; + } + + /* Unreachable */ +} diff --git a/dispatcher/elapi_dispatcher.h b/dispatcher/elapi_dispatcher.h new file mode 100644 index 0000000..909505a --- /dev/null +++ b/dispatcher/elapi_dispatcher.h @@ -0,0 +1,68 @@ +/* Copyright */ + +#ifndef ELAPI_DISPATCHER_H +#define ELAPI_DISPATCHER_H + +#include "elapi_collection.h" +#include "elapi_sink.h" + +/* Status values returned by the routing function */ +#define ELAPI_DISPATCHER_SKIP 0 +#define ELAPI_DISPATCHER_DONE 1 +#define ELAPI_DISPATCHER_NEXT 2 +#define ELAPI_DISPATCHER_ERROR 3 + + +/* Actions that can be taken against a sink */ +#define ELAPI_SINK_ACTION_ADD 0 /* Add a new sink */ +#define ELAPI_SINK_ACTION_DELETE 1 /* Delete a sink */ +#define ELAPI_SINK_ACTION_DISABLE 2 /* Disable a sink */ +#define ELAPI_SINK_ACTION_PULSE 3 /* Disable a sink temporarily for one call */ +#define ELAPI_SINK_ACTION_ENABLE 4 /* Enable sink */ + + +/* Event routing function */ +typedef int (*event_router_fn)(char *sink, + char *previous_sink, + int previous_status, + struct collection_item *event, + struct sink_descriptor *sink_data, + void *custom_data, + int *error); + +struct dispatcher_handle { + char **sinks; + char *appname; + event_router_fn router; + struct collection_item *sink_list; + int sink_counter; + void *custom_data; +}; + +/* Function to create a dispatcher */ +int create_audit_dispatcher(struct dispatcher_handle **dispatcher, /* Handle of the dispatcher will be stored in this variable */ + const char *appname, /* Application name. Passed to the sinks to do initialization */ + char **desired_sinks, /* List of names of the sinks to use. If NULL the default will be used */ + event_router_fn desired_router, /* The rounting function. If NULL the default will be used */ + void *custom_data); /* Custom data that can be used in the router function. */ + + +/* Function to clean memory associated with the audit dispatcher */ +void destroy_audit_dispatcher(struct dispatcher_handle *dispatcher); + +/* Function to log an event */ +void log_audit_event(struct dispatcher_handle *dispatcher, struct collection_item *event); + +/* Advanced functions */ +/* Managing the sink collection */ +int alter_audit_dispatcher(struct dispatcher_handle *dispatcher, /* Dispatcher */ + char *sink, /* Sink to change */ + int action); /* Action to perform for sink */ + +/* This function is exposed in case you are providing your own routing callback */ +int log_event_to_sink(struct sink_descriptor *sink_data, + struct collection_item *event, + void *custom_data); + + +#endif diff --git a/dispatcher/elapi_dispatcher_ut.c b/dispatcher/elapi_dispatcher_ut.c new file mode 100644 index 0000000..119d40a --- /dev/null +++ b/dispatcher/elapi_dispatcher_ut.c @@ -0,0 +1,201 @@ +/* Copyright */ + +#include +#include +#include "elapi_dispatcher.h" +#include "elapi_collection.h" +#include "elapi_debug.h" +#include "elapi_util.h" +#include "elapi_tools.h" + +struct collection_item *event; +struct collection_item *peer; +struct collection_item *socket; +struct collection_item *host; + + +int construct_event() +{ + char binary_dump[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + int found = 0; + + int error = EOK; + + DEBUG_STRING("construct_event","Entry."); + + if((error=create_collection(&peer,"peer")) || + (error=add_str_property(peer,NULL,"hostname","peerhost.mytest.com",0)) || + (error=add_str_property(peer,NULL,"IPv4","10.10.10.10",12)) || /* Expect trailing zero to be truncated */ + (error=add_str_property(peer,NULL,"IPv6","bla:bla:bla:bla:bla:bla",0))) { + printf("Failed to add property. Error %d",error); + destroy_collection(peer); + return error; + } + + if((error=create_collection(&host,"host")) || + (error=add_str_property(host,NULL,"hostname","myhost.mytest.com",0)) || + (error=add_str_property(host,NULL,"IPv4","20.20.20.20",13)) || + (error=add_str_property(host,NULL,"IPv6","bla:bla:bla:bla:bla:bla",0))) { + printf("Failed to add property. Error %d",error); + destroy_collection(peer); + destroy_collection(host); + return error; + } + + + if((error=create_collection(&socket,"socket")) || + (error=add_int_property(socket,NULL,"id",1)) || + (error=add_long_property(socket,NULL,"packets",100000000L)) || + (error=add_binary_property(socket,NULL,"stack",binary_dump,sizeof(binary_dump)))) { + destroy_collection(peer); + destroy_collection(host); + destroy_collection(socket); + printf("Failed to add property. Error %d\n",error); + return error; + } + + /* Embed peer host into the socket2 as reference */ + error = add_collection_to_collection(socket,NULL,"peer",peer,ELAPI_ADD_MODE_REFERENCE); + if(error) { + destroy_collection(peer); + destroy_collection(host); + destroy_collection(socket); + printf("Failed to create collection. Error %d\n",error); + return error; + } + + /* Construct event */ + if((error=create_collection(&event,"event")) || + (error=add_str_property(event,NULL,"escape1","ds\\sd=ewrw===sada",0)) || + (error=add_str_property(event,NULL,"escape2","dss,d,=,ewrw===sada",0)) || + (error=add_str_property(event,NULL,"escape3","ds\\sd=ewrw,()===sada",0)) || + (error=add_str_property(event,NULL,"escape4","dssd=ewrw===))))sada",0)) || + (error=add_str_property(event,NULL,"escape5","d\\ss(((((d=ew(()()()(),(,,\\\\\\\\rw===sada",0)) || + (error=add_int_property(event,NULL,"something",100))) { + destroy_collection(peer); + destroy_collection(host); + destroy_collection(socket); + destroy_collection(event); + printf("Failed to create collection. Error %d\n",error); + return error; + } + + /* Add host to event */ + error = add_collection_to_collection(event,NULL,NULL,host,ELAPI_ADD_MODE_REFERENCE); + if(error) { + destroy_collection(peer); + destroy_collection(host); + destroy_collection(socket); + destroy_collection(event); + printf("Failed to add collections. Error %d\n",error); + return error; + } + + error = add_collection_to_collection(event,NULL,NULL,socket,ELAPI_ADD_MODE_REFERENCE); + if(error) { + destroy_collection(peer); + destroy_collection(host); + destroy_collection(socket); + destroy_collection(event); + printf("Failed to add collections. Error %d\n",error); + return error; + } + + debug_collection(event,ELAPI_TRAVERSE_DEFAULT); + + return EOK; +} + + +int main() +{ + int error = EOK; + struct dispatcher_handle *dispatcher; + char *sinks[]= { "foo", "stderr", "bar", NULL }; + + printf("Test start\n"); + + + error = create_audit_dispatcher(&dispatcher,"my_app",sinks,NULL,NULL); + printf("create_audit_dispatcher returned %d\n", error); + + /* Try to log with invalid parameters */ + printf("%s","=================\nNegative test1\n"); + log_audit_event(NULL, NULL); + printf("%s","=================\nNegative test2\n"); + log_audit_event(dispatcher, NULL); + + printf("%s","=================\nCreating collection\n"); + error = construct_event(); + if(error) { + printf("Error creating event %d\n",error); + return error; + } + + + printf("%s","=================\nLogging peer - expect success\n"); + print_collection(peer); + log_audit_event(dispatcher, peer); + printf("%s","=================\nLogging host - expect success\n"); + print_collection(host); + log_audit_event(dispatcher, host); + printf("%s","=================\nLogging socket - expect success\n"); + print_collection(socket); + log_audit_event(dispatcher, socket); + printf("%s","=================\nLogging event - expect success\n"); + print_collection(event); + log_audit_event(dispatcher, event); + + /* Try to alter list of sinks */ + printf("%s","=================\nSeries of negative test cases.\n"); + /* Deleting non exisintg sink */ + error = alter_audit_dispatcher(dispatcher,"far2",ELAPI_SINK_ACTION_DELETE); + if(error == 0) printf("%s","Expected failure got success\n"); + else printf("Expected failure. Error : %d\n",error); + + /* Editing non exisintg sink */ + error = alter_audit_dispatcher(dispatcher,"far2",ELAPI_SINK_ACTION_ENABLE); + if(error == 0) printf("%s","Expected failure got success\n"); + else printf("Expected failure. Error : %d\n",error); + + /* Adding duplicate */ + error = alter_audit_dispatcher(dispatcher,"bar",ELAPI_SINK_ACTION_ADD); + if(error == 0) printf("%s","Expected failure got success\n"); + else printf("Expected failure. Error : %d\n",error); + + /* Adding new */ + error = alter_audit_dispatcher(dispatcher,"far2",ELAPI_SINK_ACTION_ADD); + if(error != 0) printf("Expected success got failure %d\n",error); + else printf("Success : %d\n",error); + + /* Enable */ + error = alter_audit_dispatcher(dispatcher,"far2",ELAPI_SINK_ACTION_ENABLE); + if(error != 0) printf("Expected success got failure %d\n",error); + else printf("Success : %d\n",error); + + /* Pulse */ + error = alter_audit_dispatcher(dispatcher,"far2",ELAPI_SINK_ACTION_PULSE); + if(error != 0) printf("Expected success got failure %d\n",error); + else printf("Success : %d\n",error); + + /* Disable */ + error = alter_audit_dispatcher(dispatcher,"far2",ELAPI_SINK_ACTION_DISABLE); + if(error != 0) printf("Expected success got failure %d\n",error); + else printf("Success : %d\n",error); + + /* Delete */ + error = alter_audit_dispatcher(dispatcher,"far2",ELAPI_SINK_ACTION_DELETE); + if(error != 0) printf("Expected success got failure %d\n",error); + else printf("Success : %d\n",error); + + destroy_audit_dispatcher(dispatcher); + destroy_collection(peer); + destroy_collection(host); + destroy_collection(socket); + destroy_collection(event); + printf("Test end\n"); + return error; +} + + + -- cgit