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     : mOutStream(os),
61       mInitCheck(NO_INIT) {
62     int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
63 
64     if (res < 0) {
65         mInitCheck = -errno;
66         return;
67     }
68 
69     mThread = new RelayThread(mFds[0], os);
70     mInitCheck = mThread->run("RelayThread");
71 }
72 
CloseFd(int * fd)73 void PipeRelay::CloseFd(int *fd) {
74     if (*fd >= 0) {
75         close(*fd);
76         *fd = -1;
77     }
78 }
79 
~PipeRelay()80 PipeRelay::~PipeRelay() {
81     if (mFds[1] >= 0) {
82         shutdown(mFds[1], SHUT_WR);
83     }
84 
85     if (mFds[0] >= 0) {
86         shutdown(mFds[0], SHUT_RD);
87     }
88 
89     if (mThread != NULL) {
90         mThread->join();
91         mThread.clear();
92     }
93 
94     CloseFd(&mFds[1]);
95     CloseFd(&mFds[0]);
96 }
97 
initCheck() const98 status_t PipeRelay::initCheck() const {
99     return mInitCheck;
100 }
101 
fd() const102 int PipeRelay::fd() const {
103     return mFds[1];
104 }
105 
106 }  // namespace lshal
107 }  // namespace android
108