diff --git a/README.md b/README.md index 04c0bfd01d8d86836fe303ebd79a82fc935c9271..7bf376104fbad99ecec8e68dfe3cca3f9b3f2103 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Including a power API SO and the Power API Service. #### 使用说明 1. 编译:./build.sh -2. 后台运行PowerAPI Service: ./release/pwrapis/pwrapis & +2. 后台运行PowerAPI Service: ./release/pwrapis/pwrapis pwrapis/conf/pwrapis_config.ini & 3. 运行PowerAPI demo: ./release/pwrapi_demo/pwrapic_demo #### 参与贡献 diff --git a/common/inc/pwrerr.h b/common/inc/pwrerr.h index 2bf6094b692d2723a3c0a4ec525a88bf1d435ae7..60737f519204c54fc716170f403723b78a7adac5 100644 --- a/common/inc/pwrerr.h +++ b/common/inc/pwrerr.h @@ -31,6 +31,7 @@ enum RtnCode { ERR_GOVERNOR_INVALIDE, ERR_FREQ_NOT_IN_RANGE, ERR_CALLBACK_FUNCTION_SHOULD_BE_SET_FIRST, + ERR_MODIFY_BAN_UPDATE_ATTR_CURRENTLY, ERR_NOT_REGISTED = 100, ERR_NOT_AUTHED, ERR_OVER_MAX_CONNECTION, diff --git a/common/inc/pwrmsg.h b/common/inc/pwrmsg.h index e6ebdd7f4b1c2080722afa48969899efe96f1d55..09842acd9a3e5f102963066044034f76516c8c54 100644 --- a/common/inc/pwrmsg.h +++ b/common/inc/pwrmsg.h @@ -36,7 +36,7 @@ typedef struct MsgHead { uint32_t taskNo; uint32_t crcMagic; uint32_t dataLen; - uint32_t sysId; // 消息源头的系统标识,IPC场景使用PID + uint32_t sysId; // System id of msg source, using PID for IPC scene. char reserved[4]; } MsgHead; diff --git a/pwrapic/gtest/Common.cpp b/pwrapic/gtest/Common.cpp index b8932c830dd95af012156680420f2c4cd3869b45..3c73cf618c2e40f81f542b3d874f9f3409222c96 100644 --- a/pwrapic/gtest/Common.cpp +++ b/pwrapic/gtest/Common.cpp @@ -29,7 +29,7 @@ int StartService(void) std::string gtestDir = dir; std::string pwrapisDir; - // 10: length for "gtest_test", 只保留文件的路径 + // 10: length for "gtest_test", keep only the path of file gtestDir = gtestDir.substr(0, gtestDir.length() - 10); pwrapisDir = gtestDir + "../pwrapis/pwrapis &"; ret = system(pwrapisDir.c_str()); diff --git a/pwrapic/src/sockclient.c b/pwrapic/src/sockclient.c index c866d80a6c8ed18a353ff08c3009b43f700ed17a..2eac79c48833b1373a24124eb055a7a7e285b583 100644 --- a/pwrapic/src/sockclient.c +++ b/pwrapic/src/sockclient.c @@ -40,10 +40,10 @@ static int g_sockFd = INVALID_FD; static ThreadInfo g_sockThread; -static PwrMsgBuffer g_sendBuff; // 发送队列 -static PwrMsgBuffer g_recvBuff; // 接收队列 -static ResultWaitingMsgList g_waitList; // 等待结果列表 -static char SERVER_ADDR[MAX_PATH_LEN] = "/etc/sysconfig/pwrapis/pwrserver.sock"; // 默认server路径 +static PwrMsgBuffer g_sendBuff; // Send queue +static PwrMsgBuffer g_recvBuff; // Receive queue +static ResultWaitingMsgList g_waitList; // Waiting for results list +static char SERVER_ADDR[MAX_PATH_LEN] = "/etc/sysconfig/pwrapis/pwrserver.sock"; // Default server path #define CHECK_SOCKET_STATUS() \ if (g_sockFd == INVALID_FD) { \ diff --git a/pwrapis/inc/config.h b/pwrapis/inc/config.h index 5b475e482a545bf3c10355dd275725ffee28e378..5f079a6d91a854eaf8a1b1b3b48f7e02490c49e5 100644 --- a/pwrapis/inc/config.h +++ b/pwrapis/inc/config.h @@ -25,6 +25,7 @@ #define DEFAULT_FILE_SIZE 10 // MB #define DEFAULT_FILE_NUM 3 #define MAX_SERVER_PORT 65535 +#define MD5_LEN 33 // LogCfg enum LogLevel { diff --git a/pwrapis/inc/utils.h b/pwrapis/inc/utils.h index 9bf915ca30ec4cfb5c0ee5a3655a8ba6a0191c0c..ae14eaf896f37ed4d32b592635eb446dc5033889 100644 --- a/pwrapis/inc/utils.h +++ b/pwrapis/inc/utils.h @@ -238,5 +238,6 @@ int InIntRange(int *range, int len, int a); int ReadFile(const char *strInfo, char *buf, int bufLen); int WriteFile(const char *strInfo, char *buf, int bufLen); int WriteFileAndCheck(const char *strInfo, char *buf, int bufLen); +int GetMd5(const char *filename, char *md5); #endif diff --git a/pwrapis/src/CMakeLists.txt b/pwrapis/src/CMakeLists.txt index a4dca8e6ece341242cddda0b773f6d77dddd8dcd..9b7f0a3f8c96e4b29c1bdb08c540d0751b890a6e 100644 --- a/pwrapis/src/CMakeLists.txt +++ b/pwrapis/src/CMakeLists.txt @@ -23,7 +23,7 @@ set ( CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Install path prefix" FORCE) install (TARGETS ${PG_NAME} DESTINATION sbin) # Install default config files -install (FILES "${PROJECT_SOURCE_DIR}/../conf/pwrapis_config.ini" DESTINATION /etc/sysconfig) +install (FILES "${PROJECT_SOURCE_DIR}/../conf/pwrapis_config.ini" DESTINATION /etc/sysconfig/pwrapis) install (FILES "${PROJECT_SOURCE_DIR}/../pwrapis.service" DESTINATION /usr/lib/systemd/system) # release complile mode diff --git a/pwrapis/src/comservice.c b/pwrapis/src/comservice.c index c9f583ed3f4ed1bea85d87e209c9edc89d2abff2..70aec82a4684ff82186a6d3960c1fb4e215cb4da 100644 --- a/pwrapis/src/comservice.c +++ b/pwrapis/src/comservice.c @@ -27,7 +27,7 @@ static uint32_t g_authOwner = 0; static int DoAuthRequest(uint32_t client) { if (g_authed) { - if (g_authOwner != client) { // 控制权已授予其他应用 + if (g_authOwner != client) { // Control has been granted to other app return ERR_CONTROL_AUTH_REQUESTED; } return SUCCESS; diff --git a/pwrapis/src/config.c b/pwrapis/src/config.c index c7707c876d8ca78f9d45da97823a4c93f8cafbd0..fb0b98570df73b916dd4e00de15d2b57bba5d222 100644 --- a/pwrapis/src/config.c +++ b/pwrapis/src/config.c @@ -18,6 +18,7 @@ #include #include "string.h" #include "pwrerr.h" +#include "pwrdata.h" #include "log.h" #include "utils.h" @@ -34,6 +35,7 @@ inline ServCfg *GetServCfg(void) } static char g_configPath[MAX_PATH_NAME] = "/etc/sysconfig/pwrapis/pwrapis_config.ini"; +static char g_lastMd5[MD5_LEN] = {0}; int UpdateConfigPath(const char* configPath) { @@ -188,11 +190,11 @@ static int LoadConfigFile(void) return ERR_NULL_POINTER; } while (fgets(line, sizeof(line) - 1, fp) != NULL) { - // 空行、注释行等跳过 + // Skip invalid lines such as empty lines、comment lines if (strlen(line) <= 1 || line[0] == '#' || line[0] == '[') { continue; } - // 解析当前行内容,提取(关键字,值),暂时默认配置文件中的key和value的格式为:key=value,不存在空格情况 + // Parse the current line content, extract (key, value) char key[MAX_KEY_LEN] = {0}; char value[MAX_LINE_LENGTH] = {0}; char *index = strchr(line, '='); @@ -205,7 +207,7 @@ static int LoadConfigFile(void) LRtrim(key); LRtrim(value); if (strlen(key) == 0 || strlen(value) == 0) { - // key or value is invalid + // Key or value is invalid continue; } enum CnfItemType type = StringToEnum(key); @@ -233,6 +235,14 @@ static int LoadConfigFile(void) int InitConfig(void) { + // Get initial md5 of config + bzero(g_lastMd5, sizeof(g_lastMd5)); + GetMd5(g_configPath, g_lastMd5); + if (strlen(g_lastMd5) == 0) { + Logger(ERROR, MD_NM_CFG, "Get initial md5 of config failed"); + return FAILED; + } + int ret = SUCCESS; // Init by default values ret = InitLogCfg(); @@ -250,15 +260,154 @@ int InitConfig(void) // load config file ret = LoadConfigFile(); if (ret != SUCCESS) { - Logger(ERROR, MD_NM_CFG, "config file error. ret:%d", ret); + Logger(ERROR, MD_NM_CFG, "Handle config file failed. ret:%d", ret); return ret; } return SUCCESS; } +static int HandleInvalidUpdate(char *key, char *value) +{ + enum CnfItemType type = StringToEnum(key); + switch (type) { + case E_CFG_IT_LGP: + if (strcmp(value, g_logCfg.logPath) != 0) { + Logger(ERROR, MD_NM_CFG, "%s cannot be dynamically configured to take effect", key); + return ERR_COMMON; + } + break; + case E_CFG_IT_BKP: + if (strcmp(value, g_logCfg.logBkp) != 0) { + Logger(ERROR, MD_NM_CFG, "%s cannot be dynamically configured to take effect", key); + return ERR_COMMON; + } + break; + case E_CFG_IT_PFX: + if (strcmp(value, g_logCfg.logPfx) != 0) { + Logger(ERROR, MD_NM_CFG, "%s cannot be dynamically configured to take effect", key); + return ERR_COMMON; + } + break; + case E_CFG_IT_SKF: + if (strcmp(value, g_servCfg.sockFile) != 0) { + Logger(ERROR, MD_NM_CFG, "%s cannot be dynamically configured to take effect", key); + return ERR_COMMON; + } + break; + } + return SUCCESS; +} + +int UpdateConfig(char *key, char *value) +{ + enum CnfItemType type = StringToEnum(key); + int actualValue; + switch (type) { + // Properties that can be dynamically validated + case E_CFG_IT_FLS: + actualValue = atoi(value); + if (!IsNumStr(value) || actualValue < 0) { + int curFileSize = (g_logCfg.maxFileSize + MAX_LINE_LENGTH) / UNIT_FACTOR; + Logger(ERROR, MD_NM_CFG, "File_size in config is invalid, current valid value is %d", curFileSize); + return ERR_INVALIDE_PARAM; + } + int maxFileSize = actualValue * UNIT_FACTOR - MAX_LINE_LENGTH; + if (maxFileSize != g_logCfg.maxFileSize) { + g_logCfg.maxFileSize = maxFileSize; + Logger(INFO, MD_NM_CFG, "File_size in config has been modified to %d", actualValue); + } + break; + case E_CFG_IT_CNT: + actualValue = atoi(value); + if (!IsNumStr(value) || actualValue < 0) { + Logger(ERROR, MD_NM_CFG, "Cmp_cnt in config is invalid, current valid value is %d", g_logCfg.maxCmpCnt); + return ERR_INVALIDE_PARAM; + } + if (actualValue != g_logCfg.maxCmpCnt) { + g_logCfg.maxCmpCnt = actualValue; + Logger(INFO, MD_NM_CFG, "Cmp_cnt in config has been modified to %d", actualValue); + } + break; + case E_CFG_IT_LGV: + actualValue = atoi(value); + if (!IsNumStr(value) || actualValue < 0) { + enum LogLevel curLogLevel = g_logCfg.logLevel; + Logger(ERROR, MD_NM_CFG, "Log_level in config is invalid, current valid value is %d", curLogLevel); + return ERR_INVALIDE_PARAM; + } + if (actualValue != g_logCfg.logLevel) { + UpdateLogLevel(actualValue); + Logger(INFO, MD_NM_CFG, "Log_level in config has been modified to %d", actualValue); + } + break; + // Properties that cannot be dynamically validated + default: + return HandleInvalidUpdate(key, value); + } + return SUCCESS; +} + int CheckAndUpdateConfig(void) { - // todo 检查配置文件是否有更新,有更新则更新系统配置项 + char curMd5[MD5_LEN] = {0}; + GetMd5(g_configPath, curMd5); + if (strlen(curMd5) == 0 || strcmp(curMd5, g_lastMd5) == 0) { + return SUCCESS; + } + + int invalidUpdateSum = 0; // The number of invalid updates + int nonDynamicSum = 0; // The number of undynamically validated attrs that been modified + char line[MAX_LINE_LENGTH]; + FILE *fp = fopen(g_configPath, "r"); + if (fp == NULL) { + return ERR_NULL_POINTER; + } + + while (fgets(line, sizeof(line) - 1, fp) != NULL) { + if (strlen(line) <= 1 || line[0] == '#' || line[0] == '[') { + continue; + } + char key[MAX_KEY_LEN] = {0}; + char value[MAX_LINE_LENGTH] = {0}; + char *index = strchr(line, '='); + if (index == NULL) { + continue; + } + + strncpy(key, line, index - line); + strncpy(value, index + 1, sizeof(value)); + LRtrim(key); + LRtrim(value); + if (strlen(key) == 0 || strlen(value) == 0) { + // key or value is invalid + continue; + } + switch (UpdateConfig(key, value)) { + case ERR_INVALIDE_PARAM: + invalidUpdateSum++; + break; + case ERR_COMMON: + nonDynamicSum++; + break; + } + } + pclose(fp); + strncpy(g_lastMd5, curMd5, sizeof(g_lastMd5)); + /** + * The file has been confirmed to be modified now. + * 1. Error modifying attrs, return ERR_INVALIDE_PARAM; + * 2. Undynamically validated attrs have been modified, return ERR_MODIFY_BAN_UPDATE_ATTR_CURRENTLY; + * 3. Return SUCCESS. + */ + if (invalidUpdateSum != 0) { + return ERR_INVALIDE_PARAM; + } else { + if (nonDynamicSum != 0) { + return ERR_MODIFY_BAN_UPDATE_ATTR_CURRENTLY; + } else { + return SUCCESS; + } + } } int GetLogLevel(void) diff --git a/pwrapis/src/cpuservice.c b/pwrapis/src/cpuservice.c index e4b2b6d6bc83dc8346f493e0c92f3a1fa0d3fd82..937f0c2386d59b4048ef758630e5771f45663ba8 100644 --- a/pwrapis/src/cpuservice.c +++ b/pwrapis/src/cpuservice.c @@ -893,7 +893,7 @@ void SetCpuFreqRange(PwrMsg *req) SendRspToClient(req, rspCode, NULL, 0); } -// 总CPU核数 +// Total CPU cores int GetCpuCoreNumber(void) { return sysconf(_SC_NPROCESSORS_CONF); diff --git a/pwrapis/src/server.c b/pwrapis/src/server.c index c47d7c7a7a81b1c484de45f0dbc23ff0a314d6e2..88f4741b6eec8b46160e5400de5faba51bfd38b1 100644 --- a/pwrapis/src/server.c +++ b/pwrapis/src/server.c @@ -40,9 +40,9 @@ static pthread_mutex_t g_listenFdLock = PTHREAD_MUTEX_INITIALIZER; static ThreadInfo g_sockProcThread; static ThreadInfo g_serviceThread; -static PwrClient g_pwrClients[MAX_CLIENT_NUM]; // 对该结构的读和写都在一个线程完成,因而不需要加锁 -static PwrMsgBuffer g_sendBuff; // 发送队列 -static PwrMsgBuffer g_recvBuff; // 接收队列 +static PwrClient g_pwrClients[MAX_CLIENT_NUM]; // Reading and writing the struct are done in one thread, no need locks +static PwrMsgBuffer g_sendBuff; // Send queue +static PwrMsgBuffer g_recvBuff; // Receive queue static pthread_mutex_t g_waitMsgMutex; static pthread_cond_t g_waitMsgCond; @@ -169,7 +169,7 @@ static int ReadMsg(void *pData, int len, int dstFd, int idx) static void ProcessRecvMsgFromClient(int clientIdx) { - // 从connFd获取消息,并送到service队列,等待处理 + // Get msg from connFd, send to service queue and waiting for processing int dstFd = g_pwrClients[clientIdx].fd; PwrMsg *msg = (PwrMsg *)malloc(sizeof(PwrMsg)); if (!msg || ReadMsg(msg, sizeof(PwrMsg), dstFd, clientIdx) != SUCCESS) { @@ -232,7 +232,7 @@ static int WriteMsg(const void *pData, int len, int dstFd) static void ProcessSendMsgToClient(void) { - // 从缓存中读取待发送消息,并发送出去 + // Read msg from buffer and send. int count = 0; static char data[MAX_DATA_SIZE]; while (!IsEmptyBuffer(&g_sendBuff) && count < COUNT_MAX) { @@ -458,7 +458,7 @@ void StopServer(void) pthread_mutex_destroy((pthread_mutex_t *)&g_waitMsgMutex); } -// 本函数会将data指针所指向数据迁移走,调用方勿对data进行释放操作。 +// This function will move the 'data' pointer to data migration, and the caller should not release the 'data'. void SendRspToClient(const PwrMsg *req, int rspCode, char *data, uint32_t len) { if (!req) { @@ -480,7 +480,7 @@ void SendRspToClient(const PwrMsg *req, int rspCode, char *data, uint32_t len) ReleasePwrMsg(&rsp); } } -// 本函数会将data指针所指向数据迁移走,调用方勿对data进行释放操作。 +// This function will move the 'data' pointer to data migration, and the caller should not release the 'data'. int SendMetadataToClient(uint32_t sysId, char *data, uint32_t len) { if (!data && len != 0) { diff --git a/pwrapis/src/taskservice.c b/pwrapis/src/taskservice.c index aa88aa292ce99cc01cd81612f1128d4b25e510e2..3ab111a12d3aeff862ff860291975c0fec6a64b8 100644 --- a/pwrapis/src/taskservice.c +++ b/pwrapis/src/taskservice.c @@ -39,8 +39,8 @@ typedef struct CollDataSubscriber { typedef struct CollTask { PWR_COM_COL_DATATYPE dataType; int interval; - int subNum; // 订阅数 - CollDataSubscriber subscriberList[MAX_CLIENT_NUM]; // 该数据订阅方 + int subNum; // Number of subscriptions + CollDataSubscriber subscriberList[MAX_CLIENT_NUM]; // The data subscriber ThreadInfo collThread; } CollTask; @@ -74,13 +74,17 @@ static int FindAvailebleTaskSlot(void) static inline void FiniTask(int index) { - FiniThreadInfo(&(g_collTaskList[index]->collThread)); // 必须先停止线程 + FiniThreadInfo(&(g_collTaskList[index]->collThread)); // Must stop thread first free(g_collTaskList[index]); g_collTaskList[index] = NULL; g_taskNum--; } -// 需要使用指定的订阅者周期更新task周期时,subIdx填具体订阅者的索引,否则填INVALIDE_INDEX +/** + * When the task cycle needs to be updated using the specified subscriber cycle, + * subIdx should fill in the index of the specific subscriber, + * otherwise fill in INVALIDE_ INDEX + */ static void UpdataTaskInterval(int index, int subIdx) { if (subIdx != INVALID_INDEX) { @@ -151,7 +155,7 @@ static int DeleteSubscriber(int index, uint32_t subscriber) } } - if (g_collTaskList[index]->subNum <= 0) { // 无用户订阅数据时,停止采集 + if (g_collTaskList[index]->subNum <= 0) { // Stop collecting data when there is no user subscription FiniTask(index); } else { UpdataTaskInterval(index, INVALID_INDEX); @@ -169,7 +173,7 @@ static void SendMetadataToSubscribers(CollTask *task, const char *data, int len, continue; } memcpy(dataCpy, data, len); - SendMetadataToClient(task->subscriberList[i].sysId, dataCpy, len); // 该函数内部会释放dataCpy + SendMetadataToClient(task->subscriberList[i].sysId, dataCpy, len); // Internally release 'dataCpy' task->subscriberList[i].lastSent = *startTime; } } @@ -245,7 +249,7 @@ static void *RunDcTaskProcess(void *arg) int sleepTime = 0; while (task->collThread.keepRunning) { gettimeofday(&after, NULL); - sleepTime = task->interval - GetTimeDistance(after, before); // 任务周期 - 上次执行花费时间 + sleepTime = task->interval - GetTimeDistance(after, before); // Task cycle - Last execution took time if (sleepTime > 0) { usleep(THOUSAND * sleepTime); } diff --git a/pwrapis/src/utils.c b/pwrapis/src/utils.c index 30e388c72724d2fc34a68b9fe3dc805b7eed1f97..b0333a6c65a3ce3931d2e44328059d8fcc1333d7 100644 --- a/pwrapis/src/utils.c +++ b/pwrapis/src/utils.c @@ -976,4 +976,27 @@ int WriteFileAndCheck(const char *strInfo, char *buf, int bufLen) return 1; } return 0; +} + +int GetMd5(const char *filename, char *md5) +{ + char md5Cmd[MAX_NAME_LEN]; + const char s1[] = "md5sum "; + const char s2[] = " | awk '{print $1}'"; + StrCopy(md5Cmd, s1, MAX_NAME_LEN); + strncat(md5Cmd, filename, strlen(filename)); + strncat(md5Cmd, s2, strlen(s2)); + FILE *fp = popen(md5Cmd, "r"); + if (fp == NULL) { + pclose(fp); + return ERR_NULL_POINTER; + } + char buf[MD5_LEN] = {0}; + if (fgets(buf, sizeof(buf), fp) == NULL) { + pclose(fp); + return ERR_COMMON; + } + strncpy(md5, buf, sizeof(buf)); + pclose(fp); + return SUCCESS; } \ No newline at end of file diff --git a/uninstall.sh b/uninstall.sh index b258002ef47a4c7d7496027bc1077f47f5262bfc..29ab1d397bb997bcaddf5278d156c6e79384b054 100644 --- a/uninstall.sh +++ b/uninstall.sh @@ -9,6 +9,6 @@ if [ -f "./build/install_manifest.txt" ];then else rm /usr/lib/libpwrapi.so rm /usr/sbin/pwrapis - rm /etc/sysconfig/pwrapis_config.ini + rm /etc/sysconfig/pwrapis/pwrapis_config.ini rm /usr/lib/systemd/system/pwrapis.service fi