在C语言中注册回调函数,函数需要使用静态函数,可使用bind和function来转换
案例一:
#include <iostream>
#include <functional>
#include <string.h>
#include "http_server.h"
#include "ret_err_code.h"
#include "log_api.h"
#include "file_transfer.h"
#include "request_reprogram.h"
#include "request_progress.h"
#define PORT "8089"
#define HOST_INFO "http://localhost:8089"
#define FILE_TRANSFER "/path/a"
#define REQUEST_REPROGRAM "/path/b"
#define REQUEST_PROGRESS "/path/c"
std::mutex HttpServer::mtx;
HttpServer *HttpServer::instance = nullptr;
std::function<int32_t(struct mg_connection *conn, void *cbdata)> EcuFileTransferHandler;
std::function<int32_t(struct mg_connection *conn, void *cbdata)> RequestReprogramHandler;
std::function<int32_t(struct mg_connection *conn, void *cbdata)> RequestProgressHandler;
extern "C" {
int32_t EcuFileTransferHandlerWrapper(struct mg_connection *conn, void *cbdata) {
if (EcuFileTransferHandler) {
return EcuFileTransferHandler(conn, cbdata);
}
return RET_OK;
}
int32_t RequestReprogramHandlerWrapper(struct mg_connection *conn, void *cbdata) {
if (RequestReprogramHandler) {
return RequestReprogramHandler(conn, cbdata);
}
return RET_OK;
}
int32_t RequestProgressHandlerWrapper(struct mg_connection *conn, void *cbdata) {
if (RequestProgressHandler) {
return RequestProgressHandler(conn, cbdata);
}
return RET_OK;
}
}
HttpServer::HttpServer()
{
EcuFileTransferHandler = std::bind(&EcuFileTransfer::EcuFileTransferHandler, EcuFileTransfer::GetInstance(), std::placeholders::_1, std::placeholders::_2);
RequestReprogramHandler = std::bind(&RequestReprogram::RequestReprogramHandler, RequestReprogram::GetInstance(), std::placeholders::_1, std::placeholders::_2);
RequestProgressHandler = std::bind(&RequestProgress::RequestProgressHandler, RequestProgress::GetInstance(), std::placeholders::_1, std::placeholders::_2);
}
HttpServer* HttpServer::GetInstance(void)
{
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new HttpServer;
}
}
return instance;
}
void HttpServer::DelInstance(void)
{
std::lock_guard<std::mutex> lock(mtx);
if (instance) {
delete instance;
instance = nullptr;
}
}
int32_t HttpServer::SetSourcePackagePath(string path)
{
sourcePackagePath = path;
return RET_OK;
}
int32_t HttpServer::SetTargetPackagePath(string path)
{
targetPackagePath = path;
return RET_OK;
}
static int LogMessage(const struct mg_connection *conn, const char *message)
{
puts(message);
return RET_OK;
}
int32_t HttpServer::Init()
{
EcuFileTransfer::GetInstance()->SetSourcePackagePath(sourcePackagePath);
EcuFileTransfer::GetInstance()->SetTargetPackagePath(targetPackagePath);
const char *options[] = {"listening_ports",
PORT,
"request_timeout_ms",
"10000",
"error_log_file",
"error.log",
"enable_auth_domain_check",
"no",
0};
int err = 0;
/* Check if libcivetweb has been built with all required features. */
mg_init_library(MG_FEATURES_DEFAULT);
if (err) {
LOG_ERR("Cannot start CivetWeb - inconsistent build.\n");
return RET_EINVAL;
}
/* Callback will print error messages to console */
memset(&callbacks, 0, sizeof(callbacks));
callbacks.log_message = LogMessage;
/* Start CivetWeb web server */
ctx = mg_start(&callbacks, 0, options);
if (ctx == nullptr) {
LOG_ERR("Cannot start CivetWeb - mg_start failed.");
return RET_EINVAL;
}
/* OTA-MASTER HTTP SERVER */
mg_set_request_handler(ctx, FILE_TRANSFER, EcuFileTransferHandlerWrapper, 0);
mg_set_request_handler(ctx, REQUEST_REPROGRAM, RequestReprogramHandlerWrapper, 0);
mg_set_request_handler(ctx, REQUEST_PROGRESS, RequestProgressHandlerWrapper, 0);
return RET_OK;
}
int32_t HttpServer::Deinit()
{
/* Stop the server */
mg_stop(ctx);
return RET_OK;
}
案例二:
#include <iostream>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <functional>
#include "file_transfer.h"
#include "ret_err_code.h"
#include "cJSON.h"
#include "def_databus.h"
std::mutex EcuFileTransfer::mtx;
EcuFileTransfer *EcuFileTransfer::instance = nullptr;
std::function<int32_t(const char *key, const char *filename, char *path, size_t pathlen, void *user_data)> FieldFound;
std::function<int32_t(const char *key, const char *value, size_t valuelen, void *user_data)> FieldGet;
std::function<int32_t(const char *path, long long file_size, void *user_data)> FieldStore;
extern packagesListInfo ServerPackListInfo;
extern "C" {
int32_t FieldFoundWrapper(const char *key, const char *filename, char *path, size_t pathlen, void *user_data) {
if (FieldFound) {
return FieldFound(key, filename, path, pathlen, user_data);
}
return RET_OK;
}
int32_t FieldGetWrapper(const char *key, const char *value, size_t valuelen, void *user_data) {
if (FieldGet) {
return FieldGet(key, value, valuelen, user_data);
}
return RET_OK;
}
int32_t FieldStoreWrapper(const char *path, long long file_size, void *user_data) {
if (FieldStore) {
return FieldStore(path, file_size, user_data);
}
return RET_OK;
}
}
static int SendJSON(struct mg_connection *conn, cJSON *json_obj)
{
char *json_str = cJSON_PrintUnformatted(json_obj);
size_t json_str_len = strlen(json_str);
/* Send HTTP message header */
mg_send_http_ok(conn, "application/json; charset=utf-8", json_str_len);
/* Send HTTP message content */
mg_write(conn, json_str, json_str_len);
/* Free string allocated by cJSON_Print* */
cJSON_free(json_str);
return (int)json_str_len;
}
EcuFileTransfer::EcuFileTransfer()
{
FieldFound = std::bind(&EcuFileTransfer::field_found, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5);
FieldGet = std::bind(&EcuFileTransfer::field_get, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
FieldStore = std::bind(&EcuFileTransfer::field_store, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}
EcuFileTransfer* EcuFileTransfer::GetInstance(void)
{
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new EcuFileTransfer;
}
}
return instance;
}
void EcuFileTransfer::DelInstance(void)
{
std::lock_guard<std::mutex> lock(mtx);
if (instance) {
delete instance;
instance = nullptr;
}
}
int32_t EcuFileTransfer::SetSourcePackagePath(string path)
{
sourcePackagePath = path;
return RET_OK;
}
int32_t EcuFileTransfer::SetTargetPackagePath(string path)
{
targetPackagePath = path;
return RET_OK;
}
int32_t EcuFileTransfer::field_found(const char *key, const char *filename, char *path, size_t pathlen, void *user_data)
{
if (strcmp(key, "file")) {
return MG_FORM_FIELD_STORAGE_GET;
}
strcat(path, file->GetFilePath().c_str());
if (access(path, 0) == -1) {
int flag = mkdir(path, S_IRWXU);
if (flag != 0) {
std::cout << "Fail to create directory. errno " << errno << std::endl;
}
}
strcat(path, "/");
strcat(path, filename);
return MG_FORM_FIELD_STORAGE_STORE;
}
int32_t EcuFileTransfer::field_get(const char *key, const char *value_untruncated, size_t valuelen, void *user_data)
{
/* Copy the untruncated value, so string compare functions can be used. */
/* The check unit test library does not have build in memcmp functions. */
if (!strcmp(key, "uuid")) {
string item = string(value_untruncated, valuelen);
file->SetUuid(item);
} else if (!strcmp(key, "ecuId")) {
string item = string(value_untruncated, valuelen);
file->SetEcuId(string(item));
} else if (!strcmp(key, "ecuSoftCode")) {
string item = string(value_untruncated, valuelen);
file->SetEcuSoftCode(string(item));
} else if (!strcmp(key, "ecuSoftVer")) {
string item = string(value_untruncated, valuelen);
file->SetEcuSoftVer(string(item));
} else if (!strcmp(key, "packageType")) {
string item = string(value_untruncated, valuelen);
file->SetPackageType(string(item));
} else if (!strcmp(key, "fileMd5")) {
string item = string(value_untruncated, valuelen);
file->SetFileMd5(string(item));
file->SetFilePath(string(item));
} else if (!strcmp(key, "packageCount")) {
string item = string(value_untruncated, valuelen);
file->SetPackageCount(string(item));
} else if (!strcmp(key, "packageNum")) {
string item = string(value_untruncated, valuelen);
file->SetPackageNum(string(item));
} else if (!strcmp(key, "fileCount")) {
string item = string(value_untruncated, valuelen);
file->SetFileCount(string(item));
} else if (!strcmp(key, "fileNum")) {
string item = string(value_untruncated, valuelen);
file->SetFileNum(string(item));
} else {}
return RET_OK;
}
int32_t EcuFileTransfer::field_store(const char *path, long long file_size, void *user_data)
{
file->SetStoreSuccess(true);
return RET_OK;
}
int32_t EcuFileTransfer::EcuFileTransferHandler(struct mg_connection *conn, void *cbdata)
{
const struct mg_request_info *ri = mg_get_request_info(conn);
(void)cbdata; /* currently unused */
if (0 != strcmp(ri->request_method, "POST")) {
/* this is not a POST request */
mg_send_http_error(conn, 405, "Only post method");
return 405;
}
if (file == nullptr) {
file = new EcuFile();
}
struct mg_form_data_handler fdh = {FieldFoundWrapper,
FieldGetWrapper,
FieldStoreWrapper,
NULL};
fdh.user_data = nullptr;
string status = "100";
/* Call the form handler */
int ret = mg_handle_form_request(conn, &fdh);
if (ret <= 0) {
std::cout << "no any elem" << std::endl;
}
int32_t fl = atoi(file->GetFileCount().c_str());
int32_t fr = atoi(file->GetFileNum().c_str());
int32_t pl = atoi(file->GetPackageCount().c_str());
int32_t pr = atoi(file->GetPackageNum().c_str());
if (fl == fr) {
string cmd = "cd " + file->GetFilePath() +
" &&" + " cat * > update.zip" +
" && mkdir -p " + targetPackagePath +
" && unzip -o update.zip -d " + targetPackagePath +
" && rm update.zip" +
" && cd .." +
" && rm -r " + file->GetFilePath();
FILE *fp = popen(cmd.c_str(), "r");
if(fp == NULL) {
perror("popen error");
}
pclose(fp);
if (file->GetStoreSuccess()) {
bool repeat = false;
size_t size = ServerPackListInfo.packInfo.size();
for(size_t i = 0; i < size; i++) {
string id = ServerPackListInfo.packInfo.at(i).ecuId;
if (!id.compare(file->GetEcuId())) {
repeat = true;
}
}
if (!repeat) {
struct packagesInfo info;
info.ecuId = file->GetEcuId();
info.ecuSoftCode = file->GetEcuSoftCode();
info.ecuSoftVer = file->GetEcuSoftVer();
info.packagePath = targetPackagePath;
info.packageType = file->GetPackageType();
ServerPackListInfo.packInfo.push_back(info);
ServerPackListInfo.packageCount = ServerPackListInfo.packInfo.size();
ServerPackListInfo.batchUpdateFlag = false;
ServerPackListInfo.packlistStatus = 1;
ServerPackListInfo.batchId = "0.0.0";
ServerPackListInfo.CreateTime = 0;
}
}
if (pl == pr) {
status = "200";
}
}
if (file != nullptr) {
delete file;
file = nullptr;
}
cJSON *obj = cJSON_CreateObject();
if (!obj) {
/* insufficient memory? */
mg_send_http_error(conn, 500, "Server error");
return 500;
}
cJSON_AddStringToObject(obj, "status", status.c_str());
SendJSON(conn, obj);
cJSON_Delete(obj);
return 200;
}
int32_t EcuFile::SetUuid(string id)
{
uuid = id;
return RET_OK;
}
int32_t EcuFile::SetEcuId(string id)
{
ecuId = id;
return RET_OK;
}
int32_t EcuFile::SetEcuSoftCode(string code)
{
ecuSoftCode = code;
return RET_OK;
}
int32_t EcuFile::SetEcuSoftVer(string ver)
{
ecuSoftVer = ver;
return RET_OK;
}
int32_t EcuFile::SetPackageType(string type)
{
packageType = type;
return RET_OK;
}
int32_t EcuFile::SetFileMd5(string md5)
{
fileMd5 = md5;
return RET_OK;
}
int32_t EcuFile::SetPackageCount(string cnt)
{
packageCount = cnt;
return RET_OK;
}
int32_t EcuFile::SetPackageNum(string num)
{
packageNum = num;
return RET_OK;
}
int32_t EcuFile::SetFileCount(string cnt)
{
fileCount = cnt;
return RET_OK;
}
int32_t EcuFile::SetFileNum(string num)
{
fileNum = num;
return RET_OK;
}
int32_t EcuFile::SetFilePath(string path)
{
filePath = path.substr(0, 8);
return RET_OK;
}
int32_t EcuFile::SetStoreSuccess(bool success)
{
storeSuccess = success;
return RET_OK;
}
string EcuFile::GetUuid()
{
return uuid;
}
string EcuFile::GetEcuId()
{
return ecuId;
}
string EcuFile::GetEcuSoftCode()
{
return ecuSoftCode;
}
string EcuFile::GetEcuSoftVer()
{
return ecuSoftVer;
}
string EcuFile::GetPackageType()
{
return packageType;
}
string EcuFile::GetFileMd5()
{
return fileMd5;
}
string EcuFile::GetPackageCount()
{
return packageCount;
}
string EcuFile::GetPackageNum()
{
return packageNum;
}
string EcuFile::GetFileCount()
{
return fileCount;
}
string EcuFile::GetFileNum()
{
return fileNum;
}
string EcuFile::GetFilePath()
{
return filePath;
}
bool EcuFile::GetStoreSuccess()
{
return storeSuccess;
}