net
net
midea_http_manager.c
/*
 * Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
 *
 * @author 霍长裕
 * @email huocy@midea.com
 * @date 2021-01-06 10:30
 * @des net work
 */
#include <stdio.h>
#include <stdlib.h>
#include "midea_http_manager.h"
#include "midea_http_request.h"
#include "cJSON/cJSON.h"
#include "midea_utils.h"
#include "midea_data_center.h"
// #include "base/adaptor/osal/inc/m_osal.h"
#include "midea_data_types.h"
#include "midea_utils.h"
#include "midea_utils.h"
#include "osal/midea_osal_memory.h"
#include <curl/curl.h>
int mss_http_init()
{
    //初始化http
    http_request_create();
    //初始化其他
    return 0;
}
int mss_http_uninit()
{
    http_request_destory();
    return 0;
}
int mss_http_get_base_body(cJSON **base)
{
    cJSON *root = cJSON_CreateObject();
    char *req_id = NULL; //需要释放
    midea_str_md5_random(&req_id);
    cJSON_AddItemToObject(root, "reqId", cJSON_CreateString(req_id));
    free(req_id);
    char *timestamp = NULL; //需要释放
    midea_str_time_stamp(×tamp);
    cJSON_AddItemToObject(root, "stamp", cJSON_CreateString(timestamp));
    free(timestamp);
    *base = root;
    return 0;
}
// todo http 重试
int mss_http_request(char *path, char *request_json, char **response_json)
{
    // http请求的host需要提前拼接,如果不是下面这种格式
    MS_DATA_CENTER *ms_data = mss_share_instance();
    char *host = ms_data->ms_config->server_host;
    return http_request(host, path, request_json, response_json);
}
int mss_http_request_enhanced(char *path, char *request_json, cJSON **response, int *code)
{
    int codeValue = 0;
    int tryNumber=0;
    cJSON *response_json = NULL;
    do
    {
        char *host = mss_share_instance()->ms_config->server_host;
        char *response_json_str = NULL; //需要释放
        int ret = http_request(host, path, request_json, &response_json_str);
        if (ret != 0)
        {
            // M_LOG_E("The http_request error ret =%d",ret);
            return ret;
        }
        //解析返回数据
        response_json = cJSON_Parse(response_json_str);
        if (response_json == NULL)
        {
            // M_LOG_E("The http response data format is incorrect !!!  [%s]", response_json_str);
            free(response_json_str);
            return -1;
            // return get_error_code(BC_NETWORK, SRC_SDK, CODE_NET_SYSTEM_ERROR);
        }
         
        cJSON *codeJSON = cJSON_GetObjectItem(response_json, "code");
        //对返回数据做一次转换处理
        printf("The http response data code type :%d", codeJSON->type);
        if (codeJSON->type == cJSON_String)
        {
            // M_LOG_E("The http response data code type is cJSON_String");
            codeValue = atoi(codeJSON->valuestring);
        }
        else if (codeJSON->type == cJSON_Number)
        {
            // M_LOG_E("The http response data code type is cJSON_Number");
            codeValue = (int)codeJSON->valuedouble;
        }
        else
        {
            // M_LOG_E("The http response data format is incorrect !!!  [%s]", response_json_str);
            free(response_json_str);
            return -1;
            // return get_error_code(BC_NETWORK, SRC_SDK, CODE_NET_SYSTEM_ERROR);
        }
        free(response_json_str);
        //AT失效错误码
        if (codeValue == 40002 || codeValue == 40001 || codeValue == 401)
        {
        //    int ret = midea_refresh_token("uid","tokenpwd");
        //    if (0 == ret)
        //    {
        //      //先释放之前的缓存,再重新发送请求
        //       cJSON_Delete(response_json);
        //     //   mss_http_request_enhanced(path,request_json,response,code);
        //    }
           
           ///
           
            // M_LOG_I("The http token is invailed codevalue = %d response = %s",codeValue,response_json);
            // ret = mss_data_center_get_access_token();
            // if (ret == 0)
            // {
            // }
            // else
            // {
            //     break;
            // }
        }
        else
        {
            break;
        }
    } while (1);
    // M_LOG_I("The http response data code = %d \n response = %s",codeValue,response_json);
    //返回最终数据
    *code = codeValue;
    *response = response_json;
    return 0;
}
int mss_http_download(char *url, char *file_save_path)
{
    FILE *fp = fopen(file_save_path, "w");
    if (fp == NULL)
    {
        // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        return -1;
    }
    int ret = http_download(url, fp);
    //先关闭文件
    fclose(fp);
    //如果下载失败,则删除文件
    if (ret != 0)
    {
        remove(file_save_path);
        return ret;
    }
    return 0;
}
int midea_checking_network_status(void){
    //  // Start a libcurl easy session
    // CURL *curl = curl_easy_init();
    // if (curl != NULL)
    // {
    //     // todo 条件控制调试开关
    //     int ret = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    //     if (ret != 0)
    //     {
    //         // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
    //         return -1;
    //     }
    //     curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
    //     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
    //     //超时设置
    //     curl_easy_setopt(curl, CURLOPT_TIMEOUT, http_request_timeout);
        
    //     //拼装http请求的url
    //     char *url; //需要释放
    //     assemble_url(host, path, &url);
    //     //设置http请求的url
    //     ret = curl_easy_setopt(curl, CURLOPT_URL, url);
    //     //释放内存
    //     free(url);
    //     if (ret != 0)
    //     {
    //         return -1;
    //         // printf_E("Set CURLOPT_URL failed !!!");
    //         // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
    //     }
    //     // The data pointed to is NOT copied by the library
    //     ret = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_json);
    //     if (ret != 0)
    //     {
    //         return -1;
    //         // printf_E("Set CURLOPT_POSTFIELDS failed !!!");
    //         // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
    //     }
    //     //设置post提交
    //     ret = curl_easy_setopt(curl, CURLOPT_POST, 1);
    //     if (ret != 0)
    //     {
    //         return -1;
    //         // printf_E("Set CURLOPT_POST failed !!!");
    //         // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
    //     }
    //     // todo 不校验证书,后面需要搞定证书校验
    //     ret = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    //     //发送http请求
    //     CURLcode code = curl_easy_perform(curl);
    //     printf("curl_easy_perform after\n");
    //     //释放http请求头
    //     curl_slist_free_all(header);
    //     //处理http请求结果
    //     if (code != 0)
    //     {
    //         printf("Perform http request failed: %s errorcode = %d\n", curl_easy_strerror(code),code);
    //         // ret= get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
    //         ret = -1;
    //     }
    //     // http 请求成功后,处理http请求结果
    //     printf("The response data len: %d\n", response_data.size);
    //     printf("The response data: %s\n", response_data.data);
    //     *response_json = response_data.data;
    //     curl_easy_cleanup(curl);
    //     return ret;
    // }
    return 0;
}
midea_http_manager.h
/*
 * Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
 *
 * @author 霍长裕
 * @email huocy@midea.com
 * @date 2021-01-06 10:30
 * @des net work
 */
#ifndef MIDEA_HTTP_MANAGER_H
#define MIDEA_HTTP_MANAGER_H
#include "cJSON/cJSON.h"
/**
 * @brief 整个应用程序初始化时调用一次。
 * 
 * @return int 0:成功,其他:失败
 */
int mss_http_init();
/**
 * @brief 应用程序销毁时调用一次。
 * 
 * @return int 0:成功,其他:失败
 */
int mss_http_uninit();
/**
 * @brief 获取公共的http请求体, base使用完后需要释放。
 * 包括:reqId,stamp
 *
 * @param base 
 * @return int 
 */
int mss_http_get_base_body(cJSON ** base);
/**
 * @brief 发送https请求.需要释放response_json的内存
 *  
 * @param path 如:/v1/user/login/id/get
 * @param request_json  如:{"reqId":"1a1241602f7103dcfff5b206f330a051","stamp":"20220222112007","loginAccount":"17097236214"}
 * @param response_json 请求返回json
 * @return int 0:成功,其他:错误码
 */
int mss_http_request(char *path, char *request_json, char **response_json);
/**
 * @brief 发送https请求.需要释放response的内存
 * 
 * @param path 如:/v1/user/login/id/get
 * @param request_json 如:{"reqId":"1a1241602f7103dcfff5b206f330a051","stamp":"20220222112007","loginAccount":"17097236214"}
 * @param response  服务器返回数据的cJSON对象
 * @param code 服务器返回数据的code值
 * @return int 0:成功,其他:失败
 */
int mss_http_request_enhanced(char *path, char *request_json, cJSON **response,int *code);
/**
 * @brief 下载url的资源,保存到file_save_path指定的路径中
 * 
 * @param url 待下载的资源
 * @param file_save_path 保存的路径
 * @return int 0:成功,其他:错误码
 */
int mss_http_download(char *url, char *file_save_path);
#endif
midea_http_request.c
/*
 * Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
 *
 * @author 霍长裕
 * @email huocy@midea.com
 * @date 2021-01-06 10:30
 * @des net work
 */
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "midea_common/midea_data_center.h"
#include "midea_common/midea_utils.h"
#include "midea_security/midea_data_security.h"
#include "cJSON/cJSON.h"
#include "osal/midea_osal_url_define.h"
typedef struct http_response_data
{
    char *data;
    size_t size;
} HTTP_RESPONSE_DATA;
static int curl_global_init_flag = 0;
static int http_request_timeout=10;
int http_request_create()
{
    if (curl_global_init_flag != 1)
    {
        curl_global_init_flag = 1;
        CURLcode ret = curl_global_init(CURL_GLOBAL_DEFAULT);
        if (ret != 0)
        {
            curl_global_init_flag = 0;
            return -1;
        }
    }
    return 0;
}
int http_request_destory()
{
    if (curl_global_init_flag == 1)
    {
        curl_global_cleanup();
        curl_global_init_flag = 0;
    }
    return 0;
}
/**
 * @brief 循环被curl调用写入数据,直到完成所有数据写入后结束。
 *
 * @param data 单次需要写入的数据指针
 * @param size  1
 * @param nmemb 数据大小
 * @param userp
 * @return size_t 单次写入的数据大小;需要与curl传入的size*nmemb相等,否则认为写入失败。
 */
size_t write_callback(void *data, size_t size, size_t nmemb, void *userp)
{
    size_t realsize = size * nmemb;
    HTTP_RESPONSE_DATA *mem = (HTTP_RESPONSE_DATA *)userp;
    char *ptr = realloc(mem->data, mem->size + realsize + 1);
    if (ptr == NULL)
        return 0; /* out of memory! */
    mem->data = ptr;
    memcpy(&(mem->data[mem->size]), data, realsize);
    mem->size += realsize;
    mem->data[mem->size] = 0;
    return realsize;
}
/**
 * @brief 计算签名。
 *
 * @param path
 * @param request_json
 * @param header
 * @return int
 */
static int append_sign_header(char *path, char *request_json, struct curl_slist *header)
{
    char *http_sign_secret = mss_share_instance()->ms_config->http_sign_secret; 
    char *http_sign_key = mss_share_instance()->ms_config->http_sign_key;
    int count = midea_str_count_char(path, '&');
    if (count != 0)
    {
        // todo 请求的path中带参数,需要进行参数排序
        // return get_error_code(BC_OTHER,SRC_SDK,CODE_PARAMETER_INVALID_ERROR);
    }
    // rand 使用完需要释放
    char *rand;
    midea_str_random(&rand);
    int rand_len = strlen(rand);
    int request_json_len = strlen(request_json);
    int http_sign_secret_len = strlen(http_sign_secret);
    int total = rand_len + request_json_len + http_sign_secret_len;
    char *tmp = calloc(total + 1, sizeof(char));
    strcpy(tmp, http_sign_secret);
    strcat(tmp, request_json);
    strcat(tmp, rand);
    char *sign_value; //使用完需要释放
    if (http_sign_key == NULL)
    {
        //默认MD5签名
        mss_md5_encrypt_to_lc_hex((unsigned char *)tmp, total, &sign_value);
    }
    else
    {
        //第1代签名
        header = curl_slist_append(header, "secretVersion:1");
        mss_hmac_sha256_to_lc_hex(http_sign_key, strlen(http_sign_key), tmp, strlen(tmp), &sign_value);
        // todo 计算签名
    }
    char *header_sign = calloc(strlen(sign_value) + 5 + 1, sizeof(char));
    strcpy(header_sign, "sign:");
    strcat(header_sign, sign_value);
    char *header_random = calloc(rand_len + 7 + 1, sizeof(char));
    strcpy(header_random, "random:");
    strcat(header_random, rand);
    header = curl_slist_append(header, header_sign);
    header = curl_slist_append(header, header_random);
    free(sign_value);
    free(tmp);
    free(header_sign);
    free(header_random);
    free(rand);
    return 0;
}
/**
 * @brief 组装http请求的url。
 *
 * @param host 如:http://mp-prod.smartmidea.net/mas/v5/app/proxy?alias=
 * @param path 如:/v1/user/login/id/get
 * @param url 如:http://mp-prod.smartmidea.net/mas/v5/app/proxy?alias=/v1/user/login/id/get
 * @return int 0:成功
 */
static int assemble_url(char *host, char *path, char **url)
{
    int length = strlen(host) + strlen(path);
    char *tmp = calloc(length + 1, sizeof(char));
    strcpy(tmp, host);
    strcat(tmp, path);
    *url = tmp;
    return 0;
}
int http_request(char *host, char *path, char *request_json, char **response_json)
{
    // Start a libcurl easy session
    CURL *curl = curl_easy_init();
    if (curl != NULL)
    {
        // todo 条件控制调试开关
        int ret = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        if (ret != 0)
        {
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
            return -1;
        }
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
        //超时设置
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, http_request_timeout);
        
        //拼装http请求的url
        char *url; //需要释放
        assemble_url(host, path, &url);
        //设置http请求的url
        ret = curl_easy_setopt(curl, CURLOPT_URL, url);
        //释放内存
        free(url);
        if (ret != 0)
        {
            return -1;
            // printf_E("Set CURLOPT_URL failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        // The data pointed to is NOT copied by the library
        ret = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_json);
        if (ret != 0)
        {
            return -1;
            // printf_E("Set CURLOPT_POSTFIELDS failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //设置接收http请求的返回函数
        ret = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        if (ret != 0)
        {
            return -1;
            // printf_E("Set CURLOPT_WRITEFUNCTION failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //定义返HTTP回数据的指针的存储对象
        HTTP_RESPONSE_DATA response_data = {0};
        ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response_data);
        if (ret != 0)
        {
              return -1;
            // printf_E("Set CURLOPT_WRITEDATA failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //设置post提交
        ret = curl_easy_setopt(curl, CURLOPT_POST, 1);
        if (ret != 0)
        {
            return -1;
            // printf_E("Set CURLOPT_POST failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        // todo 不校验证书,后面需要搞定证书校验
        ret = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        if (ret != 0)
        {
            return -1;
            // printf_E("Set CURLOPT_SSL_VERIFYPEER failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //设置http请求的header
        struct curl_slist *header = NULL;
        header = curl_slist_append(NULL, "Content-Type:application/json");
        if (header == NULL)
        {
            return -1;
            // printf_E("Create the http header failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //设置AT
        char *access_token = mss_share_instance()->login_info->access_token;
        if (access_token != NULL)
        {
            //需要释放
            char *header_access_token = calloc(12 + strlen(access_token) + 1, sizeof(char));
            strcpy(header_access_token, "accessToken:");
            strcat(header_access_token, access_token);
            header = curl_slist_append(header, header_access_token);
            free(header_access_token);
        }
        //计算签名
        ret = append_sign_header(path, request_json, header);
        if (ret != 0)
        {
            // printf_E("Calc the sign value failed !!!");
              return -1;
            curl_slist_free_all(header);
            return ret;
        }
        ret = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
        if (ret != 0)
        {
            // printf_E("Set CURLOPT_HTTPHEADER failed !!!");
            curl_slist_free_all(header);
            return -1;
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        printf("curl_easy_perform before\n");
        //发送http请求
        CURLcode code = curl_easy_perform(curl);
        printf("curl_easy_perform after\n");
        //释放http请求头
        curl_slist_free_all(header);
        //处理http请求结果
        if (code != 0)
        {
            printf("Perform http request failed: %s\n  %d", curl_easy_strerror(code),code);
            // ret= get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
            ret = -1;
        }
        // http 请求成功后,处理http请求结果
        printf("The response data len: %d\n", response_data.size);
        printf("The response data: %s\n", response_data.data);
        *response_json = response_data.data;
        curl_easy_cleanup(curl);
        return ret;
    }
    else
    {
        // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        return -1;
    }
}
int http_download(char *url, FILE *save_file)
{
    printf("The http download start ... ");
    // Start a libcurl easy session
    CURL *curl = curl_easy_init();
    if (curl != NULL)
    {
        // todo 条件控制调试开关
        int ret = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        if (ret != 0)
        {
            // printf_E("Set CURLOPT_VERBOSE failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //超时设置
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, http_request_timeout);
        
        //设置http请求的url
        ret = curl_easy_setopt(curl, CURLOPT_URL, url);
        if (ret != 0)
        {
            // printf_E("Set CURLOPT_URL failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //定义返HTTP回数据的指针的存储对象
        ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)save_file);
        if (ret != 0)
        {
            // printf_E("Set CURLOPT_WRITEDATA failed !!!");
            // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //发送http请求
        CURLcode code = curl_easy_perform(curl);
        //处理http请求结果
        if (code != 0)
        {
            printf("Perform http request failed: %s\n", curl_easy_strerror(code));
            // ret = get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
        }
        //清理session
        curl_easy_cleanup(curl);
        return ret;
    }
    else
    {
        // return get_error_code(BC_TRANSPORT, SRC_SDK, CODE_EXCEPTION_ERROR);
    }
}
// int delay_user_info(void){
//       ///获取用户信息
//       cJSON *base2; //需要释放
//       int ret = mss_http_get_base_body(&base2);      
//       cJSON *reset_params = cJSON_CreateObject();
//       cJSON_AddItemToObject(base2, "restParams", reset_params);
//       cJSON_AddItemToObject(reset_params, "sourceSys", cJSON_CreateString("APP"));
//       cJSON_AddItemToObject(reset_params, "brand", cJSON_CreateNumber(1));
//       char *bodyStr2 = cJSON_Print(base2);
//       cJSON_Delete(base2);
//       printf("获取用户信息请求参数 response_json_str == %s\n",bodyStr2);
//       char *response_json_str; //需要释放
//       mss_http_request("/api/mcsp_uc/mcsp-uc-member/member/getUserInfo.do", bodyStr2, &response_json_str);
//       printf("获取用户信息 response_json_str == %s\n",response_json_str);
// }
midea_http_request.h
/*
 * Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
 *
 * @author 霍长裕
 * @email huocy@midea.com
 * @date 2021-01-06 10:30
 * @des net work
 */
#ifndef MIDEA_HTTP_REQUEST_H
#define MIDEA_HTTP_REQUEST_H
#include <stdio.h>
/**
 * @brief 整个应用程序初始化时调用一次。
 * 
 * @return int 0:成功,其他:失败
 */
int http_request_create();
/**
 * @brief 应用程序销毁时调用一次。
 * 
 * @return int 0:成功,其他:失败
 */
int http_request_destory();
/**
 * @brief 发送https请求.需要释放response_json的内存
 * 
 * @param host 域名 http://mp-prod.smartmidea.net/mas/v5/app/proxy?alias=
 * @param path 请求的path,如: /v1/user/login/id/get
 * @param request_json 请求的json数据,如:{"reqId":"aa8705e71263f05a1081991548e68529","stamp":"20220223153118","loginAccount":"17097236214"}"
 * @param response_json https请求响应原始数据。
 * @return int 
 */
int http_request(char *host, char *path, char *request_json, char **response_json);
/**
 * @brief 下载文件
 * 
 * @param url 文件网络路径
 * @param file_save_path 文件保存路径
 * @return int 
 */
int http_download(char *url, FILE *);
#endif
 
                     
                    
                 
                    
                 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号