Пример #1
0
void RenderDoc::BecomeReplayHost(volatile bool32 &killReplay)
{
	Network::Socket *sock = Network::CreateServerSocket("0.0.0.0", RenderDoc_ReplayNetworkPort, 1);

	if(sock == NULL)
		return;
	
	Serialiser ser("", Serialiser::WRITING, false);

	bool newlyReady = true;
		
	while(!killReplay)
	{
		if(newlyReady)
		{
			RDCLOG("Replay host ready for requests.");
			newlyReady = false;
		}
		
		Network::Socket *client = sock->AcceptClient(false);

		if(client == NULL)
		{
			if(!sock->Connected())
			{
				RDCERR("Error in accept - shutting down server");

				SAFE_DELETE(sock);
				return;
			}

			Threading::Sleep(5);

			continue;
		}

		newlyReady = true;

		RDCLOG("Connection received.");
		
		map<RDCDriver,string> drivers = RenderDoc::Inst().GetRemoteDrivers();

		uint32_t count = (uint32_t)drivers.size();
		ser.Serialise("", count);

		for(auto it=drivers.begin(); it != drivers.end(); ++it)
		{
			RDCDriver driver = it->first;
			ser.Serialise("", driver);
			ser.Serialise("", (*it).second);
		}

		if(!SendPacket(client, ePacket_RemoteDriverList, ser))
		{
			RDCERR("Network error sending supported driver list");
			SAFE_DELETE(client);
			continue;
		}

		Threading::Sleep(4);

		// don't care about the result, just want to check that the socket hasn't been gracefully shut down
		client->IsRecvDataWaiting();
		if(!client->Connected())
		{
			RDCLOG("Connection closed after sending remote driver list");
			SAFE_DELETE(client);
			continue;
		}

		string cap_file;
		string dummy, dummy2;
		FileIO::GetDefaultFiles("remotecopy", cap_file, dummy, dummy2);

		Serialiser *fileRecv = NULL;

		if(!RecvChunkedFile(client, ePacket_CopyCapture, cap_file.c_str(), fileRecv, NULL))
		{
			FileIO::Delete(cap_file.c_str());
			
			RDCERR("Network error receiving file");

			SAFE_DELETE(fileRecv);
			SAFE_DELETE(client);
			continue;
		}
		
		RDCLOG("File received.");
		
		SAFE_DELETE(fileRecv);

		RDCDriver driverType = RDC_Unknown;
		string driverName = "";
		RenderDoc::Inst().FillInitParams(cap_file.c_str(), driverType, driverName, NULL);

		if(RenderDoc::Inst().HasRemoteDriver(driverType))
		{
			ProgressLoopData data;

			data.sock = client;
			data.killsignal = false;
			data.progress = 0.0f;

			RenderDoc::Inst().SetProgressPtr(&data.progress);

			Threading::ThreadHandle ticker = Threading::CreateThread(ProgressTicker, &data);

			IRemoteDriver *driver = NULL;
			auto status = RenderDoc::Inst().CreateRemoteDriver(driverType, cap_file.c_str(), &driver);

			if(status != eReplayCreate_Success || driver == NULL)
			{
				RDCERR("Failed to create remote driver for driver type %d name %s", driverType, driverName.c_str());
				SAFE_DELETE(client);
				continue;
			}
		
			driver->ReadLogInitialisation();
	
			RenderDoc::Inst().SetProgressPtr(NULL);

			data.killsignal = true;
			Threading::JoinThread(ticker);
			Threading::CloseThread(ticker);

			FileIO::Delete(cap_file.c_str());

			SendPacket(client, ePacket_LogReady);

			ProxySerialiser *proxy = new ProxySerialiser(client, driver);

			while(client)
			{
				if(!proxy->Tick() || killReplay)
				{
					SAFE_DELETE(client);
				}
			}
			
			driver->Shutdown();
			
			RDCLOG("Closing replay connection");

			SAFE_DELETE(proxy);
			SAFE_DELETE(client);
		}
		else
		{
			RDCERR("File needs driver for %s which isn't supported!", driverName.c_str());
		
			FileIO::Delete(cap_file.c_str());
		}

		SAFE_DELETE(client);
	}
}
Пример #2
0
void RenderDoc::RemoteAccessClientThread(void *s)
{
  Threading::KeepModuleAlive();

  Network::Socket *client = (Network::Socket *)s;

  Serialiser ser("", Serialiser::WRITING, false);

  string api = "";
  RDCDriver driver;
  RenderDoc::Inst().GetCurrentDriver(driver, api);

  ser.Rewind();

  string target = RenderDoc::Inst().GetCurrentTarget();
  ser.Serialise("", target);
  ser.Serialise("", api);
  uint32_t mypid = Process::GetCurrentPID();
  ser.Serialise("", mypid);

  if(!SendPacket(client, ePacket_Handshake, ser))
  {
    SAFE_DELETE(client);

    {
      SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock);
      RenderDoc::Inst().m_SingleClientName = "";
    }

    Threading::ReleaseModuleExitThread();
    return;
  }

  const int pingtime = 1000;    // ping every 1000ms
  const int ticktime = 10;      // tick every 10ms
  int curtime = 0;

  vector<CaptureData> captures;
  vector<pair<uint32_t, uint32_t> > children;

  while(client)
  {
    if(RenderDoc::Inst().m_RemoteClientThreadShutdown || (client && !client->Connected()))
    {
      SAFE_DELETE(client);
      break;
    }

    ser.Rewind();

    Threading::Sleep(ticktime);
    curtime += ticktime;

    PacketType packetType = ePacket_Noop;

    string curapi;
    RenderDoc::Inst().GetCurrentDriver(driver, curapi);

    vector<CaptureData> caps = RenderDoc::Inst().GetCaptures();
    vector<pair<uint32_t, uint32_t> > childprocs = RenderDoc::Inst().GetChildProcesses();

    if(curapi != api)
    {
      api = curapi;

      ser.Serialise("", api);

      packetType = ePacket_RegisterAPI;
    }
    else if(caps.size() != captures.size())
    {
      uint32_t idx = (uint32_t)captures.size();

      captures.push_back(caps[idx]);

      packetType = ePacket_NewCapture;

      std::string path = FileIO::GetFullPathname(captures.back().path);

      ser.Serialise("", idx);
      ser.Serialise("", captures.back().timestamp);
      ser.Serialise("", path);

      uint32_t len = 0;
      RENDERDOC_GetThumbnail(captures.back().path.c_str(), NULL, len);
      byte *thumb = new byte[len];
      RENDERDOC_GetThumbnail(captures.back().path.c_str(), thumb, len);

      size_t l = len;
      ser.Serialise("", len);
      ser.SerialiseBuffer("", thumb, l);
      delete[] thumb;
    }
    else if(childprocs.size() != children.size())
    {
      uint32_t idx = (uint32_t)children.size();

      children.push_back(childprocs[idx]);

      packetType = ePacket_NewChild;

      ser.Serialise("", children.back().first);
      ser.Serialise("", children.back().second);
    }

    if(curtime < pingtime && packetType == ePacket_Noop)
    {
      if(client->IsRecvDataWaiting())
      {
        PacketType type;
        Serialiser *recvser = NULL;

        if(!RecvPacket(client, type, &recvser))
          SAFE_DELETE(client);

        if(client == NULL)
        {
          SAFE_DELETE(recvser);
          continue;
        }
        else if(type == ePacket_TriggerCapture)
        {
          RenderDoc::Inst().TriggerCapture();
        }
        else if(type == ePacket_QueueCapture)
        {
          uint32_t frameNum = 0;
          recvser->Serialise("", frameNum);

          RenderDoc::Inst().QueueCapture(frameNum);
        }
        else if(type == ePacket_CopyCapture)
        {
          caps = RenderDoc::Inst().GetCaptures();

          uint32_t id = 0;
          recvser->Serialise("", id);

          if(id < caps.size())
          {
            ser.Serialise("", id);

            if(!SendPacket(client, ePacket_CopyCapture, ser))
            {
              SAFE_DELETE(client);
              continue;
            }

            ser.Rewind();

            if(!SendChunkedFile(client, ePacket_CopyCapture, caps[id].path.c_str(), ser, NULL))
            {
              SAFE_DELETE(client);
              continue;
            }

            RenderDoc::Inst().MarkCaptureRetrieved(id);
          }
        }

        SAFE_DELETE(recvser);
      }

      continue;
    }

    curtime = 0;

    if(!SendPacket(client, packetType, ser))
    {
      SAFE_DELETE(client);
      continue;
    }
  }

  // give up our connection
  {
    SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock);
    RenderDoc::Inst().m_SingleClientName = "";
  }

  Threading::ReleaseModuleExitThread();
}
Пример #3
0
void RenderDoc::BecomeRemoteServer(const char *listenhost, uint16_t port, volatile bool32 &killReplay)
{
  Network::Socket *sock = Network::CreateServerSocket(listenhost, port, 1);

  if(sock == NULL)
    return;

  bool newlyReady = true;

  std::vector<std::pair<uint32_t, uint32_t> > listenRanges;
  bool allowExecution = true;

  FILE *f = FileIO::fopen(FileIO::GetAppFolderFilename("remoteserver.conf").c_str(), "r");

  while(f && !FileIO::feof(f))
  {
    string line = trim(FileIO::getline(f));

    if(line == "")
      continue;

    // skip comments
    if(line[0] == '#')
      continue;

    if(line.substr(0, sizeof("whitelist") - 1) == "whitelist")
    {
      uint32_t ip = 0, mask = 0;

      // CIDR notation
      bool found = Network::ParseIPRangeCIDR(line.c_str() + sizeof("whitelist"), ip, mask);

      if(found)
      {
        listenRanges.push_back(std::make_pair(ip, mask));
        continue;
      }
      else
      {
        RDCLOG("Couldn't parse IP range from: %s", line.c_str() + sizeof("whitelist"));
      }

      continue;
    }
    else if(line.substr(0, sizeof("noexec") - 1) == "noexec")
    {
      allowExecution = false;

      continue;
    }

    RDCLOG("Malformed line '%s'. See documentation for file format.", line.c_str());
  }

  if(f)
    FileIO::fclose(f);

  if(listenRanges.empty())
  {
    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 "
        "this down or accept connections from more ranges.");

    listenRanges.push_back(std::make_pair(Network::MakeIP(10, 0, 0, 0), 0xff000000));
    listenRanges.push_back(std::make_pair(Network::MakeIP(172, 16, 0, 0), 0xfff00000));
    listenRanges.push_back(std::make_pair(Network::MakeIP(192, 168, 0, 0), 0xffff0000));
  }

  RDCLOG("Allowing connections from:");

  for(size_t i = 0; i < listenRanges.size(); i++)
  {
    uint32_t ip = listenRanges[i].first;
    uint32_t mask = listenRanges[i].second;

    RDCLOG("%u.%u.%u.%u / %u.%u.%u.%u", Network::GetIPOctet(ip, 0), Network::GetIPOctet(ip, 1),
           Network::GetIPOctet(ip, 2), Network::GetIPOctet(ip, 3), Network::GetIPOctet(mask, 0),
           Network::GetIPOctet(mask, 1), Network::GetIPOctet(mask, 2), Network::GetIPOctet(mask, 3));
  }

  if(allowExecution)
    RDCLOG("Allowing execution commands");
  else
    RDCLOG("Blocking execution commands");

  while(!killReplay)
  {
    if(newlyReady)
    {
      RDCLOG("Replay host ready for requests.");
      newlyReady = false;
    }

    Network::Socket *client = sock->AcceptClient(false);

    if(client == NULL)
    {
      if(!sock->Connected())
      {
        RDCERR("Error in accept - shutting down server");

        SAFE_DELETE(sock);
        return;
      }

      Threading::Sleep(5);

      continue;
    }

    uint32_t ip = client->GetRemoteIP();

    RDCLOG("Connection received from %u.%u.%u.%u.", Network::GetIPOctet(ip, 0),
           Network::GetIPOctet(ip, 1), Network::GetIPOctet(ip, 2), Network::GetIPOctet(ip, 3));

    bool valid = false;

    for(size_t i = 0; i < listenRanges.size(); i++)
    {
      if(Network::MatchIPMask(ip, listenRanges[i].first, listenRanges[i].second))
      {
        valid = true;
        break;
      }
    }

    if(!valid)
    {
      RDCLOG("Doesn't match any listen range, closing connection.");
      SAFE_DELETE(client);
      continue;
    }

    Serialiser ser("", Serialiser::WRITING, false);

    newlyReady = true;

    map<RDCDriver, string> drivers = RenderDoc::Inst().GetRemoteDrivers();

    uint32_t count = (uint32_t)drivers.size();
    ser.Serialise("", count);

    for(auto it = drivers.begin(); it != drivers.end(); ++it)
    {
      RDCDriver driver = it->first;
      ser.Serialise("", driver);
      ser.Serialise("", (*it).second);
    }

    if(!SendPacket(client, ePacket_RemoteDriverList, ser))
    {
      RDCERR("Network error sending supported driver list");
      SAFE_DELETE(client);
      continue;
    }

    Threading::Sleep(4);

    // don't care about the result, just want to check that the socket hasn't been gracefully shut
    // down
    client->IsRecvDataWaiting();
    if(!client->Connected())
    {
      RDCLOG("Connection closed after sending remote driver list");
      SAFE_DELETE(client);
      continue;
    }

    string cap_file;
    string dummy, dummy2;
    FileIO::GetDefaultFiles("remotecopy", cap_file, dummy, dummy2);

    Serialiser *fileRecv = NULL;

    if(!RecvChunkedFile(client, ePacket_CopyCapture, cap_file.c_str(), fileRecv, NULL))
    {
      FileIO::Delete(cap_file.c_str());

      RDCERR("Network error receiving file");

      SAFE_DELETE(fileRecv);
      SAFE_DELETE(client);
      continue;
    }

    RDCLOG("File received.");

    SAFE_DELETE(fileRecv);

    RDCDriver driverType = RDC_Unknown;
    string driverName = "";
    RenderDoc::Inst().FillInitParams(cap_file.c_str(), driverType, driverName, NULL);

    if(RenderDoc::Inst().HasRemoteDriver(driverType))
    {
      ProgressLoopData data;

      data.sock = client;
      data.killsignal = false;
      data.progress = 0.0f;

      RenderDoc::Inst().SetProgressPtr(&data.progress);

      Threading::ThreadHandle ticker = Threading::CreateThread(ProgressTicker, &data);

      IRemoteDriver *driver = NULL;
      auto status = RenderDoc::Inst().CreateRemoteDriver(driverType, cap_file.c_str(), &driver);

      if(status != eReplayCreate_Success || driver == NULL)
      {
        RDCERR("Failed to create remote driver for driver type %d name %s", driverType,
               driverName.c_str());
        SAFE_DELETE(client);
        continue;
      }

      driver->ReadLogInitialisation();

      RenderDoc::Inst().SetProgressPtr(NULL);

      data.killsignal = true;
      Threading::JoinThread(ticker);
      Threading::CloseThread(ticker);

      FileIO::Delete(cap_file.c_str());

      SendPacket(client, ePacket_LogReady);

      ProxySerialiser *proxy = new ProxySerialiser(client, driver);

      while(client)
      {
        if(!proxy->Tick() || killReplay)
        {
          SAFE_DELETE(client);
        }
      }

      driver->Shutdown();

      RDCLOG("Closing replay connection");

      SAFE_DELETE(proxy);
      SAFE_DELETE(client);
    }
    else
    {
      RDCERR("File needs driver for %s which isn't supported!", driverName.c_str());

      FileIO::Delete(cap_file.c_str());
    }

    SAFE_DELETE(client);
  }

  SAFE_DELETE(sock);
}
Пример #4
0
void RenderDoc::RemoteAccessServerThread(void *s)
{
  Threading::KeepModuleAlive();

  Network::Socket *sock = (Network::Socket *)s;

  RenderDoc::Inst().m_SingleClientName = "";

  Threading::ThreadHandle clientThread = 0;

  RenderDoc::Inst().m_RemoteClientThreadShutdown = false;

  while(!RenderDoc::Inst().m_RemoteServerThreadShutdown)
  {
    Network::Socket *client = sock->AcceptClient(false);

    if(client == NULL)
    {
      if(!sock->Connected())
      {
        RDCERR("Error in accept - shutting down server");

        SAFE_DELETE(sock);
        Threading::ReleaseModuleExitThread();
        return;
      }

      Threading::Sleep(5);

      continue;
    }

    string existingClient;
    string newClient;
    bool kick = false;

    // receive handshake from client and get its name
    {
      PacketType type;
      Serialiser *ser = NULL;
      if(!RecvPacket(client, type, &ser))
      {
        SAFE_DELETE(ser);
        SAFE_DELETE(client);
        continue;
      }

      if(type != ePacket_Handshake)
      {
        SAFE_DELETE(ser);
        SAFE_DELETE(client);
        continue;
      }

      ser->SerialiseString("", newClient);
      ser->Serialise("", kick);

      SAFE_DELETE(ser);

      if(newClient.empty())
      {
        SAFE_DELETE(client);
        continue;
      }
    }

    // see if we have a client
    {
      SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock);
      existingClient = RenderDoc::Inst().m_SingleClientName;
    }

    if(!existingClient.empty() && kick)
    {
      // forcibly close communication thread which will kill the connection
      RenderDoc::Inst().m_RemoteClientThreadShutdown = true;
      Threading::JoinThread(clientThread);
      Threading::CloseThread(clientThread);
      clientThread = 0;
      RenderDoc::Inst().m_RemoteClientThreadShutdown = false;
      existingClient = "";
    }

    if(existingClient.empty())
    {
      SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock);
      RenderDoc::Inst().m_SingleClientName = newClient;
    }

    // if we've claimed client status, spawn a thread to communicate
    if(existingClient.empty() || kick)
    {
      clientThread = Threading::CreateThread(RemoteAccessClientThread, client);
      continue;
    }
    else
    {
      // if we've been asked to kick the existing connection off
      // reject this connection and tell them who is busy
      Serialiser ser("", Serialiser::WRITING, false);

      string api = "";
      RDCDriver driver;
      RenderDoc::Inst().GetCurrentDriver(driver, api);

      string target = RenderDoc::Inst().GetCurrentTarget();
      ser.Serialise("", target);
      ser.Serialise("", api);

      ser.SerialiseString("", RenderDoc::Inst().m_SingleClientName);

      // don't care about errors, we're going to close the connection either way
      SendPacket(client, ePacket_Busy, ser);

      SAFE_DELETE(client);
    }
  }

  RenderDoc::Inst().m_RemoteClientThreadShutdown = true;
  // don't join, just close the thread, as we can't wait while in the middle of module unloading
  Threading::CloseThread(clientThread);
  clientThread = 0;

  Threading::ReleaseModuleExitThread();
}
Пример #5
0
void RenderDoc::RemoteAccessClientThread(void *s)
{
	Network::Socket *client = (Network::Socket *)s;

	Serialiser ser(L"", Serialiser::WRITING, false);

	wstring api = L"";
	RDCDriver driver;
	RenderDoc::Inst().GetCurrentDriver(driver, api);

	ser.Rewind();

	wstring target = RenderDoc::Inst().GetCurrentTarget();
	ser.Serialise("", target);
	ser.Serialise("", api);

	if(!SendPacket(client, ePacket_Handshake, ser))
	{
		SAFE_DELETE(client);

		{
			SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock);
			RenderDoc::Inst().m_SingleClientName = L"";
		}

		return;
	}

	const int pingtime = 1000; // ping every 1000ms
	const int ticktime = 10; // tick every 10ms
	int curtime = 0;

	vector<wstring> captures;

	while(client)
	{
		if(RenderDoc::Inst().m_RemoteClientThreadShutdown || (client && !client->Connected()))
		{
			SAFE_DELETE(client);
			break;
		}

		ser.Rewind();

		Threading::Sleep(ticktime);
		curtime += ticktime;

		PacketType packetType = ePacket_Noop;

		wstring curapi;
		RenderDoc::Inst().GetCurrentDriver(driver, curapi);

		if(curapi != api)
		{
			api = curapi;

			ser.Serialise("", api);

			packetType = ePacket_RegisterAPI;
		}
		else
		{
			vector<wstring> caps = RenderDoc::Inst().GetCaptures();

			if(caps.size() != captures.size())
			{
				uint32_t idx = (uint32_t)captures.size();

				captures.push_back(caps[idx]);

				packetType = ePacket_NewCapture;

				uint64_t timestamp = FileIO::GetModifiedTimestamp(captures.back().c_str());
				ser.Serialise("", idx);
				ser.Serialise("", timestamp);

				ser.Serialise("", captures.back());

				uint32_t len = 128*1024;
				byte *thumb = new byte[len];
				RENDERDOC_GetThumbnail(captures.back().c_str(), thumb, len);

				size_t l = len;
				ser.Serialise("", len);
				ser.SerialiseBuffer("", thumb, l);
				delete[] thumb;
			}
		}

		if(curtime < pingtime && packetType == ePacket_Noop)
		{
			if(client->IsRecvDataWaiting())
			{
				PacketType type;
				Serialiser *recvser = NULL;

				if(!RecvPacket(client, type, &recvser))
					SAFE_DELETE(client);

				if(client == NULL)
				{
					SAFE_DELETE(recvser);
					continue;
				}
				else if(type == ePacket_TriggerCapture)
				{
					RenderDoc::Inst().TriggerCapture();
				}
				else if(type == ePacket_QueueCapture)
				{
					uint32_t frameNum = 0;
					recvser->Serialise("", frameNum);
					
					RenderDoc::Inst().QueueCapture(frameNum);
				}
				else if(type == ePacket_CopyCapture)
				{
					vector<wstring> caps = RenderDoc::Inst().GetCaptures();

					uint32_t id = 0;
					recvser->Serialise("", id);

					if(id < caps.size())
					{
						ser.Serialise("", id);

						if(!SendPacket(client, ePacket_CopyCapture, ser))
						{
							SAFE_DELETE(client);
							continue;
						}

						ser.Rewind();

						if(!SendChunkedFile(client, ePacket_CopyCapture, caps[id].c_str(), ser, NULL))
						{
							SAFE_DELETE(client);
							continue;
						}

						RenderDoc::Inst().MarkCaptureRetrieved(id);
					}
				}

				SAFE_DELETE(recvser);
			}

			continue;
		}

		curtime = 0;

		if(!SendPacket(client, packetType, ser))
		{
			SAFE_DELETE(client);
			continue;
		}
	}
	
	// give up our connection
	{
		SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock);
		RenderDoc::Inst().m_SingleClientName = L"";
	}
}