27 #include "../Connection/VrpnConnectionKind.h"  
   46 #include "osvr/Server/display_json.h"  
   49 #include <boost/variant.hpp> 
   50 #include <json/reader.h> 
   51 #include <vrpn_ConnectionPtr.h> 
   59     static vrpn_ConnectionPtr
 
   61         vrpn_ConnectionPtr ret;
 
   62         if (std::string(conn->getConnectionKindID()) ==
 
   63             osvr::connection::getVRPNConnectionKindID()) {
 
   64             ret = vrpn_ConnectionPtr(
 
   65                 static_cast<vrpn_Connection *>(conn->getUnderlyingObject()));
 
   70                            boost::optional<std::string> 
const &host,
 
   71                            boost::optional<int> 
const &port)
 
   72         : m_conn(conn), m_ctx(make_shared<pluginhost::RegistrationContext>()),
 
   73           m_host(host.get_value_or(
"localhost")),
 
   74           m_port(port.get_value_or(util::UseDefaultPort)),
 
   75           m_log(util::log::make_logger(util::log::OSVR_SERVER_LOG)) {
 
   77             throw std::logic_error(
 
   78                 "Can't pass a null ConnectionPtr into Server constructor!");
 
   83         auto vrpnConn = getVRPNConnection(m_conn);
 
   85         if (!(vrpnConn->doing_okay())) {
 
   95         m_systemComponent->registerClientRouteUpdateHandler(
 
   96             &ServerImpl::m_handleUpdatedRoute, 
this);
 
  109         m_conn->registerDescriptorHandler([&] { m_handleDeviceDescriptors(); });
 
  115         vrpnConn->register_handler(
 
  116             vrpnConn->register_message_type(vrpn_got_first_connection),
 
  117             &ServerImpl::m_exitIdle, 
this);
 
  118         vrpnConn->register_handler(
 
  119             vrpnConn->register_message_type(vrpn_dropped_last_connection),
 
  120             &ServerImpl::m_enterIdle, 
this);
 
  130         boost::unique_lock<boost::mutex> lock(m_runControl);
 
  131         if (!m_ctx || !m_conn) {
 
  132             throw std::logic_error(
"Cannot start server - context or " 
  133                                    "connection destroyed (probably attempting " 
  134                                    "to restart a stopped server)");
 
  136         m_everStarted = 
true;
 
  140         m_thread = boost::thread([&] {
 
  141             bool keepRunning = 
true;
 
  142             m_mainThreadId = m_thread.get_id();
 
  143             ::util::LoopGuard guard(m_run);
 
  145                 keepRunning = this->m_loop();
 
  146             } 
while (keepRunning);
 
  147             m_orderedDestruction();
 
  150         m_run.signalAndWaitForStart();
 
  161         boost::unique_lock<boost::mutex> lock(m_runControl);
 
  163             m_run.signalAndWaitForShutdown();
 
  165             m_thread = boost::thread();
 
  167             m_orderedDestruction();
 
  172         boost::unique_lock<boost::mutex> lock(m_runControl);
 
  173         m_run.signalShutdown();
 
  177         m_callControlled([&, pluginName] { m_ctx->loadPlugin(pluginName); });
 
  188                                        std::string 
const &driver,
 
  189                                        std::string 
const ¶ms) {
 
  190         BOOST_ASSERT_MSG(m_inServerThread(),
 
  191                          "This method is only available in the server thread!");
 
  192         m_ctx->instantiateDriver(plugin, driver, params);
 
  196         m_callControlled([&] { m_triggeredDetect = 
true; });
 
  201             m_callControlled([&] { m_mainloopMethods.push_back(f); });
 
  206         boost::unique_lock<boost::mutex> lock(m_runControl);
 
  208             throw std::logic_error(
"Can't call update() if you've ever started " 
  209                                    "the server in its own thread!");
 
  213     void ServerImpl::m_update() {
 
  216         m_systemDevice->update();
 
  217         for (
auto &f : m_mainloopMethods) {
 
  220         if (m_triggeredDetect) {
 
  221             m_log->info() << 
"Performing hardware auto-detection.";
 
  222             common::tracing::markHardwareDetect();
 
  223             m_ctx->triggerHardwareDetect();
 
  224             m_triggeredDetect = 
false;
 
  227             m_log->debug() << 
"Path tree updated or connection detected";
 
  233     bool ServerImpl::m_loop() {
 
  238             boost::unique_lock<boost::mutex> lock(m_mainThreadMutex);
 
  240             shouldContinue = m_run.shouldContinue();
 
  243         if (m_currentSleepTime > 0) {
 
  246         return shouldContinue;
 
  251         m_callControlled([&] { wasNew = m_addRoute(routingDirective); });
 
  256                               std::string 
const &source,
 
  257                               common::AliasPriority priority) {
 
  261             [&] { wasChanged = m_addAlias(path, source, priority); });
 
  266                                 common::AliasPriority priority) {
 
  268         m_callControlled([&] { wasChanged = m_addAliases(aliases, priority); });
 
  273                                        std::string 
const &deviceName,
 
  274                                        std::string 
const &server,
 
  275                                        std::string 
const &descriptor) {
 
  276         Json::Value descriptorVal;
 
  278         if (!reader.parse(descriptor, descriptorVal)) {
 
  279             BOOST_ASSERT_MSG(0, 
"Should never get here - string descriptor " 
  280                                 "handed to us should have been generated from " 
  284         m_callControlled([&] {
 
  290             auto elt = common::elements::DeviceElement::createVRPNDeviceElement(
 
  292             elt.getDescriptor() = descriptorVal;
 
  302                                std::string 
const &value) {
 
  303         bool wasChanged = 
false;
 
  306         m_callControlled([&] {
 
  308             if (!(newElement == node.value())) {
 
  311                 node.value() = newElement;
 
  317     void ServerImpl::m_orderedDestruction() {
 
  319         m_systemComponent = 
nullptr; 
 
  320         m_systemDevice.reset();
 
  324     int ServerImpl::m_handleUpdatedRoute(
void *userdata, vrpn_HANDLERPARAM p) {
 
  325         auto self = 
static_cast<ServerImpl *
>(userdata);
 
  327             self->m_inServerThread(),
 
  328             "This callback should never happen outside the server thread!");
 
  330         self->m_log->info() << 
"Got an updated route from a client.";
 
  331         self->m_addRoute(std::string(p.buffer, p.payload_len));
 
  335     bool ServerImpl::m_addRoute(std::string 
const &routingDirective) {
 
  337             common::addAliasFromRoute(m_tree.getRoot(), routingDirective);
 
  338         m_treeDirty += change;
 
  342     bool ServerImpl::m_addAlias(std::string 
const &path,
 
  343                                 std::string 
const &source,
 
  344                                 common::AliasPriority priority) {
 
  348         m_treeDirty += change;
 
  352     bool ServerImpl::m_addAliases(Json::Value 
const &aliases,
 
  353                                   common::AliasPriority priority) {
 
  354         bool change = common::AliasProcessor()
 
  355                           .setDefaultPriority(priority)
 
  357                           .process(m_tree.getRoot(), aliases);
 
  358         m_treeDirty += change;
 
  361     void ServerImpl::m_queueTreeSend() {
 
  362         m_callControlled([&] { m_treeDirty += 
true; });
 
  364     void ServerImpl::m_sendTree() {
 
  366         common::tracing::markPathTreeBroadcast();
 
  367         m_systemComponent->sendReplacementTree(m_tree);
 
  368         m_log->info() << 
"Sent path tree to clients.";
 
  372         m_sleepTime = microseconds;
 
  375     int ServerImpl::getSleepTime()
 const { 
return m_sleepTime; }
 
  377     void ServerImpl::m_handleDeviceDescriptors() {
 
  378         for (
auto const &dev : m_conn->getDevices()) {
 
  379             auto const &descriptor = dev->getDeviceDescriptor();
 
  380             if (descriptor.empty()) {
 
  381                 m_log->warn() << 
"Developer Warning: No device descriptor for " 
  385                     m_tree, dev->getName(), descriptor, m_port, m_host);
 
  390     int ServerImpl::m_exitIdle(
void *userdata, vrpn_HANDLERPARAM) {
 
  391         auto self = 
static_cast<ServerImpl *
>(userdata);
 
  394         if (self->m_currentSleepTime > self->m_sleepTime) {
 
  397                 "Got first client connection, exiting idle mode.");
 
  398             self->m_currentSleepTime = 
self->m_sleepTime;
 
  401         self->m_lowLatency.reset(
new common::LowLatency);
 
  405     int ServerImpl::m_enterIdle(
void *userdata, vrpn_HANDLERPARAM) {
 
  406         auto self = 
static_cast<ServerImpl *
>(userdata);
 
  410         if (self->m_currentSleepTime < IDLE_SLEEP_TIME) {
 
  412                 "Dropped last client connection, entering idle mode.");
 
  413             self->m_currentSleepTime = IDLE_SLEEP_TIME;
 
  417         self->m_lowLatency.reset();
 
static shared_ptr< CommonComponent > create()
Factory method. 
Header defining some special values that may be passed to some functions that request a port number t...
void stop()
Signal the server to stop, and block until it does so. 
bool addString(std::string const &path, std::string const &value)
Add a string entry to the tree. 
Header including PathTree.h and all additional headers needed to define related types. 
std::string makeString(const char(&arrayLiteral)[N])
Safely and easily convert a literal array of characters (like from osvr_json_to_c) into a std::string...
void setSleepTime(int microseconds)
Sets the amount of time (in microseconds) that the server loop will sleep each loop when a client is ...
void registerMainloopMethod(MainloopMethod f)
Register a method to run during every time through the main loop. 
bool addAlias(std::string const &path, std::string const &source, common::AliasPriority priority)
Add an alias entry to the tree. 
std::function< void()> MainloopMethod
A function that can be registered by the server app to run in each mainloop iteration. 
void update()
The method to just do the update stuff, not in a thread. 
shared_ptr< Connection > ConnectionPtr
How one must hold a Connection. 
Header with a convenience function to make a std::string out of a non-null-terminated char array (str...
void addExternalDevice(std::string const &path, std::string const &deviceName, std::string const &server, std::string const &descriptor)
Add an external device entry manually to the tree. 
void loadAutoPlugins()
Load all auto-loadable plugins. 
PathNode & getNodeByPath(std::string const &path)
Returns the node indicated by the path, which must be absolute (begin with a /). Any non-existent nod...
BaseDevicePtr createServerDevice(std::string const &name, vrpn_ConnectionPtr const &conn)
Factory function for a bare server device with no components/interfaces registered by default...
void instantiateDriver(std::string const &plugin, std::string const &driver, std::string const ¶ms)
Instantiate the named driver with parameters. 
void registerPingHandler(Handler const &handler)
Register a ping handler: a ping is sent from a client device to the corresponding server device upon ...
void reset()
Reset the flag back to false. 
bool processDeviceDescriptorForPathTree(PathTree &tree, std::string const &deviceName, std::string const &jsonDescriptor, int listenPort, std::string const &host)
Set up a path tree based on a device descriptor. 
ServerImpl(connection::ConnectionPtr const &conn, boost::optional< std::string > const &host, boost::optional< int > const &port)
Constructor. 
The element type corresponding to a string value such as a JSON string. 
vrpn_Connection * getVRPNConnection(OSVR_PluginRegContext ctx)
Retrieves the vrpn_Connection pointer from an OSVR_PluginRegContext. 
static void storeConnection(pluginhost::RegistrationContext &ctx, ConnectionPtr conn)
Store a connection pointer in a RegistrationContext. 
bool addAlias(PathNode &node, std::string const &source, AliasPriority priority)
static shared_ptr< SystemComponent > create()
Factory method. 
Header to include for OSVR-internal usage of the logging mechanism: provides the needed definition of...
Internal, configured header file for verbosity macros. 
static const char * deviceName()
Get the special device name to be used with this component. 
void signalStop()
Signal the server to stop (if it is running) but return immediately. 
void startAndAwaitShutdown()
Launch a thread running the server, and block until the server shuts down. 
boost::variant< NullElement, AliasElement, SensorElement, InterfaceElement, DeviceElement, PluginElement, StringElement > PathElement
The variant type containing a particular kind of path element. 
"Guard"-type class to trace the region of a server update 
~ServerImpl()
Destructor (stops the thread first) 
bool addAliases(Json::Value const &aliases, common::AliasPriority priority)
Add alias entries to the tree from JSON. 
bool addRoute(std::string const &routingDirective)
Register a JSON string as a routing directive. 
OSVR_ReturnCode microsleep(uint64_t microseconds)
Request a thread sleep for at least the given number of microseconds. 
void set()
Set the flag to true. 
void awaitShutdown()
Block until the server shuts down. 
void setHardwareDetectOnConnection()
Adds the behavior that hardware detection should take place on client connection. ...
void triggerHardwareDetect()
Run all hardware detect callbacks. 
void start()
Launch a thread running the server. 
bool processDeviceDescriptorFromExistingDevice(PathNode &devNode, elements::DeviceElement const &devElt)
Set up a path tree based on a device descriptor from an existing DeviceElement node. 
void loadPlugin(std::string const &pluginName)
Load named plugin.