1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "socket_context.h"
17
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <vector>
22 #include "logging.h"
23 #include "securec.h"
24 #include "service_base.h"
25 #include "service_entry.h"
26
27 namespace {
28 const int PROTO_SIZE_MAX = 1024 * 1024;
29 const int MEMORY_BLOCK_UNIT = 4096;
30 const int HEARTBEAT_MSG = -1;
31 } // namespace
32
SocketContext()33 SocketContext::SocketContext()
34 {
35 socketHandle_ = -1;
36 clientState_ = CLIENT_STAT_WORKING;
37 lastProcMS_ = 0;
38 serviceBase_ = nullptr;
39 }
40
~SocketContext()41 SocketContext::~SocketContext()
42 {
43 if (socketHandle_ >= 0) {
44 HILOG_ERROR(LOG_CORE, "SocketContext socketHandle_ = %d", socketHandle_);
45
46 int ret = shutdown(socketHandle_, SHUT_RDWR);
47 if (ret < 0) {
48 const int bufSize = 256;
49 char buf[bufSize] = { 0 };
50 strerror_r(errno, buf, bufSize);
51 HILOG_ERROR(LOG_CORE, "shutdown socket err = %d %s", errno, buf);
52 }
53 ret = close(socketHandle_);
54 if (ret < 0) {
55 const int bufSize = 256;
56 char buf[bufSize] = { 0 };
57 strerror_r(errno, buf, bufSize);
58 HILOG_ERROR(LOG_CORE, "close socket err = %d %s", errno, buf);
59 }
60 socketHandle_ = -1;
61 }
62 if (recvThread_.joinable()) {
63 recvThread_.join();
64 }
65 HILOG_ERROR(LOG_CORE, "~SocketContext recvThread join success");
66 }
67
RawProtocolProc(uint32_t pnum,const int8_t * buf,const uint32_t size)68 int SocketContext::RawProtocolProc(uint32_t pnum, const int8_t* buf, const uint32_t size)
69 {
70 return -1;
71 }
72
ReceiveData(int sock,uint8_t * databuf,uint32_t size)73 bool SocketContext::ReceiveData(int sock, uint8_t* databuf, uint32_t size)
74 {
75 uint32_t p = 0;
76 if (sock < 0) {
77 return false;
78 }
79 if (size == 0) {
80 return false;
81 }
82 while (p < size) {
83 int ret = recv(sock, &databuf[p], size - p, 0);
84 if (ret <= 0) {
85 if (ret == -1 && errno == EAGAIN) {
86 continue;
87 }
88 return false;
89 }
90 p += ret;
91 }
92 return true;
93 }
94
UnixSocketRecv(void * pp)95 void* SocketContext::UnixSocketRecv(void* pp)
96 {
97 pthread_setname_np(pthread_self(), "UnixSocketRecv");
98
99 uint32_t bufferSize = MEMORY_BLOCK_UNIT;
100
101 SocketContext* pssr = (SocketContext*)pp;
102 std::vector<unsigned char> buf(bufferSize);
103
104 struct ProtocolHead* pph = (struct ProtocolHead*)buf.data();
105 uint32_t head_size = sizeof(struct ProtocolHead);
106
107 CHECK_TRUE(pssr->socketHandle_ != -1, nullptr, "UnixSocketRecv pssr->socketHandle_ ==-1");
108 while (pssr->socketHandle_ >= 0) {
109 if (!ReceiveData(pssr->socketHandle_, buf.data(), head_size)) {
110 HILOG_DEBUG(LOG_CORE, "====== IPC LOST CONNECT ======");
111 break;
112 }
113 if (pph->protoSize > bufferSize) {
114 if (pph->protoSize > PROTO_SIZE_MAX) {
115 HILOG_ERROR(LOG_CORE, "buffer size out of range %d/%d", pph->protoSize, PROTO_SIZE_MAX);
116 break;
117 }
118 bufferSize = (pph->protoSize / MEMORY_BLOCK_UNIT + 1) * MEMORY_BLOCK_UNIT;
119 buf.resize(bufferSize);
120 pph = (struct ProtocolHead*)buf.data();
121 }
122
123 if (!ReceiveData(pssr->socketHandle_, buf.data() + head_size, pph->protoSize - head_size)) {
124 HILOG_DEBUG(LOG_CORE, "====== IPC LOST CONNECT ======");
125 break;
126 }
127 switch (pph->protoType & PROTOCOL_TYPE_FILTER) {
128 case PROTOCOL_TYPE_RAW:
129 pssr->RawProtocolProc(pph->protoType & (~PROTOCOL_TYPE_FILTER), pph->datas, pph->protoSize - head_size);
130 break;
131 case PROTOCOL_TYPE_PROTOBUF:
132 if (pssr->serviceBase_ != nullptr) {
133 pssr->serviceBase_->ProtocolProc(*pssr, pph->protoType & (~PROTOCOL_TYPE_FILTER), pph->datas,
134 pph->protoSize - head_size);
135 }
136 break;
137 default:
138 HILOG_ERROR(LOG_CORE, "unknown protocol %d", pph->protoType);
139 break;
140 }
141 }
142 pssr->clientState_ = CLIENT_STAT_THREAD_EXITED;
143 HILOG_DEBUG(LOG_CORE, "UnixSocketRecv thread exit");
144 return nullptr;
145 }
146
CreateRecvThread()147 bool SocketContext::CreateRecvThread()
148 {
149 recvThread_ = std::thread(&SocketContext::UnixSocketRecv, this);
150 CHECK_TRUE(recvThread_.get_id() != std::thread::id(), false, "CreateRecvThread FAIL");
151 return true;
152 }
153
SendRaw(uint32_t pnum,const int8_t * data,uint32_t size,int sockfd)154 bool SocketContext::SendRaw(uint32_t pnum, const int8_t* data, uint32_t size, int sockfd)
155 {
156 CHECK_NOTNULL(data, false, "SendRaw data null");
157 if (sockfd == -1) {
158 sockfd = socketHandle_;
159 }
160 struct ProtocolHead phead;
161 phead.protoType = PROTOCOL_TYPE_RAW | pnum;
162 phead.protoSize = size + sizeof(struct ProtocolHead);
163 CHECK_TRUE(send(sockfd, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0) != -1, false,
164 "SendRaw Send Head ERR :%d", errno);
165
166 CHECK_TRUE(send(sockfd, data, size, 0) != -1, false, "SendRaw Send Data ERR : %d", errno);
167 return true;
168 }
169
170 #ifndef NO_PROTOBUF
SendProtobuf(uint32_t pnum,google::protobuf::Message & pmsg)171 bool SocketContext::SendProtobuf(uint32_t pnum, google::protobuf::Message& pmsg)
172 {
173 int size = pmsg.ByteSizeLong();
174 CHECK_TRUE(size > 0, false, "%s:size less than or equal to 0", __func__);
175 int8_t* data = reinterpret_cast<int8_t*>(malloc(size));
176 if (data == nullptr) {
177 return false;
178 }
179 pmsg.SerializeToArray(data, size);
180 struct ProtocolHead phead;
181 phead.protoType = PROTOCOL_TYPE_PROTOBUF | pnum;
182 phead.protoSize = size + sizeof(struct ProtocolHead);
183 send(socketHandle_, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0);
184 send(socketHandle_, data, size, 0);
185
186 free(data);
187 return true;
188 }
189 #endif
190
SendHookConfig(const uint8_t * config,size_t len)191 bool SocketContext::SendHookConfig(const uint8_t* config, size_t len)
192 {
193 if (config == nullptr || len == 0) {
194 return false;
195 }
196
197 struct ProtocolHead phead;
198 phead.protoType = PROTOCOL_TYPE_PROTOBUF;
199 phead.protoSize = len + sizeof(struct ProtocolHead);
200 send(socketHandle_, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0);
201 send(socketHandle_, config, len, 0);
202 return true;
203 }
204
SendHeartBeat()205 bool SocketContext::SendHeartBeat()
206 {
207 struct ProtocolHead phead;
208 phead.protoType = PROTOCOL_TYPE_PROTOBUF;
209 phead.protoSize = sizeof(HEARTBEAT_MSG) + sizeof(struct ProtocolHead);
210
211 if (send(socketHandle_, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0) == -1) {
212 return false;
213 }
214
215 if (send(socketHandle_, &HEARTBEAT_MSG, sizeof(HEARTBEAT_MSG), 0) == -1) {
216 return false;
217 }
218
219 return true;
220 }
221
SendFileDescriptor(int fd)222 bool SocketContext::SendFileDescriptor(int fd)
223 {
224 struct msghdr msg = {0};
225 struct cmsghdr* cmsg = nullptr;
226 char buf[CMSG_SPACE(1 * sizeof(int))] = {0};
227 char data;
228 if (memset_s(buf, sizeof(buf), 0, sizeof(buf)) != EOK) {
229 HILOG_ERROR(LOG_CORE, "memset_s error!");
230 }
231 struct iovec io = {.iov_base = &data, .iov_len = 1};
232 msg.msg_iov = &io;
233 msg.msg_iovlen = 1;
234 msg.msg_control = buf;
235 msg.msg_controllen = sizeof(buf);
236 cmsg = CMSG_FIRSTHDR(&msg);
237 cmsg->cmsg_level = SOL_SOCKET;
238 cmsg->cmsg_type = SCM_RIGHTS;
239 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 1);
240 if (memcpy_s(CMSG_DATA(cmsg), 1 * sizeof(int), &fd, 1 * sizeof(int)) != EOK) {
241 HILOG_ERROR(LOG_CORE, "memcpy_s error");
242 }
243
244 CHECK_TRUE(sendmsg(socketHandle_, &msg, 0) != -1, false, "SendFileDescriptor FAIL");
245 return true;
246 }
247
ReceiveFileDiscriptor()248 int SocketContext::ReceiveFileDiscriptor()
249 {
250 struct msghdr msg = {0};
251 struct cmsghdr* cmsg = nullptr;
252 char buf[CMSG_SPACE(1 * sizeof(int))] = {0};
253 char data;
254 struct iovec io = {.iov_base = &data, .iov_len = 1};
255 msg.msg_iov = &io;
256 msg.msg_iovlen = 1;
257 msg.msg_control = buf;
258 msg.msg_controllen = sizeof(buf);
259
260 CHECK_TRUE(recvmsg(socketHandle_, &msg, 0) != -1, -1, "ReceiveFileDiscriptor FAIL");
261 cmsg = CMSG_FIRSTHDR(&msg);
262
263 return cmsg ? *(int*)CMSG_DATA(cmsg) : -1;
264 }
265