diff options
| author | 2021-12-25 20:27:52 +0100 | |
|---|---|---|
| committer | 2022-07-25 21:59:28 +0200 | |
| commit | 705f7db84dd85555a6aef1e136cf251725cef293 (patch) | |
| tree | e110c6482a11d711d18515afce4fc50adcee76e7 /src/core/network | |
| parent | network: Add initial files and enet dependency (diff) | |
| download | yuzu-705f7db84dd85555a6aef1e136cf251725cef293.tar.gz yuzu-705f7db84dd85555a6aef1e136cf251725cef293.tar.xz yuzu-705f7db84dd85555a6aef1e136cf251725cef293.zip | |
yuzu: Add ui files for multiplayer rooms
Diffstat (limited to 'src/core/network')
| -rw-r--r-- | src/core/network/network.cpp | 637 | ||||
| -rw-r--r-- | src/core/network/network.h | 117 | ||||
| -rw-r--r-- | src/core/network/network_interface.cpp | 209 | ||||
| -rw-r--r-- | src/core/network/network_interface.h | 28 | ||||
| -rw-r--r-- | src/core/network/sockets.h | 94 |
5 files changed, 0 insertions, 1085 deletions
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp deleted file mode 100644 index fdafbea92..000000000 --- a/src/core/network/network.cpp +++ /dev/null | |||
| @@ -1,637 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <cstring> | ||
| 6 | #include <limits> | ||
| 7 | #include <utility> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/error.h" | ||
| 11 | |||
| 12 | #ifdef _WIN32 | ||
| 13 | #include <winsock2.h> | ||
| 14 | #include <ws2tcpip.h> | ||
| 15 | #elif YUZU_UNIX | ||
| 16 | #include <arpa/inet.h> | ||
| 17 | #include <errno.h> | ||
| 18 | #include <fcntl.h> | ||
| 19 | #include <netdb.h> | ||
| 20 | #include <netinet/in.h> | ||
| 21 | #include <poll.h> | ||
| 22 | #include <sys/socket.h> | ||
| 23 | #include <unistd.h> | ||
| 24 | #else | ||
| 25 | #error "Unimplemented platform" | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #include "common/assert.h" | ||
| 29 | #include "common/common_types.h" | ||
| 30 | #include "common/logging/log.h" | ||
| 31 | #include "common/settings.h" | ||
| 32 | #include "core/network/network.h" | ||
| 33 | #include "core/network/network_interface.h" | ||
| 34 | #include "core/network/sockets.h" | ||
| 35 | |||
| 36 | namespace Network { | ||
| 37 | |||
| 38 | namespace { | ||
| 39 | |||
| 40 | #ifdef _WIN32 | ||
| 41 | |||
| 42 | using socklen_t = int; | ||
| 43 | |||
| 44 | void Initialize() { | ||
| 45 | WSADATA wsa_data; | ||
| 46 | (void)WSAStartup(MAKEWORD(2, 2), &wsa_data); | ||
| 47 | } | ||
| 48 | |||
| 49 | void Finalize() { | ||
| 50 | WSACleanup(); | ||
| 51 | } | ||
| 52 | |||
| 53 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | ||
| 54 | sockaddr_in result; | ||
| 55 | |||
| 56 | #if YUZU_UNIX | ||
| 57 | result.sin_len = sizeof(result); | ||
| 58 | #endif | ||
| 59 | |||
| 60 | switch (static_cast<Domain>(input.family)) { | ||
| 61 | case Domain::INET: | ||
| 62 | result.sin_family = AF_INET; | ||
| 63 | break; | ||
| 64 | default: | ||
| 65 | UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family); | ||
| 66 | result.sin_family = AF_INET; | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | |||
| 70 | result.sin_port = htons(input.portno); | ||
| 71 | |||
| 72 | auto& ip = result.sin_addr.S_un.S_un_b; | ||
| 73 | ip.s_b1 = input.ip[0]; | ||
| 74 | ip.s_b2 = input.ip[1]; | ||
| 75 | ip.s_b3 = input.ip[2]; | ||
| 76 | ip.s_b4 = input.ip[3]; | ||
| 77 | |||
| 78 | sockaddr addr; | ||
| 79 | std::memcpy(&addr, &result, sizeof(addr)); | ||
| 80 | return addr; | ||
| 81 | } | ||
| 82 | |||
| 83 | LINGER MakeLinger(bool enable, u32 linger_value) { | ||
| 84 | ASSERT(linger_value <= std::numeric_limits<u_short>::max()); | ||
| 85 | |||
| 86 | LINGER value; | ||
| 87 | value.l_onoff = enable ? 1 : 0; | ||
| 88 | value.l_linger = static_cast<u_short>(linger_value); | ||
| 89 | return value; | ||
| 90 | } | ||
| 91 | |||
| 92 | bool EnableNonBlock(SOCKET fd, bool enable) { | ||
| 93 | u_long value = enable ? 1 : 0; | ||
| 94 | return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; | ||
| 95 | } | ||
| 96 | |||
| 97 | Errno TranslateNativeError(int e) { | ||
| 98 | switch (e) { | ||
| 99 | case WSAEBADF: | ||
| 100 | return Errno::BADF; | ||
| 101 | case WSAEINVAL: | ||
| 102 | return Errno::INVAL; | ||
| 103 | case WSAEMFILE: | ||
| 104 | return Errno::MFILE; | ||
| 105 | case WSAENOTCONN: | ||
| 106 | return Errno::NOTCONN; | ||
| 107 | case WSAEWOULDBLOCK: | ||
| 108 | return Errno::AGAIN; | ||
| 109 | case WSAECONNREFUSED: | ||
| 110 | return Errno::CONNREFUSED; | ||
| 111 | case WSAEHOSTUNREACH: | ||
| 112 | return Errno::HOSTUNREACH; | ||
| 113 | case WSAENETDOWN: | ||
| 114 | return Errno::NETDOWN; | ||
| 115 | case WSAENETUNREACH: | ||
| 116 | return Errno::NETUNREACH; | ||
| 117 | default: | ||
| 118 | return Errno::OTHER; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | #elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX | ||
| 123 | |||
| 124 | using SOCKET = int; | ||
| 125 | using WSAPOLLFD = pollfd; | ||
| 126 | using ULONG = u64; | ||
| 127 | |||
| 128 | constexpr SOCKET INVALID_SOCKET = -1; | ||
| 129 | constexpr SOCKET SOCKET_ERROR = -1; | ||
| 130 | |||
| 131 | constexpr int SD_RECEIVE = SHUT_RD; | ||
| 132 | constexpr int SD_SEND = SHUT_WR; | ||
| 133 | constexpr int SD_BOTH = SHUT_RDWR; | ||
| 134 | |||
| 135 | void Initialize() {} | ||
| 136 | |||
| 137 | void Finalize() {} | ||
| 138 | |||
| 139 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | ||
| 140 | sockaddr_in result; | ||
| 141 | |||
| 142 | switch (static_cast<Domain>(input.family)) { | ||
| 143 | case Domain::INET: | ||
| 144 | result.sin_family = AF_INET; | ||
| 145 | break; | ||
| 146 | default: | ||
| 147 | UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family); | ||
| 148 | result.sin_family = AF_INET; | ||
| 149 | break; | ||
| 150 | } | ||
| 151 | |||
| 152 | result.sin_port = htons(input.portno); | ||
| 153 | |||
| 154 | result.sin_addr.s_addr = input.ip[0] | input.ip[1] << 8 | input.ip[2] << 16 | input.ip[3] << 24; | ||
| 155 | |||
| 156 | sockaddr addr; | ||
| 157 | std::memcpy(&addr, &result, sizeof(addr)); | ||
| 158 | return addr; | ||
| 159 | } | ||
| 160 | |||
| 161 | int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) { | ||
| 162 | return poll(fds, static_cast<nfds_t>(nfds), timeout); | ||
| 163 | } | ||
| 164 | |||
| 165 | int closesocket(SOCKET fd) { | ||
| 166 | return close(fd); | ||
| 167 | } | ||
| 168 | |||
| 169 | linger MakeLinger(bool enable, u32 linger_value) { | ||
| 170 | linger value; | ||
| 171 | value.l_onoff = enable ? 1 : 0; | ||
| 172 | value.l_linger = linger_value; | ||
| 173 | return value; | ||
| 174 | } | ||
| 175 | |||
| 176 | bool EnableNonBlock(int fd, bool enable) { | ||
| 177 | int flags = fcntl(fd, F_GETFL); | ||
| 178 | if (flags == -1) { | ||
| 179 | return false; | ||
| 180 | } | ||
| 181 | if (enable) { | ||
| 182 | flags |= O_NONBLOCK; | ||
| 183 | } else { | ||
| 184 | flags &= ~O_NONBLOCK; | ||
| 185 | } | ||
| 186 | return fcntl(fd, F_SETFL, flags) == 0; | ||
| 187 | } | ||
| 188 | |||
| 189 | Errno TranslateNativeError(int e) { | ||
| 190 | switch (e) { | ||
| 191 | case EBADF: | ||
| 192 | return Errno::BADF; | ||
| 193 | case EINVAL: | ||
| 194 | return Errno::INVAL; | ||
| 195 | case EMFILE: | ||
| 196 | return Errno::MFILE; | ||
| 197 | case ENOTCONN: | ||
| 198 | return Errno::NOTCONN; | ||
| 199 | case EAGAIN: | ||
| 200 | return Errno::AGAIN; | ||
| 201 | case ECONNREFUSED: | ||
| 202 | return Errno::CONNREFUSED; | ||
| 203 | case EHOSTUNREACH: | ||
| 204 | return Errno::HOSTUNREACH; | ||
| 205 | case ENETDOWN: | ||
| 206 | return Errno::NETDOWN; | ||
| 207 | case ENETUNREACH: | ||
| 208 | return Errno::NETUNREACH; | ||
| 209 | default: | ||
| 210 | return Errno::OTHER; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | #endif | ||
| 215 | |||
| 216 | Errno GetAndLogLastError() { | ||
| 217 | #ifdef _WIN32 | ||
| 218 | int e = WSAGetLastError(); | ||
| 219 | #else | ||
| 220 | int e = errno; | ||
| 221 | #endif | ||
| 222 | const Errno err = TranslateNativeError(e); | ||
| 223 | if (err == Errno::AGAIN) { | ||
| 224 | return err; | ||
| 225 | } | ||
| 226 | LOG_ERROR(Network, "Socket operation error: {}", Common::NativeErrorToString(e)); | ||
| 227 | return err; | ||
| 228 | } | ||
| 229 | |||
| 230 | int TranslateDomain(Domain domain) { | ||
| 231 | switch (domain) { | ||
| 232 | case Domain::INET: | ||
| 233 | return AF_INET; | ||
| 234 | default: | ||
| 235 | UNIMPLEMENTED_MSG("Unimplemented domain={}", domain); | ||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | int TranslateType(Type type) { | ||
| 241 | switch (type) { | ||
| 242 | case Type::STREAM: | ||
| 243 | return SOCK_STREAM; | ||
| 244 | case Type::DGRAM: | ||
| 245 | return SOCK_DGRAM; | ||
| 246 | default: | ||
| 247 | UNIMPLEMENTED_MSG("Unimplemented type={}", type); | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | int TranslateProtocol(Protocol protocol) { | ||
| 253 | switch (protocol) { | ||
| 254 | case Protocol::TCP: | ||
| 255 | return IPPROTO_TCP; | ||
| 256 | case Protocol::UDP: | ||
| 257 | return IPPROTO_UDP; | ||
| 258 | default: | ||
| 259 | UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol); | ||
| 260 | return 0; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | SockAddrIn TranslateToSockAddrIn(sockaddr input_) { | ||
| 265 | sockaddr_in input; | ||
| 266 | std::memcpy(&input, &input_, sizeof(input)); | ||
| 267 | |||
| 268 | SockAddrIn result; | ||
| 269 | |||
| 270 | switch (input.sin_family) { | ||
| 271 | case AF_INET: | ||
| 272 | result.family = Domain::INET; | ||
| 273 | break; | ||
| 274 | default: | ||
| 275 | UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.sin_family); | ||
| 276 | result.family = Domain::INET; | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | |||
| 280 | result.portno = ntohs(input.sin_port); | ||
| 281 | |||
| 282 | result.ip = TranslateIPv4(input.sin_addr); | ||
| 283 | |||
| 284 | return result; | ||
| 285 | } | ||
| 286 | |||
| 287 | short TranslatePollEvents(PollEvents events) { | ||
| 288 | short result = 0; | ||
| 289 | |||
| 290 | if (True(events & PollEvents::In)) { | ||
| 291 | events &= ~PollEvents::In; | ||
| 292 | result |= POLLIN; | ||
| 293 | } | ||
| 294 | if (True(events & PollEvents::Pri)) { | ||
| 295 | events &= ~PollEvents::Pri; | ||
| 296 | #ifdef _WIN32 | ||
| 297 | LOG_WARNING(Service, "Winsock doesn't support POLLPRI"); | ||
| 298 | #else | ||
| 299 | result |= POLLPRI; | ||
| 300 | #endif | ||
| 301 | } | ||
| 302 | if (True(events & PollEvents::Out)) { | ||
| 303 | events &= ~PollEvents::Out; | ||
| 304 | result |= POLLOUT; | ||
| 305 | } | ||
| 306 | |||
| 307 | UNIMPLEMENTED_IF_MSG((u16)events != 0, "Unhandled guest events=0x{:x}", (u16)events); | ||
| 308 | |||
| 309 | return result; | ||
| 310 | } | ||
| 311 | |||
| 312 | PollEvents TranslatePollRevents(short revents) { | ||
| 313 | PollEvents result{}; | ||
| 314 | const auto translate = [&result, &revents](short host, PollEvents guest) { | ||
| 315 | if ((revents & host) != 0) { | ||
| 316 | revents &= static_cast<short>(~host); | ||
| 317 | result |= guest; | ||
| 318 | } | ||
| 319 | }; | ||
| 320 | |||
| 321 | translate(POLLIN, PollEvents::In); | ||
| 322 | translate(POLLPRI, PollEvents::Pri); | ||
| 323 | translate(POLLOUT, PollEvents::Out); | ||
| 324 | translate(POLLERR, PollEvents::Err); | ||
| 325 | translate(POLLHUP, PollEvents::Hup); | ||
| 326 | |||
| 327 | UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents); | ||
| 328 | |||
| 329 | return result; | ||
| 330 | } | ||
| 331 | |||
| 332 | template <typename T> | ||
| 333 | Errno SetSockOpt(SOCKET fd, int option, T value) { | ||
| 334 | const int result = | ||
| 335 | setsockopt(fd, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value)); | ||
| 336 | if (result != SOCKET_ERROR) { | ||
| 337 | return Errno::SUCCESS; | ||
| 338 | } | ||
| 339 | return GetAndLogLastError(); | ||
| 340 | } | ||
| 341 | |||
| 342 | } // Anonymous namespace | ||
| 343 | |||
| 344 | NetworkInstance::NetworkInstance() { | ||
| 345 | Initialize(); | ||
| 346 | } | ||
| 347 | |||
| 348 | NetworkInstance::~NetworkInstance() { | ||
| 349 | Finalize(); | ||
| 350 | } | ||
| 351 | |||
| 352 | std::optional<IPv4Address> GetHostIPv4Address() { | ||
| 353 | const std::string& selected_network_interface = Settings::values.network_interface.GetValue(); | ||
| 354 | const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); | ||
| 355 | if (network_interfaces.size() == 0) { | ||
| 356 | LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces"); | ||
| 357 | return {}; | ||
| 358 | } | ||
| 359 | |||
| 360 | const auto res = | ||
| 361 | std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) { | ||
| 362 | return iface.name == selected_network_interface; | ||
| 363 | }); | ||
| 364 | |||
| 365 | if (res != network_interfaces.end()) { | ||
| 366 | char ip_addr[16] = {}; | ||
| 367 | ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr); | ||
| 368 | return TranslateIPv4(res->ip_address); | ||
| 369 | } else { | ||
| 370 | LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); | ||
| 371 | return {}; | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { | ||
| 376 | const size_t num = pollfds.size(); | ||
| 377 | |||
| 378 | std::vector<WSAPOLLFD> host_pollfds(pollfds.size()); | ||
| 379 | std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) { | ||
| 380 | WSAPOLLFD result; | ||
| 381 | result.fd = fd.socket->fd; | ||
| 382 | result.events = TranslatePollEvents(fd.events); | ||
| 383 | result.revents = 0; | ||
| 384 | return result; | ||
| 385 | }); | ||
| 386 | |||
| 387 | const int result = WSAPoll(host_pollfds.data(), static_cast<ULONG>(num), timeout); | ||
| 388 | if (result == 0) { | ||
| 389 | ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(), | ||
| 390 | [](WSAPOLLFD fd) { return fd.revents == 0; })); | ||
| 391 | return {0, Errno::SUCCESS}; | ||
| 392 | } | ||
| 393 | |||
| 394 | for (size_t i = 0; i < num; ++i) { | ||
| 395 | pollfds[i].revents = TranslatePollRevents(host_pollfds[i].revents); | ||
| 396 | } | ||
| 397 | |||
| 398 | if (result > 0) { | ||
| 399 | return {result, Errno::SUCCESS}; | ||
| 400 | } | ||
| 401 | |||
| 402 | ASSERT(result == SOCKET_ERROR); | ||
| 403 | |||
| 404 | return {-1, GetAndLogLastError()}; | ||
| 405 | } | ||
| 406 | |||
| 407 | Socket::~Socket() { | ||
| 408 | if (fd == INVALID_SOCKET) { | ||
| 409 | return; | ||
| 410 | } | ||
| 411 | (void)closesocket(fd); | ||
| 412 | fd = INVALID_SOCKET; | ||
| 413 | } | ||
| 414 | |||
| 415 | Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {} | ||
| 416 | |||
| 417 | Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { | ||
| 418 | fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol)); | ||
| 419 | if (fd != INVALID_SOCKET) { | ||
| 420 | return Errno::SUCCESS; | ||
| 421 | } | ||
| 422 | |||
| 423 | return GetAndLogLastError(); | ||
| 424 | } | ||
| 425 | |||
| 426 | std::pair<Socket::AcceptResult, Errno> Socket::Accept() { | ||
| 427 | sockaddr addr; | ||
| 428 | socklen_t addrlen = sizeof(addr); | ||
| 429 | const SOCKET new_socket = accept(fd, &addr, &addrlen); | ||
| 430 | |||
| 431 | if (new_socket == INVALID_SOCKET) { | ||
| 432 | return {AcceptResult{}, GetAndLogLastError()}; | ||
| 433 | } | ||
| 434 | |||
| 435 | AcceptResult result; | ||
| 436 | result.socket = std::make_unique<Socket>(); | ||
| 437 | result.socket->fd = new_socket; | ||
| 438 | |||
| 439 | ASSERT(addrlen == sizeof(sockaddr_in)); | ||
| 440 | result.sockaddr_in = TranslateToSockAddrIn(addr); | ||
| 441 | |||
| 442 | return {std::move(result), Errno::SUCCESS}; | ||
| 443 | } | ||
| 444 | |||
| 445 | Errno Socket::Connect(SockAddrIn addr_in) { | ||
| 446 | const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in); | ||
| 447 | if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != SOCKET_ERROR) { | ||
| 448 | return Errno::SUCCESS; | ||
| 449 | } | ||
| 450 | |||
| 451 | return GetAndLogLastError(); | ||
| 452 | } | ||
| 453 | |||
| 454 | std::pair<SockAddrIn, Errno> Socket::GetPeerName() { | ||
| 455 | sockaddr addr; | ||
| 456 | socklen_t addrlen = sizeof(addr); | ||
| 457 | if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) { | ||
| 458 | return {SockAddrIn{}, GetAndLogLastError()}; | ||
| 459 | } | ||
| 460 | |||
| 461 | ASSERT(addrlen == sizeof(sockaddr_in)); | ||
| 462 | return {TranslateToSockAddrIn(addr), Errno::SUCCESS}; | ||
| 463 | } | ||
| 464 | |||
| 465 | std::pair<SockAddrIn, Errno> Socket::GetSockName() { | ||
| 466 | sockaddr addr; | ||
| 467 | socklen_t addrlen = sizeof(addr); | ||
| 468 | if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) { | ||
| 469 | return {SockAddrIn{}, GetAndLogLastError()}; | ||
| 470 | } | ||
| 471 | |||
| 472 | ASSERT(addrlen == sizeof(sockaddr_in)); | ||
| 473 | return {TranslateToSockAddrIn(addr), Errno::SUCCESS}; | ||
| 474 | } | ||
| 475 | |||
| 476 | Errno Socket::Bind(SockAddrIn addr) { | ||
| 477 | const sockaddr addr_in = TranslateFromSockAddrIn(addr); | ||
| 478 | if (bind(fd, &addr_in, sizeof(addr_in)) != SOCKET_ERROR) { | ||
| 479 | return Errno::SUCCESS; | ||
| 480 | } | ||
| 481 | |||
| 482 | return GetAndLogLastError(); | ||
| 483 | } | ||
| 484 | |||
| 485 | Errno Socket::Listen(s32 backlog) { | ||
| 486 | if (listen(fd, backlog) != SOCKET_ERROR) { | ||
| 487 | return Errno::SUCCESS; | ||
| 488 | } | ||
| 489 | |||
| 490 | return GetAndLogLastError(); | ||
| 491 | } | ||
| 492 | |||
| 493 | Errno Socket::Shutdown(ShutdownHow how) { | ||
| 494 | int host_how = 0; | ||
| 495 | switch (how) { | ||
| 496 | case ShutdownHow::RD: | ||
| 497 | host_how = SD_RECEIVE; | ||
| 498 | break; | ||
| 499 | case ShutdownHow::WR: | ||
| 500 | host_how = SD_SEND; | ||
| 501 | break; | ||
| 502 | case ShutdownHow::RDWR: | ||
| 503 | host_how = SD_BOTH; | ||
| 504 | break; | ||
| 505 | default: | ||
| 506 | UNIMPLEMENTED_MSG("Unimplemented flag how={}", how); | ||
| 507 | return Errno::SUCCESS; | ||
| 508 | } | ||
| 509 | if (shutdown(fd, host_how) != SOCKET_ERROR) { | ||
| 510 | return Errno::SUCCESS; | ||
| 511 | } | ||
| 512 | |||
| 513 | return GetAndLogLastError(); | ||
| 514 | } | ||
| 515 | |||
| 516 | std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { | ||
| 517 | ASSERT(flags == 0); | ||
| 518 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); | ||
| 519 | |||
| 520 | const auto result = | ||
| 521 | recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0); | ||
| 522 | if (result != SOCKET_ERROR) { | ||
| 523 | return {static_cast<s32>(result), Errno::SUCCESS}; | ||
| 524 | } | ||
| 525 | |||
| 526 | return {-1, GetAndLogLastError()}; | ||
| 527 | } | ||
| 528 | |||
| 529 | std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { | ||
| 530 | ASSERT(flags == 0); | ||
| 531 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); | ||
| 532 | |||
| 533 | sockaddr addr_in{}; | ||
| 534 | socklen_t addrlen = sizeof(addr_in); | ||
| 535 | socklen_t* const p_addrlen = addr ? &addrlen : nullptr; | ||
| 536 | sockaddr* const p_addr_in = addr ? &addr_in : nullptr; | ||
| 537 | |||
| 538 | const auto result = recvfrom(fd, reinterpret_cast<char*>(message.data()), | ||
| 539 | static_cast<int>(message.size()), 0, p_addr_in, p_addrlen); | ||
| 540 | if (result != SOCKET_ERROR) { | ||
| 541 | if (addr) { | ||
| 542 | ASSERT(addrlen == sizeof(addr_in)); | ||
| 543 | *addr = TranslateToSockAddrIn(addr_in); | ||
| 544 | } | ||
| 545 | return {static_cast<s32>(result), Errno::SUCCESS}; | ||
| 546 | } | ||
| 547 | |||
| 548 | return {-1, GetAndLogLastError()}; | ||
| 549 | } | ||
| 550 | |||
| 551 | std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { | ||
| 552 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); | ||
| 553 | ASSERT(flags == 0); | ||
| 554 | |||
| 555 | const auto result = send(fd, reinterpret_cast<const char*>(message.data()), | ||
| 556 | static_cast<int>(message.size()), 0); | ||
| 557 | if (result != SOCKET_ERROR) { | ||
| 558 | return {static_cast<s32>(result), Errno::SUCCESS}; | ||
| 559 | } | ||
| 560 | |||
| 561 | return {-1, GetAndLogLastError()}; | ||
| 562 | } | ||
| 563 | |||
| 564 | std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, | ||
| 565 | const SockAddrIn* addr) { | ||
| 566 | ASSERT(flags == 0); | ||
| 567 | |||
| 568 | const sockaddr* to = nullptr; | ||
| 569 | const int tolen = addr ? sizeof(sockaddr) : 0; | ||
| 570 | sockaddr host_addr_in; | ||
| 571 | |||
| 572 | if (addr) { | ||
| 573 | host_addr_in = TranslateFromSockAddrIn(*addr); | ||
| 574 | to = &host_addr_in; | ||
| 575 | } | ||
| 576 | |||
| 577 | const auto result = sendto(fd, reinterpret_cast<const char*>(message.data()), | ||
| 578 | static_cast<int>(message.size()), 0, to, tolen); | ||
| 579 | if (result != SOCKET_ERROR) { | ||
| 580 | return {static_cast<s32>(result), Errno::SUCCESS}; | ||
| 581 | } | ||
| 582 | |||
| 583 | return {-1, GetAndLogLastError()}; | ||
| 584 | } | ||
| 585 | |||
| 586 | Errno Socket::Close() { | ||
| 587 | [[maybe_unused]] const int result = closesocket(fd); | ||
| 588 | ASSERT(result == 0); | ||
| 589 | fd = INVALID_SOCKET; | ||
| 590 | |||
| 591 | return Errno::SUCCESS; | ||
| 592 | } | ||
| 593 | |||
| 594 | Errno Socket::SetLinger(bool enable, u32 linger) { | ||
| 595 | return SetSockOpt(fd, SO_LINGER, MakeLinger(enable, linger)); | ||
| 596 | } | ||
| 597 | |||
| 598 | Errno Socket::SetReuseAddr(bool enable) { | ||
| 599 | return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0); | ||
| 600 | } | ||
| 601 | |||
| 602 | Errno Socket::SetKeepAlive(bool enable) { | ||
| 603 | return SetSockOpt<u32>(fd, SO_KEEPALIVE, enable ? 1 : 0); | ||
| 604 | } | ||
| 605 | |||
| 606 | Errno Socket::SetBroadcast(bool enable) { | ||
| 607 | return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0); | ||
| 608 | } | ||
| 609 | |||
| 610 | Errno Socket::SetSndBuf(u32 value) { | ||
| 611 | return SetSockOpt(fd, SO_SNDBUF, value); | ||
| 612 | } | ||
| 613 | |||
| 614 | Errno Socket::SetRcvBuf(u32 value) { | ||
| 615 | return SetSockOpt(fd, SO_RCVBUF, value); | ||
| 616 | } | ||
| 617 | |||
| 618 | Errno Socket::SetSndTimeo(u32 value) { | ||
| 619 | return SetSockOpt(fd, SO_SNDTIMEO, value); | ||
| 620 | } | ||
| 621 | |||
| 622 | Errno Socket::SetRcvTimeo(u32 value) { | ||
| 623 | return SetSockOpt(fd, SO_RCVTIMEO, value); | ||
| 624 | } | ||
| 625 | |||
| 626 | Errno Socket::SetNonBlock(bool enable) { | ||
| 627 | if (EnableNonBlock(fd, enable)) { | ||
| 628 | return Errno::SUCCESS; | ||
| 629 | } | ||
| 630 | return GetAndLogLastError(); | ||
| 631 | } | ||
| 632 | |||
| 633 | bool Socket::IsOpened() const { | ||
| 634 | return fd != INVALID_SOCKET; | ||
| 635 | } | ||
| 636 | |||
| 637 | } // namespace Network | ||
diff --git a/src/core/network/network.h b/src/core/network/network.h deleted file mode 100644 index 10e5ef10d..000000000 --- a/src/core/network/network.h +++ /dev/null | |||
| @@ -1,117 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <optional> | ||
| 8 | |||
| 9 | #include "common/common_funcs.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | #ifdef _WIN32 | ||
| 13 | #include <winsock2.h> | ||
| 14 | #elif YUZU_UNIX | ||
| 15 | #include <netinet/in.h> | ||
| 16 | #endif | ||
| 17 | |||
| 18 | namespace Network { | ||
| 19 | |||
| 20 | class Socket; | ||
| 21 | |||
| 22 | /// Error code for network functions | ||
| 23 | enum class Errno { | ||
| 24 | SUCCESS, | ||
| 25 | BADF, | ||
| 26 | INVAL, | ||
| 27 | MFILE, | ||
| 28 | NOTCONN, | ||
| 29 | AGAIN, | ||
| 30 | CONNREFUSED, | ||
| 31 | HOSTUNREACH, | ||
| 32 | NETDOWN, | ||
| 33 | NETUNREACH, | ||
| 34 | OTHER, | ||
| 35 | }; | ||
| 36 | |||
| 37 | /// Address families | ||
| 38 | enum class Domain { | ||
| 39 | INET, ///< Address family for IPv4 | ||
| 40 | }; | ||
| 41 | |||
| 42 | /// Socket types | ||
| 43 | enum class Type { | ||
| 44 | STREAM, | ||
| 45 | DGRAM, | ||
| 46 | RAW, | ||
| 47 | SEQPACKET, | ||
| 48 | }; | ||
| 49 | |||
| 50 | /// Protocol values for sockets | ||
| 51 | enum class Protocol { | ||
| 52 | ICMP, | ||
| 53 | TCP, | ||
| 54 | UDP, | ||
| 55 | }; | ||
| 56 | |||
| 57 | /// Shutdown mode | ||
| 58 | enum class ShutdownHow { | ||
| 59 | RD, | ||
| 60 | WR, | ||
| 61 | RDWR, | ||
| 62 | }; | ||
| 63 | |||
| 64 | /// Array of IPv4 address | ||
| 65 | using IPv4Address = std::array<u8, 4>; | ||
| 66 | |||
| 67 | /// Cross-platform sockaddr structure | ||
| 68 | struct SockAddrIn { | ||
| 69 | Domain family; | ||
| 70 | IPv4Address ip; | ||
| 71 | u16 portno; | ||
| 72 | }; | ||
| 73 | |||
| 74 | /// Cross-platform poll fd structure | ||
| 75 | |||
| 76 | enum class PollEvents : u16 { | ||
| 77 | // Using Pascal case because IN is a macro on Windows. | ||
| 78 | In = 1 << 0, | ||
| 79 | Pri = 1 << 1, | ||
| 80 | Out = 1 << 2, | ||
| 81 | Err = 1 << 3, | ||
| 82 | Hup = 1 << 4, | ||
| 83 | Nval = 1 << 5, | ||
| 84 | }; | ||
| 85 | |||
| 86 | DECLARE_ENUM_FLAG_OPERATORS(PollEvents); | ||
| 87 | |||
| 88 | struct PollFD { | ||
| 89 | Socket* socket; | ||
| 90 | PollEvents events; | ||
| 91 | PollEvents revents; | ||
| 92 | }; | ||
| 93 | |||
| 94 | class NetworkInstance { | ||
| 95 | public: | ||
| 96 | explicit NetworkInstance(); | ||
| 97 | ~NetworkInstance(); | ||
| 98 | }; | ||
| 99 | |||
| 100 | #ifdef _WIN32 | ||
| 101 | constexpr IPv4Address TranslateIPv4(in_addr addr) { | ||
| 102 | auto& bytes = addr.S_un.S_un_b; | ||
| 103 | return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4}; | ||
| 104 | } | ||
| 105 | #elif YUZU_UNIX | ||
| 106 | constexpr IPv4Address TranslateIPv4(in_addr addr) { | ||
| 107 | const u32 bytes = addr.s_addr; | ||
| 108 | return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8), | ||
| 109 | static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)}; | ||
| 110 | } | ||
| 111 | #endif | ||
| 112 | |||
| 113 | /// @brief Returns host's IPv4 address | ||
| 114 | /// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array | ||
| 115 | std::optional<IPv4Address> GetHostIPv4Address(); | ||
| 116 | |||
| 117 | } // namespace Network | ||
diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp deleted file mode 100644 index 15ecc6abf..000000000 --- a/src/core/network/network_interface.cpp +++ /dev/null | |||
| @@ -1,209 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <fstream> | ||
| 6 | #include <sstream> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/bit_cast.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "common/settings.h" | ||
| 13 | #include "common/string_util.h" | ||
| 14 | #include "core/network/network_interface.h" | ||
| 15 | |||
| 16 | #ifdef _WIN32 | ||
| 17 | #include <iphlpapi.h> | ||
| 18 | #else | ||
| 19 | #include <cerrno> | ||
| 20 | #include <ifaddrs.h> | ||
| 21 | #include <net/if.h> | ||
| 22 | #endif | ||
| 23 | |||
| 24 | namespace Network { | ||
| 25 | |||
| 26 | #ifdef _WIN32 | ||
| 27 | |||
| 28 | std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { | ||
| 29 | std::vector<IP_ADAPTER_ADDRESSES> adapter_addresses; | ||
| 30 | DWORD ret = ERROR_BUFFER_OVERFLOW; | ||
| 31 | DWORD buf_size = 0; | ||
| 32 | |||
| 33 | // retry up to 5 times | ||
| 34 | for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) { | ||
| 35 | ret = GetAdaptersAddresses( | ||
| 36 | AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS, | ||
| 37 | nullptr, adapter_addresses.data(), &buf_size); | ||
| 38 | |||
| 39 | if (ret != ERROR_BUFFER_OVERFLOW) { | ||
| 40 | break; | ||
| 41 | } | ||
| 42 | |||
| 43 | adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1); | ||
| 44 | } | ||
| 45 | |||
| 46 | if (ret != NO_ERROR) { | ||
| 47 | LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses"); | ||
| 48 | return {}; | ||
| 49 | } | ||
| 50 | |||
| 51 | std::vector<NetworkInterface> result; | ||
| 52 | |||
| 53 | for (auto current_address = adapter_addresses.data(); current_address != nullptr; | ||
| 54 | current_address = current_address->Next) { | ||
| 55 | if (current_address->FirstUnicastAddress == nullptr || | ||
| 56 | current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) { | ||
| 57 | continue; | ||
| 58 | } | ||
| 59 | |||
| 60 | if (current_address->OperStatus != IfOperStatusUp) { | ||
| 61 | continue; | ||
| 62 | } | ||
| 63 | |||
| 64 | const auto ip_addr = Common::BitCast<struct sockaddr_in>( | ||
| 65 | *current_address->FirstUnicastAddress->Address.lpSockaddr) | ||
| 66 | .sin_addr; | ||
| 67 | |||
| 68 | ULONG mask = 0; | ||
| 69 | if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength, | ||
| 70 | &mask) != NO_ERROR) { | ||
| 71 | LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask"); | ||
| 72 | continue; | ||
| 73 | } | ||
| 74 | |||
| 75 | struct in_addr gateway = {.S_un{.S_addr{0}}}; | ||
| 76 | if (current_address->FirstGatewayAddress != nullptr && | ||
| 77 | current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) { | ||
| 78 | gateway = Common::BitCast<struct sockaddr_in>( | ||
| 79 | *current_address->FirstGatewayAddress->Address.lpSockaddr) | ||
| 80 | .sin_addr; | ||
| 81 | } | ||
| 82 | |||
| 83 | result.emplace_back(NetworkInterface{ | ||
| 84 | .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})}, | ||
| 85 | .ip_address{ip_addr}, | ||
| 86 | .subnet_mask = in_addr{.S_un{.S_addr{mask}}}, | ||
| 87 | .gateway = gateway}); | ||
| 88 | } | ||
| 89 | |||
| 90 | return result; | ||
| 91 | } | ||
| 92 | |||
| 93 | #else | ||
| 94 | |||
| 95 | std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { | ||
| 96 | struct ifaddrs* ifaddr = nullptr; | ||
| 97 | |||
| 98 | if (getifaddrs(&ifaddr) != 0) { | ||
| 99 | LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}", | ||
| 100 | std::strerror(errno)); | ||
| 101 | return {}; | ||
| 102 | } | ||
| 103 | |||
| 104 | std::vector<NetworkInterface> result; | ||
| 105 | |||
| 106 | for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { | ||
| 107 | if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) { | ||
| 108 | continue; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (ifa->ifa_addr->sa_family != AF_INET) { | ||
| 112 | continue; | ||
| 113 | } | ||
| 114 | |||
| 115 | if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) { | ||
| 116 | continue; | ||
| 117 | } | ||
| 118 | |||
| 119 | u32 gateway{}; | ||
| 120 | |||
| 121 | std::ifstream file{"/proc/net/route"}; | ||
| 122 | if (!file.is_open()) { | ||
| 123 | LOG_ERROR(Network, "Failed to open \"/proc/net/route\""); | ||
| 124 | |||
| 125 | result.emplace_back(NetworkInterface{ | ||
| 126 | .name{ifa->ifa_name}, | ||
| 127 | .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}, | ||
| 128 | .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr}, | ||
| 129 | .gateway{in_addr{.s_addr = gateway}}}); | ||
| 130 | continue; | ||
| 131 | } | ||
| 132 | |||
| 133 | // ignore header | ||
| 134 | file.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); | ||
| 135 | |||
| 136 | bool gateway_found = false; | ||
| 137 | |||
| 138 | for (std::string line; std::getline(file, line);) { | ||
| 139 | std::istringstream iss{line}; | ||
| 140 | |||
| 141 | std::string iface_name; | ||
| 142 | iss >> iface_name; | ||
| 143 | if (iface_name != ifa->ifa_name) { | ||
| 144 | continue; | ||
| 145 | } | ||
| 146 | |||
| 147 | iss >> std::hex; | ||
| 148 | |||
| 149 | u32 dest{}; | ||
| 150 | iss >> dest; | ||
| 151 | if (dest != 0) { | ||
| 152 | // not the default route | ||
| 153 | continue; | ||
| 154 | } | ||
| 155 | |||
| 156 | iss >> gateway; | ||
| 157 | |||
| 158 | u16 flags{}; | ||
| 159 | iss >> flags; | ||
| 160 | |||
| 161 | // flag RTF_GATEWAY (defined in <linux/route.h>) | ||
| 162 | if ((flags & 0x2) == 0) { | ||
| 163 | continue; | ||
| 164 | } | ||
| 165 | |||
| 166 | gateway_found = true; | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | |||
| 170 | if (!gateway_found) { | ||
| 171 | gateway = 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | result.emplace_back(NetworkInterface{ | ||
| 175 | .name{ifa->ifa_name}, | ||
| 176 | .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}, | ||
| 177 | .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr}, | ||
| 178 | .gateway{in_addr{.s_addr = gateway}}}); | ||
| 179 | } | ||
| 180 | |||
| 181 | freeifaddrs(ifaddr); | ||
| 182 | |||
| 183 | return result; | ||
| 184 | } | ||
| 185 | |||
| 186 | #endif | ||
| 187 | |||
| 188 | std::optional<NetworkInterface> GetSelectedNetworkInterface() { | ||
| 189 | const auto& selected_network_interface = Settings::values.network_interface.GetValue(); | ||
| 190 | const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); | ||
| 191 | if (network_interfaces.size() == 0) { | ||
| 192 | LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces"); | ||
| 193 | return std::nullopt; | ||
| 194 | } | ||
| 195 | |||
| 196 | const auto res = | ||
| 197 | std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) { | ||
| 198 | return iface.name == selected_network_interface; | ||
| 199 | }); | ||
| 200 | |||
| 201 | if (res == network_interfaces.end()) { | ||
| 202 | LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); | ||
| 203 | return std::nullopt; | ||
| 204 | } | ||
| 205 | |||
| 206 | return *res; | ||
| 207 | } | ||
| 208 | |||
| 209 | } // namespace Network | ||
diff --git a/src/core/network/network_interface.h b/src/core/network/network_interface.h deleted file mode 100644 index 9b98b6b42..000000000 --- a/src/core/network/network_interface.h +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <optional> | ||
| 7 | #include <string> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #ifdef _WIN32 | ||
| 11 | #include <winsock2.h> | ||
| 12 | #else | ||
| 13 | #include <netinet/in.h> | ||
| 14 | #endif | ||
| 15 | |||
| 16 | namespace Network { | ||
| 17 | |||
| 18 | struct NetworkInterface { | ||
| 19 | std::string name; | ||
| 20 | struct in_addr ip_address; | ||
| 21 | struct in_addr subnet_mask; | ||
| 22 | struct in_addr gateway; | ||
| 23 | }; | ||
| 24 | |||
| 25 | std::vector<NetworkInterface> GetAvailableNetworkInterfaces(); | ||
| 26 | std::optional<NetworkInterface> GetSelectedNetworkInterface(); | ||
| 27 | |||
| 28 | } // namespace Network | ||
diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h deleted file mode 100644 index f889159f5..000000000 --- a/src/core/network/sockets.h +++ /dev/null | |||
| @@ -1,94 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <utility> | ||
| 8 | |||
| 9 | #if defined(_WIN32) | ||
| 10 | #elif !YUZU_UNIX | ||
| 11 | #error "Platform not implemented" | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #include "common/common_types.h" | ||
| 15 | #include "core/network/network.h" | ||
| 16 | |||
| 17 | // TODO: C++20 Replace std::vector usages with std::span | ||
| 18 | |||
| 19 | namespace Network { | ||
| 20 | |||
| 21 | class Socket { | ||
| 22 | public: | ||
| 23 | struct AcceptResult { | ||
| 24 | std::unique_ptr<Socket> socket; | ||
| 25 | SockAddrIn sockaddr_in; | ||
| 26 | }; | ||
| 27 | |||
| 28 | explicit Socket() = default; | ||
| 29 | ~Socket(); | ||
| 30 | |||
| 31 | Socket(const Socket&) = delete; | ||
| 32 | Socket& operator=(const Socket&) = delete; | ||
| 33 | |||
| 34 | Socket(Socket&& rhs) noexcept; | ||
| 35 | |||
| 36 | // Avoid closing sockets implicitly | ||
| 37 | Socket& operator=(Socket&&) noexcept = delete; | ||
| 38 | |||
| 39 | Errno Initialize(Domain domain, Type type, Protocol protocol); | ||
| 40 | |||
| 41 | Errno Close(); | ||
| 42 | |||
| 43 | std::pair<AcceptResult, Errno> Accept(); | ||
| 44 | |||
| 45 | Errno Connect(SockAddrIn addr_in); | ||
| 46 | |||
| 47 | std::pair<SockAddrIn, Errno> GetPeerName(); | ||
| 48 | |||
| 49 | std::pair<SockAddrIn, Errno> GetSockName(); | ||
| 50 | |||
| 51 | Errno Bind(SockAddrIn addr); | ||
| 52 | |||
| 53 | Errno Listen(s32 backlog); | ||
| 54 | |||
| 55 | Errno Shutdown(ShutdownHow how); | ||
| 56 | |||
| 57 | std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message); | ||
| 58 | |||
| 59 | std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr); | ||
| 60 | |||
| 61 | std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags); | ||
| 62 | |||
| 63 | std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, const SockAddrIn* addr); | ||
| 64 | |||
| 65 | Errno SetLinger(bool enable, u32 linger); | ||
| 66 | |||
| 67 | Errno SetReuseAddr(bool enable); | ||
| 68 | |||
| 69 | Errno SetKeepAlive(bool enable); | ||
| 70 | |||
| 71 | Errno SetBroadcast(bool enable); | ||
| 72 | |||
| 73 | Errno SetSndBuf(u32 value); | ||
| 74 | |||
| 75 | Errno SetRcvBuf(u32 value); | ||
| 76 | |||
| 77 | Errno SetSndTimeo(u32 value); | ||
| 78 | |||
| 79 | Errno SetRcvTimeo(u32 value); | ||
| 80 | |||
| 81 | Errno SetNonBlock(bool enable); | ||
| 82 | |||
| 83 | bool IsOpened() const; | ||
| 84 | |||
| 85 | #if defined(_WIN32) | ||
| 86 | SOCKET fd = INVALID_SOCKET; | ||
| 87 | #elif YUZU_UNIX | ||
| 88 | int fd = -1; | ||
| 89 | #endif | ||
| 90 | }; | ||
| 91 | |||
| 92 | std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout); | ||
| 93 | |||
| 94 | } // namespace Network | ||