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_connection.h"
17
18#include <sys/socket.h>
19#include <unistd.h>
20
21#include "devicestatus_define.h"
22#include "include/util.h"
23
24#undef LOG_TAG
25#define LOG_TAG "SocketConnection"
26
27namespace OHOS {
28namespace Msdp {
29namespace DeviceStatus {
30
31SocketConnection::SocketConnection(int32_t socketFd,
32                                   std::function<void(NetPacket&)> recv,
33                                   std::function<void()> onDisconnected)
34    : socketFd_(socketFd), recv_(recv), onDisconnected_(onDisconnected)
35{}
36
37SocketConnection::~SocketConnection()
38{
39    if ((socketFd_ >= 0) && (::close(socketFd_) != 0)) {
40        FI_HILOGE("close(%{public}d) failed:%{public}s", socketFd_, ::strerror(errno));
41    }
42}
43
44std::shared_ptr<SocketConnection> SocketConnection::Connect(std::function<int32_t()> socket,
45    std::function<void(NetPacket&)> recv, std::function<void()> onDisconnected)
46{
47    CALL_DEBUG_ENTER;
48    CHKPP(socket);
49    int32_t sockFd = socket();
50    if (sockFd < 0) {
51        return nullptr;
52    }
53    return std::make_shared<SocketConnection>(sockFd, recv, onDisconnected);
54}
55
56void SocketConnection::OnReadable(int32_t fd)
57{
58    CALL_DEBUG_ENTER;
59    char buf[MAX_PACKET_BUF_SIZE] {};
60    ssize_t numRead;
61
62    do {
63        numRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
64        if (numRead > 0) {
65            buffer_.Write(buf, numRead);
66            OnReadPackets(buffer_, recv_);
67        } else if (numRead < 0) {
68            if (errno == EINTR) {
69                FI_HILOGD("recv was interrupted, read again");
70                continue;
71            }
72            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
73                FI_HILOGW("No available data");
74            } else {
75                FI_HILOGE("recv failed:%{public}s", ::strerror(errno));
76            }
77            break;
78        } else {
79            FI_HILOGE("EOF happened");
80            OnShutdown(fd);
81            break;
82        }
83    } while (numRead == sizeof(buf));
84}
85
86void SocketConnection::OnShutdown(int32_t fd)
87{
88    if (onDisconnected_) {
89        onDisconnected_();
90    }
91}
92
93void SocketConnection::OnException(int32_t fd)
94{
95    OnShutdown(fd);
96}
97} // namespace DeviceStatus
98} // namespace Msdp
99} // namespace OHOS