• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
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         PROFILER_LOG_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             PROFILER_LOG_ERROR(LOG_CORE, "shutdown socket err = %d %s", errno, buf);
52         }
53     }
54     int socketTemp = socketHandle_;
55     socketHandle_ = -1;
56     if (recvThread_.joinable()) {
57         recvThread_.join();
58     }
59     socketHandle_ = socketTemp;
60     PROFILER_LOG_ERROR(LOG_CORE, "~SocketContext recvThread join success");
61     if (socketHandle_ >= 0) {
62         int ret = close(socketHandle_);
63         if (ret < 0) {
64             const int bufSize = 256;
65             char buf[bufSize] = { 0 };
66             strerror_r(errno, buf, bufSize);
67             PROFILER_LOG_ERROR(LOG_CORE, "close socket err = %d %s", errno, buf);
68         }
69         socketHandle_ = -1;
70     }
71 }
72 
RawProtocolProc(uint32_t pnum,const int8_t * buf,const uint32_t size)73 int SocketContext::RawProtocolProc(uint32_t pnum, const int8_t* buf, const uint32_t size)
74 {
75     return -1;
76 }
77 
ReceiveData(int sock,uint8_t * databuf,uint32_t size)78 bool SocketContext::ReceiveData(int sock, uint8_t* databuf, uint32_t size)
79 {
80     uint32_t p = 0;
81     if (sock < 0) {
82         return false;
83     }
84     if (size == 0) {
85         return false;
86     }
87     const uint32_t timesToTry = 2; // try 2 times
88     uint32_t nTimes = 0;
89     while (p < size) {
90         int ret = recv(sock, &databuf[p], size - p, 0);
91         if (ret > 0) {
92             p += ret;
93         } else if (ret == -1 && errno == EAGAIN) {
94             if (++nTimes >= timesToTry) {
95                 return false;
96             }
97         } else {
98             return false;
99         }
100     }
101     return true;
102 }
103 
UnixSocketRecv(void * pp,void (* callback)())104 void* SocketContext::UnixSocketRecv(void* pp, void (*callback)())
105 {
106     pthread_setname_np(pthread_self(), "UnixSocketRecv");
107 
108     uint32_t bufferSize = MEMORY_BLOCK_UNIT;
109 
110     SocketContext* pssr = (SocketContext*)pp;
111     std::vector<unsigned char> buf(bufferSize);
112 
113     struct ProtocolHead* pph = (struct ProtocolHead*)buf.data();
114     uint32_t head_size = sizeof(struct ProtocolHead);
115 
116     CHECK_TRUE(pssr->socketHandle_ != -1, nullptr, "UnixSocketRecv pssr->socketHandle_ ==-1");
117     while (pssr->socketHandle_ >= 0) {
118         if (!ReceiveData(pssr->socketHandle_, buf.data(), head_size)) {
119             PROFILER_LOG_DEBUG(LOG_CORE, "====== IPC LOST CONNECT ======");
120             break;
121         }
122         if (pph->protoSize > bufferSize) {
123             if (pph->protoSize > PROTO_SIZE_MAX) {
124                 PROFILER_LOG_ERROR(LOG_CORE, "buffer size out of range %d/%d", pph->protoSize, PROTO_SIZE_MAX);
125                 break;
126             }
127             bufferSize = (pph->protoSize / MEMORY_BLOCK_UNIT + 1) * MEMORY_BLOCK_UNIT;
128             buf.resize(bufferSize);
129             pph = (struct ProtocolHead*)buf.data();
130         }
131         if (pph->protoSize < head_size) {
132             PROFILER_LOG_ERROR(LOG_CORE, "pph->protoSize is less than head_size!");
133             break;
134         }
135         if (!ReceiveData(pssr->socketHandle_, buf.data() + head_size, pph->protoSize - head_size)) {
136             PROFILER_LOG_DEBUG(LOG_CORE, "====== IPC LOST CONNECT ======");
137             break;
138         }
139         switch (pph->protoType & PROTOCOL_TYPE_FILTER) {
140             case PROTOCOL_TYPE_RAW: {
141                 pssr->RawProtocolProc(pph->protoType & (~PROTOCOL_TYPE_FILTER), pph->datas, pph->protoSize - head_size);
142                 break;
143             }
144             case PROTOCOL_TYPE_PROTOBUF:
145                 if (pssr->serviceBase_ != nullptr) {
146                     pssr->serviceBase_->ProtocolProc(*pssr, pph->protoType & (~PROTOCOL_TYPE_FILTER), pph->datas,
147                                                      pph->protoSize - head_size);
148                 }
149                 break;
150             default:
151                 PROFILER_LOG_ERROR(LOG_CORE, "unknown protocol %d", pph->protoType);
152                 break;
153         }
154     }
155     if (callback) {
156         callback();
157     }
158     pssr->clientState_ = CLIENT_STAT_THREAD_EXITED;
159     PROFILER_LOG_DEBUG(LOG_CORE, "UnixSocketRecv thread exit");
160     return nullptr;
161 }
162 
CreateRecvThread(void (* callback)())163 bool SocketContext::CreateRecvThread(void (*callback)())
164 {
165     recvThread_ = std::thread([this, callback] { this->UnixSocketRecv(this, callback); });
166     CHECK_TRUE(recvThread_.get_id() != std::thread::id(), false, "CreateRecvThread FAIL");
167     return true;
168 }
169 
SendRaw(uint32_t pnum,const int8_t * data,uint32_t size,int sockfd)170 bool SocketContext::SendRaw(uint32_t pnum, const int8_t* data, uint32_t size, int sockfd)
171 {
172     CHECK_NOTNULL(data, false, "SendRaw data null");
173     if (sockfd == -1) {
174         sockfd = socketHandle_;
175     }
176     struct ProtocolHead phead;
177     phead.protoType = PROTOCOL_TYPE_RAW | pnum;
178     phead.protoSize = size + sizeof(struct ProtocolHead);
179     CHECK_TRUE(send(sockfd, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0) != -1, false,
180                "SendRaw Send Head ERR :%d", errno);
181 
182     CHECK_TRUE(send(sockfd, data, size, 0) != -1, false, "SendRaw Send Data ERR : %d", errno);
183     return true;
184 }
185 
186 #ifndef NO_PROTOBUF
SendProtobuf(uint32_t pnum,google::protobuf::Message & pmsg)187 bool SocketContext::SendProtobuf(uint32_t pnum, google::protobuf::Message& pmsg)
188 {
189     int size = pmsg.ByteSizeLong();
190     CHECK_TRUE(size > 0, false, "%s:size less than or equal to 0", __func__);
191     int8_t* data = reinterpret_cast<int8_t*>(malloc(size));
192     if (data == nullptr) {
193         return false;
194     }
195     pmsg.SerializeToArray(data, size);
196     struct ProtocolHead phead;
197     phead.protoType = PROTOCOL_TYPE_PROTOBUF | pnum;
198     phead.protoSize = size + sizeof(struct ProtocolHead);
199     send(socketHandle_, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0);
200     send(socketHandle_, data, size, 0);
201 
202     free(data);
203     return true;
204 }
205 #endif
206 
SendHookConfig(const uint8_t * config,size_t len)207 bool SocketContext::SendHookConfig(const uint8_t* config, size_t len)
208 {
209     if (config == nullptr || len == 0) {
210         return false;
211     }
212 
213     struct ProtocolHead phead;
214     phead.protoType = PROTOCOL_TYPE_PROTOBUF;
215     phead.protoSize = len + sizeof(struct ProtocolHead);
216     send(socketHandle_, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0);
217     send(socketHandle_, config, len, 0);
218     return true;
219 }
220 
SendHeartBeat()221 bool SocketContext::SendHeartBeat()
222 {
223     struct ProtocolHead phead;
224     phead.protoType = PROTOCOL_TYPE_PROTOBUF;
225     phead.protoSize = sizeof(HEARTBEAT_MSG) + sizeof(struct ProtocolHead);
226 
227     if (send(socketHandle_, reinterpret_cast<int8_t*>(&phead), sizeof(struct ProtocolHead), 0) == -1) {
228         return false;
229     }
230 
231     if (send(socketHandle_, &HEARTBEAT_MSG, sizeof(HEARTBEAT_MSG), 0) == -1) {
232         return false;
233     }
234 
235     return true;
236 }
237 
IsConnected()238 bool SocketContext::IsConnected()
239 {
240     char buf[1];
241     ssize_t recv_bytes = recv(socketHandle_, buf, sizeof(buf), MSG_DONTWAIT);
242     if (recv_bytes == 0) {
243         PROFILER_LOG_ERROR(LOG_CORE, "Peer Process Exceptionally Disconnected");
244         return false;
245     } else if (recv_bytes > 0) {
246         // This is not supposed to happen because currently native_deomon does not send data to the client.
247         return true;
248     } else {
249         return errno == EAGAIN || errno == EWOULDBLOCK;
250     }
251 }
252 
SendFileDescriptor(int fd)253 bool SocketContext::SendFileDescriptor(int fd)
254 {
255     struct msghdr msg = {0};
256     struct cmsghdr* cmsg = nullptr;
257     char buf[CMSG_SPACE(1 * sizeof(int))] = {0};
258     char data;
259     if (memset_s(buf, sizeof(buf), 0, sizeof(buf)) != EOK) {
260         PROFILER_LOG_ERROR(LOG_CORE, "memset_s error!");
261     }
262     struct iovec io = {.iov_base = &data, .iov_len = 1};
263     msg.msg_iov = &io;
264     msg.msg_iovlen = 1;
265     msg.msg_control = buf;
266     msg.msg_controllen = sizeof(buf);
267     cmsg = CMSG_FIRSTHDR(&msg);
268     cmsg->cmsg_level = SOL_SOCKET;
269     cmsg->cmsg_type = SCM_RIGHTS;
270     cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 1);
271     if (memcpy_s(CMSG_DATA(cmsg), 1 * sizeof(int), &fd, 1 * sizeof(int)) != EOK) {
272         PROFILER_LOG_ERROR(LOG_CORE, "memcpy_s error");
273     }
274 
275     CHECK_TRUE(sendmsg(socketHandle_, &msg, 0) != -1, false, "SendFileDescriptor FAIL");
276     return true;
277 }
278 
ReceiveFileDiscriptor()279 int SocketContext::ReceiveFileDiscriptor()
280 {
281     struct msghdr msg = {0};
282     struct cmsghdr* cmsg = nullptr;
283     char buf[CMSG_SPACE(1 * sizeof(int))] = {0};
284     char data;
285     struct iovec io = {.iov_base = &data, .iov_len = 1};
286     msg.msg_iov = &io;
287     msg.msg_iovlen = 1;
288     msg.msg_control = buf;
289     msg.msg_controllen = sizeof(buf);
290 
291     CHECK_TRUE(recvmsg(socketHandle_, &msg, 0) != -1, -1, "ReceiveFileDiscriptor FAIL");
292     cmsg = CMSG_FIRSTHDR(&msg);
293 
294     return cmsg ? *(int*)CMSG_DATA(cmsg) : -1;
295 }
296