From 64c0b7b0415ff34fd7849759313a150721d2b126 Mon Sep 17 00:00:00 2001 From: MassimilianoPinto Date: Mon, 2 Mar 2015 17:15:31 +0100 Subject: [PATCH] Notification service support Notification service support --- server/core/config.c | 66 ++++++++++- server/core/load_utils.c | 215 ++++++++++++++++++++++++---------- server/core/service.c | 9 +- server/include/config.h | 28 ++--- server/include/notification.h | 14 +++ 5 files changed, 241 insertions(+), 91 deletions(-) create mode 100644 server/include/notification.h diff --git a/server/core/config.c b/server/core/config.c index fcf851137..4e7ccae66 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -58,6 +58,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -70,12 +71,16 @@ static int process_config_update(CONFIG_CONTEXT *); static void free_config_context(CONFIG_CONTEXT *); static char *config_get_value(CONFIG_PARAMETER *, const char *); static int handle_global_item(const char *, const char *); +static int handle_feedback_item(const char *, const char *); static void global_defaults(); +static void feedback_defaults(); static void check_config_objects(CONFIG_CONTEXT *context); +static int config_truth_value(char *str); static int internalService(char *router); static char *config_file = NULL; static GATEWAY_CONF gateway; +static FEEDBACK_CONF feedback; char *version_string = NULL; @@ -121,6 +126,12 @@ CONFIG_PARAMETER *param, *p1; { return handle_global_item(name, value); } + + if (strcasecmp(section, "feedback") == 0) + { + return handle_feedback_item(name, value); + } + /* * If we already have some parameters for the object * add the parameters to that object. If not create @@ -192,6 +203,7 @@ int rval; } global_defaults(); + feedback_defaults(); config.object = ""; config.next = NULL; @@ -337,11 +349,12 @@ int error_count = 0; serviceEnableRootUser( obj->element, config_truth_value(enable_root_user)); + if (connection_timeout) serviceSetTimeout( obj->element, atoi(connection_timeout)); - + if (weightby) serviceWeightBy(obj->element, weightby); @@ -1186,6 +1199,16 @@ config_pollsleep() return gateway.pollsleep; } +/** + * Return the feedback config data pointer + * + * @return The feedback config data pointer + */ +FEEDBACK_CONF * +notification_get_config_feedback() +{ + return &feedback; +} static struct { char *logname; @@ -1221,8 +1244,8 @@ int i; } else if (strcmp(name, "ms_timestamp") == 0) { - skygw_set_highp(atoi(value)); - } + skygw_set_highp(atoi(value)); + } else { for (i = 0; lognames[i].logname; i++) @@ -1239,6 +1262,28 @@ int i; return 1; } +/** + * Configuration handler for items in the feedback [feedback] section + * + * @param name The item name + * @param value The item value + * @return 0 on error + */ +static int +handle_feedback_item(const char *name, const char *value) +{ +int i; + if (strcmp(name, "feedback_enable") == 0) + { + feedback.feedback_enable = atoi(value); + } + else if (strcmp(name, "feedback_url") == 0) + { + feedback.feedback_enable = atoi(value); + } + return 1; +} + /** * Set the defaults for the global configuration options */ @@ -1255,6 +1300,16 @@ global_defaults() gateway.id=0; } +/** + * Set the defaults for the feedback configuration options + */ +static void +feedback_defaults() +{ + feedback.feedback_enable = 0; + feedback.feedback_last_action = 0; +} + /** * Process a configuration context update and turn it into the set of object * we need. @@ -1302,8 +1357,9 @@ SERVER *server; char *allow_localhost_match_wildcard_host; enable_root_user = config_get_value(obj->parameters, "enable_root_user"); + connection_timeout = config_get_value(obj->parameters, "connection_timeout"); - + user = config_get_value(obj->parameters, "user"); auth = config_get_value(obj->parameters, @@ -1439,11 +1495,9 @@ SERVER *server; enable_root_user = config_get_value(obj->parameters, "enable_root_user"); - connection_timeout = config_get_value(obj->parameters, "connection_timeout"); - allow_localhost_match_wildcard_host = config_get_value(obj->parameters, "localhost_match_wildcard_host"); diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 1fd6b1ab9..57564a6fa 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -26,10 +26,10 @@ * Date Who Description * 13/06/13 Mark Riddoch Initial implementation * 14/06/13 Mark Riddoch Updated to add call to ModuleInit if one is - * defined in the loaded module. + * defined in the loaded module. * Also updated to call fixed GetModuleObject * 02/06/14 Mark Riddoch Addition of module info - * 26/02/15 Massimiliano Pinto Addition of module_feedback_send + * 26/02/15 Massimiliano Pinto Addition of module_feedback_send * * @endverbatim */ @@ -44,6 +44,7 @@ #include #include #include +#include #include /** Defined in log_manager.cc */ @@ -72,18 +73,18 @@ WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; - + mem->data = realloc(mem->data, mem->size + realsize + 1); if(mem->data == NULL) { - /* out of memory! */ + /* out of memory! */ printf("not enough memory (realloc returned NULL)\n"); return 0; } - + memcpy(&(mem->data[mem->size]), contents, realsize); mem->size += realsize; mem->data[mem->size] = 0; - + return realsize; } @@ -443,24 +444,70 @@ MODULES *ptr = registered; * @param data The configuration details of notification service */ void -module_feedback_send(void* data) -{ +module_feedback_send(void* data) { MODULES *ptr = registered; CURL *curl; CURLcode res; struct curl_httppost *formpost=NULL; struct curl_httppost *lastptr=NULL; GWBUF *buffer = NULL; - char *data_ptr = NULL; - int n_mod=0; + void *data_ptr=NULL; + long http_code = 0; struct MemoryStruct chunk; + int last_action = 0; + time_t now; + struct tm *now_tm; + int hour; + int n_mod=0; + + now = time(NULL); + now_tm = localtime(&now); + hour = now_tm->tm_hour; + + FEEDBACK_CONF *feedback_config = (FEEDBACK_CONF *) data; + + /** + * Task runs nightly, from 2 AM to 4 AM + * + * If it's done in that time interval, it will be skipped + */ + + if (hour > 4 || hour < 2) { + /* It's not the rigt time, mark it as to be done and return */ + feedback_config->feedback_last_action = 0; + + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "module_feedback_create : skip task because of time interval: hour is [%d]", + hour))); + + return; + } + + /* Time to run the task: if a previous run was succesfull skip next runs */ + if (feedback_config->feedback_last_action == 1) { + /* task was done before, return */ + + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "module_feedback_create : skip task because of previous succesful run: hour is [%d], last_action [%d]", + hour, feedback_config->feedback_last_action))); + + return; + } + + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "module_feedback_create : task runs: hour is [%d], last_action [%d]", + hour, feedback_config->feedback_last_action))); + + + chunk.data = malloc(1); /* will be grown as needed by the realloc above */ + chunk.size = 0; /* no data at this point */ - chunk.data = malloc(1); /* will be grown as needed by the realloc above */ - chunk.size = 0; /* no data at this point */ - /* count loaded modules */ while (ptr) - { + { ptr = ptr->next; n_mod++; } @@ -468,56 +515,65 @@ module_feedback_send(void* data) buffer = gwbuf_alloc(n_mod * 256); data_ptr = GWBUF_DATA(buffer); + + sprintf(data_ptr, "FEEDBACK_SERVER_UID\t%s\n", "xxxfcBRIvkRlxyGdoJL0bWy+TmY"); + data_ptr+=strlen(data_ptr); + sprintf(data_ptr, "FEEDBACK_USER_INFO\t%s\n", "0467009f-xxxx-yyyy-zzzz-b6b2ec9c6cf4"); + data_ptr+=strlen(data_ptr); + sprintf(data_ptr, "VERSION\t%s\n", MAXSCALE_VERSION); + data_ptr+=strlen(data_ptr); + sprintf(data_ptr, "NOW\t%lu\nPRODUCT\t%s\n", now, "maxscale"); + data_ptr+=strlen(data_ptr); + sprintf(data_ptr, "Uname_sysname\t%s\n", "linux"); + data_ptr+=strlen(data_ptr); + sprintf(data_ptr, "Uname_distribution\t%s\n", "centos"); + data_ptr+=strlen(data_ptr); - while (ptr) - { - /* current maxscale setup */ - sprintf(data_ptr, "FEEDBACK_SERVER_UID\t%s\n", "xxxfcBRIvkRlxyGdoJL0bWy+TmY"); - data_ptr+=strlen(data_ptr); - sprintf(data_ptr, "FEEDBACK_USER_INFO\t%s\n", "0467009f-xxxx-yyyy-zzzz-b6b2ec9c6cf4"); - data_ptr+=strlen(data_ptr); - sprintf(data_ptr, "VERSION\t%s\n", MAXSCALE_VERSION); - data_ptr+=strlen(data_ptr); - sprintf(data_ptr, "NOW\t%lu\nPRODUCT\t%s\n", time(NULL), "maxscale"); - data_ptr+=strlen(data_ptr); - sprintf(data_ptr, "Uname_sysname\t%s\n", "linux"); - data_ptr+=strlen(data_ptr); - sprintf(data_ptr, "Uname_distribution\t%s\n", "centos"); + while (ptr) + { + sprintf(data_ptr, "module_%s_type\t%s\nmodule_%s_version\t%s\n", ptr->module, ptr->type, ptr->module, ptr->version); data_ptr+=strlen(data_ptr); - /* modules data */ - sprintf(data_ptr, "module_%s_type\t%s\nmodule_%s_version\t%s\n", ptr->module, ptr->type, ptr->module, ptr->version); - data_ptr+=strlen(data_ptr); - - if (ptr->info) { - sprintf(data_ptr, "module_%s_api\t%d.%d.%d\n", - ptr->module, - ptr->info->api_version.major, - ptr->info->api_version.minor, - ptr->info->api_version.patch); + if (ptr->info) { + sprintf(data_ptr, "module_%s_api\t%d.%d.%d\n", + ptr->module, + ptr->info->api_version.major, + ptr->info->api_version.minor, + ptr->info->api_version.patch); data_ptr+=strlen(data_ptr); sprintf(data_ptr, "module_%s_releasestatus\t%s\n", ptr->module, - ptr->info->status == MODULE_IN_DEVELOPMENT - ? "In Development" - : (ptr->info->status == MODULE_ALPHA_RELEASE - ? "Alpha" - : (ptr->info->status == MODULE_BETA_RELEASE - ? "Beta" - : (ptr->info->status == MODULE_GA - ? "GA" - : (ptr->info->status == MODULE_EXPERIMENTAL - ? "Experimental" : "Unknown"))))); - data_ptr+=strlen(data_ptr); + ptr->info->status == MODULE_IN_DEVELOPMENT + ? "In Development" + : (ptr->info->status == MODULE_ALPHA_RELEASE + ? "Alpha" + : (ptr->info->status == MODULE_BETA_RELEASE + ? "Beta" + : (ptr->info->status == MODULE_GA + ? "GA" + : (ptr->info->status == MODULE_EXPERIMENTAL + ? "Experimental" : "Unknown"))))); + data_ptr+=strlen(data_ptr); } - ptr = ptr->next; - } + ptr = ptr->next; + } + + + /* Initializing curl library for data send via HTTP */ + curl_global_init(CURL_GLOBAL_DEFAULT); - /* curl API call for data send via HTTP POST using a "file" type input */ curl = curl_easy_init(); if(curl) { + char error_message[CURL_ERROR_SIZE]=""; + + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_message); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + /* curl API call for data send via HTTP POST using a "file" type input */ curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "data", @@ -527,32 +583,69 @@ module_feedback_send(void* data) CURLFORM_CONTENTTYPE, "text/plain", CURLFORM_END); + curl_easy_setopt(curl, CURLOPT_HEADER, 1); + + /* some servers don't like requests that are made without a user-agent field, so we provide one */ + curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1/post.php"); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - /* send all received data to this function */ +#ifdef SKIP_PEER_VERIFICATION + /* + * This makes the connection A LOT LESS SECURE. + */ +// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * this will make the connection less secure. + */ + // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - /* we pass our 'chunk' struct to the callback function */ + /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); - - /* some servers don't like requests that are made without a user-agent field, so we provide one */ - curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); - + /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ - if(res != CURLE_OK) + if(res != CURLE_OK) { + last_action = 0; + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - else - fprintf(stderr, "Reply from remote server is\n[%s]\n", chunk.data); + fprintf(stderr, "curl error_message: [%s]\n", error_message); + } else { + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + fprintf(stderr, "Reply from remote server is\n[%s]. Code [%lu]\n", chunk.data, http_code); + } + + if (http_code == 200) { + last_action = 1; + } + } else { + last_action = 0; } + + memcpy(&feedback_config->feedback_last_action, &last_action, sizeof(int)); + + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "module_feedback_create : task run result: hour is [%d], last_action [%d], http_code [%d]", + hour, feedback_config->feedback_last_action, http_code))); if(chunk.data) free(chunk.data); gwbuf_free(buffer); + curl_easy_cleanup(curl); curl_formfree(formpost); + curl_global_cleanup(); } diff --git a/server/core/service.c b/server/core/service.c index e766263b0..346d2d73e 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -58,6 +58,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -473,11 +474,11 @@ serviceStartAll() { SERVICE *ptr; int n = 0,i; +FEEDBACK_CONF *feedback = notification_get_config_feedback(); - /** Add the notification service feedback task, if enabled */ - //if (config_feedback_enable() ) { - hktask_add("send_feedback", module_feedback_send, NULL, 30); - //} + if (feedback->feedback_enable) { + hktask_add("send_feedback", module_feedback_create, feedback, 30); + } ptr = allServices; while (ptr && !ptr->svc_do_shutdown) diff --git a/server/include/config.h b/server/include/config.h index c27184468..7b7ac9e90 100644 --- a/server/include/config.h +++ b/server/include/config.h @@ -30,7 +30,6 @@ * 07/05/14 Massimiliano Pinto Added version_string to global configuration * 23/05/14 Massimiliano Pinto Added id to global configuration * 17/10/14 Mark Riddoch Added poll tuning configuration parameters - * 26/02/15 Massimiliano Pinto Added notification service configuration parameters * * @endverbatim */ @@ -100,26 +99,15 @@ typedef struct { unsigned int pollsleep; /**< Wait time in blocking polls */ } GATEWAY_CONF; -/** - * The configuration and usage information data for feeback service - */ -typedef struct { - int feedback_enable; /**< Enable/Disable Notification feedback */ - char *feedback_url; /**< URL to which the data is sent */ - char *feedback_user_info; /**< User info included in the feedback data sent */ - char *feedback_server_uid; /**< Installation identifier included in the feedback data sent */ - int feedback_send_timeout; /**< An attempt to send the data times out and fails after this many seconds */ -} FEEDBACK_CONF; +extern int config_load(char *); +extern int config_reload(); +extern int config_threadcount(); +extern unsigned int config_nbpolls(); +extern unsigned int config_pollsleep(); +CONFIG_PARAMETER* config_get_param(CONFIG_PARAMETER* params, const char* name); +config_param_type_t config_get_paramtype(CONFIG_PARAMETER* param); +CONFIG_PARAMETER* config_clone_param(CONFIG_PARAMETER* param); -extern int config_load(char *); -extern int config_reload(); -extern int config_threadcount(); -extern unsigned int config_nbpolls(); -extern unsigned int config_pollsleep(); -CONFIG_PARAMETER* config_get_param(CONFIG_PARAMETER* params, const char* name); -config_param_type_t config_get_paramtype(CONFIG_PARAMETER* param); -CONFIG_PARAMETER* config_clone_param(CONFIG_PARAMETER* param); -int config_truth_value(char *str); bool config_set_qualified_param( CONFIG_PARAMETER* param, void* val, diff --git a/server/include/notification.h b/server/include/notification.h new file mode 100644 index 000000000..9b6356548 --- /dev/null +++ b/server/include/notification.h @@ -0,0 +1,14 @@ +/** + * The configuration and usage information data for feeback service + */ + +typedef struct { + int feedback_enable; /**< Enable/Disable Notification feedback */ + char *feedback_url; /**< URL to which the data is sent */ + char *feedback_user_info; /**< User info included in the feedback data sent */ + int feedback_send_timeout; /**< An attempt to send the data times out and fails after this many seconds */ + int feedback_last_action; /**< Holds the feedback last send action status */ +} FEEDBACK_CONF; + + +extern FEEDBACK_CONF* notification_get_config_feedback();