diff --git a/HISTORY b/HISTORY index 63da768..c96f635 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,8 @@ -Version 1.40 2018-08-16 +Version 1.40 2018-08-20 * add function conn_pool_parse_server_info and conn_pool_load_server_info + * support directive: #@add_annotation, for example: + #@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf Version 1.39 2018-07-31 * add #@function REPLACE_VARS diff --git a/src/ini_file_reader.c b/src/ini_file_reader.c index b44fec4..09dd424 100644 --- a/src/ini_file_reader.c +++ b/src/ini_file_reader.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "shared_func.h" #include "logger.h" #include "http_func.h" @@ -126,9 +127,13 @@ static void iniDoSetAnnotations(AnnotationEntry *src, const int src_count, } pDest->func_name = pSrc->func_name; + pDest->arg = pSrc->arg; pDest->func_init = pSrc->func_init; pDest->func_destroy = pSrc->func_destroy; pDest->func_get = pSrc->func_get; + pDest->func_free = pSrc->func_free; + pDest->dlhandle = pSrc->dlhandle; + pDest->inited = false; if (pDest == pDestEnd) //insert { ++(*dest_count); @@ -137,16 +142,43 @@ static void iniDoSetAnnotations(AnnotationEntry *src, const int src_count, } } -static int iniAnnotationFuncLocalIpGet(IniContext *context, char *param, - char **pOutValue, int max_values) + +static AnnotationEntry *iniFindAnnotation(AnnotationEntry *annotatios, + const char *func_name) +{ + AnnotationEntry *pAnnoEntry; + + if (annotatios == NULL) + { + return NULL; + } + + pAnnoEntry = annotatios; + while (pAnnoEntry->func_name != NULL) + { + if (strcmp(func_name, pAnnoEntry->func_name) == 0) + { + return pAnnoEntry; + } + pAnnoEntry++; + } + + return NULL; +} + +static int iniAnnotationFuncLocalIpGet(IniContext *context, + struct ini_annotation_entry *annotation, + const IniItem *item, char **pOutValue, int max_values) { bool need_private_ip; int count; int index; + char param[FAST_INI_ITEM_VALUE_SIZE]; const char *next_ip; char *square_start; char name_part[16]; + strcpy(param, item->value); memset(name_part, 0, sizeof(name_part)); square_start = strchr(param, '['); if (square_start != NULL && param[strlen(param) - 1] == ']') { @@ -197,8 +229,9 @@ static int iniAnnotationFuncLocalIpGet(IniContext *context, char *param, return count; } -static int iniAnnotationFuncShellExec(IniContext *context, char *param, - char **pOutValue, int max_values) +static int iniAnnotationFuncShellExec(IniContext *context, + struct ini_annotation_entry *annotation, + const IniItem *item, char **pOutValue, int max_values) { int count; int result; @@ -213,24 +246,24 @@ static int iniAnnotationFuncShellExec(IniContext *context, char *param, return count; } - if ((result=getExecResult(param, output, FAST_INI_ITEM_VALUE_SIZE)) != 0) + if ((result=getExecResult(item->value, output, FAST_INI_ITEM_VALUE_SIZE)) != 0) { logWarning("file: "__FILE__", line: %d, " "exec %s fail, errno: %d, error info: %s", - __LINE__, param, result, STRERROR(result)); + __LINE__, item->value, result, STRERROR(result)); free(output); return count; } if (*output == '\0') { logWarning("file: "__FILE__", line: %d, " - "empty reply when exec: %s", __LINE__, param); + "empty reply when exec: %s", __LINE__, item->value); } pOutValue[count++] = fc_trim(output); return count; } -static int iniCopyBuffer(char *dest, const int size, char *src, int len) +static int iniCopyBuffer(char *dest, const int size, const char *src, int len) { if (len == 0) { return 0; @@ -252,18 +285,19 @@ static int iniCopyBuffer(char *dest, const int size, char *src, int len) return len; } -static char *doReplaceVars(IniContext *pContext, char *param, const int max_size) +static char *doReplaceVars(IniContext *pContext, const char *param, + const int max_size) { #define VARIABLE_TAG_MIN_LENGTH 4 //%{v} SetDirectiveVars *set; - char *p; - char *e; + const char *p; + const char *e; char name[64]; - char *start; - char *value; - char *pLoopEnd; - char *pEnd; + const char *start; + const char *value; + const char *pLoopEnd; + const char *pEnd; char *pDest; char *output; int name_len; @@ -351,11 +385,12 @@ static char *doReplaceVars(IniContext *pContext, char *param, const int max_size return output; } -static int iniAnnotationReplaceVars(IniContext *pContext, char *param, - char **pOutValue, int max_values) +static int iniAnnotationReplaceVars(IniContext *pContext, + struct ini_annotation_entry *annotation, + const IniItem *item, char **pOutValue, int max_values) { char *output; - output = doReplaceVars(pContext, param, FAST_INI_ITEM_VALUE_SIZE); + output = doReplaceVars(pContext, item->value, FAST_INI_ITEM_VALUE_SIZE); if (output == NULL) { return 0; } @@ -365,7 +400,8 @@ static int iniAnnotationReplaceVars(IniContext *pContext, char *param, } } -static void iniAnnotationFuncFree(char **values, const int count) +void iniAnnotationFreeValues(struct ini_annotation_entry *annotation, + char **values, const int count) { int i; for (i=0; ifunc_name = "LOCAL_IP_GET"; - pAnnotation->func_init = NULL; - pAnnotation->func_destroy = NULL; pAnnotation->func_get = iniAnnotationFuncLocalIpGet; - pAnnotation->func_free = NULL; pAnnotation++; pAnnotation->func_name = "REPLACE_VARS"; - pAnnotation->func_init = NULL; - pAnnotation->func_destroy = NULL; pAnnotation->func_get = iniAnnotationReplaceVars; - pAnnotation->func_free = iniAnnotationFuncFree; + pAnnotation->func_free = iniAnnotationFreeValues; pAnnotation++; if ((pContext->flags & FAST_INI_FLAGS_SHELL_EXECUTE) != 0) { pAnnotation->func_name = "SHELL_EXEC"; - pAnnotation->func_init = NULL; - pAnnotation->func_destroy = NULL; pAnnotation->func_get = iniAnnotationFuncShellExec; - pAnnotation->func_free = iniAnnotationFuncFree; + pAnnotation->func_free = iniAnnotationFreeValues; pAnnotation++; } @@ -443,10 +473,9 @@ static int iniSetAnnotations(IniContext *pContext, const char annotation_type, return 0; } -int iniSetAnnotationCallBack(AnnotationEntry *map, int count) +int iniSetAnnotationCallBack(AnnotationEntry *annotations, int count) { int bytes; - AnnotationEntry *pDest; if (count <= 0) { @@ -466,34 +495,33 @@ int iniSetAnnotationCallBack(AnnotationEntry *map, int count) return ENOMEM; } - iniDoSetAnnotations(map, count, g_annotations, &g_annotation_count); - - pDest = g_annotations + g_annotation_count; - pDest->func_name = NULL; - pDest->func_init = NULL; - pDest->func_destroy = NULL; - pDest->func_get = NULL; - + memset(g_annotations + g_annotation_count, 0, + sizeof(AnnotationEntry) * (count + 1)); + iniDoSetAnnotations(annotations, count, g_annotations, &g_annotation_count); return 0; } void iniDestroyAnnotationCallBack() { - AnnotationEntry *pAnnoMap; + AnnotationEntry *pAnnoEntry; if (g_annotations == NULL) { return; } - pAnnoMap = g_annotations; - while (pAnnoMap->func_name) + pAnnoEntry = g_annotations; + while (pAnnoEntry->func_name) { - if (pAnnoMap->func_destroy != NULL) + if (pAnnoEntry->func_destroy != NULL) { - pAnnoMap->func_destroy(); + pAnnoEntry->func_destroy(pAnnoEntry); } - pAnnoMap++; + if (pAnnoEntry->dlhandle != NULL) + { + dlclose(pAnnoEntry->dlhandle); + } + pAnnoEntry++; } free(g_annotations); @@ -558,6 +586,43 @@ int iniLoadFromFile(const char *szFilename, IniContext *pContext) NULL, 0, FAST_INI_FLAGS_NONE); } +static void iniDestroyAnnotations(const int old_annotation_count) +{ + AnnotationEntry *pAnnoEntry; + + if (g_annotations == NULL) + { + return; + } + + logDebug("iniDestroyAnnotations, old_annotation_count: %d, " + "g_annotation_count: %d", + old_annotation_count, g_annotation_count); + if (old_annotation_count == 0) + { + iniDestroyAnnotationCallBack(); + return; + } + + pAnnoEntry = g_annotations + old_annotation_count; + while (pAnnoEntry->func_name) + { + if (pAnnoEntry->func_destroy != NULL) + { + pAnnoEntry->func_destroy(pAnnoEntry); + } + if (pAnnoEntry->dlhandle != NULL) + { + dlclose(pAnnoEntry->dlhandle); + } + pAnnoEntry++; + } + + memset(g_annotations + old_annotation_count, 0, + sizeof(AnnotationEntry) * (g_annotation_count - old_annotation_count)); + g_annotation_count = old_annotation_count; +} + int iniLoadFromFileEx(const char *szFilename, IniContext *pContext, const char annotation_type, AnnotationEntry *annotations, const int count, const char flags) @@ -566,6 +631,7 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext, int len; char *pLast; char full_filename[MAX_PATH_SIZE]; + int old_annotation_count; if ((result=iniInitContext(pContext, annotation_type, annotations, count, flags)) != 0) @@ -646,7 +712,13 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext, } } + old_annotation_count = g_annotation_count; result = iniDoLoadFromFile(full_filename, pContext); + if (g_annotation_count > old_annotation_count) + { + iniDestroyAnnotations(old_annotation_count); + } + if (result == 0) { iniSortItems(pContext); @@ -710,6 +782,7 @@ int iniLoadFromBufferEx(char *content, IniContext *pContext, const char flags) { int result; + int old_annotation_count; if ((result=iniInitContext(pContext, annotation_type, annotations, count, flags)) != 0) @@ -717,7 +790,13 @@ int iniLoadFromBufferEx(char *content, IniContext *pContext, return result; } + old_annotation_count = g_annotation_count; result = iniLoadItemsFromBuffer(content, pContext); + if (g_annotation_count > old_annotation_count) + { + iniDestroyAnnotations(old_annotation_count); + } + if (result == 0) { iniSortItems(pContext); @@ -737,6 +816,128 @@ int iniLoadFromBuffer(char *content, IniContext *pContext) NULL, 0, FAST_INI_FLAGS_NONE); } + +typedef int (*init_annotation_func0)(AnnotationEntry *annotation); +typedef int (*init_annotation_func1)(AnnotationEntry *annotation, + const char *arg1); +typedef int (*init_annotation_func2)(AnnotationEntry *annotation, + const char *arg1, const char *arg2); +typedef int (*init_annotation_func3)(AnnotationEntry *annotation, + const char *arg1, const char *arg2, const char *arg3); + +static int iniAddAnnotation(char *params) +{ +#define MAX_PARAMS 5 + char *cols[MAX_PARAMS]; + char *func_name; + char *library; + AnnotationEntry annotation; + void *dlhandle; + void *init_func; + char symbol[64]; + int argc; + int count; + int result; + + trim(params); + count = splitEx(params, ' ', cols, MAX_PARAMS); + if (count < 2) + { + logError("file: "__FILE__", line: %d, " + "invalid format, correct format: " + "#@add_annotation FUNC_NAME library ...", __LINE__); + return EINVAL; + } + + func_name = fc_trim(cols[0]); + library = fc_trim(cols[1]); + if (func_name == '\0') + { + logError("file: "__FILE__", line: %d, " + "empty func name, correct format: " + "#@add_annotation FUNC_NAME library ...", __LINE__); + return EINVAL; + } + if (library == '\0') + { + logError("file: "__FILE__", line: %d, " + "empty library, correct format: " + "#@add_annotation FUNC_NAME library ...", __LINE__); + return EINVAL; + } + + if (iniFindAnnotation(g_annotations, func_name) != NULL) + { + logWarning("file: "__FILE__", line: %d, " + "function %s already exist", __LINE__, func_name); + return EEXIST; + } + + if (strcmp(library, "-") == 0) + { + library = NULL; + } + else if (!fileExists(library)) + { + logError("file: "__FILE__", line: %d, " + "library %s not exist", __LINE__, library); + return ENOENT; + } + + dlhandle = dlopen(library, RTLD_LAZY); + if (dlhandle == NULL) + { + logError("file: "__FILE__", line: %d, " + "dlopen %s fail, error info: %s", + __LINE__, library != NULL ? library : "", + dlerror()); + return EFAULT; + } + + snprintf(symbol, sizeof(symbol), "%s_init_annotation", func_name); + init_func = dlsym(dlhandle, symbol); + if (init_func == NULL) + { + logError("file: "__FILE__", line: %d, " + "dlsym function %s fail, error info: %s", + __LINE__, symbol, dlerror()); + dlclose(dlhandle); + return ENOENT; + } + + memset(&annotation, 0, sizeof(annotation)); + argc = count - 2; + switch (argc) + { + case 0: + result = ((init_annotation_func0)init_func)(&annotation); + break; + case 1: + result = ((init_annotation_func1)init_func)(&annotation, cols[2]); + break; + case 2: + result = ((init_annotation_func2)init_func)(&annotation, + cols[2], cols[3]); + break; + case 3: + result = ((init_annotation_func3)init_func)(&annotation, + cols[2], cols[3], cols[4]); + break; + } + + if (result != 0) + { + logError("file: "__FILE__", line: %d, " + "call function %s fail, ret: %d", + __LINE__, symbol, result); + dlclose(dlhandle); + return EFAULT; + } + + annotation.dlhandle = dlhandle; + return iniSetAnnotationCallBack(&annotation, 1); +} + static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext) { IniSection *pSection; @@ -844,11 +1045,15 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext) free(pIncludeFilename); continue; } - else if ((*pLine == '#' && \ - strncasecmp(pLine+1, "@function", 9) == 0 && \ - (*(pLine+10) == ' ' || *(pLine+10) == '\t'))) + else if (*pLine == '#') { - if (pContext->annotation_type != FAST_INI_ANNOTATION_DISABLE) + if (pContext->annotation_type == FAST_INI_ANNOTATION_DISABLE) + { + continue; + } + + if (strncasecmp(pLine+1, "@function", 9) == 0 && + (*(pLine+10) == ' ' || *(pLine+10) == '\t')) { nNameLen = strlen(pLine + 11); if (nNameLen > FAST_INI_ITEM_NAME_LEN) @@ -870,6 +1075,16 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext) __LINE__); } } + else if (strncasecmp(pLine+1, "@add_annotation", 15) == 0 && + (*(pLine+16) == ' ' || *(pLine+16) == '\t')) + { + result = iniAddAnnotation(pLine + 17); + if (!(result == 0 || result == EEXIST)) + { + break; + } + } + continue; } @@ -985,16 +1200,15 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext) if (isAnnotation) { - AnnotationEntry *pAnnoMapBase; - AnnotationEntry *pAnnoMap = NULL; - bool found; + AnnotationEntry *pAnnoEntryBase; + AnnotationEntry *pAnnoEntry = NULL; isAnnotation = 0; - if ((pAnnoMapBase=iniGetAnnotations(pContext)) == NULL) + if ((pAnnoEntryBase=iniGetAnnotations(pContext)) == NULL) { - pAnnoMapBase = g_annotations; + pAnnoEntryBase = g_annotations; } - if (pAnnoMapBase == NULL) + if (pAnnoEntryBase == NULL) { logWarning("file: "__FILE__", line: %d, " \ "not set annotationMap and (%s) will use " \ @@ -1005,38 +1219,29 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext) continue; } - found = false; nItemCnt = -1; for (i=0; i<2; i++) { - pAnnoMap = pAnnoMapBase; - while (pAnnoMap->func_name != NULL) + pAnnoEntry = iniFindAnnotation(pAnnoEntryBase, pFuncName); + if (pAnnoEntry != NULL) { - if (strcmp(pFuncName, pAnnoMap->func_name) == 0) + if (pAnnoEntry->func_init != NULL && !pAnnoEntry->inited) { - if (pAnnoMap->func_init != NULL) - { - pAnnoMap->func_init(); - } - - if (pAnnoMap->func_get != NULL) - { - nItemCnt = pAnnoMap->func_get(pContext, - pItem->value, pItemValues, 100); - } - found = true; - break; + pAnnoEntry->inited = true; + pAnnoEntry->func_init(pAnnoEntry); } - pAnnoMap++; - } - if (found) - { + if (pAnnoEntry->func_get != NULL) + { + nItemCnt = pAnnoEntry->func_get(pContext, + pAnnoEntry, pItem, pItemValues, 100); + } break; } - if (g_annotations != NULL && pAnnoMapBase != g_annotations) + + if (g_annotations != NULL && pAnnoEntryBase != g_annotations) { - pAnnoMapBase = g_annotations; + pAnnoEntryBase = g_annotations; } else { @@ -1094,9 +1299,9 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext) } } - if (pAnnoMap != NULL && pAnnoMap->func_free != NULL) + if (pAnnoEntry != NULL && pAnnoEntry->func_free != NULL) { - pAnnoMap->func_free(pItemValues, nItemCnt); + pAnnoEntry->func_free(pAnnoEntry, pItemValues, nItemCnt); } continue; } diff --git a/src/ini_file_reader.h b/src/ini_file_reader.h index 2f11d34..d2eb8b2 100644 --- a/src/ini_file_reader.h +++ b/src/ini_file_reader.h @@ -60,10 +60,20 @@ typedef struct ini_context typedef struct ini_annotation_entry { char *func_name; - int (*func_init) (); - void (*func_destroy) (); - int (*func_get) (IniContext *context, char *param, char **pOutValue, int max_values); - void (*func_free) (char **values, const int count); + void *arg; + void *dlhandle; + + int (*func_init) (struct ini_annotation_entry *annotation); + void (*func_destroy) (struct ini_annotation_entry *annotation); + int (*func_get) (IniContext *context, + struct ini_annotation_entry *annotation, + const IniItem *item, + char **pOutValue, int max_values); + + void (*func_free) (struct ini_annotation_entry *annotation, + char **values, const int count); + + bool inited; } AnnotationEntry; #ifdef __cplusplus @@ -76,9 +86,12 @@ extern "C" { strcasecmp(pValue, "on") == 0 || \ strcmp(pValue, "1") == 0) -int iniSetAnnotationCallBack(AnnotationEntry *map, int count); +int iniSetAnnotationCallBack(AnnotationEntry *annotations, int count); void iniDestroyAnnotationCallBack(); +void iniAnnotationFreeValues(struct ini_annotation_entry *annotation, + char **values, const int count); + /** load ini items from file * parameters: * szFilename: the filename, can be an URL diff --git a/src/tests/test.ini b/src/tests/test.ini index 0464305..9215d26 100644 --- a/src/tests/test.ini +++ b/src/tests/test.ini @@ -1,6 +1,10 @@ # to support #@function CONFIG_GET +# the version of libshmcache >= 1.0.7 #@add_annotation CONFIG_GET /usr/local/lib/libshmcache.so /usr/local/etc/libshmcache.conf +#@function CONFIG_GET +app.version = app1.key1 + #@set author_name = yuqing #@set os_name = $(uname -a | awk '{print $1;}') @@ -8,7 +12,7 @@ host = hostname #@function LOCAL_IP_GET -bind_ip = inner +bind_ip = inner[0] #@function EXPRESS_CALC thread_count = 5 * 4 + 6 diff --git a/src/tests/test_ini_parser.c b/src/tests/test_ini_parser.c index b982213..388cae9 100644 --- a/src/tests/test_ini_parser.c +++ b/src/tests/test_ini_parser.c @@ -11,7 +11,8 @@ #include "fastcommon/shared_func.h" #include "fastcommon/ini_file_reader.h" -static int iniAnnotationFuncExpressCalc(IniContext *context, char *param, +static int iniAnnotationFuncExpressCalc(IniContext *context, + struct ini_annotation_entry *annotation, const IniItem *item, char **pOutValue, int max_values) { int count; @@ -20,7 +21,7 @@ static int iniAnnotationFuncExpressCalc(IniContext *context, char *param, static char output[256]; count = 0; - sprintf(cmd, "echo \'%s\' | bc -l", param); + sprintf(cmd, "echo \'%s\' | bc -l", item->value); if ((result=getExecResult(cmd, output, sizeof(output))) != 0) { logWarning("file: "__FILE__", line: %d, " @@ -31,7 +32,7 @@ static int iniAnnotationFuncExpressCalc(IniContext *context, char *param, if (*output == '\0') { logWarning("file: "__FILE__", line: %d, " - "empty reply when exec: %s", __LINE__, param); + "empty reply when exec: %s", __LINE__, item->value); } pOutValue[count++] = fc_trim(output); return count; @@ -50,11 +51,9 @@ int main(int argc, char *argv[]) log_init(); + memset(annotations, 0, sizeof(annotations)); annotations[0].func_name = "EXPRESS_CALC"; - annotations[0].func_init = NULL; - annotations[0].func_destroy = NULL; annotations[0].func_get = iniAnnotationFuncExpressCalc; - annotations[0].func_free = NULL; //printf("sizeof(IniContext): %d\n", (int)sizeof(IniContext)); result = iniLoadFromFileEx(szFilename, &context, @@ -66,7 +65,7 @@ int main(int argc, char *argv[]) } iniPrintItems(&context); - + iniDestroyAnnotationCallBack(); iniFreeContext(&context); return 0; }