* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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 "socket_session.h"
#include <sstream>
#include <sys/socket.h>
#include <unistd.h>
#include "proto.h"
#undef LOG_TAG
#define LOG_TAG "SocketSession"
namespace OHOS {
namespace Msdp {
namespace DeviceStatus {
SocketSession::SocketSession(const std::string &programName, int32_t moduleType,
int32_t tokenType, int32_t fd, int32_t uid, int32_t pid)
: fd_(fd), uid_(uid), pid_(pid), tokenType_(tokenType), programName_(programName)
{}
SocketSession::~SocketSession()
{
if ((fd_ >= 0) && (::close(fd_) != 0)) {
FI_HILOGE("close(%{public}d) failed:%{public}s", fd_, ::strerror(errno));
}
}
bool SocketSession::SendMsg(NetPacket &pkt) const
{
if (pkt.ChkRWError()) {
FI_HILOGE("Read and write status is error");
return false;
}
StreamBuffer buf;
if (!pkt.MakeData(buf)) {
FI_HILOGE("Failed to buffer packet");
return false;
}
return SendMsg(buf.Data(), buf.Size());
}
bool SocketSession::SendMsg(const char *buf, size_t size) const
{
CALL_DEBUG_ENTER;
CHKPF(buf);
if ((size == 0) || (size > MAX_PACKET_BUF_SIZE)) {
FI_HILOGE("buf size:%{public}zu", size);
return false;
}
if (fd_ < 0) {
FI_HILOGE("The fd_ is less than 0");
return false;
}
int32_t idx = 0;
int32_t retryCount = 0;
const int32_t bufSize = static_cast<int32_t>(size);
int32_t remSize = bufSize;
FI_HILOGI("Rem size:%{public}d", remSize);
while (remSize > 0 && retryCount < SEND_RETRY_LIMIT) {
retryCount += 1;
FI_HILOGD("Send message to client (%{public}d, %{public}d)", fd_, pid_);
ssize_t count = send(fd_, &buf[idx], remSize, MSG_DONTWAIT | MSG_NOSIGNAL);
if (count < 0) {
if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
usleep(SEND_RETRY_SLEEP_TIME);
FI_HILOGW("Continue for errno EAGAIN|EINTR|EWOULDBLOCK, errno:%{public}d, pid:%{public}d", errno, pid_);
continue;
}
FI_HILOGE("Send return failed, error:%{public}d, fd:%{public}d, pid:%{public}d", errno, fd_, pid_);
return false;
}
idx += count;
remSize -= count;
if (remSize > 0) {
usleep(SEND_RETRY_SLEEP_TIME);
}
}
if (retryCount >= SEND_RETRY_LIMIT || remSize != 0) {
FI_HILOGE("Send too many times:%{public}d/%{public}d, size:%{public}d/%{public}d, fd:%{public}d,"
"pid:%{public}d", retryCount, SEND_RETRY_LIMIT, idx, bufSize, fd_, pid_);
return false;
}
return true;
}
std::string SocketSession::ToString() const
{
std::ostringstream oss;
oss << "fd = " << fd_
<< ((fd_ < 0) ? ", closed" : ", opened")
<< ", pid = " << pid_
<< ", tokenType = " << tokenType_
<< std::endl;
return oss.str();
}
void SocketSession::Dispatch(const struct epoll_event &ev)
{
if ((ev.events & EPOLLIN) == EPOLLIN) {
FI_HILOGD("Data received (%{public}d)", fd_);
} else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
}
}
}
}
}