Beispiel #1
0
bool RequestURI::process(const VirtualHost *vhost, Transport *transport,
                         const string &sourceRoot,
                         const string &pathTranslation, const char *url) {
  splitURL(url, m_originalURL, m_queryString);
  m_originalURL = StringUtil::UrlDecode(m_originalURL, false);
  m_rewritten = false;

  // Fast path for files that exist unless VirtualHost option StaticFastPath is false, in
  // which case rewrite rules are applied even if the original path points to an existing static file.

  String canon(Util::canonicalize(m_originalURL.c_str(), m_originalURL.size()),
               AttachString);


  if ( vhost->staticfastpath() )
    {
    if (virtualFileExists(vhost, sourceRoot, pathTranslation, canon)) {
      m_rewrittenURL = canon;
      m_resolvedURL = canon;
      return true;
    }
  }


  if (!rewriteURL(vhost, transport, pathTranslation, sourceRoot)) {
    // Redirection
    m_done = true;
    return true;
  }
  if (!resolveURL(vhost, pathTranslation, sourceRoot)) {
    // Can't find
    return false;
  }
  return true;
}
bool RequestURI::process(const VirtualHost *vhost, Transport *transport,
                         const string &sourceRoot,
                         const string &pathTranslation, const char *url) {
  splitURL(url, m_originalURL, m_queryString);
  m_originalURL = StringUtil::UrlDecode(m_originalURL, false);

  // Fast path for files that exist
  String canon = Util::canonicalize(string(m_originalURL.c_str(),
                                           m_originalURL.size()));
  String relUrl(canon.charAt(0) == '/' ? canon.substr(1) : canon);
  if (virtualFileExists(vhost, sourceRoot, pathTranslation, relUrl)) {
    m_rewrittenURL = relUrl;
    m_resolvedURL = relUrl;
    PrependSlash(m_resolvedURL);
    return true;
  }

  if (!rewriteURL(vhost, transport, pathTranslation, sourceRoot)) {
    // Redirection
    m_done = true;
    return true;
  }
  if (!resolveURL(vhost, pathTranslation, sourceRoot)) {
    // Can't find
    return false;
  }
  return true;
}
Beispiel #3
0
/***********************************************************************
 * Launch the server
 **********************************************************************/
static int runServer(void)
{
    std::string url;
    if (optarg != NULL) url = optarg;
    if (url.empty()) url = combineURL("tcp", "::", "");

    //default url parameters when not specified
    std::string scheme, node, service; splitURL(url, scheme, node, service);
    url = combineURL(scheme.empty()?"tcp":scheme, node, service.empty()?SOAPY_REMOTE_DEFAULT_SERVICE:service);

    std::cout << uniqueProcessId() << std::endl;
    std::cout << "Launching the server... " << url << std::endl;
    SoapySocketSession sess;
    SoapyRPCSocket s;
    if (s.bind(url) != 0)
    {
        std::cerr << "Server socket bind FAIL: " << s.lastErrorMsg() << std::endl;
        return EXIT_FAILURE;
    }
    std::cout << "Server bound to " << s.getsockname() << std::endl;
    s.listen(SOAPY_REMOTE_LISTEN_BACKLOG);
    auto serverListener = new SoapyServerListener(s);

    std::cout << "Press Ctrl+C to stop the server" << std::endl;
    signal(SIGINT, sigIntHandler);
    while (not serverDone) serverListener->handleOnce();

    std::cout << "Shutdown client handler threads" << std::endl;
    delete serverListener;
    s.close();

    std::cout << "Cleanup complete, exiting" << std::endl;
    return EXIT_SUCCESS;
}
PhysicsCollisionObject::ScriptListener* PhysicsCollisionObject::ScriptListener::create(const char* url)
{
    std::string scriptPath, func;
    splitURL(url, &scriptPath, &func);
    if (func.empty())
    {
        // Only a function was specified
        func = scriptPath;
        scriptPath = "";
    }

    Script* script = NULL;
    if (!scriptPath.empty())
    {
        script = Game::getInstance()->getScriptController()->loadScript(scriptPath.c_str(), Script::GLOBAL);
        if (!script)
        {
            // Failed to load script
            return NULL;
        }
    }

    ScriptListener* listener = new ScriptListener();
    listener->url = url;
    listener->script = script;
    listener->function = func;
    return listener;
}
Beispiel #5
0
bool RequestURI::process(const VirtualHost *vhost, Transport *transport,
                         const string &sourceRoot,
                         const string &pathTranslation, const char *url) {
  splitURL(url, m_originalURL, m_queryString);
  m_originalURL = StringUtil::UrlDecode(m_originalURL, false);
  m_rewritten = false;

  // Fast path for files that exist
  if (vhost->checkExistenceBeforeRewrite()) {
    String canon(
      Util::canonicalize(m_originalURL.c_str(), m_originalURL.size()),
      AttachString);
    if (virtualFileExists(vhost, sourceRoot, pathTranslation, canon)) {
      m_rewrittenURL = canon;
      m_resolvedURL = canon;
      return true;
    }
  }

  if (!rewriteURL(vhost, transport, pathTranslation, sourceRoot)) {
    // Redirection
    m_done = true;
    return true;
  }
  if (!resolveURL(vhost, pathTranslation, sourceRoot)) {
    // Can't find
    return false;
  }
  return true;
}
Beispiel #6
0
bool Game::startup()
{
    if (_state != UNINITIALIZED)
        return false;

    setViewport(Rectangle(0.0f, 0.0f, (float)_width, (float)_height));
    RenderState::initialize();
    FrameBuffer::initialize();

    _animationController = new AnimationController();
    _animationController->initialize();

    _audioController = new AudioController();
    _audioController->initialize();

    _physicsController = new PhysicsController();
    _physicsController->initialize();

    _aiController = new AIController();
    _aiController->initialize();

    _scriptController = new ScriptController();
    _scriptController->initialize();

    // Load any gamepads, ui or physical.
    loadGamepads();

    // Set the script callback functions.
    if (_properties)
    {
        Properties* scripts = _properties->getNamespace("scripts", true);
        if (scripts)
        {
            const char* callback;
            while ((callback = scripts->getNextProperty()) != NULL)
            {
                std::string url = scripts->getString();
                std::string file;
                std::string id;
                splitURL(url, &file, &id);

                if (file.size() <= 0 || id.size() <= 0)
                {
                    GP_ERROR("Invalid %s script callback function '%s'.", callback, url.c_str());
                }
                else
                {
                    _scriptController->loadScript(file.c_str());
                    _scriptController->registerCallback(callback, id.c_str());
                }
            }
        }
    }

    _state = RUNNING;

    return true;
}
Beispiel #7
0
/**
 * Precondition: m_originalURL and m_queryString are set
 * Postcondition: Output is false and we are redirecting OR
 *  m_rewrittenURL is set and m_queryString is updated if needed
 */
bool RequestURI::rewriteURL(const VirtualHost *vhost, Transport *transport,
                            const string &pathTranslation,
                            const string &sourceRoot) {
  bool qsa = false;
  int redirect = 0;
  string host = transport->getHeader("host");
  m_rewrittenURL = m_originalURL;
  if (vhost->rewriteURL(host, m_rewrittenURL, qsa, redirect)) {
    m_rewritten = true;
    if (qsa && !m_queryString.empty()) {
      m_rewrittenURL += (m_rewrittenURL.find('?') < 0) ? "?" : "&";
      m_rewrittenURL += m_queryString;
    }
    if (redirect) {
      if (m_rewrittenURL.substr(0, 7) != s_http &&
          m_rewrittenURL.substr(0, 8) != s_https) {
        PrependSlash(m_rewrittenURL);
      }
      transport->redirect(m_rewrittenURL.c_str(), redirect, "rewriteURL");
      return false;
    }
    splitURL(m_rewrittenURL, m_rewrittenURL, m_queryString);
  }
  m_rewrittenURL = String(
      Util::canonicalize(m_rewrittenURL.c_str(), m_rewrittenURL.size()),
      AttachString);
  if (!m_rewritten && m_rewrittenURL.charAt(0) == '/') {
    // A un-rewritten URL is always relative, so remove prepending /
    m_rewrittenURL = m_rewrittenURL.substr(1);
  }

  // If the URL refers to a folder but does not end
  // with a slash, then we need to redictect
  String url = m_rewrittenURL;
  if (!url.empty() &&
      url.charAt(url.length() - 1) != '/') {
    if (virtualFolderExists(vhost, sourceRoot, pathTranslation, url)) {
      url += "/";
      m_rewritten = true;
      String queryStr;
      m_rewrittenURL = m_originalURL;
      m_rewrittenURL += "/";
      if (!m_queryString.empty()) {
        m_rewrittenURL += "?";
        m_rewrittenURL += m_queryString;
      }
      if (m_rewrittenURL.substr(0, 7) != s_http &&
          m_rewrittenURL.substr(0, 8) != s_https) {
        PrependSlash(m_rewrittenURL);
      }
      transport->redirect(m_rewrittenURL.c_str(), 301, "rewriteURL");
      return false;
    }
  }

  return true;
}
void QGpgMECryptoConfigEntry::setURLValue( const KUrl& url )
{
  QString str = splitURL( mRealArgType, url );
  if ( str.isEmpty() && !isOptional() )
    mSet = false;
  else
    mSet = true;
  mValue = str;
  mDirty = true;
}
Beispiel #9
0
bool RequestURI::process(const VirtualHost *vhost, Transport *transport,
                         const std::string &sourceRoot,
                         const std::string &pathTranslation, const char *url) {
  splitURL(url, m_originalURL, m_queryString);
  m_originalURL = StringUtil::UrlDecode(m_originalURL, false);
  m_rewritten = false;

  auto scriptFilename = transport->getScriptFilename();
  if (!scriptFilename.empty()) {
    // The transport is overriding everything and just handing us the filename
    m_originalURL = scriptFilename;
    if (!resolveURL(vhost, pathTranslation, sourceRoot)) {
      return false;
    }
    if (m_origPathInfo.empty()) {
      // PATH_INFO wasn't filled by resolveURL() because m_originalURL
      // didn't contain it. We set it now, based on PATH_TRANSLATED.
      m_origPathInfo = transport->getPathTranslated();
      if (!m_origPathInfo.empty() &&
          m_origPathInfo.charAt(0) != '/') {
        m_origPathInfo = "/" + m_origPathInfo;
      }
    }
    if (transport->isPathInfoSet()) {
      m_pathInfo =transport->getPathInfo();
    } else {
      m_pathInfo = m_origPathInfo;
    }
    return true;
  }

  // Fast path for files that exist
  if (vhost->checkExistenceBeforeRewrite()) {
    String canon = FileUtil::canonicalize(m_originalURL);
    if (virtualFileExists(vhost, sourceRoot, pathTranslation, canon)) {
      m_rewrittenURL = canon;
      m_resolvedURL = canon;
      return true;
    }
  }

  if (!rewriteURL(vhost, transport, pathTranslation, sourceRoot)) {
    // Redirection
    m_done = true;
    return true;
  }
  if (!resolveURL(vhost, pathTranslation, sourceRoot)) {
    // Can't find
    return false;
  }
  return true;
}
void QGpgMECryptoConfigEntry::setURLValueList( const KUrl::List& urls )
{
  QStringList lst;
  for( KUrl::List::const_iterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
    lst << splitURL( mRealArgType, *it );
  }
  mValue = lst;
  if ( lst.isEmpty() && !isOptional() )
    mSet = false;
  else
    mSet = true;
  mDirty = true;
}
Beispiel #11
0
std::string ScriptController::loadUrl(const char* url)
{
    std::string file;
    std::string id;
    splitURL(url, &file, &id);

    if (id.size() <= 0)
    {
        // The url does not reference a script - only a function
        return file;
    }

    // Ensure the script is loaded.
    if (file.size() > 0)
        Game::getInstance()->getScriptController()->loadScript(file.c_str());

    // Return the function name.
    return id;
}
Beispiel #12
0
void	URLParser::parseURL(const std::string &url)
{
	size_t	length	=	url.length();
	if (length	<	7)	//过短的URL可以认为是无效的
	{
		assert(false);
		return;
	}
	else
	{
		std::string	protocal	=	url.substr(0,7);
		std::string	format_url	=	url;
		if (_strcmpi(protocal.c_str(),"http://") == 0)
		{
			format_url	=	url.substr(7,length-7);
		}
		splitURL(format_url);
	}
}
std::string ScriptController::loadUrl(const char* url)
{
    std::string file;
    std::string id;
    splitURL(url, &file, &id);

    // Make sure the function isn't empty.
    if (id.size() <= 0)
    {
        GP_ERROR("Got an empty function name when parsing function url '%s'.", url);
        return std::string();
    }

    // Ensure the script is loaded.
    if (file.size() > 0)
        Game::getInstance()->getScriptController()->loadScript(file.c_str());

    // Return the function name.
    return id;
}
Beispiel #14
0
bool RequestURI::process(const VirtualHost *vhost, Transport *transport,
                         const std::string &sourceRoot,
                         const std::string &pathTranslation, const char *url) {
  splitURL(url, m_originalURL, m_queryString);
  m_originalURL = StringUtil::UrlDecode(m_originalURL, false);
  m_rewritten = false;

  auto pathTranslated = transport->getPathTranslated();
  if (!pathTranslated.empty()) {
    // The transport is overriding everything and just handing us the filename
    m_path = m_absolutePath = pathTranslated;
    processExt();
    return true;
  }

  // Fast path for files that exist
  if (vhost->checkExistenceBeforeRewrite()) {
    String canon(
      Util::canonicalize(m_originalURL.c_str(), m_originalURL.size()),
      AttachString);
    if (virtualFileExists(vhost, sourceRoot, pathTranslation, canon)) {
      m_rewrittenURL = canon;
      m_resolvedURL = canon;
      return true;
    }
  }

  if (!rewriteURL(vhost, transport, pathTranslation, sourceRoot)) {
    // Redirection
    m_done = true;
    return true;
  }
  if (!resolveURL(vhost, pathTranslation, sourceRoot)) {
    // Can't find
    return false;
  }
  return true;
}
Beispiel #15
0
void ScriptTarget::addScriptCallback(const Event* event, const char* function)
{
    GP_ASSERT(event);
    GP_ASSERT(function);

    // Parse the script name (if it exists) and function out
    std::string scriptPath, func;
    splitURL(function, &scriptPath, &func);
    if (func.length() == 0)
    {
        // The url doesn't reference a script, only a function
        func = scriptPath;
        scriptPath = "";
    }

    // Have we already loaded this global script?
    bool loaded = true;
    Script* script = NULL;
    if (!scriptPath.empty())
    {
        loaded = false;
        ScriptEntry* se = _scripts;
        while (se)
        {
            if (scriptPath == se->script->getPath() && se->script->getScope() == Script::GLOBAL)
            {
                // Script is already loaded
                script = se->script;
                loaded = true;
                break;
            }
            se = se->next;
        }
    }

    if (!loaded)
    {
        // The specified global script is not yet loaded, so do so
        script = Game::getInstance()->getScriptController()->loadScript(scriptPath.c_str(), Script::GLOBAL);
        if (script)
        {
            loaded = true;
            ScriptEntry* se = new ScriptEntry(script);
            if (_scripts)
            {
                ScriptEntry* last = _scripts;
                while (last->next)
                    last = last->next;
                last->next = se;
                se->prev = last;
            }
            else
            {
                _scripts = se;
            }
        }
        else
        {
            GP_WARN("Failed to load script '%s' for script target while registering for function: %s", scriptPath.c_str(), function);
        }
    }

    if (loaded)
    {
        // Store the callback
        if (!_scriptCallbacks)
            _scriptCallbacks = new std::map<const Event*, std::vector<CallbackFunction>>();
        (*_scriptCallbacks)[event].push_back(CallbackFunction(script, func.c_str()));
    }
}
Beispiel #16
0
void ScriptTarget::removeScriptCallback(const Event* event, const char* function)
{
    // Parse the script name (if it exists) and function out
    std::string scriptPath, func;
    splitURL(function, &scriptPath, &func);
    if (func.length() == 0)
    {
        // The url doesn't reference a script, only a function
        func = scriptPath;
        scriptPath = "";
    }

    // Find the script entry for this callback
    ScriptEntry* scriptEntry = NULL;
    if (!scriptPath.empty())
    {
        ScriptEntry* se = _scripts;
        while (se)
        {
            if (scriptPath == se->script->getPath() && se->script->getScope() == Script::GLOBAL)
            {
                scriptEntry = se;
                break;
            }
            se = se->next;
        }
    }
    Script* script = scriptEntry ? scriptEntry->script : NULL;

    // Remove any registered callback functions that match the specified one
    int removedCallbacks = 0;
    int totalCallbacks = 0;
    if (_scriptCallbacks)
    {
        std::map<const Event*, std::vector<CallbackFunction>>::iterator itr = _scriptCallbacks->begin();
        for (; itr != _scriptCallbacks->end(); ++itr)
        {
            // Erase matching callback functions for this event
            bool forEvent = itr->first == event;
            std::vector<CallbackFunction>& callbacks = itr->second;
            std::vector<CallbackFunction>::iterator itr2 = callbacks.begin();
            while (itr2 != callbacks.end())
            {
                if (itr2->script == script)
                {
                    ++totalCallbacks; // sum total number of callbacks found for this script
                    if (forEvent && itr2->function == func)
                    {
                        itr2 = callbacks.erase(itr2);
                        ++removedCallbacks; // sum number of callbacks removed
                    }
                    else
                        ++itr2;
                }
            }
        }
    }

    // Cleanup the script if there are no remaining callbacks for it
    if (scriptEntry && (totalCallbacks - removedCallbacks) <= 0)
    {
        removeScript(scriptEntry);
    }
}
Beispiel #17
0
/**
 * Precondition: m_originalURL and m_queryString are set
 * Postcondition: Output is false and we are redirecting OR
 *  m_rewrittenURL is set and m_queryString is updated if needed
 */
bool RequestURI::rewriteURL(const VirtualHost *vhost, Transport *transport,
                            const std::string &pathTranslation,
                            const std::string &sourceRoot) {
  bool qsa = false;
  int redirect = 0;
  std::string host = transport->getHeader("host");
  m_rewrittenURL = m_originalURL;
  if (vhost->rewriteURL(host, m_rewrittenURL, qsa, redirect)) {
    m_rewritten = true;
    if (qsa && !m_queryString.empty()) {
      m_rewrittenURL += (m_rewrittenURL.find('?') < 0) ? "?" : "&";
      m_rewrittenURL += m_queryString;
    }
    if (redirect) {
      if (m_rewrittenURL.substr(0, 7) != s_http &&
          m_rewrittenURL.substr(0, 8) != s_https) {
        PrependSlash(m_rewrittenURL);
      }
      if (redirect < 0) {
        std::string error;
        StringBuffer response;
        int code = 0;
        HttpProtocol::ProxyRequest(transport, true,
                                   m_rewrittenURL.toCppString(),
                                   code, error,
                                   response);
        if (!code) {
          transport->sendString(error, 500, false, false, "proxyRequest");
        } else {
          const char* respData = response.data();
          if (!respData) respData = "";
          transport->sendRaw(const_cast<char*>(respData),
                             response.size(), code);
        }
        transport->onSendEnd();
      } else {
        transport->redirect(m_rewrittenURL.c_str(), redirect);
      }
      return false;
    }
    splitURL(m_rewrittenURL, m_rewrittenURL, m_queryString);
  }
  m_rewrittenURL = FileUtil::canonicalize(m_rewrittenURL);
  if (!m_rewritten && m_rewrittenURL.charAt(0) == '/') {
    // A un-rewritten URL is always relative, so remove prepending /
    m_rewrittenURL = m_rewrittenURL.substr(1);
  }

  // If the URL refers to a folder but does not end
  // with a slash, then we need to redictect
  String url = m_rewrittenURL;
  if (!url.empty() &&
      url.charAt(url.length() - 1) != '/') {
    if (virtualFolderExists(vhost, sourceRoot, pathTranslation, url)) {
      if (m_originalURL.find("..") != String::npos) {
        transport->sendString(getDefault404(), 404);
        transport->onSendEnd();
        return false;
      }
      url += "/";
      m_rewritten = true;
      String queryStr;
      m_rewrittenURL = m_originalURL;
      m_rewrittenURL += "/";
      if (!m_queryString.empty()) {
        m_rewrittenURL += "?";
        m_rewrittenURL += m_queryString;
      }
      if (m_rewrittenURL.substr(0, 7) != s_http &&
          m_rewrittenURL.substr(0, 8) != s_https) {
        PrependSlash(m_rewrittenURL);
      }
      transport->redirect(m_rewrittenURL.c_str(), 301);
      return false;
    }
  }

  return true;
}
Beispiel #18
0
/***********************************************************************
 * Handler dispatcher implementation
 **********************************************************************/
bool SoapyClientHandler::handleOnce(SoapyRPCUnpacker &unpacker, SoapyRPCPacker &packer)
{
    SoapyRemoteCalls call;
    unpacker & call;

    switch (call)
    {

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_FIND:
    ////////////////////////////////////////////////////////////////////
    {
        SoapySDR::Kwargs args;
        unpacker & args;
        packer & SoapySDR::Device::enumerate(args);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_MAKE:
    ////////////////////////////////////////////////////////////////////
    {
        SoapySDR::Kwargs args;
        unpacker & args;
        std::lock_guard<std::mutex> lock(factoryMutex);
        if (_dev == nullptr) _dev = SoapySDR::Device::make(args);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_UNMAKE:
    ////////////////////////////////////////////////////////////////////
    {
        std::lock_guard<std::mutex> lock(factoryMutex);
        if (_dev != nullptr) SoapySDR::Device::unmake(_dev);
        _dev = nullptr;
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_HANGUP:
    ////////////////////////////////////////////////////////////////////
    {
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_SERVER_ID:
    ////////////////////////////////////////////////////////////////////
    {
        packer & uniqueProcessId();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_START_LOG_FORWARDING:
    ////////////////////////////////////////////////////////////////////
    {
        if (_logForwarder == nullptr) _logForwarder = new SoapyLogForwarder(_sock);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_STOP_LOG_FORWARDING:
    ////////////////////////////////////////////////////////////////////
    {
        if (_logForwarder != nullptr) delete _logForwarder;
        _logForwarder = nullptr;
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_DRIVER_KEY:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->getDriverKey();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_HARDWARE_KEY:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->getHardwareKey();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_HARDWARE_INFO:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->getHardwareInfo();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_FRONTEND_MAPPING:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        std::string mapping;
        unpacker & direction;
        unpacker & mapping;
        _dev->setFrontendMapping(direction, mapping);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_FRONTEND_MAPPING:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        unpacker & direction;
        packer & _dev->getFrontendMapping(direction);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_NUM_CHANNELS:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        unpacker & direction;
        packer & int(_dev->getNumChannels(direction));
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_FULL_DUPLEX:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getFullDuplex(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SETUP_STREAM:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        std::string format;
        std::vector<size_t> channels;
        SoapySDR::Kwargs args;
        std::string clientBindPort;
        std::string statusBindPort;
        unpacker & direction;
        unpacker & format;
        unpacker & channels;
        unpacker & args;
        unpacker & clientBindPort;
        unpacker & statusBindPort;

        //parse args for buffer configuration
        size_t mtu = SOAPY_REMOTE_DEFAULT_ENDPOINT_MTU;
        const auto mtuIt = args.find(SOAPY_REMOTE_KWARG_MTU);
        if (mtuIt != args.end()) mtu = size_t(std::stod(mtuIt->second));

        size_t window = SOAPY_REMOTE_DEFAULT_ENDPOINT_WINDOW;
        const auto windowIt = args.find(SOAPY_REMOTE_KWARG_WINDOW);
        if (windowIt != args.end()) window = size_t(std::stod(windowIt->second));

        double priority = SOAPY_REMOTE_DEFAULT_THREAD_PRIORITY;
        const auto priorityIt = args.find(SOAPY_REMOTE_KWARG_PRIORITY);
        if (priorityIt != args.end()) priority = std::stod(priorityIt->second);

        //create stream
        auto stream = _dev->setupStream(direction, format, channels, args);

        //load data structure
        auto &data = _streamData[_nextStreamId];
        data.streamId = _nextStreamId++;
        data.device = _dev;
        data.stream = stream;
        data.format = format;
        for (const auto chan : channels) data.chanMask |= (1 << chan);
        data.priority = priority;

        //extract socket node information
        std::string serverBindPort;
        std::string localNode, remoteNode;
        std::string scheme, node, service;
        splitURL(_sock.getsockname(), scheme, localNode, service);
        splitURL(_sock.getpeername(), scheme, remoteNode, service);

        //bind the stream socket to an automatic port
        const auto bindURL = combineURL("udp", localNode, "0");
        int ret = data.streamSock.bind(bindURL);
        if (ret != 0)
        {
            const std::string errorMsg = data.streamSock.lastErrorMsg();
            _streamData.erase(data.streamId);
            throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
        }
        SoapySDR::logf(SOAPY_SDR_INFO, "Server side stream bound to %s", data.streamSock.getsockname().c_str());
        splitURL(data.streamSock.getsockname(), scheme, node, serverBindPort);

        //connect the stream socket to the specified port
        auto connectURL = combineURL("udp", remoteNode, clientBindPort);
        ret = data.streamSock.connect(connectURL);
        if (ret != 0)
        {
            const std::string errorMsg = data.streamSock.lastErrorMsg();
            _streamData.erase(data.streamId);
            throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
        }
        SoapySDR::logf(SOAPY_SDR_INFO, "Server side stream connected to %s", data.streamSock.getpeername().c_str());

        //connect the status socket to the specified port
        connectURL = combineURL("udp", remoteNode, statusBindPort);
        ret = data.statusSock.connect(connectURL);
        if (ret != 0)
        {
            const std::string errorMsg = data.statusSock.lastErrorMsg();
            _streamData.erase(data.streamId);
            throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
        }
        SoapySDR::logf(SOAPY_SDR_INFO, "Server side status connected to %s", data.statusSock.getpeername().c_str());

        //create endpoint
        data.endpoint = new SoapyStreamEndpoint(data.streamSock, data.statusSock,
            direction == SOAPY_SDR_TX, channels.size(), formatToSize(format), mtu, window);

        //start worker thread, this is not backwards,
        //receive from device means using a send endpoint
        //transmit to device means using a recv endpoint
        if (direction == SOAPY_SDR_RX) data.startSendThread();
        if (direction == SOAPY_SDR_TX) data.startRecvThread();
        data.startStatThread();

        packer & data.streamId;
        packer & serverBindPort;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_CLOSE_STREAM:
    ////////////////////////////////////////////////////////////////////
    {
        int streamId = 0;
        unpacker & streamId;

        //cleanup data and stop worker thread
        auto &data = _streamData.at(streamId);
        data.stopThreads();
        _dev->closeStream(data.stream);
        _streamData.erase(streamId);

        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_ACTIVATE_STREAM:
    ////////////////////////////////////////////////////////////////////
    {
        int streamId = 0;
        int flags = 0;
        long long timeNs = 0;
        int numElems = 0;
        unpacker & streamId;
        unpacker & flags;
        unpacker & timeNs;
        unpacker & numElems;

        auto &data = _streamData.at(streamId);
        packer & _dev->activateStream(data.stream, flags, timeNs, size_t(numElems));
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_DEACTIVATE_STREAM:
    ////////////////////////////////////////////////////////////////////
    {
        int streamId = 0;
        int flags = 0;
        long long timeNs = 0;
        unpacker & streamId;
        unpacker & flags;
        unpacker & timeNs;

        auto &data = _streamData.at(streamId);
        packer & _dev->deactivateStream(data.stream, flags, timeNs);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_ANTENNAS:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->listAntennas(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_ANTENNA:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        _dev->setAntenna(direction, channel, name);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_ANTENNA:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getAntenna(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_HAS_DC_OFFSET_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->hasDCOffsetMode(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_DC_OFFSET_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        bool automatic = false;
        unpacker & direction;
        unpacker & channel;
        unpacker & automatic;
        _dev->setDCOffsetMode(direction, channel, automatic);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_DC_OFFSET_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getDCOffsetMode(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_HAS_DC_OFFSET:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->hasDCOffset(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_DC_OFFSET:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::complex<double> offset;
        unpacker & direction;
        unpacker & channel;
        unpacker & offset;
        _dev->setDCOffset(direction, channel, offset);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_DC_OFFSET:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getDCOffset(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_HAS_IQ_BALANCE_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->hasIQBalance(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_IQ_BALANCE_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::complex<double> balance;
        unpacker & direction;
        unpacker & channel;
        unpacker & balance;
        _dev->setIQBalance(direction, channel, balance);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_IQ_BALANCE_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getIQBalance(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_GAINS:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->listGains(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_GAIN_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        bool automatic = false;
        unpacker & direction;
        unpacker & channel;
        unpacker & automatic;
        _dev->setGainMode(direction, channel, automatic);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_GAIN_MODE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getGainMode(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_GAIN:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        double value = 0;
        unpacker & direction;
        unpacker & channel;
        unpacker & value;
        _dev->setGain(direction, channel, value);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_GAIN_ELEMENT:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        double value = 0;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        unpacker & value;
        _dev->setGain(direction, channel, name, value);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_GAIN:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getGain(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_GAIN_ELEMENT:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        packer & _dev->getGain(direction, channel, name);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_GAIN_RANGE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getGainRange(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_GAIN_RANGE_ELEMENT:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        packer & _dev->getGainRange(direction, channel, name);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_FREQUENCY:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        double value = 0;
        SoapySDR::Kwargs args;
        unpacker & direction;
        unpacker & channel;
        unpacker & value;
        unpacker & args;
        _dev->setFrequency(direction, channel, value, args);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_FREQUENCY_COMPONENT:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        double value = 0;
        SoapySDR::Kwargs args;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        unpacker & value;
        unpacker & args;
        _dev->setFrequency(direction, channel, name, value, args);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_FREQUENCY:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getFrequency(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_FREQUENCY_COMPONENT:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        packer & _dev->getFrequency(direction, channel, name);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_FREQUENCIES:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->listFrequencies(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_FREQUENCY_RANGE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getFrequencyRange(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_FREQUENCY_RANGE_COMPONENT:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        packer & _dev->getFrequencyRange(direction, channel, name);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_SAMPLE_RATE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        double rate = 0;
        unpacker & direction;
        unpacker & channel;
        unpacker & rate;
        _dev->setSampleRate(direction, channel, rate);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_SAMPLE_RATE:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getSampleRate(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_SAMPLE_RATES:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->listSampleRates(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_BANDWIDTH:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        double bw = 0;
        unpacker & direction;
        unpacker & channel;
        unpacker & bw;
        _dev->setBandwidth(direction, channel, bw);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_BANDWIDTH:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->getBandwidth(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_BANDWIDTHS:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->listBandwidths(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_MASTER_CLOCK_RATE:
    ////////////////////////////////////////////////////////////////////
    {
        double rate = 0;
        unpacker & rate;
        _dev->setMasterClockRate(rate);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_MASTER_CLOCK_RATE:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->getMasterClockRate();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_CLOCK_SOURCES:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->listClockSources();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_CLOCK_SOURCE:
    ////////////////////////////////////////////////////////////////////
    {
        std::string source;
        unpacker & source;
        _dev->setClockSource(source);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_CLOCK_SOURCE:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->getClockSource();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_TIME_SOURCES:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->listTimeSources();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_TIME_SOURCE:
    ////////////////////////////////////////////////////////////////////
    {
        std::string source;
        unpacker & source;
        _dev->setTimeSource(source);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_TIME_SOURCE:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->getTimeSource();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_HAS_HARDWARE_TIME:
    ////////////////////////////////////////////////////////////////////
    {
        std::string what;
        unpacker & what;
        packer & _dev->hasHardwareTime(what);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_GET_HARDWARE_TIME:
    ////////////////////////////////////////////////////////////////////
    {
        std::string what;
        unpacker & what;
        packer & _dev->getHardwareTime(what);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_HARDWARE_TIME:
    ////////////////////////////////////////////////////////////////////
    {
        long long timeNs = 0;
        std::string what;
        unpacker & timeNs;
        unpacker & what;
        _dev->setHardwareTime(timeNs, what);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_SET_COMMAND_TIME:
    ////////////////////////////////////////////////////////////////////
    {
        long long timeNs = 0;
        std::string what;
        unpacker & timeNs;
        unpacker & what;
        _dev->setCommandTime(timeNs, what);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_SENSORS:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->listSensors();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_SENSOR:
    ////////////////////////////////////////////////////////////////////
    {
        std::string name;
        unpacker & name;
        packer & _dev->readSensor(name);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_CHANNEL_SENSORS:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        unpacker & direction;
        unpacker & channel;
        packer & _dev->listSensors(direction, channel);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_CHANNEL_SENSOR:
    ////////////////////////////////////////////////////////////////////
    {
        char direction = 0;
        int channel = 0;
        std::string name;
        unpacker & direction;
        unpacker & channel;
        unpacker & name;
        packer & _dev->readSensor(direction, channel, name);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_REGISTER:
    ////////////////////////////////////////////////////////////////////
    {
        int addr = 0;
        int value = 0;
        unpacker & addr;
        unpacker & value;
        _dev->writeRegister(unsigned(addr), unsigned(value));
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_REGISTER:
    ////////////////////////////////////////////////////////////////////
    {
        int addr = 0;
        unpacker & addr;
        packer & int(_dev->readRegister(unsigned(addr)));
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_SETTING:
    ////////////////////////////////////////////////////////////////////
    {
        std::string key;
        std::string value;
        unpacker & key;
        unpacker & value;
        _dev->writeSetting(key, value);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_SETTING:
    ////////////////////////////////////////////////////////////////////
    {
        std::string key;
        unpacker & key;
        packer & _dev->readSetting(key);
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_GPIO_BANKS:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->listGPIOBanks();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_GPIO:
    ////////////////////////////////////////////////////////////////////
    {
        std::string bank;
        int value = 0;
        unpacker & bank;
        unpacker & value;
        _dev->writeGPIO(bank, unsigned(value));
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_GPIO_MASKED:
    ////////////////////////////////////////////////////////////////////
    {
        std::string bank;
        int value = 0;
        int mask = 0;
        unpacker & bank;
        unpacker & value;
        unpacker & mask;
        _dev->writeGPIO(bank, unsigned(value), unsigned(mask));
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_GPIO:
    ////////////////////////////////////////////////////////////////////
    {
        std::string bank;
        unpacker & bank;
        packer & int(_dev->readGPIO(bank));
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_GPIO_DIR:
    ////////////////////////////////////////////////////////////////////
    {
        std::string bank;
        int dir = 0;
        unpacker & bank;
        unpacker & dir;
        _dev->writeGPIODir(bank, unsigned(dir));
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_GPIO_DIR_MASKED:
    ////////////////////////////////////////////////////////////////////
    {
        std::string bank;
        int dir = 0;
        int mask = 0;
        unpacker & bank;
        unpacker & dir;
        unpacker & mask;
        _dev->writeGPIODir(bank, unsigned(dir), unsigned(mask));
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_GPIO_DIR:
    ////////////////////////////////////////////////////////////////////
    {
        std::string bank;
        unpacker & bank;
        packer & int(_dev->readGPIODir(bank));
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_I2C:
    ////////////////////////////////////////////////////////////////////
    {
        int addr = 0;
        std::string data;
        unpacker & addr;
        unpacker & data;
        _dev->writeI2C(addr, data);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_I2C:
    ////////////////////////////////////////////////////////////////////
    {
        int addr = 0;
        int numBytes = 0;
        unpacker & addr;
        unpacker & numBytes;
        packer & _dev->readI2C(addr, unsigned(numBytes));
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_TRANSACT_SPI:
    ////////////////////////////////////////////////////////////////////
    {
        int addr = 0;
        int data = 0;
        int numBits = 0;
        unpacker & addr;
        unpacker & data;
        unpacker & numBits;
        packer & int(_dev->transactSPI(addr, unsigned(data), size_t(numBits)));
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_LIST_UARTS:
    ////////////////////////////////////////////////////////////////////
    {
        packer & _dev->listUARTs();
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_WRITE_UART:
    ////////////////////////////////////////////////////////////////////
    {
        std::string which;
        std::string data;
        unpacker & which;
        unpacker & data;
        _dev->writeUART(which, data);
        packer & SOAPY_REMOTE_VOID;
    } break;

    ////////////////////////////////////////////////////////////////////
    case SOAPY_REMOTE_READ_UART:
    ////////////////////////////////////////////////////////////////////
    {
        std::string which;
        int timeoutUs = 0;
        unpacker & which;
        unpacker & timeoutUs;
        packer & _dev->readUART(which, long(timeoutUs));
    } break;

    default: throw std::runtime_error(
        "SoapyClientHandler::handleOnce("+std::to_string(int(call))+") unknown call");
    }

    return call != SOAPY_REMOTE_HANGUP;
}
Beispiel #19
0
SoapySDR::Stream *SoapyRemoteDevice::setupStream(
    const int direction,
    const std::string &localFormat,
    const std::vector<size_t> &channels,
    const SoapySDR::Kwargs &args)
{
    //extract remote endpoint format using special remoteFormat keyword
    //use the client's local format when the remote format is not specified
    auto remoteFormat = localFormat;
    const auto remoteFormatIt = args.find(SOAPY_REMOTE_KWARG_FORMAT);
    if (remoteFormatIt != args.end()) remoteFormat = remoteFormatIt->second;

    double scaleFactor = SOAPY_REMOTE_DEFAULT_SCALING;
    const auto scaleFactorIt = args.find(SOAPY_REMOTE_KWARG_SCALAR);
    if (scaleFactorIt != args.end()) scaleFactor = std::stod(scaleFactorIt->second);

    size_t mtu = SOAPY_REMOTE_DEFAULT_ENDPOINT_MTU;
    const auto mtuIt = args.find(SOAPY_REMOTE_KWARG_MTU);
    if (mtuIt != args.end()) mtu = size_t(std::stod(mtuIt->second));

    size_t window = SOAPY_REMOTE_DEFAULT_ENDPOINT_WINDOW;
    const auto windowIt = args.find(SOAPY_REMOTE_KWARG_WINDOW);
    if (windowIt != args.end()) window = size_t(std::stod(windowIt->second));

    SoapySDR::logf(SOAPY_SDR_INFO, "SoapyRemote::setup%sStream(remoteFormat=%s, localFormat=%s, scaleFactor=%g, mtu=%d, window=%d)",
        (direction == SOAPY_SDR_RX)?"Rx":"Tx", remoteFormat.c_str(), localFormat.c_str(), scaleFactor, int(mtu), int(window));

    //check supported formats
    ConvertTypes convertType = CONVERT_MEMCPY;
    if (localFormat == remoteFormat) convertType = CONVERT_MEMCPY;
    else if (localFormat == "CF32" and remoteFormat == "CS16") convertType = CONVERT_CF32_CS16;
    else throw std::runtime_error(
        "SoapyRemote::setupStream() conversion not supported;"
        "localFormat="+localFormat+", remoteFormat="+remoteFormat);

    //allocate new local stream data
    ClientStreamData *data = new ClientStreamData();
    data->localFormat = localFormat;
    data->remoteFormat = remoteFormat;
    data->recvBuffs.resize(channels.size());
    data->sendBuffs.resize(channels.size());
    data->convertType = convertType;
    data->scaleFactor = scaleFactor;

    //extract socket node information
    std::string clientBindPort, statusBindPort;
    std::string localNode, remoteNode;
    std::string scheme, node, service;
    splitURL(_sock.getsockname(), scheme, localNode, service);
    splitURL(_sock.getpeername(), scheme, remoteNode, service);

    //bind the stream socket to an automatic port
    const auto bindURL = combineURL("udp", localNode, "0");
    int ret = data->streamSock.bind(bindURL);
    if (ret != 0)
    {
        const std::string errorMsg = data->streamSock.lastErrorMsg();
        delete data;
        throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
    }
    SoapySDR::logf(SOAPY_SDR_INFO, "Client side stream bound to %s", data->streamSock.getsockname().c_str());
    splitURL(data->streamSock.getsockname(), scheme, node, clientBindPort);

    //bind the status socket to an automatic port
    ret = data->statusSock.bind(bindURL);
    if (ret != 0)
    {
        const std::string errorMsg = data->statusSock.lastErrorMsg();
        delete data;
        throw std::runtime_error("SoapyRemote::setupStream("+bindURL+") -- bind FAIL: " + errorMsg);
    }
    SoapySDR::logf(SOAPY_SDR_INFO, "Client side status bound to %s", data->streamSock.getsockname().c_str());
    splitURL(data->statusSock.getsockname(), scheme, node, statusBindPort);

    //setup the remote end of the stream
    std::lock_guard<std::mutex> lock(_mutex);
    SoapyRPCPacker packer(_sock);
    packer & SOAPY_REMOTE_SETUP_STREAM;
    packer & char(direction);
    packer & remoteFormat;
    packer & channels;
    packer & args;
    packer & clientBindPort;
    packer & statusBindPort;
    packer();

    SoapyRPCUnpacker unpacker(_sock);
    std::string serverBindPort;
    unpacker & data->streamId;
    unpacker & serverBindPort;

    //connect the stream socket to the specified port
    const auto connectURL = combineURL("udp", remoteNode, serverBindPort);
    ret = data->streamSock.connect(connectURL);
    if (ret != 0)
    {
        const std::string errorMsg = data->streamSock.lastErrorMsg();
        delete data;
        throw std::runtime_error("SoapyRemote::setupStream("+connectURL+") -- connect FAIL: " + errorMsg);
    }
    SoapySDR::logf(SOAPY_SDR_INFO, "Client side stream connected to %s", data->streamSock.getpeername().c_str());

    //create endpoint
    data->endpoint = new SoapyStreamEndpoint(data->streamSock, data->statusSock,
        direction == SOAPY_SDR_RX, channels.size(), formatToSize(remoteFormat), mtu, window);

    return (SoapySDR::Stream *)data;
}