<commit_before>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <ctime>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <chrono>
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <algorithm>
#include <chrono>
#include <map>
#include <set>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

char randomNucleotide(){
	switch (rand() % 4){
		case 0:
			return 'A';
		case 1:
			return 'C';
		case 2:
			return 'G';
		case 3:
			return 'T';
	}
	return 'A';
}

string randomSequence(const uint length){
	string result(length, 'A');
	for(uint i(0); i < length; ++i){
		result[i] = randomNucleotide();
	}
	return result;
}

void insertion(uint rate, string& result){
	uint dice(rand() % 100);
	if(dice < rate){
		char newNucleotide(randomNucleotide());
		result.push_back(newNucleotide);
		insertion(rate, result);
	}
}

string mutateSequence(const string& referenceSequence, uint maxMutRate=0, vector <double> ratioMutation={0.06,0.73,0.21}){
//~ string mutateSequence(const string& referenceSequence, uint maxMutRate=3, vector <double> ratioMutation={0.06,0.73,0.21}){
	string result;
	result.reserve(5 * referenceSequence.size());
	for(uint i(0); i < referenceSequence.size(); ++i){
		uint mutRate(maxMutRate);
		//~ uint mutRate(rand() % maxMutRate);
		double substitutionRate(mutRate * ratioMutation[0]);
		double insertionRate(mutRate * ratioMutation[1]);
		double deletionRate(mutRate * ratioMutation[2]);
		uint dice(rand() % 100);

		if (dice <substitutionRate ){
			//SUBSTITUTION
			char newNucleotide(randomNucleotide());
			while(newNucleotide == referenceSequence[i]){
				newNucleotide = randomNucleotide();
			}
			result.push_back(newNucleotide);
			continue;
		} else if(dice < deletionRate+substitutionRate){
			//DELETION
			uint dice2(rand() % 100);
			while (dice2 < deletionRate+substitutionRate){ // deletions larger than 1
				++i;
				dice2 = rand() % 100;
			}
			continue;
		} else if (dice < deletionRate + substitutionRate + insertionRate){
			//INSERTION
			char newNucleotide(randomNucleotide());
			result.push_back(referenceSequence[i]);
			result.push_back(newNucleotide);
			//~ --i;
			insertion(deletionRate + substitutionRate + insertionRate, result); // larger than 1 insertions

			continue;
		} else {
		//NO ERROR
			result.push_back(referenceSequence[i]);
		}

	}
	return result;
}

vector<string> generateAlternativeTranscriptReferences(uint transcriptNumber=1, uint totalExonNumber=1, uint exonNumber=1, uint sizeExons=200){

	vector<string> result;
	vector<string> exonList;
	for(uint i(0); i < totalExonNumber; ++i){
		exonList.push_back(randomSequence(sizeExons));
	}
	string transcript;
	transcript.reserve(exonNumber*sizeExons);
	unordered_set<uint> selectedExons;
	uint dice1, transcriptExonNumber;
	for(uint i(0); i < transcriptNumber; ++i){
		if (transcriptNumber > 1){
			dice1 = (rand() % (totalExonNumber-3));
			transcriptExonNumber = (dice1 + 3);
		} else {
			transcriptExonNumber = 0;
		}
		cout << transcriptExonNumber << endl;
		transcript = "";
		selectedExons = {};
		if (transcriptExonNumber > 0){
			while(selectedExons.size() != transcriptExonNumber){
				selectedExons.insert(rand() % totalExonNumber);
			}
		} else {
			selectedExons.insert(0);
		}
		for(uint ii(0); ii < totalExonNumber; ++ii){
			if(selectedExons.count(ii) == 1){
				transcript += exonList[ii];
			}

		}
		result.push_back(transcript);
	}
	return result;
}

void generateReads(uint numberReads, uint referencesNumber=1, const string& outFileName="simulatedReads.fa", const string& refFileName="RefFile"){
	ofstream out(outFileName);
	ofstream outRef(refFileName);
	vector<vector<string>> referenceList;
	for(uint i(0);i < referencesNumber; ++i){
		referenceList.push_back(generateAlternativeTranscriptReferences());
		for(uint ii(0); ii<referenceList[i].size(); ++ii){
			outRef << ">referenceNumber:" << i << " alternativeNumber" << ii << " length"<< referenceList[i][ii].size() << endl;
			outRef << referenceList[i][ii] << endl;
		}
	}

	string refRead,realRead;
	for(uint i(0); i < numberReads; ++i){
		uint dice1(rand() % referencesNumber);
		uint dice2(rand() % referenceList[dice1].size());
		refRead = referenceList[dice1][dice2];
		realRead = mutateSequence(refRead);
		out << ">referenceNumber:" << dice1 << " alternativeNumber" << dice2 << " length" << realRead.size() << endl;
		out << realRead << endl;
	}
}

int main(int argc, char ** argv){
	srand (time(NULL));
	auto startChrono = chrono::system_clock::now();
	generateReads(100);
	auto end = chrono::system_clock::now(); auto waitedFor = end - startChrono;
	cout << "Time  in ms : " << (chrono::duration_cast<chrono::milliseconds>(waitedFor).count()) << endl;
	return 0;
}
<commit_msg>some parameters as inputs of the tool<commit_after>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <ctime>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <chrono>
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <algorithm>
#include <chrono>
#include <map>
#include <set>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

char randomNucleotide(){
	switch (rand() % 4){
		case 0:
			return 'A';
		case 1:
			return 'C';
		case 2:
			return 'G';
		case 3:
			return 'T';
	}
	return 'A';
}

string randomSequence(const uint length){
	string result(length, 'A');
	for(uint i(0); i < length; ++i){
		result[i] = randomNucleotide();
	}
	return result;
}

void insertion(uint rate, string& result){
	uint dice(rand() % 100);
	if(dice < rate){
		char newNucleotide(randomNucleotide());
		result.push_back(newNucleotide);
		insertion(rate, result);
	}
}

string mutateSequence(const string& referenceSequence, uint maxMutRate, vector <double> ratioMutation={0.06,0.73,0.21}){
//~ string mutateSequence(const string& referenceSequence, uint maxMutRate=3, vector <double> ratioMutation={0.06,0.73,0.21}){
	string result;
	result.reserve(5 * referenceSequence.size());
	for(uint i(0); i < referenceSequence.size(); ++i){
		uint mutRate(maxMutRate);
		//~ uint mutRate(rand() % maxMutRate);
		double substitutionRate(mutRate * ratioMutation[0]);
		double insertionRate(mutRate * ratioMutation[1]);
		double deletionRate(mutRate * ratioMutation[2]);
		uint dice(rand() % 100);

		if (dice <substitutionRate ){
			//SUBSTITUTION
			char newNucleotide(randomNucleotide());
			while(newNucleotide == referenceSequence[i]){
				newNucleotide = randomNucleotide();
			}
			result.push_back(newNucleotide);
			continue;
		} else if(dice < deletionRate+substitutionRate){
			//DELETION
			uint dice2(rand() % 100);
			while (dice2 < deletionRate+substitutionRate){ // deletions larger than 1
				++i;
				dice2 = rand() % 100;
			}
			continue;
		} else if (dice < deletionRate + substitutionRate + insertionRate){
			//INSERTION
			char newNucleotide(randomNucleotide());
			result.push_back(referenceSequence[i]);
			result.push_back(newNucleotide);
			//~ --i;
			insertion(deletionRate + substitutionRate + insertionRate, result); // larger than 1 insertions

			continue;
		} else {
		//NO ERROR
			result.push_back(referenceSequence[i]);
		}

	}
	return result;
}

vector<string> generateAlternativeTranscriptReferences(uint transcriptNumber=3, uint totalExonNumber=15, uint exonNumber=12, uint sizeExons=200){

	vector<string> result;
	vector<string> exonList;
	for(uint i(0); i < totalExonNumber; ++i){
		exonList.push_back(randomSequence(sizeExons));
	}
	string transcript;
	transcript.reserve(exonNumber*sizeExons);
	unordered_set<uint> selectedExons;
	uint dice1, transcriptExonNumber;
	for(uint i(0); i < transcriptNumber; ++i){
		if (transcriptNumber > 1){
			dice1 = (rand() % (totalExonNumber-3));
			transcriptExonNumber = (dice1 + 3);
		} else {
			transcriptExonNumber = 0;
		}
		cout << transcriptExonNumber << endl;
		transcript = "";
		selectedExons = {};
		if (transcriptExonNumber > 0){
			while(selectedExons.size() != transcriptExonNumber){
				selectedExons.insert(rand() % totalExonNumber);
			}
		} else {
			selectedExons.insert(0);
		}
		for(uint ii(0); ii < totalExonNumber; ++ii){
			if(selectedExons.count(ii) == 1){
				transcript += exonList[ii];
			}

		}
		result.push_back(transcript);
	}
	return result;
}

void generateReads(uint numberReads, uint mutRate, uint referencesNumber, const string& outFileName="simulatedReads.fa", const string& refFileName="RefFile"){
	ofstream out(outFileName);
	ofstream outRef(refFileName);
	vector<vector<string>> referenceList;
	for(uint i(0);i < referencesNumber; ++i){
		referenceList.push_back(generateAlternativeTranscriptReferences());
		for(uint ii(0); ii<referenceList[i].size(); ++ii){
			outRef << ">referenceNumber:" << i << " alternativeNumber" << ii << " length"<< referenceList[i][ii].size() << endl;
			outRef << referenceList[i][ii] << endl;
		}
	}

	string refRead,realRead;
	for(uint i(0); i < numberReads; ++i){
		uint dice1(rand() % referencesNumber);
		uint dice2(rand() % referenceList[dice1].size());
		refRead = referenceList[dice1][dice2];
		realRead = mutateSequence(refRead, mutRate);
		out << ">referenceNumber:" << dice1 << " alternativeNumber" << dice2 << " length" << realRead.size() << endl;
		out << realRead << endl;
	}
}

int main(int argc, char ** argv){
	srand (time(NULL));
	if (argc > 3){
		auto startChrono = chrono::system_clock::now();
		uint nbReads(stoi(argv[1]));
		uint mut(stoi(argv[2]));
		uint genes(stoi(argv[3]));
		generateReads(nbReads, mut, genes);
		auto end = chrono::system_clock::now(); auto waitedFor = end - startChrono;
		cout << "Time  in ms : " << (chrono::duration_cast<chrono::milliseconds>(waitedFor).count()) << endl;
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <string>
#include "alphabet.h"

using namespace std;

string pwd;

static const unsigned char MaxChars = 20;

void checkPassword(string password)
{
    cout << "checking " << password << endl;

    // TODO: generate sha hash, compare hashes

    if (password==pwd)
    {
        cout << "match [" << password << "]" << endl;
        exit(0);
    }
}

void brute(string baseString, int width, int position)
{
    for(int i=0; i<SizeAlphabet; i++)
    {
        if (position+1 < width)
        {
            brute(baseString+alphabet[i], width, position+1);
        }

        checkPassword(baseString+alphabet[i]);
    }
}

int main()
{
    cout << "Enter a string: " << endl;
    cin >> pwd;

    for(int i=1; i<=MaxChars; i++)
    {
        cout << "checking passwords with " << i << " characters..." << endl;
        brute(string(""),i,0);
    }

    return 1;
}
<commit_msg>rename main() to bruteInit()<commit_after>#include <iostream>
#include <cstdlib>
#include <string>
#include "alphabet.h"

using namespace std;

string pwd;

static const unsigned char MaxChars = 20;

void checkPassword(string password)
{
    cout << "checking " << password << endl;

    // TODO: generate sha hash, compare hashes

    if (password==pwd)
    {
        cout << "match [" << password << "]" << endl;
        exit(0);
    }
}

void brute(string baseString, int width, int position)
{
    for(int i=0; i<SizeAlphabet; i++)
    {
        if (position+1 < width)
        {
            brute(baseString+alphabet[i], width, position+1);
        }

        checkPassword(baseString+alphabet[i]);
    }
}

int bruteInit()
{
    cout << "Enter a string: " << endl;
    cin >> pwd;

    for(int i=1; i<=MaxChars; i++)
    {
        cout << "checking passwords with " << i << " characters..." << endl;
        brute(string(""),i,0);
    }

    return 1;
}
<|endoftext|>


<commit_before>#include "dsa_common.h"

#include "link.h"

#include <util/string.h>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <fstream>
#include <regex>

#include "core/client.h"
#include "crypto/ecdh.h"
#include "module/default/console_logger.h"
#include "module/default/dummy_stream_acceptor.h"
#include "module/default/simple_security_manager.h"
#include "module/default/simple_session_manager.h"
#include "network/tcp/stcp_client_connection.h"
#include "network/tcp/tcp_client_connection.h"
#include "network/tcp/tcp_server.h"
#include "network/ws/ws_client_connection.h"
#include "node/link_root.h"
#include "stream/requester/incoming_invoke_stream.h"
#include "stream/requester/incoming_set_stream.h"
#include "util/app.h"
#include "util/string.h"

namespace opts = boost::program_options;
namespace fs = boost::filesystem;

namespace dsa {

DsLink::DsLink(int argc, const char *argv[], const string_ &link_name,
               const string_ &version, const shared_ptr_<App> &app) {
  opts::options_description desc{"Options"};
  desc.add_options()("help,h", "Help screen")  //
      ("broker,b", opts::value<string_>()->default_value("127.0.0.1"),
       "Broker Url")  // broker url
      ("log,l", opts::value<string_>()->default_value("info"),
       "Log Level [all,trace,debug,info,warn,error,fatal,none]")  // log level
      ("token,t", opts::value<string_>()->default_value(""),
       "Token file path")  // token
      ("thread", opts::value<size_t>()->default_value(1),
       "Number of thread")  // custom name
      ("name,n", opts::value<string_>()->default_value(link_name),
       "Override Link Name")  // custom name
      ("server-port", opts::value<uint16_t>()->default_value(0),
       "Tcp Server Port")  // custom name
      ;

  opts::variables_map variables;
  try {
    opts::store(opts::parse_command_line(argc, argv, desc), variables);
    opts::notify(variables);
  } catch (std::exception &e) {
    LOG_FATAL(
        LOG
        << "Invalid input, please check available parameters with --help\n");
  }

  // show help and exit
  if (variables.count("help")) {
    std::cout << desc << '\n';
    exit(0);
  }

  own_app = false;
  _app = app;
  // If app object is already given, thread option is ignored in args
  if (_app.get() == nullptr) {
    parse_thread(variables["thread"].as<size_t>());
    own_app = true;
  }

  strand.reset(new EditableStrand(
      get_app().new_strand(), std::unique_ptr<ECDH>(ECDH::from_file(".key"))));

  // TOKEN from file
  client_token = "";
  auto client_token_path = variables["token"].as<string_>();
  if (client_token_path.length() != 0) {
    try {
      client_token = string_from_file(client_token_path);
    } catch (std::exception &e) {
      LOG_FATAL(LOG << "Fatal loading token file " << client_token_path
                    << " with error : " << e.what());
    }
  }

  close_token = get_close_token_from_file();

  parse_url(variables["broker"].as<string_>());
  parse_name(variables["name"].as<string_>());
  parse_log(variables["log"].as<string_>(), *strand);
  parse_server_port(variables["server-port"].as<uint16_t>());

  LOG_TRACE(strand.get()->logger(), LOG << "DSLink initialized successfully");
}
DsLink::~DsLink() {}

App &DsLink::get_app() { return *_app; }

void DsLink::destroy_impl() {
  //  shared_ptr_<App> _app;
  //  shared_ptr_<TcpServer> _tcp_server;
  //  ref_<Client> _client;
  //
  //  bool _running = false;
  //
  //  OnConnectCallback _user_on_connect;
  if (_tcp_server != nullptr) {
    _tcp_server->destroy();
    _tcp_server.reset();
  }
  if (_client) {
    _client->destroy();
    _client.reset();
  }

  // child remove itself from array
  while (!_subscribe_mergers.empty()) {
    // If you dont create lvalue from it
    // gets heap usage after free error because
    // reference count drops zero in destroy
    auto p = _subscribe_mergers.begin()->second;
    p->destroy();
  }

  // child remove itself from array
  while (!_list_mergers.empty()) {
    // If you dont create lvalue from it
    // gets heap usage after free error because
    // reference count drops zero in destroy
    auto p = _list_mergers.begin()->second;
    p->destroy();
  }

  WrapperStrand::destroy_impl();
  if (own_app) {
    _app->close();
  }
}

void DsLink::parse_thread(size_t thread) {
  if (thread < 1) {
    thread = 1;
  } else if (thread > 16) {
    thread = 16;
  }
  _app.reset(new App(thread));
}
void DsLink::parse_url(const string_ &url) {
  static std::regex url_regex(
      R"(^(ds://|dss://|ws://|wss://)?([^/:\[]+|\[[0-9A-Fa-f:]+\])(:\d+)?(/.*)?$)");

  auto match = std::sregex_iterator(url.begin(), url.end(), url_regex);
  if (match == std::sregex_iterator()) {  // match is a empty iterator
    LOG_FATAL(LOG << "Invalid Broker Url: " << url);
  }
  string_ protocol = (*match)[1].str();

  if (protocol == "ws://" || protocol == "wss://") {
    if (protocol == "wss://") {
      secure = true;
      ws_port = 443;  // default wss port
    } else {
      ws_port = 80;  // default ws port
    }
    ws_host = (*match)[2].str();
    if ((*match)[3].length() > 1) {
      ws_port = static_cast<uint16_t>(
          std::stoi(string_((*match)[3].first + 1, (*match)[3].second)));
    }
    ws_path = (*match)[4].str();
  } else {
    if (protocol == "dss://") {
      secure = true;
      tcp_port = 4128;  // default dss port
    } else {            // "ds://" or blank
      tcp_port = 4120;  // default ds port
    }
    tcp_host = (*match)[2].str();
    if ((*match)[3].length() > 1) {
      tcp_port = static_cast<uint16_t>(
          std::stoi(string_((*match)[3].first + 1, (*match)[3].second)));
    }
  }
}

void DsLink::parse_log(const string_ &log, EditableStrand &config) {
  auto logger = std::unique_ptr<Logger>(new ConsoleLogger());
  logger->level = Logger::parse(log);
  config.set_logger(std::move(logger));
}
void DsLink::parse_name(const string_ &name) { dsid_prefix = name; }
void DsLink::parse_server_port(uint16_t port) { tcp_server_port = port; }

void DsLink::init_responder_raw(ref_<NodeModelBase> &&root_node) {
  strand->set_session_manager(make_ref_<SimpleSessionManager>(strand));
  strand->set_security_manager(make_ref_<SimpleSecurityManager>());
  strand->set_responder_model(std::move(root_node));
}
void DsLink::init_responder(ref_<NodeModelBase> &&main_node) {
  _root = make_ref_<LinkRoot>(strand->get_ref(), get_ref());
  if (main_node != nullptr) {
    _root->set_main(std::move(main_node));
  }
  init_responder_raw(_root->get_ref());
}

ref_<NodeModelBase> DsLink::add_to_main_node(const string_ &name,
                                             ref_<NodeModel> &&node) {
  return std::move(_root->add_to_main(name, std::move(node)));
}
void DsLink::remove_from_main_node(const string_ &name) {
  _root->remove_from_main(name);
}

void DsLink::connect(Client::OnConnectCallback &&on_connect,
                     uint8_t callback_type) {
  if (_connected) {
    LOG_FATAL(
        LOG << "DsLink::connect(), Dslink is already requested for connection");
    return;
  }
  _connected = true;

  strand->dispatch([ =, on_connect = std::move(on_connect) ]() mutable {

    if (tcp_server_port > 0) {
      _tcp_server = make_shared_<TcpServer>(*this);
      _tcp_server->start();
    }

    if (tcp_port > 0) {
      if (secure) {
        static boost::asio::ssl::context context(
            boost::asio::ssl::context::sslv23);
        boost::system::error_code error;
        context.load_verify_file("certificate.pem", error);
        if (error) {
          LOG_FATAL(LOG << "Failed to verify cetificate");
        }

        client_connection_maker =
            [
              &context, dsid_prefix = dsid_prefix, tcp_host = tcp_host,
              tcp_port = tcp_port
            ](LinkStrandRef & strand, const string_ &previous_session_id,
              int32_t last_ack_id) {
          return make_shared_<StcpClientConnection>(
              strand, context, dsid_prefix, tcp_host, tcp_port);
        };
      } else {
        client_connection_maker =
            [
              dsid_prefix = dsid_prefix, tcp_host = tcp_host,
              tcp_port = tcp_port
            ](LinkStrandRef & strand, const string_ &previous_session_id,
              int32_t last_ack_id) {
          return make_shared_<TcpClientConnection>(strand, dsid_prefix,
                                                   tcp_host, tcp_port);
        };
      }
    } else if (ws_port > 0) {
      client_connection_maker =
          [ dsid_prefix = dsid_prefix, ws_host = ws_host, ws_port = ws_port ](
              LinkStrandRef & strand, const string_ &previous_session_id,
              int32_t last_ack_id) {
        return make_shared_<WsClientConnection>(strand, dsid_prefix, ws_host,
                                                ws_port);
      };
    }

    _client = make_ref_<Client>(*this);
    _client->connect(std::move(on_connect), callback_type);
    LOG_SYSTEM(strand.get()->logger(), LOG << "DsLink connection requested");
  });
}

void DsLink::run(Client::OnConnectCallback &&on_connect,
                 uint8_t callback_type) {
  if (_running) {
    LOG_FATAL(LOG << "DsLink::run(), Dslink is already running");
    return;
  }
  _running = true;

  if (!strand->is_responder_set()) {
    LOG_WARN(strand->logger(), LOG << "responder is not initialized");
    _client->get_session().responder_enabled = false;
    strand->set_stream_acceptor(make_ref_<DummyStreamAcceptor>());
  }

  if (!_connected) {
    connect(std::move(on_connect), callback_type);
  } else {
    LOG_SYSTEM(strand.get()->logger(),
               LOG << "DsLink on_connect callback "
                      "ignored since it was connected "
                      "before\n");
  }
  LOG_SYSTEM(strand.get()->logger(), LOG << "DsLink running");
  if (own_app) {
    _app->wait();
    destroy();
  }
}

// requester features

ref_<IncomingSubscribeCache> DsLink::subscribe(
    const string_ &path, IncomingSubscribeCache::Callback &&callback,
    const SubscribeOptions &options) {
  if (_subscribe_mergers.count(path) == 0) {
    _subscribe_mergers[path] = make_ref_<SubscribeMerger>(get_ref(), path);
  }
  auto merger = _subscribe_mergers[path];
  return merger->subscribe(std::move(callback), options);
}
ref_<IncomingListCache> DsLink::list(const string_ &path,
                                     IncomingListCache::Callback &&callback) {
  if (_list_mergers.count(path) == 0) {
    _list_mergers[path] = make_ref_<ListMerger>(get_ref(), path);
  }
  auto merger = _list_mergers[path];
  return merger->list(std::move(callback));
}
ref_<IncomingInvokeStream> DsLink::invoke(
    IncomingInvokeStreamCallback &&callback,
    ref_<const InvokeRequestMessage> &&message) {
  return _client->get_session().requester.invoke(std::move(callback),
                                                 std::move(message));
}

ref_<IncomingSetStream> DsLink::set(IncomingSetStreamCallback &&callback,
                                    ref_<const SetRequestMessage> &&message) {
  return _client->get_session().requester.set(std::move(callback),
                                              std::move(message));
}
string_ DsLink::get_close_token() { return close_token; }
}
<commit_msg>fix VS compilation error<commit_after>#include "dsa_common.h"

#include "link.h"

#include <util/string.h>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <fstream>
#include <regex>

#include "core/client.h"
#include "crypto/ecdh.h"
#include "module/default/console_logger.h"
#include "module/default/dummy_stream_acceptor.h"
#include "module/default/simple_security_manager.h"
#include "module/default/simple_session_manager.h"
#include "network/tcp/stcp_client_connection.h"
#include "network/tcp/tcp_client_connection.h"
#include "network/tcp/tcp_server.h"
#include "network/ws/ws_client_connection.h"
#include "node/link_root.h"
#include "stream/requester/incoming_invoke_stream.h"
#include "stream/requester/incoming_set_stream.h"
#include "util/app.h"
#include "util/string.h"

namespace opts = boost::program_options;
namespace fs = boost::filesystem;

namespace dsa {

DsLink::DsLink(int argc, const char *argv[], const string_ &link_name,
               const string_ &version, const shared_ptr_<App> &app) {
  opts::options_description desc{"Options"};
  desc.add_options()("help,h", "Help screen")  //
      ("broker,b", opts::value<string_>()->default_value("127.0.0.1"),
       "Broker Url")  // broker url
      ("log,l", opts::value<string_>()->default_value("info"),
       "Log Level [all,trace,debug,info,warn,error,fatal,none]")  // log level
      ("token,t", opts::value<string_>()->default_value(""),
       "Token file path")  // token
      ("thread", opts::value<size_t>()->default_value(1),
       "Number of thread")  // custom name
      ("name,n", opts::value<string_>()->default_value(link_name),
       "Override Link Name")  // custom name
      ("server-port", opts::value<uint16_t>()->default_value(0),
       "Tcp Server Port")  // custom name
      ;

  opts::variables_map variables;
  try {
    opts::store(opts::parse_command_line(argc, argv, desc), variables);
    opts::notify(variables);
  } catch (std::exception &e) {
    LOG_FATAL(
        LOG
        << "Invalid input, please check available parameters with --help\n");
  }

  // show help and exit
  if (variables.count("help")) {
    std::cout << desc << '\n';
    exit(0);
  }

  own_app = false;
  _app = app;
  // If app object is already given, thread option is ignored in args
  if (_app.get() == nullptr) {
    parse_thread(variables["thread"].as<size_t>());
    own_app = true;
  }

  strand.reset(new EditableStrand(
      get_app().new_strand(), std::unique_ptr<ECDH>(ECDH::from_file(".key"))));

  // TOKEN from file
  client_token = "";
  auto client_token_path = variables["token"].as<string_>();
  if (client_token_path.length() != 0) {
    try {
      client_token = string_from_file(client_token_path);
    } catch (std::exception &e) {
      LOG_FATAL(LOG << "Fatal loading token file " << client_token_path
                    << " with error : " << e.what());
    }
  }

  close_token = get_close_token_from_file();

  parse_url(variables["broker"].as<string_>());
  parse_name(variables["name"].as<string_>());
  parse_log(variables["log"].as<string_>(), *strand);
  parse_server_port(variables["server-port"].as<uint16_t>());

  LOG_TRACE(strand.get()->logger(), LOG << "DSLink initialized successfully");
}
DsLink::~DsLink() {}

App &DsLink::get_app() { return *_app; }

void DsLink::destroy_impl() {
  //  shared_ptr_<App> _app;
  //  shared_ptr_<TcpServer> _tcp_server;
  //  ref_<Client> _client;
  //
  //  bool _running = false;
  //
  //  OnConnectCallback _user_on_connect;
  if (_tcp_server != nullptr) {
    _tcp_server->destroy();
    _tcp_server.reset();
  }
  if (_client) {
    _client->destroy();
    _client.reset();
  }

  // child remove itself from array
  while (!_subscribe_mergers.empty()) {
    // If you dont create lvalue from it
    // gets heap usage after free error because
    // reference count drops zero in destroy
    auto p = _subscribe_mergers.begin()->second;
    p->destroy();
  }

  // child remove itself from array
  while (!_list_mergers.empty()) {
    // If you dont create lvalue from it
    // gets heap usage after free error because
    // reference count drops zero in destroy
    auto p = _list_mergers.begin()->second;
    p->destroy();
  }

  WrapperStrand::destroy_impl();
  if (own_app) {
    _app->close();
  }
}

void DsLink::parse_thread(size_t thread) {
  if (thread < 1) {
    thread = 1;
  } else if (thread > 16) {
    thread = 16;
  }
  _app.reset(new App(thread));
}
void DsLink::parse_url(const string_ &url) {
  static std::regex url_regex(
      R"(^(ds://|dss://|ws://|wss://)?([^/:\[]+|\[[0-9A-Fa-f:]+\])(:\d+)?(/.*)?$)");

  auto match = std::sregex_iterator(url.begin(), url.end(), url_regex);
  if (match == std::sregex_iterator()) {  // match is a empty iterator
    LOG_FATAL(LOG << "Invalid Broker Url: " << url);
  }
  string_ protocol = (*match)[1].str();

  if (protocol == "ws://" || protocol == "wss://") {
    if (protocol == "wss://") {
      secure = true;
      ws_port = 443;  // default wss port
    } else {
      ws_port = 80;  // default ws port
    }
    ws_host = (*match)[2].str();
    if ((*match)[3].length() > 1) {
      ws_port = static_cast<uint16_t>(
          std::stoi(string_((*match)[3].first + 1, (*match)[3].second)));
    }
    ws_path = (*match)[4].str();
  } else {
    if (protocol == "dss://") {
      secure = true;
      tcp_port = 4128;  // default dss port
    } else {            // "ds://" or blank
      tcp_port = 4120;  // default ds port
    }
    tcp_host = (*match)[2].str();
    if ((*match)[3].length() > 1) {
      tcp_port = static_cast<uint16_t>(
          std::stoi(string_((*match)[3].first + 1, (*match)[3].second)));
    }
  }
}

void DsLink::parse_log(const string_ &log, EditableStrand &config) {
  auto logger = std::unique_ptr<Logger>(new ConsoleLogger());
  logger->level = Logger::parse(log);
  config.set_logger(std::move(logger));
}
void DsLink::parse_name(const string_ &name) { dsid_prefix = name; }
void DsLink::parse_server_port(uint16_t port) { tcp_server_port = port; }

void DsLink::init_responder_raw(ref_<NodeModelBase> &&root_node) {
  strand->set_session_manager(make_ref_<SimpleSessionManager>(strand));
  strand->set_security_manager(make_ref_<SimpleSecurityManager>());
  strand->set_responder_model(std::move(root_node));
}
void DsLink::init_responder(ref_<NodeModelBase> &&main_node) {
  _root = make_ref_<LinkRoot>(strand->get_ref(), get_ref());
  if (main_node != nullptr) {
    _root->set_main(std::move(main_node));
  }
  init_responder_raw(_root->get_ref());
}

ref_<NodeModelBase> DsLink::add_to_main_node(const string_ &name,
                                             ref_<NodeModel> &&node) {
  return std::move(_root->add_to_main(name, std::move(node)));
}
void DsLink::remove_from_main_node(const string_ &name) {
  _root->remove_from_main(name);
}

void DsLink::connect(Client::OnConnectCallback &&on_connect,
                     uint8_t callback_type) {
  if (_connected) {
    LOG_FATAL(
        LOG << "DsLink::connect(), Dslink is already requested for connection");
    return;
  }
  _connected = true;

  strand->dispatch([ =, on_connect = std::move(on_connect) ]() mutable {

    if (tcp_server_port > 0) {
      _tcp_server = make_shared_<TcpServer>(*this);
      _tcp_server->start();
    }

    if (tcp_port > 0) {
      if (secure) {
        static boost::asio::ssl::context context(
            boost::asio::ssl::context::sslv23);
        boost::system::error_code error;
        context.load_verify_file("certificate.pem", error);
        if (error) {
          LOG_FATAL(LOG << "Failed to verify cetificate");
        }

        client_connection_maker =
            [
              dsid_prefix = dsid_prefix, tcp_host = tcp_host,
              tcp_port = tcp_port
            ](LinkStrandRef & strand, const string_ &previous_session_id,
              int32_t last_ack_id) {
          return make_shared_<StcpClientConnection>(
              strand, context, dsid_prefix, tcp_host, tcp_port);
        };
      } else {
        client_connection_maker =
            [
              dsid_prefix = dsid_prefix, tcp_host = tcp_host,
              tcp_port = tcp_port
            ](LinkStrandRef & strand, const string_ &previous_session_id,
              int32_t last_ack_id) {
          return make_shared_<TcpClientConnection>(strand, dsid_prefix,
                                                   tcp_host, tcp_port);
        };
      }
    } else if (ws_port > 0) {
      client_connection_maker =
          [ dsid_prefix = dsid_prefix, ws_host = ws_host, ws_port = ws_port ](
              LinkStrandRef & strand, const string_ &previous_session_id,
              int32_t last_ack_id) {
        return make_shared_<WsClientConnection>(strand, dsid_prefix, ws_host,
                                                ws_port);
      };
    }

    _client = make_ref_<Client>(*this);
    _client->connect(std::move(on_connect), callback_type);
    LOG_SYSTEM(strand.get()->logger(), LOG << "DsLink connection requested");
  });
}

void DsLink::run(Client::OnConnectCallback &&on_connect,
                 uint8_t callback_type) {
  if (_running) {
    LOG_FATAL(LOG << "DsLink::run(), Dslink is already running");
    return;
  }
  _running = true;

  if (!strand->is_responder_set()) {
    LOG_WARN(strand->logger(), LOG << "responder is not initialized");
    _client->get_session().responder_enabled = false;
    strand->set_stream_acceptor(make_ref_<DummyStreamAcceptor>());
  }

  if (!_connected) {
    connect(std::move(on_connect), callback_type);
  } else {
    LOG_SYSTEM(strand.get()->logger(),
               LOG << "DsLink on_connect callback "
                      "ignored since it was connected "
                      "before\n");
  }
  LOG_SYSTEM(strand.get()->logger(), LOG << "DsLink running");
  if (own_app) {
    _app->wait();
    destroy();
  }
}

// requester features

ref_<IncomingSubscribeCache> DsLink::subscribe(
    const string_ &path, IncomingSubscribeCache::Callback &&callback,
    const SubscribeOptions &options) {
  if (_subscribe_mergers.count(path) == 0) {
    _subscribe_mergers[path] = make_ref_<SubscribeMerger>(get_ref(), path);
  }
  auto merger = _subscribe_mergers[path];
  return merger->subscribe(std::move(callback), options);
}
ref_<IncomingListCache> DsLink::list(const string_ &path,
                                     IncomingListCache::Callback &&callback) {
  if (_list_mergers.count(path) == 0) {
    _list_mergers[path] = make_ref_<ListMerger>(get_ref(), path);
  }
  auto merger = _list_mergers[path];
  return merger->list(std::move(callback));
}
ref_<IncomingInvokeStream> DsLink::invoke(
    IncomingInvokeStreamCallback &&callback,
    ref_<const InvokeRequestMessage> &&message) {
  return _client->get_session().requester.invoke(std::move(callback),
                                                 std::move(message));
}

ref_<IncomingSetStream> DsLink::set(IncomingSetStreamCallback &&callback,
                                    ref_<const SetRequestMessage> &&message) {
  return _client->get_session().requester.set(std::move(callback),
                                              std::move(message));
}
string_ DsLink::get_close_token() { return close_token; }
}
<|endoftext|>


<commit_before>#include "mysql.h"

#include <mysql/mysql.h>
#include <cstring>
#include <iostream>
#include <stdexcept>

// Prepared statement templates
const char *query_add_snapshot =
    "INSERT INTO snapshot(reason) VALUES (?);";

const char *query_add_reason_malloc =
    "INSERT INTO reason_malloc(snapshot_id, address, size)"
    " VALUES(?, ?, ?);";

const char *query_add_reason_free =
    "INSERT INTO reason_free(snapshot_id, address) VALUES (?, ?);";

const char *query_add_reason_calloc =
    "INSERT INTO reason_calloc(snapshot_id, address, member, size)"
    " VALUES (?, ?, ?, ?);";

const char *query_add_reason_realloc =
    "INSERT INTO reason_realloc(snapshot_id, old_address, new_address, size)"
    " VALUES (?, ?, ?, ?);";

const char *query_add_memory_write =
    "INSERT INTO memory_write(snapshot_id, address, value) VALUES (?, ?, ?);";

const char *query_create_new_block =
    "INSERT INTO block(alloc_snapshot_id, address, size) VALUES (?, ?, ?);";

const char *query_free_block =
    "UPDATE block SET free_snapshot_id = ? WHERE address = ?"
    " AND free_snapshot_id = NULL";

// Raise an exception in the case of an error
void fatal_error(MYSQL *db, int line)
{
    std::cerr << "[FATAL] MySQL error at " << line << ": " << mysql_error(db) << std::endl;
    throw std::runtime_error(mysql_error(db));
}

MySQL::MySQL(
    const char *host, const char *user, const char *password, const char *db)
{
    // Init mysql
    if (mysql_library_init(0, NULL, NULL)) {
        std::cerr << "[FATAL] mysql_library_init failed" << std::endl;
        throw std::runtime_error("mysql_library_init failed");
    }

    db_ = mysql_init(NULL);

    if (!mysql_real_connect(db_, host, user, password, db, 0, NULL, 0))
            fatal_error(db_, __LINE__);

    // Initialize prepared statements
    add_snapshot_ = mysql_stmt_init(db_);
    add_reason_malloc_ = mysql_stmt_init(db_);
    add_reason_free_ = mysql_stmt_init(db_);
    add_reason_calloc_ = mysql_stmt_init(db_);
    add_reason_realloc_ = mysql_stmt_init(db_);
    add_memory_write_ = mysql_stmt_init(db_);
    create_new_block_ = mysql_stmt_init(db_);
    free_block_ = mysql_stmt_init(db_);

    if(!add_snapshot_ || mysql_stmt_prepare(
            add_snapshot_, query_add_snapshot, strlen(query_add_snapshot)))
        fatal_error(db_, __LINE__);

    if(!add_reason_malloc_ || mysql_stmt_prepare(
            add_reason_malloc_, query_add_reason_malloc,
            strlen(query_add_reason_malloc)))
        fatal_error(db_, __LINE__);

    if(!add_reason_free_ || mysql_stmt_prepare(
            add_reason_free_, query_add_reason_free,
            strlen(query_add_reason_free)))
        fatal_error(db_, __LINE__);

    if(!add_reason_calloc_ || mysql_stmt_prepare(
            add_reason_calloc_, query_add_reason_calloc,
            strlen(query_add_reason_calloc)))
        fatal_error(db_, __LINE__);

    if(!add_reason_realloc_ || mysql_stmt_prepare(
            add_reason_realloc_, query_add_reason_realloc,
            strlen(query_add_reason_realloc)))
        fatal_error(db_, __LINE__);

    if(!add_memory_write_ || mysql_stmt_prepare(
            add_memory_write_, query_add_memory_write,
            strlen(query_add_memory_write)))
        fatal_error(db_, __LINE__);

    if(!create_new_block_ || mysql_stmt_prepare(
        create_new_block_, query_create_new_block,
            strlen(query_create_new_block)))
        fatal_error(db_, __LINE__);

    if(!free_block_ || mysql_stmt_prepare(
        free_block_, query_free_block,
            strlen(query_free_block)))
        fatal_error(db_, __LINE__);
}

MySQL::~MySQL()
{
    mysql_close(db_);
    mysql_stmt_close(add_snapshot_);
    mysql_stmt_close(add_reason_malloc_);
    mysql_stmt_close(add_reason_free_);
    mysql_stmt_close(add_reason_calloc_);
    mysql_stmt_close(add_reason_realloc_);
    mysql_stmt_close(add_memory_write_);
}

snapshot_t MySQL::addSnapshot(snapshot_reason::type_t type)
{
    MYSQL_BIND bind;
    memset(&bind, 0, sizeof(MYSQL_BIND));

    bind.buffer_type = MYSQL_TYPE_TINY;
    bind.buffer = (char*) &type;
    bind.buffer_length = sizeof(type);

    if (mysql_stmt_bind_param(add_snapshot_, &bind) ||
            mysql_stmt_execute(add_snapshot_))
        fatal_error(db_, __LINE__);

    return mysql_insert_id(db_);
}

void MySQL::addReasonMalloc(snapshot_t snapshot_id, void *mem, size_t size)
{
    MYSQL_BIND bind[3];
    memset(&bind, 0, sizeof(MYSQL_BIND)*3);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &mem;
    bind[1].buffer_length = sizeof(void*);

    // size
    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = &size;
    bind[2].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(add_reason_malloc_, bind) ||
            mysql_stmt_execute(add_reason_malloc_))
        fatal_error(db_, __LINE__);

    // Create new block
    createNewBlock(snapshot_id, mem, size);
}

void MySQL::addReasonFree(snapshot_t snapshot_id, void *mem)
{
    MYSQL_BIND bind[2];

    memset(&bind, 0, sizeof(MYSQL_BIND)*2);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &mem;
    bind[1].buffer_length = sizeof(void*);

    if (mysql_stmt_bind_param(add_reason_free_, bind) ||
            mysql_stmt_execute(add_reason_free_))
        fatal_error(db_, __LINE__);

    // Free block
    if(mem)
        freeBlock(snapshot_id, mem);
}

void MySQL::addReasonCalloc(
    snapshot_t snapshot_id, void *mem, size_t nmemb, size_t size)
{
    MYSQL_BIND bind[4];
    memset(&bind, 0, sizeof(MYSQL_BIND)*4);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &mem;
    bind[1].buffer_length = sizeof(void*);

    // nmemb
    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = &nmemb;
    bind[2].buffer_length = sizeof(size_t);

    // size
    bind[3].buffer_type = MYSQL_TYPE_LONG;
    bind[3].buffer = &size;
    bind[3].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(add_reason_calloc_, bind) ||
            mysql_stmt_execute(add_reason_calloc_))
        fatal_error(db_, __LINE__);

    // Create new block
    createNewBlock(snapshot_id, mem, nmemb * size);
}

void MySQL::addReasonRealloc(
    snapshot_t snapshot_id, void *old_mem, void *new_mem, size_t new_size)
{
    MYSQL_BIND bind[4];
    memset(&bind, 0, sizeof(MYSQL_BIND)*4);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &old_mem;
    bind[1].buffer_length = sizeof(void*);

    // nmemb
    bind[2].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[2].buffer = &new_mem;
    bind[2].buffer_length = sizeof(void*);

    // size
    bind[3].buffer_type = MYSQL_TYPE_LONG;
    bind[3].buffer = &new_size;
    bind[3].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(add_reason_realloc_, bind) ||
            mysql_stmt_execute(add_reason_realloc_))
        fatal_error(db_, __LINE__);

    // Realloc has a special logic. If new_size is equal to zero, a free
    // is performed.
    // If old_mem is equal to zero, a malloc is performed.
    if (!new_size && old_mem) {
        freeBlock(snapshot_id, old_mem);
    } else if (new_size && !old_mem) {
        createNewBlock(snapshot_id, new_mem, new_size);
    } else {
        freeBlock(snapshot_id, old_mem);
        createNewBlock(snapshot_id, new_mem, new_size);
    }
}

void MySQL::addMemoryWrites(
    snapshot_t snapshot_id, const std::map<void *, unsigned char>& writes)
{
    MYSQL_BIND bind[3];
    char current_char;
    void* current_addr = NULL;
    memset(&bind, 0, sizeof(MYSQL_BIND)*3);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // address
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &current_addr;
    bind[1].buffer_length = sizeof(void*);

    // value
    bind[2].buffer_type = MYSQL_TYPE_BLOB;
    bind[2].buffer = &current_char;
    bind[2].buffer_length = 1;

    for (std::map<void *, unsigned char>::const_iterator it = writes.begin();
            it != writes.end(); it++) {
        current_addr = it -> first;
        current_char = it -> second;
        if (mysql_stmt_bind_param(add_memory_write_, bind) ||
                    mysql_stmt_execute(add_memory_write_))
                fatal_error(db_, __LINE__);
    }
}

void MySQL::createNewBlock(snapshot_t snapshot_id, void *address, size_t size)
{
    MYSQL_BIND bind[3];
    memset(&bind, 0, sizeof(MYSQL_BIND)*3);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &address;
    bind[1].buffer_length = sizeof(void*);

    // size
    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = &size;
    bind[2].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(create_new_block_, bind) ||
            mysql_stmt_execute(create_new_block_))
        fatal_error(db_, __LINE__);
}

void MySQL::freeBlock(snapshot_t snapshot_id, void *address)
{
    MYSQL_BIND bind[2];
    memset(&bind, 0, sizeof(MYSQL_BIND)*2);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &address;
    bind[1].buffer_length = sizeof(void*);

    if (mysql_stmt_bind_param(free_block_, bind) ||
            mysql_stmt_execute(free_block_))
        fatal_error(db_, __LINE__);
}
<commit_msg>Fixed minor bug in MySQL query<commit_after>#include "mysql.h"

#include <mysql/mysql.h>
#include <cstring>
#include <iostream>
#include <stdexcept>

// Prepared statement templates
const char *query_add_snapshot =
    "INSERT INTO snapshot(reason) VALUES (?);";

const char *query_add_reason_malloc =
    "INSERT INTO reason_malloc(snapshot_id, address, size)"
    " VALUES(?, ?, ?);";

const char *query_add_reason_free =
    "INSERT INTO reason_free(snapshot_id, address) VALUES (?, ?);";

const char *query_add_reason_calloc =
    "INSERT INTO reason_calloc(snapshot_id, address, member, size)"
    " VALUES (?, ?, ?, ?);";

const char *query_add_reason_realloc =
    "INSERT INTO reason_realloc(snapshot_id, old_address, new_address, size)"
    " VALUES (?, ?, ?, ?);";

const char *query_add_memory_write =
    "INSERT INTO memory_write(snapshot_id, address, value) VALUES (?, ?, ?);";

const char *query_create_new_block =
    "INSERT INTO block(alloc_snapshot_id, address, size) VALUES (?, ?, ?);";

const char *query_free_block =
    "UPDATE block SET free_snapshot_id = ? WHERE address = ?"
    " AND free_snapshot_id IS NULL;";

// Raise an exception in the case of an error
void fatal_error(MYSQL *db, int line)
{
    std::cerr << "[FATAL] MySQL error at " << line << ": " << mysql_error(db) << std::endl;
    throw std::runtime_error(mysql_error(db));
}

MySQL::MySQL(
    const char *host, const char *user, const char *password, const char *db)
{
    // Init mysql
    if (mysql_library_init(0, NULL, NULL)) {
        std::cerr << "[FATAL] mysql_library_init failed" << std::endl;
        throw std::runtime_error("mysql_library_init failed");
    }

    db_ = mysql_init(NULL);

    if (!mysql_real_connect(db_, host, user, password, db, 0, NULL, 0))
            fatal_error(db_, __LINE__);

    // Initialize prepared statements
    add_snapshot_ = mysql_stmt_init(db_);
    add_reason_malloc_ = mysql_stmt_init(db_);
    add_reason_free_ = mysql_stmt_init(db_);
    add_reason_calloc_ = mysql_stmt_init(db_);
    add_reason_realloc_ = mysql_stmt_init(db_);
    add_memory_write_ = mysql_stmt_init(db_);
    create_new_block_ = mysql_stmt_init(db_);
    free_block_ = mysql_stmt_init(db_);

    if(!add_snapshot_ || mysql_stmt_prepare(
            add_snapshot_, query_add_snapshot, strlen(query_add_snapshot)))
        fatal_error(db_, __LINE__);

    if(!add_reason_malloc_ || mysql_stmt_prepare(
            add_reason_malloc_, query_add_reason_malloc,
            strlen(query_add_reason_malloc)))
        fatal_error(db_, __LINE__);

    if(!add_reason_free_ || mysql_stmt_prepare(
            add_reason_free_, query_add_reason_free,
            strlen(query_add_reason_free)))
        fatal_error(db_, __LINE__);

    if(!add_reason_calloc_ || mysql_stmt_prepare(
            add_reason_calloc_, query_add_reason_calloc,
            strlen(query_add_reason_calloc)))
        fatal_error(db_, __LINE__);

    if(!add_reason_realloc_ || mysql_stmt_prepare(
            add_reason_realloc_, query_add_reason_realloc,
            strlen(query_add_reason_realloc)))
        fatal_error(db_, __LINE__);

    if(!add_memory_write_ || mysql_stmt_prepare(
            add_memory_write_, query_add_memory_write,
            strlen(query_add_memory_write)))
        fatal_error(db_, __LINE__);

    if(!create_new_block_ || mysql_stmt_prepare(
        create_new_block_, query_create_new_block,
            strlen(query_create_new_block)))
        fatal_error(db_, __LINE__);

    if(!free_block_ || mysql_stmt_prepare(
        free_block_, query_free_block,
            strlen(query_free_block)))
        fatal_error(db_, __LINE__);
}

MySQL::~MySQL()
{
    mysql_close(db_);
    mysql_stmt_close(add_snapshot_);
    mysql_stmt_close(add_reason_malloc_);
    mysql_stmt_close(add_reason_free_);
    mysql_stmt_close(add_reason_calloc_);
    mysql_stmt_close(add_reason_realloc_);
    mysql_stmt_close(add_memory_write_);
}

snapshot_t MySQL::addSnapshot(snapshot_reason::type_t type)
{
    MYSQL_BIND bind;
    memset(&bind, 0, sizeof(MYSQL_BIND));

    bind.buffer_type = MYSQL_TYPE_TINY;
    bind.buffer = (char*) &type;
    bind.buffer_length = sizeof(type);

    if (mysql_stmt_bind_param(add_snapshot_, &bind) ||
            mysql_stmt_execute(add_snapshot_))
        fatal_error(db_, __LINE__);

    return mysql_insert_id(db_);
}

void MySQL::addReasonMalloc(snapshot_t snapshot_id, void *mem, size_t size)
{
    MYSQL_BIND bind[3];
    memset(&bind, 0, sizeof(MYSQL_BIND)*3);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &mem;
    bind[1].buffer_length = sizeof(void*);

    // size
    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = &size;
    bind[2].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(add_reason_malloc_, bind) ||
            mysql_stmt_execute(add_reason_malloc_))
        fatal_error(db_, __LINE__);

    // Create new block
    createNewBlock(snapshot_id, mem, size);
}

void MySQL::addReasonFree(snapshot_t snapshot_id, void *mem)
{
    MYSQL_BIND bind[2];

    memset(&bind, 0, sizeof(MYSQL_BIND)*2);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &mem;
    bind[1].buffer_length = sizeof(void*);

    if (mysql_stmt_bind_param(add_reason_free_, bind) ||
            mysql_stmt_execute(add_reason_free_))
        fatal_error(db_, __LINE__);

    // Free block
    if(mem)
        freeBlock(snapshot_id, mem);
}

void MySQL::addReasonCalloc(
    snapshot_t snapshot_id, void *mem, size_t nmemb, size_t size)
{
    MYSQL_BIND bind[4];
    memset(&bind, 0, sizeof(MYSQL_BIND)*4);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &mem;
    bind[1].buffer_length = sizeof(void*);

    // nmemb
    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = &nmemb;
    bind[2].buffer_length = sizeof(size_t);

    // size
    bind[3].buffer_type = MYSQL_TYPE_LONG;
    bind[3].buffer = &size;
    bind[3].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(add_reason_calloc_, bind) ||
            mysql_stmt_execute(add_reason_calloc_))
        fatal_error(db_, __LINE__);

    // Create new block
    createNewBlock(snapshot_id, mem, nmemb * size);
}

void MySQL::addReasonRealloc(
    snapshot_t snapshot_id, void *old_mem, void *new_mem, size_t new_size)
{
    MYSQL_BIND bind[4];
    memset(&bind, 0, sizeof(MYSQL_BIND)*4);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &old_mem;
    bind[1].buffer_length = sizeof(void*);

    // nmemb
    bind[2].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[2].buffer = &new_mem;
    bind[2].buffer_length = sizeof(void*);

    // size
    bind[3].buffer_type = MYSQL_TYPE_LONG;
    bind[3].buffer = &new_size;
    bind[3].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(add_reason_realloc_, bind) ||
            mysql_stmt_execute(add_reason_realloc_))
        fatal_error(db_, __LINE__);

    // Realloc has a special logic. If new_size is equal to zero, a free
    // is performed.
    // If old_mem is equal to zero, a malloc is performed.
    if (!new_size && old_mem) {
        freeBlock(snapshot_id, old_mem);
    } else if (new_size && !old_mem) {
        createNewBlock(snapshot_id, new_mem, new_size);
    } else {
        freeBlock(snapshot_id, old_mem);
        createNewBlock(snapshot_id, new_mem, new_size);
    }
}

void MySQL::addMemoryWrites(
    snapshot_t snapshot_id, const std::map<void *, unsigned char>& writes)
{
    MYSQL_BIND bind[3];
    char current_char;
    void* current_addr = NULL;
    memset(&bind, 0, sizeof(MYSQL_BIND)*3);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // address
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &current_addr;
    bind[1].buffer_length = sizeof(void*);

    // value
    bind[2].buffer_type = MYSQL_TYPE_BLOB;
    bind[2].buffer = &current_char;
    bind[2].buffer_length = 1;

    for (std::map<void *, unsigned char>::const_iterator it = writes.begin();
            it != writes.end(); it++) {
        current_addr = it -> first;
        current_char = it -> second;
        if (mysql_stmt_bind_param(add_memory_write_, bind) ||
                    mysql_stmt_execute(add_memory_write_))
                fatal_error(db_, __LINE__);
    }
}

void MySQL::createNewBlock(snapshot_t snapshot_id, void *address, size_t size)
{
    MYSQL_BIND bind[3];
    memset(&bind, 0, sizeof(MYSQL_BIND)*3);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &address;
    bind[1].buffer_length = sizeof(void*);

    // size
    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = &size;
    bind[2].buffer_length = sizeof(size_t);

    if (mysql_stmt_bind_param(create_new_block_, bind) ||
            mysql_stmt_execute(create_new_block_))
        fatal_error(db_, __LINE__);
}

void MySQL::freeBlock(snapshot_t snapshot_id, void *address)
{
    MYSQL_BIND bind[2];
    memset(&bind, 0, sizeof(MYSQL_BIND)*2);

    // snapshot ID
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &snapshot_id;
    bind[0].buffer_length = sizeof(snapshot_t);

    // memory pointer
    bind[1].buffer_type = MYSQL_TYPE_LONGLONG;
    bind[1].buffer = &address;
    bind[1].buffer_length = sizeof(void*);

    if (mysql_stmt_bind_param(free_block_, bind) ||
            mysql_stmt_execute(free_block_))
        fatal_error(db_, __LINE__);
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// EGLContextCompatibilityTest.cpp:
//   This test will try to use all combinations of context configs and
//   surface configs. If the configs are compatible, it checks that simple
//   rendering works, otherwise it checks an error is generated one MakeCurrent.
#include <gtest/gtest.h>

#include <vector>
#include <EGL/egl.h>
#include <EGL/eglext.h>

#include "OSWindow.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/angle_test_configs.h"

using namespace angle;

namespace
{

const EGLint contextAttribs[] =
{
    EGL_CONTEXT_CLIENT_VERSION, 2,
    EGL_NONE
};

}

class EGLContextCompatibilityTest : public ANGLETest
{
  public:
    EGLContextCompatibilityTest()
      : mDisplay(0)
    {
    }

    void SetUp() override
    {
        PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
        ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);

        EGLint dispattrs[] =
        {
            EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(),
            EGL_NONE
        };
        mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, dispattrs);
        ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);

        ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);

        int nConfigs = 0;
        ASSERT_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs) == EGL_TRUE);
        ASSERT_TRUE(nConfigs != 0);

        int nReturnedConfigs = 0;
        mConfigs.resize(nConfigs);
        ASSERT_TRUE(eglGetConfigs(mDisplay, mConfigs.data(), nConfigs, &nReturnedConfigs) == EGL_TRUE);
        ASSERT_TRUE(nConfigs == nReturnedConfigs);
    }

    void TearDown() override
    {
        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        eglTerminate(mDisplay);
    };

  protected:
    bool areConfigsCompatible(EGLConfig c1, EGLConfig c2, EGLint surfaceBit)
    {
        EGLint colorBufferType1, colorBufferType2;
        EGLint red1, red2, green1, green2, blue1, blue2, alpha1, alpha2;
        EGLint depth1, depth2, stencil1, stencil2;
        EGLint surfaceType1, surfaceType2;

        eglGetConfigAttrib(mDisplay, c1, EGL_COLOR_BUFFER_TYPE, &colorBufferType1);
        eglGetConfigAttrib(mDisplay, c2, EGL_COLOR_BUFFER_TYPE, &colorBufferType2);

        eglGetConfigAttrib(mDisplay, c1, EGL_RED_SIZE, &red1);
        eglGetConfigAttrib(mDisplay, c2, EGL_RED_SIZE, &red2);
        eglGetConfigAttrib(mDisplay, c1, EGL_GREEN_SIZE, &green1);
        eglGetConfigAttrib(mDisplay, c2, EGL_GREEN_SIZE, &green2);
        eglGetConfigAttrib(mDisplay, c1, EGL_BLUE_SIZE, &blue1);
        eglGetConfigAttrib(mDisplay, c2, EGL_BLUE_SIZE, &blue2);
        eglGetConfigAttrib(mDisplay, c1, EGL_ALPHA_SIZE, &alpha1);
        eglGetConfigAttrib(mDisplay, c2, EGL_ALPHA_SIZE, &alpha2);

        eglGetConfigAttrib(mDisplay, c1, EGL_DEPTH_SIZE, &depth1);
        eglGetConfigAttrib(mDisplay, c2, EGL_DEPTH_SIZE, &depth2);
        eglGetConfigAttrib(mDisplay, c1, EGL_STENCIL_SIZE, &stencil1);
        eglGetConfigAttrib(mDisplay, c2, EGL_STENCIL_SIZE, &stencil2);

        eglGetConfigAttrib(mDisplay, c1, EGL_SURFACE_TYPE, &surfaceType1);
        eglGetConfigAttrib(mDisplay, c2, EGL_SURFACE_TYPE, &surfaceType2);

        return colorBufferType1 == colorBufferType2 &&
               red1 == red2 && green1 == green2 && blue1 == blue2 && alpha1 == alpha2 &&
               depth1 == depth2 && stencil1 == stencil2 &&
               (surfaceType1 & surfaceBit) != 0 &&
               (surfaceType2 & surfaceBit) != 0;
    }

    void testWindowCompatibility(EGLConfig windowConfig, EGLConfig contextConfig, bool compatible) const
    {
        OSWindow *osWindow = CreateOSWindow();
        ASSERT_TRUE(osWindow != nullptr);
        osWindow->initialize("EGLContextCompatibilityTest", 500, 500);
        osWindow->setVisible(true);

        EGLContext context = eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, contextAttribs);
        ASSERT_TRUE(context != EGL_NO_CONTEXT);

        EGLSurface window = eglCreateWindowSurface(mDisplay, windowConfig, osWindow->getNativeWindow(), nullptr);
        ASSERT_EGL_SUCCESS();

        if (compatible)
        {
            testClearSurface(window, context);
        }
        else
        {
            testMakeCurrentFails(window, context);
        }

        eglDestroySurface(mDisplay, window);
        ASSERT_EGL_SUCCESS();

        eglDestroyContext(mDisplay, context);
        ASSERT_EGL_SUCCESS();

        SafeDelete(osWindow);
    }

    void testPbufferCompatibility(EGLConfig pbufferConfig, EGLConfig contextConfig, bool compatible) const
    {
        EGLContext context = eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, contextAttribs);
        ASSERT_TRUE(context != EGL_NO_CONTEXT);

        const EGLint pBufferAttribs[] =
        {
            EGL_WIDTH, 500,
            EGL_HEIGHT, 500,
            EGL_NONE,
        };
        EGLSurface pbuffer = eglCreatePbufferSurface(mDisplay, pbufferConfig, pBufferAttribs);
        ASSERT_TRUE(pbuffer != EGL_NO_SURFACE);

        if (compatible)
        {
            testClearSurface(pbuffer, context);
        }
        else
        {
            testMakeCurrentFails(pbuffer, context);
        }

        eglDestroySurface(mDisplay, pbuffer);
        ASSERT_EGL_SUCCESS();

        eglDestroyContext(mDisplay, context);
        ASSERT_EGL_SUCCESS();
    }

    std::vector<EGLConfig> mConfigs;
    EGLDisplay mDisplay;

  private:
    void testClearSurface(EGLSurface surface, EGLContext context) const
    {
        eglMakeCurrent(mDisplay, surface, surface, context);
        ASSERT_EGL_SUCCESS();

        glViewport(0, 0, 500, 500);
        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        ASSERT_GL_NO_ERROR();
        EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255);

        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        ASSERT_EGL_SUCCESS();
    }

    void testMakeCurrentFails(EGLSurface surface, EGLContext context) const
    {
        eglMakeCurrent(mDisplay, surface, surface, context);
        EXPECT_EGL_ERROR(EGL_BAD_MATCH);
    }
};

// The test is split in several subtest so that simple cases
// are tested separately. Also each surface types are not tested
// together.

// Basic test checking contexts and windows created with the
// same config can render.
TEST_P(EGLContextCompatibilityTest, WindowSameConfig)
{
    // TODO(cwallez): figure out why this is broken on Linux/AMD.
#ifdef ANGLE_PLATFORM_LINUX
    if (isAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
    {
        std::cout << "Test skipped on Linux AMD on OpenGL." << std::endl;
        return;
    }
#endif

    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config = mConfigs[i];

        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_WINDOW_BIT) != 0)
        {
            testWindowCompatibility(config, config, true);
        }
    }
}

// Basic test checking contexts and pbuffers created with the
// same config can render.
TEST_P(EGLContextCompatibilityTest, PbufferSameConfig)
{
    // TODO(cwallez): figure out why this is broken on Linux/AMD.
#ifdef ANGLE_PLATFORM_LINUX
    if (isAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
    {
        std::cout << "Test skipped on Linux AMD on OpenGL." << std::endl;
        return;
    }
#endif

    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config = mConfigs[i];

        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_PBUFFER_BIT) != 0)
        {
            testPbufferCompatibility(config, config, true);
        }
    }
}

// Check that a context rendering to a window with a different
// config works or errors according to the EGL compatibility rules
TEST_P(EGLContextCompatibilityTest, WindowDifferentConfig)
{
    // TODO(cwallez): figure out why this is broken on Linux/AMD.
#ifdef ANGLE_PLATFORM_LINUX
    if (isAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
    {
        std::cout << "Test skipped on Linux AMD on OpenGL." << std::endl;
        return;
    }
#endif

    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config1 = mConfigs[i];
        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_WINDOW_BIT) == 0)
        {
            continue;
        }

        for (size_t j = 0; j < mConfigs.size(); j++)
        {
            EGLConfig config2 = mConfigs[j];
            testPbufferCompatibility(config1, config2, areConfigsCompatible(config1, config2, EGL_WINDOW_BIT));
        }
    }
}

// Check that a context rendering to a pbuffer with a different
// config works or errors according to the EGL compatibility rules
TEST_P(EGLContextCompatibilityTest, PbufferDifferentConfig)
{
    // TODO(cwallez): figure out why this is broken on Linux/AMD.
#ifdef ANGLE_PLATFORM_LINUX
    if (isAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
    {
        std::cout << "Test skipped on Linux AMD on OpenGL." << std::endl;
        return;
    }
#endif

    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config1 = mConfigs[i];
        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_PBUFFER_BIT) == 0)
        {
            continue;
        }

        for (size_t j = 0; j < mConfigs.size(); j++)
        {
            EGLConfig config2 = mConfigs[j];
            testPbufferCompatibility(config1, config2, areConfigsCompatible(config1, config2, EGL_PBUFFER_BIT));
        }
    }
}

ANGLE_INSTANTIATE_TEST(EGLContextCompatibilityTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
<commit_msg>EGLContextCompatibilityTest: check for suppression only when a context is bound.<commit_after>//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// EGLContextCompatibilityTest.cpp:
//   This test will try to use all combinations of context configs and
//   surface configs. If the configs are compatible, it checks that simple
//   rendering works, otherwise it checks an error is generated one MakeCurrent.
#include <gtest/gtest.h>

#include <vector>
#include <EGL/egl.h>
#include <EGL/eglext.h>

#include "OSWindow.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/angle_test_configs.h"

using namespace angle;

namespace
{

const EGLint contextAttribs[] =
{
    EGL_CONTEXT_CLIENT_VERSION, 2,
    EGL_NONE
};

}

class EGLContextCompatibilityTest : public ANGLETest
{
  public:
    EGLContextCompatibilityTest()
      : mDisplay(0)
    {
    }

    void SetUp() override
    {
        PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
        ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);

        EGLint dispattrs[] =
        {
            EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(),
            EGL_NONE
        };
        mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, dispattrs);
        ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);

        ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);

        int nConfigs = 0;
        ASSERT_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs) == EGL_TRUE);
        ASSERT_TRUE(nConfigs != 0);

        int nReturnedConfigs = 0;
        mConfigs.resize(nConfigs);
        ASSERT_TRUE(eglGetConfigs(mDisplay, mConfigs.data(), nConfigs, &nReturnedConfigs) == EGL_TRUE);
        ASSERT_TRUE(nConfigs == nReturnedConfigs);
    }

    void TearDown() override
    {
        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        eglTerminate(mDisplay);
    };

  protected:
    bool areConfigsCompatible(EGLConfig c1, EGLConfig c2, EGLint surfaceBit)
    {
        EGLint colorBufferType1, colorBufferType2;
        EGLint red1, red2, green1, green2, blue1, blue2, alpha1, alpha2;
        EGLint depth1, depth2, stencil1, stencil2;
        EGLint surfaceType1, surfaceType2;

        eglGetConfigAttrib(mDisplay, c1, EGL_COLOR_BUFFER_TYPE, &colorBufferType1);
        eglGetConfigAttrib(mDisplay, c2, EGL_COLOR_BUFFER_TYPE, &colorBufferType2);

        eglGetConfigAttrib(mDisplay, c1, EGL_RED_SIZE, &red1);
        eglGetConfigAttrib(mDisplay, c2, EGL_RED_SIZE, &red2);
        eglGetConfigAttrib(mDisplay, c1, EGL_GREEN_SIZE, &green1);
        eglGetConfigAttrib(mDisplay, c2, EGL_GREEN_SIZE, &green2);
        eglGetConfigAttrib(mDisplay, c1, EGL_BLUE_SIZE, &blue1);
        eglGetConfigAttrib(mDisplay, c2, EGL_BLUE_SIZE, &blue2);
        eglGetConfigAttrib(mDisplay, c1, EGL_ALPHA_SIZE, &alpha1);
        eglGetConfigAttrib(mDisplay, c2, EGL_ALPHA_SIZE, &alpha2);

        eglGetConfigAttrib(mDisplay, c1, EGL_DEPTH_SIZE, &depth1);
        eglGetConfigAttrib(mDisplay, c2, EGL_DEPTH_SIZE, &depth2);
        eglGetConfigAttrib(mDisplay, c1, EGL_STENCIL_SIZE, &stencil1);
        eglGetConfigAttrib(mDisplay, c2, EGL_STENCIL_SIZE, &stencil2);

        eglGetConfigAttrib(mDisplay, c1, EGL_SURFACE_TYPE, &surfaceType1);
        eglGetConfigAttrib(mDisplay, c2, EGL_SURFACE_TYPE, &surfaceType2);

        return colorBufferType1 == colorBufferType2 &&
               red1 == red2 && green1 == green2 && blue1 == blue2 && alpha1 == alpha2 &&
               depth1 == depth2 && stencil1 == stencil2 &&
               (surfaceType1 & surfaceBit) != 0 &&
               (surfaceType2 & surfaceBit) != 0;
    }

    void testWindowCompatibility(EGLConfig windowConfig, EGLConfig contextConfig, bool compatible) const
    {
        OSWindow *osWindow = CreateOSWindow();
        ASSERT_TRUE(osWindow != nullptr);
        osWindow->initialize("EGLContextCompatibilityTest", 500, 500);
        osWindow->setVisible(true);

        EGLContext context = eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, contextAttribs);
        ASSERT_TRUE(context != EGL_NO_CONTEXT);

        EGLSurface window = eglCreateWindowSurface(mDisplay, windowConfig, osWindow->getNativeWindow(), nullptr);
        ASSERT_EGL_SUCCESS();

        if (compatible)
        {
            testClearSurface(window, context);
        }
        else
        {
            testMakeCurrentFails(window, context);
        }

        eglDestroySurface(mDisplay, window);
        ASSERT_EGL_SUCCESS();

        eglDestroyContext(mDisplay, context);
        ASSERT_EGL_SUCCESS();

        SafeDelete(osWindow);
    }

    void testPbufferCompatibility(EGLConfig pbufferConfig, EGLConfig contextConfig, bool compatible) const
    {
        EGLContext context = eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, contextAttribs);
        ASSERT_TRUE(context != EGL_NO_CONTEXT);

        const EGLint pBufferAttribs[] =
        {
            EGL_WIDTH, 500,
            EGL_HEIGHT, 500,
            EGL_NONE,
        };
        EGLSurface pbuffer = eglCreatePbufferSurface(mDisplay, pbufferConfig, pBufferAttribs);
        ASSERT_TRUE(pbuffer != EGL_NO_SURFACE);

        if (compatible)
        {
            testClearSurface(pbuffer, context);
        }
        else
        {
            testMakeCurrentFails(pbuffer, context);
        }

        eglDestroySurface(mDisplay, pbuffer);
        ASSERT_EGL_SUCCESS();

        eglDestroyContext(mDisplay, context);
        ASSERT_EGL_SUCCESS();
    }

    std::vector<EGLConfig> mConfigs;
    EGLDisplay mDisplay;

  private:
    void testClearSurface(EGLSurface surface, EGLContext context) const
    {
        eglMakeCurrent(mDisplay, surface, surface, context);
        ASSERT_EGL_SUCCESS();

#ifdef ANGLE_PLATFORM_LINUX
        // TODO(cwallez): figure out why this is broken on Linux/AMD.
        if (isAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
        {
            eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
            return;
        }
#endif

        glViewport(0, 0, 500, 500);
        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        ASSERT_GL_NO_ERROR();
        EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255);

        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        ASSERT_EGL_SUCCESS();
    }

    void testMakeCurrentFails(EGLSurface surface, EGLContext context) const
    {
        eglMakeCurrent(mDisplay, surface, surface, context);
        EXPECT_EGL_ERROR(EGL_BAD_MATCH);
    }
};

// The test is split in several subtest so that simple cases
// are tested separately. Also each surface types are not tested
// together.

// Basic test checking contexts and windows created with the
// same config can render.
TEST_P(EGLContextCompatibilityTest, WindowSameConfig)
{
    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config = mConfigs[i];

        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_WINDOW_BIT) != 0)
        {
            testWindowCompatibility(config, config, true);
        }
    }
}

// Basic test checking contexts and pbuffers created with the
// same config can render.
TEST_P(EGLContextCompatibilityTest, PbufferSameConfig)
{
    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config = mConfigs[i];

        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_PBUFFER_BIT) != 0)
        {
            testPbufferCompatibility(config, config, true);
        }
    }
}

// Check that a context rendering to a window with a different
// config works or errors according to the EGL compatibility rules
TEST_P(EGLContextCompatibilityTest, WindowDifferentConfig)
{
    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config1 = mConfigs[i];
        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_WINDOW_BIT) == 0)
        {
            continue;
        }

        for (size_t j = 0; j < mConfigs.size(); j++)
        {
            EGLConfig config2 = mConfigs[j];
            testPbufferCompatibility(config1, config2, areConfigsCompatible(config1, config2, EGL_WINDOW_BIT));
        }
    }
}

// Check that a context rendering to a pbuffer with a different
// config works or errors according to the EGL compatibility rules
TEST_P(EGLContextCompatibilityTest, PbufferDifferentConfig)
{
    for (size_t i = 0; i < mConfigs.size(); i++)
    {
        EGLConfig config1 = mConfigs[i];
        EGLint surfaceType;
        eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
        ASSERT_EGL_SUCCESS();

        if ((surfaceType & EGL_PBUFFER_BIT) == 0)
        {
            continue;
        }

        for (size_t j = 0; j < mConfigs.size(); j++)
        {
            EGLConfig config2 = mConfigs[j];
            testPbufferCompatibility(config1, config2, areConfigsCompatible(config1, config2, EGL_PBUFFER_BIT));
        }
    }
}

ANGLE_INSTANTIATE_TEST(EGLContextCompatibilityTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
<|endoftext|>