1/*
2 * Copyright (c) 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 "socket_session.h"
17
18#include <sstream>
19
20#include <sys/socket.h>
21#include <unistd.h>
22
23#include "proto.h"
24
25#undef LOG_TAG
26#define LOG_TAG "SocketSession"
27
28namespace OHOS {
29namespace Msdp {
30namespace DeviceStatus {
31
32SocketSession::SocketSession(const std::string &programName, int32_t moduleType,
33                             int32_t tokenType, int32_t fd, int32_t uid, int32_t pid)
34    : fd_(fd), uid_(uid), pid_(pid), tokenType_(tokenType), programName_(programName)
35{}
36
37SocketSession::~SocketSession()
38{
39    if ((fd_ >= 0) && (::close(fd_) != 0)) {
40        FI_HILOGE("close(%{public}d) failed:%{public}s", fd_, ::strerror(errno));
41    }
42}
43
44bool SocketSession::SendMsg(NetPacket &pkt) const
45{
46    if (pkt.ChkRWError()) {
47        FI_HILOGE("Read and write status is error");
48        return false;
49    }
50    StreamBuffer buf;
51    if (!pkt.MakeData(buf)) {
52        FI_HILOGE("Failed to buffer packet");
53        return false;
54    }
55    return SendMsg(buf.Data(), buf.Size());
56}
57
58bool SocketSession::SendMsg(const char *buf, size_t size) const
59{
60    CHKPF(buf);
61    if ((size == 0) || (size > MAX_PACKET_BUF_SIZE)) {
62        FI_HILOGE("buf size:%{public}zu", size);
63        return false;
64    }
65    if (fd_ < 0) {
66        FI_HILOGE("The fd_ is less than 0");
67        return false;
68    }
69
70    int32_t idx = 0;
71    int32_t retryCount = 0;
72    const int32_t bufSize = static_cast<int32_t>(size);
73    int32_t remSize = bufSize;
74    FI_HILOGD("Rem size:%{public}d", remSize);
75    while (remSize > 0 && retryCount < SEND_RETRY_LIMIT) {
76        retryCount += 1;
77        FI_HILOGD("Send message to client (%{public}d, %{public}d)", fd_, pid_);
78        ssize_t count = send(fd_, &buf[idx], remSize, MSG_DONTWAIT | MSG_NOSIGNAL);
79        if (count < 0) {
80            if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
81                usleep(SEND_RETRY_SLEEP_TIME);
82                FI_HILOGW("Continue for errno EAGAIN|EINTR|EWOULDBLOCK, errno:%{public}d, pid:%{public}d", errno, pid_);
83                continue;
84            }
85            FI_HILOGE("Send return failed, error:%{public}d, fd:%{public}d, pid:%{public}d", errno, fd_, pid_);
86            return false;
87        }
88        idx += count;
89        remSize -= count;
90        if (remSize > 0) {
91            usleep(SEND_RETRY_SLEEP_TIME);
92        }
93    }
94    if (retryCount >= SEND_RETRY_LIMIT || remSize != 0) {
95        FI_HILOGE("Send too many times:%{public}d/%{public}d, size:%{public}d/%{public}d, fd:%{public}d,"
96            "pid:%{public}d", retryCount, SEND_RETRY_LIMIT, idx, bufSize, fd_, pid_);
97        return false;
98    }
99    return true;
100}
101
102std::string SocketSession::ToString() const
103{
104    std::ostringstream oss;
105    oss << "fd = " << fd_
106        << ((fd_ < 0) ? ", closed" : ", opened")
107        << ", pid = " << pid_
108        << ", tokenType = " << tokenType_
109        << std::endl;
110    return oss.str();
111}
112
113void SocketSession::Dispatch(const struct epoll_event &ev)
114{
115    if ((ev.events & EPOLLIN) == EPOLLIN) {
116        FI_HILOGD("Data received (%{public}d)", fd_);
117    } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
118        FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
119    }
120}
121} // namespace DeviceStatus
122} // namespace Msdp
123} // namespace OHOS