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