1 /* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are
5  * met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above
9  *       copyright notice, this list of conditions and the following
10  *       disclaimer in the documentation and/or other materials provided
11  *       with the distribution.
12  *     * Neither the name of The Linux Foundation, nor the names of its
13  *       contributors may be used to endorse or promote products derived
14  *       from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <log_util.h>
34 #include "LocIpc.h"
35 
36 namespace loc_util {
37 
38 #ifdef LOG_TAG
39 #undef LOG_TAG
40 #endif
41 #define LOG_TAG "LocSvc_LocIpc"
42 
43 #define LOC_MSG_BUF_LEN 8192
44 #define LOC_MSG_HEAD "$MSGLEN$"
45 #define LOC_MSG_ABORT "LocIpcMsg::ABORT"
46 
47 class LocIpcRunnable : public LocRunnable {
48 friend LocIpc;
49 public:
LocIpcRunnable(LocIpc & locIpc,const std::string & ipcName)50     LocIpcRunnable(LocIpc& locIpc, const std::string& ipcName)
51             : mLocIpc(locIpc), mIpcName(ipcName) {}
run()52     bool run() override {
53         if (!mLocIpc.startListeningBlocking(mIpcName)) {
54             LOC_LOGe("listen to socket failed");
55         }
56 
57         return false;
58     }
59 private:
60      LocIpc& mLocIpc;
61      const std::string mIpcName;
62 };
63 
startListeningNonBlocking(const std::string & name)64 bool LocIpc::startListeningNonBlocking(const std::string& name) {
65     mRunnable = new LocIpcRunnable(*this, name);
66     std::string threadName("LocIpc-");
67     threadName.append(name);
68     return mThread.start(threadName.c_str(), mRunnable);
69 }
70 
startListeningBlocking(const std::string & name)71 bool LocIpc::startListeningBlocking(const std::string& name) {
72 
73     int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
74     if (fd < 0) {
75         LOC_LOGe("create socket error. reason:%s", strerror(errno));
76         return false;
77     }
78 
79     if ((unlink(name.c_str()) < 0) && (errno != ENOENT)) {
80        LOC_LOGw("unlink socket error. reason:%s", strerror(errno));
81     }
82 
83     struct sockaddr_un addr = { .sun_family = AF_UNIX };
84     snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", name.c_str());
85 
86     umask(0157);
87 
88     if (::bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
89         LOC_LOGe("bind socket error. reason:%s", strerror(errno));
90         ::close(fd);
91         fd = -1;
92         return false;
93     }
94 
95     mIpcFd = fd;
96 
97     // inform that the socket is ready to receive message
98     onListenerReady();
99 
100     ssize_t nBytes = 0;
101     std::string msg = "";
102     std::string abort = LOC_MSG_ABORT;
103     while (1) {
104         msg.resize(LOC_MSG_BUF_LEN);
105         nBytes = ::recvfrom(mIpcFd, (void*)(msg.data()), msg.size(), 0, NULL, NULL);
106         if (nBytes < 0) {
107             break;
108         } else if (nBytes == 0) {
109             continue;
110         }
111 
112         if (strncmp(msg.data(), abort.c_str(), abort.length()) == 0) {
113             LOC_LOGI("recvd abort msg.data %s", msg.data());
114             break;
115         }
116 
117         if (strncmp(msg.data(), LOC_MSG_HEAD, sizeof(LOC_MSG_HEAD) - 1)) {
118             // short message
119             msg.resize(nBytes);
120             onReceive(msg);
121         } else {
122             // long message
123             size_t msgLen = 0;
124             sscanf(msg.data(), LOC_MSG_HEAD"%zu", &msgLen);
125             msg.resize(msgLen);
126             size_t msgLenReceived = 0;
127             while ((msgLenReceived < msgLen) && (nBytes > 0)) {
128                 nBytes = recvfrom(mIpcFd, (void*)&(msg[msgLenReceived]),
129                         msg.size() - msgLenReceived, 0, NULL, NULL);
130                 msgLenReceived += nBytes;
131             }
132             if (nBytes > 0) {
133                 onReceive(msg);
134             } else {
135                 break;
136             }
137         }
138     }
139 
140     if (mStopRequested) {
141         mStopRequested = false;
142         return true;
143     } else {
144         LOC_LOGe("cannot read socket. reason:%s", strerror(errno));
145         (void)::close(mIpcFd);
146         mIpcFd = -1;
147         return false;
148     }
149 }
150 
stopListening()151 void LocIpc::stopListening() {
152 
153     const char *socketName = nullptr;
154     mStopRequested = true;
155 
156     if (mRunnable) {
157         std::string abort = LOC_MSG_ABORT;
158         socketName = (reinterpret_cast<LocIpcRunnable *>(mRunnable))->mIpcName.c_str();
159         send(socketName, abort);
160         mRunnable = nullptr;
161     }
162 
163     if (mIpcFd >= 0) {
164         if (::close(mIpcFd)) {
165             LOC_LOGe("cannot close socket:%s", strerror(errno));
166         }
167         mIpcFd = -1;
168     }
169 
170     //delete from the file system at the end
171     if (socketName) {
172         unlink(socketName);
173     }
174 }
175 
send(const char name[],const std::string & data)176 bool LocIpc::send(const char name[], const std::string& data) {
177     return send(name, (const uint8_t*)data.c_str(), data.length());
178 }
179 
send(const char name[],const uint8_t data[],uint32_t length)180 bool LocIpc::send(const char name[], const uint8_t data[], uint32_t length) {
181 
182     bool result = true;
183     int fd = ::socket(AF_UNIX, SOCK_DGRAM, 0);
184     if (fd < 0) {
185         LOC_LOGe("create socket error. reason:%s", strerror(errno));
186         return false;
187     }
188 
189     struct sockaddr_un addr = { .sun_family = AF_UNIX };
190     snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", name);
191 
192     result = sendData(fd, addr, data, length);
193 
194     (void)::close(fd);
195     return result;
196 }
197 
198 
sendData(int fd,const sockaddr_un & addr,const uint8_t data[],uint32_t length)199 bool LocIpc::sendData(int fd, const sockaddr_un &addr, const uint8_t data[], uint32_t length) {
200 
201     bool result = true;
202 
203     if (length <= LOC_MSG_BUF_LEN) {
204         if (::sendto(fd, data, length, 0,
205                 (struct sockaddr*)&addr, sizeof(addr)) < 0) {
206             LOC_LOGe("cannot send to socket. reason:%s", strerror(errno));
207             result = false;
208         }
209     } else {
210         std::string head = LOC_MSG_HEAD;
211         head.append(std::to_string(length));
212         if (::sendto(fd, head.c_str(), head.length(), 0,
213                 (struct sockaddr*)&addr, sizeof(addr)) < 0) {
214             LOC_LOGe("cannot send to socket. reason:%s", strerror(errno));
215             result = false;
216         } else {
217             size_t sentBytes = 0;
218             while(sentBytes < length) {
219                 size_t partLen = length - sentBytes;
220                 if (partLen > LOC_MSG_BUF_LEN) {
221                     partLen = LOC_MSG_BUF_LEN;
222                 }
223                 ssize_t rv = ::sendto(fd, data + sentBytes, partLen, 0,
224                         (struct sockaddr*)&addr, sizeof(addr));
225                 if (rv < 0) {
226                     LOC_LOGe("cannot send to socket. reason:%s", strerror(errno));
227                     result = false;
228                     break;
229                 }
230                 sentBytes += rv;
231             }
232         }
233     }
234     return result;
235 }
236 
237 }
238