{"id":17768007,"url":"https://github.com/arvidn/libsimulator","last_synced_at":"2025-07-17T01:32:43.258Z","repository":{"id":34599642,"uuid":"38547425","full_name":"arvidn/libsimulator","owner":"arvidn","description":"libsimulator is a library for building discrete event simulations, implementing the ``boost.asio`` API.","archived":false,"fork":false,"pushed_at":"2024-07-27T22:20:21.000Z","size":657,"stargazers_count":21,"open_issues_count":0,"forks_count":10,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-01T16:21:22.065Z","etag":null,"topics":["cpp","cpp11","network","simulator"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arvidn.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-07-04T20:54:59.000Z","updated_at":"2024-07-27T22:20:22.000Z","dependencies_parsed_at":"2024-07-27T10:31:03.913Z","dependency_job_id":"ad03dff0-f959-4188-ad34-4f410e0bdeda","html_url":"https://github.com/arvidn/libsimulator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/arvidn/libsimulator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arvidn%2Flibsimulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arvidn%2Flibsimulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arvidn%2Flibsimulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arvidn%2Flibsimulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arvidn","download_url":"https://codeload.github.com/arvidn/libsimulator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arvidn%2Flibsimulator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265558490,"owners_count":23787941,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp11","network","simulator"],"created_at":"2024-10-26T20:54:10.734Z","updated_at":"2025-07-17T01:32:43.238Z","avatar_url":"https://github.com/arvidn.png","language":"C++","readme":"libsimulator\n============\n\n.. image:: https://travis-ci.org/arvidn/libsimulator.svg?branch=master\n    :target: https://travis-ci.org/arvidn/libsimulator\n\n.. image:: https://ci.appveyor.com/api/projects/status/0857n4g3f6mui90i/branch/master\n    :target: https://ci.appveyor.com/project/arvidn/libsimulator/branch/master\n\n*This is still in initial development, some of this README represents ambitions\nrather than the current state*\n\nlibsimulator is a library for running discrete event simulations, implementing\nthe ``boost.asio`` API (or a somewhat faithful emulation of a subset of it,\npatches are welcome). This makes it practical to be used as a testing tool of\nreal implementations of network software as well as for writing simulators that\nlater turn into live production applications.\n\nThe simulation has to have a single time-line to be deterministic, meaning it\nmust be single threaded and use a single ``io_service`` as the message queue.\nThese requirements may affect how the program to be tested is written. It may\nfor instance require that an external io_service can be provided rather than one\nbeing wrapped in an internal thread.\n\nHowever, ``boost.asio`` programs may generally benefit from being transformed to\nthis form, as the become *composable*, i.e. agnostic to which io_service they\nrun on or how many threads are running it.\n\nfeatures\n--------\n\nThe currently (partially) supported classes are:\n\n* chrono::high_resolution_clock\n* asio::high_resolution_timer\n* asio::ip::tcp::acceptor\n* asio::ip::tcp::endpoint\n* asio::ip::address (v4 and v6 variants, these just defer to the actual\n  boost.asio types)\n* asio::ip::tcp::socket\n* asio::ip::udp::socket\n* asio::io_service\n* asio::ip::udp::resolver\n* asio::ip::tcp::resolver\n\nThe ``high_resolution_clock`` in the ``chrono`` namespace implements the timer\nconcept from the chrono library.\n\nusage\n-----\n\nThe ``io_service`` object is significantly different from the one in boost.asio.\nThis is because one simulation may only have a single message loop and a single\nordering of events. This single message loop is provided by the ``simulation``\nclass. Each simulation should have only one such object. An ``io_service``\nobject represents a single node on the network. When creating an io_service, you\nhave to pass in the simulation it belongs to as well as the IP address it should\nhave. It is also possible to pass in multiple addresses to form a multi-homed\nnode. For instance, one with both an IPv4 and IPv6 interface.\n\nWhen creating sockets, binding and connecting them, the io_service object\ndetermines what ``INADDR_ANY`` resolves to (the first IP assigned to that node).\n\nThe only aspects of the io_service interface that's preserved are ``post()``,\n``dispatch()`` and constructing timers and sockets. In short, the ``run()`` and\n``poll()`` family of functions do not exist. Every io_service object is assumed\nto be run, and all of their events are handled by the simulation object.\n\nNone of the synchronous APIs are supported, because that would require\nintegration with OS threads and scheduler.\n\nexample\n-------\n\nHere's a simple example illustrating the asio timer::\n\n\t#include \"simulator/simulator.hpp\"\n\t#include \u003cfunctional\u003e\n\t#include \u003cboost/system.hpp\u003e\n\n\tvoid print_time(sim::asio::high_resolution_timer\u0026 timer\n\t\t, boost::system::error_code const\u0026 ec)\n\t{\n\t\tusing namespace sim::chrono;\n\t\tstatic int counter = 0;\n\n\t\tprintf(\"[%d] timer fired at: %d milliseconds. error: %s\\n\"\n\t\t\t, counter\n\t\t\t, int(duration_cast\u003cmilliseconds\u003e(high_resolution_clock::now()\n\t\t\t\t\t.time_since_epoch()).count())\n\t\t\t, ec.message().c_str());\n\n\t\t++counter;\n\t\tif (counter \u003c 5)\n\t\t{\n\t\t\ttimer.expires_from_now(seconds(counter));\n\t\t\ttimer.async_wait(std::bind(\u0026print_time, std::ref(timer), _1));\n\t\t}\n\t}\n\n\tint main()\n\t{\n\t\tusing namespace sim::chrono;\n\n\t\tdefault_config cfg;\n\t\tsimulation sim(cfg);\n\t\tio_service ios(sim, ip::address_v4::from_string(\"1.2.3.4\"));\n\t\tsim::asio::high_resolution_timer timer(ios);\n\n\t\ttimer.expires_from_now(seconds(1));\n\t\ttimer.async_wait(std::bind(\u0026print_time, std::ref(timer), _1));\n\n\t\tboost::system::error_code ec;\n\t\tsim.run(ec);\n\n\t\tprintf(\"sim::run() returned: %s at: %d\\n\"\n\t\t\t, ec.message().c_str()\n\t\t\t, int(duration_cast\u003cmilliseconds\u003e(high_resolution_clock::now()\n\t\t\t\t\t.time_since_epoch()).count()));\n\t}\n\nThe output from this program is::\n\n\t[0] timer fired at: 1000 milliseconds. error: Undefined error: 0\n\t[1] timer fired at: 2000 milliseconds. error: Undefined error: 0\n\t[2] timer fired at: 4000 milliseconds. error: Undefined error: 0\n\t[3] timer fired at: 7000 milliseconds. error: Undefined error: 0\n\t[4] timer fired at: 11000 milliseconds. error: Undefined error: 0\n\tio_service::run() returned: Undefined error: 0 at: 11000\n\nAnd obviously it doesn't take 11 wall-clock seconds to run (it returns\ninstantly).\n\nconfiguration\n-------------\n\nThe simulated network can be configured with per-node pair bandwidth, round-trip\nlatency and queue sizes. This is controlled via a callback interface that\nlibsimulator will ask for these properties when nodes get connected.\n\nThe resolution of hostnames is also configurable by providing a callback on the\nconfiguration object along with the latency of individual lookups.\n\nTo configure the network for the simulation, pass in a reference to an object\nimplementing the ``sim::configuration`` interface::\n\n\tstruct configuration\n\t{\n\t\t// build the network\n\t\tvirtual void build(simulation\u0026 sim) = 0;\n\n\t\t// return the hops on the network packets from src to dst need to traverse\n\t\tvirtual route channel_route(asio::ip::address src\n\t\t\t, asio::ip::address dst) = 0;\n\n\t\t// return the hops an incoming packet to ep need to traverse before\n\t\t// reaching the socket (for instance a NAT)\n\t\tvirtual route incoming_route(asio::ip::address ip) = 0;\n\n\t\t// return the hops an outgoing packet from ep need to traverse before\n\t\t// reaching the network (for instance a DSL modem)\n\t\tvirtual route outgoing_route(asio::ip::address ip) = 0;\n\n\t\t// return the path MTU between the two IP addresses\n\t\t// For TCP sockets, this will be called once when the connection is\n\t\t// established. For UDP sockets it's called for every burst of packets\n\t\t// that are sent\n\t\tvirtual int path_mtu(asio::ip::address ip1, asio::ip::address ip2) = 0;\n\n\t\t// called for every hostname lookup made by the client. ``reqyestor`` is\n\t\t// the node performing the lookup, ``hostname`` is the name being looked\n\t\t// up. Resolve the name into addresses and fill in ``result`` or set\n\t\t// ``ec`` if the hostname is not found or some other error occurs. The\n\t\t// return value is the latency of the lookup. The client's callback won't\n\t\t// be called until after waiting this long.\n\t\tvirtual chrono::high_resolution_clock::duration hostname_lookup(\n\t\t\tasio::ip::address const\u0026 requestor\n\t\t\t, std::string hostname\n\t\t\t, std::vector\u003casio::ip::address\u003e\u0026 result\n\t\t\t, boost::system::error_code\u0026 ec) = 0;\n\t};\n\n``build()`` is called right after the simulation is constructed. It gives the\nconfiguration object an opportunity to construct the core queues, since they\nneed access to the simulator.\n\n``channel_route()`` is expected to return a *route* of network hops from the\nsource IP to the destination IP. A route is a series of ``sink`` objects. The\ntypical sink is a ``sim::queue``, which is a network node with a specific rate\nlimit, propagation delay and queue size.\n\n*TODO: finish document configuration interface*\n\nhistory\n-------\n\nlibsimulator grew out of libtorrent's unit tests, as a tool to make them reliable\nand deterministic (i.e. not depend on external systems like sockets and timers)\nand also easier to debug. The subset of the asio API initially supported by this\nlibrary is the subset used by libtorrent. Patches are welcome to improve\nfidelity and support.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farvidn%2Flibsimulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farvidn%2Flibsimulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farvidn%2Flibsimulator/lists"}