commit b83dc29e99d5e4f3a9d378fc9c07213e9d277aca Author: HuangXin Date: Thu Jul 5 10:19:12 2018 +0800 Init projects diff --git a/Example/global.db b/Example/global.db new file mode 100644 index 0000000..947d92f Binary files /dev/null and b/Example/global.db differ diff --git a/Example/main.c b/Example/main.c new file mode 100644 index 0000000..535d173 --- /dev/null +++ b/Example/main.c @@ -0,0 +1,2039 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#include "ota.h" +#include "skins.h" +#include "assistant.h" +#include "inet_api.h" +#include "skins_res.h" +#include "server_addr.h" + +static MOD_INFO_TABLE g_ModInfo; +static uv_timer_t g_tmTest; +static uv_barrier_t g_tmSync; +static uv_loop_t* pUserLoop = NULL; +static int g_isExitLoop = 0; + +static void test_task_new(uv_thread_cb pCallback, void* pParams); + +static void OnCfgMsgCb(DBUS_CMD cmd, PCFG_ITEM pMsg, int err) +{ + fprintf(stdout, "Cmd = %d, Cfg = %s\n", cmd, pMsg->pKeyName); + + if(err != 0) + { + LOG_EX(LOG_Error, "Cmd %d Error: %d\n", cmd, err); + return; + } + + switch(cmd) + { + case CMD_CFG_GET_RSP: + CfgItemPrint("Add Configure: ", pMsg); + break; + } +} + +static void __dBusDeameonCb(MODULE_NAME modName, int status) +{ +#if 1 + if(status) + { + LOG_EX(LOG_Error, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } + else + { + LOG_EX(LOG_Info, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } +#endif + if(modName == MODULE_OTA && status == 0) + { + int ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_OTA].modAliase, + CMD_SYSTEM_STANDBY, "{\"status\" : 0}"); + + LOG_EX(LOG_Debug, "Send Standby Command: %d\n", ret); + } + + LOG_EX(LOG_Debug, "Set Exit Loop\n"); + g_isExitLoop = TRUE; +} + +static void KeyEventCb(uint16_t uType, uint16_t uKey, int32_t iValue) +{ + LOG_EX(LOG_Info, "type = %u, code = %u, value = %u\n", uType, uKey, iValue); +} + +static void __uvThreadOTA(void *pParams) +{ + OTA_DATA_INFO otaInfo; + POTA_DATA_INFO pInfo = NULL; + int ret; + int version = (int)(intptr_t)pParams; + + memset(&otaInfo, 0, sizeof(OTA_DATA_INFO)); + + if(version == 130) + { + otaInfo.version = 132; + strcpy(otaInfo.otaFileInfo.url, "http://10.241.0.70/tina/tina_r16_ota_132.tar.gz"); + strcpy(otaInfo.otaFileInfo.md5, "3bda58a2eb4e90fbb35b0d33db44cf57"); + otaInfo.otaFileInfo.size = 22966488; + } + else if(version == 132) + { + otaInfo.version = 133; + strcpy(otaInfo.otaFileInfo.url, "http://10.241.0.70/tina/tina_r16_ota_133.tar.gz"); + strcpy(otaInfo.otaFileInfo.md5, "c4085cb33d6dbd5ae5fdae948365023c"); + otaInfo.otaFileInfo.size = 22966524; + } + else + { + otaInfo.version = 4; + strcpy(otaInfo.otaFileInfo.url, "http://api.multimedia.netease.com/imgtest/ota/tina_r16_ota_133.tar.gz"); + strcpy(otaInfo.otaFileInfo.md5, "c4085cb33d6dbd5ae5fdae948365023c"); + otaInfo.otaFileInfo.size = 22963814; + } + + otaInfo.otaCmd = OTA_CMD_DOWNLOAD; + otaInfo.otaMode = OTA_MODE_FORCE_NOW; + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_OTA].modAliase, + CMD_OTA_NOTIFY, + JSON_ENGINE_OTA_REQ, + &otaInfo, TRUE); + + LOG_EX(LOG_Debug, "Send OTA Command: OTA_CMD_DOWNLOAD --> %d\n", ret); +} + +#if 0 +static void __radomAlarmItem(PASSISTANT_ITEM_INFO pInfo) +{ + static unsigned int alarmId = 0; + time_t tmVal = time(NULL); + struct tm *pTmNow = localtime(&tmVal); + + if(pInfo == NULL) + { + return; + } + + memset(pInfo, 0, sizeof(ALARM_ITEM_INFO)); + + pInfo->alarmId = __sync_fetch_and_add(&alarmId, 1); + pInfo->itemType = (random() % 2 == 0) ? ALARM_TYPE_REMAIND : ALARM_TYPE_CLOCK; + pInfo->priority = random() % 10; + pInfo->repeatMode = random() % (REPEAT_MODE_EVERY_YEAR_DAY + 1); + + pTmNow->tm_hour = random() % 24; + pTmNow->tm_min = random() % 60; + + //strftime(pInfo->strDateTime, MAX_DT_LEN, "%Y-%m-%d %H:%M", pTmNow); + sprintf(pInfo->strTips, "TTS %llu", pInfo->itemId); +} +#endif + +static PDBUS_MSG_PACK DBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ + int i, ret, err; + uint32_t tm = LIBUV_CURRENT_TIME_US(); + PCFG_API_RSP pRsp = NULL; + POTA_RSP_STATUS pOTAStatus = NULL; + //PALARM_RSP_STATUS pAlarmStatus = NULL; + //PALARM_SYNC_INFO pSyncInfo = NULL; + static unsigned int iCnt = 0; + + if(!pMsg || !pLoop || !pConn) + { + return NULL; + } + +#if 1 + if(iCnt++ % 1000 == 0) + { + LOG_EX(LOG_Info, "Receive: %s\n", pMsg->pMsg); + } +#endif + + //LOG_EX(LOG_Info, "Process Message(%u --> 0x%08X) at [%lu.%06lu]: cmd = %u, size = %u, key = %d, msg(%d) = [%s]\n", + // pMsg->msgSrc, pMsg->msgDests, tm / 1000000, tm % 1000000, pMsg->busCmd, pMsg->msgSize, pMsg->msgKey, pMsg->msgSize, pMsg->pMsg); + + switch(pMsg->busCmd) + { + case CMD_CALL_DIAL: + LOG_EX(LOG_Debug, "Recv: %s\n", pMsg->pMsg); + break; + + case CMD_MISC_OTA: + print_hex_dump_bytes("OTA", DUMP_PREFIX_ADDRESS, pMsg->pMsg, (pMsg->msgSize > 128) ? 128 : pMsg->msgSize); + break; + + case CMD_CFG_GET_RSP: + pRsp = (PCFG_API_RSP)Json2Struct(pMsg->pMsg, JSON_ENGINE_CFG_RSP, TRUE, &err); + + if(pRsp == NULL || err != 0) + { + LOG_EX(LOG_Error, "CMD_CFG_GET: pRsp = %p, err = %d\n", pRsp, err); + return (NULL); + } + + LOG_EX(LOG_Debug, "Get Configure: [%s](%d) --> \"%s\"\n", pRsp->keyName, pRsp->keyType, pRsp->keyValue); + + free(pRsp); + break; + + case CMD_OTA_STATUS: + pOTAStatus = (POTA_RSP_STATUS)Json2Struct(pMsg->pMsg, JSON_ENGINE_OTA_RSP, TRUE, &err); + + LOG_EX(LOG_Debug, "%s --> %d(0x%08X)\n", otaStatusName(pOTAStatus->status), pOTAStatus->val, pOTAStatus->val); + + if(pOTAStatus->status == OTA_CURRENT_VERSION) + { + test_task_new(__uvThreadOTA, (void*)(intptr_t)pOTAStatus->val); + } + + free(pOTAStatus); + break; + + case CMD_ALARM_SYNC_REQ: + LOG_EX(LOG_Debug, "Receive CMD_ALARM_SYNC_REQ Command\n"); + + if(iCnt++ > 0) + { + break; + } +#if 0 + const char *pAddCmd = "{\"data\":[{\"createTime\":1509419640000,\"id\":672,\"label\":1,\"type\":8,\"status\":1," + "\"updateTime\":1509419640000,\"vboxDate\":{\"dayofMonth\":\"17\",\"dayofWeek\":" + "\"1,2,3,4,5\",\"hour\":\"0\",\"minute\":\"0\",\"month\":\"11\",\"second\":\"10\",\"year\":\"\"}," + "\"vboxid\":\"0-52AEDB2DF9F45FEB\",\"voiceName\":\"音效2\",\"voiceType\":2}," + "{\"createTime\":1509419547000,\"id\":671,\"label\":0,\"type\":1,\"status\":1,\"updateTime\":" + "1509419547000,\"vboxDate\":{\"dayofMonth\":\"\",\"dayofWeek\":\"\",\"hour\":\"0\"," + "\"minute\":\"0\",\"month\":\"\",\"second\":\"10\",\"year\":\"\"},\"vboxid\":\"0-52AEDB2DF9F45FEB\"," + "\"voiceName\":\"音效2\",\"voiceType\":2}]}"; +#else +#if 0 + const char *pAddCmd = "{\"data\":[{\"id\":6734,\"vboxid\":\"0-D04CDF28BB622AF7\",\"label\":0," + "\"type\":1,\"voiceType\":1,\"voiceName\":\"音效1\",\"status\":2," + "\"updateTime\":1515576709000,\"createTime\":1515576709000," + "\"vboxDate\":{\"second\":\"0\",\"minute\":\"41\",\"hour\":\"18\"," + "\"dayofMonth\":\"10\",\"month\":\"1\",\"dayofWeek\":\"3\",\"year\":" + "\"2018\"}},{\"id\":6733,\"vboxid\":\"0-D04CDF28BB622AF7\",\"label\":0," + "\"type\":1,\"voiceType\":1,\"voiceName\":\"音效1\",\"status\":2," + "\"updateTime\":1515576701000,\"createTime\":1515576701000,\"vboxDate\":" + "{\"second\":\"0\",\"minute\":\"42\",\"hour\":\"18\",\"dayofMonth\":\"10\"," + "\"month\":\"1\",\"dayofWeek\":\"3\",\"year\":\"2018\"}}]}"; +#else + const char *pAddCmd = "{\"data\":[{\"id\":8136,\"vboxid\":\"0-ADC8ED8631B2032D\",\"label\":0," + "\"type\":3,\"voiceType\":1,\"voiceName\":\"音效1\",\"status\":2," + "\"updateTime\":1520841240000,\"createTime\":1520841240000," + "\"vboxDate\":{\"second\":\"\",\"minute\":\"56\",\"hour\":\"9\"," + "\"dayofMonth\":\"13\",\"month\":\"3\",\"dayofWeek\":\"2\"," + "\"year\":\"2018\"}}]}"; +#endif +#endif +#if 0 + ALARM_SYNC_INFO alarmInfo; + ALARM_REMOVE_INFO rmInfo; + + memset(&alarmInfo, 0, sizeof(ALARM_SYNC_INFO)); + memset(&rmInfo, 0, sizeof(ALARM_REMOVE_INFO)); + + alarmInfo.nItems = 10; + //alarmInfo.cmd = CMD_ALARM_SYNC_RSP; + alarmInfo.pAlarmInfo = (PALARM_ITEM_INFO)malloc(sizeof(ALARM_ITEM_INFO) * 10); + + for(i = 0; i < 10; i++) + { + __radomAlarmItem(&alarmInfo.pAlarmInfo[i]); + } + + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_ALARM].modAliase, + CMD_ALARM_SYNC_RSP, + JSON_ENGINE_ALARM_SYNC_RSP, + &alarmInfo, TRUE); +#endif + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_ALARM].modAliase, + CMD_ALARM_SYNC_RSP, + pAddCmd); + + LOG_EX(LOG_Debug, "Send Alarm Command: JSON_ENGINE_ALARM_SYNC_RSP --> %d\n", ret); +#if 0 + rmInfo.nItems = 3; + + for(i = 0; i < 3; i++) + { + // rmInfo.rmItemId[i] = alarmInfo.pAlarmInfo[i * 2].alarmId; + } + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_ALARM].modAliase, + CMD_ALARM_REMOVE, + JSON_ENGINE_ALARM_REMOVE, + &rmInfo, TRUE); + + LOG_EX(LOG_Debug, "Send Alarm Command: JSON_ENGINE_ALARM_SYNC_RSP --> %d\n", ret); + + free(alarmInfo.pAlarmInfo); +#endif + break; +#if 0 + case CMD_ALARM_STATUS: + //LOG_EX(LOG_Debug, "CMD_ALARM_STATUS: %s\n", (const char *)pMsg->pMsg); + pAlarmStatus = (PALARM_RSP_STATUS)Json2Struct(pMsg->pMsg, JSON_ENGINE_ALARM_STATUS, TRUE, &err); + LOG_EX(LOG_Debug, "%s --> %d(0x%08X)\n", alarmStatusName(pAlarmStatus->cmd), pAlarmStatus->val, pAlarmStatus->val); + + free(pAlarmStatus); + break; + + case CMD_ALARM_NOTIFY_EVT: + //LOG_EX(LOG_Debug, "CMD_ALARM_NOTIFY_EVT: %s\n", (const char *)pMsg->pMsg); + pSyncInfo = (PALARM_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ALARM_SYNC_RSP, TRUE, &err); + + if(pSyncInfo) + { + __printAlarmSyncInfo("CMD_ALARM_NOTIFY_EVT", pSyncInfo); + free(pSyncInfo); + } + + break; +#endif + default: + break; + } + + return NULL; +} + +static unsigned int g_Delay = 1000; +static void uvSndLessCb(uv_timer_t* pTimer) +{ +#if 0 + DBusConnection* pBus = (DBusConnection*)pTimer->data; + unsigned char* pData = (unsigned char*)malloc(2048); + + memset(pData, 0x3f, 2048); + *pData = 0; + + if(g_ModInfo.modName != MODULE_CONTROLLER) + { + DBusSendToCommand(pBus, g_pModInfoTable[MODULE_CONTROLLER].modAliase, CMD_MISC_OTA, pData, 2048); + } + + free(pData); +#endif + LOG_EX(LOG_Info, "Timer Runing delay = %u ....\n", g_Delay); + uv_barrier_wait(&g_tmSync); +// AESEncrypto(); + +} + +#define TEST_AES_LEN (93) + +void test_evp_aes(void) +{ + int i; + unsigned char enData[ALIGN_AES_BLOCK(TEST_AES_LEN)]; + unsigned char* pData = (unsigned char*)malloc(ALIGN_AES_BLOCK(TEST_AES_LEN)); + int outSize = 0; + char* pKey = "0123456789abcedf"; + + for(i = 0; i < TEST_AES_LEN; i++) + { + enData[i] = i % 0xFF; + } + + strcpy(enData, "hello world"); + + fprintf(stdout, "EvpAESEncrypto: %s\n", + EvpAESEncrypto(enData, TEST_AES_LEN, pData, &outSize, (unsigned char*)pKey) == 0 ? "Success" : "Fail"); + + print_hex_dump_bytes("en_", 2, pData, outSize); + fprintf(stdout, "enc: %s --> %s\n",enData, EvpBase64EncodeNoAlignV2(pData, outSize)); + + memset(enData, 0, ALIGN_AES_BLOCK(TEST_AES_LEN)); + + fprintf(stdout, "EvpAESDecrypto: %s\n", + EvpAESDecrypto(pData, outSize, enData, &outSize, (unsigned char*)pKey) == 0 ? "Success" : "Fail"); + + fprintf(stdout, "dec:%s\n", (char*)enData); + free(pData); +} + +static void uvTimeoutCb(uv_timer_t* pTimer) +{ + PCFG_ITEM pItem = NULL; + + int ret = 0; + + if((ret = CfgGetKeyValue("Age", &pItem)) == 0) + { + CfgItemPrint("Get KeyValue: ", pItem); + } + else + { + LOG_EX(LOG_Error, "Get Key [Age] Error: %d\n", ret); + } +} + +static void EVPEncryptCb(CRYPTO_TYPE type, + const unsigned char* pData, + int iSize, + const unsigned char* pSrcData, + int iError) +{ + int i = 0; + + if(iError == 0) + { + if(type == CRYPTO_AES_ENCRYPT) + { + char* pKey = "xajhuang12345678"; + unsigned char* enData = (unsigned char*)malloc(ALIGN_AES_BLOCK(TEST_AES_LEN)); + + memset(enData, 0, ALIGN_AES_BLOCK(TEST_AES_LEN)); + + print_hex_dump_bytes("AES_Encrypt_", DUMP_PREFIX_ADDRESS, pData, iSize); + + i = EvpAddCryptoTask(CRYPTO_AES_DECRYPT, (unsigned char*)pData, iSize, enData, pKey, EVPEncryptCb); + + if(i != 0) + { + free(enData); + LOG_EX(LOG_Error, "EvpAddCryptoTask Error: %d\n", i); + } + } + else if(type == CRYPTO_AES_DECRYPT) + { + print_hex_dump_bytes("AES_Decrypt_", DUMP_PREFIX_ADDRESS, pData, iSize); + } + else if(type == CRYPTO_BASE64_ENCODE) + { + int ret = 0; + + LOG_EX(LOG_Info, "Base64(%d):[\n%s]\n", iSize, (char*)pData); + ret = EvpAddCryptoTask(CRYPTO_BASE64_DECODE, (unsigned char*)pData, iSize, NULL, NULL, EVPEncryptCb); + + if(ret != 0) + { + LOG_EX(LOG_Error, "EvpAddCryptoTask Error: %d\n", ret); + } + } + else if(type == CRYPTO_BASE64_DECODE) + { + LOG_EX(LOG_Info, "Base64(%d):[\n%s]\n", iSize, (char*)pData); + } + else if(type == CRYPTO_MD5_FILE) + { + LOG_EX(LOG_Info, "%s MD5 value [%s]\n", (char*)pSrcData, (char*)pData); + } + } + else + { + LOG_EX(LOG_Error, "pData = %p, iError = %d\n", pData, iError); + } + + free((void*)pData); +} + +static void test_aes_async(void) +{ + int i; + unsigned char enData[ALIGN_AES_BLOCK(TEST_AES_LEN)]; + unsigned char* pData = (unsigned char*)malloc(ALIGN_AES_BLOCK(TEST_AES_LEN)); + int outSize = 0; + char* pKey = "xajhuang12345678"; + + for(i = 0; i < TEST_AES_LEN; i++) + { + enData[i] = i % 0xFF; + } + + i = EvpAddCryptoTask(CRYPTO_BASE64_ENCODE, enData, TEST_AES_LEN, pData, pKey, EVPEncryptCb); + + if(i != 0) + { + LOG_EX(LOG_Error, "EvpAddCryptoTask Error: %d\n", i); + free(pData); + } + +} + +static void test_base64_async(void) +{ + int ret = 0; +#if 1 + const char* pSrc = "Wikiversity is a Wikimedia Foundation project devoted to learning resources, learning projects, \ +and research for use in all levels, types, and styles of education from pre-school to university, including professional \ +training and informal learning. We invite teachers, students, and researchers to join us in creating open educational \ +resources and collaborative learning communities. \ +This page is an index of all Wikiversity help and maintenance pages. The following articles contain guidance and \ +information about Editing, Policies and guidelines, and participating in the Wikiversity community. \ +Having trouble finding out what you need to know? If it is not covered by the FAQ, try asking at the Colloquium."; +#else + const char *pSrc = "http://www.164.com"; +#endif + const char *pBase64 = EvpBase64EncodeNoAlign(pSrc); + const char *pDecode = EvpBase64DecodeNoAlign(pBase64); + + fprintf(stdout, "Encode:\n%s\n", pBase64); + fprintf(stdout, "Decode:\n%s\n", pDecode); + +#if 0 + ret = EvpAddCryptoTask(CRYPTO_BASE64_ENCODE, (unsigned char*)pSrc, strlen(pSrc), NULL, NULL, EVPEncryptCb); + + if(ret != 0) + { + LOG_EX(LOG_Error, "EvpAddCryptoTask Error: %d\n", ret); + } +#endif + +} + +static void test_md5file_async(void) +{ + int ret = 0; + const char* pFile = "/root/time.txt"; + + ret = EvpAddCryptoTask(CRYPTO_MD5_FILE, (unsigned char*)pFile, strlen(pFile), NULL, NULL, EVPEncryptCb); + + if(ret != 0) + { + LOG_EX(LOG_Error, "EvpAddCryptoTask Error: %d\n", ret); + } +} + +static void test_s2j_task(void) +{ + PLAYER_TO_CTRL plyCtl; + PPLAYER_TO_CTRL pPlyCtl = NULL; + int err; + const char* pJson = NULL; + + strcpy(plyCtl.musicUuid, "http://www.164.com"); + plyCtl.plySt = 1; + plyCtl.curPos = 12133; + plyCtl.duration = 321000; + + pJson = Struct2Json(&plyCtl, JSON_ENGINE_P2C, TRUE, &err); + + if(pJson != NULL) + { + LOG_EX(LOG_Debug, "Json:\n %s\n", pJson); + + pPlyCtl = (PPLAYER_TO_CTRL)Json2Struct(pJson, JSON_ENGINE_P2C, TRUE, &err); + + if(pPlyCtl != NULL) + { + LOG_EX(LOG_Debug, "Struct:\nmusicUuid: %s\nplySt: %d\ncurPos: %d\nduration: %d\n", + pPlyCtl->musicUuid, pPlyCtl->plySt, pPlyCtl->curPos, pPlyCtl->duration); + + free(pPlyCtl); + } + else + { + LOG_EX(LOG_Debug, "Json2Struct Test Error\n"); + } + + free((void*)pJson); + } + else + { + LOG_EX(LOG_Debug, "test error\n"); + } +} + +extern const char* __ota_Notify_REQ2Json(void *pData); +extern void* __json2OTA_Notify_REQ(const char *pJsonS); +static void __uvThreadTestOTA(void *pParam) +{ + int err = 0, i = 0; + int ret; + const char *pMD5 = NULL; + + char* strMenu[] = { + "Usage:\n", + + "OTA Cmd download : download\n", + "OTA Cmd local : local\n", + "OTA Cmd exec : exec\n", + "Batch Test : batch\n", + "Set Config : ready\n", + "Exit : quit\n", + }; + + while(TRUE) + { + char *pInput = NULL; + char *pSub = NULL; + + + for(i = 0; i < sizeof(strMenu) / sizeof(strMenu[0]); i++) + { + fprintf(stdout, "%s", strMenu[i]); + } + + pInput = readline("Please Choise:"); + + if(pInput == NULL) + { + continue; + } + + pSub = strtok(pInput, " "); + i = 0; + + while(pSub != NULL) + { + OTA_DATA_INFO otaInfo; + POTA_DATA_INFO pInfo = NULL; + + memset(&otaInfo, 0, sizeof(OTA_DATA_INFO)); + + otaInfo.version = 1; + + if(strcmp(pSub, "download") == 0) + { + otaInfo.otaCmd = OTA_CMD_DOWNLOAD; + otaInfo.otaMode = OTA_MODE_NORMAL; + otaInfo.otaFileInfo.size = 21484772; + strcpy(otaInfo.otaFileInfo.url, "http://10.241.0.70/tina/tina_r16_ota.tar.gz"); + strcpy(otaInfo.otaFileInfo.md5, "2d58366a0846f6345730e28b021816d0"); + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_OTA].modAliase, + CMD_OTA_NOTIFY, + JSON_ENGINE_OTA_REQ, + &otaInfo, TRUE); + + LOG_EX(LOG_Debug, "Send OTA Command %s: %d\n", pSub, ret); + } + else if(strcmp(pSub, "local") == 0) + { + otaInfo.otaCmd = OTA_CMD_USED_LOCAL_IMAGE; + otaInfo.otaMode = OTA_MODE_FORCE_NOW; + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_OTA].modAliase, + CMD_OTA_NOTIFY, + JSON_ENGINE_OTA_REQ, + &otaInfo, TRUE); + + LOG_EX(LOG_Debug, "Send OTA Command %s: %d\n", pSub, ret); + } + else if(strcmp(pSub, "exec") == 0) + { + otaInfo.otaCmd = OTA_CMD_EXEC; + otaInfo.otaMode = OTA_MODE_FORCE_NOW; + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_OTA].modAliase, + CMD_OTA_NOTIFY, + JSON_ENGINE_OTA_REQ, + &otaInfo, TRUE); + + LOG_EX(LOG_Debug, "Send OTA Command %s: %d\n", pSub, ret); + } + else if(strcmp(pSub, "batch") == 0) + { +#if 0 + int err; + POTA_DATA_INFO pInfo = NULL; + const char *pJson = NULL; +#endif + +#if 0 + pJson = Struct2Json(&otaInfo, JSON_ENGINE_OTA_REQ, TRUE, &err); + fprintf(stdout, "Json(%p->%d): \n%s\n", &otaInfo, err, pJson); + + + + pInfo = (POTA_DATA_INFO)Json2Struct(pJson, JSON_ENGINE_OTA_REQ, TRUE, &err); + if(pInfo) + { + fprintf(stdout, "JsonInfo: \n%s\n", __ota_Notify_REQ2Json(pInfo)); + } + +#else + pMD5 = EvpMD5HashBufV2((const unsigned char *)&otaInfo, sizeof(OTA_DATA_INFO)); + + err = 0; + for(i = 0; i < 1000000; i++) + { + POTA_DATA_INFO pOInfo = (POTA_DATA_INFO)malloc(sizeof(OTA_DATA_INFO)); + + memcpy(pOInfo, &otaInfo, sizeof(OTA_DATA_INFO)); + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_OTA].modAliase, + CMD_OTA_NOTIFY, + JSON_ENGINE_OTA_REQ, + pOInfo, TRUE); + + free(pOInfo); + + if(ret != 0) + { + err++; + break; + //fprintf(stderr, "ret = %d\n", ret); + } + + + + //fprintf(stdout, "send [%d]: %d\n", i, err); + //LOG_EX(LOG_Debug, "Send OTA Command: %d\n", ret); + //usleep(1000); + } + + fprintf(stdout, "%s\n", pMD5); + free((void*)pMD5); + //fprintf(stdout, "send [%d]: %d\n", i, err); +#endif + } + else if(strcmp(pSub, "ready") == 0) + { + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_OTA].modAliase, + CMD_SYSTEM_STANDBY, "{\"status\" : 0}"); + + LOG_EX(LOG_Debug, "Send Standby Command: %d\n", ret); + } + else if(strcmp(pSub, "quit") == 0) + { + return; + } + + pSub = strtok(NULL, " "); + } + + free(pInput); + + usleep(1000); + } +} + +static void __uvThreadTimer(void *pParams) +{ + while(TRUE) + { + uv_barrier_init(&g_tmSync, 2); + + g_Delay += 1000; + uv_timer_stop(&g_tmTest); + LOG_EX(LOG_Info, "Re Start Timer %u...\n", g_Delay); + uv_timer_start(&g_tmTest, uvSndLessCb, g_Delay, 0); + + uv_barrier_wait(&g_tmSync); + uv_barrier_destroy(&g_tmSync); + + sleep(1); + } +} + +static void __uvThreadTestConfigure(void *pParams) +{ + int i = 0; + int ret; + + char* g_Menu[] = { + "Usage:\n", + "Get Config : get \n", + "Set Config : set \n", + "Change Config : change \n", + "Exit: quit\n", + }; + + while(TRUE) + { + char *pInput = NULL; + char *pSub = NULL; + + + for(i = 0; i < sizeof(g_Menu) / sizeof(g_Menu[0]); i++) + { + fprintf(stdout, "%s", g_Menu[i]); + } + + pInput = readline("Please Choise:"); + + if(pInput == NULL) + { + continue; + } + + pSub = strtok(pInput, " "); + i = 0; + + while(pSub != NULL) + { + if(strcmp(pSub, "get") == 0) + { + char* pKeyName = strtok(NULL, " "); + + if(pKeyName != NULL && strlen(pKeyName) > 0) + { + CFG_ITEM* pCfg; + ret = CfgGetKeyValue(pKeyName, &pCfg); + + if(ret == 0) + { + CfgItemPrint("GetLocalCfg: ", pCfg); + } + else if(ret == -ERR_CFG_WAIT_RSP) + { + LOG_EX(LOG_Debug, "Wait for server response\n"); + } + else + { + LOG_EX(LOG_Error, "Get Configure [%s] Error: %d\n", pKeyName, ret); + } + } + } + else if(strcmp(pSub, "set") == 0) + { + char* pKeyName = strtok(NULL, " "); + char *pKeyType = strtok(NULL, " "); + char* pKeyValue = strtok(NULL, " "); + char* pSaveTo = strtok(NULL, " "); + + if(pKeyName && pKeyValue && pKeyType && pSaveTo + && strlen(pKeyName) > 0 && strlen(pKeyValue) > 0 && strlen(pKeyType) > 0 && strlen(pSaveTo) > 0) + { + CFG_ITEM item; + + item.pKeyName = pKeyName; + item.keyType = strtoul(pKeyType, NULL, 10); + + if(item.keyType == CFG_TYPE_STRING) + { + item.pStrValue = pKeyValue; + } + else if(item.keyType == CFG_TYPE_INT) + { + item.intValue = strtol(pKeyValue, NULL, 10); + } + else if(item.keyType == CFG_TYPE_DOUBLE) + { + item.doubleValue = strtod(pKeyValue, NULL); + } + + ret = CfgAddKeyValue(pKeyName, &item, strtol(pSaveTo, NULL, 10)); + + if(ret == 0) + { + CfgItemPrint("Add Configure: ", &item); + } + else + { + LOG_EX(LOG_Error, "Add Configure [%s] Error: %d\n", pKeyName, ret); + } + } + } + else if(strcmp(pSub, "quit") == 0) + { + return; + } + + pSub = strtok(NULL, " "); + } + + usleep(1000); + } +} + +static void test_task_new(uv_thread_cb pCallback, void* pParams) +{ + uv_thread_t uvSyncThread; + + uv_thread_create(&uvSyncThread, pCallback, pParams); +} + +#define WAKE_CACHE_SIZE (10) + +static unsigned char g_AudioCache[WAKE_CACHE_SIZE]; +static unsigned int g_wtPos = 0; +static unsigned int g_tolCache = 0; + +static void __cacheCAEAudio(unsigned char* pBuf, unsigned int iSize) +{ + if(iSize > WAKE_CACHE_SIZE) + { + return; + } + + memmove(g_AudioCache, g_AudioCache + iSize, WAKE_CACHE_SIZE - iSize); + memcpy(g_AudioCache + WAKE_CACHE_SIZE - iSize, pBuf, iSize); +} + +static void test_move_data(void) +{ + +} + +static void __onAlarmCb(unsigned int tmId, unsigned int status, void *pUserData) +{ + LOG_EX(LOG_Debug, "Time %u On......\n", tmId); +} + +static int g_isExitApp = FALSE; + +static void uvExitLoopCb(uv_timer_t *pParams) +{ + DEBUG_CODE_LINE(); + uv_stop(GetDBusDefaultLoop()); +} + +static void __uvLoopExit(void *pParams) +{ + int ret = 0; + uv_timer_t tmExit; + uv_loop_t* pLoop = GetDBusDefaultLoop(); + DBusConnection* pBus = DBusWithLibuvInit(pLoop, g_ModInfo.modAliase, + DBusOnMessage, + __dBusDeameonCb, + NULL, //KeyEventCb, + &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return; + } + + DBusBoardcastCommand(NULL, 0x11, 10, "xajhuang"); + + //test_task_new(uvExitLoopCb, NULL); + uv_timer_init(pLoop, &tmExit); + uv_timer_start(&tmExit, uvExitLoopCb, 3000, 3000); + + DEBUG_CODE_LINE(); + //RunUVLoop(pLoop); + uv_run(pLoop, UV_RUN_DEFAULT); + //uv_loop_close(pLoop); + DEBUG_CODE_LINE(); + + g_isExitApp = TRUE; + return; +} + +static void __fs_event_handle_cb(uv_fs_event_t *pEvent, const char *pFileName, int events, int status) +{ + char path[MAX_PATH]; + size_t pathSize = MAX_PATH - 1; + + memset(path, 0, MAX_PATH); + uv_fs_event_getpath(pEvent, path, &pathSize); + + fprintf(stdout, "%s: %d, %d\n", path, events, status); +} + +static void __onPrgCb(const char *pReqUrl, const char *pTaskUuid, unsigned char uPercent, void *pUserData) +{ + static unsigned char preCnt = 0; + + if(preCnt != uPercent) + { + preCnt = uPercent; + LOG_EX(LOG_Debug, "[%s](%s): %u%%\n", pReqUrl, pTaskUuid, uPercent); + } + + if(uPercent > 50) + { + //InetCancelDownload(pTaskUuid); + } +} + +static unsigned int g_DlCount = 0; +static void __onDlCb(void *pData, unsigned int size, const char *pReqUrl, const char* pDlPath, const char *pTaskUuid, int iFinished, void *pUserData) +{ + if(g_DlCount > 0) + { + g_DlCount--; + } + + if(iFinished == 0) + { + LOG_EX(LOG_Debug, "Request(%s): [%s] --> [%s] Response: [%u] OK\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else if(iFinished == 1) + { + LOG_EX(LOG_Error, "Request(%s): [%s] --> [%s] Response: [%u] Error\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else + { + LOG_EX(LOG_Error, "Download Error Code: %d\n", iFinished); + } +#if 1 + if(iFinished != 0) + { + const char* pId = InetHttpDlFileAsync(pReqUrl, + pDlPath, + __onDlCb, + NULL,//__onPrgCb, + NULL); + + LOG_EX(LOG_Debug, "Download ID: %s\n", pId); + } +#endif +} + +static void __uvTestSkin(void *pParams) +{ + int tolItems = sizeof(g_SkinDefaultResTable) / sizeof(g_SkinDefaultResTable[0]); +#if 0 + char *pUpg = "[ \ + { \ + \"createTime\": 1510570174000, \ + \"enable\": 1, \ + \"id\": 3, \ + \"md5\": \"af065860c3667ca2508c283d660990f7\", \ + \"osType\": 0, \ + \"remark\": \"音效1文件\", \ + \"resourceName\": \"v111\", \ + \"resourceType\": 1, \ + \"resourceVersion\": \"v0.3.1\", \ + \"size\": 164460, \ + \"updateTime\": 1510570227000, \ + \"url\": \"http://vbox-resource.nos.netease.com/d627159f-bccd-4364-bccc-f196c2b83ffd.mp3\", \ + \"versionId\": 10, \ + \"versionName\": \"0.0.9\", \ + \"versionOsType\": \"0\" \ + } ]"; +#endif +#if 0 + static int i = 0; + + while(i++ < 100) + { + char *pKeyName = (char*)(g_SkinDefaultResTable[random() % tolItems].pKeyName); + char *pResPath = GetSkinsResource(pKeyName, NULL, NULL, NULL); + LOG_EX(LOG_Debug, "[%s] = {%s}\n", pKeyName, pResPath); + + free(pResPath); + sleep(3); + } +#else + for(int i = 0; i < tolItems; i++) + { + int tmUsed = 0; + struct timeval tmStart, tmEnd; + char *pKeyName = (char*)(g_SkinDefaultResTable[i].pKeyName); + char *pResPath = NULL; + + gettimeofday(&tmStart, NULL); + pResPath = GetSkinsResource(pKeyName, NULL, NULL, NULL); + gettimeofday(&tmEnd, NULL); + + tmUsed = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmStart.tv_sec * 1000000 + tmStart.tv_usec); + LOG_EX(LOG_Debug, "(%d):[%s] = {%s}\n", tmUsed, pKeyName, pResPath); + + free(pResPath); + } +#if 0 + fprintf(stdout, "-----------------------\n"); + for(int i = 0; i < tolItems; i++) + { + int tmUsed = 0; + struct timeval tmStart, tmEnd; + char *pKeyName = (char*)(g_SkinDefaultResTable[i].pKeyName); + char *pResPath = NULL; + + gettimeofday(&tmStart, NULL); + pResPath = GetSkinsResource(pKeyName, NULL, NULL, NULL); + gettimeofday(&tmEnd, NULL); + + tmUsed = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmStart.tv_sec * 1000000 + tmStart.tv_usec); + LOG_EX(LOG_Debug, "(%d):[%s] = {%s}\n", tmUsed, pKeyName, pResPath); + + free(pResPath); + } +#endif +#endif +#if 0 + SkinUpgrade(pUpg); + + sleep(5); + + GetSkinsResource("v111", NULL, NULL, NULL); +#endif +} + +static LOG_LEVEL g_logLevelInfo[] = { + LOG_Fatal, LOG_Error, LOG_Warn, LOG_Debug, LOG_Info, + LOG_Test, LOG_Call, LOG_Devp, LOG_Step, LOG_Unknown, LOG_All, LOG_Close + }; + +static void __uvLogTestProc(void *pParams) +{ + while(TRUE) + { + //SysPointMark("-----------------------------------------------------\n"); + + for(int i = 0; i < sizeof(g_logLevelInfo) / sizeof(g_logLevelInfo[0]); i++) + { + UT_string* pString = NULL; + + utstring_new(pString); + utstring_printf(pString, "This is LogLevel %s\n", LogLeveToString(g_logLevelInfo[i])); + //SysPointMark(utstring_body(pString)); + LOG_EX(g_logLevelInfo[i], "This is LogLevel %s\n", LogLeveToString(g_logLevelInfo[i])); + utstring_free(pString); + } + + sleep(1); + } +} + +static void __uvLogCtrlProc(void *pParams) +{ + int i = 0; + int ret; + + const char* g_Menu[] = { + "Usage: enable/disable [params1] [params2]\n" + " help\n", + " quit\n", + }; + + const char* pOptMenu[] = { + "\n operation:\n" + " |--------------------------------------------------------------------------|\n", + " | command | operation | params1 | params2 |\n", + " |--------------------------------------------------------------------------|\n", + " | enable | | | |\n", + " |----------| 0: Set log level | Log level | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | | |\n", + " |----------| 1: Print to file | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | | |\n", + " |----------| 2: Backup to email | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | Log server ip address | Log server port |\n", + " |----------| 3: Send to network |-----------------------|-----------------|\n", + " | disable | | Unused | Unused |\n", + " |--------------------------------------------------------------------------|\n", + }; + + while(TRUE) + { + char *pInput = NULL; + char *pCmd = NULL; + + for(i = 0; i < sizeof(g_Menu) / sizeof(g_Menu[0]); i++) + { + fprintf(stdout, "%s", g_Menu[i]); + } + + pInput = readline("Enter Command:"); + + if(pInput == NULL) + { + continue; + } +#if 1 + pCmd = strtok(pInput, " "); + i = 0; + + while(pCmd != NULL) + { + if(strcmp(pCmd, "help") == 0) + { + for(i = 0; i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0]); i++) + { + if(i == 0) + { + fprintf(stdout, " modName : %-2d --> %s\n", + i, ModuleNameToString(g_pModInfoTable[i].modName)); + } + else + { + fprintf(stdout, "%15s%-2d --> %s\n", "", + i, ModuleNameToString(g_pModInfoTable[i].modName)); + } + } + + for(i = 0; i < sizeof(g_logLevelInfo) / sizeof(g_logLevelInfo[0]); i++) + { + if(i == 0) + { + fprintf(stdout, "\n Log Level: %-2d --> %s\n", i, LogLeveToString(g_logLevelInfo[i])); + } + else + { + fprintf(stdout, "%15s%-2d --> %s\n", "", i, LogLeveToString(g_logLevelInfo[i])); + } + } + + for(i = 0; i < sizeof(pOptMenu) / sizeof(pOptMenu[0]); i++) + { + fprintf(stdout, "%s", pOptMenu[i]); + } + } + else if(strcmp(pCmd, "enable") == 0 + || strcmp(pCmd, "disable") == 0) + { + LOG_CFG_PROTOCOL logItem; + int iCmd, iMod; + char *pParams1 = NULL, *pParams2 = NULL; + char* pMod = strtok(NULL, " "); + char* pOperat = strtok(NULL, " "); + + if(pMod == NULL || strlen(pMod) == 0) + { + LOG_EX(LOG_Error, "Input error, see help\n"); + break; + } + + if(pOperat == NULL || strlen(pOperat) == 0) + { + LOG_EX(LOG_Error, "Input error, see help\n"); + break; + } + + iMod = strtol(pMod, NULL, 10); + + if(iMod < 0 || iMod >= MODULE_MAX) + { + LOG_EX(LOG_Error, "Input error: %s(%d)\n", pMod, iMod); + break; + } + + iCmd = strtol(pOperat, NULL, 10); + + memset(&logItem, 0, sizeof(LOG_CFG_PROTOCOL)); + + + + switch(iCmd) + { + case 0: + pParams1 = strtok(NULL, " "); + if(pParams1 && strlen(pParams1) > 0) + { + int logLevel = strtol(pParams1, NULL, 10); + + if(logLevel >= 0 && logLevel < sizeof(g_logLevelInfo) / sizeof(g_logLevelInfo[0])) + { + fprintf(stdout, "%s %d 0x%08X\n", pCmd, iCmd, g_logLevelInfo[logLevel]); + + logItem.cfgCmd = CMD_LOG_LEVEL; + logItem.iParams2 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + logItem.iParams1 = g_logLevelInfo[logLevel]; + + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + LOG_EX(LOG_Error, "Input error, see help\n"); + } + } + else + { + LOG_EX(LOG_Error, "Input error, see help\n"); + } + break; + + case 1: + logItem.cfgCmd = CMD_LOG_FILE; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + case 2: + logItem.cfgCmd = CMD_LOG_MAIL; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + case 3: + pParams1 = strtok(NULL, " "); + + logItem.cfgCmd = CMD_LOG_NETWORK; + if(pParams1 == NULL || strlen(pParams1) == 0) + { + + logItem.iParams1 = 0; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + pParams2 = strtok(NULL, " "); + + if(pParams2 != NULL && strlen(pParams2) > 0) + { + logItem.iParams1 = inet_addr(pParams1); + logItem.iParams2 = strtol(pParams2, NULL, 10); + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + LOG_EX(LOG_Error, "Input error, pParams2 = %s\n", + SAFE_STRING_VALUE(pParams2)); + } + } + + break; + + default: + LOG_EX(LOG_Error, "Unknown operation(0-3) %s, see help\n", pOperat); + break; + } + +#if 0 + char* pKeyName = strtok(NULL, " "); + char *pKeyType = strtok(NULL, " "); + char* pKeyValue = strtok(NULL, " "); + char* pSaveTo = strtok(NULL, " "); + + if(pKeyName && pKeyValue && pKeyType && pSaveTo + && strlen(pKeyName) > 0 && strlen(pKeyValue) > 0 && strlen(pKeyType) > 0 && strlen(pSaveTo) > 0) + { + CFG_ITEM item; + + item.pKeyName = pKeyName; + item.keyType = strtoul(pKeyType, NULL, 10); + + if(item.keyType == CFG_TYPE_STRING) + { + item.pStrValue = pKeyValue; + } + else if(item.keyType == CFG_TYPE_INT) + { + item.intValue = strtol(pKeyValue, NULL, 10); + } + else if(item.keyType == CFG_TYPE_DOUBLE) + { + item.doubleValue = strtod(pKeyValue, NULL); + } + + ret = CfgAddKeyValue(pKeyName, &item, strtol(pSaveTo, NULL, 10)); + + if(ret == 0) + { + CfgItemPrint("Add Configure: ", &item); + } + else + { + LOG_EX(LOG_Error, "Add Configure [%s] Error: %d\n", pKeyName, ret); + } + } +#endif + } + else if(strcmp(pCmd, "quit") == 0) + { + return; + } + + pCmd = strtok(NULL, " "); + } +#endif + usleep(1000); + } +} + +static void __uvMsgSendTestProc(void *pParams) +{ + char buf[DBUS_MSG_MAX_PAD_SIZE]; + unsigned int i = 0; + + memset(buf, 'a', DBUS_MSG_MAX_PAD_SIZE - 1); + buf[DBUS_MSG_MAX_PAD_SIZE - 1] = 0; + + while(TRUE) + { + // memset(buf, 0, 256); + // sprintf(buf, "%u", i); + + fprintf(stdout, "Send Message: %u\n", i); + DBusSendToCommand(NULL, g_pModInfoTable[MODULE_CONTROLLER].modAliase, CMD_CALL_DIAL, buf); + i++; + sleep(3); + } +} + +static void __uvMsgRecvProc(void *pParams) +{ + while(TRUE) + { + PDBUS_MSG_PACK pMsg = DBusGetMessage(); + PLIBUV_DBUS_PARAMS pInfo = DBusLibuvGetRuntime(); + + do + { + if(pMsg && pInfo) + { + //static PDBUS_MSG_PACK DBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) + DBusOnMessage(pInfo->pLoop, pInfo->pBus, pMsg); + DBusMsgCleanup(pMsg); + } + + pMsg = DBusGetMessage(); + } while(pMsg && pInfo); + + + usleep(100); + } +} + +void test_dbus(void) +{ + DBusError error; + DBusConnection* pBus = NULL; + + dbus_error_init(&error); + + pBus = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + + if (dbus_error_is_set(&error)) + { + fprintf(stdout, "dbus: Could not acquire the session bus\n"); + + dbus_error_free(&error); + return; + } + else + { + fprintf(stdout, "Create Session OK\n"); + } +} + +static unsigned int g_Count1 = 0; +static void __uvThreadRun(void *pParams) +{ + g_Count1++; + usleep(10); +} + +static void __uvThreadTestProc(void *pParams) +{ + LOG_EX(LOG_Debug, "Test Create Thread\n"); + + for(int i = 0; i < 1000; i++) + { + test_task_new(__uvThreadRun, NULL); + usleep(1); + } + + while(TRUE) + { + LOG_EX(LOG_Debug, "Current Cnt: %u\n", g_Count1); + sleep(1); + } +} + +#include "fifo.h" + +static DECLARE_KFIFO(g_TestFifo, unsigned char, 128); + +static void __fifoPut(void *pParams) +{ + int ret = 0; + static unsigned char val = 0; + while(TRUE) + { + for(int i = 0; i < 130; i++) + { + if(kfifo_avail(&g_TestFifo) < 1) + { + ret = kfifo_out(&g_TestFifo, NULL, 1); + } + + ret = kfifo_in_locked(&g_TestFifo, &val, 1); + + if(ret != 1) + { + LOG_EX(LOG_Error, "Add %d ret %d\n", val, ret); + } + val++; + } + + + usleep(10); + return; + } +} + +static void __fifoGet(void *pParams) +{ + unsigned char val[128]; + + while(TRUE) + { + int len = kfifo_len(&g_TestFifo); + + if(len > 0) + { + len = kfifo_out_locked(&g_TestFifo, val, len); + + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, val, len); + fprintf(stdout, "Peek %d\n", len); + } + + usleep(1000); + } +} + +static void __uvThreadTestFifo(void *pParams) +{ + INIT_KFIFO(g_TestFifo); + + test_task_new(__fifoPut, NULL); + sleep(3); + test_task_new(__fifoGet, NULL); +} + +#if 0 +static inline int round_up_pow_of_two(unsigned long x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x + 1; +} + +#define WAKE_CACHE_DATA_SIZE1 (1920000U) +#endif + +typedef struct +{ + char* mcuCmd; +} BYPASS_INFO, *PBYPASS_INFO; + +typedef struct +{ + BYPASS_INFO reported; +} SHADOW_STATE, *PSHADOW_STATE; + +typedef struct +{ + char* method; + int version; + SHADOW_STATE state; +} SHADOW_UPDATE, *PSHADOW_UPDATE; + +static const char* __shadow2Json(PSHADOW_UPDATE pInfo) +{ + cJSON *pRoot, *pStatus, *pReports; + + const char* pJsonS; + + pRoot = cJSON_CreateObject(); + + cJSON_AddNumberToObject(pRoot, "version", pInfo->version); + cJSON_AddItemToObject(pRoot, "method", cJSON_CreateString(pInfo->method)); + + pStatus = cJSON_CreateObject(); + pReports = cJSON_CreateObject(); + + cJSON_AddItemToObject(pRoot, "status", pStatus); + cJSON_AddItemToObject(pStatus, "reports", pReports); + cJSON_AddItemToObject(pReports, "mcuCmd", cJSON_CreateString(pInfo->state.reported.mcuCmd)); + + + pJsonS = cJSON_Print(pRoot); + + + cJSON_Delete(pRoot); + + return pJsonS; +} + +static void __dlThreadRuntimeCb(void *pParams) +{ + pthread_detach(pthread_self()); + pthread_exit(0); +} + +static void __uvThreadTest(void *pParams) +{ + for(int i = 0; i < 100000; i++) + { + uv_thread_t uvThread; + int err = uv_thread_create(&uvThread, __dlThreadRuntimeCb, NULL); + + if(err != 0) + { + LOG_EX(LOG_Error, "Create Thread Error: %d(%d)\n", err, i); + return; + } + + if(i % 1000 == 0) + { + LOG_EX(LOG_Debug, "Create Thread: %d\n", i); + } + usleep(1000); + } +} + +static void __dlTestThread(void* p) +{ + static char* testURL[] = { + "http://vbox-resource.nos.netease.com/20180309192932533Alianwang003.mp3", + "http://vbox-resource.nos.netease.com/20180309192932594Alianwang004.mp3", + "http://vbox-resource.nos.netease.com/20180309192932882Alianwang005.mp3", + "http://vbox-resource.nos.netease.com/20180309192933094Alianwang006.mp3", + "http://vbox-resource.nos.netease.com/20180309192933355Alianwang007.mp3", + "http://vbox-resource.nos.netease.com/20180309192933571Alianwang008.mp3", + "http://vbox-resource.nos.netease.com/20180309192933805Alianwang009.mp3", + "http://vbox-resource.nos.netease.com/20180309192934929Ashiyong002.mp3", + "http://vbox-resource.nos.netease.com/20180309192935659Ashiyong003.mp3", + "http://vbox-resource.nos.netease.com/20180309192935729Ashiyong004.mp3", + "http://vbox-resource.nos.netease.com/20180309192936130Ashiyong005.mp3", + "http://vbox-resource.nos.netease.com/20180309192936192Ashiyong006.mp3", + "http://vbox-resource.nos.netease.com/20180309192936289S001.mp3", + "http://vbox-resource.nos.netease.com/20180309192936471S002.mp3", + "http://vbox-resource.nos.netease.com/20180309192937566S006.mp3", + "http://vbox-resource.nos.netease.com/20180309192937735S007.mp3", + "http://vbox-resource.nos.netease.com/20180309192937793S008.mp3", + "http://vbox-resource.nos.netease.com/20180309192938129S009.mp3", + "http://vbox-resource.nos.netease.com/20180309192938262S010.mp3", + "http://vbox-resource.nos.netease.com/20180309192938975S011.mp3", + "http://vbox-resource.nos.netease.com/20180309192933845Alianwang010.mp3", + "http://vbox-resource.nos.netease.com/20180309192933937Alianwang011.mp3", + "http://vbox-resource.nos.netease.com/20180309192934678Ashiyong001.mp3", + "http://vbox-resource.nos.netease.com/20180605170040224Alianwang012.mp3", + "http://vbox-resource.nos.netease.com/20180605170146178Alianwang014.mp3", + "http://vbox-resource.nos.netease.com/20180605170324285Alianwang013.mp3", + "http://vbox-resource.nos.netease.com/20180605165854636Alianwang002.mp3", + "http://vbox-resource.nos.netease.com/20180607095314669S004-13DB.mp3", + "http://vbox-resource.nos.netease.com/20180607095347590S0053DB.mp3", + "https://vbox-resource.nos-hz.163yun.com/20180625120349098S003+3.mp3", + }; + + //while(TRUE) + { + for(int i = 0; i < sizeof(testURL) / sizeof(testURL[2]); i++) + { + char buf[256]; + + g_DlCount++; + memset(buf, 0, 256); + sprintf(buf, "./dl_%d.mp3", i); + InetHttpDlFileAsync(testURL[i], + buf, + __onDlCb, + NULL,//__onPrgCb, + NULL); + } + + while(g_DlCount) + { + usleep(100000); + } + } +} + +int main(int argc, char **argv) +{ + int i, j, ret = 0; + DBusConnection* pBus = NULL; + uv_timer_t uvSndLess, uvSndMore; + uv_loop_t* pLoop = GetDBusDefaultLoop(); + int modIdx = -1; + char buf[256]; + +#if 0 + FILE* pFile = fopen("/mnt/UDISK/time.txt", "w+"); + + fprintf(stdout, "WAKE_CACHE_DATA_SIZE1(%u) --> %u\n", WAKE_CACHE_DATA_SIZE1, round_up_pow_of_two(WAKE_CACHE_DATA_SIZE1)); + + fprintf(stdout, "127 --> %u\n", roundup_pow_of_two(127)); + + fprintf(stdout, "3 --> %u\n", roundup_pow_of_two(3)); + + fprintf(stdout, "256 --> %u\n", roundup_pow_of_two(256)); + + fprintf(stdout, "1024 * 2 - 1 --> %u\n", roundup_pow_of_two(1024 * 2 - 1)); +#endif +#if 0 + fprintf(stdout, "Wait system reboot for 10s"); + ret = system("sync && ubus call system watchdog \'{\"stop\" : true}\'"); + + sleep(20); + + fprintf(stdout, "Wait WDT 20s End\n"); +#endif + +#if 0 + int fd = open("/dev/watchdog", O_WRONLY); + + if(fd == -1) + { + perror("Open WDT"); + } + + sleep(20); + + fprintf(stdout, "Wait WDT 20s\n"); +#endif + +#ifdef PLATFORM_R16 +#endif + + //fprintf(stdout, "uv_default_loop = %p\n", pLoop); + + if(argc <= 1) + { + fprintf(stderr, "usage: ./dbus-r16.exe <0-%d>\n", MODULE_MAX - 1); + return 0; + } + + modIdx = strtol(argv[1], NULL, 10); + + if(modIdx >= MODULE_MAX || modIdx < 0) + { + fprintf(stderr, "Bad params of %s, max value is %d\n", argv[1], MODULE_MAX - 1); + return 0; + } + + memcpy(&g_ModInfo, &g_pModInfoTable[modIdx], sizeof(MOD_INFO_TABLE)); + + pBus = DBusWithLibuvInit(pLoop, g_ModInfo.modAliase, + DBusOnMessage, + NULL, + NULL, + &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + exit(1); + return 0; + } + + //test_task_new(__uvThreadTest, NULL); + + DumpCurServerAddr("Default"); + +#if 1 + for(int i = 0; i < 1; i++) + { + char buf[256]; + + memset(buf, 0, 256); + + sprintf(buf, "dl_%d.bin", i); + + InetHttpDlFileAsync("http://10.240.84.163/tina_r16_ota_21.tar.gz", + //"https://vbox-resource.nos-hz.163yun.com/20180628092806976tina_r16_ota_32.tar.gz", + buf, + __onDlCb, + NULL,//__onPrgCb, + NULL); + } +#endif + //SetCurrentServerMode(DEV_MODE); + //DumpCurServerAddr("DEV_MODE"); + +#if 0 + SetCurrentServerMode(TEST_MODE); + DumpCurServerAddr("TEST_MODE"); + + SetCurrentServerMode(PUBLISH_MODE); + DumpCurServerAddr("PUBLISH_MODE"); +#endif + + //test_task_new(__uvMsgRecvProc, NULL); + + //HttpPostLogFile("{}"); + + //SysPointMarkInit("123456", -1, -1); + + //SysPointMarkUpload(); +#if 0 + for(int i = 0; i < 1000; i++) + { + void* pMalloc = malloc(1024 * 1024); + + if(pMalloc == NULL) + { + LOG_EX(LOG_Error, "%d: Malloc Error\n", i); + } + else + { + LOG_EX(LOG_Debug, "%d: Malloc %p\n", i, pMalloc); + + memset(pMalloc, 0, 1024 * 1024); + } + + usleep(100000); + } +#endif + +#if 0 + g_pOnKevEvt = (uv_fs_event_t*)malloc(sizeof(uv_fs_event_t)); + + uv_fs_event_init(pLoop, g_pOnKevEvt); + + uv_fs_event_start(g_pOnKevEvt, run_command, "./1.txt", UV_FS_EVENT_RECURSIVE); +#endif + + //test_task_new(__dlTestThread, NULL); +#if 0 + if(modIdx == 20) + { + IHW_EnableLogLevel(LOG_All, 1); + test_task_new(__uvLogCtrlProc, NULL); + } + else if(modIdx == 19) + { + test_task_new(__uvLogTestProc, NULL); + } + else if(modIdx == 21) + { + test_task_new(__uvMsgSendTestProc, NULL); + } + else if(modIdx == 15) + { + test_task_new(__uvThreadTestProc, NULL); + } + else if(modIdx == 16) + { + test_task_new(__uvThreadTestFifo, NULL); + } +#endif + //LOG_EX(LOG_Debug, "Chip Serial: [%s]\n", GetCpuSerial()); + //LOG_EX(LOG_Debug, "Chip ID: [%s]\n", GetCpuChipId()); + + //LOG_BUF(LOG_Error, g_pModInfoTable, 64); + +// DBusWithLibuvCfgInit(OnCfgMsgCb); + +#if 0 + uv_timer_init(pLoop, &uvSndLess); + uvSndLess.data = pBus; + uv_timer_start(&uvSndLess, uvSndLessCb, 1000, 3000); +#endif + //uv_timer_init(pLoop, &uvSndMore); + //uv_timer_start(&uvSndMore, uvTimeoutCb, 3000, 10000); + //EvpEncrypto(); + //LOG_EX(LOG_Info, "Struct --> Json: [%s]\n", Struct2Json(NULL, 0)); + + //Json2Struct(NULL, 0); + + //free((void*)EvpBase64Encode(pSrc)); + + //LOG_EX(LOG_Debug, "Base") + //free((void*)EvpMD5HashFile("/root/time.txt")); + //test_evp_aes(); + //test_aes_async(); + //test_base64_async(); + //test_md5file_async(); + //test_task_new(__uvThreadTestConfigure); + //test_task_new(__uvThreadTestOTA, NULL); + //test_task_new(__uvThreadTimer, NULL); + //uv_timer_init(GetDBusDefaultLoop(), &g_tmTest); + //LOG_EX(LOG_Info, "Start Timer............\n"); + //uv_timer_start(&g_tmTest, uvSndLessCb, g_Delay, 0); + + //test_task_new(__uvThreadTimer, NULL); + //test_s2j_task(); + + //test_base64_async(); + + //test_move_data(); + + //AlarmTimerInit(pLoop); + +#if 0 + for(i = REPEAT_MODE_NONE; i <= REPEAT_MODE_HOLIDAY; i++) + { + { + AlarmTimerAdd2(2017 - 1900, 11 - 1, 28, + 13, 50, 30, + 0, + i, + NULL, 0, 0, NULL, NULL); + + AlarmTimerAdd2(2017-1900, 11-1, 28, + 23, 50, 30, + 0, + i, + NULL, 0, 1, NULL, NULL); + } + } +#endif +#if 0 + struct tm localTime; + time_t timeStamp = time((time_t*)NULL) + 10; + localtime_r(&timeStamp, &localTime); + + AlarmTimerAdd(2018-1900, 6-1, 26, + localTime.tm_hour, localTime.tm_min, localTime.tm_sec, + 0, + REPEAT_MODE_MONTH_LAST_DAY, + __onAlarmCb, 0, NULL, NULL); +#endif +#if 0 + for(i = REPEAT_MODE_NONE; i <= REPEAT_MODE_HOLIDAY; i++) + { + struct tm localTime; + + localtime_r(&timeStamp, &localTime); + + AlarmTimerAdd(2017-1900, 11-1, 29, + localTime.tm_hour, localTime.tm_min, localTime.tm_sec, + 0, + 1, + NULL, 0, i % 2, NULL, NULL); + } +#endif + + //InetSmtpSendEmail(); + +#if 1 +#if 1 + +#endif +#if 0 + if(modIdx == 18) + { + SkinInit(); + //SkinIsVerifyRes(TRUE); +#if 0 + char* path = "/mnt/UDISK/skinupgrade.txt"; + char* pUpgCmd = "[{\"createTime\":1517832224000,\"enable\":1,\"id\":170," + "\"md5\":\"0c8d2d487e485cf3553d7e2818ac42d9\",\"osType\":0," + "\"remark\":\"101\",\"resourceName\":\"v101\",\"resourceType\":1," + "\"resourceVersion\":\"0.3.2\",\"size\":33734,\"updateTime\":1517832224000," + "\"url\":\"http://vbox-resource.nos.netease.com/2536ded2-71a5-40ab-98dc-fe824fbbfb64.mp3\"," + "\"versionId\":68,\"versionName\":\"0.3.2\",\"versionOsType\":\"0\"}]"; + + + FILE* pFp = fopen(path, "rw"); + int fileSize = 0; + + GET_FILE_SIZE(path, fileSize); + + + fprintf(stdout, "%s size = %d\n", path, fileSize); + + if(pFp && fileSize > 0) + { + char* pData = (char*)malloc(fileSize); + + ret = fread(pData, fileSize, 1, pFp); + + fprintf(stdout, "Read: %s\n", pData); + + fclose(pFp); + + SkinUpgrade(pData); + + free(pData); + } +#else + //const char* GetSkinsResource(const char [in] *pKeyName, int [out] *pResType, int [out] *pVersion, const char [out] **pComeFrom) + + //fprintf(stdout, "[v001] = {%s}\n", GetSkinsResource("v001", NULL, NULL, NULL)); + //fprintf(stdout, "[v109] = {%s}\n", GetSkinsResource("v109", NULL, NULL, NULL)); + //fprintf(stdout, "[v311] = {%s}\n", GetSkinsResource("v311", NULL, NULL, NULL)); + + //test_task_new(__uvTestSkin, NULL); +#endif + } +#endif +#endif + +#if 0 +#define MAIL_SENDER ("pv1_es2@163.com") +#define SENDER_PASSWORD ("pv1Dev163") +#define MAIL_RECEIVER ("pv1_es2@163.com") +#define MAIL_SERVER ("smtps://smtp.163.com") +//#else +#define MAIL_SENDER ("pv1_es2@hotmail.com") +#define SENDER_PASSWORD ("netEase163") +#define MAIL_RECEIVER ("pv1_es2@163.com") +#define MAIL_SERVER ("smtp://smtp-mail.outlook.com") +#endif + +#if 0 + SMTP_MAIL_CONFIG smtpCfg; + memset(&smtpCfg, 0, sizeof(SMTP_MAIL_CONFIG)); + + smtpCfg.pUserName = MAIL_SENDER; + smtpCfg.pPassword = SENDER_PASSWORD; + smtpCfg.pSmtpServer = MAIL_SERVER; + + const char *pFrom = MAIL_SENDER; + const char *pTo[] = {"pv1_es2@163.com", "pv1_es2@126.com", NULL}; + const char *pCc[] = {"xajhuang@qq.com", "xajhuang@163.com", NULL}; + const char *pTitle = "Log Message"; + const char *pMessage = "Hi All: This is log backup mail."; + const char *pAttact[] = {"mail.txt", "time.txt", NULL}; + + InetSmtpSendEmail(pFrom, pTo, pCc, pTitle, pMessage, pAttact, &smtpCfg); +#endif + + // InetHttpUploadFileSync(UPL_HTTP_URL, "./time.txt"); +#if 0 + if((i = GZipFileCompress("./input.txt", "./input.gz")) != 0) + { + LOG_EX(LOG_Error, "Create Gzip File Error: %d\n", i); + } +//#else + + while(TRUE) + { + for(i = 0; i < 3010; i++) + { + LOG_EX(LOG_Debug, "This is log %d\n", j++); + } + + sleep(1); + } +#endif + + RunUVLoop(pLoop); + + while(TRUE) + { + usleep(1000); + } + + return (0); +} diff --git a/Framework/Compress/zlib.c b/Framework/Compress/zlib.c new file mode 100644 index 0000000..b78f863 --- /dev/null +++ b/Framework/Compress/zlib.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "crypto.h" + +#define CHUNK_BLOCK (16384) + +/* Compress from file source to file dest until EOF on source. + def() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_STREAM_ERROR if an invalid compression + level is supplied, Z_VERSION_ERROR if the version of zlib.h and the + version of the library linked do not match, or Z_ERRNO if there is + an error reading or writing the files. */ +int GZipFileCompress(const char* pInput, const char* pOutput) +{ + int ret, isFlush; + unsigned int have; + z_stream strm; + char strPath[256]; + unsigned char in[CHUNK_BLOCK]; + unsigned char out[CHUNK_BLOCK]; + FILE *source, *dest; + + if (pInput == NULL) + { + return (Z_ERRNO); + } + + if(access(pInput, F_OK) != 0) + { + return (Z_ERRNO); + } + + //fprintf(stdout, "in: %s\n", pInput); + + source = fopen(pInput, "r+"); + + memset(strPath, 0, 256); + if (pOutput == NULL || strlen(pOutput) == 0) + { + sprintf(strPath, "%s.gz", pInput); + dest = fopen(strPath, "w+"); + + //fprintf(stdout, "out: %s\n", strPath); + } + else + { + dest = fopen(pOutput, "w+"); + //fprintf(stdout, "out: %s\n", pOutput); + } + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + //ret = deflateInit(&strm, level); + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY); + + if (ret != Z_OK) + { + fclose(source); + fclose(dest); + return ret; + } + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK_BLOCK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + fclose(source); + fclose(dest); + return Z_ERRNO; + } + isFlush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = CHUNK_BLOCK; + strm.next_out = out; + ret = deflate(&strm, isFlush); /* no bad return value */ + have = CHUNK_BLOCK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)deflateEnd(&strm); + fclose(source); + fclose(dest); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when last data in file processed */ + } while (isFlush != Z_FINISH); + + /* clean up and return */ + (void)deflateEnd(&strm); + + fflush(dest); + + fclose(source); + fclose(dest); + return Z_OK; +} + diff --git a/Framework/Configure/config_engine.c b/Framework/Configure/config_engine.c new file mode 100644 index 0000000..4b5c276 --- /dev/null +++ b/Framework/Configure/config_engine.c @@ -0,0 +1,1042 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "config_engine.h" +#include "libuv_dbus.h" + +#define PROCESS_MUTEX_KEY ("/root/config_server.pid") +#define CFG_SYNC_TIME_OF_SECONDS (1) + + +static PCFG_ITEM __cfgAddItem(const char *pKeyName, const char *pKeyValue, int iType, int overWrite, int saveToDB, int* pErr); + +typedef struct +{ + char keyName[MAX_CFG_KEY_NAME]; + uint32_t tmCached; + + UT_hash_handle hh; ///< UT Hash handle +} CFG_CACHE_ITEM, *PCFG_CACHE_ITEM; + +static sqlite3* g_pSqlFileDB = NULL; +static PCFG_ITEM g_pCfgItems = NULL; +static PCFG_CACHE_ITEM g_pCfgCacheItems = NULL; +static int g_bIsCfgSvr = FALSE; +static uv_rwlock_t g_uvHashRwLock; +static uv_rwlock_t g_uvCacheRwLock; +static uv_timer_t g_uvSyncSvr; + +#if 0 +#define INT_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS integer(" \ + "keyName TEXT PRIMARY KEY NOT NULL," \ + "keyValue INTEGER NOT NULL," \ + "keyModule INTEGER NOT NULL," \ + "CreatedTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") + +#define STRING_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS string(" \ + "keyName TEXT PRIMARY KEY NOT NULL," \ + "keyValue TEXT NOT NULL," \ + "keyModule INTEGER NOT NULL," \ + "CreatedTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") + +#define FLOAT_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS double(" \ + "keyName TEXT PRIMARY KEY NOT NULL," \ + "keyValue NUMERIC NOT NULL," \ + "keyModule INTEGER NOT NULL," \ + "CreatedTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") +#endif + +#define FIRMWARE_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS %s (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "keyName TEXT UNIQUE NOT NULL," \ + "keyValue TEXT NOT NULL," \ + "keyType INTEGER NOT NULL);") + + +static const char* __cfgGetKeyTypeString(int keyType) +{ + switch(keyType) + { + case 0: + return ("string"); + case 1: + return ("integer"); + case 2: + return ("double"); + } + + return ("Unknown Type"); +} + + +static int __cfgItem2CfgRsp(PCFG_ITEM pCfgItem, PCFG_API_RSP pRsp) +{ + if(pCfgItem == NULL || pRsp == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + memset(pRsp->keyValue, 0, MAX_CFG_KEY_VALUE); + pRsp->keyType = pCfgItem->keyType; + + if(pCfgItem->keyType == CFG_TYPE_STRING) + { + strncpy(pRsp->keyValue, pCfgItem->pStrValue, MAX_CFG_KEY_VALUE); + } + else if(pCfgItem->keyType == CFG_TYPE_INT) + { + sprintf(pRsp->keyValue, "%d", pCfgItem->intValue); + } + else if(pCfgItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(pRsp->keyValue, "%f", pCfgItem->doubleValue); + } + + pRsp->errNo = 0; + + return (0); +} + +static int __cfgMsg2CfgItem(int keyType, const char *pKeyName, const char *pKeyValue, PCFG_ITEM pCfgItem) +{ + int iValue; + double dValue; + char *pEndPtr = NULL; + + if(pKeyName == NULL || pKeyValue == NULL || pCfgItem == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + strcpy(pCfgItem->pKeyName, pKeyName); + pCfgItem->keyType = keyType; + pCfgItem->keyModule = DBusLibuvGetRuntime()->modName; + + switch(keyType) + { + case CFG_TYPE_STRING: + strcpy(pCfgItem->pStrValue, pKeyValue); + break; + + case CFG_TYPE_INT: + iValue = strtol(pKeyValue, NULL, 10); + + if(errno == ERANGE || errno == EINVAL) + { + return (-ERR_STR_CONVERT); + } + else + { + pCfgItem->intValue = iValue; + } + break; + + case CFG_TYPE_DOUBLE: + dValue = strtod(pKeyValue, &pEndPtr); + + if((errno == ERANGE) || (dValue == 0 && (strcmp(pKeyValue, pEndPtr) == 0))) + { + return (-ERR_STR_CONVERT); + } + else + { + pCfgItem->doubleValue = dValue; + } + + break; + + default : + return (-ERR_UNKNOWN_TYPE); + } + + return (0); +} + +static int __cfgMsg2CfgItemV2(int keyType, const char *pKeyName, const char *pKeyValue, PCFG_ITEM* pItem) +{ + int iSize; + PCFG_ITEM pCfgItem = (PCFG_ITEM)malloc(sizeof(CFG_ITEM)); + char* pCache = NULL; + + if(pKeyName == NULL || pKeyValue == NULL || pCfgItem == NULL) + { + free(pCfgItem); + return (-ERR_INPUT_PARAMS); + } + + switch(keyType) + { + case CFG_TYPE_STRING: + iSize += strlen(pKeyValue) + 1; + pCache = (char*)malloc(iSize); + memset(pCache, 0, iSize); + pCfgItem->pKeyName = pCache; + pCfgItem->pStrValue = pCache + strlen(pKeyName) + 1; + __cfgMsg2CfgItem(pCfgItem->keyType, pKeyName, pKeyValue, pCfgItem);; + break; + + case CFG_TYPE_INT: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, pKeyName); + __cfgMsg2CfgItem(pCfgItem->keyType, pKeyName, pKeyValue, pCfgItem);; + break; + + case CFG_TYPE_DOUBLE: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, pKeyName); + __cfgMsg2CfgItem(pCfgItem->keyType, pKeyName, pKeyValue, pCfgItem);; + break; + + default: + free(pCfgItem); + return -ERR_UNKNOWN_TYPE; + } + + *pItem = pCfgItem; + + return 0; +} + +int Sqlite3SyncDB(sqlite3* pSqlMemory, const char* pMemDbName, const char* pDBFilePath, const char* pFileDbName, int isSave) +{ + int rc; + sqlite3* pSqlFile; + sqlite3_backup* pSqlBackup; + sqlite3* pSyncDest; + sqlite3* pSyncSrc; + + rc = sqlite3_open(pDBFilePath, &pSqlFile); + + if(rc != SQLITE_OK) + { + return -ERR_OPEN_SQLITE3_DB; + } + + if(pDBFilePath == NULL || strlen(pDBFilePath) == 0) + { + pMemDbName = "main"; + } + + if(pFileDbName == NULL || strlen(pFileDbName) == 0) + { + pFileDbName = "main"; + } + + pSyncSrc = isSave ? pSqlMemory : pSqlFile; + pSyncDest = isSave ? pSqlFile : pSqlMemory; + + pSqlBackup = sqlite3_backup_init(pSyncDest, pMemDbName, pSyncSrc, pFileDbName); + + if(pSqlBackup != NULL) + { +#if 1 + do + { + rc = sqlite3_backup_step(pSqlBackup, 10); + + if(rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED) + { + sqlite3_sleep(100); + } + } while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED); +#else + sqlite3_backup_step(pSqlBackup, -1); +#endif + sqlite3_backup_finish(pSqlBackup); + } + else + { + LOG_EX(LOG_Error, "Backup Database Error\n"); + } + + rc = sqlite3_errcode(pSyncDest); + + return rc; +} + +static int __sqlite3LoadCb(void* data, int argc, char** argv, char** azColName) +{ + + if(argc == 4) + { + int iSize; + PCFG_ITEM pCfgItem = (PCFG_ITEM)malloc(sizeof(CFG_ITEM)); + char* pCache = NULL; + int ret = 0; + + pCfgItem->keyType = atoi(argv[3]); + pCfgItem->keyModule = *(int*)data; + iSize = strlen(argv[1]) + 1; + + switch(pCfgItem->keyType) + { + case CFG_TYPE_STRING: + iSize += strlen(argv[2]) + 1; + pCache = (char*)malloc(iSize); + memset(pCache, 0, iSize); + pCfgItem->pKeyName = pCache; + pCfgItem->pStrValue = pCache + strlen(argv[1]) + 1; + ret = __cfgMsg2CfgItem(pCfgItem->keyType, argv[1], argv[2], pCfgItem);; + break; + + case CFG_TYPE_INT: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, argv[1]); + ret = __cfgMsg2CfgItem(pCfgItem->keyType, argv[1], argv[2], pCfgItem);; + break; + + case CFG_TYPE_DOUBLE: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, argv[1]); + ret = __cfgMsg2CfgItem(pCfgItem->keyType, argv[1], argv[2], pCfgItem);; + break; + + default: + free(pCfgItem); + return -ERR_UNKNOWN_TYPE; + } + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + + if(ret == 0) + { + CfgItemPrint("Load Configure: ", pCfgItem); + } + } + else + { + LOG_EX(LOG_Error, "argc = %d\n", argc); + } + + return 0; +} + +static int __cfgLoadGlobalConfig(void) +{ + int rc = 0; + char* pErrMsg = NULL; + char sqlCmd[1024]; + PLIBUV_DBUS_PARAMS pContext = DBusLibuvGetRuntime(); + + memset(sqlCmd, 0, 1024); + sprintf(sqlCmd, "SELECT * FROM %s", MODULE_ALIAS_NAME(MODULE_CONFIGURE)); + + // get global configure + rc = sqlite3_exec(g_pSqlFileDB, sqlCmd, __sqlite3LoadCb, (void*)MODULE_CONFIGURE, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQLite3 Query Error: %s\n", pErrMsg); + return -ERR_SQL_QUERY; + } + + if(pContext->modName != MODULE_CONFIGURE) + { + memset(sqlCmd, 0, 1024); + sprintf(sqlCmd, "SELECT * FROM %s", MODULE_ALIAS_NAME(pContext->modName)); + + // get local configure + rc = sqlite3_exec(g_pSqlFileDB, sqlCmd, __sqlite3LoadCb, (void*)&pContext->modName, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQLite3 Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + return -ERR_SQL_QUERY; + } + } + + return 0; +} + + +void CfgItemPrint(const char* pPrefix, PCFG_ITEM pCfgItem) +{ + if(pCfgItem == NULL) + { + fprintf(stderr, "CfgItemPrint: NULL\n"); + return; + } + + switch(pCfgItem->keyType) + { + case 0: + LOG_EX(LOG_Debug, "%s[%s] = \"%s\", \ttype = %s, \tmodule = %s\n", pPrefix ? pPrefix : "", + pCfgItem->pKeyName, pCfgItem->pStrValue, __cfgGetKeyTypeString(pCfgItem->keyType), ModuleNameToString(pCfgItem->keyModule)); + break; + + case 1: + LOG_EX(LOG_Debug, "%s[%s] = %d, \ttype = %s, \tmodule = %s\n", pPrefix ? pPrefix : "", + pCfgItem->pKeyName, pCfgItem->intValue, __cfgGetKeyTypeString(pCfgItem->keyType), ModuleNameToString(pCfgItem->keyModule)); + break; + + case 2: + LOG_EX(LOG_Debug, "%s[%s] = %f, \ttype = %s, \tmodule = %s\n", pPrefix ? pPrefix : "", + pCfgItem->pKeyName, pCfgItem->doubleValue, __cfgGetKeyTypeString(pCfgItem->keyType), ModuleNameToString(pCfgItem->keyModule)); + break; + + default: + LOG_EX(LOG_Error, "Unknown type = %d\n", pCfgItem->keyType); + break; + } + +} + +int CfgAddGlobalConfig(const char *pKeyName, const char *pKeyValue, CFG_DATA_TYPE keyType) +{ + CFG_API_REQ req; + int ret; + + if(pKeyName == NULL || pKeyValue == NULL || strlen(pKeyName) == 0 || strlen(pKeyValue) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + if(keyType < 0 || keyType > CFG_TYPE_DOUBLE) + { + return (-ERR_INPUT_PARAMS); + } + + memset(&req, 0, sizeof(CFG_API_REQ)); + + strncpy(req.keyName, pKeyName, MAX_CFG_KEY_NAME); + strncpy(req.keyValue, pKeyValue, MAX_CFG_KEY_VALUE); + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONFIGURE].modAliase, + CMD_CFG_ADD_REQ, + JSON_ENGINE_CFG_REQ, + &req, TRUE); + + if(ret == 0) + { + return (-ERR_CFG_WAIT_RSP); + } + else + { + return (ret); + } +} + +int CfgAddKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB) +{ + int err = 0; + PCFG_ITEM pCfgItem = NULL; + + if(pItem == NULL || pKeyName == NULL || strlen(pKeyName) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem != NULL) + { + return (-ERR_CFG_ITEM_EXIST); + } + + if(pItem->keyType == CFG_TYPE_STRING) + { + __cfgAddItem(pKeyName, (const char*)pItem->pStrValue, pItem->keyType, FALSE, saveToDB, &err); + } + else + { + char buf[256]; + memset(buf, 0, 256); + + if(pItem->keyType == CFG_TYPE_INT) + { + sprintf(buf, "%d", pItem->intValue); + } + else if(pItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(buf, "%f", pItem->doubleValue); + } + + __cfgAddItem(pKeyName, (const char*)buf, pItem->keyType, FALSE, saveToDB, &err); + } + + return (err); +} + +int CfgChangeKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB) +{ + int err = 0; + PCFG_ITEM pCfgItem = NULL; + + if(pItem == NULL || pKeyName == NULL || strlen(pKeyName) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem == NULL) + { + return (-ERR_CFG_NOITEM); + } + + HASH_DEL(g_pCfgItems, pCfgItem); + + if(pItem->keyType == CFG_TYPE_STRING) + { + __cfgAddItem(pKeyName, (const char*)pItem->pStrValue, pItem->keyType, FALSE, saveToDB, &err); + } + else + { + char buf[256]; + memset(buf, 0, 256); + + if(pItem->keyType == CFG_TYPE_INT) + { + sprintf(buf, "%d", pItem->intValue); + } + else if(pItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(buf, "%f", pItem->doubleValue); + } + + __cfgAddItem(pKeyName, (const char*)buf, pItem->keyType, FALSE, saveToDB, &err); + } + + return (err); +} + +int CfgGetKeyValue(const char* pKeyName, PCFG_ITEM* pItem) +{ + PCFG_ITEM pCfgItem = NULL; + PLIBUV_DBUS_PARAMS pContext = DBusLibuvGetRuntime(); + + if(pItem == NULL || pKeyName == NULL || strlen(pKeyName) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem == NULL) + { + if(pContext->modName == MODULE_CONFIGURE) + { + return (-ERR_CFG_NOITEM); + } + else + { + CFG_API_REQ req; + int ret = 0; + memset(&req, 0, sizeof(CFG_API_REQ)); + strncpy(req.keyName, pKeyName, MAX_CFG_KEY_NAME); + ret = DBusJsonSendToCommand(NULL, g_pModInfoTable[MODULE_CONFIGURE].modAliase, CMD_CFG_GET_REQ, JSON_ENGINE_CFG_REQ, &req, TRUE); + + if(ret == 0) + { + return (-ERR_CFG_WAIT_RSP); + } + else + { + return (ret); + } + } + } + + *pItem = pCfgItem; + + return 0; +} + +static int __cfgCreateCfgFile(const char* pCfgFilePath) +{ + /*const char* pSqlIntDB = NULL; + const char* pSqlFloatDB = NULL; + const char* pSqlStringDB = NULL; */ + char* pErrMsg = NULL; + int rc = 0; + int i = 0; + + rc = sqlite3_open_v2(pCfgFilePath, &g_pSqlFileDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + + if(rc) + { + LOG_EX(LOG_Error, "sqlite3_open_v2 error: %s\n", pCfgFilePath); + return -ERR_OPEN_SQLITE3_DB; + } + + for(i = 0; (i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0])); i++) + { + char sqlBuf[1024]; + + memset(sqlBuf, 0, 1024); + + sprintf(sqlBuf, FIRMWARE_TBL_SQL_CMD, MODULE_ALIAS_NAME(i)); + + rc = sqlite3_exec(g_pSqlFileDB, sqlBuf, NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + uv_fs_t uvFs; + LOG_EX(LOG_Error, "Create Tbl[%d] Error: %s\n", i, pErrMsg); + sqlite3_free(pErrMsg); + uv_fs_unlink(GetDBusDefaultLoop(), &uvFs, pCfgFilePath, NULL); + return -ERR_SQLITE3_CREATE_TABLE; + } + } + + return 0; +} + +#if 0 +static void onSigTermProgressExit(int sign) +{ + if(g_bIsCfgSvr) + { + } + + kill(getpid(), SIGKILL); +} + +static void onProgressExit(void) +{ + onSigTermProgressExit(0); +} +#endif + + +static int __cfgCheckCfgSvrRun(void) +{ + int rc; + int fd = open(PROCESS_MUTEX_KEY, O_CREAT | O_RDWR, 0666); + + if(fd == -1) + { + LOG_EX(LOG_Debug, "Open File Error\n"); + } + + rc = flock(fd, LOCK_EX | LOCK_NB); + + if(rc == -1) + { + LOG_EX(LOG_Debug, "Configure server running\n"); + return FALSE; + } + else + { + LOG_EX(LOG_Debug, "Configure server stoped\n"); + return TRUE; + } +} + +static int __cfgAddToCache(const char *pKeyName) +{ + PCFG_CACHE_ITEM pItem = NULL; + + uv_rwlock_rdlock(&g_uvCacheRwLock); + HASH_FIND_STR(g_pCfgCacheItems, pKeyName, pItem); + uv_rwlock_rdunlock(&g_uvCacheRwLock); + + if(pItem != NULL) + { + HASH_DEL(g_pCfgCacheItems, pItem); + free(pItem); + } + + pItem = (PCFG_CACHE_ITEM)malloc(sizeof(CFG_CACHE_ITEM)); + + strncpy(pItem->keyName, pKeyName, MAX_CFG_KEY_NAME); + pItem->tmCached = LIBUV_CURRENT_TIME_MS(); + + uv_rwlock_wrlock(&g_uvCacheRwLock); + HASH_ADD_STR(g_pCfgCacheItems, keyName, pItem); + uv_rwlock_wrunlock(&g_uvCacheRwLock); + + return (0); +} + +static PCFG_ITEM __cfgAddItem(const char *pKeyName, const char *pKeyValue, int iType, int overWrite, int saveToDB, int* pErr) +{ + PCFG_ITEM pCfgItem = NULL; + int iSize = 0; + char *pCache = NULL; + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem != NULL) + { + if(overWrite) + { + HASH_DEL(g_pCfgItems, pCfgItem); + free(pCfgItem->pKeyName); + free(pCfgItem); + } + else + { + if(pErr) + { + *pErr = -ERR_CFG_NOITEM; + } + + return NULL; + } + } + + if(iType == CFG_TYPE_STRING) + { + iSize = strlen(pKeyName) + strlen(pKeyValue) + 2; + } + else + { + iSize = strlen(pKeyName) + 1; + } + + pCache = (char *)malloc(iSize); + + memset(pCache, 0, iSize); + pCfgItem = (PCFG_ITEM)malloc(sizeof(CFG_ITEM)); + + + pCfgItem->pKeyName = pCache; + + if(iType == CFG_TYPE_STRING) + { + pCfgItem->pStrValue = pCache + strlen(pKeyName) + 1; + } + + __cfgMsg2CfgItem(iType, pKeyName, pKeyValue, pCfgItem); + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + + // if need save this configure item to database + if(saveToDB) + { + __cfgAddToCache(pKeyName); + } + + if(pErr) + { + *pErr = 0; + } + + return (pCfgItem); +} + +static void __cfgSyncServer(void) +{ + if(HASH_COUNT(g_pCfgCacheItems) > 0) + { + PCFG_CACHE_ITEM pItem = NULL, pTemp = NULL; + + sqlite3_exec(g_pSqlFileDB, "BEGIN TRANSACTION;", NULL, NULL, NULL); + + HASH_ITER(hh, g_pCfgCacheItems, pItem, pTemp) + { + PCFG_ITEM pCfgItem = NULL; + + if(CfgGetKeyValue(pItem->keyName, &pCfgItem) == 0) + { + char* pSqlInsertCmd = (char*)malloc(1024 * 4); + char* pSqlUpgradeCmd = (char*)malloc(1024 * 4); + memset(pSqlInsertCmd, 0, 1024 * 4); + memset(pSqlUpgradeCmd, 0, 1024 * 4); + + if(pCfgItem->keyType == CFG_TYPE_STRING) + { + sprintf(pSqlInsertCmd, "INSERT OR IGNORE INTO %s (keyName, keyValue, keyType) VALUES (\'%s\', \'%s\', %d)", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pKeyName, pCfgItem->pStrValue, pCfgItem->keyType); + + sprintf(pSqlUpgradeCmd, "UPDATE %s SET keyValue = \'%s\', keyType = %d WHERE keyName = \'%s\'", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pStrValue, pCfgItem->keyType, pCfgItem->pKeyName); + } + else if(pCfgItem->keyType == CFG_TYPE_INT) + { + sprintf(pSqlInsertCmd, "INSERT OR IGNORE INTO %s (keyName, keyValue, keyType) VALUES (\'%s\', \'%d\', %d)", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pKeyName, pCfgItem->intValue, pCfgItem->keyType); + + sprintf(pSqlUpgradeCmd, "UPDATE %s SET keyValue = \'%d\', keyType = %d WHERE keyName = \'%s\'", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->intValue, pCfgItem->keyType, pCfgItem->pKeyName); + } + else if(pCfgItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(pSqlInsertCmd, "INSERT OR IGNORE INTO %s (keyName, keyValue, keyType) VALUES (\'%s\', \'%f\', %d)", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pKeyName, pCfgItem->doubleValue, pCfgItem->keyType); + + sprintf(pSqlUpgradeCmd, "UPDATE %s SET keyValue = \'%f\', keyType = %d WHERE keyName = \'%s\'", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->doubleValue, pCfgItem->keyType, pCfgItem->pKeyName); + } + + if((sqlite3_exec(g_pSqlFileDB, pSqlInsertCmd, NULL, NULL, NULL) == SQLITE_OK) + && (sqlite3_exec(g_pSqlFileDB, pSqlUpgradeCmd, NULL, NULL, NULL) == SQLITE_OK)) + { + // Delete this Key + HASH_DEL(g_pCfgCacheItems, pItem); + LOG_EX(LOG_Debug, "Sync Configure %s To Database\n", pCfgItem->pKeyName); + } + else + { + free(pSqlInsertCmd); + free(pSqlUpgradeCmd); + return; + } + + free(pSqlInsertCmd); + free(pSqlUpgradeCmd); + } + else + { + // Delete this Key + HASH_DEL(g_pCfgCacheItems, pItem); + } + } + + sqlite3_exec(g_pSqlFileDB, "END TRANSACTION;", NULL, NULL, NULL); + } +} +static void __uvThreadSyncCfg(void *pParams) +{ + while(TRUE) + { + __cfgSyncServer(); + sleep(CFG_SYNC_TIME_OF_SECONDS); + } + + pthread_detach(pthread_self()); +} + +static void __cfgStartSyncGlobalCfgSvr(void) +{ + uv_thread_t uvSyncThread; + + uv_rwlock_init(&g_uvCacheRwLock); + + uv_thread_create(&uvSyncThread, __uvThreadSyncCfg, NULL); +} + +static PCFG_ITEM __onCMD_CFG_GET_REQ(const char* pKeyName, int* pErr) +{ + PCFG_ITEM pItem = NULL; + + *pErr = CfgGetKeyValue(pKeyName, &pItem); + + if(*pErr == 0) + { + return (pItem); + } + + return (NULL); +} + +static int __onCMD_CFG_ADD_REQ(const char* pKeyName, const char* pKeyValue, int keyType) +{ + PCFG_ITEM pCfgItem = NULL; + int ret; + + if(pKeyName == NULL || pKeyValue == NULL || strlen(pKeyName) == 0 || strlen(pKeyValue) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + if(keyType < 0 || keyType > CFG_TYPE_DOUBLE) + { + return (-ERR_INPUT_PARAMS); + } + + ret = __cfgMsg2CfgItemV2(keyType, pKeyName, pKeyValue, &pCfgItem); + + if(ret != 0) + { + return (ret); + } + + return CfgAddKeyValue(pKeyName, pCfgItem, TRUE); +} + +static void __cfgSvrProcessCmd(DBUS_CMD cmd, const char* pKeyName, const char* pKeyValue, int keyType, PCFG_API_RSP pRsp) +{ + PCFG_ITEM pItem = NULL; + int err; + + memset(pRsp, 0, sizeof(CFG_API_RSP)); + pRsp->errNo = -ERR_UNKNOWN_TYPE; + + if(pKeyName == NULL) + { + pRsp->errNo = -ERR_INPUT_PARAMS; + return; + } + + strncpy(pRsp->keyName, pKeyName, MAX_CFG_KEY_NAME); + + switch(cmd) + { + case CMD_CFG_ADD_REQ: + err = __onCMD_CFG_ADD_REQ(pKeyName, pKeyValue, keyType); + + pRsp->keyType = keyType; + pRsp->errNo = err; + strncpy(pRsp->keyName, pKeyName, MAX_CFG_KEY_NAME); + strncpy(pRsp->keyValue, pKeyValue, MAX_CFG_KEY_VALUE); + + break; + + case CMD_CFG_GET_REQ: + + pItem = __onCMD_CFG_GET_REQ(pKeyName, &err); + + if(pItem == NULL || err != 0) + { + pRsp->keyType = -1; + pRsp->errNo = err; + strncpy(pRsp->keyName, pKeyName, MAX_CFG_KEY_NAME); + return; + } + else + { + __cfgItem2CfgRsp(pItem, pRsp); + return; + } + + break; + } + + return; +} + +int CfgGlobalEnvInit(void) +{ + int rc = 0; + + uv_rwlock_init(&g_uvHashRwLock); + + rc = __cfgCreateCfgFile(GLOBAL_CFG_FILE_PATH); + + if(rc != SQLITE_OK) + { + return rc; + } + +#if 0 + rc = sqlite3_open_v2(":memory:", &g_pSqlMemDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Memory SQLite3 DB Error\n"); + return -ERR_CREATE_SQLITE3_DB; + } + + //rc = sqlite3SyncDatabase(g_pSqlMemDB, GLOBAL_CFG_FILE_PATH, 0); +#endif + rc = __cfgLoadGlobalConfig(); + + if(rc != SQLITE_OK) + { + return (-ERR_OPEN_SQLITE3_DB); + //sqlite3_close(g_pSqlFileDB); + } + +#if 0 + g_bIsCfgSvr = cfgCheckCfgSvrRun(); + + if(atexit(onProgressExit) != 0) + { + fprintf(stderr, "atexit error\n"); + } + + signal(SIGINT, onSigTermProgressExit); +#endif + + __cfgStartSyncGlobalCfgSvr(); + + return 0; +} + +void OnCfgMsgProcess(MODULE_NAME dest, DBUS_CMD busCmd, const char* pJsonStr) +{ + CFG_API_RSP cfgRsp; + int err = 0; + PCFG_API_REQ pReq = NULL; + PCFG_API_RSP pRsp = NULL; + PLIBUV_DBUS_PARAMS pParams = DBusLibuvGetRuntime(); + + switch(busCmd) + { + case CMD_CFG_ADD_REQ: + case CMD_CFG_GET_REQ: + pReq = Json2Struct(pJsonStr, JSON_ENGINE_CFG_REQ, TRUE, &err); + + if(pReq != NULL && err == 0) + { + pRsp = &cfgRsp; + __cfgSvrProcessCmd(busCmd, pReq->keyName, pReq->keyValue, pReq->keyType, pRsp); + DBusJsonSendToCommand(NULL, g_pModInfoTable[dest].modAliase, busCmd + 1, JSON_ENGINE_CFG_RSP, pRsp, TRUE); + } + + free(pReq); + break; +#if 0 + case CMD_CFG_GET_REQ: + pReq = Json2Struct(pJsonStr, JSON_ENGINE_CFG_REQ, TRUE, &err); + + if(pReq != NULL && err == 0) + { + pRsp = &cfgRsp; + __cfgSvrProcessCmd(busCmd, pReq->keyName, NULL, pReq->keyType, pRsp); + DBusJsonSendToCommand(NULL, g_pModInfoTable[dest].modAliase, CMD_CFG_GET_RSP, JSON_ENGINE_CFG_RSP, pRsp, TRUE); + } + break; +#endif + case CMD_CFG_ADD_RSP: + case CMD_CFG_GET_RSP: + pRsp = Json2Struct(pJsonStr, JSON_ENGINE_CFG_RSP, TRUE, &err); + + if(pRsp != NULL && err == 0 && pRsp->errNo == 0) + { + // Add to local Hash Table cache + PCFG_ITEM pCfgItem = __cfgAddItem(pRsp->keyName, pRsp->keyValue, pRsp->keyType, TRUE, FALSE, &err); + + if(err == 0 && pCfgItem != NULL) + { + if(pParams->onCfgCb) + { + pParams->onCfgCb(busCmd, pCfgItem, 0); + } + } + else + { + LOG_EX(LOG_Error, "Add Configure {[%s]<%d> = \"%s\"} Error: %d\n", + pRsp->keyName, pRsp->keyValue, pRsp->keyType, err); + } + } + else + { + if(pParams->onCfgCb) + { + pParams->onCfgCb(busCmd, NULL, (err == 0) ? pRsp->errNo : err); + } + + LOG_EX(LOG_Error, "pRsp = %p, err = %d, rspErr = %d\n", pRsp, err, pRsp ? pRsp->errNo : -err); + } + + free(pRsp); + break; + } +} diff --git a/Framework/Configure/ini_prase.c b/Framework/Configure/ini_prase.c new file mode 100644 index 0000000..8a85617 --- /dev/null +++ b/Framework/Configure/ini_prase.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" +#include "server_addr.h" + +#ifdef PLATFORM_R16 +#define DEVICE_CFG_FILE ("/mnt/UDISK/dev.conf") +#else +#define DEVICE_CFG_FILE ("./dev.conf") +#endif + +static config_t g_cfgInfo; + +void InitCfgToCfgFile(config_t* pCfg) +{ + config_setting_t *pRoot, *pSetting, *pGlobalgrp, *pLogGrp, *pSubGrp; + + if(pCfg == NULL) + { + return; + } + + pRoot = config_root_setting(pCfg); + + pGlobalgrp = config_setting_add(pRoot, "Global", CONFIG_TYPE_GROUP); + + pSetting = config_setting_add(pGlobalgrp, "ServerMode", CONFIG_TYPE_INT); + config_setting_set_int(pSetting, PUBLISH_MODE); + + pLogGrp = config_setting_add(pGlobalgrp, "Log", CONFIG_TYPE_GROUP); + + pSetting = config_setting_add(pLogGrp, "Enable", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, TRUE); + + pSetting = config_setting_add(pLogGrp, "Level", CONFIG_TYPE_INT); + config_setting_set_format(pSetting, CONFIG_FORMAT_HEX); + config_setting_set_int(pSetting, 0x000003FF); + + pSubGrp = config_setting_add(pLogGrp, "LogToEMail", CONFIG_TYPE_GROUP); + pSetting = config_setting_add(pSubGrp, "Enable", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, FALSE); + pSetting = config_setting_add(pSubGrp, "EMail", CONFIG_TYPE_STRING); + config_setting_set_string(pSetting, "pv1_es2@163.com"); + + pSetting = config_setting_add(pLogGrp, "LogToFile", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, TRUE); + + pSetting = config_setting_add(pLogGrp, "LogToServer", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, TRUE); + + pSubGrp = config_setting_add(pLogGrp, "LogToUDPServer", CONFIG_TYPE_GROUP); + pSetting = config_setting_add(pSubGrp, "Enable", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, FALSE); + pSetting = config_setting_add(pSubGrp, "UdpServerIp", CONFIG_TYPE_STRING); + config_setting_set_string(pSetting, "10.240.84.163"); + pSetting = config_setting_add(pSubGrp, "UdpBasePort", CONFIG_TYPE_INT); + config_setting_set_int(pSetting, 10000); + + + if(!config_write_file(pCfg, DEVICE_CFG_FILE)) + { + LOG_EX(LOG_Error, "Create Configure File %s Error\n", DEVICE_CFG_FILE); + } +} + +int CfgGetIntValue(const char* pTags, int defValue) +{ + int iValue = defValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return defValue; + } + + if(!config_lookup_int(&g_cfgInfo, pTags, &iValue)) + { + return defValue; + } + + return iValue; +} + +void CfgSetIntValue(const char* pTags, int iValue) +{ + config_setting_t *pRoot, *pGlobalgrp, *pSet; + + LOG_EX(LOG_Debug, "Set: %s --> %d\n", pTags, iValue); + + if(pTags == NULL || strlen(pTags) == 0) + { + LOG_EX(LOG_Error, "Input Params error: pTags = [%s]\n", pTags ? pTags : "NULL"); + return; + } + + pRoot = config_root_setting(&g_cfgInfo); + + if(pRoot == NULL) + { + LOG_EX(LOG_Error, "pRoot = NULL\n"); + return; + } + + pGlobalgrp = config_setting_get_member(pRoot, "Global"); + + if(pGlobalgrp == NULL) + { + LOG_EX(LOG_Error, "pGlobalgrp = NULL\n"); + return; + } + + pSet = config_setting_get_member(pGlobalgrp, pTags); + + if(!pSet) + { + pSet = config_setting_add(pGlobalgrp, pTags, CONFIG_TYPE_INT); + } + + if(pSet == NULL) + { + LOG_EX(LOG_Error, "pSet = NULL\n"); + return; + } + + config_setting_set_int(pSet, iValue); + + + if(!config_write_file(&g_cfgInfo, DEVICE_CFG_FILE)) + { + LOG_EX(LOG_Error, "Set %s Value Error\n", pTags); + } +} + +char* CfgGetStringValue(const char* pTags, char* pDefValue) +{ + char* pValue = pDefValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return pDefValue; + } + + if(!config_lookup_string(&g_cfgInfo, pTags, (const char**)&pValue)) + { + return pDefValue; + } + + return pValue; +} + +double CfgGetFloatValue(const char* pTags, double defValue) +{ + double dValue = defValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return defValue; + } + + if(!config_lookup_float(&g_cfgInfo, pTags, &dValue)) + { + return defValue; + } + + return dValue; +} + +int CfgGetBoolValue(const char* pTags, int defValue) +{ + int iValue = defValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return defValue; + } + + if(!config_lookup_bool(&g_cfgInfo, pTags, &iValue)) + { + return defValue; + } + + return iValue; +} + +void CfgFileInit(void) +{ + //config_setting_t *pRoot, *pSetting; + + config_init(&g_cfgInfo); + +#if 0 + config_set_options(&g_cfgInfo, + (CONFIG_OPTION_SEMICOLON_SEPARATORS + | CONFIG_OPTION_COLON_ASSIGNMENT_FOR_GROUPS + | CONFIG_OPTION_OPEN_BRACE_ON_SEPARATE_LINE)); +#endif + + config_set_tab_width(&g_cfgInfo, 4); + + if(access(DEVICE_CFG_FILE, F_OK) != 0) + { + InitCfgToCfgFile(&g_cfgInfo); + } + else if(!config_read_file(&g_cfgInfo, DEVICE_CFG_FILE)) + { + LOG_EX(LOG_Error, "Read Configure File %s Error\n", DEVICE_CFG_FILE); + return; + } +} diff --git a/Framework/Crypto/aes.c b/Framework/Crypto/aes.c new file mode 100644 index 0000000..afff0ac --- /dev/null +++ b/Framework/Crypto/aes.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include + +#include "log.h" +#include "smart_sound.h" +#include "crypto.h" +#include "libuv_dbus.h" + +int EvpAESEncrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey) +{ + int enBytes = 0; + EVP_CIPHER_CTX ctx; + //int decDataLen = 0; + if(!pInBuf || !pOutBuf || !pOutSize || !pKey) + { + return -ERR_INPUT_PARAMS; + } + + *pOutSize = 0; + //decDataLen = ((iSize + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + + EVP_CIPHER_CTX_init(&ctx); + + if(EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, pKey, NULL) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptInit_ex Error\n"); + return -ERR_EVP_INIT_KEY; + } + + if(EVP_EncryptUpdate(&ctx, pOutBuf, &enBytes, pInBuf, iSize) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptUpdate Error\n"); + return -ERR_EVP_UPDATE; + } + + pOutBuf += enBytes; + pInBuf += enBytes; + *pOutSize += enBytes; + + if(EVP_EncryptFinal_ex(&ctx, pOutBuf, &enBytes) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptFinal_ex Error\n"); + return -ERR_EVP_FINALE; + } + + *pOutSize += enBytes; + + EVP_CIPHER_CTX_cleanup(&ctx); + + return 0; +} + +int EvpAESDecrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey) +{ + int deBytes = 0; + EVP_CIPHER_CTX ctx; + + if(!pInBuf || !pOutBuf || !pOutSize || !pKey) + { + return -ERR_INPUT_PARAMS; + } + + EVP_CIPHER_CTX_init(&ctx); + + *pOutSize = 0; + + if(EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, pKey, NULL) == 0) + { + LOG_EX(LOG_Error, "EVP_DecryptInit_ex Error\n"); + return -ERR_EVP_INIT_KEY; + } + + if(EVP_DecryptUpdate(&ctx, pOutBuf, &deBytes, pInBuf, iSize) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptUpdate Error\n"); + return -ERR_EVP_UPDATE; + } + + pOutBuf += deBytes; + pInBuf += deBytes; + *pOutSize += deBytes; + + if(EVP_DecryptFinal_ex(&ctx, pOutBuf, &deBytes) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptFinal_ex Error\n"); + return -ERR_EVP_FINALE; + } + + *pOutSize += deBytes; + EVP_CIPHER_CTX_cleanup(&ctx); + + return 0; +} + diff --git a/Framework/Crypto/base64.c b/Framework/Crypto/base64.c new file mode 100644 index 0000000..6941073 --- /dev/null +++ b/Framework/Crypto/base64.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +#include "log.h" +#include "crypto.h" + +const char* EvpBase64Encode(const char* pSrc) +{ + EVP_ENCODE_CTX ctx; + int enSize = 0; + int sLen, size; + char* pEncode = NULL; + + if(pSrc == NULL || strlen(pSrc) == 0) + { + return (NULL); + } + + sLen = strlen(pSrc); + size = ((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64; + + pEncode = (char*)malloc(size); + memset(pEncode, 0, size); + + EVP_EncodeInit(&ctx); + EVP_EncodeUpdate(&ctx, pEncode, &enSize, pSrc, strlen(pSrc)); + EVP_EncodeFinal(&ctx, pEncode + enSize, &enSize); + +// fprintf(stdout, "Src: \n[%s]\n", pSrc); +// fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode); + + return pEncode; +} + +const char* EvpBase64Decode(const char* pBase64) +{ + EVP_ENCODE_CTX ctx; + int enSize = 0; + int size = 0; + char *pDecode = NULL; + + if(pBase64 == NULL || strlen(pBase64) == 0) + { + return (NULL); + } + + size = strlen(pBase64); + pDecode = (char*)malloc(size); + memset(pDecode, 0, size); + + EVP_DecodeInit(&ctx); + EVP_DecodeUpdate(&ctx, pDecode, &enSize, pBase64, strlen(pBase64)); + EVP_DecodeFinal(&ctx, pDecode + enSize, &enSize); + +// fprintf(stdout, "Decode(%d --> %d) Bytes: \n[%s]\n", size, strlen(pDecode), pDecode); + + return pDecode; +} + +const char* EvpBase64EncodeNoAlign(const char* pSrc) +{ + int size, sLen; + char* pEncode = NULL; + + if(pSrc == NULL || strlen(pSrc) == 0) + { + return (NULL); + } + + sLen = strlen(pSrc); + size = ((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64; + + pEncode = (char*)malloc(size); + memset(pEncode, 0, size); + + EVP_EncodeBlock(pEncode, (const unsigned char *)pSrc, sLen); +// fprintf(stdout, "Src: \n[%s]\n", pSrc); +// fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode); + + return pEncode; +} + +const char* EvpBase64EncodeNoAlignV2(unsigned char* pSrc, int sLen) +{ + int size; + char* pEncode = NULL; + + if(pSrc == NULL || sLen <= 0) + { + return (NULL); + } + + size = ((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64; + + pEncode = (char*)malloc(size); + memset(pEncode, 0, size); + + EVP_EncodeBlock(pEncode, (const unsigned char *)pSrc, sLen); +// fprintf(stdout, "Src: \n[%s]\n", pSrc); +// fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode); + + return pEncode; +} + +const char* EvpBase64DecodeNoAlign(const char *pBase64) +{ + int size = 0; + char *pDecode = NULL; + + if(pBase64 == NULL || strlen(pBase64) == 0) + { + return (NULL); + } + + size = strlen(pBase64); + + pDecode = (char*)malloc(size); + memset(pDecode, 0, size); + + //CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); + EVP_DecodeBlock(pDecode, (const unsigned char *)pBase64, size); + //CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); + +// fprintf(stdout, "Decode(%d --> %d) Bytes: \n[%s]\n", size, strlen(pDecode), pDecode); + + return pDecode; +} + +unsigned char* EvpBase64DecodeNoAlignV2(const char *pBase64, int* pOutSize) +{ + int size = 0; + unsigned char *pDecode = NULL; + + if(pBase64 == NULL || strlen(pBase64) == 0) + { + return (NULL); + } + + size = strlen(pBase64); + + pDecode = (char*)malloc(size); + memset(pDecode, 0, size); + + //CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); + size = EVP_DecodeBlock(pDecode, (const unsigned char *)pBase64, size); + //CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); + +// fprintf(stdout, "Decode(%d --> %d) Bytes: \n[%s]\n", size, strlen(pDecode), pDecode); + + if(pOutSize) + { + *pOutSize = size; + } + + return (pDecode); +} diff --git a/Framework/Crypto/crypto.c b/Framework/Crypto/crypto.c new file mode 100644 index 0000000..226f1a3 --- /dev/null +++ b/Framework/Crypto/crypto.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include + +#include "log.h" +#include "smart_sound.h" +#include "crypto.h" +#include "libuv_dbus.h" + +static uv_mutex_t *pEvpMutex = NULL; +typedef struct +{ + CRYPTO_TYPE type; + unsigned char* pInData; + int iInSize; + unsigned char* pOutData; + unsigned char pKey[EVP_MAX_KEY_LENGTH + 1]; + OnEVPCrypto onEvpEventCb; +} CRYPT_TASK_PARAMS, *PCRYPT_TASK_PARAMS; + +static void FreeEVPWorkCb(uv_work_t* pWork, int status) +{ + PCRYPT_TASK_PARAMS pTask = (PCRYPT_TASK_PARAMS)pWork->data; + free(pTask->pInData); + free(pTask); + free(pWork); +} + +static void OnEVPWorkCb(uv_work_t* pWork) +{ + PCRYPT_TASK_PARAMS pTask = (PCRYPT_TASK_PARAMS)pWork->data; + int iOutSize = 0; + int iError = 0; + + switch(pTask->type) + { + case CRYPTO_AES_ENCRYPT: + iError = EvpAESEncrypto(pTask->pInData, + pTask->iInSize, + pTask->pOutData, + &iOutSize, + pTask->pKey); + break; + + case CRYPTO_AES_DECRYPT: + iError = EvpAESDecrypto(pTask->pInData, + pTask->iInSize, + pTask->pOutData, + &iOutSize, + pTask->pKey); + break; + + case CRYPTO_BASE64_ENCODE: + pTask->pOutData = (unsigned char*)EvpBase64Encode((const char*)pTask->pInData); + iOutSize = strlen((char*)pTask->pOutData); + break; + + case CRYPTO_BASE64_DECODE: + pTask->pOutData = (unsigned char*)EvpBase64Decode((const char*)pTask->pInData); + iOutSize = strlen((char*)pTask->pOutData); + break; + + case CRYPTO_MD5_FILE: + pTask->pOutData = (unsigned char*)EvpMD5HashFile((const char*)pTask->pInData); + iOutSize = strlen((char*)pTask->pOutData); + break; + + default: + iError = -ERR_UNSUP_EVP_TYPE; + } + + if(iError != 0) + { + pTask->onEvpEventCb(pTask->type, pTask->pOutData, 0, pTask->pInData, iError); + } + else + { + pTask->onEvpEventCb(pTask->type, pTask->pOutData, iOutSize, pTask->pInData, 0); + } +} + +int EvpAddCryptoTask(CRYPTO_TYPE type, + unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + char* pKey, + OnEVPCrypto onEvpCryptCb) +{ + uv_work_t* puvWork = NULL; + PCRYPT_TASK_PARAMS pTask = NULL; + PLIBUV_DBUS_PARAMS pContext = DBusLibuvGetRuntime(); + + if(!pContext || !onEvpCryptCb) + { + return -ERR_INPUT_PARAMS; + } + + if(type == CRYPTO_AES_ENCRYPT || type == CRYPTO_AES_DECRYPT) + { + if(pKey == NULL || pOutBuf == NULL) + { + return -ERR_INPUT_PARAMS; + } + + switch(strlen(pKey) * 8) + { + case 128: + case 192: + case 256: + break; + default: + return -ERR_EVP_KEY_SIZE; + } + } + else if(type == CRYPTO_MD5_FILE) + { + uv_fs_t uvFs; + if(uv_fs_access(pContext->pLoop, &uvFs, (const char*)pInBuf, F_OK, NULL) != 0) + { + return -ERR_FILE_NOT_EXISTS; + } + } + + pTask = (PCRYPT_TASK_PARAMS)malloc(sizeof(CRYPT_TASK_PARAMS)); + puvWork = (uv_work_t*)malloc(sizeof(uv_work_t)); + + puvWork->data = (void*)pTask; + + pTask->type = type; + pTask->pInData = (unsigned char*)malloc(iSize + 1); + pTask->iInSize = iSize; + pTask->pOutData = pOutBuf; + pTask->onEvpEventCb = onEvpCryptCb; + + memset(pTask->pInData, 0, iSize + 1); + memset(pTask->pKey, 0, EVP_MAX_KEY_LENGTH + 1); + + if(pKey) + { + strncpy(pTask->pKey, pKey, EVP_MAX_KEY_LENGTH); + } + + memcpy(pTask->pInData, pInBuf, iSize); + + uv_queue_work(pContext->pLoop, puvWork, OnEVPWorkCb, FreeEVPWorkCb); + + return 0; +} + +static void __evpLockCb(int mode, int n, const char *pFile, int line) +{ + if(n >= CRYPTO_num_locks()) + { + return; + } + + if(mode & CRYPTO_LOCK) + { + uv_mutex_lock(&pEvpMutex[n]); + } + else + { + uv_mutex_unlock(&pEvpMutex[n]); + } +} + + +static unsigned long __evpIdCb(void) +{ + return ((unsigned long)uv_thread_self()); +} + +void EvpSystemInit(void) +{ + int i = 0; + + pEvpMutex = (uv_mutex_t *)malloc(CRYPTO_num_locks() * sizeof(uv_mutex_t)); + + for(i = 0; i < CRYPTO_num_locks(); i++) + { + uv_mutex_init(&pEvpMutex[i]); + } + + CRYPTO_set_id_callback(__evpIdCb); + CRYPTO_set_locking_callback(__evpLockCb); +} diff --git a/Framework/Crypto/md5.c b/Framework/Crypto/md5.c new file mode 100644 index 0000000..655e7b0 --- /dev/null +++ b/Framework/Crypto/md5.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "crypto.h" +#include "libuv_dbus.h" + +const char* EvpMD5HashFile(const char* pFileName) +{ + int rdSize = 0; + int fd, size; + uint8_t md5[EVP_MAX_MD_SIZE]; + uint8_t buf[1024]; + EVP_MD_CTX ctx; + char* pString = NULL; + + memset(md5, 0, EVP_MAX_MD_SIZE); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + + fd = open(pFileName, O_RDONLY); + + if(fd == -1) + { + LOG_EX(LOG_Error, "Open File \'%s\' error\n", pFileName); + return NULL; + } + do + { + rdSize = read(fd, buf, 1024); + + if(rdSize > 0) + { + EVP_DigestUpdate(&ctx, buf, rdSize); + } + } while(rdSize > 0); + + close(fd); + + EVP_DigestFinal_ex(&ctx, md5, &rdSize); + EVP_MD_CTX_cleanup(&ctx); + + size = rdSize * 2 + 1; + + pString = (char*)malloc(size); + memset(pString, 0, size); + + IHW_bin2hex(pString, md5, rdSize); + +// print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, md5, rdSize); +// fprintf(stdout, "MD5: [%s]\n", pString); + + return (const char*)pString; +} + +int EvpMD5HashFileV2(const char* pFileName, unsigned char md5[16]) +{ + int rdSize = 0; + int fd; + uint8_t buf[1024]; + EVP_MD_CTX ctx; + //char* pString = NULL; + + memset(md5, 0, 16); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + + fd = open(pFileName, O_RDONLY); + + if(fd == -1) + { + LOG_EX(LOG_Error, "Open File %s error\n", pFileName); + return (-ERR_OPEN_FILE); + } + do + { + rdSize = read(fd, buf, 1024); + + EVP_DigestUpdate(&ctx, buf, rdSize); + } while(rdSize > 0); + + close(fd); + + EVP_DigestFinal_ex(&ctx, md5, &rdSize); + EVP_MD_CTX_cleanup(&ctx); + + +// print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, md5, rdSize); +// fprintf(stdout, "MD5: [%s]\n", pString); + + return 0; +} + +int EvpMD5HashBuf(const unsigned char* pBuf, int iBufLen, unsigned char* pOutBuf, int* pOutSize) +{ + EVP_MD_CTX ctx; + + if(pBuf == NULL || pOutBuf == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + memset(pOutBuf, 0, EVP_MAX_MD_SIZE); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + EVP_DigestUpdate(&ctx, pBuf, iBufLen); + EVP_DigestFinal_ex(&ctx, pOutBuf, &iBufLen); + EVP_MD_CTX_cleanup(&ctx); + + if(pOutSize) + { + *pOutSize = iBufLen; + } + + //print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, pOutBuf, iBufLen); + + return 0; +} + +const char* EvpMD5HashBufV2(const unsigned char* pBuf, int iBufLen) +{ + int size = 0; + EVP_MD_CTX ctx; + uint8_t md5[EVP_MAX_MD_SIZE]; + char* pString = NULL; + + if(pBuf == NULL || iBufLen <= 0) + { + return NULL; + } + + memset(md5, 0, EVP_MAX_MD_SIZE); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + EVP_DigestUpdate(&ctx, pBuf, iBufLen); + EVP_DigestFinal_ex(&ctx, md5, &iBufLen); + EVP_MD_CTX_cleanup(&ctx); + + //print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, pOutBuf, iBufLen); + + size = iBufLen * 2 + 1; + + pString = (char*)malloc(size); + memset(pString, 0, size); + + IHW_bin2hex(pString, md5, iBufLen); + +// print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, md5, rdSize); +// fprintf(stdout, "MD5: [%s]\n", pString); + + return (const char*)pString; +} diff --git a/Framework/Fifo/fifo.c b/Framework/Fifo/fifo.c new file mode 100644 index 0000000..d81a3e9 --- /dev/null +++ b/Framework/Fifo/fifo.c @@ -0,0 +1,554 @@ +/* + * A generic kernel FIFO implementation + * + * Copyright (C) 2009/2010 Stefani Seibold + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#if 0 +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "fifo.h" + +#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +//#define EINVAL (1) +//#define ENOMEM (2) + +static inline int fls(int x); + +#ifdef PLATFORM_R16 +static inline int constant_fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +static int fls64(unsigned long long x) +{ + unsigned int h = x >> 32; + if (h) + return fls(h) + 32; + return fls(x); +} + +static inline int fls(int x) +{ + int ret; + + if (__builtin_constant_p(x)) + return constant_fls(x); + + asm("clz\t%0, %1" : "=r" (ret) : "r" (x)); + ret = 32 - ret; + return ret; +} +#endif + +#ifdef PLATFORM_CPU +#define __fls(x) (fls(x) - 1) +static __always_inline int fls64(unsigned long x) +{ + if (x == 0) + return 0; + return __fls(x) + 1; +} + +static inline int fls(int x) +{ + int r; + + long tmp = -1; + asm("bsrl %1,%0" + : "=r" (r) + : "rm" (x), "0" (tmp)); +#if 0 +#ifdef CONFIG_X86_64 + /* + * AMD64 says BSRL won't clobber the dest reg if x==0; Intel64 says the + * dest reg is undefined if x==0, but their CPU architect says its + * value is written to set it to the same as before, except that the + * top 32 bits will be cleared. + * + * We cannot do this on 32 bits because at the very least some + * 486 CPUs did not behave this way. + */ + long tmp = -1; + asm("bsrl %1,%0" + : "=r" (r) + : "rm" (x), "0" (tmp)); +#elif defined(CONFIG_X86_CMOV) + asm("bsrl %1,%0\n\t" + "cmovzl %2,%0" + : "=&r" (r) : "rm" (x), "rm" (-1)); +#else + asm("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n" + "1:" : "=r" (r) : "rm" (x)); +#endif +#endif + return r + 1; +} +#endif +/* + * internal helper to calculate the unused elements in a fifo + */ +static inline unsigned int kfifo_unused(struct __kfifo *fifo) +{ + return (fifo->mask + 1) - (fifo->in - fifo->out); +} + +static inline unsigned fls_long(unsigned long l) +{ + if (sizeof(l) == 4) + return fls(l); + return fls64(l); +} + +unsigned long roundup_pow_of_two(unsigned long n) +{ + return 1UL << (fls_long(n)); +} + +int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, unsigned int esize) +{ + /* + * round down to the next power of 2, since our 'let the indices + * wrap' technique works only in this case. + */ + if (!is_power_of_2(size)) + size = roundup_pow_of_two(size); + + fprintf(stdout, "+++++++++++kfifo malloc size = %u\n", size); + + fifo->in = 0; + fifo->out = 0; + fifo->esize = esize; + + if (size < 2) { + fifo->data = NULL; + fifo->mask = 0; + return -EINVAL; + } + + fifo->data = malloc(size * esize); + + if (!fifo->data) { + fifo->mask = 0; + return -ENOMEM; + } + fifo->mask = size - 1; + uv_mutex_init(&fifo->lock); + + return 0; +} + +void __kfifo_free(struct __kfifo *fifo) +{ + free(fifo->data); + fifo->in = 0; + fifo->out = 0; + fifo->esize = 0; + fifo->data = NULL; + fifo->mask = 0; +} + +int __kfifo_init(struct __kfifo *fifo, void *buffer, + unsigned int size, unsigned int esize) +{ + size /= esize; + + if (!is_power_of_2(size)) + size = roundup_pow_of_two(size); + + fifo->in = 0; + fifo->out = 0; + fifo->esize = esize; + fifo->data = buffer; + + if (size < 2) { + fifo->mask = 0; + return -EINVAL; + } + fifo->mask = size - 1; + uv_mutex_init(&fifo->lock); + + return 0; +} + +static void kfifo_copy_in(struct __kfifo *fifo, const void *src, + unsigned int len, unsigned int off) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + memcpy(fifo->data + off, src, l); + memcpy(fifo->data, src + l, len - l); + /* + * make sure that the data in the fifo is up to date before + * incrementing the fifo->in index counter + */ +// smp_wmb(); +} + +unsigned int __kfifo_in(struct __kfifo *fifo, + const void *buf, unsigned int len) +{ + unsigned int l; + + l = kfifo_unused(fifo); + if (len > l) + len = l; + + kfifo_copy_in(fifo, buf, len, fifo->in); + fifo->in += len; + return len; +} + +static void kfifo_copy_out(struct __kfifo *fifo, void *dst, + unsigned int len, unsigned int off) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + if (dst) { + memcpy(dst, fifo->data + off, l); + memcpy(dst + l, fifo->data, len - l); + } + /* + * make sure that the data is copied before + * incrementing the fifo->out index counter + */ +// smp_wmb(); +} + +unsigned int __kfifo_out_peek(struct __kfifo *fifo, + void *buf, unsigned int len) +{ + unsigned int l; + + l = fifo->in - fifo->out; + if (len > l) + len = l; + + kfifo_copy_out(fifo, buf, len, fifo->out); + return len; +} + +unsigned int __kfifo_out(struct __kfifo *fifo, + void *buf, unsigned int len) +{ + len = __kfifo_out_peek(fifo, buf, len); + fifo->out += len; + return len; +} + +#if 0 +static unsigned long kfifo_copy_from_user(struct __kfifo *fifo, + const void *from, unsigned int len, unsigned int off, + unsigned int *copied) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + unsigned long ret; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + ret = memcpy(fifo->data + off, from, l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret + len - l, esize); + else { + ret = memcpy(fifo->data, from + l, len - l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret, esize); + } + /* + * make sure that the data in the fifo is up to date before + * incrementing the fifo->in index counter + */ +// smp_wmb(); + *copied = len - ret; + /* return the number of elements which are not copied */ + return ret; +} + +int __kfifo_from_user(struct __kfifo *fifo, const void __user *from, + unsigned long len, unsigned int *copied) +{ + unsigned int l; + unsigned long ret; + unsigned int esize = fifo->esize; + int err; + + if (esize != 1) + len /= esize; + + l = kfifo_unused(fifo); + if (len > l) + len = l; + + ret = kfifo_copy_from_user(fifo, from, len, fifo->in, copied); + if (unlikely(ret)) { + len -= ret; + err = -EFAULT; + } else + err = 0; + fifo->in += len; + return err; +} + +static unsigned long kfifo_copy_to_user(struct __kfifo *fifo, void __user *to, + unsigned int len, unsigned int off, unsigned int *copied) +{ + unsigned int l; + unsigned long ret; + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + ret = memcpy(to, fifo->data + off, l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret + len - l, esize); + else { + ret = memcpy(to + l, fifo->data, len - l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret, esize); + } + /* + * make sure that the data is copied before + * incrementing the fifo->out index counter + */ + //smp_wmb(); + *copied = len - ret; + /* return the number of elements which are not copied */ + return ret; +} + +int __kfifo_to_user(struct __kfifo *fifo, void __user *to, + unsigned long len, unsigned int *copied) +{ + unsigned int l; + unsigned long ret; + unsigned int esize = fifo->esize; + int err; + + if (esize != 1) + len /= esize; + + l = fifo->in - fifo->out; + if (len > l) + len = l; + ret = kfifo_copy_to_user(fifo, to, len, fifo->out, copied); + if (unlikely(ret)) { + len -= ret; + err = -EFAULT; + } else + err = 0; + fifo->out += len; + return err; +} +#endif + +unsigned int __kfifo_max_r(unsigned int len, unsigned int recsize) +{ + unsigned int max = (1 << (recsize << 3)) - 1; + + if (len > max) + return max; + return len; +} + +#define __KFIFO_PEEK(data, out, mask) \ + ((data)[(out) & (mask)]) +/* + * __kfifo_peek_n internal helper function for determinate the length of + * the next record in the fifo + */ +static unsigned int __kfifo_peek_n(struct __kfifo *fifo, unsigned int recsize) +{ + unsigned int l; + unsigned int mask = fifo->mask; + unsigned char *data = fifo->data; + + l = __KFIFO_PEEK(data, fifo->out, mask); + + if (--recsize) + l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8; + + return l; +} + +#define __KFIFO_POKE(data, in, mask, val) \ + ( \ + (data)[(in) & (mask)] = (unsigned char)(val) \ + ) + +/* + * __kfifo_poke_n internal helper function for storeing the length of + * the record into the fifo + */ +static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, unsigned int recsize) +{ + unsigned int mask = fifo->mask; + unsigned char *data = fifo->data; + + __KFIFO_POKE(data, fifo->in, mask, n); + + if (recsize > 1) + __KFIFO_POKE(data, fifo->in + 1, mask, n >> 8); +} + +unsigned int __kfifo_len_r(struct __kfifo *fifo, unsigned int recsize) +{ + return __kfifo_peek_n(fifo, recsize); +} + +unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf, + unsigned int len, unsigned int recsize) +{ + if (len + recsize > kfifo_unused(fifo)) + return 0; + + __kfifo_poke_n(fifo, len, recsize); + + kfifo_copy_in(fifo, buf, len, fifo->in + recsize); + fifo->in += len + recsize; + return len; +} + +static unsigned int kfifo_out_copy_r(struct __kfifo *fifo, + void *buf, unsigned int len, unsigned int recsize, unsigned int *n) +{ + *n = __kfifo_peek_n(fifo, recsize); + + if (len > *n) + len = *n; + + kfifo_copy_out(fifo, buf, len, fifo->out + recsize); + return len; +} + +unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf, + unsigned int len, unsigned int recsize) +{ + unsigned int n; + + if (fifo->in == fifo->out) + return 0; + + return kfifo_out_copy_r(fifo, buf, len, recsize, &n); +} + +unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf, + unsigned int len, unsigned int recsize) +{ + unsigned int n; + + if (fifo->in == fifo->out) + return 0; + + len = kfifo_out_copy_r(fifo, buf, len, recsize, &n); + fifo->out += n + recsize; + return len; +} + +void __kfifo_skip_r(struct __kfifo *fifo, unsigned int recsize) +{ + unsigned int n; + + n = __kfifo_peek_n(fifo, recsize); + fifo->out += n + recsize; +} diff --git a/Framework/HeartDaemon/heart_daemon.c b/Framework/HeartDaemon/heart_daemon.c new file mode 100644 index 0000000..80e190b --- /dev/null +++ b/Framework/HeartDaemon/heart_daemon.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include "log.h" +#include "libuv_dbus.h" + +typedef struct +{ + MODULE_NAME modName; + uint32_t hTm[MODULE_MAX]; + int isDaemonWork[MODULE_MAX]; + int isConnected[MODULE_MAX]; + OnDaemonMsg pOnHeartLostCb; +} HEART_DAEMON, *PHEART_DAEMON; + +uint32_t g_hblTout = HEART_LOST_DELAY; ///< nano second: heart lost timeout, default 1s +static uv_loop_t *g_DeamonLoop; +static uv_idle_t g_uvDeamonIdle; +static HEART_DAEMON g_heartDaemon; + +static unsigned int g_Cnt = 0; +static int timerExpire(uint32_t tm, uint32_t tExp) +{ + uint32_t now = LIBUV_CURRENT_TIME_MS(); + int64_t diff = now - tm; + + if(tm == 0 || tExp == 0) + { + return 0; + } + + if(diff > tExp * 1000) + { + return 0; + } + else if(diff >= tExp) + { + return 1; + } + + return (0); +} + +static void RunPingSvr(void) +{ + int ret = 0; + unsigned int tm = LIBUV_CURRENT_TIME_MS(); + PING_MSG pMsg; + struct timeval tv; + + gettimeofday(&tv, NULL); + + pMsg.PING = (double)tm / 1000; + pMsg.tmSec = tv.tv_sec; + pMsg.tmMSec = tv.tv_usec; + + ret = DBusJsonBoardcastCommand(NULL, 0xFFFFFFFF, CMD_MISC_PING, JSON_ENGINE_PING, &pMsg, FALSE); + + if(ret != 0) + { + LOG_EX(LOG_Error, "DBus boardcast message error: %d\n", ret); + } +} + +void HeartDaemonHblCheck(void) +{ + if(g_heartDaemon.modName != MODULE_CONTROLLER) + { + if(g_heartDaemon.isDaemonWork[MODULE_CONTROLLER] && timerExpire(g_heartDaemon.hTm[MODULE_CONTROLLER], g_hblTout)) + { + g_heartDaemon.pOnHeartLostCb(MODULE_CONTROLLER, TRUE); + g_heartDaemon.hTm[MODULE_CONTROLLER] = 0; + g_heartDaemon.isConnected[MODULE_CONTROLLER] = FALSE; + } + } + else + { + int i; + + for(i = 0; i < MODULE_MAX; i++) + { + if(g_heartDaemon.isDaemonWork[i] + && i != MODULE_CONTROLLER + && timerExpire(g_heartDaemon.hTm[i], g_hblTout)) + { + g_heartDaemon.pOnHeartLostCb(i, TRUE); + g_heartDaemon.hTm[i] = 0; + g_heartDaemon.isConnected[i] = FALSE; + } + } + } +} + +void HeartDaemonUpgrade(int iWatcher) +{ + if(iWatcher >= MODULE_MAX) + { + return; + } + + if(g_heartDaemon.hTm[iWatcher] == 0) + { + if(g_heartDaemon.modName == MODULE_CONTROLLER) + { + g_heartDaemon.pOnHeartLostCb(iWatcher, FALSE); + } + else if(iWatcher == MODULE_CONTROLLER) + { + g_heartDaemon.pOnHeartLostCb(iWatcher, FALSE); + } + + g_heartDaemon.isConnected[iWatcher] = TRUE; + RunPingSvr(); + } + + g_heartDaemon.hTm[iWatcher] = LIBUV_CURRENT_TIME_MS(); +} + +static int __isSendPingOnTime(void) +{ + static unsigned int tmPre = 0; + unsigned int tm = LIBUV_CURRENT_TIME_MS(); + unsigned int tmOut = HEART_SEND_DELAY; + + if(g_heartDaemon.modName != MODULE_CONTROLLER + && g_heartDaemon.isConnected[MODULE_CONTROLLER] == FALSE) + { + tmOut = 5000; + } + + if(tmPre != 0 && tm - tmPre < tmOut) + { + return (FALSE); + } + + tmPre = tm; + + return (TRUE); +} + +static void __uvIdleCb(uv_idle_t* phuvIdle) +{ + if(DBusLibuvGetRuntime()->onHblCb + && __isSendPingOnTime()) + { + RunPingSvr(); + } + + HeartDaemonHblCheck(); + sleep(1); +} + +static void __uvThreadDaemon(void *pParams) +{ + g_DeamonLoop = uv_loop_new(); + + uv_idle_init(g_DeamonLoop, &g_uvDeamonIdle); + uv_idle_start(&g_uvDeamonIdle, __uvIdleCb); + + uv_run(g_DeamonLoop, UV_RUN_DEFAULT); + + pthread_detach(pthread_self()); +} + +void HeartDaemonInit(MODULE_NAME mod, int msHblTout, OnDaemonMsg cb) +{ + uv_thread_t uvDaemonThread; + int i; + + memset(&g_heartDaemon, 0, sizeof(HEART_DAEMON)); + + if(msHblTout > 0) + { + g_hblTout = msHblTout; + } + + g_heartDaemon.modName = mod; + + for(i = 0; i < MODULE_MAX; i++) + { + if(mod == MODULE_CONTROLLER) + { + g_heartDaemon.isDaemonWork[i] = (g_pModInfoTable[i].modName != MODULE_CONTROLLER) ? TRUE : FALSE; + } + else + { + g_heartDaemon.isDaemonWork[i] = (g_pModInfoTable[i].modName == MODULE_CONTROLLER) ? TRUE : FALSE; + } + + g_heartDaemon.isConnected[i] = FALSE; + } + + g_heartDaemon.pOnHeartLostCb = cb; + + uv_thread_create(&uvDaemonThread, __uvThreadDaemon, NULL); +} diff --git a/Framework/JsonUtils/json_struct.c b/Framework/JsonUtils/json_struct.c new file mode 100644 index 0000000..c9be8c3 --- /dev/null +++ b/Framework/JsonUtils/json_struct.c @@ -0,0 +1,1218 @@ +#include +#include +#include +#include + +#include "log.h" +#include "smart_sound.h" +#include "libuv_dbus.h" +#include "json_struct.h" +#include "crypto.h" +#include "ota.h" +#include "assistant.h" + +typedef const char* (*StructToJsonCb)(void* pStruct); +typedef void* (*JsonToStructCb)(const char* pJsonStr); +typedef void (*Base64Code)(void *pStruct, int enCode); + +typedef struct +{ + JSON_ENGINE_TYPE typeId; + StructToJsonCb s2jCb; + JsonToStructCb j2sCb; + Base64Code base64Cb; +} JSON_ENGINE, *PJSON_ENGINE; + +static const char* __ping_MSG2Json(void* pData) +{ + PPING_MSG pReq = (PPING_MSG)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, double, PING); + s2j_json_set_basic_element(jObject, pReq, int, tmSec); + s2j_json_set_basic_element(jObject, pReq, int, tmMSec); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2PING_MSG(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, PING_MSG); + + memset(sObject, 0, sizeof(PING_MSG)); + + s2j_struct_get_basic_element(sObject, pJson, double, PING); + s2j_struct_get_basic_element(sObject, pJson, int, tmSec); + s2j_struct_get_basic_element(sObject, pJson, int, tmMSec); + + cJSON_Delete(pJson); + + return sObject; +} + +static const char* __cfg_API_REQ2Json(void* pData) +{ + PCFG_API_REQ pReq = (PCFG_API_REQ)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, string, keyName); + s2j_json_set_basic_element(jObject, pReq, string, keyValue); + s2j_json_set_basic_element(jObject, pReq, int, keyType); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2CFG_API_REQ(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, CFG_API_REQ); + + memset(sObject, 0, sizeof(CFG_API_REQ)); + + s2j_struct_get_basic_element(sObject, pJson, string, keyName); + s2j_struct_get_basic_element(sObject, pJson, string, keyValue); + s2j_struct_get_basic_element(sObject, pJson, int, keyType); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __cfg_API_REQBase64(void *pData, int enCode) +{ + PCFG_API_REQ pReq = (PCFG_API_REQ)pData; + + if(enCode) + { + if(strlen(pReq->keyName) > 0) + { + char* pBase64 = (char *)EvpBase64Encode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char* pBase64 = (char *)EvpBase64Encode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->keyName) > 0) + { + + char *pBase64 = (char *)EvpBase64Decode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } +} + +static const char* __cfg_API_RSP2Json(void* pData) +{ + PCFG_API_RSP pReq = (PCFG_API_RSP)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, string, keyName); + s2j_json_set_basic_element(jObject, pReq, string, keyValue); + s2j_json_set_basic_element(jObject, pReq, int, keyType); + s2j_json_set_basic_element(jObject, pReq, int, errNo); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2CFG_API_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, CFG_API_RSP); + + memset(sObject, 0, sizeof(CFG_API_RSP)); + + s2j_struct_get_basic_element(sObject, pJson, string, keyName); + s2j_struct_get_basic_element(sObject, pJson, string, keyValue); + s2j_struct_get_basic_element(sObject, pJson, int, keyType); + s2j_struct_get_basic_element(sObject, pJson, int, errNo); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __cfg_API_RSPBase64(void *pData, int enCode) +{ + PCFG_API_RSP pReq = (PCFG_API_RSP)pData; + + if(enCode) + { + if(strlen(pReq->keyName) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->keyName) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } +} + +static const char* __player_TO_CTRL2Json(void* pData) +{ + PPLAYER_TO_CTRL pP2C = (PPLAYER_TO_CTRL)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pP2C, string, musicUuid); + s2j_json_set_basic_element(jObject, pP2C, int, plySt); + s2j_json_set_basic_element(jObject, pP2C, int, curPos); + s2j_json_set_basic_element(jObject, pP2C, int, duration); + + s2j_json_set_basic_element(jObject, pP2C, int, playerId); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2PLAYER_TO_CTRL(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, PLAYER_TO_CTRL); + + memset(sObject, 0, sizeof(PLAYER_TO_CTRL)); + + s2j_struct_get_basic_element(sObject, pJson, string, musicUuid); + s2j_struct_get_basic_element(sObject, pJson, int, plySt); + s2j_struct_get_basic_element(sObject, pJson, int, curPos); + s2j_struct_get_basic_element(sObject, pJson, int, duration); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __player_TO_CTRLBase64(void *pData, int enCode) +{ + PPLAYER_TO_CTRL pReq = (PPLAYER_TO_CTRL)pData; + + if(enCode) + { + if(strlen(pReq->musicUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->musicUuid); + memset(pReq->musicUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->musicUuid, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->musicUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->musicUuid); + memset(pReq->musicUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->musicUuid, pBase64); + free(pBase64); + } + } +} + +static const char* __ctrl_TO_PLAYER2Json(void* pData) +{ + PCTRL_TO_PLAYER pC2P = (PCTRL_TO_PLAYER)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pC2P, string, src); + s2j_json_set_basic_element(jObject, pC2P, string, srcUuid); + s2j_json_set_basic_element(jObject, pC2P, string, ttsText); + s2j_json_set_basic_element(jObject, pC2P, int, skTime); + s2j_json_set_basic_element(jObject, pC2P, int, plyMode); + s2j_json_set_basic_element(jObject, pC2P, int, plyListType); + s2j_json_set_basic_element(jObject, pC2P, int, adSrcType); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2CTRL_TO_PLAYER(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, CTRL_TO_PLAYER); + + memset(sObject, 0, sizeof(CTRL_TO_PLAYER)); + + s2j_struct_get_basic_element(sObject, pJson, string, src); + s2j_struct_get_basic_element(sObject, pJson, string, srcUuid); + s2j_struct_get_basic_element(sObject, pJson, string, ttsText); + s2j_struct_get_basic_element(sObject, pJson, int, skTime); + s2j_struct_get_basic_element(sObject, pJson, int, plyMode); + s2j_struct_get_basic_element(sObject, pJson, int, plyListType); + s2j_struct_get_basic_element(sObject, pJson, int, adSrcType); + s2j_struct_get_basic_element(sObject, pJson, int, duration); + s2j_struct_get_basic_element(sObject, pJson, int, volRestoreTime); + s2j_struct_get_basic_element(sObject, pJson, int, volBegin); + s2j_struct_get_basic_element(sObject, pJson, string, fifo); + s2j_struct_get_basic_element(sObject, pJson, int, channel); + s2j_struct_get_basic_element(sObject, pJson, int, bytes); + s2j_struct_get_basic_element(sObject, pJson, int, sampleRate); + s2j_struct_get_basic_element(sObject, pJson, int, playerId); + s2j_struct_get_basic_element(sObject, pJson, double, gain); + s2j_struct_get_basic_element(sObject, pJson, string, backGroundUrl); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __ctrl_TO_PLAYERBase64(void *pData, int enCode) +{ + PCTRL_TO_PLAYER pReq = (PCTRL_TO_PLAYER)pData; + + if(enCode) + { + if(strlen(pReq->src) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->src); + memset(pReq->src, 0, MAX_MUSIC_UUID); + strcpy(pReq->src, pBase64); + free(pBase64); + } + + if(strlen(pReq->srcUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->srcUuid); + memset(pReq->srcUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->srcUuid, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->src) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->src); + memset(pReq->src, 0, MAX_MUSIC_UUID); + strcpy(pReq->src, pBase64); + free(pBase64); + } + + if(strlen(pReq->srcUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->srcUuid); + memset(pReq->srcUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->srcUuid, pBase64); + free(pBase64); + } + } +} + +#if 0 +const char* __ota_Notify_REQ2Json(void* pData) +{ + int i; + POTA_DATA_INFO pReq = (POTA_DATA_INFO)pData; + cJSON* pRoot = NULL; + cJSON* pSubArray = NULL; + const char* pJsonS; + + pRoot = cJSON_CreateObject(); + + cJSON_AddNumberToObject(pRoot, "version", pReq->version); + cJSON_AddNumberToObject(pRoot, "otaMode", pReq->otaMode); + + pSubArray = cJSON_CreateArray(); + cJSON_AddItemToObject(pRoot, "otaFile", pSubArray); + + for(i = 0; i < sizeof(pReq->otaFile) / sizeof(pReq->otaFile[0]); i++) + { + cJSON *pItem = cJSON_CreateObject(); + + cJSON_AddItemToObject(pSubArray, "", pItem); + + + cJSON_AddStringToObject(pItem, "url", pReq->otaFile[i].url); + cJSON_AddStringToObject(pItem, "md5", pReq->otaFile[i].md5); + cJSON_AddNumberToObject(pItem, "size", pReq->otaFile[i].size); + } + + pJsonS = cJSON_Print(pRoot); + cJSON_Delete(pRoot); + + return pJsonS; +} + +void* __json2OTA_Notify_REQ(const char* pJsonS) +{ + POTA_DATA_INFO pInfo; + cJSON* pSubArray = NULL; + cJSON* pItem = NULL; + + cJSON* pRoot = cJSON_Parse(pJsonS); + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "otaFile"); + + pInfo = (POTA_DATA_INFO)malloc(sizeof(OTA_DATA_INFO)); + memset(pInfo, 0, sizeof(OTA_DATA_INFO)); + + pItem = cJSON_GetObjectItem(pRoot, "version"); + pInfo->version = pItem->valueint; + + pItem = cJSON_GetObjectItem(pRoot, "otaMode"); + pInfo->otaMode = pItem->valueint; + + if(pSubArray) + { + int i; + cJSON *pList = pSubArray->child; + + for(i = 0; i < cJSON_GetArraySize(pSubArray); i++) + { + strcpy(pInfo->otaFile[i].url, cJSON_GetObjectItem(pList, "url")->valuestring); + strcpy(pInfo->otaFile[i].md5, cJSON_GetObjectItem(pList, "md5")->valuestring); + pInfo->otaFile[i].size = cJSON_GetObjectItem(pList, "size")->valueint; + + pList = pList->next; + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} +#else +const char* __ota_Notify_REQ2Json(void* pData) +{ + POTA_DATA_INFO pReq = (POTA_DATA_INFO)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, version); + s2j_json_set_basic_element(jObject, pReq, int, otaCmd); + s2j_json_set_basic_element(jObject, pReq, int, otaMode); + + s2j_json_set_struct_element(json_otaRes, jObject, struct_otaRes, pReq, OTA_FILE_INFO, otaFileInfo); + s2j_json_set_basic_element(json_otaRes, struct_otaRes, string, url); + s2j_json_set_basic_element(json_otaRes, struct_otaRes, string, md5); + s2j_json_set_basic_element(json_otaRes, struct_otaRes, int, size); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2OTA_Notify_REQ(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, OTA_DATA_INFO); + + memset(sObject, 0, sizeof(OTA_DATA_INFO)); + + s2j_struct_get_basic_element(sObject, pJson, int, version); + s2j_struct_get_basic_element(sObject, pJson, int, otaCmd); + s2j_struct_get_basic_element(sObject, pJson, int, otaMode); + + s2j_struct_get_struct_element(struct_otaRes, sObject, json_otaRes, pJson, OTA_FILE_INFO, otaFileInfo); + s2j_struct_get_basic_element(struct_otaRes, json_otaRes, string, url); + s2j_struct_get_basic_element(struct_otaRes, json_otaRes, string, md5); + s2j_struct_get_basic_element(struct_otaRes, json_otaRes, int, size); + + cJSON_Delete(pJson); + + return sObject; +} +#endif +static void __ota_NotifyBase64(void *pData, int enCode) +{ + POTA_DATA_INFO pReq = (POTA_DATA_INFO)pData; + + if(enCode) + { + if(strlen(pReq->otaFileInfo.url) > 0) + { + char *pBase64 = (char *)EvpBase64EncodeNoAlign(pReq->otaFileInfo.url); + memset(pReq->otaFileInfo.url, 0, SIZE_1K); + strcpy(pReq->otaFileInfo.url, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->otaFileInfo.url) > 0) + { + char *pBase64 = (char *)EvpBase64DecodeNoAlign(pReq->otaFileInfo.url); + memset(pReq->otaFileInfo.url, 0, SIZE_1K); + strcpy(pReq->otaFileInfo.url, pBase64); + free(pBase64); + } + } +} + +const char* __ota_Status_RSP2Json(void* pData) +{ + POTA_RSP_STATUS pReq = (POTA_RSP_STATUS)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, status); + s2j_json_set_basic_element(jObject, pReq, int, val); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2OTA_Status_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, OTA_RSP_STATUS); + + memset(sObject, 0, sizeof(OTA_RSP_STATUS)); + + s2j_struct_get_basic_element(sObject, pJson, int, status); + s2j_struct_get_basic_element(sObject, pJson, int, val); + + cJSON_Delete(pJson); + + return sObject; +} + +const char* __alarm_Run_Event_RSP2Json(void* pData) +{ + const char* pJsonS; + PASSISTANT_ITEM_INFO pReq = (PASSISTANT_ITEM_INFO)pData; + cJSON* pRoot = cJSON_CreateObject(); + cJSON* pSubArray = cJSON_CreateArray(); + + cJSON_AddItemToObject(pRoot, "data", pSubArray); + + cJSON *pItem = cJSON_CreateObject(); + + cJSON_AddItemToObject(pSubArray, "", pItem); + + cJSON_AddNumberToObject(pItem, "alarmId", pReq->itemId); + cJSON_AddNumberToObject(pItem, "itemType", pReq->itemType); + cJSON_AddNumberToObject(pItem, "priority", pReq->priority); + cJSON_AddNumberToObject(pItem, "repeatMode", pReq->repeatMode); + + cJSON_AddNumberToObject(pItem, "year", pReq->year); + cJSON_AddNumberToObject(pItem, "month", pReq->month); + cJSON_AddNumberToObject(pItem, "day", pReq->day); + cJSON_AddNumberToObject(pItem, "hour", pReq->hour); + cJSON_AddNumberToObject(pItem, "minute", pReq->minute); + cJSON_AddNumberToObject(pItem, "second", pReq->second); + cJSON_AddNumberToObject(pItem, "weekDay", pReq->weekDay); + + cJSON_AddNumberToObject(pItem, "voiceId", pReq->voiceId); + cJSON_AddStringToObject(pItem, "strTips", pReq->strTips); + cJSON_AddStringToObject(pItem, "resUrl", pReq->resUrl); + + cJSON_AddStringToObject(pItem, "voiceResType", pReq->voiceResType); + cJSON_AddStringToObject(pItem, "voiceRes", pReq->voiceRes); + + pJsonS = cJSON_Print(pRoot); + cJSON_Delete(pRoot); + + return pJsonS; +} + +static void __getAlarmDateTimeInfo(cJSON* pJson, PASSISTANT_ITEM_INFO pAlarmInfo) +{ + struct tm tmNow; + time_t timep; + + const char *pStrYear = cJSON_GetObjectItem(pJson, "year")->valuestring; + const char *pStrMonth = cJSON_GetObjectItem(pJson, "month")->valuestring; + const char *pStrDay = cJSON_GetObjectItem(pJson, "dayofMonth")->valuestring; + const char *pStrHour = cJSON_GetObjectItem(pJson, "hour")->valuestring; + const char *pStrMinute = cJSON_GetObjectItem(pJson, "minute")->valuestring; + const char *pStrSecond = cJSON_GetObjectItem(pJson, "second")->valuestring; + const char *pStrWeekDay = cJSON_GetObjectItem(pJson, "dayofWeek")->valuestring; + + time(&timep); + localtime_r(&timep, &tmNow); + + if(pStrYear != NULL && strlen(pStrYear) > 0) + { + pAlarmInfo->year = strtoul(pStrYear, NULL, 10) - 1900; + } + else + { + pAlarmInfo->year = -1;//tmNow.tm_year; + } + + if(pStrMonth != NULL && strlen(pStrMonth) > 0) + { + pAlarmInfo->month = strtoul(pStrMonth, NULL, 10) - 1; + } + else + { + pAlarmInfo->month = -1;//tmNow.tm_mon; + } + + if(pStrDay != NULL && strlen(pStrDay) > 0) + { + pAlarmInfo->day = strtoul(pStrDay, NULL, 10); + } + else + { + pAlarmInfo->day = -1; //tmNow.tm_mday; + } + + if(pStrHour != NULL && strlen(pStrHour) > 0) + { + pAlarmInfo->hour = strtoul(pStrHour, NULL, 10); + } + else + { + pAlarmInfo->hour = -1; + } + + if(pStrMinute != NULL && strlen(pStrMinute) > 0) + { + pAlarmInfo->minute = strtoul(pStrMinute, NULL, 10); + } + else + { + pAlarmInfo->minute = -1; + } + + if(pStrSecond != NULL && strlen(pStrSecond) > 0) + { + pAlarmInfo->second = strtoul(pStrSecond, NULL, 10); + } + else + { + pAlarmInfo->second = -1; + } + + if(pStrWeekDay != NULL && strlen(pStrWeekDay) > 0) + { + if(strchr(pStrWeekDay, '7') != NULL) + { + pAlarmInfo->weekDay |= 1; + } + + if(strchr(pStrWeekDay, '1') != NULL) + { + pAlarmInfo->weekDay |= 1 << 1; + } + + if(strchr(pStrWeekDay, '2') != NULL) + { + pAlarmInfo->weekDay |= 1 << 2; + } + + if(strchr(pStrWeekDay, '3') != NULL) + { + pAlarmInfo->weekDay |= 1 << 3; + } + + if(strchr(pStrWeekDay, '4') != NULL) + { + pAlarmInfo->weekDay |= 1 << 4; + } + + if(strchr(pStrWeekDay, '5') != NULL) + { + pAlarmInfo->weekDay |= 1 << 5; + } + + if(strchr(pStrWeekDay, '6') != NULL) + { + pAlarmInfo->weekDay |= 1 << 6; + } + } + else + { + pAlarmInfo->weekDay = 0; + } +} + +void* __json2Alarm_sync_RSP(const char *pJsonS) +{ + PASSISTANT_SYNC_INFO pInfo; + cJSON* pSubArray = NULL; + //cJSON* pItem = NULL; + + cJSON* pRoot = cJSON_Parse(pJsonS); + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "data"); + + pInfo = (PASSISTANT_SYNC_INFO)malloc(sizeof(ASSISTANT_SYNC_INFO)); + memset(pInfo, 0, sizeof(ASSISTANT_SYNC_INFO)); + + pInfo->pAlarmInfo = NULL; + + if(pSubArray) + { + cJSON *pList = pSubArray->child; + int arraySize = cJSON_GetArraySize(pSubArray); + + if(arraySize > 0) + { + pInfo->pAlarmInfo = (PASSISTANT_ITEM_INFO)malloc(sizeof(ASSISTANT_ITEM_INFO) * arraySize); + + pInfo->nItems = arraySize; + + for(int i = 0; i < arraySize; i++) + { + cJSON* pData = cJSON_GetObjectItem(pList, "vboxDate"); + + memset(&pInfo->pAlarmInfo[i], 0, sizeof(ASSISTANT_ITEM_INFO)); + + if(pData != NULL) + { + cJSON *pItem; + + __getAlarmDateTimeInfo(pData, &pInfo->pAlarmInfo[i]); + + pInfo->pAlarmInfo[i].itemType = cJSON_GetObjectItem(pList, "label")->valueint; + pInfo->pAlarmInfo[i].itemId = cJSON_GetObjectItem(pList, "id")->valueint; + pInfo->pAlarmInfo[i].repeatMode = cJSON_GetObjectItem(pList, "type")->valueint; + pInfo->pAlarmInfo[i].voiceId = cJSON_GetObjectItem(pList, "voiceType")->valueint; + + pItem = cJSON_GetObjectItem(pList, "remark"); + + if(pInfo->pAlarmInfo[i].itemType != ASSISTANT_TYPE_CLOCK && pItem) + { + strcpy(pInfo->pAlarmInfo[i].strTips, pItem->valuestring); + } + + pItem = cJSON_GetObjectItem(pList, "resUrl"); + + if(pItem) + { + strcpy(pInfo->pAlarmInfo[i].resUrl, pItem->valuestring); + } + + pItem = cJSON_GetObjectItem(pList, "voiceRes"); + + if(pItem) + { + strcpy(pInfo->pAlarmInfo[i].voiceRes, pItem->valuestring); + } + + pItem = cJSON_GetObjectItem(pList, "voiceResType"); + + if(pItem) + { + strcpy(pInfo->pAlarmInfo[i].voiceResType, pItem->valuestring); + } + + pList = pList->next; +#if 0 + fprintf(stdout, "%04u-%02u-%02u %02u:%02u:%02u %u\n", + pInfo->pAlarmInfo[i].year, + pInfo->pAlarmInfo[i].month, + pInfo->pAlarmInfo[i].day, + pInfo->pAlarmInfo[i].hour, + pInfo->pAlarmInfo[i].minute, + pInfo->pAlarmInfo[i].second, + pInfo->pAlarmInfo[i].weekDay); +#endif + } + } + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} + +const char* __alarm_Status_RSP2Json(void* pData) +{ + const char* pJsonS; + + PASSISTANT_RSP_STATUS pReq = (PASSISTANT_RSP_STATUS)pData; + + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, cmd); + s2j_json_set_basic_element(jObject, pReq, int, val); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2Alarm_Status_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, ASSISTANT_RSP_STATUS); + + memset(sObject, 0, sizeof(ASSISTANT_RSP_STATUS)); + + s2j_struct_get_basic_element(sObject, pJson, int, cmd); + s2j_struct_get_basic_element(sObject, pJson, int, val); + + cJSON_Delete(pJson); + + return sObject; + +} + +const char* __alarm_change_RSP2Json(void* pData) +{ + const char* pJsonS; + PASSISTANT_NOTIFY_INFO pReq = (PASSISTANT_NOTIFY_INFO)pData; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, cmd); + s2j_json_set_basic_element(jObject, pReq, int, type); + s2j_json_set_array_element(jObject, pReq, double, ids, pReq->nItems); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2Alarm_change_RSP(const char* pJsonS) +{ + PASSISTANT_NOTIFY_INFO pInfo = NULL; + cJSON* pSubArray = NULL; + cJSON* pItem = NULL; + + cJSON* pRoot = cJSON_Parse(pJsonS); + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "ids"); + + pInfo = (PASSISTANT_NOTIFY_INFO)malloc(sizeof(ASSISTANT_NOTIFY_INFO)); + memset(pInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO)); + + pItem = cJSON_GetObjectItem(pRoot, "type"); + pInfo->type = pItem->valueint; + +#if 0 + pItem = cJSON_GetObjectItem(pRoot, "cmd"); + pInfo->cmd = pItem->valueint; +#endif + + if(pSubArray) + { + int arraySize = cJSON_GetArraySize(pSubArray); + + if(arraySize > 0) + { + pInfo->nItems = arraySize; + + for(int i = 0; i < arraySize; i++) + { + pInfo->ids[i] = (unsigned long long)(cJSON_GetArrayItem(pSubArray, i)->valuedouble); + } + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} +#if 0 +const char* __alarm_change_RSP2Json(void* pData) +{ + int i = 0; + PALARM_REMOVE_INFO pReq = (PALARM_REMOVE_INFO)pData; + cJSON* pRoot = NULL; + cJSON* pSubArray = NULL; + const char* pJsonS; + + pRoot = cJSON_CreateObject(); + + cJSON_AddNumberToObject(pRoot, "nItems", pReq->nItems); + + pSubArray = cJSON_CreateArray(); + cJSON_AddItemToObject(pRoot, "data", pSubArray); + + for(i = 0; i < pReq->nItems; i++) + { + cJSON *pItem = cJSON_CreateObject(); + + cJSON_AddItemToObject(pSubArray, "", pItem); + + cJSON_AddNumberToObject(pItem, "alarmId", pReq->pItemInfo[i].alarmId); + cJSON_AddNumberToObject(pItem, "itemType", pReq->pItemInfo[i].itemType); + } + + pJsonS = cJSON_Print(pRoot); + cJSON_Delete(pRoot); + + return pJsonS; +} + +void* __json2Alarm_change_RSP(const char* pJsonS) +{ + PALARM_REMOVE_INFO pInfo = NULL; + cJSON* pRoot = cJSON_Parse(pJsonS); + cJSON* pSubArray = NULL; + cJSON* pItem = NULL; + int itemType = 0; + + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "data"); + + pInfo = (PALARM_REMOVE_INFO)malloc(sizeof(ALARM_REMOVE_INFO)); + memset(pInfo, 0, sizeof(ALARM_REMOVE_INFO)); + + pItem = cJSON_GetObjectItem(pRoot, "type"); + itemType = pItem->valueint; + + pInfo->pItemInfo = NULL; + + if(pSubArray) + { + int i; + cJSON *pList = pSubArray->child; + int arraySize = cJSON_GetArraySize(pSubArray); + + if(arraySize > 0) + { + pInfo->pItemInfo = (PITEM_INFO)malloc(sizeof(ITEM_INFO) * arraySize); + pInfo->nItems = arraySize; + + for(i = 0; i < arraySize; i++) + { + memset(&pInfo->pItemInfo[i], 0, sizeof(ALARM_ITEM_INFO)); + + pInfo->pItemInfo[i].itemType = itemType; + pInfo->pItemInfo[i].alarmId = cJSON_GetObjectItem(pList, "id")->valueint; + + pList = pList->next; + } + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} +#endif + +const char* __alarm_WorkData_RSP2Json(void* pData) +{ + const char* pJsonS; + PWORKDAY_INFO pReq = (PWORKDAY_INFO)pData; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, year); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2Alarm_WorkData_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, WORKDAY_INFO); + + memset(sObject, 0, sizeof(WORKDAY_INFO)); + + s2j_struct_get_basic_element(sObject, pJson, int, year); + s2j_struct_get_array_element(sObject, pJson, int, days); + + cJSON_Delete(pJson); + + return sObject; +} + + +const char* __logCfg_RSP2Json(void* pData) +{ + PLOG_CFG_PROTOCOL pReq = (PLOG_CFG_PROTOCOL)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, cfgCmd); + s2j_json_set_basic_element(jObject, pReq, int, iParams1); + s2j_json_set_basic_element(jObject, pReq, int, iParams2); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2LogCfg_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, LOG_CFG_PROTOCOL); + + memset(sObject, 0, sizeof(LOG_CFG_PROTOCOL)); + + s2j_struct_get_basic_element(sObject, pJson, int, cfgCmd); + s2j_struct_get_basic_element(sObject, pJson, int, iParams1); + s2j_struct_get_basic_element(sObject, pJson, int, iParams2); + + cJSON_Delete(pJson); + + return sObject; +} + +const char* __wifiStatus_RSP2Json(void* pData) +{ + PWIFI_STATUS_PRO pReq = (PWIFI_STATUS_PRO)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, wifi_evt); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2WifiStatus_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, WIFI_STATUS_PRO); + + memset(sObject, 0, sizeof(WIFI_STATUS_PRO)); + + s2j_struct_get_basic_element(sObject, pJson, int, wifi_evt); + + cJSON_Delete(pJson); + + return sObject; +} + +void* __json2McuGuideCmd_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, MCU_TEST_GUIDE_CMD); + + memset(sObject, 0, sizeof(MCU_TEST_GUIDE_CMD)); + + s2j_struct_get_basic_element(sObject, pJson, int, red); + s2j_struct_get_basic_element(sObject, pJson, int, green); + s2j_struct_get_basic_element(sObject, pJson, int, blue); + + cJSON_Delete(pJson); + + return sObject; +} + +void* __json2McuMatrixCmd_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, MCU_TEST_MATRIX_CMD); + + memset(sObject, 0, sizeof(MCU_TEST_MATRIX_CMD)); + + s2j_struct_get_basic_element(sObject, pJson, int, level); + + cJSON_Delete(pJson); + + return sObject; +} + +const char* __mcuVersion_RSP2Json(void* pData) +{ + PMCU_TEST_VER_CMD pReq = (PMCU_TEST_VER_CMD)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, string, McuVer); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static JSON_ENGINE g_jSonEngine[] = +{ + {JSON_ENGINE_P2C, __player_TO_CTRL2Json, __json2PLAYER_TO_CTRL, __player_TO_CTRLBase64}, + {JSON_ENGINE_C2P, __ctrl_TO_PLAYER2Json, __json2CTRL_TO_PLAYER, __ctrl_TO_PLAYERBase64}, + {JSON_ENGINE_CFG_REQ, __cfg_API_REQ2Json, __json2CFG_API_REQ, __cfg_API_REQBase64}, + {JSON_ENGINE_CFG_RSP, __cfg_API_RSP2Json, __json2CFG_API_RSP, __cfg_API_RSPBase64 }, + {JSON_ENGINE_ASSISTANT_SYNC_RSP, NULL, __json2Alarm_sync_RSP, NULL}, + {JSON_ENGINE_ASSISTANT_NOTIFY, __alarm_change_RSP2Json, __json2Alarm_change_RSP, NULL}, + {JSON_ENGINE_ASSISTANT_STATUS, __alarm_Status_RSP2Json, __json2Alarm_Status_RSP, NULL}, + {JSON_ENGINE_ASSISTANT_RUNNING, __alarm_Run_Event_RSP2Json, NULL, NULL}, + {JSON_ENGINE_WORKDAY_REQ, __alarm_WorkData_RSP2Json, __json2Alarm_WorkData_RSP, NULL}, + {JSON_ENGINE_PING, __ping_MSG2Json, __json2PING_MSG, NULL}, + {JSON_ENGINE_OTA_REQ, __ota_Notify_REQ2Json, __json2OTA_Notify_REQ, __ota_NotifyBase64}, + {JSON_ENGINE_OTA_RSP, __ota_Status_RSP2Json, __json2OTA_Status_RSP, NULL}, + {JSON_ENGINE_LOG_CFG_CMD, __logCfg_RSP2Json, __json2LogCfg_RSP, NULL}, + {JSON_WIFI_STATUS_NOTIFY, __wifiStatus_RSP2Json, __json2WifiStatus_RSP, NULL}, + {JSON_MCU_GUIDE_TEST_CMD, NULL, __json2McuGuideCmd_RSP, NULL}, + {JSON_MCU_MATRIX_TEST_CMD, NULL, __json2McuMatrixCmd_RSP, NULL}, + {JSON_MCU_TEST_GET_VER_CMD, __mcuVersion_RSP2Json, NULL, NULL}, +}; + +void* Json2Struct(const char* pJsonStr, JSON_ENGINE_TYPE type, int enBase64, int* pErr) +{ + if(pJsonStr == NULL || pErr == NULL) + { + if(pErr) + { + *pErr = -ERR_INPUT_PARAMS; + } + return NULL; + } + + if(type < 0 || type >= JSON_ENGINE_MAX) + { + *pErr = -ERR_INPUT_PARAMS; + return NULL; + } + + *pErr = 0; + + //LOG_EX(LOG_Debug, "Json:\n%s\n", pJsonStr); + + if(g_jSonEngine[type].j2sCb) + { + void *pStruct = g_jSonEngine[type].j2sCb(pJsonStr); + + if(enBase64 && g_jSonEngine[type].base64Cb) + { + g_jSonEngine[type].base64Cb(pStruct, FALSE); + } + + return (pStruct); + } + else + { + return (NULL); + } +} + +const char* Struct2Json(void* pStruct, JSON_ENGINE_TYPE type, int enBase64, int* pErr) +{ + if(pStruct == NULL || pErr == NULL) + { + if(pErr) + { + *pErr = -ERR_INPUT_PARAMS; + } + return NULL; + } + + if(type < 0 || type >= JSON_ENGINE_MAX) + { + *pErr = -ERR_INPUT_PARAMS; + return NULL; + } + + *pErr = 0; + + if(enBase64 && g_jSonEngine[type].base64Cb) + { + g_jSonEngine[type].base64Cb(pStruct, TRUE); + } + + if(g_jSonEngine[type].s2jCb) + { + const char *pJsongStr = g_jSonEngine[type].s2jCb(pStruct); + + //LOG_EX(LOG_Debug, "Json: \n%s\n", pJsongStr); + return (pJsongStr); + } + else + { + return NULL; + } +} diff --git a/Framework/Monitor/monitor.c b/Framework/Monitor/monitor.c new file mode 100644 index 0000000..6e78f6b --- /dev/null +++ b/Framework/Monitor/monitor.c @@ -0,0 +1,347 @@ +#ifdef ENABLE_COUNT_DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" + +#define LOG_SAVE_TIME (1000) + +typedef struct +{ + long long maxValue; + long long minValue; + long long avgValue; +} STATISTICAL_VALUE, *PSTATISTICAL_VALUE; + +typedef struct +{ + long long curVaule; + long long tolValue; + unsigned int tolCount; + STATISTICAL_VALUE cVal; +} CSTATISTICAL_INFO, *PSTATISTICAL_INFO; + +typedef struct +{ + char* pMonName; + unsigned long nCount; + CSTATISTICAL_INFO nCstInfo; + uv_rwlock_t rwLock; + + uv_timer_t logTimer; + unsigned int logTime; + + UT_hash_handle hh; ///< UT Hash handle +} MONITOR_INFO, *PMONITOR_INFO; + +static uv_rwlock_t g_uvMonRwLock; +static PMONITOR_INFO g_MonTbl = NULL; +static uv_loop_t* g_MonLogLoop = NULL; + +static void __uvMonLogProc(void *pParams) +{ + RunUVLoop(g_MonLogLoop); + + while(TRUE) + { + usleep(1000); + } + + pthread_detach(pthread_self()); +} + +static void __logMonTimerProc(uv_timer_t* pTimer) +{ + PMONITOR_INFO pInfo = (PMONITOR_INFO)pTimer->data; + + if(pInfo && (pInfo->nCount + pInfo->nCstInfo.tolCount > 0)) + { + UT_string* pMsg = NULL; + utstring_new(pMsg); + + uv_rwlock_rdlock(&pInfo->rwLock); + + utstring_printf(pMsg, "%s Statistical Information:\n", pInfo->pMonName); + //LOG_EX(LOG_Debug, "%s Statistical Information:\n", pInfo->pMonName); + + if(pInfo->nCount) + { + UT_string* pMsgCount = NULL; + utstring_new(pMsgCount); + utstring_printf(pMsgCount, " Total Count = %lu\n", pInfo->nCount); + utstring_concat(pMsg, pMsgCount); + utstring_free(pMsgCount); + //LOG_EX(LOG_Debug, " Total Count = %u\n", pInfo->nCount); + } + + if(pInfo->nCstInfo.tolCount > 0) + { + UT_string* pMsgStat = NULL; + utstring_new(pMsgStat); + utstring_printf(pMsgStat, " Max Value = %lld\n" + " Min Value = %lld\n" + " Avg Value = %lld\n" + " ---- Statistical by total %lld of %u times\n", + pInfo->nCstInfo.cVal.maxValue, + pInfo->nCstInfo.cVal.minValue, + pInfo->nCstInfo.cVal.avgValue, + pInfo->nCstInfo.tolValue, + pInfo->nCstInfo.tolCount); + utstring_concat(pMsg, pMsgStat); + utstring_free(pMsgStat); +#if 0 + LOG_EX(LOG_Debug, " Max Value = %lld\n", pInfo->nCstInfo.cVal.maxValue); + LOG_EX(LOG_Debug, " Min Value = %lld\n", pInfo->nCstInfo.cVal.minValue); + LOG_EX(LOG_Debug, " Avg Value = %lld\n", pInfo->nCstInfo.cVal.avgValue); + LOG_EX(LOG_Debug, " ---- Statistical by total %lld of %u times\n", + pInfo->nCstInfo.tolValue, pInfo->nCstInfo.tolCount); +#endif + } + + LOG_EX(LOG_Debug, "%s", utstring_body(pMsg)); + + uv_rwlock_rdunlock(&pInfo->rwLock); + utstring_free(pMsg); + } +} + +int MonitorInit(void) +{ + uv_thread_t uvMonLogThread; + + g_MonLogLoop = uv_loop_new(); + + uv_rwlock_init(&g_uvMonRwLock); + + uv_thread_create(&uvMonLogThread, __uvMonLogProc, NULL); + + return 0; +} + +int MonAddNewItem(const char* pName, int logSaveTime) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo != NULL) + { + return -ERR_CFG_ITEM_EXIST; + } + + pInfo = (PMONITOR_INFO)malloc(sizeof(MONITOR_INFO)); + + if(pInfo == NULL) + { + return -ERR_MALLOC_MEMORY; + } + + memset(pInfo, 0, sizeof(MONITOR_INFO)); + + pInfo->nCstInfo.cVal.minValue = INT_MAX; + pInfo->logTime = logSaveTime; + pInfo->pMonName = strdup(pName); + + if(pInfo->logTime > 0) + { + pInfo->logTimer.data = pInfo; + uv_timer_init(g_MonLogLoop, &pInfo->logTimer); + uv_timer_start(&pInfo->logTimer, __logMonTimerProc, pInfo->logTime, pInfo->logTime); + } + else + { + pInfo->logTime = 0; + } + + uv_rwlock_init(&pInfo->rwLock); + + uv_rwlock_wrlock(&g_uvMonRwLock); + HASH_ADD_STR(g_MonTbl, pMonName, pInfo); + uv_rwlock_wrunlock(&g_uvMonRwLock); + + return 0; +} + +int MonIncreaseCount(const char* pName) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + uv_rwlock_wrlock(&pInfo->rwLock); + pInfo->nCount++; + uv_rwlock_wrunlock(&pInfo->rwLock); + + return 0; +} + +int MonDiffStatistical(const char* pName, long long newVal) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + uv_rwlock_wrlock(&pInfo->rwLock); + + if(pInfo->nCstInfo.curVaule != 0) + { + long long diffValue = newVal - pInfo->nCstInfo.curVaule; + + pInfo->nCstInfo.tolValue += diffValue; + pInfo->nCstInfo.tolCount++; + + if(pInfo->nCstInfo.tolCount > 10) + { + pInfo->nCstInfo.cVal.avgValue = pInfo->nCstInfo.tolValue / pInfo->nCstInfo.tolCount; + + if(pInfo->nCstInfo.cVal.maxValue < diffValue) + { + pInfo->nCstInfo.cVal.maxValue = diffValue; + } + + if(pInfo->nCstInfo.cVal.minValue > diffValue) + { + pInfo->nCstInfo.cVal.minValue = diffValue; + } + } + } + + pInfo->nCstInfo.curVaule = newVal; + uv_rwlock_wrunlock(&pInfo->rwLock); + + //fprintf(stdout, "%s value %lld diffValue %lld\n", pName, newVal, diffValue); + return 0; +} + +int MonUpgradeStatistical(const char* pName, long newVal) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + uv_rwlock_wrlock(&pInfo->rwLock); + + pInfo->nCstInfo.curVaule = newVal; + pInfo->nCstInfo.tolValue += newVal; + pInfo->nCstInfo.tolCount++; + pInfo->nCstInfo.cVal.avgValue = pInfo->nCstInfo.tolValue / pInfo->nCstInfo.tolCount; + + if(pInfo->nCstInfo.cVal.maxValue < newVal) + { + pInfo->nCstInfo.cVal.maxValue = newVal; + } + + if(pInfo->nCstInfo.cVal.minValue > newVal) + { + pInfo->nCstInfo.cVal.minValue = newVal; + } + + uv_rwlock_wrunlock(&pInfo->rwLock); + + //fprintf(stdout, "%s value %ld\n", pName, newVal); + return 0; +} + +int MonItemLogout(const char* pName) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + if(pInfo->nCount + pInfo->nCstInfo.tolCount == 0) + { + LOG_EX(LOG_Debug, "%s Statistical Unchanged\n", pInfo->pMonName); + return 0; + } + + uv_rwlock_rdlock(&pInfo->rwLock); + + LOG_EX(LOG_Debug, "%s Statistical Information:\n", pInfo->pMonName); + + if(pInfo->nCount) + { + LOG_EX(LOG_Debug, " Total Count = %u\n", pInfo->nCount); + } + + if(pInfo->nCstInfo.tolCount > 0) + { + LOG_EX(LOG_Debug, " Max Value = %lld\n", pInfo->nCstInfo.cVal.maxValue); + LOG_EX(LOG_Debug, " Min Value = %lld\n", pInfo->nCstInfo.cVal.minValue); + LOG_EX(LOG_Debug, " Avg Value = %lld\n", pInfo->nCstInfo.cVal.avgValue); + LOG_EX(LOG_Debug, " ---- Statistical by total %lld of %u times\n", + pInfo->nCstInfo.tolValue, pInfo->nCstInfo.tolCount); + } + + uv_rwlock_rdunlock(&pInfo->rwLock); + + return 0; +} +#endif diff --git a/Framework/Network/inet_api.c b/Framework/Network/inet_api.c new file mode 100644 index 0000000..0edd15e --- /dev/null +++ b/Framework/Network/inet_api.c @@ -0,0 +1,1396 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "inet_api.h" + +#define MAX_TIMEOUT_VALUE (10) +#define SSL_CA_FILE ("/etc/ssl/certs/ca-certificates.crt") + +typedef enum +{ + INET_HTTP_DOWNLOAD_FILE = 0, + INET_HTTP_WEBSERVICE_POST, +} INET_ACCESS_TYPE; + +typedef struct +{ + uv_poll_t uvPool; + curl_socket_t sock; +} CURL_CONTEXT_DATA, *PCURL_CONTEXT_DATA; + +typedef struct +{ + char* pReqUrl; + char sPath[MAX_PATH]; + char sDlPath[MAX_PATH]; + char* pTaskUuid; + INET_ACCESS_TYPE type; + unsigned int dlSize; + unsigned int lastTm; + unsigned int createTm; + uv_fs_t uvFsOpen; + uv_fs_t uvFsWrite; + uv_fs_t uvFsDataSync; + uv_fs_t uvFsClose; + uv_buf_t uvFsBuf; + OnProgressNotify onPrgCb; + OnHttpResponse onRspCb; + int isCancel; + CURL* pCurl; + void* pData; + int errCode; +} HTTP_REQ_PARAMS, *PHTTP_REQ_PARAMS; + +typedef struct +{ + char *pTaskUuid; + unsigned int uRetryTimes; + PHTTP_REQ_PARAMS pCurlItem; + + UT_hash_handle hh; ///< UT Hash handle +} CURL_HANDLE_TBL, *PCURL_HANDLE_TBL; + +static uv_timer_t g_uvCurlTm; +static uv_timer_t g_uvDlTm; +static CURLM* g_pCurl = NULL; +static uv_loop_t* g_pMainLoop = NULL; +static PCURL_HANDLE_TBL g_ReqHandleTbl = NULL; +static uv_rwlock_t g_uvHashRwLock; +static unsigned g_TotalDownloads = 0; + +static void __addReqIdToTable(const char* pTaskUuid, PHTTP_REQ_PARAMS pParams) +{ + PCURL_HANDLE_TBL pItem = NULL; + + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + + if(pItem == NULL) + { + pItem = (PCURL_HANDLE_TBL)malloc(sizeof(CURL_HANDLE_TBL)); + + memset(pItem, 0, sizeof(CURL_HANDLE_TBL)); + pItem->pTaskUuid = (char*)pTaskUuid; + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_STR(g_ReqHandleTbl, pTaskUuid, pItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + } + + pItem->pCurlItem = pParams; + pItem->uRetryTimes++; +} + +static void __removeReqIdFromTable(const char* pTaskUuid) +{ + PCURL_HANDLE_TBL pItem = NULL; + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + if(pItem != NULL) + { + HASH_DEL(g_ReqHandleTbl, pItem); + + if(pItem->pTaskUuid) + { + free(pItem->pTaskUuid); + } + + free(pItem); + } + uv_rwlock_wrunlock(&g_uvHashRwLock); +} + +static void __cancelDownloadTask(PHTTP_REQ_PARAMS pItem) +{ + if(pItem) + { + pItem->isCancel = TRUE; + } +} + +static void __uvFsCloseCb(uv_fs_t *puvFs) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)puvFs->data; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "[%s] Error: %d\n", __FUNCTION__, puvFs->result); + } + + uv_fs_req_cleanup(puvFs); + + if(pParams->type == INET_HTTP_DOWNLOAD_FILE) + { + if(strcmp(pParams->sDlPath, pParams->sPath) != 0) + { + CopyFile(pParams->sDlPath, pParams->sPath); + unlink(pParams->sDlPath); + } + + if(pParams->errCode == CURLE_ABORTED_BY_CALLBACK) + { + pParams->errCode = CURLE_OPERATION_TIMEDOUT; + } + + if(pParams->onRspCb && pParams->isCancel == FALSE) + { + pParams->onRspCb(NULL, pParams->dlSize, pParams->pReqUrl, pParams->sPath, + pParams->pTaskUuid, -pParams->errCode, pParams->pData); + } + } + + __removeReqIdFromTable(pParams->pTaskUuid); + + if(pParams->pReqUrl) + { + free(pParams->pReqUrl); + pParams->pReqUrl = NULL; + } + + free(pParams); + pParams = NULL; +} + +static void __uvFsDataSyncCb(uv_fs_t *puvFs) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)puvFs->data; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "[%s] Error: %d\n", __FUNCTION__, puvFs->result); + } + + uv_fs_req_cleanup(puvFs); + + uv_fs_close(g_pMainLoop, &pParams->uvFsClose, pParams->uvFsOpen.result, __uvFsCloseCb); +} + +static PCURL_CONTEXT_DATA __createCurlContext(curl_socket_t sock) +{ + PCURL_CONTEXT_DATA pContext = (PCURL_CONTEXT_DATA)malloc(sizeof(CURL_CONTEXT_DATA)); + + pContext->sock = sock; + + if(uv_poll_init_socket(g_pMainLoop, &pContext->uvPool, sock) != 0) + { + LOG_EX(LOG_Error, "uv_poll_init_socket Error\n"); + } + + pContext->uvPool.data = pContext; + + return (pContext); +} + +static void __uvCloseCb(uv_handle_t *puvPoll) +{ + PCURL_CONTEXT_DATA pContext = (PCURL_CONTEXT_DATA)puvPoll->data; + free(pContext); +} + +static void __destoryCurlContext(PCURL_CONTEXT_DATA pContext) +{ + uv_close((uv_handle_t *)&pContext->uvPool, __uvCloseCb); +} + +static void __checkMultiInfoTimeout(void) +{ + PHTTP_REQ_PARAMS pReq; + CURLMsg *pMsg = NULL; + int iPending; + + while((pMsg = curl_multi_info_read(g_pCurl, &iPending))) + { + switch(pMsg->msg) + { + case CURLMSG_DONE: + curl_easy_getinfo(pMsg->easy_handle, CURLINFO_PRIVATE, (void*)&pReq); + + LOG_EX(LOG_Debug, "Cleanup CURL: %p\n", pMsg->easy_handle); + + curl_multi_remove_handle(g_pCurl, pMsg->easy_handle); + curl_easy_cleanup(pMsg->easy_handle); + + if(pReq) + { + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + uv_fs_close(g_pMainLoop, &pReq->uvFsDataSync, pReq->uvFsOpen.result, NULL); + } + + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, pReq->pData); + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + + break; + + default: + LOG_EX(LOG_Error, "pMsg->msg(%d) != CURLMSG_DONE\n", pMsg->msg); + return; + } + } +} + +static void __checkMultiInfo(void) +{ + PHTTP_REQ_PARAMS pReq; + CURLMsg *pMsg = NULL; + int iPending; + + while((pMsg = curl_multi_info_read(g_pCurl, &iPending))) + { + switch(pMsg->msg) + { + case CURLMSG_DONE: + curl_easy_getinfo(pMsg->easy_handle, CURLINFO_PRIVATE, (void*)&pReq); + + curl_multi_remove_handle(g_pCurl, pMsg->easy_handle); + LOG_EX(LOG_Debug, "Cleanup CURL: %p\n", pMsg->easy_handle); + curl_easy_cleanup(pMsg->easy_handle); + + if(pReq) + { + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + if(pMsg->data.result != CURLE_OK) + { + pReq->errCode = pMsg->data.result; + } + else + { + pReq->errCode = 0; + } + + uv_fs_fdatasync(g_pMainLoop, &pReq->uvFsDataSync, pReq->uvFsOpen.result, __uvFsDataSyncCb); + } + else if(pReq->type == INET_HTTP_WEBSERVICE_POST) + { + if(pMsg->data.result != CURLE_OK) + { + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(pReq->uvFsBuf.base, pReq->dlSize, pReq->pReqUrl, pReq->sPath, + pReq->pTaskUuid, -pMsg->data.result, pReq->pData); + } + } + else + { + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(pReq->uvFsBuf.base, pReq->dlSize, pReq->pReqUrl, pReq->sPath, + pReq->pTaskUuid, 0, pReq->pData); + } + } + + if(pReq->uvFsBuf.base) + { + free(pReq->uvFsBuf.base); + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + else + { + if(pMsg->data.result != CURLE_OK) + { + if(pReq->onRspCb && pReq->isCancel == FALSE){ + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, -pMsg->data.result, pReq->pData); + } + } + else + { + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, 0, pReq->pData); + } + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + } + + break; + + default: + LOG_EX(LOG_Error, "pMsg->msg(%d) != CURLMSG_DONE\n", pMsg->msg); + return; + } + } +} + +static void __onDlTmoutCb(uv_timer_t *pufTimer) +{ + PCURL_HANDLE_TBL pItem = NULL, pTemp = NULL; + unsigned int curTm = (unsigned int)LIBUV_CURRENT_TIME_S(); + + HASH_ITER(hh, g_ReqHandleTbl, pItem, pTemp) + { + int dlTime; + + if(pItem->pCurlItem->isCancel) + { + continue; + } + + dlTime = curTm - pItem->pCurlItem->createTm; + + // 下载时间大于10s且平均下载速度小于10K/s超时 + if((dlTime * 10000 > pItem->pCurlItem->dlSize) && dlTime > 10) + { + LOG_EX(LOG_Error, "Download Speed less than 10k/s: %s (%uK/%ds)\n", + pItem->pTaskUuid, pItem->pCurlItem->dlSize / 1000, dlTime); + + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + break; + } + + // 10秒内没有下载任何数据超时 + if(pItem->pCurlItem->lastTm > 0) + { + if(curTm > pItem->pCurlItem->lastTm + MAX_TIMEOUT_VALUE) + { + LOG_EX(LOG_Error, "Download Timeout: %s\n", pItem->pTaskUuid); + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + break; + } + } + + // 下载最长时间设置为1800秒(30分钟) + if(dlTime > 1800) + { + LOG_EX(LOG_Error, "Download More than 1800 seconds: %s (%uK/%ds)\n", + pItem->pTaskUuid, pItem->pCurlItem->dlSize/1000, dlTime); + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + break; + } + } +} + +static void __onTimeoutCb(uv_timer_t *pufTimer) +{ + int iRun; + + curl_multi_socket_action(g_pCurl, CURL_SOCKET_TIMEOUT, 0, &iRun); + + __checkMultiInfoTimeout(); +} + +static int __curlTimerCb(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp) /* private callback pointer */ +{ + if(timeout_ms <= 0) + { + timeout_ms = 1; + } + + uv_timer_start(&g_uvCurlTm, __onTimeoutCb, timeout_ms, 0); + + return 0; +} + +static void __curlPollCb(uv_poll_t *pPoll, int status, int events) +{ + int iRun; + int flags; + PCURL_CONTEXT_DATA pContext = NULL; + + uv_timer_stop(&g_uvCurlTm); + + if(events & UV_READABLE) + { + flags = CURL_CSELECT_IN; + } + else if(events & UV_WRITABLE) + { + flags = CURL_CSELECT_OUT; + } + + pContext = (PCURL_CONTEXT_DATA)pPoll; + curl_multi_socket_action(g_pCurl, pContext->sock, flags, &iRun); + __checkMultiInfo(); +} + +static int __curlSockCb(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* describes the socket */ + void *userp, /* private callback pointer */ + void *socketp) /* private socket pointer */ +{ + PCURL_CONTEXT_DATA pContext = NULL; + + if(what == CURL_POLL_IN || what == CURL_POLL_OUT) + { + if(socketp) + { + pContext = (PCURL_CONTEXT_DATA)socketp; + } + else + { + pContext = __createCurlContext(s); + } + + curl_multi_assign(g_pCurl, s, (void *)pContext); + } + + switch(what) + { + case CURL_POLL_IN: + uv_poll_start(&pContext->uvPool, UV_READABLE, __curlPollCb); + break; + + case CURL_POLL_OUT: + uv_poll_start(&pContext->uvPool, UV_WRITABLE, __curlPollCb); + break; + + case CURL_POLL_REMOVE: + if(socketp) + { + uv_poll_stop(&((PCURL_CONTEXT_DATA)socketp)->uvPool); + __destoryCurlContext((PCURL_CONTEXT_DATA)socketp); + curl_multi_assign(g_pCurl, s, NULL); + } + break; + + default: + return (0); + } + + return (0); +} + +static size_t __writeDataCb(void *pData, size_t size, size_t nmemb, void *pParams) +{ + PHTTP_REQ_PARAMS pReq = (PHTTP_REQ_PARAMS)pParams; + int iMemSize = size * nmemb; + + //print_hex_dump_bytes("OTA", DUMP_PREFIX_ADDRESS, pData, size * nmemb); + + if(pReq->isCancel) + { + return 0; + } + + pReq->lastTm = LIBUV_CURRENT_TIME_S(); + + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + int wr = 0; + + pReq->uvFsBuf = uv_buf_init(pData, iMemSize); + + wr = uv_fs_write(g_pMainLoop, &pReq->uvFsWrite, pReq->uvFsOpen.result, &pReq->uvFsBuf, 1, -1, NULL); + + if(wr > 0) + { + pReq->dlSize += wr; + } + } + else if(pReq->type == INET_HTTP_WEBSERVICE_POST) + { + int newSize = 0; + + if(pReq->uvFsBuf.base == NULL && pReq->uvFsBuf.len == 0) + { + newSize = iMemSize + 1; + //fprintf(stdout, "size = %d, newsize = %d, dlsize = %d\n", iMemSize, newSize, pReq->dlSize); + pReq->uvFsBuf.base = malloc(newSize); + memcpy(pReq->uvFsBuf.base, pData, iMemSize); + } + else + { + newSize = pReq->dlSize + iMemSize + 1; + //fprintf(stdout, "::size = %d, newsize = %d, dlsize = %d\n", iMemSize, newSize, pReq->dlSize); + pReq->uvFsBuf.base = realloc(pReq->uvFsBuf.base, newSize); + memcpy(pReq->uvFsBuf.base + pReq->dlSize, pData, iMemSize); + } + + pReq->uvFsBuf.base[pReq->dlSize] = 0; + pReq->dlSize += iMemSize; + } + + return (size * nmemb); +} + +static int __progressCb(void* pData, + double total, + double now, + double ultotal, + double ulnow) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)pData; + + if(pParams->onPrgCb) + { + if(pParams->type == INET_HTTP_DOWNLOAD_FILE) + { + pParams->onPrgCb(pParams->pReqUrl, pParams->pTaskUuid, (unsigned char)(now * 100.0 / total), pParams->pData); + } + } + + if(pParams->isCancel) + { + LOG_EX(LOG_Debug, "Cancel Download: %s\n", pParams->pTaskUuid); + return (-CURLE_OPERATION_TIMEDOUT); + } + + return (0); +} + +static size_t __getRemoteSizeCb(void *pData, size_t size, size_t nmemb, void *pParams) +{ + return (size * nmemb); +} + +static int __iNetGetRemoteSize(const char* pURL, unsigned int reqId) +{ + double size = 0.0; + CURL *pCurl = curl_easy_init(); + CURLcode res; + + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_NOBODY, 1L); + curl_easy_setopt(pCurl, CURLOPT_HEADERFUNCTION, __getRemoteSizeCb); + curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L); + + curl_easy_perform(pCurl); + + res = curl_easy_getinfo(pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size); + + if(res != CURLE_OK) + { + return (-1); + } + + curl_easy_cleanup(pCurl); + + return (int)(size); +} + +#if 0 +static const char* __restartDlFileAsync(PHTTP_REQ_PARAMS pParams) +{ + CURL *pCurl = curl_easy_init(); + + pParams->type = INET_HTTP_DOWNLOAD_FILE; + pParams->dlSize = 0; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + + uv_fs_open(g_pMainLoop, + &pParams->uvFsOpen, + pParams->sDlPath, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, + NULL); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pParams->pReqUrl); + + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, __progressCb); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, pParams); + + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_LIMIT, 10000L); // 10K bytes + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_TIME, 10L); // 30 seconds + + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + //LOG_EX(LOG_Debug, "Total Size = %d\n", __iNetGetRemoteSize(pURL, 0)); + + curl_multi_add_handle(g_pCurl, pCurl); + + __addReqIdToTable(pParams->pTaskUuid, pCurl); + + return (pParams->pTaskUuid); +} +#endif + +const char* InetHttpDlFileAsync(const char *pURL, + const char *pPath, + OnHttpResponse onRespCb, + OnProgressNotify onProgressCb, + void* pData) +{ + CURLMcode ret; + uuid_t msgId; + char strMsgId[64]; + PHTTP_REQ_PARAMS pParams = NULL; + CURL *pCurl = NULL; + unsigned long long uMemFreeSize = GetPartitionFreeSize("/tmp/"); + + if(pURL == NULL || strlen(pURL) == 0 || onRespCb == NULL) + { + free(pParams); + return (NULL); + } + + LOG_EX(LOG_Debug, "Begin Download: %s --> %s\n", pURL, pPath); + + pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); + + memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); + + pCurl = curl_easy_init(); + + pParams->onRspCb = onRespCb; + pParams->pReqUrl = (char *)malloc(strlen(pURL) + 1); + pParams->type = INET_HTTP_DOWNLOAD_FILE; + pParams->dlSize = 0; + pParams->onPrgCb = onProgressCb; + pParams->pData = pData; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + pParams->isCancel = FALSE; + pParams->createTm = (unsigned int)LIBUV_CURRENT_TIME_S(); + + memset(pParams->pReqUrl, 0, strlen(pURL) + 1); + strcpy(pParams->pReqUrl, pURL); + + uuid_generate_random(msgId); + memset(strMsgId, 0, 64); + uuid_unparse_lower(msgId, strMsgId); + pParams->pTaskUuid = strdup(strMsgId); + + if(pPath == NULL) + { + sprintf(pParams->sPath, "./%s", basename_v2(pURL)); + } + else + { + strcpy(pParams->sPath, pPath); + } + + // Memory Free More Than 100M, Download Temp File To Memory + if(uMemFreeSize >= 100 * 1024 * 1024 && + strncmp(pParams->sPath, "/tmp/", 5) != 0) + { + int ret = system("mkdir /tmp/dl -p"); + sprintf(pParams->sDlPath, "/tmp/dl/%s_%s.dl", basename_v2(pParams->sPath), pParams->pTaskUuid); + } + else + { + strcpy(pParams->sDlPath, pParams->sPath); + } + + pParams->uvFsDataSync.data = pParams; + pParams->uvFsClose.data = pParams; + + uv_fs_open(g_pMainLoop, + &pParams->uvFsOpen, + pParams->sDlPath, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, + NULL); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, __progressCb); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, pParams); + + //curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 1800L); // Max download times (30 minutes)1800s + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_LIMIT, 10000L); // 10K bytes + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_TIME, 10L); // 30 seconds + + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); + //curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT_MS, 10L); + + + //curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + LOG_EX(LOG_Debug, "Download(%u): %s --> %p\n", g_TotalDownloads++, pParams->pTaskUuid, pCurl); + ret = curl_multi_add_handle(g_pCurl, pCurl); + if(ret == CURLE_OK) + { + __addReqIdToTable(pParams->pTaskUuid, pParams); + return (pParams->pTaskUuid); + } + else + { + free(pParams->pTaskUuid); + LOG_EX(LOG_Error, "Add Handle Error: %d\n", ret); + return NULL; + } +} + +int InetCancelDownload(const char *pTaskUuid) +{ + if(pTaskUuid && strlen(pTaskUuid) > 0) + { + PCURL_HANDLE_TBL pItem = NULL; + + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + + if(pItem != NULL && pItem->pCurlItem->isCancel != TRUE) + { + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + } + } + + return (0); +} + +static size_t __uploadCb(char *d, size_t n, size_t l, void *p) +{ + return n*l; +} + +#ifdef LIBCURL_DEBUG +struct data { + char trace_ascii; /* 1 or 0 */ +}; + +static +void dump(const char *text, + FILE *stream, unsigned char *ptr, size_t size, + char nohex) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", + text, (long)size, (long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + struct data *config = (struct data *)userp; + const char *text; + (void)handle; /* prevent compiler warning */ + + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + /* FALLTHROUGH */ + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + } + + dump(text, stderr, (unsigned char *)data, size, config->trace_ascii); + return 0; +} +#endif + +int InetHttpUploadFileSync(const char *pURL, const char* pPath, void* pAttachInfo) +{ + CURL *pCurl = NULL; + int rc = 0; + CURLcode ret; + struct curl_httppost *pPost = NULL, *pLastPtr = NULL; + +#ifdef LIBCURL_DEBUG + struct data config; + config.trace_ascii = 1; /* enable ascii tracing */ +#endif + + if(pURL == NULL || strlen(pURL) == 0) + { + LOG_EX(LOG_Error, "Url: %s(%p)\n", SAFE_STRING_VALUE(pURL), pURL); + return -ERR_INPUT_PARAMS; + } + + if(pPath == NULL || strlen(pPath) == 0) + { + LOG_EX(LOG_Error, "Url: %s(%p)\n", SAFE_STRING_VALUE(pPath), pPath); + return -ERR_INPUT_PARAMS; + } + + curl_formadd(&pPost, &pLastPtr, + CURLFORM_COPYNAME, "file", + CURLFORM_FILE, pPath, + CURLFORM_END); + + if(pAttachInfo) + { + PHTTP_POST_ATTACH pDevInfoArray = (PHTTP_POST_ATTACH)pAttachInfo; + PHTTP_POST_ATTACH pItem = NULL, pTmp = NULL; + + LL_FOREACH_SAFE(pDevInfoArray, pItem, pTmp) + { + curl_formadd(&pPost, &pLastPtr, + CURLFORM_COPYNAME, pItem->keyName, + CURLFORM_COPYCONTENTS, pItem->keyValue, + CURLFORM_END); + } + } + + pCurl = curl_easy_init(); + + if(pCurl == NULL) + { + LOG_EX(LOG_Error, "curl_easy_init() Error\n"); + return -ERR_MALLOC_MEMORY; + } + + curl_easy_setopt(pCurl, CURLOPT_ACCEPT_ENCODING, "gzip, deflate"); + curl_easy_setopt(pCurl, CURLOPT_POST, 1L); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_HTTPPOST, pPost); + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __uploadCb); + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); +#ifdef LIBCURL_DEBUG + curl_easy_setopt(pCurl, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(pCurl, CURLOPT_DEBUGDATA, &config); +#endif + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + +#ifdef LIBCURL_DEBUG + curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); +#else + curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 0L); +#endif + + ret = curl_easy_perform(pCurl); + + if(ret != CURLE_OK) + { + LOG_EX(LOG_Error, "Upload %s File %s Error %s\n", pURL, pPath, curl_easy_strerror(ret)); + rc = -ERR_NETWORK_SEND; + } + + curl_easy_cleanup(pCurl); + curl_formfree(pPost); + + return rc; +} + +const char* InetHttpWebServicePostAsync(const char *pURL, const char* pPost, OnHttpResponse onRespCb, void* pData) +{ + uuid_t msgId; + char strMsgId[64]; + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); + CURL *pCurl = NULL; + + if(pURL == NULL || strlen(pURL) == 0 || onRespCb == NULL) + { + free(pParams); + return (NULL); + } + + memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); + + pCurl = curl_easy_init(); + + pParams->onRspCb = onRespCb; + pParams->pReqUrl = (char *)malloc(strlen(pURL) + 1); + pParams->type = INET_HTTP_WEBSERVICE_POST; + pParams->dlSize = 0; + pParams->pData = pData; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + pParams->isCancel = FALSE; + + memset(pParams->pReqUrl, 0, strlen(pURL) + 1); + strcpy(pParams->pReqUrl, pURL); + + uuid_generate_random(msgId); + memset(strMsgId, 0, 64); + uuid_unparse_lower(msgId, strMsgId); + pParams->pTaskUuid = strdup(strMsgId); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(pCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + if(pPost != NULL && strlen(pPost) > 0) + { + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, pPost); + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE, (long)strlen(pPost)); + } + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + curl_multi_add_handle(g_pCurl, pCurl); + + __addReqIdToTable(pParams->pTaskUuid, pParams); + + return (pParams->pTaskUuid); +} + +#if 0 +static void __curlTaskRuntimeCb(void *pParams) +{ + PCURL_HANDLE_TBL pItem = NULL, pTmpItem = NULL; + + while(TRUE) + { + uv_rwlock_rdlock(&g_uvHashRwLock); + + HASH_ITER(hh, g_ReqHandleTbl, pItem, pTmpItem) + { + if(pItem->pCurlItem->type == INET_HTTP_DOWNLOAD_FILE + && pItem->pCurlItem->lastTm > 0) + { + //unsigned int tmNow = LIBUV_CURRENT_TIME_S(); + + if(pItem->pCurlItem->lastTm > 0) + { + //curl_multi_cleanup(pItem->pCurlItem->pCurl); + curl_multi_remove_handle(g_pCurl, pItem->pCurlItem->pCurl); + + if(pItem->uRetryTimes >= 3) + { + if(pItem->pCurlItem->onRspCb) + { + if(strcmp(pItem->pCurlItem->sPath, pItem->pCurlItem->sDlPath) != 0) + { + unlink(pItem->pCurlItem->sDlPath); + } + + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + TRUE, + pItem->pCurlItem->pData); + } + + if(pItem->pCurlItem->pReqUrl) + { + free(pItem->pCurlItem->pReqUrl); + } + } + else + { + __restartDlFileAsync(pItem->pCurlItem); + } + } + } + } + uv_rwlock_rdunlock(&g_uvHashRwLock); + usleep(100000); + } + + pthread_detach(pthread_self()); +} +#endif + +static int __getUsernameFromMail(const char *pMailAddr, char **pUsername) +{ + char *pTail; + + if(pMailAddr == NULL || pUsername == NULL || strlen(pMailAddr) == 0) + { + LOG_EX(LOG_Error, "Input Params Error: pMailAddr = [%s], pUsername = %p\n", + pMailAddr ? pMailAddr : "NULL", pUsername); + return (-ERR_INPUT_PARAMS); + } + + *pUsername = (char *)malloc(strlen(pMailAddr) + 1); + + if(*pUsername == NULL) + { + LOG_EX(LOG_Error, "Error Malloc Memory\n"); + *pUsername = ""; + return (-ERR_MALLOC_MEMORY); + } + + memset(*pUsername, 0, strlen(pMailAddr) + 1); + + pTail = strchr(pMailAddr, '@'); + + if(pTail == NULL) + { + strcpy(*pUsername, pMailAddr); + } + else + { + memcpy(*pUsername, pMailAddr, pTail - pMailAddr); + } + + return (0); +} + +int InetSmtpSendEmail(const char* pFrom, + const char* pTo[], + const char* pCc[], + const char* pTitle, + const char* pMessage, + const char* pAttach[], + PSMTP_MAIL_CONFIG pConfig) +{ + const char *pErrMsg = NULL; + quickmail pMail; + + if(pConfig == NULL) + { + LOG_EX(LOG_Error, "Input Param pConfig = NULL\n"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pPassword == NULL || strlen(pConfig->pPassword) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pPassword = [%s]\n", pConfig->pPassword ? pConfig->pPassword : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pUserName == NULL || strlen(pConfig->pUserName) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pUserName = [%s]\n", pConfig->pUserName ? pConfig->pUserName : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pSmtpServer == NULL || strlen(pConfig->pSmtpServer) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pUserName = [%s]\n", pConfig->pSmtpServer ? pConfig->pSmtpServer : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pFrom == NULL) + { + LOG_EX(LOG_Error, "Input Param pFrom = NULL\n"); + return (-ERR_INPUT_PARAMS); + } + + if(pTo == NULL && pCc == NULL) + { + LOG_EX(LOG_Error, "Input Param pTo = %p, pCc = %p\n", pTo, pCc); + return (-ERR_INPUT_PARAMS); + } + + if(pTitle == NULL) + { + pTitle = ""; + } + + if(pMessage == NULL) + { + pMessage = ""; + } + + quickmail_initialize(); + + pMail = quickmail_create(pFrom, pTitle); + + if(pMail == NULL) + { + LOG_EX(LOG_Error, "Create Quickmail Object Error\n"); + return (-ERR_MALLOC_MEMORY); + } + + for(const char **pValue = pTo; pTo && *pValue; pValue++) + { + quickmail_add_to(pMail, *pValue); + } + + for(const char **pValue = pCc; pCc && *pValue; pValue++) + { + quickmail_add_cc(pMail, *pValue); + } + + quickmail_add_header(pMail, "Importance: Low"); + quickmail_add_header(pMail, "X-Priority: 5"); + quickmail_add_header(pMail, "X-MSMail-Priority: Low"); + quickmail_add_body_memory(pMail, "text/html", (char*)pMessage, strlen(pMessage), 0); + + for(const char **pValue = pAttach; pAttach && *pValue; pValue++) + { + quickmail_add_attachment_file(pMail, *pValue, NULL); + } + + //quickmail_set_debug_log(pMail, stderr); + + pErrMsg = quickmail_send(pMail, pConfig->pSmtpServer, pConfig->smtpPort, pConfig->pUserName, pConfig->pPassword); + + if(pErrMsg != NULL) + { + LOG_EX(LOG_Error, "Send Mail Error: %s\n", pErrMsg); + return (-ERR_SEND_MAIL); + } + + return (0); +} + +int InetInit(void) +{ + int ret = 0; + + ret = curl_global_init(CURL_GLOBAL_ALL); + + if(ret != 0) + { + LOG_EX(LOG_Error, "curl init error: %d\n", ret); + return ret; + } + + g_pMainLoop = DBusLibuvGetRuntime()->pLoop; + + uv_timer_init(g_pMainLoop, &g_uvCurlTm); + uv_timer_init(g_pMainLoop, &g_uvDlTm); + + g_pCurl = curl_multi_init(); + + curl_multi_setopt(g_pCurl, CURLMOPT_SOCKETFUNCTION, __curlSockCb); + curl_multi_setopt(g_pCurl, CURLMOPT_TIMERFUNCTION, __curlTimerCb); + + uv_rwlock_init(&g_uvHashRwLock); + + uv_timer_start(&g_uvDlTm, __onDlTmoutCb, 1000, 1000); + + return (0); +} + +void InetUnInit(void) +{ + curl_multi_cleanup(g_pCurl); + curl_global_cleanup(); +} + diff --git a/Framework/Network/inet_api.c.bak b/Framework/Network/inet_api.c.bak new file mode 100644 index 0000000..7333176 --- /dev/null +++ b/Framework/Network/inet_api.c.bak @@ -0,0 +1,1327 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "inet_api.h" + +#define MAX_TIMEOUT_VALUE (10) +#define SSL_CA_FILE ("/etc/ssl/certs/ca-certificates.crt") + +typedef enum +{ + INET_HTTP_DOWNLOAD_FILE = 0, + INET_HTTP_WEBSERVICE_POST, +} INET_ACCESS_TYPE; + +typedef struct +{ + uv_poll_t uvPool; + curl_socket_t sock; +} CURL_CONTEXT_DATA, *PCURL_CONTEXT_DATA; + +typedef struct +{ + char* pReqUrl; + char sPath[MAX_PATH]; + char sDlPath[MAX_PATH]; + char* pTaskUuid; + INET_ACCESS_TYPE type; + unsigned int dlSize; + unsigned int lastTm; + unsigned int createTm; + uv_fs_t uvFsOpen; + uv_fs_t uvFsWrite; + uv_fs_t uvFsDataSync; + uv_fs_t uvFsClose; + uv_buf_t uvFsBuf; + OnProgressNotify onPrgCb; + OnHttpResponse onRspCb; + CURL* pCurl; + void* pData; + int errCode; +} HTTP_REQ_PARAMS, *PHTTP_REQ_PARAMS; + +typedef struct +{ + char *pTaskUuid; + unsigned int uRetryTimes; + int isCancel; + PHTTP_REQ_PARAMS pCurlItem; + + UT_hash_handle hh; ///< UT Hash handle +} CURL_HANDLE_TBL, *PCURL_HANDLE_TBL; + +static uv_timer_t g_uvCurlTm; +static uv_timer_t g_uvDlTm; +static CURLM* g_pCurl = NULL; +static uv_loop_t* g_pMainLoop = NULL; +static PCURL_HANDLE_TBL g_ReqHandleTbl = NULL; +static uv_rwlock_t g_uvHashRwLock; + +static void __addReqIdToTable(const char* pTaskUuid, PHTTP_REQ_PARAMS pParams) +{ + PCURL_HANDLE_TBL pItem = NULL; + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pItem == NULL) + { + pItem = (PCURL_HANDLE_TBL)malloc(sizeof(CURL_HANDLE_TBL)); + + memset(pItem, 0, sizeof(CURL_HANDLE_TBL)); + pItem->pTaskUuid = (char*)pTaskUuid; + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_STR(g_ReqHandleTbl, pTaskUuid, pItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + } + + pItem->isCancel = FALSE; + pItem->pCurlItem = pParams; + pItem->uRetryTimes++; +} + +static void __removeReqIdFromTable(const char* pTaskUuid) +{ + PCURL_HANDLE_TBL pItem = NULL; + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pItem != NULL) + { + pItem->isCancel = TRUE; + } +} + +static void __cleanUpReqIdFromTable(PCURL_HANDLE_TBL pItem) +{ + if(pItem != NULL) + { + HASH_DEL(g_ReqHandleTbl, pItem); + + if(pItem->pTaskUuid) + { + free(pItem->pTaskUuid); + } + + free(pItem); + } +} + +static void __uvFsCloseCb(uv_fs_t *puvFs) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)puvFs->data; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "[%s] Error: %d\n", __FUNCTION__, puvFs->result); + } + + uv_fs_req_cleanup(puvFs); + + if(pParams->type == INET_HTTP_DOWNLOAD_FILE) + { + if(strcmp(pParams->sDlPath, pParams->sPath) != 0) + { + CopyFile(pParams->sDlPath, pParams->sPath); + unlink(pParams->sDlPath); + } + + pParams->onRspCb(NULL, pParams->dlSize, pParams->pReqUrl, pParams->sPath, + pParams->pTaskUuid, pParams->errCode, pParams->pData); + } + + __removeReqIdFromTable(pParams->pTaskUuid); + + if(pParams->pReqUrl) + { + free(pParams->pReqUrl); + pParams->pReqUrl = NULL; + } + + free(pParams); + pParams = NULL; +} + +static void __uvFsDataSyncCb(uv_fs_t *puvFs) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)puvFs->data; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "[%s] Error: %d\n", __FUNCTION__, puvFs->result); + } + + uv_fs_req_cleanup(puvFs); + + uv_fs_close(g_pMainLoop, &pParams->uvFsClose, pParams->uvFsOpen.result, __uvFsCloseCb); +} + +static PCURL_CONTEXT_DATA __createCurlContext(curl_socket_t sock) +{ + PCURL_CONTEXT_DATA pContext = (PCURL_CONTEXT_DATA)malloc(sizeof(CURL_CONTEXT_DATA)); + + pContext->sock = sock; + + if(uv_poll_init_socket(g_pMainLoop, &pContext->uvPool, sock) != 0) + { + LOG_EX(LOG_Error, "uv_poll_init_socket Error\n"); + } + + pContext->uvPool.data = pContext; + + return (pContext); +} + +static void __uvCloseCb(uv_handle_t *puvPoll) +{ + PCURL_CONTEXT_DATA pContext = (PCURL_CONTEXT_DATA)puvPoll->data; + free(pContext); +} + +static void __destoryCurlContext(PCURL_CONTEXT_DATA pContext) +{ + uv_close((uv_handle_t *)&pContext->uvPool, __uvCloseCb); +} + +static void __checkMultiInfoTimeout(void) +{ + PHTTP_REQ_PARAMS pReq; + CURLMsg *pMsg = NULL; + int iPending; + + while((pMsg = curl_multi_info_read(g_pCurl, &iPending))) + { + switch(pMsg->msg) + { + case CURLMSG_DONE: + curl_easy_getinfo(pMsg->easy_handle, CURLINFO_PRIVATE, (void*)&pReq); + + curl_multi_remove_handle(g_pCurl, pMsg->easy_handle); + curl_easy_cleanup(pMsg->easy_handle); + + if(pReq) + { + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, pReq->pData); + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + + break; + + default: + LOG_EX(LOG_Error, "pMsg->msg(%d) != CURLMSG_DONE\n", pMsg->msg); + return; + } + } +} + +static void __checkMultiInfo(void) +{ + PHTTP_REQ_PARAMS pReq; + CURLMsg *pMsg = NULL; + int iPending; + + while((pMsg = curl_multi_info_read(g_pCurl, &iPending))) + { + switch(pMsg->msg) + { + case CURLMSG_DONE: + curl_easy_getinfo(pMsg->easy_handle, CURLINFO_PRIVATE, (void*)&pReq); + + curl_multi_remove_handle(g_pCurl, pMsg->easy_handle); + curl_easy_cleanup(pMsg->easy_handle); + + if(pReq) + { + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + if(pMsg->data.result != CURLE_OK) + { + pReq->errCode = pMsg->data.result; + } + else + { + pReq->errCode = 0; + } + + uv_fs_fdatasync(g_pMainLoop, &pReq->uvFsDataSync, pReq->uvFsOpen.result, __uvFsDataSyncCb); + } + else if(pReq->type == INET_HTTP_WEBSERVICE_POST) + { + if(pMsg->data.result != CURLE_OK) + { + pReq->onRspCb(pReq->uvFsBuf.base, pReq->dlSize, pReq->pReqUrl, pReq->sPath, + pReq->pTaskUuid, -pMsg->data.result, pReq->pData); + } + else + { + pReq->onRspCb(pReq->uvFsBuf.base, pReq->dlSize, pReq->pReqUrl, pReq->sPath, + pReq->pTaskUuid, 0, pReq->pData); + } + + if(pReq->uvFsBuf.base) + { + free(pReq->uvFsBuf.base); + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + else + { + if(pMsg->data.result != CURLE_OK) + { + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, -pMsg->data.result, pReq->pData); + } + else + { + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, 0, pReq->pData); + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + } + + break; + + default: + LOG_EX(LOG_Error, "pMsg->msg(%d) != CURLMSG_DONE\n", pMsg->msg); + return; + } + } +} + +static void __onDlTmoutCb(uv_timer_t *pufTimer) +{ + PCURL_HANDLE_TBL pItem = NULL, pTemp = NULL; + unsigned int curTm = (unsigned int)LIBUV_CURRENT_TIME_S(); + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_ITER(hh, g_ReqHandleTbl, pItem, pTemp) + { + int dlTime; + + if(pItem->isCancel) + { + continue; + } + + dlTime = curTm - pItem->pCurlItem->createTm; + + // 下载时间大于10s且平均下载速度小于10K/s超时 + if((dlTime * 10000 > pItem->pCurlItem->dlSize) && dlTime > 10) + { + LOG_EX(LOG_Error, "Download Speed less than 10k/s: %s (%uK/%ds)\n", + pItem->pTaskUuid, pItem->pCurlItem->dlSize / 1000, dlTime); + + InetCancelDownload(pItem->pTaskUuid); + break; + } + + // 10秒内没有下载任何数据超时 + if(pItem->pCurlItem->lastTm > 0) + { + if(curTm > pItem->pCurlItem->lastTm + MAX_TIMEOUT_VALUE) + { + LOG_EX(LOG_Error, "Download Timeout: %s\n", pItem->pTaskUuid); + InetCancelDownload(pItem->pTaskUuid); + break; + } + } + + // 下载最长时间设置为1800秒(30分钟) + if(dlTime > 1800) + { + LOG_EX(LOG_Error, "Download More than 1800 seconds: %s (%uK/%ds)\n", + pItem->pTaskUuid, pItem->pCurlItem->dlSize/1000, dlTime); + InetCancelDownload(pItem->pTaskUuid); + break; + } + } + uv_rwlock_rdunlock(&g_uvHashRwLock); + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ITER(hh, g_ReqHandleTbl, pItem, pTemp) + { + if(pItem->isCancel != FALSE) + { + __cleanUpReqIdFromTable(pItem); + } + } + uv_rwlock_wrunlock(&g_uvHashRwLock); +} + +static void __onTimeoutCb(uv_timer_t *pufTimer) +{ + int iRun; + + curl_multi_socket_action(g_pCurl, CURL_SOCKET_TIMEOUT, 0, &iRun); + + __checkMultiInfoTimeout(); +} + +static int __curlTimerCb(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp) /* private callback pointer */ +{ + if(timeout_ms <= 0) + { + timeout_ms = 1; + } + + uv_timer_start(&g_uvCurlTm, __onTimeoutCb, timeout_ms, 0); + + return 0; +} + +static void __curlPollCb(uv_poll_t *pPoll, int status, int events) +{ + int iRun; + int flags; + PCURL_CONTEXT_DATA pContext = NULL; + + uv_timer_stop(&g_uvCurlTm); + + if(events & UV_READABLE) + { + flags = CURL_CSELECT_IN; + } + else if(events & UV_WRITABLE) + { + flags = CURL_CSELECT_OUT; + } + + pContext = (PCURL_CONTEXT_DATA)pPoll; + curl_multi_socket_action(g_pCurl, pContext->sock, flags, &iRun); + __checkMultiInfo(); +} + +static int __curlSockCb(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* describes the socket */ + void *userp, /* private callback pointer */ + void *socketp) /* private socket pointer */ +{ + PCURL_CONTEXT_DATA pContext = NULL; + + if(what == CURL_POLL_IN || what == CURL_POLL_OUT) + { + if(socketp) + { + pContext = (PCURL_CONTEXT_DATA)socketp; + } + else + { + pContext = __createCurlContext(s); + } + + curl_multi_assign(g_pCurl, s, (void *)pContext); + } + + switch(what) + { + case CURL_POLL_IN: + uv_poll_start(&pContext->uvPool, UV_READABLE, __curlPollCb); + break; + + case CURL_POLL_OUT: + uv_poll_start(&pContext->uvPool, UV_WRITABLE, __curlPollCb); + break; + + case CURL_POLL_REMOVE: + if(socketp) + { + uv_poll_stop(&((PCURL_CONTEXT_DATA)socketp)->uvPool); + __destoryCurlContext((PCURL_CONTEXT_DATA)socketp); + curl_multi_assign(g_pCurl, s, NULL); + } + break; + + default: + return (0); + } + + return (0); +} + +static size_t __writeDataCb(void *pData, size_t size, size_t nmemb, void *pParams) +{ + PHTTP_REQ_PARAMS pReq = (PHTTP_REQ_PARAMS)pParams; + int iMemSize = size * nmemb; + //print_hex_dump_bytes("OTA", DUMP_PREFIX_ADDRESS, pData, size * nmemb); + + pReq->lastTm = LIBUV_CURRENT_TIME_S(); + + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + int wr = 0; + + pReq->uvFsBuf = uv_buf_init(pData, iMemSize); + + wr = uv_fs_write(g_pMainLoop, &pReq->uvFsWrite, pReq->uvFsOpen.result, &pReq->uvFsBuf, 1, -1, NULL); + + if(wr > 0) + { + pReq->dlSize += wr; + } + } + else if(pReq->type == INET_HTTP_WEBSERVICE_POST) + { + int newSize = 0; + + if(pReq->uvFsBuf.base == NULL && pReq->uvFsBuf.len == 0) + { + newSize = iMemSize + 1; + //fprintf(stdout, "size = %d, newsize = %d, dlsize = %d\n", iMemSize, newSize, pReq->dlSize); + pReq->uvFsBuf.base = malloc(newSize); + memcpy(pReq->uvFsBuf.base, pData, iMemSize); + } + else + { + newSize = pReq->dlSize + iMemSize + 1; + //fprintf(stdout, "::size = %d, newsize = %d, dlsize = %d\n", iMemSize, newSize, pReq->dlSize); + pReq->uvFsBuf.base = realloc(pReq->uvFsBuf.base, newSize); + memcpy(pReq->uvFsBuf.base + pReq->dlSize, pData, iMemSize); + } + + pReq->uvFsBuf.base[pReq->dlSize] = 0; + pReq->dlSize += iMemSize; + } + + return (size * nmemb); +} + +static int __progressCb(void* pData, + double total, + double now, + double ultotal, + double ulnow) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)pData; + + if(pParams->onPrgCb) + { + if(pParams->type == INET_HTTP_DOWNLOAD_FILE) + { + pParams->onPrgCb(pParams->pReqUrl, pParams->pTaskUuid, (unsigned char)(now * 100.0 / total), pParams->pData); + } + } + + return (0); +} + +static size_t __getRemoteSizeCb(void *pData, size_t size, size_t nmemb, void *pParams) +{ + return (size * nmemb); +} + +static int __iNetGetRemoteSize(const char* pURL, unsigned int reqId) +{ + double size = 0.0; + CURL *pCurl = curl_easy_init(); + CURLcode res; + + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_NOBODY, 1L); + curl_easy_setopt(pCurl, CURLOPT_HEADERFUNCTION, __getRemoteSizeCb); + curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L); + + curl_easy_perform(pCurl); + + res = curl_easy_getinfo(pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size); + + if(res != CURLE_OK) + { + return (-1); + } + + curl_easy_cleanup(pCurl); + + return (int)(size); +} + +static const char* __restartDlFileAsync(PHTTP_REQ_PARAMS pParams) +{ + CURL *pCurl = curl_easy_init(); + + pParams->type = INET_HTTP_DOWNLOAD_FILE; + pParams->dlSize = 0; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + + uv_fs_open(g_pMainLoop, + &pParams->uvFsOpen, + pParams->sDlPath, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, + NULL); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pParams->pReqUrl); + + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, __progressCb); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, pParams); + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + //LOG_EX(LOG_Debug, "Total Size = %d\n", __iNetGetRemoteSize(pURL, 0)); + + curl_multi_add_handle(g_pCurl, pCurl); + + __addReqIdToTable(pParams->pTaskUuid, pCurl); + + return (pParams->pTaskUuid); +} + +const char* InetHttpDlFileAsync(const char *pURL, + const char *pPath, + OnHttpResponse onRespCb, + OnProgressNotify onProgressCb, + void* pData) +{ + uuid_t msgId; + char strMsgId[64]; + PHTTP_REQ_PARAMS pParams = NULL; + CURL *pCurl = NULL; + unsigned long long uMemFreeSize = GetPartitionFreeSize("/tmp/"); + + if(pURL == NULL || strlen(pURL) == 0 || onRespCb == NULL) + { + free(pParams); + return (NULL); + } + + LOG_EX(LOG_Debug, "Begin Download: %s\n", pURL); + + pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); + + memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); + + pCurl = curl_easy_init(); + + pParams->onRspCb = onRespCb; + pParams->pReqUrl = (char *)malloc(strlen(pURL) + 1); + pParams->type = INET_HTTP_DOWNLOAD_FILE; + pParams->dlSize = 0; + pParams->onPrgCb = onProgressCb; + pParams->pData = pData; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + pParams->createTm = (unsigned int)LIBUV_CURRENT_TIME_S(); + + memset(pParams->pReqUrl, 0, strlen(pURL) + 1); + strcpy(pParams->pReqUrl, pURL); + + uuid_generate_random(msgId); + memset(strMsgId, 0, 64); + uuid_unparse_lower(msgId, strMsgId); + pParams->pTaskUuid = strdup(strMsgId); + + if(pPath == NULL) + { + sprintf(pParams->sPath, "./%s", basename_v2(pURL)); + } + else + { + strcpy(pParams->sPath, pPath); + } + + // Memory Free More Than 100M, Download Temp File To Memory + if(uMemFreeSize >= 100 * 1024 * 1024 && + strncmp(pParams->sPath, "/tmp/", 5) != 0) + { + int ret = system("mkdir /tmp/dl -p"); + sprintf(pParams->sDlPath, "/tmp/dl/%s_%s.dl", basename_v2(pParams->sPath), pParams->pTaskUuid); + } + else + { + strcpy(pParams->sDlPath, pParams->sPath); + } + + pParams->uvFsDataSync.data = pParams; + pParams->uvFsClose.data = pParams; + + uv_fs_open(g_pMainLoop, + &pParams->uvFsOpen, + pParams->sDlPath, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, + NULL); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, __progressCb); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, pParams); + + //curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 1800L); // Max download times (30 minutes)1800s + //curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_LIMIT, 10000L); // 10K bytes + //curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_TIME, 30L); // 30 seconds + + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); + //curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT_MS, 10L); + + + //curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + //LOG_EX(LOG_Debug, "Download: %s --> %s\n", pParams->pReqUrl, pParams->sDlPath); + + curl_multi_add_handle(g_pCurl, pCurl); + + __addReqIdToTable(pParams->pTaskUuid, pParams); + + return (pParams->pTaskUuid); +} + +int InetCancelDownload(const char *pTaskUuid) +{ + if(pTaskUuid && strlen(pTaskUuid) > 0) + { + PCURL_HANDLE_TBL pItem = NULL; + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pItem != NULL && pItem->isCancel != TRUE) + { + __removeReqIdFromTable(pTaskUuid); + curl_easy_pause(pItem->pCurlItem->pCurl, CURLPAUSE_ALL); + curl_easy_cleanup(pItem->pCurlItem->pCurl); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + } + } + + return (0); +} + +static size_t __uploadCb(char *d, size_t n, size_t l, void *p) +{ + return n*l; +} + +#ifdef LIBCURL_DEBUG +struct data { + char trace_ascii; /* 1 or 0 */ +}; + +static +void dump(const char *text, + FILE *stream, unsigned char *ptr, size_t size, + char nohex) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", + text, (long)size, (long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + struct data *config = (struct data *)userp; + const char *text; + (void)handle; /* prevent compiler warning */ + + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + /* FALLTHROUGH */ + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + } + + dump(text, stderr, (unsigned char *)data, size, config->trace_ascii); + return 0; +} +#endif + +int InetHttpUploadFileSync(const char *pURL, const char* pPath, void* pAttachInfo) +{ + CURL *pCurl = NULL; + int rc = 0; + CURLcode ret; + struct curl_httppost *pPost = NULL, *pLastPtr = NULL; + +#ifdef LIBCURL_DEBUG + struct data config; + config.trace_ascii = 1; /* enable ascii tracing */ +#endif + + if(pURL == NULL || strlen(pURL) == 0) + { + LOG_EX(LOG_Error, "Url: %s(%p)\n", SAFE_STRING_VALUE(pURL), pURL); + return -ERR_INPUT_PARAMS; + } + + if(pPath == NULL || strlen(pPath) == 0) + { + LOG_EX(LOG_Error, "Url: %s(%p)\n", SAFE_STRING_VALUE(pPath), pPath); + return -ERR_INPUT_PARAMS; + } + + curl_formadd(&pPost, &pLastPtr, + CURLFORM_COPYNAME, "file", + CURLFORM_FILE, pPath, + CURLFORM_END); + + if(pAttachInfo) + { + PHTTP_POST_ATTACH pDevInfoArray = (PHTTP_POST_ATTACH)pAttachInfo; + PHTTP_POST_ATTACH pItem = NULL, pTmp = NULL; + + LL_FOREACH_SAFE(pDevInfoArray, pItem, pTmp) + { + curl_formadd(&pPost, &pLastPtr, + CURLFORM_COPYNAME, pItem->keyName, + CURLFORM_COPYCONTENTS, pItem->keyValue, + CURLFORM_END); + } + } + + pCurl = curl_easy_init(); + + if(pCurl == NULL) + { + LOG_EX(LOG_Error, "curl_easy_init() Error\n"); + return -ERR_MALLOC_MEMORY; + } + + curl_easy_setopt(pCurl, CURLOPT_ACCEPT_ENCODING, "gzip, deflate"); + curl_easy_setopt(pCurl, CURLOPT_POST, 1L); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_HTTPPOST, pPost); + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __uploadCb); + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); +#ifdef LIBCURL_DEBUG + curl_easy_setopt(pCurl, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(pCurl, CURLOPT_DEBUGDATA, &config); +#endif + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + +#ifdef LIBCURL_DEBUG + curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); +#else + curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 0L); +#endif + + ret = curl_easy_perform(pCurl); + + if(ret != CURLE_OK) + { + LOG_EX(LOG_Error, "Upload %s File %s Error %s\n", pURL, pPath, curl_easy_strerror(ret)); + rc = -ERR_NETWORK_SEND; + } + + curl_easy_cleanup(pCurl); + curl_formfree(pPost); + + return rc; +} + +const char* InetHttpWebServicePostAsync(const char *pURL, const char* pPost, OnHttpResponse onRespCb, void* pData) +{ + uuid_t msgId; + char strMsgId[64]; + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); + CURL *pCurl = NULL; + + if(pURL == NULL || strlen(pURL) == 0 || onRespCb == NULL) + { + free(pParams); + return (NULL); + } + + memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); + + pCurl = curl_easy_init(); + + pParams->onRspCb = onRespCb; + pParams->pReqUrl = (char *)malloc(strlen(pURL) + 1); + pParams->type = INET_HTTP_WEBSERVICE_POST; + pParams->dlSize = 0; + pParams->pData = pData; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + + memset(pParams->pReqUrl, 0, strlen(pURL) + 1); + strcpy(pParams->pReqUrl, pURL); + + uuid_generate_random(msgId); + memset(strMsgId, 0, 64); + uuid_unparse_lower(msgId, strMsgId); + pParams->pTaskUuid = strdup(strMsgId); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(pCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + if(pPost != NULL && strlen(pPost) > 0) + { + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, pPost); + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE, (long)strlen(pPost)); + } + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + curl_multi_add_handle(g_pCurl, pCurl); + + __addReqIdToTable(pParams->pTaskUuid, pParams); + + return (pParams->pTaskUuid); +} + +#if 0 +static void __curlTaskRuntimeCb(void *pParams) +{ + PCURL_HANDLE_TBL pItem = NULL, pTmpItem = NULL; + + while(TRUE) + { + uv_rwlock_rdlock(&g_uvHashRwLock); + + HASH_ITER(hh, g_ReqHandleTbl, pItem, pTmpItem) + { + if(pItem->pCurlItem->type == INET_HTTP_DOWNLOAD_FILE + && pItem->pCurlItem->lastTm > 0) + { + //unsigned int tmNow = LIBUV_CURRENT_TIME_S(); + + if(pItem->pCurlItem->lastTm > 0) + { + //curl_multi_cleanup(pItem->pCurlItem->pCurl); + curl_multi_remove_handle(g_pCurl, pItem->pCurlItem->pCurl); + + if(pItem->uRetryTimes >= 3) + { + if(pItem->pCurlItem->onRspCb) + { + if(strcmp(pItem->pCurlItem->sPath, pItem->pCurlItem->sDlPath) != 0) + { + unlink(pItem->pCurlItem->sDlPath); + } + + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + TRUE, + pItem->pCurlItem->pData); + } + + if(pItem->pCurlItem->pReqUrl) + { + free(pItem->pCurlItem->pReqUrl); + } + } + else + { + __restartDlFileAsync(pItem->pCurlItem); + } + } + } + } + uv_rwlock_rdunlock(&g_uvHashRwLock); + usleep(100000); + } +} +#endif + +static int __getUsernameFromMail(const char *pMailAddr, char **pUsername) +{ + char *pTail; + + if(pMailAddr == NULL || pUsername == NULL || strlen(pMailAddr) == 0) + { + LOG_EX(LOG_Error, "Input Params Error: pMailAddr = [%s], pUsername = %p\n", + pMailAddr ? pMailAddr : "NULL", pUsername); + return (-ERR_INPUT_PARAMS); + } + + *pUsername = (char *)malloc(strlen(pMailAddr) + 1); + + if(*pUsername == NULL) + { + LOG_EX(LOG_Error, "Error Malloc Memory\n"); + *pUsername = ""; + return (-ERR_MALLOC_MEMORY); + } + + memset(*pUsername, 0, strlen(pMailAddr) + 1); + + pTail = strchr(pMailAddr, '@'); + + if(pTail == NULL) + { + strcpy(*pUsername, pMailAddr); + } + else + { + memcpy(*pUsername, pMailAddr, pTail - pMailAddr); + } + + return (0); +} + +int InetSmtpSendEmail(const char* pFrom, + const char* pTo[], + const char* pCc[], + const char* pTitle, + const char* pMessage, + const char* pAttach[], + PSMTP_MAIL_CONFIG pConfig) +{ + const char *pErrMsg = NULL; + quickmail pMail; + + if(pConfig == NULL) + { + LOG_EX(LOG_Error, "Input Param pConfig = NULL\n"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pPassword == NULL || strlen(pConfig->pPassword) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pPassword = [%s]\n", pConfig->pPassword ? pConfig->pPassword : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pUserName == NULL || strlen(pConfig->pUserName) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pUserName = [%s]\n", pConfig->pUserName ? pConfig->pUserName : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pSmtpServer == NULL || strlen(pConfig->pSmtpServer) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pUserName = [%s]\n", pConfig->pSmtpServer ? pConfig->pSmtpServer : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pFrom == NULL) + { + LOG_EX(LOG_Error, "Input Param pFrom = NULL\n"); + return (-ERR_INPUT_PARAMS); + } + + if(pTo == NULL && pCc == NULL) + { + LOG_EX(LOG_Error, "Input Param pTo = %p, pCc = %p\n", pTo, pCc); + return (-ERR_INPUT_PARAMS); + } + + if(pTitle == NULL) + { + pTitle = ""; + } + + if(pMessage == NULL) + { + pMessage = ""; + } + + quickmail_initialize(); + + pMail = quickmail_create(pFrom, pTitle); + + if(pMail == NULL) + { + LOG_EX(LOG_Error, "Create Quickmail Object Error\n"); + return (-ERR_MALLOC_MEMORY); + } + + for(const char **pValue = pTo; pTo && *pValue; pValue++) + { + quickmail_add_to(pMail, *pValue); + } + + for(const char **pValue = pCc; pCc && *pValue; pValue++) + { + quickmail_add_cc(pMail, *pValue); + } + + quickmail_add_header(pMail, "Importance: Low"); + quickmail_add_header(pMail, "X-Priority: 5"); + quickmail_add_header(pMail, "X-MSMail-Priority: Low"); + quickmail_add_body_memory(pMail, "text/html", (char*)pMessage, strlen(pMessage), 0); + + for(const char **pValue = pAttach; pAttach && *pValue; pValue++) + { + quickmail_add_attachment_file(pMail, *pValue, NULL); + } + + //quickmail_set_debug_log(pMail, stderr); + + pErrMsg = quickmail_send(pMail, pConfig->pSmtpServer, pConfig->smtpPort, pConfig->pUserName, pConfig->pPassword); + + if(pErrMsg != NULL) + { + LOG_EX(LOG_Error, "Send Mail Error: %s\n", pErrMsg); + return (-ERR_SEND_MAIL); + } + + return (0); +} + +int InetInit(void) +{ + int ret = 0; + //uv_thread_t uvThread; + + ret = curl_global_init(CURL_GLOBAL_ALL); + + if(ret != 0) + { + LOG_EX(LOG_Error, "curl init error: %d\n", ret); + return ret; + } + + g_pMainLoop = DBusLibuvGetRuntime()->pLoop; + + uv_timer_init(g_pMainLoop, &g_uvCurlTm); + uv_timer_init(g_pMainLoop, &g_uvDlTm); + + g_pCurl = curl_multi_init(); + + curl_multi_setopt(g_pCurl, CURLMOPT_SOCKETFUNCTION, __curlSockCb); + curl_multi_setopt(g_pCurl, CURLMOPT_TIMERFUNCTION, __curlTimerCb); + + uv_rwlock_init(&g_uvHashRwLock); + + uv_timer_start(&g_uvDlTm, __onDlTmoutCb, 1000, 1000); + + //uv_thread_create(&uvThread, __curlTaskRuntimeCb, NULL); + return (0); +} + +void InetUnInit(void) +{ + curl_multi_cleanup(g_pCurl); + curl_global_cleanup(); +} + diff --git a/Framework/Skins/skin_res_vtbl.c b/Framework/Skins/skin_res_vtbl.c new file mode 100644 index 0000000..ae30711 --- /dev/null +++ b/Framework/Skins/skin_res_vtbl.c @@ -0,0 +1,320 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" +#include "skins.h" +#include "log.h" + +typedef struct +{ + sqlite3_vtab vTable; + sqlite3 *pSqlDb; + char *pTblName; +} SKINRES_VTBL, *PSKINRES_VTBL; + +typedef struct +{ + sqlite3_vtab_cursor base; + int count; + int eof; +} SKINRES_CURSOR, *PSKINRES_CURSOR; + +static int __skin_res_destructor(sqlite3_vtab *pVtab) +{ + PSKINRES_VTBL p = (PSKINRES_VTBL)pVtab; + + if(p->pTblName != NULL) + { + free(p->pTblName); + p->pTblName = NULL; + } + sqlite3_free(p); + + return 0; +} + +static int __skin_res_create(sqlite3 *pDb, + void *pAux, + int argc, const char * const *argv, + sqlite3_vtab **pp_vt, + char **pzErr) +{ + UT_string *pSqlCmd; + int rc = SQLITE_OK; + PSKINRES_VTBL pVTbl; + + /* Allocate the sqlite3_vtab/example_vtab structure itself */ + pVTbl = (PSKINRES_VTBL)sqlite3_malloc(sizeof(SKINRES_VTBL)); + + if(pVTbl == NULL) + { + return SQLITE_NOMEM; + } + + pVTbl->pSqlDb = pDb; + pVTbl->pTblName = strdup(argv[2]); + + utstring_new(pSqlCmd); + if(strcmp(argv[0], RES_MODE_NAME) == 0) + { + utstring_printf(pSqlCmd, CREATE_RES_TBL_SQL, ""); + } + else + { + utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL, ""); + } + + /* Declare the vtable's structure */ + rc = sqlite3_declare_vtab(pDb, utstring_body(pSqlCmd)); + utstring_free(pSqlCmd); + + if(rc != SQLITE_OK) + { + __skin_res_destructor((sqlite3_vtab*)pVTbl); + + return SQLITE_ERROR; + } + + /* Success. Set *pp_vt and return */ + *pp_vt = &pVTbl->vTable; + + return SQLITE_OK; +} + +static int __skin_res_connect( sqlite3 *db, void *p_aux, + int argc, const char * const *argv, + sqlite3_vtab **pp_vt, char **pzErr ) +{ + return __skin_res_create(db, p_aux, argc, argv, pp_vt, pzErr); +} + +static int __skin_res_disconnect(sqlite3_vtab *pVtab) +{ + return __skin_res_destructor(pVtab); +} + +static int __skin_res_destroy(sqlite3_vtab *pVtab) +{ + int rc = SQLITE_OK; + //PSKINRES_VTBL p = (PSKINRES_VTBL)pVtab; + + if(rc == SQLITE_OK) + { + rc = __skin_res_destructor(pVtab); + } + + return rc; +} + +static int __skin_res_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)sqlite3_malloc(sizeof(SKINRES_CURSOR)); + *ppCursor = (sqlite3_vtab_cursor*)pCur; + + return (pCur ? SQLITE_OK : SQLITE_NOMEM); +} + +static int __skin_res_close(sqlite3_vtab_cursor *cur) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)cur; + sqlite3_free(pCur); + + return SQLITE_OK; +} + +static int __skin_res_eof(sqlite3_vtab_cursor *cur) +{ + return ((PSKINRES_CURSOR)cur)->eof; +} + +static int __skin_res_next(sqlite3_vtab_cursor *pInCur) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + //PSKINRES_VTBL pvTable = (PSKINRES_VTBL)pInCur->pVtab; + + /* Increment the current row count. */ + pCur->count += 1; + + /* Arbitrary contstraint: when we get to 10 rows, then stop. */ + if(pCur->count >= SkinsDefaultSize()) + { + pCur->eof = 1; + } + + return SQLITE_OK; +} + +static int __skin_res_column(sqlite3_vtab_cursor *pInCur, sqlite3_context *ctx, int iCol) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + PSKIN_RES_INFO pItem = SkinsItemById(pCur->count); + //PSKINRES_VTBL pvTable = (PSKINRES_VTBL)pInCur->pVtab; + + /* Just return the ordinal of the column requested. */ + switch(iCol) + { + case 0: + sqlite3_result_int(ctx, pCur->count); + break; + + case 1: + sqlite3_result_text(ctx, pItem->pResVer, strlen(pItem->pResVer), SQLITE_STATIC); + break; + + case 2: + sqlite3_result_text(ctx, pItem->pLocalPath, strlen(pItem->pLocalPath), SQLITE_STATIC); + break; + + case 3: + sqlite3_result_text(ctx, pItem->pLocalPath, strlen(pItem->pLocalPath), SQLITE_STATIC); + break; + + case 4: + sqlite3_result_text(ctx, pItem->pMD5Chksum, strlen(pItem->pMD5Chksum), SQLITE_STATIC); + break; + } + + return SQLITE_OK; +} + +static int __skin_cfg_column(sqlite3_vtab_cursor *pInCur, sqlite3_context *ctx, int iCol) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + PSKIN_RES_INFO pItem = SkinsItemById(pCur->count); + //PSKINRES_VTBL pvTable = (PSKINRES_VTBL)pInCur->pVtab; + + /* Just return the ordinal of the column requested. */ + switch(iCol) + { + case 0: + sqlite3_result_int(ctx, pCur->count); + break; + + case 1: + sqlite3_result_text(ctx, pItem->pKeyName, strlen(pItem->pKeyName), SQLITE_STATIC); + break; + + case 2: + sqlite3_result_int(ctx, pItem->resType); + break; + + case 3: + sqlite3_result_int(ctx, 0); + break; + + case 4: + sqlite3_result_int(ctx, pCur->count); + break; + + case 5: + sqlite3_result_text(ctx, "", 0, SQLITE_STATIC); + break; + } + + return SQLITE_OK; +} + +static int __skin_res_rowid(sqlite3_vtab_cursor *pInCur, sqlite_int64 *p_rowid) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + + /* Just use the current row count as the rowid. */ + *p_rowid = pCur->count; + + return SQLITE_OK; +} + +static int __skin_res_filter( sqlite3_vtab_cursor *pVtc, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv ) +{ + //int rc; + //int i; + + /* Initialize the cursor structure. */ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pVtc; + + /* Zero rows returned thus far. */ + pCur->count = 0; + + /* Have not reached end of set. */ + pCur->eof = 0; + + /* Move cursor to first row. */ + return __skin_res_next(pVtc); +} + +/* Pretty involved. We don't implement in this example. */ +static int __skin_res_best_index(sqlite3_vtab *pVTbl, sqlite3_index_info *pIdxInfo) +{ + return SQLITE_OK; +} + +static sqlite3_module g_ResModule = +{ + 0, /* iVersion */ + __skin_res_create, /* xCreate - create a vtable */ + __skin_res_connect, /* xConnect - associate a vtable with a connection */ + __skin_res_best_index, /* xBestIndex - best index */ + __skin_res_disconnect, /* xDisconnect - disassociate a vtable with a connection */ + __skin_res_destroy, /* xDestroy - destroy a vtable */ + __skin_res_open, /* xOpen - open a cursor */ + __skin_res_close, /* xClose - close a cursor */ + __skin_res_filter, /* xFilter - configure scan constraints */ + __skin_res_next, /* xNext - advance a cursor */ + __skin_res_eof, /* xEof - inidicate end of result set*/ + __skin_res_column, /* xColumn - read data */ + __skin_res_rowid, /* xRowid - read data */ + NULL, /* xUpdate - write data */ + NULL, /* xBegin - begin transaction */ + NULL, /* xSync - sync transaction */ + NULL, /* xCommit - commit transaction */ + NULL, /* xRollback - rollback transaction */ + NULL, /* xFindFunction - function overloading */ +}; + +static sqlite3_module g_SkinModule = +{ + 0, /* iVersion */ + __skin_res_create, /* xCreate - create a vtable */ + __skin_res_connect, /* xConnect - associate a vtable with a connection */ + __skin_res_best_index, /* xBestIndex - best index */ + __skin_res_disconnect, /* xDisconnect - disassociate a vtable with a connection */ + __skin_res_destroy, /* xDestroy - destroy a vtable */ + __skin_res_open, /* xOpen - open a cursor */ + __skin_res_close, /* xClose - close a cursor */ + __skin_res_filter, /* xFilter - configure scan constraints */ + __skin_res_next, /* xNext - advance a cursor */ + __skin_res_eof, /* xEof - inidicate end of result set*/ + __skin_cfg_column, /* xColumn - read data */ + __skin_res_rowid, /* xRowid - read data */ + NULL, /* xUpdate - write data */ + NULL, /* xBegin - begin transaction */ + NULL, /* xSync - sync transaction */ + NULL, /* xCommit - commit transaction */ + NULL, /* xRollback - rollback transaction */ + NULL, /* xFindFunction - function overloading */ +}; + +int InitSkinRomDatabase(sqlite3 *pDataBase) +{ + if((sqlite3_create_module(pDataBase, SKIN_MODE_NAME, &g_SkinModule, NULL) == SQLITE_OK) + && (sqlite3_create_module(pDataBase, RES_MODE_NAME, &g_ResModule, NULL) == SQLITE_OK)) + { + return 0; + } + else + { + return -ERR_SQL_REG_MODULE; + } +} + + diff --git a/Framework/Skins/skins.c b/Framework/Skins/skins.c new file mode 100644 index 0000000..2fc624b --- /dev/null +++ b/Framework/Skins/skins.c @@ -0,0 +1,1442 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#include "skins_res.h" +#include "inet_api.h" + +#define MAX_DOWNLOAD_ITEMS (10) + +#define DEBUG_SQL_CMD (0) + +typedef enum +{ + STATUS_CREATE_NEW = 0, + STATUS_DOWNLOADING, + STATUS_DOWNLOADED, +} RES_DOWNLOAD_STATUS; + +typedef enum +{ + UPG_STATUS_ADDNEW = (1 << 0), + UPG_STATUS_DL_NEW = (1 << 1), + UPG_STATUS_DOWNLOADED = (1 << 2), +} UPGRADE_RES_STATUS; + +typedef struct +{ + char* pKeyName; + char* pResPath; + + UT_hash_handle hh; ///< UT Hash handle +} SKINS_CACHE_ITEM, *PSKINS_CACHE_ITEM; +static uv_rwlock_t g_SkinCacheRwLock; + +#ifdef PLATFORM_CPU +#define DOWNLOAD_RES_ROOT_PATH (DEF_SKINS_ROOT_PATH) +#else +#define DOWNLOAD_RES_ROOT_PATH ("/mnt/UDISK/resources/") +#endif + +//select * FROM upgrade_skin WHERE resVersion == 4 ORDER BY resType DESC, RANDOM() LIMIT 1 +//#define SKIN_GET_SQL_CMD ("") + +#define ATTACH_DB_SQL_CMD ("ATTACH \'%s\' AS \'%s\'") +#define UPGRADE_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS %supgrade (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "keyName TEXT NOT NULL," \ + "resType INTEGER NOT NULL," \ + "priority INTEGER NOT NULL DEFAULT (1)," \ + "resVersion TEXT NOT NULL," \ + "localPath TEXT NOT NULL," \ + "serverURL TEXT NOT NULL," \ + "md5Chksum TEXT NOT NULL," \ + "resReadme TEXT NOT NULL DEFAULT (\'\')," \ + "resStatus INTEGER NOT NULL DEFAULT (1)," \ + "dlId TEXT NOT NULL DEFAULT (\'\')," \ + "dlStatus INTEGER NOT NULL DEFAULT (0)," \ + "dlRetrys INTEGER NOT NULL DEFAULT (0)," \ + "dlTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") + +#define CREATE_TMP_TBL_SQL "CREATE TABLE IF NOT EXISTS %stmp (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "localPath TEXT NOT NULL);" + +static int g_isDlFinished = FALSE; +static unsigned int g_curDlItems = 0; +static sqlite3* g_pMemDb = NULL; +static uv_rwlock_t g_uvSkinRwLock; +static uv_rwlock_t g_uvDlRwLock; +static const unsigned int g_tolDefaultSkins = (sizeof(g_SkinDefaultResTable) / sizeof(g_SkinDefaultResTable[0])); +static PSKINS_CACHE_ITEM g_pSkinCackeTbl = NULL; + +char* TblGetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom); +static int __getUpgradeInfo(const char *pUpdFilePath); +static int __reTryDlSkinResCb(void *pData, int argc, char **argv, char **azColName); +extern int InitSkinRomDatabase(sqlite3 *pDataBase); +static int g_isVerifyRes = FALSE; +static int g_isUpgradeRunning = FALSE; + +static int __dumpSkinsInfo(PSKIN_RES_INFO pItem, int nItems) +{ + LOG_EX2(LOG_Debug, "Skins Items Information:\n"); + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------" + "--------------------------------------------------------\n"); + + LOG_EX2(LOG_Debug, "| Key Name | Type | MD5 Checksum |" + " Contexts " + " |\n"); + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------" + "--------------------------------------------------------\n"); + + for(int i = 0; i < nItems && pItem; i++, pItem++) + { + LOG_EX2(LOG_Debug, "| %-8s | %-8s | %-32s | %-80s |\n", + pItem->pKeyName, pItem->pResVer, pItem->pMD5Chksum, pItem->pLocalPath); + } + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------" + "--------------------------------------------------------\n"); +} + +static int __verifyResMD5Chksum(const char* pPath, const char* pChksum, int resType) +{ + const char* pMD5Chksum; + + if(resType == TEXT_RES) + { + return (TRUE); + } + + if(pPath == NULL || pChksum == NULL) + { + return (FALSE); + } + + switch(resType) + { + case IMAGE_RES: + case VOICE_RES: + pMD5Chksum = EvpMD5HashFile(pPath); + + if(pMD5Chksum == NULL) + { + return (FALSE); + } + + if(strcmp(pMD5Chksum, pChksum) != 0) + { + LOG_EX(LOG_Error, "%s MD5 Verify Error: %s -> %s\n", pPath, pMD5Chksum, pChksum); + + free((char*)pMD5Chksum); + return (FALSE); + } + else + { + free((char*)pMD5Chksum); + } + + break; + + default: + return (FALSE); + } + + return (TRUE); +} + +static void __checkRes(sqlite3_context *pContext, int argc, sqlite3_value **argv) +{ + if(access(sqlite3_value_text(argv[0]), F_OK) != 0) + { + sqlite3_result_int(pContext, -1); + } + else if(__verifyResMD5Chksum(sqlite3_value_text(argv[0]), + sqlite3_value_text(argv[1]), + sqlite3_value_int(argv[2])) == FALSE) + { + sqlite3_result_int(pContext, -2); + } + else + { + sqlite3_result_int(pContext, 0); + } +} + +static int __cleanupSkinTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE %s.%s", SKIN_USER_DB, SKIN_TBL_NAME); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL, SKIN_USER_DB"."); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __cleanupResTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE %s.%s", SKIN_USER_DB, RES_TBL_NAME); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_RES_TBL_SQL, SKIN_USER_DB"."); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __cleanupUpgTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE %s.upgrade", SKIN_USER_DB); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, UPGRADE_TBL_SQL_CMD, SKIN_USER_DB"."); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __cleanupTmpTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE main.tmp"); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_TMP_TBL_SQL, "main."); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __skinCreateCfgDB(void) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string *pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "CREATE VIRTUAL TABLE main.%s USING %s;" + "CREATE VIRTUAL TABLE main.%s USING %s;", + SKIN_TBL_NAME, SKIN_MODE_NAME, RES_TBL_NAME, RES_MODE_NAME); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + + return (0); +} + +static int __skinCreateCfgFile(const char* pCfgFilePath) +{ + char* pErrMsg = NULL; + int rc = 0; + static sqlite3* pSqlFileDB = NULL; + UT_string *pSqlCmd = NULL; + + rc = sqlite3_open(":memory:", &g_pMemDb); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "sqlite3_open memory: %s\n", pCfgFilePath); + return -ERR_OPEN_SQLITE3_DB; + } + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_TMP_TBL_SQL, ""); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + rc = sqlite3_open_v2(pCfgFilePath, &pSqlFileDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "sqlite3_open_v2 error: %s\n", pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_OPEN_SQLITE3_DB; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL""CREATE_RES_TBL_SQL, "", ""); + + rc = sqlite3_exec(pSqlFileDB, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, UPGRADE_TBL_SQL_CMD, ""); + rc = sqlite3_exec(pSqlFileDB, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", UPGRADE_TBL_SQL_CMD, pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + sqlite3_close(pSqlFileDB); + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, ATTACH_DB_SQL_CMD, pCfgFilePath, SKIN_USER_DB); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Attach Database %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + utstring_free(pSqlCmd); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + + rc = sqlite3_create_function(g_pMemDb, "ResCheck", 3, SQLITE_UTF8, NULL, __checkRes, NULL, NULL); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Don't Support Resurces Verify Function\n"); + } + + if(InitSkinRomDatabase(g_pMemDb) != 0) + { + sqlite3_close(g_pMemDb); + return (-ERR_SQL_REG_MODULE); + } + + rc = __skinCreateCfgDB(); + + if(rc != 0) + { + sqlite3_close(g_pMemDb); + return rc; + } + + return (0); +} + +static void __onDlFileCb(void *pData, unsigned int size, + const char *pReqUrl, const char* pDlPath, + const char *pTaskUuid, int iFinished, void *pUserData) +{ + char* pId = (char*)pUserData; + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + + if(g_curDlItems > 0) + { + g_curDlItems--; + } + + if(iFinished == 0 && pId != NULL) + { + //LOG_EX(LOG_Debug, "Request(%s): [%s] --> [%s] Response: [%u] OK\n", pTaskUuid, pReqUrl, pDlPath, size); + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET dlStatus = %d, dlRetrys = %d, " + "dlTime = datetime(\'now\', \'localtime\') WHERE ID = %s AND " + "ResCheck(localPath, md5Chksum, resType) = 0", + SKIN_USER_DB, STATUS_DOWNLOADED, 0, pId); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + else + { + if(iFinished == 1) + { + LOG_EX(LOG_Error, "Request(%s): [%s] --> [%s] Response: [%u] Error\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else + { + LOG_EX(LOG_Error, "Download %s Error: %d\n", pReqUrl, iFinished); + } + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT * FROM %s.upgrade WHERE ID = %s AND dlRetrys < 5 ", SKIN_USER_DB, pId); + + //fprintf(stdout, "SQL:\n%s\n", utstring_body(pSqlCmd)); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __reTryDlSkinResCb, NULL, &pErrMsg); + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL %s Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + + if(pId) + { + free(pId); + } +} + +static int __reTryDlSkinResCb(void *pData, int argc, char **argv, char **azColName) +{ + UT_string *pSqlCmd = NULL; + char* pErrMsg = NULL; + + const char* pDlTaskId = InetHttpDlFileAsync(argv[6], + argv[5], + __onDlFileCb, + NULL, + strdup(argv[0])); + + if(pDlTaskId != NULL) + { + int rc = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET dlId = \'%s\', dlRetrys = dlRetrys + 1, " + "dlTime = datetime(\'now\', \'localtime\') WHERE ID = %s", + SKIN_USER_DB, pDlTaskId, argv[0]); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + + return 0; +} + +static int __loadDownloadSkinsCb(void *pData, int argc, char **argv, char **azColName) +{ + const char *pDlTaskId; + char* pItemId = argv[0]; + char* pURL = argv[6]; + char* pDlPath = argv[5]; + char* pDlId = argv[10]; + int dlStatus = strtol(argv[3], NULL, 10); + int dlRetry = strtol(argv[4], NULL, 10) + 1; + + if(dlStatus == STATUS_DOWNLOADING) + { + if(strlen(pDlId) > 0) + { + InetCancelDownload(pDlId); + } + + dlRetry++; + } + + //LOG_EX(LOG_Debug, "Download: %s --> %s\n", pURL, pDlPath); + + pDlTaskId = InetHttpDlFileAsync(pURL, + pDlPath, + __onDlFileCb, + NULL, + strdup(pItemId)); + + if(pDlTaskId) + { + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + + g_curDlItems++; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET dlStatus = %d, dlRetrys = %d, " + "dlId = \'%s\', dlTime = datetime(\'now\', \'localtime\') WHERE ID = %s", + SKIN_USER_DB, STATUS_DOWNLOADING, dlRetry, pDlTaskId, pItemId); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + else + { + LOG_EX(LOG_Error, "Download %s error\n", pURL); + } + + return (0); +} + +static void __uvDownloadResThread(void *pParams) +{ + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + LOG_EX(LOG_Debug, "Beging Download Skins\n"); + + while(!g_isDlFinished) + { + int rc = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT *, STRFTIME(\"%%s\", datetime(\'now\', \'localtime\')) " + "- STRFTIME(\"%%s\", upgrade.dlTime) AS diff FROM %s.upgrade " + "WHERE resStatus = %d AND (dlRetrys < 5 OR diff > 600) " + "AND (dlStatus = %d OR (dlStatus = %d AND diff > 600)) " + "LIMIT 10 - %d", + SKIN_USER_DB, UPG_STATUS_DL_NEW, STATUS_CREATE_NEW, STATUS_DOWNLOADING, g_curDlItems); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __loadDownloadSkinsCb, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + + sleep(1); + } + + LOG_EX(LOG_Debug, "Download Skins Finished\n"); + + pthread_detach(pthread_self()); +} + +static int __sqlCbRemoveUnusedFile(void *pData, int argc, char **argv, char **azColName) +{ + LOG_EX(LOG_Debug, "Clean up resources: [%s]\n", argv[1]); + + if(access(argv[1], F_OK) == 0 + && strncmp(argv[1], DEF_SKINS_ROOT_PATH, strlen(DEF_SKINS_ROOT_PATH)) != 0) + { + unlink(argv[1]); + } +} + +static int __createResTblCb(void *pData, int argc, char **argv, char **azColName) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + //DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName); + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "INSERT INTO %s.%s " + "VALUES (NULL, \'%s\', \'%s\', \'%s\', \'%s\')", + SKIN_USER_DB, RES_TBL_NAME, argv[0], argv[1], argv[2], argv[3]); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "[%s] Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -1; + } + + utstring_free(pSqlCmd); + + return 0; +} + +static int __createSkinTblCb(void *pData, int argc, char **argv, char **azColName) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + //DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName); + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, "INSERT INTO %s.%s " + "VALUES (NULL, \'%s\', %s, %s, %s, \'%s\')", + SKIN_USER_DB, SKIN_TBL_NAME, + argv[1], argv[2], argv[3], argv[0], argv[4]); + + //fprintf(stdout, "AutoId: %lld: %s\n", sqlite3_last_insert_rowid(g_pMemDb), argv[3]); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "[%s] Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + return -1; + } + + utstring_free(pSqlCmd); + return 0; +} + +static void __uvSyncResThread(void *pParams) +{ + int tolCnt = 0; + PSKINS_CACHE_ITEM pItem = NULL, pTemp = NULL; + + LOG_EX(LOG_Debug, "Beging Sync Download Skins\n"); + + while(TRUE) + { + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + char **pResult = NULL; + int iRow = 0, iCol = 0; + int nItems = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT COUNT(*) FROM %s.upgrade " + "WHERE resStatus = %d AND dlStatus != %d", + SKIN_USER_DB, UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_get_table(g_pMemDb, utstring_body(pSqlCmd), &pResult, &iRow, &iCol, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + + nItems = strtol(pResult[1], NULL, 10); + sqlite3_free_table(pResult); + + if(tolCnt++ % 20 == 0) + { + LOG_EX(LOG_Debug, "Download: Remain %d\n", nItems); + } + + if(nItems == 0) + { + g_isDlFinished = TRUE; + utstring_new(pSqlCmd); + sqlite3_exec(g_pMemDb, "BEGIN TRANSACTION;", NULL, NULL, NULL); + + utstring_printf(pSqlCmd, "INSERT INTO main.tmp " + "SELECT %s.ID, %s.localPath FROM %s.%s " + "LEFT JOIN %s.upgrade on %s.md5Chksum = upgrade.md5Chksum " + "WHERE upgrade.md5Chksum IS NULL;", + RES_TBL_NAME, RES_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + SKIN_USER_DB, RES_TBL_NAME); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + utstring_free(pSqlCmd); + break; + } + + __cleanupSkinTbl(); + __cleanupResTbl(); + + utstring_renew(pSqlCmd); + + utstring_printf(pSqlCmd, "SELECT resVersion, localPath, serverURL, md5Chksum, " + "keyName, resType, priority, resReadme, resStatus, dlStatus " + "FROM %s.upgrade WHERE resStatus = %d " + "OR (resStatus = %d AND dlStatus = %d) " + "GROUP BY md5Chksum", + SKIN_USER_DB, UPG_STATUS_DOWNLOADED, + UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __createResTblCb, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + utstring_free(pSqlCmd); + break; + } + else + { + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT %s.ID, keyName, resType, priority, " + "resReadme, resStatus, dlStatus, %s.md5Chksum " + "FROM %s.upgrade, %s.res WHERE %s.md5Chksum = upgrade.md5Chksum" + " AND (resStatus = %d OR (resStatus = %d AND dlStatus = %d)) " + "ORDER BY keyName", + RES_TBL_NAME, RES_TBL_NAME, SKIN_USER_DB, SKIN_USER_DB, RES_TBL_NAME, + UPG_STATUS_DOWNLOADED, UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __createSkinTblCb, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + utstring_free(pSqlCmd); + break; + } + else + { + sqlite3_exec(g_pMemDb, "SELECT * FROM main.tmp", __sqlCbRemoveUnusedFile, NULL, NULL); + utstring_free(pSqlCmd); + + if(__cleanupUpgTbl() != 0) + { + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + } + else + { + sqlite3_exec(g_pMemDb, "END TRANSACTION;", NULL, NULL, NULL); + break; + } + } + } + } + + sleep(1); + } + + LOG_EX(LOG_Debug, "Sync Download Skins Finished\n"); + + uv_rwlock_wrlock(&g_SkinCacheRwLock); + HASH_ITER(hh, g_pSkinCackeTbl, pItem, pTemp) + { + free(pItem->pKeyName); + free(pItem->pResPath); + free(pItem); + pItem = NULL; + } + + g_pSkinCackeTbl = NULL; + uv_rwlock_wrunlock(&g_SkinCacheRwLock); + + g_isUpgradeRunning = FALSE; + pthread_detach(pthread_self()); +} + +static int __upgStatusTblCb(void *pData, int argc, char **argv, char **azColName) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName); + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET resStatus = %d WHERE ID = %s", + SKIN_USER_DB, UPG_STATUS_DL_NEW, argv[2]); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "[%s] Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -1; + } + + utstring_free(pSqlCmd); + + return 0; +} + +static int __saveUpgradeInfo(PSKIN_RES_INFO pInfo, int nItems) +{ + int isError = FALSE; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + if(pInfo == NULL || nItems <= 0) + { + return (-ERR_INPUT_PARAMS); + } + + utstring_new(pSqlCmd); + + sqlite3_exec(g_pMemDb, "BEGIN TRANSACTION;", NULL, NULL, NULL); + __cleanupUpgTbl(); + __cleanupTmpTbl(); + + for(int i = 0; i < nItems; i++) + { + UT_string* pPath = NULL; + PSKIN_RES_INFO pItem = &pInfo[i]; + + utstring_new(pPath); + utstring_renew(pSqlCmd); + +#if 0 + if(pItem->resType == VOICE_RES) + { + utstring_printf(pPath, "%svoice/%s", DOWNLOAD_RES_ROOT_PATH, basename_v2(pItem->pLocalPath)); + } + + else if(pItem->resType == IMAGE_RES) + { + utstring_printf(pPath, "%simage/%s", DOWNLOAD_RES_ROOT_PATH, basename_v2(pItem->pLocalPath)); + } + else if(pItem->resType == TEXT_RES) + { + utstring_printf(pPath, "%s", pItem->pLocalPath); + } + else + { + utstring_free(pPath); + continue; + } +#else + utstring_printf(pPath, "%svoice/%s", DOWNLOAD_RES_ROOT_PATH, basename_v2(pItem->pLocalPath)); +#endif + utstring_printf(pSqlCmd, "INSERT INTO %s.upgrade (keyName, resType, resVersion, localPath, serverURL, md5Chksum)" + " SELECT \'%s\', %d, \'%s\', \'%s\', \'%s\', \'%s\' ", + SKIN_USER_DB, pItem->pKeyName, pItem->resType, pItem->pResVer, utstring_body(pPath), + pItem->pLocalPath, pItem->pMD5Chksum); + +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + if((sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg) != SQLITE_OK)) + { + LOG_EX(LOG_Error, "Add Skins[%d] %s To Database Error: %s\n", i, pItem->pKeyName, utstring_body(pSqlCmd)); + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + isError = TRUE; + utstring_free(pPath); + break; + } + + utstring_free(pPath); + } + + utstring_renew(pSqlCmd); + + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET resStatus = %d " + "WHERE EXISTS (SELECT %s.keyName, upgrade.md5Chksum FROM main.%s, user_db.upgrade " + "WHERE upgrade.keyName = %s.keyName)", + SKIN_USER_DB, UPG_STATUS_DL_NEW, + SKIN_TBL_NAME, SKIN_TBL_NAME, + SKIN_TBL_NAME); + +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + if(sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __upgStatusTblCb, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "Upgrade Status: %s\n", utstring_body(pSqlCmd)); + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + isError = TRUE; + } + + utstring_renew(pSqlCmd); + + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET resStatus = %d " + "WHERE EXISTS (SELECT %s.md5Chksum FROM %s.%s " + "WHERE upgrade.md5Chksum = %s.md5Chksum);" + "UPDATE %s.upgrade SET resStatus = %d, localPath = " + "(SELECT %s.localPath FROM main.%s " + "WHERE upgrade.md5Chksum = %s.md5Chksum) " + "WHERE EXISTS (SELECT %s.md5Chksum FROM main.%s " + "WHERE upgrade.md5Chksum = %s.md5Chksum);", + SKIN_USER_DB, UPG_STATUS_DOWNLOADED, + RES_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + RES_TBL_NAME, + SKIN_USER_DB, UPG_STATUS_DOWNLOADED, + RES_TBL_NAME, RES_TBL_NAME, RES_TBL_NAME, + RES_TBL_NAME, RES_TBL_NAME, RES_TBL_NAME); + +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + if(sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "Upgrade Status: %s\n", utstring_body(pSqlCmd)); + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + isError = TRUE; + } + + utstring_free(pSqlCmd); + + + if(isError == TRUE) + { + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + return (-ERR_SQL_QUERY); + } + else + { + uv_thread_t uvSyncThread, uvDlThread; + sqlite3_exec(g_pMemDb, "END TRANSACTION;", NULL, NULL, NULL); + g_curDlItems = 0; + g_isDlFinished = FALSE; + uv_thread_create(&uvDlThread, __uvDownloadResThread, NULL); + uv_thread_create(&uvSyncThread, __uvSyncResThread, NULL); + } + + return 0; +} + +static int __loadPreUpgradeInfo(void) +{ + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + char **pResult = NULL; + int iRow = 0, iCol = 0; + int nItems = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT COUNT(*) FROM %s.upgrade WHERE resStatus = %d AND dlStatus != %d", + SKIN_USER_DB, UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); + + rc = sqlite3_get_table(g_pMemDb, utstring_body(pSqlCmd), &pResult, &iRow, &iCol, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + + nItems = strtol(pResult[1], NULL, 10); + sqlite3_free_table(pResult); + + if(nItems > 0) + { + uv_thread_t uvSyncThread, uvDlThread; + g_curDlItems = 0; + g_isDlFinished = FALSE; + g_isUpgradeRunning = TRUE; + uv_thread_create(&uvDlThread, __uvDownloadResThread, NULL); + uv_thread_create(&uvSyncThread, __uvSyncResThread, NULL); + LOG_EX(LOG_Debug, "Load Pre Download Items: %d\n", nItems); + } +} + +static int __getEnumResInfo(void) +{ + __saveUpgradeInfo((PSKIN_RES_INFO)g_emuUpgradeInfo, sizeof(g_emuUpgradeInfo) / sizeof(g_emuUpgradeInfo[0])); +} + +int SkinUpgrade(char* pUpdData) +{ + int nItems = 0; + PSKIN_RES_INFO pUpgResInfo; + cJSON *pRoot, *pList; + +#if 1 + FILE *pFile = fopen("/mnt/UDISK/skinupgrade.txt", "w+"); + fwrite(pUpdData, 1, strlen(pUpdData), pFile); + fclose(pFile); +#endif + + if (pUpdData == NULL || strlen(pUpdData) == 0) + { + LOG_EX(LOG_Error, "Input Params Error\n"); + return (-ERR_INPUT_PARAMS); + } + + LOG_EX(LOG_Debug, "Upgrade Cmd: [%s]\n", pUpdData); + //fprintf(stdout, "%s\n", pUpdData); + + pRoot = cJSON_Parse(pUpdData); + + if(pRoot == NULL) + { + LOG_EX(LOG_Error, "Parse Json Error\n"); + return (-ERR_NO_ITEMS); + } + + nItems = cJSON_GetArraySize(pRoot); + + if(nItems <= 0) + { + LOG_EX(LOG_Error, "Upgrade Item: %d\n", nItems); + cJSON_Delete(pRoot); + return (-ERR_NO_ITEMS); + } + + pUpgResInfo = (PSKIN_RES_INFO)malloc(sizeof(SKIN_RES_INFO) * nItems); + + if(pUpgResInfo == NULL) + { + LOG_EX(LOG_Error, "Malloc %d Memory Error\n", nItems); + cJSON_Delete(pRoot); + return (-ERR_MALLOC_MEMORY); + } + + LOG_EX(LOG_Debug, "Array Size = %d\n", nItems); + + memset(pUpgResInfo, 0, sizeof(SKIN_RES_INFO) * nItems); + pList = pRoot->child; + + for(int i = 0; i < nItems; i++) + { + pUpgResInfo[i].resType = VOICE_RES;//cJSON_GetObjectItem(pList, "resourceType")->valueint; + pUpgResInfo[i].pResVer = strdup(cJSON_GetObjectItem(pList, "resourceVersion")->valuestring); + pUpgResInfo[i].pKeyName = strdup(cJSON_GetObjectItem(pList, "resourceName")->valuestring); + pUpgResInfo[i].pLocalPath = strdup(cJSON_GetObjectItem(pList, "url")->valuestring); + pUpgResInfo[i].pMD5Chksum = strdup(cJSON_GetObjectItem(pList, "md5")->valuestring); + + pList = pList->next; + } + + cJSON_Delete(pRoot); + + g_isUpgradeRunning = TRUE; + __dumpSkinsInfo(pUpgResInfo, nItems); + __saveUpgradeInfo(pUpgResInfo, nItems); + + free(pUpgResInfo); +} + +char* SQLiteGetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom) +{ + char *pSkinPath = strdup(""); + int rc = 0; + char* pErrMsg = NULL; + UT_string *pSqlCmd = NULL; + char **pResult = NULL; + int iRow = 0, iCol = 0; + int queCol = 13; + int colPath = 21; + + utstring_new(pSqlCmd); + + if(g_isVerifyRes) + { + utstring_printf(pSqlCmd, "SELECT *, RANDOM() AS rnd, ResCheck(localPath, md5Chksum, resType) as resOK " + "FROM %s.%s, %s.%s\n" + "WHERE %s.keyName = \'%s\' AND resOK = 0 AND %s.resId = %s.ID\n" + "UNION\n" + "SELECT *, RANDOM() AS rnd, ResCheck(localPath, md5Chksum, resType) as resOK " + "FROM main.%s, main.%s\n" + "WHERE %s.keyName = \'%s\' AND resOK = 0 AND %s.resId = %s.ID\n" + "ORDER BY priority DESC, rnd " + "LIMIT 1", + SKIN_USER_DB, SKIN_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME); + } + else + { + utstring_printf(pSqlCmd, "SELECT *, RANDOM() AS rnd " + "FROM %s.%s, %s.%s\n" + "WHERE %s.keyName = \'%s\' AND %s.resId = %s.ID\n" + "UNION\n" + "SELECT *, RANDOM() AS rnd " + "FROM main.%s, main.%s\n" + "WHERE %s.keyName = \'%s\' AND %s.resId = %s.ID\n" + "ORDER BY priority DESC, rnd " + "LIMIT 1", + SKIN_USER_DB, SKIN_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME); + queCol = 12; + colPath = 20; + } + + rc = sqlite3_get_table(g_pMemDb, utstring_body(pSqlCmd), &pResult, &iRow, &iCol, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s(%d)\n", utstring_body(pSqlCmd), pErrMsg, rc); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return (pSkinPath); + } + + if(iRow == 1 && iCol == queCol) + { + + if(access(pResult[colPath], F_OK) != 0) + { + LOG_EX(LOG_Error, "Res %s --> %s not exists\n", pKeyName, pResult[colPath]); + } + else + { + free(pSkinPath); + pSkinPath = strdup(pResult[colPath]); + } +#if 0 + for(int i = 0; i <= 21; i++) + { + LOG_EX(LOG_Debug, "[%d]: {%s}\n", i, pResult[i]); + } +#endif + } + +#if 0 + int index = iCol; + for(int i = 0; i < iRow; i++) + { + fprintf(stdout, "----------%d[%d, %d]---------\n", i, iRow, iCol); + + for(int j = 0; j < iCol; j++) + { + int tblCol = i * iCol + j; + + fprintf(stdout, "%s(%d, %d) = [%s]\n", pResult[tblCol], j, index, pResult[index]); + index++; + } + } +#endif + + sqlite3_free_table(pResult); + utstring_free(pSqlCmd); + + if(strcmp(pSkinPath, "") == 0) + { + free(pSkinPath); + return TblGetSkinsResource(pKeyName, pResType, pVersion, pComeFrom); + } + else + { + return (pSkinPath); + } +} + +char* TblGetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom) +{ + + for(int i = 0; i < sizeof(g_SkinDefaultResTable) / sizeof(g_SkinDefaultResTable[0]); i++) + { + if(strcmp(g_SkinDefaultResTable[i].pKeyName, pKeyName) == 0) + { + return strdup(g_SkinDefaultResTable[i].pLocalPath); + } + } + + return strdup(""); +} + +char* GetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom) +{ + if(g_isUpgradeRunning) + { + return TblGetSkinsResource(pKeyName, pResType, pVersion, pComeFrom); + } + else + { + return SQLiteGetSkinsResource(pKeyName, pResType, pVersion, pComeFrom); + } +} + +unsigned int SkinsDefaultSize(void) +{ + return (g_tolDefaultSkins + 1); +} + +PSKIN_RES_INFO SkinsItemById(int iId) +{ + if(iId < 0 || iId > g_tolDefaultSkins) + { + return (NULL); + } + + return ((PSKIN_RES_INFO)&g_SkinDefaultResTable[iId - 1]); +} + +static int __verifyResValuableCb(void *pData, int argc, char **argv, char **azColName) +{ + char sqlCmd[256]; + char* pErrMsg = NULL; + + if(argc < 3) + { + return 0; + } + + sqlite3_exec(g_pMemDb, "BEGIN TRANSACTION;", NULL, NULL, NULL); + for(int i = 0; i < argc; i++) + { + if(strcmp(azColName[i], "ID") == 0) + { + LOG_EX(LOG_Error, "Cleanup Bad Resources: %s\n", argv[i + 1]); + + memset(sqlCmd, 0, 256); + sprintf(sqlCmd, "DELETE FROM %s.%s WHERE ID = %s", SKIN_USER_DB, RES_TBL_NAME, argv[i]); + + if(sqlite3_exec(g_pMemDb, sqlCmd, __verifyResValuableCb, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL: %s\nError: %s\n", sqlCmd, pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + return -1; + } + + unlink(argv[i + 1]); + } + } + sqlite3_exec(g_pMemDb, "END TRANSACTION;", NULL, NULL, NULL); + + return (0); +} + +static void VerifySkinResInfo(void) +{ + UT_string *pSqlCmd = NULL; + char* pErrMsg = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT ID, localPath, md5Chksum FROM %s.%s " + "WHERE ResCheck(localPath, md5Chksum, 1) != 0", SKIN_USER_DB, RES_TBL_NAME); + + if(sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __verifyResValuableCb, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return; + } + + utstring_free(pSqlCmd); +} + +void SkinIsVerifyRes(int isVerify) +{ + g_isVerifyRes = isVerify; +} + +int SkinInit(void) +{ + int rc = 0; + UT_string* pPath = NULL; +#if 0 + int tmUsed = 0; + struct timeval tmStart, tmEnd; + + if(DBusLibuvGetRuntime() == NULL) + { + int ret = 0; + uv_thread_t uvThread; + LOG_EX(LOG_Warn, "+++++++++++++++++++++++System Uninit\n"); + + DBusConnection* pBus = DBusWithLibuvInit(GetDBusDefaultLoop(), + g_pModInfoTable[MODULE_SKINS].modAliase, + __dusOnMsg, + NULL, + NULL, //KeyEventCb, + &ret); + + if(pBus == NULL) + { + LOG_EX(LOG_Error, "DBusWithLibuvInit Error: %d\n", ret); + return -ERR_UNINIT_ITEM; + } + + uv_thread_create(&uvThread, uvLoopProc, NULL); + } +#endif + + uv_rwlock_init(&g_uvSkinRwLock); + uv_rwlock_init(&g_uvDlRwLock); + uv_rwlock_init(&g_SkinCacheRwLock); + + utstring_new(pPath); + + utstring_printf(pPath, "mkdir -p %s/image > /dev/zero", DOWNLOAD_RES_ROOT_PATH); + rc = system(utstring_body(pPath)); + + utstring_renew(pPath); + utstring_printf(pPath, "mkdir -p %s/voice > /dev/zero", DOWNLOAD_RES_ROOT_PATH); + rc = system(utstring_body(pPath)); + + utstring_free(pPath); + + rc = __skinCreateCfgFile(SKINS_DB_PATH); + + if(rc != SQLITE_OK) + { + return rc; + } + + // gettimeofday(&tmStart, NULL); + VerifySkinResInfo(); +// gettimeofday(&tmEnd, NULL); + +// tmUsed = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmStart.tv_sec * 1000000 + tmStart.tv_usec); +// LOG_EX(LOG_Debug, "VerifySkinResInfo used time: %d(us)\n", tmUsed); + + __loadPreUpgradeInfo(); + //__getEnumResInfo(); + //__getUpgradeInfo("./hotfix.txt"); + //__loadDownloadItems(); + + //__dumpSkinsInfo(); +} diff --git a/Framework/SvrManager/svr_manager.c b/Framework/SvrManager/svr_manager.c new file mode 100644 index 0000000..df0db17 --- /dev/null +++ b/Framework/SvrManager/svr_manager.c @@ -0,0 +1,224 @@ +#include "server_addr.h" +#include "log.h" +#include "config_engine.h" +#include "libuv_dbus.h" + +const char* g_ServerModuleStr[] = +{ + "YUNXIN_MODULE", + "VOICE_MODULE", + "VOICE_AI_MODULE", + "SERVER_MODULE", + "LOG_MODULE", + "MARK_POINT_MODULE", + "TTS_MODULE", + "DC_MODULE", + "UNKNOWN_MODULE" +}; + +const char* g_ServerModeStr[] = +{ + "DEV_MODE", + "TEST_MODE", + "PUBLISH_MODE", + "UNKNOWN_MODE" +}; + +const char* g_KeyMapStr[] = +{ + "VOICE_APP_KEY", + "VOICE_APP_SECRET", + "UNKNOWN_KEYMAP" +}; + +const char* SvrModuleStr(SERVER_MODULE_TYPE module) +{ + return g_ServerModuleStr[module]; +} + +const char* SvrModeStr(SERVER_MODE_TYPE mode) +{ + return g_ServerModeStr[mode]; +} + +const char* g_VoiceKeyMap[VOICE_MAX][MAX_MODE] = { + { // VOICE_APP_KEY + "vbox-dev", + "vbox-dev", + "vbox-online", + }, + { // VOICE_APP_SECRET + "b1ec33c03df80ea3035bc9ccaa4af09c", + "b1ec33c03df80ea3035bc9ccaa4af09c", + "8714d6de1c83f21dda5fc9a905a59ac1", + }, +}; + +const char* g_ServerAddr[MAX_MODULE][MAX_MODE] = { + { // YUNXIN_MODULE + "2e37bc56a9b7ec3f6b8f41f60b81eb92", + "2e37bc56a9b7ec3f6b8f41f60b81eb92", + "dbb00213c23ea3709aae12ceb4c4e54e", + }, + { // VOICE_MODULE + "ws://vbox-test.netease.com/netty/websocket", + "ws://vbox-test.netease.com/netty3/websocket", + "wss://vbox-asr.3.163.com/websocket", + }, + { // VOICE_AI_MODULE + "http://api.multimedia.netease.com/imgtest/yqbot31_8686/", + "http://api.multimedia.netease.com/imgtest/yqbot29_8686/", + "https://vbox-smart.3.163.com/ ", + }, + { // SERVER_MODULE + "http://api.multimedia.netease.com/imgtest/yqbot27_7677/", + "http://api.multimedia.netease.com/imgtest/yqbot31_7676/", + "https://vbox-server.3.163.com/", + }, + { // LOG_MODULE + "http://vbox-log-test.netease.com/logCollectDev/vbox/logCollect/uploadLog", + "http://vbox-log-test.netease.com/logCollect/vbox/logCollect/uploadLog", + "https://vbox-log.3.163.com/vbox/logCollect/uploadLog", + }, + { // MARK_POINT_MODULE + "http://vbox-log-test.netease.com/buriedDev/vbox/log/add", + "http://vbox-log-test.netease.com/buriedTest/vbox/log/add", + "https://vbox-log.3.163.com/vbox/log/add", + }, + { // TTS_MODULE + "http://api.openai.netease.com/vbox-tts-dev/vbox/tts/transform", + "http://api.openai.netease.com/vbox-tts-test/vbox/tts/transform", + "https://vbox-tts.3.163.com/vbox/tts/transform", + }, + { // DC_MODULE + "http://api.multimedia.netease.com/imgtest/yqbot27_7677/vbox/uploadFile", + "http://api.multimedia.netease.com/imgtest/yqbot31_7676/vbox/uploadFile", + "https://vbox-server.3.163.com/vbox/uploadFile", + }, +}; + +static unsigned int g_SvrMode = PUBLISH_MODE; + +void DumpCurServerAddr(const char* pTags) +{ + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Info, "%s\t Current Server Mode: %s\n", pTags, SvrModeStr(g_SvrMode)); + } + else + { + LOG_EX2(LOG_Info, "Current Server Mode: %s\n", SvrModeStr(g_SvrMode)); + } + +#if 0 + LOG_EX2(LOG_Info, "Voice Key = [%s], Secret = [%s]\n", + GetCurVoiceKeyValue(VOICE_APP_KEY), GetCurVoiceKeyValue(VOICE_APP_SECRET)); + + LOG_EX2(LOG_Info, "--------------------------------------------------------" + "----------------------------------------------\n"); + + LOG_EX2(LOG_Info, "| Module | " + "Server URL |\n"); + + LOG_EX2(LOG_Info, "--------------------------------------------------------" + "----------------------------------------------\n"); + + for(int i = 0; i < MAX_MODULE; i++) + { + LOG_EX2(LOG_Info, "| %-17s | %-78s |\n", SvrModuleStr(i), GetCurServerAddr(i)); + } + + LOG_EX2(LOG_Info, "--------------------------------------------------------" + "----------------------------------------------\n"); +#endif + +} + +SERVER_MODE_TYPE GetCurrentServerMode(void) +{ + return g_SvrMode; +} + +void SetCurrentServerMode(SERVER_MODE_TYPE mode) +{ + if(mode >= 0 && mode < MAX_MODE) + { + if(g_SvrMode != mode) + { + LOG_EX(LOG_Debug, "Change server mode from %s(%d) to %s(%d)\n", + g_ServerModeStr[g_SvrMode], g_SvrMode, g_ServerModeStr[mode], mode); + + g_SvrMode = mode; + + CfgSetIntValue("ServerMode", mode); + } + else + { + LOG_EX(LOG_Warn, "Current mode is %s(%d) yet\n", g_ServerModeStr[mode], mode); + } + } + else + { + LOG_EX(LOG_Error, "Unknown Mode: %d, current mode: %s(%d)\n", + mode, g_ServerModeStr[g_SvrMode], g_SvrMode); + } +} + +char* GetCurServerAddr(SERVER_MODULE_TYPE module) +{ + if(module >= 0 && module < MAX_MODULE) + { + return (char*)g_ServerAddr[module][g_SvrMode]; + } + else + { + LOG_EX(LOG_Error, "Unknown Module: %s(%d)\n", g_ServerModuleStr[module], module); + return ""; + } +} + +char* GetCurVoiceKeyValue(VOICE_KEYMAP_TYPE keyMap) +{ + if(keyMap >= 0 && keyMap < VOICE_MAX) + { + return (char*)g_VoiceKeyMap[keyMap][g_SvrMode]; + } + else + { + LOG_EX(LOG_Error, "Unknown KeyMap Type: %s(%d)\n", g_KeyMapStr[keyMap], keyMap); + return ""; + } +} + +static PDBUS_MSG_PACK __dusOnMsg(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ + return NULL; +} + +static void uvLoopProc(void *pParams) +{ + RunUVLoop(GetDBusDefaultLoop()); + pthread_detach(pthread_self()); +} + +void ServerManagerInit(void) +{ + int ret = 0; + uv_thread_t uvThread; + LOG_EX(LOG_Warn, "+++++++++++++++++++++++System Uninit\n"); + + DBusConnection* pBus = DBusWithLibuvInit(GetDBusDefaultLoop(), + g_pModInfoTable[MODULE_SKINS].modAliase, + __dusOnMsg, + NULL, + NULL, //KeyEventCb, + &ret); + + if(pBus == NULL) + { + LOG_EX(LOG_Error, "DBusWithLibuvInit Error: %d\n", ret); + return; + } + + uv_thread_create(&uvThread, uvLoopProc, NULL); +} diff --git a/Framework/Timer/timer.c b/Framework/Timer/timer.c new file mode 100644 index 0000000..eb019b0 --- /dev/null +++ b/Framework/Timer/timer.c @@ -0,0 +1,769 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" + +#define TIMER_TIMEOUT (200) + +#define IS_LEAP_YEAR(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +static unsigned char g_DayOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +typedef struct +{ + void* pUserData; + OnAlarmTimer pOnAlarmCb; + unsigned int alarmId; + + struct tm setDateTime; + int setWeekDay; + unsigned int repeatMode; + + struct tm onDateTime; + time_t onTimestamp; + unsigned int timerPriority; + + UT_hash_handle hh; ///< UT Hash handle +} ALARM_ITEM_DATA, *PALARM_ITEM_DATA; + +static uv_timer_t g_uvTimer; +static unsigned int g_iAlarmId = 1; +static struct tm g_LocalTime; +static time_t g_TimeStamp; +static uv_loop_t* g_pMainLoop = NULL; +static uv_rwlock_t g_uvHashRwLock; +static PALARM_ITEM_DATA g_TimerTbl = NULL; + +const char* DumpTimerRepeatModeString(int mode) +{ + switch(mode & 0xFF) + { + case REPEAT_MODE_NONE: return "NONE"; + case REPEAT_MODE_EVERY_DAY: return "EVERY_DAY"; + case REPEAT_MODE_WORKDAY: return "WORKDAY"; + case REPEAT_MODE_HOLIDAY: return ("REPEAT_MODE_HOLIDAY"); + case REPEAT_MODE_WEEKEND: return "WEEKEND"; + case REPEAT_MODE_WEEKDAY: return "WEEKDAY"; + case REPEAT_MODE_EVERY_MONTH_DAY: return "EVERY_MONTH_DAY"; + case REPEAT_MODE_EVERY_YEAR_DAY: return "EVERY_YEAR_DAY"; + case REPEAT_MODE_EVERY_TIME: return ("EVERY_TIME"); + case REPEAT_MODE_MONTH_LAST_DAY: return "REPEAT_MODE_MONTH_LAST_DAY"; + default: return ("Unknown Mode"); + } +} + +static int __timestampSort(PALARM_ITEM_DATA p1, PALARM_ITEM_DATA p2) +{ + if(p1->onTimestamp == p2->onTimestamp) + { + return (p2->timerPriority - p1->timerPriority); + } + else + { + return (p1->onTimestamp - p2->onTimestamp); + } +} + +static int __getNextOnTimestamp(PALARM_ITEM_DATA pInfo) +{ + int ret; + struct tm setTime; + time_t timestamp; + + if(pInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + if(pInfo->repeatMode == REPEAT_MODE_NONE) + { + pInfo->onTimestamp = 0; + return (-ERR_INPUT_PARAMS); + } + + timestamp = pInfo->onTimestamp + 24 * 3600; + pInfo->onTimestamp = timestamp; + localtime_r(×tamp, &setTime); + + switch(pInfo->repeatMode) + { + case REPEAT_MODE_EVERY_DAY: + localtime_r(×tamp, &pInfo->onDateTime); + break; + + case REPEAT_MODE_WORKDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 0); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_HOLIDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 1); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_WEEKEND: + while(setTime.tm_wday != 0 && setTime.tm_wday != 6) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + + case REPEAT_MODE_WEEKDAY: + if(pInfo->setDateTime.tm_wday == 0) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + else if(pInfo->setDateTime.tm_wday & (1 << 7)) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + + while(((1 << setTime.tm_wday) & pInfo->setDateTime.tm_wday) == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + + break; + + case REPEAT_MODE_EVERY_TIME: + timestamp = mktime(&g_LocalTime); + + if(pInfo->setDateTime.tm_hour > 0) + { + timestamp += pInfo->setDateTime.tm_hour * 3600; + } + + if(pInfo->setDateTime.tm_min > 0) + { + timestamp += pInfo->setDateTime.tm_min * 60; + } + + if(pInfo->setDateTime.tm_sec > 0) + { + timestamp += pInfo->setDateTime.tm_sec; + } + + localtime_r(×tamp, &pInfo->onDateTime); + pInfo->onTimestamp = timestamp; + break; + + case REPEAT_MODE_MONTH_LAST_DAY: + if(pInfo->onDateTime.tm_mon < 11) + { + pInfo->onDateTime.tm_mon++; + } + else + { + pInfo->onDateTime.tm_mon = 0; + pInfo->onDateTime.tm_year++; + } + + pInfo->onDateTime.tm_mday = g_DayOfMonth[pInfo->onDateTime.tm_mon]; + if(IS_LEAP_YEAR(pInfo->onDateTime.tm_year) && (pInfo->onDateTime.tm_mon == 1)) + { + pInfo->onDateTime.tm_mday += 1; + } + + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + } + + return (0); +} + +static int __getOnTimestamp(PALARM_ITEM_DATA pInfo) +{ + int ret = 0; + struct tm setTime; + time_t timestamp; + + if(pInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + if(pInfo->setDateTime.tm_hour == -1) + { + pInfo->onDateTime.tm_hour = g_LocalTime.tm_hour; + } + else + { + pInfo->onDateTime.tm_hour = pInfo->setDateTime.tm_hour; + } + + if(pInfo->setDateTime.tm_min == -1) + { + pInfo->onDateTime.tm_min = g_LocalTime.tm_min; + } + else + { + pInfo->onDateTime.tm_min = pInfo->setDateTime.tm_min; + } + + if(pInfo->setDateTime.tm_sec == -1) + { + pInfo->onDateTime.tm_sec = g_LocalTime.tm_sec; + } + else + { + pInfo->onDateTime.tm_sec = pInfo->setDateTime.tm_sec; + } + + switch(pInfo->repeatMode) + { + case REPEAT_MODE_EVERY_MONTH_DAY: + case REPEAT_MODE_EVERY_YEAR_DAY: + case REPEAT_MODE_NONE: + if(pInfo->setDateTime.tm_year == -1) + { + pInfo->onDateTime.tm_year = g_LocalTime.tm_year; + } + else + { + pInfo->onDateTime.tm_year = pInfo->setDateTime.tm_year; + } + + if(pInfo->setDateTime.tm_mon == -1) + { + pInfo->onDateTime.tm_mon = g_LocalTime.tm_mon; + } + else + { + pInfo->onDateTime.tm_mon = pInfo->setDateTime.tm_mon; + } + + if(pInfo->setDateTime.tm_mday == -1) + { + pInfo->onDateTime.tm_mday = g_LocalTime.tm_mday; + } + else + { + pInfo->onDateTime.tm_mday = pInfo->setDateTime.tm_mday; + } + break; + + case REPEAT_MODE_EVERY_DAY: + case REPEAT_MODE_WORKDAY: + case REPEAT_MODE_WEEKEND: + case REPEAT_MODE_WEEKDAY: + case REPEAT_MODE_EVERY_TIME: + case REPEAT_MODE_HOLIDAY: + pInfo->onDateTime.tm_year = g_LocalTime.tm_year; + pInfo->onDateTime.tm_mon = g_LocalTime.tm_mon; + pInfo->onDateTime.tm_mday = g_LocalTime.tm_mday; + break; + case REPEAT_MODE_MONTH_LAST_DAY: + pInfo->onDateTime.tm_year = g_LocalTime.tm_year; + pInfo->onDateTime.tm_mon = g_LocalTime.tm_mon; + pInfo->onDateTime.tm_mday = g_DayOfMonth[g_LocalTime.tm_mon]; + if(IS_LEAP_YEAR(g_LocalTime.tm_year) && (g_LocalTime.tm_mon == 1)) + { + pInfo->onDateTime.tm_mday += 1; + } + break; + } + + pInfo->onDateTime.tm_wday = g_LocalTime.tm_wday; + pInfo->onDateTime.tm_yday = g_LocalTime.tm_yday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + + if(pInfo->repeatMode == REPEAT_MODE_NONE) + { + return (0); + } + + memcpy(&setTime, &g_LocalTime, sizeof(struct tm)); + + if(mktime(&setTime) > (pInfo->onTimestamp + 1)) + { + if(pInfo->repeatMode == REPEAT_MODE_EVERY_MONTH_DAY) + { + if(pInfo->onDateTime.tm_mon < 11) + { + pInfo->onDateTime.tm_mon++; + } + else + { + pInfo->onDateTime.tm_mon = 0; + pInfo->onDateTime.tm_year++; + } + + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + return (0); + } + else if(pInfo->repeatMode == REPEAT_MODE_EVERY_YEAR_DAY) + { + pInfo->onDateTime.tm_year++; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + return (0); + } + else if(pInfo->repeatMode == REPEAT_MODE_MONTH_LAST_DAY) + { + if(pInfo->onDateTime.tm_mon < 11) + { + pInfo->onDateTime.tm_mon++; + } + else + { + pInfo->onDateTime.tm_mon = 0; + pInfo->onDateTime.tm_year++; + } + + pInfo->onDateTime.tm_mday = g_DayOfMonth[pInfo->onDateTime.tm_mon]; + if(IS_LEAP_YEAR(pInfo->onDateTime.tm_year) && (pInfo->onDateTime.tm_mon == 1)) + { + pInfo->onDateTime.tm_mday += 1; + } + + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + return (0); + } + else + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + } + + switch(pInfo->repeatMode) + { + case REPEAT_MODE_EVERY_DAY: + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + + case REPEAT_MODE_WORKDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 0); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_HOLIDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 1); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_WEEKEND: + while(setTime.tm_wday != 0 && setTime.tm_wday != 6) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + + case REPEAT_MODE_WEEKDAY: + if(pInfo->setDateTime.tm_wday == 0) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + else if(pInfo->setDateTime.tm_wday & (1 << 7)) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + + while(((1 << setTime.tm_wday) & pInfo->setDateTime.tm_wday) == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + + break; + + case REPEAT_MODE_EVERY_TIME: + timestamp = mktime(&g_LocalTime); + + if(pInfo->setDateTime.tm_hour > 0) + { + timestamp += pInfo->setDateTime.tm_hour * 3600; + } + + if(pInfo->setDateTime.tm_min > 0) + { + timestamp += pInfo->setDateTime.tm_min * 60; + } + + if(pInfo->setDateTime.tm_sec > 0) + { + timestamp += pInfo->setDateTime.tm_sec; + } + + localtime_r(×tamp, &pInfo->onDateTime); + pInfo->onTimestamp = timestamp; + break; + } + + return (0); +} + +static void __timerout200msCb(uv_timer_t *pTimer) +{ + PALARM_ITEM_DATA pItem = NULL, pTemp = NULL; + + // upgrade current time and timestamp + g_TimeStamp = time((time_t*)NULL); + localtime_r(&g_TimeStamp, &g_LocalTime); + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ITER(hh, g_TimerTbl, pItem, pTemp) + { + // cleanup out of time more than 10s timer + if(g_TimeStamp - pItem->onTimestamp > 10) + { + LOG_EX(LOG_Warn, "Remove out of time timer: %u, %ld, %ld\n", pItem->alarmId, g_TimeStamp, pItem->onTimestamp); + HASH_DEL(g_TimerTbl, pItem); + free(pItem); + + continue; + } + + // timer not on time + if(pItem->onTimestamp != g_TimeStamp) + { + break; + } + + // timer on time, call callback + if(pItem->pOnAlarmCb) + { + pItem->pOnAlarmCb(pItem->alarmId, g_TimeStamp, pItem->pUserData); + } + + //LOG_EX(LOG_Debug, "Timer %d Alarming..................\n", pItem->alarmId); + + // cleanup not repeat timer + if(pItem->repeatMode == REPEAT_MODE_NONE) + { + HASH_DEL(g_TimerTbl, pItem); + free(pItem); + } + else + { + // calc next on time + int ret = __getNextOnTimestamp(pItem); + + if(ret != 0 || pItem->onTimestamp == 0) + { + // some error, remove it + LOG_EX(LOG_Error, "Timer %d repeat error: ret = %d, timestamp = %u\n", pItem->alarmId, ret, pItem->onTimestamp); + HASH_DEL(g_TimerTbl, pItem); + free(pItem); + } + else + { + // resort table by upgrade timestamp + HASH_SORT(g_TimerTbl, __timestampSort); + + // show log + LOG_EX(LOG_Debug, "Readd Timer: %u at [%04u-%02u-%02u %02u:%02u:%02u], repMode = %s, Timestamp = %u\n", + pItem->alarmId, + pItem->onDateTime.tm_year + 1900, + pItem->onDateTime.tm_mon + 1, + pItem->onDateTime.tm_mday, + pItem->onDateTime.tm_hour, + pItem->onDateTime.tm_min, + pItem->onDateTime.tm_sec, + DumpTimerRepeatModeString(pItem->repeatMode), + pItem->onTimestamp); + } + } + } + uv_rwlock_wrunlock(&g_uvHashRwLock); +} + +int AlarmTimerInit(uv_loop_t* pLoop) +{ + g_pMainLoop = pLoop; + uv_rwlock_init(&g_uvHashRwLock); + uv_timer_init(g_pMainLoop, &g_uvTimer); + + g_TimeStamp = time((time_t*)NULL); + localtime_r(&g_TimeStamp, &g_LocalTime); + + g_iAlarmId = 1; + + uv_timer_start(&g_uvTimer, __timerout200msCb, 0, TIMER_TIMEOUT); +} + +int AlarmTimerCleanup(void) +{ + uv_timer_stop(&g_uvTimer); + uv_rwlock_destroy(&g_uvHashRwLock); + + if(g_pMainLoop != NULL) + { + AlarmTimerInit(g_pMainLoop); + } +} + +int AlarmTimerRemove(unsigned int tmId) +{ + PALARM_ITEM_DATA pItem = NULL; + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_INT(g_TimerTbl, &tmId, pItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pItem == NULL) + { + LOG_EX(LOG_Error, "Can't find item: %u\n", tmId); + return (-ERR_NO_ITEMS); + } + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_DEL(g_TimerTbl, pItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + free(pItem); + + return (tmId); +} + +unsigned int AlarmTimerAdd(int year, + int month, + int day, + int hour, + int minute, + int second, + int weekDay, + int repMode, + OnAlarmTimer pOnTimerCb, + int priority, + void *pUserData, + int *pError) +{ + int et; + PALARM_ITEM_DATA pAlarmData = NULL; + + if(pOnTimerCb == NULL) + { + LOG_EX(LOG_Error, "Input Params Error: pOnTimerCb = %p\n", pOnTimerCb); + if(pError) + { + *pError = -ERR_INPUT_PARAMS; + } + + return (0xFFFFFFFF); + } + + g_TimeStamp = time((time_t*)NULL); + localtime_r(&g_TimeStamp, &g_LocalTime); + + pAlarmData = (PALARM_ITEM_DATA)malloc(sizeof(ALARM_ITEM_DATA)); + + if(pAlarmData == NULL) + { + LOG_EX(LOG_Error, "Malloc Memory Error\n"); + + if(pError) + { + *pError = -ERR_MALLOC_MEMORY; + } + + return (0xFFFFFFFF); + } + + memset(pAlarmData, 0, sizeof(ALARM_ITEM_DATA)); + + // save input params + pAlarmData->setDateTime.tm_year = year; + pAlarmData->setDateTime.tm_mon = month; + pAlarmData->setDateTime.tm_mday = day; + pAlarmData->setDateTime.tm_hour = hour; + pAlarmData->setDateTime.tm_min = minute; + pAlarmData->setDateTime.tm_sec = second; + pAlarmData->setDateTime.tm_wday = weekDay; + + pAlarmData->repeatMode = repMode; + pAlarmData->pOnAlarmCb = pOnTimerCb; + pAlarmData->pUserData = pUserData; + pAlarmData->timerPriority = priority; + + // get timer on time + __getOnTimestamp(pAlarmData); + + // check on time + et = pAlarmData->onTimestamp - mktime(&g_LocalTime); + + if(et < -1 || pAlarmData->onTimestamp == 0) + { + LOG_EX(LOG_Debug, "Add Timer Error: [%04u-%02u-%02u %02u:%02u:%02u], repMode = %s(%u), %d, %u/%u\n", + pAlarmData->setDateTime.tm_year + 1900, + pAlarmData->setDateTime.tm_mon + 1, + pAlarmData->setDateTime.tm_mday, + pAlarmData->setDateTime.tm_hour, + pAlarmData->setDateTime.tm_min, + pAlarmData->setDateTime.tm_sec, + DumpTimerRepeatModeString(repMode), repMode, + et, pAlarmData->onTimestamp, mktime(&g_LocalTime)); + + if(pError) + { + *pError = -ERR_INPUT_PARAMS; + } + + return (0xFFFFFFFF); + } + + if(pError) + { + *pError = 0; + } + + // upgrade time global id + pAlarmData->alarmId = __sync_fetch_and_add(&g_iAlarmId, 1); + + // save new timer to hash table, and sort it by timestamp + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_INT(g_TimerTbl, alarmId, pAlarmData); + HASH_SORT(g_TimerTbl, __timestampSort); + uv_rwlock_wrunlock(&g_uvHashRwLock); + + LOG_EX(LOG_Debug, "Add: %u [%04u-%02u-%02u %02u:%02u:%02u] at [%04u-%02u-%02u %02u:%02u:%02u], repMode = %s, priority = %d, Timestamp = %u\n", + pAlarmData->alarmId, + (pAlarmData->setDateTime.tm_year == -1) ? 1900 : pAlarmData->setDateTime.tm_year + 1900, + (pAlarmData->setDateTime.tm_mon == -1) ? 0 : pAlarmData->setDateTime.tm_mon + 1, + (pAlarmData->setDateTime.tm_mday == -1) ? 0 : pAlarmData->setDateTime.tm_mday, + (pAlarmData->setDateTime.tm_hour == -1) ? 0 : pAlarmData->setDateTime.tm_hour, + (pAlarmData->setDateTime.tm_min == -1) ? 0 : pAlarmData->setDateTime.tm_min, + (pAlarmData->setDateTime.tm_sec == -1) ? 0 : pAlarmData->setDateTime.tm_sec, + pAlarmData->onDateTime.tm_year + 1900, + pAlarmData->onDateTime.tm_mon + 1, + pAlarmData->onDateTime.tm_mday, + pAlarmData->onDateTime.tm_hour, + pAlarmData->onDateTime.tm_min, + pAlarmData->onDateTime.tm_sec, + DumpTimerRepeatModeString(repMode), + pAlarmData->timerPriority, + pAlarmData->onTimestamp); + + return (pAlarmData->alarmId); +} + + diff --git a/Framework/WireshartScript/log_pv1.lua b/Framework/WireshartScript/log_pv1.lua new file mode 100644 index 0000000..c5edfdd --- /dev/null +++ b/Framework/WireshartScript/log_pv1.lua @@ -0,0 +1,93 @@ +pv1_log_proto = Proto("PV1_Log", "PV1 ES2 Log Protocol") + +log_level_str = +{ + [ 1 ] = "[F]", + [ 2 ] = "[E]", + [ 4 ] = "[W]", + [ 8 ] = "[D]", + [ 16 ] = "[I]", + [ 32 ] = "[T]", + [ 64 ] = "[I]", + [ 128 ] = "[V]", + [ 256 ] = "[S]", + [ 512 ] = "[U]", + [ 0xFFFFFFFF ] = "[A]", +} + +local log_content = ProtoField.string("logContent", "Message:\t") +local log_Seq = ProtoField.uint16("logSeq", "Sequence: \t", base.DEC) +local log_pid = ProtoField.uint32("logPid", "PID: \t\t", base.DEC) +local log_datetime = ProtoField.string("logDateTime", "DateTime:\t\t") +local log_time = ProtoField.string("logTime", "Date:\t\t") +local log_level = ProtoField.uint32("logLevel", "Level: \t\t", base.DEC, log_level_str) + +pv1_log_proto.fields = { +log_Seq, log_content, log_pid, log_datetime, log_level +} + +function pv1_log_proto.dissector(buffer, pinfo, tree) + pinfo.cols.protocol:set("LOG") + local offset = 0 + local buf_len = buffer:len() + local logInfoTree = tree:add(pv1_log_proto, buffer(0, 18), "Log Message Information") + + logInfoTree:add(log_Seq, buffer(offset, 2)) + offset = offset + 2 + + local l_pid = buffer(offset, 4):uint() + logInfoTree:add(log_pid, buffer(offset, 4)) + offset = offset + 4 + + local l_second = buffer(offset, 4):uint() + offset = offset + 4 + + local l_nsecond = buffer(offset, 4):uint() + offset = offset + 4 + + logInfoTree:add(log_datetime, "[" .. os.date("%c", l_second) .. "." .. string.format("%03d", l_nsecond / 1000) .. "]") + + local l_level = buffer(offset, 4):uint() + local l_lvStr + + if l_level == 1 then + l_lvStr = "F" + elseif l_level == 2 then + l_lvStr = "E" + elseif l_level == 4 then + l_lvStr = "W" + elseif l_level == 8 then + l_lvStr = "D" + elseif l_level == 16 then + l_lvStr = "I" + elseif l_level == 32 then + l_lvStr = "T" + elseif l_level == 64 then + l_lvStr = "C" + elseif l_level == 128 then + l_lvStr = "V" + elseif l_level == 256 then + l_lvStr = "S" + elseif l_level == 0xFFFFFFFF then + l_lvStr = "A" + else + l_lvStr = "U" + end + + logInfoTree:add(log_level, buffer(offset, 4)) + offset = offset + 4 + + local logInfo = buffer(offset, buf_len - 19):string() + local logMsgTree = tree:add(pv1_log_proto, buffer(18, buf_len - 18), "Log Message Content") + logMsgTree:add(log_content, logInfo) + + if buffer(buf_len - 1, 1):string() == '\n' then + pinfo.cols.info:set("{" .. tostring(l_pid) .. "} [" .. os.date("%X", l_second) .. "." .. string.format("%03d", l_nsecond / 1000) .. "] [" .. tostring(l_lvStr) .. "] " .. buffer(18, buf_len - 19):string()) + else + pinfo.cols.info:set("{" .. tostring(l_pid) .. "} [" .. os.date("%X", l_second) .. "." .. string.format("%03d", l_nsecond / 1000) .. "] [" .. tostring(l_lvStr) .. "] " .. buffer(18, buf_len - 18):string()) + end +end + +local pv1_log_udp_port_table = DissectorTable.get("udp.port") +--local pv1_log_port = 10000 +pv1_log_udp_port_table:add("10000-10020", pv1_log_proto) diff --git a/Framework/libuvEngine/libuv_dbus.c b/Framework/libuvEngine/libuv_dbus.c new file mode 100644 index 0000000..f99ed88 --- /dev/null +++ b/Framework/libuvEngine/libuv_dbus.c @@ -0,0 +1,2308 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" +#include "json_struct.h" +#include "inet_api.h" +#include "crypto.h" +#include "server_addr.h" +#ifdef ENABLE_COUNT_DEBUG +#include "monitor.h" +#endif + +#ifdef ENABLE_COUNT_DEBUG +#define MON_MSG_PROC_STAT ("Message Process") +#define MON_MSG_BST_PROC_STAT ("Boardcast Message Process") +#define MON_USER_MSG_PROC_STAT ("User Message Process") +#define MON_USER_MSG_BST_PROC_STAT ("User Boardcast Message Process") +#endif + +typedef void (*OnDBusSendError)(int, void*); +static void uvOpenKeyEventCb(uv_fs_t* puvFs); + +typedef struct LOOP_TASK_ARRAY +{ + uv_loop_t* pLoop; + int isRunning; + + struct LOOP_TASK_ARRAY *next, *prev; +} *PLOOP_TASK_ARRAY; + +typedef struct +{ + key_t shmKey; +// uint32_t tarMask; +// uint32_t tmSend; + uint32_t msgSize; + + UT_hash_handle hh; ///< UT Hash handle +} UV_SHM_ITEM, *PUV_SHM_ITEM; + +typedef struct +{ + long int msgMask; + unsigned char pMsgContext[0]; +} DBUS_MSG_DATA, *PDBUS_MSG_DATA; + +typedef struct +{ + DBusConnection* pBus; + const char* pBusName; + uint32_t busCmd; + JSON_ENGINE_TYPE type; + void* pStruct; + int iSize; + OnDBusAsyncSendTo cbSendTo; + int enBase64; +} DBUS_ASYNC_PARAMS, *PDBUS_ASYNC_PARAMS; + +static LIBUV_DBUS_PARAMS g_LibuvDBusParam; + +static uv_idle_t g_uvIdleHandle; +static uv_timer_t g_uvTimerPing; +static uv_fs_t g_uvKeyEvent; +static WORKDAY_INFO g_workDayArray; +static WIFI_STATUS g_WifiConnStatus = WIFI_CONNECTED; +static PDBUS_MSG_PROC g_pMsgProcList = NULL; +static uv_rwlock_t g_uvLoopRwLock; +static PLOOP_TASK_ARRAY g_LoopArray = NULL; +static unsigned int g_EnHBLExit = TRUE; +static uv_rwlock_t g_uvMsgProcRwLock; + +#if USED_SHM_TO_DBUS +static uv_rwlock_t g_uvShmHashRwLock; +static PUV_SHM_ITEM g_pShmTbl = NULL; + +static void __addShmIdToTable(key_t shmKey, uint32_t tmSend, uint32_t tarMask, uint32_t msgSize) +{ + PUV_SHM_ITEM pItem = NULL; + + uv_rwlock_rdlock(&g_uvShmHashRwLock); + HASH_FIND_INT(g_pShmTbl, &shmKey, pItem); + uv_rwlock_rdunlock(&g_uvShmHashRwLock); + + if(pItem == NULL) + { + pItem = (PUV_SHM_ITEM)malloc(sizeof(UV_SHM_ITEM)); + + memset(pItem, 0, sizeof(UV_SHM_ITEM)); + pItem->shmKey = shmKey; + + uv_rwlock_wrlock(&g_uvShmHashRwLock); + HASH_ADD_INT(g_pShmTbl, shmKey, pItem); + uv_rwlock_wrunlock(&g_uvShmHashRwLock); + } + + pItem->tmSend = tmSend; + pItem->tarMask = tarMask; + pItem->msgSize = msgSize; +} + +static void __removeReqIdFromTable(key_t shmKey) +{ + PUV_SHM_ITEM pItem = NULL; + + uv_rwlock_rdlock(&g_uvShmHashRwLock); + HASH_FIND_INT(g_pShmTbl, &shmKey, pItem); + uv_rwlock_rdunlock(&g_uvShmHashRwLock); + + if(pItem != NULL) + { + uv_rwlock_wrlock(&g_uvShmHashRwLock); + HASH_DEL(g_pShmTbl, pItem); + uv_rwlock_wrunlock(&g_uvShmHashRwLock); + free(pItem); + } +} + +static void __uvShmTblTaskThreadCb(void *pParam) +{ + struct timeval tv; + PUV_SHM_ITEM pItem = NULL, pTmpItem = NULL; + + while(TRUE) + { + gettimeofday(&tv, NULL); + + HASH_ITER(hh, g_pShmTbl, pItem, pTmpItem) + { + int msgId; + + if(tv.tv_sec - pItem->tmSend <= 60) + { + continue; + } + + msgId = shmget((key_t)pItem->shmKey, pItem->msgSize, 0666 | IPC_CREAT); + + if(msgId == -1) + { + continue; + } + + // Not Boardcast Message + if((pItem->tarMask & 0xFFFF0000) != 0xFFFF0000) + { + PDBUS_MSG_DATA pData = (PDBUS_MSG_DATA)shmat(msgId, NULL, 0); + + if(pData == (void*)-1) + { + continue; + } + + // Nevery Recevied By Anyone + if(pData->msgMask == pItem->tarMask) + { + continue; + } + + shmdt(pData); + shmctl(msgId, IPC_RMID, 0); + __removeReqIdFromTable((key_t)pItem->shmKey); + } + } + + sleep(1); + } + + pthread_detach(pthread_self()); +} +#endif + +PLIBUV_DBUS_PARAMS DBusLibuvGetRuntime(void) +{ + if(g_LibuvDBusParam.pBus == NULL || g_LibuvDBusParam.pLoop == NULL) + { + return NULL; + } + + return &g_LibuvDBusParam; +} + +MODULE_NAME DBusLibGetModName(void) +{ + return g_LibuvDBusParam.modName; +} + +uv_loop_t* GetDBusDefaultLoop(void) +{ + if(g_LibuvDBusParam.pBus == NULL || g_LibuvDBusParam.pLoop == NULL) + { + return uv_default_loop(); + } + + return g_LibuvDBusParam.pLoop; +} + +static void uvAsyncCb(uv_async_t* pAsync) +{ + DBusConnection* pConn = (DBusConnection*)pAsync->data; + dbus_connection_read_write(pConn, 0); + + while(dbus_connection_dispatch(pConn) == DBUS_DISPATCH_DATA_REMAINS); +} + +static void uvTimeoutCb(uv_timer_t* pTimer) +{ + DBusTimeout* timeout = (DBusTimeout*)pTimer->data; + dbus_timeout_handle(timeout); +} + +static void uvPollCb(uv_poll_t* pPoll, int status, int events) +{ + DBusWatch* watch = (DBusWatch*)pPoll->data; + unsigned int uvFlags = 0; + + if(events & UV_READABLE) + { + uvFlags |= DBUS_WATCH_READABLE; + } + + if(events & UV_WRITABLE) + { + uvFlags |= DBUS_WATCH_WRITABLE; + } + + dbus_watch_handle(watch, uvFlags); +} + +static void uvIdleCb(uv_idle_t* phuvIdle) +{ + usleep(1000); +} + +static void uvFsAccessCb(uv_fs_t* puvFs) +{ + if(puvFs->result != 0) + { + IHW_EnableLogLevel((LOG_LEVEL)(LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info), 1); + } + + uv_fs_req_cleanup(puvFs); + free(puvFs); +} + +static void uvReadKeyEventCb(uv_fs_t* puvFs) +{ + if(puvFs->result < 0) + { + uv_fs_req_cleanup(puvFs); + return; + } + else if(puvFs->result == 0) + { + uv_fs_t uvClose; + uv_fs_close(g_LibuvDBusParam.pLoop, &uvClose, g_uvKeyEvent.result, NULL); + } + else + { + uv_buf_t* puvIov = (uv_buf_t*)puvFs->data; + + if(puvIov->len == sizeof(struct input_event)) + { + struct input_event* pKeyEvt = (struct input_event*)puvIov->base; + + if(g_LibuvDBusParam.onKeyCb) + { +// LOG_EX(LOG_Info, "type = %u, code = %u, value = %u\n", pKeyEvt->type, pKeyEvt->code, pKeyEvt->value); + g_LibuvDBusParam.onKeyCb(pKeyEvt->type, pKeyEvt->code, pKeyEvt->value); + } + } + } + + uv_fs_req_cleanup(puvFs); + + usleep(1000); + uv_fs_open(g_LibuvDBusParam.pLoop, &g_uvKeyEvent, R16_TINA_KEY_EVENT_PATH, O_RDONLY, 0, uvOpenKeyEventCb); +} + +static void uvOpenKeyEventCb(uv_fs_t* puvFs) +{ + static uv_buf_t uvIoV; + static struct input_event keyEvent; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "Open Key Event File[%s] Error: %d\n", R16_TINA_KEY_EVENT_PATH, puvFs->result); + uv_fs_req_cleanup(puvFs); + return; + } + + uvIoV = uv_buf_init((void*)&keyEvent, sizeof(struct input_event)); + puvFs->data = (void*)&uvIoV; + + uv_fs_read(g_LibuvDBusParam.pLoop, &g_uvKeyEvent, puvFs->result, &uvIoV, 1, -1, uvReadKeyEventCb); + uv_fs_req_cleanup(puvFs); + + return; +} + +static void DBusAsyncFreeCb(void* pData) +{ + uv_async_t* pAsync = (uv_async_t*)pData; + + if(pAsync) + { + pAsync->data = NULL; + uv_close((uv_handle_t*)pAsync, (uv_close_cb)free); + } +} + +static void DBusPollFreeCb(void* pData) +{ + uv_poll_t* pPoll = (uv_poll_t*)pData; + + if(pPoll) + { + pPoll->data = NULL; + + uv_ref((uv_handle_t*)pPoll); + uv_poll_stop(pPoll); + uv_close((uv_handle_t*)pPoll, (uv_close_cb)free); + } +} + +static dbus_bool_t DBusAddWatchCb(DBusWatch* pWatch, void* pData) +{ + static int isCreate = 0; + int fdDBus, uvPollFlags = 0; + unsigned int dBusWatchFlags; + uv_poll_t* pPoll = NULL; + uv_loop_t* pLoop = (uv_loop_t*)pData; + + if(!dbus_watch_get_enabled(pWatch) + || dbus_watch_get_data(pWatch) != NULL + || isCreate != 0) + { + return TRUE; + } + + fdDBus = dbus_watch_get_unix_fd(pWatch); + dBusWatchFlags = dbus_watch_get_flags(pWatch); + + if(dBusWatchFlags & DBUS_WATCH_READABLE) + { + uvPollFlags |= UV_READABLE; + } + + if(dBusWatchFlags & DBUS_WATCH_WRITABLE) + { + uvPollFlags |= UV_WRITABLE; + } + + pPoll = (uv_poll_t*)malloc(sizeof(uv_poll_t)); + pPoll->data = (void*)pWatch; + + uv_poll_init(pLoop, pPoll, fdDBus); + uv_poll_start(pPoll, uvPollFlags, uvPollCb); + LOG_EX(LOG_Debug, "Create POOL by FD: %d\n", fdDBus); + + uv_unref((uv_handle_t*)pPoll); + + dbus_watch_set_data(pWatch, (void*)pPoll, DBusPollFreeCb); + + isCreate = 1; + return TRUE; +} + +static void DBusRemoveWatchCb(DBusWatch* pWatch, void* pData) +{ + uv_poll_t* pPoll = (uv_poll_t*)dbus_watch_get_data(pWatch); + + if(pPoll) + { + dbus_watch_set_data(pWatch, NULL, NULL); + } +} + +static void DBusNotifyWatchCb(DBusWatch* pWatch, void* pData) +{ + if(dbus_watch_get_enabled(pWatch)) + { + DBusAddWatchCb(pWatch, pData); + } + else + { + DBusRemoveWatchCb(pWatch, pData); + } +} + +static void DBusTimeoutFreeCb(void* pData) +{ + uv_timer_t* pTimer = (uv_timer_t*)pData; + + if(pTimer == NULL) + { + return; + } + + pTimer->data = NULL; + uv_timer_stop(pTimer); + uv_unref((uv_handle_t*)pTimer); + uv_close((uv_handle_t*)pTimer, (uv_close_cb)free); +} + +static dbus_bool_t DBusAddTimeoutCb(DBusTimeout* pTimeout, void* pData) +{ + uv_timer_t* pTimer = NULL; + uv_loop_t* pLoop = (uv_loop_t*)pData; + + if(!dbus_timeout_get_enabled(pTimeout) + || dbus_timeout_get_data(pTimeout) != NULL) + { + return TRUE; + } + + pTimer = (uv_timer_t*)malloc(sizeof(uv_timer_t)); + pTimer->data = pTimeout; + + uv_timer_init(pLoop, pTimer); + uv_timer_start(pTimer, uvTimeoutCb, dbus_timeout_get_interval(pTimeout), 0); + + dbus_timeout_set_data(pTimeout, (void*)pTimer, DBusTimeoutFreeCb); + return TRUE; +} + +static void DBusRemoveTimeoutCb(DBusTimeout* pTimeout, void* pData) +{ + uv_timer_t* pTimer = (uv_timer_t*)dbus_timeout_get_data(pTimeout); + + if(pTimer) + { + dbus_timeout_set_data(pTimeout, NULL, NULL); + } +} + +static void DBusNotifyTimeoutCb(DBusTimeout* pTimeout, void* pData) +{ + if(dbus_timeout_get_enabled(pTimeout)) + { + DBusAddTimeoutCb(pTimeout, pData); + } + else + { + DBusRemoveTimeoutCb(pTimeout, pData); + } +} + +static void DBusWakeupMainLoopCb(void* pData) +{ + uv_async_t* pAsync = (uv_async_t*)pData; + uv_async_send(pAsync); +} + +static void FreeDBusOnMsgCb(uv_work_t* pWork, int status) +{ + PDBUS_MSG_PACK pMsg = (PDBUS_MSG_PACK)pWork->data; + + if(pMsg) + { + free(pMsg); + } + free(pWork); +} + +#if 0 +static void DBusOnBoardcastMsgWorkCb(uv_work_t* pWork) +#else +static int DBusOnBoardcastMsgWorkCb(PDBUS_MSG_PACK pMsg) +#endif +{ + + pMsg->isBstMsg = TRUE; + // Message context on dbus message pad + if(pMsg->msgSize < DBUS_MSG_MAX_PAD_SIZE) + { + if(pMsg->busCmd == CMD_WIFI_STATE_NTF) + { + int err = 0; + PWIFI_STATUS_PRO pWifiInfo = (PWIFI_STATUS_PRO)Json2Struct((const char *)pMsg->pMsg, + JSON_WIFI_STATUS_NOTIFY, FALSE, &err); + + //LOG_EX(LOG_Debug, "pWifiInfo: %s\n", pMsg->pMsg); + if(pWifiInfo && err == 0) + { + if(pWifiInfo->wifi_evt == 0) + { + g_WifiConnStatus = WIFI_CONNECTED; + } + else + { + g_WifiConnStatus = WIFI_DISCONNECTED; + } + } + + if(pWifiInfo) + { + free(pWifiInfo); + } + } + else if(pMsg->busCmd == CMD_CFG_UPG_NOTIFY) + { + } + else if(pMsg->busCmd == CMD_LOG_CONFIG) + { + int err = 0; + PLOG_CFG_PROTOCOL pCfgInfo = (PLOG_CFG_PROTOCOL)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_LOG_CFG_CMD, FALSE, &err); + + //LOG_EX(LOG_Debug, "pCfgInfo: %s\n", pMsg->pMsg); + if(pCfgInfo && err == 0) + { + UpgradLogConfigure(pCfgInfo); + } + + if(pCfgInfo) + { + free(pCfgInfo); + } + } + else if(pMsg->busCmd != CMD_MISC_PING) + { + pMsg->msgDests = 0xFFFFFFFF; + if(g_LibuvDBusParam.onMsgCb) + { + g_LibuvDBusParam.onMsgCb(g_LibuvDBusParam.pLoop, g_LibuvDBusParam.pBus, pMsg); + } + + return 1; + } + } + + return 0; +} + +#if 0 +static void DBusOnMsgWorkAPICb(uv_work_t* pWork) +#else +static int DBusOnMsgWorkAPICb(PDBUS_MSG_PACK pMsg) +#endif +{ + int err = 0; + + pMsg->isBstMsg = FALSE; + + // Message context on dbus message pad + if(pMsg->msgSize < DBUS_MSG_MAX_PAD_SIZE) + { + if(pMsg->busCmd >= CMD_CFG_ADD_REQ && pMsg->busCmd < CMD_CFG_UPG_NOTIFY) + { + OnCfgMsgProcess(pMsg->msgSrc, pMsg->busCmd, pMsg->pMsg); + } + else if(pMsg->busCmd == CMD_LOG_CONFIG) + { + PLOG_CFG_PROTOCOL pCfgInfo = (PLOG_CFG_PROTOCOL)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_LOG_CFG_CMD, FALSE, &err); + + //LOG_EX(LOG_Debug, "pCfgInfo: %s\n", pMsg->pMsg); + if(pCfgInfo && err == 0) + { + UpgradLogConfigure(pCfgInfo); + } + + if(pCfgInfo) + { + free(pCfgInfo); + } + } + else if(pMsg->busCmd == CMD_WORKDAY_DB_RSP) + { + PWORKDAY_INFO pWorkDayInfo = (PWORKDAY_INFO)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_WORKDAY_REQ, FALSE, &err); + + //LOG_EX(LOG_Debug, "WorkDay: %s\n", pMsg->pMsg); + if(pWorkDayInfo && err == 0) + { + memcpy(&g_workDayArray, pWorkDayInfo, sizeof(WORKDAY_INFO)); + } + + //LOG_EX2(LOG_Debug, "Database: %s\n", pMsg->pMsg); + + if(pWorkDayInfo) + { + free(pWorkDayInfo); + } + } + else if(pMsg->busCmd != CMD_MISC_PING) + { + if(g_LibuvDBusParam.onMsgCb) + { + g_LibuvDBusParam.onMsgCb(g_LibuvDBusParam.pLoop, g_LibuvDBusParam.pBus, pMsg); + } + + return 1; + } + } + else // More than 4K size used Share Memory + { + LOG_EX(LOG_Error, "Receive Message Error Size: %d\n", pMsg->msgSize); +#if 0 + PDBUS_MSG_DATA pData = NULL; + int key = strtol(pMsg->pMsg, NULL, 10); + + int msgId = shmget((key_t)key, pMsg->msgSize, 0666 | IPC_CREAT); + + if(msgId == -1) + { + return; + } + + pData = (PDBUS_MSG_DATA)shmat(msgId, NULL, 0); + + if(pData == (void*)-1) + { + return; + } + + //print_hex_dump_bytes("send_", 2, pData, pMsg->msgSize); + + pMsg->pMsg = pData->pMsgContext; + pMsg->msgSize -= sizeof(long int); + + if(pMsg->busCmd != CMD_MISC_PING) + { + g_LibuvDBusParam.onMsgCb(g_LibuvDBusParam.pLoop, g_LibuvDBusParam.pBus, pMsg); + } + + pData->msgMask &= ~(1 << g_LibuvDBusParam.modName); + + // Cleanup Share Memory + if(pData->msgMask == 0) + { + shmctl(msgId, IPC_RMID, 0); +#if USED_SHM_TO_DBUS + __removeReqIdFromTable((key_t)key); +#endif + } + + shmdt(pData); +#endif + } + + return 0; +} + +static DBusHandlerResult DBusOnMsgCb(DBusConnection* pConn, DBusMessage* pMsg, void* user_data) +{ +#if 0 + struct timeval tmBegin, tmEnd; + long long diffTm; +#endif + DBusError error; + PDBUS_MSG_PROC pMsgProc = NULL; + + PDBUS_MSG_PACK pMsgPack = (PDBUS_MSG_PACK)malloc(sizeof(DBUS_MSG_PACK)); + + if(pMsgPack == NULL) + { + LOG_EX(LOG_Error, "Receive Message: No Memory\n"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + memset(pMsgPack, 0, sizeof(DBUS_MSG_PACK)); + + dbus_error_init(&error); + + if(dbus_message_is_signal(pMsg, DBUS_MESSAGE_INTERFACE_NAME, "Notify")) + { + if(dbus_message_get_args(pMsg, &error, + DBUS_TYPE_UINT32, &pMsgPack->msgSrc, // from + DBUS_TYPE_UINT32, &pMsgPack->msgDests, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &pMsgPack->tmTickMSec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &pMsgPack->busCmd, // command type + DBUS_TYPE_STRING, &pMsgPack->pMsg, // message context if had + DBUS_TYPE_INVALID)) + { + pMsgPack->msgSize = strlen((char*)pMsgPack->pMsg); + // reset timeout timer + if(g_LibuvDBusParam.onHblCb && pMsgPack->msgSrc != g_LibuvDBusParam.modName) + { + HeartDaemonUpgrade(pMsgPack->msgSrc); + } + + // Dispatch message except from it's self + if(pMsgPack->msgSrc != g_LibuvDBusParam.modName + && pMsgPack->msgDests & (1 << g_LibuvDBusParam.modName)) + { + if(g_LibuvDBusParam.onMsgCb == NULL) + { + pMsgProc = (PDBUS_MSG_PROC)malloc(sizeof(struct DBUS_MSG_PROC)); + + if(pMsgProc == NULL) + { + LOG_EX(LOG_Error, "Receive Message: No Memory\n"); + free(pMsgPack); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + memset(pMsgProc, 0, sizeof(struct DBUS_MSG_PROC)); + memcpy(&pMsgProc->msgContent, pMsgPack, sizeof(DBUS_MSG_PACK)); + pMsgProc->msgContent.pMsg = strdup(pMsgPack->pMsg); + pMsgProc->msgFrom = 0; + + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_APPEND(g_pMsgProcList, pMsgProc); + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + } + else + { + DBusOnBoardcastMsgWorkCb(pMsgPack); + } + } + } + else + { + LOG_EX(LOG_Error, "Receive Notify Message Error: %s\n", error.message); + dbus_error_free(&error); + } + + free(pMsgPack); + return DBUS_HANDLER_RESULT_HANDLED; + } + else if(dbus_message_is_method_call(pMsg, DBUS_MESSAGE_INTERFACE_NAME, "API")) + { + if(dbus_message_get_args(pMsg, &error, + DBUS_TYPE_UINT32, &pMsgPack->msgSrc, // from + DBUS_TYPE_UINT32, &pMsgPack->msgDests, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &pMsgPack->tmTickMSec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &pMsgPack->busCmd, // command type + DBUS_TYPE_UINT32, &pMsgPack->msgSize, // message size(in bytes) + DBUS_TYPE_STRING, &pMsgPack->pMsg, // message context if had + DBUS_TYPE_INVALID)) + { + // reset timeout timer + if(g_LibuvDBusParam.onHblCb && pMsgPack->msgSrc != g_LibuvDBusParam.modName) + { + HeartDaemonUpgrade(pMsgPack->msgSrc); + } + + // Dispatch message except from it's self + if(pMsgPack->msgSrc != g_LibuvDBusParam.modName + && pMsgPack->msgDests == (1 << g_LibuvDBusParam.modName)) + { + if(g_LibuvDBusParam.onMsgCb == NULL) + { + pMsgProc = (PDBUS_MSG_PROC)malloc(sizeof(struct DBUS_MSG_PROC)); + + if(pMsgProc == NULL) + { + LOG_EX(LOG_Error, "Receive Message: No Memory\n"); + free(pMsgPack); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + memset(pMsgProc, 0, sizeof(struct DBUS_MSG_PROC)); + memcpy(&pMsgProc->msgContent, pMsgPack, sizeof(DBUS_MSG_PACK)); + pMsgProc->msgContent.pMsg = strdup(pMsgPack->pMsg); + pMsgProc->msgFrom = 1; + + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_APPEND(g_pMsgProcList, pMsgProc); + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + } + else + { + DBusOnMsgWorkAPICb(pMsgPack); + } + } + } + else + { + LOG_EX(LOG_Error, "Receive API Message Error: %s\n", error.message); + dbus_error_free(&error); + } + + free(pMsgPack); + return DBUS_HANDLER_RESULT_HANDLED; + } + + free(pMsgPack); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void freeSHMResource(int shmId, void* pData) +{ + // Cleanup Share Memory + if(pData) + { + shmdt(pData); + } + + shmctl(shmId, IPC_RMID, 0); +} + +static void FreeDBusSendToAsyncCb(uv_work_t* pWork, int status) +{ + PDBUS_ASYNC_PARAMS pParam = (PDBUS_ASYNC_PARAMS)pWork->data; + free(pParam->pStruct); + free(pParam); + free(pWork); +} + +static void DBusSendToAsyncCb(uv_work_t* pWork) +{ + int err = 0; + PDBUS_ASYNC_PARAMS pParam = (PDBUS_ASYNC_PARAMS)pWork->data; + const char *pJsonStr = Struct2Json(pParam->pStruct, pParam->type, pParam->enBase64, &err); + + if(pJsonStr == NULL || err != 0) + { + pParam->cbSendTo(err); + return; + } + + err = DBusSendToCommand(pParam->pBus, pParam->pBusName, pParam->busCmd, pJsonStr); + + free((void*)pJsonStr); + + pParam->cbSendTo(err); +} + +int DBusJsonSendToCommandAsync(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int iSize, + OnDBusAsyncSendTo cbSendTo, + int enBase64) +{ + PDBUS_ASYNC_PARAMS pParam = NULL; + uv_work_t* puvWork = NULL; + + if(cbSendTo == NULL) + { + return 0; + } + + pParam = (PDBUS_ASYNC_PARAMS)malloc(sizeof(DBUS_ASYNC_PARAMS)); + puvWork = (uv_work_t*)malloc(sizeof(uv_work_t)); + + pParam->pBus = pBus; + pParam->pBusName = pBusName; + pParam->busCmd = busCmd; + pParam->type = type; + pParam->iSize = iSize; + pParam->pStruct = malloc(iSize); + pParam->cbSendTo = cbSendTo; + pParam->enBase64 = enBase64; + memcpy(pParam->pStruct, pStruct, iSize); + + puvWork->data = (void*)pParam; + uv_queue_work(g_LibuvDBusParam.pLoop, puvWork, DBusSendToAsyncCb, FreeDBusSendToAsyncCb); + + return 0; +} + +int DBusJsonSendToCommand(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64) +{ + int ret, err = 0; + const char* pJsonStr = Struct2Json(pStruct, type, enBase64, &err); + + if(pJsonStr == NULL || err != 0) + { + return err; + } + + ret = DBusSendToCommand(pBus, pBusName, busCmd, pJsonStr); + + free((void*)pJsonStr); + + return ret; +} + +int DBusJsonBoardcastCommand(DBusConnection* pBus, + uint32_t msgToMask, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64) +{ + int ret, err = 0; + const char* pJsonStr = Struct2Json(pStruct, type, enBase64, &err); + + if(pJsonStr == NULL || err != 0) + { + return err; + } + + ret = DBusBoardcastCommand(pBus, msgToMask, busCmd, pJsonStr); + + free((void*)pJsonStr); + return ret; +} + +static unsigned int __getShmReqId(void) +{ + static unsigned int g_shmReqId = 1; + unsigned int iReqId; + + if(g_shmReqId >= 0xFFFF - 1) + { + g_shmReqId = 1; + } + + iReqId = __sync_fetch_and_add(&g_shmReqId, 1); + + return (iReqId & 0xFFFF) | (g_LibuvDBusParam.modName << 16); +} + +int DBusSendToCommand(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + const char* pContext) +{ +#if USED_SHM_TO_DBUS + struct timeval tv; +#endif + int i; + int msgId; + //char msgContext[DBUS_MSG_MAX_PAD_SIZE]; + DBusMessage* pMsg = NULL; + uint32_t msgLen = 0; + uint32_t msgToMask = 0; + OnDBusSendError pErrorCb = NULL; + uint8_t* pMsgInfo = NULL; + PDBUS_MSG_DATA pShmData = NULL; + const char* pPath = NULL; + char* pMsgContent = NULL; + +#if 0 + if(pContext == NULL || (msgLen = strlen(pContext)) <= 0) + { + return (-ERR_INPUT_PARAMS); + } +#else + if(pContext == NULL) + { + pContext = ""; + msgLen = 0; + } + else + { + msgLen = strlen(pContext); + } +#endif + + pMsgContent = (char*)malloc(msgLen + 1); + + if(pMsgContent == NULL) + { + LOG_EX(LOG_Error, "Malloc memory %d error\n", msgLen + 1); + return -ERR_MALLOC_MEMORY; + } + + pMsgInfo = (uint8_t*)pMsgContent; + + memset(pMsgContent, 0, msgLen + 1); + + if(pBus == NULL) + { + pBus = g_LibuvDBusParam.pBus; + } + + for(i = 0; (i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0])); i++) + { + // Skip match it'self + if(strcmp(g_pModInfoTable[i].modAliase, pBusName) == 0) + { + msgToMask = 1 << i; + pPath = g_pModInfoTable[i].modPath; + break; + } + } + + pMsg = dbus_message_new_method_call(pBusName, + pPath, + DBUS_MESSAGE_INTERFACE_NAME, + "API"); + + if(pMsg == NULL) + { + free(pMsgContent); + LOG_EX(LOG_Error, "DBus Create Message Error\n"); + return -ERR_DBUS_CREATE_MSG; + } + + dbus_message_set_no_reply(pMsg, TRUE); + +#if USED_SHM_TO_DBUS + gettimeofday(&tv, NULL); +#endif + + if(msgLen < DBUS_MSG_MAX_PAD_SIZE) + { + strcpy(pMsgContent, pContext); + } + else + { +#if 0 + int msgKey = __getShmReqId(); + msgLen += sizeof(long int); + + // Make message with Memory Share + msgId = shmget((key_t)msgKey, msgLen, 0666 | IPC_CREAT); + + if(msgId == -1) + { + perror("shmget_"); + return (-ERR_CREATE_SHM); + } + else + { + pShmData = (PDBUS_MSG_DATA)shmat(msgId, NULL, 0); + + if(pShmData == (void*)-1) + { + return -ERR_MAP_SHM; + } + + pShmData->msgMask = msgToMask; + + memcpy(pShmData->pMsgContext, pContext, msgLen); + sprintf(pMsgInfo, "%d", msgKey); + + shmdt(pShmData); + //print_hex_dump_bytes("send_", 2, pShmData, msgLen); + //strcpy(pMsgInfo, (void*)&msgKey, sizeof(key_t)); + +#if USED_SHM_TO_DBUS + __addShmIdToTable((key_t)msgKey, tv.tv_sec, msgToMask, msgLen); +#endif + pErrorCb = freeSHMResource; + } +//#else +#endif + free(pMsgContent); + LOG_EX(LOG_Error, "Send Message size %d more than DBUS_MSG_MAX_PAD_SIZE, busCmd = %u, pBusName = %s\n", + msgLen, busCmd, pBusName); + return -ERR_INPUT_PARAMS; + } + + dbus_message_append_args(pMsg, + DBUS_TYPE_UINT32, &g_LibuvDBusParam.modName, // from + DBUS_TYPE_UINT32, &msgToMask, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &tv.tv_sec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &busCmd, // command type + DBUS_TYPE_UINT32, &msgLen, // message size(in bytes) + DBUS_TYPE_STRING, &pMsgInfo, + // msgLen[0, 512): pad to message; msgLen[512, ~): memory map key, + //DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pMsgInfo, (msgLen < DBUS_MSG_MAX_PAD_SIZE) ? msgLen : sizeof(key_t), + DBUS_TYPE_INVALID); + + free(pMsgContent); + + if(!dbus_connection_send(pBus, pMsg, NULL)) + { + LOG_EX(LOG_Error, "Send Message Error\n"); + if(pErrorCb) + { + pErrorCb(msgId, pShmData); + } + + return -ERR_BUS_SEND_MSG; + } + + //dbus_connection_flush(pBus); + dbus_message_unref(pMsg); + + usleep(100); + + return 0; +} + +int DBusBoardcastCommand(DBusConnection* pBus, + uint32_t msgToMask, + uint32_t busCmd, + const char* pContext) +{ +#if USED_SHM_TO_DBUS + struct timeval tv; +#endif + DBusMessage* pMsg = NULL; + + if(pContext == NULL) + { + pContext = ""; + } + + if(strlen(pContext) >= DBUS_MSG_MAX_PAD_SIZE) + { + LOG_EX(LOG_Error, "Msg size = %u more than DBUS_MSG_MAX_PAD_SIZE\n", strlen(pContext)); + return -ERR_DBUS_MSG_TO_LARGE; + } + + if(pBus == NULL) + { + pBus = g_LibuvDBusParam.pBus; + } + + pMsg = dbus_message_new_signal(g_LibuvDBusParam.pBusPath, DBUS_MESSAGE_INTERFACE_NAME, "Notify"); + + if(pMsg == NULL) + { + return -ERR_DBUS_CREATE_MSG; + } + + dbus_message_set_no_reply(pMsg, TRUE); + +#if USED_SHM_TO_DBUS + gettimeofday(&tv, NULL); +#endif + + dbus_message_append_args(pMsg, + DBUS_TYPE_UINT32, &g_LibuvDBusParam.modName, // from + DBUS_TYPE_UINT32, &msgToMask, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &tv.tv_sec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &busCmd, // command type + DBUS_TYPE_STRING, &pContext, + DBUS_TYPE_INVALID); + + if(!dbus_connection_send(pBus, pMsg, NULL)) + { + return -ERR_BUS_SEND_MSG; + } + + //dbus_connection_flush(pBus); + dbus_message_unref(pMsg); + + usleep(100); + return 0; +} + +static void __addNewLoopTask(uv_loop_t* pLoop) +{ + PLOOP_TASK_ARRAY pItem = NULL; + PLOOP_TASK_ARRAY pTask = NULL; + if(pLoop == NULL) + { + return; + } + + uv_rwlock_wrlock(&g_uvLoopRwLock); + LL_FOREACH(g_LoopArray, pItem) + { + if(pItem->pLoop == pLoop) + { + LOG_EX(LOG_Warn, "Loop %p is added\n", pLoop); + uv_rwlock_wrunlock(&g_uvLoopRwLock); + return; + } + } + + pTask = (PLOOP_TASK_ARRAY)malloc(sizeof(struct LOOP_TASK_ARRAY)); + if(pTask == NULL) + { + LOG_EX(LOG_Error, "Malloc Memory Error\n"); + return; + } + memset(pTask, 0, sizeof(struct LOOP_TASK_ARRAY)); + pTask->pLoop = pLoop; + pTask->isRunning = FALSE; + LL_APPEND(g_LoopArray, pTask); + uv_rwlock_wrunlock(&g_uvLoopRwLock); +} + +static void __uvLoopRuntime(void *pParam) +{ + uv_loop_t* pLoop = (uv_loop_t*)pParam; + + if(pLoop) + { + while(TRUE) + { + uv_run(pLoop, UV_RUN_DEFAULT); + usleep(1000); + } + } + + pthread_detach(pthread_self()); +} + +static void __runUVLoopTask(uv_loop_t* pLoop, void* pCallback) +{ + uv_thread_t uvThread; + if(pLoop == NULL) + { + return; + } + + uv_thread_create(&uvThread, __uvLoopRuntime, pLoop); +} + +void RunUVLoop(uv_loop_t *pLoop) +{ +#if 1 + int more; + + while(TRUE) + { + more = uv_run(g_LibuvDBusParam.pLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(g_LibuvDBusParam.pLoop); + + if(uv_run(g_LibuvDBusParam.pLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } +#else + int more; + + do + { + if(pLoop && pLoop != g_LibuvDBusParam.pUserLoop) + { + more = uv_run(pLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(pLoop); + + if(uv_run(pLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } + + if(g_LibuvDBusParam.pUserLoop) + { + more = uv_run(g_LibuvDBusParam.pUserLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(g_LibuvDBusParam.pUserLoop); + + if(uv_run(g_LibuvDBusParam.pUserLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } + + if(g_LibuvDBusParam.pLoop) + { + more = uv_run(g_LibuvDBusParam.pLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(g_LibuvDBusParam.pLoop); + + if(uv_run(g_LibuvDBusParam.pLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } + } + while(TRUE); +//#else + //__runUVLoopTask(pLoop, NULL); + //__addNewLoopTask(pLoop); +#endif +} + +static void __uvDBusRecvProc(void *pParams) +{ + while(TRUE) + { + DBusMessage* pMsg = NULL; + dbus_connection_read_write(g_LibuvDBusParam.pBus, 0); + + pMsg = dbus_connection_pop_message(g_LibuvDBusParam.pBus); + + if(pMsg != NULL) + { + DBusOnMsgCb(g_LibuvDBusParam.pBus, pMsg, NULL); + } + + usleep(100); + } +} + +void DBusMsgCleanup(PDBUS_MSG_PACK pMsg) +{ + if(pMsg) + { + if(pMsg->pMsg) + { + free(pMsg->pMsg); + } + + free(pMsg); + } +} + +PDBUS_MSG_PACK DBusGetMessage(void) +{ + int iCount, ret = 0; + PDBUS_MSG_PACK pMsg = NULL; + PDBUS_MSG_PROC pItem = NULL, pTmp = NULL; + + if(g_LibuvDBusParam.onMsgCb) + { + return NULL; + } + + DL_COUNT(g_pMsgProcList, pItem, iCount); + + if(iCount == 0) + { + return pMsg; + } + + pItem = NULL; + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_FOREACH_SAFE(g_pMsgProcList, pItem, pTmp) + { + if(pItem->msgFrom == 0) + { + ret = DBusOnBoardcastMsgWorkCb(&pItem->msgContent); + } + else + { + ret = DBusOnMsgWorkAPICb(&pItem->msgContent); + } + + if(ret != 0) + { + pMsg = (PDBUS_MSG_PACK)malloc(sizeof(DBUS_MSG_PACK)); + + if(pMsg) + { + memset(pMsg, 0, sizeof(DBUS_MSG_PACK)); + memcpy(pMsg, &pItem->msgContent, sizeof(DBUS_MSG_PACK)); + pMsg->pMsg = strdup(pItem->msgContent.pMsg); + } + } + + DL_DELETE(g_pMsgProcList, pItem); + free(pItem->msgContent.pMsg); + free(pItem); + + break; + } + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + + return pMsg; +} + +#if 0 +static void __uvMsgProc(void *pParams) +{ +#ifdef ENABLE_COUNT_DEBUG + struct timeval tmBegin, tmEnd; + long long diffTm; +#endif + + while(TRUE) + { + int iMaxProcMsg = 100; + PDBUS_MSG_PROC pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_FOREACH_SAFE(g_pMsgProcList, pItem, pTmp) + { + if(--iMaxProcMsg == 0) + { + break; + } + +#ifdef ENABLE_COUNT_DEBUG + gettimeofday(&tmBegin, NULL); +#endif + if(pItem->msgFrom == 0) + { + DBusOnBoardcastMsgWorkCb(&pItem->msgContent); +#ifdef ENABLE_COUNT_DEBUG + gettimeofday(&tmEnd, NULL); + diffTm = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmBegin.tv_sec * 1000000 + tmBegin.tv_usec); + MonUpgradeStatistical(MON_MSG_BST_PROC_STAT, diffTm); +#endif + } + else + { + DBusOnMsgWorkAPICb(&pItem->msgContent); +#ifdef ENABLE_COUNT_DEBUG + gettimeofday(&tmEnd, NULL); + diffTm = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmBegin.tv_sec * 1000000 + tmBegin.tv_usec); + MonUpgradeStatistical(MON_MSG_PROC_STAT, diffTm); +#endif + } + + if(pItem->msgContent.pMsg) + { + free(pItem->msgContent.pMsg); + } + + DL_DELETE(g_pMsgProcList, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + usleep(1000); + } + + pthread_detach(pthread_self()); +} +#endif + +void SetHBLAutoExit(int flag) +{ + g_EnHBLExit = flag ? TRUE : FALSE; +} + +static void __dBusDeameonCb(MODULE_NAME modName, int status) +{ + LOG_EX(status == 0 ? LOG_Info : LOG_Error, + "Daemon %s(%d) Msg: [%s]\n", ModuleNameToString(modName), modName, + status == 0 ? "Connect" : "Disconnect"); + + if(status != 0 && modName == MODULE_CONTROLLER && g_EnHBLExit) + { + sleep(1); + //exit(0); + } +} + +static void __waitUDISKMount(void) +{ +#ifdef PLATFORM_R16 + const char* pDoneStat = "done"; + const char* pBootStatFile = "/tmp/booting_state"; + char buf[5]; + FILE* pFile; + + // wait system create setup status file + LOG_EX(LOG_Debug, "Wait boot status file create ......\n"); + while(access(pBootStatFile, F_OK) != 0) + { + usleep(10000); + } + + pFile = fopen(pBootStatFile, "rb"); + + if(pFile == NULL) + { + LOG_EX(LOG_Error, "Open boot status file error\n"); + return; + } + + LOG_EX(LOG_Debug, "Wait boot status done ......\n"); + + // when UDISK mount, file /tmp/booting_state content is "done" + do + { + fseek(pFile, 0, SEEK_SET); + memset(buf, 0, 5); + fread(buf, 1, 4, pFile); // read 4 bytes status tags + + usleep(10000); + } + while(strncmp(buf, pDoneStat, strlen(pDoneStat)) != 0); + + fclose(pFile); + + LOG_EX(LOG_Debug, "Boot status done ......\n"); +#endif +} + +DBusConnection* DBusWithLibuvInit(uv_loop_t* pUserLoop, + const char* pBusName, + OnDBusMessage cbOnMsg, + OnDaemonMsg cbOnHbl, + OnKeyEvent cbOnKey, + int* pErrno) +{ + int i, ret = 0; + DBusError error; + SERVER_MODULE_TYPE svrMode; + uv_async_t* pAsync = NULL; + DBusConnection* pBus = NULL; + uv_fs_t* puvFsReq; + //uv_thread_t uvMsgProcThread; + //uv_thread_t uvMsgRecvThread; + + //uv_thread_t uvLoopThread; + char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH - 1]; +#if USED_SHM_TO_DBUS + uv_thread_t uvSyncThread; +#endif + //uv_loop_t *pLoop = uv_loop_new(); + uv_loop_t *pLoop = pUserLoop; + + memset(&g_LibuvDBusParam, 0, sizeof(LIBUV_DBUS_PARAMS)); + + for(i = 0; (i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0])); i++) + { + // Skip match it'self + if(strcmp(g_pModInfoTable[i].modAliase, pBusName) == 0) + { + g_LibuvDBusParam.modName = g_pModInfoTable[i].modName; + g_LibuvDBusParam.pBusName = g_pModInfoTable[i].modAliase; + g_LibuvDBusParam.pBusPath = g_pModInfoTable[i].modPath; + break; + } + } + + memset(&g_workDayArray, 0, sizeof(WORKDAY_INFO)); + srand(time(NULL)); + + if(pLoop == NULL || pBusName == NULL || pErrno == NULL) + { + if(pErrno) + { + *pErrno = -ERR_INPUT_PARAMS; + } + + LOG_EX(LOG_Error, "Input params error: pLoop = %p, pBusName = %p, pErrno = %p\n", + pLoop, pBusName, pErrno); + return NULL; + } + + puvFsReq = (uv_fs_t*)malloc(sizeof(uv_fs_t)); + + CfgFileInit(); + + IHW_InitLOG(strrchr(pBusName, '.') + 1, NULL, TRUE); + IHW_EnableLogLevel(LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info, 1); + + APP_BUILD_INFO(strrchr(pBusName, '.') + 1, GetCurrentVersion()); + + // wait UDISK mount, configure file save in UDISK partition + __waitUDISKMount(); + + svrMode = CfgGetIntValue("Global.ServerMode", PUBLISH_MODE); + + SetCurrentServerMode(svrMode); + DumpCurServerAddr("Default"); + + +#if USED_SHM_TO_DBUS + uv_rwlock_init(&g_uvShmHashRwLock); +#endif + + uv_rwlock_init(&g_uvMsgProcRwLock); + uv_rwlock_init(&g_uvLoopRwLock); + + uv_fs_access(pLoop, puvFsReq, "/mnt/UDISK/debug.dbg", F_OK, uvFsAccessCb); + + memset(rule, 0, DBUS_MAXIMUM_MATCH_RULE_LENGTH - 1); + srand(time(NULL)); + + //setenv("UV_THREADPOOL_SIZE", "128", 1); + + dbus_error_init(&error); + + pBus = dbus_bus_get(DBUS_BUS_SESSION, &error); + + if (dbus_error_is_set(&error)) + { + LOG_EX(LOG_Error, "dbus: Could not acquire the session bus\n"); + + dbus_error_free(&error); + *pErrno = -ERR_GET_BUS; + return NULL; + } + + ret = dbus_bus_request_name(pBus, pBusName, DBUS_NAME_FLAG_REPLACE_EXISTING, &error); + + if(dbus_error_is_set(&error)) + { + LOG_EX(LOG_Error, "dbus: Could not request dbus name\n"); + + dbus_error_free(&error); + *pErrno = -ERR_REQUEST_BUS_NAME; + return NULL; + } + + if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + LOG_EX(LOG_Error, "dbus: Could not request dbus name\n"); + + dbus_error_free(&error); + *pErrno = -ERR_REQUEST_BUS_NAME; + return NULL; + } +#if 1 + if(!dbus_connection_set_watch_functions(pBus, + DBusAddWatchCb, + DBusRemoveWatchCb, + DBusNotifyWatchCb, + (void*)pLoop, NULL)) + { + LOG_EX(LOG_Error, "dbus: Could not set watch function\n"); + + *pErrno = -ERR_SET_WATCH_FUNCTION; + return NULL; + } + + if(!dbus_connection_set_timeout_functions(pBus, + DBusAddTimeoutCb, + DBusRemoveTimeoutCb, + DBusNotifyTimeoutCb, + (void*)pLoop, NULL)) + { + LOG_EX(LOG_Error, "dbus: Could not set watch function\n"); + + *pErrno = -ERR_SET_TIMEOUT_FUNCTION; + return NULL; + } +#endif + + pAsync = malloc(sizeof(uv_async_t)); + pAsync->data = (void*)pBus; + + uv_async_init(pLoop, pAsync, uvAsyncCb); + uv_unref((uv_handle_t*)pAsync); + +#if 1 + dbus_connection_set_wakeup_main_function(pBus, + DBusWakeupMainLoopCb, + (void*)pAsync, DBusAsyncFreeCb); +#endif + + sprintf(rule, "type='signal', interface='%s'", DBUS_MESSAGE_INTERFACE_NAME); + dbus_bus_add_match(pBus, rule, &error); + + if(dbus_error_is_set(&error)) + { + LOG_EX(LOG_Error, "dbus_bus_add_match [%s] error: %s\n", DBUS_MESSAGE_INTERFACE_NAME, error.message); + dbus_error_free(&error); + *pErrno = -ERR_BUS_MATCH; + return NULL; + } +#if 1 + if(!dbus_connection_add_filter(pBus, DBusOnMsgCb, pLoop, NULL)) + { + LOG_EX(LOG_Error, "dbus_connection_add_filter error\n"); + *pErrno = -ERR_BUS_SET_MSG_CB; + return NULL; + } +#endif + + uv_idle_init(pLoop, &g_uvIdleHandle); + g_uvIdleHandle.data = pBus; + uv_idle_start(&g_uvIdleHandle, uvIdleCb); + + if(cbOnKey) + { + uv_fs_open(pLoop, &g_uvKeyEvent, R16_TINA_KEY_EVENT_PATH, O_RDONLY, 0, uvOpenKeyEventCb); + g_LibuvDBusParam.onKeyCb = cbOnKey; + } + + g_LibuvDBusParam.pLoop = pLoop; + g_LibuvDBusParam.pUserLoop = pUserLoop; + g_LibuvDBusParam.pBus = pBus; + g_LibuvDBusParam.onMsgCb = cbOnMsg; + +#if 0 + if(cbOnHbl) + { + g_LibuvDBusParam.onHblCb = cbOnHbl; + HeartDaemonInit(g_LibuvDBusParam.modName, HEART_LOST_DELAY, cbOnHbl); + } +#else + g_LibuvDBusParam.onHblCb = __dBusDeameonCb; + HeartDaemonInit(g_LibuvDBusParam.modName, HEART_LOST_DELAY, __dBusDeameonCb); +#endif + +#if USED_SHM_TO_DBUS + uv_thread_create(&uvSyncThread, __uvShmTblTaskThreadCb, NULL); +#endif + +#ifdef ENABLE_COUNT_DEBUG + MonitorInit(); + MonAddNewItem(MON_MSG_PROC_STAT, 100000); + MonAddNewItem(MON_MSG_BST_PROC_STAT, 100000); + MonAddNewItem(MON_USER_MSG_PROC_STAT, 100000); + MonAddNewItem(MON_USER_MSG_BST_PROC_STAT, 100000); +#endif + + InetInit(); + EvpSystemInit(); + +#if 0 + if(g_LibuvDBusParam.onMsgCb) + { + uv_thread_create(&uvMsgProcThread, __uvMsgProc, NULL); + } +#endif + + IHW_RunLogService(); + + return pBus; +} + +int DBusWithLibuvCfgInit(OnCfgMsg cbOnCfgMsg) +{ + CfgGlobalEnvInit(); + + if(cbOnCfgMsg == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + g_LibuvDBusParam.onCfgCb = cbOnCfgMsg; + + return (0); +} + +int GetShellExecResult(const char *pCmd, char **pResult) +{ + FILE *pFile = NULL; + unsigned int uRdSize = 0; + char *pCmdOut; + + *pResult = NULL; + + if(pCmd == NULL || strlen(pCmd) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + pFile = popen(pCmd, "r"); + + if(pFile == NULL) + { + return (-ERR_OPEN_FILE); + } + + *pResult = (char *)malloc(4096); + pCmdOut = *pResult; + + uRdSize = fread(pCmdOut, sizeof(char), 4096, pFile); + + pCmdOut[uRdSize] = 0; + + if(pCmdOut[strlen(pCmdOut) - 1] == '\n') + { + pCmdOut[strlen(pCmdOut) - 1] = 0; + } + + pclose(pFile); + //fprintf(stdout, "%s --> [%s](%u)\n", pCmd, pCmdOut, uRdSize); + return (0); +} + +void SystemSafeReboot(void) +{ + int ret, reTry = 0; +#if 0 + ret = system("sync"); + + ret = system("ubus call system watchdog \'{\"stop\" : true}\'"); + + reTry = 3; + do + { + sleep(1); + } while(reTry--); + + reTry = 0; + + LOG_EX(LOG_Debug, "Reboot System By Power Control Chips\n"); + sleep(1); + + ret = system("echo 3140 > /sys/bus/platform/devices/axp22_board/axp22_reg"); + + sleep(10); +#endif + while(TRUE) + { + LOG_EX(LOG_Debug, "Reboot System: %d times\n", reTry++); + sleep(1); + ret = system("reboot -f"); + sleep(3); + } +} + +char* GetCpuChipId(void) +{ + char* pRet = NULL; +#ifdef PLATFORM_R16 + char* pChipId = NULL; + + GetShellExecResult("cat /proc/cpuinfo | grep Chipid | awk '{print $3}'", &pChipId); + + if(pChipId == NULL) + { + return strdup(""); + } + + pRet = strdup(pChipId); + free(pChipId); + return pRet; +#else + return strdup("Unknown CPU Chip ID"); +#endif +} + +char* GetCpuSerial(void) +{ + char* pRet = NULL; +#ifdef PLATFORM_R16 + char* pSerial = NULL; + + GetShellExecResult("cat /proc/cpuinfo | grep Serial | awk '{print $3}'", &pSerial); + + if(pSerial == NULL) + { + return strdup(""); + } + + pRet = strdup(pSerial); + free(pSerial); + return pRet; +#else + return strdup("Unknown CPU Serial"); +#endif +} + +int CopyFile(const char *pSrc, const char *pDest) +{ + int fdSrc, fdDest; + struct stat st; + ssize_t sz; + + if(stat(pSrc, &st) != 0) + { + LOG_EX(LOG_Error, "Get File %s Size Error\n", pSrc); + return (-ERR_GET_FILE_SIZE); + } + + fdSrc = open(pSrc, O_RDONLY); + + if(fdSrc < 0) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pSrc); + return (-ERR_OPEN_FILE); + } + + fdDest = open(pDest, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + if(fdDest < 0) + { + close(fdSrc); + LOG_EX(LOG_Error, "Open File %s Error\n", pDest); + return (-ERR_OPEN_FILE); + } + + sz = sendfile(fdDest, fdSrc, NULL, st.st_size); + + if(sz != st.st_size) + { + LOG_EX(LOG_Error, "Copy File Size Error: %d, %d\n", sz, st.st_size); + close(fdSrc); + close(fdDest); + return (-ERR_COPY_FILE); + } + + fsync(fdDest); + + close(fdSrc); + close(fdDest); + + return (0); +} + +int CopyFileWithSize(const char *pSrc, const char *pDest, int iSize) +{ + int fdSrc, fdDest; + struct stat st; + ssize_t sz; + size_t cpSize = iSize; + + if(iSize <= 0) + { + if(stat(pSrc, &st) != 0) + { + LOG_EX(LOG_Error, "Get File %s Size Error\n", pSrc); + return (-ERR_GET_FILE_SIZE); + } + + cpSize = st.st_size; + } + + fdSrc = open(pSrc, O_RDONLY); + + if(fdSrc < 0) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pSrc); + return (-ERR_OPEN_FILE); + } + + fdDest = open(pDest, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |S_IWOTH); + + if(fdDest < 0) + { + close(fdSrc); + LOG_EX(LOG_Error, "Open File %s Error\n", pDest); + return (-ERR_OPEN_FILE); + } + + sz = sendfile(fdDest, fdSrc, NULL, cpSize); + + if(sz != cpSize) + { + LOG_EX(LOG_Error, "Copy File Size Error: %d, %d\n", sz, cpSize); + close(fdSrc); + close(fdDest); + return (-ERR_COPY_FILE); + } + + close(fdSrc); + close(fdDest); + + return (0); +} + +int ReadFileToBuf(const char *pSrc, unsigned char *pBuf, int iSize) +{ + int fdSrc; + struct stat st; + ssize_t sz; + size_t cpSize = iSize; + + if(iSize < 0) + { + if(stat(pSrc, &st) != 0) + { + LOG_EX(LOG_Error, "Get File %s Size Error\n", pSrc); + return (-ERR_GET_FILE_SIZE); + } + + cpSize = st.st_size; + } + + fdSrc = open(pSrc, O_RDONLY); + + if(fdSrc < 0) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pSrc); + return (-ERR_OPEN_FILE); + } + + sz = read(fdSrc, pBuf, cpSize); + + if(sz != cpSize) + { + LOG_EX(LOG_Error, "Copy File Size Error: %d, %d\n", sz, cpSize); + close(fdSrc); + return (-ERR_COPY_FILE); + } + + close(fdSrc); + + return (sz); +} + +static int __reqWorkDayInfo(int year) +{ + int ret = 0; + WORKDAY_INFO reqInfo; + + memset(&reqInfo, 0, sizeof(WORKDAY_INFO)); + + if(year <= 0) + { + struct tm localTime; + time_t tmStamp = time((time_t*)NULL); + + localtime_r(&tmStamp, &localTime); + + reqInfo.year = localTime.tm_year; + } + else + { + reqInfo.year = year; + } + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_WORKDAY_DB_REQ, + JSON_ENGINE_WORKDAY_REQ, + &reqInfo, FALSE); + + return (ret); +} + +int CurrentIsWorkDay(int year, int day) +{ +// LOG_EX(LOG_Debug, "CurrentIsWorkDay: year = %d, day = %d\n", year, day); + + if(day > 365) + { + LOG_EX(LOG_Error, "Error Input Params: day = %d\n", day); + return (-ERR_INPUT_PARAMS); + } + + if(g_workDayArray.year <= 0) + { + __reqWorkDayInfo(year); + LOG_EX(LOG_Error, "Unsync Database: year = %d\n", year); + return (-ERR_UNINIT_ITEM); + } + + if(day < 0 || year <= 0) + { + struct tm localTime; + time_t tmStamp = time((time_t*)NULL); + localtime_r(&tmStamp, &localTime); + + if(day < 0) + { + day = localTime.tm_yday; + } + + if(year <= 0) + { + year = localTime.tm_year; + } + } + + if(year != g_workDayArray.year - 1900) + { + __reqWorkDayInfo(year); + LOG_EX(LOG_Error, "Have No Current Year Database: year = %d, g_workDayArray.year = %d\n", + year, g_workDayArray.year); + + return (-ERR_NO_ITEMS); + } + + // 0 work day, 1 holiday + return (g_workDayArray.days[day] == 0); +} + +unsigned long long GetPartitionFreeSize(const char *pPartPath) +{ + struct statfs myStatfs; + unsigned long long freeSize; + + if(statfs(pPartPath, &myStatfs) == -1) + { + return 0; + } + + freeSize = myStatfs.f_bsize * myStatfs.f_bfree; + + //fprintf(stdout, "%s free = %llu bytes\n", pPartPath, freeSize); + + return freeSize; +} + +#ifdef CURRENT_VERSION +char* GetCurrentVersion(void) +{ + return CURRENT_VERSION; +} +#else +char* GetCurrentVersion(void) +{ + return "0.0.1"; +} +#endif + +WIFI_STATUS GetCurrWIFIConnStatus(void) +{ + return g_WifiConnStatus; +} + +const char* ErrcodeToString(int errCode) +{ + switch(errCode) + { + case ERR_INPUT_PARAMS: return "ERR_INPUT_PARAMS"; + case ERR_NO_ITEMS: return "ERR_NO_ITEMS"; + case ERR_GET_BUS: return "ERR_GET_BUS"; + case ERR_DBUS_CONNECTION: return "ERR_DBUS_CONNECTION"; + case ERR_REQUEST_BUS_NAME: return "ERR_REQUEST_BUS_NAME"; + case ERR_SET_WATCH_FUNCTION: return "ERR_SET_WATCH_FUNCTION"; + case ERR_SET_TIMEOUT_FUNCTION: return "ERR_SET_TIMEOUT_FUNCTION"; + case ERR_BUS_MATCH: return "ERR_BUS_MATCH"; + case ERR_BUS_SET_MSG_CB: return "ERR_BUS_SET_MSG_CB"; + case ERR_DBUS_CREATE_MSG: return "ERR_DBUS_CREATE_MSG"; + case ERR_BUS_SEND_MSG: return "ERR_BUS_SEND_MSG"; + case ERR_DBUS_MSG_TO_LARGE: return "ERR_DBUS_MSG_TO_LARGE"; + case ERR_BUS_RCV_MSG: return "ERR_BUS_RCV_MSG"; + case ERR_ADD_TASK: return "ERR_ADD_TASK"; + case ERR_UNSUP_EVP_TYPE: return "ERR_UNSUP_EVP_TYPE"; + case ERR_CREATE_MQ: return "ERR_CREATE_MQ"; + case ERR_MQ_SENDMSG: return "ERR_MQ_SENDMSG"; + case ERR_CREATE_SHM: return "ERR_CREATE_SHM"; + case ERR_MAP_SHM: return "ERR_MAP_SHM"; + case ERR_MALLOC_MEMORY: return "ERR_MALLOC_MEMORY"; + case ERR_EVP_INIT_KEY: return "ERR_EVP_INIT_KEY"; + case ERR_EVP_UPDATE: return "ERR_EVP_UPDATE"; + case ERR_EVP_FINALE: return "ERR_EVP_FINALE"; + case ERR_EVP_KEY_SIZE: return "ERR_EVP_KEY_SIZE"; + case ERR_OPEN_FILE: return "ERR_OPEN_FILE"; + case ERR_READ_FILE: return "ERR_READ_FILE"; + case ERR_WRITE_FILE: return "ERR_WRITE_FILE"; + case ERR_COPY_FILE: return "ERR_COPY_FILE"; + case ERR_FILE_NOT_EXISTS: return "ERR_FILE_NOT_EXISTS"; + case ERR_GET_FILE_SIZE: return "ERR_GET_FILE_SIZE"; + case ERR_UNINIT_ITEM: return "ERR_UNINIT_ITEM"; + case ERR_FILE_EMPTY: return "ERR_FILE_EMPTY"; + case ERR_SEND_MAIL: return "ERR_SEND_MAIL"; + case ERR_NETWORK_SEND: return "ERR_NETWORK_SEND"; + case ERR_NETWORK_NOT_CONNECTED: return "ERR_NETWORK_NOT_CONNECTED"; + case ERR_UNSUPPORT: return "ERR_UNSUPPORT"; + case ERR_NO_INIT_IPL3: return "ERR_NO_INIT_IPL3"; + case ERR_BAD_IPL3: return "ERR_BAD_IPL3"; + case ERR_BAD_FILE_SIZE: return "ERR_BAD_FILE_SIZE"; + case ERR_MD5_FILE: return "ERR_MD5_FILE"; + case ERR_MD5_CHECK_SUM: return "ERR_MD5_CHECK_SUM"; + case ERR_OTA_WRITE_BOOT: return "ERR_OTA_WRITE_BOOT"; + case ERR_OTA_WRITE_ROOTFS: return "ERR_OTA_WRITE_ROOTFS"; + case ERR_OTA_WRITE_IPL3: return "ERR_OTA_WRITE_IPL3"; + case ERR_OTA_WRITE_PARAMS: return "ERR_OTA_WRITE_PARAMS"; + case ERR_OTA_DOWNLOAD_FILE: return "ERR_OTA_DOWNLOAD_FILE"; + case ERR_VERIFY_PARTITION_MD5: return "ERR_VERIFY_PARTITION_MD5"; + case ERR_OTA_PRE_STATR: return "ERR_OTA_PRE_STATR"; + case ERR_OTA_YET_CUR_VER: return "ERR_OTA_YET_CUR_VER"; + case ERR_OTA_NOT_READY: return "ERR_OTA_NOT_READY"; + case ERR_CREATE_CFG_FILE: return "ERR_CREATE_CFG_FILE"; + case ERR_CREATE_SQLITE3_DB: return "ERR_CREATE_SQLITE3_DB"; + case ERR_OPEN_SQLITE3_DB: return "ERR_OPEN_SQLITE3_DB"; + case ERR_SQLITE3_CREATE_TABLE: return "ERR_SQLITE3_CREATE_TABLE"; + case ERR_SYNC_DATABASE: return "ERR_SYNC_DATABASE"; + case ERR_SQL_QUERY: return "ERR_SQL_QUERY"; + case ERR_SQL_DELETE: return "ERR_SQL_DELETE"; + case ERR_UNKNOWN_TYPE: return "ERR_UNKNOWN_TYPE"; + case ERR_PERMISSION_DENIED: return "ERR_PERMISSION_DENIED"; + case ERR_CFG_NOITEM: return "ERR_CFG_NOITEM"; + case ERR_CFG_ITEM_EXIST: return "ERR_CFG_ITEM_EXIST"; + case ERR_CFG_WAIT_RSP: return "ERR_CFG_WAIT_RSP"; + case ERR_CFG_BUSY: return "ERR_CFG_BUSY"; + case ERR_STR_CONVERT: return "ERR_STR_CONVERT"; + case ERR_SQL_REG_MODULE: return "ERR_SQL_REG_MODULE"; + default: return "Unknown Error"; + } +} + +const char* DBusCmdToString(DBUS_CMD cmd) +{ + switch(cmd) + { + case CMD_MISC_PING: return "CMD_MISC_PING"; + case CMD_MISC_OTA: return "CMD_MISC_OTA"; + case CMD_MISC_WEATHER: return "CMD_MISC_WEATHER"; + case CMD_MISC_NOWTIME: return "CMD_MISC_NOWTIME"; + case CMD_MISC_UPGRADE: return "CMD_MISC_UPGRADE"; + case CMD_SYSTEM_STANDBY: return "CMD_SYSTEM_STANDBY"; + case CMD_MISC_QUERY_OTA_STATUS: return "CMD_MISC_QUERY_OTA_STATUS"; + case CMD_MISC_QUERY_DL_STATUS: return "CMD_MISC_QUERY_DL_STATUS"; + case CMD_CALL_DIAL: return "CMD_CALL_DIAL"; + case CMD_CALL_ACCEPI: return "CMD_CALL_ACCEPI"; + case CMD_CALL_HANGUP: return "CMD_CALL_HANGUP"; + case CMD_CALL_MESSAGE: return "CMD_CALL_MESSAGE"; + case CMD_PLAY_MODECHANGE: return "CMD_PLAY_MODECHANGE"; + case CMD_PLAY_PLAY: return "CMD_PLAY_PLAY"; + case CMD_PLAY_PAUSE: return "CMD_PLAY_PAUSE"; + case CMD_PLAY_STOP: return "CMD_PLAY_STOP"; + case CMD_PLAY_SEEKTO: return "CMD_PLAY_SEEKTO"; + case CMD_PLAY_SHOWMODE: return "CMD_PLAY_SHOWMODE"; + case CMD_PLAY_NEXT: return "CMD_PLAY_NEXT"; + case CMD_PLAY_PRE: return "CMD_PLAY_PRE"; + case CMD_PLAY_SHOWLIST: return "CMD_PLAY_SHOWLIST"; + case CMD_PLAY_UPDATELIST: return "CMD_PLAY_UPDATELIST"; + case CMD_PLAY_PREPARE_NEXT: return "CMD_PLAY_PREPARE_NEXT"; + case CMD_PLAY_ADDTOLIST: return "CMD_PLAY_ADDTOLIST"; + case CMD_PLAY_DELETEFROMLIST: return "CMD_PLAY_DELETEFROMLIST"; + case CMD_PLAY_RESETLIST: return "CMD_PLAY_RESETLIST"; + case CMD_PLAY_AUDIO_STOP: return "CMD_PLAY_AUDIO_STOP"; + case CMD_PLAY_AUDIO_PLAY: return "CMD_PLAY_AUDIO_PLAY"; + case CMD_SE_PLAY: return "CMD_SE_PLAY"; + case CMD_PLAY_RET_STATUS: return "CMD_PLAY_RET_STATUS"; + case CMD_CFG_ADD_REQ: return "CMD_CFG_ADD_REQ"; + case CMD_CFG_ADD_RSP: return "CMD_CFG_ADD_RSP"; + case CMD_CFG_CHANGE_REQ: return "CMD_CFG_CHANGE_REQ"; + case CMD_CFG_CHANGE_RSP: return "CMD_CFG_CHANGE_RSP"; + case CMD_CFG_GET_REQ: return "CMD_CFG_GET_REQ"; + case CMD_CFG_GET_RSP: return "CMD_CFG_GET_RSP"; + case CMD_CFG_UPG_NOTIFY: return "CMD_CFG_UPG_NOTIFY"; + case CMD_MSC_MSG_CONTROLLER_RECOG_SUCCESS: return "CMD_MSC_MSG_CONTROLLER_RECOG_SUCCESS"; + case CMD_MSC_MSG_CONTROLLER_RECOG_ERROR: return "CMD_MSC_MSG_CONTROLLER_RECOG_ERROR"; + case CMD_MSC_MSG_CONTROLLER_WAKEUP: return "CMD_MSC_MSG_CONTROLLER_WAKEUP"; + case CMD_MSC_MSG_CONTROLLER_RECOGING: return "CMD_MSC_MSG_CONTROLLER_RECOGING"; + case CMD_CONTROLLER_REQMSG_INITARGS: return "CMD_CONTROLLER_REQMSG_INITARGS"; + case CMD_CONTROLLER_RSPMSG_INITARGS: return "CMD_CONTROLLER_RSPMSG_INITARGS"; + case CMD_CONTROLLER_REQMSG_PLAYERSTATUS: return "CMD_CONTROLLER_REQMSG_PLAYERSTATUS"; + case CMD_CONTROLLER_RSPMSG_PLAYERSTATUS: return "CMD_CONTROLLER_RSPMSG_PLAYERSTATUS"; + case CMD_MSC_REQMSG_MIC_CONTROL: return "CMD_MSC_REQMSG_MIC_CONTROL"; + case CMD_MSC_RSPMSG_MIC_CONTROL: return "CMD_MSC_RSPMSG_MIC_CONTROL"; + case CMD_YUNXIN_RECVMSG: return "CMD_YUNXIN_RECVMSG"; + case CMD_YUNXIN_SENDMSG: return "CMD_YUNXIN_SENDMSG"; + case CMD_YUNXIN_SENDMSG_BYPASS: return "CMD_YUNXIN_SENDMSG_BYPASS"; + case CMD_YUNXIN_SENDMSGCB: return "CMD_YUNXIN_SENDMSGCB"; + case CMD_CONTROLLER_MSG_YUNXIN: return "CMD_CONTROLLER_MSG_YUNXIN"; + case CMD_YUNXIN_STATUS: return "CMD_YUNXIN_STATUS"; + case CMD_YUNXIN_SYSMSG: return "CMD_YUNXIN_SYSMSG"; + case CMD_WIFI_CONF: return "CMD_WIFI_CONF"; + case CMD_WIFI_CONF_RESP: return "CMD_WIFI_CONF_RESP"; + case CMD_WIFI_AUTO_CONN: return "CMD_WIFI_AUTO_CONN"; + case CMD_WIFI_AUTO_CONN_RESP: return "CMD_WIFI_AUTO_CONN_RESP"; + case CMD_WIFI_STATE_REQ: return "CMD_WIFI_STATE_REQ"; + case CMD_WIFI_STATE_RESP: return "CMD_WIFI_STATE_RESP"; + case CMD_WIFI_STATE_NTF: return "CMD_WIFI_STATE_NTF"; + case CMD_BT_NAME_GET_REQ: return "CMD_BT_NAME_GET_REQ"; + case CMD_BT_NAME_GET_RESP: return "CMD_BT_NAME_GET_RESP"; + case CMD_BT_EVT_NTF: return "CMD_BT_EVT_NTF"; + case CMD_KPLAYER_START: return "CMD_KPLAYER_START"; + case CMD_KPLAYER_STOP: return "CMD_KPLAYER_STOP"; + case CMD_KPLAYER_NOTIF_DUR: return "CMD_KPLAYER_NOTIF_DUR"; + case CMD_KPLAYER_HOST_ACTION: return "CMD_KPLAYER_HOST_ACTION"; + case CMD_KPLAYER_CTR_NTF_BASE: return "CMD_KPLAYER_CTR_NTF_BASE"; + case CMD_KPLAYER_CTR_CREATED: return "CMD_KPLAYER_CTR_CREATED"; + case CMD_KPLAYER_CTR_DELED: return "CMD_KPLAYER_CTR_DELED"; + case CMD_KPLAYER_CTR_PLAY: return "CMD_KPLAYER_CTR_PLAY"; + case CMD_KPLAYER_CTR_STOP: return "CMD_KPLAYER_CTR_STOP"; + case CMD_KPLAYER_CTR_PAUSE: return "CMD_KPLAYER_CTR_PAUSE"; + case CMD_KPLAYER_CTR_SEEK: return "CMD_KPLAYER_CTR_SEEK"; + case CMD_KPLAYER_CTR_SET_URL: return "CMD_KPLAYER_CTR_SET_URL"; + case CMD_KPLAYER_CTR_SET_VOLUME: return "CMD_KPLAYER_CTR_SET_VOLUME"; + case CMD_KPLAYER_CTR_SET_MUTE: return "CMD_KPLAYER_CTR_SET_MUTE"; + case CMD_KPLAYER_CTR_SET_NXT_URL: return "CMD_KPLAYER_CTR_SET_NXT_URL"; + case CMD_KPLAYER_CTR_SET_NEXT: return "CMD_KPLAYER_CTR_SET_NEXT"; + case CMD_KPLAYER_CTR_SET_PREV: return "CMD_KPLAYER_CTR_SET_PREV"; + case CMD_ALARM_SYNC_REQ: return "CMD_ALARM_SYNC_REQ"; + case CMD_ALARM_SYNC_RSP: return "CMD_ALARM_SYNC_RSP"; + case CMD_ALARM_ADD: return "CMD_ALARM_ADD"; + case CMD_ALARM_REMOVE: return "CMD_ALARM_REMOVE"; + case CMD_ALARM_REMOVEALL: return "CMD_ALARM_REMOVEALL"; + case CMD_REMAIND_SYNC_REQ: return "CMD_REMAIND_SYNC_REQ"; + case CMD_REMAIND_SYNC_RSP: return "CMD_REMAIND_SYNC_RSP"; + case CMD_REMAIND_ADD: return "CMD_REMAIND_ADD"; + case CMD_REMAIND_REMOVE: return "CMD_REMAIND_REMOVE"; + case CMD_REMAIND_REMOVEALL: return "CMD_REMAIND_REMOVEALL"; + case CMD_ASSISTANT_STATUS: return "CMD_ASSISTANT_STATUS"; + case CMD_ASSISTANT_RUNNING: return "CMD_ASSISTANT_RUNNING"; + case CMD_ASSISTANT_NOTIFY: return "CMD_ASSISTANT_NOTIFY"; + case CMD_SESSION_ALARM_SYNC: return "CMD_SESSION_ALARM_SYNC"; + case CMD_WORKDAY_DB_REQ: return "CMD_WORKDAY_DB_REQ"; + case CMD_WORKDAY_DB_RSP: return "CMD_WORKDAY_DB_RSP"; + case CMD_OTA_NOTIFY: return "CMD_OTA_NOTIFY"; + case CMD_OTA_STATUS: return "CMD_OTA_STATUS"; + case CMD_OTA_RUNNOW: return "CMD_OTA_RUNNOW"; + case CMD_LOG_CONFIG: return "CMD_LOG_CONFIG"; + default: return "Unknown CMD"; + } +} + +const char* ModuleNameToString(MODULE_NAME modName) +{ + switch(modName) + { + case MODULE_CONTROLLER: return "MODULE_CONTROLLER"; + case MODULE_ALARM: return "MODULE_ALARM"; + case MODULE_CALL: return "MODULE_CALL"; + case MODULE_VOICEENGINE: return "MODULE_VOICEENGINE"; + case MODULE_PLAYER: return "MODULE_PLAYER"; + case MODULE_CONFIGURE: return "MODULE_CONFIGURE"; + case MODULE_OTA: return "MODULE_OTA"; + case MODULE_WIFI: return "MODULE_WIFI"; + case MODULE_BT: return "MODULE_BT"; + case MODULE_KPLAYER: return "MODULE_KPLAYER"; + case MODULE_KPLAYER_TEST: return "MODULE_KPLAYER_TEST"; + case MODULE_SPLAYER: return "MODULE_SPLAYER"; + case MODULE_SPLAYER_TEST: return "MODULE_SPLAYER_TEST"; + case MODULE_LIGHT_MCU: return "MODULE_LIGHT_MCU"; + case MODULE_BLUEKC: return "MODULE_BLUEKC"; + case MODULE_BLUEKC_TEST: return "MODULE_BLUEKC_TEST"; + case MODULE_MANUFACTURE: return "MODULE_MANUFACTURE"; + case MODULE_BT_DEMO: return "MODULE_BT_DEMO"; + case MODULE_LOG_CTRL: return "MODULE_LOG_CTRL"; + } + + return "Unknown Module Name"; +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0ee6e8f --- /dev/null +++ b/Makefile @@ -0,0 +1,90 @@ +SHELL := /bin/sh + +DIS_BUILD_WARRING ?= FALSE +EN_MAKE_MSG ?= TRUE + +ifeq ($(EN_MAKE_MSG), TRUE) +MAKE_FLAGS := +else +MAKE_FLAGS := -s +endif + +ifneq ($(OPT), clean) +ifneq ($(OPT), install) +MAKE_FLAGS += -j$(shell cat /proc/cpuinfo | grep processor | wc -l) +endif +endif + +ifeq ($(DIR), ) +DEMO_INS_PATH := ./release +else +DEMO_INS_PATH := $(DIR) +endif + +.PHONY : uvdbus example cfgserver alarm ota voice logctrl + +all: uvdbus example alarm ota logctrl + + +uvdbus: +ifeq ($(OPT), clean) + @make $(MAKE_FLAGS) -C build -f Makefile.lib.cross cleanall MAKE_TARGET=uvdbus +else ifeq ($(OPT), install) + @make $(MAKE_FLAGS) -C build -f Makefile.lib.cross install DIR=$(DIR) MAKE_TARGET=uvdbus +else + @make all $(MAKE_FLAGS) -C build -f Makefile.lib.cross DISABLE_WARRING=$(DIS_BUILD_WARRING) MAKE_TARGET=uvdbus +endif + +example: +ifeq ($(OPT), clean) + @make $(MAKE_FLAGS) -C build -f Makefile.app.cross cleanall MAKE_TARGET=example +else ifeq ($(OPT), install) + @make $(MAKE_FLAGS) -C build -f Makefile.app.cross install DIR=$(DIR) MAKE_TARGET=example +else + @make all $(MAKE_FLAGS) -C build -f Makefile.app.cross DISABLE_WARRING=$(DIS_BUILD_WARRING) MAKE_TARGET=example +endif + +cfgserver: +ifeq ($(OPT), clean) + @make $(MAKE_FLAGS) -C build -f Makefile.cfgsvr.cross cleanall MAKE_TARGET=cfgserver +else ifeq ($(OPT), install) + @make $(MAKE_FLAGS) -C build -f Makefile.cfgsvr.cross install DIR=$(DIR) MAKE_TARGET=cfgserver +else + @make all $(MAKE_FLAGS) -C build -f Makefile.cfgsvr.cross DISABLE_WARRING=$(DIS_BUILD_WARRING) MAKE_TARGET=cfgserver +endif + +alarm: +ifeq ($(OPT), clean) + @make $(MAKE_FLAGS) -C build -f Makefile.alarm.cross cleanall MAKE_TARGET=alarm +else ifeq ($(OPT), install) + @make $(MAKE_FLAGS) -C build -f Makefile.alarm.cross install DIR=$(DIR) MAKE_TARGET=alarm +else + @make all $(MAKE_FLAGS) -C build -f Makefile.alarm.cross DISABLE_WARRING=$(DIS_BUILD_WARRING) MAKE_TARGET=alarm +endif + +ota: +ifeq ($(OPT), clean) + @make $(MAKE_FLAGS) -C build -f Makefile.ota.cross cleanall MAKE_TARGET=ota +else ifeq ($(OPT), install) + @make $(MAKE_FLAGS) -C build -f Makefile.ota.cross install DIR=$(DIR) MAKE_TARGET=ota +else + @make all $(MAKE_FLAGS) -C build -f Makefile.ota.cross DISABLE_WARRING=$(DIS_BUILD_WARRING) MAKE_TARGET=ota +endif + +voice: +ifeq ($(OPT), clean) + @make $(MAKE_FLAGS) -C build -f Makefile.voice.cross cleanall MAKE_TARGET=voice +else ifeq ($(OPT), install) + @make $(MAKE_FLAGS) -C build -f Makefile.voice.cross install DIR=$(DIR) MAKE_TARGET=voice +else + @make all $(MAKE_FLAGS) -C build -f Makefile.voice.cross DISABLE_WARRING=$(DIS_BUILD_WARRING) MAKE_TARGET=voice +endif + +logctrl: +ifeq ($(OPT), clean) + @make $(MAKE_FLAGS) -C build -f Makefile.logctrl.cross cleanall MAKE_TARGET=logctrl +else ifeq ($(OPT), install) + @make $(MAKE_FLAGS) -C build -f Makefile.logctrl.cross install DIR=$(DIR) MAKE_TARGET=logctrl +else + @make all $(MAKE_FLAGS) -C build -f Makefile.logctrl.cross DISABLE_WARRING=$(DIS_BUILD_WARRING) MAKE_TARGET=logctrl +endif diff --git a/Modules/Alarm/assistant.c b/Modules/Alarm/assistant.c new file mode 100644 index 0000000..040083a --- /dev/null +++ b/Modules/Alarm/assistant.c @@ -0,0 +1,789 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) +#include "log.h" +#include "libuv_dbus.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#include "assistant.h" +#else +#include +#include +#include +#include +#include +#include +#endif + +#define SYNC_TIME_DELAY (5) + +static PASSISTANT_ARRAY_INFO g_pAlarmArray = NULL, + g_pRemaindArray = NULL, + g_pSessionArray = NULL; + +static uv_rwlock_t g_uvListRwLock; +static unsigned char g_syncFlags; +static unsigned int g_sessionId = 0; + +static void __onAlarmCb(unsigned int tmId, unsigned int status, void *pUserData); + +static int __getTimerPriorty(ASSISTANT_TYPE itemType) +{ + switch(itemType) + { + case ASSISTANT_TYPE_CLOCK: + return (2); + + case ASSISTANT_TYPE_REMAIND: + return (3); + + case ASSISTANT_TYPE_SESSION: + return (1); + } + + return (0); +} + +static void __addTaskToTimer(PASSISTANT_ARRAY_INFO pItem) +{ + int ret = 0; + unsigned int alarmId; + + pItem->alarmItem.second = 0; + + alarmId = AlarmTimerAdd(pItem->alarmItem.year, + pItem->alarmItem.month, + pItem->alarmItem.day, + pItem->alarmItem.hour, + pItem->alarmItem.minute, + pItem->alarmItem.second, + pItem->alarmItem.weekDay, + pItem->alarmItem.repeatMode, + __onAlarmCb, + __getTimerPriorty(pItem->alarmItem.itemType), + &pItem->alarmItem, + &ret); + + if(alarmId != 0xFFFFFFFF && ret == 0) + { + pItem->alarmItem.timerId = alarmId; + } + else + { + pItem->alarmItem.timerId = 0xFFFFFFFF; + } +} + +static int __assistantRspStatus(int cmd, int val) +{ + int ret = 0; + ASSISTANT_RSP_STATUS oStatus; + + memset(&oStatus, 0, sizeof(ASSISTANT_RSP_STATUS)); + + oStatus.cmd = cmd; + oStatus.val = val; + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_STATUS, + JSON_ENGINE_ASSISTANT_STATUS, + &oStatus, TRUE); + + return (ret); +} + +static int __assistantRunningEvent(PASSISTANT_ITEM_INFO pInfo) +{ + int ret = 0; + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_RUNNING, + JSON_ENGINE_ASSISTANT_RUNNING, + pInfo, FALSE); + + return (ret); +} + +static int __assistantNotifyChange(int cmdNotify, int nItems, ASSISTANT_TYPE nType, PASSISTANT_ITEM_INFO pInfo) +{ + int ret = 0; + ASSISTANT_NOTIFY_INFO notifyInfo; + + memset(¬ifyInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO)); + + notifyInfo.type = nType; + notifyInfo.cmd = cmdNotify; + + if(pInfo) + { + notifyInfo.nItems = nItems; + for(int i = 0; i < nItems; i++) + { + notifyInfo.ids[i] = pInfo[i].itemId; + } + } + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_NOTIFY, + JSON_ENGINE_ASSISTANT_NOTIFY, + ¬ifyInfo, TRUE); + + return (ret); +} + +static int __assistantArrayNotifyChange(int cmdNotify, int nItems, ASSISTANT_TYPE nType, unsigned long long* pArray) +{ + int ret = 0; + ASSISTANT_NOTIFY_INFO notifyInfo; + + memset(¬ifyInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO)); + + notifyInfo.type = nType; + notifyInfo.cmd = cmdNotify; + + if(pArray) + { + notifyInfo.nItems = nItems; + for(int i = 0; i < nItems; i++) + { + notifyInfo.ids[i] = pArray[i]; + } + } + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_NOTIFY, + JSON_ENGINE_ASSISTANT_NOTIFY, + ¬ifyInfo, TRUE); + + return (ret); +} + +static void __cleanupAlarmArray(void) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pAlarmArray, pItem, pTmp) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pAlarmArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvListRwLock); +} + +static void __cleanupRemaindArray(void) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pRemaindArray, pItem, pTmp) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pRemaindArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvListRwLock); +} + +static void __cleanupSessionArray(void) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pSessionArray, pItem, pTmp) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pSessionArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvListRwLock); +} + +static int __addNewItems(PASSISTANT_SYNC_INFO pInfo) +{ + struct tm localTime; + time_t loclStamp, tmStamp = time((time_t*)NULL); + + localtime_r(&tmStamp, &localTime); + loclStamp = mktime(&localTime); + + for(int i = 0; i < pInfo->nItems; i++) + { + PASSISTANT_ARRAY_INFO pItem = (PASSISTANT_ARRAY_INFO)malloc(sizeof(struct ASSISTANT_ARRAY_INFO)); + + if(pItem == NULL) + { + LOG_EX(LOG_Error, "Malloc Memory Error\n"); + return (-ERR_MALLOC_MEMORY); + } + + memset(pItem, 0, sizeof(struct ASSISTANT_ARRAY_INFO)); + + strcpy(pItem->alarmItem.strTips, pInfo->pAlarmInfo[i].strTips); + strcpy(pItem->alarmItem.resUrl, pInfo->pAlarmInfo[i].resUrl); + strcpy(pItem->alarmItem.voiceRes, pInfo->pAlarmInfo[i].voiceRes); + strcpy(pItem->alarmItem.voiceResType, pInfo->pAlarmInfo[i].voiceResType); + + pItem->alarmItem.itemType = pInfo->pAlarmInfo[i].itemType; + pItem->alarmItem.repeatMode = pInfo->pAlarmInfo[i].repeatMode; + pItem->alarmItem.voiceId = pInfo->pAlarmInfo[i].voiceId; + + pItem->alarmItem.year = pInfo->pAlarmInfo[i].year; + pItem->alarmItem.month = pInfo->pAlarmInfo[i].month; + pItem->alarmItem.day = pInfo->pAlarmInfo[i].day; + pItem->alarmItem.hour = pInfo->pAlarmInfo[i].hour; + pItem->alarmItem.minute = pInfo->pAlarmInfo[i].minute; + pItem->alarmItem.second = pInfo->pAlarmInfo[i].second; + pItem->alarmItem.weekDay = pInfo->pAlarmInfo[i].weekDay; + + if(ASSISTANT_TYPE_SESSION == pItem->alarmItem.itemType) + { + pItem->alarmItem.itemId = g_sessionId++; + } + else + { + pItem->alarmItem.itemId = pInfo->pAlarmInfo[i].itemId; + } + + if(pItem->alarmItem.repeatMode == REPEAT_MODE_NONE) + { + struct tm setTime; + time_t onTimeStamp; + int tmDiff; + + setTime.tm_year = pItem->alarmItem.year; + setTime.tm_mon = pItem->alarmItem.month; + setTime.tm_mday = pItem->alarmItem.day; + setTime.tm_hour = pItem->alarmItem.hour; + setTime.tm_min = pItem->alarmItem.minute; + setTime.tm_sec = pItem->alarmItem.second; + + onTimeStamp = mktime(&setTime); + tmDiff = (int)difftime(loclStamp, onTimeStamp); + + if(tmDiff >= 3) + { + LOG_EX(LOG_Warn, "%llu: Was Expired %d!!!!!!\n", pItem->alarmItem.itemId, tmDiff); + continue; + } + } + + uv_rwlock_wrlock(&g_uvListRwLock); + if(ASSISTANT_TYPE_CLOCK == pItem->alarmItem.itemType) + { + DL_APPEND(g_pAlarmArray, pItem); + } + else if(ASSISTANT_TYPE_REMAIND == pItem->alarmItem.itemType) + { + DL_APPEND(g_pRemaindArray, pItem); + } + else if(ASSISTANT_TYPE_SESSION == pItem->alarmItem.itemType) + { + DL_APPEND(g_pSessionArray, pItem); + } + else + { + LOG_EX(LOG_Error, "Unknown Type: %d\n", pItem->alarmItem.itemType); + } + uv_rwlock_wrunlock(&g_uvListRwLock); + + __addTaskToTimer(pItem); + } + + return (0); +} + +static void __removeAlarmItem(PASSISTANT_NOTIFY_INFO pRemove) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + for(int i = 0; i < pRemove->nItems; i++) + { + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pAlarmArray, pItem, pTmp) + { + if(pItem->alarmItem.itemId == pRemove->ids[i] + && pItem->alarmItem.itemType == pRemove->type) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pAlarmArray, pItem); + free(pItem); + } + } + uv_rwlock_wrunlock(&g_uvListRwLock); + } +} + +static void __removeRemaindItem(PASSISTANT_NOTIFY_INFO pRemove) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + for(int i = 0; i < pRemove->nItems; i++) + { + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pRemaindArray, pItem, pTmp) + { + if(pItem->alarmItem.itemId == pRemove->ids[i] + && pItem->alarmItem.itemType == pRemove->type) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pRemaindArray, pItem); + free(pItem); + } + } + uv_rwlock_wrunlock(&g_uvListRwLock); + } +} + +static int __alarmItemCmp(PASSISTANT_ARRAY_INFO pSrc, PASSISTANT_ARRAY_INFO pDst) +{ +#if 0 + fprintf(stdout, "id: %llu --> %llu, type: %u --> %u\n", + pSrc->alarmItem.itemId, pDst->alarmItem.itemId, + pSrc->alarmItem.itemType, pDst->alarmItem.itemType); +#endif + if(pSrc->alarmItem.itemId == pDst->alarmItem.itemId + && pSrc->alarmItem.itemType == pDst->alarmItem.itemType) + { + return (0); + } + else + { + return (1); + } +} + +static void __onAlarmCb(unsigned int tmId, unsigned int status, void *pUserData) +{ + PASSISTANT_ITEM_INFO pAlarm = (PASSISTANT_ITEM_INFO)pUserData; + PASSISTANT_ARRAY_INFO pItem = NULL; + struct ASSISTANT_ARRAY_INFO tmpItem; + + struct tm localTime; + time_t tmStamp = time((time_t*)NULL); + + localtime_r(&tmStamp, &localTime); + + LOG_EX(LOG_Debug, "Timer[%lld] %u On at [%04u-%02u-%02u %02u:%02u:%02u], status = %u\n", pAlarm->itemId, tmId, + localTime.tm_year + 1900, localTime.tm_mon + 1, localTime.tm_mday, + localTime.tm_hour, localTime.tm_min, localTime.tm_sec, + status); + + memset(&tmpItem, 0, sizeof(struct ASSISTANT_ARRAY_INFO)); + + tmpItem.alarmItem.itemId = pAlarm->itemId; + tmpItem.alarmItem.itemType = pAlarm->itemType; + + uv_rwlock_rdlock(&g_uvListRwLock); + if(pAlarm->itemType == ASSISTANT_TYPE_CLOCK) + { + DL_SEARCH(g_pAlarmArray, pItem, &tmpItem, __alarmItemCmp); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_REMAIND) + { + DL_SEARCH(g_pRemaindArray, pItem, &tmpItem, __alarmItemCmp); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_SESSION) + { + DL_SEARCH(g_pSessionArray, pItem, &tmpItem, __alarmItemCmp); + } + else + { + LOG_EX(LOG_Error, "Unknown type: %d\n", pAlarm->itemType); + } + uv_rwlock_rdunlock(&g_uvListRwLock); + + if(pItem) + { + pItem->alarmItem.year += 1900; + pItem->alarmItem.month += 1; + + __assistantRunningEvent(&pItem->alarmItem); + + if((pItem->alarmItem.repeatMode & 0xFF) == REPEAT_MODE_NONE) + { + uv_rwlock_wrlock(&g_uvListRwLock); + if(pAlarm->itemType == ASSISTANT_TYPE_CLOCK) + { + DL_DELETE(g_pAlarmArray, pItem); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_REMAIND) + { + DL_DELETE(g_pRemaindArray, pItem); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_SESSION) + { + DL_DELETE(g_pSessionArray, pItem); + } + else + { + LOG_EX(LOG_Error, "Unknown type: %d\n", pAlarm->itemType); + } + uv_rwlock_wrunlock(&g_uvListRwLock); + + free(pItem); + } + } +} + +static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t *pLoop, DBusConnection *pConn, PDBUS_MSG_PACK pMsg) +{ + PASSISTANT_SYNC_INFO pInfo = NULL; + PASSISTANT_NOTIFY_INFO pNotifyInfo = NULL; + int err = 0; + + if(!pMsg || !pLoop || !pConn) + { + return (NULL); + } + + if(pMsg->msgDests == 0xFFFFFFFF) + { + return (NULL); + } + + LOG_EX(LOG_Debug, "JSON(%08X) %s: %s\n", pMsg->busCmd, DBusCmdToString(pMsg->busCmd), (const char *)pMsg->pMsg); + + switch(pMsg->busCmd) + { + case CMD_SESSION_ALARM_SYNC: + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err); + + if(pInfo) + { + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + __cleanupSessionArray(); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + } + + __assistantRspStatus(pMsg->busCmd, err); + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_ALARM_SYNC_RSP: + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err); + + if(pInfo) + { + g_syncFlags |= 1 << ASSISTANT_TYPE_CLOCK; + + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + __cleanupAlarmArray(); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + } + + __assistantRspStatus(pMsg->busCmd, err); + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + break; + + case CMD_ALARM_ADD: + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, TRUE, &err); + + if(pInfo) + { + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + __assistantRspStatus(pMsg->busCmd, err); + + if(err == 0) + { + __assistantNotifyChange(pMsg->busCmd, pInfo->nItems, ASSISTANT_TYPE_CLOCK, pInfo->pAlarmInfo); + } + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_ALARM_REMOVE: + pNotifyInfo = (PASSISTANT_NOTIFY_INFO)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_ASSISTANT_NOTIFY, FALSE, &err); + + if(pNotifyInfo) + { + __printAssistantNofifyInfo(DBusCmdToString(pMsg->busCmd), pNotifyInfo); + + if(pNotifyInfo->nItems > 0) + { + __removeAlarmItem(pNotifyInfo); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantArrayNotifyChange(pMsg->busCmd, pNotifyInfo->nItems, ASSISTANT_TYPE_CLOCK, pNotifyInfo->ids); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pNotifyInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + break; + + case CMD_ALARM_REMOVEALL: + __cleanupAlarmArray(); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantNotifyChange(pMsg->busCmd, 0, ASSISTANT_TYPE_CLOCK, NULL); + break; + + case CMD_REMAIND_SYNC_RSP: + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err); + + if(pInfo) + { + g_syncFlags |= 1 << ASSISTANT_TYPE_REMAIND; + + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + __cleanupRemaindArray(); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + } + + __assistantRspStatus(pMsg->busCmd, err); + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_REMAIND_ADD: + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, TRUE, &err); + + if(pInfo) + { + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + __assistantRspStatus(pMsg->busCmd, err); + + if(err == 0) + { + __assistantNotifyChange(pMsg->busCmd, pInfo->nItems, ASSISTANT_TYPE_REMAIND, pInfo->pAlarmInfo); + } + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_REMAIND_REMOVE: + pNotifyInfo = (PASSISTANT_NOTIFY_INFO)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_ASSISTANT_NOTIFY, FALSE, &err); + + if(pNotifyInfo) + { + __printAssistantNofifyInfo(DBusCmdToString(pMsg->busCmd), pNotifyInfo); + + if(pNotifyInfo->nItems > 0) + { + __removeRemaindItem(pNotifyInfo); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantArrayNotifyChange(pMsg->busCmd, pNotifyInfo->nItems, ASSISTANT_TYPE_REMAIND, pNotifyInfo->ids); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pNotifyInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_REMAIND_REMOVEALL: + __cleanupRemaindArray(); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantNotifyChange(pMsg->busCmd, 0, ASSISTANT_TYPE_REMAIND, NULL); + break; + } + + return (NULL); +} + +static void __dBusDeameonCb(MODULE_NAME modName, int status) +{ + if(status) + { + LOG_EX(LOG_Error, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } + else + { + LOG_EX(LOG_Info, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } + +#if 0 + if(modName == MODULE_CONTROLLER && status == 0) + { + int ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ALARM_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret); + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_REMAIND_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret); + } +#endif +} + +static void __assistantSyncThread(void *pParam) +{ + int ret, isSynced = -1; + + LOG_EX(LOG_Debug, "Beging Sync holiday Database\n"); + + do + { + if((g_syncFlags & (1 << ASSISTANT_TYPE_CLOCK)) == 0) + { + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ALARM_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret); + } + + if((g_syncFlags & (1 << ASSISTANT_TYPE_REMAIND)) == 0) + { + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_REMAIND_SYNC_REQ, ""); + +// LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret); + } + + if(isSynced < 0) + { + isSynced = CurrentIsWorkDay(0, 0); + } + + sleep(SYNC_TIME_DELAY); + } while(g_syncFlags != ((1 << ASSISTANT_TYPE_CLOCK) | (1 << ASSISTANT_TYPE_REMAIND))); + + LOG_EX(LOG_Debug, "Sync holiday Database Finished\n"); + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ALARM_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret); + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_REMAIND_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret); + + pthread_detach(pthread_self()); +} + +int main(int argc, char **argv) +{ + int ret = 0; + DBusConnection* pBus; + uv_loop_t* pLoop = GetDBusDefaultLoop(); + uv_thread_t uvSyncThread; + + pBus = DBusWithLibuvInit(pLoop, g_pModInfoTable[MODULE_ALARM].modAliase, + __dBusOnMessage, + __dBusDeameonCb, + NULL, &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return 0; + } + + uv_rwlock_init(&g_uvListRwLock); + + AlarmTimerInit(pLoop); + + g_syncFlags = 0; + uv_thread_create(&uvSyncThread, __assistantSyncThread, NULL); + RunUVLoop(pLoop); + + while(TRUE) + { + usleep(1000); + } + + return 0; +} diff --git a/Modules/ConfigServer/config_server.c b/Modules/ConfigServer/config_server.c new file mode 100644 index 0000000..e7b2ed0 --- /dev/null +++ b/Modules/ConfigServer/config_server.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PLATFORM_R16 +#include "log.h" +#include "libuv_dbus.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#else +#include +#include +#include +#include +#include +#endif + +static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ +#if 0 + int err; + int iValue; + double dValue; + PCFG_API_REQ pReq = NULL; + const char *pJsonStr = NULL; + CFG_API_RSP cfgRsp; + char *pEndPtr = NULL; + int overWrite = FALSE; + + if(pMsg == NULL || pMsg->pMsg == NULL) + { + return (NULL); + } + + pJsonStr = (const char *)pMsg->pMsg; + pReq = (PCFG_API_REQ)Json2Struct(pJsonStr, JSON_ENGINE_CFG_REQ, TRUE, &err); + + memset(&cfgRsp, 0, sizeof(CFG_API_RSP)); + strncpy(cfgRsp.keyName, pReq->keyName, MAX_CFG_KEY_NAME); + strncpy(cfgRsp.keyValue, pReq->keyValue, MAX_CFG_KEY_VALUE); + cfgRsp.keyType = pReq->keyType; + + if(pReq == NULL || err != 0) + { + LOG_EX(LOG_Error, "Decode Json Error: %p, %d\n", pReq, err); + if(pReq) + { + free(pReq); + } + return (NULL); + } + + switch(pMsg->busCmd) + { + case CMD_CFG_ADD: + case CMD_CFG_CHANGE: + + if(pMsg->busCmd == CMD_CFG_CHANGE) + { + CFG_ITEM item; + PCFG_ITEM pItem = &item; + + if(CfgGetKeyValue(pReq->keyName, &pItem) == -ERR_CFG_NOITEM) + { + cfgRsp.errNo = -ERR_CFG_NOITEM; + DBusJsonSendToCommand(NULL, g_pModInfoTable[pMsg->msgSrc].modAliase, CMD_CFG_UPG_NOTIFY, JSON_ENGINE_CFG_RSP, &cfgRsp, TRUE); + return (NULL); + } + + overWrite = TRUE; + } + + switch(pReq->keyType) + { + case CFG_TYPE_STRING: + cfgRsp.errNo = CfgAddGlobalStringItem(pReq->keyName, pReq->keyValue, overWrite); + break; + + case CFG_TYPE_INT: + iValue = strtol(pReq->keyValue, NULL, 10); + + if(errno != ERANGE && errno != EINVAL) + { + cfgRsp.errNo = CfgAddGlobalIntItem(pReq->keyName, iValue, overWrite); + + if(cfgRsp.errNo != 0) + { + LOG_EX(LOG_Error, "Add Configure [%s](%d) --> [%s] Error: %d\n", + pReq->keyName, pReq->keyType, pReq->keyValue, err); + } + } + else + { + cfgRsp.errNo = -ERR_INPUT_PARAMS; + + LOG_EX(LOG_Error, "Input Params Error: [%s](%d) --> [%s]\n", + pReq->keyName, pReq->keyType, pReq->keyValue); + } + + break; + + case CFG_TYPE_DOUBLE: + dValue = strtod(pReq->keyValue, &pEndPtr); + + if((errno == ERANGE) || (dValue == 0 && (strcmp(pReq->keyName, pEndPtr) == 0))) + { + cfgRsp.errNo = -ERR_INPUT_PARAMS; + LOG_EX(LOG_Error, "Input Params Error: [%s](%d) --> [%s]\n", + pReq->keyName, pReq->keyType, pReq->keyValue); + } + else + { + cfgRsp.errNo = CfgAddGlobalIntItem(pReq->keyName, dValue, overWrite); + + if(cfgRsp.errNo != 0) + { + LOG_EX(LOG_Error, "Add Configure [%s](%d) --> [%s] Error: %d\n", + pReq->keyName, pReq->keyType, pReq->keyValue, err); + } + } + break; + + default: + cfgRsp.errNo = -ERR_UNKNOWN_TYPE; + break; + } + + if(cfgRsp.errNo == 0) + { + DBusJsonBoardcastCommand(NULL, 0xFFFFFFFF, CMD_CFG_UPG_NOTIFY, JSON_ENGINE_CFG_RSP, &cfgRsp, TRUE); + } + else + { + DBusJsonSendToCommand(NULL, g_pModInfoTable[pMsg->msgSrc].modAliase, CMD_CFG_UPG_NOTIFY, JSON_ENGINE_CFG_RSP, &cfgRsp, TRUE); + } + break; + + case CMD_CFG_GET: + { + PCFG_ITEM pItem = NULL; + + if(CfgGetKeyValue(pReq->keyName, &pItem) == -ERR_CFG_NOITEM) + { + cfgRsp.errNo = -ERR_CFG_NOITEM; + DBusJsonSendToCommand(NULL, g_pModInfoTable[pMsg->msgSrc].modAliase, CMD_CFG_UPG_NOTIFY, JSON_ENGINE_CFG_RSP, &cfgRsp, TRUE); + return (NULL); + } + else + { + memset(cfgRsp.keyValue, 0, MAX_CFG_KEY_VALUE); + cfgRsp.keyType = pItem->keyType; + + if(pItem->keyType == CFG_TYPE_STRING) + { + strncpy(cfgRsp.keyValue, pItem->pStrValue, MAX_CFG_KEY_VALUE); + } + else if(pItem->keyType == CFG_TYPE_INT) + { + sprintf(cfgRsp.keyValue, "%d", pItem->intValue); + } + else if(pItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(cfgRsp.keyValue, "%f", pItem->doubleValue); + } + + DBusJsonSendToCommand(NULL, g_pModInfoTable[pMsg->msgSrc].modAliase, CMD_CFG_GET, JSON_ENGINE_CFG_RSP, &cfgRsp, TRUE); + } + } + break; + + default: + //cfgRsp.errNo = -ERR_UNKNOWN_TYPE; + //DBusJsonSendToCommand(NULL, g_pModInfoTable[pMsg->msgSrc].modAliase, CMD_CFG_UPG_NOTIFY, JSON_ENGINE_CFG_RSP, &cfgRsp, TRUE); + break; + } +#endif + return NULL; +} + +static void __dBusHeartLost(MODULE_NAME loster) +{ + LOG_EX(LOG_Error, "Found %d Heart Lost\n", loster); +} + +int main(int argc, char** argv) +{ + int ret = 0; + uv_loop_t* pLoop = GetDBusDefaultLoop(); + DBusConnection* pBus = DBusWithLibuvInit(pLoop, g_pModInfoTable[MODULE_CONFIGURE].modAliase, + __dBusOnMessage, + NULL, + NULL, &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return 0; + } + + //DBusWithLibuvCfgInit(__onCfgMsgCb); + //DBusWithLibuvCfgInit(); + return uv_run(pLoop, UV_RUN_DEFAULT); +} + diff --git a/Modules/LogCtrl/log_ctrl.c b/Modules/LogCtrl/log_ctrl.c new file mode 100644 index 0000000..ce94a86 --- /dev/null +++ b/Modules/LogCtrl/log_ctrl.c @@ -0,0 +1,323 @@ + #include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) +#include "log.h" +#include "libuv_dbus.h" +#include "json_struct.h" + +#else +#include +#include +#include +#endif + +static MOD_INFO_TABLE g_ModInfo; + + +static PDBUS_MSG_PACK DBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ + //int i, ret, err; + //uint32_t tm = LIBUV_CURRENT_TIME_US(); + + if(!pMsg || !pLoop || !pConn) + { + return NULL; + } + + //LOG_EX(LOG_Info, "Process Message(%u --> 0x%08X) at [%lu.%06lu]: cmd = %u, size = %u, key = %d, msg(%d) = [%s]\n", + // pMsg->msgSrc, pMsg->msgDests, tm / 1000000, tm % 1000000, pMsg->busCmd, pMsg->msgSize, pMsg->msgKey, pMsg->msgSize, pMsg->pMsg); + + return NULL; +} + +static void __logCtrlProc(void *pParams) +{ + int i = 0; + //int ret; + + LOG_LEVEL logLevelInfo[] = { + LOG_Fatal, LOG_Error, LOG_Warn, LOG_Debug, LOG_Info, + LOG_Test, LOG_Call, LOG_Devp, LOG_Step, LOG_Unknown, LOG_All, LOG_Close + }; + + const char* g_Menu[] = { + "Usage: enable/disable [params1] [params2]\n" + " help\n", + " quit\n", + }; + + const char* pOptMenu[] = { + "\n operation:\n" + " |--------------------------------------------------------------------------|\n", + " | command | operation | params1 | params2 |\n", + " |--------------------------------------------------------------------------|\n", + " | enable | | | |\n", + " |----------| 0: Set log level | Log level | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | | |\n", + " |----------| 1: Print to file | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | | |\n", + " |----------| 2: Backup to email | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | Log server ip address | Log server port |\n", + " |----------| 3: Send to network |-----------------------|-----------------|\n", + " | disable | | Unused | Unused |\n", + " |--------------------------------------------------------------------------|\n", + " | enable | | | |\n", + " |----------| 4: Backup to Server | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + }; + + while(TRUE) + { + char *pInput = NULL; + char *pCmd = NULL; + + for(i = 0; i < sizeof(g_Menu) / sizeof(g_Menu[0]); i++) + { + LOG_EX2(LOG_Info, "%s", g_Menu[i]); + } + + pInput = readline("Enter Command:"); + + if(pInput == NULL) + { + continue; + } + + pCmd = strtok(pInput, " "); + i = 0; + + while(pCmd != NULL) + { + if(strcmp(pCmd, "help") == 0) + { + for(i = 0; i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0]); i++) + { + if(i == 0) + { + LOG_EX2(LOG_Info, " modName : %-2d --> %s\n", + i, ModuleNameToString(g_pModInfoTable[i].modName)); + } + else + { + LOG_EX2(LOG_Info, "%15s%-2d --> %s\n", "", + i, ModuleNameToString(g_pModInfoTable[i].modName)); + } + } + + for(i = 0; i < sizeof(logLevelInfo) / sizeof(logLevelInfo[0]); i++) + { + if(i == 0) + { + LOG_EX2(LOG_Info, "\n Log Level: %-2d --> %s\n", i, LogLeveToString(logLevelInfo[i])); + } + else + { + LOG_EX2(LOG_Info, "%15s%-2d --> %s\n", "", i, LogLeveToString(logLevelInfo[i])); + } + } + + for(i = 0; i < sizeof(pOptMenu) / sizeof(pOptMenu[0]); i++) + { + LOG_EX2(LOG_Info, "%s", pOptMenu[i]); + } + } + else if(strcmp(pCmd, "enable") == 0 + || strcmp(pCmd, "disable") == 0) + { + LOG_CFG_PROTOCOL logItem; + int iCmd, iMod; + char *pParams1 = NULL, *pParams2 = NULL; + char* pMod = strtok(NULL, " "); + char* pOperat = strtok(NULL, " "); + + if(pMod == NULL || strlen(pMod) == 0) + { + LOG_EX(LOG_Error, "Input error, see help\n"); + break; + } + + if(pOperat == NULL || strlen(pOperat) == 0) + { + LOG_EX(LOG_Error, "Input error, see help\n"); + break; + } + + iMod = strtol(pMod, NULL, 10); + + if(iMod < 0 || iMod >= MODULE_MAX) + { + LOG_EX(LOG_Error, "Input error: %s(%d)\n", pMod, iMod); + break; + } + + iCmd = strtol(pOperat, NULL, 10); + + memset(&logItem, 0, sizeof(LOG_CFG_PROTOCOL)); + + switch(iCmd) + { + case 0: + pParams1 = strtok(NULL, " "); + if(pParams1 && strlen(pParams1) > 0) + { + int logLevel = strtol(pParams1, NULL, 10); + + if(logLevel >= 0 && logLevel < sizeof(logLevelInfo) / sizeof(logLevelInfo[0])) + { + LOG_EX2(LOG_Info, "%s %d 0x%08X\n", pCmd, iCmd, logLevelInfo[logLevel]); + + logItem.cfgCmd = CMD_LOG_LEVEL; + logItem.iParams2 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + logItem.iParams1 = logLevelInfo[logLevel]; + + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + LOG_EX(LOG_Error, "Input error, see help\n"); + } + } + else + { + LOG_EX(LOG_Error, "Input error, see help\n"); + } + break; + + case 1: + logItem.cfgCmd = CMD_LOG_FILE; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + case 2: + logItem.cfgCmd = CMD_LOG_MAIL; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + case 3: + pParams1 = strtok(NULL, " "); + + logItem.cfgCmd = CMD_LOG_NETWORK; + if(pParams1 == NULL || strlen(pParams1) == 0) + { + + logItem.iParams1 = 0; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + pParams2 = strtok(NULL, " "); + + if(pParams2 != NULL && strlen(pParams2) > 0) + { + logItem.iParams1 = inet_addr(pParams1); + logItem.iParams2 = strtol(pParams2, NULL, 10); + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + LOG_EX(LOG_Error, "Input error, pParams2 = %s\n", + SAFE_STRING_VALUE(pParams2)); + } + } + + break; + + case 4: + logItem.cfgCmd = CMD_LOG_SERVER; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + default: + LOG_EX(LOG_Error, "Unknown operation(0-3) %s, see help\n", pOperat); + break; + } + } + else if(strcmp(pCmd, "quit") == 0) + { + return; + } + + pCmd = strtok(NULL, " "); + } + + usleep(1000); + } + + pthread_detach(pthread_self()); +} + +int main(int argc, char **argv) +{ + int ret = 0; + DBusConnection* pBus = NULL; + uv_thread_t uvThread; + uv_loop_t* pLoop = GetDBusDefaultLoop(); + + memcpy(&g_ModInfo, &g_pModInfoTable[MODULE_LOG_CTRL], sizeof(MOD_INFO_TABLE)); + + pBus = DBusWithLibuvInit(pLoop, g_ModInfo.modAliase, + DBusOnMessage, + NULL, + NULL, + &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return 0; + } + + uv_thread_create(&uvThread, __logCtrlProc, NULL); + + RunUVLoop(pLoop); + + while(TRUE) + { + usleep(1000); + } + + return (0); +} + diff --git a/Modules/OTA/ota.c b/Modules/OTA/ota.c new file mode 100644 index 0000000..953bb07 --- /dev/null +++ b/Modules/OTA/ota.c @@ -0,0 +1,1389 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) +#include "log.h" +#include "libuv_dbus.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#include "inet_api.h" +#include "ota.h" +#else +#include +#include +#include +#include +#include +#include +#include +#endif + + +#define MAX_IPL_ITEM (4) +#define IPL_PARAMS_PARTITION ("/dev/by-name/IPL3") +#define IPL3_MAGIC_NAME ("R16IPL3\0") +#define BOOT_IMG_FILE_NAME ("boot.img") +#define ROOTFS_IMG_FILE_NAME ("rootfs.img") +#define EXT_FS_UUID_FILE ("/etc/.extroot-uuid") +#define OTA_TEMP_DIR ("/tmp/ota") +#define OTA_FILE_DOWNLOAD_DIR ("/mnt/UDISK/ota") +#define OTA_MEMORY_DOWNLOAD_DIR ("/tmp/UDISK/ota") + +typedef enum +{ + OTA_PARTITION_BOOT = 0, + OTA_PARTITION_ROOTFS, + OTA_PARTITION_IPL_BOOT, + OTA_PARTITION_IPL_ROOTFS, + OTA_PARTITION_IPL_PARAMS, + OTA_PARTITION_MAX +} OTA_PARTITION_NAME; + +typedef struct +{ + OTA_PARTITION_NAME partName; + const char *pPartPath; + unsigned int partSize; +} OTA_PARTITION_INFO, *POTA_PARTITION_INFO; + +typedef struct { + unsigned int fileSize; + unsigned char md5sum[MD5_CHKSUM_LEN]; + int reserved[4]; +}IPL_DATA_ITEM, *PIPL_DATA_ITEM; + +typedef struct { + char pMagicTag[8]; + unsigned int setupStatus; + SETUP_MODE setupMode; + int curVersion; +// int kernelVer; +// char rfsVersion[1024]; + IPL_DATA_ITEM iplItem[OTA_PARTITION_MAX - 1]; + unsigned char md5sum[MD5_CHKSUM_LEN]; +}IPL_DATA_INFO, *PIPL_DATA_INFO; + +typedef struct +{ + OTA_FILE_INFO fileInfo; + + char pPath[MAX_PATH]; + int dlStatus; + int retCode; + uv_barrier_t* puvBarrier; +} DOWNLOAD_TASK_INFO, *PDOWNLOAD_TASK_INFO; + +static IPL_DATA_INFO g_iplInfo; +static char g_otaDownloadPath[MAX_PATH]; +static SETUP_MODE g_sSetupStatus = NORMAL_SETUP; + +static OTA_PARTITION_INFO g_otaPartInfo[] = { + {OTA_PARTITION_BOOT, "/dev/by-name/boot", 0}, + {OTA_PARTITION_ROOTFS, "/dev/by-name/rootfs", 0}, + {OTA_PARTITION_IPL_BOOT, "/dev/by-name/IPL1", 0}, + {OTA_PARTITION_IPL_ROOTFS, "/dev/by-name/IPL2", 0}, + {OTA_PARTITION_IPL_PARAMS, "/dev/by-name/IPL3", 0}, +}; + +static unsigned int g_IsOTAMode = 0; +static uv_barrier_t g_otaBarrier; +static uv_loop_t* g_pMainLoop = NULL; +static int g_isDownloading = FALSE; +static int g_isBackupMode = FALSE; + +static const char *g_umountPart[] = { "/usr", "/overlay", "/boot", "/rom", "/" }; + +static void __printfOTANotifyCmd(const char *pTags, POTA_DATA_INFO pInfo) +{ + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Debug, "%s:\n", pTags); + LOG_EX2(LOG_Debug, "**************************************************************\n"); + } + + LOG_EX2(LOG_Debug, "Version : %d\n", pInfo->version); + LOG_EX2(LOG_Debug, "OTA Command : %d(0x%08X)\n", pInfo->otaCmd, pInfo->otaCmd); + LOG_EX2(LOG_Debug, "OTA Type : %d(0x%08X)\n", pInfo->otaMode, pInfo->otaMode); + + LOG_EX2(LOG_Debug, "---------------------------------------------------------\n"); + LOG_EX2(LOG_Debug, "\tURL : %s\n", pInfo->otaFileInfo.url); + LOG_EX2(LOG_Debug, "\tMD5 : %s\n", pInfo->otaFileInfo.md5); + LOG_EX2(LOG_Debug, "\tsize : %u\n", pInfo->otaFileInfo.size); +} + +static int __otaRspStatus(OTA_STATUS_TYPE type, int val) +{ + int ret = 0; + OTA_RSP_STATUS oStatus; + + if(OTA_ERR_CODE == type && val != 0) + { + g_IsOTAMode = FALSE; + } + + memset(&oStatus, 0, sizeof(OTA_RSP_STATUS)); + + oStatus.status = type; + oStatus.val = val; + + LOG_EX(LOG_Debug, "Rsponse: %d --> %d\n", type, val); + + if(type == OTA_UPGRADE_START || type == OTA_REBOOT_SYSTEM || type == OTA_RECOVERY_START) + { + ret = DBusJsonBoardcastCommand(NULL, 0xFFFFFFFF, CMD_OTA_STATUS, JSON_ENGINE_OTA_RSP, &oStatus, FALSE); + } + else + { + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_OTA_STATUS, + JSON_ENGINE_OTA_RSP, + &oStatus, FALSE); + } + + return (ret); +} + +#if 0 +static void __dlThreadRuntimeCb(void *pParams) +{ + PDOWNLOAD_TASK_INFO pDlInfo = (PDOWNLOAD_TASK_INFO)pParams; + + LOG_EX(LOG_Debug, "Cleanup barrier\n"); + uv_barrier_wait(pDlInfo->puvBarrier); + pthread_detach(pthread_self()); +} +#endif + +void __onHttpResponseCb(void *pData, unsigned int size, const char *pReqUrl, const char* pDlPath, const char *pTaskUuid, int iFinished, void *pUserData) +{ + PDOWNLOAD_TASK_INFO pDlInfo = (PDOWNLOAD_TASK_INFO)pUserData; + + if(iFinished == 0) + { + LOG_EX(LOG_Debug, "Request(%s): [%s] --> [%s] Response: [%u] OK\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else if(iFinished == 1) + { + LOG_EX(LOG_Error, "Request(%s): [%s] --> [%s] Response: [%u] Error\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else + { + LOG_EX(LOG_Error, "Download Error Code: %d\n", iFinished); + } + + if(pDlInfo) + { +// int err; + uv_thread_t uvThread; + pDlInfo->retCode = iFinished; +// LOG_EX(LOG_Debug, "Cleanup barrier task start: %u\n", g_ThreadCnt); + LOG_EX(LOG_Debug, "Cleanup barrier\n"); + uv_barrier_wait(pDlInfo->puvBarrier); +#if 0 + g_ThreadCnt++; + err = uv_thread_create(&uvThread, __dlThreadRuntimeCb, pDlInfo); + + if(err != 0) + { + LOG_EX(LOG_Error, "1:Create Thread Error: %d\n", err); + } +#endif + } + else + { + LOG_EX(LOG_Debug, "pDlInfo == NULL\n"); + } +} + +void __onProgressNotifyCb(const char *pReqUrl, const char *pTaskUuid, unsigned char uPercent, void* pUserData) +{ + static unsigned char preCnt = 0; + + if(preCnt != uPercent && uPercent != 0) + { + preCnt = uPercent; + __otaRspStatus(OTA_DOWNLOAD_PROGRESS, uPercent); + LOG_EX(LOG_Debug, "[%s]: %u%%\n", pReqUrl, uPercent); + } +} + +static void __printIPLParams(PIPL_DATA_INFO pIPLInfo, const char* pTags) +{ + int i; + char md5[MD5_CHKSUM_STR_LEN]; + + if(pTags != NULL && strlen(pTags) > 0) + { + LOG_EX2(LOG_Debug, "%s\n", pTags); + LOG_EX2(LOG_Debug, "------------------------------------------------\n"); + } + LOG_EX2(LOG_Debug, "Magic Tag : %s\n", pIPLInfo->pMagicTag); + LOG_EX2(LOG_Debug, "Setup Status : %u\n", pIPLInfo->setupStatus); + LOG_EX2(LOG_Debug, "Setup Module : %d(0x%08X)\n", pIPLInfo->setupMode, pIPLInfo->setupMode); + LOG_EX2(LOG_Debug, "Version : %d\n", pIPLInfo->curVersion); + + memset(md5, 0, MD5_CHKSUM_STR_LEN); + + IHW_bin2hex(md5, pIPLInfo->md5sum, MD5_CHKSUM_LEN); + LOG_EX2(LOG_Debug, "MD5 Checksum : %s\n", md5); + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------------\n"); + LOG_EX2(LOG_Debug, "| Partition | size | MD5 Checksum |\n"); + LOG_EX2(LOG_Debug, "-------------------------------------------------------------------\n"); + + for(i = 0; i < sizeof(pIPLInfo->iplItem) / sizeof(pIPLInfo->iplItem[0]); i++) + { + char *pPartName = strdup(g_otaPartInfo[i].pPartPath); + + memset(md5, 0, MD5_CHKSUM_STR_LEN); + IHW_bin2hex(md5, pIPLInfo->iplItem[i].md5sum, MD5_CHKSUM_LEN); + LOG_EX2(LOG_Debug, "| %9s | %16u | %32s |\n", basename_v2(pPartName), pIPLInfo->iplItem[i].fileSize, md5); + free(pPartName); + } + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------------\n"); +} + +static int __ReadIPLParams(PIPL_DATA_INFO pIPLInfo) +{ + uv_fs_t uvOpen, uvRead, uvClose; + int ret, rdSize = 0; + unsigned char md5Buf[MD5_CHKSUM_LEN]; + + uv_loop_t* pLoop = g_pMainLoop; + uv_buf_t uvBuf = uv_buf_init((char*)pIPLInfo, sizeof(IPL_DATA_INFO)); + + if(pIPLInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + memset(pIPLInfo, 0, sizeof(IPL_DATA_INFO)); + + ret = system("sync"); + + if(uv_fs_open(pLoop, &uvOpen, IPL_PARAMS_PARTITION, O_RDWR, 0, NULL) == -1) + { + LOG_EX(LOG_Error, "Open Partition %s Error\n", IPL_PARAMS_PARTITION); + return (-ERR_OPEN_FILE); + } + + if((rdSize = uv_fs_read(pLoop, &uvRead, uvOpen.result, &uvBuf, 1, -1, NULL)) != sizeof(IPL_DATA_INFO)) + { + LOG_EX(LOG_Error, "Read Partition Error: Read %d Bytes, Need Read %d Bytes %d\n", rdSize, sizeof(IPL_DATA_INFO)); + return (-ERR_READ_FILE); + } + + uv_fs_close(pLoop, &uvClose, uvOpen.result, NULL); + + if(memcmp(pIPLInfo->pMagicTag, IPL3_MAGIC_NAME, 8) != 0) + { + LOG_EX(LOG_Error, "Check Magic Head Error: [%s], need [%s]\n", pIPLInfo->pMagicTag, IPL3_MAGIC_NAME); + return (-ERR_NO_INIT_IPL3); + } + + EvpMD5HashBuf((const unsigned char *)pIPLInfo, sizeof(IPL_DATA_INFO) - MD5_CHKSUM_LEN, md5Buf, &rdSize); + + if(memcmp(pIPLInfo->md5sum, md5Buf, MD5_CHKSUM_LEN) != 0) + { + //print_hex_dump_bytes("CACL_", DUMP_PREFIX_ADDRESS, md5Buf, MD5_CHKSUM_LEN); + //print_hex_dump_bytes("SAVE_", DUMP_PREFIX_ADDRESS, pIPLInfo->md5sum, MD5_CHKSUM_LEN); + + LOG_EX(LOG_Error, "Verify MD5 Error\n"); + return (-ERR_BAD_IPL3); + } + + //print_hex_dump_bytes("IPL3", DUMP_PREFIX_ADDRESS, pIPLInfo, sizeof(IPL_DATA_INFO)); + + return (0); +} + +static int __Write2NandPartition(OTA_PARTITION_NAME partName, const char *pFilePath) +{ + int fileSize = 0; + char bufCmd[MAX_PATH]; + + if(partName < 0 || partName >= OTA_PARTITION_MAX || pFilePath == NULL || strlen(pFilePath) == 0) + { + LOG_EX(LOG_Error, "Input params error\n"); + return (-ERR_INPUT_PARAMS); + } + + if(access(pFilePath, F_OK) == -1) + { + LOG_EX(LOG_Error, "File %s not exist\n", pFilePath); + return (-ERR_FILE_NOT_EXISTS); + } + + GET_FILE_SIZE(pFilePath, fileSize); + + if(fileSize > g_otaPartInfo[partName].partSize || fileSize == -1) + { + LOG_EX(LOG_Error, "File %s size %d more than partition size %u\n", + pFilePath, fileSize, g_otaPartInfo[partName].partSize); + return (-ERR_BAD_FILE_SIZE); + } + + memset(bufCmd, 0, MAX_PATH); + + if(partName == OTA_PARTITION_IPL_ROOTFS || partName == OTA_PARTITION_ROOTFS) + { + sprintf(bufCmd, "dd if=%s of=%s bs=128k conv=sync", pFilePath, g_otaPartInfo[partName].pPartPath); + } + else + { + sprintf(bufCmd, "dd if=%s of=%s bs=4k conv=sync", pFilePath, g_otaPartInfo[partName].pPartPath); + } + + LOG_EX(LOG_Debug, "Run OTA: [%s]\n", bufCmd); + + fileSize = system(bufCmd); + fileSize = system("sync"); + + return (0); +} + +static int __SaveIPLParams(PIPL_DATA_INFO pIPLInfo) +{ + int ret, wrSize = 0; + uv_fs_t uvOpen, uvWrite, uvSync, uvClose; + unsigned char md5Buf[MD5_CHKSUM_LEN]; + unsigned char buf[MAX_PATH]; + + uv_loop_t* pLoop = g_pMainLoop; + uv_buf_t uvBuf = uv_buf_init((char*)pIPLInfo, sizeof(IPL_DATA_INFO)); + + if(pIPLInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + if(memcmp(pIPLInfo->pMagicTag, IPL3_MAGIC_NAME, 8) != 0) + { + memcpy(pIPLInfo->pMagicTag, IPL3_MAGIC_NAME, 8); + LOG_EX(LOG_Error, "Check Magic Head Error: [%s], need [%s]\n", pIPLInfo->pMagicTag, IPL3_MAGIC_NAME); + return (-ERR_NO_INIT_IPL3); + } + + EvpMD5HashBuf((const unsigned char *)pIPLInfo, sizeof(IPL_DATA_INFO) - MD5_CHKSUM_LEN, md5Buf, &wrSize); + + if(wrSize != MD5_CHKSUM_LEN) + { + LOG_EX(LOG_Error, "Error MD5: size = %d, need %d\n", wrSize, MD5_CHKSUM_LEN); + return (-ERR_BAD_IPL3); + } + + memcpy(pIPLInfo->md5sum, md5Buf, MD5_CHKSUM_LEN); + + memset(buf, 0, MAX_PATH); + ret = system("mkdir -p /tmp/ota_param/"); + sprintf(buf, "/tmp/ota_param/ota_%d.params", pIPLInfo->curVersion); + + //print_hex_dump_bytes("IPL3", DUMP_PREFIX_ADDRESS, pIPLInfo, sizeof(IPL_DATA_INFO)); + + if(uv_fs_open(pLoop, &uvOpen, buf, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, NULL) == -1) + { + LOG_EX(LOG_Error, "Open Partition %s Error\n", IPL_PARAMS_PARTITION); + return (-ERR_OPEN_FILE); + } + + if((wrSize = uv_fs_write(pLoop, &uvWrite, uvOpen.result, &uvBuf, 1, -1, NULL)) != sizeof(IPL_DATA_INFO)) + { + LOG_EX(LOG_Error, "Write Partition Error: Read %d Bytes, Need Read %d Bytes %d\n", wrSize, sizeof(IPL_DATA_INFO)); + return (-ERR_READ_FILE); + } + + uv_fs_fdatasync(pLoop, &uvSync, uvOpen.result, NULL); + uv_fs_close(pLoop, &uvClose, uvOpen.result, NULL); + + ret = __Write2NandPartition(OTA_PARTITION_IPL_PARAMS, (const char*)buf); + + if(ret != 0) + { + LOG_EX(LOG_Error, "Write OTA Params Error: %d\n", ret); + return (-ERR_OTA_WRITE_IPL3); + } + + return (0); +} + +static int __otaBackupWifi(int iBackup) +{ + int ret = 0; + if(iBackup == TRUE) + { + const char *pBackCmd = "mkdir -p /mnt/UDISK/ota/wifi_bak/ && rm -rf /mnt/UDISK/ota/wifi_bak/* \ +&& cp -rf /etc/wifi/* /mnt/UDISK/ota/wifi_bak/"; + + ret = system(pBackCmd); + } + else + { + const char *pBackCmd = "rm -rf /etc/wifi/*.* && cp -rf /mnt/UDISK/ota/wifi_bak/*.* /etc/wifi/"; + ret = system(pBackCmd); + } + + return ret; +} + +static int __otaRunning(char* pCheckSumFile, int ver) +{ + ssize_t rdRet; + size_t rdSize; + unsigned char strMD5[MD5_CHKSUM_STR_LEN]; + char dirPath[MAX_PATH]; + char basePath[MAX_PATH]; + const char *pChkMD5 = NULL; + char *pRdLine = NULL; + char *pChkSumFile = pCheckSumFile; + FILE *pFile = fopen(pChkSumFile, "r"); + int ret, i = 0; + int step = 0; + + if(pFile == NULL) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pChkSumFile); + return (-ERR_OPEN_FILE); + } + + memset(dirPath, 0, MAX_PATH); + dirname_v2(pChkSumFile, dirPath); + + LOG_EX(LOG_Debug, "Step %d: Check OTA image .......\n", step++); + // check download ota file + while((rdRet = getline(&pRdLine, &rdSize, pFile)) != -1) + { + char* pToken = NULL; + char *pItem[2]; + char pMD5Val[MD5_CHKSUM_LEN]; + char pMD5Str[MD5_CHKSUM_STR_LEN]; + int fileSize = 0; + + if(rdSize == 0 || pRdLine == NULL) + { + continue; + } + + if(pRdLine[strlen(pRdLine) - 1] == '\n') + { + pRdLine[strlen(pRdLine) - 1] = 0; + } + + i = 0; + + for(pToken = strtok(pRdLine, " "); pToken != NULL && i <= 1; pToken = strtok(NULL, " "), i++) + { + pItem[i] = pToken; + } + + //fprintf(stdout, "md5 = %s, file = \'%s\'\n", pItem[0], pItem[1]); + + if(pItem[0] == NULL || pItem[1] == NULL || strlen(pItem[0]) != 32 || strlen(pItem[1]) == 0) + { + free(pRdLine); + fclose(pFile); + return (-ERR_MD5_CHECK_SUM); + } + + memset(basePath, 0, MAX_PATH); + sprintf(basePath, "%s/%s", dirPath, pItem[1]); + + LOG_EX(LOG_Debug, "OTA File: %s --> %s\n", basePath, pItem[0]); + + if((ret = EvpMD5HashFileV2(basePath, pMD5Val)) != 0) + { + free(pRdLine); + fclose(pFile); + LOG_EX(LOG_Error, "%s Check MD5 error: %d\n", ret); + return (-ERR_MD5_FILE); + } + + memset(pMD5Str, 0, MD5_CHKSUM_STR_LEN); + IHW_bin2hex(pMD5Str, pMD5Val, MD5_CHKSUM_LEN); + + //LOG_EX(LOG_Debug, "%s Check MD5 Info: [%s] need [%s]\n", basePath, pMD5Str, pItem[0]); + + if(strcmp(pMD5Str, pItem[0]) != 0) + { + + free(pRdLine); + fclose(pFile); + LOG_EX(LOG_Error, "%s Check MD5 error: [%s] need [%s]\n", basePath, pMD5Str, pItem[0]); + return (-ERR_MD5_FILE); + } + + if(strcmp(pItem[1], BOOT_IMG_FILE_NAME) == 0) + { + memcpy(g_iplInfo.iplItem[OTA_PARTITION_BOOT].md5sum, pMD5Val, MD5_CHKSUM_LEN); + } + else if(strcmp(pItem[1], ROOTFS_IMG_FILE_NAME) == 0) + { + GET_FILE_SIZE(basePath, fileSize); + //fprintf(stdout, "fileSize = %lu\n", fileSize); + memcpy(g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].md5sum, pMD5Val, MD5_CHKSUM_LEN); + g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].fileSize = fileSize; + } + } + + if(pRdLine) + { + free(pRdLine); + } + fclose(pFile); + + LOG_EX(LOG_Debug, "Step %d: Remove EXT4 UUID File %s .......\n", step++, EXT_FS_UUID_FILE); + remove(EXT_FS_UUID_FILE); + + __otaRspStatus(OTA_VERIFY_FILE, NO_OTA_STATUS_VAL_TAG); + +#if 0 + for(i = 0; i < sizeof(g_umountPart) / sizeof(g_umountPart[0]); i++) + { + char *pRet = NULL; + + memset(cmdBuf, 0, MAX_PATH); + sprintf(cmdBuf, "cat /proc/mounts | awk '{printf $2\"\\n\"}' | grep -Fx \"%s\" | wc -L", g_umountPart[i]); + + if(GetShellExecResult(cmdBuf, &pRet) == 0) + { + unsigned int tarLen = strtoul(pRet, NULL, 10); + free(pRet); + + if(strlen(g_umountPart[i]) != tarLen) + { + continue; + } + } + + LOG_EX(LOG_Debug, "Step %d: Umount %s Partition .......\n", step++, g_umountPart[i]); + + memset(cmdBuf, 0, MAX_PATH); + sprintf(cmdBuf, "umount %s", g_umountPart[i]); + ret = system(cmdBuf); + } +#else + ret = system("umount /rom"); +#endif + + __otaRspStatus(OTA_UPGRADE_PARTITION, OTA_PARTITION_BOOT); + + // write to partition + LOG_EX(LOG_Debug, "Step %d: OTA %s Partition .......\n", step++, g_otaPartInfo[OTA_PARTITION_BOOT].pPartPath); + memset(basePath, 0, MAX_PATH); + sprintf(basePath, "%s/%s", dirPath, BOOT_IMG_FILE_NAME); + ret = __Write2NandPartition(OTA_PARTITION_BOOT, basePath); + + if(ret != 0) + { + LOG_EX(LOG_Error, "OTA OTA_PARTITION_BOOT Error: %d\n", ret); + return (-ERR_OTA_WRITE_BOOT); + } + + __otaRspStatus(OTA_UPGRADE_PARTITION, OTA_PARTITION_ROOTFS); + LOG_EX(LOG_Debug, "Step %d: OTA %s Partition .......\n", step++, g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath); + memset(basePath, 0, MAX_PATH); + sprintf(basePath, "%s/%s", dirPath, ROOTFS_IMG_FILE_NAME); + ret = __Write2NandPartition(OTA_PARTITION_ROOTFS, basePath); + + if(ret != 0) + { + LOG_EX(LOG_Error, "OTA ROOTFS_IMG_FILE_NAME Error: %d\n", ret); + return (-ERR_OTA_WRITE_ROOTFS); + } + + LOG_EX(LOG_Debug, "Step %d: Verify Partition %d .......\n", step++, OTA_PARTITION_BOOT); + + __otaRspStatus(OTA_VERIFY_PARTITION, OTA_PARTITION_BOOT); + pChkMD5 = EvpMD5HashFile(g_otaPartInfo[OTA_PARTITION_BOOT].pPartPath); + IHW_bin2hex(strMD5, g_iplInfo.iplItem[OTA_PARTITION_BOOT].md5sum, MD5_CHKSUM_LEN); + if(strcmp(pChkMD5, strMD5) != 0) + { + LOG_EX(LOG_Error, "Verify %s Partition MD5 Error: %s --> %s\n", g_otaPartInfo[OTA_PARTITION_BOOT].pPartPath, pChkMD5, strMD5); + return (-ERR_VERIFY_PARTITION_MD5); + } + + __otaRspStatus(OTA_VERIFY_PARTITION, OTA_PARTITION_ROOTFS); + LOG_EX(LOG_Debug, "Step %d: Verify Partition %d .......\n", step++, OTA_PARTITION_ROOTFS); + CopyFileWithSize(g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath, "/tmp/dump_rootfs.img", g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].fileSize); + pChkMD5 = EvpMD5HashFile("/tmp/dump_rootfs.img"); + IHW_bin2hex(strMD5, g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].md5sum, MD5_CHKSUM_LEN); + if(strcmp(pChkMD5, strMD5) != 0) + { + LOG_EX(LOG_Error, "Verify %s Partition MD5 Error: %s --> %s\n", g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath, pChkMD5, strMD5); + return (-ERR_VERIFY_PARTITION_MD5); + } + +#if 0 + LOG_EX(LOG_Debug, "Step %d: Upgrade Partition %d MD5 Checksum .......\n", step++, OTA_PARTITION_ROOTFS); + EvpMD5HashFileV2(g_otaPartInfo[OTA_PARTITION_ROOTFS].pPartPath, g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].md5sum); + g_iplInfo.iplItem[OTA_PARTITION_ROOTFS].fileSize = g_otaPartInfo[OTA_PARTITION_ROOTFS].partSize; +#endif + + LOG_EX(LOG_Debug, "Step %d: Save OTA Information .......\n", step++); + + g_iplInfo.curVersion = ver; + g_iplInfo.setupStatus = 0; + + if(g_iplInfo.setupMode != RECOVERY_SETUP) + { + g_iplInfo.setupMode = SYSTEM_OTA; + } + + ret = __SaveIPLParams(&g_iplInfo); + + if(ret != 0) + { + LOG_EX(LOG_Error, "Save IPL3 Error: %d\n", ret); + return (-ERR_OTA_WRITE_PARAMS); + } + + //print_hex_dump_bytes("IPL3", DUMP_PREFIX_ADDRESS, &g_iplInfo, sizeof(IPL_DATA_INFO)); + + __printIPLParams(&g_iplInfo, "OTA Succesed_____:"); + + LOG_EX(LOG_Debug, "Step %d: Waitting for reboot ......\n", step++); + + return (0); +} + +static void __otaFromLocalImage(void *pParams) +{ + int ret, reTry; + int step = 0; + char buf[MAX_PATH]; + char *pFileName = NULL, *pMD5Val = NULL; + const char *pMD5Chk = NULL; + int version = (int)(intptr_t)pParams; + + LOG_EX(LOG_Debug, "Step %d: Get OTA information .......\n", step++); + memset(buf, 0, MAX_PATH); + sprintf(buf, "%s/ota.md5", g_otaDownloadPath); + + if(access(buf, F_OK) != 0) + { + __otaRspStatus(OTA_ERR_CODE, -ERR_FILE_NOT_EXISTS); + g_IsOTAMode = FALSE; + return; + } + + memset(buf, 0, MAX_PATH); + sprintf(buf, "cat %s/ota.md5 | awk '{print $2}'", g_otaDownloadPath); + + if(GetShellExecResult(buf, &pFileName) != 0) + { + LOG_EX(LOG_Error, "Get File Name Error: %s\n", buf); + __otaRspStatus(OTA_ERR_CODE, -ERR_READ_FILE); + g_IsOTAMode = FALSE; + return; + } + + memset(buf, 0, MAX_PATH); + sprintf(buf, "cat %s/ota.md5 | awk '{print $1}'", g_otaDownloadPath); + + if(GetShellExecResult(buf, &pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Get MD5 Value Error: %s\n", buf); + free(pFileName); + __otaRspStatus(OTA_ERR_CODE, -ERR_READ_FILE); + g_IsOTAMode = FALSE; + return; + } + + LOG_EX(LOG_Debug, "Step %d: Verify OTA image .......\n", step++); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "%s/%s", g_otaDownloadPath, pFileName); + + pMD5Chk = EvpMD5HashFile(buf); + + if(strcmp(pMD5Chk, pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Check %s MD5 Error: %s --> %s\n", buf, pMD5Chk, pMD5Val); + __otaRspStatus(OTA_ERR_CODE, -ERR_MD5_CHECK_SUM); + g_IsOTAMode = FALSE; + return; + } + + free(pMD5Val); + free(pFileName); + free((void *)pMD5Chk); + + LOG_EX(LOG_Debug, "Step %d: Decompress OTA file .......\n", step++); + + pFileName = strdup(buf); + + __otaRspStatus(OTA_DECOMPRESS_FILE, NO_OTA_STATUS_VAL_TAG); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "mkdir -p %s/%d/ && tar -C %s/%d -xvzf %s > /dev/null", + OTA_TEMP_DIR, version, + OTA_TEMP_DIR, version, + pFileName); + + ret = system(buf); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "%s/%d/ota.md5", OTA_TEMP_DIR, version); + + SetHBLAutoExit(FALSE); + __otaRspStatus(OTA_UPGRADE_START, NO_OTA_STATUS_VAL_TAG); + + LOG_EX(LOG_Debug, "Step %d: OTA write to partition .......\n", step++); + + //__otaBackupWifi(TRUE); + + //LOG_EX(LOG_Debug, "Step %d: OTA Backup WIFI .......\n", step++); + + LOG_EX(LOG_Debug, "System into mini ramfs mode\n"); + ret = system("/sbin/ramfs.sh"); + LOG_EX(LOG_Debug, "Ramfs ready......\n"); + + reTry = 3; + while(reTry--) + { + if((ret = __otaRunning(buf, version)) == 0) + { + break; + } + } + + if(ret == ERR_OPEN_FILE + || ret == ERR_MD5_FILE + || ret == ERR_MD5_CHECK_SUM + || ret == ERR_OTA_WRITE_BOOT + || ret == ERR_OTA_WRITE_ROOTFS + || ret == ERR_OTA_WRITE_PARAMS) + { + __otaRspStatus(OTA_ERR_CODE, -12345); + } + + __otaRspStatus(OTA_REBOOT_SYSTEM, NO_OTA_STATUS_VAL_TAG); + +#if 0 + LOG_EX(LOG_Debug, "Step %d: Clean resource and evn ......\n", step++); + + for(i = 0; i < sizeof(g_processName) / sizeof(g_processName[0]); i++) + { + memset(buf, 0, MAX_PATH); + sprintf(buf, "killall -9 %s > /dev/null", g_processName[i]); + ret = system(buf); + } +#endif +#if 0 + SysPointMarkUpload(); + LogUploadCurLogFile(); + + ret = system("sync && ubus call system watchdog \'{\"stop\" : true}\'"); + + reTry = 3; + do + { + sleep(1); + } while(reTry--); + + reTry = 0; + + LOG_EX(LOG_Debug, "Reboot System By Power Control Chips\n"); + sleep(1); + + ret = system("sync && echo 3140 > /sys/bus/platform/devices/axp22_board/axp22_reg"); + + sleep(10); + + while(TRUE) + { + LOG_EX(LOG_Debug, "Reboot System: %d times\n", reTry++); + ret = system("reboot -f"); + sleep(3); + } +#endif + + reTry = 300; + + while(reTry--) + { + LOG_EX(LOG_Debug, "System force reboot before %d seconds\n", reTry); + sleep(1); + } + + while(TRUE) + { + ret = system("reboot -f"); + sleep(5); + } + + return; +} + +static int __isPreDownloader(POTA_DATA_INFO pInfo) +{ + UT_string* pDlPath = NULL, *pChkPath = NULL; + + char *pFileName = NULL, *pMD5Val = NULL; + const char *pMD5Chk = NULL; + + if(pInfo == NULL) + { + return (-ERR_FILE_NOT_EXISTS); + } + + utstring_new(pDlPath); + utstring_new(pChkPath); + utstring_printf(pDlPath, "%s/tina_r16_ota_%d.tar.gz", g_otaDownloadPath, pInfo->version); + utstring_printf(pChkPath, "%s/ota.md5", g_otaDownloadPath); + + if(access(utstring_body(pDlPath), F_OK) != 0 + || access(utstring_body(pChkPath), F_OK) != 0) + { + utstring_free(pDlPath); + utstring_free(pChkPath); + return (-ERR_FILE_NOT_EXISTS); + } + + utstring_renew(pChkPath); + utstring_printf(pChkPath, "cat %s/ota.md5 | awk '{print $2}'", g_otaDownloadPath); + + if(GetShellExecResult(utstring_body(pChkPath), &pFileName) != 0) + { + LOG_EX(LOG_Error, "Get File Name Error: %s\n", utstring_body(pChkPath)); + utstring_free(pDlPath); + utstring_free(pChkPath); + return -ERR_FILE_NOT_EXISTS; + } + + utstring_renew(pChkPath); + utstring_printf(pChkPath, "cat %s/ota.md5 | awk '{print $1}'", g_otaDownloadPath); + + if(GetShellExecResult(utstring_body(pChkPath), &pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Get MD5 Value Error: %s\n", utstring_body(pChkPath)); + free(pFileName); + utstring_free(pDlPath); + utstring_free(pChkPath); + return -ERR_MD5_CHECK_SUM; + } + + if(strcmp(pMD5Val, pInfo->otaFileInfo.md5) != 0) + { + LOG_EX(LOG_Debug, "Download File Chksum Diff: %s -> %s\n", pMD5Val, pInfo->otaFileInfo.md5); + free(pFileName); + free(pMD5Val); + utstring_free(pDlPath); + utstring_free(pChkPath); + return -ERR_FILE_NOT_EXISTS; + } + + utstring_renew(pChkPath); + utstring_printf(pChkPath, "%s/%s", g_otaDownloadPath, pFileName); + + pMD5Chk = EvpMD5HashFile(utstring_body(pChkPath)); + + if(pMD5Chk == NULL || strcmp(pMD5Chk, pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Check %s MD5 Error: %s --> %s\n", utstring_body(pChkPath), pMD5Chk, pMD5Val); + free(pFileName); + free(pMD5Val); + utstring_free(pDlPath); + utstring_free(pChkPath); + if(pMD5Chk) + { + free((void *)pMD5Chk); + } + return -ERR_MD5_CHECK_SUM; + } + + free(pMD5Val); + free(pFileName); + free((void *)pMD5Chk); + utstring_free(pDlPath); + utstring_free(pChkPath); + + return (0); +} + +static void __otaDownloadImageCb(void *pParams) +{ + POTA_DATA_INFO pInfo = (POTA_DATA_INFO)pParams; + DOWNLOAD_TASK_INFO dlInfo; + char buf[SIZE_1K]; + int ret, reTry = 3; + + g_isDownloading = TRUE; + + // Notify CC Beging Download + __otaRspStatus(OTA_DOWNLOAD_FILE, 2); + + if(__isPreDownloader(pInfo) == 0) + { + g_isDownloading = FALSE; + g_IsOTAMode = FALSE; + __otaRspStatus(OTA_DOWNLOAD_PROGRESS, 100); + __otaRspStatus(OTA_DOWNLOAD_FILE, 0); + + if(pInfo->otaMode == OTA_MODE_FORCE_NOW) + { + g_IsOTAMode = TRUE; + __otaFromLocalImage((void*)(intptr_t)pInfo->version); + g_IsOTAMode = FALSE; + } + + free(pInfo); + pthread_detach(pthread_self()); + return; + } + + while(reTry--) + { + uv_barrier_t uvBarrier; + uv_barrier_init(&uvBarrier, 2); + + memset(buf, 0, SIZE_1K); + sprintf(buf, "rm -rf %s/*", g_otaDownloadPath); + ret = system(buf); + + memset(&dlInfo, 0, sizeof(DOWNLOAD_TASK_INFO)); + sprintf(dlInfo.pPath, "%s/tina_r16_ota_%d.tar.gz", g_otaDownloadPath, pInfo->version); + + memcpy(&dlInfo.fileInfo, &pInfo->otaFileInfo, sizeof(OTA_FILE_INFO)); + + dlInfo.dlStatus = 0; + + dlInfo.puvBarrier = &uvBarrier; + + InetHttpDlFileAsync(dlInfo.fileInfo.url, + dlInfo.pPath, + __onHttpResponseCb, + __onProgressNotifyCb, + &dlInfo); + + LOG_EX(LOG_Debug, ">>>>>>>>>>>>>>>>>>>Wait Download Finished.............\n"); + uv_barrier_wait(&uvBarrier); + uv_barrier_destroy(&uvBarrier); + LOG_EX(LOG_Debug, "<<<<<<<<<<<<<<<<<<otaFileInfo.md5) != 0) + { + LOG_EX(LOG_Error, "Download File MD5 Error: %s --> %s\n", pChkVal, pInfo->otaFileInfo.md5); + dlInfo.retCode = -ERR_MD5_CHECK_SUM; + } + else + { + break; + } + } + } + + if(dlInfo.retCode != 0) + { + ret = system(buf); + g_IsOTAMode = FALSE; + g_isDownloading = FALSE; + + if(dlInfo.retCode > 0) + { + dlInfo.retCode = -dlInfo.retCode; + } + + __otaRspStatus(OTA_DOWNLOAD_FILE, dlInfo.retCode); + pthread_detach(pthread_self()); + return; + } + + LOG_EX(LOG_Debug, "Step 1: Download File result: %d\n", dlInfo.retCode); + + memset(buf, 0, SIZE_1K); + sprintf(buf, "echo \"%s %s\" > %s/ota.md5", + dlInfo.fileInfo.md5, basename_v2(dlInfo.pPath), g_otaDownloadPath); + + ret = system(buf); + + LOG_EX(LOG_Debug, "Step 2: Save MD5 File; %d\n", ret); + + g_IsOTAMode = FALSE; + __otaRspStatus(OTA_DOWNLOAD_FILE, 0); + + if(pInfo->otaMode == OTA_MODE_FORCE_NOW) + { + g_IsOTAMode = TRUE; + __otaFromLocalImage((void*)(intptr_t)pInfo->version); + g_IsOTAMode = FALSE; + } + + free(pInfo); + + g_isDownloading = FALSE; + + pthread_detach(pthread_self()); +} + +static void __dBusDeameonCb(MODULE_NAME modName, int status) +{ + if(status) + { + LOG_EX(LOG_Error, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } + else + { + LOG_EX(LOG_Info, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } + + if(modName == MODULE_CONTROLLER && status == 0) + { + __otaRspStatus(OTA_CURRENT_VERSION, g_iplInfo.curVersion); + __otaRspStatus(OTA_CURRENT_SETUP_MODE, g_iplInfo.setupMode); + __otaRspStatus(OTA_CURRENT_REBOOT_TIME, g_iplInfo.setupStatus); + } +} + +static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ + int err; + uv_thread_t uvThread; + POTA_DATA_INFO pInfo = NULL; + + if(!pMsg || !pLoop || !pConn) + { + return NULL; + } + + //fprintf(stdout, "Recv: cmd = %u, Json = [%s]\n", pMsg->busCmd, (const char *)pMsg->pMsg); + + switch(pMsg->busCmd) + { + case CMD_OTA_RUNNOW: + if(g_IsOTAMode == 1) + { + LOG_EX(LOG_Info, "Trigger OTA Now.......\n"); + uv_barrier_wait(&g_otaBarrier); + } + else + { + __otaRspStatus(OTA_ERR_CODE, -ERR_OTA_NOT_READY); + LOG_EX(LOG_Error, "Current Not In OTA Mode\n"); + } + break; + + case CMD_MISC_QUERY_DL_STATUS: + if(g_isDownloading) + { + __otaRspStatus(OTA_DOWNLOAD_FILE, 1); + } + else + { + __otaRspStatus(OTA_DOWNLOAD_FILE, 0); + } + break; + + case CMD_MISC_QUERY_OTA_STATUS: + if(g_sSetupStatus == SYSTEM_OTA_OK) + { + __otaRspStatus(OTA_SUCCESED, 0); + } + else if(g_sSetupStatus == RECOVERY_SETUP) + { + __otaRspStatus(OTA_SUCCESED, -1); + } + else if(g_sSetupStatus == NORMAL_SETUP) + { + __otaRspStatus(OTA_SUCCESED, 1); + } + break; + + case CMD_SYSTEM_STANDBY: + LOG_EX(LOG_Debug, "System Ready ....\n"); + break; + + case CMD_OTA_NOTIFY: + + if(g_IsOTAMode == 0) + { + if(g_iplInfo.setupMode == SYSTEM_OTA) + { + LOG_EX(LOG_Debug, "Current System Mode: SYSTEM_OTA\n"); + } + else if(g_iplInfo.setupMode == RECOVERY_SETUP) + { + LOG_EX(LOG_Debug, "Current System Mode: RECOVERY_SETUP\n"); + } + else if(g_iplInfo.setupMode == SYSTEM_OTA_OK) + { + LOG_EX(LOG_Debug, "Current System Mode: SYSTEM_OTA_OK\n"); + } + else + { + LOG_EX(LOG_Debug, "Current System Mode: NORMAL_SETUP\n"); + } + + if(g_isDownloading) + { + __otaRspStatus(OTA_DOWNLOAD_FILE, 1); + break; + } + + pInfo = (POTA_DATA_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_OTA_REQ, TRUE, &err); + + if(pInfo == NULL) + { + __otaRspStatus(OTA_ERR_CODE, -ERR_INPUT_PARAMS); + free(pInfo); + } + else + { + //unsigned long long uDiskFreeSize = GetPartitionFreeSize("/mnt/UDISK/"); + unsigned long long uMemFreeSize = GetPartitionFreeSize("/tmp/"); + unsigned long long uUsedSize = 0; + + g_IsOTAMode = TRUE; +#if TEST_OTA_SERVER + memset(&pInfo->otaFileInfo, 0, sizeof(OTA_FILE_INFO)); + strcpy(pInfo->otaFileInfo.md5, "78bcf3236f54543301ee1a2f74282917"); + strcpy(pInfo->otaFileInfo.url, "http://10.240.84.163/tina_r16_ota_2.tar.gz"); + pInfo->otaFileInfo.size = 57106052; +#endif + __printfOTANotifyCmd("On OTA Notify Command++", pInfo); + + uUsedSize = pInfo->otaFileInfo.size + (1024 * 1024 * 10); + + if(g_isBackupMode) + { + LOG_EX(LOG_Debug, "OTA on recovery mode\n"); + pInfo->otaMode == OTA_MODE_FORCE_NOW; + } + else + { + LOG_EX(LOG_Debug, "OTA on normal mode\n"); + } + +#if 0 + if(uUsedSize > uDiskFreeSize) + { + LOG_EX(LOG_Error, "Error: File Size = %u bytes, Need %llu bytes, UDISK Free %llu bytes\n", + pInfo->otaFileInfo.size, uUsedSize, uDiskFreeSize); + + if(uUsedSize > uMemFreeSize) + { + LOG_EX(LOG_Error, "Error: Not Enought Space, Memory Free %llu bytes\n", uMemFreeSize); + __otaRspStatus(OTA_DISK_FULL, pInfo->otaCmd); + break; + } + else + { + memset(g_otaDownloadPath, 0, MAX_PATH); + strcpy(g_otaDownloadPath, OTA_MEMORY_DOWNLOAD_DIR); + LOG_EX(LOG_Warn, "Warnning: Storage OTA File To Memory: %s\n", g_otaDownloadPath); + } + } +#else + if(uUsedSize > uMemFreeSize) + { + g_IsOTAMode = FALSE; + LOG_EX(LOG_Error, "Error: Not Enought Space, Memory Free %llu bytes\n", uMemFreeSize); + __otaRspStatus(OTA_DISK_FULL, pInfo->otaCmd); + break; + } + else + { + memset(g_otaDownloadPath, 0, MAX_PATH); + strcpy(g_otaDownloadPath, OTA_MEMORY_DOWNLOAD_DIR); + LOG_EX(LOG_Warn, "Warnning: Storage OTA File To Memory: %s\n", g_otaDownloadPath); + } +#endif + + switch(pInfo->otaCmd) + { + case OTA_CMD_DOWNLOAD: + if(strlen(pInfo->otaFileInfo.md5) == 0 + || strlen(pInfo->otaFileInfo.url) == 0) + { + g_IsOTAMode = FALSE; + LOG_EX(LOG_Error, "OTA Information Error\n"); + } + else + { + err = uv_thread_create(&uvThread, __otaDownloadImageCb, pInfo); + if(err != 0) + { + LOG_EX(LOG_Error, "Create Thread Error: %d\n", err); + } + } + break; + + case OTA_CMD_USED_LOCAL_IMAGE: + case OTA_CMD_EXEC: + err = uv_thread_create(&uvThread, __otaFromLocalImage, (void*)(intptr_t)pInfo->version); + if(err != 0) + { + LOG_EX(LOG_Error, "Create Thread Error: %d\n", err); + } + free(pInfo); + break; + + default: + __otaRspStatus(OTA_UNKNOWN_CMD, pInfo->otaCmd); + free(pInfo); + break; + } + } + } + else + { + __otaRspStatus(OTA_ERR_CODE, -ERR_OTA_PRE_STATR); + } + + break; + + default: + break; + } + + return NULL; +} + +int main(int argc, char **argv) +{ + int i, ret = 0; + char buf[256]; + DBusConnection* pBus; + + //struct tm *pTm = NULL; + g_pMainLoop = GetDBusDefaultLoop(); + + pBus = DBusWithLibuvInit(g_pMainLoop, + g_pModInfoTable[MODULE_OTA].modAliase, + __dBusOnMessage, + __dBusDeameonCb, + NULL, + &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return (-1); + } + + g_IsOTAMode = 0; + strcpy(g_otaDownloadPath, OTA_FILE_DOWNLOAD_DIR); + + memset(buf, 0, 256); + sprintf(buf, "mkdir -p %s", OTA_FILE_DOWNLOAD_DIR); + ret = system(buf); + + memset(buf, 0, 256); + sprintf(buf, "mkdir -p %s", OTA_MEMORY_DOWNLOAD_DIR); + ret = system(buf); + + for(i = 0; i < OTA_PARTITION_MAX; i++) + { + char *pCmdRet = NULL; + + memset(buf, 0, 256); + + sprintf(buf, "cat /proc/partitions | grep `readlink %s | xargs basename` | awk '{print $3}'", + g_otaPartInfo[i].pPartPath); + + if((ret = GetShellExecResult((const char *)buf, &pCmdRet)) == 0) + { + g_otaPartInfo[i].partSize = strtoul(pCmdRet, NULL, 10); + + if(errno == ERANGE || errno == EINVAL) + { + g_otaPartInfo[i].partSize = 0; + } + + g_otaPartInfo[i].partSize *= 1024; + + //fprintf(stdout, "%d: %s --> %s\n", i, g_otaPartInfo[i].pPartPath, pCmdRet); + + free(pCmdRet); + } + } + + LOG_EX(LOG_Debug, "__ReadIPLParams: %d\n", __ReadIPLParams(&g_iplInfo)); + + if(ret == 0) + { + __printIPLParams(&g_iplInfo, "Current OTA Information:"); + } + + g_sSetupStatus = g_iplInfo.setupMode; + + if(g_iplInfo.setupMode == SYSTEM_OTA) + { + LOG_EX(LOG_Debug, "System setup on OTA mode\n"); + if(g_iplInfo.setupStatus > 3 && g_iplInfo.setupStatus != 0xFFFFFFFF) + { + LOG_EX(LOG_Error, "Check OTA error more than 3 times, Ask server todo next step.....\n"); + __otaRspStatus(OTA_SUCCESED, -1); + } + else if(g_iplInfo.setupStatus <= 3) + { + LOG_EX(LOG_Error, "Check OTA error less than 3 times, Redo OTA used last image.....\n"); + g_IsOTAMode = 1; + __otaFromLocalImage(&g_iplInfo.curVersion); + g_IsOTAMode = 0; + } + } + else if(g_iplInfo.setupMode == RECOVERY_SETUP) + { + g_isBackupMode = TRUE; + LOG_EX(LOG_Error, "System on recovery mode\n"); + __otaRspStatus(OTA_CURRENT_SETUP_MODE, RECOVERY_SETUP); + } + else if(g_iplInfo.setupMode == SYSTEM_OTA_OK) + { + LOG_EX(LOG_Info, "System OTA OK\n"); + __otaRspStatus(OTA_CURRENT_SETUP_MODE, SYSTEM_OTA_OK); + } + else + { + LOG_EX(LOG_Debug, "System setup on normal mode\n"); + } + + if(g_iplInfo.setupStatus != 0) + { + if(g_iplInfo.setupMode == SYSTEM_OTA_OK) + { + g_iplInfo.setupMode = NORMAL_SETUP; + } + + g_iplInfo.setupStatus = 0; + __SaveIPLParams(&g_iplInfo); + } + + // Make sure continue last download task + __otaRspStatus(OTA_DOWNLOAD_FILE, -28); + + RunUVLoop(g_pMainLoop); + + while(TRUE) + { + usleep(1000); + } + + return (0); +} + diff --git a/Modules/voice/SrcApi.h b/Modules/voice/SrcApi.h new file mode 100644 index 0000000..d2a8f4a --- /dev/null +++ b/Modules/voice/SrcApi.h @@ -0,0 +1,75 @@ +#ifndef _SRCAPI_H_ +#define _SRCAPI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _SRCParam +{ + const char* URL; + const char* appKey; + const char* appSecret; + const char* cuid; + const char* severVadThresh1; + const char* severVadThresh2; + +} SRCParam; + +enum SRC_ERROR +{ + SRC_SUCCESS = 0, + SRC_HTTP_ERROR = 1, + SRC_SERVER_ERROR = 2, + SRC_SESSION_BEGIN_ERROR = 3, +}; + +enum VAD_STATUS +{ + SRC_VAD_LOOKING_FOR_SPEECH = 0, + SRC_VAD_IN_SPEECH = 1, + SRC_VAD_END_SPEECH = 2, +}; + +enum REC_STATUS +{ + SRC_REC_SENT_AUDIO_SUCCESS = 1000, + SRC_REC_SENT_AUDIO_FAILED = 1001, + SRC_REC_SENT_AUDIO_END_DETECTED = 1002, + SRC_REC_RESULT_COMPLETE = 2000, + SRC_REC_TIMEOUT_SERVICE_CLOSING = 2001, + SRC_REC_TIMEOUT_SERVICE_CLOSED = 2002, + SRC_REC_RESULT_NOT_COMPLETE = 2003, + SRC_REC_NLU_SUCCESS = 3100, + SRC_REC_NLU_FAILED = 3101, + SRC_REC_RESULT_PARAM_NULL = 4001, + SRC_REC_MISS_AUTHEN_PARAM = 4002, + SRC_REC_AUTHEN_FAILURE = 4003, + SRC_REC_MISS_IDX_OR_ILLEGAL = 4004, + SRC_REC_MISS_CUID = 4005, + SRC_REC_MISS_CHANNEL = 4006, + SRC_REC_MISS_PTC_OR_ILLEGAL = 4007, + SRC_REC_MISS_RATE_OR_ILLEGAL = 4008, + SRC_REC_MISS_SESSIONID = 4009, +}; + +void SRCSetUPParam(const char* strKey, const char* strValue); + +void SRCSetSPParam(const char* strKey, const char* strValue); + +const char* SRCSessionBegin(SRCParam srcParam, int *error); + +int SRCAudioWrite(const char* session_id, const short *audioData, unsigned int audioLen, int *vadStat, int *recStat); + +const char* SRCGetResult(const char* session_id , int *server_ret); + +int SRCSessionEnd(const char* session_id); + +const char* SRCGetVersion(); + + +#ifdef __cplusplus +}; +#endif + +#endif // _SRCAPI_H_ diff --git a/Modules/voice/data.pcm b/Modules/voice/data.pcm new file mode 100644 index 0000000..5da058a Binary files /dev/null and b/Modules/voice/data.pcm differ diff --git a/Modules/voice/demo.c b/Modules/voice/demo.c new file mode 100644 index 0000000..94ee62b --- /dev/null +++ b/Modules/voice/demo.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include "SrcApi.h" + +#define DEBUG_CODE_LINE() (printf("%s(%d)\n", __FUNCTION__, __LINE__)) + +#define POSTURL "api-test.vop.netease.com/echo_api?rate=16000&lan=zh" +int main() +{ +#if 1 + const int kSamples = 1024; //40ms + int rcv_code = 0; + int error_code = 0; + + short data[kSamples]; + + SRCParam srcParam; + srcParam.URL = POSTURL; + srcParam.appKey = "onlinedemo"; + srcParam.appSecret = "4ea70c117a5b858cd9e6e384009bbad7"; + srcParam.severVadThresh1 = "2.0"; + srcParam.severVadThresh2 = "2.0"; + srcParam.cuid = "1215468784532"; + SRCSetUPParam("uuid","0-A024067C55B0163C"); + SRCSetUPParam("aes", "0"); + //SRCSetUPParam("state", "{\"filed\":1}"); + //SRCSetSPParam("name1", "xxxxxx"); + //SRCSetSPParam("name2", "xxxxxx"); + const char* session_id; + + DEBUG_CODE_LINE(); + int status = 0; + FILE *asrFile = fopen("data.pcm", "rb"); + session_id = SRCSessionBegin(srcParam, &status); + if (status != SRC_SUCCESS) + { + printf("SRCStartNewSession error:%d\n", status); + } + + printf("ssid = %s\n", session_id); + int getResCnt = 0; + rcv_code = 0; + const char *asr_out = NULL; + + DEBUG_CODE_LINE(); + while (1) + { + if (fread(data, 2, kSamples, asrFile) == 0) + { + fseek(asrFile, 0, 0); + } + int vadFlag = 0; + int recFlag = 0; + DEBUG_CODE_LINE(); + status = SRCAudioWrite(session_id, data, kSamples, &vadFlag, &recFlag); + DEBUG_CODE_LINE(); + if (status != SRC_SUCCESS) + { + printf("SRCAudioWrite error:%d\n", status); + } + + printf("vadFlag = %d, recFlag = %d\n", vadFlag, recFlag); + if (vadFlag == SRC_VAD_END_SPEECH || recFlag == 1002) + break; + usleep(40 * 1000); + } + + DEBUG_CODE_LINE(); + while (rcv_code != 3100) + { + usleep(100 * 1000); + asr_out = SRCGetResult(session_id, &rcv_code); + getResCnt++; + if (error_code != 0) + { + break; + } + if (getResCnt > 10) + { + break; + } + printf("rcv_code = %d, retry = %d\n", rcv_code, getResCnt); + } + printf("=============%s=============\n", (asr_out)); + fclose(asrFile); + + SRCSessionEnd(session_id); +#endif + printf("Demo++++++++++++++++++++++\n"); + return 0; +} diff --git a/Modules/voice/libSRC.so b/Modules/voice/libSRC.so new file mode 100644 index 0000000..07977bd Binary files /dev/null and b/Modules/voice/libSRC.so differ diff --git a/Modules/voice/voice b/Modules/voice/voice new file mode 100644 index 0000000..f98234f Binary files /dev/null and b/Modules/voice/voice differ diff --git a/build/Makefile.alarm.cross b/build/Makefile.alarm.cross new file mode 100644 index 0000000..208bc76 --- /dev/null +++ b/build/Makefile.alarm.cross @@ -0,0 +1,76 @@ +include Makefile.def.cross +# target name, the target name must have the same name of c source file +TARGET_NAME=alarm + +# target +# for linux module driver: KO +# for application: EXE +# for dynamic library: DLL +TARGET_TYPE = EXE + +# target object +# for application: APP +# for device driver: DRV +TARGET_OBJ = APP + +TARGET_BOX = + +#debug mode or release mode +DEBUG = TRUE + +PLAT_R16 ?= TRUE +PLAT_LINUX ?= TRUE +PLAT_WIN32 ?= FALSE +PLAT_WIN64 ?= FALSE + +VPATH = ../Modules/Alarm/ + +# source code + +# set the source file, don't used .o because of ... +# MRS Board Source Files +PLAT_R16_SRCS = assistant.c + +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) +# gcc CFLAGS + +PLAT_R16_CFLAGS := -I./ -I../include +PLAT_LINUX_CFLAGS := $(PLAT_R16_CFLAGS) -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ +PLAT_LINUX_CFLAGS += -I../linux32/inc/ -I../linux32/inc/cjson/ -I../linux32/inc/uthash/ + +#R16_LIBS := -lgobject-2.0 -lffi -lglib-2.0 -ldbus-1 -ldbus-glib-1 -luv +R16_LIBS := $(COMMON_R16_LIBS) +R16_LIBS += ./libuvdbus-r16.so + +LINUX_LIBS := $(COMMON_LINUX_LIBS) +LINUX_LIBS += ./libuvdbus-linux.so + + +ifeq ($(PLAT_R16), TRUE) +DEPEND_LIB += ./debug/libuvdbus-r16.so +USER_CLEAN_ITEMS += ./libuvdbus-r16.so +endif + +ifeq ($(PLAT_LINUX), TRUE) +DEPEND_LIB += ./debug/libuvdbus-linux.so +USER_CLEAN_ITEMS += ./libuvdbus-linux.so +endif + +# this line must be at below of thus, because of... +include /opt/common/Makefile.cross + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(MAKECMDGOALS), cleanall) +ifneq ($(notdir $(DEPEND_LIB)), $(wildcard $(DEPEND_LIB))) +$(shell $(CP) $(DEPEND_LIB) ./) +endif +endif +endif + +ifeq ($(MAKECMDGOALS), ) +$(shell find ./ -name $(TARGET)-*.exe -delete) +else +ifeq ($(MAKECMDGOALS), all) +$(shell find ./ -name "$(TARGET)-*.exe" -delete) +endif +endif diff --git a/build/Makefile.app.cross b/build/Makefile.app.cross new file mode 100644 index 0000000..0c5e42d --- /dev/null +++ b/build/Makefile.app.cross @@ -0,0 +1,75 @@ +include Makefile.def.cross +# target name, the target name must have the same name of c source file +TARGET_NAME=dbus + +# target +# for linux module driver: KO +# for application: EXE +# for dynamic library: DLL +TARGET_TYPE = EXE + +# target object +# for application: APP +# for device driver: DRV +TARGET_OBJ = APP + +TARGET_BOX = + +#debug mode or release mode +DEBUG = TRUE + +PLAT_R16 ?= TRUE +PLAT_LINUX ?= TRUE +PLAT_WIN32 ?= FALSE +PLAT_WIN64 ?= FALSE + +VPATH = ../Example + +# source code + +# set the source file, don't used .o because of ... +# MRS Board Source Files +PLAT_R16_SRCS = main.c + +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) +# gcc CFLAGS + +PLAT_R16_CFLAGS := -I./ -I../include +PLAT_LINUX_CFLAGS := $(PLAT_R16_CFLAGS) -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ +PLAT_LINUX_CFLAGS += -I../linux32/inc/ -I../linux32/inc/cjson/ -I../linux32/inc/uthash/ + +#R16_LIBS := -lgobject-2.0 -lffi -lglib-2.0 -ldbus-1 -ldbus-glib-1 -luv -lnghttp2 +R16_LIBS := $(COMMON_R16_LIBS) -lreadline -lcurses +R16_LIBS += ./libuvdbus-r16.so + +LINUX_LIBS := $(COMMON_LINUX_LIBS) -lreadline -lnghttp2 +LINUX_LIBS += ./libuvdbus-linux.so + +ifeq ($(PLAT_R16), TRUE) +DEPEND_LIB := ./debug/libuvdbus-r16.so +USER_CLEAN_ITEMS += ./libuvdbus-r16.so +endif + +ifeq ($(PLAT_LINUX), TRUE) +DEPEND_LIB += ./debug/libuvdbus-linux.so +USER_CLEAN_ITEMS += ./libuvdbus-linux.so +endif + +# this line must be at below of thus, because of... +include /opt/common/Makefile.cross + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(MAKECMDGOALS), cleanall) +ifneq ($(notdir $(DEPEND_LIB)), $(wildcard $(DEPEND_LIB))) +$(shell $(CP) $(DEPEND_LIB) ./) +endif +endif +endif + +ifeq ($(MAKECMDGOALS), ) +$(shell find ./ -name $(TARGET)-*.exe -delete) +else +ifeq ($(MAKECMDGOALS), all) +$(shell find ./ -name "$(TARGET)-*.exe" -delete) +endif +endif diff --git a/build/Makefile.cfgsvr.cross b/build/Makefile.cfgsvr.cross new file mode 100644 index 0000000..20a5e7d --- /dev/null +++ b/build/Makefile.cfgsvr.cross @@ -0,0 +1,68 @@ +include Makefile.def.cross + +# target name, the target name must have the same name of c source file +TARGET_NAME=config_server + +# target +# for linux module driver: KO +# for application: EXE +# for dynamic library: DLL +TARGET_TYPE = EXE + +# target object +# for application: APP +# for device driver: DRV +TARGET_OBJ = APP + +TARGET_BOX = + +#debug mode or release mode +DEBUG = TRUE + +PLAT_R16 ?= TRUE +PLAT_LINUX ?= FALSE +PLAT_WIN32 ?= FALSE +PLAT_WIN64 ?= FALSE + +VPATH = ../Modules/ConfigServer/ + +# source code + +# set the source file, don't used .o because of ... +# MRS Board Source Files +PLAT_R16_SRCS = config_server.c + +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) +# gcc CFLAGS + +PLAT_R16_CFLAGS := -I./ -I../include +PLAT_LINUX_CFLAGS := $(PLAT_R16_CFLAGS) -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ + +#R16_LIBS := -lgobject-2.0 -lffi -lglib-2.0 -ldbus-1 -ldbus-glib-1 -luv +R16_LIBS := $(COMMON_R16_LIBS) +#LINUX_LIBS := -ldbus-1 -luv -lcrypto -lcjson +R16_LIBS += ./libuvdbus-r16.so + +ifeq ($(PLAT_R16), TRUE) +DEPEND_LIB := ./debug/libuvdbus-r16.so +USER_CLEAN_ITEMS += ./libuvdbus-r16.so +endif + +# this line must be at below of thus, because of... +include /opt/common/Makefile.cross + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(MAKECMDGOALS), cleanall) +ifneq ($(notdir $(DEPEND_LIB)), $(wildcard $(DEPEND_LIB))) +$(shell $(CP) $(DEPEND_LIB) ./) +endif +endif +endif + +ifeq ($(MAKECMDGOALS), ) +$(shell find ./ -name $(TARGET)-*.exe -delete) +else +ifeq ($(MAKECMDGOALS), all) +$(shell find ./ -name "$(TARGET)-*.exe" -delete) +endif +endif diff --git a/build/Makefile.def.cross b/build/Makefile.def.cross new file mode 100644 index 0000000..f99a8ac --- /dev/null +++ b/build/Makefile.def.cross @@ -0,0 +1,2 @@ +COMMON_R16_LIBS := -ldbus-1 -luv -lcrypto -lcjson -ls2json -lsqlite3 -lnghttp2 -lquickmail -lz -luuid -lconfig -lcurl -lssl -lpthread +COMMON_LINUX_LIBS := -ldbus-1 -luv -lcrypto -lcurl -lm -lnghttp2 -lsqlite3 -lquickmail -lz -luuid -lconfig -lssl -lpthread diff --git a/build/Makefile.lib.cross b/build/Makefile.lib.cross new file mode 100644 index 0000000..5e2747e --- /dev/null +++ b/build/Makefile.lib.cross @@ -0,0 +1,79 @@ +include Makefile.def.cross + +# target name, the target name must have the same name of c source file +TARGET_NAME=libuvdbus + +# target +# for linux module driver: KO +# for application: EXE +# for dynamic library: DLL +TARGET_TYPE = DLL + +# target object +# for application: APP +# for device driver: DRV +TARGET_OBJ = APP + +TARGET_BOX = + +#debug mode or release mode +DEBUG = TRUE + +PLAT_R16 ?= TRUE +PLAT_LINUX ?= TRUE +PLAT_WIN32 ?= FALSE +PLAT_WIN64 ?= FALSE + +VPATH = ../Framework ../log ../Modules ../linux32 + +# source code + +# set the source file, don't used .o because of ... +# MRS Board Source Files +PLAT_R16_SRCS = \ + libuvEngine/libuv_dbus.c \ + HeartDaemon/heart_daemon.c \ + JsonUtils/json_struct.c \ + Configure/config_engine.c \ + Configure/ini_prase.c \ + Crypto/aes.c \ + Crypto/base64.c \ + Crypto/md5.c \ + Crypto/crypto.c \ + Compress/zlib.c \ + Network/inet_api.c \ + Timer/timer.c \ + Fifo/fifo.c \ + Skins/skins.c \ + Skins/skin_res_vtbl.c \ + Monitor/monitor.c \ + log.c \ + SvrManager/svr_manager.c \ + hexdump.c + +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) \ + src/cJSON.c \ + src/s2j.c + +# gcc CFLAGS + +PLAT_R16_CFLAGS := -I../include -fPIC +PLAT_LINUX_CFLAGS := $(PLAT_R16_CFLAGS) -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ -I../linux32/inc/ -I../linux32/inc/cjson/ +PLAT_LINUX_CFLAGS += -I../linux32/inc/uthash/ + +PLAT_R16_LDFLAGS := -shared -fPIC +PLAT_LINUX_LDFLAGS := $(PLAT_R16_LDFLAGS) + +R16_LIBS := $(COMMON_R16_LIBS) +LINUX_LIBS := $(COMMON_LINUX_LIBS) + +# this line must be at below of thus, because of... +include /opt/common/Makefile.cross + +ifeq ($(MAKECMDGOALS), ) +$(shell find ./ -name $(TARGET)-*.exe -delete) +else +ifeq ($(MAKECMDGOALS), all) +$(shell find ./ -name "$(TARGET)-*.exe" -delete) +endif +endif diff --git a/build/Makefile.logctrl.cross b/build/Makefile.logctrl.cross new file mode 100644 index 0000000..d4973af --- /dev/null +++ b/build/Makefile.logctrl.cross @@ -0,0 +1,76 @@ +include Makefile.def.cross + +# target name, the target name must have the same name of c source file +TARGET_NAME=logCtrl + +# target +# for linux module driver: KO +# for application: EXE +# for dynamic library: DLL +TARGET_TYPE = EXE + +# target object +# for application: APP +# for device driver: DRV +TARGET_OBJ = APP + +TARGET_BOX = + +#debug mode or release mode +DEBUG = TRUE + +PLAT_R16 ?= TRUE +PLAT_LINUX ?= TRUE +PLAT_WIN32 ?= FALSE +PLAT_WIN64 ?= FALSE + +VPATH = ../Modules/LogCtrl/ + +# source code + +# set the source file, don't used .o because of ... +# MRS Board Source Files +PLAT_R16_SRCS = log_ctrl.c + +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) +# gcc CFLAGS + +PLAT_R16_CFLAGS := -I./ -I../include +PLAT_LINUX_CFLAGS := $(PLAT_R16_CFLAGS) -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ +PLAT_LINUX_CFLAGS += -I../linux32/inc/ -I../linux32/inc/cjson/ -I../linux32/inc/uthash/ + +R16_LIBS := $(COMMON_R16_LIBS) -lreadline -lcurses +R16_LIBS += ./libuvdbus-r16.so + +LINUX_LIBS := $(COMMON_LINUX_LIBS) -lreadline +LINUX_LIBS += ./libuvdbus-linux.so + + +ifeq ($(PLAT_R16), TRUE) +DEPEND_LIB += ./debug/libuvdbus-r16.so +USER_CLEAN_ITEMS += ./libuvdbus-r16.so +endif + +ifeq ($(PLAT_LINUX), TRUE) +DEPEND_LIB += ./debug/libuvdbus-linux.so +USER_CLEAN_ITEMS += ./libuvdbus-linux.so +endif + +# this line must be at below of thus, because of... +include /opt/common/Makefile.cross + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(MAKECMDGOALS), cleanall) +ifneq ($(notdir $(DEPEND_LIB)), $(wildcard $(DEPEND_LIB))) +$(shell $(CP) $(DEPEND_LIB) ./) +endif +endif +endif + +ifeq ($(MAKECMDGOALS), ) +$(shell find ./ -name $(TARGET)-*.exe -delete) +else +ifeq ($(MAKECMDGOALS), all) +$(shell find ./ -name "$(TARGET)-*.exe" -delete) +endif +endif diff --git a/build/Makefile.ota.cross b/build/Makefile.ota.cross new file mode 100644 index 0000000..b78bc4b --- /dev/null +++ b/build/Makefile.ota.cross @@ -0,0 +1,76 @@ +include Makefile.def.cross +# target name, the target name must have the same name of c source file +TARGET_NAME=ota + +# target +# for linux module driver: KO +# for application: EXE +# for dynamic library: DLL +TARGET_TYPE = EXE + +# target object +# for application: APP +# for device driver: DRV +TARGET_OBJ = APP + +TARGET_BOX = + +#debug mode or release mode +DEBUG = TRUE + +PLAT_R16 ?= TRUE +PLAT_LINUX ?= TRUE +PLAT_WIN32 ?= FALSE +PLAT_WIN64 ?= FALSE + +VPATH = ../Modules/OTA/ + +# source code + +# set the source file, don't used .o because of ... +# MRS Board Source Files +PLAT_R16_SRCS = ota.c + +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) +# gcc CFLAGS + +PLAT_R16_CFLAGS := -I./ -I../include +PLAT_LINUX_CFLAGS := $(PLAT_R16_CFLAGS) -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ +PLAT_LINUX_CFLAGS += -I../linux32/inc/ -I../linux32/inc/cjson/ -I../linux32/inc/uthash/ + +#R16_LIBS := -lgobject-2.0 -lffi -lglib-2.0 -ldbus-1 -ldbus-glib-1 -luv +R16_LIBS := $(COMMON_R16_LIBS) +R16_LIBS += ./libuvdbus-r16.so + +LINUX_LIBS := $(COMMON_LINUX_LIBS) +LINUX_LIBS += ./libuvdbus-linux.so + + +ifeq ($(PLAT_R16), TRUE) +DEPEND_LIB += ./debug/libuvdbus-r16.so +USER_CLEAN_ITEMS += ./libuvdbus-r16.so +endif + +ifeq ($(PLAT_LINUX), TRUE) +DEPEND_LIB += ./debug/libuvdbus-linux.so +USER_CLEAN_ITEMS += ./libuvdbus-linux.so +endif + +# this line must be at below of thus, because of... +include /opt/common/Makefile.cross + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(MAKECMDGOALS), cleanall) +ifneq ($(notdir $(DEPEND_LIB)), $(wildcard $(DEPEND_LIB))) +$(shell $(CP) $(DEPEND_LIB) ./) +endif +endif +endif + +ifeq ($(MAKECMDGOALS), ) +$(shell find ./ -name $(TARGET)-*.exe -delete) +else +ifeq ($(MAKECMDGOALS), all) +$(shell find ./ -name "$(TARGET)-*.exe" -delete) +endif +endif diff --git a/build/Makefile.voice.cross b/build/Makefile.voice.cross new file mode 100644 index 0000000..8a005ad --- /dev/null +++ b/build/Makefile.voice.cross @@ -0,0 +1,72 @@ +include Makefile.def.cross + +# target name, the target name must have the same name of c source file +TARGET_NAME=voice + +# target +# for linux module driver: KO +# for application: EXE +# for dynamic library: DLL +TARGET_TYPE = EXE + +# target object +# for application: APP +# for device driver: DRV +TARGET_OBJ = APP + +TARGET_BOX = + +#debug mode or release mode +DEBUG = TRUE + +PLAT_R16 ?= TRUE +PLAT_LINUX ?= FALSE +PLAT_WIN32 ?= FALSE +PLAT_WIN64 ?= FALSE + +VPATH = ../Modules/voice/ + +# source code + +# set the source file, don't used .o because of ... +# MRS Board Source Files +PLAT_R16_SRCS = demo.c + +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) +# gcc CFLAGS + +PLAT_R16_CFLAGS := -I./ -I../include +PLAT_LINUX_CFLAGS := $(PLAT_R16_CFLAGS) -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ +PLAT_LINUX_CFLAGS += -I../linux32/inc/ -I../linux32/inc/cjson/ -I../linux32/inc/uthash/ + +#R16_LIBS := -lgobject-2.0 -lffi -lglib-2.0 -ldbus-1 -ldbus-glib-1 -luv +R16_LIBS := $(COMMON_R16_LIBS) +R16_LIBS += ./libuvdbus-r16.so ./libSRC.so + +LINUX_LIBS := $(COMMON_LINUX_LIBS) +LINUX_LIBS += ./libuvdbus-linux.so + + +ifeq ($(PLAT_R16), TRUE) +DEPEND_LIB += ../Modules/voice/libSRC.so +USER_CLEAN_ITEMS += ./libSRC.so +endif + +# this line must be at below of thus, because of... +include /opt/common/Makefile.cross + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(MAKECMDGOALS), cleanall) +ifneq ($(notdir $(DEPEND_LIB)), $(wildcard $(DEPEND_LIB))) +$(shell $(CP) $(DEPEND_LIB) ./) +endif +endif +endif + +ifeq ($(MAKECMDGOALS), ) +$(shell find ./ -name $(TARGET)-*.exe -delete) +else +ifeq ($(MAKECMDGOALS), all) +$(shell find ./ -name "$(TARGET)-*.exe" -delete) +endif +endif diff --git a/compile.sh b/compile.sh new file mode 100755 index 0000000..f1f9a05 --- /dev/null +++ b/compile.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +source /etc/profile +make OPT=clean && make && make OPT=install +#make && make OPT=install diff --git a/include/assistant.h b/include/assistant.h new file mode 100644 index 0000000..56b28f7 --- /dev/null +++ b/include/assistant.h @@ -0,0 +1,168 @@ +#ifndef ASSISTANT_H +#define ASSISTANT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_TIP_LEN (60 * 4 + 1) +#define MAX_ALARM_ITEMS (1024) + +typedef enum +{ + ASSISTANT_TYPE_CLOCK = 0, + ASSISTANT_TYPE_REMAIND, + ASSISTANT_TYPE_SESSION, +} ASSISTANT_TYPE; + +typedef enum +{ + STATUS_IDLE = 0, + STATUS_PREPARE_STANDBY, + STATUS_RUNNING, + STATUS_NOT_IN_USE, + STATUS_REMOVE_ITEM, + STATUS_ADD_ITEM, +} ASSISTANT_STATUS; + +typedef struct +{ + unsigned long long itemId; ///< 提醒、闹钟ID + ASSISTANT_TYPE itemType; ///< 类型: 0 闹钟, 1 提醒 + int priority; ///< 优先级: 暂未使用 + REPEAT_MODE repeatMode; ///< 重复模式 + + int year; ///< 年 + int month; ///< 月 + int day; ///< 日 + int hour; ///< 小时 + int minute; ///< 分钟 + int second; ///< 秒钟 + int weekDay; ///< 星期 + + unsigned int timerId; ///< 关联的定时器ID + unsigned long long voiceId; ///< 闹钟资源ID + char strTips[MAX_TIP_LEN]; ///< 提醒 TTS 文本 + char resUrl[2048]; ///< 资源URL + char voiceRes[32]; ///< 资源声音文件ID + char voiceResType[64]; ///< 资源类型 +} ASSISTANT_ITEM_INFO, *PASSISTANT_ITEM_INFO; + +typedef struct +{ + int nItems; ///< 协议包含的数据个数 + PASSISTANT_ITEM_INFO pAlarmInfo; ///< 提醒、闹钟数据详细信息 +} ASSISTANT_SYNC_INFO, *PASSISTANT_SYNC_INFO; + +typedef struct ASSISTANT_ARRAY_INFO +{ + ASSISTANT_ITEM_INFO alarmItem; + struct ASSISTANT_ARRAY_INFO *next, *prev; +} *PASSISTANT_ARRAY_INFO; + +typedef struct +{ + int cmd; + int nItems; + ASSISTANT_TYPE type; + unsigned long long ids[MAX_ALARM_ITEMS]; +} ASSISTANT_NOTIFY_INFO, *PASSISTANT_NOTIFY_INFO; + +typedef struct +{ + int cmd; + int val; +} ASSISTANT_RSP_STATUS, *PASSISTANT_RSP_STATUS; + +typedef struct +{ + int cmd; + int val; + int errCode; +} ASSISTANT_NOFIFY_EVENT, *PASSISTANT_NOFIFY_EVENT; + +static void __printAssistantNofifyInfo(const char *pTags, PASSISTANT_NOTIFY_INFO pInfo) +{ + int i; + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Debug, "%s:\n", pTags); + LOG_EX2(LOG_Debug, "**************************************************************\n"); + } + + LOG_EX2(LOG_Debug, "Sync Items : %d\n", pInfo->nItems); + LOG_EX2(LOG_Debug, "-------------------------\n"); + LOG_EX2(LOG_Debug, "| Alarm Id | Type |\n"); + LOG_EX2(LOG_Debug, "-------------------------\n"); + + for(i = 0; i < pInfo->nItems; i++) + { + LOG_EX2(LOG_Debug, "| %8llu | %11s |\n", + pInfo->ids[i], + (pInfo->type == ASSISTANT_TYPE_REMAIND) ? "Remaind" : "Alarm Clock"); + } + + LOG_EX2(LOG_Debug, "-------------------------\n"); +} + +static void __printAssistantSyncInfo(const char* pTags, PASSISTANT_SYNC_INFO pInfo) +{ + int i; + char buf[MAX_PATH]; + struct tm localTime; + time_t tmStamp; + + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Debug, "%s:\n", pTags); + LOG_EX2(LOG_Debug, "**************************************************************\n"); + } + + //fprintf(stdout, "Command : %d(%08X)\n", pInfo->cmd, pInfo->cmd); + LOG_EX2(LOG_Debug, "Sync Items : %d\n", pInfo->nItems); + + LOG_EX2(LOG_Debug, "---------------------------------------------------------------------" + "-----------------------------------------------------------\n"); + + LOG_EX2(LOG_Debug, "| Alarm Id | Type | Priority | Repeat Mode | Week Day |" + " DateTime | Tips | Resource |\n"); + + LOG_EX2(LOG_Debug, "---------------------------------------------------------------------" + "-----------------------------------------------------------\n"); + + for(i = 0; i < pInfo->nItems; i++) + { + memset(buf, 0, MAX_PATH); + + sprintf(buf, "%04u-%02u-%02u %02u:%02u:%02u", + (pInfo->pAlarmInfo[i].year == -1) ? 1900 : pInfo->pAlarmInfo[i].year + 1900, + (pInfo->pAlarmInfo[i].month == -1) ? 0 : pInfo->pAlarmInfo[i].month + 1, + (pInfo->pAlarmInfo[i].day == -1) ? 0 : pInfo->pAlarmInfo[i].day, + (pInfo->pAlarmInfo[i].hour == -1) ? 0 : pInfo->pAlarmInfo[i].hour, + (pInfo->pAlarmInfo[i].minute == -1) ? 0 : pInfo->pAlarmInfo[i].minute, + (pInfo->pAlarmInfo[i].second == -1) ? 0 : pInfo->pAlarmInfo[i].second); + + LOG_EX2(LOG_Debug, "| %8llu | %11s | %8d | %15s | %d%d%d%d %d%d%d%d | %20s | %20s | %8llu |\n", + pInfo->pAlarmInfo[i].itemId, + (pInfo->pAlarmInfo[i].itemType == ASSISTANT_TYPE_REMAIND) ? "Remaind" : "Alarm Clock", + pInfo->pAlarmInfo[i].priority, + DumpTimerRepeatModeString(pInfo->pAlarmInfo[i].repeatMode), + (pInfo->pAlarmInfo[i].weekDay & (1 << 7))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 6))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 5))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 4))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 3))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 2))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 1))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 0))? 1 : 0, + buf, + pInfo->pAlarmInfo[i].strTips, + pInfo->pAlarmInfo[i].voiceId); + } + + LOG_EX2(LOG_Debug, "---------------------------------------------------------------------" + "-----------------------------------------------------------\n"); +} +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/config_engine.h b/include/config_engine.h new file mode 100644 index 0000000..80dfc49 --- /dev/null +++ b/include/config_engine.h @@ -0,0 +1,58 @@ +#ifndef CONFIG_ENGINE_H +#define CONFIG_ENGINE_H +#include +#include + +#include "smart_sound.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GLOBAL_CFG_FILE_PATH ("/mnt/UDISK/global.db") + + +typedef enum +{ + CFG_TYPE_STRING = 0, + CFG_TYPE_INT = 1, + CFG_TYPE_DOUBLE = 2, +} CFG_DATA_TYPE; + +typedef struct +{ + char* pKeyName; + int keyType; + int keyModule; + + union + { + char* pStrValue; + int intValue; + double doubleValue; + }; + + UT_hash_handle hh; ///< UT Hash handle +} CFG_ITEM, *PCFG_ITEM; + +typedef void (*OnCfgMsg)(DBUS_CMD cmd, PCFG_ITEM pMsg, int err); + +int CfgGlobalEnvInit(void); + +void CfgItemPrint(const char* pPrefix, PCFG_ITEM pCfgItem); + +int CfgGetKeyValue(const char* pKeyName, PCFG_ITEM* pItem); +int CfgChangeKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB); +int CfgAddKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB); + +void CfgSetIntValue(const char* pTags, int iValue); + +void OnCfgMsgProcess(MODULE_NAME dest, DBUS_CMD busCmd, const char *pJsonStr); + +int Sqlite3SyncDB(sqlite3* pSqlMemory, const char* pMemDbName, const char* pDBFilePath, const char* pFileDbName, int isSave); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/include/crypto.h b/include/crypto.h new file mode 100644 index 0000000..57961f8 --- /dev/null +++ b/include/crypto.h @@ -0,0 +1,81 @@ +#ifndef CRYPTO_H +#define CRYPTO_H +#include +#include +#ifdef __cplusplus +extern "C" { +#endif +#define ALIGN_AES_BLOCK(size) (((size + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE) + +#define MD5_VALUE_LEN (16) +#define MD5_STR_VALUE_LEN (MD5_VALUE_LEN * 2) + +typedef enum +{ + CRYPTO_AES_ENCRYPT = 0, + CRYPTO_AES_DECRYPT, + CRYPTO_BASE64_ENCODE, + CRYPTO_BASE64_DECODE, + CRYPTO_MD5_FILE, +} CRYPTO_TYPE; + +void EvpSystemInit(void); + +//***************************************************** +// AES +//***************************************************** +typedef void (*OnEVPCrypto)(CRYPTO_TYPE type, + const unsigned char* pData, + int iSize, + const unsigned char* pSrcData, + int iError); + + + +int EvpAESEncrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey); + +int EvpAESDecrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey); + +//***************************************************** +// BASE64 +//***************************************************** +const char* EvpBase64Encode(const char* pSrc); +const char* EvpBase64Decode(const char* pBase64); +const char* EvpBase64EncodeNoAlign(const char *pSrc); +const char* EvpBase64DecodeNoAlign(const char *pBase64); +const char* EvpBase64EncodeNoAlignV2(unsigned char *pSrc, int sLen); +unsigned char* EvpBase64DecodeNoAlignV2(const char *pBase64, int *pOutSize); +//***************************************************** +// MD5 +//***************************************************** +const char* EvpMD5HashFile(const char* pFileName); +int EvpMD5HashFileV2(const char *pFileName, unsigned char md5[16]);; +int EvpMD5HashBuf(const unsigned char *pBuf, int iBufLen, unsigned char *pOutBuf, int *pOutSize); +const char* EvpMD5HashBufV2(const unsigned char *pBuf, int iBufLen); +//***************************************************** +// Async Engine +//***************************************************** +int EvpAddCryptoTask(CRYPTO_TYPE type, + unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + char* pKey, + OnEVPCrypto onEvpCryptCb); + +//***************************************************** +// Compress +//***************************************************** +int GZipFileCompress(const char *pInput, const char *pOutput); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/fifo.h b/include/fifo.h new file mode 100644 index 0000000..4ea395b --- /dev/null +++ b/include/fifo.h @@ -0,0 +1,724 @@ +/* + * A generic kernel FIFO implementation + * + * Copyright (C) 2009/2010 Stefani Seibold + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef FIFO_H +#define FIFO_H + +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#define __must_check __attribute__((warn_unused_result)) +/* + * How to porting drivers to the new generic FIFO API: + * + * - Modify the declaration of the "struct kfifo *" object into a + * in-place "struct kfifo" object + * - Init the in-place object with kfifo_alloc() or kfifo_init() + * Note: The address of the in-place "struct kfifo" object must be + * passed as the first argument to this functions + * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get + * into kfifo_out + * - Replace the use of kfifo_put into kfifo_in_spinlocked and kfifo_get + * into kfifo_out_spinlocked + * Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc + * must be passed now to the kfifo_in_spinlocked and kfifo_out_spinlocked + * as the last parameter + * - The formerly __kfifo_* functions are renamed into kfifo_* + */ + +/* + * Note about locking : There is no locking required until only * one reader + * and one writer is using the fifo and no kfifo_reset() will be * called + * kfifo_reset_out() can be safely used, until it will be only called + * in the reader thread. + * For multiple writer and one reader there is only a need to lock the writer. + * And vice versa for only one writer and multiple reader there is only a need + * to lock the reader. + */ + + +struct __kfifo { + unsigned int in; + unsigned int out; + unsigned int mask; + unsigned int esize; + void *data; + uv_mutex_t lock; +}; + +#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \ + union { \ + struct __kfifo kfifo; \ + datatype *type; \ + char (*rectype)[recsize]; \ + ptrtype *ptr; \ + const ptrtype *ptr_const; \ + } + +#define __STRUCT_KFIFO(type, size, recsize, ptrtype) \ +{ \ + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \ +} + +#define STRUCT_KFIFO(type, size) \ + struct __STRUCT_KFIFO(type, size, 0, type) + +#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \ +{ \ + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[0]; \ +} + +#define STRUCT_KFIFO_PTR(type) \ + struct __STRUCT_KFIFO_PTR(type, 0, type) + +/* + * define compatibility "struct kfifo" for dynamic allocated fifos + */ +struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void); + +#define STRUCT_KFIFO_REC_1(size) \ + struct __STRUCT_KFIFO(unsigned char, size, 1, void) + +#define STRUCT_KFIFO_REC_2(size) \ + struct __STRUCT_KFIFO(unsigned char, size, 2, void) + +/* + * define kfifo_rec types + */ +struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void); +struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void); + +/* + * helper macro to distinguish between real in place fifo where the fifo + * array is a part of the structure and the fifo type where the array is + * outside of the fifo structure. + */ +#define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo)) + +/** + * DECLARE_KFIFO_PTR - macro to declare a fifo pointer object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + */ +#define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) fifo + +/** + * DECLARE_KFIFO - macro to declare a fifo object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + */ +#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo + +/** + * INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO + * @fifo: name of the declared fifo datatype + */ +#define INIT_KFIFO(fifo) \ +(void)({ \ + typeof(&(fifo)) __tmp = &(fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __kfifo->in = 0; \ + __kfifo->out = 0; \ + __kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\ + __kfifo->esize = sizeof(*__tmp->buf); \ + __kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \ +}) + +/** + * DEFINE_KFIFO - macro to define and initialize a fifo + * @fifo: name of the declared fifo datatype + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + * + * Note: the macro can be used for global and local fifo data type variables. + */ +#define DEFINE_KFIFO(fifo, type, size) \ + DECLARE_KFIFO(fifo, type, size) = \ + (typeof(fifo)) { \ + { \ + { \ + .in = 0, \ + .out = 0, \ + .mask = __is_kfifo_ptr(&(fifo)) ? \ + 0 : \ + ARRAY_SIZE((fifo).buf) - 1, \ + .esize = sizeof(*(fifo).buf), \ + .data = __is_kfifo_ptr(&(fifo)) ? \ + NULL : \ + (fifo).buf, \ + } \ + } \ + } + + +static inline unsigned int __must_check +__kfifo_uint_must_check_helper(unsigned int val) +{ + return val; +} + +static inline int __must_check +__kfifo_int_must_check_helper(int val) +{ + return val; +} + +/** + * kfifo_initialized - Check if the fifo is initialized + * @fifo: address of the fifo to check + * + * Return %true if fifo is initialized, otherwise %false. + * Assumes the fifo was 0 before. + */ +#define kfifo_initialized(fifo) ((fifo)->kfifo.mask) + +/** + * kfifo_esize - returns the size of the element managed by the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_esize(fifo) ((fifo)->kfifo.esize) + +/** + * kfifo_recsize - returns the size of the record length field + * @fifo: address of the fifo to be used + */ +#define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype)) + +/** + * kfifo_size - returns the size of the fifo in elements + * @fifo: address of the fifo to be used + */ +#define kfifo_size(fifo) ((fifo)->kfifo.mask + 1) + +/** + * kfifo_reset - removes the entire fifo content + * @fifo: address of the fifo to be used + * + * Note: usage of kfifo_reset() is dangerous. It should be only called when the + * fifo is exclusived locked or when it is secured that no other thread is + * accessing the fifo. + */ +#define kfifo_reset(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->kfifo.in = __tmp->kfifo.out = 0; \ +}) + +/** + * kfifo_reset_out - skip fifo content + * @fifo: address of the fifo to be used + * + * Note: The usage of kfifo_reset_out() is safe until it will be only called + * from the reader thread and there is only one concurrent reader. Otherwise + * it is dangerous and must be handled in the same way as kfifo_reset(). + */ +#define kfifo_reset_out(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->kfifo.out = __tmp->kfifo.in; \ +}) + +/** + * kfifo_len - returns the number of used elements in the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_len(fifo) \ +({ \ + typeof((fifo) + 1) __tmpl = (fifo); \ + __tmpl->kfifo.in - __tmpl->kfifo.out; \ +}) + +/** + * kfifo_is_empty - returns true if the fifo is empty + * @fifo: address of the fifo to be used + */ +#define kfifo_is_empty(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + __tmpq->kfifo.in == __tmpq->kfifo.out; \ +}) + +/** + * kfifo_is_full - returns true if the fifo is full + * @fifo: address of the fifo to be used + */ +#define kfifo_is_full(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + kfifo_len(__tmpq) > __tmpq->kfifo.mask; \ +}) + +/** + * kfifo_avail - returns the number of unused elements in the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_avail(fifo) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + const unsigned int __recsize = sizeof(*__tmpq->rectype); \ + unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \ + (__recsize) ? ((__avail <= __recsize) ? 0 : \ + __kfifo_max_r(__avail - __recsize, __recsize)) : \ + __avail; \ +}) \ +) + +/** + * kfifo_skip - skip output data + * @fifo: address of the fifo to be used + */ +#define kfifo_skip(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__recsize) \ + __kfifo_skip_r(__kfifo, __recsize); \ + else \ + __kfifo->out++; \ +}) + +/** + * kfifo_peek_len - gets the size of the next fifo record + * @fifo: address of the fifo to be used + * + * This function returns the size of the next fifo record in number of bytes. + */ +#define kfifo_peek_len(fifo) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (!__recsize) ? kfifo_len(__tmp) * sizeof(*__tmp->type) : \ + __kfifo_len_r(__kfifo, __recsize); \ +}) \ +) + +/** + * kfifo_alloc - dynamically allocates a new fifo buffer + * @fifo: pointer to the fifo + * @size: the number of elements in the fifo, this must be a power of 2 + * @gfp_mask: get_free_pages mask, passed to kmalloc() + * + * This macro dynamically allocates a new fifo buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * The fifo will be release with kfifo_free(). + * Return 0 if no error, otherwise an error code. + */ +#define kfifo_alloc(fifo, size) \ +__kfifo_int_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __is_kfifo_ptr(__tmp) ? \ + __kfifo_alloc(__kfifo, size, sizeof(*__tmp->type)) : \ + -EINVAL; \ +}) \ +) + +/** + * kfifo_free - frees the fifo + * @fifo: the fifo to be freed + */ +#define kfifo_free(fifo) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__is_kfifo_ptr(__tmp)) \ + __kfifo_free(__kfifo); \ +}) + +/** + * kfifo_init - initialize a fifo using a preallocated buffer + * @fifo: the fifo to assign the buffer + * @buffer: the preallocated buffer to be used + * @size: the size of the internal buffer, this have to be a power of 2 + * + * This macro initialize a fifo using a preallocated buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * Return 0 if no error, otherwise an error code. + */ +#define kfifo_init(fifo, buffer, size) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __is_kfifo_ptr(__tmp) ? \ + __kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \ + -EINVAL; \ +}) + +/** + * kfifo_put - put data into the fifo + * @fifo: address of the fifo to be used + * @val: the data to be added + * + * This macro copies the given value into the fifo. + * It returns 0 if the fifo was full. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_put(fifo, val) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \ + __dummy = (typeof(__val))NULL; \ + } \ + if (__recsize) \ + __ret = __kfifo_in_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_full(__tmp); \ + if (__ret) { \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->in & __tmp->kfifo.mask] = \ + *(typeof(__tmp->type))__val; \ + __kfifo->in++; \ + } \ + } \ + __ret; \ +}) + +/** + * kfifo_get - get data from the fifo + * @fifo: address of the fifo to be used + * @val: the var where to store the data to be added + * + * This macro reads the data from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_get(fifo, val) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) \ + __val = (typeof(__tmp->ptr))0; \ + if (__recsize) \ + __ret = __kfifo_out_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->out & __tmp->kfifo.mask]; \ + __kfifo->out++; \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * kfifo_peek - get data from the fifo without removing + * @fifo: address of the fifo to be used + * @val: the var where to store the data to be added + * + * This reads the data from the fifo without removing it from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_peek(fifo, val) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) \ + __val = (typeof(__tmp->ptr))NULL; \ + if (__recsize) \ + __ret = __kfifo_out_peek_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->out & __tmp->kfifo.mask]; \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * kfifo_in - put data into the fifo + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * + * This macro copies the given buffer into the fifo and returns the + * number of copied elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_in(fifo, buf, n) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \ + __dummy = (typeof(__buf))NULL; \ + } \ + (__recsize) ?\ + __kfifo_in_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_in(__kfifo, __buf, __n); \ +}) + +/** + * kfifo_in_spinlocked - put data into the fifo using a spinlock for locking + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * @lock: pointer to the spinlock to use for locking + * + * This macro copies the given values buffer into the fifo and returns the + * number of copied elements. + */ +#define kfifo_in_locked(fifo, buf, n) \ +({ \ + unsigned int __ret; \ + uv_mutex_t __lock = ((struct __kfifo*)fifo)->lock; \ + uv_mutex_lock(&__lock); \ + __ret = kfifo_in(fifo, buf, n); \ + uv_mutex_unlock(&__lock); \ + __ret; \ +}) + + +/** + * kfifo_out - get data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get some data from the fifo and return the numbers of elements + * copied. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr) __dummy = NULL; \ + __buf = __dummy; \ + } \ + (__recsize) ?\ + __kfifo_out_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_out(__kfifo, __buf, __n); \ +}) \ +) + +/** + * kfifo_out_spinlocked - get data from the fifo using a spinlock for locking + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * @lock: pointer to the spinlock to use for locking + * + * This macro get the data from the fifo and return the numbers of elements + * copied. + */ +#define kfifo_out_locked(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + unsigned int __ret; \ + uv_mutex_t __lock = ((struct __kfifo*)fifo)->lock; \ + uv_mutex_lock(&__lock); \ + __ret = kfifo_out(fifo, buf, n); \ + uv_mutex_unlock(&__lock); \ + __ret; \ +}) \ +) + +/** + * kfifo_from_user - puts some data from user space into the fifo + * @fifo: address of the fifo to be used + * @from: pointer to the data to be added + * @len: the length of the data to be added + * @copied: pointer to output variable to store the number of copied bytes + * + * This macro copies at most @len bytes from the @from into the + * fifo, depending of the available space and returns -EFAULT/0. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_from_user(fifo, from, len, copied) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const void __user *__from = (from); \ + unsigned int __len = (len); \ + unsigned int *__copied = (copied); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_from_user_r(__kfifo, __from, __len, __copied, __recsize) : \ + __kfifo_from_user(__kfifo, __from, __len, __copied); \ +}) \ +) + +/** + * kfifo_to_user - copies data from the fifo into user space + * @fifo: address of the fifo to be used + * @to: where the data must be copied + * @len: the size of the destination buffer + * @copied: pointer to output variable to store the number of copied bytes + * + * This macro copies at most @len bytes from the fifo into the + * @to buffer and returns -EFAULT/0. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_to_user(fifo, to, len, copied) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + void __user *__to = (to); \ + unsigned int __len = (len); \ + unsigned int *__copied = (copied); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \ + __kfifo_to_user(__kfifo, __to, __len, __copied); \ +}) \ +) + +/** + * kfifo_out_peek - gets some data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get the data from the fifo and return the numbers of elements + * copied. The data is not removed from the fifo. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out_peek(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr) __dummy __attribute__ ((unused)) = NULL; \ + __buf = __dummy; \ + } \ + (__recsize) ? \ + __kfifo_out_peek_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_out_peek(__kfifo, __buf, __n); \ +}) \ +) + +#define kfifo_peek_locked(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + unsigned int __ret; \ + uv_mutex_t __lock = ((struct __kfifo*)fifo)->lock; \ + uv_mutex_lock(&__lock); \ + __ret = kfifo_out_peek(fifo, buf, n); \ + uv_mutex_unlock(&__lock); \ + __ret; \ +}) \ +) + +extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, unsigned int esize); + +extern void __kfifo_free(struct __kfifo *fifo); + +extern int __kfifo_init(struct __kfifo *fifo, void *buffer, + unsigned int size, unsigned int esize); + +extern unsigned int __kfifo_in(struct __kfifo *fifo, + const void *buf, unsigned int len); + +extern unsigned int __kfifo_out(struct __kfifo *fifo, + void *buf, unsigned int len); + +extern unsigned int __kfifo_out_peek(struct __kfifo *fifo, + void *buf, unsigned int len); + +extern unsigned int __kfifo_in_r(struct __kfifo *fifo, + const void *buf, unsigned int len, unsigned int recsize); + +extern unsigned int __kfifo_out_r(struct __kfifo *fifo, + void *buf, unsigned int len, unsigned int recsize); + +extern unsigned int __kfifo_len_r(struct __kfifo *fifo, unsigned int recsize); + +extern void __kfifo_skip_r(struct __kfifo *fifo, unsigned int recsize); + +extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, + void *buf, unsigned int len, unsigned int recsize); + +extern unsigned int __kfifo_max_r(unsigned int len, unsigned int recsize); + +#endif diff --git a/include/inet_api.h b/include/inet_api.h new file mode 100644 index 0000000..c49936d --- /dev/null +++ b/include/inet_api.h @@ -0,0 +1,51 @@ +#ifndef INET_API_H +#define INET_API_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_HTTP_POST_SIZE (1024) + +typedef struct HTTP_POST_ATTACH +{ + char keyName[64]; + char keyValue[MAX_HTTP_POST_SIZE]; + + struct HTTP_POST_ATTACH *next, *prev; +} *PHTTP_POST_ATTACH; + +typedef struct +{ + char *pUserName; + char *pPassword; + char *pSmtpServer; + short smtpPort; +} SMTP_MAIL_CONFIG, *PSMTP_MAIL_CONFIG; + +int InetSmtpSendEmail(const char *pFrom, + const char *pTo[], + const char *pCc[], + const char *pTitle, + const char *pMessage, + const char *pAttach[], + PSMTP_MAIL_CONFIG pConfig); +#define InetHttpsDownloadFile(pURL, pPath, onRespCb, onPrgCb) InetHttpDlFileAsync(pURL, pPath, onRespCb, onPrgCb) +#define InetHttpsWebServicePost(pURL, pPost, onRespCb) InetHttpWebServicePostAsync(pURL, pPost, onRespCb) +int InetCancelDownload(const char *pTaskUuid); + +typedef void (*OnHttpResponse)(void* pData, unsigned int size, const char* pReqUrl, const char* pDlPath, const char* pTaskUuid, int iFinished, void* pUserData); +typedef void (*OnProgressNotify)(const char* pReqUrl, const char* pTaskUuid, unsigned char uPercent, void* pUserData); + +int InetInit(void); +void InetUnInit(void); + +const char* InetHttpDlFileAsync(const char*, const char*, OnHttpResponse, OnProgressNotify, void*); +const char* InetHttpWebServicePostAsync(const char *pURL, const char *pPost, OnHttpResponse onRespCb, void *pData); +int InetHttpUploadFileSync(const char *pURL, const char* pPath, void* pAttachInfo); +//int InetSmtpSendEmail(void); +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/json_struct.h b/include/json_struct.h new file mode 100644 index 0000000..5664316 --- /dev/null +++ b/include/json_struct.h @@ -0,0 +1,150 @@ +#ifndef JSON_STRUCT_H +#define JSON_STRUCT_H +#include + +#include "smart_sound.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_MUSIC_UUID (256) +#define MAX_MUSIC_URL (2048) + +typedef enum +{ +//****************************************** +// Player <--> Controller +//****************************************** + JSON_ENGINE_P2C = 0, + JSON_ENGINE_C2P, + +//****************************************** +// Configure Req & Rsp +//****************************************** + JSON_ENGINE_CFG_REQ, + JSON_ENGINE_CFG_RSP, + +//****************************************** +// Alarm Req & Rsp +//****************************************** + JSON_ENGINE_ASSISTANT_SYNC_RSP, + JSON_ENGINE_ASSISTANT_NOTIFY, + JSON_ENGINE_ASSISTANT_STATUS, + JSON_ENGINE_ASSISTANT_RUNNING, + +//****************************************** +// Work Day API Req & Rsp +//****************************************** + JSON_ENGINE_WORKDAY_REQ, + +//****************************************** +// PING Cmd +//****************************************** + JSON_ENGINE_PING, + +//****************************************** +// OTA Cmd +//****************************************** + JSON_ENGINE_OTA_REQ, + JSON_ENGINE_OTA_RSP, + +//****************************************** +// LOG System Configure Cmd +//****************************************** + JSON_ENGINE_LOG_CFG_CMD, + +//****************************************** +// WIFI Status Changed Nofify Cmd +//****************************************** + JSON_WIFI_STATUS_NOTIFY, + +//****************************************** +// mcu test Cmd +//****************************************** + JSON_MCU_GUIDE_TEST_CMD, + JSON_MCU_MATRIX_TEST_CMD, + JSON_MCU_TEST_GET_VER_CMD, + + JSON_ENGINE_MAX, +} JSON_ENGINE_TYPE; + +typedef struct +{ + uint32_t playerId; + char musicUuid[MAX_MUSIC_UUID]; + int plySt; + uint32_t curPos; + uint32_t duration; +} PLAYER_TO_CTRL, *PPLAYER_TO_CTRL; + +typedef struct +{ + uint32_t playerId; + char src[MAX_MUSIC_URL]; + char srcUuid[MAX_MUSIC_URL]; + char ttsText[MAX_MUSIC_UUID * 2]; + int skTime; + int plyMode; + int plyListType; + char adSrcType; + int duration; + int volRestoreTime; + char volBegin; + float gain; + char fifo[MAX_MUSIC_UUID]; + char channel; + char bytes; + int sampleRate; + char backGroundUrl[MAX_MUSIC_URL]; +} CTRL_TO_PLAYER, *PCTRL_TO_PLAYER; + +typedef struct +{ + char keyName[MAX_CFG_KEY_NAME]; + char keyValue[MAX_CFG_KEY_VALUE]; + int keyType; +} CFG_API_REQ, *PCFG_API_REQ; + +typedef struct +{ + int red; + int green; + int blue; +} MCU_TEST_GUIDE_CMD, *PMCU_TEST_GUIDE_CMD; + +typedef struct +{ + int level; +} MCU_TEST_MATRIX_CMD, *PMCU_TEST_MATRIX_CMD; + +typedef struct +{ + char McuVer[16]; +} MCU_TEST_VER_CMD, *PMCU_TEST_VER_CMD; + + +typedef struct +{ + char keyName[MAX_CFG_KEY_NAME]; + char keyValue[MAX_CFG_KEY_VALUE]; + int keyType; + int errNo; +} CFG_API_RSP, *PCFG_API_RSP; + +typedef struct +{ + double PING; + int tmSec; + int tmMSec; +} PING_MSG, *PPING_MSG; + +void* Json2Struct(const char* pJsonStr, JSON_ENGINE_TYPE type, int enBase64, int* pErr); +const char* Struct2Json(void* pStruct, JSON_ENGINE_TYPE type, int enBase64, int* pErr); + + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/include/libuv_dbus.h b/include/libuv_dbus.h new file mode 100644 index 0000000..1b8f350 --- /dev/null +++ b/include/libuv_dbus.h @@ -0,0 +1,225 @@ +#ifndef LIBUV_DEBUS_H +#define LIBUV_DEBUS_H +#include "smart_sound.h" + +#include +#include +#include "json_struct.h" +#include "config_engine.h" + +#ifdef __cplusplus +extern "C" { +#endif +#define SAFE_STRING_VALUE(s) (s ? s : "") +#define R16_TINA_KEY_EVENT_PATH ("/dev/input/event2") +#define DBUS_MESSAGE_INTERFACE_NAME "netease.ihw.SmartAudio" + +#define DBUS_PATH_HEAD "/netease/ihw/" +#define DBUS_INTERFACE_HEAD "netease.ihw." + +#define DBUS_MSG_MAX_PAD_SIZE (1024 * 1024 * 2) +#define LIBUV_CURRENT_TIME_S() (uv_hrtime() / 1000000000) +#define LIBUV_CURRENT_TIME_MS() (uv_hrtime() / 1000000) +#define LIBUV_CURRENT_TIME_US() (uv_hrtime() / 1000) +#define MODULE_ALIAS_NAME(i) (strrchr(g_pModInfoTable[i].modAliase, '.') + 1) + +#define HEART_SEND_DELAY (5000) +#define HEART_LOST_DELAY (20000) + +typedef enum +{ + WIFI_CONNECTED = 0, + WIFI_DISCONNECTED = 1, +} WIFI_STATUS; + +typedef struct +{ + int wifi_evt; +} WIFI_STATUS_PRO, *PWIFI_STATUS_PRO; + +typedef struct +{ + int year; + unsigned char days[366]; +} WORKDAY_INFO, *PWORKDAY_INFO; + +typedef struct +{ + int32_t msgSrc; ///< message who send + uint32_t msgDests; ///< who need receive message(not only one) +#if USED_SHM_TO_DBUS + uint32_t tmTickMSec; ///< timestamp of second +#endif + uint32_t busCmd; ///< command of message + uint32_t msgSize; ///< how many bytes of this message + uint32_t msgKey; ///< share key for copy large message + char* pMsg; ///< message context if has + int isBstMsg; +} DBUS_MSG_PACK, *PDBUS_MSG_PACK; + +typedef struct DBUS_MSG_PROC +{ + int msgFrom; ///< 0: Boardcast Msg, 1: P2P Message + DBUS_MSG_PACK msgContent; + + struct DBUS_MSG_PROC *next, *prev; +} *PDBUS_MSG_PROC; + +typedef void (*OnDBusAsyncSendTo)(int err); +typedef PDBUS_MSG_PACK (*OnDBusMessage)(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg); +typedef void (*OnDaemonMsg)(MODULE_NAME modName, int status); +typedef void (*OnKeyEvent)(uint16_t uType, uint16_t uKey, int32_t iValue); + +typedef struct +{ + MODULE_NAME modName; ///< Module Name + const char* modPath; ///< Attach to dbus path + const char* modAliase; ///< Attach to dbus bus name +} MOD_INFO_TABLE, *PMOD_INFO_TABLE; + + +typedef struct +{ + uv_loop_t* pLoop; ///< libuv default main loop + uv_loop_t* pUserLoop; ///< libuv user main loop + DBusConnection* pBus; ///< D-Bus object + MODULE_NAME modName; ///< Process name + const char* pBusName; ///< D-Bus object's interface name + const char* pBusPath; ///< D-Bus object's path name + OnDBusMessage onMsgCb; ///< D-Bus receive message callback + OnKeyEvent onKeyCb; ///< Keyboard event callback + OnDaemonMsg onHblCb; ///< Process HBL event callback + OnCfgMsg onCfgCb; ///< Configure message callback +// unsigned int uDaemon[MODULE_MAX]; ///< Daemon Service +} LIBUV_DBUS_PARAMS, *PLIBUV_DBUS_PARAMS; + +static MOD_INFO_TABLE g_pModInfoTable[] = +{ + {MODULE_CONTROLLER, DBUS_PATH_HEAD"controller", DBUS_INTERFACE_HEAD"controller"}, + {MODULE_ALARM, DBUS_PATH_HEAD"alarm", DBUS_INTERFACE_HEAD"alarm"}, + {MODULE_CALL, DBUS_PATH_HEAD"call", DBUS_INTERFACE_HEAD"call"}, + {MODULE_VOICEENGINE, DBUS_PATH_HEAD"voice_engine", DBUS_INTERFACE_HEAD"voice_engine"}, + {MODULE_PLAYER, DBUS_PATH_HEAD"player", DBUS_INTERFACE_HEAD"player"}, + {MODULE_CONFIGURE, DBUS_PATH_HEAD"config", DBUS_INTERFACE_HEAD"config"}, + {MODULE_OTA, DBUS_PATH_HEAD"ota", DBUS_INTERFACE_HEAD"ota"}, + {MODULE_WIFI, DBUS_PATH_HEAD"wifi", DBUS_INTERFACE_HEAD"wifi"}, + {MODULE_BT, DBUS_PATH_HEAD"bt", DBUS_INTERFACE_HEAD"bt"}, + {MODULE_KPLAYER, DBUS_PATH_HEAD"kplayer", DBUS_INTERFACE_HEAD"kplayer"}, + {MODULE_KPLAYER_TEST, DBUS_PATH_HEAD"kplayerTest", DBUS_INTERFACE_HEAD"kplayerTest"}, + {MODULE_SPLAYER, DBUS_PATH_HEAD"splayer", DBUS_INTERFACE_HEAD"splayer"}, + {MODULE_SPLAYER_TEST, DBUS_PATH_HEAD"splayerTest", DBUS_INTERFACE_HEAD"splayerTest"}, + {MODULE_LIGHT_MCU, DBUS_PATH_HEAD"light_mcu", DBUS_INTERFACE_HEAD"light_mcu"}, + {MODULE_BLUEKC, DBUS_PATH_HEAD"blukc", DBUS_INTERFACE_HEAD"blukc"}, + {MODULE_BLUEKC_TEST, DBUS_PATH_HEAD"bluekcTest", DBUS_INTERFACE_HEAD"bluekcTest"}, + {MODULE_MANUFACTURE, DBUS_PATH_HEAD"manufacture", DBUS_INTERFACE_HEAD"manufacture"}, + {MODULE_BT_DEMO, DBUS_PATH_HEAD"btdemo", DBUS_INTERFACE_HEAD"btdemo"}, + {MODULE_SKINS, DBUS_PATH_HEAD"skins", DBUS_INTERFACE_HEAD"skins"}, + {MODULE_LOG_CTRL, DBUS_PATH_HEAD"logCtrl", DBUS_INTERFACE_HEAD"logCtrl"}, + {MODULE_WIRELESSTEST, DBUS_PATH_HEAD"wirelessTest", DBUS_INTERFACE_HEAD"wirelessTest"}, + {MODULE_WIRELESSTEST_DEMO, DBUS_PATH_HEAD"wirelessTestDemo", DBUS_INTERFACE_HEAD"wirelessTestDemo"}, + {MODULE_MANUFACTURE_CONTROLLER, DBUS_PATH_HEAD"manufacture_controller", DBUS_INTERFACE_HEAD"manufacture_controller"}, + {MODULE_WIFI_DEMO, DBUS_PATH_HEAD"wifiDemo", DBUS_INTERFACE_HEAD"wifiDemo"}, +}; + +PLIBUV_DBUS_PARAMS DBusLibuvGetRuntime(void); +MODULE_NAME DBusLibGetModName(void); +uv_loop_t* GetDBusDefaultLoop(void); + +void RunUVLoop(uv_loop_t *pLoop); + +PDBUS_MSG_PACK DBusGetMessage(void); +void DBusMsgCleanup(PDBUS_MSG_PACK pMsg); + +DBusConnection* DBusWithLibuvInit(uv_loop_t* pUserLoop, + const char* pBusName, + OnDBusMessage cbOnMsg, + OnDaemonMsg cbOnHbl, + OnKeyEvent cbOnKey, + int* pErrno); + +int DBusJsonSendToCommandAsync(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int iSize, + OnDBusAsyncSendTo cbSendTo, + int enBase64); + +int DBusJsonSendToCommand(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64); + +int DBusJsonBoardcastCommand(DBusConnection* pBus, + uint32_t msgToMask, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64); + +int DBusBoardcastCommand(DBusConnection *pBus, + uint32_t msgToMask, + uint32_t busCmd, + const char *pContext); + +int DBusSendToCommand(DBusConnection *pBus, + const char *pBusName, + uint32_t busCmd, + const char *pContext); + +void HeartDaemonUpgrade(int iWatcher); +void HeartDaemonInit(MODULE_NAME mod, int msHblTout, OnDaemonMsg cb); +void HeartDaemonHblCheck(void); + +int DBusWithLibuvCfgInit(OnCfgMsg cbOnCfgMsg); +int GetShellExecResult(const char *pCmd, char **pResult); +int CopyFile(const char *pSrc, const char *pDest); +int CopyFileWithSize(const char *pSrc, const char *pDest, int iSize); +int ReadFileToBuf(const char *pSrc, unsigned char *pBuf, int iSize); +void SystemSafeReboot(void); + +typedef void (*OnAlarmTimer)(unsigned int tmId, unsigned int status, void* pUserData); +int AlarmTimerInit(uv_loop_t *pLoop); +int AlarmTimerCleanup(void); +int AlarmTimerRemove(unsigned int tmId); +#if 0 +unsigned int AlarmTimerAdd(struct tm *pOnTime, unsigned int repMode, OnAlarmTimer pOnTimerCb, void *pUserData, int *pError); +#endif +unsigned int AlarmTimerAdd(int year, + int month, + int day, + int hour, + int minute, + int second, + int weekDay, + int repMode, + OnAlarmTimer pOnTimerCb, + int priority, + void *pUserData, + int *pError); + +int CurrentIsWorkDay(int year, int day); +const char* DumpTimerRepeatModeString(int mode); +unsigned long long GetPartitionFreeSize(const char *pPartPath); +WIFI_STATUS GetCurrWIFIConnStatus(void); +const char* ErrcodeToString(int errCode); +const char* DBusCmdToString(DBUS_CMD cmd); +const char* ModuleNameToString(MODULE_NAME modName); + +char* GetCpuSerial(void); +char* GetCpuChipId(void); +char* GetCurrentVersion(void); + +void CfgFileInit(void); +int CfgGetIntValue(const char* pTags, int defValue); +char* CfgGetStringValue(const char* pTags, char* pDefValue); +double CfgGetFloatValue(const char* pTags, double defValue); +int CfgGetBoolValue(const char* pTags, int defValue); +void SetHBLAutoExit(int flag); +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/log.h b/include/log.h new file mode 100644 index 0000000..118d79c --- /dev/null +++ b/include/log.h @@ -0,0 +1,233 @@ +/** @file log.h + @brief + @details + @version 1.0.0 +*/ +#ifndef LOG_H_ +#define LOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __KERNEL__ +#include +#include +#else +#include +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef MAX +/** @def MAX + @brief 取最大值 +*/ +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +/** @def MIN + @brief 取最小值 +*/ +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define TIMEZONE_EAST_8H (8 * 3600) + +#ifndef __KERNEL__ +#define DUMP_PREFIX_ADDRESS (1) +#define DUMP_PREFIX_OFFSET (2) +#endif + +#define DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName) do { \ + for(int i = 0; i < argc; i++) { \ + fprintf(stdout, "%s = [%s], ", azColName[i], argv[i]); \ + } \ + fprintf(stdout, "\n"); \ +} while(0); + +#define print(format, ...) fprintf(stdout, format, __VA_ARGS__) + +typedef struct +{ + int cfgCmd; + int iParams1; + int iParams2; +} LOG_CFG_PROTOCOL, *PLOG_CFG_PROTOCOL; + +typedef enum +{ + CMD_LOG_ENABLE = 0, + CMD_LOG_FILE = 1, + CMD_LOG_MAIL = 2, + CMD_LOG_LEVEL = 3, + CMD_LOG_NETWORK = 4, + CMD_LOG_SERVER = 5 +} LOG_CFG_CMD; + +/** @enum _LOG_LEVEL_ + * LOG等级枚举变量 + */ +typedef enum +{ + LOG_Fatal = (1 << 0), + LOG_Error = (1 << 1), + LOG_Warn = (1 << 2), + LOG_Debug = (1 << 3), + LOG_Info = (1 << 4), + LOG_Test = (1 << 5), + LOG_Call = (1 << 6), + LOG_Devp = (1 << 7), + LOG_Step = (1 << 8), + LOG_Unknown = (1 << 9), + LOG_All = (0xFFFFFFFF), + LOG_Close = 0x0, +} LOG_LEVEL; +/** @var typedef _LOG_LEVEL_ LOG_LEVEL + * @brief 错误值枚举类型 + */ + +#ifdef DISABLE_LOG +#define LOG_BUF(level, buf, len) +#define LOG_EX(level, format, args...) +#define LOG_EX2(level, format, args...) +#define LOG_TAG_EX(tag, level, format, args...) +#define DEBUG_CODE_LINE() +#define DEBUG_FUNCTION_BEGIN() +#define DEBUG_FUNCTION_END() +#else +#define LOG_BUF(level, buf, len) do { \ + const char* pFmtBuf = format_hex_buf("", DUMP_PREFIX_ADDRESS, 16, 1, buf, len, 1); \ + IHW_LOG(level, "[%s] - %s(%d): %s[0-%d]:\n%s", basename_v2(__FILE__), __FUNCTION__, __LINE__, \ + #buf, len, pFmtBuf); \ + free((void*)pFmtBuf); \ +} while(0); +/*! \def LOG_EX + \brief 系统日志调试宏标识 +*/ +#define LOG_EX(level, format, args...) (IHW_LOG(level, "[%s] - %s(%d):" format , basename_v2(__FILE__), __FUNCTION__, __LINE__, ##args)) + +/*! \def LOG_TAG_EX + \brief 系统日志调试宏标识 +*/ +#define LOG_TAG_EX(tag, level, format, args...) (IHW_LOG(level, "{%s} [%s] %s(%d):" format , tag, basename_v2(__FILE__), __FUNCTION__, __LINE__, ##args)) + +#define LOG_EX2(level, format, args...) (IHW_LOG_UNTAG(level, format , ##args)) + +/*! @def APP_BUILD_INFO + @brief 应用程序编译信息 +*/ +#define APP_BUILD_INFO(appname, appver) (IHW_LOG(LOG_Info, "%s Ver:%s (Build: %s %s GCC Ver:%s) With %d(bits) OS\n", \ + appname, appver, __DATE__, __TIME__, __VERSION__, sizeof(int*) * 8)) + + +/*! @def DEBUG_CODE_LINE + @brief 输出当前函数名,行号 +*/ +#define DEBUG_CODE_LINE() (LOG_EX(LOG_Info, "\n")) + +/*! @def DEBUG_FUNCTION_BEGIN + @brief 函数入口标志 +*/ +#define DEBUG_FUNCTION_BEGIN() (LOG_EX(LOG_Call, "+++++\n")) + +/*! @def DEBUG_FUNCTION_END + @brief 函数出口标志 +*/ +#define DEBUG_FUNCTION_END() (LOG_EX(LOG_Call, "-----\n")) + +/** + * @brief 输出调试信息 + * @param level 调试信息开关 + * @param pMsg 调试信息内容 + */ +void IHW_LOG(LOG_LEVEL level, const char* pMsg, ...); +void IHW_LOG_UNTAG(LOG_LEVEL level, const char* pMsg, ...); + +void IHW_LogStrWithoutPrint(int level, char* pMsg); +void IHW_LogRawString(int level, char* pMsg); + +/** + * @brief 设置调试等级 + * @param level 调试等级 + * @param iEnable 1 打开调试等级, 0 关闭调试等级 + */ +void IHW_EnableLogLevel(LOG_LEVEL level, int iEnable); + +/** + * @brief 初始化系统日志功能 + * @param pLogTag 系统日志标志 + * @param pPath 系统日志保存路径 + * @param bEnable 打开/关闭调试信息 + */ +void IHW_InitLOG(const char* pLogTag, const char* pPath, int bEnable); + +void IHW_RunLogService(void); + +/** + * @brief 判断文件、路径是否存在 + * @param pPath - 文件路径 + * @return int 存在返回 1, 否则返回 0; + */ +int IHW_IsFileExist(const char* pPath); + +void IHW_EnableLogOut(void); +void IHW_DisableLogOut(void); + +char* IHW_bin2hex(char *p, const unsigned char *cp, int count); + +void UpgradLogConfigure(PLOG_CFG_PROTOCOL pCfg); +//void LogUploadCurLogFile(void); + +/* Return the last part of a pathname */ +static inline const char* basename_v2(const char* path) +{ + const char* tail = strrchr(path, '/'); + return tail ? tail + 1 : path; +} + +static inline int dirname_v2(const char* path, char* dir) +{ + const char* tail = strrchr(path, '/'); + + if(tail) + { + memcpy(dir, path, tail - path); + dir[tail - path] = 0; + } + else + { + strcpy(dir, "./"); + } + + return 0; +} +#endif + +const char* LogLeveToString(LOG_LEVEL lv); + +const char* format_hex_buf(const char* prefix_str, int prefix_type, + int rowsize, int groupsize, + const void* buf, int len, int ascii); +#ifndef __KERNEL__ +void print_hex_dump_bytes(const char* prefix_str, int prefix_type, + const void* buf, int len); +#endif + +int HttpPostLogFile(char* pSession); +//void UploadLogFile(char* pFilePath); +int SysPointMarkUpload(void); +int SysPointMark(char* pMarkInfo); +int SysPointMarkInit(char* pDevId, int iMaxSize, int iPostTime); +#ifdef __cplusplus +} +#endif +#endif //LOG_H_ + diff --git a/include/log_info.h b/include/log_info.h new file mode 100644 index 0000000..cd24c61 --- /dev/null +++ b/include/log_info.h @@ -0,0 +1,13 @@ +#ifndef LOG_INFO_H +#define LOG_INFO_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/monitor.h b/include/monitor.h new file mode 100644 index 0000000..e5f8513 --- /dev/null +++ b/include/monitor.h @@ -0,0 +1,21 @@ +#ifndef _MONITOR_H +#define _MONITOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ENABLE_COUNT_DEBUG +int MonAddNewItem(const char* pName, int logSaveTime); +int MonIncreaseCount(const char* pName); +int MonUpgradeStatistical(const char* pName, long newVal); +int MonDiffStatistical(const char* pName, long long newVal); +int MonItemLogout(const char* pName); +int MonitorInit(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ota.h b/include/ota.h new file mode 100644 index 0000000..7d4be75 --- /dev/null +++ b/include/ota.h @@ -0,0 +1,156 @@ +#ifndef OTA_H +#define OTA_H +#ifdef __cplusplus +extern "C" { +#endif + +#define SIZE_1K (1024) ///< 1K 字节大小 +#define MD5_CHKSUM_LEN (16) ///< MD5校验和长度 +#define MD5_CHKSUM_STR_LEN (MD5_CHKSUM_LEN * 2 + 1) ///< MD5校验和字符串格式长度 +#define NO_OTA_STATUS_VAL_TAG (0) ///< 状态默认值 + + +/** + * 系统启动模式定义 + */ +typedef enum +{ + NORMAL_SETUP = 0x1234, ///< 普通启动模式 + RECOVERY_SETUP, ///< 恢复模式 + SYSTEM_OTA, ///< OTA升级模式 + SYSTEM_OTA_OK, +} SETUP_MODE; + +/** + * OTA状态命令定义 + */ +typedef enum +{ + OTA_CURRENT_VERSION = 0, ///< 当前系统版本号 + OTA_CURRENT_SETUP_MODE, ///< 当前系统启动模式 + OTA_CURRENT_REBOOT_TIME, ///< 当前系统未正常启动次数 + OTA_DOWNLOAD_FILE, ///< OTA升级包下载状态 + OTA_DOWNLOAD_PROGRESS, ///< OTA升级包下载进度 + OTA_VERIFY_FILE, ///< 文件校验结果 + OTA_VERIFY_PARTITION, ///< OTA分区校验结果 + OTA_DECOMPRESS_FILE, ///< OTA当前进度:解压文件 + OTA_UPGRADE_READY, ///< OTA更新准备完成 + OTA_UPGRADE_START, ///< OTA更新开始 + OTA_UPGRADE_PARTITION, ///< OTA写入分区数据 + OTA_RECOVERY_START, ///< OTA恢复模式启动 + OTA_REREQ_OTA_NOW, ///< OTA请求立即执行OTA更新系统 + OTA_REBOOT_SYSTEM, ///< OTA准备重启系统 + OTA_SUCCESED, ///< OTA执行成功 + OTA_UNKNOWN_CMD, ///< 位置OTA状态命令 + OTA_ERR_CODE, ///< OTA过程异常 + OTA_DISK_FULL, ///< 存储空间不足 +} OTA_STATUS_TYPE; + + +/** + * OTA模式 + */ +typedef enum +{ + OTA_MODE_NORMAL = 9029, ///< 普通OTA更新模式 + OTA_MODE_FORCE_NOW, ///< 强制OTA更新模式 + OTA_MODE_RECOVERY, ///< OTA恢复模式 +} OTA_MODE; + + +/** + * OTA操作命令 + */ +typedef enum +{ + OTA_CMD_DOWNLOAD = 1234, ///< 下载OTA升级包 + OTA_CMD_USED_LOCAL_IMAGE, ///< 从上次备份的OTA升级包升级 + OTA_CMD_EXEC, ///< 开始OTA更新系统 +} OTA_CMD; + + + +/** + * OTA级包信息 + * + */ +typedef struct +{ + char url[SIZE_1K]; ///< URL, Base64编码 + char md5[MD5_CHKSUM_STR_LEN]; ///< OTA升级包MD5校验和 + unsigned int size; ///< OTA升级包文件大小 +} OTA_FILE_INFO, *POTA_FILE_INFO; + +/** + * 控制中心控制命令协议 + * + * @see OTA_CMD + * @see OTA_MODE + * @see OTA_FILE_INFO + */ +typedef struct +{ + int version; ///< OTA版本号 + OTA_CMD otaCmd; ///< OTA命令 + OTA_MODE otaMode; ///< OTA模式 + OTA_FILE_INFO otaFileInfo; ///< OTA升级包信息 +} OTA_DATA_INFO, *POTA_DATA_INFO; + +/** + * OTA状态信息协议 + * + * @see OTA_STATUS_TYPE + */ +typedef struct +{ + OTA_STATUS_TYPE status; ///< 状态命令 + int val; ///< 状态值 +} OTA_RSP_STATUS, *POTA_RSP_STATUS; + +static inline const char* otaStatusName(OTA_STATUS_TYPE type) +{ + switch(type) + { + case OTA_CURRENT_VERSION: + return ("OTA_CURRENT_VERSION"); + case OTA_CURRENT_SETUP_MODE: + return ("OTA_CURRENT_SETUP_MODE"); + case OTA_CURRENT_REBOOT_TIME: + return ("OTA_CURRENT_REBOOT_TIME"); + case OTA_DOWNLOAD_FILE: + return ("OTA_DOWNLOAD_FILE"); + case OTA_DOWNLOAD_PROGRESS: + return ("OTA_DOWNLOAD_PROGRESS"); + case OTA_VERIFY_FILE: + return ("OTA_VERIFY_FILE"); + case OTA_VERIFY_PARTITION: + return ("OTA_VERIFY_PARTITION"); + case OTA_DECOMPRESS_FILE: + return ("OTA_DECOMPRESS_FILE"); + case OTA_UPGRADE_READY: + return ("OTA_UPGRADE_READY"); + case OTA_UPGRADE_START: + return ("OTA_UPGRADE_START"); + case OTA_UPGRADE_PARTITION: + return ("OTA_UPGRADE_PARTITION"); + case OTA_RECOVERY_START: + return ("OTA_RECOVERY_START"); + case OTA_REREQ_OTA_NOW: + return ("OTA_REREQ_OTA_NOW"); + case OTA_REBOOT_SYSTEM: + return ("OTA_REBOOT_SYSTEM"); + case OTA_SUCCESED: + return ("OTA_SUCCESED"); + case OTA_UNKNOWN_CMD: + return ("OTA_UNKNOWN_CMD"); + case OTA_ERR_CODE: + return ("OTA_ERR_CODE"); + default: + return ("Unknown Type"); + } +} +#ifdef __cplusplus +} +#endif +#endif + diff --git a/include/server_addr.h b/include/server_addr.h new file mode 100644 index 0000000..1a11667 --- /dev/null +++ b/include/server_addr.h @@ -0,0 +1,48 @@ +#ifndef SERVER_ADDR_H +#define SERVER_ADDR_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + YUNXIN_MODULE = 0, + VOICE_MODULE = 1, + VOICE_AI_MODULE = 2, + SERVER_MODULE = 3, + LOG_MODULE = 4, + MARK_POINT_MODULE = 5, + TTS_MODULE = 6, + DC_MODULE = 7, + MAX_MODULE +} SERVER_MODULE_TYPE; + +typedef enum +{ + DEV_MODE = 0, + TEST_MODE = 1, + PUBLISH_MODE = 2, + MAX_MODE +} SERVER_MODE_TYPE; + +typedef enum +{ + VOICE_APP_KEY = 0, + VOICE_APP_SECRET = 1, + VOICE_MAX +} VOICE_KEYMAP_TYPE; + +const char* SvrModeStr(SERVER_MODE_TYPE mode); +const char* SvrModuleStr(SERVER_MODULE_TYPE module); +void DumpCurServerAddr(const char* pTags); + +void ServerManagerInit(void); +SERVER_MODE_TYPE GetCurrentServerMode(void); +void SetCurrentServerMode(SERVER_MODE_TYPE mode); + +char* GetCurServerAddr(SERVER_MODULE_TYPE module); +char* GetCurVoiceKeyValue(VOICE_KEYMAP_TYPE keyMap); +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/skins.h b/include/skins.h new file mode 100644 index 0000000..1403813 --- /dev/null +++ b/include/skins.h @@ -0,0 +1,58 @@ +#ifndef SKINS_H +#define SKINS_H +#ifdef __cplusplus +extern "C" { +#endif + +#define MD5_STR_LEN (36) ///< +#define MAX_KEY_NAME (64) +#define MAX_KEY_PATH (256) + +#define SKIN_MODE_NAME ("ModuleSkin") +#define RES_MODE_NAME ("ModuleRes") +#define RES_TBL_NAME "res" +#define SKIN_TBL_NAME "skin" +#define SKIN_USER_DB "user_db" + +#define CREATE_SKIN_TBL_SQL "CREATE TABLE IF NOT EXISTS %s"SKIN_TBL_NAME" (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "keyName TEXT NOT NULL," \ + "resType INTEGER NOT NULL," \ + "priority INTEGER NOT NULL," \ + "resID INTEGER NOT NULL," \ + "resReadme TEXT NOT NULL DEFAULT \'\');" + +#define CREATE_RES_TBL_SQL "CREATE TABLE IF NOT EXISTS %s"RES_TBL_NAME" (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "resVersion TEXT NOT NULL," \ + "localPath TEXT NOT NULL," \ + "serverURL TEXT NOT NULL," \ + "md5Chksum TEXT NOT NULL);" + +typedef enum +{ + VOICE_RES = 1, + IMAGE_RES, + TEXT_RES, +} SKINS_RES_TYPE; + +typedef struct +{ + SKINS_RES_TYPE resType; + const char *pResVer; + const char *pKeyName; + const char *pLocalPath; + const char *pMD5Chksum; +} SKIN_RES_INFO, *PSKIN_RES_INFO; + +int SkinInit(void); +char* GetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom); +int SkinUpgrade(char *pUpdFilePath); +void SkinIsVerifyRes(int isVerify); +unsigned int SkinsDefaultSize(void); +PSKIN_RES_INFO SkinsItemById(int iId); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/skins_res.h b/include/skins_res.h new file mode 100644 index 0000000..8e3fb8f --- /dev/null +++ b/include/skins_res.h @@ -0,0 +1,294 @@ +#ifndef SKINS_RES_H +#define SKINS_RES_H + +#include "skins.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PLATFORM_CPU +#define SKINS_DB_PATH ("./skins.db") +#define DEF_SKINS_ROOT_PATH "/home/hx/MyProjects/release/drivers/skins/" +#else +#define SKINS_DB_PATH ("/mnt/UDISK/skins.db") +#define DEF_SKINS_ROOT_PATH "/usr/share/resource/" +#endif + +#define EMU_HTTP_URL_ROOT "http://10.240.84.163/resource/" + +#if 0 +#define TEXT_WIFIPARING_APPARINGANDCONNECTING ("接收到WIFI配置参数,开始连接,可能时间比较长,请耐心等待") +#define TEXT_BT_WIFIPARING ("进入蓝牙网络配对模式") +#define TEXT_AP_WIFIPARING ("进入AP网络配对模式") +#define TEXT_WIFICONNECTED ("联网成功") +#define TEXT_SYSTEMBOOT ("很高兴遇见你,我是如意") +#define TEXT_NOTRECVINGWIFICONFIG ("没有收到网络配置信息") +#define TEXT_BLE_SUUCCESS_WAIT_CONFIG ("低功耗蓝牙已连接,等待配网") +#define TEXT_AP_WAIT_CONFIG ("当前在AP配网模式,等待配网") +#define TEXT_WIFINOTCONNECT ("网络未连接") +#define TEXT_REQSERVER_ERROR ("服务器请求失败,请重新配网") +#define TEXT_BLE_CONNECT ("ble已连接") +#define TEXT_BLE_DISCONNECT ("ble已断开") +#define TEXT_WIFIPARINGSUCCESS ("网络配对成功") +#define TEXT_BT_ON ("开启传统蓝牙") +#define TEXT_BT_OFF ("关闭传统蓝牙") +#define TEXT_ALARM_REMOVE_ALL ("删除全部闹钟成功") +#define TEXT_ALARM_REMOVE ("删除闹钟成功") +#define TEXT_ALARM_ADD ("闹钟设置成功") +#define TEXT_AP_APP_CONNECTED ("APP已通过wifi连接音箱") +#define TEXT_WIFICONNECT_ERR_REPARING ("wifi联网失败,请重新配网") +#define TEXT_WIFICONNECT_ERR_PASS ("ssid或密码错误,请重新配网") +#define TEXT_WIFIPARING_ERR_SERVERCONNECT ("服务器连接失败,请重新配网") +#define TEXT_NOT_UNSUPPORT ("不支持当前操作") +#define TEXT_BOOT_DONE ("你好,欢迎使用如意音箱") +#define TEXT_WIFIPARING_FIRST_NOTICE ("请使用网易云音乐APP ,进入账号页面 为音箱配网,请下载如意音响APP,为音箱配网") +#endif + +const SKIN_RES_INFO g_SkinDefaultResTable[] = { + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// voice resources + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef RES_FACTORY_MODE + {VOICE_RES, "0", "v102", DEF_SKINS_ROOT_PATH"voice/Alianwang002.mp3", "2ecc61d16a3ee0f02c4e580f00396d1f"}, +#endif + {VOICE_RES, "0", "v103", DEF_SKINS_ROOT_PATH"voice/Alianwang003.mp3", "33c00781480680a9ea5ef6be1f7ac258"}, + {VOICE_RES, "0", "v104", DEF_SKINS_ROOT_PATH"voice/Alianwang004.mp3", "d8ee9527dd6635f7251b455fcf177723"}, + {VOICE_RES, "0", "v105", DEF_SKINS_ROOT_PATH"voice/Alianwang005.mp3", "87849f3c844a42d765e85631ccfca2eb"}, + {VOICE_RES, "0", "v106", DEF_SKINS_ROOT_PATH"voice/Alianwang006.mp3", "46a63182f73e242fff7f202fc621ef17"}, + {VOICE_RES, "0", "v107", DEF_SKINS_ROOT_PATH"voice/Alianwang007.mp3", "fc02f25d84abfe066fd4ae8c140fe5f7"}, + {VOICE_RES, "0", "v108", DEF_SKINS_ROOT_PATH"voice/Alianwang008.mp3", "da772f7fcec24ebcd85bc3d9fe323f88"}, + {VOICE_RES, "0", "v109", DEF_SKINS_ROOT_PATH"voice/Alianwang009.mp3", "22b8163a5956bb877db55d38f1223cb2"}, + {VOICE_RES, "0", "v110", DEF_SKINS_ROOT_PATH"voice/Alianwang010.mp3", "5d83539bcb59558dd53352b898512227"}, + {VOICE_RES, "0", "v111", DEF_SKINS_ROOT_PATH"voice/Alianwang011.mp3", "58de437b7778885481678cc48bc4b592"}, + {VOICE_RES, "0", "v112", DEF_SKINS_ROOT_PATH"voice/Alianwang012.mp3", "0e1d0afc6663a73c5aa5d9de0072b8df"}, + {VOICE_RES, "0", "v113", DEF_SKINS_ROOT_PATH"voice/Alianwang013.mp3", "f495927bf6b5c67991685e751f2fca40"}, + {VOICE_RES, "0", "v114", DEF_SKINS_ROOT_PATH"voice/Alianwang014.mp3", "06b0f3de13c21c60ab73253ee16f36b3"}, + {VOICE_RES, "0", "v202", DEF_SKINS_ROOT_PATH"voice/Ashiyong002.mp3", "e825e5c5b6989afb88d4084ffe1eff01"}, + {VOICE_RES, "0", "v203", DEF_SKINS_ROOT_PATH"voice/Ashiyong003.mp3", "d7245a20b4a3597894e6af8a83770044"}, + {VOICE_RES, "0", "v204", DEF_SKINS_ROOT_PATH"voice/Ashiyong004.mp3", "d546fe1b69f8ba62c14acd299ae5bc7e"}, + {VOICE_RES, "0", "v205", DEF_SKINS_ROOT_PATH"voice/Ashiyong005.mp3", "79df29d63ac4ea40546f0274b7dd3c84"}, + {VOICE_RES, "0", "v206", DEF_SKINS_ROOT_PATH"voice/Ashiyong006.mp3", "7f47f1796e125078778556d62bd573e2"}, + {VOICE_RES, "0", "v301", DEF_SKINS_ROOT_PATH"voice/S001.mp3", "eee1506b7ed801e5aa6a6ccc18c0c1f1"}, + {VOICE_RES, "0", "v302", DEF_SKINS_ROOT_PATH"voice/S002.mp3", "c90dbc04cda7bdb778a9cb196eb208a2"}, + {VOICE_RES, "0", "v303", DEF_SKINS_ROOT_PATH"voice/S003.mp3", "89340aa9f735d082d9404bae014d7bae"}, + {VOICE_RES, "0", "v304", DEF_SKINS_ROOT_PATH"voice/S004-1.mp3", "2a03648026864291cf0aad7bf6569734"}, + {VOICE_RES, "0", "v3041", DEF_SKINS_ROOT_PATH"voice/S004-2.mp3", "33cafc99de51b53afc97156866e82473"}, + {VOICE_RES, "0", "v3042", DEF_SKINS_ROOT_PATH"voice/S004-3.mp3", "0a1057342a661597730b521427d6097c"}, + {VOICE_RES, "0", "v3043", DEF_SKINS_ROOT_PATH"voice/S004-4.mp3", "c8061b90c50558c155ddc9ffef114e61"}, + {VOICE_RES, "0", "v3044", DEF_SKINS_ROOT_PATH"voice/S004-5.mp3", "97f94d1350bc09c9e974525172ad8fc0"}, + {VOICE_RES, "0", "v305", DEF_SKINS_ROOT_PATH"voice/S005.mp3", "2e7a489501b76c73e5aa4be4f7e7aa5f"}, + {VOICE_RES, "0", "v306", DEF_SKINS_ROOT_PATH"voice/S006.mp3", "437ddb3e99f77696d60c2f28c1b268cb"}, + {VOICE_RES, "0", "v307", DEF_SKINS_ROOT_PATH"voice/S007.mp3", "a6c6be6f702b5b47ddebad61d28eb1ad"}, + {VOICE_RES, "0", "v308", DEF_SKINS_ROOT_PATH"voice/S008.mp3", "5918f635de28b45f2d32e3eb4b05b9ad"}, + {VOICE_RES, "0", "v309", DEF_SKINS_ROOT_PATH"voice/S009.mp3", "f9039012752b3ed2a00f173aa305acf1"}, + {VOICE_RES, "0", "v310", DEF_SKINS_ROOT_PATH"voice/S010.mp3", "446ec757495bdf7aee31a41a9efe8bab"}, + {VOICE_RES, "0", "v311", DEF_SKINS_ROOT_PATH"voice/S011.mp3", "e9fa92d8929dcb2e134f42c1cedf4827"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/b-h-01.mp3", "68ecfbab58563071b6663a348a39a51b"}, + {VOICE_RES, "0", "v402", DEF_SKINS_ROOT_PATH"voice/b-h-50.mp3", "017b53f7610f6dd99e21b546e6b35605"}, + {VOICE_RES, "0", "v403", DEF_SKINS_ROOT_PATH"voice/b-h-51.mp3", "422b4550253780343b7a9805ca7b629a"}, + {VOICE_RES, "0", "v5011", DEF_SKINS_ROOT_PATH"voice/a-a-01.mp3", "5d9d186ef50b603ab84a9abbfd348630"}, + {VOICE_RES, "0", "v5012", DEF_SKINS_ROOT_PATH"voice/a-a-02.mp3", "837a2222c961824e98c0d3751a234ae6"}, + {VOICE_RES, "0", "v5013", DEF_SKINS_ROOT_PATH"voice/a-a-03.mp3", "0ec34a1f19ee7cea6b139d214e59026d"}, + {VOICE_RES, "0", "v502", DEF_SKINS_ROOT_PATH"voice/a-n-01.mp3", "b1eb13ed8c9afaa2989763c3d379b39a"}, + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// picture resources + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + {IMAGE_RES, "0", "p001", DEF_SKINS_ROOT_PATH"image/IconChaozuo001.jpg", "0d4aa6351cc71daf2c699e42c1b74cde"}, + {IMAGE_RES, "0", "p005", DEF_SKINS_ROOT_PATH"image/IconChaozuo005.jpg", "1ceca68b9e7d49c537376a08c07a2b88"}, + {IMAGE_RES, "0", "p101", DEF_SKINS_ROOT_PATH"image/IconLianjie001.jpg", "236dbc343bd1d0c5e651f33900a13c07"}, + {IMAGE_RES, "0", "p102", DEF_SKINS_ROOT_PATH"image/IconLianjie002.jpg", "c627364aec00131589fc942c902c65bc"}, + {IMAGE_RES, "0", "p103", DEF_SKINS_ROOT_PATH"image/IconLianjie003.jpg", "edb04af03cf7c7e4d29aee43c332235b"}, + {IMAGE_RES, "0", "p201", DEF_SKINS_ROOT_PATH"image/IconNaozhong001.jpg", "bd5e7a00b4902ca971684d6ee021fb06"}, + {IMAGE_RES, "0", "p302", DEF_SKINS_ROOT_PATH"image/Iconstart002.gif", "90f2b52b1399348debcec2f447dbd383"}, + {IMAGE_RES, "0", "p401", DEF_SKINS_ROOT_PATH"image/IconTixing001.jpg", "feff2fbedffc955b491e0349385ef6c3"}, + {IMAGE_RES, "0", "p500", DEF_SKINS_ROOT_PATH"image/Iconyinliang000.jpg", "a0c29ad20d51cf86e808c83ee90b6510"}, + {IMAGE_RES, "0", "p501", DEF_SKINS_ROOT_PATH"image/Iconyinliang001.jpg", "196ba4082358d3238d0dcb0035764465"}, + {IMAGE_RES, "0", "p502", DEF_SKINS_ROOT_PATH"image/Iconyinliang002.jpg", "196ba4082358d3238d0dcb0035764465"}, + {IMAGE_RES, "0", "p503", DEF_SKINS_ROOT_PATH"image/Iconyinliang003.jpg", "196ba4082358d3238d0dcb0035764465"}, + {IMAGE_RES, "0", "p504", DEF_SKINS_ROOT_PATH"image/Iconyinliang004.jpg", "d3157ec3c194e4cc6dbcbe683fd40d3f"}, + {IMAGE_RES, "0", "p505", DEF_SKINS_ROOT_PATH"image/Iconyinliang005.jpg", "3f857b11062aeddaa6061e7cabfde044"}, + {IMAGE_RES, "0", "p506", DEF_SKINS_ROOT_PATH"image/Iconyinliang006.jpg", "3f857b11062aeddaa6061e7cabfde044"}, + {IMAGE_RES, "0", "p507", DEF_SKINS_ROOT_PATH"image/Iconyinliang007.jpg", "64a461ee34bea341879aa5a08c717705"}, + {IMAGE_RES, "0", "p508", DEF_SKINS_ROOT_PATH"image/Iconyinliang008.jpg", "b932b0b1c7766c6a995ce3e63b2b7422"}, + {IMAGE_RES, "0", "p509", DEF_SKINS_ROOT_PATH"image/Iconyinliang009.jpg", "dce1278710e1831f02d8dd4fd5d0aac6"}, + {IMAGE_RES, "0", "p510", DEF_SKINS_ROOT_PATH"image/Iconyinliang010.jpg", "b9ac1d7469b34d2aabe04d849c4f1112"}, + {IMAGE_RES, "0", "p511", DEF_SKINS_ROOT_PATH"image/Iconyinliang011.jpg", "45e001edc7d973b15434334ad7f77771"}, + {IMAGE_RES, "0", "p512", DEF_SKINS_ROOT_PATH"image/Iconyinliang012.jpg", "c9c22063c381e5cb775c82b105dce0f1"}, + {IMAGE_RES, "0", "p513", DEF_SKINS_ROOT_PATH"image/Iconyinliang013.jpg", "6e06e51e83498185d148070c0643852c"}, + {IMAGE_RES, "0", "p514", DEF_SKINS_ROOT_PATH"image/Iconyinliang014.jpg", "6e06e51e83498185d148070c0643852c"}, + {IMAGE_RES, "0", "p515", DEF_SKINS_ROOT_PATH"image/Iconyinliang015.jpg", "694a1698c16539805ed4ee238f36586c"}, + {IMAGE_RES, "0", "p516", DEF_SKINS_ROOT_PATH"image/Iconyinliang016.jpg", "0e7e847191e429618c6684ae89d30ac6"}, + {IMAGE_RES, "0", "p517", DEF_SKINS_ROOT_PATH"image/Iconyinliang017.jpg", "a18f5107ada535d664b2483b02080e70"}, + {IMAGE_RES, "0", "p518", DEF_SKINS_ROOT_PATH"image/Iconyinliang018.jpg", "d64992577a379c0faed0078dde767fcc"}, + {IMAGE_RES, "0", "p519", DEF_SKINS_ROOT_PATH"image/Iconyinliang019.jpg", "58268a96482df75c97a177371d295bd3"}, + {IMAGE_RES, "0", "p520", DEF_SKINS_ROOT_PATH"image/Iconyinliang020.jpg", "81ffbdc7857790696e3a7e353bd86908"}, + {IMAGE_RES, "0", "p601", DEF_SKINS_ROOT_PATH"image/Iconlianwang001.gif", "9e18565313b6b1769b7c5979a248dbd6"}, + {IMAGE_RES, "0", "p605", DEF_SKINS_ROOT_PATH"image/Iconlianwang005.gif", "ee81f49fe49864d4cbc4f7f9a1ec52c0"}, + {IMAGE_RES, "0", "p703", DEF_SKINS_ROOT_PATH"image/IconZhuangtai003.gif","e2bdf79f8c2825c23ffbb0233328df97"}, + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// tts resources + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if 0 + {{TEXT_RES, 0, "wifiparing_apparingandconnecting", ""}, "", TEXT_WIFIPARING_APPARINGANDCONNECTING, ""}, + {{TEXT_RES, 0, "bt_wifiparing", ""}, "", TEXT_BT_WIFIPARING, ""}, + {{TEXT_RES, 0, "ap_wifiparing", ""}, "", TEXT_AP_WIFIPARING, ""}, + {{TEXT_RES, 0, "wificonnected", ""}, "", TEXT_WIFICONNECTED, ""}, + {{TEXT_RES, 0, "systemboot", ""}, "", TEXT_SYSTEMBOOT, ""}, + {{TEXT_RES, 0, "notrecvingwificonfig", ""}, "", TEXT_NOTRECVINGWIFICONFIG, ""}, + {{TEXT_RES, 0, "ble_suuccess_wait_config", ""}, "", TEXT_BLE_SUUCCESS_WAIT_CONFIG, ""}, + {{TEXT_RES, 0, "ap_wait_config", ""}, "", TEXT_AP_WAIT_CONFIG, ""}, + {{TEXT_RES, 0, "wifinotconnect", ""}, "", TEXT_WIFINOTCONNECT, ""}, + {{TEXT_RES, 0, "reqserver_error", ""}, "", TEXT_REQSERVER_ERROR, ""}, + {{TEXT_RES, 0, "ble_connect", ""}, "", TEXT_BLE_CONNECT, ""}, + {{TEXT_RES, 0, "ble_disconnect", ""}, "", TEXT_BLE_DISCONNECT, ""}, + {{TEXT_RES, 0, "wifiparingsuccess", ""}, "", TEXT_WIFIPARINGSUCCESS, ""}, + {{TEXT_RES, 0, "bt_on", ""}, "", TEXT_BT_ON, ""}, + {{TEXT_RES, 0, "bt_off", ""}, "", TEXT_BT_OFF, ""}, + {{TEXT_RES, 0, "alarm_remove_all", ""}, "", TEXT_ALARM_REMOVE_ALL, ""}, + {{TEXT_RES, 0, "alarm_remove", ""}, "", TEXT_ALARM_REMOVE, ""}, + {{TEXT_RES, 0, "alarm_add", ""}, "", TEXT_ALARM_ADD, ""}, + {{TEXT_RES, 0, "ap_app_connected", ""}, "", TEXT_AP_APP_CONNECTED, ""}, + {{TEXT_RES, 0, "wificonnect_err_reparing", ""}, "", TEXT_WIFICONNECT_ERR_REPARING, ""}, + {{TEXT_RES, 0, "wificonnect_err_pass", ""}, "", TEXT_WIFICONNECT_ERR_PASS, ""}, + {{TEXT_RES, 0, "wifiparing_err_serverconnect", ""}, "", TEXT_WIFIPARING_ERR_SERVERCONNECT, ""}, + {{TEXT_RES, 0, "not_unsupport", ""}, "", TEXT_NOT_UNSUPPORT, ""}, + {{TEXT_RES, 0, "boot_done", ""}, "", TEXT_BOOT_DONE, ""}, + {{TEXT_RES, 0, "wifiparing_first_notice", ""}, "", TEXT_WIFIPARING_FIRST_NOTICE, ""}, +#endif +}; + +static const SKIN_RES_INFO g_emuUpgradeInfo[] = { + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"android.txt", "8dc557037b69c69efd5615cdfc06934a"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"applying-patches.txt", "8d65812b01d64c9df1529509083e189d"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"atomic_ops.txt", "0d6a66d951ed4747aeee1aa7ab99d8d3"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"bad_memory.txt", "e81b536c2095eb53f9209e26b914f426"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"basic_profiling.txt", "1c70596bd41eb49077af5e91e16d2967"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"binfmt_misc.txt", "8936b928d685bdf98f83f1b3e86562a4"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"braille-console.txt", "4263bbce1595bdb3923bcb7885f866f5"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"bt8xxgpio.txt", "3a61d033e71cff3c75c778dad89ac565"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"btmrvl.txt", "f5ce90fb4a0ef97d23914fef37fba39d"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"bus-virt-phys-mapping.txt", "23fedac31d1b6ee5dae644ed86cc2c37"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"cachetlb.txt", "5db6b816869d89822759bca684024430"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"circular-buffers.txt", "3be2b7f00c13b160d5dba390b2ee8a54"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"clk.txt", "e60704c45037f922a73f49fc827b5225"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"coccinelle.txt", "379a83726bbf8f2ffbb12ba454788909"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"cpu-hotplug.txt", "e3676063c62c556a94ebf3b9296db82f"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"cpu-load.txt", "d9d096434110f5c017ab27ea397cee1d"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"cputopology.txt", "4ead2141d532dfaf1057cd2964ced3f4"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"crc32.txt", "644ff3d58c8ab6ca0c5c721dc78e7343"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"dcdbas.txt", "ad88b9a2d9b547a81ec3f28006a897bc"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"debugging-modules.txt", "c3b0d7040e83f85b5593dac628b3ffa5"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"debugging-via-ohci1394.txt", "a58d95e96be1ca24c5946c6636c4e041"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"dell_rbu.txt", "d5324f7ddcfbf19eb00e4c81bbb5cb7f"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"devices.txt", "8aa73c9268a9012eecbbb78fc4e4cc68"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"digsig.txt", "44b680ee0b743d63f9d0d2849e39d982"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"DMA-API-HOWTO.txt", "3225970a70a6a79c5112ff29b8f99ec6"}, + {VOICE_RES, "1", "v310", EMU_HTTP_URL_ROOT"DMA-API.txt", "3110d6930bd1c4c692c741f960310810"}, + {VOICE_RES, "1", "v310", EMU_HTTP_URL_ROOT"DMA-attributes.txt", "1ccc7f613bde5312a6a7452e8381d518"}, + {VOICE_RES, "1", "v311", EMU_HTTP_URL_ROOT"dma-buf-sharing.txt", "303f87732efc9effee0d6ed16e89ee37"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"dmaengine.txt", "80881dc6b0c7c9761be617a8f2e5eee3"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"DMA-ISA-LPC.txt", "a0b20e82cadca3595c95a9b7909a2120"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"dynamic-debug-howto.txt", "d15ef07d9fae98de0e096897da1e06ab"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"edac.txt", "a83b6d68f9e4c2d03ac619f912c13eb9"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"eisa.txt", "cae33ca2a108401d9465a0589503b845"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"email-clients.txt", "a1e6b9470ea752cf97a99ebcb9594aa0"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"feature-removal-schedule.txt", "e45405d2fac3a3bf87b26b3faeaad5de"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"flexible-arrays.txt", "03bfe3a8cb65aecdc96f710a140b8c27"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"futex-requeue-pi.txt", "684984d4f7026c76533ad7f247136ef4"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"gcov.txt", "fb711ca5323092e285f2e0b59a574009"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"gpio.txt", "13417a2589abd22672e8c109e5c57e8e"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"highuid.txt", "1c3e14d700b302d76b1bca29325a4a8e"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"hw_random.txt", "6c78af2ee2fab6ae30aca725c3970da1"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"hwspinlock.txt", "2ac1e75e3ee30099527e344287340b0a"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"initrd.txt", "c889974503df36fc073c891e6d9b8b0a"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"init.txt", "bdbcc42bf6ae739157092a7fa64aaaac"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"Intel-IOMMU.txt", "e693ef88d3d7d42c7a65a23f3975aa97"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"intel_txt.txt", "9dd22fd4de8b9e718fefc96c15b994c8"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"io-mapping.txt", "a7785b478117c65839749521fc020dc3"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"io_ordering.txt", "f7a404c9794d133f9167ff1a7e2953bb"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"iostats.txt", "4248f808a42956c73b79032686ae77bb"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"IPMI.txt", "8b8bc6bf4528e8d82017113c17d58a37"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"IRQ-affinity.txt", "d89c8d406a2618cc19db636ba81ce4ca"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"IRQ-domain.txt", "ec9bde5aa997211d7ded9658cfde4fff"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"irqflags-tracing.txt", "b8ca946951177d2cb8099feb9c4587e2"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"IRQ.txt", "0ef9f8f98b9eac9336c0ffb95cfc1d65"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"isapnp.txt", "ab111f0d42d1e748d9745c09e7ff935b"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"java.txt", "fbe28a3d11651fd214ad1d897700fd4f"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kernel-doc-nano-HOWTO.txt", "28579d296e40e460678d0587991e9d48"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kernel-docs.txt", "afc6fd5cdcc8b49ba794bcf5382ff2c3"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kernel-parameters.txt", "2dc9abd6790fd24c3e841f15d0d24a38"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kmemcheck.txt", "b301c758aed537468e98183bd04dc15d"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kmemleak.txt", "b5108533723c0a616e8723e009244d55"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kobject.txt", "d47cf170cd9ce2aaca082fa322b3c271"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kprobes.txt", "7a4c60ba6c646746ca64a311b24a7919"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kref.txt", "e6ee109e7185aafc4efe67cad2576352"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"ldm.txt", "3492835c4e3f2340ef0a0d5af464b962"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"local_ops.txt", "809dba9261b3704813557cccaeb3d83d"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"lockdep-design.txt", "b5379d04c39758d7f979d8c6c459285b"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"lockstat.txt", "c672433097ed3823b84bea98cafbb921"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"lockup-watchdogs.txt", "36c72be9bf511bd0e76975f7987f97a2"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"logo.txt", "c12e6a02a126220ed420586143f96d7e"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"magic-number.txt", "2baed34f647a4dab43357718050ded53"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"mca.txt", "1ea3eab396d5433f30952ad1b30ab133"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"md.txt", "6cdd602644e47836f0cb357e910a4db7"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"media-framework.txt", "1f3f9ba9afc6c1323df2c03160b4db4d"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"memory-barriers.txt", "1b2369bd78d18c2f80c23ca3ab2fb8d8"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"memory-hotplug.txt", "e9bc23bc43814ef7fbe2bcd89692c55b"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"memory.txt", "c17ccb89201a46532f3b95fee4adc372"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"mono.txt", "da6d7823007522089fc4bfefc1752b16"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"mutex-design.txt", "278a8bef9b14c136939715738cc0f0e8"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"nommu-mmap.txt", "9f4e01823e63aec8b42bf523389664fc"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"numastat.txt", "bebd74fc4713e1500702be1a90113f74"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"oops-tracing.txt", "87f1184ede24989279c9a1dfa1ccfae1"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"padata.txt", "bd3486df46e488dd75d1e67b2bb52da9"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"parport-lowlevel.txt", "a7d58201239229037269d4fd7ba720ac"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"parport.txt", "fa8d7291a3e7d5c2afe5a2060a0abb50"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"pi-futex.txt", "492ac92f69716bfaa0c40a909c992ade"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"pinctrl.txt", "9b7c710bba0b9aaae7e4f3794a548511"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"pnp.txt", "a7338b790fd6b30b4071fcacbfcedc4e"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"preempt-locking.txt", "5b7ed3fd44bb218e897492667b316a56"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"printk-formats.txt", "8eaefbea3500e15cc155045b3d3ef39c"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"prio_tree.txt", "1b079f5eac72227ecee86a7693ae8f69"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"ramoops.txt", "b50016891d7184720439346f362083e3"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"rbtree.txt", "a35e53c01ecfe9fbc534425504b8f408"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"remoteproc.txt", "d9599a6eda47e17ade41491b1106db22"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"rfkill.txt", "d86dc1dc7f27a25692b40cb739a88a09"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"robust-futex-ABI.txt", "32be0a8a71053b3258c8dc13c8e3f981"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"robust-futexes.txt", "1ac8f369bc00680aa40e8dfd3bc766c3"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rpmsg.txt", "67b8fcf7e064b15d910e6ef41b944984"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rtc.txt", "51577c35a6c713e85bc4325dde78f1f9"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rt-mutex-design.txt", "25703f95e001b8ab0a92ec7e22f85527"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rt-mutex.txt", "b449bdf78dad3a5ff62eb7a0853c0c99"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"SAK.txt", "bb81ce113927582c1513704f360129fd"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"serial-console.txt", "814e90de90e893f56eb12cc536dc7d42"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"sgi-ioc4.txt", "f4e0584fa5b55907435c3374c6ae6601"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"sgi-visws.txt", "0bb26ebbfc96a898f54126d5762cd3de"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"SM501.txt", "58ce960675582f8414019f33a27e1260"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"sparse.txt", "8bc3d0ada8ca01475d69431cd9cd4ec0"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"spinlocks.txt", "d903caeac016182fd7bb349af658bb1a"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"stable_api_nonsense.txt", "ca2acd6fd94048b5b03b213922d962b5"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"stable_kernel_rules.txt", "3948439142160832a55510a93746b738"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"static-keys.txt", "6d801dd48021a20394a7eaa82f0b758d"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"svga.txt", "ffc4306708801c3489dc575998ecca43"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"sync.txt", "381c9f8905dfc34f66eef3e3e486f0d1"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"sysfs-rules.txt", "84cfa60b3ba436be5acd54034bc15c84"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"sysrq.txt", "f24e71d4fed0257178078b820927791b"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"unaligned-memory-access.txt", "a5a387aeec918a0f528f85bcb76bc8c5"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"unicode.txt", "fd815b4b43d0cf5a85ca44d0db76dde7"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"unshare.txt", "a3ca54a1d655c512654510e56b4c8e53"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"vgaarbiter.txt", "802d04a400dfb5959711fe8088c62f01"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"VGA-softcursor.txt", "88c93a1b83277f3fc3fb07de148fd726"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"video-output.txt", "60ab68e5be73008948e8f1426db0941b"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"volatile-considered-harmful.txt", "8983aa37ffb5d56400e7f54ca9aa88d6"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"workqueue.txt", "6fadee709d10fbbdc4ed587020dbb9b7"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"xz.txt", "4c3cdd3cc9795936719f90c5998e444d"}, + {VOICE_RES, "1", "v904", EMU_HTTP_URL_ROOT"zorro.txt", "5afccd5699a870edbaeeb4842171e637"} +}; +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/smart_sound.h b/include/smart_sound.h new file mode 100644 index 0000000..5647275 --- /dev/null +++ b/include/smart_sound.h @@ -0,0 +1,507 @@ +#ifndef SMART_SOUND_H +#define SMART_SOUND_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CMD_BT_AVK_OPEN CMD_BT_BREDR_ENABLE +#define CMD_BT_AVK_CLOSE CMD_BT_BREDR_DISABLE + +//***************************************************************** +//* Global Configure +//***************************************************************** +#define USED_SHM_TO_DBUS (0) // used shm for dbus transfer data +#ifndef MAX_PATH +#define MAX_PATH (256) +#endif + +//************************************************************* + +typedef enum { + MODULE_CONTROLLER = 0, + MODULE_ALARM, + MODULE_CALL, + MODULE_VOICEENGINE, + MODULE_PLAYER, + MODULE_CONFIGURE, + MODULE_OTA, + MODULE_WIFI, + MODULE_BT, + MODULE_KPLAYER, + MODULE_KPLAYER_TEST, + MODULE_SPLAYER, + MODULE_SPLAYER_TEST, + MODULE_LIGHT_MCU, + MODULE_BLUEKC, + MODULE_BLUEKC_TEST, + MODULE_MANUFACTURE, + MODULE_BT_DEMO, + MODULE_SKINS, + MODULE_LOG_CTRL, + MODULE_WIRELESSTEST, + MODULE_WIRELESSTEST_DEMO, + MODULE_MANUFACTURE_CONTROLLER, + MODULE_WIFI_DEMO, + MODULE_MAX, +} MODULE_NAME; + +typedef enum { + CMD_MISC_PING = 0x0000, + CMD_MISC_OTA, + CMD_MISC_WEATHER, + CMD_MISC_NOWTIME, + CMD_MISC_UPGRADE, + CMD_SYSTEM_STANDBY, + CMD_MISC_QUERY_OTA_STATUS, + CMD_MISC_QUERY_DL_STATUS, + CMD_MISC_CHANGE2TEST, + CMD_MISC_CHANGE2ONLINE, + + CMD_SEARCH_PLAYER_REQ, + CMD_SEARCH_PLAYER_RESP, + + CMD_PROCESS_START, + + CMD_CALL_DIAL = 0x0300, + CMD_CALL_ACCEPI, + CMD_CALL_HANGUP, + CMD_CALL_MESSAGE, + + CMD_PLAY_MODECHANGE = 0x0600, + CMD_PLAY_PLAY, + CMD_PLAY_PAUSE, + CMD_PLAY_STOP, + CMD_PLAY_SEEKTO, + CMD_PLAY_SHOWMODE, + CMD_PLAY_NEXT, + CMD_PLAY_PRE, + CMD_PLAY_SEEKTO_PLAY, + CMD_PLAY_SHOWLIST, + CMD_PLAY_UPDATELIST, + CMD_PLAY_PREPARE_NEXT, + CMD_PLAY_ADDTOLIST, + CMD_PLAY_DELETEFROMLIST, + CMD_PLAY_RESETLIST, + CMD_PLAY_VOL_SET, + CMD_PLAY_VOL_RESTORE, + CMD_PLAY_MAX, + + CMD_PLAY_AUDIO_STOP = 0x0700, + CMD_PLAY_AUDIO_PLAY, + CMD_PLAY_AUDIO_MAX, + + CMD_SE_PLAY = 0x0780, + CMD_SE_PLAYER_STATE_NTF, + + CMD_MUSIC_PCM_PLAY = 0X0790, + CMD_MUSIC_PCM_PAUSE = 0X0791, + CMD_MUSIC_PCM_STOP = 0X0792, + CMD_MUSIC_PCM_MAX, + + CMD_PLAYER_MAX = 0X07FF, + + CMD_PLAY_RET_STATUS = 0x0800, + + CMD_CFG_ADD_REQ = 0x0900, + CMD_CFG_ADD_RSP, + CMD_CFG_CHANGE_REQ, + CMD_CFG_CHANGE_RSP, + CMD_CFG_GET_REQ, + CMD_CFG_GET_RSP, + CMD_CFG_UPG_NOTIFY, + + CMD_MSC_MSG_CONTROLLER_RECOG_SUCCESS = 0x0a00, + CMD_MSC_MSG_CONTROLLER_RECOG_ERROR, + CMD_MSC_MSG_CONTROLLER_WAKEUP, + CMD_MSC_MSG_CONTROLLER_SESSION_BEGIN, + CMD_MSC_MSG_CONTROLLER_RECOGING, + CMD_CC_MSC_BEGIN_SESSION, + CMD_CC_MSC_END_SESSION, + CMD_CONTROLLER_REQMSG_INITARGS, + CMD_CONTROLLER_RSPMSG_INITARGS, + CMD_CONTROLLER_REQMSG_PLAYERSTATUS, + CMD_CONTROLLER_RSPMSG_PLAYERSTATUS, + CMD_MSC_REQMSG_MIC_CONTROL, + CMD_MSC_RSPMSG_MIC_CONTROL, + CMD_NDUILITE_FESPA_SET_ARG, + CMD_YUNXIN_RECVMSG, + CMD_YUNXIN_SENDMSG, + CMD_YUNXIN_SENDMSG_BYPASS, + CMD_YUNXIN_SENDMSGCB, + CMD_CONTROLLER_MSG_YUNXIN, + CMD_YUNXIN_STATUS, + CMD_YUNXIN_SYSMSG, + + CMD_WIFI_CONF = 0x0b00, + CMD_WIFI_CONF_RESP, + CMD_WIFI_AUTO_CONN, + CMD_WIFI_AUTO_CONN_RESP, + CMD_WIFI_AUTO_CONN_OUT, + CMD_WIFI_STATE_REQ, + CMD_WIFI_STATE_RESP, + CMD_WIFI_STATE_NTF, + CMD_WIFI_CHANGE_VALID_AP, + CMD_WIFI_CHANGE_VALID_AP_OUT, + CMD_WIFI_CHANGE_VALID_AP_RESP, + + CMD_BT_NAME_GET_REQ, + CMD_BT_NAME_GET_RESP, + CMD_BT_EVT_NTF, + CMD_BT_CREATED, + + CMD_BT_RESET, + CMD_BT_BREDR_ENABLE, // 0xb10 + CMD_BT_BREDR_DISABLE, // 0xb11 + + CMD_BT_AVK_SOUND_OPEN, + CMD_BT_AVK_SOUND_CLOSE, + + CMD_BT_AVK_CON_EVT, + CMD_BT_AVK_DISC_EVT, + + CMD_BT_AVK_CON_DEV, + CMD_BT_AVK_DISC_DEV, + CMD_BT_AVK_PLAY, + CMD_BT_AVK_PAUSE, + CMD_BT_AVK_STOP, + CMD_BT_AVK_PRE, + CMD_BT_AVK_NEXT, + CMD_BT_AVK_VOL_UP, + CMD_BT_AVK_VOL_DOWN, + + CMD_BT_AVK_SOUND_START_EVT, // 0xb1f + CMD_BT_AVK_SOUND_STOP_EVT, // 0xb20 + + CMD_BT_LE_ENABLE, // 0xb21 + CMD_BT_LE_DISABLE, + CMD_BT_LE_NEVSPS_DISC, + + CMD_BT_AVK_CRTED, + CMD_BT_AVK_DELETED, + + CMD_BT_AVK_RC_PLAY, + CMD_BT_AVK_RC_PAUSE, + + CMD_WIFI_UNBIND_ACCOUNT, + CMD_BT_VOL_CHANGE, + + CMD_BT_BREDR_REBOOT_CLOSE, + + CMD_KPLAYER_START = 0x1b00, + CMD_KPLAYER_STOP, + CMD_KPLAYER_NOTIF_DUR, + CMD_KPLAYER_HOST_ACTION, + CMD_KPLAYER_CTR_NTF_BASE = 0x1c00, + CMD_KPLAYER_CTR_CREATED, + CMD_KPLAYER_CTR_DELED, + CMD_KPLAYER_CTR_PLAY, + CMD_KPLAYER_CTR_STOP, + CMD_KPLAYER_CTR_PAUSE, + CMD_KPLAYER_CTR_SEEK, + CMD_KPLAYER_CTR_SET_URL, + CMD_KPLAYER_CTR_SET_VOLUME, + CMD_KPLAYER_CTR_SET_MUTE, + CMD_KPLAYER_CTR_SET_NXT_URL, + CMD_KPLAYER_CTR_SET_NEXT, + CMD_KPLAYER_CTR_SET_PREV, + + CMD_SPLAYER_SFIFO_TEST = 0x1d00, + CMD_SPLAYER_START, + CMD_SPLAYER_STOP, + CMD_SPLAYER_HOST_ACTION, + + CMD_SPLAYER_CTR_NTF_BASE = 0x1e00, + CMD_SPLAYER_MSG_TYPE_CREATE, + CMD_SPLAYER_MSG_TYPE_DEL, + CMD_SPALYER_MSG_TYPE_START, + CMD_SPLAYER_MSG_TYPE_STOP, + CMD_SPLAYER_MSG_TYPE_SET_VOLUME, + CMD_SPLAYER_MSG_TYPE_STREAMING, + CMD_SPLAYER_MSG_TYPE_DESTRY, + CMD_SPLAYER_MSG_TYPE_DURATION, + CMD_SPLAYER_MSG_TYPE_STREAM_NTF, + CMD_SPLAYER_MSG_TYPE_STREAM_PLAYPAUSE, + + CMD_BLUEKC_POOL_TEST = 0x1f00, + CMD_BLUEKC_LOG_DEBUG, + CMD_BLUEKC_LOG_RESTORE, + + // 厂测 + CMD_TEST_GET_VER_REQ = 0X2000, + CMD_TEST_GET_VER_RESP, + CMD_TEST_GET_MCU_VER_REQ, + CMD_TEST_GET_MCU_VER_RESP, + CMD_TEST_KNOB_REQ, + CMD_TEST_KNOB_RESP, + CMD_TEST_BUTTON_REQ, + CMD_TEST_BUTTON_RESP, + CMD_TEST_GET_VOLUME_REQ, + CMD_TEST_GET_VOLUME_RESP, + CMD_TEST_SET_VOLUME_REQ, + CMD_TEST_SET_VOLUME_RESP, + CMD_TEST_BT_ADDR_REQ, + CMD_TEST_BT_ADDR_RESP, + CMD_TEST_BT_PARRING_REQ, + CMD_TEST_BT_PARRING_RESP, + CMD_TEST_GET_CPLD_REQ, + + // RF cmd---> + + CMD_TEST_RF_BASE = 0x2100, + CMD_TEST_RF_BT_ENTER, + CMD_TEST_RF_BT_ENTER_RESP, + CMD_TEST_RF_EXIT_TO_NORNAL, + CMD_TEST_RF_EXIT_TO_NORNAL_RESP, + + CMD_TEST_RF_BT_TX = 0x2200, + CMD_TEST_RF_BT_TX_RESP, + CMD_TEST_RF_BT_TX_2402_1DH1, + CMD_TEST_RF_BT_TX_2402_1DH1_RESP, + CMD_TEST_RF_BT_TX_2440_1DH1, + CMD_TEST_RF_BT_TX_2440_1DH1_RESP, + CMD_TEST_RF_BT_TX_2480_1DH1, + CMD_TEST_RF_BT_TX_2480_1DH1_RESP, + CMD_TEST_RF_BT_TX_2402_2DH3, + CMD_TEST_RF_BT_TX_2402_2DH3_RESP, + CMD_TEST_RF_BT_TX_2440_2DH3, + CMD_TEST_RF_BT_TX_2440_2DH3_RESP, + CMD_TEST_RF_BT_TX_2480_2DH3, + CMD_TEST_RF_BT_TX_2480_2DH3_RESP, + CMD_TEST_RF_BT_TX_2402_3DH5, + CMD_TEST_RF_BT_TX_2402_3DH5_RESP, + CMD_TEST_RF_BT_TX_2440_3DH5, + + CMD_TEST_RF_BT_TX_2440_3DH5_RESP, + CMD_TEST_RF_BT_TX_2480_3DH5, + CMD_TEST_RF_BT_TX_2480_3DH5_RESP, + + // varible extend---> + CMD_TEST_RF_BT_TX_VARIABLE = 0x22f0, + CMD_TEST_RF_BT_TX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_BT_RX = 0x2300, + CMD_TEST_RF_BT_RX_RESP, + CMD_TEST_RF_BT_RX_2402_1DH1, + CMD_TEST_RF_BT_RX_2402_1DH1_RESP, + CMD_TEST_RF_BT_RX_2440_1DH1, + CMD_TEST_RF_BT_RX_2440_1DH1_RESP, + CMD_TEST_RF_BT_RX_2480_1DH1, + CMD_TEST_RF_BT_RX_2480_1DH1_RESP, + CMD_TEST_RF_BT_RX_2402_2DH3, + CMD_TEST_RF_BT_RX_2402_2DH3_RESP, + CMD_TEST_RF_BT_RX_2440_2DH3, + CMD_TEST_RF_BT_RX_2440_2DH3_RESP, + CMD_TEST_RF_BT_RX_2480_2DH3, + CMD_TEST_RF_BT_RX_2480_2DH3_RESP, + CMD_TEST_RF_BT_RX_2402_3DH5, + CMD_TEST_RF_BT_RX_2402_3DH5_RESP, + CMD_TEST_RF_BT_RX_2440_3DH5, + + CMD_TEST_RF_BT_RX_2440_3DH5_RESP, + CMD_TEST_RF_BT_RX_2480_3DH5, + CMD_TEST_RF_BT_RX_2480_3DH5_RESP, + + // varible extend---> + CMD_TEST_RF_BT_RX_VARIABLE = 0x23f0, + CMD_TEST_RF_BT_RX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_BT_EXIT = 0x2400, + CMD_TEST_RF_BT_EXIT_RESP, + + CMD_TEST_RF_WIFI_ENTER = 0x2500, + CMD_TEST_RF_WIFI_ENTER_RESP, + + CMD_TEST_RF_WIFI_TX = 0x2600, + CMD_TEST_RF_WIFI_TX_RESP, + + CMD_TEST_RF_WIFI_TX_CHANNEL1, + CMD_TEST_RF_WIFI_TX_CHANNEL1_RESP, + CMD_TEST_RF_WIFI_TX_CHANNEL7, + CMD_TEST_RF_WIFI_TX_CHANNEL7_RESP, + CMD_TEST_RF_WIFI_TX_CHANNEL13, + CMD_TEST_RF_WIFI_TX_CHANNEL13_RESP, + + // varible extend---> + CMD_TEST_RF_WIFI_TX_VARIABLE = 0x26f0, + CMD_TEST_RF_WIFI_TX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_WIFI_RX = 0x2700, + CMD_TEST_RF_WIFI_RX_RESP, + + CMD_TEST_RF_WIFI_RX_CHANNEL1, + CMD_TEST_RF_WIFI_RX_CHANNEL1_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL1_RET, + CMD_TEST_RF_WIFI_RX_CHANNEL1_RET_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL7, + CMD_TEST_RF_WIFI_RX_CHANNEL7_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL7_RET, + CMD_TEST_RF_WIFI_RX_CHANNEL7_RET_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL13, + CMD_TEST_RF_WIFI_RX_CHANNEL13_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL13_RET, + CMD_TEST_RF_WIFI_RX_CHANNEL13_RET_RESP, + + // varible extend---> + CMD_TEST_RF_WIFI_RX_VARIABLE = 0x27f0, + CMD_TEST_RF_WIFI_RX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_WIFI_EXIT = 0x2800, + CMD_TEST_RF_WIFI_EXIT_RESP, + + CMD_TEST_MCU_LED_GUIDE = 0X2900, + CMD_TEST_MCU_LED_GUIDE_RSP, + CMD_TEST_MCU_LED_MATRIX, + CMD_TEST_MCU_LED_MATRIX_RSP, + //<-----RF cmd + + CMD_TEST_RELEASE_SYSTEM, + + CMD_ALARM_SYNC_REQ = 0xF000, + CMD_ALARM_SYNC_RSP, + CMD_ALARM_ADD, + CMD_ALARM_REMOVE, + CMD_ALARM_REMOVEALL, + + CMD_REMAIND_SYNC_REQ, + CMD_REMAIND_SYNC_RSP, + CMD_REMAIND_ADD, + CMD_REMAIND_REMOVE, + CMD_REMAIND_REMOVEALL, + + CMD_ASSISTANT_STATUS, + CMD_ASSISTANT_RUNNING, + CMD_ASSISTANT_NOTIFY, + + CMD_SESSION_ALARM_SYNC, + + CMD_WORKDAY_DB_REQ = 0xF100, + CMD_WORKDAY_DB_RSP, + + CMD_OTA_NOTIFY = 0xF200, + CMD_OTA_STATUS, + CMD_OTA_RUNNOW, + + CMD_LOG_CONFIG = 0xF300, + + CMD_DEMO_PERFORM_TEST = 0xff00, + +} DBUS_CMD; + +typedef enum { + ERR_INPUT_PARAMS = 1, + ERR_NO_ITEMS, + ERR_GET_BUS, + ERR_DBUS_CONNECTION, + ERR_REQUEST_BUS_NAME, + ERR_SET_WATCH_FUNCTION, + ERR_SET_TIMEOUT_FUNCTION, + ERR_BUS_MATCH, + ERR_BUS_SET_MSG_CB, + ERR_DBUS_CREATE_MSG, + ERR_BUS_SEND_MSG, + ERR_DBUS_MSG_TO_LARGE, + ERR_BUS_RCV_MSG, + ERR_ADD_TASK, + ERR_UNSUP_EVP_TYPE, + + ERR_CREATE_MQ, + ERR_MQ_SENDMSG, + ERR_CREATE_SHM, + ERR_MAP_SHM, + ERR_MALLOC_MEMORY, + + ERR_EVP_INIT_KEY, + ERR_EVP_UPDATE, + ERR_EVP_FINALE, + ERR_EVP_KEY_SIZE, + + ERR_OPEN_FILE, + ERR_READ_FILE, + ERR_WRITE_FILE, + ERR_COPY_FILE, + ERR_FILE_NOT_EXISTS, + ERR_GET_FILE_SIZE, + ERR_UNINIT_ITEM, + ERR_FILE_EMPTY, + + ERR_SEND_MAIL, + ERR_NETWORK_SEND, + ERR_NETWORK_NOT_CONNECTED, + + ERR_UNSUPPORT, +} DBUS_WITH_LIBUV_ERROR; + +/** + * 错误码 + */ +typedef enum { + ERR_NO_INIT_IPL3 = 2000, ///< (0xF101) 未初始化OTA参数 + ERR_BAD_IPL3, ///< OTA参数异常 + ERR_BAD_FILE_SIZE, ///< 文件大小不正确 + ERR_MD5_FILE, ///< 计算文件MD5校验和异常 + ERR_MD5_CHECK_SUM, ///< MD5校验和不正确 + ERR_OTA_WRITE_BOOT, ///< 写入BOOT分区异常 + ERR_OTA_WRITE_ROOTFS, ///< 写入ROOTFS分区异常 + ERR_OTA_WRITE_IPL3, ///< 写入IPL3分区异常 + ERR_OTA_WRITE_PARAMS, ///< 写入OTA参数异常 + ERR_OTA_DOWNLOAD_FILE, ///< 下载文件失败 + ERR_VERIFY_PARTITION_MD5, ///< 校验分区MD5异常 + ERR_OTA_PRE_STATR, ///< 先前已经启动了一个未完成的OTA任务 + ERR_OTA_YET_CUR_VER, ///< 当前版本已经更新 + ERR_OTA_NOT_READY, ///< OTA未准备好,暂时不能进行OTA升级 +} OTA_ERROR; + +typedef enum { + ERR_CREATE_CFG_FILE = 1000, + ERR_CREATE_SQLITE3_DB, + ERR_OPEN_SQLITE3_DB, + ERR_SQLITE3_CREATE_TABLE, + ERR_SYNC_DATABASE, + ERR_SQL_QUERY, + ERR_SQL_DELETE, + ERR_UNKNOWN_TYPE, + ERR_PERMISSION_DENIED, + ERR_CFG_NOITEM, + ERR_CFG_ITEM_EXIST, + ERR_CFG_WAIT_RSP, + ERR_CFG_BUSY, + ERR_STR_CONVERT, + ERR_SQL_REG_MODULE, +} CONFIG_MODE_ERRCODE; + +typedef enum { + REPEAT_MODE_NONE = 1, + REPEAT_MODE_EVERY_DAY = 2, + REPEAT_MODE_WORKDAY = 3, + REPEAT_MODE_WEEKEND = 4, + REPEAT_MODE_WEEKDAY = 5, + REPEAT_MODE_EVERY_MONTH_DAY = 6, + REPEAT_MODE_EVERY_YEAR_DAY = 7, + REPEAT_MODE_EVERY_TIME = 8, + REPEAT_MODE_MONTH_LAST_DAY = 9, + REPEAT_MODE_HOLIDAY = 10, +} REPEAT_MODE; + +#define MAX_CFG_KEY_NAME (256) +#define MAX_CFG_KEY_VALUE (1024) +#define DATA_TIME_STR_LEN (20) + +#define GET_FILE_SIZE(path, size) \ + do { \ + struct stat st; \ + memset(&st, 0, sizeof(struct stat)); \ + if (stat(path, &st) != 0) { \ + size = -1; \ + } else { \ + size = st.st_size; \ + } \ + } while (0) +#ifdef __cplusplus +} +#endif +#endif diff --git a/linux32/inc/cjson/cJSON.h b/linux32/inc/cjson/cJSON.h new file mode 100644 index 0000000..bd10099 --- /dev/null +++ b/linux32/inc/cjson/cJSON.h @@ -0,0 +1,154 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* cJSON Types: */ +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON { + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int type; /* The type of the item, as above. */ + + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ + + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ +} cJSON; + +typedef struct cJSON_Hooks { + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +/* Supply malloc, realloc and free functions to cJSON */ +extern void cJSON_InitHooks(cJSON_Hooks* hooks); + + +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ +extern cJSON *cJSON_Parse(const char *value); +/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ +extern char *cJSON_Print(cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ +extern char *cJSON_PrintUnformatted(cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); +/* Delete a cJSON entity and all subentities. */ +extern void cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +extern int cJSON_GetArraySize(cJSON *array); +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); +/* Get item "string" from object. Case insensitive. */ +extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); +extern int cJSON_HasObjectItem(cJSON *object,const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +extern const char *cJSON_GetErrorPtr(void); + +/* These calls create a cJSON item of the appropriate type. */ +extern cJSON *cJSON_CreateNull(void); +extern cJSON *cJSON_CreateTrue(void); +extern cJSON *cJSON_CreateFalse(void); +extern cJSON *cJSON_CreateBool(int b); +extern cJSON *cJSON_CreateNumber(double num); +extern cJSON *cJSON_CreateString(const char *string); +extern cJSON *cJSON_CreateArray(void); +extern cJSON *cJSON_CreateObject(void); + +/* These utilities create an Array of count items. */ +extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); +extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); +extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); +extern cJSON *cJSON_CreateStringArray(const char **strings,int count); + +/* Append item to the specified array/object. */ +extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); +extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); +extern void cJSON_DeleteItemFromArray(cJSON *array,int which); +extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); +extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); + +/* Update array items. */ +extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ +extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); +extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ + +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); + +extern void cJSON_Minify(char *json); + +/* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) +#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) + +/* Macro for iterating over an array */ +#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linux32/inc/cjson/s2j.h b/linux32/inc/cjson/s2j.h new file mode 100644 index 0000000..8d89d8f --- /dev/null +++ b/linux32/inc/cjson/s2j.h @@ -0,0 +1,91 @@ +/* + * This file is part of the struct2json Library. + * + * Copyright (c) 2015, Armink, + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Function: It is an head file for this library. You can see all be called functions. + * Created on: 2015-10-14 + */ + +#ifndef __S2J_H__ +#define __S2J_H__ + +#include +#include +#include "s2jdef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* struct2json software version number */ +#define S2J_SW_VERSION "1.0.3" + +/* Create JSON object */ +#define s2j_create_json_obj(json_obj) \ + S2J_CREATE_JSON_OBJECT(json_obj) + +/* Delete JSON object */ +#define s2j_delete_json_obj(json_obj) \ + S2J_DELETE_JSON_OBJECT(json_obj) + +/* Set basic type element for JSON object */ +#define s2j_json_set_basic_element(to_json, from_struct, type, element) \ + S2J_JSON_SET_BASIC_ELEMENT(to_json, from_struct, type, element) + +/* Set array type element for JSON object */ +#define s2j_json_set_array_element(to_json, from_struct, type, element, size) \ + S2J_JSON_SET_ARRAY_ELEMENT(to_json, from_struct, type, element, size) + +/* Set child structure type element for JSON object */ +#define s2j_json_set_struct_element(child_json, to_json, child_struct, from_struct, type, element) \ + S2J_JSON_SET_STRUCT_ELEMENT(child_json, to_json, child_struct, from_struct, type, element) + +/* Create structure object */ +#define s2j_create_struct_obj(struct_obj, type) \ + S2J_CREATE_STRUCT_OBJECT(struct_obj, type) + +/* Delete structure object */ +#define s2j_delete_struct_obj(struct_obj) \ + S2J_DELETE_STRUCT_OBJECT(struct_obj) + +/* Get basic type element for structure object */ +#define s2j_struct_get_basic_element(to_struct, from_json, type, element) \ + S2J_STRUCT_GET_BASIC_ELEMENT(to_struct, from_json, type, element) + +/* Get array type element for structure object */ +#define s2j_struct_get_array_element(to_struct, from_json, type, element) \ + S2J_STRUCT_GET_ARRAY_ELEMENT(to_struct, from_json, type, element) + +/* Get child structure type element for structure object */ +#define s2j_struct_get_struct_element(child_struct, to_struct, child_json, from_json, type, element) \ + S2J_STRUCT_GET_STRUCT_ELEMENT(child_struct, to_struct, child_json, from_json, type, element) + +/* s2j.c */ +extern S2jHook s2jHook; +void s2j_init(S2jHook *hook); + +#ifdef __cplusplus +} +#endif + +#endif /* __S2J_H__ */ diff --git a/linux32/inc/cjson/s2jdef.h b/linux32/inc/cjson/s2jdef.h new file mode 100644 index 0000000..ec7dcfc --- /dev/null +++ b/linux32/inc/cjson/s2jdef.h @@ -0,0 +1,150 @@ +/* + * This file is part of the struct2json Library. + * + * Copyright (c) 2015, Armink, + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Function: It is an head file for this library. + * Created on: 2015-10-14 + */ + +#ifndef __S2JDEF_H__ +#define __S2JDEF_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} S2jHook, *S2jHook_t; + +#define S2J_STRUCT_GET_int_ELEMENT(to_struct, from_json, _element) \ + json_temp = cJSON_GetObjectItem(from_json, #_element); \ + if (json_temp) (to_struct)->_element = json_temp->valueint; + +#define S2J_STRUCT_GET_string_ELEMENT(to_struct, from_json, _element) \ + json_temp = cJSON_GetObjectItem(from_json, #_element); \ + if (json_temp) strcpy((to_struct)->_element, json_temp->valuestring); + +#define S2J_STRUCT_GET_double_ELEMENT(to_struct, from_json, _element) \ + json_temp = cJSON_GetObjectItem(from_json, #_element); \ + if (json_temp) (to_struct)->_element = json_temp->valuedouble; + +#define S2J_STRUCT_ARRAY_GET_int_ELEMENT(to_struct, from_json, _element, index) \ + (to_struct)->_element[index] = from_json->valueint; + +#define S2J_STRUCT_ARRAY_GET_string_ELEMENT(to_struct, from_json, _element, index) \ + strcpy((to_struct)->_element[index], from_json->valuestring); + +#define S2J_STRUCT_ARRAY_GET_double_ELEMENT(to_struct, from_json, _element, index) \ + (to_struct)->_element[index] = from_json->valuedouble; + +#define S2J_STRUCT_ARRAY_GET_ELEMENT(to_struct, from_json, type, _element, index) \ + S2J_STRUCT_ARRAY_GET_##type##_ELEMENT(to_struct, from_json, _element, index) + +#define S2J_JSON_SET_int_ELEMENT(to_json, from_struct, _element) \ + cJSON_AddNumberToObject(to_json, #_element, (from_struct)->_element); + +#define S2J_JSON_SET_double_ELEMENT(to_json, from_struct, _element) \ + cJSON_AddNumberToObject(to_json, #_element, (from_struct)->_element); + +#define S2J_JSON_SET_string_ELEMENT(to_json, from_struct, _element) \ + cJSON_AddStringToObject(to_json, #_element, (from_struct)->_element); + +#define S2J_JSON_ARRAY_SET_int_ELEMENT(to_json, from_struct, _element, index) \ + cJSON_AddItemToArray(to_json, cJSON_CreateNumber((from_struct)->_element[index])); + +#define S2J_JSON_ARRAY_SET_double_ELEMENT(to_json, from_struct, _element, index) \ + cJSON_AddItemToArray(to_json, cJSON_CreateNumber((from_struct)->_element[index])); + +#define S2J_JSON_ARRAY_SET_string_ELEMENT(to_json, from_struct, _element, index) \ + cJSON_AddItemToArray(to_json, cJSON_CreateString((from_struct)->_element[index])); + +#define S2J_JSON_ARRAY_SET_ELEMENT(to_json, from_struct, type, _element, index) \ + S2J_JSON_ARRAY_SET_##type##_ELEMENT(to_json, from_struct, _element, index) + + +#define S2J_CREATE_JSON_OBJECT(json_obj) \ + cJSON *json_obj = cJSON_CreateObject(); + +#define S2J_DELETE_JSON_OBJECT(json_obj) \ + cJSON_Delete(json_obj); + +#define S2J_JSON_SET_BASIC_ELEMENT(to_json, from_struct, type, _element) \ + S2J_JSON_SET_##type##_ELEMENT(to_json, from_struct, _element) + +#define S2J_JSON_SET_ARRAY_ELEMENT(to_json, from_struct, type, _element, size) \ + { \ + cJSON *array; \ + size_t index = 0; \ + array = cJSON_CreateArray(); \ + if (array) { \ + while (index < size) { \ + S2J_JSON_ARRAY_SET_ELEMENT(array, from_struct, type, _element, index++); \ + } \ + cJSON_AddItemToObject(to_json, #_element, array); \ + } \ + } + +#define S2J_JSON_SET_STRUCT_ELEMENT(child_json, to_json, child_struct, from_struct, type, _element) \ + type *child_struct = &((from_struct)->_element); \ + cJSON *child_json = cJSON_CreateObject(); \ + if (child_json) cJSON_AddItemToObject(to_json, #_element, child_json); + +#define S2J_CREATE_STRUCT_OBJECT(struct_obj, type) \ + cJSON *json_temp; \ + type *struct_obj = s2jHook.malloc_fn(sizeof(type)); \ + if (struct_obj) memset(struct_obj, 0, sizeof(type)); + +#define S2J_DELETE_STRUCT_OBJECT(struct_obj) \ + s2jHook.free_fn(struct_obj); + +#define S2J_STRUCT_GET_BASIC_ELEMENT(to_struct, from_json, type, _element) \ + S2J_STRUCT_GET_##type##_ELEMENT(to_struct, from_json, _element) + +#define S2J_STRUCT_GET_ARRAY_ELEMENT(to_struct, from_json, type, _element) \ + { \ + cJSON *array, *array_element; \ + size_t index = 0, size = 0; \ + array = cJSON_GetObjectItem(from_json, #_element); \ + if (array) { \ + size = cJSON_GetArraySize(array); \ + while (index < size) { \ + array_element = cJSON_GetArrayItem(array, index); \ + if (array_element) S2J_STRUCT_ARRAY_GET_ELEMENT(to_struct, array_element, type, _element, index++); \ + } \ + } \ + } + +#define S2J_STRUCT_GET_STRUCT_ELEMENT(child_struct, to_struct, child_json, from_json, type, _element) \ + type *child_struct = &((to_struct)->_element); \ + cJSON *child_json = cJSON_GetObjectItem(from_json, #_element); + +#ifdef __cplusplus +} +#endif + +#endif /* __S2JDEF_H__ */ diff --git a/linux32/inc/uthash/utarray.h b/linux32/inc/uthash/utarray.h new file mode 100644 index 0000000..80e2f9d --- /dev/null +++ b/linux32/inc/uthash/utarray.h @@ -0,0 +1,238 @@ +/* +Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic array implementation using macros + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 2.0.2 + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#ifdef __GNUC__ +#define UTARRAY_UNUSED __attribute__((__unused__)) +#else +#define UTARRAY_UNUSED +#endif + +#ifndef oom +#define oom() exit(-1) +#endif + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + UT_icd icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd = *(_icd); \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd.dtor) { \ + unsigned _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + (a) = (UT_array*)malloc(sizeof(UT_array)); \ + if ((a) == NULL) oom(); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+(by)) > (a)->n) { \ + char *utarray_tmp; \ + while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \ + if (utarray_tmp == NULL) oom(); \ + (a)->d=utarray_tmp; \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((a)->d + ((a)->icd.sz * (j))) + +#define utarray_insert(a,p,j) do { \ + if ((j) > (a)->i) utarray_resize(a,j); \ + utarray_reserve(a,1); \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if ((j) > (a)->i) utarray_resize(a,j); \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { \ + unsigned _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd.sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + unsigned _ut_i; \ + if ((dst)->i > (unsigned)(num)) { \ + if ((dst)->icd.dtor) { \ + for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \ + (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \ + } \ + } \ + } else if ((dst)->i < (unsigned)(num)) { \ + utarray_reserve(dst, (num) - (dst)->i); \ + if ((dst)->icd.init) { \ + for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \ + (dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst, (dst)->i), 0, (dst)->icd.sz*((num) - (dst)->i)); \ + } \ + } \ + (dst)->i = (num); \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta(dst, src, utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd.dtor) { \ + unsigned _ut_i; \ + for (_ut_i = 0; _ut_i < (len); _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \ + } \ + } \ + if ((a)->i > ((pos) + (len))) { \ + memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \ + ((a)->i - ((pos) + (len))) * (a)->icd.sz); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_renew(a,u) do { \ + if (a) utarray_clear(a); \ + else utarray_new(a, u); \ +} while(0) + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd.dtor) { \ + unsigned _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ +} while(0) + +#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc != NULL) free(*eltc); +} +static const UT_icd ut_str_icd UTARRAY_UNUSED = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int),NULL,NULL,NULL}; +static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void*),NULL,NULL,NULL}; + + +#endif /* UTARRAY_H */ diff --git a/linux32/inc/uthash/uthash.h b/linux32/inc/uthash/uthash.h new file mode 100644 index 0000000..b1faf46 --- /dev/null +++ b/linux32/inc/uthash/uthash.h @@ -0,0 +1,1107 @@ +/* +Copyright (c) 2003-2017, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#define UTHASH_VERSION 2.0.2 + +#include /* memcmp, memset, strlen */ +#include /* ptrdiff_t */ +#include /* exit */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE(x) +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while (0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while (0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined(_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include +#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#elif defined(__GNUC__) && !defined(__VXWORKS__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#endif +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_bzero +#define uthash_bzero(a,n) memset(a,'\0',n) +#endif +#ifndef uthash_memcmp +#define uthash_memcmp(a,b,n) memcmp(a,b,n) +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho))) + +#define HASH_VALUE(keyptr,keylen,hashv) \ +do { \ + HASH_FCN(keyptr, keylen, hashv); \ +} while (0) + +#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ + } \ + } \ +} while (0) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + uthash_fatal("out of memory"); \ + } \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + uthash_fatal("out of memory"); \ + } \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + if (!(head)->hh.tbl->buckets) { \ + uthash_fatal("out of memory"); \ + } \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ +} while (0) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ +} while (0) + +#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ +} while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ +do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ +} while (0) + +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + do { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) + +#ifdef NO_DECLTYPE +#undef HASH_AKBI_INNER_LOOP +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + char *_hs_saved_head = (char*)(head); \ + do { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) +#endif + +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + (head) = (add); \ + HASH_MAKE_TABLE(hh, head); \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ +} while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ +do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + (head) = (add); \ + HASH_MAKE_TABLE(hh, head); \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ +} while (0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv,num_bkts,bkt) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ +} while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) + +#define HASH_DELETE_HH(hh,head,delptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE"); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ + HASH_REPLACE(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add,replaced) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head,where) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void*)_thh->hh_prev, (void*)_prev); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char*)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void*)_thh->prev, (void*)_prev); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head,where) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,hashv) \ +do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,hashv) \ +do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char*)(key); \ + hashv = 0; \ + for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,hashv) \ +do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char*)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ +} while (0) + +#define HASH_OAT(key,keylen,hashv) \ +do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ +} while (0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,hashv) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned const char *_hj_key=(unsigned const char*)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ + case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ +} while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,hashv) \ +do { \ + unsigned const char *_sfh_key=(unsigned const char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ +} while (0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6bu; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35u; \ + _h ^= _h >> 16; \ +} while (0) + +#define HASH_MUR(key,keylen,hashv) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (int)(keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353u; \ + uint32_t _mur_c1 = 0xcc9e2d51u; \ + uint32_t _mur_c2 = 0x1b873593u; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ + int _mur_i; \ + for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ + _mur_k1=0; \ + switch ((keylen) & 3U) { \ + case 0: break; \ + case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ + case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ + case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (uint32_t)(keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ +} while (0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ +do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ +} while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ + && !(addhh)->tbl->noexpand) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while (0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(head,delhh) \ +do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ +} while (0) + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { \ + uthash_fatal("out of memory"); \ + } \ + uthash_bzero(_he_new_buckets, \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ + _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / (tbl)->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ + ((tbl)->ineff_expands+1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while (0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ + )) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail != NULL ) { \ + _hs_tail->next = ((_hs_e != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = ((_hs_tail != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if ((src) != NULL) { \ + for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], _dst_hh); \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if ((head) != NULL) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ +} while (0) + +#define HASH_OVERHEAD(hh,head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/linux32/inc/uthash/utlist.h b/linux32/inc/uthash/utlist.h new file mode 100644 index 0000000..0e5e287 --- /dev/null +++ b/linux32/inc/uthash/utlist.h @@ -0,0 +1,1073 @@ +/* +Copyright (c) 2007-2017, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 2.0.2 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define IF_NO_DECLTYPE(x) x +#define LDECLTYPE(x) char* +#define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define UTLIST_NEXT(elt,list,next) ((char*)((list)->next)) +#define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define IF_NO_DECLTYPE(x) +#define UTLIST_SV(elt,list) +#define UTLIST_NEXT(elt,list,next) ((elt)->next) +#define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */ +#define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define UTLIST_RS(list) +#define UTLIST_CASTASGN(a,b) (a)=(b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) \ + LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ + } \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + + +#define DL_SORT(list, cmp) \ + DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } else if ((_ls_qsize == 0) || (!_ls_q)) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev, _ls_tail); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +#define CDL_SORT(list, cmp) \ + CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + LDECLTYPE(list) _ls_oldhead; \ + LDECLTYPE(list) _tmp; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + UTLIST_CASTASGN(_ls_oldhead,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); \ + if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) { \ + _ls_q = NULL; \ + } else { \ + _ls_q = UTLIST_NEXT(_ls_q,list,next); \ + } \ + UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev,_ls_tail); \ + UTLIST_CASTASGN(_tmp,list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head,add) \ + LL_PREPEND2(head,add,next) + +#define LL_PREPEND2(head,add,next) \ +do { \ + (add)->next = (head); \ + (head) = (add); \ +} while (0) + +#define LL_CONCAT(head1,head2) \ + LL_CONCAT2(head1,head2,next) + +#define LL_CONCAT2(head1,head2,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head1) { \ + _tmp = (head1); \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(head2); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#define LL_APPEND(head,add) \ + LL_APPEND2(head,add,next) + +#define LL_APPEND2(head,add,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + (add)->next=NULL; \ + if (head) { \ + _tmp = (head); \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(add); \ + } else { \ + (head)=(add); \ + } \ +} while (0) + +#define LL_INSERT_INORDER(head,add,cmp) \ + LL_INSERT_INORDER2(head,add,cmp,next) + +#define LL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + LL_LOWER_BOUND(head, _tmp, add, cmp); \ + LL_APPEND_ELEM(head, _tmp, add); \ + } else { \ + (head) = (add); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define LL_LOWER_BOUND(head,elt,like,cmp) \ + LL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define LL_LOWER_BOUND2(head,elt,like,cmp,next) \ + do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if (cmp((elt)->next, like) >= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) + +#define LL_DELETE(head,del) \ + LL_DELETE2(head,del,next) + +#define LL_DELETE2(head,del,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (del)->next; \ + } \ + } \ +} while (0) + +#define LL_COUNT(head,el,counter) \ + LL_COUNT2(head,el,counter,next) \ + +#define LL_COUNT2(head,el,counter,next) \ +do { \ + (counter) = 0; \ + LL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define LL_FOREACH(head,el) \ + LL_FOREACH2(head,el,next) + +#define LL_FOREACH2(head,el,next) \ + for ((el) = (head); el; (el) = (el)->next) + +#define LL_FOREACH_SAFE(head,el,tmp) \ + LL_FOREACH_SAFE2(head,el,tmp,next) + +#define LL_FOREACH_SAFE2(head,el,tmp,next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +#define LL_SEARCH_SCALAR(head,out,field,val) \ + LL_SEARCH_SCALAR2(head,out,field,val,next) + +#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while (0) + +#define LL_SEARCH(head,out,elt,cmp) \ + LL_SEARCH2(head,out,elt,cmp,next) + +#define LL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while (0) + +#define LL_REPLACE_ELEM2(head, el, add, next) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) + +#define LL_REPLACE_ELEM(head, el, add) \ + LL_REPLACE_ELEM2(head, el, add, next) + +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ +} while (0) \ + +#define LL_PREPEND_ELEM(head, el, add) \ + LL_PREPEND_ELEM2(head, el, add, next) + +#define LL_APPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (el)->next = (add); \ + } else { \ + LL_PREPEND2(head, add, next); \ + } \ +} while (0) \ + +#define LL_APPEND_ELEM(head, el, add) \ + LL_APPEND_ELEM2(head, el, add, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef LL_CONCAT2 +#define LL_CONCAT2(head1,head2,next) \ +do { \ + char *_tmp; \ + if (head1) { \ + _tmp = (char*)(head1); \ + while ((head1)->next) { (head1) = (head1)->next; } \ + (head1)->next = (head2); \ + UTLIST_RS(head1); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#undef LL_APPEND2 +#define LL_APPEND2(head,add,next) \ +do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { (add)->next = (add)->next->next; } \ + (add)->next->next=(add); \ + } else { \ + (head)=(add); \ + } \ + (add)->next=NULL; \ +} while (0) + +#undef LL_INSERT_INORDER2 +#define LL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, add)) >= 0) { \ + (add)->next = (head); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_DELETE2 +#define LL_DELETE2(head,del,next) \ +do { \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + (head) = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_REPLACE_ELEM2 +#define LL_REPLACE_ELEM2(head, el, add, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = head; \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el)->next; \ +} while (0) + +#undef LL_PREPEND_ELEM2 +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = (head); \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el); \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ +} while (0) \ + +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head,add) \ + DL_PREPEND2(head,add,prev,next) + +#define DL_PREPEND2(head,add,prev,next) \ +do { \ + (add)->next = (head); \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev = (add); \ + } else { \ + (add)->prev = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define DL_APPEND(head,add) \ + DL_APPEND2(head,add,prev,next) + +#define DL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_INSERT_INORDER(head,add,cmp) \ + DL_INSERT_INORDER2(head,add,cmp,next) + +#define DL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + DL_LOWER_BOUND(head, _tmp, add, cmp); \ + DL_APPEND_ELEM(head, _tmp, add); \ + } else { \ + (head) = (add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_LOWER_BOUND(head,elt,like,cmp) \ + DL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define DL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ +} while (0) + +#define DL_CONCAT(head1,head2) \ + DL_CONCAT2(head1,head2,prev,next) + +#define DL_CONCAT2(head1,head2,prev,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head2) { \ + if (head1) { \ + UTLIST_CASTASGN(_tmp, (head2)->prev); \ + (head2)->prev = (head1)->prev; \ + (head1)->prev->next = (head2); \ + UTLIST_CASTASGN((head1)->prev, _tmp); \ + } else { \ + (head1)=(head2); \ + } \ + } \ +} while (0) + +#define DL_DELETE(head,del) \ + DL_DELETE2(head,del,prev,next) + +#define DL_DELETE2(head,del,prev,next) \ +do { \ + assert((head) != NULL); \ + assert((del)->prev != NULL); \ + if ((del)->prev == (del)) { \ + (head)=NULL; \ + } else if ((del)==(head)) { \ + (del)->next->prev = (del)->prev; \ + (head) = (del)->next; \ + } else { \ + (del)->prev->next = (del)->next; \ + if ((del)->next) { \ + (del)->next->prev = (del)->prev; \ + } else { \ + (head)->prev = (del)->prev; \ + } \ + } \ +} while (0) + +#define DL_COUNT(head,el,counter) \ + DL_COUNT2(head,el,counter,next) \ + +#define DL_COUNT2(head,el,counter,next) \ +do { \ + (counter) = 0; \ + DL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define DL_FOREACH(head,el) \ + DL_FOREACH2(head,el,next) + +#define DL_FOREACH2(head,el,next) \ + for ((el) = (head); el; (el) = (el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head,el,tmp) \ + DL_FOREACH_SAFE2(head,el,tmp,next) + +#define DL_FOREACH_SAFE2(head,el,tmp,next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM2(head, el, add, prev, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + (add)->next = (el)->next; \ + if ((el)->next == NULL) { \ + (add)->prev = (add); \ + } else { \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + } \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->prev->next = (add); \ + if ((el)->next == NULL) { \ + (head)->prev = (add); \ + } else { \ + (add)->next->prev = (add); \ + } \ + } \ +} while (0) + +#define DL_REPLACE_ELEM(head, el, add) \ + DL_REPLACE_ELEM2(head, el, add, prev, next) + +#define DL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ + } else { \ + DL_APPEND2(head, add, prev, next); \ + } \ +} while (0) \ + +#define DL_PREPEND_ELEM(head, el, add) \ + DL_PREPEND_ELEM2(head, el, add, prev, next) + +#define DL_APPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } else { \ + DL_PREPEND2(head, add, prev, next); \ + } \ +} while (0) \ + +#define DL_APPEND_ELEM(head, el, add) \ + DL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef DL_INSERT_INORDER2 +#define DL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = NULL; \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_APPEND(head,add) \ + CDL_APPEND2(head,add,prev,next) + +#define CDL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } \ +} while (0) + +#define CDL_PREPEND(head,add) \ + CDL_PREPEND2(head,add,prev,next) + +#define CDL_PREPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define CDL_INSERT_INORDER(head,add,cmp) \ + CDL_INSERT_INORDER2(head,add,cmp,next) + +#define CDL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + CDL_LOWER_BOUND(head, _tmp, add, cmp); \ + CDL_APPEND_ELEM(head, _tmp, add); \ + } else { \ + (head) = (add); \ + (head)->next = (head); \ + (head)->prev = (head); \ + } \ +} while (0) + +#define CDL_LOWER_BOUND(head,elt,like,cmp) \ + CDL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define CDL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ +} while (0) + +#define CDL_DELETE(head,del) \ + CDL_DELETE2(head,del,prev,next) + +#define CDL_DELETE2(head,del,prev,next) \ +do { \ + if (((head)==(del)) && ((head)->next == (head))) { \ + (head) = NULL; \ + } else { \ + (del)->next->prev = (del)->prev; \ + (del)->prev->next = (del)->next; \ + if ((del) == (head)) (head)=(del)->next; \ + } \ +} while (0) + +#define CDL_COUNT(head,el,counter) \ + CDL_COUNT2(head,el,counter,next) \ + +#define CDL_COUNT2(head, el, counter,next) \ +do { \ + (counter) = 0; \ + CDL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define CDL_FOREACH(head,el) \ + CDL_FOREACH2(head,el,next) + +#define CDL_FOREACH2(head,el,next) \ + for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next)) + +#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ + CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) + +#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ + for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \ + (el) && ((tmp2) = (el)->next, 1); \ + (el) = ((el) == (tmp1) ? NULL : (tmp2))) + +#define CDL_SEARCH_SCALAR(head,out,field,val) \ + CDL_SEARCH_SCALAR2(head,out,field,val,next) + +#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while (0) + +#define CDL_SEARCH(head,out,elt,cmp) \ + CDL_SEARCH2(head,out,elt,cmp,next) + +#define CDL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while (0) + +#define CDL_REPLACE_ELEM2(head, el, add, prev, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((el)->next == (el)) { \ + (add)->next = (add); \ + (add)->prev = (add); \ + (head) = (add); \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } \ +} while (0) + +#define CDL_REPLACE_ELEM(head, el, add) \ + CDL_REPLACE_ELEM2(head, el, add, prev, next) + +#define CDL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } else { \ + CDL_APPEND2(head, add, prev, next); \ + } \ +} while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ + CDL_PREPEND_ELEM2(head, el, add, prev, next) + +#define CDL_APPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + (add)->next->prev = (add); \ + } else { \ + CDL_PREPEND2(head, add, prev, next); \ + } \ +} while (0) + +#define CDL_APPEND_ELEM(head, el, add) \ + CDL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef CDL_INSERT_INORDER2 +#define CDL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (add)->prev->next = (add); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (add)->next->prev = (add); \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ + +#endif /* UTLIST_H */ diff --git a/linux32/inc/uthash/utringbuffer.h b/linux32/inc/uthash/utringbuffer.h new file mode 100644 index 0000000..b3b5938 --- /dev/null +++ b/linux32/inc/uthash/utringbuffer.h @@ -0,0 +1,108 @@ +/* +Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a ring-buffer implementation using macros + */ +#ifndef UTRINGBUFFER_H +#define UTRINGBUFFER_H + +#define UTRINGBUFFER_VERSION 2.0.2 + +#include +#include +#include "utarray.h" // for "UT_icd" + +typedef struct { + unsigned i; /* index of next available slot; wraps at n */ + unsigned n; /* capacity */ + unsigned char f; /* full */ + UT_icd icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz */ +} UT_ringbuffer; + +#define utringbuffer_init(a, _n, _icd) do { \ + memset(a, 0, sizeof(UT_ringbuffer)); \ + (a)->icd = *(_icd); \ + (a)->n = (_n); \ + if ((a)->n) { (a)->d = (char*)malloc((a)->n * (_icd)->sz); } \ +} while(0) + +#define utringbuffer_clear(a) do { \ + if ((a)->icd.dtor) { \ + if ((a)->f) { \ + unsigned _ut_i; \ + for (_ut_i = 0; _ut_i < (a)->n; ++_ut_i) { \ + (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \ + } \ + } else { \ + unsigned _ut_i; \ + for (_ut_i = 0; _ut_i < (a)->i; ++_ut_i) { \ + (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \ + } \ + } \ + } \ + (a)->i = 0; \ + (a)->f = 0; \ +} while(0) + +#define utringbuffer_done(a) do { \ + utringbuffer_clear(a); \ + free((a)->d); (a)->d = NULL; \ + (a)->n = 0; \ +} while(0) + +#define utringbuffer_new(a,n,_icd) do { \ + a = (UT_ringbuffer*)malloc(sizeof(UT_ringbuffer)); \ + utringbuffer_init(a, n, _icd); \ +} while(0) + +#define utringbuffer_free(a) do { \ + utringbuffer_done(a); \ + free(a); \ +} while(0) + +#define utringbuffer_push_back(a,p) do { \ + if ((a)->icd.dtor && (a)->f) { (a)->icd.dtor(_utringbuffer_internalptr(a,(a)->i)); } \ + if ((a)->icd.copy) { (a)->icd.copy( _utringbuffer_internalptr(a,(a)->i), p); } \ + else { memcpy(_utringbuffer_internalptr(a,(a)->i), p, (a)->icd.sz); }; \ + if (++(a)->i == (a)->n) { (a)->i = 0; (a)->f = 1; } \ +} while(0) + +#define utringbuffer_len(a) ((a)->f ? (a)->n : (a)->i) +#define utringbuffer_empty(a) ((a)->i == 0 && !(a)->f) +#define utringbuffer_full(a) ((a)->f != 0) + +#define _utringbuffer_real_idx(a,j) ((a)->f ? ((j) + (a)->i) % (a)->n : (j)) +#define _utringbuffer_internalptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j)))) +#define utringbuffer_eltptr(a,j) ((0 <= (j) && (j) < utringbuffer_len(a)) ? _utringbuffer_internalptr(a,_utringbuffer_real_idx(a,j)) : NULL) + +#define _utringbuffer_fake_idx(a,j) ((a)->f ? ((j) + (a)->n - (a)->i) % (a)->n : (j)) +#define _utringbuffer_internalidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1) +#define utringbuffer_eltidx(a,e) _utringbuffer_fake_idx(a, _utringbuffer_internalidx(a,e)) + +#define utringbuffer_front(a) utringbuffer_eltptr(a,0) +#define utringbuffer_next(a,e) ((e)==NULL ? utringbuffer_front(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)+1)) +#define utringbuffer_prev(a,e) ((e)==NULL ? utringbuffer_back(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)-1)) +#define utringbuffer_back(a) (utringbuffer_empty(a) ? NULL : utringbuffer_eltptr(a, utringbuffer_len(a) - 1)) + +#endif /* UTRINGBUFFER_H */ diff --git a/linux32/inc/uthash/utstring.h b/linux32/inc/uthash/utstring.h new file mode 100644 index 0000000..4e90ebb --- /dev/null +++ b/linux32/inc/uthash/utstring.h @@ -0,0 +1,398 @@ +/* +Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic string implementation using macros + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 2.0.2 + +#include +#include +#include +#include + +#ifdef __GNUC__ +#define UTSTRING_UNUSED __attribute__((__unused__)) +#else +#define UTSTRING_UNUSED +#endif + +#ifndef oom +#define oom() exit(-1) +#endif + +typedef struct { + char *d; + size_t n; /* allocd size */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + char *utstring_tmp = (char*)realloc( \ + (s)->d, (s)->n + (amt)); \ + if (utstring_tmp == NULL) oom(); \ + (s)->d = utstring_tmp; \ + (s)->n += (amt); \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + s = (UT_string*)calloc(sizeof(UT_string),1); \ + if (!s) oom(); \ + utstring_init(s); \ +} while(0) + +#define utstring_renew(s) \ +do { \ + if (s) { \ + utstring_clear(s); \ + } else { \ + utstring_new(s); \ + } \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve((s),(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + (s)->i += (l); \ + (s)->d[(s)->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve((dst),((src)->i)+1); \ + if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ + (dst)->i += (src)->i; \ + (dst)->d[(dst)->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((s)->i) + +#define utstring_body(s) ((s)->d) + +UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + for (;;) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && ((size_t) n < (s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +#ifdef __GNUC__ +/* support printf format checking (2=the format string, 3=start of varargs) */ +static void utstring_printf(UT_string *s, const char *fmt, ...) + __attribute__ (( format( printf, 2, 3) )); +#endif +UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +/******************************************************************************* + * begin substring search functions * + ******************************************************************************/ +/* Build KMP table from left to right. */ +UTSTRING_UNUSED static void _utstring_BuildTable( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = 0; + j = i - 1; + P_KMP_Table[i] = j; + while (i < (long) P_NeedleLen) + { + while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j]; + } + i++; + j++; + if (i < (long) P_NeedleLen) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i] = P_KMP_Table[j]; + } + else + { + P_KMP_Table[i] = j; + } + } + else + { + P_KMP_Table[i] = j; + } + } + + return; +} + + +/* Build KMP table from right to left. */ +UTSTRING_UNUSED static void _utstring_BuildTableR( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = P_NeedleLen - 1; + j = i + 1; + P_KMP_Table[i + 1] = j; + while (i >= 0) + { + while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j + 1]; + } + i--; + j--; + if (i >= 0) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; + } + else + { + P_KMP_Table[i + 1] = j; + } + } + else + { + P_KMP_Table[i + 1] = j; + } + } + + return; +} + + +/* Search data from left to right. ( Multiple search mode. ) */ +UTSTRING_UNUSED static long _utstring_find( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from left to right. */ + i = j = 0; + while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) + { + while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i]; + } + i++; + j++; + if (i >= (int)P_NeedleLen) + { + /* Found. */ + V_FindPosition = j - i; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( Multiple search mode. ) */ +UTSTRING_UNUSED static long _utstring_findR( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from right to left. */ + j = (P_HaystackLen - 1); + i = (P_NeedleLen - 1); + while ( (j >= 0) && (j >= i) ) + { + while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i + 1]; + } + i--; + j--; + if (i < 0) + { + /* Found. */ + V_FindPosition = j + 1; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from left to right. ( One time search mode. ) */ +UTSTRING_UNUSED static long utstring_find( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = s->i - V_StartPosition; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_find(s->d + V_StartPosition, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + if (V_FindPosition >= 0) + { + V_FindPosition += V_StartPosition; + } + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( One time search mode. ) */ +UTSTRING_UNUSED static long utstring_findR( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = V_StartPosition + 1; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_findR(s->d, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} +/******************************************************************************* + * end substring search functions * + ******************************************************************************/ + +#endif /* UTSTRING_H */ diff --git a/linux32/src/cJSON.c b/linux32/src/cJSON.c new file mode 100644 index 0000000..5a9008f --- /dev/null +++ b/linux32/src/cJSON.c @@ -0,0 +1,762 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#include +#include +#include +#include +#include +#include +#include +#include "cJSON.h" + +static const char *ep; + +const char *cJSON_GetErrorPtr(void) {return ep;} + +static int cJSON_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} + +static void *(*cJSON_malloc)(size_t sz) = malloc; +static void (*cJSON_free)(void *ptr) = free; + +static char* cJSON_strdup(const char* str) +{ + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = (char*)cJSON_malloc(len))) return 0; + memcpy(copy,str,len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (!hooks) { /* Reset hooks */ + cJSON_malloc = malloc; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; + cJSON_free = (hooks->free_fn)?hooks->free_fn:free; +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(void) +{ + cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + if (node) memset(node,0,sizeof(cJSON)); + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_Delete(cJSON *c) +{ + cJSON *next; + while (c) + { + next=c->next; + if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); + if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); + cJSON_free(c); + c=next; + } +} + +/* Parse the input text to generate a number, and populate the result into item. */ +static const char *parse_number(cJSON *item,const char *num) +{ + double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; + + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ + } + + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ + + item->valuedouble=n; + item->valueint=(int)n; + item->type=cJSON_Number; + return num; +} + +static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } + +typedef struct {char *buffer; int length; int offset; } printbuffer; + +static char* ensure(printbuffer *p,int needed) +{ + char *newbuffer;int newsize; + if (!p || !p->buffer) return 0; + needed+=p->offset; + if (needed<=p->length) return p->buffer+p->offset; + + newsize=pow2gt(needed); + newbuffer=(char*)cJSON_malloc(newsize); + if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} + if (newbuffer) memcpy(newbuffer,p->buffer,p->length); + cJSON_free(p->buffer); + p->length=newsize; + p->buffer=newbuffer; + return newbuffer+p->offset; +} + +static int update(printbuffer *p) +{ + char *str; + if (!p || !p->buffer) return 0; + str=p->buffer+p->offset; + return p->offset+strlen(str); +} + +/* Render the number nicely from the given item into a string. */ +static char *print_number(cJSON *item,printbuffer *p) +{ + char *str=0; + double d=item->valuedouble; + if (d==0) + { + if (p) str=ensure(p,2); + else str=(char*)cJSON_malloc(2); /* special case for 0. */ + if (str) strcpy(str,"0"); + } + else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) + { + if (p) str=ensure(p,21); + else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ + if (str) sprintf(str,"%d",item->valueint); + } + else + { + if (p) str=ensure(p,64); + else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ + if (str) + { + if (fpclassify(d) != FP_ZERO && !isnormal(d)) sprintf(str,"null"); + else if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60) sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } + } + return str; +} + +static unsigned parse_hex4(const char *str) +{ + unsigned h=0; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + return h; +} + +/* Parse the input text into an unescaped cstring, and populate item. */ +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; + if (*str!='\"') {ep=str;return 0;} /* not a string! */ + + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ + + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ + if (!out) return 0; + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && *ptr) + { + if (*ptr!='\\') *ptr2++=*ptr++; + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': /* transcode utf16 to utf8. */ + uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ + + if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ + { + if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ + uc2=parse_hex4(ptr+3);ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ + uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; + + switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static char *print_string_ptr(const char *str,printbuffer *p) +{ + const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; + + for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; + if (!flag) + { + len=ptr-str; + if (p) out=ensure(p,len+3); + else out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + ptr2=out;*ptr2++='\"'; + strcpy(ptr2,str); + ptr2[len]='\"'; + ptr2[len+1]=0; + return out; + } + + if (!str) + { + if (p) out=ensure(p,3); + else out=(char*)cJSON_malloc(3); + if (!out) return 0; + strcpy(out,"\"\""); + return out; + } + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} + + if (p) out=ensure(p,len+3); + else out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (token=*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +/* Invote print_string_ptr (which is useful) on an item. */ +static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} + +/* Predeclare these prototypes. */ +static const char *parse_value(cJSON *item,const char *value); +static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); +static const char *parse_array(cJSON *item,const char *value); +static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); +static const char *parse_object(cJSON *item,const char *value); +static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); + +/* Utility to jump whitespace and cr/lf */ +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} + +/* Parse an object - create a new root, and populate. */ +cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) +{ + const char *end=0; + cJSON *c=cJSON_New_Item(); + ep=0; + if (!c) return 0; /* memory fail */ + + end=parse_value(c,skip(value)); + if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} + if (return_parse_end) *return_parse_end=end; + return c; +} +/* Default options for cJSON_Parse */ +cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} + +/* Render a cJSON item/entity/structure to text. */ +char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} +char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} + +char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) +{ + printbuffer p; + p.buffer=(char*)cJSON_malloc(prebuffer); + p.length=prebuffer; + p.offset=0; + return print_value(item,0,fmt,&p); + return p.buffer; +} + + +/* Parser core - when encountering text, process appropriately. */ +static const char *parse_value(cJSON *item,const char *value) +{ + if (!value) return 0; /* Fail on null. */ + if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } + if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } + if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } + if (*value=='\"') { return parse_string(item,value); } + if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } + if (*value=='[') { return parse_array(item,value); } + if (*value=='{') { return parse_object(item,value); } + + ep=value;return 0; /* failure. */ +} + +/* Render a value to text. */ +static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char *out=0; + if (!item) return 0; + if (p) + { + switch ((item->type)&255) + { + case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} + case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} + case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} + case cJSON_Number: out=print_number(item,p);break; + case cJSON_String: out=print_string(item,p);break; + case cJSON_Array: out=print_array(item,depth,fmt,p);break; + case cJSON_Object: out=print_object(item,depth,fmt,p);break; + } + } + else + { + switch ((item->type)&255) + { + case cJSON_NULL: out=cJSON_strdup("null"); break; + case cJSON_False: out=cJSON_strdup("false");break; + case cJSON_True: out=cJSON_strdup("true"); break; + case cJSON_Number: out=print_number(item,0);break; + case cJSON_String: out=print_string(item,0);break; + case cJSON_Array: out=print_array(item,depth,fmt,0);break; + case cJSON_Object: out=print_object(item,depth,fmt,0);break; + } + } + return out; +} + +/* Build an array from input text. */ +static const char *parse_array(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='[') {ep=value;return 0;} /* not an array! */ + + item->type=cJSON_Array; + value=skip(value+1); + if (*value==']') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_value(child,skip(value+1))); + if (!value) return 0; /* memory fail */ + } + + if (*value==']') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an array to text */ +static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char **entries; + char *out=0,*ptr,*ret;int len=5; + cJSON *child=item->child; + int numentries=0,i=0,fail=0; + size_t tmplen=0; + + /* How many entries in the array? */ + while (child) numentries++,child=child->next; + /* Explicitly handle numentries==0 */ + if (!numentries) + { + if (p) out=ensure(p,3); + else out=(char*)cJSON_malloc(3); + if (out) strcpy(out,"[]"); + return out; + } + + if (p) + { + /* Compose the output array. */ + i=p->offset; + ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; + child=item->child; + while (child && !fail) + { + print_value(child,depth+1,fmt,p); + p->offset=update(p); + if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} + child=child->next; + } + ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; + out=(p->buffer)+i; + } + else + { + /* Allocate an array to hold the values for each */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + /* Retrieve all the results: */ + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt,0); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; + } + + /* If we didn't fail, try to malloc the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + /* If that fails, we fail. */ + if (!out) fail=1; + + /* Handle failure. */ + if (fail) + { + for (i=0;itype=cJSON_Object; + value=skip(value+1); + if (*value=='}') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; + value=skip(parse_string(child,skip(value))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_string(child,skip(value+1))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + } + + if (*value=='}') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an object to text. */ +static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char **entries=0,**names=0; + char *out=0,*ptr,*ret,*str;int len=7,i=0,j; + cJSON *child=item->child; + int numentries=0,fail=0; + size_t tmplen=0; + /* Count the number of entries. */ + while (child) numentries++,child=child->next; + /* Explicitly handle empty object case */ + if (!numentries) + { + if (p) out=ensure(p,fmt?depth+4:3); + else out=(char*)cJSON_malloc(fmt?depth+4:3); + if (!out) return 0; + ptr=out;*ptr++='{'; + if (fmt) {*ptr++='\n';for (i=0;ioffset; + len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; + *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; + child=item->child;depth++; + while (child) + { + if (fmt) + { + ptr=ensure(p,depth); if (!ptr) return 0; + for (j=0;joffset+=depth; + } + print_string_ptr(child->string,p); + p->offset=update(p); + + len=fmt?2:1; + ptr=ensure(p,len); if (!ptr) return 0; + *ptr++=':';if (fmt) *ptr++='\t'; + p->offset+=len; + + print_value(child,depth,fmt,p); + p->offset=update(p); + + len=(fmt?1:0)+(child->next?1:0); + ptr=ensure(p,len+1); if (!ptr) return 0; + if (child->next) *ptr++=','; + if (fmt) *ptr++='\n';*ptr=0; + p->offset+=len; + child=child->next; + } + ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; + if (fmt) for (i=0;ibuffer)+i; + } + else + { + /* Allocate space for the names and the objects */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + names=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!names) {cJSON_free(entries);return 0;} + memset(entries,0,sizeof(char*)*numentries); + memset(names,0,sizeof(char*)*numentries); + + /* Collect all the results into our arrays: */ + child=item->child;depth++;if (fmt) len+=depth; + while (child && !fail) + { + names[i]=str=print_string_ptr(child->string,0); + entries[i++]=ret=print_value(child,depth,fmt,0); + if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; + child=child->next; + } + + /* Try to allocate the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + if (!out) fail=1; + + /* Handle failure */ + if (fail) + { + for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} +cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} +int cJSON_HasObjectItem(cJSON *object,const char *string) { + cJSON *c=object->child; + while (c ) + { + if(cJSON_strcasecmp(c->string,string)==0){ + return 1; + } + c=c->next; + } + return 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +/* Utility for handling references. */ +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} + +/* Add item to array/object. */ +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} +void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} + +cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; + if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} +void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} + +/* Replace array/object items with new ones. */ +void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} + newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} +void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} + +/* Create basic types: */ +cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} + +/* Create Arrays: */ +cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} + +/* Duplication */ +cJSON *cJSON_Duplicate(cJSON *item,int recurse) +{ + cJSON *newitem,*cptr,*nptr=0,*newchild; + /* Bail on bad ptr */ + if (!item) return 0; + /* Create new item */ + newitem=cJSON_New_Item(); + if (!newitem) return 0; + /* Copy over all vars */ + newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; + if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} + if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} + /* If non-recursive, then we're done! */ + if (!recurse) return newitem; + /* Walk the ->next chain for the child. */ + cptr=item->child; + while (cptr) + { + newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) {cJSON_Delete(newitem);return 0;} + if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ + cptr=cptr->next; + } + return newitem; +} + +void cJSON_Minify(char *json) +{ + char *into=json; + while (*json) + { + if (*json==' ') json++; + else if (*json=='\t') json++; /* Whitespace characters. */ + else if (*json=='\r') json++; + else if (*json=='\n') json++; + else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ + else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ + else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ + else *into++=*json++; /* All other characters. */ + } + *into=0; /* and null-terminate. */ +} diff --git a/linux32/src/s2j.c b/linux32/src/s2j.c new file mode 100644 index 0000000..0ae716d --- /dev/null +++ b/linux32/src/s2j.c @@ -0,0 +1,52 @@ +/* + * This file is part of the struct2json Library. + * + * Copyright (c) 2015, Armink, + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Function: Initialize interface for this library. + * Created on: 2015-10-14 + */ + +#include +#include + +S2jHook s2jHook = { + .malloc_fn = malloc, + .free_fn = free, +}; + +/** + * struct2json library initialize + * @note It will initialize cJSON library hooks. + */ +void s2j_init(S2jHook *hook) { + /* initialize cJSON library */ + cJSON_InitHooks((cJSON_Hooks *)hook); + /* initialize hooks */ + if (hook) { + s2jHook.malloc_fn = (hook->malloc_fn) ? hook->malloc_fn : malloc; + s2jHook.free_fn = (hook->free_fn) ? hook->free_fn : free; + } else { + s2jHook.malloc_fn = malloc; + s2jHook.free_fn = free; + } +} diff --git a/log/hexdump.c b/log/hexdump.c new file mode 100644 index 0000000..0217b34 --- /dev/null +++ b/log/hexdump.c @@ -0,0 +1,326 @@ +#ifndef __KERNEL__ +#include +#include +#include +#include +#include + +#include "log.h" + +static const char hex_asc[] = "0123456789abcdef"; + +#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] +#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] + +char* IHW_bin2hex(char *p, const unsigned char *cp, int count) +{ + while (count) { + unsigned char c = *cp++; + /* put lowercase hex digits */ + *p++ = 0x20 | hex_asc[c >> 4]; + *p++ = 0x20 | hex_asc[c & 0xf]; + count--; + } + + return p; +} + +/** + * hex_to_bin - convert a hex digit to its real value + * @ch: ascii character represents hex digit + * + * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad + * input. + */ +int hex_to_bin(char ch) +{ + if((ch >= '0') && (ch <= '9')) + { + return ch - '0'; + } + + ch = tolower(ch); + + if((ch >= 'a') && (ch <= 'f')) + { + return ch - 'a' + 10; + } + + return -1; +} + +/** + * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @linebuf: where to put the converted data + * @linebuflen: total size of @linebuf, including space for terminating NUL + * @ascii: include ASCII after the hex output + * + * hex_dump_to_buffer() works on one "line" of output at a time, i.e., + * 16 or 32 bytes of input data converted to hex + ASCII output. + * + * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data + * to a hex + ASCII dump at the supplied memory location. + * The converted output is always NUL-terminated. + * + * E.g.: + * hex_dump_to_buffer(frame->data, frame->len, 16, 1, + * linebuf, sizeof(linebuf), true); + * + * example output buffer: + * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO + */ +void hex_dump_to_buffer(const void* buf, int len, int rowsize, + int groupsize, char* linebuf, size_t linebuflen, + int ascii) +{ + const unsigned char* ptr = (const unsigned char *)buf; + unsigned char ch; + int j, lx = 0; + int ascii_column; + + if(rowsize != 16 && rowsize != 32) + { + rowsize = 16; + } + + if(!len) + { + goto nil; + } + + if(len > rowsize) /* limit to one line at a time */ + { + len = rowsize; + } + + if((len % groupsize) != 0) /* no mixed size output */ + { + groupsize = 1; + } + + switch(groupsize) + { + case 8: + { + const unsigned long long* ptr8 = (const unsigned long long *)buf; + int ngroups = len / groupsize; + + for(j = 0; j < ngroups; j++) + lx += snprintf(linebuf + lx, linebuflen - lx, + "%s%16.16llx", j ? " " : "", + (unsigned long long) * (ptr8 + j)); + + ascii_column = 17 * ngroups + 2; + break; + } + + case 4: + { + const unsigned int* ptr4 = (const unsigned int *)buf; + int ngroups = len / groupsize; + + for(j = 0; j < ngroups; j++) + lx += snprintf(linebuf + lx, linebuflen - lx, + "%s%8.8x", j ? " " : "", *(ptr4 + j)); + + ascii_column = 9 * ngroups + 2; + break; + } + + case 2: + { + const unsigned short* ptr2 = (const unsigned short *)buf; + int ngroups = len / groupsize; + + for(j = 0; j < ngroups; j++) + lx += snprintf(linebuf + lx, linebuflen - lx, + "%s%4.4x", j ? " " : "", *(ptr2 + j)); + + ascii_column = 5 * ngroups + 2; + break; + } + + default: + for(j = 0; (j < len) && (lx + 3) <= linebuflen; j++) + { + ch = ptr[j]; + linebuf[lx++] = hex_asc_hi(ch); + linebuf[lx++] = hex_asc_lo(ch); + linebuf[lx++] = ' '; + } + + if(j) + { + lx--; + } + + ascii_column = 3 * rowsize + 2; + break; + } + + if(!ascii) + { + goto nil; + } + + while(lx < (linebuflen - 1) && lx < (ascii_column - 1)) + { + linebuf[lx++] = ' '; + } + + for(j = 0; (j < len) && (lx + 2) < linebuflen; j++) + { + ch = ptr[j]; + linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; + } + +nil: + linebuf[lx++] = '\0'; +} + +/** + * print_hex_dump - print a text hex dump to syslog for a binary blob of data + * @level: kernel log level (e.g. KERN_DEBUG) + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @ascii: include ASCII after the hex output + * + * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump + * to the kernel log at the specified kernel log level, with an optional + * leading prefix. + * + * print_hex_dump() works on one "line" of output at a time, i.e., + * 16 or 32 bytes of input data converted to hex + ASCII output. + * print_hex_dump() iterates over the entire input @buf, breaking it into + * "line size" chunks to format and print. + * + * E.g.: + * print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, + * 16, 1, frame->data, frame->len, true); + * + * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode: + * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO + * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: + * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. + */ +void print_hex_dump(const char* prefix_str, int prefix_type, + int rowsize, int groupsize, + const void* buf, int len, int ascii) +{ + const unsigned char* ptr = (const unsigned char *)buf; + int i, remaining = len; + unsigned char linebuf[32 * 3 + 2 + 32 + 1]; + + if(rowsize != 16 && rowsize != 32) + { + rowsize = 16; + } + + for(i = 0; i < len; i += rowsize) + { + int linelen = MIN(remaining, rowsize); + remaining -= rowsize; + + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, + (char *)linebuf, sizeof(linebuf), ascii); + + switch(prefix_type) + { + case DUMP_PREFIX_ADDRESS: + print("%s%p: %s\n", + prefix_str, ptr + i, linebuf); + break; + + case DUMP_PREFIX_OFFSET: + print("%s%.8x: %s\n", prefix_str, i, linebuf); + break; + + default: + print("%s%.8x: %s\n", prefix_str, i, linebuf); + break; + } + } + + print("%s", "\n"); +} + +/** + * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) + * @buf: data blob to dump + * @len: number of bytes in the @buf + * + * Calls print_hex_dump(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ +void print_hex_dump_bytes(const char* prefix_str, int prefix_type, + const void* buf, int len) +{ + print_hex_dump(prefix_str, prefix_type, 16, 1, + buf, len, 1); +} + +const char* format_hex_buf(const char* prefix_str, int prefix_type, + int rowsize, int groupsize, + const void* buf, int len, int ascii) +{ + UT_string* pLogStr = NULL; + const char* pFormatStr; + const unsigned char* ptr = (const unsigned char *)buf; + int i, remaining = len; + unsigned char linebuf[32 * 3 + 2 + 32 + 1]; + + if(rowsize != 16 && rowsize != 32) + { + rowsize = 16; + } + + utstring_new(pLogStr); + + for(i = 0; i < len; i += rowsize) + { + int linelen = MIN(remaining, rowsize); + remaining -= rowsize; + + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, + (char *)linebuf, sizeof(linebuf), ascii); + + switch(prefix_type) + { + case DUMP_PREFIX_ADDRESS: + utstring_printf(pLogStr, "%s%p: %s\n", + prefix_str, ptr + i, linebuf); + break; + + case DUMP_PREFIX_OFFSET: + utstring_printf(pLogStr, "%s%.8x: %s\n", + prefix_str, i, linebuf); + break; + + default: + utstring_printf(pLogStr, "%s%.8x: %s\n", + prefix_str, i, linebuf); + break; + } + } + + pFormatStr = strdup(utstring_body(pLogStr)); + utstring_free(pLogStr); + + return pFormatStr; +} + +#endif diff --git a/log/log.c b/log/log.c new file mode 100644 index 0000000..bd4db80 --- /dev/null +++ b/log/log.c @@ -0,0 +1,1314 @@ +/** @file log.c + @brief 系统日志接口文件 + @version 1.0.0 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef PLATFORM_R16 +#include +#endif + +#include "log.h" +#include "smart_sound.h" +#include "inet_api.h" +#include "crypto.h" +#include "libuv_dbus.h" +#include "server_addr.h" + +#define SHOW_CONSOLE_RED ("\033[31;48m\033[1m%s\033[0m%c") +#define SHOW_CONSOLE_YELLOW ("\033[33;48m\033[1m%s\033[0m%c") +#define SHOW_CONSOLE_GREEN ("\033[32;48m\033[1m%s\033[0m%c") +#define SHOW_CONSOLE_BLUE ("\033[34;48m\033[1m%s\033[0m%c") + +#ifdef PLATFORM_CPU +#define LOG_FILE_BASEDIR (".") +#else +#define LOG_FILE_BASEDIR ("/tmp") +#endif + +#ifdef PLATFORM_R16 +#define NIC_NAME ("wlan0") +#else +#define NIC_NAME ("enp3s0") +#endif + +#define MAX_LOG_ITEM (1000) +#define MAX_LOG_FILE_SIZE (1024 * 1024) +#define LOG_PRE_SIZE (512) + +#if 0 +#define LOG_MAIL_USERNAME ("pv1_es2@hotmail.com") +#define LOG_MAIL_PASSWORD ("netEase163") +#define LOG_MAIL_SERVER ("smtp://smtp-mail.outlook.com") +#define LOG_MAIL_PORT (587) +#else +#define LOG_MAIL_USERNAME ("pv1_es2@163.com") +#define LOG_MAIL_LOGPASSWD ("netEase163") +#define LOG_MAIL_PASSWORD ("pv1Dev163") +#define LOG_MAIL_SERVER ("smtp.163.com") +#define LOG_MAIL_PORT (25) +#endif + +#define LOG_MAIL_RECEIVER ("pv1_es2@163.com") + +#define SYS_POINT_UPLOAD_TIME (600) + +typedef struct +{ + char* pDeviceId; + char savePath[MAX_PATH]; + int iMaxCacheSize; + int iEveryUploadTime; + time_t lastPostTime; + time_t lastMarkTime; + FILE* pMarkFile; + uv_rwlock_t uvRwLock; + uv_thread_t uvIOThread; +} SYSPOINT_INFO, *PSYSPOINT_INFO; + +typedef struct SYSPOINT_ITEM +{ + char* pContent; + struct SYSPOINT_ITEM *next, *prev; +} *PSYSPOINT_ITEM; + +typedef struct LOG_ITEM +{ + LOG_LEVEL level; + int isPrinted; + int isAddTags; + struct timeval timestamp; + char *pLogContent; + struct LOG_ITEM *next, *prev; +}*PLOG_ITEM; + +typedef struct LOG_BACKUP +{ + time_t timestamp; + char *plogFilePath; + char *pGzFilePath; + unsigned int sendTimes; + unsigned int tolLogs; + struct LOG_BACKUP *next, *prev; +} *PLOG_BACKUP; + +typedef struct +{ + pid_t pid; + char* pChipId; + char* pChipSerial; + char exeName[MAX_PATH]; + char logFilePath[MAX_PATH]; + FILE *pLogFile; +} LOG_PROCESS_INFO, *PLOG_PROCESS_INFO; + +static int g_bEnableLog = TRUE; // 是否启用 Log 功能 +static int g_bEnMailBackup = FALSE; +static char* g_pEmailBox = NULL; +static int g_bEnLogToFile = TRUE; +static int g_bEnLogToServer = TRUE; +static char g_strLogTag[32]; // Log 标志 +static unsigned int g_LogRdPos = 0; +static pthread_t g_logThreadId; +static pthread_t g_backupThreadId; +static LOG_PROCESS_INFO g_LogProcessInfo; +static uv_rwlock_t g_uvLogLock; +static uv_rwlock_t g_uvLogBackLock; +static PLOG_ITEM g_pLogItemList = NULL; +static PLOG_BACKUP g_pLogBackupList = NULL; +static int g_logSock = -1; +struct sockaddr_in g_logAddr; + +static SYSPOINT_INFO g_SysPonitInfo; +static PSYSPOINT_ITEM g_pSysPointArray = NULL; +static PHTTP_POST_ATTACH g_pLogParamsArray = NULL; + + +static int g_iMinLevel = LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info | LOG_Step; + +/** + * @brief Log 调试等级转字符串 + * @param level 调试等级 + * @return 调试等级对应的字符串 + */ +const char* LogLevelToStr(LOG_LEVEL level) +{ + switch(level) + { + case LOG_Test: + return "T"; + + case LOG_Info: + return "I"; + + case LOG_Call: + return "C"; + + case LOG_Debug: + return "D"; + + case LOG_Warn: + return "W"; + + case LOG_Error: + return "E"; + + case LOG_Fatal: + return "F"; + + case LOG_Step: + return "S"; + + case LOG_Devp: + return "V"; + + case LOG_Unknown: + return "U"; + + case LOG_All: + return "A"; + + default: + return "?"; + } + + return "U"; +} + +#pragma pack (push) +#pragma pack (1) +typedef struct +{ + unsigned short logSeq; + unsigned int pid; + unsigned int timeStamp; + unsigned int nanotime; + unsigned int logLevel; + char logContent[0]; +} LOG_PROTO_CONTENT, *PLOG_PROTO_CONTENT; +#pragma pack (pop) + +static struct HTTP_POST_ATTACH g_PostLogParams[] = +{ + {"CPUID", "", NULL, NULL}, + {"MAC", "", NULL, NULL}, + {"Version", "", NULL, NULL}, + {"BuildTime", "", NULL, NULL}, + {"SerialNumber", "", NULL, NULL}, + {"Datetime", "", NULL, NULL}, + {"content", "", NULL, NULL}, +}; + +static void __initPostLogParams(void) +{ + char *pMacAddr = NULL; + struct tm localTime; + time_t timeStamp = time((time_t*)NULL); + + GetShellExecResult("ifconfig wlan0 | grep HWaddr | awk \'{print $5}\'", &pMacAddr); + + localtime_r(&timeStamp, &localTime); + + strncpy(g_PostLogParams[0].keyValue, g_LogProcessInfo.pChipId, MAX_HTTP_POST_SIZE); + strncpy(g_PostLogParams[1].keyValue, (pMacAddr && strlen(pMacAddr) > 0) ? pMacAddr : "00:00:00:00:00:00", MAX_HTTP_POST_SIZE); + strncpy(g_PostLogParams[2].keyValue, GetCurrentVersion(), MAX_HTTP_POST_SIZE); + sprintf(g_PostLogParams[3].keyValue, "Build: %s %s", __DATE__, __TIME__); + strncpy(g_PostLogParams[4].keyValue, g_LogProcessInfo.pChipSerial, MAX_HTTP_POST_SIZE); + + for(int i = 0; i < sizeof(g_PostLogParams) / sizeof(g_PostLogParams[0]); i++) + { + LL_APPEND(g_pLogParamsArray, &g_PostLogParams[i]); + } + + if(pMacAddr) + { + free(pMacAddr); + } +} + +int HttpPostLogFile(char* pSession) +{ + int ret; + struct tm localTime; + const char* pFileName = "/tmp/backuplog.tar.gz"; + const char* pLastFile = "/mnt/UDISK/backuplog_nand.tar.gz"; + char* pLogServerURL = GetCurServerAddr(LOG_MODULE); + time_t timeStamp = time((time_t*)NULL); + + ret = system(" /usr/sbin/backuplocalfiles.sh"); + + if(access(pFileName, F_OK) != 0 + && access(pLastFile, F_OK) != 0) + { + return -ERR_FILE_NOT_EXISTS; + } + + localtime_r(&timeStamp, &localTime); + + memset(g_PostLogParams[5].keyValue, 0, MAX_HTTP_POST_SIZE); + sprintf(g_PostLogParams[5].keyValue, "%04u-%02u-%02u %02u:%02u:%02u", + localTime.tm_year + 1900, + localTime.tm_mon + 1, + localTime.tm_mday, + localTime.tm_hour, + localTime.tm_min, + localTime.tm_sec); + + memset(g_PostLogParams[6].keyValue, 0, MAX_HTTP_POST_SIZE); + + if(pSession && strlen(pSession) >= 2) + { + strncpy(g_PostLogParams[6].keyValue, pSession, MAX_HTTP_POST_SIZE); + } + else + { + strncpy(g_PostLogParams[6].keyValue, "{}", MAX_HTTP_POST_SIZE); + } + + if(access(pFileName, F_OK) == 0) + { + ret = InetHttpUploadFileSync(pLogServerURL, pFileName, g_pLogParamsArray); + + if(ret == 0) + { + LOG_EX(LOG_Debug, "Upload Log Data [%s] To Server [%s]\n", pFileName, pLogServerURL); + unlink(pFileName); + } + else + { + LOG_EX(LOG_Error, "Upload Log Data [%s] To Server [%s]\n", pFileName, pLogServerURL); + } + } + + if(access(pLastFile, F_OK) == 0) + { + ret = InetHttpUploadFileSync(pLogServerURL, pLastFile, g_pLogParamsArray); + + if(ret == 0) + { + LOG_EX(LOG_Debug, "Upload Log Data [%s] To Server [%s]\n", pLastFile, pLogServerURL); + unlink(pLastFile); + } + else + { + LOG_EX(LOG_Error, "Upload Log Data [%s] To Server [%s]\n", pLastFile, pLogServerURL); + } + } + + //fprintf(stdout, "Upload Log Data [%s] To Server [%s], size = %d\n", pFileName, UPL_HTTP_URL, fileSize); + + return ret; +} + +static int __logNetworkSend(PLOG_ITEM pItem) +{ + PLOG_PROTO_CONTENT pLogInfo; + unsigned char *pBuf; + int ret, totalSize = 0; + static unsigned short sendSeq = 0; + + if(pItem == NULL || pItem->pLogContent == NULL || strlen(pItem->pLogContent) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + totalSize = sizeof(LOG_PROTO_CONTENT) + strlen(pItem->pLogContent); + + pBuf = (unsigned char *)malloc(totalSize); + + if(pBuf == NULL) + { + return (-ERR_MALLOC_MEMORY); + } + + memset(pBuf, 0, totalSize); + + pLogInfo = (PLOG_PROTO_CONTENT)pBuf; + + pLogInfo->logSeq = htons(sendSeq++); + pLogInfo->timeStamp = htonl(pItem->timestamp.tv_sec); + pLogInfo->nanotime = htonl(pItem->timestamp.tv_usec); + pLogInfo->pid = htonl(g_LogProcessInfo.pid); + pLogInfo->logLevel = htonl(pItem->level); + + memcpy(pLogInfo->logContent, pItem->pLogContent, strlen(pItem->pLogContent)); + + ret = sendto(g_logSock, pBuf, totalSize, 0, + (struct sockaddr *)&g_logAddr, sizeof(g_logAddr)); + + if(ret == totalSize) + { + return (0); + } + else + { + //LOG_EX(LOG_Error, "Send %d bytes, need %d bytes\n", ret, totalSize); + return (-ERR_NETWORK_SEND); + } +} + +static void __cleanupBackupItem(PLOG_BACKUP pItem) +{ + if(pItem) + { + LL_DELETE(g_pLogBackupList, pItem); + + if(pItem->plogFilePath) + { + if(access(pItem->plogFilePath, F_OK) == 0) + { + unlink(pItem->plogFilePath); + } + + free(pItem->plogFilePath); + } + + if(pItem->pGzFilePath) + { + if(access(pItem->pGzFilePath, F_OK) == 0) + { + unlink(pItem->pGzFilePath); + } + + free(pItem->pGzFilePath); + } + + free(pItem); + } +} + +static void* __uvLogBackupProc(void *pParams) +{ + SMTP_MAIL_CONFIG smtpCfg; + char gzLogPath[MAX_PATH]; + struct tm localTime; + const char *pFrom = LOG_MAIL_USERNAME; + const char *pTo[] = {g_pEmailBox, NULL}; + char *pMacAddr = NULL; + + //const char *pCc[] = {"xajhuang@qq.com", "xajhuang@163.com", NULL}; + + memset(&smtpCfg, 0, sizeof(SMTP_MAIL_CONFIG)); + + smtpCfg.pUserName = LOG_MAIL_USERNAME; + smtpCfg.pPassword = LOG_MAIL_PASSWORD; + smtpCfg.pSmtpServer = LOG_MAIL_SERVER; + smtpCfg.smtpPort = LOG_MAIL_PORT; + +#ifdef PLATFORM_CPU + GetShellExecResult("ifconfig enp3s0 | grep HWaddr | awk \'{print $5}\'", &pMacAddr); +#else + GetShellExecResult("ifconfig wlan0 | grep HWaddr | awk \'{print $5}\'", &pMacAddr); +#endif + + if(pMacAddr == NULL || strlen(pMacAddr) == 0) + { + pMacAddr = strdup("00:00:00:00:00:00"); + } + + while(TRUE) + { + PLOG_BACKUP pItem = NULL, pTmp = NULL; + time_t timeStamp = time((time_t*)NULL); + localtime_r(&timeStamp, &localTime); + + uv_rwlock_wrlock(&g_uvLogBackLock); + + LL_FOREACH_SAFE(g_pLogBackupList, pItem, pTmp) + { + const char *pAttact[2]; + UT_string *pTitle, *pMessage, *pDatetime; + char* pMD5Val; + + pAttact[1] = NULL; + + if(pItem->plogFilePath == NULL || strlen(pItem->plogFilePath) == 0) + { + __cleanupBackupItem(pItem); + continue; + } + + if(timeStamp - pItem->timestamp >= 3600) + { + __cleanupBackupItem(pItem); + continue; + } + + if(pItem->sendTimes >= 3) + { + __cleanupBackupItem(pItem); + continue; + } +#if 0 + if(g_bEnLogToServer) + { + __logHttpPostFile(pItem->plogFilePath); + //InetHttpUploadFileSync(UPL_HTTP_URL, pItem->pGzFilePath, NULL); + } +#endif + if(pItem->pGzFilePath == NULL) + { + memset(gzLogPath, 0, MAX_PATH); + sprintf(gzLogPath, "%s/%d_%s_%u.log.gz", + LOG_FILE_BASEDIR, g_LogProcessInfo.pid, g_LogProcessInfo.exeName, pItem->tolLogs); + + if(GZipFileCompress(pItem->plogFilePath, gzLogPath) != 0) + { + LOG_EX(LOG_Error, "Create Gzip File Error: %s\n", gzLogPath); + continue; + } + else + { + pItem->pGzFilePath = strdup(gzLogPath); + } + } + + pMD5Val = (char*)EvpMD5HashFile(pItem->pGzFilePath); + + utstring_new(pTitle); + utstring_new(pMessage); + utstring_new(pDatetime); + + utstring_printf(pDatetime, "%04u-%02u-%02u %02u:%02u:%02u", + localTime.tm_year + 1900, + localTime.tm_mon + 1, + localTime.tm_mday, + localTime.tm_hour, + localTime.tm_min, + localTime.tm_sec); + + utstring_printf(pTitle, "Log [%s]-[%s]-[%s]", + g_LogProcessInfo.exeName, + g_LogProcessInfo.pChipSerial, + utstring_body(pDatetime)); + + utstring_printf(pMessage, "\r\n" + "

Summary information:

" + "


" + "

" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
Items
%u
Process PID
%d
Process Name
%s
CPU ID
%s
Serial
%s
Mac Address
%s
File Checksum
%s
Log Level
0x%08X
Datetime
%s
" + "

" + "\r\n", + pItem->tolLogs, + g_LogProcessInfo.pid, + g_LogProcessInfo.exeName, + g_LogProcessInfo.pChipId, + g_LogProcessInfo.pChipSerial, + pMacAddr, + SAFE_STRING_VALUE(pMD5Val), + g_iMinLevel, + utstring_body(pDatetime)); + + pAttact[0] = pItem->pGzFilePath; +#if 0 + if(g_bEnMailBackup && + InetSmtpSendEmail(pFrom, pTo, NULL, utstring_body(pTitle), + utstring_body(pMessage), pAttact, &smtpCfg) == 0) + { + __cleanupBackupItem(pItem); + } + else + { + LOG_EX(LOG_Error, "Send email error: %s\n", pItem->pGzFilePath); + } +#endif + pItem->sendTimes++; + + if(pMD5Val) + { + free(pMD5Val); + } + + utstring_free(pTitle); + utstring_free(pMessage); + utstring_free(pDatetime); + } + + uv_rwlock_wrunlock(&g_uvLogBackLock); + + sleep(1); + } + + free(pMacAddr); + pthread_detach(pthread_self()); + return (NULL); +} + +static void __logColorOutput(const char* pColFmt, UT_string* pLog) +{ + if(pLog == NULL) + { + return; + } + + if(pColFmt == NULL) + { + print("%s", utstring_body(pLog)); + } + else + { + if(utstring_find(pLog, -1, "\n", 1) == utstring_len(pLog) - 1) + { + char* pLogArray = utstring_body(pLog); + pLogArray[utstring_len(pLog) - 1] = 0; + + print(pColFmt, pLogArray, '\n'); + + strcat(pLogArray, "\n"); + } + else + { + print(pColFmt, utstring_body(pLog), '\0'); + } + } +} + +static void* __logOutputThread(void *p) +{ + while(TRUE) + { + int isWriteLog = FALSE; + PLOG_ITEM pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvLogLock); + + LL_FOREACH_SAFE(g_pLogItemList, pItem, pTmp) + { + UT_string *pLogStr; + struct tm lTime; + int logFileSize = 0; + + if(++g_LogRdPos % 100 == 0) + { + GET_FILE_SIZE(g_LogProcessInfo.logFilePath, logFileSize); + } + + localtime_r(&(pItem->timestamp.tv_sec), &lTime); + + utstring_new(pLogStr); + + if(pItem->isAddTags) + { + utstring_printf(pLogStr, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld] [%s] %s", + lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday, + lTime.tm_hour, lTime.tm_min, lTime.tm_sec, pItem->timestamp.tv_usec / 1000, + LogLevelToStr(pItem->level), pItem->pLogContent); + } + else + { + utstring_printf(pLogStr, "%s", pItem->pLogContent); + } + + if(pItem->isPrinted == FALSE) + { + if(pItem->level & LOG_Error + || pItem->level & LOG_Fatal) + { + __logColorOutput(SHOW_CONSOLE_RED, pLogStr); + } + else if(pItem->level & LOG_Warn + || pItem->level & LOG_Unknown) + { + __logColorOutput(SHOW_CONSOLE_YELLOW, pLogStr); + } + else if(pItem->level & LOG_Test + || pItem->level & LOG_Call) + { + __logColorOutput(SHOW_CONSOLE_BLUE, pLogStr); + } + else if(pItem->level & LOG_Devp) + { + __logColorOutput(SHOW_CONSOLE_GREEN, pLogStr); + } + else + { + print("%s", utstring_body(pLogStr)); + } + + pItem->isPrinted = TRUE; + } + + if(g_logSock != -1 && GetCurrWIFIConnStatus() == WIFI_CONNECTED) + { + __logNetworkSend(pItem); + } + + if(g_LogProcessInfo.pLogFile != NULL && g_bEnLogToFile) + { + if(logFileSize >= MAX_LOG_FILE_SIZE) + { + fflush(g_LogProcessInfo.pLogFile); + fclose(g_LogProcessInfo.pLogFile); +#if 0 + if(g_bEnMailBackup) + { + PLOG_BACKUP pBackup = (PLOG_BACKUP)malloc(sizeof(struct LOG_BACKUP)); + char path[MAX_PATH]; + + memset(path, 0, MAX_PATH); + sprintf(path, "%s/%s.bak_%u.log", + LOG_FILE_BASEDIR, + basename_v2(g_LogProcessInfo.logFilePath), + g_LogRdPos); + rename(g_LogProcessInfo.logFilePath, path); + + if(pBackup) + { + memset(pBackup, 0, sizeof(struct LOG_BACKUP)); + pBackup->timestamp = time(NULL); + pBackup->plogFilePath = strdup(path); + pBackup->sendTimes = 0; + pBackup->tolLogs = g_LogRdPos - 1; + + uv_rwlock_wrlock(&g_uvLogBackLock); + LL_APPEND(g_pLogBackupList, pBackup); + uv_rwlock_wrunlock(&g_uvLogBackLock); + } + } +#endif + g_LogProcessInfo.pLogFile = fopen(g_LogProcessInfo.logFilePath, "w+"); + } + + if(g_LogProcessInfo.pLogFile) + { + fwrite(utstring_body(pLogStr), 1, utstring_len(pLogStr), g_LogProcessInfo.pLogFile); + } + + isWriteLog = TRUE; + } + + LL_DELETE(g_pLogItemList, pItem); + + utstring_free(pLogStr); + free(pItem->pLogContent); + free(pItem); + + if(g_LogRdPos % 100 == 0) + { + break; + } + } + + uv_rwlock_wrunlock(&g_uvLogLock); + + usleep(1000); + if(g_LogProcessInfo.pLogFile != NULL && isWriteLog) + { + fflush(g_LogProcessInfo.pLogFile); + } + } + + pthread_detach(pthread_self()); + return (NULL); +} + +/** + * @brief 设置调试等级 + * @param level 调试等级 + * @param iEnable 1 打开调试等级, 0 关闭调试等级 + */ +void IHW_EnableLogLevel(LOG_LEVEL level, int iEnable) +{ + if(iEnable > 0) + { + g_iMinLevel |= level; + } + else + { + g_iMinLevel &= ~(level); + } +} + +static int __getCfgFromCfgFile(void) +{ + int ret = 0; + g_bEnableLog = CfgGetBoolValue("Global.Log.Enable", g_bEnableLog); + g_iMinLevel = CfgGetIntValue("Global.Log.Level", g_iMinLevel); + g_bEnMailBackup = CfgGetBoolValue("Global.Log.LogToEMail.Enable", g_bEnMailBackup); + g_pEmailBox = CfgGetStringValue("Global.Log.LogToEMail.EMail", LOG_MAIL_RECEIVER); + g_bEnLogToFile = CfgGetBoolValue("Global.Log.LogToFile", g_bEnLogToFile); + g_bEnLogToServer = CfgGetBoolValue("Global.Log.LogToServer", g_bEnLogToServer); + +#if 0 + LOG_EX(LOG_Debug, "g_bEnableLog = %d\n", g_bEnableLog); + LOG_EX(LOG_Debug, "g_iMinLevel = 0x%X\n", g_iMinLevel); + LOG_EX(LOG_Debug, "g_bEnMailBackup = %d\n", g_bEnMailBackup); + LOG_EX(LOG_Debug, "g_pEmailBox = %s\n", g_pEmailBox); + LOG_EX(LOG_Debug, "g_bEnLogToFile = %d\n", g_bEnLogToFile); + LOG_EX(LOG_Debug, "g_bEnLogToServer = %d\n", g_bEnLogToServer); +#endif + + ret = CfgGetBoolValue("Global.Log.LogToUDPServer.Enable", FALSE); + + if(ret) + { + char *pIpAddr = NULL; + int udpPortBase = CfgGetBoolValue("Global.Log.LogToUDPServer.UdpBasePort", 10000); + int port = udpPortBase + DBusLibGetModName(); + + if(g_logSock != -1) + { + close(g_logSock); + g_logSock = -1; + } + + pIpAddr = CfgGetStringValue("Global.Log.LogToUDPServer.UdpServerIp", NULL); + + LOG_EX(LOG_Debug, "UDP Ipaddr = %s, port = %d\n", pIpAddr, port); + + if(pIpAddr) + { + memset(&g_logAddr, 0, sizeof(g_logAddr)); + g_logAddr.sin_family = AF_INET; + g_logAddr.sin_port = htons(port); + g_logAddr.sin_addr.s_addr = inet_addr(pIpAddr); + + g_logSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + } + } +} +/** + * @brief 初始化系统日志功能 + * @param pLogTag 系统日志标志 + * @param pPath 系统日志保存路径 + * @param bEnable 打开/关闭调试信息 + */ +void IHW_InitLOG(const char* pLogTag, const char* pPath, int bEnable) +{ + int ret; + char strPath[MAX_PATH]; + + memset(&g_logAddr, 0, sizeof(g_logAddr)); + uv_rwlock_init(&g_uvLogLock); + g_LogRdPos = 0; + memset(g_strLogTag, 0, 32); + + memset(&g_LogProcessInfo, 0, sizeof(LOG_PROCESS_INFO)); + + if(pLogTag == NULL) + { + strcpy(g_strLogTag, ""); + } + else + { + strncpy(g_strLogTag, pLogTag, 31); + } + + memset(strPath, 0, MAX_PATH); + + g_LogProcessInfo.pid = getpid(); + if(readlink("/proc/self/exe", strPath, MAX_PATH) == -1) + { + strcpy(g_LogProcessInfo.exeName, pLogTag); + } + else + { + char *pExeName = strrchr(strPath, '/'); + + if(pExeName == NULL) + { + strncpy(g_LogProcessInfo.exeName, strPath, MAX_PATH - 1); + } + else + { + strncpy(g_LogProcessInfo.exeName, pExeName + 1, MAX_PATH - 1); + } + } + + //fprintf(stdout, "pid = %d, name = %s\n", g_LogProcessInfo.pid, g_LogProcessInfo.exeName); + g_LogProcessInfo.pChipId = GetCpuChipId(); + g_LogProcessInfo.pChipSerial = GetCpuSerial(); + memset(g_LogProcessInfo.logFilePath, 0, MAX_PATH); + sprintf(g_LogProcessInfo.logFilePath, "%s/%s_%d.log", LOG_FILE_BASEDIR, g_LogProcessInfo.exeName, g_LogProcessInfo.pid); + + memset(strPath, 0, MAX_PATH); + sprintf(strPath, "rm -f %s/%s_*.log > /dev/zero", LOG_FILE_BASEDIR, g_LogProcessInfo.exeName); + ret = system(strPath); + + g_LogProcessInfo.pLogFile = fopen(g_LogProcessInfo.logFilePath, "w+"); + + g_bEnableLog = bEnable; + + __getCfgFromCfgFile(); + +#if 0 + LOG_CFG_PROTOCOL logCfg; + + memset(&logCfg, 0, sizeof(LOG_CFG_PROTOCOL)); + logCfg.cfgCmd = CMD_LOG_NETWORK; + logCfg.iParams1 = inet_addr("10.240.84.163"); + logCfg.iParams2 = htons(10000); + UpgradLogConfigure(&logCfg); +#endif + + __initPostLogParams(); +} + +void IHW_RunLogService(void) +{ + pthread_create(&g_logThreadId, NULL, __logOutputThread, NULL); + pthread_create(&g_backupThreadId, NULL, __uvLogBackupProc, NULL); +} + +static void __logTo(LOG_LEVEL level, int isAddTag, char* pMsg, int isPrint) +{ + PLOG_ITEM pLogItem; + + pLogItem = (PLOG_ITEM)malloc(sizeof(struct LOG_ITEM)); + + if(pLogItem == NULL) + { + return; + } + + pLogItem->pLogContent = strdup(pMsg); + pLogItem->isPrinted = isPrint ? FALSE : TRUE; + pLogItem->level = level; + pLogItem->isAddTags = isAddTag ? TRUE : FALSE; + gettimeofday(&(pLogItem->timestamp), NULL); + + uv_rwlock_wrlock(&g_uvLogLock); + LL_APPEND(g_pLogItemList, pLogItem); + uv_rwlock_wrunlock(&g_uvLogLock); +} + +void IHW_LogStrWithoutPrint(int level, char* pMsg) +{ + __logTo(level, TRUE, pMsg, FALSE); +} + +void IHW_LogRawString(int level, char* pMsg) +{ + __logTo(level, TRUE, pMsg, TRUE); +} + +/** + * @brief 输出调试信息 + * @param cFlag 调试信息开关 + * @param pMsg 调试信息内容 + */ +void IHW_LOG_UNTAG(LOG_LEVEL level, const char* pMsg, ...) +{ + va_list arg_ptr; + UT_string *pLogContent; + + if(!g_bEnableLog) + { + return; + } + + // 检查调试等级 + if(!(g_iMinLevel & level)) + { + return; + } + + utstring_new(pLogContent); + va_start(arg_ptr, pMsg); + utstring_printf_va(pLogContent, pMsg, arg_ptr); + va_end(arg_ptr); + + __logTo(level, FALSE, utstring_body(pLogContent), TRUE); + + utstring_free(pLogContent); +} + +/** + * @brief 输出调试信息 + * @param cFlag 调试信息开关 + * @param pMsg 调试信息内容 + */ +void IHW_LOG(LOG_LEVEL level, const char* pMsg, ...) +{ + UT_string* pLogContent = NULL; + va_list arg_ptr; + + if(!g_bEnableLog) + { + return; + } + + // 检查调试等级 + if(!(g_iMinLevel & level)) + { + return; + } + + utstring_new(pLogContent); + va_start(arg_ptr, pMsg); + utstring_printf_va(pLogContent, pMsg, arg_ptr); + va_end(arg_ptr); + + __logTo(level, TRUE, utstring_body(pLogContent), TRUE); + + utstring_free(pLogContent); +} + +void IHW_DisableLogOut(void) +{ + g_bEnableLog = FALSE; +} + +void IHW_EnableLogOut(void) +{ + g_bEnableLog = TRUE; +} + +#if 0 +void LogUploadCurLogFile(void) +{ + UT_string *pFn = NULL, *pCmd = NULL; + utstring_new(pFn); + utstring_new(pCmd); + + utstring_printf(pFn, "/tmp/%s_%s.bak.log", g_LogProcessInfo.exeName, g_LogProcessInfo.pChipId); + utstring_printf(pCmd, "cp %s %s", g_LogProcessInfo.logFilePath, utstring_body(pFn)); + + __logHttpPostFile(utstring_body(pFn)); + //InetHttpUploadFileSync(UPL_HTTP_URL, utstring_body(pFn), NULL); + + utstring_free(pFn); + utstring_free(pCmd); +} +#endif + +#if 0 +void UploadLogFile(char* pFilePath) +{ + int fileSize = 0; + + if(pFilePath == NULL || strlen(pFilePath) == 0) + { + return; + } + + GET_FILE_SIZE(pFilePath, fileSize); + + if(fileSize <= 0) + { + LOG_EX(LOG_Warn, "File Size Error: %d\n", fileSize); + return; + } + + __logHttpPostFile(pFilePath); +} +#endif + +void UpgradLogConfigure(PLOG_CFG_PROTOCOL pCfg) +{ + switch(pCfg->cfgCmd) + { + case CMD_LOG_ENABLE: + g_bEnableLog = pCfg->iParams1; + break; + + case CMD_LOG_FILE: + if(pCfg->iParams1 == FALSE) + { + g_bEnMailBackup = g_bEnLogToFile = FALSE; + } + else + { + g_bEnLogToFile = TRUE; + } + break; + + case CMD_LOG_MAIL: + g_bEnMailBackup = pCfg->iParams1; + break; + + case CMD_LOG_LEVEL: + if(pCfg->iParams2 == FALSE) + { + if(pCfg->iParams1 == 0) + { + g_iMinLevel = LOG_Fatal | LOG_Error | LOG_Devp; + } + else + { + g_iMinLevel &= ~(pCfg->iParams1); + } + } + else + { + g_iMinLevel |= pCfg->iParams1; + } + break; + + case CMD_LOG_NETWORK: + if(pCfg->iParams1 == 0) + { + memset(&g_logAddr, 0, sizeof(g_logAddr)); + close(g_logSock); + g_logSock = -1; + } + else + { + if(g_logSock != -1) + { + close(g_logSock); + } + + memset(&g_logAddr, 0, sizeof(g_logAddr)); + g_logAddr.sin_family = AF_INET; + g_logAddr.sin_port = htons((pCfg->iParams2 & 0xFFFF)); + g_logAddr.sin_addr.s_addr = (pCfg->iParams1); + + g_logSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + } + break; + + case CMD_LOG_SERVER: + g_bEnLogToServer = pCfg->iParams1; + break; + + default: break; + } +} + +const char* LogLeveToString(LOG_LEVEL lv) +{ + switch(lv) + { + case LOG_Fatal: return "LOG_Fatal"; + case LOG_Error: return "LOG_Error"; + case LOG_Warn: return "LOG_Warn"; + case LOG_Debug: return "LOG_Debug"; + case LOG_Info: return "LOG_Info"; + case LOG_Test: return "LOG_Test"; + case LOG_Call: return "LOG_Call"; + case LOG_Devp: return "LOG_Devp"; + case LOG_Step: return "LOG_Step"; + case LOG_Unknown: return "LOG_Unknown"; + case LOG_All: return "LOG_All"; + case LOG_Close: return "LOG_Close"; + } + + return "Unknown"; +} + +static void __uvSysPointIOProc(void *pParams) +{ + while(TRUE) + { + PSYSPOINT_ITEM pItem = NULL, pTmp = NULL; + int iFileSize; + time_t tmNow = time(NULL); + + if(g_SysPonitInfo.pMarkFile) + { + uv_rwlock_wrlock(&g_SysPonitInfo.uvRwLock); + LL_FOREACH_SAFE(g_pSysPointArray, pItem, pTmp) + { + fwrite(pItem->pContent, 1, strlen(pItem->pContent), g_SysPonitInfo.pMarkFile); + free(pItem->pContent); + LL_DELETE(g_pSysPointArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_SysPonitInfo.uvRwLock); + } + + GET_FILE_SIZE(g_SysPonitInfo.savePath, iFileSize); + + if(g_SysPonitInfo.lastPostTime == 0 || tmNow < g_SysPonitInfo.lastPostTime) + { + g_SysPonitInfo.lastPostTime = g_SysPonitInfo.lastMarkTime = tmNow; + tmNow = 0; + } +#if 0 + LOG_EX(LOG_Debug, "iFile = %d, MaxSize = %d, upTime = %d\n", + iFileSize, g_SysPonitInfo.iMaxCacheSize, g_SysPonitInfo.iEveryUploadTime); + + LOG_EX(LOG_Debug, "tm = %d, last = %d\n", tmNow, g_SysPonitInfo.lastPostTime); +#endif + if(iFileSize > g_SysPonitInfo.iMaxCacheSize + || tmNow - g_SysPonitInfo.lastPostTime > g_SysPonitInfo.iEveryUploadTime) + { + int fileSize = 0; + + GET_FILE_SIZE(g_SysPonitInfo.savePath, fileSize); + + if(fileSize > 0) + { + SysPointMarkUpload(); + g_SysPonitInfo.lastPostTime = tmNow; + } + + if(tmNow - g_SysPonitInfo.lastPostTime > g_SysPonitInfo.iEveryUploadTime) + { + SysPointMarkUpload(); + g_SysPonitInfo.lastPostTime = tmNow; + } + } + + if(g_SysPonitInfo.pMarkFile) + { + fflush(g_SysPonitInfo.pMarkFile); + } + + sleep(1); + } + + pthread_detach(pthread_self()); +} + +int SysPointMarkInit(char* pDevId, int iMaxSize, int iPostTime) +{ + LOG_EX(LOG_Debug, "pDevId = %s, iMaxSize = %d, iPostTime = %d\n", pDevId, iMaxSize, iPostTime); + + if(g_SysPonitInfo.pDeviceId != NULL) + { + if(pDevId && strlen(pDevId) > 0) + { + free(g_SysPonitInfo.pDeviceId); + g_SysPonitInfo.pDeviceId = strdup(pDevId); + } + + if(iMaxSize > 0) + { + g_SysPonitInfo.iMaxCacheSize = iMaxSize; + } + else + { + g_SysPonitInfo.iMaxCacheSize = 1024 * 10; + } + + if(iPostTime > 0) + { + g_SysPonitInfo.iEveryUploadTime = iPostTime; + } + else + { + g_SysPonitInfo.iEveryUploadTime = SYS_POINT_UPLOAD_TIME; + } + } + else + { + memset(&g_SysPonitInfo, 0, sizeof(SYSPOINT_INFO)); + + if(pDevId && strlen(pDevId) > 0) + { + g_SysPonitInfo.pDeviceId = strdup(pDevId); + } + + if(iMaxSize > 0) + { + g_SysPonitInfo.iMaxCacheSize = iMaxSize; + } + else + { + g_SysPonitInfo.iMaxCacheSize = 1024 * 1024; + } + + if(iPostTime > 0) + { + g_SysPonitInfo.iEveryUploadTime = iPostTime; + } + else + { + g_SysPonitInfo.iEveryUploadTime = SYS_POINT_UPLOAD_TIME; + } + + sprintf(g_SysPonitInfo.savePath, "%s/sys_point_mark.log", LOG_FILE_BASEDIR); + + g_SysPonitInfo.pMarkFile = fopen(g_SysPonitInfo.savePath, "w+"); + + if(g_SysPonitInfo.pMarkFile == NULL) + { + LOG_EX(LOG_Error, "Create File: %s Error\n", g_SysPonitInfo.savePath); + return -ERR_OPEN_FILE; + } + + uv_rwlock_init(&g_SysPonitInfo.uvRwLock); + + uv_thread_create(&g_SysPonitInfo.uvIOThread, __uvSysPointIOProc, NULL); + } + + return 0; +} + +int SysPointMark(char* pMarkInfo) +{ + PSYSPOINT_ITEM pItem; + + if(pMarkInfo == NULL || strlen(pMarkInfo) == 0) + { + return -ERR_INPUT_PARAMS; + } + + if(g_SysPonitInfo.iMaxCacheSize <= 0) + { + return -ERR_UNSUPPORT; + } + + pItem = (PSYSPOINT_ITEM)malloc(sizeof(struct SYSPOINT_ITEM)); + + if(pItem == NULL) + { + return -ERR_MALLOC_MEMORY; + } + + pItem->pContent = strdup(pMarkInfo); + g_SysPonitInfo.lastMarkTime = time(NULL); + + uv_rwlock_wrlock(&g_SysPonitInfo.uvRwLock); + LL_APPEND(g_pSysPointArray, pItem); + uv_rwlock_wrunlock(&g_SysPonitInfo.uvRwLock); + + //LOG_EX(LOG_Debug, "SysMark: %s\n", pItem->pContent); + + return 0; +} + +int SysPointMarkUpload(void) +{ + char path[MAX_PATH]; + + memset(path, 0, MAX_PATH); + sprintf(path, "%s.txt", g_SysPonitInfo.savePath); + + if(access(path, F_OK) == 0) + { + unlink(path); + } + + rename(g_SysPonitInfo.savePath, path); + + fclose(g_SysPonitInfo.pMarkFile); + g_SysPonitInfo.pMarkFile = fopen(g_SysPonitInfo.savePath, "w+"); + + InetHttpUploadFileSync(GetCurServerAddr(MARK_POINT_MODULE), path, NULL); + LOG_EX(LOG_Debug, "Upload System Mark Data [%s] To Server [%s]\n", path, GetCurServerAddr(MARK_POINT_MODULE)); + + unlink(path); +} +