summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaichi Hirono2017-03-05 23:02:42 -0600
committerDaichi Hirono2017-03-13 19:09:29 -0500
commit57b780fbc3e2c2442c2f58dcb83818e786246b35 (patch)
treecf2426a800b3566d8f65b884831bf75e42cd47e1 /libappfuse/FuseBuffer.cc
parentcc9d94ce04dbb63a745001323213bb667ea2e00f (diff)
downloadplatform-system-core-57b780fbc3e2c2442c2f58dcb83818e786246b35.tar.gz
platform-system-core-57b780fbc3e2c2442c2f58dcb83818e786246b35.tar.xz
platform-system-core-57b780fbc3e2c2442c2f58dcb83818e786246b35.zip
Add ReadOrAgain and WriteOrAgain methods to FuseMessage.
These methods return kAgain if operation cannot be done without blocking the current thread. The CL also introduecs new helper function SetupMessageSockets so that FuseMessages are always transfered via sockets that save message boundaries. Bug: 34903085 Test: libappfuse_test Change-Id: I34544372cc1b0c7bc9622e581ae16c018a123fa9
Diffstat (limited to 'libappfuse/FuseBuffer.cc')
-rw-r--r--libappfuse/FuseBuffer.cc157
1 files changed, 106 insertions, 51 deletions
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 8fb2dbcc5..13cfc88ec 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -23,77 +23,132 @@
23#include <algorithm> 23#include <algorithm>
24#include <type_traits> 24#include <type_traits>
25 25
26#include <sys/socket.h>
27
26#include <android-base/file.h> 28#include <android-base/file.h>
27#include <android-base/logging.h> 29#include <android-base/logging.h>
28#include <android-base/macros.h> 30#include <android-base/macros.h>
29 31
30namespace android { 32namespace android {
31namespace fuse { 33namespace fuse {
32 34namespace {
33static_assert(
34 std::is_standard_layout<FuseBuffer>::value,
35 "FuseBuffer must be standard layout union.");
36 35
37template <typename T> 36template <typename T>
38bool FuseMessage<T>::CheckHeaderLength(const char* name) const { 37bool CheckHeaderLength(const FuseMessage<T>* self, const char* name) {
39 const auto& header = static_cast<const T*>(this)->header; 38 const auto& header = static_cast<const T*>(self)->header;
40 if (header.len >= sizeof(header) && header.len <= sizeof(T)) { 39 if (header.len >= sizeof(header) && header.len <= sizeof(T)) {
41 return true; 40 return true;
42 } else { 41 } else {
43 LOG(ERROR) << "Invalid header length is found in " << name << ": " << 42 LOG(ERROR) << "Invalid header length is found in " << name << ": " << header.len;
44 header.len; 43 return false;
45 return false; 44 }
46 }
47} 45}
48 46
49template <typename T> 47template <typename T>
50bool FuseMessage<T>::Read(int fd) { 48ResultOrAgain ReadInternal(FuseMessage<T>* self, int fd, int sockflag) {
51 char* const buf = reinterpret_cast<char*>(this); 49 char* const buf = reinterpret_cast<char*>(self);
52 const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, buf, sizeof(T))); 50 const ssize_t result = sockflag ? TEMP_FAILURE_RETRY(recv(fd, buf, sizeof(T), sockflag))
53 if (result < 0) { 51 : TEMP_FAILURE_RETRY(read(fd, buf, sizeof(T)));
54 PLOG(ERROR) << "Failed to read a FUSE message"; 52
55 return false; 53 switch (result) {
56 } 54 case 0:
57 55 // Expected EOF.
58 const auto& header = static_cast<const T*>(this)->header; 56 return ResultOrAgain::kFailure;
59 if (result < static_cast<ssize_t>(sizeof(header))) { 57 case -1:
60 LOG(ERROR) << "Read bytes " << result << " are shorter than header size " << 58 if (errno == EAGAIN) {
61 sizeof(header); 59 return ResultOrAgain::kAgain;
62 return false; 60 }
63 } 61 PLOG(ERROR) << "Failed to read a FUSE message";
62 return ResultOrAgain::kFailure;
63 }
64
65 const auto& header = static_cast<const T*>(self)->header;
66 if (result < static_cast<ssize_t>(sizeof(header))) {
67 LOG(ERROR) << "Read bytes " << result << " are shorter than header size " << sizeof(header);
68 return ResultOrAgain::kFailure;
69 }
70
71 if (!CheckHeaderLength<T>(self, "Read")) {
72 return ResultOrAgain::kFailure;
73 }
74
75 if (static_cast<uint32_t>(result) != header.len) {
76 LOG(ERROR) << "Read bytes " << result << " are different from header.len " << header.len;
77 return ResultOrAgain::kFailure;
78 }
79
80 return ResultOrAgain::kSuccess;
81}
64 82
65 if (!CheckHeaderLength("Read")) { 83template <typename T>
66 return false; 84ResultOrAgain WriteInternal(const FuseMessage<T>* self, int fd, int sockflag) {
67 } 85 if (!CheckHeaderLength<T>(self, "Write")) {
86 return ResultOrAgain::kFailure;
87 }
88
89 const char* const buf = reinterpret_cast<const char*>(self);
90 const auto& header = static_cast<const T*>(self)->header;
91 const int result = sockflag ? TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag))
92 : TEMP_FAILURE_RETRY(write(fd, buf, header.len));
93
94 if (result == -1) {
95 if (errno == EAGAIN) {
96 return ResultOrAgain::kAgain;
97 }
98 PLOG(ERROR) << "Failed to write a FUSE message";
99 return ResultOrAgain::kFailure;
100 }
101
102 CHECK(static_cast<uint32_t>(result) == header.len);
103 return ResultOrAgain::kSuccess;
104}
105}
68 106
69 if (static_cast<uint32_t>(result) > header.len) { 107static_assert(std::is_standard_layout<FuseBuffer>::value,
70 LOG(ERROR) << "Read bytes " << result << " are longer than header.len " << 108 "FuseBuffer must be standard layout union.");
71 header.len; 109
72 return false; 110bool SetupMessageSockets(base::unique_fd (*result)[2]) {
73 } 111 base::unique_fd fds[2];
112 {
113 int raw_fds[2];
114 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_fds) == -1) {
115 PLOG(ERROR) << "Failed to create sockets for proxy";
116 return false;
117 }
118 fds[0].reset(raw_fds[0]);
119 fds[1].reset(raw_fds[1]);
120 }
121
122 constexpr int kMaxMessageSize = sizeof(FuseBuffer);
123 if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0 ||
124 setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0) {
125 PLOG(ERROR) << "Failed to update buffer size for socket";
126 return false;
127 }
128
129 (*result)[0] = std::move(fds[0]);
130 (*result)[1] = std::move(fds[1]);
131 return true;
132}
74 133
75 if (!base::ReadFully(fd, buf + result, header.len - result)) { 134template <typename T>
76 PLOG(ERROR) << "ReadFully failed"; 135bool FuseMessage<T>::Read(int fd) {
77 return false; 136 return ReadInternal(this, fd, 0) == ResultOrAgain::kSuccess;
78 } 137}
79 138
80 return true; 139template <typename T>
140ResultOrAgain FuseMessage<T>::ReadOrAgain(int fd) {
141 return ReadInternal(this, fd, MSG_DONTWAIT);
81} 142}
82 143
83template <typename T> 144template <typename T>
84bool FuseMessage<T>::Write(int fd) const { 145bool FuseMessage<T>::Write(int fd) const {
85 if (!CheckHeaderLength("Write")) { 146 return WriteInternal(this, fd, 0) == ResultOrAgain::kSuccess;
86 return false; 147}
87 }
88
89 const char* const buf = reinterpret_cast<const char*>(this);
90 const auto& header = static_cast<const T*>(this)->header;
91 if (!base::WriteFully(fd, buf, header.len)) {
92 PLOG(ERROR) << "WriteFully failed";
93 return false;
94 }
95 148
96 return true; 149template <typename T>
150ResultOrAgain FuseMessage<T>::WriteOrAgain(int fd) const {
151 return WriteInternal(this, fd, MSG_DONTWAIT);
97} 152}
98 153
99template class FuseMessage<FuseRequest>; 154template class FuseMessage<FuseRequest>;