Ejemplo n.º 1
0
TEST(ProcessTest, Remote)
{
  ASSERT_TRUE(GTEST_IS_THREADSAFE);

  RemoteProcess process;
  spawn(process);

  Future<Nothing> handler;
  EXPECT_CALL(process, handler(_, _))
    .WillOnce(FutureSatisfy(&handler));

  Try<Socket> create = Socket::create();
  ASSERT_SOME(create);

  Socket socket = create.get();

  AWAIT_READY(socket.connect(process.self().address));

  Message message;
  message.name = "handler";
  message.from = UPID();
  message.to = process.self();

  const string data = MessageEncoder::encode(&message);

  AWAIT_READY(socket.send(data));

  AWAIT_READY(handler);

  terminate(process);
  wait(process);
}
Ejemplo n.º 2
0
void ProcessCommander::onProcessFinished(RemoteProcess &process, bool error, int status)
{
	boost::mutex::scoped_lock lock(_mutex);
	
	if(_nodeCommands.RemoveNode(process.ClientHostname()) && _nodeCommands.Empty())
		onCurrentTaskFinished();
	
	if(error)
	{
		std::stringstream s;
		s << "Remote process to " << process.ClientHostname() << " reported an error";
		if(status != 0) s << " (status " << status << ")";
		_errors.push_back(s.str());
	}
}
Ejemplo n.º 3
0
// Like the 'remote' test but uses http::connect.
TEST(ProcessTest, Http1)
{
  ASSERT_TRUE(GTEST_IS_THREADSAFE);

  RemoteProcess process;
  spawn(process);

  http::URL url = http::URL(
      "http",
      process.self().address.ip,
      process.self().address.port,
      process.self().id + "/handler");

  Future<http::Connection> connect = http::connect(url);
  AWAIT_READY(connect);

  http::Connection connection = connect.get();

  Future<UPID> pid;
  Future<string> body;
  EXPECT_CALL(process, handler(_, _))
    .WillOnce(DoAll(FutureArg<0>(&pid),
                    FutureArg<1>(&body)));

  http::Request request;
  request.method = "POST";
  request.url = url;
  request.headers["User-Agent"] = "libprocess/";
  request.body = "hello world";

  // Send the libprocess request. Note that we will not
  // receive a 202 due to the use of the `User-Agent`
  // header, therefore we need to explicitly disconnect!
  Future<http::Response> response = connection.send(request);

  AWAIT_READY(body);
  ASSERT_EQ("hello world", body.get());

  AWAIT_READY(pid);
  ASSERT_EQ(UPID(), pid.get());

  EXPECT_TRUE(response.isPending());

  AWAIT_READY(connection.disconnect());

  terminate(process);
  wait(process);
}
Ejemplo n.º 4
0
void ProcessCommander::Run(bool finishConnections)
{
	_errors.clear();
	_finishConnections = finishConnections;
	
	if(!_observation.GetItems().empty() && !_tasks.empty())
	{
		const std::string thisHostName = GetHostName();
		
		// make a list of the involved nodes
		_nodeCommands.Initialize(_observation);
		
		// recycle idle connections
		ConnectionVector list = _idleConnections;
		_idleConnections.clear();
		for(ConnectionVector::iterator i=list.begin();i!=list.end();++i)
		{
			onConnectionAwaitingCommand(*i);
		}
		
		if(_processes.empty())
		{
			//construct a process for each unique node name
			std::vector<std::string> list;
			_nodeCommands.NodeList(list);
			for(std::vector<std::string>::const_iterator i=list.begin();i!=list.end();++i)
			{
				RemoteProcess *process = new RemoteProcess(*i, thisHostName);
				process->SignalFinished() = boost::bind(&ProcessCommander::onProcessFinished, this, _1, _2, _3);
				process->Start();
				_processes.push_back(process);
			}
		}
		
		// We will now start accepting connections. The Run() method will not return until the server
		// stops listening and there are no more io operations pending. With asynchroneous
		// handles, the server and its connections will call onEvent...(). These handles
		// will push new tasks until all tasks in the ProcessCommander are finished.
		_server.Run();
	}
}
Ejemplo n.º 5
0
TEST(Process, remote)
{
  ASSERT_TRUE(GTEST_IS_THREADSAFE);

  RemoteProcess process;

  volatile bool handlerCalled = false;

  EXPECT_CALL(process, handler(_, _))
    .WillOnce(Assign(&handlerCalled, true));

  spawn(process);

  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

  ASSERT_LE(0, s);

  sockaddr_in addr;
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = PF_INET;
  addr.sin_port = htons(process.self().port);
  addr.sin_addr.s_addr = process.self().ip;

  ASSERT_EQ(0, connect(s, (sockaddr*) &addr, sizeof(addr)));

  Message message;
  message.name = "handler";
  message.from = UPID();
  message.to = process.self();

  const std::string& data = MessageEncoder::encode(&message);

  ASSERT_EQ(data.size(), write(s, data.data(), data.size()));

  ASSERT_EQ(0, close(s));

  while (!handlerCalled);

  terminate(process);
  wait(process);
}
Ejemplo n.º 6
0
 //----------------------- EXPORT TO PROCESS --------------------------
 SharedMemory::Export SharedMemory::exportToProcess(RemoteProcess &target, bool readOnly) const
 {
   HANDLE targetProcessHandle = target.getHandle();
   HANDLE exportHandle;
   BOOL success = DuplicateHandle(
     GetCurrentProcess(),        // source process handle
     this->mappingObjectHandle,  // source handle
     targetProcessHandle,        // target process handle
     &exportHandle,              // out: target handle
     NULL,                       // access
     false,                      // inherit
     readOnly ? PAGE_READONLY : DUPLICATE_SAME_ACCESS);
   if(!success)
   {
     throw GeneralException(__FUNCTION__ ": failed export SharedMemory");
   }
   Export exportObject;
   exportObject.bufferSize = this->bufferSize;
   exportObject.targetProcessMappingObjectHandle = exportHandle;
   exportObject.readOnly = readOnly;
   return exportObject;
 }
Ejemplo n.º 7
0
// Like 'http1' but uses the 'Libprocess-From' header. We can
// also use http::post here since we expect a 202 response.
TEST(ProcessTest, Http2)
{
  ASSERT_TRUE(GTEST_IS_THREADSAFE);

  RemoteProcess process;
  spawn(process);

  // Create a receiving socket so we can get messages back.
  Try<Socket> create = Socket::create();
  ASSERT_SOME(create);

  Socket socket = create.get();

  ASSERT_SOME(socket.bind(Address()));

  // Create a UPID for 'Libprocess-From' based on the IP and port we
  // got assigned.
  Try<Address> address = socket.address();
  ASSERT_SOME(address);

  UPID from("", address.get());

  ASSERT_SOME(socket.listen(1));

  Future<UPID> pid;
  Future<string> body;
  EXPECT_CALL(process, handler(_, _))
    .WillOnce(DoAll(FutureArg<0>(&pid),
                    FutureArg<1>(&body)));

  http::Headers headers;
  headers["Libprocess-From"] = stringify(from);

  Future<http::Response> response =
    http::post(process.self(), "handler", headers, "hello world");

  AWAIT_READY(response);
  ASSERT_EQ(http::Status::ACCEPTED, response->code);
  ASSERT_EQ(http::Status::string(http::Status::ACCEPTED),
            response->status);

  AWAIT_READY(body);
  ASSERT_EQ("hello world", body.get());

  AWAIT_READY(pid);
  ASSERT_EQ(from, pid.get());

  // Now post a message as though it came from the process.
  const string name = "reply";
  post(process.self(), from, name);

  // Accept the incoming connection.
  Future<Socket> accept = socket.accept();
  AWAIT_READY(accept);

  Socket client = accept.get();

  const string data = "POST /" + name + " HTTP/1.1";

  AWAIT_EXPECT_EQ(data, client.recv(data.size()));

  terminate(process);
  wait(process);
}