<commit_before>#include "assert.hh"
#include "buffer.hh"
#include "buffer_manager.hh"
#include "client_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "commands.hh"
#include "context.hh"
#include "debug.hh"
#include "event_manager.hh"
#include "file.hh"
#include "filters.hh"
#include "highlighters.hh"
#include "hook_manager.hh"
#include "ncurses.hh"
#include "option_manager.hh"
#include "parameters_parser.hh"
#include "register_manager.hh"
#include "remote.hh"
#include "shell_manager.hh"
#include "string.hh"
#include "window.hh"

#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif

#include <unordered_map>
#include <locale>
#include <signal.h>

using namespace Kakoune;

void run_unit_tests();

String runtime_directory()
{
    char buffer[2048];
#if defined(__linux__)
    ssize_t res = readlink("/proc/self/exe", buffer, 2048);
    kak_assert(res != -1);
    buffer[res] = '\0';
#elif defined(__APPLE__)
    uint32_t bufsize = 2048;
    _NSGetExecutablePath(buffer, &bufsize);
    char* canonical_path = realpath(buffer, NULL);
    strncpy(buffer, canonical_path, 2048);
    free(canonical_path);
#else
# error "finding executable path is not implemented on this platform"
#endif
    char* ptr = strrchr(buffer, '/');
    if (not ptr)
        throw runtime_error("unable to determine runtime directory");
    return String(buffer, ptr);
}

void register_env_vars()
{
    ShellManager& shell_manager = ShellManager::instance();

    shell_manager.register_env_var("bufname",
                                   [](const String& name, const Context& context)
                                   { return context.buffer().display_name(); });
    shell_manager.register_env_var("timestamp",
                                   [](const String& name, const Context& context)
                                   { return int_to_str(context.buffer().timestamp()); });
    shell_manager.register_env_var("selection",
                                   [](const String& name, const Context& context)
                                   { return context.editor().main_selection().content(); });
    shell_manager.register_env_var("selections",
                                   [](const String& name, const Context& context)
                                   { auto sels = context.editor().selections_content();
                                     return std::accumulate(sels.begin(), sels.end(), ""_str,
                                     [](const String& lhs, const String& rhs) { return lhs.empty() ? rhs : lhs + "," + rhs; }); });
    shell_manager.register_env_var("runtime",
                                   [](const String& name, const Context& context)
                                   { return runtime_directory(); });
    shell_manager.register_env_var("opt_.+",
                                   [](const String& name, const Context& context)
                                   { return context.options()[name.substr(4_byte)].get_as_string(); });
    shell_manager.register_env_var("reg_.+",
                                   [](const String& name, const Context& context)
                                   { return RegisterManager::instance()[name[4]].values(context)[0]; });
    shell_manager.register_env_var("socket",
                                   [](const String& name, const Context& context)
                                   { return Server::instance().filename(); });
    shell_manager.register_env_var("client",
                                   [](const String& name, const Context& context)
                                   { return ClientManager::instance().get_client(context).name(); });
    shell_manager.register_env_var("cursor_line",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.editor().main_selection().last().line() + 1); });
    shell_manager.register_env_var("cursor_column",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.editor().main_selection().last().column() + 1); });
    shell_manager.register_env_var("selection_desc",
                                   [](const String& name, const Context& context)
                                   { auto& sel = context.editor().main_selection();
                                     auto beg = sel.begin();
                                     return int_to_str((int)beg.line() + 1) + ':' + int_to_str((int)beg.column() + 1) + '+' + int_to_str((int)(sel.end() - beg)); });
    shell_manager.register_env_var("window_width",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.window().dimensions().column); });
    shell_manager.register_env_var("window_height",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.window().dimensions().line); });
}

void register_registers()
{
    RegisterManager& register_manager = RegisterManager::instance();

    register_manager.register_dynamic_register('%', [](const Context& context) { return std::vector<String>(1, context.buffer().display_name()); });
    register_manager.register_dynamic_register('.', [](const Context& context) { return context.editor().selections_content(); });
    for (size_t i = 0; i < 10; ++i)
    {
        register_manager.register_dynamic_register('0'+i,
            [i](const Context& context) {
                std::vector<String> result;
                for (auto& sel : context.editor().selections())
                    result.emplace_back(i < sel.captures().size() ? sel.captures()[i] : "");
                return result;
            });
    }
}

void create_local_client(const String& init_command)
{
    class LocalNCursesUI : public NCursesUI
    {
        ~LocalNCursesUI()
        {
            if (not ClientManager::instance().empty() and fork())
            {
                this->NCursesUI::~NCursesUI();
                puts("detached from terminal\n");
                exit(0);
            }
        }
    };

    UserInterface* ui = new LocalNCursesUI{};
    static Client* client = ClientManager::instance().create_client(
        std::unique_ptr<UserInterface>{ui}, init_command);
    signal(SIGHUP, [](int) {
        if (client)
            ClientManager::instance().remove_client(*client);
        client = nullptr;
    });
}

void signal_handler(int signal)
{
    NCursesUI::abort();
    const char* text = nullptr;
    switch (signal)
    {
        case SIGSEGV: text = "SIGSEGV"; break;
        case SIGFPE:  text = "SIGFPE";  break;
        case SIGQUIT: text = "SIGQUIT"; break;
        case SIGTERM: text = "SIGTERM"; break;
    }
    on_assert_failed(text);
    abort();
}

int main(int argc, char* argv[])
{
    try
    {
        std::locale::global(std::locale(""));

        signal(SIGSEGV, signal_handler);
        signal(SIGFPE,  signal_handler);
        signal(SIGQUIT, signal_handler);
        signal(SIGTERM, signal_handler);

        std::vector<String> params;
        for (size_t i = 1; i < argc; ++i)
             params.push_back(argv[i]);
        ParametersParser parser(params, { { "c", true }, { "e", true }, { "n", false } });
        EventManager event_manager;

        String init_command;
        if (parser.has_option("e"))
            init_command = parser.option_value("e");

        if (parser.has_option("c"))
        {
            try
            {
                auto client = connect_to(parser.option_value("c"),
                                         std::unique_ptr<UserInterface>{new NCursesUI{}},
                                         init_command);
                while (true)
                    event_manager.handle_next_events();
            }
            catch (peer_disconnected&)
            {
                puts("disconnected");
            }
            return 0;
        }

        GlobalOptions       global_options;
        GlobalHooks         global_hooks;
        ShellManager        shell_manager;
        CommandManager      command_manager;
        BufferManager       buffer_manager;
        RegisterManager     register_manager;
        HighlighterRegistry highlighter_registry;
        FilterRegistry      filter_registry;
        ColorRegistry       color_registry;
        ClientManager       client_manager;

        run_unit_tests();

        register_env_vars();
        register_registers();
        register_commands();
        register_highlighters();
        register_filters();

        write_debug("*** This is the debug buffer, where debug info will be written ***");
        write_debug("pid: " + int_to_str(getpid()));
        write_debug("utf-8 test: é á ï");

        Server server;

        if (not parser.has_option("n")) try
        {
            Context initialisation_context;
            command_manager.execute("source " + runtime_directory() + "/kakrc",
                                    initialisation_context);
        }
        catch (Kakoune::runtime_error& error)
        {
             write_debug("error while parsing kakrc: "_str + error.what());
        }
        catch (Kakoune::client_removed&)
        {
             write_debug("error while parsing kakrc: asked to quit");
        }

        {
            Context empty_context;
            global_hooks.run_hook("KakBegin", "", empty_context);
        }

        if (parser.positional_count() != 0)
        {
            // create buffers in reverse order so that the first given buffer
            // is the most recently created one.
            for (int i = parser.positional_count() - 1; i >= 0; --i)
            {
                const String& file = parser[i];
                if (not create_buffer_from_file(file))
                    new Buffer(file, Buffer::Flags::New | Buffer::Flags::File);
            }
        }
        else
            new Buffer("*scratch*", Buffer::Flags::None);

        create_local_client(init_command);

        while (not client_manager.empty())
            event_manager.handle_next_events();

        {
            Context empty_context;
            global_hooks.run_hook("KakEnd", "", empty_context);
        }
    }
    catch (Kakoune::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (std::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (...)
    {
        on_assert_failed("uncaught exception");
        return -1;
    }
    return 0;
}
<commit_msg>catch errors when opening files given on command line<commit_after>#include "assert.hh"
#include "buffer.hh"
#include "buffer_manager.hh"
#include "client_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "commands.hh"
#include "context.hh"
#include "debug.hh"
#include "event_manager.hh"
#include "file.hh"
#include "filters.hh"
#include "highlighters.hh"
#include "hook_manager.hh"
#include "ncurses.hh"
#include "option_manager.hh"
#include "parameters_parser.hh"
#include "register_manager.hh"
#include "remote.hh"
#include "shell_manager.hh"
#include "string.hh"
#include "window.hh"

#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif

#include <unordered_map>
#include <locale>
#include <signal.h>

using namespace Kakoune;

void run_unit_tests();

String runtime_directory()
{
    char buffer[2048];
#if defined(__linux__)
    ssize_t res = readlink("/proc/self/exe", buffer, 2048);
    kak_assert(res != -1);
    buffer[res] = '\0';
#elif defined(__APPLE__)
    uint32_t bufsize = 2048;
    _NSGetExecutablePath(buffer, &bufsize);
    char* canonical_path = realpath(buffer, NULL);
    strncpy(buffer, canonical_path, 2048);
    free(canonical_path);
#else
# error "finding executable path is not implemented on this platform"
#endif
    char* ptr = strrchr(buffer, '/');
    if (not ptr)
        throw runtime_error("unable to determine runtime directory");
    return String(buffer, ptr);
}

void register_env_vars()
{
    ShellManager& shell_manager = ShellManager::instance();

    shell_manager.register_env_var("bufname",
                                   [](const String& name, const Context& context)
                                   { return context.buffer().display_name(); });
    shell_manager.register_env_var("timestamp",
                                   [](const String& name, const Context& context)
                                   { return int_to_str(context.buffer().timestamp()); });
    shell_manager.register_env_var("selection",
                                   [](const String& name, const Context& context)
                                   { return context.editor().main_selection().content(); });
    shell_manager.register_env_var("selections",
                                   [](const String& name, const Context& context)
                                   { auto sels = context.editor().selections_content();
                                     return std::accumulate(sels.begin(), sels.end(), ""_str,
                                     [](const String& lhs, const String& rhs) { return lhs.empty() ? rhs : lhs + "," + rhs; }); });
    shell_manager.register_env_var("runtime",
                                   [](const String& name, const Context& context)
                                   { return runtime_directory(); });
    shell_manager.register_env_var("opt_.+",
                                   [](const String& name, const Context& context)
                                   { return context.options()[name.substr(4_byte)].get_as_string(); });
    shell_manager.register_env_var("reg_.+",
                                   [](const String& name, const Context& context)
                                   { return RegisterManager::instance()[name[4]].values(context)[0]; });
    shell_manager.register_env_var("socket",
                                   [](const String& name, const Context& context)
                                   { return Server::instance().filename(); });
    shell_manager.register_env_var("client",
                                   [](const String& name, const Context& context)
                                   { return ClientManager::instance().get_client(context).name(); });
    shell_manager.register_env_var("cursor_line",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.editor().main_selection().last().line() + 1); });
    shell_manager.register_env_var("cursor_column",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.editor().main_selection().last().column() + 1); });
    shell_manager.register_env_var("selection_desc",
                                   [](const String& name, const Context& context)
                                   { auto& sel = context.editor().main_selection();
                                     auto beg = sel.begin();
                                     return int_to_str((int)beg.line() + 1) + ':' + int_to_str((int)beg.column() + 1) + '+' + int_to_str((int)(sel.end() - beg)); });
    shell_manager.register_env_var("window_width",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.window().dimensions().column); });
    shell_manager.register_env_var("window_height",
                                   [](const String& name, const Context& context)
                                   { return int_to_str((int)context.window().dimensions().line); });
}

void register_registers()
{
    RegisterManager& register_manager = RegisterManager::instance();

    register_manager.register_dynamic_register('%', [](const Context& context) { return std::vector<String>(1, context.buffer().display_name()); });
    register_manager.register_dynamic_register('.', [](const Context& context) { return context.editor().selections_content(); });
    for (size_t i = 0; i < 10; ++i)
    {
        register_manager.register_dynamic_register('0'+i,
            [i](const Context& context) {
                std::vector<String> result;
                for (auto& sel : context.editor().selections())
                    result.emplace_back(i < sel.captures().size() ? sel.captures()[i] : "");
                return result;
            });
    }
}

void create_local_client(const String& init_command)
{
    class LocalNCursesUI : public NCursesUI
    {
        ~LocalNCursesUI()
        {
            if (not ClientManager::instance().empty() and fork())
            {
                this->NCursesUI::~NCursesUI();
                puts("detached from terminal\n");
                exit(0);
            }
        }
    };

    UserInterface* ui = new LocalNCursesUI{};
    static Client* client = ClientManager::instance().create_client(
        std::unique_ptr<UserInterface>{ui}, init_command);
    signal(SIGHUP, [](int) {
        if (client)
            ClientManager::instance().remove_client(*client);
        client = nullptr;
    });
}

void signal_handler(int signal)
{
    NCursesUI::abort();
    const char* text = nullptr;
    switch (signal)
    {
        case SIGSEGV: text = "SIGSEGV"; break;
        case SIGFPE:  text = "SIGFPE";  break;
        case SIGQUIT: text = "SIGQUIT"; break;
        case SIGTERM: text = "SIGTERM"; break;
    }
    on_assert_failed(text);
    abort();
}

int main(int argc, char* argv[])
{
    try
    {
        std::locale::global(std::locale(""));

        signal(SIGSEGV, signal_handler);
        signal(SIGFPE,  signal_handler);
        signal(SIGQUIT, signal_handler);
        signal(SIGTERM, signal_handler);

        std::vector<String> params;
        for (size_t i = 1; i < argc; ++i)
             params.push_back(argv[i]);
        ParametersParser parser(params, { { "c", true }, { "e", true }, { "n", false } });
        EventManager event_manager;

        String init_command;
        if (parser.has_option("e"))
            init_command = parser.option_value("e");

        if (parser.has_option("c"))
        {
            try
            {
                auto client = connect_to(parser.option_value("c"),
                                         std::unique_ptr<UserInterface>{new NCursesUI{}},
                                         init_command);
                while (true)
                    event_manager.handle_next_events();
            }
            catch (peer_disconnected&)
            {
                puts("disconnected");
            }
            return 0;
        }

        GlobalOptions       global_options;
        GlobalHooks         global_hooks;
        ShellManager        shell_manager;
        CommandManager      command_manager;
        BufferManager       buffer_manager;
        RegisterManager     register_manager;
        HighlighterRegistry highlighter_registry;
        FilterRegistry      filter_registry;
        ColorRegistry       color_registry;
        ClientManager       client_manager;

        run_unit_tests();

        register_env_vars();
        register_registers();
        register_commands();
        register_highlighters();
        register_filters();

        write_debug("*** This is the debug buffer, where debug info will be written ***");
        write_debug("pid: " + int_to_str(getpid()));
        write_debug("utf-8 test: é á ï");

        Server server;

        if (not parser.has_option("n")) try
        {
            Context initialisation_context;
            command_manager.execute("source " + runtime_directory() + "/kakrc",
                                    initialisation_context);
        }
        catch (Kakoune::runtime_error& error)
        {
             write_debug("error while parsing kakrc: "_str + error.what());
        }
        catch (Kakoune::client_removed&)
        {
             write_debug("error while parsing kakrc: asked to quit");
        }

        {
            Context empty_context;
            global_hooks.run_hook("KakBegin", "", empty_context);
        }

        if (parser.positional_count() != 0) try
        {
            // create buffers in reverse order so that the first given buffer
            // is the most recently created one.
            for (int i = parser.positional_count() - 1; i >= 0; --i)
            {
                const String& file = parser[i];
                if (not create_buffer_from_file(file))
                    new Buffer(file, Buffer::Flags::New | Buffer::Flags::File);
            }
        }
        catch (Kakoune::runtime_error& error)
        {
             write_debug("error while opening command line files: "_str + error.what());
        }
        else
            new Buffer("*scratch*", Buffer::Flags::None);

        create_local_client(init_command);

        while (not client_manager.empty())
            event_manager.handle_next_events();

        {
            Context empty_context;
            global_hooks.run_hook("KakEnd", "", empty_context);
        }
    }
    catch (Kakoune::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (std::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (...)
    {
        on_assert_failed("uncaught exception");
        return -1;
    }
    return 0;
}
<|endoftext|>


<commit_before>#include "main.h"

#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include "tiny_obj_loader.h"
#include "config.h"
#include "mesh_loader.h"
#include "mesh.h"

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

int main(int argc, char* argv[]) {
    options_t options;
    int parse_result = parse_options(argc, argv, options);
    if (parse_result > 0) {
        return 0;
    } else if (parse_result < 0) {
        return -1;
    }

    config::load_config_file(options.config_file);

    for (std::string mesh_file : options.mesh_files) {
        std::cout << mesh_file << std::endl;

        Mesh mesh;
        try {
            load_obj(mesh_file, mesh);
        } catch (std::exception e) {
            std::cerr << e.what() << std::endl;
        }
    }
}

int parse_options(int argc, char** argv, options_t& options) {
    // Find default config file path.
    std::string homedir = getenv("HOME");
    if (homedir.empty()) {
        homedir = getpwuid(getuid())->pw_dir;
    }
    fs::path default_rc(homedir);
    default_rc /= kConfigFileName;

    // Declare the supported options.
    po::options_description desc("Options");
    auto config_opt = po::value<std::string>()->default_value(default_rc.string());
    auto resolution_opt = po::value<int>()->default_value(640);
    auto mesh_files_opt = po::value<std::vector<std::string>>()->required();
    desc.add_options()
        ("version,v", "print version string")
        ("help", "produce help message")
        ("config-file,c", config_opt, "path to configuration file")
        ("resolution,r", resolution_opt, "resolution of output images")
        ("mesh-files", mesh_files_opt, "supported file types: .obj");

    po::positional_options_description positionalOptions;
    positionalOptions.add("mesh-files", -1);
    po::variables_map vm;

    try {
        po::store(po::command_line_parser(argc, argv)
                      .options(desc)
                      .positional(positionalOptions)
                      .run(), vm);

        if (vm.count("help") || !vm.count("mesh-files")) {
            std::cout << kAppDesc << std::endl << std::endl << desc;
            return 1;
        }

        if (vm.count("version")) {
            std::cout << kAppName << " " << VERSION << std::endl;
            return 1;
        }

        po::notify(vm);

        options.config_file = vm["config-file"].as<std::string>();
        options.mesh_files = vm["mesh-files"].as<std::vector<std::string>>();
        options.resolution = vm["resolution"].as<int>();
    } catch (std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl << std::endl << desc;
        return -1;
    }

    return 0;
}
<commit_msg>Fix --version<commit_after>#include "main.h"

#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include "tiny_obj_loader.h"
#include "config.h"
#include "mesh_loader.h"
#include "mesh.h"

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

int main(int argc, char* argv[]) {
    options_t options;
    int parse_result = parse_options(argc, argv, options);
    if (parse_result > 0) {
        return 0;
    } else if (parse_result < 0) {
        return -1;
    }

    config::load_config_file(options.config_file);

    for (std::string mesh_file : options.mesh_files) {
        std::cout << mesh_file << std::endl;

        Mesh mesh;
        try {
            load_obj(mesh_file, mesh);
        } catch (std::exception e) {
            std::cerr << e.what() << std::endl;
        }
    }
}

int parse_options(int argc, char** argv, options_t& options) {
    // Find default config file path.
    std::string homedir = getenv("HOME");
    if (homedir.empty()) {
        homedir = getpwuid(getuid())->pw_dir;
    }
    fs::path default_rc(homedir);
    default_rc /= kConfigFileName;

    // Declare the supported options.
    po::options_description desc("Options");
    auto config_opt = po::value<std::string>()->default_value(default_rc.string());
    auto resolution_opt = po::value<int>()->default_value(640);
    auto mesh_files_opt = po::value<std::vector<std::string>>()->required();
    desc.add_options()
        ("version,v", "print version string")
        ("help", "produce help message")
        ("config-file,c", config_opt, "path to configuration file")
        ("resolution,r", resolution_opt, "resolution of output images")
        ("mesh-files", mesh_files_opt, "supported file types: .obj");

    po::positional_options_description positionalOptions;
    positionalOptions.add("mesh-files", -1);
    po::variables_map vm;

    try {
        po::store(po::command_line_parser(argc, argv)
                      .options(desc)
                      .positional(positionalOptions)
                      .run(), vm);

        if (vm.count("version")) {
            std::cout << kAppName << " " << VERSION << std::endl;
            return 1;
        }

        if (vm.count("help") || !vm.count("mesh-files")) {
            std::cout << kAppDesc << std::endl << std::endl << desc;
            return 1;
        }

        po::notify(vm);

        options.config_file = vm["config-file"].as<std::string>();
        options.mesh_files = vm["mesh-files"].as<std::vector<std::string>>();
        options.resolution = vm["resolution"].as<int>();
    } catch (std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl << std::endl << desc;
        return -1;
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <thread>
#include <vector>

#include "threadPool.hh"

void TestFunction()
{
	for( volatile unsigned int i=0; i < 200000; ++i )
		for( volatile unsigned int j=0; j < 10; ++j );
}

void WorkerLoop( WorkerContext *context, ThreadPool &pool )
{
	context->threadId = std::this_thread::get_id();

	// Run until thread should stop
	while( !context->shouldStop )
	{
		Task *task = context->taskManager->GetTask();
		if( !task )
		{
			std::this_thread::yield();
			std::this_thread::sleep_for( std::chrono::microseconds( 10 ) );
			continue;
		}

		// Execute the task
		task->f();

		// Delete the task when we're done with it
		delete task;
	}

	// Erase this context from the context list
	std::lock_guard<std::mutex> contextLock( pool.contextListMutex );
	for( auto currContext  = pool.contexts.begin();
	          currContext != pool.contexts.end();
	          currContext++ )
	{
		if( (*currContext) == context )
		{
			pool.contexts.erase( currContext );
			delete context;
			break;
		}
	}
}

int main()
{
	unsigned int hardwareThreads = std::thread::hardware_concurrency();

	ThreadPool  threadPool;
	TaskManager taskManager;

	// Create few test tasks
	for( int i = 0; i < 10000; ++i )
	{
		Task *t = new Task();
		t->f = TestFunction;
		t->dependencies = 0;
		taskManager.AddTask( t );
	}

	// Create worker threads
	for( unsigned int i = 0; i < hardwareThreads; ++i )
	{
		// Create the context
		threadPool.contextListMutex.lock();
		WorkerContext *context = new WorkerContext();
		context->taskManager   = &taskManager;
		context->shouldStop    = false;
		threadPool.contexts.push_back( context );
		threadPool.contextListMutex.unlock();

		// Create the thread
		threadPool.threadListMutex.lock();
		std::thread *newThread = new std::thread( WorkerLoop, context, std::ref( threadPool ) );
		std::cout << "Created thread: " << newThread->get_id() << std::endl;
		threadPool.threads.push_back( newThread );
		threadPool.threadListMutex.unlock();
	}

	// Wait for tasks to end
	size_t taskCount;
	do
	{
		taskCount = taskManager.GetTaskCount();
		std::cout << "Task queue size: " << taskCount << std::endl;
		if( taskCount )
		{
			std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
		}
	}
	while( taskCount );

	// Command worker threads to stop
	threadPool.contextListMutex.lock();
	for( auto context  = threadPool.contexts.begin();
	          context != threadPool.contexts.end();
	          context++ )
	{
		(*context)->shouldStop = true;
	}
	threadPool.contextListMutex.unlock();

	// Wait for the thread pool to empty
	while( threadPool.threads.size() > 0 )
	{

		// Remove unjoinable threads
		threadPool.CleanThreads();

		std::this_thread::yield();
	}

	// Finish
	std::cout << "Finished." << std::endl;
	getc( stdin );

    return 0;
}

<commit_msg>Testing task dependencies.<commit_after>#include <iostream>
#include <thread>
#include <vector>

#include "threadPool.hh"

void TestFunction()
{
	for( volatile unsigned int i=0; i < 200000; ++i )
		for( volatile unsigned int j=0; j < 10; ++j );
}

void WorkerLoop( WorkerContext *context, ThreadPool &pool )
{
	context->threadId = std::this_thread::get_id();

	// Run until thread should stop
	while( !context->shouldStop )
	{
		Task *task = context->taskManager->GetTask();
		if( !task )
		{
			std::this_thread::yield();
			std::this_thread::sleep_for( std::chrono::microseconds( 10 ) );
			continue;
		}

		// Execute the task
		task->f();

		// Delete the task when we're done with it
		delete task;
	}

	// Erase this context from the context list
	std::lock_guard<std::mutex> contextLock( pool.contextListMutex );
	for( auto currContext  = pool.contexts.begin();
	          currContext != pool.contexts.end();
	          currContext++ )
	{
		if( (*currContext) == context )
		{
			pool.contexts.erase( currContext );
			delete context;
			break;
		}
	}
}

int main()
{
	unsigned int hardwareThreads = std::thread::hardware_concurrency();

	ThreadPool  threadPool;
	TaskManager taskManager;

	// Create few test tasks
	for( int i = 0; i < 10000; ++i )
	{
		Task *t = new Task();
		t->f = TestFunction;
		t->dependencies = 0;
		taskManager.AddTask( t );
	}

	// Create a dependency critical task as a test and use anonymous functions.
	Task *dependent = new Task();
	dependent->dependencies = 2;
	dependent->f = []()
	{
		std::cout << "Executing the dependency critical task!" << std::endl;
	};

	Task *dep1 = new Task();
	dep1->dependencies = 0;
	dep1->f = []()
	{
		std::cout << "Dependency #1 satisfied\n";
	};
	dep1->dependents.push_back( dependent );

	Task *dep2 = new Task();
	dep2->dependencies = 0;
	dep2->f = []()
	{
		std::cout << "Dependency #2 satisfied\n";
	};
	dep2->dependents.push_back( dependent );

	taskManager.AddTask( dependent );
	taskManager.AddTask( dep2 );
	taskManager.AddTask( dep1 );

	// Create worker threads
	for( unsigned int i = 0; i < hardwareThreads; ++i )
	{
		// Create the context
		threadPool.contextListMutex.lock();
		WorkerContext *context = new WorkerContext();
		context->taskManager   = &taskManager;
		context->shouldStop    = false;
		threadPool.contexts.push_back( context );
		threadPool.contextListMutex.unlock();

		// Create the thread
		threadPool.threadListMutex.lock();
		std::thread *newThread = new std::thread( WorkerLoop, context, std::ref( threadPool ) );
		std::cout << "Created thread: " << newThread->get_id() << std::endl;
		threadPool.threads.push_back( newThread );
		threadPool.threadListMutex.unlock();
	}

	// Wait for tasks to end
	size_t taskCount;
	do
	{
		taskCount = taskManager.GetTaskCount();
		std::cout << "Task queue size: " << taskCount << std::endl;
		if( taskCount )
		{
			std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
		}
	}
	while( taskCount );

	// Command worker threads to stop
	threadPool.contextListMutex.lock();
	for( auto context  = threadPool.contexts.begin();
	          context != threadPool.contexts.end();
	          context++ )
	{
		(*context)->shouldStop = true;
	}
	threadPool.contextListMutex.unlock();

	// Wait for the thread pool to empty
	while( threadPool.threads.size() > 0 )
	{

		// Remove unjoinable threads
		threadPool.CleanThreads();

		std::this_thread::yield();
	}

	// Finish
	std::cout << "Finished." << std::endl;
	getc( stdin );

    return 0;
}

<|endoftext|>


<commit_before>#include "vast/program.h"

#include <cstdlib>
#include <csignal>
#include <iostream>
#include "vast/archive.h"
#include "vast/file_system.h"
#include "vast/id_tracker.h"
#include "vast/index.h"
#include "vast/ingestor.h"
#include "vast/logger.h"
#include "vast/receiver.h"
#include "vast/schema.h"
#include "vast/schema_manager.h"
#include "vast/search.h"
#include "vast/signal_monitor.h"
#include "vast/detail/type_manager.h"
#include "vast/util/profiler.h"

#ifdef VAST_HAVE_BROCCOLI
#include "vast/util/broccoli.h"
#endif

#ifdef VAST_HAVE_EDITLINE
#include "vast/console.h"
#endif

using namespace cppa;

namespace vast {

program::program(configuration const& config)
  : config_{config}
{
}

void program::act()
{
  chaining(false);

  behavior default_behavior = (
      on(atom("signal"), arg_match) >> [&](int signal)
      {
        VAST_LOG_ACTOR_VERBOSE("received signal " << signal);
        if (signal == SIGINT || signal == SIGTERM)
          quit(exit::stop);
      },
      others() >> [=]
      {
        quit(exit::error);
        VAST_LOG_ACTOR_ERROR("terminated after unexpected message from " <<
                             VAST_ACTOR_ID(last_sender()) << ": " <<
                             to_string(self->last_dequeued()));
      });

  become(default_behavior);

  auto monitor = spawn<signal_monitor, detached+linked>(self);
  send(monitor, atom("act"));

  auto vast_dir = path{*config_.get("directory")};
  try
  {
    if (config_.check("profile"))
    {
      auto ms = *config_.as<unsigned>("profile");
      auto profiler = spawn<util::profiler, detached+linked>(
          vast_dir / "log", std::chrono::seconds(ms));

      if (config_.check("profile-cpu"))
        send(profiler, atom("start"), atom("perftools"), atom("cpu"));

      if (config_.check("profile-heap"))
        send(profiler, atom("start"), atom("perftools"), atom("heap"));

      send(profiler, atom("start"), atom("rusage"));
    }

    auto schema_manager = spawn<schema_manager_actor, linked>();
    if (config_.check("schema.file"))
    {
      send(schema_manager, atom("load"), *config_.get("schema.file"));
      if (config_.check("schema.print"))
      {
        sync_send(schema_manager, atom("schema")).then(
            on_arg_match >> [](schema const& s)
            {
              std::cout << to_string(s);
            });
        quit();
      }
    }

    actor_ptr tracker;
    auto tracker_host = *config_.get("tracker.host");
    auto tracker_port = *config_.as<unsigned>("tracker.port");
    if (config_.check("tracker-actor") || config_.check("all-server"))
    {
      tracker = spawn<id_tracker_actor, linked>(vast_dir);
      VAST_LOG_ACTOR_VERBOSE(
          "publishes tracker at " << tracker_host << ':' << tracker_port);

      publish(tracker, tracker_port, tracker_host.c_str());
    }
    else if (config_.check("receiver-actor"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to tracker at " << tracker_host << ':' << tracker_port);
      tracker = remote_actor(tracker_host, tracker_port);
    }

    actor_ptr archive;
    auto archive_host = *config_.get("archive.host");
    auto archive_port = *config_.as<unsigned>("archive.port");
    if (config_.check("archive-actor") || config_.check("all-server"))
    {
      archive = spawn<archive_actor, linked>(
          vast_dir / "archive",
          *config_.as<size_t>("archive.max-segments"));

      VAST_LOG_ACTOR_VERBOSE(
          "publishes archive at " << archive_host << ':' << archive_port);

      publish(archive, archive_port, archive_host.c_str());
    }
    else if (config_.check("receiver-actor")
             || config_.check("search-actor")
             || config_.check("index.rebuild"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to archive at " << archive_host << ':' << archive_port);

      archive = remote_actor(archive_host, archive_port);
    }

    actor_ptr index;
    auto index_host = *config_.get("index.host");
    auto index_port = *config_.as<unsigned>("index.port");
    if (config_.check("index-actor") || config_.check("all-server"))
    {
      index = spawn<index_actor, linked>(
          vast_dir / "index", *config_.as<size_t>("index.batch-size"));

      VAST_LOG_ACTOR_VERBOSE(
          "publishes index " << index_host << ':' << index_port);

      publish(index, index_port, index_host.c_str());
    }
    else if (config_.check("receiver-actor")
             || config_.check("search-actor")
             || config_.check("index.rebuild"))
    {
      VAST_LOG_ACTOR_VERBOSE("connects to index at " <<
                           index_host << ":" << index_port);

      index = remote_actor(index_host, index_port);
    }

    if (auto partition = config_.get("index.partition"))
    {
      send(index, atom("partition"), *partition);
    }
    else if (config_.check("index.rebuild"))
    {
      become(
        on_arg_match >> [=](segment const& s)
        {
          event_id next = s.base() + s.events();
          send(archive, atom("segment"), next);
          forward_to(index);
        },
        on(atom("no segment"), arg_match) >> [=](event_id eid)
        {
          VAST_LOG_INFO("sent all segments to index (" << eid - 1 << " events)");
          become(default_behavior);
        });

      VAST_LOG_INFO("begins rebuilding index");
      send(index, atom("delete"));
      send(archive, atom("segment"), event_id{1});
    }

    actor_ptr receiver;
    auto receiver_host = *config_.get("receiver.host");
    auto receiver_port = *config_.as<unsigned>("receiver.port");
    if (config_.check("receiver-actor") || config_.check("all-server"))
    {
      receiver = spawn<receiver_actor, linked>(tracker, archive, index);
      VAST_LOG_ACTOR_VERBOSE(
          "publishes receiver at " << receiver_host << ':' << receiver_port);

      publish(receiver, receiver_port, receiver_host.c_str());
    }
    else if (config_.check("ingestor-actor"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to receiver at " << receiver_host << ":" << receiver_port);

      receiver = remote_actor(receiver_host, receiver_port);
    }

    actor_ptr ingestor;
    if (config_.check("ingestor-actor"))
    {
      ingestor = spawn<ingestor_actor, linked>(
          vast_dir,
          receiver,
          *config_.as<size_t>("ingest.max-events-per-chunk"),
          *config_.as<size_t>("ingest.max-segment-size") * 1000000,
          *config_.as<size_t>("ingest.batch-size"));

      if (config_.check("ingest.submit"))
        send(ingestor, atom("submit"));

#ifdef VAST_HAVE_BROCCOLI
      util::broccoli::init(config_.check("broccoli-messages"),
                           config_.check("broccoli-calltrace"));
      if (config_.check("ingest.broccoli-events"))
      {
        auto host = *config_.get("ingest.broccoli-host");
        auto port = *config_.as<unsigned>("ingest.broccoli-port");
        auto events =
          *config_.as<std::vector<std::string>>("ingest.broccoli-events");

        send(ingestor, atom("ingest"), atom("broccoli"), host, port,
             std::move(events));
      }
#endif

      if (auto file = config_.get("ingest.file-name"))
      {
        auto type = *config_.get("ingest.file-type");
        if (! exists(string(*file)))
        {
          VAST_LOG_ACTOR_ERROR("no such file: " << *file);
          send_exit(self, exit::error);
          return;
        }

        send(ingestor, atom("ingest"), type, *file);
      }
      else
      {
        send_exit(ingestor, exit::done);
      }
    }

    actor_ptr search;
    auto search_host = *config_.get("search.host");
    auto search_port = *config_.as<unsigned>("search.port");
    if (config_.check("search-actor") || config_.check("all-server"))
    {
      search = spawn<search_actor, linked>(archive, index, schema_manager);
      VAST_LOG_ACTOR_VERBOSE(
          "publishes search at " << search_host << ':' << search_port);

      publish(search, search_port, search_host.c_str());
    }
#ifdef VAST_HAVE_EDITLINE
    else if (config_.check("console-actor"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to search at " << search_host << ":" << search_port);

      search = remote_actor(search_host, search_port);

      auto c = spawn<console, detached+linked>(search, vast_dir / "console");
      delayed_send(c, std::chrono::milliseconds(200), atom("prompt"));
    }
#endif
  }
  catch (network_error const& e)
  {
    VAST_LOG_ACTOR_ERROR("encountered network error: " << e.what());
    send_exit(self, exit::error);
  }
}

char const* program::description() const
{
  return "program";
}

} // namespace vast
<commit_msg>Elevate log level of publishing endpoints.<commit_after>#include "vast/program.h"

#include <cstdlib>
#include <csignal>
#include <iostream>
#include "vast/archive.h"
#include "vast/file_system.h"
#include "vast/id_tracker.h"
#include "vast/index.h"
#include "vast/ingestor.h"
#include "vast/logger.h"
#include "vast/receiver.h"
#include "vast/schema.h"
#include "vast/schema_manager.h"
#include "vast/search.h"
#include "vast/signal_monitor.h"
#include "vast/detail/type_manager.h"
#include "vast/util/profiler.h"

#ifdef VAST_HAVE_BROCCOLI
#include "vast/util/broccoli.h"
#endif

#ifdef VAST_HAVE_EDITLINE
#include "vast/console.h"
#endif

using namespace cppa;

namespace vast {

program::program(configuration const& config)
  : config_{config}
{
}

void program::act()
{
  chaining(false);

  behavior default_behavior = (
      on(atom("signal"), arg_match) >> [&](int signal)
      {
        VAST_LOG_ACTOR_VERBOSE("received signal " << signal);
        if (signal == SIGINT || signal == SIGTERM)
          quit(exit::stop);
      },
      others() >> [=]
      {
        quit(exit::error);
        VAST_LOG_ACTOR_ERROR("terminated after unexpected message from " <<
                             VAST_ACTOR_ID(last_sender()) << ": " <<
                             to_string(self->last_dequeued()));
      });

  become(default_behavior);

  auto monitor = spawn<signal_monitor, detached+linked>(self);
  send(monitor, atom("act"));

  auto vast_dir = path{*config_.get("directory")};
  try
  {
    if (config_.check("profile"))
    {
      auto ms = *config_.as<unsigned>("profile");
      auto profiler = spawn<util::profiler, detached+linked>(
          vast_dir / "log", std::chrono::seconds(ms));

      if (config_.check("profile-cpu"))
        send(profiler, atom("start"), atom("perftools"), atom("cpu"));

      if (config_.check("profile-heap"))
        send(profiler, atom("start"), atom("perftools"), atom("heap"));

      send(profiler, atom("start"), atom("rusage"));
    }

    auto schema_manager = spawn<schema_manager_actor, linked>();
    if (config_.check("schema.file"))
    {
      send(schema_manager, atom("load"), *config_.get("schema.file"));
      if (config_.check("schema.print"))
      {
        sync_send(schema_manager, atom("schema")).then(
            on_arg_match >> [](schema const& s)
            {
              std::cout << to_string(s);
            });
        quit();
      }
    }

    actor_ptr tracker;
    auto tracker_host = *config_.get("tracker.host");
    auto tracker_port = *config_.as<unsigned>("tracker.port");
    if (config_.check("tracker-actor") || config_.check("all-server"))
    {
      tracker = spawn<id_tracker_actor, linked>(vast_dir);
      VAST_LOG_ACTOR_INFO(
          "publishes tracker at " << tracker_host << ':' << tracker_port);

      publish(tracker, tracker_port, tracker_host.c_str());
    }
    else if (config_.check("receiver-actor"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to tracker at " << tracker_host << ':' << tracker_port);
      tracker = remote_actor(tracker_host, tracker_port);
    }

    actor_ptr archive;
    auto archive_host = *config_.get("archive.host");
    auto archive_port = *config_.as<unsigned>("archive.port");
    if (config_.check("archive-actor") || config_.check("all-server"))
    {
      archive = spawn<archive_actor, linked>(
          vast_dir / "archive",
          *config_.as<size_t>("archive.max-segments"));

      VAST_LOG_ACTOR_INFO(
          "publishes archive at " << archive_host << ':' << archive_port);

      publish(archive, archive_port, archive_host.c_str());
    }
    else if (config_.check("receiver-actor")
             || config_.check("search-actor")
             || config_.check("index.rebuild"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to archive at " << archive_host << ':' << archive_port);

      archive = remote_actor(archive_host, archive_port);
    }

    actor_ptr index;
    auto index_host = *config_.get("index.host");
    auto index_port = *config_.as<unsigned>("index.port");
    if (config_.check("index-actor") || config_.check("all-server"))
    {
      index = spawn<index_actor, linked>(
          vast_dir / "index", *config_.as<size_t>("index.batch-size"));

      VAST_LOG_ACTOR_INFO(
          "publishes index " << index_host << ':' << index_port);

      publish(index, index_port, index_host.c_str());
    }
    else if (config_.check("receiver-actor")
             || config_.check("search-actor")
             || config_.check("index.rebuild"))
    {
      VAST_LOG_ACTOR_VERBOSE("connects to index at " <<
                           index_host << ":" << index_port);

      index = remote_actor(index_host, index_port);
    }

    if (auto partition = config_.get("index.partition"))
    {
      send(index, atom("partition"), *partition);
    }
    else if (config_.check("index.rebuild"))
    {
      become(
        on_arg_match >> [=](segment const& s)
        {
          event_id next = s.base() + s.events();
          send(archive, atom("segment"), next);
          forward_to(index);
        },
        on(atom("no segment"), arg_match) >> [=](event_id eid)
        {
          VAST_LOG_INFO("sent all segments to index (" << eid - 1 << " events)");
          become(default_behavior);
        });

      VAST_LOG_INFO("begins rebuilding index");
      send(index, atom("delete"));
      send(archive, atom("segment"), event_id{1});
    }

    actor_ptr receiver;
    auto receiver_host = *config_.get("receiver.host");
    auto receiver_port = *config_.as<unsigned>("receiver.port");
    if (config_.check("receiver-actor") || config_.check("all-server"))
    {
      receiver = spawn<receiver_actor, linked>(tracker, archive, index);
      VAST_LOG_ACTOR_INFO(
          "publishes receiver at " << receiver_host << ':' << receiver_port);

      publish(receiver, receiver_port, receiver_host.c_str());
    }
    else if (config_.check("ingestor-actor"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to receiver at " << receiver_host << ":" << receiver_port);

      receiver = remote_actor(receiver_host, receiver_port);
    }

    actor_ptr ingestor;
    if (config_.check("ingestor-actor"))
    {
      ingestor = spawn<ingestor_actor, linked>(
          vast_dir,
          receiver,
          *config_.as<size_t>("ingest.max-events-per-chunk"),
          *config_.as<size_t>("ingest.max-segment-size") * 1000000,
          *config_.as<size_t>("ingest.batch-size"));

      if (config_.check("ingest.submit"))
        send(ingestor, atom("submit"));

#ifdef VAST_HAVE_BROCCOLI
      util::broccoli::init(config_.check("broccoli-messages"),
                           config_.check("broccoli-calltrace"));
      if (config_.check("ingest.broccoli-events"))
      {
        auto host = *config_.get("ingest.broccoli-host");
        auto port = *config_.as<unsigned>("ingest.broccoli-port");
        auto events =
          *config_.as<std::vector<std::string>>("ingest.broccoli-events");

        send(ingestor, atom("ingest"), atom("broccoli"), host, port,
             std::move(events));
      }
#endif

      if (auto file = config_.get("ingest.file-name"))
      {
        auto type = *config_.get("ingest.file-type");
        if (! exists(string(*file)))
        {
          VAST_LOG_ACTOR_ERROR("no such file: " << *file);
          send_exit(self, exit::error);
          return;
        }

        send(ingestor, atom("ingest"), type, *file);
      }
      else
      {
        send_exit(ingestor, exit::done);
      }
    }

    actor_ptr search;
    auto search_host = *config_.get("search.host");
    auto search_port = *config_.as<unsigned>("search.port");
    if (config_.check("search-actor") || config_.check("all-server"))
    {
      search = spawn<search_actor, linked>(archive, index, schema_manager);
      VAST_LOG_ACTOR_INFO(
          "publishes search at " << search_host << ':' << search_port);

      publish(search, search_port, search_host.c_str());
    }
#ifdef VAST_HAVE_EDITLINE
    else if (config_.check("console-actor"))
    {
      VAST_LOG_ACTOR_VERBOSE(
          "connects to search at " << search_host << ":" << search_port);

      search = remote_actor(search_host, search_port);

      auto c = spawn<console, detached+linked>(search, vast_dir / "console");
      delayed_send(c, std::chrono::milliseconds(200), atom("prompt"));
    }
#endif
  }
  catch (network_error const& e)
  {
    VAST_LOG_ACTOR_ERROR("encountered network error: " << e.what());
    send_exit(self, exit::error);
  }
}

char const* program::description() const
{
  return "program";
}

} // namespace vast
<|endoftext|>


<commit_before>/*
 Copyright (c) 2014, The Cinder Project

 This code is intended to be used with the Cinder C++ library, http://libcinder.org

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this list of conditions and
 the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "cinder/audio/SampleRecorderNode.h"
#include "cinder/audio/Context.h"
#include "cinder/audio/Target.h"

using namespace ci;
using namespace std;

namespace cinder { namespace audio {

namespace {

const size_t DEFAULT_RECORD_BUFFER_FRAMES = 44100;

void resizeBufferAndShuffleChannels( BufferDynamic *buffer, size_t resultNumFrames )
{
	const size_t currentNumFrames = buffer->getNumFrames();
	const size_t sampleSize = sizeof( BufferDynamic::SampleType );

	if( currentNumFrames < resultNumFrames ) {
		// if expanding, resize and then shuffle. Make sure to get the data pointer after the resize.
		buffer->setNumFrames( resultNumFrames );
		float *data = buffer->getData();

		for( size_t ch = 1; ch < buffer->getNumChannels(); ch++ ) {
			const size_t numZeroFrames = resultNumFrames - currentNumFrames;
			const float *currentChannel = &data[ch * currentNumFrames];
			float *resultChannel = &data[ch * resultNumFrames];

			memmove( resultChannel, currentChannel, currentNumFrames * sampleSize );
			memset( resultChannel - numZeroFrames, 0, numZeroFrames * sampleSize );
		}
	}
	else if( currentNumFrames > resultNumFrames ) {
		// if shrinking, shuffle first and then resize.
		float *data = buffer->getData();

		for( size_t ch = 1; ch < buffer->getNumChannels(); ch++ ) {
			const float *currentChannel = &data[ch * currentNumFrames];
			float *resultChannel = &data[ch * resultNumFrames];

			memmove( resultChannel, currentChannel, currentNumFrames * sampleSize );
		}

		const size_t numZeroFrames = ( currentNumFrames - resultNumFrames ) * buffer->getNumChannels();
		memset( data + buffer->getSize() - numZeroFrames, 0, numZeroFrames * sampleSize );

		buffer->setNumFrames( resultNumFrames );
	}
}

}

// ----------------------------------------------------------------------------------------------------
// MARK: - SampleRecorderNode
// ----------------------------------------------------------------------------------------------------

SampleRecorderNode::SampleRecorderNode( const Format &format )
	: NodeAutoPullable( format ), mWritePos( 0 )
{
}

// ----------------------------------------------------------------------------------------------------
// MARK: - BufferRecorderNode
// ----------------------------------------------------------------------------------------------------

BufferRecorderNode::BufferRecorderNode( const Format &format )
	: SampleRecorderNode( format ), mLastOverrun( 0 )
{
	initBuffers( DEFAULT_RECORD_BUFFER_FRAMES );
}

BufferRecorderNode::BufferRecorderNode( size_t numFrames, const Format &format )
	: SampleRecorderNode( format ), mLastOverrun( 0 )
{
	initBuffers( numFrames );
}

void BufferRecorderNode::initialize()
{
	// adjust recorder buffer to match channels once initialized, since they could have changed since construction.
	bool resize = mRecorderBuffer.getNumFrames() != 0;
	mRecorderBuffer.setNumChannels( getNumChannels() );

	// if the buffer had already been resized, zero out any posisbly existing data.
	if( resize )
		mRecorderBuffer.zero();
}

void BufferRecorderNode::initBuffers( size_t numFrames )
{
	mRecorderBuffer.setSize( numFrames, getNumChannels() );
	mCopiedBuffer = make_shared<BufferDynamic>( numFrames, getNumChannels() );
}

void BufferRecorderNode::start()
{
	mWritePos = 0;
	enable();
}

void BufferRecorderNode::stop()
{
	disable();
}

void BufferRecorderNode::setNumSeconds( double numSeconds, bool shrinkToFit )
{
	setNumFrames( size_t( numSeconds * (double)getSampleRate() ), shrinkToFit );
}

double BufferRecorderNode::getNumSeconds() const
{
	return (double)getNumFrames() / (double)getSampleRate();
}

void BufferRecorderNode::setNumFrames( size_t numFrames, bool shrinkToFit )
{
	if( mRecorderBuffer.getNumFrames() == numFrames )
		return;

	lock_guard<mutex> lock( getContext()->getMutex() );

	if( mWritePos != 0 )
		resizeBufferAndShuffleChannels( &mRecorderBuffer, numFrames );
	else
		mRecorderBuffer.setNumFrames( numFrames );

	if( shrinkToFit )
		mRecorderBuffer.shrinkToFit();
}

BufferRef BufferRecorderNode::getRecordedCopy() const
{
	// first grab the number of current frames, which may be increasing as the recording continues.
	size_t numFrames = mWritePos;
	mCopiedBuffer->setSize( numFrames, mRecorderBuffer.getNumChannels() );

	mCopiedBuffer->copy( mRecorderBuffer, numFrames );
	return mCopiedBuffer;
}

void BufferRecorderNode::writeToFile( const fs::path &filePath, SampleType sampleType )
{
	size_t currentWritePos = mWritePos;
	BufferRef copiedBuffer = getRecordedCopy();

	audio::TargetFileRef target = audio::TargetFile::create( filePath, getSampleRate(), getNumChannels(), sampleType );
	target->write( copiedBuffer.get(), currentWritePos );
}

uint64_t BufferRecorderNode::getLastOverrun()
{
	uint64_t result = mLastOverrun;
	mLastOverrun = 0;
	return result;
}

void BufferRecorderNode::process( Buffer *buffer )
{
	size_t writePos = mWritePos;
	size_t numWriteFrames = buffer->getNumFrames();

	if( writePos + numWriteFrames > mRecorderBuffer.getNumFrames() )
		numWriteFrames = mRecorderBuffer.getNumFrames() - writePos;

	mRecorderBuffer.copyOffset( *buffer, numWriteFrames, writePos, 0 );

	if( numWriteFrames < buffer->getNumFrames() )
		mLastOverrun = getContext()->getNumProcessedFrames();

    const size_t writePosNew = writePos + numWriteFrames;

    // only update mWritePos if it hasn't been reset by start() in the meanwhile
    mWritePos.compare_exchange_strong( writePos, writePosNew );
}

} } // namespace cinder::audio
<commit_msg>minor whitespace fix<commit_after>/*
 Copyright (c) 2014, The Cinder Project

 This code is intended to be used with the Cinder C++ library, http://libcinder.org

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this list of conditions and
 the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "cinder/audio/SampleRecorderNode.h"
#include "cinder/audio/Context.h"
#include "cinder/audio/Target.h"

using namespace ci;
using namespace std;

namespace cinder { namespace audio {

namespace {

const size_t DEFAULT_RECORD_BUFFER_FRAMES = 44100;

void resizeBufferAndShuffleChannels( BufferDynamic *buffer, size_t resultNumFrames )
{
	const size_t currentNumFrames = buffer->getNumFrames();
	const size_t sampleSize = sizeof( BufferDynamic::SampleType );

	if( currentNumFrames < resultNumFrames ) {
		// if expanding, resize and then shuffle. Make sure to get the data pointer after the resize.
		buffer->setNumFrames( resultNumFrames );
		float *data = buffer->getData();

		for( size_t ch = 1; ch < buffer->getNumChannels(); ch++ ) {
			const size_t numZeroFrames = resultNumFrames - currentNumFrames;
			const float *currentChannel = &data[ch * currentNumFrames];
			float *resultChannel = &data[ch * resultNumFrames];

			memmove( resultChannel, currentChannel, currentNumFrames * sampleSize );
			memset( resultChannel - numZeroFrames, 0, numZeroFrames * sampleSize );
		}
	}
	else if( currentNumFrames > resultNumFrames ) {
		// if shrinking, shuffle first and then resize.
		float *data = buffer->getData();

		for( size_t ch = 1; ch < buffer->getNumChannels(); ch++ ) {
			const float *currentChannel = &data[ch * currentNumFrames];
			float *resultChannel = &data[ch * resultNumFrames];

			memmove( resultChannel, currentChannel, currentNumFrames * sampleSize );
		}

		const size_t numZeroFrames = ( currentNumFrames - resultNumFrames ) * buffer->getNumChannels();
		memset( data + buffer->getSize() - numZeroFrames, 0, numZeroFrames * sampleSize );

		buffer->setNumFrames( resultNumFrames );
	}
}

}

// ----------------------------------------------------------------------------------------------------
// MARK: - SampleRecorderNode
// ----------------------------------------------------------------------------------------------------

SampleRecorderNode::SampleRecorderNode( const Format &format )
	: NodeAutoPullable( format ), mWritePos( 0 )
{
}

// ----------------------------------------------------------------------------------------------------
// MARK: - BufferRecorderNode
// ----------------------------------------------------------------------------------------------------

BufferRecorderNode::BufferRecorderNode( const Format &format )
	: SampleRecorderNode( format ), mLastOverrun( 0 )
{
	initBuffers( DEFAULT_RECORD_BUFFER_FRAMES );
}

BufferRecorderNode::BufferRecorderNode( size_t numFrames, const Format &format )
	: SampleRecorderNode( format ), mLastOverrun( 0 )
{
	initBuffers( numFrames );
}

void BufferRecorderNode::initialize()
{
	// adjust recorder buffer to match channels once initialized, since they could have changed since construction.
	bool resize = mRecorderBuffer.getNumFrames() != 0;
	mRecorderBuffer.setNumChannels( getNumChannels() );

	// if the buffer had already been resized, zero out any posisbly existing data.
	if( resize )
		mRecorderBuffer.zero();
}

void BufferRecorderNode::initBuffers( size_t numFrames )
{
	mRecorderBuffer.setSize( numFrames, getNumChannels() );
	mCopiedBuffer = make_shared<BufferDynamic>( numFrames, getNumChannels() );
}

void BufferRecorderNode::start()
{
	mWritePos = 0;
	enable();
}

void BufferRecorderNode::stop()
{
	disable();
}

void BufferRecorderNode::setNumSeconds( double numSeconds, bool shrinkToFit )
{
	setNumFrames( size_t( numSeconds * (double)getSampleRate() ), shrinkToFit );
}

double BufferRecorderNode::getNumSeconds() const
{
	return (double)getNumFrames() / (double)getSampleRate();
}

void BufferRecorderNode::setNumFrames( size_t numFrames, bool shrinkToFit )
{
	if( mRecorderBuffer.getNumFrames() == numFrames )
		return;

	lock_guard<mutex> lock( getContext()->getMutex() );

	if( mWritePos != 0 )
		resizeBufferAndShuffleChannels( &mRecorderBuffer, numFrames );
	else
		mRecorderBuffer.setNumFrames( numFrames );

	if( shrinkToFit )
		mRecorderBuffer.shrinkToFit();
}

BufferRef BufferRecorderNode::getRecordedCopy() const
{
	// first grab the number of current frames, which may be increasing as the recording continues.
	size_t numFrames = mWritePos;
	mCopiedBuffer->setSize( numFrames, mRecorderBuffer.getNumChannels() );

	mCopiedBuffer->copy( mRecorderBuffer, numFrames );
	return mCopiedBuffer;
}

void BufferRecorderNode::writeToFile( const fs::path &filePath, SampleType sampleType )
{
	size_t currentWritePos = mWritePos;
	BufferRef copiedBuffer = getRecordedCopy();

	audio::TargetFileRef target = audio::TargetFile::create( filePath, getSampleRate(), getNumChannels(), sampleType );
	target->write( copiedBuffer.get(), currentWritePos );
}

uint64_t BufferRecorderNode::getLastOverrun()
{
	uint64_t result = mLastOverrun;
	mLastOverrun = 0;
	return result;
}

void BufferRecorderNode::process( Buffer *buffer )
{
	size_t writePos = mWritePos;
	size_t numWriteFrames = buffer->getNumFrames();

	if( writePos + numWriteFrames > mRecorderBuffer.getNumFrames() )
		numWriteFrames = mRecorderBuffer.getNumFrames() - writePos;

	mRecorderBuffer.copyOffset( *buffer, numWriteFrames, writePos, 0 );

	if( numWriteFrames < buffer->getNumFrames() )
		mLastOverrun = getContext()->getNumProcessedFrames();

	const size_t writePosNew = writePos + numWriteFrames;

	// only update mWritePos if it hasn't been reset by start() in the meanwhile
	mWritePos.compare_exchange_strong( writePos, writePosNew );
}

} } // namespace cinder::audio
<|endoftext|>


<commit_before>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER 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 Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file routeFeeder.cpp
 * @author Geoff Lawler <geoff.lawler@cobham.com>
 * @date 2009-07-15
 */
#include <stdio.h>
#include <sysexits.h> 	// portablish exit values.
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <string.h>
#include <assert.h>

#include <string>
#include <vector>

#include <libwatcher/client.h>                         // we are a client of the watcher.
#include <libwatcher/edgeMessage.h>         // we may send edgeMessages to the watcher.
#include <libwatcher/connectivityMessage.h> // we may send connectivityMessages to the watcher.
#include <logger.h>

using namespace std;
using namespace watcher;
using namespace watcher::event;

static const char *rcsid __attribute__ ((unused)) = "$Id: routingfeeder.c,v 1.0 2009/04/28 22:08:47 glawler Exp $";

// #define DEBUG 1

/* This is a feeder which polls the routing table,
 * and draws the routing algorithm's edges on the watcher
 *
 *  Copyright (C) 2006,2007,2008,2009 Sparta Inc.  Written by the NIP group, SRD, ISSO
 */

struct Route
{
    unsigned int dst;
    unsigned int nexthop;
    unsigned int mask;
    char iface[16];

    Route(int d, int n, int m, char i[16]) : dst(d), nexthop(n), mask(m) { memcpy(iface, i, sizeof(iface)); }
    Route(const Route &cpy) { dst=cpy.dst; nexthop=cpy.nexthop; mask=cpy.mask; memcpy(iface, cpy.iface, sizeof(iface)); }
    ~Route() { }
    ostream &operator<<(ostream &out) { return out << "dst: " << dst << " nexthop: " << nexthop << " mask: " << mask << " iface: " << (const char *)iface; }

};

bool operator==(const Route &a, const Route &b) {
    return a.dst==b.dst && a.nexthop==b.nexthop && a.mask==b.mask && !strncmp(a.iface, b.iface, sizeof(a.iface));
}

bool operator<(const Route &a, const Route &b) {
    return a.dst < b.dst;
}

typedef vector<Route> RouteList;

#if DEBUG
static void routeDump(const RouteList &r)
{
    TRACE_ENTER();

    if (r.size()) {
        for (RouteList::const_iterator i=r.begin(); i!=r.end(); i++) {
            ostringstream out;
            out << *i;
        }
        LOG_DEBUG("%s", out.str().c_str());
    }

    TRACE_EXIT();
}
#endif // DEBUG

typedef struct detector
{
    Client *watcherClientPtr;

    useconds_t reportperiod;		/* frequency to generate reports at */
    int reportnum;
    string iface;
    int routeedgewidth;
    Color onehopcolor;
    Color nexthopcolor;

    string nexthoplayer;
    string onehoplayer;

    int duration;			  /* Time to run (in seconds) or 0 to run until broken */

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

    RouteList prevNextHopRoutes;   /* The previous next hop list we saw. */
    RouteList prevOneHopRoutes;    /* the previous one hop list we saw. */

    bool constantUpdates;

} detector;

typedef struct DetectorInit
{
    useconds_t reportperiod;		/* frequency to generate reports at */
    string iface;
    int onehopfamily;
    Color onehopcolor;
    Color nexthopcolor;
    int mouthnum;
    int duration;			  /* Time to run (in seconds) or 0 to run until broken */
    int routeedgewidth;

    string serverName;

    string nexthoplayer;
    string onehoplayer;

    bool constantUpdates;

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

} DetectorInit;

/*
   Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask       MTU      Window  IRTT
   eth0    7402A8C0        7C02A8C0        0007    0       0       0       FFFFFFFF   00       0
   eth0    7402A8C0        7202A8C0        0007    0       0       0       FFFFFFFF   00       0
   */
static void routeRead(unsigned int network, unsigned int netmask, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    FILE *fil;
    char line[1024];

    fil=fopen("/proc/net/route","r");
    while(fgets(line,sizeof(line)-1,fil))
    {
        char iface[16];
        int flags,refcnt,use,metric,mtu,window;
        unsigned int dst,nexthop,mask;
        int rc;

        rc=sscanf(line,"%s\t%x\t%x\t%d\t%d\t%d\t%d\t%x\t%o\t%d\n",iface,&dst,&nexthop,&flags,&refcnt,&use,&metric,&mask,&mtu,&window);

        if (rc==10 && (ntohl(dst)!=ntohl(network)) && ((ntohl(dst) & ntohl(netmask)) == ntohl(network))) {
            if (nexthop!=0)
                nextHopRoutes.push_back(Route(ntohl(dst), ntohl(nexthop), ntohl(mask), iface));
            else
                oneHopRoutes.push_back(Route(ntohl(dst), ntohl(nexthop), ntohl(mask), iface));
        }
    }

    fclose(fil);

    TRACE_EXIT();
    return;
}

static void updateRoutes(detector *st, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    static vector<MessagePtr> messages;
    if(!messages.empty())
        messages.clear();

    bool sendMessage=false;

    /*
     * If constant updates is true, always send route list. Else only send when the new list differs from the old.
     */
    if (st->constantUpdates || oneHopRoutes!=st->prevOneHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ONE_HOP_ROUTING_LAYER;
        for (RouteList::const_iterator i=oneHopRoutes.begin(); i!=oneHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->dst));
        st->prevOneHopRoutes=oneHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }
    if (st->constantUpdates || nextHopRoutes!=st->prevNextHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ROUTING_LAYER;
        for (RouteList::const_iterator i=nextHopRoutes.begin(); i!=nextHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->nexthop));
        st->prevNextHopRoutes=nextHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }

    if (sendMessage)
        st->watcherClientPtr->sendMessages(messages);

    TRACE_EXIT();
}

/* This is called regularly by the select loop (below)
 * It will create a message, and send it to this node's coordinator
 */
static void detectorSend(detector *st)
{
    TRACE_ENTER();

    RouteList oneHopRoutes, nextHopRoutes;

    routeRead(st->filterNetwork.s_addr, st->filterMask.s_addr, oneHopRoutes, nextHopRoutes);

    long long int curtime;
    struct timeval tp;
    gettimeofday(&tp, NULL);
    curtime=(long long int)tp.tv_sec*1000 + (long long int)tp.tv_usec/1000;

    LOG_DEBUG("node= " << st->localhost.s_addr << " time= " << curtime << " routes= " << nextHopRoutes.size() << " onehoproutes= " << oneHopRoutes.size() << " totalroutes= " << nextHopRoutes.size()+oneHopRoutes.size());

    st->reportnum++;

    updateRoutes(st,oneHopRoutes, nextHopRoutes);

    TRACE_EXIT();
}

static detector *detectorInit(DetectorInit *detinit)
{
    TRACE_ENTER();
    detector *st;

    st=new detector;
    st->iface="";

    st->watcherClientPtr=new Client(detinit->serverName);
    if(st->watcherClientPtr==NULL)
        return NULL;

    st->duration=detinit->duration;
    st->constantUpdates=detinit->constantUpdates;
    st->reportperiod=detinit->reportperiod;
    st->reportnum=0;
    st->iface=detinit->iface;

    st->onehoplayer=detinit->onehoplayer;
    st->onehopcolor=detinit->onehopcolor;

    st->nexthoplayer=detinit->nexthoplayer;
    st->nexthopcolor=st->nexthopcolor;

    st->routeedgewidth=detinit->routeedgewidth;

	st->filterNetwork.s_addr=detinit->filterNetwork.s_addr;
	st->filterMask.s_addr=detinit->filterMask.s_addr;
	st->localhost.s_addr=detinit->localhost.s_addr;

    TRACE_EXIT();
    return st;
}

/*
 * Wait around until we are ready to generate a message, then do it.
 */
static void selectLoop(detector *dt)
{
    TRACE_ENTER();

    time_t startTime=time(NULL);

    while(1)
    {
        usleep(dt->reportperiod*(useconds_t)1000.0);
        detectorSend(dt);

        if (dt->duration)
            if (time(NULL)-startTime>dt->duration)
                break;
    }

    dt->watcherClientPtr->wait();

    TRACE_EXIT();
}

int main(int argc, char *argv[])
{
    TRACE_ENTER();
    detector *dt;
    int ch;
    string logPropsFile("routeFeeder.log.properties");

    DetectorInit detinit;
    detinit.iface="";
    detinit.onehopcolor=Color::green;
    detinit.onehoplayer="One Hop Routing";
    detinit.nexthopcolor=Color::blue;
    detinit.nexthoplayer="Network Routing";
    detinit.reportperiod=2000;
    detinit.duration=0;
    detinit.routeedgewidth=15;

	detinit.filterNetwork.s_addr=0;
	detinit.filterMask.s_addr=0;
	detinit.localhost.s_addr=0;

    detinit.constantUpdates=false;

    while ((ch = getopt(argc, argv, "m:n:h:o:x:t:e:b:i:d:p:w:l:cu?")) != -1)
        switch (ch)
        {
            case 'm': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterMask))
                      {
                          fprintf(stderr, "Error parsing filter mask: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'n': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterNetwork))
                      {
                          fprintf(stderr, "Error parsing filter network: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'h': if(-1 == inet_pton(AF_INET, optarg, &detinit.localhost))
                      {
                          fprintf(stderr, "Error parsing localhost address: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'o':
                      detinit.onehopcolor.fromString(optarg);
                      break;
            case 'x':
                      detinit.nexthopcolor.fromString(optarg);
                      break;
            case 't':
                      sscanf(optarg,"%d",&detinit.duration);
                      break;
            case 'e':
                      detinit.onehoplayer=string(optarg);
                      break;
            case 'b':
                      detinit.nexthoplayer=string(optarg);
                      break;
            case 'i':
                      detinit.iface=string(optarg);
                      break;
            case 'd':
                      detinit.serverName=string(optarg);
                      break;
            case 'p':
                      sscanf(optarg,"%d",&detinit.reportperiod);
                      break;
            case 'w':
                      sscanf(optarg, "%d", &detinit.routeedgewidth);
                      break;
            case 'l':
                      logPropsFile=string(optarg);
                      break;
            case 'u':
                      detinit.constantUpdates=true;
                      break;
            case '?':
            default:
                      fprintf(stderr,"%s - poll the linux routing table, and draw the routes in the watcher\n"
                              "-d ipaddr/hostname - specify watcherd address to connect to (duck)\n"
                              "-h ipaddr - this host's address\n"
                              "-m netmask - the mask used to filter the routes (ex. 255.255.255.0)\n"
                              "-n network - the network used to filter the routes (ex. 192.168.1.0)\n"
                              "-p milliseconds - specify the period to poll and report\n"
                              "-i interface - display only routes through this ethernet interface (or any if unspecified)\n"
                              "-e layer - onehop layer name\n"
                              "-b layer - nexthop layer name\n"
                              "-t seconds - Run for this long, then exit\n"
                              "-u - send updates every period. If not set, only send updates when the routes change.\n",
                              // "-c - use connectivity messages instead of edge messages (this disables width and color settings)\n"
                              basename(argv[0])
                             );
                      exit(1);
                      break;
        }

    // init the logging system
    LOAD_LOG_PROPS(logPropsFile);
    LOG_INFO("Logger initialized from file \"" << logPropsFile << "\"");

	// check args, errors, etc before doing real work
	if(detinit.localhost.s_addr == 0)
    {
        fprintf(stderr, "localhost address cannot be blank\n");
        exit(EX_USAGE);
    }
	if(detinit.filterNetwork.s_addr == 0)
	{
        fprintf(stderr, "filter network cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.filterMask.s_addr == 0)
	{
        fprintf(stderr, "filter mask cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.serverName.empty())
	{
        fprintf(stderr, "watcherd hostname cannot be blank\n");
        exit(EX_USAGE);
	}

    dt=detectorInit(&detinit);

    if (dt==NULL)
    {
        fprintf(stderr,"detector init failed, probably could not connect to infrastructure demon.\n");
        exit(1);
    }
    printf("%s: starting\n",argv[0]);
    selectLoop(dt);

    TRACE_EXIT();
    return 0;
}
<commit_msg>routeFeeder: set from node id in messages.<commit_after>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER 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 Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file routeFeeder.cpp
 * @author Geoff Lawler <geoff.lawler@cobham.com>
 * @date 2009-07-15
 */
#include <stdio.h>
#include <sysexits.h> 	// portablish exit values.
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <string.h>
#include <assert.h>

#include <string>
#include <vector>

#include <libwatcher/client.h>                         // we are a client of the watcher.
#include <libwatcher/edgeMessage.h>         // we may send edgeMessages to the watcher.
#include <libwatcher/connectivityMessage.h> // we may send connectivityMessages to the watcher.
#include <logger.h>

using namespace std;
using namespace watcher;
using namespace watcher::event;

static const char *rcsid __attribute__ ((unused)) = "$Id: routingfeeder.c,v 1.0 2009/04/28 22:08:47 glawler Exp $";

// #define DEBUG 1

/* This is a feeder which polls the routing table,
 * and draws the routing algorithm's edges on the watcher
 *
 *  Copyright (C) 2006,2007,2008,2009 Sparta Inc.  Written by the NIP group, SRD, ISSO
 */

struct Route
{
    unsigned int dst;
    unsigned int nexthop;
    unsigned int mask;
    char iface[16];

    Route(int d, int n, int m, char i[16]) : dst(d), nexthop(n), mask(m) { memcpy(iface, i, sizeof(iface)); }
    Route(const Route &cpy) { dst=cpy.dst; nexthop=cpy.nexthop; mask=cpy.mask; memcpy(iface, cpy.iface, sizeof(iface)); }
    ~Route() { }
    ostream &operator<<(ostream &out) { return out << "dst: " << dst << " nexthop: " << nexthop << " mask: " << mask << " iface: " << (const char *)iface; }

};

bool operator==(const Route &a, const Route &b) {
    return a.dst==b.dst && a.nexthop==b.nexthop && a.mask==b.mask && !strncmp(a.iface, b.iface, sizeof(a.iface));
}

bool operator<(const Route &a, const Route &b) {
    return a.dst < b.dst;
}

typedef vector<Route> RouteList;

#if DEBUG
static void routeDump(const RouteList &r)
{
    TRACE_ENTER();

    if (r.size()) {
        for (RouteList::const_iterator i=r.begin(); i!=r.end(); i++) {
            ostringstream out;
            out << *i;
        }
        LOG_DEBUG("%s", out.str().c_str());
    }

    TRACE_EXIT();
}
#endif // DEBUG

typedef struct detector
{
    Client *watcherClientPtr;

    useconds_t reportperiod;		/* frequency to generate reports at */
    int reportnum;
    string iface;
    int routeedgewidth;
    Color onehopcolor;
    Color nexthopcolor;

    string nexthoplayer;
    string onehoplayer;

    int duration;			  /* Time to run (in seconds) or 0 to run until broken */

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

    RouteList prevNextHopRoutes;   /* The previous next hop list we saw. */
    RouteList prevOneHopRoutes;    /* the previous one hop list we saw. */

    bool constantUpdates;

} detector;

typedef struct DetectorInit
{
    useconds_t reportperiod;		/* frequency to generate reports at */
    string iface;
    int onehopfamily;
    Color onehopcolor;
    Color nexthopcolor;
    int mouthnum;
    int duration;			  /* Time to run (in seconds) or 0 to run until broken */
    int routeedgewidth;

    string serverName;

    string nexthoplayer;
    string onehoplayer;

    bool constantUpdates;

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

} DetectorInit;

/*
   Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask       MTU      Window  IRTT
   eth0    7402A8C0        7C02A8C0        0007    0       0       0       FFFFFFFF   00       0
   eth0    7402A8C0        7202A8C0        0007    0       0       0       FFFFFFFF   00       0
   */
static void routeRead(unsigned int network, unsigned int netmask, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    FILE *fil;
    char line[1024];

    fil=fopen("/proc/net/route","r");
    while(fgets(line,sizeof(line)-1,fil))
    {
        char iface[16];
        int flags,refcnt,use,metric,mtu,window;
        unsigned int dst,nexthop,mask;
        int rc;

        rc=sscanf(line,"%s\t%x\t%x\t%d\t%d\t%d\t%d\t%x\t%o\t%d\n",iface,&dst,&nexthop,&flags,&refcnt,&use,&metric,&mask,&mtu,&window);

        if (rc==10 && (ntohl(dst)!=ntohl(network)) && ((ntohl(dst) & ntohl(netmask)) == ntohl(network))) {
            if (nexthop!=0)
                nextHopRoutes.push_back(Route(ntohl(dst), ntohl(nexthop), ntohl(mask), iface));
            else
                oneHopRoutes.push_back(Route(ntohl(dst), ntohl(nexthop), ntohl(mask), iface));
        }
    }

    fclose(fil);

    TRACE_EXIT();
    return;
}

static void updateRoutes(detector *st, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    static vector<MessagePtr> messages;
    if(!messages.empty())
        messages.clear();

    bool sendMessage=false;

    /*
     * If constant updates is true, always send route list. Else only send when the new list differs from the old.
     */
    if (st->constantUpdates || oneHopRoutes!=st->prevOneHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ONE_HOP_ROUTING_LAYER;
        message->fromNodeID=boost::asio::ip::address_v4(st->localhost.s_addr);
        for (RouteList::const_iterator i=oneHopRoutes.begin(); i!=oneHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->dst));
        st->prevOneHopRoutes=oneHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }
    if (st->constantUpdates || nextHopRoutes!=st->prevNextHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ROUTING_LAYER;
        message->fromNodeID=boost::asio::ip::address_v4(st->localhost.s_addr);
        for (RouteList::const_iterator i=nextHopRoutes.begin(); i!=nextHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->nexthop));
        st->prevNextHopRoutes=nextHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }

    if (sendMessage)
        st->watcherClientPtr->sendMessages(messages);

    TRACE_EXIT();
}

/* This is called regularly by the select loop (below)
 * It will create a message, and send it to this node's coordinator
 */
static void detectorSend(detector *st)
{
    TRACE_ENTER();

    RouteList oneHopRoutes, nextHopRoutes;

    routeRead(st->filterNetwork.s_addr, st->filterMask.s_addr, oneHopRoutes, nextHopRoutes);

    long long int curtime;
    struct timeval tp;
    gettimeofday(&tp, NULL);
    curtime=(long long int)tp.tv_sec*1000 + (long long int)tp.tv_usec/1000;

    LOG_DEBUG("node= " << st->localhost.s_addr << " time= " << curtime << " routes= " << nextHopRoutes.size() << " onehoproutes= " << oneHopRoutes.size() << " totalroutes= " << nextHopRoutes.size()+oneHopRoutes.size());

    st->reportnum++;

    updateRoutes(st,oneHopRoutes, nextHopRoutes);

    TRACE_EXIT();
}

static detector *detectorInit(DetectorInit *detinit)
{
    TRACE_ENTER();
    detector *st;

    st=new detector;
    st->iface="";

    st->watcherClientPtr=new Client(detinit->serverName);
    if(st->watcherClientPtr==NULL)
        return NULL;

    st->duration=detinit->duration;
    st->constantUpdates=detinit->constantUpdates;
    st->reportperiod=detinit->reportperiod;
    st->reportnum=0;
    st->iface=detinit->iface;

    st->onehoplayer=detinit->onehoplayer;
    st->onehopcolor=detinit->onehopcolor;

    st->nexthoplayer=detinit->nexthoplayer;
    st->nexthopcolor=st->nexthopcolor;

    st->routeedgewidth=detinit->routeedgewidth;

	st->filterNetwork.s_addr=detinit->filterNetwork.s_addr;
	st->filterMask.s_addr=detinit->filterMask.s_addr;
	st->localhost.s_addr=detinit->localhost.s_addr;

    TRACE_EXIT();
    return st;
}

/*
 * Wait around until we are ready to generate a message, then do it.
 */
static void selectLoop(detector *dt)
{
    TRACE_ENTER();

    time_t startTime=time(NULL);

    while(1)
    {
        usleep(dt->reportperiod*(useconds_t)1000.0);
        detectorSend(dt);

        if (dt->duration)
            if (time(NULL)-startTime>dt->duration)
                break;
    }

    dt->watcherClientPtr->wait();

    TRACE_EXIT();
}

int main(int argc, char *argv[])
{
    TRACE_ENTER();
    detector *dt;
    int ch;
    string logPropsFile("routeFeeder.log.properties");

    DetectorInit detinit;
    detinit.iface="";
    detinit.onehopcolor=Color::green;
    detinit.onehoplayer="One Hop Routing";
    detinit.nexthopcolor=Color::blue;
    detinit.nexthoplayer="Network Routing";
    detinit.reportperiod=2000;
    detinit.duration=0;
    detinit.routeedgewidth=15;

	detinit.filterNetwork.s_addr=0;
	detinit.filterMask.s_addr=0;
	detinit.localhost.s_addr=0;

    detinit.constantUpdates=false;

    while ((ch = getopt(argc, argv, "m:n:h:o:x:t:e:b:i:d:p:w:l:cu?")) != -1)
        switch (ch)
        {
            case 'm': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterMask))
                      {
                          fprintf(stderr, "Error parsing filter mask: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'n': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterNetwork))
                      {
                          fprintf(stderr, "Error parsing filter network: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'h': if(-1 == inet_pton(AF_INET, optarg, &detinit.localhost))
                      {
                          fprintf(stderr, "Error parsing localhost address: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'o':
                      detinit.onehopcolor.fromString(optarg);
                      break;
            case 'x':
                      detinit.nexthopcolor.fromString(optarg);
                      break;
            case 't':
                      sscanf(optarg,"%d",&detinit.duration);
                      break;
            case 'e':
                      detinit.onehoplayer=string(optarg);
                      break;
            case 'b':
                      detinit.nexthoplayer=string(optarg);
                      break;
            case 'i':
                      detinit.iface=string(optarg);
                      break;
            case 'd':
                      detinit.serverName=string(optarg);
                      break;
            case 'p':
                      sscanf(optarg,"%d",&detinit.reportperiod);
                      break;
            case 'w':
                      sscanf(optarg, "%d", &detinit.routeedgewidth);
                      break;
            case 'l':
                      logPropsFile=string(optarg);
                      break;
            case 'u':
                      detinit.constantUpdates=true;
                      break;
            case '?':
            default:
                      fprintf(stderr,"%s - poll the linux routing table, and draw the routes in the watcher\n"
                              "-d ipaddr/hostname - specify watcherd address to connect to (duck)\n"
                              "-h ipaddr - this host's address\n"
                              "-m netmask - the mask used to filter the routes (ex. 255.255.255.0)\n"
                              "-n network - the network used to filter the routes (ex. 192.168.1.0)\n"
                              "-p milliseconds - specify the period to poll and report\n"
                              "-i interface - display only routes through this ethernet interface (or any if unspecified)\n"
                              "-e layer - onehop layer name\n"
                              "-b layer - nexthop layer name\n"
                              "-t seconds - Run for this long, then exit\n"
                              "-u - send updates every period. If not set, only send updates when the routes change.\n",
                              // "-c - use connectivity messages instead of edge messages (this disables width and color settings)\n"
                              basename(argv[0])
                             );
                      exit(1);
                      break;
        }

    // init the logging system
    LOAD_LOG_PROPS(logPropsFile);
    LOG_INFO("Logger initialized from file \"" << logPropsFile << "\"");

	// check args, errors, etc before doing real work
	if(detinit.localhost.s_addr == 0)
    {
        fprintf(stderr, "localhost address cannot be blank\n");
        exit(EX_USAGE);
    }
	if(detinit.filterNetwork.s_addr == 0)
	{
        fprintf(stderr, "filter network cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.filterMask.s_addr == 0)
	{
        fprintf(stderr, "filter mask cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.serverName.empty())
	{
        fprintf(stderr, "watcherd hostname cannot be blank\n");
        exit(EX_USAGE);
	}

    dt=detectorInit(&detinit);

    if (dt==NULL)
    {
        fprintf(stderr,"detector init failed, probably could not connect to infrastructure demon.\n");
        exit(1);
    }
    printf("%s: starting\n",argv[0]);
    selectLoop(dt);

    TRACE_EXIT();
    return 0;
}
<|endoftext|>