/* * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ipc_unix_socket.h" #include #include #include #include #include "hhlog.h" namespace OHOS { namespace Developtools { namespace Hiebpf { IpcUnixSocketServer::IpcUnixSocketServer() {} IpcUnixSocketServer::~IpcUnixSocketServer() { Stop(); } bool IpcUnixSocketServer::Start(const std::string &pathname) { CHECK_TRUE(serverFd_ == -1, false, "Unix Socket Server is running"); serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0); CHECK_TRUE(serverFd_ != -1, false, "create Unix Socket Server failed, %d: %s", errno, strerror(errno)); unlink(pathname.c_str()); struct sockaddr_un addr = {0}; addr.sun_family = AF_UNIX; std::copy(pathname.c_str(), pathname.c_str() + pathname.size() + 1, addr.sun_path); if (bind(serverFd_, (struct sockaddr*)&addr, sizeof(sockaddr_un)) != 0) { HHLOGE(true, "bind failed, Unix Socket(%s), %d: %s", pathname.c_str(), errno, strerror(errno)); close(serverFd_); return false; } if (listen(serverFd_, UNIX_SOCKET_LISTEN_COUNT) != 0) { HHLOGE(true, "listen failed, Unix Socket(%s), %d: %s", pathname.c_str(), errno, strerror(errno)); close(serverFd_); unlink(pathname.c_str()); return false; } pathName_ = pathname; isRunning_ = true; handleThread_ = std::thread([this] { this->HandleThreadLoop(); }); return true; } bool IpcUnixSocketServer::Stop() { isRunning_ = false; if (serverFd_ != -1) { close(serverFd_); serverFd_ = -1; } if (clientFd_ != -1) { close(clientFd_); clientFd_ = -1; } if (handleThread_.joinable()) { handleThread_.join(); } unlink(pathName_.c_str()); return true; } bool IpcUnixSocketServer::SendMessage(const void *buf, size_t size) { CHECK_TRUE(clientFd_ != -1, false, "no available Unix Socket"); CHECK_TRUE(send(clientFd_, buf, size, 0) != -1, false, "send failed, Unix Socket(%d) %zu bytes, %d: %s", clientFd_, size, errno, strerror(errno)); return true; } void IpcUnixSocketServer::HandleThreadLoop() { while (isRunning_) { struct pollfd pollFd {serverFd_, POLLIN, 0}; const int timeout = 1000; int polled = TEMP_FAILURE_RETRY(poll(&pollFd, 1, timeout)); if (polled == 0) { // timeout continue; } else if (polled < 0 || !(pollFd.revents & POLLIN)) { HHLOGE(true, "poll failed, Unix Socket(%d), %d: %s", serverFd_, errno, strerror(errno)); close(serverFd_); serverFd_ = -1; break; } clientFd_ = accept(serverFd_, nullptr, nullptr); if (clientFd_ == -1) { HHLOGE(true, "accept failed, Unix Socket(%d), %d: %s", serverFd_, errno, strerror(errno)); continue; } while (isRunning_ && clientFd_ != -1) { uint8_t buf[UNIX_SOCKET_BUFFER_SIZE] = {0}; int recvSize = recv(clientFd_, buf, UNIX_SOCKET_BUFFER_SIZE, 0); if (recvSize > 0) { if (handleMessageFn_) { handleMessageFn_(buf, recvSize); } continue; } else if (recvSize == 0) { HHLOGE(true, "recv failed, peer has closed"); } else { HHLOGE(true, "recv failed, Unix Socket(%d), %d: %s", clientFd_, errno, strerror(errno)); } close(clientFd_); clientFd_ = -1; } } } IpcUnixSocketClient::IpcUnixSocketClient() {} IpcUnixSocketClient::~IpcUnixSocketClient() { Disconnect(); } bool IpcUnixSocketClient::Connect(const std::string &pathname) { CHECK_TRUE(sockFd_ == -1, false, "Unix Socket has connected"); sockFd_ = socket(AF_UNIX, SOCK_STREAM, 0); CHECK_TRUE(sockFd_ != -1, false, "create Unix Socket Server failed, %d: %s", errno, strerror(errno)); struct sockaddr_un addr = {0}; addr.sun_family = AF_UNIX; std::copy(pathname.c_str(), pathname.c_str() + pathname.size() + 1, addr.sun_path); if (connect(sockFd_, (struct sockaddr*)&addr, sizeof(sockaddr_un)) == -1) { HHLOGE(true, "connect failed, %d: %s", errno, strerror(errno)); sockFd_ = -1; return false; } return true; } void IpcUnixSocketClient::Disconnect() { if (sockFd_ != -1) { close(sockFd_); sockFd_ = -1; } } bool IpcUnixSocketClient::SendMessage(const void *buf, size_t size) { CHECK_TRUE(sockFd_ != -1, false, "Unix Socket disconnected"); if (send(sockFd_, buf, size, 0) != -1) { return true; } HHLOGE(true, "send failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno)); return false; } bool IpcUnixSocketClient::RecvMessage(void *buf, size_t &size, uint32_t timeout) { CHECK_TRUE(sockFd_ != -1, false, "Unix Socket disconnected"); struct pollfd pollFd {sockFd_, POLLIN | POLLERR | POLLHUP, 0}; int polled = poll(&pollFd, 1, timeout); if (polled == 0) { // timeout size = 0; return true; } else if (polled < 0 || !(pollFd.revents & POLLIN)) { HHLOGE(true, "poll failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno)); return false; } int recvSize = recv(sockFd_, buf, size, 0); if (recvSize > 0) { size = static_cast(recvSize); return true; } else if (recvSize == 0) { HHLOGE(true, "recv failed, peer has closed"); } else { HHLOGE(true, "recv failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno)); } return false; } } // namespace Hiebpf } // namespace Developtools } // namespace OHOS