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 "stream_session.h"
17
18#include <cinttypes>
19#include <sstream>
20
21#include <fcntl.h>
22#include <sys/types.h>
23#include <sys/un.h>
24#include <unistd.h>
25
26#include "stream_socket.h"
27#include "proto.h"
28
29#undef LOG_TAG
30#define LOG_TAG "StreamSession"
31
32namespace OHOS {
33namespace Msdp {
34namespace DeviceStatus {
35namespace {
36const std::string FOUNDATION { "foundation" };
37} // namespace
38
39StreamSession::StreamSession(const std::string &programName, int32_t moduleType, int32_t fd, int32_t uid, int32_t pid)
40    : fd_(fd), pid_(pid)
41{}
42
43bool StreamSession::SendMsg(const char *buf, size_t size) const
44{
45    CHKPF(buf);
46    if ((size == 0) || (size > MAX_PACKET_BUF_SIZE)) {
47        FI_HILOGE("buf size:%{public}zu", size);
48        return false;
49    }
50    if (fd_ < 0) {
51        FI_HILOGE("The fd_ is less than 0");
52        return false;
53    }
54
55    int32_t idx = 0;
56    int32_t retryCount = 0;
57    const int32_t bufSize = static_cast<int32_t>(size);
58    int32_t remSize = bufSize;
59    while (remSize > 0 && retryCount < SEND_RETRY_LIMIT) {
60        retryCount += 1;
61        ssize_t count = send(fd_, &buf[idx], remSize, MSG_DONTWAIT | MSG_NOSIGNAL);
62        if (count < 0) {
63            if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
64                usleep(SEND_RETRY_SLEEP_TIME);
65                FI_HILOGW("Continue for errno EAGAIN|EINTR|EWOULDBLOCK, errno:%{public}d", errno);
66                continue;
67            }
68            FI_HILOGE("Send return failed, error:%{public}d, fd:%{public}d", errno, fd_);
69            return false;
70        }
71        idx += count;
72        remSize -= count;
73        if (remSize > 0) {
74            usleep(SEND_RETRY_SLEEP_TIME);
75        }
76    }
77    if (retryCount >= SEND_RETRY_LIMIT || remSize != 0) {
78        FI_HILOGE("Send too many times:%{public}d/%{public}d, size:%{public}d/%{public}d, fd:%{public}d",
79            retryCount, SEND_RETRY_LIMIT, idx, bufSize, fd_);
80        return false;
81    }
82    return true;
83}
84
85void StreamSession::Close()
86{
87    CALL_DEBUG_ENTER;
88    FI_HILOGD("Enter fd_:%{public}d", fd_);
89    if (fd_ >= 0) {
90        if (close(fd_) < 0) {
91            FI_HILOGE("Close fd failed, error:%{public}s, fd_:%{public}d", strerror(errno), fd_);
92        }
93        fd_ = -1;
94    }
95}
96
97bool StreamSession::SendMsg(NetPacket &pkt) const
98{
99    if (pkt.ChkRWError()) {
100        FI_HILOGE("Read and write status is error");
101        return false;
102    }
103    StreamBuffer buf;
104    if (!pkt.MakeData(buf)) {
105        FI_HILOGE("Failed to buffer packet");
106        return false;
107    }
108    return SendMsg(buf.Data(), buf.Size());
109}
110} // namespace DeviceStatus
111} // namespace Msdp
112} // namespace OHOS