diff --git a/server/core/config.c b/server/core/config.c index 6959a13d1..0fa519a25 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -41,6 +41,7 @@ * 30/10/14 Massimiliano Pinto Added disable_master_failback parameter * 07/11/14 Massimiliano Pinto Addition of monitor timeouts for connect/read/write * 20/02/15 Markus Mäkelä Added connection_timeout parameter for services + * 05/03/15 Massimiliano Pinto Added notification_feedback support * * @endverbatim */ @@ -55,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -63,10 +65,12 @@ #include #include #include +#include #include #include #include #include +#include /** Defined in log_manager.cc */ @@ -84,10 +88,11 @@ 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); -int get_release_string(char* release); -int config_get_ifaddr(unsigned char *output); +int config_truth_value(char *str); +static int internalService(char *router); +int config_get_ifaddr(unsigned char *output); +int config_get_release_string(char* release); + static char *config_file = NULL; static GATEWAY_CONF gateway; static FEEDBACK_CONF feedback; @@ -746,7 +751,7 @@ int error_count = 0; /* if id is not set, do it now */ if (gateway.id == 0) { setipaddress(&serv_addr.sin_addr, (address == NULL) ? "0.0.0.0" : address); - gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + port + getpid()); + gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + atoi(port) + getpid()); } if (service && socket && protocol) { @@ -1215,7 +1220,7 @@ config_pollsleep() * @return The feedback config data pointer */ FEEDBACK_CONF * -notification_get_config_feedback() +config_get_feedback_data() { return &feedback; } @@ -1312,6 +1317,8 @@ int i; static void global_defaults() { + uint8_t mac_addr[6]=""; + struct utsname uname_data; gateway.n_threads = 1; gateway.n_nbpoll = DEFAULT_NBPOLLS; gateway.pollsleep = DEFAULT_POLLSLEEP; @@ -1321,20 +1328,23 @@ global_defaults() gateway.version_string = NULL; gateway.id=0; - if(!get_release_string(gateway.release_string)) - { + /* get release string */ + if(!config_get_release_string(gateway.release_string)) sprintf(gateway.release_string,"undefined"); + + /* get first mac_address in SHA1 */ + if(config_get_ifaddr(mac_addr)) { + gw_sha1_str(mac_addr, 6, gateway.mac_sha1); + } else { + memset(gateway.mac_sha1, '\0', sizeof(gateway.mac_sha1)); + memcpy(gateway.mac_sha1, "MAC-undef", 9); } - unsigned char mac[6]; - if(config_get_ifaddr(mac)) - { - SHA1(mac,6,gateway.mac_sha1); - } - else - { - sprintf(gateway.mac_sha1,"MAC-undef"); - } + /* get uname info */ + if (uname(&uname_data)) + strcpy(gateway.sysname, "undefined"); + else + strncpy(gateway.sysname, uname_data.sysname, _SYSNAME_STR_LENGTH); } /** @@ -1344,12 +1354,14 @@ static void feedback_defaults() { feedback.feedback_enable = 0; - feedback.feedback_last_action = 0; - feedback.feedback_timeout = 30; - feedback.feedback_connect_timeout = 30; - feedback.feedback_url = NULL; - feedback.feedback_setup_info = strdup("10000-eee-AAA-444"); feedback.feedback_user_info = NULL; + feedback.feedback_last_action = _NOTIFICATION_SEND_PENDING; + feedback.feedback_timeout = _NOTIFICATION_OPERATION_TIMEOUT; + feedback.feedback_connect_timeout = _NOTIFICATION_CONNECT_TIMEOUT; + feedback.feedback_url = NULL; + feedback.release_info = gateway.release_string; + feedback.sysname = gateway.sysname; + feedback.mac_sha1 = gateway.mac_sha1; } /** @@ -1970,158 +1982,190 @@ int i; } return 0; } - -int config_get_ifaddr(unsigned char *output) +/** + * Get the MAC address of first network interface + * + * and fill the provided allocated buffer with SHA1 encoding + * @param output Allocated 6 bytes buffer + * @return 1 on success, 0 on failure + * + */ +int +config_get_ifaddr(unsigned char *output) { - struct ifreq ifr; - struct ifconf ifc; - char buf[1024]; - int success = 0; + struct ifreq ifr; + struct ifconf ifc; + char buf[1024]; + struct ifreq* it; + struct ifreq* end; + int success = 0; - int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - if (sock == -1) { /* handle error*/ }; + int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock == -1) { + return 0; + }; - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; - if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { /* handle error */ } + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { + return 0; + } - struct ifreq* it = ifc.ifc_req; - const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq)); + it = ifc.ifc_req; + end = it + (ifc.ifc_len / sizeof(struct ifreq)); - for (; it != end; ++it) { - strcpy(ifr.ifr_name, it->ifr_name); - if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { - if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback - if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) { - success = 1; - break; - } - } - } - else { /* handle error */ } - } + for (; it != end; ++it) { + strcpy(ifr.ifr_name, it->ifr_name); + if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { + if (! (ifr.ifr_flags & IFF_LOOPBACK)) { /* don't count loopback */ + if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) { + success = 1; + break; + } + } + } else { + return 0; + } + } - if (success) memcpy(output, ifr.ifr_hwaddr.sa_data, 6); + if (success) + memcpy(output, ifr.ifr_hwaddr.sa_data, 6); - return success; + return success; } /** + * Get the linux distribution info + * + * @param release The allocated buffer where + * the found distribution is copied into. + * @return 1 on success, 0 on failure * - * @param release - * @return */ -int get_release_string(char* release) +int +config_get_release_string(char* release) { - const char *masks[]= { - "/etc/*-version", "/etc/*-release", - "/etc/*_version", "/etc/*_release" - }; - bool have_ubuf; - struct utsname ubuf; - bool have_distribution; - char distribution[256]; - int fd; - int i; - char *to; + const char *masks[]= { + "/etc/*-version", "/etc/*-release", + "/etc/*_version", "/etc/*_release" + }; - have_ubuf = (uname(&ubuf) != -1); - have_distribution= false; - if ((fd= open("/etc/lsb-release", O_RDONLY)) != -1) - { - /* LSB-compliant distribution! */ - size_t len= read(fd, (char*)distribution, sizeof(distribution)-1); - close(fd); - if (len != (size_t)-1) + bool have_distribution; + char distribution[_RELEASE_STR_LENGTH]=""; + int fd; + int i; + char *to; + + have_distribution= false; + + /* get data from lsb-release first */ + if ((fd= open("/etc/lsb-release", O_RDONLY)) != -1) { - distribution[len]= 0; // safety - char *found= strstr(distribution, "DISTRIB_DESCRIPTION="); - if (found) - { - have_distribution = true; - char *end = strstr(found, "\n"); - if (end == NULL) - end = distribution + len; - found += 20; - - if (*found == '"' && end[-1] == '"') + /* LSB-compliant distribution! */ + size_t len= read(fd, (char*)distribution, sizeof(distribution)-1); + close(fd); + if (len != (size_t)-1) { - found++; - end--; + distribution[len]= 0; + char *found= strstr(distribution, "DISTRIB_DESCRIPTION="); + if (found) + { + have_distribution = true; + char *end = strstr(found, "\n"); + if (end == NULL) + end = distribution + len; + found += 20; + + if (*found == '"' && end[-1] == '"') + { + found++; + end--; + } + *end = 0; + + to = strcpy(distribution, "lsb: "); + memmove(to, found, end - found + 1); + + strncpy(release, to, _RELEASE_STR_LENGTH); + + return 1; + } } - *end = 0; - - to = strcpy(distribution, "lsb: "); - memmove(to, found, end - found + 1); - - strncpy(release, to, 255); - return 1; - } } - } - /* if not an LSB-compliant distribution */ - for (i= 0; !have_distribution && i < 4; i++) - { - glob_t found; - char *new_to; - fprintf(stderr, "glob %d: [%s]\n", i, masks[i]); + /* if not an LSB-compliant distribution */ + for (i= 0; !have_distribution && i < 4; i++) + { + glob_t found; + char *new_to; - if (glob(masks[i], GLOB_NOSORT, NULL, &found) == 0) - { - int fd; - int k = 0; - int skipindex = 0; - int startindex = 0; + if (glob(masks[i], GLOB_NOSORT, NULL, &found) == 0) + { + int fd; + int k = 0; + int skipindex = 0; + int startindex = 0; - fprintf(stderr, "Matched [%lu] paths\n", found.gl_pathc); + for (k = 0; k< found.gl_pathc; k++) { + if (strcmp(found.gl_pathv[k], "/etc/lsb-release") == 0) { + skipindex = k; + } + } - for (k = 0; k< found.gl_pathc; k++) { - fprintf(stderr, "Possibly opening [%s]\n", found.gl_pathv[k]); - if (strcmp(found.gl_pathv[k], "/etc/lsb-release") == 0) { - fprintf(stderr, "Skipping [%s]\n", found.gl_pathv[k]); - skipindex = k; - } - } + if ( skipindex == 0) + startindex++; + if ((fd= open(found.gl_pathv[startindex], O_RDONLY)) != -1) + { + /* + +5 and -8 below cut the file name part out of the + full pathname that corresponds to the mask as above. + */ + new_to = strcpy(distribution, found.gl_pathv[0] + 5); + new_to += 8; + *new_to++ = ':'; + *new_to++ = ' '; - if ( skipindex == 0) - startindex++; + size_t to_len= distribution + sizeof(distribution) - 1 - new_to; + size_t len= read(fd, (char*)new_to, to_len); - // skip ound.gl_pathv[0] if it's /etc/lsb-release - if ((fd= open(found.gl_pathv[startindex], O_RDONLY)) != -1) - { - /* - +5 and -8 below cut the file name part out of the - full pathname that corresponds to the mask as above. - */ - //char *to= strmov(distribution, found.gl_pathv[0] + 5) - 8; - new_to = strcpy(distribution, found.gl_pathv[0] + 5); - new_to += 8; - *new_to++ = ':'; - *new_to++ = ' '; + close(fd); - size_t to_len= distribution + sizeof(distribution) - 1 - new_to; - size_t len= read(fd, (char*)new_to, to_len); - close(fd); - if (len != (size_t)-1) - { - new_to[len]= 0; // safety - char *end= strstr(new_to, "\n"); - if (end) - *end= 0; + if (len != (size_t)-1) + { + new_to[len]= 0; + char *end= strstr(new_to, "\n"); + if (end) + *end= 0; - have_distribution= true; - fprintf(stderr, "Distribution [%i]=[%s]\n", i, new_to); - strncpy(release, new_to, 255); - } - } - } - globfree(&found); - } + have_distribution= true; + strncpy(release, new_to, _RELEASE_STR_LENGTH); + } + } + } + globfree(&found); + } - if (have_distribution) - return 1; - else - return 0; + if (have_distribution) + return 1; + else + return 0; +} + +/** + * Add the 'send_feedback' task to the task list + */ +void +config_enable_feedback_task(void) { + FEEDBACK_CONF *cfg = config_get_feedback_data(); + if (cfg->feedback_enable) + hktask_add("send_feedback", module_feedback_send, cfg, 30); +} + +/** + * Remove the 'send_feedback' task + */ +void +config_disable_feedback_task(void) { + hktask_remove("send_feedback"); } diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 69c2d52b0..d0e1dd11d 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -47,6 +47,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -537,10 +538,7 @@ module_feedback_send(void* data) { struct tm *now_tm; int hour; int n_mod=0; - struct utsname uname_data; - unsigned char setup_if_address[6]=""; - unsigned char sha1_if_address[20]=""; - char hex_setup_info[40 + 1]=""; + char hex_setup_info[2 * SHA_DIGEST_LENGTH + 1]=""; now = time(NULL); now_tm = localtime(&now); @@ -565,7 +563,7 @@ module_feedback_send(void* data) { 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; + feedback_config->feedback_last_action = _NOTIFICATION_SEND_PENDING; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, @@ -576,7 +574,7 @@ module_feedback_send(void* data) { } /* Time to run the task: if a previous run was succesfull skip next runs */ - if (feedback_config->feedback_last_action == 1) { + if (feedback_config->feedback_last_action == _NOTIFICATION_SEND_OK) { /* task was done before, return */ LOGIF(LE, (skygw_log_write_flush( @@ -593,14 +591,9 @@ module_feedback_send(void* data) { hour, feedback_config->feedback_last_action))); - /* get uname info */ - uname(&uname_data); + /* encode MAC-sha1 to HEX */ + gw_bin2hex(hex_setup_info, feedback_config->mac_sha1, SHA_DIGEST_LENGTH); - /* get first available network interface info */ - if (config_get_ifaddr(setup_if_address)) { - gw_sha1_str(setup_if_address, 6, sha1_if_address); - gw_bin2hex(hex_setup_info, sha1_if_address, 20); - } /* allocate first memory chunck for httpd servr reply */ chunk.data = malloc(1); /* will be grown as needed by the realloc above */ @@ -617,11 +610,7 @@ module_feedback_send(void* data) { buffer = gwbuf_alloc(n_mod * 256); data_ptr = GWBUF_DATA(buffer); - if (strlen(hex_setup_info)) - sprintf(data_ptr, "FEEDBACK_SERVER_UID\t%s\n", hex_setup_info); - else - sprintf(data_ptr, "FEEDBACK_SERVER_UID\t%s\n", feedback_config->feedback_setup_info); - + sprintf(data_ptr, "FEEDBACK_SERVER_UID\t%s\n", hex_setup_info); data_ptr+=strlen(data_ptr); sprintf(data_ptr, "FEEDBACK_USER_INFO\t%s\n", feedback_config->feedback_user_info); data_ptr+=strlen(data_ptr); @@ -629,14 +618,9 @@ module_feedback_send(void* data) { data_ptr+=strlen(data_ptr); sprintf(data_ptr, "NOW\t%lu\nPRODUCT\t%s\n", now, "maxscale"); data_ptr+=strlen(data_ptr); - - if (strlen(uname_data.sysname)) - sprintf(data_ptr, "Uname_sysname\t%s\n", uname_data.sysname); - else - sprintf(data_ptr, "Uname_sysname\t%s\n", ""); - + sprintf(data_ptr, "Uname_sysname\t%s\n", feedback_config->sysname); data_ptr+=strlen(data_ptr); - sprintf(data_ptr, "Uname_distribution\t%s\n", ""); + sprintf(data_ptr, "Uname_distribution\t%s\n", feedback_config->release_info); data_ptr+=strlen(data_ptr); while (ptr) @@ -704,14 +688,14 @@ module_feedback_send(void* data) { /* * This makes the connection A LOT LESS SECURE. */ -// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + 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); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif /* send all data to this function */ @@ -725,7 +709,7 @@ module_feedback_send(void* data) { /* Check for errors */ if(res != CURLE_OK) { - last_action = 0; + last_action = _NOTIFICATION_SEND_ERROR; fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); fprintf(stderr, "curl error_message: [%s]\n", error_message); @@ -736,10 +720,10 @@ module_feedback_send(void* data) { } if (http_code == 200) { - last_action = 1; + last_action = _NOTIFICATION_SEND_OK; } } else { - last_action = 0; + last_action = _NOTIFICATION_SEND_ERROR; } memcpy(&feedback_config->feedback_last_action, &last_action, sizeof(int)); diff --git a/server/core/service.c b/server/core/service.c index 4e59a7f62..246243a93 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -35,6 +35,7 @@ * 13/10/14 Massimiliano Pinto Added hashtable for resources (i.e database names for MySQL services) * 06/02/15 Mark Riddoch Added caching of authentication data * 18/02/15 Mark Riddoch Added result set management + * 03/03/15 Massimiliano Pinto Added config_enable_feedback_task() call in serviceStartAll * * @endverbatim */ @@ -60,7 +61,6 @@ #include #include #include -#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -476,11 +476,8 @@ serviceStartAll() { SERVICE *ptr; int n = 0,i; -FEEDBACK_CONF *feedback = notification_get_config_feedback(); - if (feedback->feedback_enable) { - hktask_add("send_feedback", module_feedback_send, feedback, 300); - } + config_enable_feedback_task(); ptr = allServices; while (ptr && !ptr->svc_do_shutdown) diff --git a/server/include/config.h b/server/include/config.h index 811260205..3648c97a0 100644 --- a/server/include/config.h +++ b/server/include/config.h @@ -30,12 +30,15 @@ * 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 + * 05/03/15 Massimiliano Pinto Added sysname, release, sha1_mac to gateway struct * * @endverbatim */ #define DEFAULT_NBPOLLS 3 /**< Default number of non block polls before we block */ #define DEFAULT_POLLSLEEP 1000 /**< Default poll wait time (milliseconds) */ +#define _SYSNAME_STR_LENGTH 256 /**< sysname len */ +#define _RELEASE_STR_LENGTH 256 /**< release len */ /** * Maximum length for configuration parameter value. */ @@ -92,11 +95,12 @@ typedef struct config_context { * The gateway global configuration data */ typedef struct { - int n_threads; /**< Number of polling threads */ - char *version_string; /**< The version string of embedded database library */ - char release_string[256]; /**< The release name string of the system */ - char mac_sha1[SHA_DIGEST_LENGTH]; /*< The SHA1 digest of an interface MAC address */ - unsigned long id; /**< MaxScale ID */ + int n_threads; /**< Number of polling threads */ + char *version_string; /**< The version string of embedded database library */ + char release_string[_SYSNAME_STR_LENGTH]; /**< The release name string of the system */ + char sysname[_SYSNAME_STR_LENGTH]; /**< The release name string of the system */ + uint8_t mac_sha1[SHA_DIGEST_LENGTH]; /*< The SHA1 digest of an interface MAC address */ + unsigned long id; /**< MaxScale ID */ unsigned int n_nbpoll; /**< Tune number of non-blocking polls */ unsigned int pollsleep; /**< Wait time in blocking polls */ } GATEWAY_CONF; @@ -109,7 +113,7 @@ 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_truth_value(char *); bool config_set_qualified_param( CONFIG_PARAMETER* param, void* val, @@ -133,4 +137,7 @@ bool config_get_valtarget( CONFIG_PARAMETER* param, const char* name, /*< if NULL examine current param only */ config_param_type_t ptype); + +void config_enable_feedback_task(void); +void config_disable_feedback_task(void); #endif diff --git a/server/include/notification.h b/server/include/notification.h index b802e934d..ca91684b3 100644 --- a/server/include/notification.h +++ b/server/include/notification.h @@ -1,5 +1,5 @@ -#ifndef _NOTIFICATION_H -#define _NOTIFICATION_H +#ifndef _NOTIFICATION_SERVICE_H +#define _NOTIFICATION_SERVICE_H /* * This file is distributed as part of the MariaDB Corporation MaxScale. It is free * software: you can redistribute it and/or modify it under the terms of the @@ -32,6 +32,12 @@ * @endverbatim */ +#define _NOTIFICATION_CONNECT_TIMEOUT 30 +#define _NOTIFICATION_OPERATION_TIMEOUT 30 +#define _NOTIFICATION_SEND_PENDING 0 +#define _NOTIFICATION_SEND_OK 1 +#define _NOTIFICATION_SEND_ERROR 2 + /** * The configuration and usage information data for feeback service */ @@ -39,14 +45,15 @@ typedef struct { int feedback_enable; /**< Enable/Disable Notification feedback */ char *feedback_url; /**< URL to which the data is sent */ - char *feedback_setup_info; /**< MaxScale setup identifier info included in the feedback data sent */ char *feedback_user_info; /**< User info included in the feedback data sent */ int feedback_timeout; /**< An attempt to write/read the data times out and fails after this many seconds */ int feedback_connect_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 */ + char *release_info; /**< Operating system Release name */ + char *sysname; /**< Operating system name */ + uint8_t *mac_sha1; /**< First available MAC address*/ } FEEDBACK_CONF; - -extern FEEDBACK_CONF* notification_get_config_feedback(); - +extern char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len); +extern void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out); #endif