<commit_before>#include "stdafx.h"
#include <dukat/messenger.h>

namespace dukat
{
	void Messenger::trigger(const Message& message)
	{
		if (!subscriptions.count(message.event))
			return;
		active_trigger = message.event;
		const auto& subs = subscriptions.at(message.event);
		for (const auto& r : subs)
			r->receive(message);
		active_trigger = Events::None;
	}

	void Messenger::subscribe(Recipient* recipient, Event ev)
	{
		assert(active_trigger != ev);
		if (subscriptions.count(ev) == 0)
			subscriptions.emplace(ev, std::list<Recipient*>());
		auto& list = subscriptions.at(ev);
		auto it = std::find(list.begin(), list.end(), recipient);
		if (it == list.end())
			list.push_back(recipient);
	}

	void Messenger::subscribe(Recipient * recipient, const std::vector<Event>& events)
	{
		std::for_each(events.begin(), events.end(), [&](const Event& e) { subscribe(recipient, e); });
	}

	void Messenger::subscribe_all(Recipient* recipient)
	{
		for (auto it = Events::None + 1; it != Events::Any; ++it)
			subscribe(recipient, it);
	}

	void Messenger::do_unsubscribe(Recipient* recipient, std::list<Recipient*>& list)
	{
		for (auto it = list.begin(); it != list.end(); ++it)
		{
			if (*it == recipient)
			{
				list.erase(it);
				break;
			}
		}
	}

	void Messenger::unsubscribe(Recipient* recipient, Event ev)
	{
		if (subscriptions.count(ev))
		{
			assert(active_trigger != ev);
			do_unsubscribe(recipient, subscriptions.at(ev));
		}
	}

	void Messenger::unsubscribe(Recipient* recipient, const std::vector<Event>& events)
	{
		std::for_each(events.begin(), events.end(), [&](const Event& e) { unsubscribe(recipient, e); });
	}

	void Messenger::unsubscribe_all(Recipient* recipient)
	{
		for (auto it = subscriptions.begin(); it != subscriptions.end(); ++it)
			do_unsubscribe(recipient, it->second);
	}
}
<commit_msg>Better exception handling in messager<commit_after>#include "stdafx.h"
#include <dukat/messenger.h>

namespace dukat
{
	struct EventLock
	{
		Event& active_event;

		EventLock(Event& active_event, const Event& event_trigger) : active_event(active_event)
		{
			active_event = event_trigger;
		}

		~EventLock(void)
		{
			active_event = Events::None;
		}
	};

	void Messenger::trigger(const Message& message)
	{
		if (!subscriptions.count(message.event))
			return;
		EventLock lock(active_trigger, message.event);
		const auto& subs = subscriptions.at(message.event);
		for (const auto& r : subs)
			r->receive(message);
	}

	void Messenger::subscribe(Recipient* recipient, Event ev)
	{
		assert(active_trigger != ev);
		if (subscriptions.count(ev) == 0)
			subscriptions.emplace(ev, std::list<Recipient*>());
		auto& list = subscriptions.at(ev);
		auto it = std::find(list.begin(), list.end(), recipient);
		if (it == list.end())
			list.push_back(recipient);
	}

	void Messenger::subscribe(Recipient * recipient, const std::vector<Event>& events)
	{
		std::for_each(events.begin(), events.end(), [&](const Event& e) { subscribe(recipient, e); });
	}

	void Messenger::subscribe_all(Recipient* recipient)
	{
		for (auto it = Events::None + 1; it != Events::Any; ++it)
			subscribe(recipient, it);
	}

	void Messenger::do_unsubscribe(Recipient* recipient, std::list<Recipient*>& list)
	{
		for (auto it = list.begin(); it != list.end(); ++it)
		{
			if (*it == recipient)
			{
				list.erase(it);
				break;
			}
		}
	}

	void Messenger::unsubscribe(Recipient* recipient, Event ev)
	{
		if (subscriptions.count(ev))
		{
			assert(active_trigger != ev);
			do_unsubscribe(recipient, subscriptions.at(ev));
		}
	}

	void Messenger::unsubscribe(Recipient* recipient, const std::vector<Event>& events)
	{
		std::for_each(events.begin(), events.end(), [&](const Event& e) { unsubscribe(recipient, e); });
	}

	void Messenger::unsubscribe_all(Recipient* recipient)
	{
		for (auto it = subscriptions.begin(); it != subscriptions.end(); ++it)
			do_unsubscribe(recipient, it->second);
	}
}
<|endoftext|>


<commit_before>//
//  src/misc/flags.cc
//  tbd
//
//  Created by inoahdev on 7/10/17.
//  Copyright © 2017 inoahdev. All rights reserved.
//

#include <cerrno>

#include <cstdint>
#include <cstdio>

#include <cstdlib>
#include <cstring>

#include "flags.h"

flags::flags(long length)
: length_(length) {
    if (length > bit_size()) {
        size_t size = length * bit_size();
        flags_.ptr = calloc(1, size);

        if (!flags_.ptr) {
            fprintf(stderr, "Failed to allocate data of size (%ld), failing with error (%s)\n", size, strerror(errno));
            exit(EXIT_FAILURE);
        }
    }
}

flags::~flags() {
    if (length_ > bit_size()) {
        free(flags_.ptr);
    }
}

void flags::cast(long index, bool result) noexcept {
    if (length_ > bit_size()) {
        auto ptr = (unsigned int *)flags_.ptr;

        const auto bit_size = this->bit_size();
        const auto bits_length = bit_size * length_;

        // As length_ can be of any size, it is not possible to
        // simply cast flags_.ptr to unsigned int *, instead, the
        // pointer must be (temporarily) advanced to allow casting
        // as unsigned int *.

        // As length_ is larger than sizeof(unsigned int)
        // It is often necessary to advance the flags-pointer
        // to the next byte to access the bit at the index the
        // caller provided.

        // To advance the flags-pointer to the right byte(s), the
        // flags-pointer is advanced by one byte until index_from_back
        // is smaller than bit_size (bit-count of unsigned int).

        while (index > bits_length) {
            index -= 8;
            ptr = (unsigned int *)((uintptr_t)ptr + 1);
        }

        if (result) {
            *ptr |= 1 << index;
        } else {
            *ptr &= ~(1 << index);
        }

    } else {
        auto flags = flags_.flags;

        if (result) {
            flags |= 1 << index;
        } else {
            flags &= ~(1 << index);
        }

        flags_.flags = flags;
    }
}

bool flags::at(long index) const noexcept {
    if (length_ > bit_size()) {
        auto ptr = (unsigned int *)flags_.ptr;

        const auto bit_size = this->bit_size();
        const auto bits_length = bit_size * length_;

        // As length_ can be of any size, it is not possible to
        // simply cast flags_.ptr to unsigned int *, instead, the
        // pointer must be (temporarily) advanced to allow casting
        // as unsigned int *.

        // As length_ is larger than sizeof(unsigned int)
        // It is often necessary to advance the flags-pointer
        // to the next byte to access the bit at the index the
        // caller provided.

        // To advance the flags-pointer to the right byte(s), the
        // flags-pointer is advanced by one byte until index_from_back
        // is smaller than bit_size (bit-count of unsigned int).

        while (index > bits_length) {
            index -= 8;
            ptr = (unsigned int *)((uintptr_t)ptr + 1);
        }

        return (*ptr & 1 << index) ? true : false;
    } else {
        const auto flags = flags_.flags;
        return (flags & 1 << index) ? true : false;
    }
}

bool flags::operator==(const flags &flags) const noexcept {
    if (length_ != flags.length_) {
        return false;
    }

    if (length_ > bit_size()) {
        return memcmp(flags_.ptr, flags.flags_.ptr, length_);
    } else {
        return flags_.flags == flags.flags_.flags;
    }
}
<commit_msg>Try avoiding unaligned pointer access<commit_after>//
//  src/misc/flags.cc
//  tbd
//
//  Created by inoahdev on 7/10/17.
//  Copyright © 2017 inoahdev. All rights reserved.
//

#include <cerrno>

#include <cstdint>
#include <cstdio>

#include <cstdlib>
#include <cstring>

#include "flags.h"

flags::flags(long length)
: length_(length) {
    if (length > bit_size()) {
        size_t size = length * bit_size();
        flags_.ptr = calloc(1, size);

        if (!flags_.ptr) {
            fprintf(stderr, "Failed to allocate data of size (%ld), failing with error (%s)\n", size, strerror(errno));
            exit(EXIT_FAILURE);
        }
    }
}

flags::~flags() {
    if (length_ > bit_size()) {
        free(flags_.ptr);
    }
}

void flags::cast(long index, bool result) noexcept {
    if (length_ > bit_size()) {
        auto ptr = (unsigned int *)flags_.ptr;

        const auto bit_size = this->bit_size();
        const auto bits_length = bit_size * length_;

        // As length_ can be of any size, it is not possible to
        // simply cast flags_.ptr to unsigned int *, instead, the
        // pointer must be (temporarily) advanced to allow casting
        // as unsigned int *.

        // As length_ is larger than sizeof(unsigned int)
        // It is often necessary to advance the flags-pointer
        // to the next byte to access the bit at the index the
        // caller provided.

        // To advance the flags-pointer to the right byte(s), the
        // flags-pointer is advanced by one byte until index_from_back
        // is smaller than bit_size (bit-count of unsigned int).

        while (index > bits_length) {
            index -= sizeof(unsigned int);
            ptr = (unsigned int *)((uintptr_t)ptr + sizeof(unsigned int));
        }

        if (result) {
            *ptr |= 1 << index;
        } else {
            *ptr &= ~(1 << index);
        }

    } else {
        auto flags = flags_.flags;

        if (result) {
            flags |= 1 << index;
        } else {
            flags &= ~(1 << index);
        }

        flags_.flags = flags;
    }
}

bool flags::at(long index) const noexcept {
    if (length_ > bit_size()) {
        auto ptr = (unsigned int *)flags_.ptr;

        const auto bit_size = this->bit_size();
        const auto bits_length = bit_size * length_;

        // As length_ can be of any size, it is not possible to
        // simply cast flags_.ptr to unsigned int *, instead, the
        // pointer must be (temporarily) advanced to allow casting
        // as unsigned int *.

        // As length_ is larger than sizeof(unsigned int)
        // It is often necessary to advance the flags-pointer
        // to the next byte to access the bit at the index the
        // caller provided.

        // To advance the flags-pointer to the right byte(s), the
        // flags-pointer is advanced by one byte until index_from_back
        // is smaller than bit_size (bit-count of unsigned int).

        while (index > bits_length) {
            index -= 8;
            ptr = (unsigned int *)((uintptr_t)ptr + 1);
        }

        return (*ptr & 1 << index) ? true : false;
    } else {
        const auto flags = flags_.flags;
        return (flags & 1 << index) ? true : false;
    }
}

bool flags::operator==(const flags &flags) const noexcept {
    if (length_ != flags.length_) {
        return false;
    }

    if (length_ > bit_size()) {
        return memcmp(flags_.ptr, flags.flags_.ptr, length_);
    } else {
        return flags_.flags == flags.flags_.flags;
    }
}
<|endoftext|>


<commit_before>// Code for basic data manipulation
//
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;

#define ERROR        "Error: "
#define MAX_WORD_LEN 100

struct node{				// node data structure for DLL
	char word[MAX_WORD_LEN];
	node * next;
	node * prev;
};

node * getWords(char * infile)
{
	node * head = NULL;
	node * prev = NULL;

	ifstream file (infile);								// open file into an input file stream
	if(file.is_open()){
		string word;
		while(file >> word){							// stream operator parses on white space (seperating words)
			transform(word.begin(), word.end(), word.begin(), ::tolower);	// make sure all words are lower case

			node * current;				// create a new node pointer
			current = new node;			// allocate memory for the node

			strcpy(current->word, word.c_str());	// copy the lower case word into the node
			if(prev != NULL){
			       	prev->next = current;		// set next, prev pointers
				current->prev = prev;
			}

			if(head == NULL) head = current;	// set head node pointer
			prev = current;				// remember the last node
		}
		file.close();
	}else{
		cout << ERROR << "cannot open file" << endl;
		return NULL;
	}
	return head;
}

void printDLL_forward(node * head)
{
	node * current = head;
	while(current->next != NULL ){		// rotate threw list untill end
		cout << current->word << ", ";  // print out the current word
		current = current->next;	// set the next node to be the current
	}
	cout << current->word << endl;
}

void printDLL_backward(node * head)
{
	node * current = head;
	while(current->next != NULL){		// find the tail
		current = current->next;
	}

	while(current->prev != NULL){
		cout << current->word << ", ";
		current = current->prev;
	}
	cout << current->word << endl;
}

void remove2ndNode(node * head)
{
	node * current = head;

	current = current->next;
	current->next->prev = current->prev;
	current->prev->next = current->next;
	delete current;
}

int main(int argc, char * argv[])
{
	// get file input
	if(argc != 2){
		cout << ERROR << "Please include file to open" << endl;
		return -1;
	}
	node * head = getWords(argv[1]);

	cout << "Test 1: Words in order" << endl;
	//TODO sort DLL!!!
	printDLL_forward(head);

	cout << "Test 2: Words in reverse order" << endl;
	printDLL_backward(head);

	cout << "Test 3: Remove the 2nd item" << endl;
	remove2ndNode(head);

	cout << "Test 4: Words in order" << endl;
	printDLL_forward(head);

	return 0;
}

<commit_msg>added comments<commit_after>// Code for basic data manipulation
//
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;

#define ERROR        "Error: "
#define MAX_WORD_LEN 100

struct node{				// node data structure for DLL
	char word[MAX_WORD_LEN];
	node * next;
	node * prev;
};

node * getWords(char * infile)
{
	node * head = NULL;
	node * prev = NULL;

	ifstream file (infile);								// open file into an input file stream
	if(file.is_open()){
		string word;
		while(file >> word){							// stream operator parses on white space (seperating words)
			transform(word.begin(), word.end(), word.begin(), ::tolower);	// make sure all words are lower case

			node * current;				// create a new node pointer
			current = new node;			// allocate memory for the node

			strcpy(current->word, word.c_str());	// copy the lower case word into the node
			if(head == NULL) head = current;	// set head node pointer
			if(prev != NULL){
			       	prev->next = current;		// set next, prev pointers
				current->prev = prev;
			}

			prev = current;				// remember the last node
		}
		file.close();
	}else{
		cout << ERROR << "cannot open file" << endl;
		return NULL;
	}
	return head;
}

void printDLL_forward(node * head)
{
	node * current = head;
	while(current->next != NULL ){		// rotate threw list untill end
		cout << current->word << ", ";  // print out the current word
		current = current->next;	// set the next node to be the current
	}
	cout << current->word << endl;
}

void printDLL_backward(node * head)
{
	node * current = head;
	while(current->next != NULL){		// find the tail
		current = current->next;
	}

	while(current->prev != NULL){		// reversed print forward
		cout << current->word << ", ";
		current = current->prev;
	}
	cout << current->word << endl;
}

void remove2ndNode(node * head)
{
	node * current = head;

	current = current->next;
	current->next->prev = current->prev;	// create the link around the deleted node
	current->prev->next = current->next;
	delete current;				// deallocate memory for node
}

int main(int argc, char * argv[])
{
	// get file input
	if(argc != 2){
		cout << ERROR << "Please include file to open" << endl;
		return -1;
	}
	node * head = getWords(argv[1]);

	cout << "Test 1: Words in order" << endl;
	//TODO sort DLL!!! Do we want to sort in getWords???
	printDLL_forward(head);

	cout << "Test 2: Words in reverse order" << endl;
	printDLL_backward(head);

	cout << "Test 3: Remove the 2nd item" << endl;
	remove2ndNode(head);

	cout << "Test 4: Words in order" << endl;
	printDLL_forward(head);

	return 0;
}

<|endoftext|>


<commit_before>
#include "tfactory.h"

#include <iostream>
#include <string>

class Base
{
public:
	virtual void doSomething()=0;
	virtual ~Base(){}
};

class Derived1:public Base{
public:
	Derived1(int num=10):num(num){}
	void doSomething() override {std::cout<<"num="<<num<<"\n";}
private:
	int num;
};

class Derived2:public Base{
public:
	Derived2(int num=8):num(num),str("lonestar"){}
	Derived2(std::string str):num(0),str(str){}
	void doSomething() override {std::cout<<"num="<<num<<", str="<<str<<"\n";}
protected:
	int num;
	std::string str;

};

class Derived3:public Derived2{
private:
	bool isItMe;
public:
	Derived3(int num=33,bool isItYou=true):Derived2(num),isItMe(isItYou){}
	void doSomething() override {std::cout<<"num="<<num<<" ,isItMe="<<std::boolalpha<<isItMe<<"\n";}
};

class Unattached{
public:
	void doSomething()  {std::cout<<"i'm unattached\n";}
};

enum class  en {Derived1Default,Derived1Param1,Derived2Default,Derived2Param1,Derived2Param2,Derived3Default,Derived3Param2,uat};

template <typename T>
struct EnumClassHash
{
	std::size_t operator()(T t) const
	{
		return static_cast<std::size_t>(t);
	}
};

int main()
{
	std::string allstars {"allstars"};
	int number=256;

	TFactory<std::string,Base> testfactoryWStr;
	testfactoryWStr.registerClass<Derived1>("Derived1Default");
	testfactoryWStr.registerClass<Derived1>("Derived1Param1",11);
	testfactoryWStr.registerClass<Derived2>("Derived2Default");
	testfactoryWStr.registerClass<Derived2>("Derived2Param1", number);
	testfactoryWStr.registerClass<Derived2>("Derived2Param2", allstars);

	std::cout<<"test with string key:\n";
	testfactoryWStr.getInstance("Derived1Default")->doSomething();
	testfactoryWStr.getInstance("Derived1Param1")->doSomething();
	testfactoryWStr.getInstance("Derived2Default")->doSomething();
	testfactoryWStr.getInstance("Derived2Param1")->doSomething();
	testfactoryWStr.getInstance("Derived2Param2")->doSomething();
	try
	{
		testfactoryWStr.getInstance("Derivam2")->doSomething();//good - Throws exception
	}
	catch(std::exception& ex )
	{
		std::cout<<"\nexception: "<<ex.what()<<"\n";
	}

	int number2=1024;
	TFactory<en,Base,EnumClassHash<en>> testfactoryWEnum;
	testfactoryWEnum.registerClass<Derived1>(en::Derived1Default);
	testfactoryWEnum.registerClass<Derived2>(en::Derived2Param1,number2);
	testfactoryWEnum.registerClass<Derived3>(en::Derived3Default);
	testfactoryWEnum.registerClass<Derived3>(en::Derived3Default,16);//overwrites previous constructor
	testfactoryWEnum.registerClass<Derived3>(en::Derived3Param2,18,false);
	//testfactoryWEnum.registerClass<Unattached>(en::uat);//excellent - failes at compilation

	std::cout<<"\ntest with enum key:\n";
	testfactoryWEnum.getInstance(en::Derived1Default)->doSomething();
	testfactoryWEnum.getInstance(en::Derived2Param1)->doSomething();
	testfactoryWEnum.getInstance(en::Derived3Default)->doSomething();
	testfactoryWEnum.getInstance(en::Derived3Param2)->doSomething();

}
<commit_msg>Delete tfactorytest.cpp<commit_after><|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "sbregister.h"
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/exceptions.h>

#include <vespa/log/log.h>
LOG_SETUP(".slobrok.register");

using vespalib::NetworkSetupFailureException;

namespace {

vespalib::string
createSpec(FRT_Supervisor &orb)
{
    vespalib::string spec;
    if (orb.GetListenPort() != 0) {
        vespalib::asciistream str;
        str << "tcp/";
        str << vespalib::HostName::get();
        str << ":";
        str << orb.GetListenPort();
        spec = str.str();
    }
    return spec;
}

void
discard(std::vector<vespalib::string> &vec, vespalib::stringref val)
{
    uint32_t i = 0;
    uint32_t size = vec.size();
    while (i < size) {
        if (vec[i] == val) {
            std::swap(vec[i], vec[size - 1]);
            vec.pop_back();
            --size;
        } else {
            ++i;
        }
    }
    LOG_ASSERT(size == vec.size());
}

} // namespace <unnamed>

namespace slobrok::api {

RegisterAPI::RegisterAPI(FRT_Supervisor &orb, const ConfiguratorFactory & config)
    : FNET_Task(orb.GetScheduler()),
      _orb(orb),
      _hooks(*this),
      _lock(),
      _reqDone(false),
      _logOnSuccess(true),
      _busy(false),
      _slobrokSpecs(),
      _configurator(config.create(_slobrokSpecs)),
      _currSlobrok(""),
      _idx(0),
      _backOff(),
      _names(),
      _pending(),
      _unreg(),
      _target(0),
      _req(0)
{
    _configurator->poll();
    if ( ! _slobrokSpecs.ok()) {
        throw NetworkSetupFailureException("Failed configuring the RegisterAPI. No valid slobrok specs from config",
                                           VESPA_STRLOC);
    }
    ScheduleNow();
}

RegisterAPI::~RegisterAPI()
{
    Kill();
    _configurator.reset(0);
    if (_req != 0) {
        _req->Abort();
        _req->SubRef();
    }
    if (_target != 0) {
        _target->SubRef();
    }
}

void
RegisterAPI::registerName(vespalib::stringref name)
{
    std::lock_guard<std::mutex> guard(_lock);
    for (uint32_t i = 0; i < _names.size(); ++i) {
        if (_names[i] == name) {
            return;
        }
    }
    _busy.store(true, std::memory_order_relaxed);
    _names.push_back(name);
    _pending.push_back(name);
    discard(_unreg, name);
    ScheduleNow();
}

void
RegisterAPI::unregisterName(vespalib::stringref name)
{
    std::lock_guard<std::mutex> guard(_lock);
    _busy.store(true, std::memory_order_relaxed);
    discard(_names, name);
    discard(_pending, name);
    _unreg.push_back(name);
    ScheduleNow();
}

// handle any request that completed
void
RegisterAPI::handleReqDone()
{
    std::lock_guard guard(_lock);
    if (_reqDone) {
        _reqDone = false;
        if (_req->IsError()) {
            if (_req->GetErrorCode() != FRTE_RPC_METHOD_FAILED) {
                LOG(debug, "register failed: %s (code %d)",
                    _req->GetErrorMessage(), _req->GetErrorCode());
                // unexpected error; close our connection to this
                // slobrok server and try again with a fresh slate
                if (_target != 0) {
                    _target->SubRef();
                }
                _target = 0;
                _busy.store(true, std::memory_order_relaxed);
            } else {
                LOG(warning, "%s(%s -> %s) failed: %s",
                    _req->GetMethodName(),
                    (*_req->GetParams())[0]._string._str,
                    (*_req->GetParams())[1]._string._str,
                    _req->GetErrorMessage());
            }
        } else {
            if (_logOnSuccess && (_pending.size() == 0) && (_names.size() > 0)) {
                LOG(info, "[RPC @ %s] registering %s with location broker %s completed successfully",
                    createSpec(_orb).c_str(), _names[0].c_str(), _currSlobrok.c_str());
                _logOnSuccess = false;
            }
            // reset backoff strategy on any successful request
            _backOff.reset();
        }
        _req->SubRef();
        _req = 0;
    }
}

// do we need to try to reconnect?
void
RegisterAPI::handleReconnect()
{
    if (_configurator->poll() && _target != 0) {
        if (! _slobrokSpecs.contains(_currSlobrok)) {
            vespalib::string cps = _slobrokSpecs.logString();
            LOG(warning, "[RPC @ %s] location broker %s removed, will disconnect and use one of: %s",
                createSpec(_orb).c_str(), _currSlobrok.c_str(), cps.c_str());
            _target->SubRef();
            _target = 0;
        }
    }
    if (_target == 0) {
        _logOnSuccess = true;
        _currSlobrok = _slobrokSpecs.nextSlobrokSpec();
        if (_currSlobrok.size() > 0) {
            // try next possible server.
            _target = _orb.GetTarget(_currSlobrok.c_str());
        }
        {
            std::lock_guard<std::mutex> guard(_lock);
            // now that we have a new connection, we need to
            // immediately re-register everything.
            _pending = _names;
        }
        if (_target == 0) {
            // we have tried all possible servers.
            // start from the top after a delay,
            // possibly with a warning.
            double delay = _backOff.get();
            Schedule(delay);
            const char * const msgfmt = "[RPC @ %s] no location brokers available, retrying: %s (in %.1f seconds)";
            vespalib::string cps = _slobrokSpecs.logString();
            if (_backOff.shouldWarn()) {
                LOG(warning, msgfmt, createSpec(_orb).c_str(), cps.c_str(), delay);
            } else {
                LOG(debug, msgfmt, createSpec(_orb).c_str(), cps.c_str(), delay);
            }
            return;
        }
    }
}

// perform any unregister or register that is pending
void
RegisterAPI::handlePending()
{
    bool unreg = false;
    bool reg   = false;
    vespalib::string name;
    {
        std::lock_guard<std::mutex> guard(_lock);
        // pop off the todo stack, unregister has priority
        if (_unreg.size() > 0) {
            name = _unreg.back();
            _unreg.pop_back();
            unreg = true;
        } else if (_pending.size() > 0) {
            name = _pending.back();
            _pending.pop_back();
            reg = true;
        }
    }

    if (unreg) {
        // start a new unregister request
        LOG_ASSERT(!reg);
        _req = _orb.AllocRPCRequest();
        _req->SetMethodName("slobrok.unregisterRpcServer");
        _req->GetParams()->AddString(name.c_str());
        LOG(debug, "unregister [%s]", name.c_str());
        _req->GetParams()->AddString(createSpec(_orb).c_str());
        _target->InvokeAsync(_req, 35.0, this);
    } else if (reg) {
        // start a new register request
        _req = _orb.AllocRPCRequest();
        _req->SetMethodName("slobrok.registerRpcServer");
        _req->GetParams()->AddString(name.c_str());
        LOG(debug, "register [%s]", name.c_str());
        _req->GetParams()->AddString(createSpec(_orb).c_str());
        _target->InvokeAsync(_req, 35.0, this);
    } else {
        // nothing more to do right now; schedule to re-register all
        // names after a long delay.
        std::lock_guard<std::mutex> guard(_lock);
        _pending = _names;
        LOG(debug, "done, reschedule in 30s");
        _busy.store(false, std::memory_order_relaxed);
        Schedule(30.0);
    }
}

void
RegisterAPI::PerformTask()
{
    handleReqDone();
    if (_req != 0) {
        LOG(debug, "req in progress");
        return; // current request still in progress, don't start anything new
    }
    handleReconnect();
    // still no connection?
    if (_target == 0) return;
    handlePending();
}

void
RegisterAPI::RequestDone([[maybe_unused]] FRT_RPCRequest *req)
{
    {
        std::lock_guard guard(_lock);
        LOG_ASSERT(req == _req && !_reqDone);
        _reqDone = true;
    }
    ScheduleNow();
}

//-----------------------------------------------------------------------------

RegisterAPI::RPCHooks::RPCHooks(RegisterAPI &owner)
    : _owner(owner)
{
    FRT_ReflectionBuilder rb(&_owner._orb);
    //-------------------------------------------------------------------------
    rb.DefineMethod("slobrok.callback.listNamesServed", "", "S",
                    FRT_METHOD(RPCHooks::rpc_listNamesServed), this);
    rb.MethodDesc("List rpcserver names");
    rb.ReturnDesc("names", "The rpcserver names this server wants to serve");
    //-------------------------------------------------------------------------
    rb.DefineMethod("slobrok.callback.notifyUnregistered", "s", "",
                    FRT_METHOD(RPCHooks::rpc_notifyUnregistered), this);
    rb.MethodDesc("Notify a server about removed registration");
    rb.ParamDesc("name", "RpcServer name");
    //-------------------------------------------------------------------------
}

RegisterAPI::RPCHooks::~RPCHooks()
{
}

void
RegisterAPI::RPCHooks::rpc_listNamesServed(FRT_RPCRequest *req)
{
    FRT_Values &dst = *req->GetReturn();
    std::lock_guard<std::mutex> guard(_owner._lock);
    FRT_StringValue *names = dst.AddStringArray(_owner._names.size());
    for (uint32_t i = 0; i < _owner._names.size(); ++i) {
        dst.SetString(&names[i], _owner._names[i].c_str());
    }
}

void
RegisterAPI::RPCHooks::rpc_notifyUnregistered(FRT_RPCRequest *req)
{
    FRT_Values &args = *req->GetParams();
    LOG(warning, "unregistered name %s", args[0]._string._str);
}

}
<commit_msg>Minor code cleanups - no change in semantics<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "sbregister.h"
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/exceptions.h>

#include <vespa/log/log.h>
LOG_SETUP(".slobrok.register");

using vespalib::NetworkSetupFailureException;

namespace {

vespalib::string
createSpec(FRT_Supervisor &orb)
{
    vespalib::string spec;
    if (orb.GetListenPort() != 0) {
        vespalib::asciistream str;
        str << "tcp/";
        str << vespalib::HostName::get();
        str << ":";
        str << orb.GetListenPort();
        spec = str.str();
    }
    return spec;
}

void
discard(std::vector<vespalib::string> &vec, vespalib::stringref val)
{
    uint32_t i = 0;
    uint32_t size = vec.size();
    while (i < size) {
        if (vec[i] == val) {
            std::swap(vec[i], vec[size - 1]);
            vec.pop_back();
            --size;
        } else {
            ++i;
        }
    }
    LOG_ASSERT(size == vec.size());
}

} // namespace <unnamed>

namespace slobrok::api {

RegisterAPI::RegisterAPI(FRT_Supervisor &orb, const ConfiguratorFactory & config)
    : FNET_Task(orb.GetScheduler()),
      _orb(orb),
      _hooks(*this),
      _lock(),
      _reqDone(false),
      _logOnSuccess(true),
      _busy(false),
      _slobrokSpecs(),
      _configurator(config.create(_slobrokSpecs)),
      _currSlobrok(""),
      _idx(0),
      _backOff(),
      _names(),
      _pending(),
      _unreg(),
      _target(nullptr),
      _req(nullptr)
{
    _configurator->poll();
    if ( ! _slobrokSpecs.ok()) {
        throw NetworkSetupFailureException("Failed configuring the RegisterAPI. No valid slobrok specs from config",
                                           VESPA_STRLOC);
    }
    ScheduleNow();
}

RegisterAPI::~RegisterAPI()
{
    Kill();
    _configurator.reset();
    if (_req != nullptr) {
        _req->Abort();
        _req->SubRef();
    }
    if (_target != nullptr) {
        _target->SubRef();
    }
}

void
RegisterAPI::registerName(vespalib::stringref name)
{
    std::lock_guard guard(_lock);
    for (const auto& existing_name : _names) {
        if (existing_name == name) {
            return;
        }
    }
    _busy.store(true, std::memory_order_relaxed);
    _names.emplace_back(name);
    _pending.emplace_back(name);
    discard(_unreg, name);
    ScheduleNow();
}

void
RegisterAPI::unregisterName(vespalib::stringref name)
{
    std::lock_guard guard(_lock);
    _busy.store(true, std::memory_order_relaxed);
    discard(_names, name);
    discard(_pending, name);
    _unreg.emplace_back(name);
    ScheduleNow();
}

// handle any request that completed
void
RegisterAPI::handleReqDone()
{
    std::lock_guard guard(_lock);
    if (_reqDone) {
        _reqDone = false;
        if (_req->IsError()) {
            if (_req->GetErrorCode() != FRTE_RPC_METHOD_FAILED) {
                LOG(debug, "register failed: %s (code %d)",
                    _req->GetErrorMessage(), _req->GetErrorCode());
                // unexpected error; close our connection to this
                // slobrok server and try again with a fresh slate
                if (_target != nullptr) {
                    _target->SubRef();
                }
                _target = nullptr;
                _busy.store(true, std::memory_order_relaxed);
            } else {
                LOG(warning, "%s(%s -> %s) failed: %s",
                    _req->GetMethodName(),
                    (*_req->GetParams())[0]._string._str,
                    (*_req->GetParams())[1]._string._str,
                    _req->GetErrorMessage());
            }
        } else {
            if (_logOnSuccess && _pending.empty() && !_names.empty()) {
                LOG(info, "[RPC @ %s] registering %s with location broker %s completed successfully",
                    createSpec(_orb).c_str(), _names[0].c_str(), _currSlobrok.c_str());
                _logOnSuccess = false;
            }
            // reset backoff strategy on any successful request
            _backOff.reset();
        }
        _req->SubRef();
        _req = nullptr;
    }
}

// do we need to try to reconnect?
void
RegisterAPI::handleReconnect()
{
    if (_configurator->poll() && _target != nullptr) {
        if (! _slobrokSpecs.contains(_currSlobrok)) {
            vespalib::string cps = _slobrokSpecs.logString();
            LOG(warning, "[RPC @ %s] location broker %s removed, will disconnect and use one of: %s",
                createSpec(_orb).c_str(), _currSlobrok.c_str(), cps.c_str());
            _target->SubRef();
            _target = nullptr;
        }
    }
    if (_target == nullptr) {
        _logOnSuccess = true;
        _currSlobrok = _slobrokSpecs.nextSlobrokSpec();
        if (!_currSlobrok.empty()) {
            // try next possible server.
            _target = _orb.GetTarget(_currSlobrok.c_str());
        }
        {
            std::lock_guard guard(_lock);
            // now that we have a new connection, we need to
            // immediately re-register everything.
            _pending = _names;
        }
        if (_target == nullptr) {
            // we have tried all possible servers.
            // start from the top after a delay,
            // possibly with a warning.
            double delay = _backOff.get();
            Schedule(delay);
            const char * const msgfmt = "[RPC @ %s] no location brokers available, retrying: %s (in %.1f seconds)";
            vespalib::string cps = _slobrokSpecs.logString();
            if (_backOff.shouldWarn()) {
                LOG(warning, msgfmt, createSpec(_orb).c_str(), cps.c_str(), delay);
            } else {
                LOG(debug, msgfmt, createSpec(_orb).c_str(), cps.c_str(), delay);
            }
            return;
        }
    }
}

// perform any unregister or register that is pending
void
RegisterAPI::handlePending()
{
    bool unreg = false;
    bool reg   = false;
    vespalib::string name;
    {
        std::lock_guard guard(_lock);
        // pop off the todo stack, unregister has priority
        if (!_unreg.empty()) {
            name = _unreg.back();
            _unreg.pop_back();
            unreg = true;
        } else if (!_pending.empty()) {
            name = _pending.back();
            _pending.pop_back();
            reg = true;
        }
    }

    if (unreg) {
        // start a new unregister request
        LOG_ASSERT(!reg);
        _req = _orb.AllocRPCRequest();
        _req->SetMethodName("slobrok.unregisterRpcServer");
        _req->GetParams()->AddString(name.c_str());
        LOG(debug, "unregister [%s]", name.c_str());
        _req->GetParams()->AddString(createSpec(_orb).c_str());
        _target->InvokeAsync(_req, 35.0, this);
    } else if (reg) {
        // start a new register request
        _req = _orb.AllocRPCRequest();
        _req->SetMethodName("slobrok.registerRpcServer");
        _req->GetParams()->AddString(name.c_str());
        LOG(debug, "register [%s]", name.c_str());
        _req->GetParams()->AddString(createSpec(_orb).c_str());
        _target->InvokeAsync(_req, 35.0, this);
    } else {
        // nothing more to do right now; schedule to re-register all
        // names after a long delay.
        std::lock_guard guard(_lock);
        _pending = _names;
        LOG(debug, "done, reschedule in 30s");
        _busy.store(false, std::memory_order_relaxed);
        Schedule(30.0);
    }
}

void
RegisterAPI::PerformTask()
{
    handleReqDone();
    if (_req != nullptr) {
        LOG(debug, "req in progress");
        return; // current request still in progress, don't start anything new
    }
    handleReconnect();
    // still no connection?
    if (_target == nullptr) return;
    handlePending();
}

void
RegisterAPI::RequestDone([[maybe_unused]] FRT_RPCRequest *req)
{
    {
        std::lock_guard guard(_lock);
        LOG_ASSERT(req == _req && !_reqDone);
        _reqDone = true;
    }
    ScheduleNow();
}

//-----------------------------------------------------------------------------

RegisterAPI::RPCHooks::RPCHooks(RegisterAPI &owner)
    : _owner(owner)
{
    FRT_ReflectionBuilder rb(&_owner._orb);
    //-------------------------------------------------------------------------
    rb.DefineMethod("slobrok.callback.listNamesServed", "", "S",
                    FRT_METHOD(RPCHooks::rpc_listNamesServed), this);
    rb.MethodDesc("List rpcserver names");
    rb.ReturnDesc("names", "The rpcserver names this server wants to serve");
    //-------------------------------------------------------------------------
    rb.DefineMethod("slobrok.callback.notifyUnregistered", "s", "",
                    FRT_METHOD(RPCHooks::rpc_notifyUnregistered), this);
    rb.MethodDesc("Notify a server about removed registration");
    rb.ParamDesc("name", "RpcServer name");
    //-------------------------------------------------------------------------
}

RegisterAPI::RPCHooks::~RPCHooks() = default;

void
RegisterAPI::RPCHooks::rpc_listNamesServed(FRT_RPCRequest *req)
{
    FRT_Values &dst = *req->GetReturn();
    std::lock_guard guard(_owner._lock);
    FRT_StringValue *names = dst.AddStringArray(_owner._names.size());
    for (uint32_t i = 0; i < _owner._names.size(); ++i) {
        dst.SetString(&names[i], _owner._names[i].c_str());
    }
}

void
RegisterAPI::RPCHooks::rpc_notifyUnregistered(FRT_RPCRequest *req)
{
    FRT_Values &args = *req->GetParams();
    LOG(warning, "unregistered name %s", args[0]._string._str);
}

}
<|endoftext|>


<commit_before>#ifndef N3RV_PROTO_HPP
#define N3RV_PROTO_HPP

#include <vector>
#include <map>

#include "n3rvcommon.hpp"

namespace n3rv {

  /** Main n3rv message struct */
  typedef struct message_ {

    /** message sender (automatically filled at send-time) */
    std::string sender;
    /** which action is required to process payload. */
    std::string action;
    /** eventual arguments needed to complete action. */
    std::vector<std::string> args;
    /** message payload. */
    std::string payload;

  } message;

  /**
   * Serializes message for later sending over the net as a JSON string.
   * @param msg message to serialize.
   * @return serialized message as string.
   */
  std::string serialize_msg(n3rv::message& msg);

  /**
   * Parses a Protobuf message comming from a service and
   * puts it inside a n3rvquery structure.
   * @param msgstr message to parse.
   * @return parsed message.
   */
  n3rv::message parse_msg(std::string msgstr);

  /**
   * Parses a Protobuf message directly from zmq message container.
   * @param msg ZMQ message to parse.
   * @return parsed message.
   */
  n3rv::message parse_msg(zmq::message_t* msg);

  /**
   * Performs the protobuf-serialization of a services directory.
   * @param directory Directory to serialize.
   * @return String-serialized directory.
   */
  std::string serialize_directory(std::vector<n3rv::qserv>& directory);

  /**
   * Performs parsing of protobuf dirstring.
   * @param String-serialized directory.
   * @return Unserialized Directory.
   */
  std::vector<n3rv::qserv> parse_directory(std::string dirstr);

  void t128bug(std::string& q);

}

#endif<commit_msg>n3rvproto: fixed word inside docstring.<commit_after>#ifndef N3RV_PROTO_HPP
#define N3RV_PROTO_HPP

#include <vector>
#include <map>

#include "n3rvcommon.hpp"

namespace n3rv {

  /** Main n3rv message struct */
  typedef struct message_ {

    /** message sender (automatically filled at send-time) */
    std::string sender;
    /** which action is required to process payload. */
    std::string action;
    /** eventual arguments needed to complete action. */
    std::vector<std::string> args;
    /** message payload. */
    std::string payload;

  } message;

  /**
   * Serializes message for later sending over the net as a JSON string.
   * @param msg message to serialize.
   * @return serialized message as string.
   */
  std::string serialize_msg(n3rv::message& msg);

  /**
   * Parses a serialized message comming from a service and
   * puts it inside a n3rv message structure.
   * @param msgstr message to parse.
   * @return parsed message.
   */
  n3rv::message parse_msg(std::string msgstr);

  /**
   * Parses a Protobuf message directly from zmq message container.
   * @param msg ZMQ message to parse.
   * @return parsed message.
   */
  n3rv::message parse_msg(zmq::message_t* msg);

  /**
   * Performs the protobuf-serialization of a services directory.
   * @param directory Directory to serialize.
   * @return String-serialized directory.
   */
  std::string serialize_directory(std::vector<n3rv::qserv>& directory);

  /**
   * Performs parsing of protobuf dirstring.
   * @param String-serialized directory.
   * @return Unserialized Directory.
   */
  std::vector<n3rv::qserv> parse_directory(std::string dirstr);

  void t128bug(std::string& q);

}

#endif<|endoftext|>


<commit_before>// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "snapshot/win/system_snapshot_win.h"

#include <sys/time.h>
#include <time.h>

#include <regex>
#include <string>

#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/win/process_reader_win.h"

namespace crashpad {
namespace test {
namespace {

class SystemSnapshotWinTest : public testing::Test {
 public:
  SystemSnapshotWinTest()
      : Test(),
        process_reader_(),
        system_snapshot_() {
  }

  const internal::SystemSnapshotWin& system_snapshot() const {
    return system_snapshot_;
  }

  // testing::Test:
  void SetUp() override {
    ASSERT_TRUE(process_reader_.Initialize(GetCurrentProcess(),
                                           ProcessSuspensionState::kRunning));
    system_snapshot_.Initialize(&process_reader_);
  }

 private:
  ProcessReaderWin process_reader_;
  internal::SystemSnapshotWin system_snapshot_;

  DISALLOW_COPY_AND_ASSIGN(SystemSnapshotWinTest);
};

TEST_F(SystemSnapshotWinTest, GetCPUArchitecture) {
  CPUArchitecture cpu_architecture = system_snapshot().GetCPUArchitecture();

#if defined(ARCH_CPU_X86)
  EXPECT_EQ(cpu_architecture, kCPUArchitectureX86);
#elif defined(ARCH_CPU_X86_64)
  EXPECT_EQ(cpu_architecture, kCPUArchitectureX86_64);
#elif defined(ARCH_CPU_ARM64)
  EXPECT_EQ(cpu_architecture, kCPUArchitectureARM64);
#else
#error Unsupported Windows Arch
#endif
}

TEST_F(SystemSnapshotWinTest, CPUCount) {
  EXPECT_GE(system_snapshot().CPUCount(), 1);
}

TEST_F(SystemSnapshotWinTest, CPUVendor) {
  std::string cpu_vendor = system_snapshot().CPUVendor();
#if defined(ARCH_CPU_X86_FAMILY)
  EXPECT_TRUE(cpu_vendor == "GenuineIntel" || cpu_vendor == "AuthenticAMD");
#elif defined(ARCH_CPU_ARM64)
  std::regex cpu_vendor_regex("[a-zA-Z0-9 \\-.]+");
  EXPECT_TRUE(std::regex_match(cpu_vendor, cpu_vendor_regex));
#else
#error Unsupported Windows Arch
#endif
}

#if defined(ARCH_CPU_X86_FAMILY)
TEST_F(SystemSnapshotWinTest, CPUX86SupportsDAZ) {
  // Most SSE2+ machines support Denormals-Are-Zero. This may fail if run on
  // older machines.
  EXPECT_TRUE(system_snapshot().CPUX86SupportsDAZ());
}
#endif

TEST_F(SystemSnapshotWinTest, GetOperatingSystem) {
  EXPECT_EQ(system_snapshot().GetOperatingSystem(),
            SystemSnapshot::kOperatingSystemWindows);
}

TEST_F(SystemSnapshotWinTest, OSVersion) {
  int major;
  int minor;
  int bugfix;
  std::string build;
  system_snapshot().OSVersion(&major, &minor, &bugfix, &build);

  EXPECT_GE(major, 5);
  if (major == 5)
    EXPECT_GE(minor, 1);
  if (major == 6)
    EXPECT_TRUE(minor >= 0 && minor <= 3);
}

TEST_F(SystemSnapshotWinTest, OSVersionFull) {
  EXPECT_FALSE(system_snapshot().OSVersionFull().empty());
}

TEST_F(SystemSnapshotWinTest, MachineDescription) {
  EXPECT_TRUE(system_snapshot().MachineDescription().empty());
}

TEST_F(SystemSnapshotWinTest, TimeZone) {
  SystemSnapshot::DaylightSavingTimeStatus dst_status;
  int standard_offset_seconds;
  int daylight_offset_seconds;
  std::string standard_name;
  std::string daylight_name;

  system_snapshot().TimeZone(&dst_status,
                             &standard_offset_seconds,
                             &daylight_offset_seconds,
                             &standard_name,
                             &daylight_name);

  // |standard_offset_seconds| gives seconds east of UTC, and |timezone| gives
  // seconds west of UTC.
  long timezone = 0;
  _get_timezone(&timezone);
  EXPECT_EQ(standard_offset_seconds, -timezone);

  // In contemporary usage, most time zones have an integer hour offset from
  // UTC, although several are at a half-hour offset, and two are at 15-minute
  // offsets. Throughout history, other variations existed. See
  // https://www.timeanddate.com/time/time-zones-interesting.html.
  EXPECT_EQ(standard_offset_seconds % (15 * 60), 0)
      << "standard_offset_seconds " << standard_offset_seconds;

  // dst_status of kDoesNotObserveDaylightSavingTime can mean only that the
  // adjustment is not automatic, as opposed to daylight/standard differences
  // not existing at all. So it cannot be asserted that the two offsets are the
  // same in that case.

  EXPECT_EQ(daylight_offset_seconds % (15 * 60), 0)
      << "daylight_offset_seconds " << daylight_offset_seconds;

  // In contemporary usage, dst_delta_seconds will almost always be one hour,
  // except for Lord Howe Island, Australia, which uses a 30-minute delta.
  // Throughout history, other variations existed. See
  // https://www.timeanddate.com/time/dst/.
  int dst_delta_seconds = daylight_offset_seconds - standard_offset_seconds;
  if (dst_delta_seconds != 60 * 60 && dst_delta_seconds != 30 * 60) {
    FAIL() << "dst_delta_seconds " << dst_delta_seconds;
  }

  if (dst_status != SystemSnapshot::kDoesNotObserveDaylightSavingTime) {
    EXPECT_NE(standard_name, daylight_name);
  }
}

}  // namespace
}  // namespace test
}  // namespace crashpad
<commit_msg>Don't use a regex to test the CPU vendor string.<commit_after>// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "snapshot/win/system_snapshot_win.h"

#include <sys/time.h>
#include <time.h>

#include <string>

#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/win/process_reader_win.h"

namespace crashpad {
namespace test {
namespace {

class SystemSnapshotWinTest : public testing::Test {
 public:
  SystemSnapshotWinTest()
      : Test(),
        process_reader_(),
        system_snapshot_() {
  }

  const internal::SystemSnapshotWin& system_snapshot() const {
    return system_snapshot_;
  }

  // testing::Test:
  void SetUp() override {
    ASSERT_TRUE(process_reader_.Initialize(GetCurrentProcess(),
                                           ProcessSuspensionState::kRunning));
    system_snapshot_.Initialize(&process_reader_);
  }

 private:
  ProcessReaderWin process_reader_;
  internal::SystemSnapshotWin system_snapshot_;

  DISALLOW_COPY_AND_ASSIGN(SystemSnapshotWinTest);
};

TEST_F(SystemSnapshotWinTest, GetCPUArchitecture) {
  CPUArchitecture cpu_architecture = system_snapshot().GetCPUArchitecture();

#if defined(ARCH_CPU_X86)
  EXPECT_EQ(cpu_architecture, kCPUArchitectureX86);
#elif defined(ARCH_CPU_X86_64)
  EXPECT_EQ(cpu_architecture, kCPUArchitectureX86_64);
#elif defined(ARCH_CPU_ARM64)
  EXPECT_EQ(cpu_architecture, kCPUArchitectureARM64);
#else
#error Unsupported Windows Arch
#endif
}

TEST_F(SystemSnapshotWinTest, CPUCount) {
  EXPECT_GE(system_snapshot().CPUCount(), 1);
}

TEST_F(SystemSnapshotWinTest, CPUVendor) {
  std::string cpu_vendor = system_snapshot().CPUVendor();
#if defined(ARCH_CPU_X86_FAMILY)
  EXPECT_TRUE(cpu_vendor == "GenuineIntel" || cpu_vendor == "AuthenticAMD");
#elif defined(ARCH_CPU_ARM64)
  EXPECT_FALSE(cpu_vendor.empty());
#else
#error Unsupported Windows Arch
#endif
}

#if defined(ARCH_CPU_X86_FAMILY)
TEST_F(SystemSnapshotWinTest, CPUX86SupportsDAZ) {
  // Most SSE2+ machines support Denormals-Are-Zero. This may fail if run on
  // older machines.
  EXPECT_TRUE(system_snapshot().CPUX86SupportsDAZ());
}
#endif

TEST_F(SystemSnapshotWinTest, GetOperatingSystem) {
  EXPECT_EQ(system_snapshot().GetOperatingSystem(),
            SystemSnapshot::kOperatingSystemWindows);
}

TEST_F(SystemSnapshotWinTest, OSVersion) {
  int major;
  int minor;
  int bugfix;
  std::string build;
  system_snapshot().OSVersion(&major, &minor, &bugfix, &build);

  EXPECT_GE(major, 5);
  if (major == 5)
    EXPECT_GE(minor, 1);
  if (major == 6)
    EXPECT_TRUE(minor >= 0 && minor <= 3);
}

TEST_F(SystemSnapshotWinTest, OSVersionFull) {
  EXPECT_FALSE(system_snapshot().OSVersionFull().empty());
}

TEST_F(SystemSnapshotWinTest, MachineDescription) {
  EXPECT_TRUE(system_snapshot().MachineDescription().empty());
}

TEST_F(SystemSnapshotWinTest, TimeZone) {
  SystemSnapshot::DaylightSavingTimeStatus dst_status;
  int standard_offset_seconds;
  int daylight_offset_seconds;
  std::string standard_name;
  std::string daylight_name;

  system_snapshot().TimeZone(&dst_status,
                             &standard_offset_seconds,
                             &daylight_offset_seconds,
                             &standard_name,
                             &daylight_name);

  // |standard_offset_seconds| gives seconds east of UTC, and |timezone| gives
  // seconds west of UTC.
  long timezone = 0;
  _get_timezone(&timezone);
  EXPECT_EQ(standard_offset_seconds, -timezone);

  // In contemporary usage, most time zones have an integer hour offset from
  // UTC, although several are at a half-hour offset, and two are at 15-minute
  // offsets. Throughout history, other variations existed. See
  // https://www.timeanddate.com/time/time-zones-interesting.html.
  EXPECT_EQ(standard_offset_seconds % (15 * 60), 0)
      << "standard_offset_seconds " << standard_offset_seconds;

  // dst_status of kDoesNotObserveDaylightSavingTime can mean only that the
  // adjustment is not automatic, as opposed to daylight/standard differences
  // not existing at all. So it cannot be asserted that the two offsets are the
  // same in that case.

  EXPECT_EQ(daylight_offset_seconds % (15 * 60), 0)
      << "daylight_offset_seconds " << daylight_offset_seconds;

  // In contemporary usage, dst_delta_seconds will almost always be one hour,
  // except for Lord Howe Island, Australia, which uses a 30-minute delta.
  // Throughout history, other variations existed. See
  // https://www.timeanddate.com/time/dst/.
  int dst_delta_seconds = daylight_offset_seconds - standard_offset_seconds;
  if (dst_delta_seconds != 60 * 60 && dst_delta_seconds != 30 * 60) {
    FAIL() << "dst_delta_seconds " << dst_delta_seconds;
  }

  if (dst_status != SystemSnapshot::kDoesNotObserveDaylightSavingTime) {
    EXPECT_NE(standard_name, daylight_name);
  }
}

}  // namespace
}  // namespace test
}  // namespace crashpad
<|endoftext|>


<commit_before>#pragma once
#include "../arglist.hpp"
static cov_basic::extension runtime_ext;
namespace runtime_cbs_ext {
	using namespace cov_basic;
	cov::any info(array&)
	{
		std::cout<<"Covariant Basic Parser\nVersion:"<<cov_basic::version<<"\nCopyright (C) 2017 Michael Lee"<<std::endl;
		return number(0);
	}
	cov::any time(array&)
	{
		return number(cov::timer::time(cov::timer::time_unit::milli_sec));
	}
	cov::any delay(array& args)
	{
		arglist::check<number>(args);
		cov::timer::delay(cov::timer::time_unit::milli_sec,cov::timer::timer_t(args.front().const_val<number>()));
		return number(0);
	}
	cov::any rand(array& args)
	{
		arglist::check<number,number>(args);
		return number(cov::rand<number>(args.at(0).const_val<number>(),args.at(1).const_val<number>()));
	}
	cov::any randint(array& args)
	{
		arglist::check<number,number>(args);
		return number(cov::rand<long>(args.at(0).const_val<number>(),args.at(1).const_val<number>()));
	}
	cov::any error(array& args)
	{
		arglist::check<string>(args);
		throw lang_error(args.front().const_val<string>());
		return number(0);
	}
	cov::any load_extension(array& args)
	{
		arglist::check<string>(args);
		return std::make_shared<extension_holder>(args.front().const_val<string>());
	}
	cov::any type_hash(array& args)
	{
		if(args.size()!=1)
			throw syntax_error("Wrong size of arguments.");
		if(args.front().type()==typeid(structure))
			return cov::hash<std::string>(args.front().const_val<structure>().get_name());
		else
			return cov::hash<std::string>(args.front().type().name());
	}
	cov::any hash(array& args)
	{
		if(args.size()!=1)
			throw syntax_error("Wrong size of arguments.");
		return args.front().hash();
	}
	using expression_t=cov::tree<token_base*>;
	cov::any build(array& args)
	{
		arglist::check<string>(args);
		std::deque<char> buff;
		std::deque<token_base*> tokens;
		expression_t tree;
		for(auto& ch:args.at(0).const_val<string>())
			buff.push_back(ch);
		translate_into_tokens(buff,tokens);
		process_brackets(tokens);
		kill_brackets(tokens);
		gen_tree(tree,tokens);
		return cov::any::make<expression_t>(tree);
	}
	cov::any solve(array& args)
	{
		arglist::check<expression_t>(args);
		return parse_expr(args.at(0).val<expression_t>(true).root());
	}
	void init()
	{
		runtime_ext.add_var("info",native_interface(info));
		runtime_ext.add_var("time",native_interface(time));
		runtime_ext.add_var("delay",native_interface(delay));
		runtime_ext.add_var("rand",native_interface(rand));
		runtime_ext.add_var("randint",native_interface(randint));
		runtime_ext.add_var("error",native_interface(error));
		runtime_ext.add_var("load_extension",native_interface(load_extension));
		runtime_ext.add_var("type_hash",native_interface(type_hash));
		runtime_ext.add_var("hash",native_interface(hash));
		runtime_ext.add_var("build",native_interface(build));
		runtime_ext.add_var("solve",native_interface(solve));
	}
}
<commit_msg>支持exit函数<commit_after>#pragma once
#include "../arglist.hpp"
#include <cstdlib>
static cov_basic::extension runtime_ext;
namespace runtime_cbs_ext {
	using namespace cov_basic;
	cov::any info(array&)
	{
		std::cout<<"Covariant Basic Parser\nVersion:"<<cov_basic::version<<"\nCopyright (C) 2017 Michael Lee"<<std::endl;
		return number(0);
	}
	cov::any time(array&)
	{
		return number(cov::timer::time(cov::timer::time_unit::milli_sec));
	}
	cov::any delay(array& args)
	{
		arglist::check<number>(args);
		cov::timer::delay(cov::timer::time_unit::milli_sec,cov::timer::timer_t(args.front().const_val<number>()));
		return number(0);
	}
	cov::any rand(array& args)
	{
		arglist::check<number,number>(args);
		return number(cov::rand<number>(args.at(0).const_val<number>(),args.at(1).const_val<number>()));
	}
	cov::any randint(array& args)
	{
		arglist::check<number,number>(args);
		return number(cov::rand<long>(args.at(0).const_val<number>(),args.at(1).const_val<number>()));
	}
	cov::any error(array& args)
	{
		arglist::check<string>(args);
		throw lang_error(args.front().const_val<string>());
		return number(0);
	}
	cov::any load_extension(array& args)
	{
		arglist::check<string>(args);
		return std::make_shared<extension_holder>(args.front().const_val<string>());
	}
	cov::any type_hash(array& args)
	{
		if(args.size()!=1)
			throw syntax_error("Wrong size of arguments.");
		if(args.front().type()==typeid(structure))
			return cov::hash<std::string>(args.front().const_val<structure>().get_name());
		else
			return cov::hash<std::string>(args.front().type().name());
	}
	cov::any hash(array& args)
	{
		if(args.size()!=1)
			throw syntax_error("Wrong size of arguments.");
		return args.front().hash();
	}
	using expression_t=cov::tree<token_base*>;
	cov::any build(array& args)
	{
		arglist::check<string>(args);
		std::deque<char> buff;
		std::deque<token_base*> tokens;
		expression_t tree;
		for(auto& ch:args.at(0).const_val<string>())
			buff.push_back(ch);
		translate_into_tokens(buff,tokens);
		process_brackets(tokens);
		kill_brackets(tokens);
		gen_tree(tree,tokens);
		return cov::any::make<expression_t>(tree);
	}
	cov::any solve(array& args)
	{
		arglist::check<expression_t>(args);
		return parse_expr(args.at(0).val<expression_t>(true).root());
	}
	cov::any exit(array& args)
	{
		arglist::check<number>(args);
		std::exit(args.at(0).const_val<number>());
		return number(0);
	}
	void init()
	{
		runtime_ext.add_var("info",native_interface(info));
		runtime_ext.add_var("time",native_interface(time));
		runtime_ext.add_var("delay",native_interface(delay));
		runtime_ext.add_var("rand",native_interface(rand));
		runtime_ext.add_var("randint",native_interface(randint));
		runtime_ext.add_var("error",native_interface(error));
		runtime_ext.add_var("load_extension",native_interface(load_extension));
		runtime_ext.add_var("type_hash",native_interface(type_hash));
		runtime_ext.add_var("hash",native_interface(hash));
		runtime_ext.add_var("build",native_interface(build));
		runtime_ext.add_var("solve",native_interface(solve));
		runtime_ext.add_var("exit",native_interface(exit));
	}
}
<|endoftext|>


<commit_before>/*************************************
** Tsunagari Tile Engine            **
** main.cpp                         **
** Copyright 2016-2019 Paul Merrill **
*************************************/

// **********
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// **********

#include "os/c.h"
#include "os/mutex.h"
#include "os/os.h"
#include "pack/pack-reader.h"
#include "pack/pack-writer.h"
#include "pack/ui.h"
#include "pack/walker.h"
#include "util/int.h"
#include "util/move.h"
#include "util/optional.h"
#include "util/string-view.h"
#include "util/string.h"
#include "util/unique.h"

static String exe;

static void
usage() noexcept {
    fprintf(stderr,
            "usage: %s create [-v] <output-archive> [input-file]...\n",
            exe.null().get());
    fprintf(stderr, "       %s list <input-archive>\n", exe.null().get());
    fprintf(stderr,
            "       %s extract [-v] <input-archive>\n",
            exe.null().get());
}

struct CreateArchiveContext {
    Unique<PackWriter> pack;
    Mutex packMutex;
};

static void
addFile(CreateArchiveContext& ctx, StringView path) noexcept {
    Optional<String> data = readFile(path);

    if (!data) {
        uiShowSkippedMissingFile(path);
        return;
    }

    String data_ = move_(*data);

    uiShowAddedFile(path, data_.size());

    LockGuard guard(ctx.packMutex);
    ctx.pack->addBlob(move_(path), static_cast<uint32_t>(data_.size()), data_.data());

    data_.reset_lose_memory();  // Don't delete data pointer.
}

static bool
createArchive(StringView archivePath, Vector<StringView> paths) noexcept {
    UI ui;

    CreateArchiveContext ctx;
    ctx.pack = PackWriter::make();

    walk(move_(paths), [&](StringView path) { addFile(ctx, path); });

    uiShowWritingArchive(archivePath);

    return ctx.pack->writeToFile(archivePath);
}

static bool
listArchive(StringView archivePath) noexcept {
    UI ui;

    Unique<PackReader> pack = PackReader::fromFile(archivePath);

    if (pack) {
        String output;

        for (PackReader::BlobIndex i = 0; i < pack->size(); i++) {
            StringView blobPath = pack->getBlobPath(i);
            uint64_t blobSize = pack->getBlobSize(i);

            output.append(blobPath.data, blobPath.size);
            output << ": " << blobSize << " bytes\n";
        }

        printf("%s", output.null().get());
        return true;
    }
    else {
        fprintf(stderr,
                "%s",
                (String() << exe << ": " << archivePath << ": not found\n")
                        .null()
                        .get());
        return false;
    }
}

static Optional<StringView>
getParentPath(StringView path) noexcept {
    Optional<size_t> sep = path.rfind('/');
    if (!sep) {
        return Optional<StringView>();
    }
    else {
        return Optional<StringView>(path.substr(0, sep));
    }
}

static void
createDirs(StringView path) noexcept {
    Optional<StringView> parentPath = getParentPath(path);
    if (parentPath) {
        // Make sure parentPath's parent exists.
        createDirs(*parentPath);

        makeDirectory(*parentPath);
    }
}

static void
putFile(StringView path, uint32_t size, void* data) noexcept {
    createDirs(path);

    // TODO: Propagate error up.
    writeFile(path, size, data);
}

static bool
extractArchive(StringView archivePath) noexcept {
    UI ui;

    Unique<PackReader> pack = PackReader::fromFile(archivePath);

    if (pack) {
        Vector<PackReader::BlobIndex> blobIndicies;
        for (PackReader::BlobIndex i = 0; i < pack->size(); i++) {
            blobIndicies.push_back(i);
        }

        Vector<void*> blobDatas = pack->getBlobDatas(blobIndicies);

        for (PackReader::BlobIndex i = 0; i < pack->size(); i++) {
            StringView blobPath = pack->getBlobPath(i);
            uint32_t blobSize = pack->getBlobSize(i);
            void* blobData = blobDatas[i];

            uiShowExtractingFile(blobPath, blobSize);

            putFile(blobPath, blobSize, blobData);
        }

        return true;
    }
    else {
        fprintf(stderr,
                "%s: %s: not found\n",
                exe.null().get(),
                String(archivePath).null().get());
        return false;
    }
}

int
main(int argc, char* argv[]) noexcept {
    exe = argv[0];
    Optional<size_t> dir = exe.view().rfind(dirSeparator);
    if (dir) {
        exe = exe.view().substr(*dir + 1);
    }

    if (argc == 1) {
        usage();
        return 0;
    }
    if (argc == 2) {
        usage();
        return 1;
    }

    StringView command = argv[1];
    Vector<StringView> args;

    for (int i = 2; i < argc; i++) {
        args.push_back(argv[i]);
    }

    int exitCode;

    if (command == "create") {
        if (args.size() > 0 && args[0] == "-v") {
            verbose = true;
            args.erase(args.begin());
        }

        if (args.size() < 2) {
            usage();
            return 1;
        }

        // The first argument is the archive, the rest are files to add to it.
        StringView archivePath = args[0];
        args.erase(args.begin());

        return createArchive(archivePath, move_(args)) ? 0 : 1;
    }
    else if (command == "list") {
        verbose = true;

        if (args.size() != 1) {
            usage();
            return 1;
        }

        exitCode = listArchive(args[0]) ? 0 : 1;
    }
    else if (command == "extract") {
        if (args.size() > 0 && args[0] == "-v") {
            verbose = true;
            args.erase(args.begin());
        }

        if (args.size() != 1) {
            usage();
            return 1;
        }

        exitCode = extractArchive(args[0]) ? 0 : 1;
    }
    else {
        usage();
        return 1;
    }

    return exitCode;
}
<commit_msg>pack: Fix bug in archive extraction<commit_after>/*************************************
** Tsunagari Tile Engine            **
** main.cpp                         **
** Copyright 2016-2019 Paul Merrill **
*************************************/

// **********
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// **********

#include "os/c.h"
#include "os/mutex.h"
#include "os/os.h"
#include "pack/pack-reader.h"
#include "pack/pack-writer.h"
#include "pack/ui.h"
#include "pack/walker.h"
#include "util/int.h"
#include "util/move.h"
#include "util/optional.h"
#include "util/string-view.h"
#include "util/string.h"
#include "util/unique.h"

static String exe;

static void
usage() noexcept {
    fprintf(stderr,
            "usage: %s create [-v] <output-archive> [input-file]...\n",
            exe.null().get());
    fprintf(stderr, "       %s list <input-archive>\n", exe.null().get());
    fprintf(stderr,
            "       %s extract [-v] <input-archive>\n",
            exe.null().get());
}

struct CreateArchiveContext {
    Unique<PackWriter> pack;
    Mutex packMutex;
};

static void
addFile(CreateArchiveContext& ctx, StringView path) noexcept {
    Optional<String> data = readFile(path);

    if (!data) {
        uiShowSkippedMissingFile(path);
        return;
    }

    String data_ = move_(*data);

    uiShowAddedFile(path, data_.size());

    LockGuard guard(ctx.packMutex);
    ctx.pack->addBlob(move_(path), static_cast<uint32_t>(data_.size()), data_.data());

    data_.reset_lose_memory();  // Don't delete data pointer.
}

static bool
createArchive(StringView archivePath, Vector<StringView> paths) noexcept {
    UI ui;

    CreateArchiveContext ctx;
    ctx.pack = PackWriter::make();

    walk(move_(paths), [&](StringView path) { addFile(ctx, path); });

    uiShowWritingArchive(archivePath);

    return ctx.pack->writeToFile(archivePath);
}

static bool
listArchive(StringView archivePath) noexcept {
    UI ui;

    Unique<PackReader> pack = PackReader::fromFile(archivePath);

    if (pack) {
        String output;

        for (PackReader::BlobIndex i = 0; i < pack->size(); i++) {
            StringView blobPath = pack->getBlobPath(i);
            uint64_t blobSize = pack->getBlobSize(i);

            output.append(blobPath.data, blobPath.size);
            output << ": " << blobSize << " bytes\n";
        }

        printf("%s", output.null().get());
        return true;
    }
    else {
        fprintf(stderr,
                "%s",
                (String() << exe << ": " << archivePath << ": not found\n")
                        .null()
                        .get());
        return false;
    }
}

static Optional<StringView>
getParentPath(StringView path) noexcept {
    Optional<size_t> sep = path.rfind('/');
    if (!sep) {
        return Optional<StringView>();
    }
    else {
        return Optional<StringView>(path.substr(0, *sep));
    }
}

static void
createDirs(StringView path) noexcept {
    Optional<StringView> parentPath = getParentPath(path);
    if (parentPath) {
        // Make sure parentPath's parent exists.
        createDirs(*parentPath);

        makeDirectory(*parentPath);
    }
}

static void
putFile(StringView path, uint32_t size, void* data) noexcept {
    createDirs(path);

    // TODO: Propagate error up.
    writeFile(path, size, data);
}

static bool
extractArchive(StringView archivePath) noexcept {
    UI ui;

    Unique<PackReader> pack = PackReader::fromFile(archivePath);

    if (pack) {
        Vector<PackReader::BlobIndex> blobIndicies;
        for (PackReader::BlobIndex i = 0; i < pack->size(); i++) {
            blobIndicies.push_back(i);
        }

        Vector<void*> blobDatas = pack->getBlobDatas(blobIndicies);

        for (PackReader::BlobIndex i = 0; i < pack->size(); i++) {
            StringView blobPath = pack->getBlobPath(i);
            uint32_t blobSize = pack->getBlobSize(i);
            void* blobData = blobDatas[i];

            uiShowExtractingFile(blobPath, blobSize);

            putFile(blobPath, blobSize, blobData);
        }

        return true;
    }
    else {
        fprintf(stderr,
                "%s: %s: not found\n",
                exe.null().get(),
                String(archivePath).null().get());
        return false;
    }
}

int
main(int argc, char* argv[]) noexcept {
    exe = argv[0];
    Optional<size_t> dir = exe.view().rfind(dirSeparator);
    if (dir) {
        exe = exe.view().substr(*dir + 1);
    }

    if (argc == 1) {
        usage();
        return 0;
    }
    if (argc == 2) {
        usage();
        return 1;
    }

    StringView command = argv[1];
    Vector<StringView> args;

    for (int i = 2; i < argc; i++) {
        args.push_back(argv[i]);
    }

    int exitCode;

    if (command == "create") {
        if (args.size() > 0 && args[0] == "-v") {
            verbose = true;
            args.erase(args.begin());
        }

        if (args.size() < 2) {
            usage();
            return 1;
        }

        // The first argument is the archive, the rest are files to add to it.
        StringView archivePath = args[0];
        args.erase(args.begin());

        return createArchive(archivePath, move_(args)) ? 0 : 1;
    }
    else if (command == "list") {
        verbose = true;

        if (args.size() != 1) {
            usage();
            return 1;
        }

        exitCode = listArchive(args[0]) ? 0 : 1;
    }
    else if (command == "extract") {
        if (args.size() > 0 && args[0] == "-v") {
            verbose = true;
            args.erase(args.begin());
        }

        if (args.size() != 1) {
            usage();
            return 1;
        }

        exitCode = extractArchive(args[0]) ? 0 : 1;
    }
    else {
        usage();
        return 1;
    }

    return exitCode;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
/// \file  pcapcut.cpp
//------------------------------------------------------------------------------
/// \brief Utility for cutting a part of a large pcap file
//------------------------------------------------------------------------------
// Copyright (c) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-11-28
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <signal.h>
#include <utxx/pcap.hpp>
#include <utxx/string.hpp>
#include <utxx/path.hpp>
#include <utxx/get_option.hpp>
#include <utxx/buffer.hpp>
#include <utxx/version.hpp>

using namespace std;

//------------------------------------------------------------------------------
void usage(std::string const& err="")
{
    auto prog = utxx::path::basename(
        utxx::path::program::name().c_str(),
        utxx::path::program::name().c_str() + utxx::path::program::name().size()
    );

    if (!err.empty())
        cerr << "Invalid option: " << err << "\n\n";
    else {
        cerr << prog <<
        " - Tool for extracting packets from a pcap file\n"
        "Copyright (c) 2016 Serge Aleynikov\n"  <<
        VERSION() << "\n\n"                     <<
        "Usage: " << prog                       <<
        "[-V] [-h] -f InputFile -s StartPktNum -e EndPktNum [-n PktCount]"
                    " -o|-O OutputFile [-h]\n\n"
        "   -V|--version            - Version\n"
        "   -h|--help               - Help screen\n"
        "   -f InputFile            - Input file name\n"
        "   -o OutputFile           - Ouput file name (don't overwrite if exists)\n"
        "   -O OutputFile           - Ouput file name (overwrite if exists)\n"
        "   -s|--start StartPktNum  - Starting packet number (counting from 1)\n"
        "   -e|--end   EndPktNum    - Ending packet number (must be >= StartPktNum)\n"
        "   -n|--count PktCount     - Number of packets to save\n"
        "   -r|--raw                - Output raw packet payload only without pcap format\n\n";
    }

    exit(1);
}

//------------------------------------------------------------------------------
void unhandled_exception() {
  auto p = current_exception();
  try    { rethrow_exception(p); }
  catch  ( exception& e ) { cerr << e.what() << endl; }
  catch  ( ... )          { cerr << "Unknown exception" << endl; }
  exit(1);
}

//------------------------------------------------------------------------------
//  MAIN
//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    string in_file;
    string out_file;
    size_t pk_start  = 1, pk_end = 0, pk_cnt = 0;
    bool   overwrite = false;
    bool   raw_mode  = false;

    set_terminate (&unhandled_exception);

    utxx::opts_parser opts(argc, argv);

    while (opts.next()) {
        if (opts.match("-f", "",        &in_file))  continue;
        if (opts.match("-o", "",        &out_file)) continue;
        if (opts.match("-O", "",        &out_file)){overwrite=true; continue;}
        if (opts.match("-r", "--raw",   &raw_mode)) continue;
        if (opts.match("-s", "--start", &pk_start)) continue;
        if (opts.match("-e", "--end",   &pk_end))   continue;
        if (opts.match("-n", "--count", &pk_cnt))   continue;
        if (opts.match("-V", "--version")) throw std::runtime_error(VERSION());
        if (opts.is_help())                         usage();

        usage(opts());
    }

    if (pk_end > 0 && pk_cnt > 0)
        throw std::runtime_error("Cannot specify both -n and -e options!");
    else if (!pk_end && !pk_cnt)
        throw std::runtime_error("Must specify either -n or -e option!");
    else if (!pk_start)
        throw std::runtime_error("PktStartNumber (-s) must be greater than 0!");
    else if (pk_end && pk_end < pk_start)
        throw std::runtime_error
             ("Ending packet number (-e) must not be less than starting packet number (-s)!");
    else if (in_file.empty() || out_file.empty())
        throw std::runtime_error("Must specify -f and -o options!");
    else if (utxx::path::file_exists(out_file)) {
        if (!overwrite)
            throw std::runtime_error("Found existing output file: " + out_file);
        if (!utxx::path::file_unlink(out_file))
            throw std::runtime_error("Error deleting file " + out_file +
                                     ": " + strerror(errno));
    }

    if (pk_cnt) {
        pk_end = pk_start + pk_cnt - 1;
        pk_cnt = 0;
    }

    utxx::pcap fin;
    if (fin.open_read(in_file) < 0)
        throw std::runtime_error("Error opening " + in_file + ": " + strerror(errno));
    else if (fin.read_file_header() < 0)
        throw std::runtime_error("File " + in_file + " is not in PCAP format!");

    int n;
    utxx::pcap fout(fin.big_endian(), fin.nsec_time());
    n = raw_mode ? fout.open(out_file.c_str(), "wb")
                 : fout.open_write(out_file, false, fin.get_link_type());
    if (n < 0)
        throw std::runtime_error("Error creating file " + out_file + ": " + strerror(errno));

    utxx::basic_io_buffer<(64*1024)> buf;

    while ((n = fin.read(buf.wr_ptr(), buf.capacity())) > 0) {
        buf.commit(n);
        while (buf.size() > sizeof(utxx::pcap::packet_header)) {
            const char*       header;
            const char*       begin  = header = buf.rd_ptr();
            int               frame_sz, sz;
            utxx::pcap::proto proto;

            // sz - total size of payload including frame_sz
            std::tie(frame_sz, sz, proto) = fin.read_packet_hdr_and_frame(begin, n);

            if (frame_sz < 0 || int(buf.size()) < sz) { // Not enough data in the buffer
                buf.reserve(sz);
                break;
            }

            if (++pk_cnt >= pk_start) {
                if (pk_cnt > pk_end)
                    goto DONE;

                // Write to the output file
                if (!raw_mode) {
                    fout.write_packet_header(fin.packet());
                    buf.read(sizeof(utxx::pcap::packet_header));
                    sz -= sizeof(utxx::pcap::packet_header);
                } else {
                    buf.read(frame_sz);
                    sz -= frame_sz;
                }
                if (fout.write(buf.rd_ptr(), sz) < 0)
                    throw std::runtime_error(string("Error writing to file: ") + strerror(errno));
            }

            buf.read(sz);
        }

        buf.crunch();
    }

  DONE:
    fout.close();
    fin.close();

    return 0;
}<commit_msg>Add -c|--count option to count packets<commit_after>//------------------------------------------------------------------------------
/// \file  pcapcut.cpp
//------------------------------------------------------------------------------
/// \brief Utility for cutting a part of a large pcap file
/// \see
///      Alternative implementation using pcap.h
//------------------------------------------------------------------------------
// Copyright (c) 2016 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-11-28
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <signal.h>
#include <utxx/pcap.hpp>
#include <utxx/string.hpp>
#include <utxx/path.hpp>
#include <utxx/get_option.hpp>
#include <utxx/buffer.hpp>
#include <utxx/version.hpp>

using namespace std;

//------------------------------------------------------------------------------
void usage(std::string const& err="")
{
    auto prog = utxx::path::basename(
        utxx::path::program::name().c_str(),
        utxx::path::program::name().c_str() + utxx::path::program::name().size()
    );

    if (!err.empty())
        cerr << "Invalid option: " << err << "\n\n";
    else {
        cerr << prog <<
        " - Tool for extracting packets from a pcap file\n"
        "Copyright (c) 2016 Serge Aleynikov\n"  <<
        VERSION() << "\n\n"                     <<
        "Usage: " << prog                       <<
        "[-V] [-h] -f InputFile -s StartPktNum -e EndPktNum [-n NumPkts] [-c|--count]"
                    " -o|-O OutputFile [-h]\n\n"
        "   -V|--version            - Version\n"
        "   -h|--help               - Help screen\n"
        "   -f InputFile            - Input file name\n"
        "   -o OutputFile           - Ouput file name (don't overwrite if exists)\n"
        "   -O OutputFile           - Ouput file name (overwrite if exists)\n"
        "   -s|--start StartPktNum  - Starting packet number (counting from 1)\n"
        "   -e|--end   EndPktNum    - Ending packet number (must be >= StartPktNum)\n"
        "   -n|--num   TotNumPkts   - Number of packets to save\n"
        "   -r|--raw                - Output raw packet payload only without pcap format\n"
        "   -c|--count              - Count number of packets in the file\n";
    }

    exit(1);
}

//------------------------------------------------------------------------------
void unhandled_exception() {
  auto p = current_exception();
  try    { rethrow_exception(p); }
  catch  ( exception& e ) { cerr << e.what() << endl; }
  catch  ( ... )          { cerr << "Unknown exception" << endl; }
  exit(1);
}

//------------------------------------------------------------------------------
//  MAIN
//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    string in_file;
    string out_file;
    size_t pk_start  = 1, pk_end = 0, pk_cnt = 0;
    bool   overwrite = false;
    bool   raw_mode  = false;
    bool   count     = false;

    set_terminate (&unhandled_exception);

    utxx::opts_parser opts(argc, argv);

    while (opts.next()) {
        if (opts.match("-f", "",        &in_file))  continue;
        if (opts.match("-o", "",        &out_file)) continue;
        if (opts.match("-O", "",        &out_file)){overwrite=true; continue;}
        if (opts.match("-r", "--raw",   &raw_mode)) continue;
        if (opts.match("-s", "--start", &pk_start)) continue;
        if (opts.match("-e", "--end",   &pk_end))   continue;
        if (opts.match("-n", "--num",   &pk_cnt))   continue;
        if (opts.match("-c", "--count", &count))    continue;
        if (opts.match("-V", "--version")) throw std::runtime_error(VERSION());
        if (opts.is_help())                         usage();

        usage(opts());
    }

    if (pk_end > 0 && pk_cnt > 0)
        throw std::runtime_error("Cannot specify both -n and -e options!");
    else if (!pk_end && !pk_cnt && !count)
        throw std::runtime_error("Must specify either -n or -e option!");
    else if (!pk_start && !count)
        throw std::runtime_error("PktStartNumber (-s) must be greater than 0!");
    else if (pk_end && pk_end < pk_start)
        throw std::runtime_error
             ("Ending packet number (-e) must not be less than starting packet number (-s)!");
    else if (in_file.empty() || (!count && out_file.empty()))
        throw std::runtime_error("Must specify -f and -o options!");
    else if (!count && utxx::path::file_exists(out_file)) {
        if (!overwrite)
            throw std::runtime_error("Found existing output file: " + out_file);
        if (!utxx::path::file_unlink(out_file))
            throw std::runtime_error("Error deleting file " + out_file +
                                     ": " + strerror(errno));
    }

    if (pk_cnt) {
        pk_end = pk_start + pk_cnt - 1;
        pk_cnt = 0;
    }

    utxx::pcap fin;
    if (fin.open_read(in_file) < 0)
        throw std::runtime_error("Error opening " + in_file + ": " + strerror(errno));
    else if (fin.read_file_header() < 0)
        throw std::runtime_error("File " + in_file + " is not in PCAP format!");

    int n = 0;
    utxx::pcap fout(fin.big_endian(), fin.nsec_time());

    if (!count) {
        n = raw_mode ? fout.open(out_file.c_str(), "wb")
                    : fout.open_write(out_file, false, fin.get_link_type());
        if (n < 0)
            throw std::runtime_error("Error creating file " + out_file + ": " + strerror(errno));
    }

    utxx::basic_io_buffer<(64*1024)> buf;

    while ((n = fin.read(buf.wr_ptr(), buf.capacity())) > 0) {
        buf.commit(n);
        while (buf.size() > sizeof(utxx::pcap::packet_header)) {
            const char*       header;
            const char*       begin  = header = buf.rd_ptr();
            int               frame_sz, sz;
            utxx::pcap::proto proto;

            // sz - total size of payload including frame_sz
            std::tie(frame_sz, sz, proto) = fin.read_packet_hdr_and_frame(begin, n);

            if (frame_sz < 0 || int(buf.size()) < sz) { // Not enough data in the buffer
                buf.reserve(sz);
                break;
            }

            if (++pk_cnt >= pk_start && !count) {
                if (pk_cnt > pk_end)
                    goto DONE;

                // Write to the output file
                if (!raw_mode) {
                    fout.write_packet_header(fin.packet());
                    buf.read(sizeof(utxx::pcap::packet_header));
                    sz -= sizeof(utxx::pcap::packet_header);
                } else {
                    buf.read(frame_sz);
                    sz -= frame_sz;
                }
                if (fout.write(buf.rd_ptr(), sz) < 0)
                    throw std::runtime_error(string("Error writing to file: ") + strerror(errno));
            }

            buf.read(sz);
        }

        buf.crunch();
    }

  DONE:
    fout.close();
    fin.close();

    if (count)
        cout << pk_cnt << " packets\n";

    return 0;
}<|endoftext|>


<commit_before>#include <rleahylib/rleahylib.hpp>
#include <base_64.hpp>
#include <json.hpp>
#include <mod.hpp>
#include <server.hpp>
#include <utility>

using namespace MCPP;

static const String protocol_error("Protocol error");
static const String name("Ping Support");
static const Word priority=1;
static const String ping_template("{0}:{1} pinged");
static const String favicon_key("favicon");
static const String favicon_prefix("data:image/png;base64,");

class ServerListPing : public Module {

	public:

		virtual Word Priority () const noexcept override {

			return priority;

		}

		virtual const String & Name () const noexcept override {

			return name;

		}

		virtual void Install () override {

			//	Get a reference to the packet router
			auto & router=Server::Get().Router;

			//	Install handler for the status
			//	request packet
			router(0,ProtocolState::Status)=[] (ReceiveEvent event) {

				auto & server=Server::Get();

				//	Get list of players currently on-line
				//	and number of players currently on-line
				//	for the "players" JSON object

				JSON::Array arr;
				Word player_count=0;

				for (auto & client : server.Clients) {

					if (client->GetState()==ProtocolState::Play) {

						JSON::Object obj;
						obj.Add(
							String("name"),client->GetUsername(),
							String("id"),String()
						);

						arr.Values.Add(std::move(obj));

						++player_count;

					}

				}

				//	Determine maximum number of players
				Word max_players=server.MaximumPlayers;
				Double json_max_players=(max_players==0) ? std::numeric_limits<Double>::max() : Double(max_players);

				//	Create "players" object
				JSON::Object players;
				players.Add(
					String("max"),json_max_players,
					String("online"),Double(player_count),
					String("sample"),std::move(arr)
				);

				//	Add "players" object to the
				//	root object
				JSON::Object root;
				root.Add(
					String("players"),std::move(players)
				);

				//	Add "version" object
				JSON::Object version;
				version.Add(
					String("name"),String("MCPP"),
					String("protocol"),Double(1)
				);

				root.Add(
					String("version"),std::move(version)
				);

				//	Add "description" object
				JSON::Object description;
				description.Add(
					String("text"),server.GetMessageOfTheDay()
				);

				root.Add(
					String("description"),std::move(description)
				);

				//	Add "favicon" if applicable
				auto icon=server.Data().GetBinary(favicon_key);
				if (!icon.IsNull()) {

					String favi(favicon_prefix);
					favi << Base64::Encode(*icon);

					root.Add(
						String("favicon"),std::move(favi)
					);

				}

				//	Create and send reply
				Packets::Status::Clientbound::Response packet;
				packet.Value=std::move(root);

				event.From->Send(packet);

			};

			//	Install handler for the ping request
			router(1,ProtocolState::Status)=[] (ReceiveEvent event) {

				auto & packet=event.Data.Get<Packets::Status::Serverbound::Ping>();

				//	Just send the time right back
				//	to the client
				Packets::Status::Clientbound::Ping reply;
				reply.Time=packet.Time;

				event.From->Send(reply);

				Server::Get().WriteLog(
					String::Format(
						ping_template,
						event.From->IP(),
						event.From->Port()
					),
					Service::LogType::Information
				);

			};

		}

};

INSTALL_MODULE(ServerListPing)
<commit_msg>Server Status Cleanup<commit_after>#include <rleahylib/rleahylib.hpp>
#include <base_64.hpp>
#include <json.hpp>
#include <mod.hpp>
#include <server.hpp>
#include <utility>

using namespace MCPP;

static const String protocol_error("Protocol error");
static const String name("Ping Support");
static const Word priority=1;
static const String ping_template("{0}:{1} pinged");
static const String favicon_key("favicon");
static const String favicon_prefix("data:image/png;base64,");

class ServerListPing : public Module {

	private:

		//	Client sends this packet to
		//	request server status information
		typedef Packets::Status::Serverbound::Request request;
		//	Client sends this packet to
		//	attempt to establish latency
		//	to the server
		typedef Packets::Status::Serverbound::Ping ping_cs;

		//	Server sends this packet with
		//	status information
		typedef Packets::Status::Clientbound::Response response;
		//	Server sends this packet so
		//	client can establish latency
		typedef Packets::Status::Clientbound::Ping ping_sc;

	public:

		virtual Word Priority () const noexcept override {

			return priority;

		}

		virtual const String & Name () const noexcept override {

			return name;

		}

		virtual void Install () override {

			//	Get a reference to the packet router
			auto & router=Server::Get().Router;

			//	Install handler for the status
			//	request packet
			router(
				request::PacketID,
				ProtocolState::Status
			)=[] (ReceiveEvent event) {

				auto & server=Server::Get();

				//	Get list of players currently on-line
				//	and number of players currently on-line
				//	for the "players" JSON object

				JSON::Array arr;
				Word player_count=0;

				for (auto & client : server.Clients) {

					if (client->GetState()==ProtocolState::Play) {

						JSON::Object obj;
						obj.Add(
							String("name"),client->GetUsername(),
							String("id"),String()
						);

						arr.Values.Add(std::move(obj));

						++player_count;

					}

				}

				//	Determine maximum number of players
				Word max_players=server.MaximumPlayers;
				Double json_max_players=(max_players==0) ? std::numeric_limits<Double>::max() : Double(max_players);

				//	Create "players" object
				JSON::Object players;
				players.Add(
					String("max"),json_max_players,
					String("online"),Double(player_count),
					String("sample"),std::move(arr)
				);

				//	Add "players" object to the
				//	root object
				JSON::Object root;
				root.Add(
					String("players"),std::move(players)
				);

				//	Add "version" object
				JSON::Object version;
				version.Add(
					String("name"),server.GetName(),
					String("protocol"),Double(ProtocolVersion)
				);

				root.Add(
					String("version"),std::move(version)
				);

				//	Add "description" object
				JSON::Object description;
				description.Add(
					String("text"),server.GetMessageOfTheDay()
				);

				root.Add(
					String("description"),std::move(description)
				);

				//	Add "favicon" if applicable
				auto icon=server.Data().GetBinary(favicon_key);
				if (!icon.IsNull()) {

					String favi(favicon_prefix);
					favi << Base64::Encode(*icon);

					root.Add(
						String("favicon"),std::move(favi)
					);

				}

				//	Create and send reply
				response packet;
				packet.Value=std::move(root);

				event.From->Send(packet);

			};

			//	Install handler for the ping request
			router(
				ping_cs::PacketID,
				ProtocolState::Status
			)=[] (ReceiveEvent event) {

				auto & packet=event.Data.Get<ping_cs>();

				//	Just send the time right back
				//	to the client
				ping_sc reply;
				reply.Time=packet.Time;

				event.From->Send(reply);

				Server::Get().WriteLog(
					String::Format(
						ping_template,
						event.From->IP(),
						event.From->Port()
					),
					Service::LogType::Information
				);

			};

		}

};

INSTALL_MODULE(ServerListPing)
<|endoftext|>