simulator.cpp 7.79 KB
/****************************************************************************
 *
 *   Copyright (c) 2015 Mark Charlebois. All rights reserved.
 *   Copyright (c) 2016-2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file simulator.cpp
 *
 * This module interfaces via MAVLink to a software in the loop simulator (SITL)
 * such as jMAVSim or Gazebo.
 */

#include <px4_platform_common/log.h>
#include <px4_platform_common/tasks.h>
#include <px4_platform_common/time.h>
#include <systemlib/err.h>
#include <drivers/drv_board_led.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <fstream>
#include <cstring>

#include "simulator.h"

static px4_task_t g_sim_task = -1;

Simulator *Simulator::_instance = nullptr;

void Simulator::parameters_update(bool force)
{
	// check for parameter updates
	if (_parameter_update_sub.updated() || force) {
		// clear update
		parameter_update_s pupdate;
		_parameter_update_sub.copy(&pupdate);

		// update parameters from storage
		updateParams();
	}
}

int Simulator::verify()
{
/*
	char path[256];
	if(getcwd(path, 256) == NULL)
		PX4_INFO("Test path: %s", strerror(errno));
	else
		PX4_INFO("Test path: %s", path);
*/

	std::ifstream fin;
	BIO* bio;
	EVP_PKEY* pkey = NULL;

	const char* file_path = "../../bin/px4";	
//	const char* file_path = "../../../../Tools/test.txt";
	const char* sig_path = "../../../../Tools/signature";	
	const char* key_path = "../../../../Tools/public_key";

	int file_size = 0, sig_size = 0, key_size = 0;

	// open exe file
	fin.open(file_path);
	if (fin.fail()) {
		PX4_WARN("Error: Can't open exe file during signature verifying.");
		return 0;
	}
	fin.seekg(0, std::ios::end);
	file_size = fin.tellg();
	fin.seekg(0, std::ios::beg);
	unsigned char* file = new unsigned char[file_size];
	fin.read((char*)file, file_size);
	fin.close();

	// open signature file
	fin.open(sig_path);
	if (fin.fail()) {
		PX4_WARN("Error: Can't open signature file during signature verifying.");
		return 0;
	}
	fin.seekg(0, std::ios::end);
	sig_size = fin.tellg();
	fin.seekg(0, std::ios::beg);
	unsigned char* sig_char = new unsigned char[sig_size];
	fin.read((char*)sig_char, sig_size);
	fin.close();
	unsigned char sig[65] = { 0 };
	char temp[3] = { 0 };
	for (int i = 0; i < sig_size; i+=2)
	{
		temp[0] = sig_char[i];
		temp[1] = sig_char[i+1];
		sig[i/2] = (unsigned char)strtol(temp, NULL, 16);
	}
	delete[] sig_char;
	sig_size /= 2;

	// open public key file
	fin.open(key_path);
	if (fin.fail()) {
		PX4_WARN("Error: Can't open public key file during signature verifying.");
		return 0;
	}
	fin.seekg(0, std::ios::end);
	key_size = fin.tellg();
	fin.seekg(0, std::ios::beg);
	unsigned char* key = new unsigned char[key_size];
	fin.read((char*)key, key_size);
	fin.close();

	// make key file to pkey
	bio = BIO_new( BIO_s_mem() );
	BIO_write(bio, key, key_size);
	if (PEM_read_bio_PUBKEY(bio, &pkey, NULL, NULL) == NULL) {
		PX4_WARN("Error: PEM_read_bio_PUBKEY");	//ERR_error_string(ERR_get_error(), NULL)
		return 0;
	}
	delete[] key;
	BIO_free(bio);

	// verifying signature
	EVP_MD_CTX* ctx = EVP_MD_CTX_new();
	if (EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey) != 1) {
		PX4_WARN("Error: EVP_DigestVerifyInit");	//ERR_error_string(ERR_get_error(), NULL)
		return 0;
	}
	if (EVP_DigestVerify(ctx, sig, sig_size, file, file_size) != 1) {
		return 0;
	}
	EVP_PKEY_free(pkey);	
	EVP_MD_CTX_free(ctx);
	delete[] file;

	PX4_INFO("Success: Verifying Signature");

	return 1;
}

int Simulator::start(int argc, char *argv[])
{

	_instance = new Simulator();

	if (_instance->verify() != 1) {
		PX4_ERR("Signature Verifying failed");
		return 1;
	}

	if (_instance) {

		if (argc == 5 && strcmp(argv[3], "-u") == 0) {
			_instance->set_ip(InternetProtocol::UDP);
			_instance->set_port(atoi(argv[4]));
		}

		if (argc == 5 && strcmp(argv[3], "-c") == 0) {
			_instance->set_ip(InternetProtocol::TCP);
			_instance->set_port(atoi(argv[4]));
		}

		if (argc == 6 && strcmp(argv[3], "-t") == 0) {
			PX4_INFO("Simulator using TCP on remote host %s port %s", argv[4], argv[5]);
			PX4_WARN("Please ensure port %s is not blocked by a firewall.", argv[5]);
			_instance->set_ip(InternetProtocol::TCP);
			_instance->set_tcp_remote_ipaddr(argv[4]);
			_instance->set_port(atoi(argv[5]));
		}

		if (argc == 6 && strcmp(argv[3], "-h") == 0) {
			PX4_INFO("Simulator using TCP on remote host %s port %s", argv[4], argv[5]);
			PX4_WARN("Please ensure port %s is not blocked by a firewall.", argv[5]);
			_instance->set_ip(InternetProtocol::TCP);
			_instance->set_hostname(argv[4]);
			_instance->set_port(atoi(argv[5]));
		}

		_instance->run();

		return 0;

	} else {
		PX4_WARN("Simulator creation failed");
		return 1;
	}
}

static void usage()
{
	PX4_INFO("Usage: simulator {start -[spt] [-u udp_port / -c tcp_port] |stop|status}");
	PX4_INFO("Start simulator:     simulator start");
	PX4_INFO("Connect using UDP: simulator start -u udp_port");
	PX4_INFO("Connect using TCP: simulator start -c tcp_port");
	PX4_INFO("Connect to a remote server using TCP: simulator start -t ip_addr tcp_port");
	PX4_INFO("Connect to a remote server via hostname using TCP: simulator start -h hostname tcp_port");
}

__BEGIN_DECLS
extern int simulator_main(int argc, char *argv[]);
__END_DECLS


int simulator_main(int argc, char *argv[])
{
	if (argc > 1 && strcmp(argv[1], "start") == 0) {

		if (g_sim_task >= 0) {
			PX4_WARN("Simulator already started");
			return 0;
		}

		g_sim_task = px4_task_spawn_cmd("simulator",
						SCHED_DEFAULT,
						SCHED_PRIORITY_MAX,
						1500,
						Simulator::start,
						argv);

#if defined(ENABLE_LOCKSTEP_SCHEDULER)

		// We want to prevent the rest of the startup script from running until time
		// is initialized by the HIL_SENSOR messages from the simulator.
		while (true) {
			if (Simulator::getInstance() && Simulator::getInstance()->has_initialized()) {
				break;
			}

			system_usleep(100);
		}

#endif

	} else if (argc == 2 && strcmp(argv[1], "stop") == 0) {
		if (g_sim_task < 0) {
			PX4_WARN("Simulator not running");
			return 1;

		} else {
			px4_task_delete(g_sim_task);
			g_sim_task = -1;
		}

	} else if (argc == 2 && strcmp(argv[1], "status") == 0) {
		if (g_sim_task < 0) {
			PX4_WARN("Simulator not running");
			return 1;

		} else {
			PX4_INFO("running");
		}

	} else {
		usage();
		return 1;
	}

	return 0;
}