简单服务器框架---(基于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_

 

posted @ 2025-02-25 17:26  白伟碧一些小心得  阅读(47)  评论(0)    收藏  举报