<commit_before>#include "dbusgateway.h"

#include <boost/shared_ptr.hpp>
#include "logger.h"
#include "types.h"

DbusGateway::DbusGateway(const Config& config_in, command::Channel* command_channel_in) : config(config_in), command_channel(command_channel_in), swlm(config) {
  int ret;
  dbus_error_init(&err);
  conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
  if (dbus_error_is_set(&err)) {
    LOGGER_LOG(LVL_error, "Dbus Connection Error: " << err.message);
    dbus_error_free(&err);
    return;
  }

  ret = dbus_bus_request_name(conn, config_in.dbus.interface.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
    LOGGER_LOG(LVL_error, "Cannot request Dbus name '" << config_in.dbus.interface << "' as primary owner");
    return;
  }
  boost::thread(boost::bind(&DbusGateway::run, this));
}

DbusGateway::~DbusGateway() {
  dbus_bus_release_name(conn, config.dbus.interface.c_str(), NULL);
  dbus_connection_unref(conn);
}

void DbusGateway::processEvent(const boost::shared_ptr<event::BaseEvent>& event) {
  if (event->variant == "DownloadComplete") {
    event::DownloadComplete* download_complete_event = static_cast<event::DownloadComplete*>(event.get());
    swlm.downloadComplete(download_complete_event->download_complete.update_image, download_complete_event->download_complete.signature);
    fireDownloadCompleteEvent(download_complete_event->download_complete);
  } else if (event->variant == "InstalledSoftwareNeeded") {
    fireInstalledSoftwareNeededEvent();
  } else if (event->variant == "UpdateAvailable") {
    event::UpdateAvailable* update_vailable_event = static_cast<event::UpdateAvailable*>(event.get());
    fireUpdateAvailableEvent(update_vailable_event->update_vailable);
  }
}

void DbusGateway::fireInstalledSoftwareNeededEvent() {
  DBusMessage* msg;
  msg = dbus_message_new_signal(config.dbus.path.c_str(), config.dbus.interface.c_str(), "InstalledSoftwareNeeded");

  dbus_connection_send(conn, msg, NULL);

  dbus_message_unref(msg);
}

void DbusGateway::fireUpdateAvailableEvent(const data::UpdateAvailable& update_available) {
  DBusMessage* msg;
  DBusMessageIter iter;

  msg = dbus_message_new_signal(config.dbus.path.c_str(), config.dbus.interface.c_str(), "UpdateAvailable");

  dbus_message_iter_init_append(msg, &iter);

  DBusMessageIter sub_iter;
  dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &sub_iter);
  const char* update_id = update_available.update_id.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &update_id);
  const char* description = update_available.description.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &description);
  const char* signature = update_available.signature.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &signature);
  unsigned long long size = update_available.size;
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_UINT64, &size);

  dbus_message_iter_close_container(&iter, &sub_iter);

  dbus_connection_send(conn, msg, NULL);

  dbus_message_unref(msg);
}

void DbusGateway::fireDownloadCompleteEvent(const data::DownloadComplete& download_complete) {
  DBusMessage* msg;
  DBusMessageIter iter;

  msg = dbus_message_new_signal(config.dbus.path.c_str(), config.dbus.interface.c_str(), "DownloadComplete");
  dbus_message_iter_init_append(msg, &iter);

  DBusMessageIter sub_iter;
  dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &sub_iter);
  const char* update_id = download_complete.update_id.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &update_id);
  const char* update_image = download_complete.update_image.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &update_image);
  const char* signature = download_complete.signature.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &signature);
  dbus_message_iter_close_container(&iter, &sub_iter);

  dbus_connection_send(conn, msg, NULL);
  dbus_message_unref(msg);
}

void DbusGateway::run() {
  DBusMessage* msg;
  char* string_param;
  DBusMessageIter args;

  while (true) {
    dbus_connection_read_write(conn, 0);
    msg = dbus_connection_pop_message(conn);
    if (NULL == msg) {
      sleep(1);
      continue;
    }

    if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "initiateDownload") ||
        dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "abortDownload") ||
        dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "updateReport")) {
      if (!dbus_message_iter_init(msg, &args) || DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) {
        LOGGER_LOG(LVL_error, "dbus method initiateDownload called with wrong arguments");
        dbus_message_unref(msg);
        continue;
      } else {
        dbus_message_iter_get_basic(&args, &string_param);
      }
    }
    if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "initiateDownload")) {
      *command_channel << boost::shared_ptr<command::StartDownload>(new command::StartDownload(string_param));
    } else if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "abortDownload")) {
      *command_channel << boost::shared_ptr<command::AbortDownload>(new command::AbortDownload(string_param));
    } else if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "updateReport")) {
      data::UpdateReport update_report;
      update_report.update_id = string_param;
      if (dbus_message_iter_next(&args) && DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&args)) {
        DBusMessageIter operation_result_args;
        int results_count = dbus_message_iter_get_element_count(&args);
        dbus_message_iter_recurse(&args, &operation_result_args);
        do {
          try {
            update_report.operation_results.push_back(getOperationResult(&operation_result_args));
          } catch (...) {
            LOGGER_LOG(LVL_error, "dbus method 'updateReport' called with wrong arguments");
          }
          dbus_message_iter_next(&operation_result_args);
          results_count--;
        } while (results_count);

      } else {
        LOGGER_LOG(LVL_error, "dbus methid called with wrong argents");
        dbus_message_unref(msg);
        continue;
      }
      *command_channel << boost::shared_ptr<command::SendUpdateReport>(new command::SendUpdateReport(update_report));
    }

    DBusMessage* reply = dbus_message_new_method_return(msg);
    dbus_connection_send(conn, reply, NULL);
    dbus_connection_flush(conn);

    dbus_message_unref(reply);
    dbus_message_unref(msg);
  }
}

data::OperationResult DbusGateway::getOperationResult(DBusMessageIter* iter) {
  DBusMessageIter subiter, dict_iter, variant_iter;
  char* string_param;
  int int_param;
  data::OperationResult result;
  int params = dbus_message_iter_get_element_count(iter);
  dbus_message_iter_recurse(iter, &subiter);
  if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(iter)) {
    while (params) {
      dbus_message_iter_recurse(&subiter, &dict_iter);
      dbus_message_iter_get_basic(&dict_iter, &string_param);
      dbus_message_iter_next(&dict_iter);
      dbus_message_iter_recurse(&dict_iter, &variant_iter);
      if (std::string(string_param) == "id") {
        dbus_message_iter_get_basic(&variant_iter, &string_param);
        result.id = string_param;
        dbus_message_iter_next(&subiter);
      } else if (std::string(string_param) == "result_code") {
        dbus_message_iter_get_basic(&variant_iter, &int_param);
        result.result_code = (data::UpdateResultCode)int_param;
        dbus_message_iter_next(&subiter);
      } else if (std::string(string_param) == "result_text") {
        dbus_message_iter_get_basic(&variant_iter, &string_param);
        result.result_text = string_param;
        dbus_message_iter_next(&subiter);
      }
      params--;
    }
  }
  return result;
}
<commit_msg>Explicitly initialise libsbus in 'threads' mode<commit_after>#include "dbusgateway.h"

#include <boost/shared_ptr.hpp>
#include "logger.h"
#include "types.h"

DbusGateway::DbusGateway(const Config& config_in, command::Channel* command_channel_in) : config(config_in), command_channel(command_channel_in), swlm(config) {
  dbus_threads_init_default();
  dbus_error_init(&err);
  conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
  if (dbus_error_is_set(&err)) {
    LOGGER_LOG(LVL_error, "Dbus Connection Error: " << err.message);
    dbus_error_free(&err);
    return;
  }

  int ret = dbus_bus_request_name(conn, config_in.dbus.interface.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
    LOGGER_LOG(LVL_error, "Cannot request Dbus name '" << config_in.dbus.interface << "' as primary owner");
    return;
  }
  boost::thread(boost::bind(&DbusGateway::run, this));
}

DbusGateway::~DbusGateway() {
  dbus_bus_release_name(conn, config.dbus.interface.c_str(), NULL);
  dbus_connection_unref(conn);
}

void DbusGateway::processEvent(const boost::shared_ptr<event::BaseEvent>& event) {
  if (event->variant == "DownloadComplete") {
    event::DownloadComplete* download_complete_event = static_cast<event::DownloadComplete*>(event.get());
    swlm.downloadComplete(download_complete_event->download_complete.update_image, download_complete_event->download_complete.signature);
    fireDownloadCompleteEvent(download_complete_event->download_complete);
  } else if (event->variant == "InstalledSoftwareNeeded") {
    fireInstalledSoftwareNeededEvent();
  } else if (event->variant == "UpdateAvailable") {
    event::UpdateAvailable* update_vailable_event = static_cast<event::UpdateAvailable*>(event.get());
    fireUpdateAvailableEvent(update_vailable_event->update_vailable);
  }
}

void DbusGateway::fireInstalledSoftwareNeededEvent() {
  DBusMessage* msg;
  msg = dbus_message_new_signal(config.dbus.path.c_str(), config.dbus.interface.c_str(), "InstalledSoftwareNeeded");

  dbus_connection_send(conn, msg, NULL);

  dbus_message_unref(msg);
}

void DbusGateway::fireUpdateAvailableEvent(const data::UpdateAvailable& update_available) {
  DBusMessage* msg;
  DBusMessageIter iter;

  msg = dbus_message_new_signal(config.dbus.path.c_str(), config.dbus.interface.c_str(), "UpdateAvailable");

  dbus_message_iter_init_append(msg, &iter);

  DBusMessageIter sub_iter;
  dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &sub_iter);
  const char* update_id = update_available.update_id.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &update_id);
  const char* description = update_available.description.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &description);
  const char* signature = update_available.signature.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &signature);
  unsigned long long size = update_available.size;
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_UINT64, &size);

  dbus_message_iter_close_container(&iter, &sub_iter);

  dbus_connection_send(conn, msg, NULL);

  dbus_message_unref(msg);
}

void DbusGateway::fireDownloadCompleteEvent(const data::DownloadComplete& download_complete) {
  DBusMessage* msg;
  DBusMessageIter iter;

  msg = dbus_message_new_signal(config.dbus.path.c_str(), config.dbus.interface.c_str(), "DownloadComplete");
  dbus_message_iter_init_append(msg, &iter);

  DBusMessageIter sub_iter;
  dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &sub_iter);
  const char* update_id = download_complete.update_id.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &update_id);
  const char* update_image = download_complete.update_image.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &update_image);
  const char* signature = download_complete.signature.c_str();
  dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &signature);
  dbus_message_iter_close_container(&iter, &sub_iter);

  dbus_connection_send(conn, msg, NULL);
  dbus_message_unref(msg);
}

void DbusGateway::run() {
  DBusMessage* msg;
  char* string_param;
  DBusMessageIter args;

  while (true) {
    dbus_connection_read_write(conn, 0);
    msg = dbus_connection_pop_message(conn);
    if (NULL == msg) {
      sleep(1);
      continue;
    }

    if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "initiateDownload") ||
        dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "abortDownload") ||
        dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "updateReport")) {
      if (!dbus_message_iter_init(msg, &args) || DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) {
        LOGGER_LOG(LVL_error, "dbus method initiateDownload called with wrong arguments");
        dbus_message_unref(msg);
        continue;
      } else {
        dbus_message_iter_get_basic(&args, &string_param);
      }
    }
    if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "initiateDownload")) {
      *command_channel << boost::shared_ptr<command::StartDownload>(new command::StartDownload(string_param));
    } else if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "abortDownload")) {
      *command_channel << boost::shared_ptr<command::AbortDownload>(new command::AbortDownload(string_param));
    } else if (dbus_message_is_method_call(msg, config.dbus.interface.c_str(), "updateReport")) {
      data::UpdateReport update_report;
      update_report.update_id = string_param;
      if (dbus_message_iter_next(&args) && DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&args)) {
        DBusMessageIter operation_result_args;
        int results_count = dbus_message_iter_get_element_count(&args);
        dbus_message_iter_recurse(&args, &operation_result_args);
        do {
          try {
            update_report.operation_results.push_back(getOperationResult(&operation_result_args));
          } catch (...) {
            LOGGER_LOG(LVL_error, "dbus method 'updateReport' called with wrong arguments");
          }
          dbus_message_iter_next(&operation_result_args);
          results_count--;
        } while (results_count);

      } else {
        LOGGER_LOG(LVL_error, "dbus methid called with wrong argents");
        dbus_message_unref(msg);
        continue;
      }
      *command_channel << boost::shared_ptr<command::SendUpdateReport>(new command::SendUpdateReport(update_report));
    }

    DBusMessage* reply = dbus_message_new_method_return(msg);
    dbus_connection_send(conn, reply, NULL);
    dbus_connection_flush(conn);

    dbus_message_unref(reply);
    dbus_message_unref(msg);
  }
}

data::OperationResult DbusGateway::getOperationResult(DBusMessageIter* iter) {
  DBusMessageIter subiter, dict_iter, variant_iter;
  char* string_param;
  int int_param;
  data::OperationResult result;
  int params = dbus_message_iter_get_element_count(iter);
  dbus_message_iter_recurse(iter, &subiter);
  if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(iter)) {
    while (params) {
      dbus_message_iter_recurse(&subiter, &dict_iter);
      dbus_message_iter_get_basic(&dict_iter, &string_param);
      dbus_message_iter_next(&dict_iter);
      dbus_message_iter_recurse(&dict_iter, &variant_iter);
      if (std::string(string_param) == "id") {
        dbus_message_iter_get_basic(&variant_iter, &string_param);
        result.id = string_param;
        dbus_message_iter_next(&subiter);
      } else if (std::string(string_param) == "result_code") {
        dbus_message_iter_get_basic(&variant_iter, &int_param);
        result.result_code = (data::UpdateResultCode)int_param;
        dbus_message_iter_next(&subiter);
      } else if (std::string(string_param) == "result_text") {
        dbus_message_iter_get_basic(&variant_iter, &string_param);
        result.result_text = string_param;
        dbus_message_iter_next(&subiter);
      }
      params--;
    }
  }
  return result;
}
<|endoftext|>


<commit_before><commit_msg>Added default colors to the color values used in the *_dialog() functions.<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file libuobject/uvar.cc

#include <libport/format.hh>

#include <libport/debug.hh>
#include <libport/escape.hh>
#include <libport/lexical-cast.hh>

#include <urbi/uabstractclient.hh>
#include <urbi/ublend-type.hh>
#include <urbi/uexternal.hh>
#include <urbi/umessage.hh>
#include <urbi/uobject.hh>
#include <urbi/usyncclient.hh>

#include <liburbi/compatibility.hh>

#include <libuobject/remote-ucontext-impl.hh>

namespace urbi
{
  namespace impl
  {

  GD_CATEGORY(LibUObject);

  //! UVar initialization
  void
  RemoteUVarImpl::initialize(UVar* owner)
  {
    owner_ = owner;
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    client_ = ctx->client_;
    std::string name = owner_->get_name();
    ctx->varmap()[name].push_back(owner_);
    URBI_SEND_PIPED_COMMAND_C((*client_), "if (!isdef(" << name << ")) var "
                            << name);
    URBI_SEND_PIPED_COMMAND_C
          ((*client_),
           libport::format("external var %s from dummy",
                           owner_->get_name()));
    ctx->dataSent = true;
  }

  bool RemoteUVarImpl::setBypass(bool enable)
  {
    return !enable;
  }

  //! UVar out value (read mode)
  ufloat&
  RemoteUVarImpl::out()
  {
    return const_cast<ufloat&>(get().val);
  }

  //! UVar in value (write mode)
  ufloat&
  RemoteUVarImpl::in()
  {
    return const_cast<ufloat&>(get().val);
  }

  void
  RemoteUVarImpl::setProp(UProperty p, const UValue& v)
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    URBI_SEND_PIPED_COMMAND_C((*client_), owner_->get_name() << "->"
                              << urbi::name(p) << " = " << v);
    ctx->dataSent = true;
  }

  void
  RemoteUVarImpl::keepSynchronized()
  {
    //FIXME: do something?
  }

  UValue
  RemoteUVarImpl::getProp(UProperty p)
  {
    UMessage* m = client_->syncGet("%s->%s", owner_->get_name().c_str(),
                                  urbi::name(p));
    aver(m->value);
    UValue res = *m->value;
    delete m;
    return res;
  }

  /*
    UBlendType
    UVar::blend()
    {
    echo("Properties not implemented in remote mode yet.\n");
    return UNORMAL;
    }
  */

  //! UVar destructor.
  void
  RemoteUVarImpl::clean()
  {
    RemoteUContextImpl* ctx = dynamic_cast<RemoteUContextImpl*>(owner_->ctx_);
    ctx->varmap().clean(*owner_);
  }

  static
  std::string
  rtp_id()
  {
    // Compute once in some thread implementations, each thread has different
    // PID.
    static std::string res =
      libport::format("URTP_%s_%s", getFilteredHostname(),
#ifdef __UCLIBC__
   "default"
#else
   getpid()
#endif
    );
    return res;
  }

  std::string
  RemoteUContextImpl::makeRTPLink(const std::string& key)
  {
    /* Setup RTP mode
    * We create two instances of the URTP UObject: one local to this
    * remote, and one plugged in the engine, and connect them together.
    */
    // Spawn a new local RTP instance
    std::string localRTP = rtp_id();
    RemoteUContextImpl::objects_type::iterator oi = objects.find(localRTP);
    if (oi == objects.end())
      return "";
    baseURBIStarter* bsa = oi->second->cloner;
    std::string linkName = localRTP + "_" + key;
    GD_SINFO_TRACE("Instanciating local RTP " << linkName);
    linkName[linkName.find_first_of(".")] = '_';
    bsa->instanciate(this, linkName);
    // Call init
    localCall(linkName, "init");

    // Spawn a remote RTP instance and bind it.
    // Also destroy it when this remote disconnects
    std::string rLinkName = linkName + "_l";
    *client_
      << "var " << rLinkName <<" = URTP.new|\n"
      << rLinkName << ".sourceContext = lobby.uid|\n"
      << "disown({var t = Tag.new | t:at(Lobby.onDisconnect?(lobby))\n"
      << "{\n"
      << "  wall(\" destroying lRTP...\")|\n"
      << "  try { " << rLinkName << ".destroy} catch {}|\n"
      << "  t.stop\n"
      << "}})|;\n";
    GD_SINFO_TRACE("fetching engine listen port...");
    UMessage* mport =
    client_->syncGet(rLinkName +".listen(\"0.0.0.0\", \"0\");");
    if (!mport || mport->type != MESSAGE_DATA
        || mport->value->type != DATA_DOUBLE)
    {
      GD_SWARN("Failed to get remote RTP port, disabling RTP");
      enableRTP = false;
      return "";
    }
    int port = int(mport->value->val);
    delete mport;
    GD_SINFO_TRACE("...ok: " << port);
    // Invoke the connect method on our RTP instance. Having a reference
    // to URTP symbols would be painful, so pass through our
    // UGenericCallback mechanism.
    localCall(linkName, "connect", client_->getRemoteHost(), port);
    UObject* ob = getUObject(linkName);
    rtpLinks[key]  = ob;
    // Monitor this RTP link.
    (*client_) << "detach('external'.monitorRTP(" << linkName << ","
               << rLinkName << ", closure() {'external'.failRTP}))|"
               << std::endl;
    return linkName;
  }

  void
  RemoteUVarImpl::set(const UValue& v)
  {
    std::string fullname = owner_->get_name();
    size_t pos = fullname.rfind(".");
    assert(pos != std::string::npos);
    std::string owner = fullname.substr(0, pos);
    std::string name = fullname.substr(pos + 1);
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    libport::utime_t time = libport::utime();
    bool rtp = false;
    if (v.type == DATA_BINARY)
    {
      std::string localRTP = rtp_id();
      if (ctx->enableRTP && getUObject(localRTP)
          && owner_->get_rtp() != UVar::RTP_NO)
      {
        GD_SINFO_TRACE("Trying RTP mode using " << localRTP);
        RemoteUContextImpl::RTPLinks::iterator i
          = ctx->rtpLinks.find(owner_->get_name());
        if (i == ctx->rtpLinks.end())
        {
          std::string linkName = ctx->makeRTPLink(owner_->get_name());
          if (linkName.empty())
            goto rtpfail;

          std::string rLinkName = linkName + "_l";
          (*ctx->client_)
           << rLinkName << ".receiveVar(\"" << owner_->get_name()
           <<"\")|";
          i = ctx->rtpLinks.find(owner_->get_name());
        }
        ctx->localCall(i->second->__name, "send", v);
        rtp = true;
      }
    rtpfail:
      if (!rtp)
      {
        client_->startPack();
        (*client_) << owner << ".getSlot(\"" << libport::escape(name) << "\").update_timed(";
        UBinary& b = *(v.binary);
        client_->sendBinary(b.common.data, b.common.size,
                            b.getMessage());
        *client_ << ", " << time << ")|";
        client_->endPack();
      }
    }
    else
    {
      if (ctx->enableRTP && owner_->get_rtp())
      {
        RemoteUContextImpl::RTPLinks::iterator i
          = ctx->rtpLinks.find("_shared_");
        if (i == ctx->rtpLinks.end())
        {
          std::string linkName = ctx->makeRTPLink("_shared_");
          if (linkName.empty())
            goto rtpfail2;
          i = ctx->rtpLinks.find("_shared_");
        }
        ctx->localCall(i->second->__name, "sendGrouped",
                         owner_->get_name(), v);
        rtp = true;
      }
    rtpfail2:
      if (!rtp)
      {
        client_->startPack();
        (*client_) << owner << ".getSlot(\"" << libport::escape(name) << "\").update_timed(";
        if (v.type == DATA_STRING)
          (*client_) << "\"" << libport::escape(*v.stringValue, '"') << "\"";
        else
          *client_ << v ;
        *client_ << ", " << time << ")|";
        client_->endPack();
      }
    }
    // Loopback notification
    ctx->assignMessage(owner_->get_name(), v, time);
    if (!rtp)
      ctx->dataSent = true;
  }

  const UValue& RemoteUVarImpl::get() const
  {
    return value_;
  };

  //! set own mode
  void
  RemoteUVarImpl::setOwned()
  {
    owner_->owned = true;
  }

  //! Get Uvalue type
  UDataType
  RemoteUVarImpl::type() const
  {
    return get().type;
  }

  void
  RemoteUVarImpl::request()
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    std::string name = owner_->get_name();
    //build a getvalue message  that will be parsed and returned by the server
    URBI_SEND_PIPED_COMMAND_C((*client_), externalModuleTag << "<<"
                            <<'[' << UEM_ASSIGNVALUE << ","
                            << '"' << name << '"' << ',' << name << ']');
    ctx->dataSent = true;
  }

  void
  RemoteUVarImpl::sync()
  {
    std::string tag(client_->fresh());
    std::string repeatChannel;
    if (client_->kernelMajor() < 2)
      repeatChannel = tag + " << ";
    static boost::format
      fmt("{\n"
          "  if (isdef (%s) && !(%s))\n"
          "  {\n"
          "    %s %s\n"
          "  }\n"
          "  else\n"
          "  {\n"
          "     %s 1/0\n"
          "  }\n"
          "};\n");
    std::string name = owner_->get_name();
    std::string cmd = str(fmt
                          % name
                          % compatibility::isvoid(name.c_str(),
                                                  client_->kernelMajor())
                          % repeatChannel
                          % name
                          % repeatChannel);
    UMessage* m = client_->syncGetTag("%s", tag.c_str(), 0, cmd.c_str());
    if (m->type == MESSAGE_DATA)
      value_ = *m->value;
  }

  time_t
  RemoteUVarImpl::timestamp() const
  {
    return timestamp_;
  }

  void
  RemoteUVarImpl::update(const UValue& v, time_t timestamp)
  {
    value_ = v;
    timestamp_ = timestamp;
  }

  void RemoteUVarImpl::unnotify()
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    std::string name = owner_->get_name();
    size_t p = name.find_first_of(".");
    if (p == name.npos)
      throw std::runtime_error("Invalid argument to unnotify: "+name);
    // Each UVar creation and each notifychange causes an 'external var'
    // message, so when the UVar dies, creation count is callbacks.size +1
    send(libport::format(
                         "UObject.unnotify(\"%s\", \"%s\", %s)|",
                         name.substr(0, p), name.substr(p+1, name.npos),
                         callbacks_.size()+1));
    foreach(RemoteUGenericCallbackImpl* c, callbacks_)
    {
      UTable& t =
      dynamic_cast<RemoteUContextImpl*>(c->owner_->ctx_)
        ->tableByName(c->owner_->type);
      UTable::callbacks_type& ct = t[c->owner_->name];
      UTable::callbacks_type::iterator i =
        std::find(ct.begin(), ct.end(), c->owner_);
      if (i != ct.end())
        ct.erase(i);
      owner_->ctx_->addCleanup(c->owner_);
      owner_->ctx_->addCleanup(c);
    }
    callbacks_.clear();
    ctx->dataSent = true;
  };
  void RemoteUVarImpl::useRTP(bool enable)
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    std::string name = owner_->get_name();
    size_t p = name.find_first_of(".");
    if (p == name.npos)
      throw std::runtime_error("Invalid argument to useRTP: "+name);
    send(name.substr(0, p) + ".getSlot(\"" + name.substr(p+1, name.npos)
         + "\").rtp = " + (enable?"true;":"false;"));
    ctx->dataSent = true;
  }
  }
} //namespace urbi
<commit_msg>uobject remote: Stop updating UVars on which unnotify was called.<commit_after>/*
 * Copyright (C) 2005-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file libuobject/uvar.cc

#include <libport/format.hh>

#include <libport/debug.hh>
#include <libport/escape.hh>
#include <libport/lexical-cast.hh>

#include <urbi/uabstractclient.hh>
#include <urbi/ublend-type.hh>
#include <urbi/uexternal.hh>
#include <urbi/umessage.hh>
#include <urbi/uobject.hh>
#include <urbi/usyncclient.hh>

#include <liburbi/compatibility.hh>

#include <libuobject/remote-ucontext-impl.hh>

namespace urbi
{
  namespace impl
  {

  GD_CATEGORY(LibUObject);

  //! UVar initialization
  void
  RemoteUVarImpl::initialize(UVar* owner)
  {
    owner_ = owner;
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    client_ = ctx->client_;
    std::string name = owner_->get_name();
    ctx->varmap()[name].push_back(owner_);
    URBI_SEND_PIPED_COMMAND_C((*client_), "if (!isdef(" << name << ")) var "
                            << name);
    URBI_SEND_PIPED_COMMAND_C
          ((*client_),
           libport::format("external var %s from dummy",
                           owner_->get_name()));
    ctx->dataSent = true;
  }

  bool RemoteUVarImpl::setBypass(bool enable)
  {
    return !enable;
  }

  //! UVar out value (read mode)
  ufloat&
  RemoteUVarImpl::out()
  {
    return const_cast<ufloat&>(get().val);
  }

  //! UVar in value (write mode)
  ufloat&
  RemoteUVarImpl::in()
  {
    return const_cast<ufloat&>(get().val);
  }

  void
  RemoteUVarImpl::setProp(UProperty p, const UValue& v)
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    URBI_SEND_PIPED_COMMAND_C((*client_), owner_->get_name() << "->"
                              << urbi::name(p) << " = " << v);
    ctx->dataSent = true;
  }

  void
  RemoteUVarImpl::keepSynchronized()
  {
    //FIXME: do something?
  }

  UValue
  RemoteUVarImpl::getProp(UProperty p)
  {
    UMessage* m = client_->syncGet("%s->%s", owner_->get_name().c_str(),
                                  urbi::name(p));
    aver(m->value);
    UValue res = *m->value;
    delete m;
    return res;
  }

  /*
    UBlendType
    UVar::blend()
    {
    echo("Properties not implemented in remote mode yet.\n");
    return UNORMAL;
    }
  */

  //! UVar destructor.
  void
  RemoteUVarImpl::clean()
  {
    RemoteUContextImpl* ctx = dynamic_cast<RemoteUContextImpl*>(owner_->ctx_);
    ctx->varmap().clean(*owner_);
  }

  static
  std::string
  rtp_id()
  {
    // Compute once in some thread implementations, each thread has different
    // PID.
    static std::string res =
      libport::format("URTP_%s_%s", getFilteredHostname(),
#ifdef __UCLIBC__
   "default"
#else
   getpid()
#endif
    );
    return res;
  }

  std::string
  RemoteUContextImpl::makeRTPLink(const std::string& key)
  {
    /* Setup RTP mode
    * We create two instances of the URTP UObject: one local to this
    * remote, and one plugged in the engine, and connect them together.
    */
    // Spawn a new local RTP instance
    std::string localRTP = rtp_id();
    RemoteUContextImpl::objects_type::iterator oi = objects.find(localRTP);
    if (oi == objects.end())
      return "";
    baseURBIStarter* bsa = oi->second->cloner;
    std::string linkName = localRTP + "_" + key;
    GD_SINFO_TRACE("Instanciating local RTP " << linkName);
    linkName[linkName.find_first_of(".")] = '_';
    bsa->instanciate(this, linkName);
    // Call init
    localCall(linkName, "init");

    // Spawn a remote RTP instance and bind it.
    // Also destroy it when this remote disconnects
    std::string rLinkName = linkName + "_l";
    *client_
      << "var " << rLinkName <<" = URTP.new|\n"
      << rLinkName << ".sourceContext = lobby.uid|\n"
      << "disown({var t = Tag.new | t:at(Lobby.onDisconnect?(lobby))\n"
      << "{\n"
      << "  wall(\" destroying lRTP...\")|\n"
      << "  try { " << rLinkName << ".destroy} catch {}|\n"
      << "  t.stop\n"
      << "}})|;\n";
    GD_SINFO_TRACE("fetching engine listen port...");
    UMessage* mport =
    client_->syncGet(rLinkName +".listen(\"0.0.0.0\", \"0\");");
    if (!mport || mport->type != MESSAGE_DATA
        || mport->value->type != DATA_DOUBLE)
    {
      GD_SWARN("Failed to get remote RTP port, disabling RTP");
      enableRTP = false;
      return "";
    }
    int port = int(mport->value->val);
    delete mport;
    GD_SINFO_TRACE("...ok: " << port);
    // Invoke the connect method on our RTP instance. Having a reference
    // to URTP symbols would be painful, so pass through our
    // UGenericCallback mechanism.
    localCall(linkName, "connect", client_->getRemoteHost(), port);
    UObject* ob = getUObject(linkName);
    rtpLinks[key]  = ob;
    // Monitor this RTP link.
    (*client_) << "detach('external'.monitorRTP(" << linkName << ","
               << rLinkName << ", closure() {'external'.failRTP}))|"
               << std::endl;
    return linkName;
  }

  void
  RemoteUVarImpl::set(const UValue& v)
  {
    std::string fullname = owner_->get_name();
    size_t pos = fullname.rfind(".");
    assert(pos != std::string::npos);
    std::string owner = fullname.substr(0, pos);
    std::string name = fullname.substr(pos + 1);
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    libport::utime_t time = libport::utime();
    bool rtp = false;
    if (v.type == DATA_BINARY)
    {
      std::string localRTP = rtp_id();
      if (ctx->enableRTP && getUObject(localRTP)
          && owner_->get_rtp() != UVar::RTP_NO)
      {
        GD_SINFO_TRACE("Trying RTP mode using " << localRTP);
        RemoteUContextImpl::RTPLinks::iterator i
          = ctx->rtpLinks.find(owner_->get_name());
        if (i == ctx->rtpLinks.end())
        {
          std::string linkName = ctx->makeRTPLink(owner_->get_name());
          if (linkName.empty())
            goto rtpfail;

          std::string rLinkName = linkName + "_l";
          (*ctx->client_)
           << rLinkName << ".receiveVar(\"" << owner_->get_name()
           <<"\")|";
          i = ctx->rtpLinks.find(owner_->get_name());
        }
        ctx->localCall(i->second->__name, "send", v);
        rtp = true;
      }
    rtpfail:
      if (!rtp)
      {
        client_->startPack();
        (*client_) << owner << ".getSlot(\"" << libport::escape(name) << "\").update_timed(";
        UBinary& b = *(v.binary);
        client_->sendBinary(b.common.data, b.common.size,
                            b.getMessage());
        *client_ << ", " << time << ")|";
        client_->endPack();
      }
    }
    else
    {
      if (ctx->enableRTP && owner_->get_rtp())
      {
        RemoteUContextImpl::RTPLinks::iterator i
          = ctx->rtpLinks.find("_shared_");
        if (i == ctx->rtpLinks.end())
        {
          std::string linkName = ctx->makeRTPLink("_shared_");
          if (linkName.empty())
            goto rtpfail2;
          i = ctx->rtpLinks.find("_shared_");
        }
        ctx->localCall(i->second->__name, "sendGrouped",
                         owner_->get_name(), v);
        rtp = true;
      }
    rtpfail2:
      if (!rtp)
      {
        client_->startPack();
        (*client_) << owner << ".getSlot(\"" << libport::escape(name) << "\").update_timed(";
        if (v.type == DATA_STRING)
          (*client_) << "\"" << libport::escape(*v.stringValue, '"') << "\"";
        else
          *client_ << v ;
        *client_ << ", " << time << ")|";
        client_->endPack();
      }
    }
    // Loopback notification
    ctx->assignMessage(owner_->get_name(), v, time);
    if (!rtp)
      ctx->dataSent = true;
  }

  const UValue& RemoteUVarImpl::get() const
  {
    return value_;
  };

  //! set own mode
  void
  RemoteUVarImpl::setOwned()
  {
    owner_->owned = true;
  }

  //! Get Uvalue type
  UDataType
  RemoteUVarImpl::type() const
  {
    return get().type;
  }

  void
  RemoteUVarImpl::request()
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    std::string name = owner_->get_name();
    //build a getvalue message  that will be parsed and returned by the server
    URBI_SEND_PIPED_COMMAND_C((*client_), externalModuleTag << "<<"
                            <<'[' << UEM_ASSIGNVALUE << ","
                            << '"' << name << '"' << ',' << name << ']');
    ctx->dataSent = true;
  }

  void
  RemoteUVarImpl::sync()
  {
    std::string tag(client_->fresh());
    std::string repeatChannel;
    if (client_->kernelMajor() < 2)
      repeatChannel = tag + " << ";
    static boost::format
      fmt("{\n"
          "  if (isdef (%s) && !(%s))\n"
          "  {\n"
          "    %s %s\n"
          "  }\n"
          "  else\n"
          "  {\n"
          "     %s 1/0\n"
          "  }\n"
          "};\n");
    std::string name = owner_->get_name();
    std::string cmd = str(fmt
                          % name
                          % compatibility::isvoid(name.c_str(),
                                                  client_->kernelMajor())
                          % repeatChannel
                          % name
                          % repeatChannel);
    UMessage* m = client_->syncGetTag("%s", tag.c_str(), 0, cmd.c_str());
    if (m->type == MESSAGE_DATA)
      value_ = *m->value;
  }

  time_t
  RemoteUVarImpl::timestamp() const
  {
    return timestamp_;
  }

  void
  RemoteUVarImpl::update(const UValue& v, time_t timestamp)
  {
    value_ = v;
    timestamp_ = timestamp;
  }

  void RemoteUVarImpl::unnotify()
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    std::string name = owner_->get_name();
    size_t p = name.find_first_of(".");
    if (p == name.npos)
      throw std::runtime_error("Invalid argument to unnotify: "+name);
    // Each UVar creation and each notifychange causes an 'external var'
    // message, so when the UVar dies, creation count is callbacks.size +1
    send(libport::format(
                         "UObject.unnotify(\"%s\", \"%s\", %s)|",
                         name.substr(0, p), name.substr(p+1, name.npos),
                         callbacks_.size()+1));
    foreach(RemoteUGenericCallbackImpl* c, callbacks_)
    {
      UTable& t =
      dynamic_cast<RemoteUContextImpl*>(c->owner_->ctx_)
        ->tableByName(c->owner_->type);
      UTable::callbacks_type& ct = t[c->owner_->name];
      UTable::callbacks_type::iterator i =
        std::find(ct.begin(), ct.end(), c->owner_);
      if (i != ct.end())
        ct.erase(i);
      owner_->ctx_->addCleanup(c->owner_);
      owner_->ctx_->addCleanup(c);
    }
    callbacks_.clear();
    ctx->dataSent = true;
    if (std::list<UVar*> *us = ctx->varmap().find0(name))
      us->remove(owner_);
  };
  void RemoteUVarImpl::useRTP(bool enable)
  {
    RemoteUContextImpl* ctx = static_cast<RemoteUContextImpl*>(owner_->ctx_);
    std::string name = owner_->get_name();
    size_t p = name.find_first_of(".");
    if (p == name.npos)
      throw std::runtime_error("Invalid argument to useRTP: "+name);
    send(name.substr(0, p) + ".getSlot(\"" + name.substr(p+1, name.npos)
         + "\").rtp = " + (enable?"true;":"false;"));
    ctx->dataSent = true;
  }
  }
} //namespace urbi
<|endoftext|>


<commit_before>/*

Copyright (c) 2009-2012, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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 OWNER 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 <ctime>
#include <string>
#include <cstdio>
#include <boost/limits.hpp>
#include <boost/version.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/time.hpp"

#ifndef _WIN32
#include <unistd.h>
#endif

namespace libtorrent
{
	namespace aux
	{
		// used to cache the current time
		// every 100 ms. This is cheaper
		// than a system call and can be
		// used where more accurate time
		// is not necessary
		ptime g_current_time;
	}

	TORRENT_EXPORT ptime const& time_now() { return aux::g_current_time; }

	char const* time_now_string()
	{
//		time_t t = std::time(0);
//		tm* timeinfo = std::localtime(&t);
//		static char str[200];
//		std::strftime(str, 200, "%b %d %X", timeinfo);
//		return str;

		static const ptime start = time_now_hires();
		static char ret[200];
		int t = total_milliseconds(time_now_hires() - start);
		int h = t / 1000 / 60 / 60;
		t -= h * 60 * 60 * 1000;
		int m = t / 1000 / 60;
		t -= m * 60 * 1000;
		int s = t / 1000;
		t -= s * 1000;
		int ms = t;
		snprintf(ret, sizeof(ret), "%02d:%02d:%02d.%03d", h, m, s, ms);
		return ret;
	}

	std::string log_time()
	{
		static const ptime start = time_now_hires();
		char ret[200];
		snprintf(ret, sizeof(ret), "%"PRId64, total_microseconds(time_now_hires() - start));
		return ret;
	}
}

#if defined TORRENT_USE_BOOST_DATE_TIME

#include <boost/date_time/microsec_time_clock.hpp>

namespace libtorrent
{
	ptime time_now_hires()
	{ return boost::date_time::microsec_clock<ptime>::universal_time(); }
	ptime min_time()
	{ return boost::posix_time::ptime(boost::posix_time::min_date_time); }
	ptime max_time()
	{ return boost::posix_time::ptime(boost::posix_time::max_date_time); }
	time_duration seconds(int s) { return boost::posix_time::seconds(s); }
	time_duration milliseconds(int s) { return boost::posix_time::milliseconds(s); }
	time_duration microsec(int s) { return boost::posix_time::microsec(s); }
	time_duration minutes(int s) { return boost::posix_time::minutes(s); }
	time_duration hours(int s) { return boost::posix_time::hours(s); }

	int total_seconds(time_duration td)
	{ return td.total_seconds(); }
	int total_milliseconds(time_duration td)
	{ return td.total_milliseconds(); }
	boost::int64_t total_microseconds(time_duration td)
	{ return td.total_microseconds(); }
}

#else // TORRENT_USE_BOOST_DATE_TIME

namespace libtorrent
{
	ptime min_time() { return ptime(0); }
	ptime max_time() { return ptime((std::numeric_limits<boost::uint64_t>::max)()); }
}

#if defined TORRENT_USE_ABSOLUTE_TIME

#include <mach/mach_time.h>
#include <boost/cstdint.hpp>
#include "libtorrent/assert.hpp"

// high precision timer for darwin intel and ppc

namespace libtorrent
{
	ptime time_now_hires()
	{
		static mach_timebase_info_data_t timebase_info = {0,0};
		if (timebase_info.denom == 0)
			mach_timebase_info(&timebase_info);
		boost::uint64_t at = mach_absolute_time();
		// make sure we don't overflow
		TORRENT_ASSERT((at >= at / 1000 * timebase_info.numer / timebase_info.denom)
			|| (at < 0 && at < at / 1000 * timebase_info.numer / timebase_info.denom));
		return ptime(at / 1000 * timebase_info.numer / timebase_info.denom);
	}
}
#elif defined TORRENT_USE_QUERY_PERFORMANCE_TIMER

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	namespace aux
	{
		boost::int64_t performance_counter_to_microseconds(boost::int64_t pc)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);

#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
			TORRENT_ASSERT((pc >= 0 && pc >= ret) || (pc < 0 && pc < ret));
#endif
			return (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
		}

		boost::int64_t microseconds_to_performance_counter(boost::int64_t ms)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);
#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
			TORRENT_ASSERT((ms >= 0 && ms <= ret)
				|| (ms < 0 && ms > ret));
#endif
			return (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
		}
	}

	ptime time_now_hires()
	{
		LARGE_INTEGER now;
		QueryPerformanceCounter(&now);
		return ptime(now.QuadPart);
	}
}

#elif defined TORRENT_USE_CLOCK_GETTIME

#include <time.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	ptime time_now_hires()
	{
		timespec ts;
		clock_gettime(CLOCK_MONOTONIC, &ts);
		return ptime(boost::uint64_t(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000);
	}
}

#elif defined TORRENT_USE_SYSTEM_TIME

#include <kernel/OS.h>

namespace libtorrent
{
	ptime time_now_hires()
	{ return ptime(system_time()); }
}

#endif // TORRENT_USE_SYSTEM_TIME

#endif // TORRENT_USE_BOOST_DATE_TIME

<commit_msg>fix time_duration rounding on windows<commit_after>/*

Copyright (c) 2009-2012, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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 OWNER 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 <ctime>
#include <string>
#include <cstdio>
#include <boost/limits.hpp>
#include <boost/version.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/time.hpp"

#ifndef _WIN32
#include <unistd.h>
#endif

namespace libtorrent
{
	namespace aux
	{
		// used to cache the current time
		// every 100 ms. This is cheaper
		// than a system call and can be
		// used where more accurate time
		// is not necessary
		ptime g_current_time;
	}

	TORRENT_EXPORT ptime const& time_now() { return aux::g_current_time; }

	char const* time_now_string()
	{
//		time_t t = std::time(0);
//		tm* timeinfo = std::localtime(&t);
//		static char str[200];
//		std::strftime(str, 200, "%b %d %X", timeinfo);
//		return str;

		static const ptime start = time_now_hires();
		static char ret[200];
		int t = total_milliseconds(time_now_hires() - start);
		int h = t / 1000 / 60 / 60;
		t -= h * 60 * 60 * 1000;
		int m = t / 1000 / 60;
		t -= m * 60 * 1000;
		int s = t / 1000;
		t -= s * 1000;
		int ms = t;
		snprintf(ret, sizeof(ret), "%02d:%02d:%02d.%03d", h, m, s, ms);
		return ret;
	}

	std::string log_time()
	{
		static const ptime start = time_now_hires();
		char ret[200];
		snprintf(ret, sizeof(ret), "%"PRId64, total_microseconds(time_now_hires() - start));
		return ret;
	}
}

#if defined TORRENT_USE_BOOST_DATE_TIME

#include <boost/date_time/microsec_time_clock.hpp>

namespace libtorrent
{
	ptime time_now_hires()
	{ return boost::date_time::microsec_clock<ptime>::universal_time(); }
	ptime min_time()
	{ return boost::posix_time::ptime(boost::posix_time::min_date_time); }
	ptime max_time()
	{ return boost::posix_time::ptime(boost::posix_time::max_date_time); }
	time_duration seconds(int s) { return boost::posix_time::seconds(s); }
	time_duration milliseconds(int s) { return boost::posix_time::milliseconds(s); }
	time_duration microsec(int s) { return boost::posix_time::microsec(s); }
	time_duration minutes(int s) { return boost::posix_time::minutes(s); }
	time_duration hours(int s) { return boost::posix_time::hours(s); }

	int total_seconds(time_duration td)
	{ return td.total_seconds(); }
	int total_milliseconds(time_duration td)
	{ return td.total_milliseconds(); }
	boost::int64_t total_microseconds(time_duration td)
	{ return td.total_microseconds(); }
}

#else // TORRENT_USE_BOOST_DATE_TIME

namespace libtorrent
{
	ptime min_time() { return ptime(0); }
	ptime max_time() { return ptime((std::numeric_limits<boost::uint64_t>::max)()); }
}

#if defined TORRENT_USE_ABSOLUTE_TIME

#include <mach/mach_time.h>
#include <boost/cstdint.hpp>
#include "libtorrent/assert.hpp"

// high precision timer for darwin intel and ppc

namespace libtorrent
{
	ptime time_now_hires()
	{
		static mach_timebase_info_data_t timebase_info = {0,0};
		if (timebase_info.denom == 0)
			mach_timebase_info(&timebase_info);
		boost::uint64_t at = mach_absolute_time();
		// make sure we don't overflow
		TORRENT_ASSERT((at >= at / 1000 * timebase_info.numer / timebase_info.denom)
			|| (at < 0 && at < at / 1000 * timebase_info.numer / timebase_info.denom));
		return ptime(at / 1000 * timebase_info.numer / timebase_info.denom);
	}
}
#elif defined TORRENT_USE_QUERY_PERFORMANCE_TIMER

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	namespace aux
	{
		boost::int64_t performance_counter_to_microseconds(boost::int64_t pc)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);

#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
			TORRENT_ASSERT((pc >= 0 && pc >= ret) || (pc < 0 && pc < ret));
#endif
			return ((pc * 1000 + performace_counter_frequency.QuadPart / 2) / performace_counter_frequency.QuadPart) * 1000;
		}

		boost::int64_t microseconds_to_performance_counter(boost::int64_t ms)
		{
			static LARGE_INTEGER performace_counter_frequency = {0,0};
			if (performace_counter_frequency.QuadPart == 0)
				QueryPerformanceFrequency(&performace_counter_frequency);
#ifdef TORRENT_DEBUG
			// make sure we don't overflow
			boost::int64_t ret = (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
			TORRENT_ASSERT((ms >= 0 && ms <= ret)
				|| (ms < 0 && ms > ret));
#endif
			return (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
		}
	}

	ptime time_now_hires()
	{
		LARGE_INTEGER now;
		QueryPerformanceCounter(&now);
		return ptime(now.QuadPart);
	}
}

#elif defined TORRENT_USE_CLOCK_GETTIME

#include <time.h>
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	ptime time_now_hires()
	{
		timespec ts;
		clock_gettime(CLOCK_MONOTONIC, &ts);
		return ptime(boost::uint64_t(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000);
	}
}

#elif defined TORRENT_USE_SYSTEM_TIME

#include <kernel/OS.h>

namespace libtorrent
{
	ptime time_now_hires()
	{ return ptime(system_time()); }
}

#endif // TORRENT_USE_SYSTEM_TIME

#endif // TORRENT_USE_BOOST_DATE_TIME

<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgProducer/GraphicsContextImplementation>
#include <osg/TextureRectangle>
#include <osg/TextureCubeMap>
#include <osg/Notify>

using namespace osgProducer;

namespace osgProducer
{
    struct MyWindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface
    {
        virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& /*screenIdentifier*/)
        {
            return Producer::RenderSurface::getNumberOfScreens();
        }

        virtual void getScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int& width, unsigned int& height)
        {
            osg::ref_ptr<Producer::RenderSurface> rs = new Producer::RenderSurface;
            rs->setHostName(screenIdentifier.hostName);
            rs->setDisplayNum(screenIdentifier.displayNum);
            rs->setScreenNum(screenIdentifier.screenNum);
            rs->getScreenSize(width, height);
        }

        virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
        {
            return new GraphicsContextImplementation(traits);
        }
    };

    struct RegisterWindowingSystemInterfaceProxy
    {
        RegisterWindowingSystemInterfaceProxy()
        {
            osg::GraphicsContext::setWindowingSystemInterface(new MyWindowingSystemInterface);
        }

        ~RegisterWindowingSystemInterfaceProxy()
        {
            osg::GraphicsContext::setWindowingSystemInterface(0);
        }
    };

    RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
};

GraphicsContextImplementation::GraphicsContextImplementation(Traits* traits)
{
    _traits = traits;

    _rs = new Producer::RenderSurface;
    _rs->setWindowName(traits->windowName);
    _rs->setWindowRectangle(traits->x, traits->y, traits->width, traits->height);
    _rs->useBorder(traits->windowDecoration);
    _rs->setDisplayNum(traits->displayNum);
    _rs->setScreenNum(traits->screenNum);

    // set the visual chooser
    Producer::VisualChooser* rs_vc = _rs->getVisualChooser();
    if (!rs_vc)
    {
        rs_vc = new Producer::VisualChooser;
        _rs->setVisualChooser(rs_vc);
    }

    rs_vc->setRedSize(_traits->red);
    rs_vc->setGreenSize(_traits->green);
    rs_vc->setBlueSize(_traits->blue);
    rs_vc->setAlphaSize(_traits->alpha);

    rs_vc->setDepthSize(_traits->depth);
    rs_vc->setStencilSize(_traits->stencil);

    if (_traits->doubleBuffer) rs_vc->useDoubleBuffer();

    rs_vc->addAttribute( Producer::VisualChooser::RGBA );

    // Always use UseGL
    rs_vc->addAttribute( Producer::VisualChooser::UseGL );

    if (traits->pbuffer)
    {
        _rs->setDrawableType(Producer::RenderSurface::DrawableType_PBuffer);

        if (traits->target)
        {

            _rs->setRenderToTextureOptions(traits->mipMapGeneration ? Producer::RenderSurface::RequestSpaceForMipMaps :
                                                                       Producer::RenderSurface::RenderToTextureOptions_Default);
            _rs->setRenderToTextureMipMapLevel(traits->level);
            _rs->setRenderToTextureMode(traits->alpha>0 ? Producer::RenderSurface::RenderToRGBATexture :
                                                           Producer::RenderSurface::RenderToRGBTexture);

            switch(traits->target)
            {
                case(GL_TEXTURE_1D) :
                    _rs->setRenderToTextureTarget(Producer::RenderSurface::Texture1D);
                    break;
                case(GL_TEXTURE_2D) :
                    _rs->setRenderToTextureTarget(Producer::RenderSurface::Texture2D);
                    break;
                case(GL_TEXTURE_3D) :
                    osg::notify(osg::NOTICE)<<"PBuffer render to Texture3D not supported."<<std::endl;
                    // not supported.
                    // _rs->setRenderToTextureTarget(Producer::RenderSurface::Texture3D);
                    break;
                case(GL_TEXTURE_RECTANGLE) :
                    osg::notify(osg::NOTICE)<<"PBuffer render to TextureRectangle not supported."<<std::endl;
                    // not supported.
                    // _rs->setRenderToTextureTarget(Producer::RenderSurface::TextureRectangle);
                    break;
                case(GL_TEXTURE_CUBE_MAP_POSITIVE_X) :
                case(GL_TEXTURE_CUBE_MAP_NEGATIVE_X) :
                case(GL_TEXTURE_CUBE_MAP_POSITIVE_Y) :
                case(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) :
                case(GL_TEXTURE_CUBE_MAP_POSITIVE_Z) :
                case(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) :
                    _rs->setRenderToTextureTarget(Producer::RenderSurface::TextureCUBE);
                    _rs->setRenderToTextureFace( Producer::RenderSurface::CubeMapFace(traits->target - GL_TEXTURE_CUBE_MAP_POSITIVE_X));
                    break;
            }

        }

    }

    GraphicsContextImplementation* sharedContext = dynamic_cast<GraphicsContextImplementation*>(traits->sharedContext);

    if (sharedContext)
    {
        // different graphics context so we have our own state.
        setState(new osg::State);

        if (sharedContext->getState())
        {
            getState()->setContextID( sharedContext->getState()->getContextID() );
            incrementContextIDUsageCount( sharedContext->getState()->getContextID() );
        }
        else
        {
            getState()->setContextID( osg::GraphicsContext::createNewContextID() );
        }

        // but we share texture objects etc. so we also share the same contextID
        //_rs->realize( 0, sharedContext->_rs->getGLContext() );

    }
    else
    {

        // need to do something here....
        setState( new osg::State );
        getState()->setContextID( osg::GraphicsContext::createNewContextID() );

        //_rs->realize();
    }

    // _rs->useConfigEventThread(false);

    _closeOnDestruction = true;
}

GraphicsContextImplementation::GraphicsContextImplementation(Producer::RenderSurface* rs)
{
    _rs = rs;
    _closeOnDestruction = false;

    _traits = new osg::GraphicsContext::Traits;
    _traits->windowName = _rs->getWindowName();
    _traits->displayNum = _rs->getDisplayNum();
    _traits->screenNum = _rs->getScreenNum();
}

GraphicsContextImplementation::~GraphicsContextImplementation()
{
    if (_closeOnDestruction) close();
}

bool GraphicsContextImplementation::realizeImplementation()
{
    if (_rs.valid())
    {
        GraphicsContextImplementation* sharedContext = dynamic_cast<GraphicsContextImplementation*>(_traits->sharedContext);

        if (sharedContext)
        {
            _rs->realize( 0, sharedContext->_rs->getGLContext() );
        }
        else
        {
            osg::notify(osg::NOTICE)<<"GraphicsContextImplementation::realize"<<std::endl;

            _rs->realize();
        }
        return _rs->isRealized();
    }
    else
    {
        return false;
    }
}

bool GraphicsContextImplementation::makeCurrentImplementation()
{
    if (!_rs)
    {
        osg::notify(osg::NOTICE)<<"Error: GraphicsContextImplementation::makeCurrentImplementation() no RenderSurface."<<std::endl;
        return false;
    }

    if (!isRealized())
    {
        osg::notify(osg::NOTICE)<<"Error: GraphicsContextImplementation::makeCurrentImplementation() not Realized."<<std::endl;
        return false;
    }

//    osg::notify(osg::INFO)<<"GraphicsContextImplementation::makeCurrentImplementation()"<<std::endl;

    _rs->setReadDrawable( 0 );

    // comment out right now, as Producer's setReadDrawable() is doing a call for us.
    // _rs->makeCurrent();

    return true;
}

bool GraphicsContextImplementation::makeContextCurrentImplementation(osg::GraphicsContext* readContext)
{
    if (!_rs) return false;

    GraphicsContextImplementation* readContextImplemention = dynamic_cast<GraphicsContextImplementation*>(readContext);

    if (readContextImplemention)
    {
        _rs->setReadDrawable( readContextImplemention->getRenderSurface() );
    }
    else
    {
        _rs->setReadDrawable( 0 );
    }

    // comment out right now, as Producer's setReadDrawable() is doing a call for us.
    // _rs->makeCurrent();

    return true;
}

void GraphicsContextImplementation::closeImplementation()
{
    if (!_rs) return;

    // close render surface by deleting it
    _rs = 0;
}

void GraphicsContextImplementation::bindPBufferToTextureImplementation(GLenum buffer)
{
    if (!_rs) return;

    Producer::RenderSurface::BufferType bufferType = Producer::RenderSurface::FrontBuffer;
    switch(buffer)
    {
        case(GL_BACK): bufferType = Producer::RenderSurface::BackBuffer; break;
        case(GL_FRONT): bufferType = Producer::RenderSurface::FrontBuffer; break;
        default: bufferType = Producer::RenderSurface::FrontBuffer; break;
    }

    _rs->bindPBufferToTexture(bufferType);
}

void GraphicsContextImplementation::swapBuffersImplementation()
{
    _rs->swapBuffers();
}
<commit_msg>Added releaseContextImplementation method<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgProducer/GraphicsContextImplementation>
#include <osg/TextureRectangle>
#include <osg/TextureCubeMap>
#include <osg/Notify>

using namespace osgProducer;

namespace osgProducer
{
    struct MyWindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface
    {
        virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& /*screenIdentifier*/)
        {
            return Producer::RenderSurface::getNumberOfScreens();
        }

        virtual void getScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int& width, unsigned int& height)
        {
            osg::ref_ptr<Producer::RenderSurface> rs = new Producer::RenderSurface;
            rs->setHostName(screenIdentifier.hostName);
            rs->setDisplayNum(screenIdentifier.displayNum);
            rs->setScreenNum(screenIdentifier.screenNum);
            rs->getScreenSize(width, height);
        }

        virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
        {
            return new GraphicsContextImplementation(traits);
        }
    };

    struct RegisterWindowingSystemInterfaceProxy
    {
        RegisterWindowingSystemInterfaceProxy()
        {
            osg::GraphicsContext::setWindowingSystemInterface(new MyWindowingSystemInterface);
        }

        ~RegisterWindowingSystemInterfaceProxy()
        {
            osg::GraphicsContext::setWindowingSystemInterface(0);
        }
    };

    RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
};

GraphicsContextImplementation::GraphicsContextImplementation(Traits* traits)
{
    _traits = traits;

    _rs = new Producer::RenderSurface;
    _rs->setWindowName(traits->windowName);
    _rs->setWindowRectangle(traits->x, traits->y, traits->width, traits->height);
    _rs->useBorder(traits->windowDecoration);
    _rs->setDisplayNum(traits->displayNum);
    _rs->setScreenNum(traits->screenNum);

    // set the visual chooser
    Producer::VisualChooser* rs_vc = _rs->getVisualChooser();
    if (!rs_vc)
    {
        rs_vc = new Producer::VisualChooser;
        _rs->setVisualChooser(rs_vc);
    }

    rs_vc->setRedSize(_traits->red);
    rs_vc->setGreenSize(_traits->green);
    rs_vc->setBlueSize(_traits->blue);
    rs_vc->setAlphaSize(_traits->alpha);

    rs_vc->setDepthSize(_traits->depth);
    rs_vc->setStencilSize(_traits->stencil);

    if (_traits->doubleBuffer) rs_vc->useDoubleBuffer();

    rs_vc->addAttribute( Producer::VisualChooser::RGBA );

    // Always use UseGL
    rs_vc->addAttribute( Producer::VisualChooser::UseGL );

    if (traits->pbuffer)
    {
        _rs->setDrawableType(Producer::RenderSurface::DrawableType_PBuffer);

        if (traits->target)
        {

            _rs->setRenderToTextureOptions(traits->mipMapGeneration ? Producer::RenderSurface::RequestSpaceForMipMaps :
                                                                       Producer::RenderSurface::RenderToTextureOptions_Default);
            _rs->setRenderToTextureMipMapLevel(traits->level);
            _rs->setRenderToTextureMode(traits->alpha>0 ? Producer::RenderSurface::RenderToRGBATexture :
                                                           Producer::RenderSurface::RenderToRGBTexture);

            switch(traits->target)
            {
                case(GL_TEXTURE_1D) :
                    _rs->setRenderToTextureTarget(Producer::RenderSurface::Texture1D);
                    break;
                case(GL_TEXTURE_2D) :
                    _rs->setRenderToTextureTarget(Producer::RenderSurface::Texture2D);
                    break;
                case(GL_TEXTURE_3D) :
                    osg::notify(osg::NOTICE)<<"PBuffer render to Texture3D not supported."<<std::endl;
                    // not supported.
                    // _rs->setRenderToTextureTarget(Producer::RenderSurface::Texture3D);
                    break;
                case(GL_TEXTURE_RECTANGLE) :
                    osg::notify(osg::NOTICE)<<"PBuffer render to TextureRectangle not supported."<<std::endl;
                    // not supported.
                    // _rs->setRenderToTextureTarget(Producer::RenderSurface::TextureRectangle);
                    break;
                case(GL_TEXTURE_CUBE_MAP_POSITIVE_X) :
                case(GL_TEXTURE_CUBE_MAP_NEGATIVE_X) :
                case(GL_TEXTURE_CUBE_MAP_POSITIVE_Y) :
                case(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) :
                case(GL_TEXTURE_CUBE_MAP_POSITIVE_Z) :
                case(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) :
                    _rs->setRenderToTextureTarget(Producer::RenderSurface::TextureCUBE);
                    _rs->setRenderToTextureFace( Producer::RenderSurface::CubeMapFace(traits->target - GL_TEXTURE_CUBE_MAP_POSITIVE_X));
                    break;
            }

        }

    }

    GraphicsContextImplementation* sharedContext = dynamic_cast<GraphicsContextImplementation*>(traits->sharedContext);

    if (sharedContext)
    {
        // different graphics context so we have our own state.
        setState(new osg::State);

        if (sharedContext->getState())
        {
            getState()->setContextID( sharedContext->getState()->getContextID() );
            incrementContextIDUsageCount( sharedContext->getState()->getContextID() );
        }
        else
        {
            getState()->setContextID( osg::GraphicsContext::createNewContextID() );
        }

        // but we share texture objects etc. so we also share the same contextID
        //_rs->realize( 0, sharedContext->_rs->getGLContext() );

    }
    else
    {

        // need to do something here....
        setState( new osg::State );
        getState()->setContextID( osg::GraphicsContext::createNewContextID() );

        //_rs->realize();
    }

    // _rs->useConfigEventThread(false);

    _closeOnDestruction = true;
}

GraphicsContextImplementation::GraphicsContextImplementation(Producer::RenderSurface* rs)
{
    _rs = rs;
    _closeOnDestruction = false;

    _traits = new osg::GraphicsContext::Traits;
    _traits->windowName = _rs->getWindowName();
    _traits->displayNum = _rs->getDisplayNum();
    _traits->screenNum = _rs->getScreenNum();
}

GraphicsContextImplementation::~GraphicsContextImplementation()
{
    if (_closeOnDestruction) close();
}

bool GraphicsContextImplementation::realizeImplementation()
{
    if (_rs.valid())
    {
        GraphicsContextImplementation* sharedContext = dynamic_cast<GraphicsContextImplementation*>(_traits->sharedContext);

        if (sharedContext)
        {
            _rs->realize( 0, sharedContext->_rs->getGLContext() );
        }
        else
        {
            osg::notify(osg::NOTICE)<<"GraphicsContextImplementation::realize"<<std::endl;

            _rs->realize();
        }
        return _rs->isRealized();
    }
    else
    {
        return false;
    }
}

bool GraphicsContextImplementation::makeCurrentImplementation()
{
    if (!_rs)
    {
        osg::notify(osg::NOTICE)<<"Error: GraphicsContextImplementation::makeCurrentImplementation() no RenderSurface."<<std::endl;
        return false;
    }

    if (!isRealized())
    {
        osg::notify(osg::NOTICE)<<"Error: GraphicsContextImplementation::makeCurrentImplementation() not Realized."<<std::endl;
        return false;
    }

//    osg::notify(osg::INFO)<<"GraphicsContextImplementation::makeCurrentImplementation()"<<std::endl;

    _rs->setReadDrawable( 0 );

    // comment out right now, as Producer's setReadDrawable() is doing a call for us.
    // _rs->makeCurrent();

    return true;
}

bool GraphicsContextImplementation::makeContextCurrentImplementation(osg::GraphicsContext* readContext)
{
    if (!_rs) return false;

    GraphicsContextImplementation* readContextImplemention = dynamic_cast<GraphicsContextImplementation*>(readContext);

    if (readContextImplemention)
    {
        _rs->setReadDrawable( readContextImplemention->getRenderSurface() );
    }
    else
    {
        _rs->setReadDrawable( 0 );
    }

    // comment out right now, as Producer's setReadDrawable() is doing a call for us.
    // _rs->makeCurrent();

    return true;
}

bool GraphicsContextImplementation::makeCurrentImplementation()
{
    osg::notify(osg::NOTICE)<<"GraphicsContextImplementation::makeCurrentImplementation(): not implemented - release not supported under Producer."<<std::endl;
    return false;
}

void GraphicsContextImplementation::closeImplementation()
{
    if (!_rs) return;

    // close render surface by deleting it
    _rs = 0;
}

void GraphicsContextImplementation::bindPBufferToTextureImplementation(GLenum buffer)
{
    if (!_rs) return;

    Producer::RenderSurface::BufferType bufferType = Producer::RenderSurface::FrontBuffer;
    switch(buffer)
    {
        case(GL_BACK): bufferType = Producer::RenderSurface::BackBuffer; break;
        case(GL_FRONT): bufferType = Producer::RenderSurface::FrontBuffer; break;
        default: bufferType = Producer::RenderSurface::FrontBuffer; break;
    }

    _rs->bindPBufferToTexture(bufferType);
}

void GraphicsContextImplementation::swapBuffersImplementation()
{
    _rs->swapBuffers();
}
<|endoftext|>


<commit_before>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Daemon Source Code 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

#include "server.h"
#include "framework/CvarSystem.h"

/*
===============================================================================

OPERATOR CONSOLE ONLY COMMANDS

These commands can only be entered from stdin or by a remote operator datagram
===============================================================================
*/

class MapCmd: public Cmd::StaticCmd {
    public:
        MapCmd(Str::StringRef name, Str::StringRef description, bool cheat):
            Cmd::StaticCmd(name, Cmd::SYSTEM, description), cheat(cheat) {
        }

        void Run(const Cmd::Args& args) const override {
            if (args.Argc() < 2) {
                PrintUsage(args, "<mapname> (layoutname)", "loads a new map");
                return;
            }

            const std::string& mapName = args.Argv(1);

            //Make sure the map exists to avoid typos that would kill the game
            FS::GetAvailableMaps();
            const auto loadedPakInfo = FS::PakPath::LocateFile(Str::Format("maps/%s.bsp", mapName));
            if (!loadedPakInfo) {
                Print("Can't find map %s", mapName);
                return;
            }

            //Gets the layout list from the command but do not override if there is nothing
            std::string layouts = args.ConcatArgs(2);
            if (not layouts.empty()) {
                Cvar::SetValue("g_layouts", layouts);
            }

            Cvar::SetValueForce("sv_cheats", cheat ? "1" : "0");
            SV_SpawnServer(loadedPakInfo->name, mapName);
        }

        Cmd::CompletionResult Complete(int argNum, const Cmd::Args& args, Str::StringRef prefix) const override {
            if (argNum == 1) {
                Cmd::CompletionResult out;
                for (auto& map: FS::GetAvailableMaps()) {
                    if (Str::IsPrefix(prefix, map))
                        out.push_back({map, ""});
                }
                return out;
            } else if (argNum > 1) {
                return FS::HomePath::CompleteFilename(prefix, "game/layouts/" + args.Argv(1), ".dat", false, true);
            }

            return {};
        }

    private:
        bool cheat;
};
static MapCmd MapCmdRegistration("map", "starts a new map", false);
static MapCmd DevmapCmdRegistration("devmap", "starts a new map with cheats enabled", true);

void MSG_PrioritiseEntitystateFields();
void MSG_PrioritisePlayerStateFields();

static void SV_FieldInfo_f()
{
	MSG_PrioritiseEntitystateFields();
	MSG_PrioritisePlayerStateFields();
}

/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f()
{
	int         i;
	client_t    *client;
	bool    denied;
	char        reason[ MAX_STRING_CHARS ];
	bool    isBot;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId )
	{
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified )
	{
		char mapname[ MAX_QPATH ];
		char pakname[ MAX_OSPATH ];

		Log::Notice( "sv_maxclients variable change — restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );
		Q_strncpyz( pakname, Cvar_VariableString( "pakname" ), sizeof( pakname ) );

		SV_SpawnServer(pakname, mapname);
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// reset all the VM data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = serverState_t::SS_LOADING;
	sv.restarting = true;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0; i < GAME_INIT_FRAMES; i++ )
	{
		gvm.GameRunFrame( sv.time );
		svs.time += FRAMETIME;
		sv.time += FRAMETIME;
	}

	// create a baseline for more efficient communications
	// Gordon: meh, this won't work here as the client doesn't know it has happened
//  SV_CreateBaseline ();

	sv.state = serverState_t::SS_GAME;
	sv.restarting = false;

	// connect and begin all the clients
	for ( i = 0; i < sv_maxclients->integer; i++ )
	{
		client = &svs.clients[ i ];

		// send the new gamestate to all connected clients
		if ( client->state < clientState_t::CS_CONNECTED )
		{
			continue;
		}

		isBot = SV_IsBot(client);

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = gvm.GameClientConnect( reason, sizeof( reason ), i, false, isBot );

		if ( denied )
		{
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, reason );

			if ( !isBot )
			{
				Log::Notice( "SV_MapRestart_f: dropped client %i: denied!\n", i );
			}

			continue;
		}

		client->state = clientState_t::CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	gvm.GameRunFrame( sv.time );
	svs.time += FRAMETIME;
	sv.time += FRAMETIME;
}

class StatusCmd: public Cmd::StaticCmd
{
public:
	StatusCmd():
		StaticCmd("status", Cmd::SYSTEM, "Shows a table with server and player information")
	{}

	void Run(const Cmd::Args&) const override
	{
		// make sure server is running
		if ( !com_sv_running->integer )
		{
			Log::Notice( "Server is not running.\n" );
			return;
		}

		float cpu = ( svs.stats.latched_active + svs.stats.latched_idle );

		if ( cpu )
		{
			cpu = 100 * svs.stats.latched_active / cpu;
		}

		auto players = std::count_if(
			svs.clients,
			svs.clients+sv_maxclients->integer,
			[](const client_t& cl) {
				return cl.state != clientState_t::CS_FREE;
			}
		);

		std::string time_string;
		auto seconds = svs.time / 1000 % 60;
		auto minutes = svs.time / 1000 / 60 % 60;
		if ( auto hours = svs.time / 1000 / 60 / 60 / 60 )
		{
			time_string = Str::Format("%02d:", hours);
		}
		time_string += Str::Format("%02d:%02d", minutes, seconds);

		Print(
			"(begin server status)\n"
			"hostname: %s\n"
			"version:  %s\n"
			"protocol: %d\n"
			"cpu:      %.0f%%\n"
			"time:     %s\n"
			"map:      %s\n"
			"players:  %d / %d\n"
			"num score connection address                port   name\n"
			"--- ----- ---------- ---------------------- ------ ----",
			sv_hostname->string,
			Q3_VERSION " on " Q3_ENGINE,
			PROTOCOL_VERSION,
			cpu,
			time_string,
			sv_mapname->string,
			players,
			sv_maxclients->integer
		);

		for ( int i = 0; i < sv_maxclients->integer; i++ )
		{
			const client_t& cl = svs.clients[i];
			if ( cl.state == clientState_t::CS_FREE )
			{
				continue;
			}

			std::string connection;

			if ( cl.state == clientState_t::CS_CONNECTED )
			{
				connection = "CONNECTED";
			}
			else if ( cl.state == clientState_t::CS_ZOMBIE )
			{
				connection = "ZOMBIE";
			}
			else
			{
				connection = std::to_string(cl.ping);
				if ( connection.size() > 10 )
				{
					connection = "ERROR";
				}
			}
			OpaquePlayerState* ps = SV_GameClientNum( i );

			const char *address = NET_AdrToString( cl.netchan.remoteAddress );

			Print(
				"%3i %5i %10s %-22s %-6i %s",
				i,
				ps->persistant[ PERS_SCORE ],
				connection,
				address,
				cl.netchan.qport,
				cl.name
			);
		}

		Print( "(end server status)" );
	}
};
static StatusCmd StatusCmdRegistration;

/*
==================
SV_Heartbeat_f

Also called by SV_DropClient, SV_DirectConnect, and SV_SpawnServer
==================
*/
void SV_Heartbeat_f()
{
	svs.nextHeartbeatTime = -9999999;
}

/*
===========
SV_Serverinfo_f

Examine the serverinfo string
===========
*/
static void SV_Serverinfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "Server info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SERVERINFO, false ) );
}

/*
===========
SV_Systeminfo_f

Examine the systeminfo string
===========
*/
static void SV_Systeminfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "System info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SYSTEMINFO, false ) );
}

class ListMapsCmd: public Cmd::StaticCmd
{
public:
	ListMapsCmd():
		StaticCmd("listmaps", Cmd::SYSTEM, "Lists all maps available to the server")
	{}

	void Run(const Cmd::Args&) const override
	{
		auto maps = FS::GetAvailableMaps();

		Print("Listing %d maps:", maps.size());

		for ( const auto& map: maps )
		{
			Print(map.c_str());
		}
	}
};

#if BUILD_SERVER
static ListMapsCmd ListMapsCmdRegistration;
#endif

/*
==================
SV_AddOperatorCommands
==================
*/
void SV_AddOperatorCommands()
{
	if ( com_sv_running->integer )
	{
		// These commands should only be available while the server is running.
		Cmd_AddCommand( "fieldinfo",   SV_FieldInfo_f );
		Cmd_AddCommand( "heartbeat",   SV_Heartbeat_f );
		Cmd_AddCommand( "map_restart", SV_MapRestart_f );
		Cmd_AddCommand( "serverinfo",  SV_Serverinfo_f );
		Cmd_AddCommand( "systeminfo",  SV_Systeminfo_f );
	}
}

/*
==================
SV_RemoveOperatorCommands
==================
*/
void SV_RemoveOperatorCommands()
{
	Cmd_RemoveCommand( "fieldinfo" );
	Cmd_RemoveCommand( "heartbeat" );
	Cmd_RemoveCommand( "map_restart" );
	Cmd_RemoveCommand( "serverinfo" );
	Cmd_RemoveCommand( "status" );
	Cmd_RemoveCommand( "systeminfo" );
}
<commit_msg>[server] Do not truncate cpu stats from double to float<commit_after>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Daemon Source Code 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

#include "server.h"
#include "framework/CvarSystem.h"

/*
===============================================================================

OPERATOR CONSOLE ONLY COMMANDS

These commands can only be entered from stdin or by a remote operator datagram
===============================================================================
*/

class MapCmd: public Cmd::StaticCmd {
    public:
        MapCmd(Str::StringRef name, Str::StringRef description, bool cheat):
            Cmd::StaticCmd(name, Cmd::SYSTEM, description), cheat(cheat) {
        }

        void Run(const Cmd::Args& args) const override {
            if (args.Argc() < 2) {
                PrintUsage(args, "<mapname> (layoutname)", "loads a new map");
                return;
            }

            const std::string& mapName = args.Argv(1);

            //Make sure the map exists to avoid typos that would kill the game
            FS::GetAvailableMaps();
            const auto loadedPakInfo = FS::PakPath::LocateFile(Str::Format("maps/%s.bsp", mapName));
            if (!loadedPakInfo) {
                Print("Can't find map %s", mapName);
                return;
            }

            //Gets the layout list from the command but do not override if there is nothing
            std::string layouts = args.ConcatArgs(2);
            if (not layouts.empty()) {
                Cvar::SetValue("g_layouts", layouts);
            }

            Cvar::SetValueForce("sv_cheats", cheat ? "1" : "0");
            SV_SpawnServer(loadedPakInfo->name, mapName);
        }

        Cmd::CompletionResult Complete(int argNum, const Cmd::Args& args, Str::StringRef prefix) const override {
            if (argNum == 1) {
                Cmd::CompletionResult out;
                for (auto& map: FS::GetAvailableMaps()) {
                    if (Str::IsPrefix(prefix, map))
                        out.push_back({map, ""});
                }
                return out;
            } else if (argNum > 1) {
                return FS::HomePath::CompleteFilename(prefix, "game/layouts/" + args.Argv(1), ".dat", false, true);
            }

            return {};
        }

    private:
        bool cheat;
};
static MapCmd MapCmdRegistration("map", "starts a new map", false);
static MapCmd DevmapCmdRegistration("devmap", "starts a new map with cheats enabled", true);

void MSG_PrioritiseEntitystateFields();
void MSG_PrioritisePlayerStateFields();

static void SV_FieldInfo_f()
{
	MSG_PrioritiseEntitystateFields();
	MSG_PrioritisePlayerStateFields();
}

/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f()
{
	int         i;
	client_t    *client;
	bool    denied;
	char        reason[ MAX_STRING_CHARS ];
	bool    isBot;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId )
	{
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified )
	{
		char mapname[ MAX_QPATH ];
		char pakname[ MAX_OSPATH ];

		Log::Notice( "sv_maxclients variable change — restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );
		Q_strncpyz( pakname, Cvar_VariableString( "pakname" ), sizeof( pakname ) );

		SV_SpawnServer(pakname, mapname);
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// reset all the VM data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = serverState_t::SS_LOADING;
	sv.restarting = true;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0; i < GAME_INIT_FRAMES; i++ )
	{
		gvm.GameRunFrame( sv.time );
		svs.time += FRAMETIME;
		sv.time += FRAMETIME;
	}

	// create a baseline for more efficient communications
	// Gordon: meh, this won't work here as the client doesn't know it has happened
//  SV_CreateBaseline ();

	sv.state = serverState_t::SS_GAME;
	sv.restarting = false;

	// connect and begin all the clients
	for ( i = 0; i < sv_maxclients->integer; i++ )
	{
		client = &svs.clients[ i ];

		// send the new gamestate to all connected clients
		if ( client->state < clientState_t::CS_CONNECTED )
		{
			continue;
		}

		isBot = SV_IsBot(client);

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = gvm.GameClientConnect( reason, sizeof( reason ), i, false, isBot );

		if ( denied )
		{
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, reason );

			if ( !isBot )
			{
				Log::Notice( "SV_MapRestart_f: dropped client %i: denied!\n", i );
			}

			continue;
		}

		client->state = clientState_t::CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	gvm.GameRunFrame( sv.time );
	svs.time += FRAMETIME;
	sv.time += FRAMETIME;
}

class StatusCmd: public Cmd::StaticCmd
{
public:
	StatusCmd():
		StaticCmd("status", Cmd::SYSTEM, "Shows a table with server and player information")
	{}

	void Run(const Cmd::Args&) const override
	{
		// make sure server is running
		if ( !com_sv_running->integer )
		{
			Log::Notice( "Server is not running.\n" );
			return;
		}

		double cpu = ( svs.stats.latched_active + svs.stats.latched_idle );

		if ( cpu )
		{
			cpu = 100 * svs.stats.latched_active / cpu;
		}

		auto players = std::count_if(
			svs.clients,
			svs.clients+sv_maxclients->integer,
			[](const client_t& cl) {
				return cl.state != clientState_t::CS_FREE;
			}
		);

		std::string time_string;
		auto seconds = svs.time / 1000 % 60;
		auto minutes = svs.time / 1000 / 60 % 60;
		if ( auto hours = svs.time / 1000 / 60 / 60 / 60 )
		{
			time_string = Str::Format("%02d:", hours);
		}
		time_string += Str::Format("%02d:%02d", minutes, seconds);

		Print(
			"(begin server status)\n"
			"hostname: %s\n"
			"version:  %s\n"
			"protocol: %d\n"
			"cpu:      %.0f%%\n"
			"time:     %s\n"
			"map:      %s\n"
			"players:  %d / %d\n"
			"num score connection address                port   name\n"
			"--- ----- ---------- ---------------------- ------ ----",
			sv_hostname->string,
			Q3_VERSION " on " Q3_ENGINE,
			PROTOCOL_VERSION,
			cpu,
			time_string,
			sv_mapname->string,
			players,
			sv_maxclients->integer
		);

		for ( int i = 0; i < sv_maxclients->integer; i++ )
		{
			const client_t& cl = svs.clients[i];
			if ( cl.state == clientState_t::CS_FREE )
			{
				continue;
			}

			std::string connection;

			if ( cl.state == clientState_t::CS_CONNECTED )
			{
				connection = "CONNECTED";
			}
			else if ( cl.state == clientState_t::CS_ZOMBIE )
			{
				connection = "ZOMBIE";
			}
			else
			{
				connection = std::to_string(cl.ping);
				if ( connection.size() > 10 )
				{
					connection = "ERROR";
				}
			}
			OpaquePlayerState* ps = SV_GameClientNum( i );

			const char *address = NET_AdrToString( cl.netchan.remoteAddress );

			Print(
				"%3i %5i %10s %-22s %-6i %s",
				i,
				ps->persistant[ PERS_SCORE ],
				connection,
				address,
				cl.netchan.qport,
				cl.name
			);
		}

		Print( "(end server status)" );
	}
};
static StatusCmd StatusCmdRegistration;

/*
==================
SV_Heartbeat_f

Also called by SV_DropClient, SV_DirectConnect, and SV_SpawnServer
==================
*/
void SV_Heartbeat_f()
{
	svs.nextHeartbeatTime = -9999999;
}

/*
===========
SV_Serverinfo_f

Examine the serverinfo string
===========
*/
static void SV_Serverinfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "Server info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SERVERINFO, false ) );
}

/*
===========
SV_Systeminfo_f

Examine the systeminfo string
===========
*/
static void SV_Systeminfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "System info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SYSTEMINFO, false ) );
}

class ListMapsCmd: public Cmd::StaticCmd
{
public:
	ListMapsCmd():
		StaticCmd("listmaps", Cmd::SYSTEM, "Lists all maps available to the server")
	{}

	void Run(const Cmd::Args&) const override
	{
		auto maps = FS::GetAvailableMaps();

		Print("Listing %d maps:", maps.size());

		for ( const auto& map: maps )
		{
			Print(map.c_str());
		}
	}
};

#if BUILD_SERVER
static ListMapsCmd ListMapsCmdRegistration;
#endif

/*
==================
SV_AddOperatorCommands
==================
*/
void SV_AddOperatorCommands()
{
	if ( com_sv_running->integer )
	{
		// These commands should only be available while the server is running.
		Cmd_AddCommand( "fieldinfo",   SV_FieldInfo_f );
		Cmd_AddCommand( "heartbeat",   SV_Heartbeat_f );
		Cmd_AddCommand( "map_restart", SV_MapRestart_f );
		Cmd_AddCommand( "serverinfo",  SV_Serverinfo_f );
		Cmd_AddCommand( "systeminfo",  SV_Systeminfo_f );
	}
}

/*
==================
SV_RemoveOperatorCommands
==================
*/
void SV_RemoveOperatorCommands()
{
	Cmd_RemoveCommand( "fieldinfo" );
	Cmd_RemoveCommand( "heartbeat" );
	Cmd_RemoveCommand( "map_restart" );
	Cmd_RemoveCommand( "serverinfo" );
	Cmd_RemoveCommand( "status" );
	Cmd_RemoveCommand( "systeminfo" );
}
<|endoftext|>