/*********************************************************************** * 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; }
/*********************************************************************** * Discovery routine -- connect to server when key specified **********************************************************************/ static std::vector<SoapySDR::Kwargs> findRemote(const SoapySDR::Kwargs &args) { std::vector<SoapySDR::Kwargs> result; if (args.count(SOAPY_REMOTE_KWARG_STOP) != 0) return result; //no remote specified, use the discovery protocol if (args.count("remote") == 0) { //On non-windows platforms the endpoint instance can last the //duration of the process because it can be cleaned up safely. //Windows has issues cleaning up threads and sockets on exit. #ifndef _MSC_VER static #endif //_MSC_VER auto ssdpEndpoint = SoapySSDPEndpoint::getInstance(); //enable forces new search queries ssdpEndpoint->enablePeriodicSearch(true); //wait maximum timeout for replies std::this_thread::sleep_for(std::chrono::microseconds(SOAPY_REMOTE_SOCKET_TIMEOUT_US)); for (const auto &url : SoapySSDPEndpoint::getInstance()->getServerURLs()) { auto argsWithURL = args; argsWithURL["remote"] = url; const auto subResult = findRemote(argsWithURL); result.insert(result.end(), subResult.begin(), subResult.end()); } return result; } //otherwise connect to a specific url and enumerate auto url = SoapyURL(args.at("remote")); //default url parameters when not specified if (url.getScheme().empty()) url.setScheme("tcp"); if (url.getService().empty()) url.setService(SOAPY_REMOTE_DEFAULT_SERVICE); //try to connect to the remote server SoapySocketSession sess; SoapyRPCSocket s; int ret = s.connect(url.toString()); if (ret != 0) { SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyRemote::find() -- connect(%s) FAIL: %s", url.toString().c_str(), s.lastErrorMsg()); return result; } //find transaction try { SoapyLogAcceptor logAcceptor(url.toString(), s); SoapyRPCPacker packer(s); packer & SOAPY_REMOTE_FIND; packer & translateArgs(args); packer(); SoapyRPCUnpacker unpacker(s); unpacker & result; //graceful disconnect SoapyRPCPacker packerHangup(s); packerHangup & SOAPY_REMOTE_HANGUP; packerHangup(); SoapyRPCUnpacker unpackerHangup(s); } catch (const std::exception &ex) { SoapySDR::logf(SOAPY_SDR_ERROR, "SoapyRemote::find() -- transact FAIL: %s", ex.what()); } //remove instances of the stop key from the result for (auto &resultArgs : result) { resultArgs.erase(SOAPY_REMOTE_KWARG_STOP); if (resultArgs.count("driver") != 0) { resultArgs["remote:driver"] = resultArgs.at("driver"); resultArgs.erase("driver"); } if (resultArgs.count("type") != 0) { resultArgs["remote:type"] = resultArgs.at("type"); resultArgs.erase("type"); } resultArgs["remote"] = url.toString(); } return result; }