1 /*
2 * Copyright (c) 2021 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 "transport.h"
17
18 #include <__mutex_base>
19 #include <cerrno>
20 #include <cstddef>
21 #include <iosfwd>
22 #include <list>
23 #include <securec.h>
24 #include <string>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <unistd.h>
28
29 #include "def.h"
30 #include "hilog/log.h"
31
32 namespace OHOS {
33 namespace HiviewDFX {
34 namespace {
35 constexpr HiLogLabel LABEL = { LOG_CORE, 0xD002D08, "HISYSEVENT" };
36 constexpr size_t BUF_SIZE = 2000;
37 char errMsg[BUF_SIZE] = { 0 };
38 }
39 Transport Transport::instance_;
40
GetInstance()41 Transport& Transport::GetInstance()
42 {
43 return instance_;
44 }
45
InitRecvBuffer(int socketId)46 void Transport::InitRecvBuffer(int socketId)
47 {
48 int oldN = 0;
49 socklen_t oldOutSize = static_cast<socklen_t>(sizeof(int));
50 if (getsockopt(socketId, SOL_SOCKET, SO_SNDBUF, static_cast<void *>(&oldN), &oldOutSize) < 0) {
51 strerror_r(errno, errMsg, BUF_SIZE);
52 HiLog::Error(LABEL, "get socket send buffer error=%{public}d, msg=%{public}s", errno, errMsg);
53 }
54
55 int sendBuffSize = MAX_DATA_SIZE;
56 if (setsockopt(socketId, SOL_SOCKET, SO_SNDBUF, static_cast<void *>(&sendBuffSize), sizeof(int)) < 0) {
57 strerror_r(errno, errMsg, BUF_SIZE);
58 HiLog::Error(LABEL, "set socket send buffer error=%{public}d, msg=%{public}s", errno, errMsg);
59 }
60
61 int newN = 0;
62 socklen_t newOutSize = static_cast<socklen_t>(sizeof(int));
63 if (getsockopt(socketId, SOL_SOCKET, SO_SNDBUF, static_cast<void *>(&newN), &newOutSize) < 0) {
64 strerror_r(errno, errMsg, BUF_SIZE);
65 HiLog::Error(LABEL, "get new socket send buffer error=%{public}d, msg=%{public}s", errno, errMsg);
66 }
67 HiLog::Debug(LABEL, "reset send buffer size old=%{public}d, new=%{public}d", oldN, newN);
68 }
69
SendToHiSysEventDataSource(const std::string & text)70 int Transport::SendToHiSysEventDataSource(const std::string &text)
71 {
72 struct sockaddr_un serverAddr;
73 serverAddr.sun_family = AF_UNIX;
74 if (strcpy_s(serverAddr.sun_path, sizeof(serverAddr.sun_path), "/dev/unix/socket/hisysevent") != EOK) {
75 HiLog::Error(LABEL, "can not assign server path");
76 return ERR_DOES_NOT_INIT;
77 }
78 serverAddr.sun_path[sizeof(serverAddr.sun_path) - 1] = '\0';
79
80 int socketId = TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
81 if (socketId < 0) {
82 strerror_r(errno, errMsg, BUF_SIZE);
83 HiLog::Error(LABEL, "create hisysevent client socket failed, error=%{public}d, msg=%{public}s",
84 errno, errMsg);
85 return ERR_DOES_NOT_INIT;
86 }
87 InitRecvBuffer(socketId);
88 auto sendRet = 0;
89 auto retryTimes = RETRY_TIMES;
90 do {
91 sendRet = sendto(socketId, text.c_str(), text.size(), 0,
92 reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr));
93 retryTimes--;
94 } while (sendRet < 0 && retryTimes > 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR));
95 if (sendRet < 0) {
96 close(socketId);
97 strerror_r(errno, errMsg, BUF_SIZE);
98 HiLog::Error(LABEL, "send data to hisysevent server failed, error=%{public}d, msg=%{public}s",
99 errno, errMsg);
100 return ERR_SEND_FAIL;
101 }
102 close(socketId);
103 HiLog::Debug(LABEL, "HiSysEvent send data successful");
104 return SUCCESS;
105 }
106
AddFailedData(const std::string & text)107 void Transport::AddFailedData(const std::string &text)
108 {
109 std::lock_guard<std::mutex> lock(mutex_);
110 if (retryDataList_.size() >= RETRY_QUEUE_SIZE) {
111 HiLog::Info(LABEL, "dispatch retry sysevent data as reach max size");
112 retryDataList_.pop_front();
113 }
114 retryDataList_.push_back(text);
115 }
116
RetrySendFailedData()117 void Transport::RetrySendFailedData()
118 {
119 std::lock_guard<std::mutex> lock(mutex_);
120 while (!retryDataList_.empty()) {
121 std::string text = retryDataList_.front();
122 HiLog::Debug(LABEL, "resend data size=%{public}lu, sysevent=%{public}s",
123 static_cast<unsigned long>(text.size()), text.c_str());
124 if (SendToHiSysEventDataSource(text) != SUCCESS) {
125 return;
126 }
127 retryDataList_.pop_front();
128 }
129 }
130
SendData(const std::string & text)131 int Transport::SendData(const std::string &text)
132 {
133 if (text.size() > MAX_DATA_SIZE) {
134 HiLog::Error(LABEL, "data is too long %{public}lu", static_cast<unsigned long>(text.length()));
135 return ERR_OVER_SIZE;
136 }
137 HiLog::Debug(LABEL, "size=%{public}lu, sysevent=%{public}s",
138 static_cast<unsigned long>(text.size()), text.c_str());
139
140 RetrySendFailedData();
141 int tryTimes = RETRY_TIMES;
142 int retCode = SUCCESS;
143 while (tryTimes > 0) {
144 tryTimes--;
145 retCode = SendToHiSysEventDataSource(text);
146 if (retCode == SUCCESS) {
147 return retCode;
148 }
149 }
150
151 AddFailedData(text);
152 return retCode;
153 }
154 } // namespace HiviewDFX
155 } // namespace OHOS
156
157