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 "fault_logger_pipe.h"
17
18#include <algorithm>
19#include <cerrno>
20#include <cstdio>
21#include <cstdlib>
22#include <cstring>
23#include <ctime>
24#include <fcntl.h>
25#include <securec.h>
26#include <string>
27#include <sys/socket.h>
28#include <sys/stat.h>
29#include <sys/syscall.h>
30#include <sys/types.h>
31#include <sys/un.h>
32#include <unistd.h>
33#include <vector>
34#include "dfx_define.h"
35#include "dfx_log.h"
36
37namespace OHOS {
38namespace HiviewDFX {
39namespace {
40const std::string FAULTLOGGER_PIPE_TAG = "FaultLoggerPipe";
41const int PIPE_TIMEOUT = 10000; // 10 seconds
42}
43
44FaultLoggerPipe::FaultLoggerPipe()
45{
46    init_ = false;
47    write_ = false;
48    Init();
49}
50
51FaultLoggerPipe::~FaultLoggerPipe()
52{
53    Destroy();
54}
55
56int FaultLoggerPipe::GetReadFd(void)
57{
58    DFXLOGD("%{public}s :: pipe read fd: %{public}d", __func__, fds_[PIPE_READ]);
59    return fds_[PIPE_READ];
60}
61
62int FaultLoggerPipe::GetWriteFd(void)
63{
64    DFXLOGD("%{public}s :: pipe write fd: %{public}d", __func__, fds_[PIPE_WRITE]);
65    if (!write_) {
66        write_ = true;
67        return fds_[PIPE_WRITE];
68    }
69    return -1;
70}
71
72bool FaultLoggerPipe::Init(void)
73{
74    if (!init_) {
75        if (pipe2(fds_, O_NONBLOCK) != 0) {
76            DFXLOGE("%{public}s :: Failed to create pipe.", __func__);
77            return false;
78        }
79        DFXLOGD("%{public}s :: create pipe.", __func__);
80    }
81    init_ = true;
82    if (!SetSize(MAX_PIPE_SIZE)) {
83        DFXLOGE("%{public}s :: Failed to set pipe size.", __func__);
84    }
85    return true;
86}
87
88bool FaultLoggerPipe::SetSize(long sz)
89{
90    if (!init_) {
91        return false;
92    }
93    if (fcntl(fds_[PIPE_READ], F_SETPIPE_SZ, sz) < 0) {
94        return false;
95    }
96    if (fcntl(fds_[PIPE_WRITE], F_SETPIPE_SZ, sz) < 0) {
97        return false;
98    }
99    return true;
100}
101
102void FaultLoggerPipe::Destroy(void)
103{
104    if (init_) {
105        DFXLOGD("%{public}s :: close pipe.", __func__);
106        Close(fds_[PIPE_READ]);
107        Close(fds_[PIPE_WRITE]);
108    }
109    init_ = false;
110}
111
112void FaultLoggerPipe::Close(int fd) const
113{
114    if (fd > 0) {
115        syscall(SYS_close, fd);
116    }
117}
118
119FaultLoggerPipe2::FaultLoggerPipe2(uint64_t time, bool isJson)
120{
121    if (isJson) {
122        faultLoggerJsonPipeBuf_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
123        faultLoggerJsonPipeRes_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
124    } else {
125        faultLoggerPipeBuf_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
126        faultLoggerPipeRes_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
127    }
128    time_ = time;
129}
130
131FaultLoggerPipe2::~FaultLoggerPipe2()
132{
133    faultLoggerPipeBuf_.reset();
134    faultLoggerPipeRes_.reset();
135    faultLoggerJsonPipeBuf_.reset();
136    faultLoggerJsonPipeRes_.reset();
137    time_ = 0;
138}
139
140FaultLoggerPipeMap::FaultLoggerPipeMap()
141{
142    std::lock_guard<std::mutex> lck(pipeMapsMutex_);
143    faultLoggerPipes_.clear();
144}
145
146FaultLoggerPipeMap::~FaultLoggerPipeMap()
147{
148    std::lock_guard<std::mutex> lck(pipeMapsMutex_);
149    std::map<int, std::unique_ptr<FaultLoggerPipe2> >::iterator iter = faultLoggerPipes_.begin();
150    while (iter != faultLoggerPipes_.end()) {
151        faultLoggerPipes_.erase(iter++);
152    }
153}
154
155void FaultLoggerPipeMap::Set(int pid, uint64_t time, bool isJson)
156{
157    std::lock_guard<std::mutex> lck(pipeMapsMutex_);
158    if (!Find(pid)) {
159        std::unique_ptr<FaultLoggerPipe2> ptr = std::unique_ptr<FaultLoggerPipe2>(new FaultLoggerPipe2(time, isJson));
160        faultLoggerPipes_.emplace(pid, std::move(ptr));
161    }
162}
163
164bool FaultLoggerPipeMap::Check(int pid, uint64_t time)
165{
166    std::lock_guard<std::mutex> lck(pipeMapsMutex_);
167    std::map<int, std::unique_ptr<FaultLoggerPipe2> >::const_iterator iter = faultLoggerPipes_.find(pid);
168    if (iter != faultLoggerPipes_.end()) {
169        if ((time > faultLoggerPipes_[pid]->time_) && (time - faultLoggerPipes_[pid]->time_) > PIPE_TIMEOUT) {
170            faultLoggerPipes_.erase(iter);
171            return false;
172        }
173        return true;
174    }
175    return false;
176}
177
178FaultLoggerPipe2* FaultLoggerPipeMap::Get(int pid)
179{
180    std::lock_guard<std::mutex> lck(pipeMapsMutex_);
181    if (!Find(pid)) {
182        return nullptr;
183    }
184    return faultLoggerPipes_[pid].get();
185}
186
187void FaultLoggerPipeMap::Del(int pid)
188{
189    std::lock_guard<std::mutex> lck(pipeMapsMutex_);
190    std::map<int, std::unique_ptr<FaultLoggerPipe2> >::const_iterator iter = faultLoggerPipes_.find(pid);
191    if (iter != faultLoggerPipes_.end()) {
192        faultLoggerPipes_.erase(iter);
193    }
194}
195
196bool FaultLoggerPipeMap::Find(int pid) const
197{
198    std::map<int, std::unique_ptr<FaultLoggerPipe2> >::const_iterator iter = faultLoggerPipes_.find(pid);
199    if (iter != faultLoggerPipes_.end()) {
200        return true;
201    }
202    return false;
203}
204} // namespace HiviewDfx
205} // namespace OHOS
206