From b8320cc85af29d7a3095f3992cfbb739992f855c Mon Sep 17 00:00:00 2001 From: HuangXin Date: Tue, 18 Sep 2018 16:09:12 +0800 Subject: [PATCH] Change Project Structs --- 3partys/allwinner/libpv1comm-linux.so | Bin 0 -> 131024 bytes 3partys/allwinner/libpv1comm-r16.so | Bin 0 -> 97424 bytes 3partys/allwinner/libpv1comm-r311.so | Bin 0 -> 97376 bytes Example/main.c | 11 +- Framework/Fifo/fifo.c | 554 ------ Framework/Network/inet_api.c | 1396 -------------- Framework/Skins/skin_res_vtbl.c | 320 ---- Framework/Skins/skins.c | 40 +- Framework/Timer/timer.c | 772 -------- Framework/libuvEngine/libcomm.c | 505 ++++++ Framework/libuvEngine/libuv_dbus.c | 2405 ------------------------- build/Makefile.app.cross | 2 +- build/Makefile.def.cross | 6 +- build/Makefile.lib.cross | 40 +- include/skins_res.h | 24 +- log/hexdump.c | 326 ---- log/log.c | 1332 -------------- log/mark_point.c | 270 +++ 18 files changed, 864 insertions(+), 7139 deletions(-) create mode 100755 3partys/allwinner/libpv1comm-linux.so create mode 100755 3partys/allwinner/libpv1comm-r16.so create mode 100755 3partys/allwinner/libpv1comm-r311.so delete mode 100644 Framework/Fifo/fifo.c delete mode 100644 Framework/Network/inet_api.c delete mode 100644 Framework/Skins/skin_res_vtbl.c delete mode 100644 Framework/Timer/timer.c create mode 100644 Framework/libuvEngine/libcomm.c delete mode 100644 Framework/libuvEngine/libuv_dbus.c delete mode 100644 log/hexdump.c delete mode 100644 log/log.c create mode 100644 log/mark_point.c diff --git a/3partys/allwinner/libpv1comm-linux.so b/3partys/allwinner/libpv1comm-linux.so new file mode 100755 index 0000000000000000000000000000000000000000..84eaf58fce3c4cca4cc7406ef8ee0951eedba552 GIT binary patch literal 131024 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 literal 0 HcmV?d00001 diff --git a/3partys/allwinner/libpv1comm-r16.so b/3partys/allwinner/libpv1comm-r16.so new file mode 100755 index 0000000000000000000000000000000000000000..521f1a092aaa97ff8f6d411d87847ef892f97b14 GIT binary patch literal 97424 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
    BlC%edJKIX_ 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 literal 0 HcmV?d00001 diff --git a/Example/main.c b/Example/main.c index 5a378ab..0e57a87 100644 --- a/Example/main.c +++ b/Example/main.c @@ -1909,7 +1909,7 @@ void test_nl80211(void) nl_recvmsgs_default(sk); } #endif - +#include int main(int argc, char **argv) { @@ -1922,7 +1922,7 @@ int main(int argc, char **argv) struct tm tm; - + memset(&tm, 0, sizeof(struct tm)); strptime("2001-11-12 18:31:01", "%Y-%m-%d %H:%M:%S", &tm); strftime(buf, sizeof(buf), "%d %b %Y %H:%M", &tm); @@ -2001,6 +2001,7 @@ int main(int argc, char **argv) return 0; } + SetHBLAutoExit(TRUE); //SysPointMarkInit(NULL, -1, -1); //test_task_new(__uvThreadSysPointUpload, NULL); @@ -2202,7 +2203,7 @@ int main(int argc, char **argv) if(modIdx == 18) { SkinInit(); - //SkinIsVerifyRes(TRUE); + SkinIsVerifyRes(TRUE); #if 0 char* path = "/mnt/UDISK/skinupgrade.txt"; char* pUpgCmd = "[{\"createTime\":1517832224000,\"enable\":1,\"id\":170," @@ -2237,8 +2238,9 @@ int main(int argc, char **argv) } #else //const char* GetSkinsResource(const char [in] *pKeyName, int [out] *pResType, int [out] *pVersion, const char [out] **pComeFrom) + //fprintf(stdout, "[v401] = {%s}\n", GetSkinsResource("v401", NULL, NULL, NULL)); +#if 0 - fprintf(stdout, "[v401] = {%s}\n", GetSkinsResource("v401", NULL, NULL, NULL)); fprintf(stdout, "[v109] = {%s}\n", GetSkinsResource("v109", NULL, NULL, NULL)); fprintf(stdout, "[v311] = {%s}\n", GetSkinsResource("v311", NULL, NULL, NULL)); fprintf(stdout, "[v401] = {%s}\n", GetSkinsResource("v401", NULL, NULL, NULL)); @@ -2253,6 +2255,7 @@ int main(int argc, char **argv) fprintf(stdout, "[v401] = {%s}\n", GetSkinsResource("v401", NULL, NULL, NULL)); test_task_new(__uvTestSkin, NULL); +#endif #endif } #endif diff --git a/Framework/Fifo/fifo.c b/Framework/Fifo/fifo.c deleted file mode 100644 index 5fd3753..0000000 --- a/Framework/Fifo/fifo.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - * 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); - -#if defined(PLATFORM_R16) || defined(PLATFORM_R311) -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/Network/inet_api.c b/Framework/Network/inet_api.c deleted file mode 100644 index ee3a9db..0000000 --- a/Framework/Network/inet_api.c +++ /dev/null @@ -1,1396 +0,0 @@ -#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(%d)\n", pURL, pPath, curl_easy_strerror(ret), 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/Skins/skin_res_vtbl.c b/Framework/Skins/skin_res_vtbl.c deleted file mode 100644 index ae30711..0000000 --- a/Framework/Skins/skin_res_vtbl.c +++ /dev/null @@ -1,320 +0,0 @@ -#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 index 2fc624b..d44b51f 100644 --- a/Framework/Skins/skins.c +++ b/Framework/Skins/skins.c @@ -354,7 +354,7 @@ static int __skinCreateCfgFile(const char* pCfgFilePath) int rc = 0; static sqlite3* pSqlFileDB = NULL; UT_string *pSqlCmd = NULL; - +#if 0 rc = sqlite3_open(":memory:", &g_pMemDb); if(rc != SQLITE_OK) @@ -377,8 +377,8 @@ static int __skinCreateCfgFile(const char* pCfgFilePath) utstring_free(pSqlCmd); return -ERR_SQLITE3_CREATE_TABLE; } - - rc = sqlite3_open_v2(pCfgFilePath, &pSqlFileDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); +#endif + rc = sqlite3_open_v2(pCfgFilePath, &pSqlFileDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE , NULL); if(rc != SQLITE_OK) { @@ -388,6 +388,8 @@ static int __skinCreateCfgFile(const char* pCfgFilePath) return -ERR_OPEN_SQLITE3_DB; } + LOG_EX(LOG_Debug, "Create Database: %s\n", pCfgFilePath); +#if 0 utstring_renew(pSqlCmd); utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL""CREATE_RES_TBL_SQL, "", ""); @@ -395,7 +397,22 @@ static int __skinCreateCfgFile(const char* pCfgFilePath) if(rc != SQLITE_OK) { - LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + LOG_EX(LOG_Error, "Create Tbl \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } +#else + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL, ""); + + rc = sqlite3_exec(pSqlFileDB, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl \n[%s]\n Error(%d): %s\n", utstring_body(pSqlCmd), rc, pErrMsg); sqlite3_free(pErrMsg); unlink(pCfgFilePath); sqlite3_close(g_pMemDb); @@ -403,6 +420,21 @@ static int __skinCreateCfgFile(const char* pCfgFilePath) return -ERR_SQLITE3_CREATE_TABLE; } + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_RES_TBL_SQL, ""); + + rc = sqlite3_exec(pSqlFileDB, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } +#endif utstring_renew(pSqlCmd); utstring_printf(pSqlCmd, UPGRADE_TBL_SQL_CMD, ""); rc = sqlite3_exec(pSqlFileDB, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); diff --git a/Framework/Timer/timer.c b/Framework/Timer/timer.c deleted file mode 100644 index 3f91d7c..0000000 --- a/Framework/Timer/timer.c +++ /dev/null @@ -1,772 +0,0 @@ -#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: - pInfo->setDateTime.tm_mon = -1; - pInfo->setDateTime.tm_year = -1; - case REPEAT_MODE_EVERY_YEAR_DAY: - pInfo->setDateTime.tm_year = -1; - 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/libuvEngine/libcomm.c b/Framework/libuvEngine/libcomm.c new file mode 100644 index 0000000..141e7fb --- /dev/null +++ b/Framework/libuvEngine/libcomm.c @@ -0,0 +1,505 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" + +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); +} + +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 +} + +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 + +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/Framework/libuvEngine/libuv_dbus.c b/Framework/libuvEngine/libuv_dbus.c deleted file mode 100644 index e73264b..0000000 --- a/Framework/libuvEngine/libuv_dbus.c +++ /dev/null @@ -1,2405 +0,0 @@ -#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)); - g_workDayArray.isReady = TRUE; - LOG_EX(LOG_Debug, "Sync Alarm Database: %s\n", pMsg->pMsg); - } - - //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 - fprintf(stdout, "Wait boot status file create ......\n"); - while(access(pBootStatFile, F_OK) != 0) - { - usleep(10000); - } - - pFile = fopen(pBootStatFile, "rb"); - - if(pFile == NULL) - { - fprintf(stdout, "Open boot status file error\n"); - return; - } - - fprintf(stdout, "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); - - fprintf(stdout, "Boot status done ......\n"); -#endif -} - -int GetServerModeFromCC(int defValue, int* pErr) -{ - char* pSvrMode = NULL; - int iValue = defValue; - - GetShellExecResult("curl --silent http://localhost:1705/httpenv/999 | grep 'env:' | awk '{print $3}'", &pSvrMode); - - if(pSvrMode == NULL) - { - if(pErr) - { - *pErr = -ERR_NO_ITEMS; - } - return defValue; - } - - iValue = strtol(pSvrMode, NULL, 10); - free(pSvrMode); - - if(errno == EINVAL || errno == ERANGE) - { - if(pErr) - { - *pErr = -ERR_STR_CONVERT; - } - - return defValue; - } - - if(pErr) - { - *pErr = 0; - } - - return iValue; -} - -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)); - - // wait UDISK mount, configure file save in UDISK partition - __waitUDISKMount(); - - CfgFileInit(); - - IHW_InitLOG(strrchr(pBusName, '.') + 1, NULL, TRUE); - IHW_EnableLogLevel(LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info, 1); - IHW_RunLogService(); - - APP_BUILD_INFO(strrchr(pBusName, '.') + 1, GetCurrentVersion()); - - i = 0; - do - { - svrMode = CfgGetIntValueV1("Global.ServerMode", PUBLISH_MODE, &ret); - - if(ret != 0) - { - sleep(1); - } - else - { - usleep(1000); - } - - LOG_EX(LOG_Debug, "ServerMode = %d, Error = %d\n", svrMode, ret); - } while (ret != 0 && i++ <= 3); - - if(ret != 0) - { - LOG_EX(LOG_Error, "Read Server Mode Error: ret = %d\n", ret); - svrMode = CfgGetIntValueV2("ServerMode", PUBLISH_MODE, &ret); - - if(ret == 0) - { - LOG_EX(LOG_Warn, "Recovery Server Mode OK: ServerMode = %d\n", svrMode); - } - else - { - LOG_EX(LOG_Error, "CfgGetInvValueV2 Read Server Mode Error: ret = %d\n", ret); - svrMode = GetServerModeFromCC(PUBLISH_MODE, &ret); - - if(ret == 0) - { - LOG_EX(LOG_Warn, "Netease Controller Server Mode OK: ServerMode = %d\n", svrMode); - } - else - { - svrMode = PUBLISH_MODE; - LOG_EX(LOG_Error, "GetServerModeFromCC Read Server Mode Error: " - "ret = %d, Set to default: PUBLISH_MODE\n", ret); - } - } - } - - 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 - - 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; - } - - if(reqInfo.year < (2018 - 1900)) - { - return 0; - } - - ret = DBusJsonSendToCommand(NULL, - g_pModInfoTable[MODULE_CONTROLLER].modAliase, - CMD_WORKDAY_DB_REQ, - JSON_ENGINE_WORKDAY_REQ, - &reqInfo, FALSE); - - return (ret); -} - -int IsHolidayDBSynced(void) -{ - return g_workDayArray.isReady; -} - -int CurrentIsWorkDay(int year, int day) -{ - static unsigned int i = 0; - - if(year != 0) - { - 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); - if(i++ % 10 == 0) - { - 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/build/Makefile.app.cross b/build/Makefile.app.cross index 72cad07..44ec0a1 100644 --- a/build/Makefile.app.cross +++ b/build/Makefile.app.cross @@ -43,7 +43,7 @@ PLAT_LINUX_CFLAGS += -I../linux32/inc/ -I../linux32/inc/cjson/ -I../linux32/inc R16_LIBS := $(COMMON_R16_LIBS) -lreadline -lcurses R16_LIBS += ./libuvdbus-r16.so -R311_LIBS := $(COMMON_R16_LIBS) -lreadline -lcurses +R311_LIBS := $(COMMON_R311_LIBS) -lreadline -lcurses R311_LIBS += ./libuvdbus-r311.so LINUX_LIBS := $(COMMON_LINUX_LIBS) -lreadline -lnghttp2 diff --git a/build/Makefile.def.cross b/build/Makefile.def.cross index e7a46f4..0f58a18 100644 --- a/build/Makefile.def.cross +++ b/build/Makefile.def.cross @@ -1,2 +1,6 @@ -COMMON_R16_LIBS := -ldbus-1 -luv -lcrypto -lcjson -ls2json -lsqlite3 -lnghttp2 -lquickmail -lz -luuid -lconfig -lcurl -lssl -lpthread ../3partys/boardlink/libfastcon.a +COMMON_R16_LIBS := -ldbus-1 -luv -lcrypto -lcjson -ls2json -lsqlite3 -lnghttp2 -lquickmail -lz -luuid -lconfig -lcurl -lssl -lpthread +COMMON_R16_LIBS += ../3partys/boardlink/libfastcon.a ./libpv1comm-r16.so +COMMON_R311_LIBS := -ldbus-1 -luv -lcrypto -lcjson -ls2json -lsqlite3 -lnghttp2 -lquickmail -lz -luuid -lconfig -lcurl -lssl -lpthread +COMMON_R311_LIBS += ../3partys/boardlink/libfastcon.a ./libpv1comm-r311.so COMMON_LINUX_LIBS := -ldbus-1 -luv -lcrypto -lcurl -lm -lnghttp2 -lsqlite3 -lquickmail -lz -luuid -lconfig -lssl -lpthread +COMMON_LINUX_LIBS += ./libpv1comm-linux.so diff --git a/build/Makefile.lib.cross b/build/Makefile.lib.cross index 4f15807..02060b6 100644 --- a/build/Makefile.lib.cross +++ b/build/Makefile.lib.cross @@ -32,7 +32,7 @@ VPATH = ../Framework ../log ../Modules ../linux32 # set the source file, don't used .o because of ... # MRS Board Source Files PLAT_R16_SRCS = \ - libuvEngine/libuv_dbus.c \ + libuvEngine/libcomm.c \ HeartDaemon/heart_daemon.c \ JsonUtils/json_struct.c \ Configure/config_engine.c \ @@ -42,20 +42,13 @@ PLAT_R16_SRCS = \ 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 \ IoT/Boardlink/boardlink_iot.c \ Monitor/monitor.c \ - log.c \ - SvrManager/svr_manager.c \ - hexdump.c + SvrManager/svr_manager.c \ + mark_point.c -PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) \ - src/cJSON.c \ - src/s2j.c +PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) PLAT_R311_SRCS := $(PLAT_R16_SRCS) # gcc CFLAGS @@ -70,12 +63,35 @@ PLAT_R311_LDFLAGS := $(PLAT_R16_LDFLAGS) PLAT_LINUX_LDFLAGS := $(PLAT_R16_LDFLAGS) R16_LIBS := $(COMMON_R16_LIBS) -R311_LIBS := $(COMMON_R16_LIBS) +R311_LIBS := $(COMMON_R311_LIBS) LINUX_LIBS := $(COMMON_LINUX_LIBS) +ifeq ($(PLAT_R16), TRUE) +DEPEND_LIB := ../3partys/allwinner/libpv1comm-r16.so +USER_CLEAN_ITEMS += ./libpv1comm-r16.so +endif + +ifeq ($(PLAT_R311), TRUE) +DEPEND_LIB += ../3partys/allwinner/libpv1comm-r311.so +USER_CLEAN_ITEMS += ./libpv1comm-r311.so +endif + +ifeq ($(PLAT_LINUX), TRUE) +DEPEND_LIB += ../3partys/allwinner/libpv1comm-linux.so +USER_CLEAN_ITEMS += ./libpv1comm-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 diff --git a/include/skins_res.h b/include/skins_res.h index 742ccda..af757d1 100644 --- a/include/skins_res.h +++ b/include/skins_res.h @@ -84,18 +84,18 @@ const SKIN_RES_INFO g_SkinDefaultResTable[] = { {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", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-60.mp3", "61b24ec25307072464866da912d38287"}, - {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-61.mp3", "a231dc24277e25e6d762269efa9a1e07"}, - {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-62.mp3", "27402531c6aff9a9cfb5e418267fb41e"}, - {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-63.mp3", "f9487a6bf86f82961011920509ae0704"}, - {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-64.mp3", "1e67f62e7d8f38dbd8535355cb50fd81"}, - {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-65.mp3", "d2e6c99c68e981e6126306cfe8a8058e"}, - {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-66.mp3", "cb64153aef2ea8d5d9baeb0fc683fd54"}, - {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-67.mp3", "6661a903cd05fdab1ecd5193fb789e51"}, - {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-68.mp3", "db32f17dc439c25255d934bbeaec6275"}, - {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-69.mp3", "a93fea8d57e37a519f3ee0388cbd6e9a"}, - {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-70.mp3", "f91f277864c927fedfee53fb1e9d964a"}, - {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-71.mp3", "a4a4ff36d63fa47072c9eb181712e5cb"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-60.mp3", "9828d1ab422bc917bc6aeb1b3e87be78"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-61.mp3", "26afdbca771abb35ae30be251211245c"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-62.mp3", "56bda2a05dee06eb64271d69df16a5f7"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-63.mp3", "bfa246ebc08235208b01d251279c3c3a"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-64.mp3", "4a18af279fce82af357a4d8061f76608"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-65.mp3", "ec06ed18a96a28a5c2a8335f8c94af22"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-66.mp3", "014233835f5b9996adb572c7ba7b2cfa"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-67.mp3", "29a476772a85097a5fe31d2147234110"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-68.mp3", "5a746e5a466c2beee159174b08049221"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-69.mp3", "986d49e19cef9e19ed059112ed8ebbdf"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-70.mp3", "666c2d4f6de83dfaf7a8b0ead3db7231"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-71.mp3", "d39d5b43690f01bfb5746cadf1d98b17"}, {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"}, diff --git a/log/hexdump.c b/log/hexdump.c deleted file mode 100644 index 0217b34..0000000 --- a/log/hexdump.c +++ /dev/null @@ -1,326 +0,0 @@ -#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 deleted file mode 100644 index 0802634..0000000 --- a/log/log.c +++ /dev/null @@ -1,1332 +0,0 @@ -/** @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 = FALSE; // 是否启用 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) -{ - int ret, size = 0; - char path[MAX_PATH]; - - memset(path, 0, MAX_PATH); - sprintf(path, "%s.txt", g_SysPonitInfo.savePath); - - if(access(path, F_OK) == 0) - { - unlink(path); - } - - GET_FILE_SIZE(g_SysPonitInfo.savePath, size); - - if(size <= 0) - { - LOG_EX(LOG_Debug, "Upload System Mark Data [%s] Is Empty, Skip......\n", g_SysPonitInfo.savePath); - return 0; - } - - rename(g_SysPonitInfo.savePath, path); - - fclose(g_SysPonitInfo.pMarkFile); - g_SysPonitInfo.pMarkFile = fopen(g_SysPonitInfo.savePath, "w+"); - - size = 0; - - do - { - ret = InetHttpUploadFileSync(GetCurServerAddr(MARK_POINT_MODULE), path, NULL); - sleep(1); - } while(ret != 0 && ++size < 3); - - LOG_EX(LOG_Debug, "Upload System Mark Data [%s] To Server [%s]\n", path, GetCurServerAddr(MARK_POINT_MODULE)); - - unlink(path); - - return 0; -} - diff --git a/log/mark_point.c b/log/mark_point.c new file mode 100644 index 0000000..ddc4a06 --- /dev/null +++ b/log/mark_point.c @@ -0,0 +1,270 @@ +/** @file log.c + @brief 系统日志接口文件 + @version 1.0.0 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "smart_sound.h" +#include "inet_api.h" +#include "libuv_dbus.h" +#include "server_addr.h" + + +#ifdef PLATFORM_CPU +#define LOG_FILE_BASEDIR (".") +#else +#define LOG_FILE_BASEDIR ("/tmp") +#endif + +#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; + + +static SYSPOINT_INFO g_SysPonitInfo; +static PSYSPOINT_ITEM g_pSysPointArray = NULL; +static PHTTP_POST_ATTACH g_pLogParamsArray = NULL; + +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) +{ + int ret, size = 0; + char path[MAX_PATH]; + + memset(path, 0, MAX_PATH); + sprintf(path, "%s.txt", g_SysPonitInfo.savePath); + + if(access(path, F_OK) == 0) + { + unlink(path); + } + + GET_FILE_SIZE(g_SysPonitInfo.savePath, size); + + if(size <= 0) + { + LOG_EX(LOG_Debug, "Upload System Mark Data [%s] Is Empty, Skip......\n", g_SysPonitInfo.savePath); + return 0; + } + + rename(g_SysPonitInfo.savePath, path); + + fclose(g_SysPonitInfo.pMarkFile); + g_SysPonitInfo.pMarkFile = fopen(g_SysPonitInfo.savePath, "w+"); + + size = 0; + + do + { + ret = InetHttpUploadFileSync(GetCurServerAddr(MARK_POINT_MODULE), path, NULL); + sleep(1); + } while(ret != 0 && ++size < 3); + + LOG_EX(LOG_Debug, "Upload System Mark Data [%s] To Server [%s]\n", path, GetCurServerAddr(MARK_POINT_MODULE)); + + unlink(path); + + return 0; +} +