diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index 8bae59291..cd69a9647 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -30,39 +30,16 @@ #include "core/core.h" #include "os/os_specific.h" #include "replay/replay_controller.h" +#include "serialise/rdcfile.h" #include "serialise/serialiser.h" #include "strings/string_utils.h" #include "replay_proxy.h" -using std::pair; - -template <> -void Serialiser::Serialise(const char *name, PathEntry &el) -{ - ScopedContext scope(this, name, "DirectoryFile", 0, true); - - Serialise("filename", el.filename); - Serialise("flags", el.flags); - Serialise("lastmod", el.lastmod); - Serialise("size", el.size); -} - -template <> -void Serialiser::Serialise(const char *name, EnvironmentModification &el) -{ - ScopedContext scope(this, name, "EnvironmentModification", 0, true); - - Serialise("mod", el.mod); - Serialise("sep", el.sep); - Serialise("name", el.name); - Serialise("value", el.value); -} - -static const uint32_t RemoteServerProtocolVersion = 1; +static const uint32_t RemoteServerProtocolVersion = 2; enum RemoteServerPacket { - eRemoteServer_Noop, + eRemoteServer_Noop = 1, eRemoteServer_Handshake, eRemoteServer_VersionMismatch, eRemoteServer_Busy, @@ -75,6 +52,10 @@ enum RemoteServerPacket eRemoteServer_OpenLog, eRemoteServer_LogOpenProgress, eRemoteServer_LogOpened, + eRemoteServer_HasCallstacks, + eRemoteServer_InitResolver, + eRemoteServer_ResolverProgress, + eRemoteServer_GetResolve, eRemoteServer_CloseLog, eRemoteServer_HomeDir, eRemoteServer_ListDir, @@ -86,30 +67,8 @@ enum RemoteServerPacket RDCCOMPILE_ASSERT((int)eRemoteServer_RemoteServerCount < (int)eReplayProxy_First, "Remote server and Replay Proxy packets overlap"); -struct ProgressLoopData -{ - Network::Socket *sock; - float progress; - bool killsignal; -}; - -static void ProgressTicker(ProgressLoopData *data) -{ - Serialiser ser("", Serialiser::WRITING, false); - - while(!data->killsignal) - { - ser.Rewind(); - ser.Serialise("", data->progress); - - if(!SendPacket(data->sock, eRemoteServer_LogOpenProgress, ser)) - { - SAFE_DELETE(data->sock); - break; - } - Threading::Sleep(100); - } -} +#define WRITE_DATA_SCOPE() WriteSerialiser &ser = writer; +#define READ_DATA_SCOPE() ReadSerialiser &ser = reader; struct ClientThread { @@ -131,38 +90,54 @@ static void InactiveRemoteClientThread(ClientThread *threadData) { uint32_t ip = threadData->socket->GetRemoteIP(); - // this thread just handles receiving the handshake and sending a busy signal without blocking the - // server thread - RemoteServerPacket type = eRemoteServer_Noop; - Serialiser *recvser = NULL; - - if(!RecvPacket(threadData->socket, type, &recvser) || type != eRemoteServer_Handshake) { - RDCWARN("Didn't receive proper handshake"); + uint32_t version = 0; + + { + ReadSerialiser ser(new StreamReader(threadData->socket, Ownership::Nothing), Ownership::Stream); + + // this thread just handles receiving the handshake and sending a busy signal without blocking + // the server thread + RemoteServerPacket type = ser.ReadChunk(); + + if(ser.IsErrored() || type != eRemoteServer_Handshake) + { + RDCWARN("Didn't receive proper handshake"); + SAFE_DELETE(threadData->socket); + return; + } + + SERIALISE_ELEMENT(version); + + ser.EndChunk(); + } + + { + WriteSerialiser ser(new StreamWriter(threadData->socket, Ownership::Nothing), + Ownership::Stream); + + ser.SetStreamingMode(true); + + if(version != RemoteServerProtocolVersion) + { + RDCLOG("Connection using protocol %u, but we are running %u", version, + RemoteServerProtocolVersion); + + { + SCOPED_SERIALISE_CHUNK(eRemoteServer_VersionMismatch); + } + } + else + { + SCOPED_SERIALISE_CHUNK(eRemoteServer_Busy); + } + } + SAFE_DELETE(threadData->socket); - return; + + RDCLOG("Closed inactive connection from %u.%u.%u.%u.", Network::GetIPOctet(ip, 0), + Network::GetIPOctet(ip, 1), Network::GetIPOctet(ip, 2), Network::GetIPOctet(ip, 3)); } - - uint32_t version = 0; - recvser->Serialise("version", version); - - SAFE_DELETE(recvser); - - if(version != RemoteServerProtocolVersion) - { - RDCLOG("Connection using protocol %u, but we are running %u", version, - RemoteServerProtocolVersion); - SendPacket(threadData->socket, eRemoteServer_VersionMismatch); - } - else - { - SendPacket(threadData->socket, eRemoteServer_Busy); - } - - SAFE_DELETE(threadData->socket); - - RDCLOG("Closed inactive connection from %u.%u.%u.%u.", Network::GetIPOctet(ip, 0), - Network::GetIPOctet(ip, 1), Network::GetIPOctet(ip, 2), Network::GetIPOctet(ip, 3)); } static void ActiveRemoteClientThread(ClientThread *threadData) @@ -171,40 +146,60 @@ static void ActiveRemoteClientThread(ClientThread *threadData) uint32_t ip = client->GetRemoteIP(); - RemoteServerPacket type = eRemoteServer_Noop; - Serialiser *handshakeSer = NULL; - - if(!RecvPacket(threadData->socket, type, &handshakeSer) || type != eRemoteServer_Handshake) - { - RDCWARN("Didn't receive proper handshake"); - SAFE_DELETE(client); - return; - } - uint32_t version = 0; - handshakeSer->Serialise("version", version); - SAFE_DELETE(handshakeSer); + { + ReadSerialiser ser(new StreamReader(client, Ownership::Nothing), Ownership::Stream); - if(version != RemoteServerProtocolVersion) - { - RDCLOG("Connection using protocol %u, but we are running %u", version, - RemoteServerProtocolVersion); - SendPacket(threadData->socket, eRemoteServer_VersionMismatch); - SAFE_DELETE(client); - return; - } - else - { - // handshake and continue - SendPacket(threadData->socket, eRemoteServer_Handshake); + // this thread just handles receiving the handshake and sending a busy signal without blocking + // the server thread + RemoteServerPacket type = ser.ReadChunk(); + + if(ser.IsErrored() || type != eRemoteServer_Handshake) + { + RDCWARN("Didn't receive proper handshake"); + SAFE_DELETE(client); + return; + } + + SERIALISE_ELEMENT(version); + + ser.EndChunk(); } - vector tempFiles; + { + WriteSerialiser ser(new StreamWriter(client, Ownership::Nothing), Ownership::Stream); + + ser.SetStreamingMode(true); + + if(version != RemoteServerProtocolVersion) + { + RDCLOG("Connection using protocol %u, but we are running %u", version, + RemoteServerProtocolVersion); + + { + SCOPED_SERIALISE_CHUNK(eRemoteServer_VersionMismatch); + } + SAFE_DELETE(client); + return; + } + else + { + // handshake and continue + SCOPED_SERIALISE_CHUNK(eRemoteServer_Handshake); + } + } + + std::vector tempFiles; IRemoteDriver *driver = NULL; ReplayProxy *proxy = NULL; + RDCFile *rdc = NULL; + Callstack::StackResolver *resolver = NULL; - Serialiser sendSer("", Serialiser::WRITING, false); + WriteSerialiser writer(new StreamWriter(client, Ownership::Nothing), Ownership::Stream); + ReadSerialiser reader(new StreamReader(client, Ownership::Nothing), Ownership::Stream); + + writer.SetStreamingMode(true); while(client) { @@ -214,205 +209,374 @@ static void ActiveRemoteClientThread(ClientThread *threadData) if(threadData->killThread) break; - RemoteServerPacket sendType = eRemoteServer_Noop; - sendSer.Rewind(); - Threading::Sleep(4); if(client->IsRecvDataWaiting()) { - type = eRemoteServer_Noop; - Serialiser *recvser = NULL; + RemoteServerPacket type = reader.ReadChunk(); - if(!RecvPacket(client, type, &recvser)) + if(reader.IsErrored() || writer.IsErrored()) break; if(client == NULL) - { - SAFE_DELETE(recvser); continue; - } - else if(type == eRemoteServer_Ping) + + if(type == eRemoteServer_Ping) { - sendType = eRemoteServer_Ping; + reader.EndChunk(); + + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_Ping); } else if(type == eRemoteServer_RemoteDriverList) { - map drivers = RenderDoc::Inst().GetRemoteDrivers(); - - sendType = eRemoteServer_RemoteDriverList; + reader.EndChunk(); + std::map drivers = RenderDoc::Inst().GetRemoteDrivers(); uint32_t count = (uint32_t)drivers.size(); - sendSer.Serialise("", count); + + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_RemoteDriverList); + SERIALISE_ELEMENT(count); for(auto it = drivers.begin(); it != drivers.end(); ++it) { RDCDriver driverType = it->first; - sendSer.Serialise("", driverType); - sendSer.Serialise("", (*it).second); + const std::string &driverName = it->second; + + SERIALISE_ELEMENT(driverType); + SERIALISE_ELEMENT(driverName); } } else if(type == eRemoteServer_HomeDir) { - sendType = eRemoteServer_HomeDir; + reader.EndChunk(); - string home = FileIO::GetHomeFolderFilename(); - sendSer.Serialise("", home); + std::string home = FileIO::GetHomeFolderFilename(); + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_HomeDir); + SERIALISE_ELEMENT(home); + } } else if(type == eRemoteServer_ListDir) { - string path; - recvser->Serialise("path", path); + std::string path; - sendType = eRemoteServer_ListDir; + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); + } + + reader.EndChunk(); std::vector files = FileIO::GetFilesInDirectory(path.c_str()); - sendSer.Serialise("", files); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ListDir); + SERIALISE_ELEMENT(files); + } } else if(type == eRemoteServer_CopyCaptureFromRemote) { - string path; - recvser->Serialise("path", path); + std::string path; - if(!SendChunkedFile(client, eRemoteServer_CopyCaptureFromRemote, path.c_str(), sendSer, NULL)) { - RDCERR("Network error sending file"); - SAFE_DELETE(recvser); - break; + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); } - sendSer.Rewind(); + reader.EndChunk(); + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureFromRemote); + + StreamReader fileStream(FileIO::fopen(path.c_str(), "rb")); + ser.SerialiseStream(path, fileStream); + } } else if(type == eRemoteServer_CopyCaptureToRemote) { - string cap_file; - string dummy, dummy2; - FileIO::GetDefaultFiles("remotecopy", cap_file, dummy, dummy2); + std::string path; + std::string dummy, dummy2; + FileIO::GetDefaultFiles("remotecopy", path, dummy, dummy2); - Serialiser *fileRecv = NULL; + RDCLOG("Copying file to local path '%s'.", path.c_str()); - RDCLOG("Copying file to local path '%s'.", cap_file.c_str()); - - if(!RecvChunkedFile(client, type, cap_file.c_str(), fileRecv, NULL)) { - FileIO::Delete(cap_file.c_str()); + READ_DATA_SCOPE(); + + StreamWriter streamWriter(FileIO::fopen(path.c_str(), "wb"), Ownership::Stream); + + ser.SerialiseStream(path.c_str(), streamWriter, NULL); + } + + reader.EndChunk(); + + if(reader.IsErrored()) + { + FileIO::Delete(path.c_str()); RDCERR("Network error receiving file"); - - SAFE_DELETE(fileRecv); - SAFE_DELETE(recvser); break; } RDCLOG("File received."); - tempFiles.push_back(cap_file); + tempFiles.push_back(path); - SAFE_DELETE(fileRecv); - - sendType = eRemoteServer_CopyCaptureToRemote; - sendSer.Serialise("path", cap_file); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureToRemote); + SERIALISE_ELEMENT(path); + } } else if(type == eRemoteServer_TakeOwnershipCapture) { - string cap_file; - recvser->Serialise("filename", cap_file); + std::string path; - RDCLOG("Taking ownership of '%s'.", cap_file.c_str()); + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); + } - tempFiles.push_back(cap_file); + reader.EndChunk(); + + RDCLOG("Taking ownership of '%s'.", path.c_str()); + + tempFiles.push_back(path); } else if(type == eRemoteServer_ShutdownServer) { + reader.EndChunk(); + RDCLOG("Requested to shut down."); threadData->killServer = true; threadData->killThread = true; - sendType = eRemoteServer_ShutdownServer; + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ShutdownServer); + } } else if(type == eRemoteServer_OpenLog) { - string cap_file; - recvser->Serialise("filename", cap_file); + std::string path; - RDCASSERT(driver == NULL && proxy == NULL); - - RDCDriver driverType = RDC_Unknown; - string driverName = ""; - uint64_t fileMachineIdent = 0; - ReplayStatus status = RenderDoc::Inst().FillInitParams(cap_file.c_str(), driverType, - driverName, fileMachineIdent, NULL); - - if(status != ReplayStatus::Succeeded) { - RDCERR("Failed to open %s", cap_file.c_str()); + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); } - else if(RenderDoc::Inst().HasRemoteDriver(driverType)) + + reader.EndChunk(); + + RDCASSERT(driver == NULL && proxy == NULL && rdc == NULL); + ReplayStatus status = ReplayStatus::InternalError; + + rdc = new RDCFile(); + rdc->Open(path.c_str()); + + if(rdc->ErrorCode() != ContainerError::NoError) { - ProgressLoopData progressData; + RDCERR("Failed to open '%s': %d", path.c_str(), rdc->ErrorCode()); - progressData.sock = client; - progressData.killsignal = false; - progressData.progress = 0.0f; - - RenderDoc::Inst().SetProgressPtr(&progressData.progress); - - Threading::ThreadHandle ticker = - Threading::CreateThread([&progressData]() { ProgressTicker(&progressData); }); - - status = RenderDoc::Inst().CreateRemoteDriver(driverType, cap_file.c_str(), &driver); - - if(status != ReplayStatus::Succeeded || driver == NULL) + switch(rdc->ErrorCode()) { - RDCERR("Failed to create remote driver for driver type %d name %s", driverType, - driverName.c_str()); - } - else - { - driver->ReadLogInitialisation(); - - RenderDoc::Inst().SetProgressPtr(NULL); - - progressData.killsignal = true; - Threading::JoinThread(ticker); - Threading::CloseThread(ticker); - - proxy = new ReplayProxy(client, driver); + case ContainerError::FileNotFound: status = ReplayStatus::FileNotFound; break; + case ContainerError::FileIO: status = ReplayStatus::FileIOFailed; break; + case ContainerError::Corrupt: status = ReplayStatus::FileCorrupted; break; + case ContainerError::UnsupportedVersion: + status = ReplayStatus::FileIncompatibleVersion; + break; + default: break; } } else { - RDCERR("File needs driver for %s which isn't supported!", driverName.c_str()); + if(RenderDoc::Inst().HasRemoteDriver(rdc->GetDriver())) + { + bool kill = false; + float progress = 0.0f; - status = ReplayStatus::APIUnsupported; + RenderDoc::Inst().SetProgressPtr(&progress); + + Threading::ThreadHandle ticker = Threading::CreateThread([&writer, &kill, &progress]() { + while(!kill) + { + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpenProgress); + SERIALISE_ELEMENT(progress); + } + Threading::Sleep(100); + } + }); + + status = RenderDoc::Inst().CreateRemoteDriver(rdc, &driver); + + if(status != ReplayStatus::Succeeded || driver == NULL) + { + RDCERR("Failed to create remote driver for driver '%s'", rdc->GetDriverName().c_str()); + } + else + { + driver->ReadLogInitialisation(rdc); + + RenderDoc::Inst().SetProgressPtr(NULL); + + kill = true; + Threading::JoinThread(ticker); + Threading::CloseThread(ticker); + + proxy = new ReplayProxy(reader, writer, driver); + } + } + else + { + RDCERR("File needs driver for '%s' which isn't supported!", rdc->GetDriverName().c_str()); + + status = ReplayStatus::APIUnsupported; + } } - sendType = eRemoteServer_LogOpened; - sendSer.Serialise("status", status); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpened); + SERIALISE_ELEMENT(status); + } + } + else if(type == eRemoteServer_HasCallstacks) + { + reader.EndChunk(); + + bool HasCallstacks = rdc && rdc->SectionIndex(SectionType::ResolveDatabase) >= 0; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_HasCallstacks); + SERIALISE_ELEMENT(HasCallstacks); + } + } + else if(type == eRemoteServer_InitResolver) + { + reader.EndChunk(); + + bool success = false; + + int sectionIndex = rdc ? rdc->SectionIndex(SectionType::ResolveDatabase) : -1; + + SAFE_DELETE(resolver); + if(sectionIndex >= 0) + { + StreamReader *sectionReader = rdc->ReadSection(sectionIndex); + + std::vector buf; + buf.resize((size_t)sectionReader->GetSize()); + success = sectionReader->Read(buf.data(), sectionReader->GetSize()); + + delete sectionReader; + + if(success) + { + float progress = 0.0f; + + Threading::ThreadHandle ticker = + Threading::CreateThread([&writer, &resolver, &progress]() { + while(!resolver) + { + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ResolverProgress); + SERIALISE_ELEMENT(progress); + } + Threading::Sleep(100); + } + }); + + resolver = Callstack::MakeResolver(buf.data(), buf.size(), &progress, NULL); + + Threading::JoinThread(ticker); + Threading::CloseThread(ticker); + } + else + { + RDCERR("Failed to read resolve database."); + } + } + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_InitResolver); + SERIALISE_ELEMENT(success); + } + } + else if(type == eRemoteServer_GetResolve) + { + rdcarray StackAddresses; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(StackAddresses); + } + + reader.EndChunk(); + + rdcarray StackFrames; + + if(resolver) + { + StackFrames.reserve(StackAddresses.size()); + for(uint64_t frame : StackAddresses) + { + Callstack::AddressDetails info = resolver->GetAddr(frame); + StackFrames.push_back(info.formattedString()); + } + } + else + { + StackFrames = {""}; + } + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_GetResolve); + SERIALISE_ELEMENT(StackFrames); + } } else if(type == eRemoteServer_CloseLog) { + reader.EndChunk(); + if(driver) driver->Shutdown(); driver = NULL; SAFE_DELETE(proxy); + SAFE_DELETE(rdc); + SAFE_DELETE(resolver); } else if(type == eRemoteServer_ExecuteAndInject) { - string app, workingDir, cmdLine, logfile; + std::string app, workingDir, cmdLine, logfile; CaptureOptions opts; - recvser->Serialise("app", app); - recvser->Serialise("workingDir", workingDir); - recvser->Serialise("cmdLine", cmdLine); - recvser->Serialise("opts", opts); - rdcarray env; - recvser->Serialise("env", env); - uint32_t ident = uint32_t(ReplayStatus::NetworkIOFailed); + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(app); + SERIALISE_ELEMENT(workingDir); + SERIALISE_ELEMENT(cmdLine); + SERIALISE_ELEMENT(opts); + SERIALISE_ELEMENT(env); + } + + reader.EndChunk(); + + uint32_t ident = 0; if(threadData->allowExecution) { @@ -424,14 +588,15 @@ static void ActiveRemoteClientThread(ClientThread *threadData) RDCWARN("Requested to execute program - disallowing based on configuration"); } - sendType = eRemoteServer_ExecuteAndInject; - sendSer.Serialise("ident", ident); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ExecuteAndInject); + SERIALISE_ELEMENT(ident); + } } else if((int)type >= eReplayProxy_First && proxy) { - bool ok = proxy->Tick(type, recvser); - - SAFE_DELETE(recvser); + bool ok = proxy->Tick(type); if(!ok) break; @@ -439,14 +604,6 @@ static void ActiveRemoteClientThread(ClientThread *threadData) continue; } - SAFE_DELETE(recvser); - - if(sendType != eRemoteServer_Noop && !SendPacket(client, sendType, sendSer)) - { - RDCERR("Network error sending supported driver list"); - break; - } - continue; } } @@ -454,6 +611,8 @@ static void ActiveRemoteClientThread(ClientThread *threadData) if(driver) driver->Shutdown(); SAFE_DELETE(proxy); + SAFE_DELETE(rdc); + SAFE_DELETE(resolver); for(size_t i = 0; i < tempFiles.size(); i++) { @@ -527,7 +686,8 @@ void RenderDoc::BecomeRemoteServer(const char *listenhost, uint16_t port, volati { RDCLOG("No whitelist IP ranges configured - using default private IP ranges."); RDCLOG( - "Create a config file remoteserver.conf in ~/.renderdoc or %%APPDATA%%/renderdoc to narrow " + "Create a config file remoteserver.conf in ~/.renderdoc or %%APPDATA%%/renderdoc to " + "narrow " "this down or accept connections from more ranges."); listenRanges.push_back(std::make_pair(Network::MakeIP(10, 0, 0, 0), 0xff000000)); @@ -679,25 +839,38 @@ void RenderDoc::BecomeRemoteServer(const char *listenhost, uint16_t port, volati struct RemoteServer : public IRemoteServer { public: - RemoteServer(Network::Socket *sock, const char *hostname) : m_Socket(sock), m_hostname(hostname) + RemoteServer(Network::Socket *sock, const char *hostname) + : m_Socket(sock), + m_hostname(hostname), + reader(new StreamReader(sock, Ownership::Nothing), Ownership::Stream), + writer(new StreamWriter(sock, Ownership::Nothing), Ownership::Stream) { - map m = RenderDoc::Inst().GetReplayDrivers(); + writer.SetStreamingMode(true); + + std::map m = RenderDoc::Inst().GetReplayDrivers(); m_Proxies.reserve(m.size()); for(auto it = m.begin(); it != m.end(); ++it) m_Proxies.push_back(*it); } - const string &hostname() const { return m_hostname; } + const std::string &hostname() const { return m_hostname; } virtual ~RemoteServer() { SAFE_DELETE(m_Socket); } void ShutdownConnection() { delete this; } void ShutdownServerAndConnection() { - Serialiser sendData("", Serialiser::WRITING, false); - Send(eRemoteServer_ShutdownServer, sendData); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ShutdownServer); + } + + { + READ_DATA_SCOPE(); + RemoteServerPacket type = ser.ReadChunk(); + ser.EndChunk(); + + RDCASSERT(type == eRemoteServer_ShutdownServer); + } - RemoteServerPacket type = eRemoteServer_Noop; - vector payload; - RecvPacket(m_Socket, type, payload); delete this; } bool Connected() { return m_Socket != NULL && m_Socket->Connected(); } @@ -706,14 +879,18 @@ public: if(!Connected()) return false; - Serialiser sendData("", Serialiser::WRITING, false); - Send(eRemoteServer_Ping, sendData); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_Ping); + } - RemoteServerPacket type = eRemoteServer_Noop; - Serialiser *ser = NULL; - Get(type, &ser); + RemoteServerPacket type; - SAFE_DELETE(ser); + { + READ_DATA_SCOPE(); + type = ser.ReadChunk(); + ser.EndChunk(); + } return type == eRemoteServer_Ping; } @@ -736,33 +913,39 @@ public: rdcarray out; { - Serialiser sendData("", Serialiser::WRITING, false); - Send(eRemoteServer_RemoteDriverList, sendData); + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_RemoteDriverList); + } - RemoteServerPacket type = eRemoteServer_RemoteDriverList; + { + READ_DATA_SCOPE(); - Serialiser *ser = NULL; - Get(type, &ser); + RemoteServerPacket type = ser.ReadChunk(); - if(ser) + if(type == eRemoteServer_RemoteDriverList) { uint32_t count = 0; - ser->Serialise("", count); + SERIALISE_ELEMENT(count); out.reserve(count); for(uint32_t i = 0; i < count; i++) { - RDCDriver driver = RDC_Unknown; - string name = ""; - ser->Serialise("", driver); - ser->Serialise("", name); + RDCDriver driverType = RDC_Unknown; + std::string driverName = ""; - out.push_back(name); + SERIALISE_ELEMENT(driverType); + SERIALISE_ELEMENT(driverName); + + out.push_back(driverName); } - - delete ser; } + else + { + RDCERR("Unexpected response to remote driver list request"); + } + + ser.EndChunk(); } return out; @@ -773,27 +956,31 @@ public: if(Android::IsHostADB(m_hostname.c_str())) return "/"; - rdcstr ret; - - Serialiser sendData("", Serialiser::WRITING, false); - Send(eRemoteServer_HomeDir, sendData); - - RemoteServerPacket type = eRemoteServer_HomeDir; - - Serialiser *ser = NULL; - Get(type, &ser); - - if(ser) { - string home; - ser->Serialise("", home); - - ret = home; - - delete ser; + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_HomeDir); } - return ret; + rdcstr home; + + { + READ_DATA_SCOPE(); + + RemoteServerPacket type = ser.ReadChunk(); + + if(type == eRemoteServer_HomeDir) + { + SERIALISE_ELEMENT(home); + } + else + { + RDCERR("Unexpected response to home folder request"); + } + + ser.EndChunk(); + } + + return home; } rdcarray ListFolder(const char *path) @@ -827,145 +1014,167 @@ public: return packages; } - string folderPath = path; - - Serialiser sendData("", Serialiser::WRITING, false); - sendData.Serialise("", folderPath); - Send(eRemoteServer_ListDir, sendData); - - RemoteServerPacket type = eRemoteServer_ListDir; - - Serialiser *ser = NULL; - Get(type, &ser); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ListDir); + SERIALISE_ELEMENT(path); + } rdcarray files; - if(ser) { - std::vector paths; + READ_DATA_SCOPE(); - ser->Serialise("", paths); + RemoteServerPacket type = ser.ReadChunk(); - files = paths; + if(type == eRemoteServer_ListDir) + { + SERIALISE_ELEMENT(files); + } + else + { + RDCERR("Unexpected response to list directory request"); + files.resize(1); + files[0].filename = path; + files[0].flags = PathProperty::ErrorUnknown; + } - delete ser; - } - else - { - files.resize(1); - files[0].filename = path; - files[0].flags = PathProperty::ErrorUnknown; + ser.EndChunk(); } return files; } - uint32_t ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, + uint32_t ExecuteAndInject(const char *a, const char *w, const char *c, const rdcarray &env, const CaptureOptions &opts) { const char *host = hostname().c_str(); if(Android::IsHostADB(host)) - return Android::StartAndroidPackageForCapture(host, app); + return Android::StartAndroidPackageForCapture(host, a); - string appstr = app && app[0] ? app : ""; - string workstr = workingDir && workingDir[0] ? workingDir : ""; - string cmdstr = cmdLine && cmdLine[0] ? cmdLine : ""; + std::string app = a && a[0] ? a : ""; + std::string workingDir = w && w[0] ? w : ""; + std::string cmdline = c && c[0] ? c : ""; - Serialiser sendData("", Serialiser::WRITING, false); - sendData.Serialise("app", appstr); - sendData.Serialise("workingDir", workstr); - sendData.Serialise("cmdLine", cmdstr); - sendData.Serialise("opts", (CaptureOptions &)opts); - sendData.Serialise("env", (rdcarray &)env); - - Send(eRemoteServer_ExecuteAndInject, sendData); - - RemoteServerPacket type = eRemoteServer_ExecuteAndInject; - - Serialiser *ser = NULL; - Get(type, &ser); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ExecuteAndInject); + SERIALISE_ELEMENT(app); + SERIALISE_ELEMENT(workingDir); + SERIALISE_ELEMENT(cmdline); + SERIALISE_ELEMENT(opts); + SERIALISE_ELEMENT(env); + } uint32_t ident = 0; - if(ser) - ser->Serialise("ident", ident); + { + READ_DATA_SCOPE(); + RemoteServerPacket type = ser.ReadChunk(); - SAFE_DELETE(ser); + if(type == eRemoteServer_ExecuteAndInject) + { + SERIALISE_ELEMENT(ident); + } + else + { + RDCERR("Unexpected response to execute and inject request"); + } + + ser.EndChunk(); + } return ident; } void CopyCaptureFromRemote(const char *remotepath, const char *localpath, float *progress) { - string path = remotepath; - Serialiser sendData("", Serialiser::WRITING, false); - sendData.Serialise("path", path); - Send(eRemoteServer_CopyCaptureFromRemote, sendData); + std::string path = remotepath; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureFromRemote); + SERIALISE_ELEMENT(path); + } float dummy = 0.0f; if(progress == NULL) progress = &dummy; - Serialiser *fileRecv = NULL; - - if(!RecvChunkedFile(m_Socket, eRemoteServer_CopyCaptureFromRemote, localpath, fileRecv, progress)) { - SAFE_DELETE(fileRecv); - RDCERR("Network error receiving file"); - return; + READ_DATA_SCOPE(); + RemoteServerPacket type = ser.ReadChunk(); + + if(type == eRemoteServer_CopyCaptureFromRemote) + { + StreamWriter streamWriter(FileIO::fopen(localpath, "wb"), Ownership::Stream); + + ser.SerialiseStream(localpath, streamWriter, NULL); + + if(ser.IsErrored()) + { + RDCERR("Network error receiving file"); + return; + } + } + else + { + RDCERR("Unexpected response to capture copy request"); + } + + ser.EndChunk(); } - SAFE_DELETE(fileRecv); } rdcstr CopyCaptureToRemote(const char *filename, float *progress) { - Serialiser sendData("", Serialiser::WRITING, false); - Send(eRemoteServer_CopyCaptureToRemote, sendData); - - float dummy = 0.0f; - if(progress == NULL) - progress = &dummy; - - sendData.Rewind(); - - if(!SendChunkedFile(m_Socket, eRemoteServer_CopyCaptureToRemote, filename, sendData, progress)) { - SAFE_DELETE(m_Socket); - return ""; + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureToRemote); + + StreamReader fileStream(FileIO::fopen(filename, "rb")); + ser.SerialiseStream(filename, fileStream); } - RemoteServerPacket type = eRemoteServer_Noop; - Serialiser *ser = NULL; - Get(type, &ser); + std::string path; - if(type == eRemoteServer_CopyCaptureToRemote && ser) { - string remotepath; - ser->Serialise("path", remotepath); - return remotepath; + READ_DATA_SCOPE(); + RemoteServerPacket type = ser.ReadChunk(); + + if(type == eRemoteServer_CopyCaptureToRemote) + { + SERIALISE_ELEMENT(path); + } + else + { + RDCERR("Unexpected response to capture copy request"); + } + + ser.EndChunk(); } - return ""; + return path; } void TakeOwnershipCapture(const char *filename) { - string logfile = filename; + std::string path = filename; - Serialiser sendData("", Serialiser::WRITING, false); - sendData.Serialise("logfile", logfile); - Send(eRemoteServer_TakeOwnershipCapture, sendData); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_TakeOwnershipCapture); + SERIALISE_ELEMENT(path); + } } rdcpair OpenCapture(uint32_t proxyid, const char *filename, - float *progress) + float *progressPtr) { rdcpair ret; ret.first = ReplayStatus::InternalError; ret.second = NULL; - string logfile = filename; - if(proxyid != ~0U && proxyid >= m_Proxies.size()) { RDCERR("Invalid proxy driver id %d specified for remote renderer", proxyid); @@ -974,45 +1183,51 @@ public: } float dummy = 0.0f; - if(progress == NULL) - progress = &dummy; + if(progressPtr == NULL) + progressPtr = &dummy; + + float &progress = *progressPtr; // if the proxy id is ~0U, then we just don't care so let RenderDoc pick the most // appropriate supported proxy for the current platform. RDCDriver proxydrivertype = proxyid == ~0U ? RDC_Unknown : m_Proxies[proxyid].first; - Serialiser sendData("", Serialiser::WRITING, false); - sendData.Serialise("logfile", logfile); - Send(eRemoteServer_OpenLog, sendData); - - Serialiser *progressSer = NULL; - RemoteServerPacket type = eRemoteServer_Noop; - while(m_Socket) { - Get(type, &progressSer); - - if(!m_Socket || progressSer == NULL || type != eRemoteServer_LogOpenProgress) - break; - - progressSer->Serialise("", *progress); - - RDCLOG("% 3.0f%%...", (*progress) * 100.0f); - - SAFE_DELETE(progressSer); + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_OpenLog); + SERIALISE_ELEMENT(filename); } - if(!m_Socket || progressSer == NULL || type != eRemoteServer_LogOpened) + RemoteServerPacket type = eRemoteServer_Noop; + while(!reader.IsErrored()) + { + READ_DATA_SCOPE(); + type = ser.ReadChunk(); + + if(reader.IsErrored() || type != eRemoteServer_LogOpenProgress) + break; + + SERIALISE_ELEMENT(progress); + + ser.EndChunk(); + + RDCLOG("% 3.0f%%...", progress * 100.0f); + } + + if(reader.IsErrored() || type != eRemoteServer_LogOpened) { ret.first = ReplayStatus::NetworkIOFailed; return ret; } ReplayStatus status = ReplayStatus::Succeeded; - progressSer->Serialise("status", status); + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(status); + ser.EndChunk(); + } - SAFE_DELETE(progressSer); - - *progress = 1.0f; + progress = 1.0f; if(status != ReplayStatus::Succeeded) { @@ -1023,7 +1238,7 @@ public: RDCLOG("Log ready on replay host"); IReplayDriver *proxyDriver = NULL; - status = RenderDoc::Inst().CreateReplayDriver(proxydrivertype, NULL, &proxyDriver); + status = RenderDoc::Inst().CreateProxyReplayDriver(proxydrivertype, &proxyDriver); if(status != ReplayStatus::Succeeded || !proxyDriver) { @@ -1035,7 +1250,7 @@ public: ReplayController *rend = new ReplayController(); - ReplayProxy *proxy = new ReplayProxy(m_Socket, proxyDriver); + ReplayProxy *proxy = new ReplayProxy(reader, writer, proxyDriver); status = rend->SetDevice(proxy); if(status != ReplayStatus::Succeeded) @@ -1053,36 +1268,132 @@ public: return ret; } + bool HasCallstacks() + { + if(!Connected()) + return false; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_HasCallstacks); + } + + bool hasCallstacks = false; + + { + READ_DATA_SCOPE(); + RemoteServerPacket type = ser.ReadChunk(); + + if(type == eRemoteServer_HasCallstacks) + { + SERIALISE_ELEMENT(hasCallstacks); + } + else + { + RDCERR("Unexpected response to has callstacks request"); + } + + ser.EndChunk(); + } + + return hasCallstacks; + } + + bool InitResolver(float *progressPtr, volatile bool *killSignal) + { + float dummy = 0.0f; + if(progressPtr == NULL) + progressPtr = &dummy; + + float &progress = *progressPtr; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_InitResolver); + } + + RemoteServerPacket type = eRemoteServer_Noop; + while(!reader.IsErrored()) + { + READ_DATA_SCOPE(); + type = ser.ReadChunk(); + + if(reader.IsErrored() || type != eRemoteServer_ResolverProgress) + break; + + SERIALISE_ELEMENT(progress); + + ser.EndChunk(); + + RDCLOG("% 3.0f%%...", progress * 100.0f); + } + + if(reader.IsErrored() || type != eRemoteServer_InitResolver) + { + return false; + } + + bool success = false; + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(success); + ser.EndChunk(); + } + + progress = 1.0f; + + return success; + } + + rdcarray GetResolve(const rdcarray &callstack) + { + if(!Connected()) + return {""}; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_GetResolve); + SERIALISE_ELEMENT(callstack); + } + + rdcarray StackFrames; + + { + READ_DATA_SCOPE(); + RemoteServerPacket type = ser.ReadChunk(); + + if(type == eRemoteServer_GetResolve) + { + SERIALISE_ELEMENT(StackFrames); + } + else + { + RDCERR("Unexpected response to resolve request"); + } + + ser.EndChunk(); + } + + return StackFrames; + } + void CloseCapture(IReplayController *rend) { - Serialiser sendData("", Serialiser::WRITING, false); - Send(eRemoteServer_CloseLog, sendData); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_CloseLog); + } rend->Shutdown(); } private: Network::Socket *m_Socket; - string m_hostname; + WriteSerialiser writer; + ReadSerialiser reader; + std::string m_hostname; - void Send(RemoteServerPacket type, const Serialiser &ser) { SendPacket(m_Socket, type, ser); } - void Get(RemoteServerPacket &type, Serialiser **ser) - { - vector payload; - - if(!RecvPacket(m_Socket, type, payload)) - { - SAFE_DELETE(m_Socket); - if(ser) - *ser = NULL; - return; - } - - if(ser) - *ser = new Serialiser(payload.size(), &payload[0], false); - } - - vector > m_Proxies; + std::vector > m_Proxies; }; extern "C" RENDERDOC_API ReplayStatus RENDERDOC_CC @@ -1106,7 +1417,8 @@ RENDERDOC_CreateRemoteServerConnection(const char *host, uint32_t port, IRemoteS std::string deviceID; Android::extractDeviceIDAndIndex(host, index, deviceID); - // each subsequent device gets a new range of ports. The deviceID isn't needed since we already + // each subsequent device gets a new range of ports. The deviceID isn't needed since we + // already // forwarded the ports to the right devices. if(port == RENDERDOC_GetDefaultRemoteServerPort()) port += RenderDoc_AndroidPortOffset * (index + 1); @@ -1122,30 +1434,45 @@ RENDERDOC_CreateRemoteServerConnection(const char *host, uint32_t port, IRemoteS return ReplayStatus::NetworkIOFailed; } - Serialiser sendData("", Serialiser::WRITING, false); uint32_t version = RemoteServerProtocolVersion; - sendData.Serialise("version", version); - SendPacket(sock, eRemoteServer_Handshake, sendData); - RemoteServerPacket type = (RemoteServerPacket)RecvPacket(sock); - - if(type == eRemoteServer_Busy) { - SAFE_DELETE(sock); - return ReplayStatus::NetworkRemoteBusy; + WriteSerialiser ser(new StreamWriter(sock, Ownership::Nothing), Ownership::Stream); + + ser.SetStreamingMode(true); + + SCOPED_SERIALISE_CHUNK(eRemoteServer_Handshake); + SERIALISE_ELEMENT(version); } - if(type == eRemoteServer_VersionMismatch) - { - SAFE_DELETE(sock); - return ReplayStatus::NetworkVersionMismatch; - } - - if(type != eRemoteServer_Handshake) - { - RDCWARN("Didn't get proper handshake"); - SAFE_DELETE(sock); + if(!sock->Connected()) return ReplayStatus::NetworkIOFailed; + + { + ReadSerialiser ser(new StreamReader(sock, Ownership::Nothing), Ownership::Stream); + + RemoteServerPacket type = ser.ReadChunk(); + + ser.EndChunk(); + + if(type == eRemoteServer_Busy) + { + SAFE_DELETE(sock); + return ReplayStatus::NetworkRemoteBusy; + } + + if(type == eRemoteServer_VersionMismatch) + { + SAFE_DELETE(sock); + return ReplayStatus::NetworkVersionMismatch; + } + + if(ser.IsErrored() || type != eRemoteServer_Handshake) + { + RDCWARN("Didn't get proper handshake"); + SAFE_DELETE(sock); + return ReplayStatus::NetworkIOFailed; + } } *rend = new RemoteServer(sock, host);