简单服务器框架---(基于boost实现)
整个交互流程如下:
车机(HU)与其他Firmware(Firmware)通信的数据帧结构


1.server.h
#ifndef _OTA_SERVER_H_
#define _OTA_SERVER_H_
#include "session.h"
#include <cstdint>
#include <boost/asio.hpp>
#include <vector>
class server
{
public:
server(uint32_t port);
server(server &&) = delete;
server(const server &) = delete;
server &operator=(server &&) = delete;
server &operator=(const server &) = delete;
~server() = default;
void run();
void stop();
void delete_session(session* sess);
private:
void start_accept();
void handle_accept(session_ptr session, const boost::system::error_code& ec);
private:
boost::asio::io_service m_io_service;
boost::asio::ip::tcp::acceptor m_acceptor;
boost::asio::io_service::work m_work;
std::vector<session*> m_sessions;
};
#endif // !_OTA_SERVER_H_
server.cpp
#include "server.h" #include "request_handler.h" #include "zros/app_log/log.h" #include <iostream> #include <algorithm> #include <cstdlib> #include <deque> #include <set> #include <boost/enable_shared_from_this.hpp> #include <boost/asio/deadline_timer.hpp> #include <boost/asio/io_service.hpp> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/read_until.hpp> #include <boost/asio/streambuf.hpp> #include <boost/asio/write.hpp> using boost::asio::deadline_timer; using boost::asio::ip::tcp; server::server(uint32_t port) : m_acceptor(m_io_service, tcp::endpoint(tcp::v4(), port)), m_work(m_io_service) { start_accept(); } void server::run() { m_io_service.run(); } void server::stop() { boost::system::error_code ignored_ec; m_acceptor.close(ignored_ec); std::vector<session*> sessions(std::move(m_sessions)); for (auto &&s : sessions) { s->stop(); } m_io_service.stop(); } void server::delete_session(session* sess) { m_sessions.erase(std::remove_if(m_sessions.begin(), m_sessions.end(), [sess](session* psession){ return sess == psession; }), m_sessions.end()); } void server::start_accept() { session_ptr new_session(new session(m_io_service, *this)); m_sessions.push_back(new_session.get()); m_acceptor.async_accept(new_session->socket(), std::bind(&server::handle_accept, this, new_session, std::placeholders::_1)); } void server::handle_accept(session_ptr session, const boost::system::error_code& ec) { if (!ec) { boost::system::error_code ec; auto remote_endpoint = session->socket().remote_endpoint(ec); if (!ec) { std::string client_ip = remote_endpoint.address().to_string(); unsigned short client_port = remote_endpoint.port(); zinfo("accept connection from: %s: %d", client_ip.c_str(), client_port); } session->start(); } else { zinfo("async_accept failed with error: %s", ec.message().c_str()); } start_accept(); }
定义会话类:
session.h
#ifndef _OTA_SESSION_H_ #define _OTA_SESSION_H_ #include "boost/asio.hpp" #include "request_handler.h" #include <cstdint> #include <vector> #include <deque> #include <memory> #include <thread> class server; class session: public std::enable_shared_from_this<session> { public: session(boost::asio::io_service& ios, server& s); session(session &&) = default; session(const session &) = delete; session &operator=(session &&) = default; session &operator=(const session &) = delete; ~session(); void start(); void stop(); boost::asio::ip::tcp::socket& socket(); void send_data(const std::vector<uint8_t>& datas); void send_data_in_same_thread(const std::vector<uint8_t>& datas); private: bool stopped() const; void start_read(); void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred); void await_output(); void start_write(); void handle_write(const boost::system::error_code& ec); void check_deadline(boost::asio::deadline_timer* deadline); private: std::vector<uint8_t> m_recv_buffer; std::deque<std::vector<uint8_t>> m_send_buffer; server& m_server; boost::asio::io_service& m_io_service; boost::asio::ip::tcp::socket m_socket; boost::asio::deadline_timer m_input_deadline; boost::asio::deadline_timer m_non_empty_output_queue; request_handler m_request_handler; std::thread::id m_thread_id; }; typedef std::shared_ptr<session> session_ptr; #endif // !_OTA_SESSION_H_
实现session.cpp
#include "session.h" #include "zros/app_log/log.h" #include "server.h" using boost::asio::ip::tcp; session::session(boost::asio::io_service& ios, server& s) : m_thread_id(std::this_thread::get_id()), m_recv_buffer(4096), m_server(s), m_io_service(ios), m_socket(ios), m_input_deadline(ios), m_non_empty_output_queue(ios), m_request_handler(std::bind(&session::send_data, this, std::placeholders::_1)) { m_input_deadline.expires_at(boost::posix_time::pos_infin); // The non_empty_output_queue deadline_timer is set to pos_infin whenever // the output queue is empty. This ensures that the output actor stays // asleep until a message is put into the queue. m_non_empty_output_queue.expires_at(boost::posix_time::pos_infin); } session::~session() { zinfo("destruct session"); } void session::start() { m_request_handler.send_update_state(); start_read(); m_input_deadline.async_wait( std::bind(&session::check_deadline, shared_from_this(), &m_input_deadline)); await_output(); } tcp::socket& session::socket() { return m_socket; } void session::send_data_in_same_thread(const std::vector<uint8_t>& datas) { assert(m_thread_id == std::this_thread::get_id()); m_send_buffer.push_back(datas); // Signal that the output queue contains messages. Modifying the expiry // will wake the output actor, if it is waiting on the timer. m_non_empty_output_queue.expires_at(boost::posix_time::neg_infin); } void session::send_data(const std::vector<uint8_t>& datas) { m_io_service.post([datas, self=shared_from_this()](){ self->send_data_in_same_thread(datas); }); } void session::stop() { boost::system::error_code ignored_ec; auto remote_endpoint = socket().remote_endpoint(ignored_ec); if (!ignored_ec) { std::string client_ip = remote_endpoint.address().to_string(); unsigned short client_port = remote_endpoint.port(); zinfo("close connection with: %s: %d", client_ip.c_str(), client_port); } m_socket.close(ignored_ec); m_input_deadline.cancel(ignored_ec); m_non_empty_output_queue.cancel(ignored_ec); m_server.delete_session(this); } bool session::stopped() const { return !m_socket.is_open(); } void session::start_read() { // Set a deadline for the read operation. m_input_deadline.expires_from_now(boost::posix_time::minutes(30)); // Start an asynchronous operation zdebug("start async read data"); m_socket.async_read_some(boost::asio::buffer(m_recv_buffer), std::bind(&session::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } void session::handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred) { if (stopped()) return; if (!ec) { zdebug("recv %d bytes data", bytes_transferred); if (bytes_transferred > 0) { m_request_handler.handle_request(gsl::span<uint8_t>(m_recv_buffer.data(), bytes_transferred)); } start_read(); } else { zinfo("read data failed with error: %s", ec.message().c_str()); stop(); } } void session::await_output() { if (stopped()) return; if (m_send_buffer.empty()) { // There are no messages that are ready to be sent. The actor goes to // sleep by waiting on the non_empty_output_queue_ timer. When a new // message is added, the timer will be modified and the actor will wake. m_non_empty_output_queue.expires_at(boost::posix_time::pos_infin); m_non_empty_output_queue.async_wait( std::bind(&session::await_output, shared_from_this())); } else { start_write(); } } void session::start_write() { boost::asio::async_write(m_socket, boost::asio::buffer(m_send_buffer.front()), std::bind(&session::handle_write, shared_from_this(), std::placeholders::_1)); } void session::handle_write(const boost::system::error_code& ec) { if (stopped()) return; if (!ec) { m_send_buffer.pop_front(); await_output(); } else { zinfo("write data fail with error:%s", ec.message().c_str()); stop(); } } void session::check_deadline(boost::asio::deadline_timer* deadline) { if (stopped()) return; // Check whether the deadline has passed. We compare the deadline against // the current time since a new asynchronous operation may have moved the // deadline before this actor had a chance to run. if (deadline->expires_at() <= boost::asio::deadline_timer::traits_type::now()) { // The deadline has passed. Stop the session. The other actors will // terminate as soon as possible. zinfo("dealine timer timeout and close connection"); stop(); } else { // Put the actor back to sleep. deadline->async_wait( std::bind(&session::check_deadline, shared_from_this(), deadline)); } }
实现request_handler.h
#ifndef _OTA_REQUEST_HANDLER_H_ #define _OTA_REQUEST_HANDLER_H_ #include "gsl/span" #include <functional> #include <vector> class request_handler { public: using data_send_func = std::function<void(const std::vector<uint8_t>&)>; request_handler(const data_send_func& data_sender); request_handler(request_handler &&) = default; request_handler(const request_handler &) = default; request_handler &operator=(request_handler &&) = default; request_handler &operator=(const request_handler &) = default; ~request_handler() = default; void handle_request(gsl::span<uint8_t> datas); void send_update_state(); private: std::vector<uint8_t> m_buffer; data_send_func m_data_sender; }; #endif // !_OTA_REQUEST_HANDLER_H_
request_handler.cpp
#include "request_handler.h" #include "parser.h" #include "cmd_executor.h" #include "update_mgr.h" #include "update_state.h" #include "zros/app_log/log.h" #include <functional> #include <vector> #include <algorithm> #include <arpa/inet.h> #include <string.h> static const uint32_t update_cmd = 0x74; static const uint32_t update_sub_cmd = 0x01; static std::vector<uint8_t> make_error_response_frame(const request& req, ERROR_CODE error_code) { uint32_t error = static_cast<uint32_t>(error_code); return make_response_frame(req, false, std::vector<uint8_t>((uint8_t*)&error, (uint8_t*)&error+sizeof(error))); } #define RETURN_ERR_RESPONSE_IF_FAIL(req, error_code) \ if (ERROR_CODE::OK != error_code) { \ return make_error_response_frame(req, error_code); \ } static std::vector<uint8_t> invalid_cmd_executor(const request& req) { zinfo("invalid request"); return make_error_response_frame(req, ERROR_CODE::INVALID_REQUEST); } static std::vector<uint8_t> read_version_executor(const request& req) { zinfo("request read version"); version_info version = {0}; ERROR_CODE error_code = read_version(version); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); std::vector<uint8_t> res; res.insert(res.end(), version.hard_partnumber.begin(), version.hard_partnumber.end()); res.insert(res.end(), version.hard_version.begin(), version.hard_version.end()); res.insert(res.end(), version.soft_partnumber.begin(), version.soft_partnumber.end()); res.insert(res.end(), version.soft_version.begin(), version.soft_version.end()); zinfo("end read version request"); return make_response_frame(req, true, res); } #define RETURN_ERROR_RESP_IF_REQ_DATA_IS_ERR(req, required_data_size, cmd) \ if (req.datas.size() < required_data_size) { \ zinfo("data of %s is not correct, require size %d, get size %d", cmd, required_data_size, req.datas.size()); \ return make_error_response_frame(req, ERROR_CODE::INVALID_REQUEST_DATA); \ } static void file_info_to_local_byte_order(const file_info& source_file_info, file_info& dest_file_info) { memcpy(&dest_file_info, &source_file_info, sizeof(dest_file_info)); //dest_file_info.file_length = ntohl(dest_file_info.file_length); } static std::vector<uint8_t> start_write_file_executor(const request& req) { zinfo("request starting write file"); RETURN_ERROR_RESP_IF_REQ_DATA_IS_ERR(req, sizeof(file_info), "start_write_file"); file_info* file = (file_info*)req.datas.data(); file_info file_info_in_local_byte_order; file_info_to_local_byte_order(*file, file_info_in_local_byte_order); uint32_t file_offset = 0; ERROR_CODE error_code = start_write_file(file_info_in_local_byte_order, file_offset); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); uint32_t file_offset_in_net_order = file_offset; std::vector<uint8_t> res; res.insert(res.end(), (uint8_t*)file, (uint8_t*)file+sizeof(file_info)); res.insert(res.end(), (uint8_t*)&file_offset_in_net_order, (uint8_t*)&file_offset_in_net_order+sizeof(file_offset_in_net_order)); zinfo("end start write file request"); return make_response_frame(req, true, res); } static void convert_file_data_info_header(file_data_info_header* header) { header->data_length = ntohl(header->data_length); header->file_length = ntohl(header->file_length); header->offset = ntohl(header->offset); } static std::vector<uint8_t> write_file_data_executor(const request& req) { //zinfo("request write file data"); RETURN_ERROR_RESP_IF_REQ_DATA_IS_ERR(req, sizeof(file_data_info_header), "write_file_data"); file_data_info_header* header = (file_data_info_header*)req.datas.data(); //convert_file_data_info_header(header); uint32_t data_size = req.datas.size() - sizeof(file_data_info_header); if (data_size < header->data_length) { zinfo("file data(%d) less than length in header(%d)", data_size, header->data_length); return make_error_response_frame(req, ERROR_CODE::INVALID_REQUEST_DATA); } file_data_info file_data; memcpy((char*)&(file_data.header), (char*)header, sizeof(file_data.header)); file_data.file_datas.insert(file_data.file_datas.end(), (uint8_t*)header+sizeof(file_data_info_header), (uint8_t*)header+sizeof(file_data_info_header)+header->data_length); uint32_t file_length = 0; std::array<char, 32> file_md5; ERROR_CODE error_code = write_file_data(file_data, file_md5, file_length); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); //file_length = htonl(file_length); uint32_t offset_in_net_order = header->offset; std::vector<uint8_t> res; res.insert(res.end(), header->file_name, header->file_name+sizeof(header->file_name)); res.insert(res.end(), (uint8_t*)&file_length, (uint8_t*)&file_length+sizeof(file_length)); res.insert(res.end(), file_md5.begin(), file_md5.end()); res.insert(res.end(), (uint8_t*)&offset_in_net_order, (uint8_t*)&offset_in_net_order+sizeof(offset_in_net_order)); //zinfo("end write file data request"); return make_response_frame(req, true, res); } static std::vector<uint8_t> end_write_file_executor(const request& req) { zinfo("request finish write file"); ERROR_CODE error_code = end_write_file(); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); zinfo("end finish write file request"); std::vector<uint8_t> res(256, 0); return make_response_frame(req, true, res); } //add bwb //获取证书id static std::vector<uint8_t> read_certificate_id_executor(const request& req) { zinfo("request read certificate id"); std::string certificate_id; char cer_id[64]={0}; ERROR_CODE error_code = read_certificate(certificate_id); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); strncpy(cer_id,certificate_id.c_str(),certificate_id.size()); std::vector<uint8_t> res; res.insert(res.end(), (uint8_t*)cer_id, (uint8_t*)cer_id+sizeof(cer_id)); zinfo("end read certificate id request"); return make_response_frame(req, true, res); } //证书校验请求 static std::vector<uint8_t> certificate_verify_executor(const request& req) { zinfo("request certificate_verify"); RETURN_ERROR_RESP_IF_REQ_DATA_IS_ERR(req, 64, "certificate_verify"); char* certificate_id= (char*)req.datas.data(); std::string local_certificate_id(certificate_id); ERROR_CODE error_code = certificate_verify(local_certificate_id); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); std::vector<uint8_t> res; zinfo("end certificate_verify request"); return make_response_frame(req, true, res); } //文件验签 static std::vector<uint8_t> filesignature_verify_executor(const request& req) { zinfo("request filesignature_verify"); RETURN_ERROR_RESP_IF_REQ_DATA_IS_ERR(req, sizeof(filesignature_info), "filesignature_verify"); filesignature_info* filesignature1= (filesignature_info*)req.datas.data(); /* filesignature1.file_sign.insert(filesignature1->file_sign.end(), (uint8_t*)&filesignature1->file_sign+(uint8_t*)&filesignature1->file_sign+filesignature1.file_sign_size); */ //filesignature_info filesignature_info_in_local; zinfo("%s,%s,%s\n",filesignature1->file_name,filesignature1->cer_id,filesignature1->file_sign); ERROR_CODE error_code = filesignature_verify(*filesignature1); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); // free(filesignature_info_in_local.file_sign); zinfo("end filesignature_verify request"); std::vector<uint8_t> res; res.insert(res.end(),filesignature1->file_name ,filesignature1->file_name+sizeof(filesignature1->file_name)); res.insert(res.end(), (uint8_t*)&filesignature1->file_length, (uint8_t*)&filesignature1->file_length+sizeof(filesignature1->file_length)); return make_response_frame(req, true, res); } static std::vector<uint8_t> check_file_executor(const request& req) { zinfo("request check file"); RETURN_ERROR_RESP_IF_REQ_DATA_IS_ERR(req, sizeof(file_info), "check_file"); file_info* file = (file_info*)req.datas.data(); file_info file_info_in_local_byte_order; file_info_to_local_byte_order(*file, file_info_in_local_byte_order); ERROR_CODE error_code = check_file(file_info_in_local_byte_order); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); std::vector<uint8_t> res; res.insert(res.end(), (uint8_t*)file, (uint8_t*)file+sizeof(file_info)); zinfo("end check file request"); return make_response_frame(req, true, ); } static std::vector<uint8_t> install_precondition_executor(const request& req) { zinfo("request check install precondition"); ERROR_CODE error_code = check_install_precondition(); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); zinfo("end check install precondition request"); std::vector<uint8_t> res(256, 0); return make_response_frame(req, true, res); } static std::vector<uint8_t> start_update_executor(const request& req) { zinfo("request start update"); //client does not send request data, so don't check data here //RETURN_ERROR_RESP_IF_REQ_DATA_IS_ERR(req, sizeof(install_type), "start_update"); ERROR_CODE error_code=start_update(install_type::NORMAL); zinfo("end start update request"); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); std::vector<uint8_t> res(256, 0); return make_response_frame(req, true, res); //return std::vector<uint8_t>(); //only return state when finish update; } static std::vector<uint8_t> read_rollback_result_executor(const request& req) { zinfo("request read rollback result"); ERROR_CODE error_code = get_rollback_result(); RETURN_ERR_RESPONSE_IF_FAIL(req, error_code); zinfo("end read rollback result request"); std::vector<uint8_t> res(256, 0); return make_response_frame(req, true, res); } using cmd_executor = std::function<std::vector<uint8_t>(const request&)>; struct request_cmd_executor_pair { uint32_t cmd; uint32_t sub_cmd; cmd_executor executor; }; static std::vector<request_cmd_executor_pair> executors{ {0x70, 0x01, read_version_executor}, {0x71, 0x01, start_write_file_executor}, {0x71, 0x02, write_file_data_executor}, {0x71, 0x03, end_write_file_executor}, {0x71, 0x04, check_file_executor}, {0x73, 0x01, install_precondition_executor}, {update_cmd, update_sub_cmd, start_update_executor}, {0x75, 0x01, read_rollback_result_executor}, //add bwb //get cerid,read_certificate_id_executor {0x76, 0x01, read_certificate_id_executor}, //cer verify,certificate_verify__executor {0x76, 0x02, certificate_verify_executor}, //file verify {0x76, 0x03, filesignature_verify_executor}, }; std::vector<uint8_t> handle_req(const request& req) { auto ite = std::find_if(executors.begin(), executors.end(), [&req](const request_cmd_executor_pair& pair){ return (pair.cmd == req.header.cmd) && (pair.sub_cmd == req.header.sub_cmd); }); if (executors.end() == ite) { return invalid_cmd_executor(req); } return ite->executor(req); } request_handler::request_handler(const data_send_func& data_sender) : m_data_sender(data_sender) {} void request_handler::handle_request(gsl::span<uint8_t> datas) { m_buffer.insert(m_buffer.end(), datas.begin(), datas.end()); std::vector<request> requests = parse_data(m_buffer); for (auto &&req : requests) { zdebug("handle req, cmd: %d, sub cmd: %d", req.header.cmd, req.header.sub_cmd); std::vector<uint8_t> response = handle_req(req); if (!response.empty()) { m_data_sender(response); } } } void request_handler::send_update_state() { if (!has_just_update()) { return; } request req; req.header.cmd = update_cmd; req.header.sub_cmd = update_sub_cmd; if (!is_update_success()) { m_data_sender(make_error_response_frame(req, ERROR_CODE::ABNORMAL_EXIT)); } else { std::vector<uint8_t> res(256, 0); m_data_sender(make_response_frame(req, true, res)); } delete_prev_update_result(); }
parser.h
#ifndef _OTA_CMD_PARSER_H_ #define _OTA_CMD_PARSER_H_ #include <vector> #include "request.h" std::vector<request> parse_data(std::vector<uint8_t>& datas); std::vector<uint8_t> make_response_frame(const request& req, bool succeed, const std::vector<uint8_t>& resp_datas); #endif // !_OTA_CMD_PARSER_H_
parser.cpp
#include "parser.h" #include "zros/app_log/log.h" #include "cmd_executor.h" #include "gsl/span" #include "error_code.h" #include "request.h" #include "response.h" #include <cstddef> #include <arpa/inet.h> #include <algorithm> #include <cassert> #include <map> #include <string.h> #include <boost/optional.hpp> constexpr static uint8_t HEADER_FLAG[] = {0xFF,0x5A,0xFF,0xA5}; constexpr static uint8_t TAIL_FLAG[] = {0xFF,0xA5,0xFF,0x5A}; constexpr static std::size_t HEADER_FLAG_LENGTH = sizeof(HEADER_FLAG); constexpr static std::size_t TAIL_FLAG_LENGTH = sizeof(TAIL_FLAG); constexpr static std::size_t REQUEST_HEADER_LENGTH = sizeof(request_header); constexpr static std::size_t HEADER_FLAG_AND_REQ_HEADER_SIZE = HEADER_FLAG_LENGTH + REQUEST_HEADER_LENGTH; static bool find_header_flag(const std::vector<uint8_t>& datas, std::size_t& index) { assert(datas.size() >= HEADER_FLAG_LENGTH); for (index = 0; index <= datas.size()-HEADER_FLAG_LENGTH; index++) { bool found = true; for (size_t header_index = 0; header_index < HEADER_FLAG_LENGTH; header_index++) { if (datas[index+header_index] != HEADER_FLAG[header_index]) { found = false; break; } } if (!found) { continue; } return true; } return false; } static request_header convert_request_header(const request_header& header) { request_header new_request_header = {0}; new_request_header.cmd = header.cmd; new_request_header.sub_cmd = header.sub_cmd; new_request_header.data_length = header.data_length; return new_request_header; } std::vector<uint8_t> make_response_frame(const request& req, bool succeed, const std::vector<uint8_t>& resp_datas) { handle_result result = succeed ? handle_result::OK : handle_result::FAILED; response_header resp_header; resp_header.cmd = req.header.cmd; resp_header.sub_cmd = req.header.sub_cmd; resp_header.error_code = static_cast<uint32_t>(result); resp_header.data_length = resp_datas.size(); std::vector<uint8_t> repsonse_frame; repsonse_frame.insert(repsonse_frame.end(), HEADER_FLAG, HEADER_FLAG + HEADER_FLAG_LENGTH); repsonse_frame.insert(repsonse_frame.end(), (uint8_t*)&resp_header, (uint8_t*)&resp_header + RESPONSE_HEADER_LENGTH); repsonse_frame.insert(repsonse_frame.end(), resp_datas.begin(), resp_datas.end()); repsonse_frame.insert(repsonse_frame.end(), TAIL_FLAG, TAIL_FLAG + TAIL_FLAG_LENGTH); return repsonse_frame; } static boost::optional<request> get_one_request(const std::vector<uint8_t>& datas) { request_header* header = (request_header*)(datas.data() + HEADER_FLAG_LENGTH); request_header new_request_header = convert_request_header(*header); if ((datas.size() - HEADER_FLAG_AND_REQ_HEADER_SIZE) < new_request_header.data_length) { zdebug("find header flag, but frame data is unenough, request data size: %d, but left data size: %d", new_request_header.data_length, datas.size()); return boost::none; } request new_request; new_request.header = new_request_header; new_request.datas.insert(new_request.datas.end(), (uint8_t*)header+REQUEST_HEADER_LENGTH, (uint8_t*)header+REQUEST_HEADER_LENGTH+new_request_header.data_length); return new_request; } std::vector<request> parse_data(std::vector<uint8_t>& datas) { std::vector<request> requests; while (true) { if (datas.size() < HEADER_FLAG_AND_REQ_HEADER_SIZE) { return requests; } std::size_t header_index = 0; bool is_find_header = find_header_flag(datas, header_index); datas.erase(datas.begin(), std::next(datas.begin(), header_index)); if (!is_find_header) { zdebug("not find header flag"); return requests; } if (datas.size() < HEADER_FLAG_AND_REQ_HEADER_SIZE) { zdebug("find header flag, but frame header data is unenough"); return requests; } auto new_request = get_one_request(datas); if (!new_request) { zdebug("find header flag, but frame data is unenough"); return requests; } zdebug("parse request, request cmd: %d", new_request->header.cmd); datas.erase(datas.begin(), std::next(datas.begin(), HEADER_FLAG_AND_REQ_HEADER_SIZE+new_request->datas.size())); requests.push_back(*new_request); } return requests; }
request.h
#ifndef _OTA_REQUEST_H_ #define _OTA_REQUEST_H_ #include <cstdint> #include <vector> enum class REQUEST_CMD { INVALID_CMD, READ_VERSION, START_WRITE_FILE, WRITE_FILE_DATA, END_WRITE_FILE, CHECK_FILE, CHECK_INSTALL_PRECONDITION, START_UPDATE, GET_ROLLBACK_RESULT, }; struct request_header { uint32_t cmd; uint32_t sub_cmd; uint32_t data_length; }; struct request { request_header header; std::vector<uint8_t> datas; }; #endif // !_OTA_REQUEST_H_
response.h
#ifndef _OTA_RESPONSE_H_ #define _OTA_RESPONSE_H_ enum class handle_result: uint32_t {FAILED = 0, OK = 1}; struct response_header { uint32_t cmd; uint32_t sub_cmd; uint32_t error_code; uint32_t data_length; }; struct response { response_header header; std::vector<uint8_t> datas; }; constexpr static std::size_t RESPONSE_HEADER_LENGTH = sizeof(response_header); #endif // !_OTA_RESPONSE_H_

浙公网安备 33010602011771号