106f6ba60Sopenharmony_ci/*
206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License.
506f6ba60Sopenharmony_ci * You may obtain a copy of the License at
606f6ba60Sopenharmony_ci *
706f6ba60Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
806f6ba60Sopenharmony_ci *
906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and
1306f6ba60Sopenharmony_ci * limitations under the License.
1406f6ba60Sopenharmony_ci */
1506f6ba60Sopenharmony_ci#include "ipc_unix_socket.h"
1606f6ba60Sopenharmony_ci
1706f6ba60Sopenharmony_ci#include <poll.h>
1806f6ba60Sopenharmony_ci#include <sys/socket.h>
1906f6ba60Sopenharmony_ci#include <sys/un.h>
2006f6ba60Sopenharmony_ci#include <unistd.h>
2106f6ba60Sopenharmony_ci
2206f6ba60Sopenharmony_ci#include "hhlog.h"
2306f6ba60Sopenharmony_ci
2406f6ba60Sopenharmony_cinamespace OHOS {
2506f6ba60Sopenharmony_cinamespace Developtools {
2606f6ba60Sopenharmony_cinamespace Hiebpf {
2706f6ba60Sopenharmony_ciIpcUnixSocketServer::IpcUnixSocketServer() {}
2806f6ba60Sopenharmony_ci
2906f6ba60Sopenharmony_ciIpcUnixSocketServer::~IpcUnixSocketServer()
3006f6ba60Sopenharmony_ci{
3106f6ba60Sopenharmony_ci    Stop();
3206f6ba60Sopenharmony_ci}
3306f6ba60Sopenharmony_ci
3406f6ba60Sopenharmony_cibool IpcUnixSocketServer::Start(const std::string &pathname)
3506f6ba60Sopenharmony_ci{
3606f6ba60Sopenharmony_ci    CHECK_TRUE(serverFd_ == -1, false, "Unix Socket Server is running");
3706f6ba60Sopenharmony_ci
3806f6ba60Sopenharmony_ci    serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0);
3906f6ba60Sopenharmony_ci    CHECK_TRUE(serverFd_ != -1, false, "create Unix Socket Server failed, %d: %s", errno, strerror(errno));
4006f6ba60Sopenharmony_ci
4106f6ba60Sopenharmony_ci    unlink(pathname.c_str());
4206f6ba60Sopenharmony_ci    struct sockaddr_un addr = {0};
4306f6ba60Sopenharmony_ci    addr.sun_family = AF_UNIX;
4406f6ba60Sopenharmony_ci    std::copy(pathname.c_str(), pathname.c_str() + pathname.size() + 1, addr.sun_path);
4506f6ba60Sopenharmony_ci    if (bind(serverFd_, (struct sockaddr*)&addr, sizeof(sockaddr_un)) != 0) {
4606f6ba60Sopenharmony_ci        HHLOGE(true, "bind failed, Unix Socket(%s), %d: %s", pathname.c_str(), errno, strerror(errno));
4706f6ba60Sopenharmony_ci        close(serverFd_);
4806f6ba60Sopenharmony_ci        return false;
4906f6ba60Sopenharmony_ci    }
5006f6ba60Sopenharmony_ci    if (listen(serverFd_, UNIX_SOCKET_LISTEN_COUNT) != 0) {
5106f6ba60Sopenharmony_ci        HHLOGE(true, "listen failed, Unix Socket(%s), %d: %s", pathname.c_str(), errno, strerror(errno));
5206f6ba60Sopenharmony_ci        close(serverFd_);
5306f6ba60Sopenharmony_ci        unlink(pathname.c_str());
5406f6ba60Sopenharmony_ci        return false;
5506f6ba60Sopenharmony_ci    }
5606f6ba60Sopenharmony_ci    pathName_ = pathname;
5706f6ba60Sopenharmony_ci
5806f6ba60Sopenharmony_ci    isRunning_ = true;
5906f6ba60Sopenharmony_ci    handleThread_ = std::thread([this] { this->HandleThreadLoop(); });
6006f6ba60Sopenharmony_ci    return true;
6106f6ba60Sopenharmony_ci}
6206f6ba60Sopenharmony_ci
6306f6ba60Sopenharmony_cibool IpcUnixSocketServer::Stop()
6406f6ba60Sopenharmony_ci{
6506f6ba60Sopenharmony_ci    isRunning_ = false;
6606f6ba60Sopenharmony_ci    if (serverFd_ != -1) {
6706f6ba60Sopenharmony_ci        close(serverFd_);
6806f6ba60Sopenharmony_ci        serverFd_ = -1;
6906f6ba60Sopenharmony_ci    }
7006f6ba60Sopenharmony_ci    if (clientFd_ != -1) {
7106f6ba60Sopenharmony_ci        close(clientFd_);
7206f6ba60Sopenharmony_ci        clientFd_ = -1;
7306f6ba60Sopenharmony_ci    }
7406f6ba60Sopenharmony_ci    if (handleThread_.joinable()) {
7506f6ba60Sopenharmony_ci        handleThread_.join();
7606f6ba60Sopenharmony_ci    }
7706f6ba60Sopenharmony_ci    unlink(pathName_.c_str());
7806f6ba60Sopenharmony_ci    return true;
7906f6ba60Sopenharmony_ci}
8006f6ba60Sopenharmony_ci
8106f6ba60Sopenharmony_cibool IpcUnixSocketServer::SendMessage(const void *buf, size_t size)
8206f6ba60Sopenharmony_ci{
8306f6ba60Sopenharmony_ci    CHECK_TRUE(clientFd_ != -1, false, "no available Unix Socket");
8406f6ba60Sopenharmony_ci
8506f6ba60Sopenharmony_ci    CHECK_TRUE(send(clientFd_, buf, size, 0) != -1, false,
8606f6ba60Sopenharmony_ci               "send failed, Unix Socket(%d) %zu bytes, %d: %s", clientFd_, size, errno, strerror(errno));
8706f6ba60Sopenharmony_ci    return true;
8806f6ba60Sopenharmony_ci}
8906f6ba60Sopenharmony_ci
9006f6ba60Sopenharmony_civoid IpcUnixSocketServer::HandleThreadLoop()
9106f6ba60Sopenharmony_ci{
9206f6ba60Sopenharmony_ci    while (isRunning_) {
9306f6ba60Sopenharmony_ci        struct pollfd pollFd {serverFd_, POLLIN, 0};
9406f6ba60Sopenharmony_ci        const int timeout = 1000;
9506f6ba60Sopenharmony_ci        int polled = TEMP_FAILURE_RETRY(poll(&pollFd, 1, timeout));
9606f6ba60Sopenharmony_ci        if (polled == 0) { // timeout
9706f6ba60Sopenharmony_ci            continue;
9806f6ba60Sopenharmony_ci        } else if (polled < 0 || !(pollFd.revents & POLLIN)) {
9906f6ba60Sopenharmony_ci            HHLOGE(true, "poll failed, Unix Socket(%d), %d: %s", serverFd_, errno, strerror(errno));
10006f6ba60Sopenharmony_ci            close(serverFd_);
10106f6ba60Sopenharmony_ci            serverFd_ = -1;
10206f6ba60Sopenharmony_ci            break;
10306f6ba60Sopenharmony_ci        }
10406f6ba60Sopenharmony_ci
10506f6ba60Sopenharmony_ci        clientFd_ = accept(serverFd_, nullptr, nullptr);
10606f6ba60Sopenharmony_ci        if (clientFd_ == -1) {
10706f6ba60Sopenharmony_ci            HHLOGE(true, "accept failed, Unix Socket(%d), %d: %s", serverFd_, errno, strerror(errno));
10806f6ba60Sopenharmony_ci            continue;
10906f6ba60Sopenharmony_ci        }
11006f6ba60Sopenharmony_ci
11106f6ba60Sopenharmony_ci        while (isRunning_ && clientFd_ != -1) {
11206f6ba60Sopenharmony_ci            uint8_t buf[UNIX_SOCKET_BUFFER_SIZE] = {0};
11306f6ba60Sopenharmony_ci            int recvSize = recv(clientFd_, buf, UNIX_SOCKET_BUFFER_SIZE, 0);
11406f6ba60Sopenharmony_ci            if (recvSize > 0) {
11506f6ba60Sopenharmony_ci                if (handleMessageFn_) {
11606f6ba60Sopenharmony_ci                    handleMessageFn_(buf, recvSize);
11706f6ba60Sopenharmony_ci                }
11806f6ba60Sopenharmony_ci                continue;
11906f6ba60Sopenharmony_ci            } else if (recvSize == 0) {
12006f6ba60Sopenharmony_ci                HHLOGE(true, "recv failed, peer has closed");
12106f6ba60Sopenharmony_ci            } else {
12206f6ba60Sopenharmony_ci                HHLOGE(true, "recv failed, Unix Socket(%d), %d: %s", clientFd_, errno, strerror(errno));
12306f6ba60Sopenharmony_ci            }
12406f6ba60Sopenharmony_ci            close(clientFd_);
12506f6ba60Sopenharmony_ci            clientFd_ = -1;
12606f6ba60Sopenharmony_ci        }
12706f6ba60Sopenharmony_ci    }
12806f6ba60Sopenharmony_ci}
12906f6ba60Sopenharmony_ci
13006f6ba60Sopenharmony_ciIpcUnixSocketClient::IpcUnixSocketClient() {}
13106f6ba60Sopenharmony_ci
13206f6ba60Sopenharmony_ciIpcUnixSocketClient::~IpcUnixSocketClient()
13306f6ba60Sopenharmony_ci{
13406f6ba60Sopenharmony_ci    Disconnect();
13506f6ba60Sopenharmony_ci}
13606f6ba60Sopenharmony_ci
13706f6ba60Sopenharmony_cibool IpcUnixSocketClient::Connect(const std::string &pathname)
13806f6ba60Sopenharmony_ci{
13906f6ba60Sopenharmony_ci    CHECK_TRUE(sockFd_ == -1, false, "Unix Socket has connected");
14006f6ba60Sopenharmony_ci
14106f6ba60Sopenharmony_ci    sockFd_ = socket(AF_UNIX, SOCK_STREAM, 0);
14206f6ba60Sopenharmony_ci    CHECK_TRUE(sockFd_ != -1, false, "create Unix Socket Server failed, %d: %s", errno, strerror(errno));
14306f6ba60Sopenharmony_ci
14406f6ba60Sopenharmony_ci    struct sockaddr_un addr = {0};
14506f6ba60Sopenharmony_ci    addr.sun_family = AF_UNIX;
14606f6ba60Sopenharmony_ci    std::copy(pathname.c_str(), pathname.c_str() + pathname.size() + 1, addr.sun_path);
14706f6ba60Sopenharmony_ci    if (connect(sockFd_, (struct sockaddr*)&addr, sizeof(sockaddr_un)) == -1) {
14806f6ba60Sopenharmony_ci        HHLOGE(true, "connect failed, %d: %s", errno, strerror(errno));
14906f6ba60Sopenharmony_ci        sockFd_ = -1;
15006f6ba60Sopenharmony_ci        return false;
15106f6ba60Sopenharmony_ci    }
15206f6ba60Sopenharmony_ci
15306f6ba60Sopenharmony_ci    return true;
15406f6ba60Sopenharmony_ci}
15506f6ba60Sopenharmony_ci
15606f6ba60Sopenharmony_civoid IpcUnixSocketClient::Disconnect()
15706f6ba60Sopenharmony_ci{
15806f6ba60Sopenharmony_ci    if (sockFd_ != -1) {
15906f6ba60Sopenharmony_ci        close(sockFd_);
16006f6ba60Sopenharmony_ci        sockFd_ = -1;
16106f6ba60Sopenharmony_ci    }
16206f6ba60Sopenharmony_ci}
16306f6ba60Sopenharmony_ci
16406f6ba60Sopenharmony_cibool IpcUnixSocketClient::SendMessage(const void *buf, size_t size)
16506f6ba60Sopenharmony_ci{
16606f6ba60Sopenharmony_ci    CHECK_TRUE(sockFd_ != -1, false, "Unix Socket disconnected");
16706f6ba60Sopenharmony_ci
16806f6ba60Sopenharmony_ci    if (send(sockFd_, buf, size, 0) != -1) {
16906f6ba60Sopenharmony_ci        return true;
17006f6ba60Sopenharmony_ci    }
17106f6ba60Sopenharmony_ci    HHLOGE(true, "send failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno));
17206f6ba60Sopenharmony_ci    return false;
17306f6ba60Sopenharmony_ci}
17406f6ba60Sopenharmony_ci
17506f6ba60Sopenharmony_cibool IpcUnixSocketClient::RecvMessage(void *buf, size_t &size, uint32_t timeout)
17606f6ba60Sopenharmony_ci{
17706f6ba60Sopenharmony_ci    CHECK_TRUE(sockFd_ != -1, false, "Unix Socket disconnected");
17806f6ba60Sopenharmony_ci
17906f6ba60Sopenharmony_ci    struct pollfd pollFd {sockFd_, POLLIN | POLLERR | POLLHUP, 0};
18006f6ba60Sopenharmony_ci    int polled = poll(&pollFd, 1, timeout);
18106f6ba60Sopenharmony_ci    if (polled == 0) { // timeout
18206f6ba60Sopenharmony_ci        size = 0;
18306f6ba60Sopenharmony_ci        return true;
18406f6ba60Sopenharmony_ci    } else if (polled < 0 || !(pollFd.revents & POLLIN)) {
18506f6ba60Sopenharmony_ci        HHLOGE(true, "poll failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno));
18606f6ba60Sopenharmony_ci        return false;
18706f6ba60Sopenharmony_ci    }
18806f6ba60Sopenharmony_ci
18906f6ba60Sopenharmony_ci    int recvSize = recv(sockFd_, buf, size, 0);
19006f6ba60Sopenharmony_ci    if (recvSize > 0) {
19106f6ba60Sopenharmony_ci        size = static_cast<size_t>(recvSize);
19206f6ba60Sopenharmony_ci        return true;
19306f6ba60Sopenharmony_ci    } else if (recvSize == 0) {
19406f6ba60Sopenharmony_ci        HHLOGE(true, "recv failed, peer has closed");
19506f6ba60Sopenharmony_ci    } else {
19606f6ba60Sopenharmony_ci        HHLOGE(true, "recv failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno));
19706f6ba60Sopenharmony_ci    }
19806f6ba60Sopenharmony_ci
19906f6ba60Sopenharmony_ci    return false;
20006f6ba60Sopenharmony_ci}
20106f6ba60Sopenharmony_ci} // namespace Hiebpf
20206f6ba60Sopenharmony_ci} // namespace Developtools
20306f6ba60Sopenharmony_ci} // namespace OHOS
204