• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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