blob: c1b75f692b2d35f06eaa0a7db7a2efe0ba445fdd [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ARC_VM_MOJO_PROXY_MOJO_PROXY_H_
#define ARC_VM_MOJO_PROXY_MOJO_PROXY_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <base/files/file_descriptor_watcher_posix.h>
#include <base/files/scoped_file.h>
#include <base/macros.h>
#include <base/memory/weak_ptr.h>
#include <base/threading/thread.h>
#include "arc/vm/mojo_proxy/message.pb.h"
namespace base {
class FilePath;
}
namespace arc {
class LocalFile;
class ProxyFileSystem;
// MojoProxy proxies data going through file descriptors used for mojo
// communication between the host and the guest.
class MojoProxy {
public:
// Represents whether this proxy is server (host) side one, or client (guest)
// side one.
enum class Type {
SERVER = 1,
CLIENT = 2,
};
class Delegate {
public:
virtual ~Delegate() = default;
// Returns the type of this proxy.
virtual Type GetType() const = 0;
// Returns the file descriptor to watch for incoming messages.
virtual int GetPollFd() = 0;
// Creates a proxied file descriptor for the given handle.
// Accessing the returned FD results in calling Pread(), Pwrite(), and
// Fstat().
virtual base::ScopedFD CreateProxiedRegularFile(int64_t handle,
int32_t flags) = 0;
// Sends the message to the proxy process on the other side and returns true
// on success.
virtual bool SendMessage(const arc_proxy::MojoMessage& message,
const std::vector<base::ScopedFD>& fds) = 0;
// Receives a message from the proxy process on the other side and returns
// true on success.
virtual bool ReceiveMessage(arc_proxy::MojoMessage* message,
std::vector<base::ScopedFD>* fds) = 0;
// Called when the mojo proxy has stopped.
virtual void OnStopped() = 0;
};
explicit MojoProxy(Delegate* delegate);
MojoProxy(const MojoProxy&) = delete;
MojoProxy& operator=(const MojoProxy&) = delete;
~MojoProxy();
// Registers the |fd| whose type is |fd_type| to watch.
// When |handle| is not 0, associates the specified handle with the given FD.
// When |handle| is 0, generates a new handle value for the given FD.
// Returns the handle, or 0 on error.
int64_t RegisterFileDescriptor(base::ScopedFD fd,
arc_proxy::FileDescriptor::Type fd_type,
int64_t handle);
// Requests to connect(2) to a unix domain socket at |path| in the other
// side.
// |callback| will be called with errno, and the connected handle iff
// succeeded.
using ConnectCallback = base::OnceCallback<void(int, int64_t)>;
void Connect(const base::FilePath& path, ConnectCallback callback);
// Requests to call pread(2) for the file in the other side represented by
// the |handle| with |count| and |offset|.
// |callback| will be called with errno, and read blob iff succeeded.
using PreadCallback = base::OnceCallback<void(int, const std::string&)>;
void Pread(int64_t handle,
uint64_t count,
uint64_t offset,
PreadCallback callback);
// Requests to call pwrite(2) for the file in the other side represented by
// the |handle| with |blob| and |offset|.
// |callback| will be called with errno and the number of bytes written.
using PwriteCallback = base::OnceCallback<void(int, int64_t)>;
void Pwrite(int64_t handle,
std::string blob,
uint64_t offset,
PwriteCallback callback);
// Sends an event to close the given |handle| to the other side.
void Close(int64_t handle);
// Requests to call fstat(2) for the file in the other side represented by
// the |handle|.
// |callback| will be called with errno, and size if succeeded.
using FstatCallback = base::OnceCallback<void(int, int64_t)>;
void Fstat(int64_t handle, FstatCallback callback);
private:
// Callback called when a new mojo message is available.
void OnMojoMessageAvailable();
// Handles a message sent from the other side's proxy.
bool HandleMessage(arc_proxy::MojoMessage* message,
std::vector<base::ScopedFD>* received_fds);
// Stops this proxy.
void Stop();
// Handlers for each command.
// TODO(crbug.com/842960): Use pass-by-value when protobuf is upreved enough
// to support rvalues. (At least, 3.5, or maybe 3.6).
bool OnClose(arc_proxy::Close* close);
bool OnData(arc_proxy::Data* data, std::vector<base::ScopedFD>* received_fds);
bool OnDataInternal(arc_proxy::Data* data);
bool OnConnectRequest(arc_proxy::ConnectRequest* request);
bool OnConnectResponse(arc_proxy::ConnectResponse* response);
void OnPreadRequest(arc_proxy::PreadRequest* request);
void SendPreadResponse(int64_t cookie, arc_proxy::PreadResponse response);
bool OnPreadResponse(arc_proxy::PreadResponse* response);
void OnPwriteRequest(arc_proxy::PwriteRequest* request);
void SendPwriteResponse(int64_t cookie, arc_proxy::PwriteResponse response);
bool OnPwriteResponse(arc_proxy::PwriteResponse* response);
void OnFstatRequest(arc_proxy::FstatRequest* request);
void SendFstatResponse(int64_t cookie, arc_proxy::FstatResponse response);
bool OnFstatResponse(arc_proxy::FstatResponse* response);
// Callback called when local file descriptor gets ready to read.
// Reads Message from the file descriptor corresponding to the |handle|,
// and forwards it to the proxy process on the other side.
void OnLocalFileDesciptorReadReady(int64_t handle);
// Converts the given data to outgoing MojoMessage.
bool ConvertDataToMojoMessage(std::string blob,
std::vector<base::ScopedFD> fds,
arc_proxy::MojoMessage* message,
std::vector<base::ScopedFD>* fds_to_send);
// Handles an error on a local file.
void HandleLocalFileError(int64_t handle);
// Returns a bland new cookie to start a sequence of operations.
int64_t GenerateCookie();
Delegate* delegate_;
std::unique_ptr<base::FileDescriptorWatcher::Controller> message_watcher_;
base::Thread blocking_task_thread_{"BlockingThread"};
// Map from a |handle| (see message.proto for details) to a file
// instance wrapping the file descriptor and its watcher.
// Erasing the entry from this map should close the file descriptor
// automatically, because file descriptor is owned by |file|.
struct FileDescriptorInfo {
// File instance to read/write Message.
std::unique_ptr<LocalFile> file;
// Controller of FileDescriptorWatcher. Destroying this will
// stop watching.
// This can be null, if there's no need to watch the file descriptor.
std::unique_ptr<base::FileDescriptorWatcher::Controller> controller;
};
std::map<int64_t, FileDescriptorInfo> fd_map_;
// For handle and cookie generation rules, please find the comment in
// message.proto.
int64_t next_handle_;
int64_t next_cookie_;
// Map from cookie to its pending callback.
std::map<int64_t, ConnectCallback> pending_connect_;
std::map<int64_t, PreadCallback> pending_pread_;
std::map<int64_t, PwriteCallback> pending_pwrite_;
std::map<int64_t, FstatCallback> pending_fstat_;
// WeakPtrFactory needs to be declared as the member of the class, so that
// on destruction, any pending Callbacks bound to WeakPtr are cancelled
// first.
base::WeakPtrFactory<MojoProxy> weak_factory_{this};
};
} // namespace arc
#endif // ARC_VM_MOJO_PROXY_MOJO_PROXY_H_