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