1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17
18 #include <binder/unique_fd.h>
19 #include <poll.h>
20
21 #include "FdTrigger.h"
22 #include "RpcState.h"
23
24 namespace android {
25
26 template <typename SendOrReceive>
interruptableReadOrWrite(const android::RpcTransportFd & socket,FdTrigger * fdTrigger,iovec * iovs,int niovs,SendOrReceive sendOrReceiveFun,const char * funName,int16_t event,const std::optional<binder::impl::SmallFunction<status_t ()>> & altPoll)27 status_t interruptableReadOrWrite(
28 const android::RpcTransportFd& socket, FdTrigger* fdTrigger, iovec* iovs, int niovs,
29 SendOrReceive sendOrReceiveFun, const char* funName, int16_t event,
30 const std::optional<binder::impl::SmallFunction<status_t()>>& altPoll) {
31 MAYBE_WAIT_IN_FLAKE_MODE;
32
33 if (niovs < 0) {
34 return BAD_VALUE;
35 }
36
37 // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
38 // may never know we should be shutting down.
39 if (fdTrigger->isTriggered()) {
40 return DEAD_OBJECT;
41 }
42
43 // If iovs has one or more empty vectors at the end and
44 // we somehow advance past all the preceding vectors and
45 // pass some or all of the empty ones to sendmsg/recvmsg,
46 // the call will return processSize == 0. In that case
47 // we should be returning OK but instead return DEAD_OBJECT.
48 // To avoid this problem, we make sure here that the last
49 // vector at iovs[niovs - 1] has a non-zero length.
50 while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
51 niovs--;
52 }
53 if (niovs == 0) {
54 // The vectors are all empty, so we have nothing to send.
55 return OK;
56 }
57
58 bool havePolled = false;
59 while (true) {
60 ssize_t processSize = sendOrReceiveFun(iovs, niovs);
61 if (processSize < 0) {
62 int savedErrno = errno;
63
64 // Still return the error on later passes, since it would expose
65 // a problem with polling
66 if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
67 LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
68 return -savedErrno;
69 }
70 } else if (processSize == 0) {
71 return DEAD_OBJECT;
72 } else {
73 while (processSize > 0 && niovs > 0) {
74 auto& iov = iovs[0];
75 if (static_cast<size_t>(processSize) < iov.iov_len) {
76 // Advance the base of the current iovec
77 iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
78 iov.iov_len -= processSize;
79 break;
80 }
81
82 // The current iovec was fully written
83 processSize -= iov.iov_len;
84 iovs++;
85 niovs--;
86 }
87 if (niovs == 0) {
88 LOG_ALWAYS_FATAL_IF(processSize > 0,
89 "Reached the end of iovecs "
90 "with %zd bytes remaining",
91 processSize);
92 return OK;
93 }
94 }
95
96 if (altPoll) {
97 if (status_t status = (*altPoll)(); status != OK) return status;
98 if (fdTrigger->isTriggered()) {
99 return DEAD_OBJECT;
100 }
101 } else {
102 if (status_t status = fdTrigger->triggerablePoll(socket, event); status != OK)
103 return status;
104 if (!havePolled) havePolled = true;
105 }
106 }
107 }
108
109 } // namespace android
110