/* * Copyright (c) 2020 YuQing <384681@qq.com> * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the Lesser GNU General Public License, version 3 * or later ("LGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the Lesser GNU General Public License * along with this program. If not, see . */ #ifndef SHARED_FUNC_H #define SHARED_FUNC_H #include #include #include #include #include #include #include #include #include #include "common_define.h" #ifdef OS_LINUX #include #endif #include "fc_memory.h" #include "ini_file_reader.h" #define NORMALIZE_FLAGS_URL_ENABLED 1 #define NORMALIZE_FLAGS_URL_APPEND_PARAMS 2 #define NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS \ (NORMALIZE_FLAGS_URL_ENABLED | NORMALIZE_FLAGS_URL_APPEND_PARAMS) #define FC_SET_CLOEXEC(fd) \ if (g_set_cloexec) fd_set_cloexec(fd) #ifdef __cplusplus extern "C" { #endif extern bool g_set_cloexec; extern const char *g_lower_hex_chars; extern const char *g_upper_hex_chars; static inline void fc_enable_fd_cloexec(const bool cloexec) { g_set_cloexec = cloexec; } /** lowercase the string * parameters: * src: input string, will be changed * return: lowercased string */ char *toLowercase(char *src); /** uppercase the string * parameters: * src: input string, will be changed * return: uppercased string */ char *toUppercase(char *src); /** date format to string * parameters: * nTime: unix timestamp * szDateFormat: date format, more detail man strftime * buff: store the formated result, can be NULL * buff_size: buffer size, max bytes can contain * return: formated date string */ char *formatDatetime(const time_t nTime, \ const char *szDateFormat, \ char *buff, const int buff_size); /** get character count, only support GB charset * parameters: * s: the string * return: character count */ int getCharLen(const char *s); /** string replace * parameters: * src: the input string * old_str: the old string * new_str: the new string * dest: the output string * size: the size of output buffer * return: 0 for success, != 0 for fail */ int str_replace(const string_t *src, const string_t *old_str, const string_t *new_str, string_t *dest, const int size); /** replace \r and \n to space * parameters: * s: the string * return: replaced string */ char *replaceCRLF2Space(char *s); /** get the filename absolute path * parameters: * fileame: the filename * szAbsPath: store the absolute path * pathSize: max bytes to contain * return: absolute path, NULL for fail */ char *getAbsolutePath(const char *fileame, char *szAbsPath, \ const int pathSize); /** get the executable file absolute filename * parameters: * exeFilename: the executable filename * szAbsFilename: store the absolute filename * maxSize: max bytes to contain * return: absolute filename, NULL for fail */ char *getExeAbsoluteFilename(const char *exeFilename, char *szAbsFilename, \ const int maxSize); #ifndef WIN32 /** get running process count by program name such as fdfs_trackerd * parameters: * progName: the program name * bAllOwners: false for only get my proccess count * return: proccess count, >= 0 success, < 0 fail */ int getProccessCount(const char *progName, const bool bAllOwners); /** get running process ids by program name such as fdfs_trackerd * parameters: * progName: the program name * bAllOwners: false for only get my proccess count * pids: store the pids * arrSize: max pids * return: proccess count, >= 0 success, < 0 fail */ int getUserProcIds(const char *progName, const bool bAllOwners, \ int pids[], const int arrSize); /** execute program, get it's output * parameters: * command: the program * output: store ouput result * buff_size: output max size (bytes) * return: error no, 0 success, != 0 fail */ int getExecResult(const char *command, char *output, const int buff_size); #endif /** daemon init * parameters: * bCloseFiles: if close the stdin, stdout and stderr * return: none */ void daemon_init(bool bCloseFiles); /** convert buffer content to hex string such as 0B82A1 * parameters: * s: the buffer * len: the buffer length * szHexBuff: store the hex string (must have enough space) * return: hex string (szHexBuff) */ char *bin2hex(const char *s, const int len, char *szHexBuff); /** parse hex string to binary content * parameters: * s: the hex string such as 8B04CD * szBinBuff: store the converted binary content(must have enough space) * nDestLen: store the converted content length * return: converted binary content (szBinBuff) */ char *hex2bin(const char *s, char *szBinBuff, int *nDestLen); /** print binary buffer as hex string * parameters: * s: the buffer * len: the buffer length * return: none */ void printBuffHex(const char *s, const int len); /** 16 bits int convert to buffer (big-endian) * parameters: * n: 16 bits int value * buff: the buffer, at least 2 bytes space, no tail \0 * return: none */ static inline void short2buff(const short n, char *buff) { unsigned char *p; p = (unsigned char *)buff; *p++ = (n >> 8) & 0xFF; *p++ = n & 0xFF; } /** buffer convert to 16 bits int * parameters: * buff: big-endian 2 bytes buffer * return: 16 bits int value */ static inline short buff2short(const char *buff) { return (short)((((unsigned char)(*(buff))) << 8) | ((unsigned char)(*(buff+1)))); } /** 32 bits int convert to buffer (big-endian) * parameters: * n: 32 bits int value * buff: the buffer, at least 4 bytes space, no tail \0 * return: none */ static inline void int2buff(const int n, char *buff) { unsigned char *p; p = (unsigned char *)buff; *p++ = (n >> 24) & 0xFF; *p++ = (n >> 16) & 0xFF; *p++ = (n >> 8) & 0xFF; *p++ = n & 0xFF; } /** buffer convert to 32 bits int * parameters: * buff: big-endian 4 bytes buffer * return: 32 bits int value */ static inline int buff2int(const char *buff) { return (((unsigned char)(*buff)) << 24) | (((unsigned char)(*(buff+1))) << 16) | (((unsigned char)(*(buff+2))) << 8) | ((unsigned char)(*(buff+3))); } /** long (64 bits) convert to buffer (big-endian) * parameters: * n: 64 bits int value * buff: the buffer, at least 8 bytes space, no tail \0 * return: none */ static inline void long2buff(int64_t n, char *buff) { unsigned char *p; p = (unsigned char *)buff; *p++ = (n >> 56) & 0xFF; *p++ = (n >> 48) & 0xFF; *p++ = (n >> 40) & 0xFF; *p++ = (n >> 32) & 0xFF; *p++ = (n >> 24) & 0xFF; *p++ = (n >> 16) & 0xFF; *p++ = (n >> 8) & 0xFF; *p++ = n & 0xFF; } /** buffer convert to 64 bits int * parameters: * buff: big-endian 8 bytes buffer * return: 64 bits int value */ static inline int64_t buff2long(const char *buff) { unsigned char *p; p = (unsigned char *)buff; return (((int64_t)(*p)) << 56) | (((int64_t)(*(p+1))) << 48) | (((int64_t)(*(p+2))) << 40) | (((int64_t)(*(p+3))) << 32) | (((int64_t)(*(p+4))) << 24) | (((int64_t)(*(p+5))) << 16) | (((int64_t)(*(p+6))) << 8) | ((int64_t)(*(p+7))); } /** 32 bits float convert to buffer (big-endian) * parameters: * n: 32 bits float value * buff: the buffer, at least 4 bytes space, no tail \0 * return: none */ static inline void float2buff(float f, char *buff) { int *p; p = (int *)&f; int2buff(*p, buff); } /** buffer convert to 32 bits float * parameters: * buff: big-endian 8 bytes buffer * return: 32 bits float value */ static inline float buff2float(const char *buff) { int n; float *p; n = buff2int(buff); p = (float *)&n; return *p; } /** double (64 bits) convert to buffer (big-endian) * parameters: * n: 64 bits double value * buff: the buffer, at least 8 bytes space, no tail \0 * return: none */ static inline void double2buff(double d, char *buff) { int64_t *p; p = (int64_t *)&d; long2buff(*p, buff); } /** buffer convert to 64 bits double * parameters: * buff: big-endian 8 bytes buffer * return: 64 bits double value */ static inline double buff2double(const char *buff) { int64_t n; double *p; n = buff2long(buff); p = (double *)&n; return *p; } static inline int padding_hex(char *buff, const int len, const int padding_len) { char *p; char *end; char *stop; int new_len; int fill_len; if (padding_len == len) { return len; } else if (padding_len > len) { fill_len = padding_len - len; memmove(buff + fill_len, buff, len + 1); memset(buff, '0', fill_len); return padding_len; } else if (*buff != '0') { return len; } end = buff + len; if (padding_len <= 0) { stop = end - 1; } else { stop = end - padding_len; } p = buff + 1; while (p < stop && *p == '0') { ++p; } new_len = end - p; memmove(buff, p, new_len + 1); return new_len; } static inline int short2hex(const short n, char *buff, const int padding_len) { unsigned char *p; p = (unsigned char *)buff; *p++ = g_lower_hex_chars[(n >> 12) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 8) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 4) & 0x0F]; *p++ = g_lower_hex_chars[n & 0x0F]; *p = '\0'; return padding_hex(buff, 4, padding_len); } static inline int short2HEX(const short n, char *buff, const int padding_len) { unsigned char *p; p = (unsigned char *)buff; *p++ = g_upper_hex_chars[(n >> 12) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 8) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 4) & 0x0F]; *p++ = g_upper_hex_chars[n & 0x0F]; *p = '\0'; return padding_hex(buff, 4, padding_len); } static inline int int2hex(const int n, char *buff, const int padding_len) { unsigned char *p; p = (unsigned char *)buff; *p++ = g_lower_hex_chars[(n >> 28) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 24) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 20) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 16) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 12) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 8) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 4) & 0x0F]; *p++ = g_lower_hex_chars[n & 0x0F]; *p = '\0'; return padding_hex(buff, 8, padding_len); } static inline int int2HEX(const int n, char *buff, const int padding_len) { unsigned char *p; p = (unsigned char *)buff; *p++ = g_upper_hex_chars[(n >> 28) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 24) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 20) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 16) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 12) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 8) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 4) & 0x0F]; *p++ = g_upper_hex_chars[n & 0x0F]; *p = '\0'; return padding_hex(buff, 8, padding_len); } static inline int long2hex(const int64_t n, char *buff, const int padding_len) { unsigned char *p; p = (unsigned char *)buff; *p++ = g_lower_hex_chars[(n >> 60) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 56) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 52) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 48) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 44) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 40) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 36) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 32) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 28) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 24) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 20) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 16) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 12) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 8) & 0x0F]; *p++ = g_lower_hex_chars[(n >> 4) & 0x0F]; *p++ = g_lower_hex_chars[n & 0x0F]; *p = '\0'; return padding_hex(buff, 16, padding_len); } static inline int long2HEX(const int64_t n, char *buff, const int padding_len) { unsigned char *p; p = (unsigned char *)buff; *p++ = g_upper_hex_chars[(n >> 60) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 56) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 52) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 48) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 44) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 40) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 36) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 32) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 28) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 24) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 20) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 16) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 12) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 8) & 0x0F]; *p++ = g_upper_hex_chars[(n >> 4) & 0x0F]; *p++ = g_upper_hex_chars[n & 0x0F]; *p = '\0'; return padding_hex(buff, 16, padding_len); } /** trim leading spaces ( \t\r\n) * parameters: * pStr: the string to trim * return: trimed string porinter as pStr */ char *trim_left(char *pStr); /** trim tail spaces ( \t\r\n) * parameters: * pStr: the string to trim * return: trimed string porinter as pStr */ char *trim_right(char *pStr); /** trim leading and tail spaces ( \t\r\n) * parameters: * pStr: the string to trim * return: trimed string porinter as pStr */ static inline char *fc_trim(char *pStr) { trim_right(pStr); trim_left(pStr); return pStr; } /** trim leading spaces ( \t\r\n) * parameters: * s: the string to trim * return: none */ void string_ltrim(string_t *s); /** trim tail spaces ( \t\r\n) * parameters: * s: the string to trim * return: none */ void string_rtrim(string_t *s); #define FC_STRING_TRIM(s) \ do { \ string_ltrim(s); \ string_rtrim(s); \ } while (0) static inline void string_trim(string_t *s) { FC_STRING_TRIM(s); } /** copy string to BufferInfo * parameters: * pBuff: the dest buffer * str: source string * return: error no, 0 success, != 0 fail */ int buffer_strcpy(BufferInfo *pBuff, const char *str); /** copy binary buffer to BufferInfo * parameters: * pBuff: the dest buffer * buff: source buffer * len: source buffer length * return: error no, 0 success, != 0 fail */ int buffer_memcpy(BufferInfo *pBuff, const char *buff, const int len); /** url encode * parameters: * src: the source string to encode * src_len: source string length * dest: store dest string * dest_len: store the dest string length * return: error no, 0 success, != 0 fail */ char *urlencode(const char *src, const int src_len, char *dest, int *dest_len); /** url decode, terminated with \0 * parameters: * src: the source string to decode * src_len: source string length * dest: store dest string * dest_len: store the dest string length * return: error no, 0 success, != 0 fail */ char *urldecode(const char *src, const int src_len, char *dest, int *dest_len); /** url decode, no terminate with \0 * parameters: * src: the source string to decode * src_len: source string length * dest: store dest string * dest_len: store the dest string length * return: error no, 0 success, != 0 fail */ char *urldecode_ex(const char *src, const int src_len, char *dest, int *dest_len); /** get char occurs count * parameters: * src: the source string * seperator: find this char occurs times * return: char occurs count */ int getOccurCount(const char *src, const char seperator); /** get the file line count * parameters: * filename: the filename * until_offset: util the file offset, -1 for file end * line_count: store the line count * return: error no, 0 success, != 0 fail */ int fc_get_file_line_count_ex(const char *filename, const int64_t until_offset, int64_t *line_count); static inline int fc_get_file_line_count(const char *filename, int64_t *line_count) { const int64_t until_offset = -1; return fc_get_file_line_count_ex(filename, until_offset, line_count); } /** split string * parameters: * src: the source string, will be modified by this function * seperator: seperator char * nMaxCols: max columns (max split count) * nColCount: store the columns (array elements) count * return: string array, should call freeSplit to free, return NULL when fail */ char **split(char *src, const char seperator, const int nMaxCols, \ int *nColCount); /** free split results * parameters: * p: return by function split * return: none */ void freeSplit(char **p); /** split string * parameters: * src: the source string, will be modified by this function * seperator: seperator char * pCols: store split strings * nMaxCols: max columns (max split count) * return: string array / column count */ int splitEx(char *src, const char seperator, char **pCols, const int nMaxCols); /** split string * parameters: * src: the source string * seperator: seperator char * dest: store split strings * max_count: max split count * ignore_empty: if ignore empty string * return: string array count */ int split_string_ex(const string_t *src, const char seperator, string_t *dest, const int max_count, const bool ignore_empty); /** split string by delimiter characters * parameters: * src: the source string, will be modified by this function * delim: the delimiter characters * pCols: store split strings * nMaxCols: max columns (max split count) * return: string array / column count */ int fc_split_string(char *src, const char *delim, char **pCols, const int nMaxCols); /** if the input string contains all delimiter characters * parameters: * str: the input string * delim: the delimiter characters * return: true for contains all delimiter characters, otherwise false */ bool fc_match_delim(const char *str, const char *delim); /** split string * parameters: * src: the source string, will be modified by this function * seperator: seperator char * pCols: store split strings * nMaxCols: max columns (max split count) * return: string array / column count */ int my_strtok(char *src, const char *delim, char **pCols, const int nMaxCols); /** check file exist * parameters: * filename: the filename * return: true if file exists, otherwise false */ bool fileExists(const char *filename); /** check if a directory * parameters: * filename: the filename * return: true for directory */ bool isDir(const char *filename); /** check if a regular file * parameters: * filename: the filename * return: true for regular file */ bool isFile(const char *filename); /** check if filename securty, /../ ocur in filename not allowed * parameters: * filename: the filename * len: filename length * return: true for regular file */ bool is_filename_secure(const char *filename, const int len); /** load log_level from config context * parameters: * pIniContext: the config context * return: none */ void load_log_level(IniContext *pIniContext); /** load log_level from config file * parameters: * conf_filename: the config filename * return: none */ int load_log_level_ex(const char *conf_filename); /** set global log level * parameters: * pLogLevel: the log level string value * return: none */ void set_log_level(char *pLogLevel); /** get log level by caption * parameters: * pLogLevel: the log level string value * default_value: the default log level * return: the log level integer value */ int get_log_level(char *pLogLevel, const int default_value); /** get log level caption * parameters: * log_level: the log level integer value * return: the log level caption */ const char *get_log_level_caption(const int log_level); /** load allow hosts from config context * parameters: * pIniContext: the config context * allow_ip_addrs: store allow ip addresses * allow_ip_count: store allow ip address count * return: error no , 0 success, != 0 fail */ int load_allow_hosts(IniContext *pIniContext, \ in_addr_64_t **allow_ip_addrs, int *allow_ip_count); /** get time item from config context * parameters: * ini_ctx: the full ini context * item_name: item name in config file, time format as hour:minute, such as 15:25 * pTimeInfo: store time info * default_hour: default hour value * default_minute: default minute value * bRetryGlobal: if fetch from global section when the item not exist * return: error no , 0 success, != 0 fail */ int get_time_item_from_conf_ex(IniFullContext *ini_ctx, const char *item_name, TimeInfo *pTimeInfo, const byte default_hour, const byte default_minute, const bool bRetryGlobal); /** get time item from config context * parameters: * pIniContext: the config context * item_name: item name in config file, time format as hour:minute, such as 15:25 * pTimeInfo: store time info * default_hour: default hour value * default_minute: default minute value * return: error no , 0 success, != 0 fail */ int get_time_item_from_conf(IniContext *pIniContext, \ const char *item_name, TimeInfo *pTimeInfo, \ const byte default_hour, const byte default_minute); /** get time item from string * parameters: * pValue: the time string, format as hour:minute, such as 15:25 * item_name: item name in config file * pTimeInfo: store time info * default_hour: default hour value * default_minute: default minute value * return: error no , 0 success, != 0 fail */ int get_time_item_from_str(const char *pValue, const char *item_name, TimeInfo *pTimeInfo, const byte default_hour, const byte default_minute); /** trim path tail char / * parameters: * filePath: the file path to chop * return: none */ void chopPath(char *filePath); /** remove redundant slashes * parameters: * src: the input path * dest: the output path * size: the max size of dest path * return: error no , 0 success, != 0 fail */ int fc_remove_redundant_slashes(const string_t *src, string_t *dest, const int size); static inline int fc_remove_redundant_slashes1(const char *input, string_t *dest, const int size) { string_t src; FC_SET_STRING(src, (char *)input); return fc_remove_redundant_slashes(&src, dest, size); } static inline int fc_remove_redundant_slashes2(const char *input, char *output, const int size) { string_t src; string_t dest; FC_SET_STRING(src, (char *)input); dest.str = output; return fc_remove_redundant_slashes(&src, &dest, size); } /** get file content by fd * parameters: * fd: the file descriptor * filename: the filename * buff: return the buff, must be freed * file_size: store the file size * return: error no , 0 success, != 0 fail */ int getFileContent1(int fd, const char *filename, char **buff, int64_t *file_size); /** get file content * parameters: * filename: the filename * buff: return the buff, must be freed * file_size: store the file size * return: error no , 0 success, != 0 fail */ int getFileContent(const char *filename, char **buff, int64_t *file_size); /** get file content * parameters: * fd: the file descriptor * filename: the filename * buff: the buff to store file content * offset: the start offset * size: specify the size to fetch and return the fetched size * return: error no , 0 success, != 0 fail */ int getFileContentEx1(int fd, const char *filename, char *buff, int64_t offset, int64_t *size); /** get file content * parameters: * filename: the filename * buff: the buff to store file content * offset: the start offset * size: specify the size to fetch and return the fetched size * return: error no , 0 success, != 0 fail */ int getFileContentEx(const char *filename, char *buff, \ int64_t offset, int64_t *size); /** get file size * parameters: * filename: the filename * file_size: store the file size * return: error no , 0 success, != 0 fail */ int getFileSize(const char *filename, int64_t *file_size); /** write to file * parameters: * filename: the filename to write * buff: the buffer to write * file_size: the file size * return: error no , 0 success, != 0 fail */ int writeToFile(const char *filename, const char *buff, const int file_size); /** safe write to file, first write to tmp file, then rename to true filename * parameters: * filename: the filename to write * buff: the buffer to write * file_size: the file size * return: error no , 0 success, != 0 fail */ int safeWriteToFile(const char *filename, const char *buff, \ const int file_size); /** get a line from file * parameters: * fd: the fd to read * buff: the buffer to store the line * size: the buffer max size * once_bytes: the bytes per read * return: error no , 0 success, != 0 fail */ int fd_gets(int fd, char *buff, const int size, int once_bytes); /** set unix rlimit * parameters: * resource: resource id, please see sys/resource.h * value: the value to set * return: error no , 0 success, != 0 fail */ int set_rlimit(int resource, const rlim_t value); /** fcntl add flags such as O_NONBLOCK or FD_CLOEXEC * parameters: * fd: the fd to set * get_cmd: the get command * set_cmd: the set command * adding_flags: the flags to add * return: error no , 0 success, != 0 fail */ int fcntl_add_flags(int fd, int get_cmd, int set_cmd, int adding_flags); /** set fd flags such as O_NONBLOCK * parameters: * fd: the fd to set * adding_flags: the flags to add * return: error no , 0 success, != 0 fail */ int fd_add_flags(int fd, int adding_flags); /** set non block mode * parameters: * fd: the fd to set * return: error no , 0 success, != 0 fail */ #define set_nonblock(fd) fd_add_flags(fd, O_NONBLOCK) /** set fd FD_CLOEXEC flags * parameters: * fd: the fd to set * return: error no , 0 success, != 0 fail */ int fd_set_cloexec(int fd); /** set run by group and user * parameters: * group_name: the group name, can be NULL or empty * username: the username, can be NULL or empty * return: error no , 0 success, != 0 fail */ int set_run_by(const char *group_name, const char *username); /** compare ip address, type is (in_addr_64_t *) * parameters: * p1: the first ip address * p2: the second ip address * return: > 0 when p1 > p2, 0 when p1 == p2, < 0 when p1 < p2 */ int cmp_by_ip_addr_t(const void *p1, const void *p2); int fc_compare_int64_ptr(const int64_t *n1, const int64_t *n2); /** parse bytes * parameters: * pStr: the string to parse * default_unit_bytes: default unit if not specified the unit like MB etc. * bytes: store the parsed bytes * return: error no , 0 success, != 0 fail */ int parse_bytes(const char *pStr, const int default_unit_bytes, int64_t *bytes); /** set rand seed * return: error no , 0 success, != 0 fail */ int set_rand_seed(); /** set timer wrapper * parameters: * first_remain_seconds: remain time for first time, in seconds * interval: the interval * sighandler: handler function * return: error no , 0 success, != 0 fail */ int set_timer(const int first_remain_seconds, const int interval, \ void (*sighandler)(int)); /** set file access and modified times * parameters: * filename: the file to modify times * new_time: the time to set * return: error no , 0 success, != 0 fail */ int set_file_utimes(const char *filename, const time_t new_time); /** ignore singal pipe (SIGPIPE) * return: error no , 0 success, != 0 fail */ int ignore_signal_pipe(); double get_line_distance_km(const double lat1, const double lon1, const double lat2, const double lon2); /** is private ip address for IPv4 * return: true for private ip, otherwise false */ bool is_private_ip(const char* ip); /** 从字符串中解析IP地址和端口号 * parameters: * src: the source string, will be modified by this function * parts: store split strings * return: string array / column count */ int parseAddress(char *src, char *parts[2]); /** get current time in ns * return: current time */ int64_t get_current_time_ns(); /** get current time in us * return: current time */ int64_t get_current_time_us(); #define get_current_time_ms() (get_current_time_us() / 1000) /** is the number power 2 * parameters: * n: the number to test * return: true for power 2, otherwise false */ static inline bool is_power2(const int64_t n) { return ((n != 0) && (n & (n - 1)) == 0); } /** set file read lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_read_lock(int fd); /** set file write lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_write_lock(int fd); /** file unlock * parameters: * fd: the file descriptor to unlock * return: error no, 0 for success, != 0 fail */ int file_unlock(int fd); /** try file read lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_try_read_lock(int fd); /** try file write lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_try_write_lock(int fd); /** try file unlock * parameters: * fd: the file descriptor to unlock * return: error no, 0 for success, != 0 fail */ int file_try_unlock(int fd); /** is a leading spaces line * parameters: * content: the whole string content * current: the current line * return: error no, 0 for success, != 0 fail */ bool isLeadingSpacesLine(const char *content, const char *current); /** is a trailing spaces line * parameters: * tail: the current line tail * end: the string end ptr * return: error no, 0 for success, != 0 fail */ bool isTrailingSpacesLine(const char *tail, const char *end); /** safe write wrapper * parameters: * fd: the fd to write * buf: the buffer * nbyte: the buffer length * return: written bytes for success, -1 when fail */ ssize_t fc_safe_write(int fd, const char *buf, const size_t nbyte); /** safe writev wrapper * parameters: * fd: the fd to write * iov: the iov array * iovcnt: the iov count * return: written bytes for success, -1 when fail */ ssize_t fc_safe_writev(int fd, const struct iovec *iov, int iovcnt); /** lock and write to file * parameters: * fd: the fd to write * buf: the buffer * nbyte: the buffer length * return: written bytes for success, -1 when fail */ ssize_t fc_lock_write(int fd, const char *buf, const size_t nbyte); /** read from file * parameters: * fd: the fd to read * buf: the buffer * count: expect read bytes * return: read bytes for success, -1 when fail */ ssize_t fc_safe_read(int fd, char *buf, const size_t count); /** read integral lines from file * parameters: * fd: the fd to read * buf: the buffer to store the line * size: max read bytes * return: error no , 0 success, != 0 fail */ ssize_t fc_read_lines(int fd, char *buf, const size_t size); /** ftok with hash code * parameters: * path: the file path * proj_id: the project id * return: read bytes for success, -1 when fail */ key_t fc_ftok(const char *path, const int proj_id); /** convert int to string * parameters: * n: the 32 bits integer * buff: output buffer * thousands_separator: if add thousands separator * return: string buffer */ const char *int2str(const int n, char *buff, const bool thousands_separator); static inline const char *int_to_comma_str(const int n, char *buff) { return int2str(n, buff, true); } /** convert long to string * parameters: * n: the 64 bits integer * buff: output buffer * thousands_separator: if add thousands separator * return: string buffer */ const char *long2str(const int64_t n, char *buff, const bool thousands_separator); static inline const char *long_to_comma_str(const int64_t n, char *buff) { return long2str(n, buff, true); } /** if the string starts with the needle string * parameters: * str: the string to detect * needle: the needle string * return: true for starts with the needle string, otherwise false */ bool starts_with(const char *str, const char *needle); /** if the string ends with the needle string * parameters: * str: the string to detect * needle: the needle string * return: true for ends with the needle string, otherwise false */ bool ends_with(const char *str, const char *needle); /** strdup extension * parameters: * str: the string to duplicate * len: the length of string * return: the duplicated string, NULL for fail */ char *fc_strdup1(const char *str, const int len); /** memmem * parameters: * str: the string to match * needle: the needle string * return: the matched string, NULL for fail */ const char *fc_memmem(const string_t *str, const string_t *needle); /** memmem * parameters: * str: the string to match * needle: the needle string * return: the matched string, NULL for fail */ const char *fc_memrchr(const char *str, const int ch, const int len); /** format HTTP Date as: Sat, 11 Mar 2017 21:49:51 GMT * parameters: * t: the time to format * buffer: the buffer * return: formatted GMT date string */ char *format_http_date(time_t t, BufferInfo *buffer); /** return full path for the filename (the second parameter) * parameters: * from: the input full path filename to get base path, * NULL for current work directory * filename: the filename to resolve path * full_filename: store the resolved full path filename * size: the max size of full_filename * return: length of the resolved full path */ int normalize_path(const string_t *from, const string_t *filename, char *full_filename, const int size); static inline int normalize_path1(const char *from, const char *filename, char *full_filename, const int size) { string_t from_string; string_t filename_string; FC_SET_STRING(from_string, (char *)from); FC_SET_STRING(filename_string, (char *)filename); return normalize_path(&from_string, &filename_string, full_filename, size); } /** return full path for the filename (the second parameter) * parameters: * from: the input full path filename to get base path * filename: the filename to resolve path * full_filename: store the resolved full path filename * size: the max size of full_filename * flags: * NORMALIZE_FLAGS_URL_ENABLED: support url resolve * NORMALIZE_FLAGS_URL_APPEND_PARAMS: append params of from * return: length of the resolved full path */ int normalize_path_ex(const string_t *from, const string_t *filename, char *full_filename, const int size, const int flags); static inline int resolve_path(const char *from, const char *filename, char *full_filename, const int size) { string_t from_string; string_t filename_string; FC_SET_STRING(from_string, (char *)from); FC_SET_STRING(filename_string, (char *)filename); return normalize_path_ex(&from_string, &filename_string, full_filename, size, NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS); } static inline int fc_combine_two_strings_ex( const char *first_str, const int first_len, const char *second_str, const int second_len, const char seperator, char *combined_str, const int size) { char *p; if (first_len + 1 + second_len >= size) { return snprintf(combined_str, size, "%s%c%s", first_str, seperator, second_str); } memcpy(combined_str, first_str, first_len); p = combined_str + first_len; if (seperator != '\0') { *p++ = seperator; } memcpy(p, second_str, second_len); p += second_len; *p = '\0'; return p - combined_str; } #define fc_combine_two_strings_s(first, second, seperator, combined, size) \ fc_combine_two_strings_ex(first, strlen(first), second, strlen(second), \ seperator, combined, size) #define fc_combine_two_strings(first, second, seperator, combined) \ fc_combine_two_strings_s(first, second, seperator, \ combined, sizeof(combined)) #define fc_concat_two_strings(first, second, combined) \ fc_combine_two_strings(first, second, '\0', combined) static inline int fc_get_full_filename_ex( const char *base_path_str, const int base_path_len, const char *filename_str, const int filename_len, char *full_filename, const int size) { const char seperator = '/'; return fc_combine_two_strings_ex(base_path_str, base_path_len, filename_str, filename_len, seperator, full_filename, size); } #define fc_get_full_filename(base_path_str, base_path_len, \ filename_str, filename_len, full_filename) \ fc_get_full_filename_ex(base_path_str, base_path_len, \ filename_str, filename_len, full_filename, sizeof(full_filename)) #define fc_combine_full_filename(base_path, filename, full_filename) \ fc_get_full_filename(base_path, strlen(base_path), \ filename, strlen(filename), full_filename) #define fc_get_full_filepath_ex(base_path_str, base_path_len, \ filepath_str, filepath_len, full_filename, size) \ fc_get_full_filename_ex(base_path_str, base_path_len, \ filepath_str, filepath_len, full_filename, size) #define fc_get_full_filepath(base_path_str, base_path_len, \ filepath_str, filepath_len, full_filename) \ fc_get_full_filename(base_path_str, base_path_len, \ filepath_str, filepath_len, full_filename) #define fc_combine_full_filepath(base_path, filepath, full_filename) \ fc_combine_full_filename(base_path, filepath, full_filename) static inline int fc_get_hex_subdir_filepath(const char *base_path, const int base_len, const int subdir_index, char *file_path) { const int padding_len = 2; char *p; memcpy(file_path, base_path, base_len); p = file_path + base_len; *p++ = '/'; if (subdir_index <= UINT8_MAX) { *p++ = g_upper_hex_chars[(subdir_index >> 4) & 0x0F]; *p++ = g_upper_hex_chars[subdir_index & 0x0F]; *p = '\0'; } else { if (subdir_index <= UINT16_MAX) { p += short2HEX(subdir_index, p, padding_len); } else { p += int2HEX(subdir_index, p, padding_len); } } return p - file_path; } static inline int fc_get_two_subdirs_full_filepath_ex( const char *base_path, const int base_len, const char *subdir_str1, const int subdir_len1, const char *subdir_str2, const int subdir_len2, char *file_path, const int size) { char *p; if (base_len + 1 + subdir_len1 + 1 + subdir_len2 >= size) { return snprintf(file_path, size, "%s/%s/%s", base_path, subdir_str1, subdir_str2); } memcpy(file_path, base_path, base_len); p = file_path + base_len; *p++ = '/'; memcpy(p, subdir_str1, subdir_len1); p += subdir_len1; *p++ = '/'; memcpy(p, subdir_str2, subdir_len2); p += subdir_len2; *p = '\0'; return p - file_path; } #define fc_get_two_subdirs_full_filepath(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, file_path) \ fc_get_two_subdirs_full_filepath_ex(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, \ file_path, sizeof(file_path)) #define fc_get_one_subdir_full_filename_ex(base_path, base_len, subdir_str, \ subdir_len, filename_str, filename_len, full_filename, size) \ fc_get_two_subdirs_full_filepath_ex(base_path, base_len, \ subdir_str, subdir_len, filename_str, filename_len, \ full_filename, size) #define fc_get_one_subdir_full_filename(base_path, base_len, subdir_str, \ subdir_len, filename_str, filename_len, full_filename) \ fc_get_one_subdir_full_filename_ex(base_path, base_len, \ subdir_str, subdir_len, filename_str, filename_len, \ full_filename, sizeof(full_filename)) static inline int fc_get_three_subdirs_full_filepath_ex( const char *base_path, const int base_len, const char *subdir_str1, const int subdir_len1, const char *subdir_str2, const int subdir_len2, const char *subdir_str3, const int subdir_len3, char *file_path, const int size) { char *p; if (base_len + 1 + subdir_len1 + 1 + subdir_len2 + subdir_len3 >= size) { return snprintf(file_path, size, "%s/%s/%s/%s", base_path, subdir_str1, subdir_str2, subdir_str3); } memcpy(file_path, base_path, base_len); p = file_path + base_len; *p++ = '/'; memcpy(p, subdir_str1, subdir_len1); p += subdir_len1; *p++ = '/'; memcpy(p, subdir_str2, subdir_len2); p += subdir_len2; *p++ = '/'; memcpy(p, subdir_str3, subdir_len3); p += subdir_len3; *p = '\0'; return p - file_path; } #define fc_get_three_subdirs_full_filepath(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, \ subdir_str3, subdir_len3, file_path) \ fc_get_three_subdirs_full_filepath_ex(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, \ subdir_str3, subdir_len3, file_path, sizeof(file_path)) #define fc_get_two_subdirs_full_filename_ex(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, \ filename_str, filename_len, full_filename, size) \ fc_get_three_subdirs_full_filepath_ex(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, \ filename_str, filename_len, full_filename, size) #define fc_get_two_subdirs_full_filename(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, \ filename_str, filename_len, full_filename) \ fc_get_two_subdirs_full_filename_ex(base_path, base_len, \ subdir_str1, subdir_len1, subdir_str2, subdir_len2, \ filename_str, filename_len, full_filename, sizeof(full_filename)) /** get gzip command full filename * return: the gzip command full filename */ const char *get_gzip_command_filename(); /** delete file * parameters: * filename: the filename to delete * caption: the caption of this filename * return: error no, 0 success, != 0 fail */ int fc_delete_file_ex(const char *filename, const char *caption); static inline int fc_delete_file(const char *filename) { return fc_delete_file_ex(filename, ""); } /** if prime number * parameters: * n: the number to detect * return: true for prime number, otherwise false */ bool fc_is_prime(const int64_t n); /** find the largest prime number not greater than n * parameters: * n: the number to detect * return: the largest prime number near n */ int64_t fc_floor_prime(const int64_t n); /** find the smallest prime number not less than n * parameters: * n: the number to detect * return: the smallest prime number near n */ int64_t fc_ceil_prime(const int64_t n); /** init buffer * parameters: * buffer: the buffer to init * buffer_size: the buffer size * return: error no, 0 success, != 0 fail */ int fc_init_buffer(BufferInfo *buffer, const int buffer_size); /** free buffer * parameters: * buffer: the buffer to free * return: none */ void fc_free_buffer(BufferInfo *buffer); /** realloc buffer * parameters: * buffer: the buffer to init * init_buff_size: the init buffer size * expect_size: the expect buffer size * return: error no, 0 success, != 0 fail */ int fc_realloc_buffer(BufferInfo *buffer, const int init_buff_size, const int expect_size); static inline int fc_get_umask() { mode_t mode; mode = umask(0); //fetch umask(mode); //restore return mode; } int fc_check_mkdir_ex(const char *path, const mode_t mode, bool *created); static inline int fc_check_mkdir(const char *path, const mode_t mode) { bool created; return fc_check_mkdir_ex(path, mode, &created); } int fc_mkdirs_ex(const char *path, const mode_t mode, int *create_count); static inline int fc_mkdirs(const char *path, const mode_t mode) { int create_count; return fc_mkdirs_ex(path, mode, &create_count); } int fc_check_rename_ex(const char *oldpath, const char *newpath, const bool overwritten); static inline int fc_check_rename(const char *oldpath, const char *newpath) { const bool overwritten = true; return fc_check_rename_ex(oldpath, newpath, overwritten); } int fc_get_path_child_count(const char *path); int fc_copy_file(const char *src_filename, const char *dest_filename); int fc_copy_to_path(const char *src_filename, const char *dest_path); int fc_get_first_line(const char *filename, char *buff, const int buff_size, string_t *line); int fc_get_first_lines(const char *filename, char *buff, const int buff_size, string_t *lines, int *count); int fc_get_last_line(const char *filename, char *buff, const int buff_size, int64_t *file_size, string_t *line); int fc_get_last_lines(const char *filename, char *buff, const int buff_size, string_t *lines, int *count); /** if the input path contains the needle path * parameters: * path: the absolute path to match * needle: the needle path, must be absolute * result: store the errno * return: true for contain, otherwise false */ bool fc_path_contains(const string_t *path, const string_t *needle, int *result); /** itoa output as decimal number * parameters: * n: the number to convert * buff: store the converted string * return: string length */ int fc_itoa(int64_t n, char *buff); static inline int fc_ltostr_ex(int64_t n, char *buff, const int padding_len) { int len; int fill_len; len = fc_itoa(n, buff); *(buff + len) = '\0'; if (padding_len <= len) { return len; } fill_len = padding_len - len; memmove(buff + fill_len, buff, len + 1); memset(buff, '0', fill_len); return padding_len; } static inline int fc_ltostr(int64_t n, char *buff) { const int padding_len = 0; return fc_ltostr_ex(n, buff, padding_len); } static inline size_t fc_strlcpy(char *dest, const char *src, const size_t size) { int len; len = strlen(src); if (len < size) { memcpy(dest, src, len + 1); } else { len = size - 1; memcpy(dest, src, len); *(dest + len) = '\0'; } return len; } #define fc_safe_strcpy(dest, src) fc_strlcpy(dest, src, sizeof(dest)) /** sleep in microseconds * parameters: * microseconds: microseconds to sleep * return: 0 for success, != 0 for fail */ static inline int fc_sleep_us(const int microseconds) { struct timespec ts; ts.tv_sec = microseconds / (1000 * 1000); ts.tv_nsec = (microseconds % (1000 * 1000)) * 1000; if (nanosleep(&ts, NULL) == 0) { return 0; } else { return errno != 0 ? errno : EINVAL; } } /** sleep in milliseconds * parameters: * milliseconds: milliseconds to sleep * return: 0 for success, != 0 for fail */ static inline int fc_sleep_ms(const int milliseconds) { struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = (milliseconds % 1000) * (1000 * 1000); if (nanosleep(&ts, NULL) == 0) { return 0; } else { return errno != 0 ? errno : EINVAL; } } int fc_check_filename_ex(const string_t *filename, const char *caption, char *error_info, int *error_len, const int error_size); int fc_check_filename(const string_t *filename, const char *caption); /** is pure digital string * parameters: * str: the string to detect * return: true for digital string, otherwise false */ bool is_digital_string(const char *str); int fc_safe_write_file_init(SafeWriteFileInfo *fi, const char *file_path, const char *redo_filename, const char *tmp_filename); static inline int fc_safe_write_file_open(SafeWriteFileInfo *fi) { const int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC; int result; if ((fi->fd=open(fi->tmp_filename, flags, 0644)) < 0) { result = errno != 0 ? errno : EIO; logError("file: "__FILE__", line: %d, " "open file %s fail, errno: %d, error info: %s", __LINE__, fi->tmp_filename, result, STRERROR(result)); return result; } else { return 0; } } static inline int fc_safe_write_file_close(SafeWriteFileInfo *fi) { int result; close(fi->fd); if (rename(fi->tmp_filename, fi->filename) != 0) { result = errno != 0 ? errno : EIO; logError("file: "__FILE__", line: %d, " "rename file \"%s\" to \"%s\" fail, " "errno: %d, error info: %s", __LINE__, fi->tmp_filename, fi->filename, result, STRERROR(result)); return result; } else { return 0; } } static inline int fc_check_realloc_iovec_array( iovec_array_t *array, const int target_size) { int new_alloc; struct iovec *new_iovs; if (array->alloc >= target_size) { return 0; } if (array->alloc == 0) { new_alloc = 64; } else { new_alloc = array->alloc * 2; } while (new_alloc < target_size) { new_alloc *= 2; } new_iovs = (struct iovec *)fc_malloc( sizeof(struct iovec) * new_alloc); if (new_iovs == NULL) { return ENOMEM; } if (array->iovs != NULL) { free(array->iovs); } array->iovs = new_iovs; array->alloc = new_alloc; return 0; } static inline void fc_free_iovec_array(iovec_array_t *array) { if (array->iovs != NULL) { free(array->iovs); array->iovs = NULL; array->alloc = 0; } } static inline pid_t fc_gettid() { #ifdef OS_LINUX #ifdef SYS_gettid return (pid_t)syscall(SYS_gettid); #else return getpid(); #endif #else return getpid(); #endif } static inline size_t fc_iov_get_bytes(const struct iovec *iov, const int iovcnt) { const struct iovec *iob; const struct iovec *end; size_t bytes; switch (iovcnt) { case 0: return 0; case 1: return iov[0].iov_len; case 2: return iov[0].iov_len + iov[1].iov_len; case 3: return iov[0].iov_len + iov[1].iov_len + iov[2].iov_len; case 4: return iov[0].iov_len + iov[1].iov_len + iov[2].iov_len + iov[3].iov_len; default: bytes = 0; end = iov + iovcnt; for (iob=iov; iobiov_len; } return bytes; } } #ifdef __cplusplus } #endif #endif