1 /*
2  * Copyright (C) 2017 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 
17 #include "PipeRelay.h"
18 
19 #include <sys/socket.h>
20 #include <utils/Thread.h>
21 
22 namespace android {
23 namespace lshal {
24 
25 struct PipeRelay::RelayThread : public Thread {
26     explicit RelayThread(int fd, std::ostream &os);
27 
28     bool threadLoop() override;
29 
30 private:
31     int mFd;
32     std::ostream &mOutStream;
33 
34     DISALLOW_COPY_AND_ASSIGN(RelayThread);
35 };
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 
RelayThread(int fd,std::ostream & os)39 PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
40     : mFd(fd),
41       mOutStream(os) {
42 }
43 
threadLoop()44 bool PipeRelay::RelayThread::threadLoop() {
45     char buffer[1024];
46     ssize_t n = read(mFd, buffer, sizeof(buffer));
47 
48     if (n <= 0) {
49         return false;
50     }
51 
52     mOutStream.write(buffer, n);
53 
54     return true;
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 
PipeRelay(std::ostream & os)59 PipeRelay::PipeRelay(std::ostream &os)
60     : mInitCheck(NO_INIT) {
61     int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
62 
63     if (res < 0) {
64         mInitCheck = -errno;
65         return;
66     }
67 
68     mThread = new RelayThread(mFds[0], os);
69     mInitCheck = mThread->run("RelayThread");
70 }
71 
CloseFd(int * fd)72 void PipeRelay::CloseFd(int *fd) {
73     if (*fd >= 0) {
74         close(*fd);
75         *fd = -1;
76     }
77 }
78 
~PipeRelay()79 PipeRelay::~PipeRelay() {
80     if (mFds[1] >= 0) {
81         shutdown(mFds[1], SHUT_WR);
82     }
83 
84     if (mFds[0] >= 0) {
85         shutdown(mFds[0], SHUT_RD);
86     }
87 
88     if (mThread != NULL) {
89         mThread->join();
90         mThread.clear();
91     }
92 
93     CloseFd(&mFds[1]);
94     CloseFd(&mFds[0]);
95 }
96 
initCheck() const97 status_t PipeRelay::initCheck() const {
98     return mInitCheck;
99 }
100 
fd() const101 int PipeRelay::fd() const {
102     return mFds[1];
103 }
104 
105 }  // namespace lshal
106 }  // namespace android
107