Allow multiple remote servers on one hostname, on different ports

* When a port is specified (with the usual :12345 suffix on the hostname) we use
  that for remote replay connections. We disable target control enumeration
  since that requires a port _range_ and captured applications self-assign those
  ports. Those can still be accessed via a normal unsuffixed remote specifier -
  even if there is no remote server running on the default port.
This commit is contained in:
baldurk
2022-02-15 15:59:46 +00:00
parent 435ed5ad38
commit 99adcc614f
6 changed files with 66 additions and 11 deletions
+4
View File
@@ -31,6 +31,10 @@ This manager allows you to configure both which remote hosts are available, as w
To add a new host, simply type its hostname in the hostname box and click ``Add``. It will be added to the list of known remote hosts, and immediately a network lookup will happen to see if the remote server or any running RenderDoc-injected applications are alive.
.. note::
You can run multiple remote servers on a single hostname by listening on different ports and specifying that in the hostname as with ``hostname:12345``.
At minimum, this is all you must configure. However it is recommended that you configure a command which can be run on the **local** machine which will **remotely** start the remote server on that host. The reason for this is that it allows easy capture each time with zero manual extra steps.
.. figure:: ../imgs/Screenshots/RemoteHostConfigure.png
+4 -3
View File
@@ -1872,14 +1872,15 @@ This function will block until a remote connection tells the server to shut down
``killReplay`` callback returns ``True``.
:param str listenhost: The name of the interface to listen on.
:param int port: The port to listen on, or ``0`` to listen on the default port.
:param KillCallback killReplay: A callback that returns a ``bool`` indicating if the server should
be shut down or not.
:param PreviewWindowCallback previewWindow: A callback that returns information for a preview window
when the server wants to display some preview of the ongoing replay.
)");
extern "C" RENDERDOC_API void RENDERDOC_CC
RENDERDOC_BecomeRemoteServer(const rdcstr &listenhost, RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow);
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
const rdcstr &listenhost, uint16_t port, RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow);
//////////////////////////////////////////////////////////////////////////
// Injection/execution capture functions.
+21
View File
@@ -289,6 +289,8 @@ static void ActiveRemoteClientThread(ClientThread *threadData,
writer.SetStreamingMode(true);
reader.SetStreamingMode(true);
uint32_t captureNum = 0;
while(client)
{
if(client && !client->Connected())
@@ -396,6 +398,13 @@ static void ActiveRemoteClientThread(ClientThread *threadData,
rdcstr dummy, dummy2;
FileIO::GetDefaultFiles("remotecopy", path, dummy, dummy2);
// remove the .rdc
path.erase(path.size() - 4, 4);
// append a process- and capture- specific suffix to avoid clashes
path += StringFormat::Fmt("_remotecopy_%u_%u.rdc", Process::GetCurrentPID(), captureNum);
captureNum++;
RDCLOG("Copying file to local path '%s'.", path.c_str());
FileIO::CreateParentDirectory(path);
@@ -1147,6 +1156,18 @@ RENDERDOC_CreateRemoteServerConnection(const rdcstr &URL, IRemoteServer **rend)
port = protocol->RemapPort(deviceID, port);
}
else
{
int32_t idx = deviceID.indexOf(':');
if(idx > 0)
{
host = deviceID.substr(0, idx);
port = atoi(deviceID.substr(idx + 1).c_str()) & 0xffff;
}
}
if(port == 0)
return ReplayStatus::NetworkIOFailed;
Network::Socket *sock = Network::CreateClientSocket(host, port, 750);
+12
View File
@@ -945,6 +945,18 @@ extern "C" RENDERDOC_API ITargetControl *RENDERDOC_CC RENDERDOC_CreateTargetCont
port = protocol->RemapPort(deviceID, port);
}
else
{
int32_t idx = deviceID.indexOf(':');
if(idx > 0)
{
host = deviceID.substr(0, idx);
port = atoi(deviceID.substr(idx + 1).c_str()) & 0xffff;
}
}
if(port == 0)
return NULL;
Network::Socket *sock = Network::CreateClientSocket(host, port, 750);
+15 -5
View File
@@ -429,6 +429,13 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(
if(host.empty())
return 0;
}
else
{
// hosts specified with a port are supported only for replay, do not enumerate targets on those
// hosts
if(URL.contains(':'))
return 0;
}
for(; nextIdent <= RenderDoc_LastTargetControlPort; nextIdent++)
{
@@ -475,9 +482,9 @@ RENDERDOC_GetDeviceProtocolController(const rdcstr &protocol)
return RenderDoc::Inst().GetDeviceProtocol(protocol);
}
extern "C" RENDERDOC_API void RENDERDOC_CC
RENDERDOC_BecomeRemoteServer(const rdcstr &listenhost, RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow)
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
const rdcstr &listenhost, uint16_t port, RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow)
{
// ensure a sensible default if no callback is provided, that just never kills
if(!killReplay)
@@ -490,8 +497,11 @@ RENDERDOC_BecomeRemoteServer(const rdcstr &listenhost, RENDERDOC_KillCallback ki
return ret;
};
RenderDoc::Inst().BecomeRemoteServer(listenhost.empty() ? "0.0.0.0" : listenhost,
RenderDoc_RemoteServerPort, killReplay, previewWindow);
if(port == 0)
port = RenderDoc_RemoteServerPort;
RenderDoc::Inst().BecomeRemoteServer(listenhost.empty() ? "0.0.0.0" : listenhost, port,
killReplay, previewWindow);
}
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartSelfHostCapture(const rdcstr &dllname)
+10 -3
View File
@@ -456,6 +456,7 @@ private:
std::string host;
bool daemon = false;
bool preview = false;
uint16_t port = 0;
public:
RemoteServerCommand() : Command() {}
@@ -465,6 +466,9 @@ public:
parser.add<std::string>(
"host", 'h', "The interface to listen on. By default listens on all interfaces", false, "");
parser.add("preview", 'v', "Display a preview window when a replay is active.");
parser.add<uint32_t>(
"port", 'p',
"The port to listen on. Default is 0, which listens on RenderDoc's default port.", false, 0);
}
virtual const char *Description()
{
@@ -478,12 +482,15 @@ public:
host = parser.get<std::string>("host");
daemon = parser.exist("daemon");
preview = parser.exist("preview");
port = parser.get<uint32_t>("port") & 0xffff;
return true;
}
virtual int Execute(const CaptureOptions &)
{
std::cerr << "Spawning a replay host listening on " << (host.empty() ? "*" : host) << "..."
<< std::endl;
std::cerr << "Spawning a replay host listening on " << (host.empty() ? "*" : host);
if(port != 0)
std::cerr << ":" << port;
std::cerr << "..." << std::endl;
if(daemon)
{
@@ -504,7 +511,7 @@ public:
if(DisplayRemoteServerPreview(false, {}).system != WindowingSystem::Unknown)
previewWindow = &DisplayRemoteServerPreview;
RENDERDOC_BecomeRemoteServer(conv(host), []() { return killSignal; }, previewWindow);
RENDERDOC_BecomeRemoteServer(conv(host), port, []() { return killSignal; }, previewWindow);
std::cerr << std::endl << "Cleaning up from replay hosting." << std::endl;