minifi::c2::C2Payload CoapProtocol::serialize()

in extensions/coap/protocols/CoapC2Protocol.cpp [193:295]


minifi::c2::C2Payload CoapProtocol::serialize(const minifi::c2::C2Payload &payload) {
  if (nullptr == coap_service_) {
    // return an error if we don't have a coap service
    logger_->log_error("CoAP service requested without any configured hostname or port");
    return {payload.getOperation(), state::UpdateState::READ_ERROR};
  }

  if (require_registration_) {
    logger_->log_debug("Server requested agent registration, so attempting");
    auto response = minifi::c2::RESTSender::consumePayload(rest_uri_, payload, minifi::c2::TRANSMIT, false);
    if (response.getStatus().getState() == state::UpdateState::READ_ERROR) {
      logger_->log_trace("Could not register");
      return {payload.getOperation(), state::UpdateState::READ_COMPLETE};
    } else {
      logger_->log_trace("Registered agent.");
    }
    require_registration_ = false;

    return {payload.getOperation(), state::UpdateState::READ_COMPLETE};
  }

  uint16_t version = 0;
  uint8_t payload_type = 0;
  uint16_t size = 0;
  io::BufferStream stream;

  stream.write(version);
  std::string endpoint = "heartbeat";
  switch (payload.getOperation()) {
    case minifi::c2::Operation::acknowledge:
      endpoint = "acknowledge";
      payload_type = 0;
      stream.write(&payload_type, 1);
      if (writeAcknowledgement(&stream, payload) != 0) {
        return {payload.getOperation(), state::UpdateState::READ_ERROR};
      }
      break;
    case minifi::c2::Operation::heartbeat:
      payload_type = 1;
      stream.write(&payload_type, 1);
      if (writeHeartbeat(&stream, payload) != 0) {
        logger_->log_error("Could not write heartbeat");
        return {payload.getOperation(), state::UpdateState::READ_ERROR};
      }
      break;
    default:
      logger_->log_error("Could not identify operation");
      return {payload.getOperation(), state::UpdateState::READ_ERROR};
  }

  size_t bsize = stream.size();

  CoapMessage msg;
  msg.data_ = const_cast<uint8_t *>(utils::as_span<const uint8_t>(stream.getBuffer()).data());
  msg.size_ = bsize;

  coap::controllers::CoapResponse message = coap_service_->sendPayload(COAP_REQUEST_POST, endpoint, &msg);
  const auto message_data = message.getData();

  if (isRegistrationMessage(message)) {
    require_registration_ = true;
  } else if (!message_data.empty()) {
    io::BufferStream responseStream(message_data);
    responseStream.read(version);
    responseStream.read(size);
    logger_->log_trace("Received ack. version %d. number of operations %d", version, size);
    minifi::c2::C2Payload new_payload(payload.getOperation(), state::UpdateState::NESTED);
    for (int i = 0; i < size; i++) {
      uint8_t operationType;
      uint16_t argsize = 0;
      std::string operand;
      std::string id;
      REQUIRE_SIZE_IF(1, responseStream.read(operationType))
      REQUIRE_VALID(responseStream.read(id, false))
      REQUIRE_VALID(responseStream.read(operand, false))

      logger_->log_trace("Received op %d, with id %s and operand %s", operationType, id, operand);
      auto newOp = getOperation(operationType);
      minifi::c2::C2Payload nested_payload(newOp, state::UpdateState::READ_COMPLETE);
      nested_payload.setIdentifier(id);
      minifi::c2::C2ContentResponse new_command(newOp);
      new_command.delay = 0;
      new_command.required = true;
      new_command.ttl = -1;
      new_command.name = operand;
      new_command.ident = id;
      responseStream.read(argsize);
      for (int j = 0; j < argsize; j++) {
        std::string key;
        std::string value;
        REQUIRE_VALID(responseStream.read(key))
        REQUIRE_VALID(responseStream.read(value))
        new_command.operation_arguments[key] = value;
      }

      nested_payload.addContent(std::move(new_command));
      new_payload.addPayload(std::move(nested_payload));
    }
    return new_payload;
  }

  return {payload.getOperation(), state::UpdateState::READ_ERROR};
}