mirror of
https://github.com/skyline-emu/skyline.git
synced 2025-01-03 18:41:48 +01:00
Implement required bsd calls
Co-authored-by: PabloG02 <tioo23000@gmail.com>
This commit is contained in:
parent
64d914639f
commit
b22471fb46
@ -1,13 +1,14 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <poll.h>
|
||||
#include "IClient.h"
|
||||
|
||||
namespace skyline::service::socket {
|
||||
IClient::IClient(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
||||
|
||||
Result IClient::RegisterClient(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
response.Push<u32>(0);
|
||||
response.Push<i32>(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -15,53 +16,185 @@ namespace skyline::service::socket {
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IClient::Select(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
Result IClient::Socket(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
i32 domain{request.Pop<i32>()};
|
||||
i32 type{request.Pop<i32>()};
|
||||
i32 protocol{request.Pop<i32>()};
|
||||
i32 fd{::socket(domain, type, protocol)};
|
||||
Logger::Info("File Descriptor {} with Domain {}, Type {}, Protocol {}", fd, domain, type, protocol);
|
||||
if (fd == -1)
|
||||
Logger::Error("Error creating socket: {}", strerror(errno));
|
||||
return PushBsdResult(response, fd, 0);
|
||||
}
|
||||
|
||||
Result IClient::Poll(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fdsCount{request.Pop<i32>()};
|
||||
i32 timeout{request.Pop<i32>()};
|
||||
|
||||
if (fdsCount == 0)
|
||||
return PushBsdResult(response, -1, 0);
|
||||
|
||||
span outputBuf{request.outputBuf.at(0)};
|
||||
auto fds{span<pollfd>(reinterpret_cast<pollfd*>(outputBuf.data()), static_cast<u32>(fdsCount))};
|
||||
i32 result{poll(fds.data(), static_cast<u32>(fdsCount), static_cast<i32>(timeout))};
|
||||
return PushBsdResult(response, result, errno);
|
||||
}
|
||||
|
||||
Result IClient::Recv(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 flags{request.Pop<i32>()};
|
||||
if (fcntl(fd, F_GETFL) == -1)
|
||||
return PushBsdResult(response, -1, EBADF);
|
||||
|
||||
bool shouldBlockAfterOperation{false};
|
||||
if (!(fcntl(fd, F_GETFL) & O_NONBLOCK) && (flags & MSG_EOR)) {
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
shouldBlockAfterOperation = true;
|
||||
}
|
||||
|
||||
ssize_t result{recv(fd, request.outputBuf.at(0).data(), request.outputBuf.at(0).size(), flags)};
|
||||
|
||||
if (shouldBlockAfterOperation)
|
||||
fcntl(fd, F_SETFL, MSG_EOR);
|
||||
return PushBsdResultErrno(response, result);
|
||||
}
|
||||
|
||||
Result IClient::RecvFrom(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 flags{request.Pop<i32>()};
|
||||
if (fcntl(fd, F_GETFL) == -1)
|
||||
return PushBsdResult(response, -1, EBADF);
|
||||
|
||||
bool shouldBlockAfterOperation{false};
|
||||
if (!(fcntl(fd, F_GETFL) & O_NONBLOCK) && (flags & MSG_EOR)) {
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
shouldBlockAfterOperation = true;
|
||||
}
|
||||
|
||||
sockaddr addrIn{};
|
||||
socklen_t addrLen{sizeof(addrIn)};
|
||||
span message{request.outputBuf.at(0)};
|
||||
ssize_t result{recvfrom(fd, message.data(), message.size(), 0, &addrIn, &addrLen)};
|
||||
|
||||
if (shouldBlockAfterOperation)
|
||||
fcntl(fd, F_SETFL, MSG_EOR);
|
||||
|
||||
request.outputBuf.at(0).copy_from(message);
|
||||
if (!request.outputBuf.at(1).empty())
|
||||
request.outputBuf.at(1).copy_from(span{addrIn});
|
||||
response.Push(request.outputBuf.at(1).size());
|
||||
return PushBsdResultErrno(response, result);
|
||||
}
|
||||
|
||||
Result IClient::Send(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 flags{request.Pop<i32>()};
|
||||
|
||||
ssize_t result{send(fd, request.inputBuf.at(0).data(), request.inputBuf.at(0).size(), flags)};
|
||||
return PushBsdResultErrno(response, result);
|
||||
}
|
||||
|
||||
Result IClient::SendTo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
response.Push<u32>(0);
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 flags{request.Pop<i32>()};
|
||||
|
||||
sockaddr addrIn{request.inputBuf.at(1).as<sockaddr>()};
|
||||
addrIn.sa_family = AF_INET;
|
||||
ssize_t result{sendto(fd, request.inputBuf.at(0).data(), request.inputBuf.at(0).size(), flags,
|
||||
&addrIn, sizeof(addrIn))};
|
||||
return PushBsdResultErrno(response, result);
|
||||
}
|
||||
|
||||
Result IClient::Accept(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
sockaddr addr{};
|
||||
socklen_t addrLen{sizeof(addr)};
|
||||
i32 result{accept(fd, &addr, &addrLen)};
|
||||
if (errno != 0)
|
||||
return PushBsdResult(response, -1, errno);
|
||||
|
||||
request.outputBuf.at(0).copy_from(span{addr});
|
||||
response.Push(request.outputBuf.at(0).size());
|
||||
return PushBsdResult(response, result, errno);
|
||||
}
|
||||
|
||||
Result IClient::Bind(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
sockaddr addr{request.inputBuf.at(0).as<sockaddr>()};
|
||||
addr.sa_family = AF_INET;
|
||||
|
||||
i32 result{bind(fd, &addr, sizeof(addr))};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::Connect(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
sockaddr addr{request.inputBuf.at(0).as<sockaddr>()};
|
||||
addr.sa_family = AF_INET;
|
||||
|
||||
i32 result{connect(fd, &addr, sizeof(addr))};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::GetPeerName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
i32 fd{request.Pop<i32>()};
|
||||
sockaddr addr{};
|
||||
socklen_t addrLen{sizeof(addr)};
|
||||
i32 result{getpeername(fd, &addr, &addrLen)};
|
||||
request.outputBuf.at(0).copy_from(span{addr});
|
||||
response.Push(request.outputBuf.at(0).size());
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::GetSockName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
i32 fd{request.Pop<i32>()};
|
||||
sockaddr addr{};
|
||||
socklen_t addrLen{sizeof(addr)};
|
||||
i32 result{getsockname(fd, &addr, &addrLen)};
|
||||
request.outputBuf.at(0).copy_from(span{addr});
|
||||
response.Push(request.outputBuf.at(0).size());
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::GetSockOpt(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 level{request.Pop<i32>()};
|
||||
OptionName optionName{request.Pop<OptionName>()};
|
||||
socklen_t addrLen{sizeof(request.outputBuf.at(0))};
|
||||
i32 result{getsockopt(fd, level, GetOption(optionName), request.outputBuf.at(0).data(), &addrLen)};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::Listen(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 backlog{request.Pop<i32>()};
|
||||
i32 result{listen(fd, backlog)};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::Fcntl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 cmd{request.Pop<i32>()};
|
||||
i32 arg{request.Pop<i32>()};
|
||||
i32 result{fcntl(fd, cmd, arg)};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::SetSockOpt(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 level{request.Pop<i32>()};
|
||||
OptionName optionName{request.Pop<OptionName>()};
|
||||
if (level == 0xFFFF)
|
||||
level = SOL_SOCKET;
|
||||
i32 result{setsockopt(fd, level, GetOption(optionName), request.inputBuf.at(0).data(), static_cast<socklen_t>(request.inputBuf.at(0).size()))};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::Shutdown(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 how{request.Pop<i32>()};
|
||||
i32 result{shutdown(fd, how)};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::ShutdownAllSockets(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
@ -69,16 +202,52 @@ namespace skyline::service::socket {
|
||||
}
|
||||
|
||||
Result IClient::Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 flags{request.Pop<i32>()};
|
||||
ssize_t result{send(fd, request.inputBuf.at(0).data(), request.inputBuf.at(0).size(), flags)};
|
||||
return PushBsdResultErrno(response, result);
|
||||
}
|
||||
|
||||
Result IClient::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
response.Push<u32>(0);
|
||||
response.Push<u32>(0);
|
||||
return {};
|
||||
i32 fd{request.Pop<i32>()};
|
||||
ssize_t result{recv(fd, request.outputBuf.at(0).data(), request.outputBuf.at(0).size(), 0)};
|
||||
return PushBsdResultErrno(response, result);
|
||||
}
|
||||
|
||||
Result IClient::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
i32 fd{request.Pop<i32>()};
|
||||
i32 result{close(fd)};
|
||||
return PushBsdResult(response, 0, errno);
|
||||
}
|
||||
|
||||
Result IClient::EventFd(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return PushBsdResult(response, 1, 0);
|
||||
}
|
||||
|
||||
Result IClient::PushBsdResult(ipc::IpcResponse &response, i32 result, i32 errorCode) {
|
||||
if (errorCode != 0)
|
||||
result = -1;
|
||||
|
||||
response.Push(result);
|
||||
response.Push(errorCode);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IClient::PushBsdResultErrno(ipc::IpcResponse &response, i64 result) {
|
||||
response.Push(result);
|
||||
response.Push(result == -1 ? errno : 0);
|
||||
return {};
|
||||
}
|
||||
|
||||
i32 IClient::GetOption(OptionName optionName) {
|
||||
switch (optionName) {
|
||||
case OptionName::ReuseAddr: return SO_REUSEADDR;
|
||||
case OptionName::Broadcast: return SO_BROADCAST;
|
||||
case OptionName::Linger: return SO_LINGER;
|
||||
case OptionName::SndBuf: return SO_SNDBUF;
|
||||
case OptionName::RcvBuf: return SO_RCVBUF;
|
||||
case OptionName::SndTimeo: return SO_SNDTIMEO;
|
||||
case OptionName::RcvTimeo: return SO_RCVTIMEO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <services/serviceman.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace skyline::service::socket {
|
||||
enum class OptionName : u32 {
|
||||
ReuseAddr = 0x4,
|
||||
Broadcast = 0x20,
|
||||
Linger = 0x80,
|
||||
SndBuf = 0x1001,
|
||||
RcvBuf = 0x1002,
|
||||
SndTimeo = 0x1005,
|
||||
RcvTimeo = 0x1006,
|
||||
};
|
||||
/**
|
||||
* @brief IClient or bsd:u is used by applications create network sockets
|
||||
* @url https://switchbrew.org/wiki/Sockets_services#bsd:u.2C_bsd:s
|
||||
@ -25,10 +35,7 @@ namespace skyline::service::socket {
|
||||
*/
|
||||
Result StartMonitoring(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Selects the socket
|
||||
*/
|
||||
Result Select(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
Result Socket(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Polls the socket for events
|
||||
@ -70,11 +77,32 @@ namespace skyline::service::socket {
|
||||
*/
|
||||
Result Connect(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the address of the peer to which a socket is connected
|
||||
*/
|
||||
Result GetPeerName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the current local address of the socket
|
||||
*/
|
||||
Result GetSockName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Retrieves socket options
|
||||
*/
|
||||
Result GetSockOpt(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Places a socket in a state in which it is listening for an incoming connection
|
||||
*/
|
||||
Result Listen(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Performs a control operation on an open file descriptor
|
||||
* @url https://switchbrew.org/wiki/Sockets_services#Fcntl
|
||||
*/
|
||||
Result Fcntl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Manipulates the options associated with a socket
|
||||
*/
|
||||
@ -105,10 +133,21 @@ namespace skyline::service::socket {
|
||||
*/
|
||||
Result Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
Result EventFd(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
Result PushBsdResult(ipc::IpcResponse &response, i32 result, i32 errorCode);
|
||||
|
||||
Result PushBsdResultErrno(ipc::IpcResponse &response, i64 result);
|
||||
|
||||
/**
|
||||
* @brief Translates option name to a socket option
|
||||
*/
|
||||
i32 GetOption(OptionName optionName);
|
||||
|
||||
SERVICE_DECL(
|
||||
SFUNC(0x0, IClient, RegisterClient),
|
||||
SFUNC(0x1, IClient, StartMonitoring),
|
||||
SFUNC(0x5, IClient, Select),
|
||||
SFUNC(0x2, IClient, Socket),
|
||||
SFUNC(0x6, IClient, Poll),
|
||||
SFUNC(0x8, IClient, Recv),
|
||||
SFUNC(0x9, IClient, RecvFrom),
|
||||
@ -117,13 +156,18 @@ namespace skyline::service::socket {
|
||||
SFUNC(0xC, IClient, Accept),
|
||||
SFUNC(0xD, IClient, Bind),
|
||||
SFUNC(0xE, IClient, Connect),
|
||||
SFUNC(0xF, IClient, GetPeerName),
|
||||
SFUNC(0x10, IClient, GetSockName),
|
||||
SFUNC(0x11, IClient, GetSockOpt),
|
||||
SFUNC(0x12, IClient, Listen),
|
||||
SFUNC(0x14, IClient, Fcntl),
|
||||
SFUNC(0x15, IClient, SetSockOpt),
|
||||
SFUNC(0x16, IClient, Shutdown),
|
||||
SFUNC(0x17, IClient, ShutdownAllSockets),
|
||||
SFUNC(0x18, IClient, Write),
|
||||
SFUNC(0x19, IClient, Read),
|
||||
SFUNC(0x1A, IClient, Close)
|
||||
SFUNC(0x1A, IClient, Close),
|
||||
SFUNC(0x1F, IClient, EventFd)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user