diff --git a/http/restful.c b/http/restful.c index 7461894..25de003 100644 --- a/http/restful.c +++ b/http/restful.c @@ -13,11 +13,13 @@ #define SSL_CA_FILE ("/etc/ssl/certs/ca-certificates.crt") +#define CURL_TIMEOUT (5) + typedef struct { char *pReqUrl; char sPath[MAX_PATH]; char sDlPath[MAX_PATH]; - unsigned int reqResult[4096]; + unsigned char reqResult[4096]; unsigned int dlSize; OnHttpResponse onRspCb; CURL *pCurl; @@ -36,15 +38,20 @@ static size_t __writeDataCb(void *pData, size_t size, size_t nmemb, void *pParam return (iMemSize); } -int http_post_request(const char *pURL, const char *pPost, OnHttpResponse onRespCb) +int http_post_request_async(const char *pURL, const char *pPost, OnHttpResponse onRespCb) { long flag = (long)CURL_GLOBAL_ALL; - int value = 1; + int value = 1, timeout = CURL_TIMEOUT; CURL *pCurl = NULL; int ret = 0; struct curl_slist *pList; PHTTP_REQ_PARAMS pParams = NULL; + if(pURL == NULL || strlen(pURL) == 0) { + LOG_EX(LOG_Error, "Input URL error\n"); + return -ERR_INPUTERR; + } + pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); if(pParams == NULL) { @@ -72,13 +79,10 @@ int http_post_request(const char *pURL, const char *pPost, OnHttpResponse onResp memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); pParams->onRspCb = onRespCb; - pParams->pReqUrl = (char *)malloc(strlen(pURL) + 1); + pParams->pReqUrl = strdup(pURL); pParams->dlSize = 0; pParams->pCurl = pCurl; - memset(pParams->pReqUrl, 0, strlen(pURL) + 1); - strcpy(pParams->pReqUrl, pURL); - pList = curl_slist_append(NULL, "Content-Type:application/json;charset=UTF-8"); curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); @@ -86,6 +90,7 @@ int http_post_request(const char *pURL, const char *pPost, OnHttpResponse onResp curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); curl_easy_setopt(pCurl, CURLOPT_URL, pURL); curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, value); + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, timeout); curl_easy_setopt(pCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList); @@ -125,16 +130,19 @@ int http_post_request(const char *pURL, const char *pPost, OnHttpResponse onResp ret = curl_easy_perform(pCurl); if(ret != CURLE_OK) { - LOG_EX(LOG_Error, "Http Post error: %u\n", ret); + LOG_EX(LOG_Error, "Http Post error(%u): %s\n", ret, curl_easy_strerror(ret)); } curl_slist_free_all(pList); curl_easy_cleanup(pCurl); curl_global_cleanup(); - if(onRespCb) { + if(onRespCb && ret == CURLE_OK) { onRespCb(pParams->reqResult, pParams->dlSize, pParams->pReqUrl, pParams->sPath, - NULL, -pParams->errCode, pParams->pData); + NULL, CURLE_OK, pParams->pData); + } else { + onRespCb(NULL, 0, pParams->pReqUrl, pParams->sPath, + NULL, -ret, pParams->pData); } if(pParams->pReqUrl) { @@ -145,3 +153,118 @@ int http_post_request(const char *pURL, const char *pPost, OnHttpResponse onResp return ret; } + +int http_post_request(const char *pURL, const char *pPost, unsigned char* pBuf, unsigned int *pOutSize) +{ + long flag = (long)CURL_GLOBAL_ALL; + int value = 1, timeout = CURL_TIMEOUT; + CURL *pCurl = NULL; + int ret = 0; + struct curl_slist *pList; + PHTTP_REQ_PARAMS pParams = NULL; + + if(pURL == NULL || strlen(pURL) == 0 || pBuf == NULL || pOutSize == NULL) { + LOG_EX(LOG_Error, "Input params error\n"); + return -ERR_NOMEM; + } + + pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); + + if(pParams == NULL) { + LOG_EX(LOG_Error, "Malloc %u memory error\n", sizeof(HTTP_REQ_PARAMS)); + return -ERR_NOMEM; + } + + ret = curl_global_init(flag); + + if(ret != CURLE_OK) { + LOG_EX(LOG_Error, "Init curl global error: %d\n", ret); + free(pParams); + return -ERR_ERR; + } + + pCurl = curl_easy_init(); + + if(!pCurl) { + LOG_EX(LOG_Error, "Init easy curl error: %d\n", ret); + curl_global_cleanup(); + free(pParams); + return -ERR_ERR; + } + + memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); + + pParams->pReqUrl = strdup(pURL); + pParams->dlSize = 0; + pParams->pCurl = pCurl; + + pList = curl_slist_append(NULL, "Content-Type:application/json;charset=UTF-8"); + + 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, value); + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, timeout); + curl_easy_setopt(pCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList); + + if(pPost != NULL && strlen(pPost) > 0) { + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, pPost); + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE, (long)strlen(pPost)); + pParams->pData = (void*)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, value); +#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 + + ret = curl_easy_perform(pCurl); + + if(ret != CURLE_OK) { + LOG_EX(LOG_Error, "Http Post error(%u): %s\n", ret, curl_easy_strerror(ret)); + } + + curl_slist_free_all(pList); + curl_easy_cleanup(pCurl); + curl_global_cleanup(); + + if(*pOutSize < pParams->dlSize) { + ret = -ERR_OUTSIZE; + } else { + *pOutSize = pParams->dlSize; + } + + memcpy(pBuf, pParams->reqResult, *pOutSize); + + if(pParams->pReqUrl) { + free(pParams->pReqUrl); + } + + free(pParams); + + return ret; +} diff --git a/include/err_code.h b/include/err_code.h index 2ce4ef9..cb0d7af 100644 --- a/include/err_code.h +++ b/include/err_code.h @@ -24,6 +24,7 @@ #define ERR_SRCERR (15) #define ERR_JSONERR (16) #define ERR_USED (17) +#define ERR_OUTSIZE (18) #define ERR_READFILE (100) @@ -34,45 +35,27 @@ static inline char *err2string(int err) } switch(err) { - case ERR_OK: return "OK"; - - case ERR_ERR: return "Error"; - - case ERR_UNKNOWN: return "Unkown"; - - case ERR_SYSERR: return "SystemError"; - - case ERR_NOTFOUND: return "NotFound"; - - case ERR_TIMEOUT: return "Timeout"; - - case ERR_NULLP: return "NullPointer" ; - - case ERR_NOMEM: return "NotEnoughMemory"; - - case ERR_CHKERR: return "CheckError"; - - case ERR_NOTSUPPORT: return "NotSupport"; - - case ERR_INPUTERR: return "InputError"; - - case ERR_EXIST: return "AlreadyExist"; - - case ERR_FULL: return "Full"; - - case ERR_SENDERR: return "SendErr"; - - case ERR_NOCMID: return "CanNotFindConfig"; - - case ERR_SRCERR: return "ConfigSourceErr"; - - case ERR_JSONERR: return "JsonFormatErr"; - - case ERR_USED: return "ItemUsed"; - - case ERR_READFILE: return "Read File Error"; - - default: return "Unknown err code"; + case ERR_OK: return (char*) "OK"; + case ERR_ERR: return (char*) "Error"; + case ERR_UNKNOWN: return (char*) "Unkown"; + case ERR_SYSERR: return (char*) "SystemError"; + case ERR_NOTFOUND: return (char*) "NotFound"; + case ERR_TIMEOUT: return (char*) "Timeout"; + case ERR_NULLP: return (char*) "NullPointer" ; + case ERR_NOMEM: return (char*) "NotEnoughMemory"; + case ERR_CHKERR: return (char*) "CheckError"; + case ERR_NOTSUPPORT: return (char*) "NotSupport"; + case ERR_INPUTERR: return (char*) "InputError"; + case ERR_EXIST: return (char*) "AlreadyExist"; + case ERR_FULL: return (char*) "Full"; + case ERR_SENDERR: return (char*) "SendErr"; + case ERR_NOCMID: return (char*) "CanNotFindConfig"; + case ERR_SRCERR: return (char*) "ConfigSourceErr"; + case ERR_JSONERR: return (char*) "JsonFormatErr"; + case ERR_USED: return (char*) "ItemUsed"; + case ERR_READFILE: return (char*) "Read File Error"; + case ERR_OUTSIZE: return (char*) "Out of memory size"; + default: return (char*) "Unknown err code"; } } diff --git a/include/json_interface.h b/include/json_interface.h index 2ac1fd3..fd19bad 100644 --- a/include/json_interface.h +++ b/include/json_interface.h @@ -17,8 +17,8 @@ typedef struct { typedef struct { char *status; - unsigned int iptype; - unsigned int ip; + int iptype; + char *ip; char *code; } AUTH_ZTH_RSP, *PAUTH_ZTH_RSP; diff --git a/include/restful.h b/include/restful.h index dbed218..8392d21 100644 --- a/include/restful.h +++ b/include/restful.h @@ -8,5 +8,7 @@ typedef void (*OnHttpResponse)(void *pData, unsigned int size, const char *pReqUrl, const char *pDlPath, const char *pTaskUuid, int iFinished, void *pUserData); -int http_post_request(const char *pURL, const char *pPost, OnHttpResponse onRespCb); +int http_post_request_async(const char *pURL, const char *pPost, OnHttpResponse onRespCb); + +int http_post_request(const char *pURL, const char *pPost, unsigned char* pBuf, unsigned int *pOutSize); #endif //ZTP_CLIENT_RESTFUL_H diff --git a/json_engine/json_interface.c b/json_engine/json_interface.c index ec74376..fad96ec 100644 --- a/json_engine/json_interface.c +++ b/json_engine/json_interface.c @@ -67,13 +67,14 @@ static int __ztp_auth_decode(const char *pJsonS, void **pStruct) pVal = cJSON_GetObjectItem(pRoot, "iptype"); if(cJSON_IsString(pVal)) { - pData->iptype = (unsigned int)strtoul(pVal->valuestring, 0, 10); + pData->iptype = (int)strtoul(pVal->valuestring, 0, 10); } pVal = cJSON_GetObjectItem(pRoot, "ip"); if(cJSON_IsString(pVal)) { - pData->ip = (unsigned int)strtoul(pVal->valuestring, 0, 10); + pData->ip = strdup(pVal->valuestring); + //(unsigned int)strtoul(pVal->valuestring, 0, 10); } pVal = cJSON_GetObjectItem(pRoot, "code"); diff --git a/unit_test/GoogleTest.cmake b/unit_test/GoogleTest.cmake index 1e73787..d574054 100644 --- a/unit_test/GoogleTest.cmake +++ b/unit_test/GoogleTest.cmake @@ -4,12 +4,12 @@ project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG master - SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" - BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) \ No newline at end of file + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) \ No newline at end of file diff --git a/unit_test/test/json_test.cpp b/unit_test/test/json_test.cpp index a86766a..941f550 100644 --- a/unit_test/test/json_test.cpp +++ b/unit_test/test/json_test.cpp @@ -11,10 +11,9 @@ using namespace std; extern "C" { #include "err_code.h" #include "json_interface.h" -#include "restful.h" } -TEST(json_encode_test, retOK) +TEST(json_test, encode) { int ret = 0; const char *pJson; @@ -32,7 +31,7 @@ TEST(json_encode_test, retOK) ASSERT_EQ(ERR_OK, ret); } -TEST(json_decode_test, retOK) +TEST(json_test, decode) { #define JSON_STR ("{\"code\":\"fBBx8Q\",\"ip\":\"172.28.73.38\",\"iptype\":\"1\",\"status\":\"SUCCESS\"}") int ret = 0; @@ -59,77 +58,6 @@ TEST(json_decode_test, retOK) ASSERT_EQ(0, ret); } -TEST(ztp_auth, success) -{ -#define JSON_REQ ("{\"ESN\": \"tt21\"}") -#define REQ_URL ("http://172.28.73.43:8088/device/esn") - int ret; - int size = 4096; - char buf[4096]; - PAUTH_ZTH_RSP pZTPRsp; - - memset(buf, 0, 4096); - ret = http_post_request(REQ_URL, JSON_REQ, (unsigned char*)buf, &size); - - EXPECT_EQ(ERR_OK, ret); - - ret = Json2Struct(buf, &pZTPRsp, JE_AUTH_ZTP, false); - - ASSERT_EQ(ERR_OK, ret); - - ASSERT_STRCASEEQ(pZTPRsp->status, "SUCCESS"); - - if(pZTPRsp) { - if(pZTPRsp->status) { - free(pZTPRsp->status); - } - - if(pZTPRsp->code) { - free(pZTPRsp->code); - } - - if(pZTPRsp->ip) { - free(pZTPRsp->ip); - } - free(pZTPRsp); - } -} - -TEST(ztp_auth, failed) -{ -#define JSON_REQ_FAIL ("{\"ESN\": \"ace08484843\"}") - int ret; - int size = 4096; - char buf[4096]; - PAUTH_ZTH_RSP pZTPRsp; - - memset(buf, 0, 4096); - ret = http_post_request(REQ_URL, JSON_REQ_FAIL, (unsigned char*)buf, &size); - - EXPECT_EQ(ERR_OK, ret); - - ret = Json2Struct(buf, &pZTPRsp, JE_AUTH_ZTP, false); - - ASSERT_EQ(ERR_OK, ret); - - ASSERT_STRCASEEQ(pZTPRsp->status, "FAILED"); - - if(pZTPRsp) { - if(pZTPRsp->status) { - free(pZTPRsp->status); - } - - if(pZTPRsp->code) { - free(pZTPRsp->code); - } - - if(pZTPRsp->ip) { - free(pZTPRsp->ip); - } - free(pZTPRsp); - } -} - auto main(int argc, char *argv[]) -> int { testing::InitGoogleTest(&argc, argv); diff --git a/unit_test/test/restful_test.cpp b/unit_test/test/restful_test.cpp new file mode 100644 index 0000000..b87820d --- /dev/null +++ b/unit_test/test/restful_test.cpp @@ -0,0 +1,92 @@ +// +// Created by xajhu on 2019/12/2 0002. +// +#include + +using namespace std; + +#include "gtest/gtest.h" + +extern "C" { +#include "err_code.h" +#include "json_interface.h" +#include "restful.h" +} + +TEST(ztp_auth, authorized_success) +{ +#define JSON_REQ ("{\"ESN\": \"tt21\"}") +#define REQ_URL ("http://172.28.73.43:8088/device/esn") + int ret; + unsigned int size = 4096; + char buf[4096]; + PAUTH_ZTH_RSP pZTPRsp; + + memset(buf, 0, 4096); + ret = http_post_request(REQ_URL, JSON_REQ, (unsigned char *)buf, &size); + + EXPECT_EQ(ERR_OK, ret); + + ret = Json2Struct(buf, &pZTPRsp, JE_AUTH_ZTP, false); + + ASSERT_EQ(ERR_OK, ret); + + ASSERT_STRCASEEQ(pZTPRsp->status, "SUCCESS") << "\nValue-->[" + << "status: " << pZTPRsp->status + << ", code: " << pZTPRsp->code + << ", ip: " << pZTPRsp->ip + << ", iptype: " << pZTPRsp->iptype << "]" <status) { + free(pZTPRsp->status); + } + + if(pZTPRsp->code) { + free(pZTPRsp->code); + } + + if(pZTPRsp->ip) { + free(pZTPRsp->ip); + } + + + + free(pZTPRsp); + } +} + +TEST(ztp_auth, unauthorized_failed) +{ +#define JSON_REQ_FAIL ("{\"ESN\": \"ace08484843\"}") + int ret; + unsigned int size = 4096; + char buf[4096]; + PAUTH_ZTH_RSP pZTPRsp; + + memset(buf, 0, 4096); + ret = http_post_request(REQ_URL, JSON_REQ_FAIL, (unsigned char *)buf, &size); + + EXPECT_EQ(ERR_OK, ret); + + ret = Json2Struct(buf, &pZTPRsp, JE_AUTH_ZTP, false); + + ASSERT_EQ(ERR_OK, ret); + + ASSERT_STRCASEEQ(pZTPRsp->status, "FAILED"); + + if(pZTPRsp) { + if(pZTPRsp->status) { + free(pZTPRsp->status); + } + + if(pZTPRsp->code) { + free(pZTPRsp->code); + } + + if(pZTPRsp->ip) { + free(pZTPRsp->ip); + } + free(pZTPRsp); + } +} diff --git a/ztp_main.c b/ztp_main.c index c971a6e..8b2a0cc 100644 --- a/ztp_main.c +++ b/ztp_main.c @@ -28,33 +28,36 @@ void __onPost(void *pData, unsigned int size, const char *pReqUrl, if(pUserData && strlen(pUserData) > 0) { LOG_EX(LOG_Info, "Post Data: [%s]\n", pUserData); } - LOG_EX(LOG_Info, "Post Result: [%s]\n", (char *)pData); - ret = Json2Struct(pData, &pZTPRsp, JE_AUTH_ZTP, FALSE); + if(pData) { + LOG_EX(LOG_Info, "Post Result: [%s]\n", (char *)pData); - if(ret == ERR_OK && pZTPRsp) { - if(strcasecmp(pZTPRsp->status, "SUCCESS") == 0) { - LOG_EX(LOG_Debug, "Request OK\n"); + ret = Json2Struct(pData, &pZTPRsp, JE_AUTH_ZTP, FALSE); + + if(ret == ERR_OK && pZTPRsp) { + if(strcasecmp(pZTPRsp->status, "SUCCESS") == 0) { + LOG_EX(LOG_Debug, "Request OK\n"); + } else { + LOG_EX(LOG_Error, "Request Error\n"); + } } else { - LOG_EX(LOG_Error, "Request Error\n"); - } - } else { - LOG_EX(LOG_Error, "Decode JSON error: %d\n", ret); - } - - if(pZTPRsp) { - if(pZTPRsp->status) { - free(pZTPRsp->status); + LOG_EX(LOG_Error, "Decode JSON error: %d\n", ret); } - if(pZTPRsp->code) { - free(pZTPRsp->code); - } + if(pZTPRsp) { + if(pZTPRsp->status) { + free(pZTPRsp->status); + } - if(pZTPRsp->ip) { - free(pZTPRsp->ip); + if(pZTPRsp->code) { + free(pZTPRsp->code); + } + + if(pZTPRsp->ip) { + free(pZTPRsp->ip); + } + free(pZTPRsp); } - free(pZTPRsp); } }