blob: 63b5b1078a168e3c2d6597b01483c42586adf1d8 [file] [log] [blame]
#ifndef ANDROID_PDX_UDS_IPC_HELPER_H_
#define ANDROID_PDX_UDS_IPC_HELPER_H_
#include <sys/socket.h>
#include <utility>
#include <vector>
#include <pdx/rpc/serializable.h>
#include <pdx/rpc/serialization.h>
#include <pdx/status.h>
#include <pdx/utility.h>
namespace android {
namespace pdx {
namespace uds {
// Test interfaces used for unit-testing payload sending/receiving over sockets.
class SendInterface {
public:
virtual ssize_t Send(int socket_fd, const void* data, size_t size,
int flags) = 0;
virtual ssize_t SendMessage(int socket_fd, const msghdr* msg, int flags) = 0;
protected:
virtual ~SendInterface() = default;
};
class RecvInterface {
public:
virtual ssize_t Receive(int socket_fd, void* data, size_t size,
int flags) = 0;
virtual ssize_t ReceiveMessage(int socket_fd, msghdr* msg, int flags) = 0;
protected:
virtual ~RecvInterface() = default;
};
// Helper methods that allow to send/receive data through abstract interfaces.
// Useful for mocking out the underlying socket I/O.
Status<void> SendAll(SendInterface* sender, const BorrowedHandle& socket_fd,
const void* data, size_t size);
Status<void> SendMsgAll(SendInterface* sender, const BorrowedHandle& socket_fd,
const msghdr* msg);
Status<void> RecvAll(RecvInterface* receiver, const BorrowedHandle& socket_fd,
void* data, size_t size);
Status<void> RecvMsgAll(RecvInterface* receiver,
const BorrowedHandle& socket_fd, msghdr* msg);
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
decltype(fnc_call) result; \
do { \
result = (fnc_call); \
} while (result == -1 && errno == EINTR); \
return result; \
})()
class SendPayload : public MessageWriter, public OutputResourceMapper {
public:
SendPayload(SendInterface* sender = nullptr) : sender_{sender} {}
Status<void> Send(const BorrowedHandle& socket_fd);
Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred,
const iovec* data_vec = nullptr, size_t vec_count = 0);
// MessageWriter
void* GetNextWriteBufferSection(size_t size) override;
OutputResourceMapper* GetOutputResourceMapper() override;
// OutputResourceMapper
Status<FileReference> PushFileHandle(const LocalHandle& handle) override;
Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override;
Status<FileReference> PushFileHandle(const RemoteHandle& handle) override;
Status<ChannelReference> PushChannelHandle(
const LocalChannelHandle& handle) override;
Status<ChannelReference> PushChannelHandle(
const BorrowedChannelHandle& handle) override;
Status<ChannelReference> PushChannelHandle(
const RemoteChannelHandle& handle) override;
private:
SendInterface* sender_;
ByteBuffer buffer_;
std::vector<int> file_handles_;
};
class ReceivePayload : public MessageReader, public InputResourceMapper {
public:
ReceivePayload(RecvInterface* receiver = nullptr) : receiver_{receiver} {}
Status<void> Receive(const BorrowedHandle& socket_fd);
Status<void> Receive(const BorrowedHandle& socket_fd, ucred* cred);
// MessageReader
BufferSection GetNextReadBufferSection() override;
void ConsumeReadBufferSectionData(const void* new_start) override;
InputResourceMapper* GetInputResourceMapper() override;
// InputResourceMapper
bool GetFileHandle(FileReference ref, LocalHandle* handle) override;
bool GetChannelHandle(ChannelReference ref,
LocalChannelHandle* handle) override;
private:
RecvInterface* receiver_;
ByteBuffer buffer_;
std::vector<LocalHandle> file_handles_;
size_t read_pos_{0};
};
template <typename FileHandleType>
class ChannelInfo {
public:
FileHandleType data_fd;
FileHandleType pollin_event_fd;
FileHandleType pollhup_event_fd;
private:
PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, pollin_event_fd,
pollhup_event_fd);
};
template <typename FileHandleType>
class ChannelConnectionInfo {
public:
FileHandleType channel_fd;
private:
PDX_SERIALIZABLE_MEMBERS(ChannelConnectionInfo, channel_fd);
};
template <typename FileHandleType>
class RequestHeader {
public:
int32_t op{0};
ucred cred;
uint32_t send_len{0};
uint32_t max_recv_len{0};
std::vector<FileHandleType> file_descriptors;
std::vector<ChannelInfo<FileHandleType>> channels;
std::array<uint8_t, 32> impulse_payload;
bool is_impulse{false};
private:
PDX_SERIALIZABLE_MEMBERS(RequestHeader, op, send_len, max_recv_len,
file_descriptors, channels, impulse_payload,
is_impulse);
};
template <typename FileHandleType>
class ResponseHeader {
public:
int32_t ret_code{0};
uint32_t recv_len{0};
std::vector<FileHandleType> file_descriptors;
std::vector<ChannelInfo<FileHandleType>> channels;
private:
PDX_SERIALIZABLE_MEMBERS(ResponseHeader, ret_code, recv_len, file_descriptors,
channels);
};
template <typename T>
inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data,
const iovec* data_vec = nullptr,
size_t vec_count = 0) {
SendPayload payload;
rpc::Serialize(data, &payload);
return payload.Send(socket_fd, nullptr, data_vec, vec_count);
}
template <typename FileHandleType>
inline Status<void> SendData(const BorrowedHandle& socket_fd,
const RequestHeader<FileHandleType>& request,
const iovec* data_vec = nullptr,
size_t vec_count = 0) {
SendPayload payload;
rpc::Serialize(request, &payload);
return payload.Send(socket_fd, &request.cred, data_vec, vec_count);
}
Status<void> SendData(const BorrowedHandle& socket_fd, const void* data,
size_t size);
Status<void> SendDataVector(const BorrowedHandle& socket_fd, const iovec* data,
size_t count);
template <typename T>
inline Status<void> ReceiveData(const BorrowedHandle& socket_fd, T* data) {
ReceivePayload payload;
Status<void> status = payload.Receive(socket_fd);
if (status && rpc::Deserialize(data, &payload) != rpc::ErrorCode::NO_ERROR)
status.SetError(EIO);
return status;
}
template <typename FileHandleType>
inline Status<void> ReceiveData(const BorrowedHandle& socket_fd,
RequestHeader<FileHandleType>* request) {
ReceivePayload payload;
Status<void> status = payload.Receive(socket_fd, &request->cred);
if (status && rpc::Deserialize(request, &payload) != rpc::ErrorCode::NO_ERROR)
status.SetError(EIO);
return status;
}
Status<void> ReceiveData(const BorrowedHandle& socket_fd, void* data,
size_t size);
Status<void> ReceiveDataVector(const BorrowedHandle& socket_fd,
const iovec* data, size_t count);
size_t CountVectorSize(const iovec* data, size_t count);
void InitRequest(android::pdx::uds::RequestHeader<BorrowedHandle>* request,
int opcode, uint32_t send_len, uint32_t max_recv_len,
bool is_impulse);
Status<void> WaitForEndpoint(const std::string& endpoint_path,
int64_t timeout_ms);
} // namespace uds
} // namespace pdx
} // namespace android
#endif // ANDROID_PDX_UDS_IPC_HELPER_H_