diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index eaefb3f048..7d7353cc5a 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -462,6 +462,7 @@ target_sources(rpcs3_emu PRIVATE NP/rpcn_countries.cpp NP/upnp_config.cpp NP/upnp_handler.cpp + NP/ip_address.cpp ) # Memory diff --git a/rpcs3/Emu/Cell/Modules/sceNp.h b/rpcs3/Emu/Cell/Modules/sceNp.h index 0d425df157..bc2ab7c6e2 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.h +++ b/rpcs3/Emu/Cell/Modules/sceNp.h @@ -1,5 +1,6 @@ #pragma once +#include "Emu/NP/rpcn_types.h" #include "cellRtc.h" #include "Emu/Cell/ErrorCodes.h" #include "util/shared_ptr.hpp" @@ -1826,7 +1827,7 @@ public: virtual ~SendMessageDialogBase() = default; virtual error_code Exec(message_data& msg_data, std::set& npids) = 0; - virtual void callback_handler(u16 ntype, const std::string& username, bool status) = 0; + virtual void callback_handler(rpcn::NotificationType ntype, const std::string& username, bool status) = 0; protected: std::shared_ptr m_rpcn; diff --git a/rpcs3/Emu/Cell/lv2/sys_net.cpp b/rpcs3/Emu/Cell/lv2/sys_net.cpp index 2eb0e037f1..827a4c98f2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #ifdef __clang__ #pragma GCC diagnostic pop diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp index 7bdd18b3fd..0d2a598214 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp @@ -35,7 +35,7 @@ std::size_t lv2_socket::get_queue_size() const } socket_type lv2_socket::get_socket() const { - return socket; + return native_socket; } #ifdef _WIN32 diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h index f0e3b61d00..314840f245 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h @@ -6,6 +6,7 @@ #include "Utilities/mutex.h" #include "Emu/IdManager.h" #include "Emu/Cell/lv2/sys_net.h" +#include "Emu/NP/ip_address.h" #ifdef _WIN32 #include @@ -21,12 +22,6 @@ #endif #endif -#ifdef _WIN32 -using socket_type = uptr; -#else -using socket_type = int; -#endif - enum class thread_state : u32; class lv2_socket @@ -126,7 +121,7 @@ protected: shared_mutex mutex; s32 lv2_id = 0; - socket_type socket = 0; + socket_type native_socket = 0; lv2_socket_family family{}; lv2_socket_type type{}; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp index d0a735b178..d420f23cc8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp @@ -87,9 +87,9 @@ s32 lv2_socket_native::create_socket() return CELL_OK; } -void lv2_socket_native::set_socket(socket_type socket, lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol) +void lv2_socket_native::set_socket(socket_type native_socket, lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol) { - this->socket = socket; + this->native_socket = native_socket; this->family = family; this->type = type; this->protocol = protocol; @@ -115,12 +115,12 @@ std::tuple, sys_net_sockaddr> lv2_socket_nativ sys_net.error("Calling socket::accept() from a previously connected socket!"); } - socket_type native_socket = ::accept(socket, reinterpret_cast(&native_addr), &native_addrlen); + socket_type client_socket = ::accept(native_socket, reinterpret_cast(&native_addr), &native_addrlen); - if (native_socket != invalid_socket) + if (client_socket != invalid_socket) { auto newsock = make_single(family, type, protocol); - newsock->set_socket(native_socket, family, type, protocol); + newsock->set_socket(client_socket, family, type, protocol); // Sockets inherit non blocking behaviour from their parent newsock->so_nbio = so_nbio; @@ -173,7 +173,7 @@ s32 lv2_socket_native::bind(const sys_net_sockaddr& addr) sys_net.warning("[Native] Trying to bind %s:%d", native_addr.sin_addr, std::bit_cast, u16>(native_addr.sin_port)); - if (::bind(socket, reinterpret_cast(&native_addr), native_addr_len) == 0) + if (::bind(native_socket, reinterpret_cast(&native_addr), native_addr_len) == 0) { // Only UPNP port forward binds to 0.0.0.0 if (saddr == 0) @@ -182,7 +182,7 @@ s32 lv2_socket_native::bind(const sys_net_sockaddr& addr) { sockaddr_in client_addr; socklen_t client_addr_size = sizeof(client_addr); - ensure(::getsockname(socket, reinterpret_cast(&client_addr), &client_addr_size) == 0); + ensure(::getsockname(native_socket, reinterpret_cast(&client_addr), &client_addr_size) == 0); bound_port = std::bit_cast>(client_addr.sin_port); } else @@ -245,7 +245,7 @@ std::optional lv2_socket_native::connect(const sys_net_sockaddr& addr) return -SYS_NET_EALREADY; } - if (::connect(socket, reinterpret_cast(&native_addr), native_addr_len) == 0) + if (::connect(native_socket, reinterpret_cast(&native_addr), native_addr_len) == 0) { return CELL_OK; } @@ -272,7 +272,7 @@ std::optional lv2_socket_native::connect(const sys_net_sockaddr& addr) { int native_error; ::socklen_t size = sizeof(native_error); - if (::getsockopt(socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&native_error), &size) != 0 || size != sizeof(int)) + if (::getsockopt(native_socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&native_error), &size) != 0 || size != sizeof(int)) { so_error = 1; } @@ -304,7 +304,7 @@ s32 lv2_socket_native::connect_followup() { int native_error; ::socklen_t size = sizeof(native_error); - if (::getsockopt(socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&native_error), &size) != 0 || size != sizeof(int)) + if (::getsockopt(native_socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&native_error), &size) != 0 || size != sizeof(int)) { return -1; } @@ -320,7 +320,7 @@ std::pair lv2_socket_native::getpeername() ::sockaddr_storage native_addr; ::socklen_t native_addrlen = sizeof(native_addr); - if (::getpeername(socket, reinterpret_cast(&native_addr), &native_addrlen) == 0) + if (::getpeername(native_socket, reinterpret_cast(&native_addr), &native_addrlen) == 0) { ensure(native_addr.ss_family == AF_INET); @@ -339,7 +339,7 @@ std::pair lv2_socket_native::getsockname() ::sockaddr_storage native_addr; ::socklen_t native_addrlen = sizeof(native_addr); - if (::getsockname(socket, reinterpret_cast(&native_addr), &native_addrlen) == 0) + if (::getsockname(native_socket, reinterpret_cast(&native_addr), &native_addrlen) == 0) { ensure(native_addr.ss_family == AF_INET); @@ -581,7 +581,7 @@ std::tuple lv2_socket_native::getsockopt(s32 return {-SYS_NET_EINVAL, {}, {}}; } - if (::getsockopt(socket, native_level, native_opt, native_val.ch, &native_len) != 0) + if (::getsockopt(native_socket, native_level, native_opt, native_val.ch, &native_len) != 0) { return {-get_last_error(false), {}, {}}; } @@ -864,7 +864,7 @@ s32 lv2_socket_native::setsockopt(s32 level, s32 optname, const std::vector& return -SYS_NET_EINVAL; } - if (::setsockopt(socket, native_level, native_opt, static_cast(native_val), native_len) == 0) + if (::setsockopt(native_socket, native_level, native_opt, static_cast(native_val), native_len) == 0) { return {}; } @@ -876,7 +876,7 @@ s32 lv2_socket_native::listen(s32 backlog) { std::lock_guard lock(mutex); - if (::listen(socket, backlog) == 0) + if (::listen(native_socket, backlog) == 0) { return CELL_OK; } @@ -930,7 +930,7 @@ std::optional, sys_net_sockaddr>> lv2_socket_nat native_flags |= MSG_WAITALL; } - auto native_result = ::recvfrom(socket, reinterpret_cast(res_buf.data()), len, native_flags, reinterpret_cast(&native_addr), &native_addrlen); + auto native_result = ::recvfrom(native_socket, reinterpret_cast(res_buf.data()), len, native_flags, reinterpret_cast(&native_addr), &native_addrlen); if (native_result >= 0) { @@ -1021,7 +1021,7 @@ std::optional lv2_socket_native::sendto(s32 flags, const std::vector& b } } - native_result = ::sendto(socket, reinterpret_cast(buf.data()), ::narrow(buf.size()), native_flags, native_addr ? reinterpret_cast(&native_addr.value()) : nullptr, native_addr ? sizeof(sockaddr_in) : 0); + native_result = ::sendto(native_socket, reinterpret_cast(buf.data()), ::narrow(buf.size()), native_flags, native_addr ? reinterpret_cast(&native_addr.value()) : nullptr, native_addr ? sizeof(sockaddr_in) : 0); if (native_result >= 0) { @@ -1075,7 +1075,7 @@ std::optional lv2_socket_native::sendmsg(s32 flags, const sys_net_msghdr& m const u32 len = msg.msg_iov[i].iov_len; const std::vector buf_copy(vm::_ptr(iov_base.addr()), vm::_ptr(iov_base.addr()) + len); - native_result = ::send(socket, reinterpret_cast(buf_copy.data()), ::narrow(buf_copy.size()), native_flags); + native_result = ::send(native_socket, reinterpret_cast(buf_copy.data()), ::narrow(buf_copy.size()), native_flags); if (native_result >= 0) { @@ -1096,15 +1096,9 @@ std::optional lv2_socket_native::sendmsg(s32 flags, const sys_net_msghdr& m void lv2_socket_native::close() { std::lock_guard lock(mutex); - if (socket) - { -#ifdef _WIN32 - ::closesocket(socket); -#else - ::close(socket); -#endif - socket = {}; - } + + np::close_socket(native_socket); + native_socket = {}; if (auto dnshook = g_fxo->try_get()) { @@ -1141,7 +1135,7 @@ s32 lv2_socket_native::shutdown(s32 how) SHUT_RDWR; #endif - if (::shutdown(socket, native_how) == 0) + if (::shutdown(native_socket, native_how) == 0) { return CELL_OK; } @@ -1163,7 +1157,7 @@ s32 lv2_socket_native::poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) sys_net.warning("sys_net_bnet_poll(fd=%d): events=0x%x", sn_pfd.fd, sn_pfd.events); } - native_pfd.fd = socket; + native_pfd.fd = native_socket; if (sn_pfd.events & SYS_NET_POLLIN) { @@ -1179,7 +1173,7 @@ s32 lv2_socket_native::poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) std::tuple lv2_socket_native::select(bs_t selected, pollfd& native_pfd) { - native_pfd.fd = socket; + native_pfd.fd = native_socket; if (selected & lv2_socket::poll_t::read) { native_pfd.events |= POLLIN; @@ -1196,12 +1190,12 @@ void lv2_socket_native::set_default_buffers() { // Those are the default PS3 values u32 default_RCVBUF = (type == SYS_NET_SOCK_STREAM) ? 65535 : 9216; - if (::setsockopt(socket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&default_RCVBUF), sizeof(default_RCVBUF)) != 0) + if (::setsockopt(native_socket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&default_RCVBUF), sizeof(default_RCVBUF)) != 0) { sys_net.error("Error setting default SO_RCVBUF on sys_net_bnet_socket socket"); } u32 default_SNDBUF = 131072; - if (::setsockopt(socket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&default_SNDBUF), sizeof(default_SNDBUF)) != 0) + if (::setsockopt(native_socket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&default_SNDBUF), sizeof(default_SNDBUF)) != 0) { sys_net.error("Error setting default SO_SNDBUF on sys_net_bnet_socket socket"); } @@ -1212,12 +1206,7 @@ void lv2_socket_native::set_non_blocking() // Set non-blocking // This is done to avoid having threads stuck on blocking socket functions // Blocking functions just put the thread to sleep and delegate the waking up to network_thread which polls the sockets -#ifdef _WIN32 - u_long _true = 1; - ::ioctlsocket(socket, FIONBIO, &_true); -#else - ::fcntl(socket, F_SETFL, ::fcntl(socket, F_GETFL, 0) | O_NONBLOCK); -#endif + np::set_socket_non_blocking(native_socket); } bool lv2_socket_native::is_socket_connected() @@ -1232,7 +1221,7 @@ bool lv2_socket_native::is_socket_connected() int listening = 0; socklen_t len = sizeof(listening); - if (::getsockopt(socket, SOL_SOCKET, SO_ACCEPTCONN, reinterpret_cast(&listening), &len) == -1) + if (::getsockopt(native_socket, SOL_SOCKET, SO_ACCEPTCONN, reinterpret_cast(&listening), &len) == -1) { return false; } @@ -1248,8 +1237,8 @@ bool lv2_socket_native::is_socket_connected() FD_ZERO(&readfds); FD_ZERO(&writefds); - FD_SET(socket, &readfds); - FD_SET(socket, &writefds); + FD_SET(native_socket, &readfds); + FD_SET(native_socket, &writefds); // Use select to check for readability and writability const int result = ::select(1, &readfds, &writefds, NULL, &timeout); @@ -1261,5 +1250,5 @@ bool lv2_socket_native::is_socket_connected() } // Socket is connected if it's readable or writable - return FD_ISSET(socket, &readfds) || FD_ISSET(socket, &writefds); + return FD_ISSET(native_socket, &readfds) || FD_ISSET(native_socket, &writefds); } diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h index 1f7e3be905..cf07dfcb76 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h @@ -17,7 +17,6 @@ #include #include #include -#include #include #ifdef __clang__ #pragma GCC diagnostic pop @@ -61,7 +60,7 @@ public: s32 shutdown(s32 how) override; private: - void set_socket(socket_type socket, lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol); + void set_socket(socket_type native_socket, lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol); void set_default_buffers(); void set_non_blocking(); diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp index 8614d37205..7acb1273d6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp @@ -164,7 +164,7 @@ s32 lv2_socket_p2p::bind(const sys_net_sockaddr& addr) std::lock_guard lock(mutex); port = p2p_port; vport = p2p_vport; - socket = real_socket; + native_socket = real_socket; bound_addr = psa_in_p2p->sin_addr; } @@ -176,7 +176,7 @@ std::pair lv2_socket_p2p::getsockname() std::lock_guard lock(mutex); // Unbound socket - if (!socket) + if (!native_socket) { return {CELL_OK, {}}; } @@ -299,7 +299,7 @@ std::optional lv2_socket_p2p::sendto(s32 flags, const std::vector& buf, native_flags |= MSG_WAITALL; } - auto native_result = ::sendto(socket, reinterpret_cast(p2p_data.data()), ::size32(p2p_data), native_flags, reinterpret_cast(&native_addr), sizeof(native_addr)); + auto native_result = np::sendto_possibly_ipv6(native_socket, reinterpret_cast(p2p_data.data()), ::size32(p2p_data), &native_addr, native_flags); if (native_result >= 0) { diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp index d6c98b670a..3996eae82d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "Utilities/Thread.h" -#include "util/asm.hpp" #include "util/atomic.hpp" #include "lv2_socket_p2ps.h" #include "Emu/NP/np_helpers.h" @@ -275,10 +274,10 @@ lv2_socket_p2ps::lv2_socket_p2ps(lv2_socket_family family, lv2_socket_type type, sockopts[(static_cast(SYS_NET_SOL_SOCKET) << 32ull) | SYS_NET_SO_TYPE] = cache_type; } -lv2_socket_p2ps::lv2_socket_p2ps(socket_type socket, u16 port, u16 vport, u32 op_addr, u16 op_port, u16 op_vport, u64 cur_seq, u64 data_beg_seq, s32 so_nbio) +lv2_socket_p2ps::lv2_socket_p2ps(socket_type native_socket, u16 port, u16 vport, u32 op_addr, u16 op_port, u16 op_vport, u64 cur_seq, u64 data_beg_seq, s32 so_nbio) : lv2_socket_p2p(SYS_NET_AF_INET, SYS_NET_SOCK_STREAM_P2P, SYS_NET_IPPROTO_IP) { - this->socket = socket; + this->native_socket = native_socket; this->port = port; this->vport = vport; this->op_addr = op_addr; @@ -467,7 +466,7 @@ bool lv2_socket_p2ps::handle_listening(p2ps_encapsulated_tcp* tcp_header, [[mayb const u16 new_op_vport = tcp_header->src_port; const u64 new_cur_seq = send_hdr.seq + 1; const u64 new_data_beg_seq = send_hdr.ack; - auto sock_lv2 = make_shared(socket, port, vport, new_op_addr, new_op_port, new_op_vport, new_cur_seq, new_data_beg_seq, so_nbio); + auto sock_lv2 = make_shared(native_socket, port, vport, new_op_addr, new_op_port, new_op_vport, new_cur_seq, new_data_beg_seq, so_nbio); const s32 new_sock_id = idm::import_existing(sock_lv2); sock_lv2->set_lv2_id(new_sock_id); const u64 key_connected = (reinterpret_cast(op_addr)->sin_addr.s_addr) | (static_cast(tcp_header->src_port) << 48) | (static_cast(tcp_header->dst_port) << 32); @@ -518,8 +517,9 @@ void lv2_socket_p2ps::send_u2s_packet(std::vector data, const ::sockaddr_in* { char ip_str[16]; inet_ntop(AF_INET, &dst->sin_addr, ip_str, sizeof(ip_str)); - sys_net.trace("[P2PS] Sending U2S packet on socket %d(id:%d): data(%d, seq %d, require_ack %d) to %s:%d", socket, lv2_id, data.size(), seq, require_ack, ip_str, std::bit_cast>(dst->sin_port)); - while (::sendto(socket, reinterpret_cast(data.data()), ::size32(data), 0, reinterpret_cast(dst), sizeof(sockaddr_in)) == -1) + sys_net.trace("[P2PS] Sending U2S packet on socket %d(id:%d): data(%d, seq %d, require_ack %d) to %s:%d", native_socket, lv2_id, data.size(), seq, require_ack, ip_str, std::bit_cast>(dst->sin_port)); + + while (np::sendto_possibly_ipv6(native_socket, reinterpret_cast(data.data()), ::size32(data), dst, 0) == -1) { const sys_net_error err = get_last_error(false); // concurrency on the socket can result in EAGAIN error in which case we try again @@ -707,7 +707,7 @@ s32 lv2_socket_p2ps::bind(const sys_net_sockaddr& addr) port = p2p_port; vport = p2p_vport; - socket = real_socket; + native_socket = real_socket; bound_addr = psa_in_p2p->sin_addr; } } @@ -720,7 +720,7 @@ std::pair lv2_socket_p2ps::getsockname() std::lock_guard lock(mutex); // Unbound socket - if (!socket) + if (!native_socket) { return {CELL_OK, {}}; } @@ -783,7 +783,7 @@ std::optional lv2_socket_p2ps::connect(const sys_net_sockaddr& addr) } } - socket = real_socket; + native_socket = real_socket; send_hdr.src_port = vport; send_hdr.dst_port = dst_vport; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp index 84e90e53fe..61bd5a4045 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp @@ -1,35 +1,73 @@ +#include "Emu/NP/ip_address.h" #include "stdafx.h" #include "Emu/Cell/lv2/sys_sync.h" #include "Emu/Cell/Modules/sceNp.h" // for SCE_NP_PORT #include "network_context.h" -#include "Emu/system_config.h" #include "sys_net_helpers.h" LOG_CHANNEL(sys_net); // Used by RPCN to send signaling packets to RPCN server(for UDP hole punching) -s32 send_packet_from_p2p_port(const std::vector& data, const sockaddr_in& addr) +bool send_packet_from_p2p_port_ipv4(const std::vector& data, const sockaddr_in& addr) { - s32 res{}; auto& nc = g_fxo->get(); { std::lock_guard list_lock(nc.list_p2p_ports_mutex); if (nc.list_p2p_ports.contains(SCE_NP_PORT)) { auto& def_port = ::at32(nc.list_p2p_ports, SCE_NP_PORT); - res = ::sendto(def_port.p2p_socket, reinterpret_cast(data.data()), ::size32(data), 0, reinterpret_cast(&addr), sizeof(sockaddr_in)); - if (res == -1) - sys_net.error("Failed to send signaling packet: %s", get_last_error(false, false)); + if (def_port.is_ipv6) + { + const auto addr6 = np::sockaddr_to_sockaddr6(addr); + + if (::sendto(def_port.p2p_socket, reinterpret_cast(data.data()), ::size32(data), 0, reinterpret_cast(&addr6), sizeof(sockaddr_in6)) == -1) + { + sys_net.error("Failed to send IPv4 signaling packet on IPv6 socket: %s", get_last_error(false, false)); + return false; + } + } + else if (::sendto(def_port.p2p_socket, reinterpret_cast(data.data()), ::size32(data), 0, reinterpret_cast(&addr), sizeof(sockaddr_in)) == -1) + { + sys_net.error("Failed to send signaling packet on IPv4 socket: %s", get_last_error(false, false)); + return false; + } } else { - sys_net.error("send_packet_from_p2p_port: port %d not present", +SCE_NP_PORT); + sys_net.error("send_packet_from_p2p_port_ipv4: port %d not present", +SCE_NP_PORT); + return false; } } - return res; + return true; +} + +bool send_packet_from_p2p_port_ipv6(const std::vector& data, const sockaddr_in6& addr) +{ + auto& nc = g_fxo->get(); + { + std::lock_guard list_lock(nc.list_p2p_ports_mutex); + if (nc.list_p2p_ports.contains(SCE_NP_PORT)) + { + auto& def_port = ::at32(nc.list_p2p_ports, SCE_NP_PORT); + ensure(def_port.is_ipv6); + + if (::sendto(def_port.p2p_socket, reinterpret_cast(data.data()), ::size32(data), 0, reinterpret_cast(&addr), sizeof(sockaddr_in6)) == -1) + { + sys_net.error("Failed to send signaling packet on IPv6 socket: %s", get_last_error(false, false)); + return false; + } + } + else + { + sys_net.error("send_packet_from_p2p_port_ipv6: port %d not present", +SCE_NP_PORT); + return false; + } + } + + return true; } std::vector> get_rpcn_msgs() @@ -241,13 +279,18 @@ void p2p_thread::operator()() auto num_p2p_sockets = 0; std::memset(p2p_fd.data(), 0, p2p_fd.size() * sizeof(::pollfd)); { - std::lock_guard lock(list_p2p_ports_mutex); - for (const auto& p2p_port : list_p2p_ports) + auto set_fd = [&](socket_type socket) { p2p_fd[num_p2p_sockets].events = POLLIN; p2p_fd[num_p2p_sockets].revents = 0; - p2p_fd[num_p2p_sockets].fd = p2p_port.second.p2p_socket; + p2p_fd[num_p2p_sockets].fd = socket; num_p2p_sockets++; + }; + + std::lock_guard lock(list_p2p_ports_mutex); + for (const auto& [_, p2p_port] : list_p2p_ports) + { + set_fd(p2p_port.p2p_socket); } } @@ -260,14 +303,20 @@ void p2p_thread::operator()() { std::lock_guard lock(list_p2p_ports_mutex); auto fd_index = 0; - for (auto& p2p_port : list_p2p_ports) + + auto process_fd = [&](nt_p2p_port& p2p_port) { if ((p2p_fd[fd_index].revents & POLLIN) == POLLIN || (p2p_fd[fd_index].revents & POLLRDNORM) == POLLRDNORM) { - while (p2p_port.second.recv_data()) + while (p2p_port.recv_data()) ; } fd_index++; + }; + + for (auto& [_, p2p_port] : list_p2p_ports) + { + process_fd(p2p_port); } wake_threads(); diff --git a/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp b/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp index 574d670978..5f48d273dd 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp @@ -1,11 +1,7 @@ #include "stdafx.h" - -#include - +#include "Emu/NP/ip_address.h" #include "nt_p2p_port.h" -#include "lv2_socket_native.h" #include "lv2_socket_p2ps.h" -#include "util/asm.hpp" #include "sys_net_helpers.h" #include "Emu/NP/signaling_handler.h" #include "sys_net_helpers.h" @@ -44,9 +40,10 @@ namespace sys_net_helpers nt_p2p_port::nt_p2p_port(u16 port) : port(port) { - // Creates and bind P2P Socket - p2p_socket = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + is_ipv6 = np::is_ipv6_supported(); + // Creates and bind P2P Socket + p2p_socket = is_ipv6 ? ::socket(AF_INET6, SOCK_DGRAM, 0) : ::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); #ifdef _WIN32 if (p2p_socket == INVALID_SOCKET) #else @@ -54,22 +51,30 @@ nt_p2p_port::nt_p2p_port(u16 port) #endif fmt::throw_exception("Failed to create DGRAM socket for P2P socket: %s!", get_last_error(true)); -#ifdef _WIN32 - u_long _true = 1; - ::ioctlsocket(p2p_socket, FIONBIO, &_true); -#else - ::fcntl(p2p_socket, F_SETFL, ::fcntl(p2p_socket, F_GETFL, 0) | O_NONBLOCK); -#endif + np::set_socket_non_blocking(p2p_socket); u32 optval = 131072; // value obtained from DECR for a SOCK_DGRAM_P2P socket(should maybe be bigger for actual socket?) if (setsockopt(p2p_socket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&optval), sizeof(optval)) != 0) fmt::throw_exception("Error setsockopt SO_RCVBUF on P2P socket: %s", get_last_error(true)); - ::sockaddr_in p2p_saddr{}; - p2p_saddr.sin_family = AF_INET; - p2p_saddr.sin_port = std::bit_cast>(port); // htons(port); - p2p_saddr.sin_addr.s_addr = 0; // binds to 0.0.0.0 - const auto ret_bind = ::bind(p2p_socket, reinterpret_cast(&p2p_saddr), sizeof(p2p_saddr)); + int ret_bind = 0; + const u16 be_port = std::bit_cast>(port); + + if (is_ipv6) + { + // Some OS(Windows, maybe more) will only support IPv6 adressing by default and we need IPv4 over IPv6 + optval = 0; + if (setsockopt(p2p_socket, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&optval), sizeof(optval)) != 0) + fmt::throw_exception("Error setsockopt IPV6_V6ONLY on P2P socket: %s", get_last_error(true)); + + ::sockaddr_in6 p2p_ipv6_addr{.sin6_family = AF_INET6, .sin6_port = be_port}; + ret_bind = ::bind(p2p_socket, reinterpret_cast(&p2p_ipv6_addr), sizeof(p2p_ipv6_addr)); + } + else + { + ::sockaddr_in p2p_ipv4_addr{.sin_family = AF_INET, .sin_port = be_port}; + ret_bind = ::bind(p2p_socket, reinterpret_cast(&p2p_ipv4_addr), sizeof(p2p_ipv4_addr)); + } if (ret_bind == -1) fmt::throw_exception("Failed to bind DGRAM socket to %d for P2P: %s!", port, get_last_error(true)); @@ -82,14 +87,7 @@ nt_p2p_port::nt_p2p_port(u16 port) nt_p2p_port::~nt_p2p_port() { - if (p2p_socket) - { -#ifdef _WIN32 - ::closesocket(p2p_socket); -#else - ::close(p2p_socket); -#endif - } + np::close_socket(p2p_socket); } void nt_p2p_port::dump_packet(p2ps_encapsulated_tcp* tcph) @@ -153,7 +151,7 @@ bool nt_p2p_port::recv_data() { auto lerr = get_last_error(false); if (lerr != SYS_NET_EINPROGRESS && lerr != SYS_NET_EWOULDBLOCK) - sys_net.error("Error recvfrom on P2P socket: %d", lerr); + sys_net.error("Error recvfrom on %s P2P socket: %d", is_ipv6 ? "IPv6" : "IPv4", lerr); return false; } @@ -166,6 +164,14 @@ bool nt_p2p_port::recv_data() u16 dst_vport = reinterpret_cast&>(p2p_recv_data[0]); + if (is_ipv6) + { + const auto* addr_ipv6 = reinterpret_cast(&native_addr); + const auto addr_ipv4 = np::sockaddr6_to_sockaddr(*addr_ipv6); + native_addr = {}; + std::memcpy(&native_addr, &addr_ipv4, sizeof(addr_ipv4)); + } + if (dst_vport == 0) { if (recv_res < VPORT_0_HEADER_SIZE) @@ -339,7 +345,7 @@ bool nt_p2p_port::recv_data() send_hdr.flags = p2ps_tcp_flags::RST; auto packet = generate_u2s_packet(send_hdr, nullptr, 0); - if (::sendto(p2p_socket, reinterpret_cast(packet.data()), ::size32(packet), 0, reinterpret_cast(&native_addr), sizeof(sockaddr_in)) == -1) + if (np::sendto_possibly_ipv6(p2p_socket, reinterpret_cast(packet.data()), ::size32(packet), reinterpret_cast(&native_addr), 0) == -1) { sys_net.error("[P2PS] Error sending RST to sender to unbound P2PS: %s", get_last_error(false)); return true; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.h b/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.h index 2d57bc8461..3ffc3df54d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.h @@ -48,6 +48,8 @@ struct nt_p2p_port socket_type p2p_socket = 0; u16 port = 0; + bool is_ipv6 = false; + shared_mutex bound_p2p_vports_mutex; // For DGRAM_P2P sockets (vport, sock_ids) std::map> bound_p2p_vports{}; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp b/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp index 0fabc61cae..acd4bf6a1f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp @@ -1,11 +1,8 @@ #include "stdafx.h" - #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" - #include "lv2_socket.h" #include "sys_net_helpers.h" - #include "network_context.h" LOG_CHANNEL(sys_net); @@ -32,13 +29,13 @@ sys_net_error convert_error(bool is_blocking, int native_error, [[maybe_unused]] #define ERROR_CASE(error) \ case WSA##error: \ result = SYS_NET_##error; \ - name = #error; \ + name = #error; \ break; #else #define ERROR_CASE(error) \ case error: \ result = SYS_NET_##error; \ - name = #error; \ + name = #error; \ break; #endif switch (native_error) @@ -86,11 +83,11 @@ sys_net_error convert_error(bool is_blocking, int native_error, [[maybe_unused]] ERROR_CASE(EHOSTDOWN); ERROR_CASE(EHOSTUNREACH); #ifdef _WIN32 - // Windows likes to be special with unique errors - case WSAENETRESET: - result = SYS_NET_ECONNRESET; - name = "WSAENETRESET"; - break; + // Windows likes to be special with unique errors + case WSAENETRESET: + result = SYS_NET_ECONNRESET; + name = "WSAENETRESET"; + break; #endif default: fmt::throw_exception("sys_net get_last_error(is_blocking=%d, native_error=%d): Unknown/illegal socket error", is_blocking, native_error); @@ -137,11 +134,11 @@ sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_ad sys_net_sockaddr_in* paddr = reinterpret_cast(&sn_addr); - paddr->sin_len = sizeof(sys_net_sockaddr_in); + paddr->sin_len = sizeof(sys_net_sockaddr_in); paddr->sin_family = SYS_NET_AF_INET; - paddr->sin_port = std::bit_cast, u16>(reinterpret_cast(&native_addr)->sin_port); - paddr->sin_addr = std::bit_cast, u32>(reinterpret_cast(&native_addr)->sin_addr.s_addr); - paddr->sin_zero = 0; + paddr->sin_port = std::bit_cast, u16>(reinterpret_cast(&native_addr)->sin_port); + paddr->sin_addr = std::bit_cast, u32>(reinterpret_cast(&native_addr)->sin_addr.s_addr); + paddr->sin_zero = 0; return sn_addr; } @@ -153,8 +150,8 @@ sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_ad const sys_net_sockaddr_in* psa_in = reinterpret_cast(&sn_addr); ::sockaddr_in native_addr{}; - native_addr.sin_family = AF_INET; - native_addr.sin_port = std::bit_cast(psa_in->sin_port); + native_addr.sin_family = AF_INET; + native_addr.sin_port = std::bit_cast(psa_in->sin_port); native_addr.sin_addr.s_addr = std::bit_cast(psa_in->sin_addr); #ifdef _WIN32 @@ -189,9 +186,9 @@ u32 network_clear_queue(ppu_thread& ppu) u32 cleared = 0; idm::select([&](u32, lv2_socket& sock) - { - cleared += sock.clear_queue(&ppu); - }); + { + cleared += sock.clear_queue(&ppu); + }); return cleared; } @@ -204,6 +201,7 @@ void clear_ppu_to_awake(ppu_thread& ppu) #ifdef _WIN32 // Workaround function for WSAPoll not reporting failed connections +// Note that this was fixed in Windows 10 version 2004 (after more than 10 years lol) void windows_poll(std::vector& fds, unsigned long nfds, int timeout, std::vector& connecting) { ensure(fds.size() >= nfds); @@ -237,12 +235,12 @@ void windows_poll(std::vector& fds, unsigned long nfds, int timeout, std { if (!fds[i].revents) { - int error = 0; + int error = 0; socklen_t intlen = sizeof(error); if (getsockopt(fds[i].fd, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &intlen) == -1 || error != 0) { // Connection silently failed - connecting[i] = false; + connecting[i] = false; fds[i].revents = POLLERR | POLLHUP | (fds[i].events & (POLLIN | POLLOUT)); } } diff --git a/rpcs3/Emu/NP/fb_helpers.cpp b/rpcs3/Emu/NP/fb_helpers.cpp index 434a90298d..100c3e864c 100644 --- a/rpcs3/Emu/NP/fb_helpers.cpp +++ b/rpcs3/Emu/NP/fb_helpers.cpp @@ -45,7 +45,7 @@ namespace np { sce_group->groupId = fb_group->groupId(); sce_group->withPassword = fb_group->withPassword(); - sce_group->withLabel = fb_group->withLabel(); + sce_group->withLabel = fb_group->label() ? 1 : 0; if (fb_group->label()) { for (flatbuffers::uoffset_t l_index = 0; l_index < fb_group->label()->size(); l_index++) diff --git a/rpcs3/Emu/NP/generated/np2_structs.fbs b/rpcs3/Emu/NP/generated/np2_structs.fbs index 634d3fe6b8..bf360bdb86 100644 --- a/rpcs3/Emu/NP/generated/np2_structs.fbs +++ b/rpcs3/Emu/NP/generated/np2_structs.fbs @@ -1,3 +1,18 @@ +table SignalingAddr { + ip:[uint8]; + port:uint16; +} + +table MatchingSignalingInfo { + npid:string; + addr:SignalingAddr; +} + +table Matching2SignalingInfo { + member_id:uint16; + addr:SignalingAddr; +} + table BinAttr { id:uint16; data:[uint8]; @@ -27,7 +42,6 @@ table OptParam { table GroupConfig { slotNum:uint32; - withLabel:bool; label:[uint8]; withPassword:bool; } @@ -52,7 +66,6 @@ table RoomMemberDataInternal { table RoomGroup { groupId:uint8; withPassword:bool; - withLabel:bool; label:[uint8]; slotNum:uint32; curGroupMemberNum:uint32; @@ -108,7 +121,7 @@ table PresenceOptionData { } table RoomGroupPasswordConfig { - groupId:[uint8]; + groupId:uint8; withPassword:bool; } @@ -161,6 +174,11 @@ table JoinRoomRequest { teamId:uint8; } +table JoinRoomResponse { + room_data: RoomDataInternal; + signaling_data: [Matching2SignalingInfo]; +} + table LeaveRoomRequest { roomId:uint64; optData:PresenceOptionData; @@ -221,6 +239,12 @@ table RoomMemberUpdateInfo { optData:PresenceOptionData; } +table NotificationUserJoinedRoom { + room_id:uint64; + update_info:RoomMemberUpdateInfo; + signaling:SignalingAddr; +} + table RoomUpdateInfo { eventCause:uint8; errorCode:int32; diff --git a/rpcs3/Emu/NP/generated/np2_structs_generated.h b/rpcs3/Emu/NP/generated/np2_structs_generated.h index a31fc0c9c4..f1d24ae568 100644 --- a/rpcs3/Emu/NP/generated/np2_structs_generated.h +++ b/rpcs3/Emu/NP/generated/np2_structs_generated.h @@ -13,6 +13,15 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 24 && FLATBUFFERS_VERSION_REVISION == 25, "Non-compatible flatbuffers version included"); +struct SignalingAddr; +struct SignalingAddrBuilder; + +struct MatchingSignalingInfo; +struct MatchingSignalingInfoBuilder; + +struct Matching2SignalingInfo; +struct Matching2SignalingInfoBuilder; + struct BinAttr; struct BinAttrBuilder; @@ -70,6 +79,9 @@ struct CreateJoinRoomRequestBuilder; struct JoinRoomRequest; struct JoinRoomRequestBuilder; +struct JoinRoomResponse; +struct JoinRoomResponseBuilder; + struct LeaveRoomRequest; struct LeaveRoomRequestBuilder; @@ -100,6 +112,9 @@ struct GetRoomDataInternalRequestBuilder; struct RoomMemberUpdateInfo; struct RoomMemberUpdateInfoBuilder; +struct NotificationUserJoinedRoom; +struct NotificationUserJoinedRoomBuilder; + struct RoomUpdateInfo; struct RoomUpdateInfoBuilder; @@ -256,6 +271,185 @@ struct SearchJoinRoomGUIRequestBuilder; struct MatchingSearchJoinRoomInfo; struct MatchingSearchJoinRoomInfoBuilder; +struct SignalingAddr FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef SignalingAddrBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_IP = 4, + VT_PORT = 6 + }; + const ::flatbuffers::Vector *ip() const { + return GetPointer *>(VT_IP); + } + uint16_t port() const { + return GetField(VT_PORT, 0); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_IP) && + verifier.VerifyVector(ip()) && + VerifyField(verifier, VT_PORT, 2) && + verifier.EndTable(); + } +}; + +struct SignalingAddrBuilder { + typedef SignalingAddr Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_ip(::flatbuffers::Offset<::flatbuffers::Vector> ip) { + fbb_.AddOffset(SignalingAddr::VT_IP, ip); + } + void add_port(uint16_t port) { + fbb_.AddElement(SignalingAddr::VT_PORT, port, 0); + } + explicit SignalingAddrBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateSignalingAddr( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset<::flatbuffers::Vector> ip = 0, + uint16_t port = 0) { + SignalingAddrBuilder builder_(_fbb); + builder_.add_ip(ip); + builder_.add_port(port); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateSignalingAddrDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *ip = nullptr, + uint16_t port = 0) { + auto ip__ = ip ? _fbb.CreateVector(*ip) : 0; + return CreateSignalingAddr( + _fbb, + ip__, + port); +} + +struct MatchingSignalingInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef MatchingSignalingInfoBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NPID = 4, + VT_ADDR = 6 + }; + const ::flatbuffers::String *npid() const { + return GetPointer(VT_NPID); + } + const SignalingAddr *addr() const { + return GetPointer(VT_ADDR); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NPID) && + verifier.VerifyString(npid()) && + VerifyOffset(verifier, VT_ADDR) && + verifier.VerifyTable(addr()) && + verifier.EndTable(); + } +}; + +struct MatchingSignalingInfoBuilder { + typedef MatchingSignalingInfo Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_npid(::flatbuffers::Offset<::flatbuffers::String> npid) { + fbb_.AddOffset(MatchingSignalingInfo::VT_NPID, npid); + } + void add_addr(::flatbuffers::Offset addr) { + fbb_.AddOffset(MatchingSignalingInfo::VT_ADDR, addr); + } + explicit MatchingSignalingInfoBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateMatchingSignalingInfo( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset<::flatbuffers::String> npid = 0, + ::flatbuffers::Offset addr = 0) { + MatchingSignalingInfoBuilder builder_(_fbb); + builder_.add_addr(addr); + builder_.add_npid(npid); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateMatchingSignalingInfoDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + const char *npid = nullptr, + ::flatbuffers::Offset addr = 0) { + auto npid__ = npid ? _fbb.CreateString(npid) : 0; + return CreateMatchingSignalingInfo( + _fbb, + npid__, + addr); +} + +struct Matching2SignalingInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef Matching2SignalingInfoBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_MEMBER_ID = 4, + VT_ADDR = 6 + }; + uint16_t member_id() const { + return GetField(VT_MEMBER_ID, 0); + } + const SignalingAddr *addr() const { + return GetPointer(VT_ADDR); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_MEMBER_ID, 2) && + VerifyOffset(verifier, VT_ADDR) && + verifier.VerifyTable(addr()) && + verifier.EndTable(); + } +}; + +struct Matching2SignalingInfoBuilder { + typedef Matching2SignalingInfo Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_member_id(uint16_t member_id) { + fbb_.AddElement(Matching2SignalingInfo::VT_MEMBER_ID, member_id, 0); + } + void add_addr(::flatbuffers::Offset addr) { + fbb_.AddOffset(Matching2SignalingInfo::VT_ADDR, addr); + } + explicit Matching2SignalingInfoBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateMatching2SignalingInfo( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint16_t member_id = 0, + ::flatbuffers::Offset addr = 0) { + Matching2SignalingInfoBuilder builder_(_fbb); + builder_.add_addr(addr); + builder_.add_member_id(member_id); + return builder_.Finish(); +} + struct BinAttr FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { typedef BinAttrBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { @@ -549,16 +743,12 @@ struct GroupConfig FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { typedef GroupConfigBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_SLOTNUM = 4, - VT_WITHLABEL = 6, - VT_LABEL = 8, - VT_WITHPASSWORD = 10 + VT_LABEL = 6, + VT_WITHPASSWORD = 8 }; uint32_t slotNum() const { return GetField(VT_SLOTNUM, 0); } - bool withLabel() const { - return GetField(VT_WITHLABEL, 0) != 0; - } const ::flatbuffers::Vector *label() const { return GetPointer *>(VT_LABEL); } @@ -568,7 +758,6 @@ struct GroupConfig FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_SLOTNUM, 4) && - VerifyField(verifier, VT_WITHLABEL, 1) && VerifyOffset(verifier, VT_LABEL) && verifier.VerifyVector(label()) && VerifyField(verifier, VT_WITHPASSWORD, 1) && @@ -583,9 +772,6 @@ struct GroupConfigBuilder { void add_slotNum(uint32_t slotNum) { fbb_.AddElement(GroupConfig::VT_SLOTNUM, slotNum, 0); } - void add_withLabel(bool withLabel) { - fbb_.AddElement(GroupConfig::VT_WITHLABEL, static_cast(withLabel), 0); - } void add_label(::flatbuffers::Offset<::flatbuffers::Vector> label) { fbb_.AddOffset(GroupConfig::VT_LABEL, label); } @@ -606,28 +792,24 @@ struct GroupConfigBuilder { inline ::flatbuffers::Offset CreateGroupConfig( ::flatbuffers::FlatBufferBuilder &_fbb, uint32_t slotNum = 0, - bool withLabel = false, ::flatbuffers::Offset<::flatbuffers::Vector> label = 0, bool withPassword = false) { GroupConfigBuilder builder_(_fbb); builder_.add_label(label); builder_.add_slotNum(slotNum); builder_.add_withPassword(withPassword); - builder_.add_withLabel(withLabel); return builder_.Finish(); } inline ::flatbuffers::Offset CreateGroupConfigDirect( ::flatbuffers::FlatBufferBuilder &_fbb, uint32_t slotNum = 0, - bool withLabel = false, const std::vector *label = nullptr, bool withPassword = false) { auto label__ = label ? _fbb.CreateVector(*label) : 0; return CreateGroupConfig( _fbb, slotNum, - withLabel, label__, withPassword); } @@ -854,10 +1036,9 @@ struct RoomGroup FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_GROUPID = 4, VT_WITHPASSWORD = 6, - VT_WITHLABEL = 8, - VT_LABEL = 10, - VT_SLOTNUM = 12, - VT_CURGROUPMEMBERNUM = 14 + VT_LABEL = 8, + VT_SLOTNUM = 10, + VT_CURGROUPMEMBERNUM = 12 }; uint8_t groupId() const { return GetField(VT_GROUPID, 0); @@ -865,9 +1046,6 @@ struct RoomGroup FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { bool withPassword() const { return GetField(VT_WITHPASSWORD, 0) != 0; } - bool withLabel() const { - return GetField(VT_WITHLABEL, 0) != 0; - } const ::flatbuffers::Vector *label() const { return GetPointer *>(VT_LABEL); } @@ -881,7 +1059,6 @@ struct RoomGroup FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { return VerifyTableStart(verifier) && VerifyField(verifier, VT_GROUPID, 1) && VerifyField(verifier, VT_WITHPASSWORD, 1) && - VerifyField(verifier, VT_WITHLABEL, 1) && VerifyOffset(verifier, VT_LABEL) && verifier.VerifyVector(label()) && VerifyField(verifier, VT_SLOTNUM, 4) && @@ -900,9 +1077,6 @@ struct RoomGroupBuilder { void add_withPassword(bool withPassword) { fbb_.AddElement(RoomGroup::VT_WITHPASSWORD, static_cast(withPassword), 0); } - void add_withLabel(bool withLabel) { - fbb_.AddElement(RoomGroup::VT_WITHLABEL, static_cast(withLabel), 0); - } void add_label(::flatbuffers::Offset<::flatbuffers::Vector> label) { fbb_.AddOffset(RoomGroup::VT_LABEL, label); } @@ -927,7 +1101,6 @@ inline ::flatbuffers::Offset CreateRoomGroup( ::flatbuffers::FlatBufferBuilder &_fbb, uint8_t groupId = 0, bool withPassword = false, - bool withLabel = false, ::flatbuffers::Offset<::flatbuffers::Vector> label = 0, uint32_t slotNum = 0, uint32_t curGroupMemberNum = 0) { @@ -935,7 +1108,6 @@ inline ::flatbuffers::Offset CreateRoomGroup( builder_.add_curGroupMemberNum(curGroupMemberNum); builder_.add_slotNum(slotNum); builder_.add_label(label); - builder_.add_withLabel(withLabel); builder_.add_withPassword(withPassword); builder_.add_groupId(groupId); return builder_.Finish(); @@ -945,7 +1117,6 @@ inline ::flatbuffers::Offset CreateRoomGroupDirect( ::flatbuffers::FlatBufferBuilder &_fbb, uint8_t groupId = 0, bool withPassword = false, - bool withLabel = false, const std::vector *label = nullptr, uint32_t slotNum = 0, uint32_t curGroupMemberNum = 0) { @@ -954,7 +1125,6 @@ inline ::flatbuffers::Offset CreateRoomGroupDirect( _fbb, groupId, withPassword, - withLabel, label__, slotNum, curGroupMemberNum); @@ -1565,16 +1735,15 @@ struct RoomGroupPasswordConfig FLATBUFFERS_FINAL_CLASS : private ::flatbuffers:: VT_GROUPID = 4, VT_WITHPASSWORD = 6 }; - const ::flatbuffers::Vector *groupId() const { - return GetPointer *>(VT_GROUPID); + uint8_t groupId() const { + return GetField(VT_GROUPID, 0); } bool withPassword() const { return GetField(VT_WITHPASSWORD, 0) != 0; } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_GROUPID) && - verifier.VerifyVector(groupId()) && + VerifyField(verifier, VT_GROUPID, 1) && VerifyField(verifier, VT_WITHPASSWORD, 1) && verifier.EndTable(); } @@ -1584,8 +1753,8 @@ struct RoomGroupPasswordConfigBuilder { typedef RoomGroupPasswordConfig Table; ::flatbuffers::FlatBufferBuilder &fbb_; ::flatbuffers::uoffset_t start_; - void add_groupId(::flatbuffers::Offset<::flatbuffers::Vector> groupId) { - fbb_.AddOffset(RoomGroupPasswordConfig::VT_GROUPID, groupId); + void add_groupId(uint8_t groupId) { + fbb_.AddElement(RoomGroupPasswordConfig::VT_GROUPID, groupId, 0); } void add_withPassword(bool withPassword) { fbb_.AddElement(RoomGroupPasswordConfig::VT_WITHPASSWORD, static_cast(withPassword), 0); @@ -1603,25 +1772,14 @@ struct RoomGroupPasswordConfigBuilder { inline ::flatbuffers::Offset CreateRoomGroupPasswordConfig( ::flatbuffers::FlatBufferBuilder &_fbb, - ::flatbuffers::Offset<::flatbuffers::Vector> groupId = 0, + uint8_t groupId = 0, bool withPassword = false) { RoomGroupPasswordConfigBuilder builder_(_fbb); - builder_.add_groupId(groupId); builder_.add_withPassword(withPassword); + builder_.add_groupId(groupId); return builder_.Finish(); } -inline ::flatbuffers::Offset CreateRoomGroupPasswordConfigDirect( - ::flatbuffers::FlatBufferBuilder &_fbb, - const std::vector *groupId = nullptr, - bool withPassword = false) { - auto groupId__ = groupId ? _fbb.CreateVector(*groupId) : 0; - return CreateRoomGroupPasswordConfig( - _fbb, - groupId__, - withPassword); -} - struct SearchRoomRequest FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { typedef SearchRoomRequestBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { @@ -2250,6 +2408,71 @@ inline ::flatbuffers::Offset CreateJoinRoomRequestDirect( teamId); } +struct JoinRoomResponse FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef JoinRoomResponseBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ROOM_DATA = 4, + VT_SIGNALING_DATA = 6 + }; + const RoomDataInternal *room_data() const { + return GetPointer(VT_ROOM_DATA); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *signaling_data() const { + return GetPointer> *>(VT_SIGNALING_DATA); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_ROOM_DATA) && + verifier.VerifyTable(room_data()) && + VerifyOffset(verifier, VT_SIGNALING_DATA) && + verifier.VerifyVector(signaling_data()) && + verifier.VerifyVectorOfTables(signaling_data()) && + verifier.EndTable(); + } +}; + +struct JoinRoomResponseBuilder { + typedef JoinRoomResponse Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_room_data(::flatbuffers::Offset room_data) { + fbb_.AddOffset(JoinRoomResponse::VT_ROOM_DATA, room_data); + } + void add_signaling_data(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> signaling_data) { + fbb_.AddOffset(JoinRoomResponse::VT_SIGNALING_DATA, signaling_data); + } + explicit JoinRoomResponseBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateJoinRoomResponse( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset room_data = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> signaling_data = 0) { + JoinRoomResponseBuilder builder_(_fbb); + builder_.add_signaling_data(signaling_data); + builder_.add_room_data(room_data); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateJoinRoomResponseDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset room_data = 0, + const std::vector<::flatbuffers::Offset> *signaling_data = nullptr) { + auto signaling_data__ = signaling_data ? _fbb.CreateVector<::flatbuffers::Offset>(*signaling_data) : 0; + return CreateJoinRoomResponse( + _fbb, + room_data, + signaling_data__); +} + struct LeaveRoomRequest FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { typedef LeaveRoomRequestBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { @@ -2995,6 +3218,69 @@ inline ::flatbuffers::Offset CreateRoomMemberUpdateInfo( return builder_.Finish(); } +struct NotificationUserJoinedRoom FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef NotificationUserJoinedRoomBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ROOM_ID = 4, + VT_UPDATE_INFO = 6, + VT_SIGNALING = 8 + }; + uint64_t room_id() const { + return GetField(VT_ROOM_ID, 0); + } + const RoomMemberUpdateInfo *update_info() const { + return GetPointer(VT_UPDATE_INFO); + } + const SignalingAddr *signaling() const { + return GetPointer(VT_SIGNALING); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ROOM_ID, 8) && + VerifyOffset(verifier, VT_UPDATE_INFO) && + verifier.VerifyTable(update_info()) && + VerifyOffset(verifier, VT_SIGNALING) && + verifier.VerifyTable(signaling()) && + verifier.EndTable(); + } +}; + +struct NotificationUserJoinedRoomBuilder { + typedef NotificationUserJoinedRoom Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_room_id(uint64_t room_id) { + fbb_.AddElement(NotificationUserJoinedRoom::VT_ROOM_ID, room_id, 0); + } + void add_update_info(::flatbuffers::Offset update_info) { + fbb_.AddOffset(NotificationUserJoinedRoom::VT_UPDATE_INFO, update_info); + } + void add_signaling(::flatbuffers::Offset signaling) { + fbb_.AddOffset(NotificationUserJoinedRoom::VT_SIGNALING, signaling); + } + explicit NotificationUserJoinedRoomBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateNotificationUserJoinedRoom( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint64_t room_id = 0, + ::flatbuffers::Offset update_info = 0, + ::flatbuffers::Offset signaling = 0) { + NotificationUserJoinedRoomBuilder builder_(_fbb); + builder_.add_room_id(room_id); + builder_.add_signaling(signaling); + builder_.add_update_info(update_info); + return builder_.Finish(); +} + struct RoomUpdateInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { typedef RoomUpdateInfoBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { diff --git a/rpcs3/Emu/NP/ip_address.cpp b/rpcs3/Emu/NP/ip_address.cpp new file mode 100644 index 0000000000..705f4782e2 --- /dev/null +++ b/rpcs3/Emu/NP/ip_address.cpp @@ -0,0 +1,249 @@ +#include "stdafx.h" +#include "ip_address.h" +#include "Utilities/StrFmt.h" +#include "Emu/IdManager.h" +#include "util/endian.hpp" +#include "util/types.hpp" +#include "Emu/NP/rpcn_config.h" +#include + +#ifndef _WIN32 +#include +#include +#endif + +LOG_CHANNEL(IPv6_log, "IPv6_layer"); + +namespace np +{ + bool ip_address_translator::is_ipv6(u32 addr_be) + { + const u32 addr = std::bit_cast>(addr_be); + return (addr >= translation_range_begin && addr <= translation_range_end); + } + + u32 ip_address_translator::register_ipv6(const std::array& ipv6_addr) + { + if (ipv6_addr[10] == 0xFF && ipv6_addr[11] == 0xFF && + std::all_of(ipv6_addr.begin(), ipv6_addr.begin() + 10, [](u8 val) + { + return val == 0; + })) + { + // IPv4 over IPv6 + u32 ip_addr{}; + std::memcpy(&ip_addr, &ipv6_addr[12], sizeof(u32)); + return ip_addr; + } + + std::lock_guard lock(mutex); + + const auto it = ipv6_to_ipv4.find(ipv6_addr); + + if (it == ipv6_to_ipv4.end()) + { + ensure(cur_addr != translation_range_end); + const u32 translation_ip = cur_addr++; + const u32 translation_ip_be = std::bit_cast>(translation_ip); + ipv6_to_ipv4.emplace(ipv6_addr, translation_ip_be); + ipv4_to_ipv6.push_back(ipv6_addr); + return translation_ip_be; + } + + return it->second; + } + + sockaddr_in6 ip_address_translator::get_ipv6_sockaddr(u32 addr_be, u16 port_be) + { + const u32 addr_native = std::bit_cast>(addr_be); + const auto ipv6_addr = ::at32(ipv4_to_ipv6, addr_native - translation_range_begin); + + sockaddr_in6 sockaddr_ipv6{.sin6_family = AF_INET6, .sin6_port = port_be}; + std::memcpy(&sockaddr_ipv6.sin6_addr, ipv6_addr.data(), ipv6_addr.size()); + + return sockaddr_ipv6; + } + + u32 register_ip(const flatbuffers::Vector* vec) + { + if (vec->size() == 4) + { + const u32 ip = static_cast(vec->Get(0)) << 24 | static_cast(vec->Get(1)) << 16 | + static_cast(vec->Get(2)) << 8 | static_cast(vec->Get(3)); + + u32 result_ip = std::bit_cast>(ip); + + return result_ip; + } + else if (vec->size() == 16) + { + std::array ipv6_addr{}; + std::memcpy(ipv6_addr.data(), vec->Data(), 16); + + auto& translator = g_fxo->get(); + return translator.register_ipv6(ipv6_addr); + } + else + { + fmt::throw_exception("Received ip address with size = %d", vec->size()); + } + } + + bool is_ipv6_supported(std::optional force_state) + { + static atomic_t ipv6_status = IPV6_SUPPORT::IPV6_UNKNOWN; + + if (force_state) + ipv6_status = *force_state; + + if (ipv6_status != IPV6_SUPPORT::IPV6_UNKNOWN) + return ipv6_status == IPV6_SUPPORT::IPV6_SUPPORTED; + + static shared_mutex mtx; + std::lock_guard lock(mtx); + + if (ipv6_status != IPV6_SUPPORT::IPV6_UNKNOWN) + return ipv6_status == IPV6_SUPPORT::IPV6_SUPPORTED; + + // IPv6 feature is only used by RPCN + if (!g_cfg_rpcn.get_ipv6_support()) + { + IPv6_log.notice("is_ipv6_supported(): disabled through config"); + ipv6_status = IPV6_SUPPORT::IPV6_UNSUPPORTED; + return false; + } + + // We try to connect to ipv6.google.com:8080 + addrinfo* addr_info{}; + socket_type socket_ipv6{}; + + auto cleanup = [&]() + { + if (socket_ipv6) + close_socket(socket_ipv6); + + if (addr_info) + freeaddrinfo(addr_info); + }; + + auto error_and_disable = [&](const char* message) -> bool + { + IPv6_log.error("is_ipv6_supported(): %s", message); + ipv6_status = IPV6_SUPPORT::IPV6_UNSUPPORTED; + cleanup(); + return false; + }; + + addrinfo hints{.ai_family = AF_INET6}; + + if (getaddrinfo("ipv6.google.com", nullptr, &hints, &addr_info)) + return error_and_disable("Failed to resolve ipv6.google.com!"); + + addrinfo* found = addr_info; + + while (found != nullptr) + { + if (found->ai_family == AF_INET6) + break; + + found = found->ai_next; + } + + if (found == nullptr) + return error_and_disable("Failed to find IPv6 for ipv6.google.com"); + + socket_type socket_or_err = ::socket(AF_INET6, SOCK_STREAM, 0); + +#ifdef _WIN32 + if (socket_or_err == INVALID_SOCKET) +#else + if (socket_or_err == -1) +#endif + return error_and_disable("Failed to create IPv6 socket!"); + + socket_ipv6 = socket_or_err; + sockaddr_in6 ipv6_addr = *reinterpret_cast(found->ai_addr); + ipv6_addr.sin6_port = std::bit_cast>(443); + + if (::connect(socket_ipv6, reinterpret_cast(&ipv6_addr), sizeof(ipv6_addr)) != 0) + return error_and_disable("Failed to connect to ipv6.google.com"); + + cleanup(); + + IPv6_log.success("Successfully tested IPv6 support!"); + ipv6_status = IPV6_SUPPORT::IPV6_SUPPORTED; + return true; + } + + s32 sendto_possibly_ipv6(socket_type native_socket, const char* data, u32 size, const sockaddr_in* addr, int native_flags) + { + if (is_ipv6_supported()) + { + sockaddr_in6 addr_ipv6{}; + + if (np::ip_address_translator::is_ipv6(addr->sin_addr.s_addr)) + { + auto& translator = g_fxo->get(); + addr_ipv6 = translator.get_ipv6_sockaddr(addr->sin_addr.s_addr, addr->sin_port); + } + else + { + addr_ipv6 = sockaddr_to_sockaddr6(*addr); + } + + return ::sendto(native_socket, data, size, native_flags, reinterpret_cast(&addr_ipv6), sizeof(sockaddr_in6)); + } + + return ::sendto(native_socket, data, size, native_flags, reinterpret_cast(addr), sizeof(sockaddr_in)); + } + + sockaddr_in6 sockaddr_to_sockaddr6(const sockaddr_in& addr) + { + sockaddr_in6 addr_ipv6{.sin6_family = AF_INET6, .sin6_port = addr.sin_port}; + std::array ipv6{}; + + // IPv4 over IPv6 + ipv6[10] = 0xFF; + ipv6[11] = 0xFF; + std::memcpy(ipv6.data() + 12, &addr.sin_addr.s_addr, 4); + std::memcpy(&addr_ipv6.sin6_addr, ipv6.data(), ipv6.size()); + return addr_ipv6; + } + + sockaddr_in sockaddr6_to_sockaddr(const sockaddr_in6& addr) + { + sockaddr_in addr_ipv4{.sin_family = AF_INET, .sin_port = addr.sin6_port}; + + std::array ipv6{}; + std::memcpy(ipv6.data(), &addr.sin6_addr, 16); + auto& translator = g_fxo->get(); + addr_ipv4.sin_addr.s_addr = translator.register_ipv6(ipv6); + + return addr_ipv4; + } + + void close_socket(socket_type socket) + { + if (socket) + { +#ifdef _WIN32 + ::closesocket(socket); +#else + ::close(socket); +#endif + } + } + + void set_socket_non_blocking(socket_type socket) + { + if (socket) + { +#ifdef _WIN32 + u_long _true = 1; + ::ioctlsocket(socket, FIONBIO, &_true); +#else + ::fcntl(socket, F_SETFL, ::fcntl(socket, F_GETFL, 0) | O_NONBLOCK); +#endif + } + } +} // namespace np diff --git a/rpcs3/Emu/NP/ip_address.h b/rpcs3/Emu/NP/ip_address.h new file mode 100644 index 0000000000..3857275aac --- /dev/null +++ b/rpcs3/Emu/NP/ip_address.h @@ -0,0 +1,86 @@ +#pragma once + +#include +#include + +#include + +#include "util/types.hpp" +#include "Utilities/mutex.h" + +#ifdef _WIN32 +#include +#include +#else +#ifdef __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" +#endif +#include +#include +#include +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif +#endif + +#ifdef _WIN32 +using socket_type = uptr; +#else +using socket_type = int; +#endif + +template <> +struct std::hash> +{ + std::size_t operator()(const std::array& array) const noexcept + { + std::size_t hash = 0; + std::hash hasher; + + for (auto byte : array) + { + hash ^= hasher(byte) + 0x9e3779b9 + (hash << 6) + (hash >> 2); + } + + return hash; + } +}; + +namespace np +{ + class ip_address_translator + { + public: + static bool is_ipv6(u32 addr_be); + + u32 register_ipv6(const std::array& ipv6_addr); + sockaddr_in6 get_ipv6_sockaddr(u32 addr_be, u16 port_be); + + private: + static constexpr u32 translation_range_begin = 0x00'00'00'01; + static constexpr u32 translation_range_end = 0x00'00'FF'FF; + + shared_mutex mutex; + u32 cur_addr = translation_range_begin; + std::unordered_map, u32> ipv6_to_ipv4; + std::vector> ipv4_to_ipv6; + }; + + u32 register_ip(const flatbuffers::Vector* vec); + + enum class IPV6_SUPPORT : u8 + { + IPV6_UNKNOWN, + IPV6_UNSUPPORTED, + IPV6_SUPPORTED, + }; + + bool is_ipv6_supported(std::optional force_state = std::nullopt); + s32 sendto_possibly_ipv6(socket_type native_socket, const char* data, u32 size, const sockaddr_in* addr, int native_flags); + sockaddr_in6 sockaddr_to_sockaddr6(const sockaddr_in& addr); + sockaddr_in sockaddr6_to_sockaddr(const sockaddr_in6& addr); + + void close_socket(socket_type socket); + void set_socket_non_blocking(socket_type socket); +} // namespace np diff --git a/rpcs3/Emu/NP/np_contexts.cpp b/rpcs3/Emu/NP/np_contexts.cpp index e448a3f56c..acc934c8b9 100644 --- a/rpcs3/Emu/NP/np_contexts.cpp +++ b/rpcs3/Emu/NP/np_contexts.cpp @@ -45,11 +45,10 @@ error_code generic_async_transaction_context::wait_for_completion() return *result; } -bool generic_async_transaction_context::set_result_and_wake(error_code err) +void generic_async_transaction_context::set_result_and_wake(error_code err) { result = err; wake_cond.notify_one(); - return true; } tus_ctx::tus_ctx(vm::cptr communicationId, vm::cptr passphrase) diff --git a/rpcs3/Emu/NP/np_contexts.h b/rpcs3/Emu/NP/np_contexts.h index 7b4157024b..20e123730b 100644 --- a/rpcs3/Emu/NP/np_contexts.h +++ b/rpcs3/Emu/NP/np_contexts.h @@ -23,7 +23,7 @@ struct generic_async_transaction_context std::optional get_transaction_status(); void abort_transaction(); error_code wait_for_completion(); - bool set_result_and_wake(error_code err); + void set_result_and_wake(error_code err); shared_mutex mutex; std::condition_variable_any wake_cond, completion_cond; diff --git a/rpcs3/Emu/NP/np_handler.cpp b/rpcs3/Emu/NP/np_handler.cpp index 5afff4db2e..6c2ac08b48 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -788,7 +788,14 @@ namespace np break; std::lock_guard lock(mutex_rpcn); - rpcn = rpcn::rpcn_client::get_instance(); + + bool was_already_started = true; + + if (!rpcn) + { + rpcn = rpcn::rpcn_client::get_instance(); + was_already_started = false; + } // Make sure we're connected @@ -808,7 +815,8 @@ namespace np return; } - rsx::overlays::queue_message(localized_string_id::RPCN_SUCCESS_LOGGED_ON); + if (!was_already_started) + rsx::overlays::queue_message(localized_string_id::RPCN_SUCCESS_LOGGED_ON); string_to_online_name(rpcn->get_online_name(), online_name); string_to_avatar_url(rpcn->get_avatar_url(), avatar_url); @@ -836,11 +844,20 @@ namespace np { np_memory.release(); + manager_cb = {}; + manager_cb_arg = {}; + basic_handler_registered = false; + room_event_cb = {}; + room_event_cb_ctx = 0; + room_event_cb_arg = {}; + room_msg_cb = {}; + room_msg_cb_ctx = 0; + room_msg_cb_arg = {}; + if (g_cfg.net.psn_status == np_psn_status::psn_rpcn) { - rpcn_log.notice("Disconnecting from RPCN!"); - std::lock_guard lock(mutex_rpcn); - rpcn.reset(); + rpcn_log.notice("Setting RPCN state to disconnected!"); + rpcn->reset_state(); } } @@ -854,10 +871,13 @@ namespace np auto& data = ::at32(match2_req_results, event_key); data.apply_relocations(dest_addr); - vm::ptr dest = vm::cast(dest_addr); + const u32 size_copied = std::min(size, data.size()); - u32 size_copied = std::min(size, data.size()); - memcpy(dest.get_ptr(), data.data(), size_copied); + if (dest_addr && size_copied) + { + vm::ptr dest = vm::cast(dest_addr); + memcpy(dest.get_ptr(), data.data(), size_copied); + } np_memory.free(data.addr()); match2_req_results.erase(event_key); @@ -1073,61 +1093,63 @@ namespace np auto replies = rpcn->get_replies(); for (auto& reply : replies) { - const u16 command = reply.second.first; + const rpcn::CommandType command = static_cast(reply.second.first); const u32 req_id = reply.first; std::vector& data = reply.second.second; // Every reply should at least contain a return value/error code ensure(data.size() >= 1); + const auto error = static_cast(data[0]); + vec_stream reply_data(data, 1); switch (command) { - case rpcn::CommandType::GetWorldList: reply_get_world_list(req_id, data); break; - case rpcn::CommandType::CreateRoom: reply_create_join_room(req_id, data); break; - case rpcn::CommandType::JoinRoom: reply_join_room(req_id, data); break; - case rpcn::CommandType::LeaveRoom: reply_leave_room(req_id, data); break; - case rpcn::CommandType::SearchRoom: reply_search_room(req_id, data); break; - case rpcn::CommandType::GetRoomDataExternalList: reply_get_roomdata_external_list(req_id, data); break; - case rpcn::CommandType::SetRoomDataExternal: reply_set_roomdata_external(req_id, data); break; - case rpcn::CommandType::GetRoomDataInternal: reply_get_roomdata_internal(req_id, data); break; - case rpcn::CommandType::SetRoomDataInternal: reply_set_roomdata_internal(req_id, data); break; - case rpcn::CommandType::GetRoomMemberDataInternal: reply_get_roommemberdata_internal(req_id, data); break; - case rpcn::CommandType::SetRoomMemberDataInternal: reply_set_roommemberdata_internal(req_id, data); break; - case rpcn::CommandType::SetUserInfo: reply_set_userinfo(req_id, data); break; - case rpcn::CommandType::PingRoomOwner: reply_get_ping_info(req_id, data); break; - case rpcn::CommandType::SendRoomMessage: reply_send_room_message(req_id, data); break; - case rpcn::CommandType::RequestSignalingInfos: reply_req_sign_infos(req_id, data); break; - case rpcn::CommandType::RequestTicket: reply_req_ticket(req_id, data); break; - case rpcn::CommandType::GetBoardInfos: reply_get_board_infos(req_id, data); break; - case rpcn::CommandType::RecordScore: reply_record_score(req_id, data); break; - case rpcn::CommandType::RecordScoreData: reply_record_score_data(req_id, data); break; - case rpcn::CommandType::GetScoreData: reply_get_score_data(req_id, data); break; - case rpcn::CommandType::GetScoreRange: reply_get_score_range(req_id, data); break; - case rpcn::CommandType::GetScoreFriends: reply_get_score_friends(req_id, data); break; - case rpcn::CommandType::GetScoreNpid: reply_get_score_npid(req_id, data); break; - case rpcn::CommandType::TusSetMultiSlotVariable: reply_tus_set_multislot_variable(req_id, data); break; - case rpcn::CommandType::TusGetMultiSlotVariable: reply_tus_get_multislot_variable(req_id, data); break; - case rpcn::CommandType::TusGetMultiUserVariable: reply_tus_get_multiuser_variable(req_id, data); break; - case rpcn::CommandType::TusGetFriendsVariable: reply_tus_get_friends_variable(req_id, data); break; - case rpcn::CommandType::TusAddAndGetVariable: reply_tus_add_and_get_variable(req_id, data); break; - case rpcn::CommandType::TusTryAndSetVariable: reply_tus_try_and_set_variable(req_id, data); break; - case rpcn::CommandType::TusDeleteMultiSlotVariable: reply_tus_delete_multislot_variable(req_id, data); break; - case rpcn::CommandType::TusSetData: reply_tus_set_data(req_id, data); break; - case rpcn::CommandType::TusGetData: reply_tus_get_data(req_id, data); break; - case rpcn::CommandType::TusGetMultiSlotDataStatus: reply_tus_get_multislot_data_status(req_id, data); break; - case rpcn::CommandType::TusGetMultiUserDataStatus: reply_tus_get_multiuser_data_status(req_id, data); break; - case rpcn::CommandType::TusGetFriendsDataStatus: reply_tus_get_friends_data_status(req_id, data); break; - case rpcn::CommandType::TusDeleteMultiSlotData: reply_tus_delete_multislot_data(req_id, data); break; - case rpcn::CommandType::CreateRoomGUI: reply_create_room_gui(req_id, data); break; - case rpcn::CommandType::JoinRoomGUI: reply_join_room_gui(req_id, data); break; - case rpcn::CommandType::LeaveRoomGUI: reply_leave_room_gui(req_id, data); break; - case rpcn::CommandType::GetRoomListGUI: reply_get_room_list_gui(req_id, data); break; - case rpcn::CommandType::SetRoomSearchFlagGUI: reply_set_room_search_flag_gui(req_id, data); break; - case rpcn::CommandType::GetRoomSearchFlagGUI: reply_get_room_search_flag_gui(req_id, data); break; - case rpcn::CommandType::SetRoomInfoGUI: reply_set_room_info_gui(req_id, data); break; - case rpcn::CommandType::GetRoomInfoGUI: reply_get_room_info_gui(req_id, data); break; - case rpcn::CommandType::QuickMatchGUI: reply_quickmatch_gui(req_id, data); break; - case rpcn::CommandType::SearchJoinRoomGUI: reply_searchjoin_gui(req_id, data); break; + case rpcn::CommandType::GetWorldList: reply_get_world_list(req_id, error, reply_data); break; + case rpcn::CommandType::CreateRoom: reply_create_join_room(req_id, error, reply_data); break; + case rpcn::CommandType::JoinRoom: reply_join_room(req_id, error, reply_data); break; + case rpcn::CommandType::LeaveRoom: reply_leave_room(req_id, error, reply_data); break; + case rpcn::CommandType::SearchRoom: reply_search_room(req_id, error, reply_data); break; + case rpcn::CommandType::GetRoomDataExternalList: reply_get_roomdata_external_list(req_id, error, reply_data); break; + case rpcn::CommandType::SetRoomDataExternal: reply_set_roomdata_external(req_id, error); break; + case rpcn::CommandType::GetRoomDataInternal: reply_get_roomdata_internal(req_id, error, reply_data); break; + case rpcn::CommandType::SetRoomDataInternal: reply_set_roomdata_internal(req_id, error); break; + case rpcn::CommandType::GetRoomMemberDataInternal: reply_get_roommemberdata_internal(req_id, error, reply_data); break; + case rpcn::CommandType::SetRoomMemberDataInternal: reply_set_roommemberdata_internal(req_id, error); break; + case rpcn::CommandType::SetUserInfo: reply_set_userinfo(req_id, error); break; + case rpcn::CommandType::PingRoomOwner: reply_get_ping_info(req_id, error, reply_data); break; + case rpcn::CommandType::SendRoomMessage: reply_send_room_message(req_id, error); break; + case rpcn::CommandType::RequestSignalingInfos: reply_req_sign_infos(req_id, error, reply_data); break; + case rpcn::CommandType::RequestTicket: reply_req_ticket(req_id, error, reply_data); break; + case rpcn::CommandType::GetBoardInfos: reply_get_board_infos(req_id, error, reply_data); break; + case rpcn::CommandType::RecordScore: reply_record_score(req_id, error, reply_data); break; + case rpcn::CommandType::RecordScoreData: reply_record_score_data(req_id, error); break; + case rpcn::CommandType::GetScoreData: reply_get_score_data(req_id, error, reply_data); break; + case rpcn::CommandType::GetScoreRange: reply_get_score_range(req_id, error, reply_data); break; + case rpcn::CommandType::GetScoreFriends: reply_get_score_friends(req_id, error, reply_data); break; + case rpcn::CommandType::GetScoreNpid: reply_get_score_npid(req_id, error, reply_data); break; + case rpcn::CommandType::TusSetMultiSlotVariable: reply_tus_set_multislot_variable(req_id, error); break; + case rpcn::CommandType::TusGetMultiSlotVariable: reply_tus_get_multislot_variable(req_id, error, reply_data); break; + case rpcn::CommandType::TusGetMultiUserVariable: reply_tus_get_multiuser_variable(req_id, error, reply_data); break; + case rpcn::CommandType::TusGetFriendsVariable: reply_tus_get_friends_variable(req_id, error, reply_data); break; + case rpcn::CommandType::TusAddAndGetVariable: reply_tus_add_and_get_variable(req_id, error, reply_data); break; + case rpcn::CommandType::TusTryAndSetVariable: reply_tus_try_and_set_variable(req_id, error, reply_data); break; + case rpcn::CommandType::TusDeleteMultiSlotVariable: reply_tus_delete_multislot_variable(req_id, error); break; + case rpcn::CommandType::TusSetData: reply_tus_set_data(req_id, error); break; + case rpcn::CommandType::TusGetData: reply_tus_get_data(req_id, error, reply_data); break; + case rpcn::CommandType::TusGetMultiSlotDataStatus: reply_tus_get_multislot_data_status(req_id, error, reply_data); break; + case rpcn::CommandType::TusGetMultiUserDataStatus: reply_tus_get_multiuser_data_status(req_id, error, reply_data); break; + case rpcn::CommandType::TusGetFriendsDataStatus: reply_tus_get_friends_data_status(req_id, error, reply_data); break; + case rpcn::CommandType::TusDeleteMultiSlotData: reply_tus_delete_multislot_data(req_id, error); break; + case rpcn::CommandType::CreateRoomGUI: reply_create_room_gui(req_id, error, reply_data); break; + case rpcn::CommandType::JoinRoomGUI: reply_join_room_gui(req_id, error, reply_data); break; + case rpcn::CommandType::LeaveRoomGUI: reply_leave_room_gui(req_id, error, reply_data); break; + case rpcn::CommandType::GetRoomListGUI: reply_get_room_list_gui(req_id, error, reply_data); break; + case rpcn::CommandType::SetRoomSearchFlagGUI: reply_set_room_search_flag_gui(req_id, error); break; + case rpcn::CommandType::GetRoomSearchFlagGUI: reply_get_room_search_flag_gui(req_id, error, reply_data); break; + case rpcn::CommandType::SetRoomInfoGUI: reply_set_room_info_gui(req_id, error); break; + case rpcn::CommandType::GetRoomInfoGUI: reply_get_room_info_gui(req_id, error, reply_data); break; + case rpcn::CommandType::QuickMatchGUI: reply_quickmatch_gui(req_id, error, reply_data); break; + case rpcn::CommandType::SearchJoinRoomGUI: reply_searchjoin_gui(req_id, error, reply_data); break; default: fmt::throw_exception("Unknown reply(%d) received!", command); break; } } @@ -1142,9 +1164,8 @@ namespace np case rpcn::NotificationType::RoomDestroyed: notif_room_destroyed(notif.second); break; case rpcn::NotificationType::UpdatedRoomDataInternal: notif_updated_room_data_internal(notif.second); break; case rpcn::NotificationType::UpdatedRoomMemberDataInternal: notif_updated_room_member_data_internal(notif.second); break; - case rpcn::NotificationType::SignalP2PConnect: notif_p2p_connect(notif.second); break; case rpcn::NotificationType::RoomMessageReceived: notif_room_message_received(notif.second); break; - case rpcn::NotificationType::SignalingInfo: notif_signaling_info(notif.second); break; + case rpcn::NotificationType::SignalingHelper: notif_signaling_helper(notif.second); break; case rpcn::NotificationType::MemberJoinedRoomGUI: notif_member_joined_room_gui(notif.second); break; case rpcn::NotificationType::MemberLeftRoomGUI: notif_member_left_room_gui(notif.second); break; case rpcn::NotificationType::RoomDisappearedGUI: notif_room_disappeared_gui(notif.second); break; diff --git a/rpcs3/Emu/NP/np_handler.h b/rpcs3/Emu/NP/np_handler.h index a8b349fd5d..4e0352c332 100644 --- a/rpcs3/Emu/NP/np_handler.h +++ b/rpcs3/Emu/NP/np_handler.h @@ -298,8 +298,7 @@ namespace np void notif_room_destroyed(std::vector& data); void notif_updated_room_data_internal(std::vector& data); void notif_updated_room_member_data_internal(std::vector& data); - void notif_p2p_connect(std::vector& data); - void notif_signaling_info(std::vector& data); + void notif_signaling_helper(std::vector& data); void notif_room_message_received(std::vector& data); void generic_gui_notification_handler(std::vector& data, std::string_view name, s32 notification_type); @@ -312,60 +311,60 @@ namespace np void notif_quickmatch_complete_gui(std::vector& data); // Reply handlers - bool reply_get_world_list(u32 req_id, std::vector& reply_data); - bool reply_create_join_room(u32 req_id, std::vector& reply_data); - bool reply_join_room(u32 req_id, std::vector& reply_data); - bool reply_leave_room(u32 req_id, std::vector& reply_data); - bool reply_search_room(u32 req_id, std::vector& reply_data); - bool reply_get_roomdata_external_list(u32 req_id, std::vector& reply_data); - bool reply_set_roomdata_external(u32 req_id, std::vector& reply_data); - bool reply_get_roomdata_internal(u32 req_id, std::vector& reply_data); - bool reply_set_roomdata_internal(u32 req_id, std::vector& reply_data); - bool reply_set_roommemberdata_internal(u32 req_id, std::vector& reply_data); - bool reply_get_roommemberdata_internal(u32 req_id, std::vector& reply_data); - bool reply_set_userinfo(u32 req_id, std::vector& reply_data); - bool reply_get_ping_info(u32 req_id, std::vector& reply_data); - bool reply_send_room_message(u32 req_id, std::vector& reply_data); - bool reply_req_sign_infos(u32 req_id, std::vector& reply_data); - bool reply_req_ticket(u32 req_id, std::vector& reply_data); - bool reply_get_board_infos(u32 req_id, std::vector& reply_data); - bool reply_record_score(u32 req_id, std::vector& reply_data); - bool reply_record_score_data(u32 req_id, std::vector& reply_data); - bool reply_get_score_data(u32 req_id, std::vector& reply_data); - bool reply_get_score_range(u32 req_id, std::vector& reply_data); - bool reply_get_score_friends(u32 req_id, std::vector& reply_data); - bool reply_get_score_npid(u32 req_id, std::vector& reply_data); - bool reply_tus_set_multislot_variable(u32 req_id, std::vector& reply_data); - bool reply_tus_get_multislot_variable(u32 req_id, std::vector& reply_data); - bool reply_tus_get_multiuser_variable(u32 req_id, std::vector& reply_data); - bool reply_tus_get_friends_variable(u32 req_id, std::vector& reply_data); - bool reply_tus_add_and_get_variable(u32 req_id, std::vector& reply_data); - bool reply_tus_try_and_set_variable(u32 req_id, std::vector& reply_data); - bool reply_tus_delete_multislot_variable(u32 req_id, std::vector& reply_data); - bool reply_tus_set_data(u32 req_id, std::vector& reply_data); - bool reply_tus_get_data(u32 req_id, std::vector& reply_data); - bool reply_tus_get_multislot_data_status(u32 req_id, std::vector& reply_data); - bool reply_tus_get_multiuser_data_status(u32 req_id, std::vector& reply_data); - bool reply_tus_get_friends_data_status(u32 req_id, std::vector& reply_data); - bool reply_tus_delete_multislot_data(u32 req_id, std::vector& reply_data); - bool reply_create_room_gui(u32 req_id, std::vector& reply_data); - bool reply_join_room_gui(u32 req_id, std::vector& reply_data); - bool reply_leave_room_gui(u32 req_id, std::vector& reply_data); - bool reply_get_room_list_gui(u32 req_id, std::vector& reply_data); - bool reply_set_room_search_flag_gui(u32 req_id, std::vector& reply_data); - bool reply_get_room_search_flag_gui(u32 req_id, std::vector& reply_data); - bool reply_set_room_info_gui(u32 req_id, std::vector& reply_data); - bool reply_get_room_info_gui(u32 req_id, std::vector& reply_data); - bool reply_quickmatch_gui(u32 req_id, std::vector& reply_data); - bool reply_searchjoin_gui(u32 req_id, std::vector& reply_data); + void reply_get_world_list(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_create_join_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_join_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_leave_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_search_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_get_roomdata_external_list(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_set_roomdata_external(u32 req_id, rpcn::ErrorType error); + void reply_get_roomdata_internal(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_set_roomdata_internal(u32 req_id, rpcn::ErrorType error); + void reply_set_roommemberdata_internal(u32 req_id, rpcn::ErrorType error); + void reply_get_roommemberdata_internal(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_set_userinfo(u32 req_id, rpcn::ErrorType error); + void reply_get_ping_info(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_send_room_message(u32 req_id, rpcn::ErrorType error); + void reply_req_sign_infos(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_req_ticket(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_get_board_infos(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_record_score(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_record_score_data(u32 req_id, rpcn::ErrorType error); + void reply_get_score_data(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_get_score_range(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_get_score_friends(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_get_score_npid(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_set_multislot_variable(u32 req_id, rpcn::ErrorType error); + void reply_tus_get_multislot_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_get_multiuser_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_get_friends_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_add_and_get_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_try_and_set_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_delete_multislot_variable(u32 req_id, rpcn::ErrorType error); + void reply_tus_set_data(u32 req_id, rpcn::ErrorType error); + void reply_tus_get_data(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_get_multislot_data_status(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_get_multiuser_data_status(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_get_friends_data_status(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_tus_delete_multislot_data(u32 req_id, rpcn::ErrorType error); + void reply_create_room_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_join_room_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_leave_room_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_get_room_list_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_set_room_search_flag_gui(u32 req_id, rpcn::ErrorType error); + void reply_get_room_search_flag_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_set_room_info_gui(u32 req_id, rpcn::ErrorType error); + void reply_get_room_info_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_quickmatch_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void reply_searchjoin_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply); // Helper functions std::pair get_match2_context_options(u32 ctx_id); - bool handle_GetScoreResponse(u32 req_id, std::vector& reply_data, bool simple_result = false); - bool handle_tus_no_data(u32 req_id, std::vector& reply_data); - bool handle_TusVarResponse(u32 req_id, std::vector& reply_data); - bool handle_TusVariable(u32 req_id, std::vector& reply_data); - bool handle_TusDataStatusResponse(u32 req_id, std::vector& reply_data); + void handle_GetScoreResponse(u32 req_id, rpcn::ErrorType error, vec_stream& reply, bool simple_result = false); + void handle_tus_no_data(u32 req_id, rpcn::ErrorType error); + void handle_TusVarResponse(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void handle_TusVariable(u32 req_id, rpcn::ErrorType error, vec_stream& reply); + void handle_TusDataStatusResponse(u32 req_id, rpcn::ErrorType error, vec_stream& reply); struct callback_info { diff --git a/rpcs3/Emu/NP/np_notifications.cpp b/rpcs3/Emu/NP/np_notifications.cpp index 160c7f8967..e051c64d65 100644 --- a/rpcs3/Emu/NP/np_notifications.cpp +++ b/rpcs3/Emu/NP/np_notifications.cpp @@ -7,6 +7,7 @@ #include "Emu/NP/np_structs_extra.h" #include "Emu/NP/fb_helpers.h" #include "Emu/NP/signaling_handler.h" +#include "Emu/NP/ip_address.h" LOG_CHANNEL(rpcn_log, "rpcn"); @@ -15,8 +16,7 @@ namespace np void np_handler::notif_user_joined_room(std::vector& data) { vec_stream noti(data); - u64 room_id = noti.get(); - const auto* update_info = noti.get_flatbuffer(); + const auto* notification = noti.get_flatbuffer(); if (noti.is_error()) { @@ -24,20 +24,44 @@ namespace np return; } + ensure(notification->update_info()); + const u32 event_key = get_event_key(); - auto [include_onlinename, include_avatarurl] = get_match2_context_options(room_event_cb_ctx); + const auto [include_onlinename, include_avatarurl] = get_match2_context_options(room_event_cb_ctx); + const auto room_id = notification->room_id(); auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomMemberUpdateInfo, sizeof(SceNpMatching2RoomMemberUpdateInfo)); auto* notif_data = reinterpret_cast(edata.data()); - RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(edata, update_info, notif_data, include_onlinename, include_avatarurl); + RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(edata, notification->update_info(), notif_data, include_onlinename, include_avatarurl); np_memory.shrink_allocation(edata.addr(), edata.size()); + // Ensures we do not call the callback if the room is not in the cache(ie we left the room already) if (!np_cache.add_member(room_id, notif_data->roomMemberDataInternal.get_ptr())) + { + get_match2_event(event_key, 0, 0); return; + } rpcn_log.notice("Received notification that user %s(%d) joined the room(%d)", notif_data->roomMemberDataInternal->userInfo.npId.handle.data, notif_data->roomMemberDataInternal->memberId, room_id); extra_nps::print_SceNpMatching2RoomMemberDataInternal(notif_data->roomMemberDataInternal.get_ptr()); + // We initiate signaling if necessary + if (const auto* signaling_info = notification->signaling()) + { + const u32 addr_p2p = register_ip(signaling_info->ip()); + const u16 port_p2p = signaling_info->port(); + + const u16 member_id = notif_data->roomMemberDataInternal->memberId; + const SceNpId& npid = notif_data->roomMemberDataInternal->userInfo.npId; + + rpcn_log.notice("Join notification told to connect to member(%d=%s) of room(%d): %s:%d", member_id, reinterpret_cast(npid.handle.data), room_id, ip_to_string(addr_p2p), port_p2p); + + // Attempt Signaling + auto& sigh = g_fxo->get>(); + const u32 conn_id = sigh.init_sig2(npid, room_id, member_id); + sigh.start_sig(conn_id, addr_p2p, port_p2p); + } + if (room_event_cb) { sysutil_register_cb([room_event_cb = this->room_event_cb, room_id, event_key, room_event_cb_ctx = this->room_event_cb_ctx, room_event_cb_arg = this->room_event_cb_arg, size = edata.size()](ppu_thread& cb_ppu) -> s32 @@ -68,8 +92,12 @@ namespace np RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(edata, update_info, notif_data, include_onlinename, include_avatarurl); np_memory.shrink_allocation(edata.addr(), edata.size()); + // Ensures we do not call the callback if the room is not in the cache(ie we left the room already) if (!np_cache.del_member(room_id, notif_data->roomMemberDataInternal->memberId)) + { + get_match2_event(event_key, 0, 0); return; + } rpcn_log.notice("Received notification that user %s(%d) left the room(%d)", notif_data->roomMemberDataInternal->userInfo.npId.handle.data, notif_data->roomMemberDataInternal->memberId, room_id); extra_nps::print_SceNpMatching2RoomMemberDataInternal(notif_data->roomMemberDataInternal.get_ptr()); @@ -175,7 +203,10 @@ namespace np np_memory.shrink_allocation(edata.addr(), edata.size()); if (!np_cache.add_member(room_id, notif_data->newRoomMemberDataInternal.get_ptr())) + { + get_match2_event(event_key, 0, 0); return; + } rpcn_log.notice("Received notification that user's %s(%d) room (%d) data was updated", notif_data->newRoomMemberDataInternal->userInfo.npId.handle.data, notif_data->newRoomMemberDataInternal->memberId, room_id); extra_nps::print_SceNpMatching2RoomMemberDataInternal(notif_data->newRoomMemberDataInternal.get_ptr()); @@ -223,33 +254,7 @@ namespace np } } - void np_handler::notif_p2p_connect(std::vector& data) - { - vec_stream noti(data); - const u64 room_id = noti.get(); - const u16 member_id = noti.get(); - const u16 port_p2p = noti.get(); - const u32 addr_p2p = noti.get(); - - if (noti.is_error()) - { - rpcn_log.error("Received faulty SignalP2PConnect notification"); - return; - } - - auto [res, npid] = np_cache.get_npid(room_id, member_id); - if (!npid) - return; - - rpcn_log.notice("Received notification to connect to member(%d=%s) of room(%d): %s:%d", member_id, reinterpret_cast((*npid).handle.data), room_id, ip_to_string(addr_p2p), port_p2p); - - // Attempt Signaling - auto& sigh = g_fxo->get>(); - const u32 conn_id = sigh.init_sig2(*npid, room_id, member_id); - sigh.start_sig(conn_id, addr_p2p, port_p2p); - } - - void np_handler::notif_signaling_info(std::vector& data) + void np_handler::notif_signaling_helper(std::vector& data) { vec_stream noti(data); const u32 addr_p2p = noti.get(); @@ -258,7 +263,7 @@ namespace np if (noti.is_error()) { - rpcn_log.error("Received faulty SignalingInfo notification"); + rpcn_log.error("Received faulty SignalingHelper notification"); return; } diff --git a/rpcs3/Emu/NP/np_requests.cpp b/rpcs3/Emu/NP/np_requests.cpp index e213c039ff..1fc8a0c1e2 100644 --- a/rpcs3/Emu/NP/np_requests.cpp +++ b/rpcs3/Emu/NP/np_requests.cpp @@ -1,3 +1,7 @@ +#include "Emu/Cell/Modules/sceNp.h" +#include "Emu/Cell/Modules/sceNp2.h" +#include "Emu/NP/rpcn_types.h" +#include "Utilities/StrFmt.h" #include "stdafx.h" #include "Emu/Cell/PPUCallback.h" #include "Emu/Cell/lv2/sys_sync.h" @@ -11,6 +15,7 @@ #include "np_structs_extra.h" #include "fb_helpers.h" #include "Emu/NP/signaling_handler.h" +#include "Emu/NP/ip_address.h" LOG_CHANNEL(rpcn_log, "rpcn"); @@ -115,14 +120,14 @@ namespace np return req_id; } - bool np_handler::reply_get_world_list(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_world_list(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - vec_stream reply(reply_data, 1); + ensure(error == rpcn::ErrorType::NoError, "Unexpected error in GetWorldList reply"); std::vector world_list; u32 num_worlds = reply.get(); @@ -131,10 +136,7 @@ namespace np world_list.push_back(reply.get()); } - if (reply.is_error()) - { - return error_and_disconnect("Malformed reply to GetWorldList command"); - } + ensure(!reply.is_error(), "Malformed reply to GetWorldList command"); const u32 event_key = get_event_key(); @@ -153,8 +155,6 @@ namespace np np_memory.shrink_allocation(edata.addr(), edata.size()); cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); - - return true; } u32 np_handler::create_join_room(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2CreateJoinRoomRequest* req) @@ -175,18 +175,32 @@ namespace np return req_id; } - bool np_handler::reply_create_join_room(u32 req_id, std::vector& reply_data) + void np_handler::reply_create_join_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; + + s32 error_code = CELL_OK; + + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomGroupMaxSlotMismatch: error_code = SCE_NP_MATCHING2_SERVER_ERROR_MAX_OVER_SLOT_GROUP; break; + case rpcn::ErrorType::RoomPasswordMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_PASSWORD; break; + case rpcn::ErrorType::RoomGroupNoJoinLabel: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_JOIN_GROUP_LABEL; break; + default: fmt::throw_exception("Unexpected error in reply to CreateRoom: %d", static_cast(error)); + } + + if (error_code != CELL_OK) + { + cb_info_opt->queue_callback(req_id, 0, error_code, 0); + return; + } - vec_stream reply(reply_data, 1); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to CreateRoom command"); + ensure(!reply.is_error(), "Malformed reply to CreateRoom command"); const u32 event_key = get_event_key(); auto [include_onlinename, include_avatarurl] = get_match2_context_options(cb_info_opt->ctx_id); @@ -203,8 +217,6 @@ namespace np extra_nps::print_SceNpMatching2CreateJoinRoomResponse(room_resp); cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); - - return true; } u32 np_handler::join_room(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2JoinRoomRequest* req) @@ -222,55 +234,79 @@ namespace np return req_id; } - bool np_handler::reply_join_room(u32 req_id, std::vector& reply_data) + void np_handler::reply_join_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; s32 error_code = 0; - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; - case rpcn::ErrorType::RoomAlreadyJoined: error_code = SCE_NP_MATCHING2_SERVER_ERROR_ALREADY_JOINED; break; - case rpcn::ErrorType::RoomFull: error_code = SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL; break; - default: return false; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + case rpcn::ErrorType::RoomAlreadyJoined: error_code = SCE_NP_MATCHING2_SERVER_ERROR_ALREADY_JOINED; break; + case rpcn::ErrorType::RoomFull: error_code = SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL; break; + case rpcn::ErrorType::RoomPasswordMismatch: error_code = SCE_NP_MATCHING2_SERVER_ERROR_PASSWORD_MISMATCH; break; + case rpcn::ErrorType::RoomGroupFull: error_code = SCE_NP_MATCHING2_SERVER_ERROR_GROUP_FULL; break; + case rpcn::ErrorType::RoomGroupJoinLabelNotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_GROUP; break; + default: fmt::throw_exception("Unexpected error in reply to JoinRoom: %d", static_cast(error)); ; } if (error_code != 0) { cb_info_opt->queue_callback(req_id, 0, error_code, 0); - return true; + return; } - vec_stream reply(reply_data, 1); - - const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to JoinRoom command"); + const auto* resp = reply.get_flatbuffer(); + ensure(!reply.is_error(), "Malformed reply to JoinRoom command"); + ensure(resp->room_data()); const u32 event_key = get_event_key(); - auto [include_onlinename, include_avatarurl] = get_match2_context_options(cb_info_opt->ctx_id); + const auto [include_onlinename, include_avatarurl] = get_match2_context_options(cb_info_opt->ctx_id); auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_JoinRoom, sizeof(SceNpMatching2JoinRoomResponse)); auto* room_resp = reinterpret_cast(edata.data()); auto* room_info = edata.allocate(sizeof(SceNpMatching2RoomDataInternal), room_resp->roomDataInternal); - RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, resp, room_info, npid, include_onlinename, include_avatarurl); + RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, resp->room_data(), room_info, npid, include_onlinename, include_avatarurl); np_memory.shrink_allocation(edata.addr(), edata.size()); np_cache.insert_room(room_info); extra_nps::print_SceNpMatching2RoomDataInternal(room_info); - cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); + // We initiate signaling if necessary + if (const auto* signaling_data = resp->signaling_data()) + { + const u64 room_id = resp->room_data()->roomId(); - return true; + for (unsigned int i = 0; i < signaling_data->size(); i++) + { + const auto* signaling_info = signaling_data->Get(i); + ensure(signaling_info->addr()); + + const u32 addr_p2p = register_ip(signaling_info->addr()->ip()); + const u16 port_p2p = signaling_info->addr()->port(); + + const u16 member_id = signaling_info->member_id(); + const auto [npid_res, npid_p2p] = np_cache.get_npid(room_id, member_id); + + if (npid_res != CELL_OK) + continue; + + rpcn_log.notice("JoinRoomResult told to connect to member(%d=%s) of room(%d): %s:%d", member_id, reinterpret_cast(npid_p2p->handle.data), room_id, ip_to_string(addr_p2p), port_p2p); + + // Attempt Signaling + auto& sigh = g_fxo->get>(); + const u32 conn_id = sigh.init_sig2(*npid_p2p, room_id, member_id); + sigh.start_sig(conn_id, addr_p2p, port_p2p); + } + } + + cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); } u32 np_handler::leave_room(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2LeaveRoomRequest* req) @@ -286,24 +322,35 @@ namespace np return req_id; } - bool np_handler::reply_leave_room(u32 req_id, std::vector& reply_data) + void np_handler::reply_leave_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; + + s32 error_code = CELL_OK; + + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + default: fmt::throw_exception("Unexpected error in reply to LeaveRoom: %d", static_cast(error)); ; + } + + if (error_code != CELL_OK) + { + cb_info_opt->queue_callback(req_id, 0, error_code, 0); + return; + } - vec_stream reply(reply_data, 1); u64 room_id = reply.get(); - if (reply.is_error()) - return error_and_disconnect("Malformed reply to LeaveRoom command"); + ensure(!reply.is_error(), "Malformed reply to LeaveRoom command"); // Disconnect all users from that room auto& sigh = g_fxo->get>(); sigh.disconnect_sig2_users(room_id); cb_info_opt->queue_callback(req_id, 0, 0, 0); - - return true; } u32 np_handler::search_room(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2SearchRoomRequest* req) @@ -321,18 +368,17 @@ namespace np return req_id; } - bool np_handler::reply_search_room(u32 req_id, std::vector& reply_data) + void np_handler::reply_search_room(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; + + ensure(error == rpcn::ErrorType::NoError, "Unexpected error in SearchRoom reply"); - vec_stream reply(reply_data, 1); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to SearchRoom command"); + ensure(!reply.is_error(), "Malformed reply to SearchRoom command"); const u32 event_key = get_event_key(); @@ -344,8 +390,6 @@ namespace np extra_nps::print_SceNpMatching2SearchRoomResponse(search_resp); cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); - - return true; } u32 np_handler::get_roomdata_external_list(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2GetRoomDataExternalListRequest* req) @@ -363,18 +407,17 @@ namespace np return req_id; } - bool np_handler::reply_get_roomdata_external_list(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_roomdata_external_list(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; + + ensure(error == rpcn::ErrorType::NoError, "Unexpected error in GetRoomDataExternalList reply"); - vec_stream reply(reply_data, 1); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to GetRoomDataExternalList command"); + ensure(!reply.is_error(), "Malformed reply to GetRoomDataExternalList command"); const u32 event_key = get_event_key(); auto [include_onlinename, include_avatarurl] = get_match2_context_options(cb_info_opt->ctx_id); @@ -387,8 +430,6 @@ namespace np extra_nps::print_SceNpMatching2GetRoomDataExternalListResponse(sce_get_room_ext_resp); cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); - - return true; } u32 np_handler::set_roomdata_external(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2SetRoomDataExternalRequest* req) @@ -406,16 +447,24 @@ namespace np return req_id; } - bool np_handler::reply_set_roomdata_external(u32 req_id, std::vector& /*reply_data*/) + void np_handler::reply_set_roomdata_external(u32 req_id, rpcn::ErrorType error) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - cb_info_opt->queue_callback(req_id, 0, 0, 0); + s32 error_code = CELL_OK; - return true; + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN; break; + default: fmt::throw_exception("Unexpected error in reply to SetRoomDataExternal: %d", static_cast(error)); + } + + cb_info_opt->queue_callback(req_id, 0, error_code, 0); } u32 np_handler::get_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2GetRoomDataInternalRequest* req) @@ -431,19 +480,30 @@ namespace np return req_id; } - bool np_handler::reply_get_roomdata_internal(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_roomdata_internal(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - vec_stream reply(reply_data, 1); + s32 error_code = CELL_OK; + + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + default: fmt::throw_exception("Unexpected error in reply to GetRoomDataInternal: %d", static_cast(error)); + } + + if (error_code != CELL_OK) + { + cb_info_opt->queue_callback(req_id, 0, error_code, 0); + return; + } const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to GetRoomDataInternal command"); + ensure(!reply.is_error(), "Malformed reply to GetRoomDataInternal command"); const u32 event_key = get_event_key(); auto [include_onlinename, include_avatarurl] = get_match2_context_options(cb_info_opt->ctx_id); @@ -459,8 +519,6 @@ namespace np extra_nps::print_SceNpMatching2RoomDataInternal(room_info); cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); - - return true; } u32 np_handler::set_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2SetRoomDataInternalRequest* req) @@ -478,16 +536,23 @@ namespace np return req_id; } - bool np_handler::reply_set_roomdata_internal(u32 req_id, std::vector& /*reply_data*/) + void np_handler::reply_set_roomdata_internal(u32 req_id, rpcn::ErrorType error) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - cb_info_opt->queue_callback(req_id, 0, 0, 0); + s32 error_code = CELL_OK; - return true; + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + default: fmt::throw_exception("Unexpected error in reply to GetRoomDataInternal: %d", static_cast(error)); ; + } + + cb_info_opt->queue_callback(req_id, 0, error_code, 0); } u32 np_handler::get_roommemberdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2GetRoomMemberDataInternalRequest* req) @@ -504,34 +569,31 @@ namespace np return req_id; } - bool np_handler::reply_get_roommemberdata_internal(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_roommemberdata_internal(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - if (rpcn::is_error(static_cast(reply_data[0]))) + s32 error_code = CELL_OK; + + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: - { - rpcn_log.error("GetRoomMemberDataInternal: Room or User wasn't found"); - cb_info_opt->queue_callback(req_id, 0, -1, 0); - return true; - } - default: - return error_and_disconnect(fmt::format("GetRoomMemberDataInternal failed with unknown error(%d)!", reply_data[0])); - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER; break; + default: fmt::throw_exception("Unexpected error in reply to GetRoomMemberDataInternal: %d", static_cast(error)); ; } - vec_stream reply(reply_data, 1); + if (error_code != CELL_OK) + { + cb_info_opt->queue_callback(req_id, 0, error_code, 0); + return; + } const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to GetRoomMemberDataInternal command"); + ensure(!reply.is_error(), "Malformed reply to GetRoomMemberDataInternal command"); const u32 event_key = get_event_key(); auto [include_onlinename, include_avatarurl] = get_match2_context_options(cb_info_opt->ctx_id); @@ -543,7 +605,6 @@ namespace np np_memory.shrink_allocation(edata.addr(), edata.size()); cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); - return true; } u32 np_handler::set_roommemberdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2SetRoomMemberDataInternalRequest* req) @@ -561,16 +622,25 @@ namespace np return req_id; } - bool np_handler::reply_set_roommemberdata_internal(u32 req_id, std::vector& /*reply_data*/) + void np_handler::reply_set_roommemberdata_internal(u32 req_id, rpcn::ErrorType error) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - cb_info_opt->queue_callback(req_id, 0, 0, 0); + s32 error_code = CELL_OK; - return true; + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER; break; + case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN; break; + default: fmt::throw_exception("Unexpected error in reply to SetRoomMemberDataInternal: %d", static_cast(error)); + } + + cb_info_opt->queue_callback(req_id, 0, error_code, 0); } u32 np_handler::set_userinfo(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2SetUserInfoRequest* req) @@ -586,21 +656,20 @@ namespace np return req_id; } - bool np_handler::reply_set_userinfo(u32 req_id, std::vector& reply_data) + void np_handler::reply_set_userinfo(u32 req_id, rpcn::ErrorType error) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - return error_and_disconnect(fmt::format("SetUserInfo failed with unknown error(%d)!", reply_data[0])); + case rpcn::ErrorType::NoError: break; + default: fmt::throw_exception("Unexpected error in reply to SetUserInfo: %d", static_cast(error)); } cb_info_opt->queue_callback(req_id, 0, 0, 0); - - return true; } u32 np_handler::get_ping_info(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2SignalingGetPingInfoRequest* req) @@ -616,19 +685,30 @@ namespace np return req_id; } - bool np_handler::reply_get_ping_info(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_ping_info(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - vec_stream reply(reply_data, 1); + s32 error_code = CELL_OK; + + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + default: fmt::throw_exception("Unexpected error in reply to PingRoomOwner: %d", static_cast(error)); + } + + if (error_code != CELL_OK) + { + cb_info_opt->queue_callback(req_id, 0, error_code, 0); + return; + } const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to PingRoomOwner command"); + ensure(!reply.is_error(), "Malformed reply to PingRoomOwner command"); const u32 event_key = get_event_key(); @@ -637,8 +717,6 @@ namespace np GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(resp, final_ping_resp); np_memory.shrink_allocation(edata.addr(), edata.size()); cb_info_opt->queue_callback(req_id, event_key, 0, edata.size()); - - return true; } u32 np_handler::send_room_message(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2SendRoomMessageRequest* req) @@ -654,16 +732,24 @@ namespace np return req_id; } - bool np_handler::reply_send_room_message(u32 req_id, std::vector& /*reply_data*/) + void np_handler::reply_send_room_message(u32 req_id, rpcn::ErrorType error) { auto cb_info_opt = take_pending_request(req_id); if (!cb_info_opt) - return true; + return; - cb_info_opt->queue_callback(req_id, 0, 0, 0); + s32 error_code = CELL_OK; - return true; + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; + case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN; break; + default: fmt::throw_exception("Unexpected error in reply to SendRoomMessage: %d", static_cast(error)); + } + + cb_info_opt->queue_callback(req_id, 0, error_code, 0); } void np_handler::req_sign_infos(const std::string& npid, u32 conn_id) @@ -681,7 +767,7 @@ namespace np } } - bool np_handler::reply_req_sign_infos(u32 req_id, std::vector& reply_data) + void np_handler::reply_req_sign_infos(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { u32 conn_id; { @@ -690,33 +776,23 @@ namespace np pending_sign_infos_requests.erase(req_id); } - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: - { - rpcn_log.error("Signaling information was requested for a user that doesn't exist or is not online"); - return true; - } - case rpcn::ErrorType::Malformed: - return error_and_disconnect("RequestSignalingInfos request was malformed!"); - default: - return error_and_disconnect(fmt::format("RequestSignalingInfos failed with unknown error(%d)!", reply_data[0])); - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::NotFound: + { + rpcn_log.error("Signaling information was requested for a user that doesn't exist or is not online"); + return; + } + default: fmt::throw_exception("Unexpected error in reply to RequestSignalingInfos: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); - const u32 addr = reply.get(); - const u16 port = reply.get(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to RequestSignalingInfos command"); + const auto* resp = reply.get_flatbuffer(); + ensure(!reply.is_error() && resp->ip(), "Malformed reply to RequestSignalingInfos command"); + u32 addr = register_ip(resp->ip()); auto& sigh = g_fxo->get>(); - sigh.start_sig(conn_id, addr, port); - - return true; + sigh.start_sig(conn_id, addr, resp->port()); } u32 np_handler::get_lobby_info_list(SceNpMatching2ContextId ctx_id, vm::cptr optParam, const SceNpMatching2GetLobbyInfoListRequest* req) @@ -780,13 +856,11 @@ namespace np return current_ticket; } - bool np_handler::reply_req_ticket([[maybe_unused]] u32 req_id, std::vector& reply_data) + void np_handler::reply_req_ticket(u32 /* req_id */, rpcn::ErrorType error, vec_stream& reply) { - vec_stream reply(reply_data, 1); + ensure(error == rpcn::ErrorType::NoError, "Unexpected error in reply to RequestTicket"); auto ticket_raw = reply.get_rawdata(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to RequestTicket command"); + ensure(!reply.is_error(), "Malformed reply to RequestTicket command"); current_ticket = ticket(std::move(ticket_raw)); auto ticket_size = static_cast(current_ticket.size()); @@ -799,8 +873,6 @@ namespace np return 0; }); } - - return true; } void np_handler::transaction_async_handler(std::unique_lock lock, const shared_ptr& trans_ctx, u32 req_id, bool async) @@ -854,14 +926,37 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_get_board_infos(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_board_infos(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - vec_stream reply(reply_data, 1); + std::lock_guard lock_trans(mutex_async_transactions); + if (!async_transactions.count(req_id)) + { + rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); + return; + } + + auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); + ensure(score_trans); + + s32 error_code = CELL_OK; + + switch (error) + { + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::NotFound: error_code = SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_BOARD_MASTER_NOT_FOUND; break; + default: fmt::throw_exception("Unexpected error in reply to GetBoardInfos: %d", static_cast(error)); + } + + if (error_code != CELL_OK) + { + std::lock_guard lock(score_trans->mutex); + score_trans->result = error_code; + score_trans->wake_cond.notify_one(); + return; + } const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to GetBoardInfos command"); + ensure(!reply.is_error(), "Malformed reply to GetBoardInfos command"); const SceNpScoreBoardInfo board_info{ .rankLimit = resp->rankLimit(), @@ -871,16 +966,6 @@ namespace np .uploadSizeLimit = resp->uploadSizeLimit() }; - std::lock_guard lock_trans(mutex_async_transactions); - if (!async_transactions.count(req_id)) - { - rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; - } - - auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); - ensure(score_trans); - std::lock_guard lock(score_trans->mutex); const auto* tdata = std::get_if(&score_trans->tdata); @@ -889,8 +974,6 @@ namespace np memcpy(reinterpret_cast(tdata->boardInfo.get_ptr()), &board_info, sizeof(SceNpScoreBoardInfo)); score_trans->result = CELL_OK; score_trans->wake_cond.notify_one(); - - return true; } void np_handler::record_score(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, vm::cptr scoreComment, const u8* data, u32 data_size, vm::ptr tmpRank, bool async) @@ -912,13 +995,13 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_record_score(u32 req_id, std::vector& reply_data) + void np_handler::reply_record_score(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); @@ -926,28 +1009,20 @@ namespace np std::lock_guard lock(score_trans->mutex); - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::ScoreNotBest: - { - score_trans->result = SCE_NP_COMMUNITY_SERVER_ERROR_NOT_BEST_SCORE; - score_trans->wake_cond.notify_one(); - return true; - } - default: return false; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::ScoreNotBest: + { + score_trans->result = SCE_NP_COMMUNITY_SERVER_ERROR_NOT_BEST_SCORE; + score_trans->wake_cond.notify_one(); + return; + } + default: fmt::throw_exception("Unexpected error in reply_record_score: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); auto tmp_rank = reply.get(); - - if (reply.is_error()) - { - rpcn_log.error("Error parsing response in reply_record_score"); - return false; - } + ensure(!reply.is_error(), "Error parsing response in reply_record_score"); const auto* tdata = std::get_if(&score_trans->tdata); ensure(tdata); @@ -959,7 +1034,6 @@ namespace np score_trans->result = CELL_OK; score_trans->wake_cond.notify_one(); - return true; } void np_handler::record_score_data(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, u32 totalSize, u32 sendSize, const u8* score_data, bool async) @@ -989,37 +1063,26 @@ namespace np } } - bool np_handler::reply_record_score_data(u32 req_id, std::vector& reply_data) + void np_handler::reply_record_score_data(u32 req_id, rpcn::ErrorType error) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto trans = ::at32(async_transactions, req_id); std::lock_guard lock(trans->mutex); - auto set_result_and_wake = [&](error_code err) -> bool + switch (error) { - trans->result = err; - trans->wake_cond.notify_one(); - return true; - }; - - if (rpcn::is_error(static_cast(reply_data[0]))) - { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_STORE_NOT_FOUND); - case rpcn::ErrorType::ScoreInvalid: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_SCORE); - case rpcn::ErrorType::ScoreHasData: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_GAME_DATA_ALREADY_EXISTS); - default: return false; - } + case rpcn::ErrorType::NoError: trans->set_result_and_wake(CELL_OK); break; + case rpcn::ErrorType::NotFound: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_STORE_NOT_FOUND); break; + case rpcn::ErrorType::ScoreInvalid: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_SCORE); break; + case rpcn::ErrorType::ScoreHasData: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_GAME_DATA_ALREADY_EXISTS); break; + default: fmt::throw_exception("Unexpected error in reply to RecordScoreData: %d", static_cast(error)); ; } - - return set_result_and_wake(CELL_OK); } void np_handler::get_score_data(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const SceNpId& npId, vm::ptr totalSize, u32 recvSize, vm::ptr score_data, bool async) @@ -1054,40 +1117,31 @@ namespace np trans_ctx->result = not_an_error(to_copy); } - bool np_handler::reply_get_score_data(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_score_data(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(score_trans); std::lock_guard lock(score_trans->mutex); - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: return score_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_GAME_DATA_MASTER_NOT_FOUND); - default: return false; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::NotFound: score_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_GAME_DATA_MASTER_NOT_FOUND); return; + default: fmt::throw_exception("Unexpected error in reply to GetScoreData: %d", static_cast(error)); ; } - vec_stream reply(reply_data, 1); - auto* tdata = std::get_if(&score_trans->tdata); ensure(tdata); tdata->game_data = reply.get_rawdata(); - - if (reply.is_error()) - { - rpcn_log.error("Error parsing response in reply_get_score_data"); - return false; - } + ensure(!reply.is_error(), "Error parsing response in reply_get_score_data"); tdata->game_data_size = ::size32(tdata->game_data); @@ -1096,7 +1150,7 @@ namespace np tdata->game_data.erase(tdata->game_data.begin(), tdata->game_data.begin() + to_copy); *tdata->totalSize = tdata->game_data_size; - return score_trans->set_result_and_wake(not_an_error(to_copy)); + score_trans->set_result_and_wake(not_an_error(to_copy)); } void np_handler::get_score_range(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreRankNumber startSerialRank, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) @@ -1144,32 +1198,27 @@ namespace np cur_rank.recordDate.tick = fb_rankdata->recordDate(); } - bool np_handler::handle_GetScoreResponse(u32 req_id, std::vector& reply_data, bool simple_result) + void np_handler::handle_GetScoreResponse(u32 req_id, rpcn::ErrorType error, vec_stream& reply, bool simple_result) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(score_trans); std::lock_guard lock(score_trans->mutex); - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - return false; + case rpcn::ErrorType::NoError: break; + default: fmt::throw_exception("Unexpected error in GetScoreResponse: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - { - rpcn_log.error("Error parsing response in handle_GetScoreResponse"); - return false; - } + ensure(!reply.is_error(), "Error parsing response in handle_GetScoreResponse"); const auto* tdata = std::get_if(&score_trans->tdata); ensure(tdata); @@ -1273,12 +1322,11 @@ namespace np score_trans->result = SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND; score_trans->wake_cond.notify_one(); - return true; } - bool np_handler::reply_get_score_range(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_score_range(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_GetScoreResponse(req_id, reply_data); + handle_GetScoreResponse(req_id, error, reply); } void np_handler::get_score_friend(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) @@ -1305,9 +1353,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_get_score_friends(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_score_friends(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_GetScoreResponse(req_id, reply_data); + handle_GetScoreResponse(req_id, error, reply); } void np_handler::get_score_npid(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const std::vector>& npid_vec, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) @@ -1334,76 +1382,57 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_get_score_npid(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_score_npid(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_GetScoreResponse(req_id, reply_data, true); + handle_GetScoreResponse(req_id, error, reply, true); } - bool np_handler::handle_tus_no_data(u32 req_id, std::vector& reply_data) + void np_handler::handle_tus_no_data(u32 req_id, rpcn::ErrorType error) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto trans = ::at32(async_transactions, req_id); std::lock_guard lock(trans->mutex); - auto set_result_and_wake = [&](error_code err) -> bool + switch (error) { - trans->result = err; - trans->wake_cond.notify_one(); - return true; - }; - - if (rpcn::is_error(static_cast(reply_data[0]))) - { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); - case rpcn::ErrorType::Unauthorized: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); - case rpcn::ErrorType::CondFail: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); - default: return false; - } + case rpcn::ErrorType::NoError: trans->set_result_and_wake(CELL_OK); break; + case rpcn::ErrorType::NotFound: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); break; + case rpcn::ErrorType::Unauthorized: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); break; + case rpcn::ErrorType::CondFail: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); break; + default: fmt::throw_exception("Unexpected error in handle_tus_no_data: %d", static_cast(error)); } - - return set_result_and_wake(CELL_OK); } - bool np_handler::handle_TusVarResponse(u32 req_id, std::vector& reply_data) + void np_handler::handle_TusVarResponse(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); - case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); - case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); - default: return false; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); + case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); + case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); + default: fmt::throw_exception("Unexpected error in handle_TusVarResponse: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - { - rpcn_log.error("Error parsing response in handle_TusVarResponse"); - return false; - } + ensure(!reply.is_error(), "Error parsing response in handle_TusVarResponse"); const auto* tdata = std::get_if(&tus_trans->tdata); ensure(tdata); @@ -1436,42 +1465,32 @@ namespace np tus_trans->result = not_an_error(fb_vars->size()); tus_trans->wake_cond.notify_one(); - - return true; } - bool np_handler::handle_TusVariable(u32 req_id, std::vector& reply_data) + void np_handler::handle_TusVariable(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); - case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); - case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); - default: return false; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); + case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); + case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); + default: fmt::throw_exception("Unexpected error in handle_TusVariable: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); const auto* fb_var = reply.get_flatbuffer(); - - if (reply.is_error()) - { - rpcn_log.error("Error parsing response in handle_TusVariable"); - return false; - } + ensure(!reply.is_error(), "Error parsing response in handle_TusVariable"); const auto* tdata = std::get_if(&tus_trans->tdata); ensure(tdata); @@ -1494,42 +1513,32 @@ namespace np tus_trans->result = CELL_OK; tus_trans->wake_cond.notify_one(); - - return true; } - bool np_handler::handle_TusDataStatusResponse(u32 req_id, std::vector& reply_data) + void np_handler::handle_TusDataStatusResponse(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); - case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); - case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); - default: return false; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); + case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); + case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); + default: fmt::throw_exception("Unexpected error in handle_TusDataStatusResponse: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - { - rpcn_log.error("Error parsing response in handle_TusDataStatusReponse"); - return false; - } + ensure(!reply.is_error(), "Error parsing response in handle_TusDataStatusReponse"); const auto* tdata = std::get_if(&tus_trans->tdata); ensure(tdata); @@ -1565,8 +1574,6 @@ namespace np tus_trans->result = not_an_error(fb_status->size()); tus_trans->wake_cond.notify_one(); - - return true; } void np_handler::tus_set_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::cptr variableArray, s32 arrayNum, bool vuser, bool async) @@ -1578,9 +1585,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_set_multislot_variable(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_set_multislot_variable(u32 req_id, rpcn::ErrorType error) { - return handle_tus_no_data(req_id, reply_data); + return handle_tus_no_data(req_id, error); } void np_handler::tus_get_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async) @@ -1597,9 +1604,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_get_multislot_variable(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_get_multislot_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusVarResponse(req_id, reply_data); + return handle_TusVarResponse(req_id, error, reply); } void np_handler::tus_get_multiuser_variable(shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async) @@ -1616,9 +1623,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_get_multiuser_variable(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_get_multiuser_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusVarResponse(req_id, reply_data); + return handle_TusVarResponse(req_id, error, reply); } void np_handler::tus_get_friends_variable(shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr variableArray,s32 arrayNum, bool async) @@ -1635,9 +1642,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_get_friends_variable(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_get_friends_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusVarResponse(req_id, reply_data); + return handle_TusVarResponse(req_id, error, reply); } void np_handler::tus_add_and_get_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s64 inVariable, vm::ptr outVariable, vm::ptr option, bool vuser, bool async) @@ -1653,9 +1660,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_add_and_get_variable(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_add_and_get_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusVariable(req_id, reply_data); + return handle_TusVariable(req_id, error, reply); } void np_handler::tus_try_and_set_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s32 opeType, s64 variable, vm::ptr resultVariable, vm::ptr option, bool vuser, bool async) @@ -1671,9 +1678,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_try_and_set_variable(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_try_and_set_variable(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusVariable(req_id, reply_data); + return handle_TusVariable(req_id, error, reply); } void np_handler::tus_delete_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async) @@ -1685,9 +1692,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_delete_multislot_variable(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_delete_multislot_variable(u32 req_id, rpcn::ErrorType error) { - return handle_tus_no_data(req_id, reply_data); + return handle_tus_no_data(req_id, error); } void np_handler::tus_set_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr data, vm::cptr info, vm::ptr option, bool vuser, bool async) @@ -1719,9 +1726,9 @@ namespace np } } - bool np_handler::reply_tus_set_data(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_set_data(u32 req_id, rpcn::ErrorType error) { - return handle_tus_no_data(req_id, reply_data); + return handle_tus_no_data(req_id, error); } void np_handler::tus_get_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, vm::ptr dataStatus, vm::ptr data, u32 recvSize, bool vuser, bool async) @@ -1754,45 +1761,38 @@ namespace np trans_ctx->result = not_an_error(to_copy); } - bool np_handler::reply_tus_get_data(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_get_data(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { std::lock_guard lock_trans(mutex_async_transactions); if (!async_transactions.count(req_id)) { rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id); - return false; + return; } auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (reply_data[0]) - { - case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); - case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); - case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); - default: return false; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); + case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); + case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); + default: fmt::throw_exception("Unexpected error in reply to TusGetData: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); const auto* fb_data = reply.get_flatbuffer(); - - if (reply.is_error()) - { - rpcn_log.error("Error parsing response in reply_tus_get_data"); - return false; - } + ensure(!reply.is_error(), "Error parsing response in reply_tus_get_data"); auto* tdata = std::get_if(&tus_trans->tdata); ensure(tdata); const auto* fb_status = fb_data->status(); ensure(fb_status && fb_status->ownerId()); - if (!fb_status) return false; // Sanity check to make compiler happy + if (!fb_status) + return; // Sanity check to make compiler happy auto* data_status = tdata->dataStatus.get_ptr(); auto* data = static_cast(tdata->data.get_ptr()); @@ -1833,7 +1833,6 @@ namespace np } tus_trans->wake_cond.notify_one(); - return true; } void np_handler::tus_get_multislot_data_status(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async) @@ -1850,9 +1849,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_get_multislot_data_status(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_get_multislot_data_status(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusDataStatusResponse(req_id, reply_data); + return handle_TusDataStatusResponse(req_id, error, reply); } void np_handler::tus_get_multiuser_data_status(shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async) @@ -1869,9 +1868,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_get_multiuser_data_status(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_get_multiuser_data_status(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusDataStatusResponse(req_id, reply_data); + return handle_TusDataStatusResponse(req_id, error, reply); } void np_handler::tus_get_friends_data_status(shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr statusArray, s32 arrayNum, bool async) @@ -1888,9 +1887,9 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_get_friends_data_status(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_get_friends_data_status(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { - return handle_TusDataStatusResponse(req_id, reply_data); + return handle_TusDataStatusResponse(req_id, error, reply); } void np_handler::tus_delete_multislot_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async) @@ -1902,8 +1901,8 @@ namespace np transaction_async_handler(std::move(lock), trans_ctx, req_id, async); } - bool np_handler::reply_tus_delete_multislot_data(u32 req_id, std::vector& reply_data) + void np_handler::reply_tus_delete_multislot_data(u32 req_id, rpcn::ErrorType error) { - return handle_tus_no_data(req_id, reply_data); + return handle_tus_no_data(req_id, error); } } // namespace np diff --git a/rpcs3/Emu/NP/np_requests_gui.cpp b/rpcs3/Emu/NP/np_requests_gui.cpp index 88d6a5b60f..8d5771dfcd 100644 --- a/rpcs3/Emu/NP/np_requests_gui.cpp +++ b/rpcs3/Emu/NP/np_requests_gui.cpp @@ -1,3 +1,4 @@ +#include "Emu/NP/rpcn_types.h" #include "stdafx.h" #include "Emu/Cell/PPUCallback.h" #include "Emu/Memory/vm_ptr.h" @@ -156,20 +157,16 @@ namespace np return CELL_OK; } - bool np_handler::reply_create_room_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_create_room_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - ensure(!rpcn::is_error(static_cast(reply_data[0])), "Unexpected error in CreateRoomGUI reply"); - - vec_stream reply(reply_data, 1); + ensure(error == rpcn::ErrorType::NoError, "Unexpected error in CreateRoomGUI reply"); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to CreateRoomGUI command"); + ensure(!reply.is_error(), "Malformed reply to CreateRoomGUI command"); event_data edata(np_memory.allocate(MAX_SceNpMatchingJoinedRoomInfo_SIZE), sizeof(SceNpMatchingJoinedRoomInfo), MAX_SceNpMatchingJoinedRoomInfo_SIZE); auto* room_info = reinterpret_cast(edata.data()); @@ -182,8 +179,6 @@ namespace np set_gui_result(SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM, std::move(edata)); ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM, 0); gui_epilog(ctx); - - return true; } error_code np_handler::join_room_gui(u32 ctx_id, vm::ptr roomid, vm::ptr handler, vm::ptr arg) @@ -201,44 +196,42 @@ namespace np return CELL_OK; } - bool np_handler::reply_join_room_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_join_room_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - if (rpcn::is_error(static_cast(reply_data[0]))) + s32 error_code = CELL_OK; + + switch (error) { - s32 error = -1; - - switch (static_cast(reply_data[0])) - { - case rpcn::ErrorType::RoomMissing: - error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; - break; - case rpcn::ErrorType::RoomFull: - // Might also be SCE_NP_MATCHING_SERVER_ERROR_ACCESS_FORBIDDEN or SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED ? - error = SCE_NP_MATCHING_SERVER_ERROR_ROOM_CLOSED; - break; - case rpcn::ErrorType::RoomAlreadyJoined: - error = SCE_NP_MATCHING_SERVER_ERROR_ACCESS_FORBIDDEN; - break; - default: - fmt::throw_exception("Unexpected error in JoinRoomGUI reply: %d", reply_data[0]); - break; - } - - ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_JOIN_ROOM, error); - gui_epilog(ctx); - return true; + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: + error_code = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; + break; + case rpcn::ErrorType::RoomFull: + // Might also be SCE_NP_MATCHING_SERVER_ERROR_ACCESS_FORBIDDEN or SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED ? + error_code = SCE_NP_MATCHING_SERVER_ERROR_ROOM_CLOSED; + break; + case rpcn::ErrorType::RoomAlreadyJoined: + error_code = SCE_NP_MATCHING_SERVER_ERROR_ACCESS_FORBIDDEN; + break; + default: + fmt::throw_exception("Unexpected error in JoinRoomGUI reply: %d", static_cast(error)); + break; } - vec_stream reply(reply_data, 1); - const auto* resp = reply.get_flatbuffer(); + if (error_code != 0) + { + ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_JOIN_ROOM, error_code); + gui_epilog(ctx); + return; + } - if (reply.is_error()) - return error_and_disconnect("Malformed reply to JoinRoomGUI command"); + const auto* resp = reply.get_flatbuffer(); + ensure(!reply.is_error(), "Malformed reply to JoinRoomGUI command"); event_data edata(np_memory.allocate(MAX_SceNpMatchingJoinedRoomInfo_SIZE), sizeof(SceNpMatchingJoinedRoomInfo), MAX_SceNpMatchingJoinedRoomInfo_SIZE); auto* room_info = reinterpret_cast(edata.data()); @@ -257,8 +250,6 @@ namespace np set_gui_result(SCE_NP_MATCHING_GUI_EVENT_JOIN_ROOM, std::move(edata)); ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_JOIN_ROOM, 0); gui_epilog(ctx); - - return true; } error_code np_handler::leave_room_gui(u32 ctx_id, vm::cptr roomid) @@ -278,36 +269,29 @@ namespace np return not_an_error(req_id); } - bool np_handler::reply_leave_room_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_leave_room_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - if (rpcn::is_error(static_cast(reply_data[0]))) + s32 error_code = CELL_OK; + + switch (error) { - s32 error = -1; - - switch (static_cast(reply_data[0])) - { - case rpcn::ErrorType::NotFound: - error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; - break; - default: - fmt::throw_exception("Unexpected error in LeaveRoomGUI reply: %d", reply_data[0]); - break; - } - - ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, error); - return true; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; break; + default: fmt::throw_exception("Unexpected error in LeaveRoomGUI reply: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); - const auto* resp = reply.get_flatbuffer(); + if (error_code != CELL_OK) + { + ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, error_code); + return; + } - if (reply.is_error()) - return error_and_disconnect("Malformed reply to LeaveRoomGUI command"); + const auto* resp = reply.get_flatbuffer(); + ensure(!reply.is_error(), "Malformed reply to LeaveRoomGUI command"); event_data edata(np_memory.allocate(MAX_SceNpMatchingRoomStatus_SIZE), sizeof(SceNpMatchingRoomStatus), MAX_SceNpMatchingRoomStatus_SIZE); auto* room_status = reinterpret_cast(edata.data()); @@ -320,7 +304,6 @@ namespace np gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, .edata = std::move(edata)}); ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, 0); - return true; } error_code np_handler::get_room_list_gui(u32 ctx_id, vm::cptr communicationId, vm::ptr range, vm::ptr cond, vm::ptr attr, vm::ptr handler, vm::ptr arg, bool limit) @@ -351,20 +334,16 @@ namespace np return CELL_OK; } - bool np_handler::reply_get_room_list_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_room_list_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - ensure(!rpcn::is_error(static_cast(reply_data[0])), "Unexpected error in GetRoomListGUI reply"); - - vec_stream reply(reply_data, 1); + ensure(error == rpcn::ErrorType::NoError, "Unexpected error in GetRoomListGUI reply"); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to GetRoomListGUI command"); + ensure(!reply.is_error(), "Malformed reply to GetRoomListGUI command"); event_data edata(np_memory.allocate(MAX_SceNpMatchingRoomList_SIZE), sizeof(SceNpMatchingRoomList), MAX_SceNpMatchingRoomList_SIZE); auto* room_list = reinterpret_cast(edata.data()); @@ -385,7 +364,6 @@ namespace np } gui_epilog(ctx); - return true; } error_code np_handler::set_room_search_flag_gui(u32 ctx_id, vm::ptr /* lobby_id */, vm::ptr room_id, s32 flag) @@ -405,33 +383,24 @@ namespace np return not_an_error(req_id); } - bool np_handler::reply_set_room_search_flag_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_set_room_search_flag_gui(u32 req_id, rpcn::ErrorType error) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - s32 error = 0; + s32 error_code = CELL_OK; - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (static_cast(reply_data[0])) - { - case rpcn::ErrorType::NotFound: - error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; - break; - case rpcn::ErrorType::Unauthorized: - error = SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED; - break; - default: - fmt::throw_exception("Unexpected error in SetRoomSearchFlagGUI reply: %d", reply_data[0]); - break; - } + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; break; + case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED; break; + default: fmt::throw_exception("Unexpected error in SetRoomSearchFlagGUI reply: %d", static_cast(error)); } - ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_SET_ROOM_SEARCH_FLAG_DONE, error); - return true; + ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_SET_ROOM_SEARCH_FLAG_DONE, error_code); } error_code np_handler::get_room_search_flag_gui(u32 ctx_id, vm::ptr /* lobby_id */, vm::ptr room_id) @@ -451,36 +420,30 @@ namespace np return not_an_error(req_id); } - bool np_handler::reply_get_room_search_flag_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_room_search_flag_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - if (rpcn::is_error(static_cast(reply_data[0]))) + s32 error_code = CELL_OK; + + switch (error) { - s32 error = -1; - - switch (static_cast(reply_data[0])) - { - case rpcn::ErrorType::NotFound: - error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; - break; - default: - fmt::throw_exception("Unexpected error in GetRoomSearchFlagGUI reply: %d", reply_data[0]); - break; - } - - ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, error); - return true; + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; break; + default: fmt::throw_exception("Unexpected error in GetRoomSearchFlagGUI reply: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); - const auto* resp = reply.get_flatbuffer(); + if (error_code != CELL_OK) + { + ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, error_code); + return; + } - if (reply.is_error()) - return error_and_disconnect("Malformed reply to GetRoomSearchFlagGUI command"); + const auto* resp = reply.get_flatbuffer(); + ensure(!reply.is_error(), "Malformed reply to GetRoomSearchFlagGUI command"); event_data edata(np_memory.allocate(MAX_SceNpMatchingRoom_SIZE), sizeof(SceNpMatchingRoom), MAX_SceNpMatchingRoom_SIZE); auto* room_info = reinterpret_cast(edata.data()); @@ -491,7 +454,6 @@ namespace np gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, .edata = std::move(edata)}); ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, 0); - return true; } error_code np_handler::set_room_info_gui(u32 ctx_id, vm::ptr /* lobby_id */, vm::ptr room_id, vm::ptr attr) @@ -516,33 +478,23 @@ namespace np return not_an_error(req_id); } - bool np_handler::reply_set_room_info_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_set_room_info_gui(u32 req_id, rpcn::ErrorType error) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - s32 error = 0; + s32 error_code = CELL_OK; - if (rpcn::is_error(static_cast(reply_data[0]))) + switch (error) { - switch (static_cast(reply_data[0])) - { - case rpcn::ErrorType::NotFound: - error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; - break; - case rpcn::ErrorType::Unauthorized: - error = SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED; - break; - default: - fmt::throw_exception("Unexpected error in SetRoomInfoGUI reply: %d", reply_data[0]); - break; - } + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; break; + case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED; break; + default: fmt::throw_exception("Unexpected error in SetRoomInfoGUI reply: %d", static_cast(error)); } - ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_SET_ROOM_INFO_DONE, error); - return true; + ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_SET_ROOM_INFO_DONE, error_code); } error_code np_handler::get_room_info_gui(u32 ctx_id, vm::ptr /* lobby_id */, vm::ptr room_id, vm::ptr attr) @@ -562,36 +514,30 @@ namespace np return not_an_error(req_id); } - bool np_handler::reply_get_room_info_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_get_room_info_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - if (rpcn::is_error(static_cast(reply_data[0]))) + s32 error_code = CELL_OK; + + switch (error) { - s32 error = -1; - - switch (static_cast(reply_data[0])) - { - case rpcn::ErrorType::NotFound: - error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; - break; - default: - fmt::throw_exception("Unexpected error in GetRoomInfoGUI reply: %d", reply_data[0]); - break; - } - - ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, error); - return true; + case rpcn::ErrorType::NoError: break; + case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM; break; + default: fmt::throw_exception("Unexpected error in GetRoomInfoGUI reply: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); - const auto* resp = reply.get_flatbuffer(); + if (error_code != CELL_OK) + { + ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, error_code); + return; + } - if (reply.is_error()) - return error_and_disconnect("Malformed reply to GetRoomInfoGUI command"); + const auto* resp = reply.get_flatbuffer(); + ensure(!reply.is_error(), "Malformed reply to GetRoomInfoGUI command"); event_data edata(np_memory.allocate(MAX_SceNpMatchingRoom_SIZE), sizeof(SceNpMatchingRoom), MAX_SceNpMatchingRoom_SIZE); auto* room_info = reinterpret_cast(edata.data()); @@ -602,7 +548,6 @@ namespace np gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, .edata = std::move(edata)}); ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, 0); - return true; } error_code np_handler::quickmatch_gui(u32 ctx_id, vm::cptr communicationId, vm::cptr cond, s32 available_num, s32 timeout, vm::ptr handler, vm::ptr arg) @@ -621,20 +566,16 @@ namespace np return CELL_OK; } - bool np_handler::reply_quickmatch_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_quickmatch_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - ensure(!rpcn::is_error(static_cast(reply_data[0])), "Unexpected error in QuickMatchGUI reply"); - - vec_stream reply(reply_data, 1); + ensure(error == rpcn::ErrorType::NoError, "Unexpected error in QuickMatchGUI reply"); const auto* resp = reply.get_flatbuffer(); - - if (reply.is_error()) - return error_and_disconnect("Malformed reply to QuickMatchGUI command"); + ensure(!reply.is_error(), "Malformed reply to QuickMatchGUI command"); SceNpRoomId room_id{}; ensure(resp->id() && resp->id()->size() == sizeof(SceNpRoomId::opt)); @@ -675,7 +616,6 @@ namespace np ctx->wakey = 0; auto& thread = *ctx->thread; thread(room_id); - return true; } error_code np_handler::searchjoin_gui(u32 ctx_id, vm::cptr communicationId, vm::cptr cond, vm::cptr attr, vm::ptr handler, vm::ptr arg) @@ -692,37 +632,30 @@ namespace np return CELL_OK; } - bool np_handler::reply_searchjoin_gui(u32 req_id, std::vector& reply_data) + void np_handler::reply_searchjoin_gui(u32 req_id, rpcn::ErrorType error, vec_stream& reply) { auto ctx = take_pending_gui_request(req_id); if (!ctx) - return true; + return; - if (rpcn::is_error(static_cast(reply_data[0]))) + s32 error_code = CELL_OK; + + switch (error) { - s32 error = -1; - - switch (static_cast(reply_data[0])) - { - case rpcn::ErrorType::NotFound: - error = SCE_NP_MATCHING_ERROR_SEARCH_JOIN_ROOM_NOT_FOUND; - break; - default: - fmt::throw_exception("Unexpected error in SearchJoinRoomGUI reply: %d", reply_data[0]); - break; - } - - ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_SEARCH_JOIN, error); - gui_epilog(ctx); - return true; + case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING_ERROR_SEARCH_JOIN_ROOM_NOT_FOUND; break; + default: fmt::throw_exception("Unexpected error in SearchJoinRoomGUI reply: %d", static_cast(error)); } - vec_stream reply(reply_data, 1); - const auto* resp = reply.get_flatbuffer(); + if (error_code != CELL_OK) + { + ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_SEARCH_JOIN, error_code); + gui_epilog(ctx); + return; + } - if (reply.is_error()) - return error_and_disconnect("Malformed reply to SearchJoinRoomGUI command"); + const auto* resp = reply.get_flatbuffer(); + ensure(!reply.is_error(), "Malformed reply to SearchJoinRoomGUI command"); event_data edata(np_memory.allocate(MAX_SceNpMatchingSearchJoinRoomInfo_SIZE), sizeof(SceNpMatchingSearchJoinRoomInfo), MAX_SceNpMatchingSearchJoinRoomInfo_SIZE); auto* room_info = reinterpret_cast(edata.data()); @@ -741,8 +674,6 @@ namespace np set_gui_result(SCE_NP_MATCHING_GUI_EVENT_SEARCH_JOIN, std::move(edata)); ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_SEARCH_JOIN, 0); gui_epilog(ctx); - - return true; } // Local cache requests diff --git a/rpcs3/Emu/NP/np_structs_extra.cpp b/rpcs3/Emu/NP/np_structs_extra.cpp index 87b49621fe..2acba3d045 100644 --- a/rpcs3/Emu/NP/np_structs_extra.cpp +++ b/rpcs3/Emu/NP/np_structs_extra.cpp @@ -1,3 +1,4 @@ +#include "Utilities/StrUtil.h" #include "stdafx.h" #include #include "np_structs_extra.h" @@ -117,9 +118,13 @@ namespace extra_nps print_SceNpMatching2BinAttr(&req->roomBinAttrExternal[i]); sceNp2.warning("roomPassword: *0x%x", req->roomPassword); + + if (req->roomPassword) + sceNp2.warning("data: %s", fmt::buf_to_hexstring(req->roomPassword->data, sizeof(req->roomPassword->data))); + sceNp2.warning("groupConfig: *0x%x", req->groupConfig); sceNp2.warning("groupConfigNum: %d", req->groupConfigNum); - sceNp2.warning("passwordSlotMask: *0x%x", req->passwordSlotMask); + sceNp2.warning("passwordSlotMask: *0x%x, value: 0x%x", req->passwordSlotMask, req->passwordSlotMask ? static_cast(*req->passwordSlotMask) : 0ull); sceNp2.warning("allowedUser: *0x%x", req->allowedUser); sceNp2.warning("allowedUserNum: %d", req->allowedUserNum); sceNp2.warning("blockedUser: *0x%x", req->blockedUser); diff --git a/rpcs3/Emu/NP/rpcn_client.cpp b/rpcs3/Emu/NP/rpcn_client.cpp index e61c9fea4f..0f0c9d871c 100644 --- a/rpcs3/Emu/NP/rpcn_client.cpp +++ b/rpcs3/Emu/NP/rpcn_client.cpp @@ -1,3 +1,5 @@ +#include "Emu/Cell/lv2/sys_net/sys_net_helpers.h" +#include "Emu/NP/ip_address.h" #include "stdafx.h" #include #include @@ -5,6 +7,7 @@ #include #include "rpcn_client.h" #include "Utilities/StrUtil.h" +#include "Utilities/StrFmt.h" #include "Utilities/Thread.h" #include "Emu/System.h" #include "Emu/NP/rpcn_config.h" @@ -42,6 +45,160 @@ LOG_CHANNEL(rpcn_log, "rpcn"); int get_native_error(); +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](auto value) + { + switch (value) + { + case rpcn::ErrorType::NoError: return "NoError"; + case rpcn::ErrorType::Malformed: return "Malformed"; + case rpcn::ErrorType::Invalid: return "Invalid"; + case rpcn::ErrorType::InvalidInput: return "InvalidInput"; + case rpcn::ErrorType::TooSoon: return "TooSoon"; + case rpcn::ErrorType::LoginError: return "LoginError"; + case rpcn::ErrorType::LoginAlreadyLoggedIn: return "LoginAlreadyLoggedIn"; + case rpcn::ErrorType::LoginInvalidUsername: return "LoginInvalidUsername"; + case rpcn::ErrorType::LoginInvalidPassword: return "LoginInvalidPassword"; + case rpcn::ErrorType::LoginInvalidToken: return "LoginInvalidToken"; + case rpcn::ErrorType::CreationError: return "CreationError"; + case rpcn::ErrorType::CreationExistingUsername: return "CreationExistingUsername"; + case rpcn::ErrorType::CreationBannedEmailProvider: return "CreationBannedEmailProvider"; + case rpcn::ErrorType::CreationExistingEmail: return "CreationExistingEmail"; + case rpcn::ErrorType::RoomMissing: return "RoomMissing"; + case rpcn::ErrorType::RoomAlreadyJoined: return "RoomAlreadyJoined"; + case rpcn::ErrorType::RoomFull: return "RoomFull"; + case rpcn::ErrorType::RoomPasswordMismatch: return "RoomPasswordMismatch"; + case rpcn::ErrorType::RoomPasswordMissing: return "RoomPasswordMissing"; + case rpcn::ErrorType::RoomGroupNoJoinLabel: return "RoomGroupNoJoinLabel"; + case rpcn::ErrorType::RoomGroupFull: return "RoomGroupFull"; + case rpcn::ErrorType::RoomGroupJoinLabelNotFound: return "RoomGroupJoinLabelNotFound"; + case rpcn::ErrorType::RoomGroupMaxSlotMismatch: return "RoomGroupMaxSlotMismatch"; + case rpcn::ErrorType::Unauthorized: return "Unauthorized"; + case rpcn::ErrorType::DbFail: return "DbFail"; + case rpcn::ErrorType::EmailFail: return "EmailFail"; + case rpcn::ErrorType::NotFound: return "NotFound"; + case rpcn::ErrorType::Blocked: return "Blocked"; + case rpcn::ErrorType::AlreadyFriend: return "AlreadyFriend"; + case rpcn::ErrorType::ScoreNotBest: return "ScoreNotBest"; + case rpcn::ErrorType::ScoreInvalid: return "ScoreInvalid"; + case rpcn::ErrorType::ScoreHasData: return "ScoreHasData"; + case rpcn::ErrorType::CondFail: return "CondFail"; + case rpcn::ErrorType::Unsupported: return "Unsupported"; + default: break; + } + + return unknown; + }); +} + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](auto value) + { + switch (value) + { + case rpcn::CommandType::Login: return "Login"; + case rpcn::CommandType::Terminate: return "Terminate"; + case rpcn::CommandType::Create: return "Create"; + case rpcn::CommandType::SendToken: return "SendToken"; + case rpcn::CommandType::SendResetToken: return "SendResetToken"; + case rpcn::CommandType::ResetPassword: return "ResetPassword"; + case rpcn::CommandType::ResetState: return "ResetState"; + case rpcn::CommandType::AddFriend: return "AddFriend"; + case rpcn::CommandType::RemoveFriend: return "RemoveFriend"; + case rpcn::CommandType::AddBlock: return "AddBlock"; + case rpcn::CommandType::RemoveBlock: return "RemoveBlock"; + case rpcn::CommandType::GetServerList: return "GetServerList"; + case rpcn::CommandType::GetWorldList: return "GetWorldList"; + case rpcn::CommandType::CreateRoom: return "CreateRoom"; + case rpcn::CommandType::JoinRoom: return "JoinRoom"; + case rpcn::CommandType::LeaveRoom: return "LeaveRoom"; + case rpcn::CommandType::SearchRoom: return "SearchRoom"; + case rpcn::CommandType::GetRoomDataExternalList: return "GetRoomDataExternalList"; + case rpcn::CommandType::SetRoomDataExternal: return "SetRoomDataExternal"; + case rpcn::CommandType::GetRoomDataInternal: return "GetRoomDataInternal"; + case rpcn::CommandType::SetRoomDataInternal: return "SetRoomDataInternal"; + case rpcn::CommandType::GetRoomMemberDataInternal: return "GetRoomMemberDataInternal"; + case rpcn::CommandType::SetRoomMemberDataInternal: return "SetRoomMemberDataInternal"; + case rpcn::CommandType::SetUserInfo: return "SetUserInfo"; + case rpcn::CommandType::PingRoomOwner: return "PingRoomOwner"; + case rpcn::CommandType::SendRoomMessage: return "SendRoomMessage"; + case rpcn::CommandType::RequestSignalingInfos: return "RequestSignalingInfos"; + case rpcn::CommandType::RequestTicket: return "RequestTicket"; + case rpcn::CommandType::SendMessage: return "SendMessage"; + case rpcn::CommandType::GetBoardInfos: return "GetBoardInfos"; + case rpcn::CommandType::RecordScore: return "RecordScore"; + case rpcn::CommandType::RecordScoreData: return "RecordScoreData"; + case rpcn::CommandType::GetScoreData: return "GetScoreData"; + case rpcn::CommandType::GetScoreRange: return "GetScoreRange"; + case rpcn::CommandType::GetScoreFriends: return "GetScoreFriends"; + case rpcn::CommandType::GetScoreNpid: return "GetScoreNpid"; + case rpcn::CommandType::GetNetworkTime: return "GetNetworkTime"; + case rpcn::CommandType::TusSetMultiSlotVariable: return "TusSetMultiSlotVariable"; + case rpcn::CommandType::TusGetMultiSlotVariable: return "TusGetMultiSlotVariable"; + case rpcn::CommandType::TusGetMultiUserVariable: return "TusGetMultiUserVariable"; + case rpcn::CommandType::TusGetFriendsVariable: return "TusGetFriendsVariable"; + case rpcn::CommandType::TusAddAndGetVariable: return "TusAddAndGetVariable"; + case rpcn::CommandType::TusTryAndSetVariable: return "TusTryAndSetVariable"; + case rpcn::CommandType::TusDeleteMultiSlotVariable: return "TusDeleteMultiSlotVariable"; + case rpcn::CommandType::TusSetData: return "TusSetData"; + case rpcn::CommandType::TusGetData: return "TusGetData"; + case rpcn::CommandType::TusGetMultiSlotDataStatus: return "TusGetMultiSlotDataStatus"; + case rpcn::CommandType::TusGetMultiUserDataStatus: return "TusGetMultiUserDataStatus"; + case rpcn::CommandType::TusGetFriendsDataStatus: return "TusGetFriendsDataStatus"; + case rpcn::CommandType::TusDeleteMultiSlotData: return "TusDeleteMultiSlotData"; + case rpcn::CommandType::SetPresence: return "SetPresence"; + case rpcn::CommandType::CreateRoomGUI: return "CreateRoomGUI"; + case rpcn::CommandType::JoinRoomGUI: return "JoinRoomGUI"; + case rpcn::CommandType::LeaveRoomGUI: return "LeaveRoomGUI"; + case rpcn::CommandType::GetRoomListGUI: return "GetRoomListGUI"; + case rpcn::CommandType::SetRoomSearchFlagGUI: return "SetRoomSearchFlagGUI"; + case rpcn::CommandType::GetRoomSearchFlagGUI: return "GetRoomSearchFlagGUI"; + case rpcn::CommandType::SetRoomInfoGUI: return "SetRoomInfoGUI"; + case rpcn::CommandType::GetRoomInfoGUI: return "GetRoomInfoGUI"; + case rpcn::CommandType::QuickMatchGUI: return "QuickMatchGUI"; + case rpcn::CommandType::SearchJoinRoomGUI: return "SearchJoinRoomGUI"; + } + + return unknown; + }); +} + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](auto value) + { + switch (value) + { + case rpcn::NotificationType::UserJoinedRoom: return "UserJoinedRoom"; + case rpcn::NotificationType::UserLeftRoom: return "UserLeftRoom"; + case rpcn::NotificationType::RoomDestroyed: return "RoomDestroyed"; + case rpcn::NotificationType::UpdatedRoomDataInternal: return "UpdatedRoomDataInternal"; + case rpcn::NotificationType::UpdatedRoomMemberDataInternal: return "UpdatedRoomMemberDataInternal"; + case rpcn::NotificationType::FriendQuery: return "FriendQuery"; + case rpcn::NotificationType::FriendNew: return "FriendNew"; + case rpcn::NotificationType::FriendLost: return "FriendLost"; + case rpcn::NotificationType::FriendStatus: return "FriendStatus"; + case rpcn::NotificationType::RoomMessageReceived: return "RoomMessageReceived"; + case rpcn::NotificationType::MessageReceived: return "MessageReceived"; + case rpcn::NotificationType::FriendPresenceChanged: return "FriendPresenceChanged"; + case rpcn::NotificationType::SignalingHelper: return "SignalingHelper"; + case rpcn::NotificationType::MemberJoinedRoomGUI: return "MemberJoinedRoomGUI"; + case rpcn::NotificationType::MemberLeftRoomGUI: return "MemberLeftRoomGUI"; + case rpcn::NotificationType::RoomDisappearedGUI: return "RoomDisappearedGUI"; + case rpcn::NotificationType::RoomOwnerChangedGUI: return "RoomOwnerChangedGUI"; + case rpcn::NotificationType::UserKickedGUI: return "UserKickedGUI"; + case rpcn::NotificationType::QuickMatchCompleteGUI: return "QuickMatchCompleteGUI"; + } + + return unknown; + }); +} + void vec_stream::dump() const { rpcn_log.error("vec_stream dump:\n%s", fmt::buf_to_hexstring(vec.data(), vec.size())); @@ -99,51 +256,64 @@ namespace rpcn rpcn_log.notice("online: %s, pr_com_id: %s, pr_title: %s, pr_status: %s, pr_comment: %s, pr_data: %s", online ? "true" : "false", pr_com_id.data, pr_title, pr_status, pr_comment, fmt::buf_to_hexstring(pr_data.data(), pr_data.size())); } - constexpr u32 RPCN_PROTOCOL_VERSION = 25; - constexpr usz RPCN_HEADER_SIZE = 15; + constexpr u32 RPCN_PROTOCOL_VERSION = 26; + constexpr usz RPCN_HEADER_SIZE = 15; - bool is_error(ErrorType err) + const char* error_to_explanation(rpcn::ErrorType error) { - if (err >= ErrorType::__error_last) + switch (error) { - rpcn_log.error("Invalid error returned!"); - return true; + case rpcn::ErrorType::NoError: return "No error"; + case rpcn::ErrorType::Malformed: return "Sent packet was malformed!"; + case rpcn::ErrorType::Invalid: return "Sent command was invalid!"; + case rpcn::ErrorType::InvalidInput: return "Sent data was invalid!"; + case rpcn::ErrorType::TooSoon: return "Request happened too soon!"; + case rpcn::ErrorType::LoginError: return "Unknown login error!"; + case rpcn::ErrorType::LoginAlreadyLoggedIn: return "User is already logged in!"; + case rpcn::ErrorType::LoginInvalidUsername: return "Login error: invalid username!"; + case rpcn::ErrorType::LoginInvalidPassword: return "Login error: invalid password!"; + case rpcn::ErrorType::LoginInvalidToken: return "Login error: invalid token!"; + case rpcn::ErrorType::CreationError: return "Error creating an account!"; + case rpcn::ErrorType::CreationExistingUsername: return "Error creating an account: existing username!"; + case rpcn::ErrorType::CreationBannedEmailProvider: return "Error creating an account: banned email provider!"; + case rpcn::ErrorType::CreationExistingEmail: return "Error creating an account: an account with that email already exist!"; + case rpcn::ErrorType::RoomMissing: return "User tried to join a non-existent room!"; + case rpcn::ErrorType::RoomAlreadyJoined: return "User has already joined!"; + case rpcn::ErrorType::RoomFull: return "User tried to join a full room!"; + case rpcn::ErrorType::RoomPasswordMismatch: return "Room password used was invalid"; + case rpcn::ErrorType::RoomPasswordMissing: return "Room password was missing during room creation"; + case rpcn::ErrorType::RoomGroupNoJoinLabel: return "Tried to join a group room without a label"; + case rpcn::ErrorType::RoomGroupFull: return "Room group is full"; + case rpcn::ErrorType::RoomGroupJoinLabelNotFound: return "Join label was invalid"; + case rpcn::ErrorType::RoomGroupMaxSlotMismatch: return "Mismatch between max_slot and the listed slots in groups"; + case rpcn::ErrorType::Unauthorized: return "User attempted an unauthorized operation!"; + case rpcn::ErrorType::DbFail: return "A db query failed on the server!"; + case rpcn::ErrorType::EmailFail: return "An email action failed on the server!"; + case rpcn::ErrorType::NotFound: return "A request replied not found!"; + case rpcn::ErrorType::Blocked: return "You're blocked!"; + case rpcn::ErrorType::AlreadyFriend: return "You're already friends!"; + case rpcn::ErrorType::ScoreNotBest: return "Attempted to register a score that is not better!"; + case rpcn::ErrorType::ScoreInvalid: return "Score for player was found but wasn't what was expected!"; + case rpcn::ErrorType::ScoreHasData: return "Score already has game data associated with it!"; + case rpcn::ErrorType::CondFail: return "Condition related to the query failed!"; + case rpcn::ErrorType::Unsupported: return "An unsupported operation was attempted!"; } - switch (err) - { - case NoError: return false; - case Malformed: rpcn_log.error("Sent packet was malformed!"); break; - case Invalid: rpcn_log.error("Sent command was invalid!"); break; - case InvalidInput: rpcn_log.error("Sent data was invalid!"); break; - case TooSoon: rpcn_log.error("Request happened too soon!"); break; - case LoginError: rpcn_log.error("Unknown login error!"); break; - case LoginAlreadyLoggedIn: rpcn_log.error("User is already logged in!"); break; - case LoginInvalidUsername: rpcn_log.error("Login error: invalid username!"); break; - case LoginInvalidPassword: rpcn_log.error("Login error: invalid password!"); break; - case LoginInvalidToken: rpcn_log.error("Login error: invalid token!"); break; - case CreationError: rpcn_log.error("Error creating an account!"); break; - case CreationExistingUsername: rpcn_log.error("Error creating an account: existing username!"); break; - case CreationBannedEmailProvider: rpcn_log.error("Error creating an account: banned email provider!"); break; - case CreationExistingEmail: rpcn_log.error("Error creating an account: an account with that email already exist!"); break; - case RoomMissing: rpcn_log.error("User tried to join a non-existent room!"); break; - case RoomAlreadyJoined: rpcn_log.error("User has already joined!"); break; - case RoomFull: rpcn_log.error("User tried to join a full room!"); break; - case Unauthorized: rpcn_log.error("User attempted an unauthorized operation!"); break; - case DbFail: rpcn_log.error("A db query failed on the server!"); break; - case EmailFail: rpcn_log.error("An email action failed on the server!"); break; - case NotFound: rpcn_log.error("A request replied not found!"); break; - case Blocked: rpcn_log.error("You're blocked!"); break; - case AlreadyFriend: rpcn_log.error("You're already friends!"); break; - case ScoreNotBest: rpcn_log.error("Attempted to register a score that is not better!"); break; - case ScoreInvalid: rpcn_log.error("Score for player was found but wasn't what was expected!"); break; - case ScoreHasData: rpcn_log.error("Score already has game data associated with it!"); break; - case CondFail: rpcn_log.error("Condition related to the query failed!"); break; - case Unsupported: rpcn_log.error("An unsupported operation was attempted!"); break; - default: rpcn_log.fatal("Unhandled ErrorType reached the switch?"); break; - } + fmt::throw_exception("Unknown error returned: %d", static_cast(error)); + } - return true; + void print_error(rpcn::CommandType command, rpcn::ErrorType error) + { + const std::string error_message = fmt::format("command: %s result: %s, explanation: %s", command, error, error_to_explanation(error)); + + if (error == rpcn::ErrorType::NoError) + { + rpcn_log.trace("%s", error_message); + } + else + { + rpcn_log.warning("%s", error_message); + } } // Constructor, destructor & singleton manager @@ -267,6 +437,10 @@ namespace rpcn { thread_base::set_name("RPCN Client"); + // UDP Signaling related + steady_clock::time_point last_ping_time_ipv4{}, last_pong_time_ipv4{}; + steady_clock::time_point last_ping_time_ipv6{}, last_pong_time_ipv6{}; + while (true) { sem_rpcn.acquire(); @@ -321,16 +495,15 @@ namespace rpcn if (authentified && !Emu.IsStopped()) { // Ping the UDP Signaling Server if we're authentified & ingame - auto now = steady_clock::now(); - - auto rpcn_msgs = get_rpcn_msgs(); + const auto now = steady_clock::now(); + const auto rpcn_msgs = get_rpcn_msgs(); for (const auto& msg : rpcn_msgs) { if (msg.size() == 6) { const u32 new_addr_sig = read_from_ptr>(&msg[0]); - const u32 new_port_sig = read_from_ptr>(&msg[4]); + const u16 new_port_sig = read_from_ptr>(&msg[4]); const u32 old_addr_sig = addr_sig; const u32 old_port_sig = port_sig; @@ -352,7 +525,16 @@ namespace rpcn } } - last_pong_time = now; + last_pong_time_ipv4 = now; + } + else if (msg.size() == 18) + { + // We don't really need ipv6 info stored so we just update the pong data + // std::array new_ipv6_addr; + // std::memcpy(new_ipv6_addr.data(), &msg[3], 16); + // const u32 new_ipv6_port = read_from_ptr>(&msg[16]); + + last_pong_time_ipv6 = now; } else { @@ -360,36 +542,64 @@ namespace rpcn } } - // Send a packet every 5 seconds and then every 500 ms until reply is received - if (now - last_pong_time >= 5s && now - last_ping_time > 500ms) + const std::chrono::nanoseconds time_since_last_ipv4_ping = now - last_ping_time_ipv4; + const std::chrono::nanoseconds time_since_last_ipv4_pong = now - last_pong_time_ipv4; + const std::chrono::nanoseconds time_since_last_ipv6_ping = now - last_ping_time_ipv6; + const std::chrono::nanoseconds time_since_last_ipv6_pong = now - last_pong_time_ipv6; + + auto forge_ping_packet = [&]() -> std::vector { std::vector ping(13); - ping[0] = 1; + ping[0] = 1; write_to_ptr>(ping, 1, user_id); write_to_ptr>(ping, 9, +local_addr_sig); - if (send_packet_from_p2p_port(ping, addr_rpcn_udp) == -1) - { - rpcn_log.error("Failed to send ping to RPCN!"); - } - last_ping_time = now; - } - else + return ping; + }; + + // Send a packet every 5 seconds and then every 500 ms until reply is received + if (time_since_last_ipv4_pong >= 5s && time_since_last_ipv4_ping > 500ms) + { + const auto ping = forge_ping_packet(); + + if (!send_packet_from_p2p_port_ipv4(ping, addr_rpcn_udp_ipv4)) + rpcn_log.error("Failed to send IPv4 ping to RPCN!"); + + last_ping_time_ipv4 = now; + continue; + } + + if (np::is_ipv6_supported() && time_since_last_ipv6_pong >= 5s && time_since_last_ipv6_ping > 500ms) + { + const auto ping = forge_ping_packet(); + + if (!send_packet_from_p2p_port_ipv6(ping, addr_rpcn_udp_ipv6)) + rpcn_log.error("Failed to send IPv6 ping to RPCN!"); + + last_ping_time_ipv6 = now; + continue; + } + + auto min_duration_for = [&](const auto last_ping_time, const auto last_pong_time) -> std::chrono::nanoseconds { - std::chrono::nanoseconds duration; if ((now - last_pong_time) < 5s) { - duration = 5s - (now - last_pong_time); + return (5s - (now - last_pong_time)); } else { - duration = 500ms - (now - last_ping_time); + return (500ms - (now - last_ping_time)); } + }; - if (!sem_rpcn.try_acquire_for(duration)) - { - // TODO - } + auto duration = min_duration_for(last_ping_time_ipv4, last_pong_time_ipv4); + + if (np::is_ipv6_supported()) + { + const auto duration_ipv6 = min_duration_for(last_ping_time_ipv6, last_pong_time_ipv6); + duration = std::min(duration, duration_ipv6); } + + sem_rpcn.try_acquire_for(duration); } } } @@ -410,10 +620,10 @@ namespace rpcn case recvn_result::recvn_terminate: return error_and_disconnect_notice("Recvn was forcefully aborted"); } - const u8 packet_type = header[0]; - const u16 command = read_from_ptr>(&header[1]); + const u8 packet_type = header[0]; + const auto command = static_cast(static_cast(read_from_ptr>(&header[1]))); const u32 packet_size = read_from_ptr>(&header[3]); - const u64 packet_id = read_from_ptr>(&header[7]); + const u64 packet_id = read_from_ptr>(&header[7]); if (packet_size < RPCN_HEADER_SIZE) return error_and_disconnect("Invalid packet size"); @@ -435,6 +645,13 @@ namespace rpcn if (data.empty()) return error_and_disconnect("Reply packet without result"); + // Internal commands without feedback + if (command == CommandType::ResetState) + { + ensure(data[0] == static_cast(ErrorType::NoError)); + break; + } + // Those commands are handled synchronously and won't be forwarded to NP Handler if (command == CommandType::Login || command == CommandType::GetServerList || command == CommandType::Create || command == CommandType::AddFriend || command == CommandType::RemoveFriend || @@ -463,7 +680,9 @@ namespace rpcn } case PacketType::Notification: { - switch (command) + auto notif_type = static_cast(command); + + switch (notif_type) { case NotificationType::FriendNew: case NotificationType::FriendLost: @@ -471,7 +690,7 @@ namespace rpcn case NotificationType::FriendStatus: case NotificationType::FriendPresenceChanged: { - handle_friend_notification(command, std::move(data)); + handle_friend_notification(notif_type, std::move(data)); break; } case NotificationType::MessageReceived: @@ -482,7 +701,7 @@ namespace rpcn default: { std::lock_guard lock(mutex_notifs); - notifications.emplace_back(std::make_pair(command, std::move(data))); + notifications.emplace_back(std::make_pair(notif_type, std::move(data))); break; } } @@ -493,7 +712,7 @@ namespace rpcn if (data.size() != 4) return error_and_disconnect("Invalid size of ServerInfo packet"); - received_version = reinterpret_cast&>(data[0]); + received_version = reinterpret_cast&>(data[0]); server_info_received = true; break; } @@ -623,7 +842,7 @@ namespace rpcn bool rpcn_client::send_packet(const std::vector& packet) { u32 num_timeouts = 0; - usz n_sent = 0; + usz n_sent = 0; while (n_sent != packet.size()) { if (terminate) @@ -682,7 +901,7 @@ namespace rpcn // Helper functions - bool rpcn_client::forge_send(u16 command, u64 packet_id, const std::vector& data) + bool rpcn_client::forge_send(rpcn::CommandType command, u64 packet_id, const std::vector& data) { // TODO: add a check for status? @@ -691,7 +910,7 @@ namespace rpcn return true; } - bool rpcn_client::forge_send_reply(u16 command, u64 packet_id, const std::vector& data, std::vector& reply_data) + bool rpcn_client::forge_send_reply(rpcn::CommandType command, u64 packet_id, const std::vector& data, std::vector& reply_data) { if (!forge_send(command, packet_id, data)) return false; @@ -738,8 +957,8 @@ namespace rpcn sockfd = 0; } - connected = false; - authentified = false; + connected = false; + authentified = false; server_info_received = false; } @@ -811,28 +1030,63 @@ namespace rpcn memset(&addr_rpcn, 0, sizeof(addr_rpcn)); - addr_rpcn.sin_port = std::bit_cast>(port); // htons + addr_rpcn.sin_port = std::bit_cast>(port); // htons addr_rpcn.sin_family = AF_INET; -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4996) -#endif - hostent* host_addr = gethostbyname(splithost[0].c_str()); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - if (!host_addr) + addrinfo* addr_info{}; + + if (getaddrinfo(splithost[0].c_str(), nullptr, nullptr, &addr_info)) { - rpcn_log.error("connect: Failed to resolve %s", host); + rpcn_log.error("connect: Failed to getaddrinfo %s", host); state = rpcn_state::failure_resolve; return false; } - addr_rpcn.sin_addr.s_addr = *reinterpret_cast(host_addr->h_addr_list[0]); + bool found_ipv4 = false, found_ipv6 = false; + addrinfo* found = addr_info; - memcpy(&addr_rpcn_udp, &addr_rpcn, sizeof(addr_rpcn_udp)); - addr_rpcn_udp.sin_port = std::bit_cast>(3657); // htons + while (found != nullptr) + { + switch (found->ai_family) + { + case AF_INET: + { + addr_rpcn.sin_addr = reinterpret_cast(found->ai_addr)->sin_addr; + found_ipv4 = true; + break; + } + case AF_INET6: + { + if (np::is_ipv6_supported()) + { + addr_rpcn_udp_ipv6.sin6_family = AF_INET6; + addr_rpcn_udp_ipv6.sin6_port = std::bit_cast>(3657); + addr_rpcn_udp_ipv6.sin6_addr = reinterpret_cast(found->ai_addr)->sin6_addr; + found_ipv6 = true; + } + break; + } + default: break; + } + + found = found->ai_next; + } + + if (!found_ipv4) + { + rpcn_log.error("connect: Failed to find IPv4 for %s", host); + state = rpcn_state::failure_resolve; + return false; + } + + if (np::is_ipv6_supported() && !found_ipv6) + { + rpcn_log.warning("IPv6 seems supported but no IPv6 could be found for the RPCN server, IPv6 is disabled!"); + is_ipv6_supported(np::IPV6_SUPPORT::IPV6_UNSUPPORTED); + } + + memcpy(&addr_rpcn_udp_ipv4, &addr_rpcn, sizeof(addr_rpcn_udp_ipv4)); + addr_rpcn_udp_ipv4.sin_port = std::bit_cast>(3657); // htons sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef _WIN32 @@ -926,10 +1180,6 @@ namespace rpcn } rpcn_log.notice("connect: Protocol version matches"); - - last_ping_time = steady_clock::now() - 5s; - last_pong_time = last_ping_time; - return true; } @@ -968,10 +1218,10 @@ namespace rpcn } vec_stream reply(packet_data); - auto error = static_cast(reply.get()); + auto error = static_cast(reply.get()); online_name = reply.get_string(false); - avatar_url = reply.get_string(false); - user_id = reply.get(); + avatar_url = reply.get_string(false); + user_id = reply.get(); auto get_usernames_and_status = [](vec_stream& stream, std::map& friends) { @@ -1016,15 +1266,15 @@ namespace rpcn get_usernames(reply, friend_infos.blocked); } - if (is_error(error)) + if (error != rpcn::ErrorType::NoError) { switch (error) { - case LoginError: state = rpcn_state::failure_id; break; - case LoginAlreadyLoggedIn: state = rpcn_state::failure_id_already_logged_in; break; - case LoginInvalidUsername: state = rpcn_state::failure_id_username; break; - case LoginInvalidPassword: state = rpcn_state::failure_id_password; break; - case LoginInvalidToken: state = rpcn_state::failure_id_token; break; + case rpcn::ErrorType::LoginError: state = rpcn_state::failure_id; break; + case rpcn::ErrorType::LoginAlreadyLoggedIn: state = rpcn_state::failure_id_already_logged_in; break; + case rpcn::ErrorType::LoginInvalidUsername: state = rpcn_state::failure_id_username; break; + case rpcn::ErrorType::LoginInvalidPassword: state = rpcn_state::failure_id_password; break; + case rpcn::ErrorType::LoginInvalidToken: state = rpcn_state::failure_id_token; break; default: state = rpcn_state::failure_id; break; } @@ -1056,6 +1306,15 @@ namespace rpcn return true; } + void rpcn_client::reset_state() + { + if (!connected || !authentified) + return; + + std::vector data; + forge_send(CommandType::ResetState, rpcn_request_counter.fetch_add(1), data); + } + ErrorType rpcn_client::create_user(std::string_view npid, std::string_view password, std::string_view online_name, std::string_view avatar_url, std::string_view email) { std::vector data; @@ -1082,14 +1341,12 @@ namespace rpcn vec_stream reply(packet_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error == rpcn::ErrorType::NoError) { - return error; + rpcn_log.success("You have successfully created a RPCN account(%s | %s)!", npid, online_name); } - rpcn_log.success("You have successfully created a RPCN account(%s | %s)!", npid, online_name); - - return ErrorType::NoError; + return error; } ErrorType rpcn_client::resend_token(const std::string& npid, const std::string& password) @@ -1117,14 +1374,12 @@ namespace rpcn vec_stream reply(packet_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error == rpcn::ErrorType::NoError) { - return error; + rpcn_log.success("Token has successfully been resent!"); } - rpcn_log.success("Token has successfully been resent!"); - - return ErrorType::NoError; + return error; } ErrorType rpcn_client::send_reset_token(std::string_view npid, std::string_view email) @@ -1152,14 +1407,12 @@ namespace rpcn vec_stream reply(packet_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error == rpcn::ErrorType::NoError) { - return error; + rpcn_log.success("Password reset token has successfully been sent!"); } - rpcn_log.success("Password reset token has successfully been sent!"); - - return ErrorType::NoError; + return error; } ErrorType rpcn_client::reset_password(std::string_view npid, std::string_view token, std::string_view password) @@ -1189,14 +1442,12 @@ namespace rpcn vec_stream reply(packet_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error == rpcn::ErrorType::NoError) { - return error; + rpcn_log.success("Password has successfully been reset!"); } - rpcn_log.success("Password has successfully been reset!"); - - return ErrorType::NoError; + return error; } bool rpcn_client::add_friend(const std::string& friend_username) @@ -1216,7 +1467,7 @@ namespace rpcn vec_stream reply(packet_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error != rpcn::ErrorType::NoError) { return false; } @@ -1242,7 +1493,7 @@ namespace rpcn vec_stream reply(packet_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error != rpcn::ErrorType::NoError) { return false; } @@ -1251,18 +1502,18 @@ namespace rpcn return true; } - std::vector>> rpcn_client::get_notifications() + std::vector>> rpcn_client::get_notifications() { std::lock_guard lock(mutex_notifs); - std::vector>> notifs = std::move(notifications); + auto notifs = std::move(notifications); notifications.clear(); return notifs; } - std::unordered_map>> rpcn_client::get_replies() + std::unordered_map>> rpcn_client::get_replies() { std::lock_guard lock(mutex_replies); - std::unordered_map>> ret_replies = std::move(replies); + auto ret_replies = std::move(replies); replies.clear(); return ret_replies; } @@ -1331,7 +1582,7 @@ namespace rpcn vec_stream reply(reply_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error != rpcn::ErrorType::NoError) { return false; } @@ -1364,7 +1615,7 @@ namespace rpcn vec_stream reply(reply_data); auto error = static_cast(reply.get()); - if (is_error(error)) + if (error != rpcn::ErrorType::NoError) { return 0; } @@ -1380,7 +1631,6 @@ namespace rpcn return network_time; } - bool rpcn_client::get_world_list(u32 req_id, const SceNpCommunicationId& communication_id, u16 server_id) { std::vector data(COMMUNICATION_ID_SIZE + sizeof(u16)); @@ -1447,7 +1697,7 @@ namespace rpcn std::vector> davec; for (u32 i = 0; i < req->groupConfigNum; i++) { - auto bin = CreateGroupConfig(builder, req->groupConfig[i].slotNum, req->groupConfig[i].withLabel, builder.CreateVector(req->groupConfig[i].label.data, 8), req->groupConfig[i].withPassword); + auto bin = CreateGroupConfig(builder, req->groupConfig[i].slotNum, req->groupConfig[i].withLabel ? builder.CreateVector(req->groupConfig[i].label.data, 8) : 0, req->groupConfig[i].withPassword); davec.push_back(bin); } final_groupconfigs_vec = builder.CreateVector(davec); @@ -1549,7 +1799,7 @@ namespace rpcn { flatbuffers::FlatBufferBuilder builder(1024); flatbuffers::Offset final_optdata = CreatePresenceOptionData(builder, builder.CreateVector(req->optData.data, 16), req->optData.length); - auto req_finished = CreateLeaveRoomRequest(builder, req->roomId, final_optdata); + auto req_finished = CreateLeaveRoomRequest(builder, req->roomId, final_optdata); builder.Finish(req_finished); return forge_request_with_com_id(builder, communication_id, CommandType::LeaveRoom, req_id); @@ -1565,7 +1815,7 @@ namespace rpcn for (u32 i = 0; i < req->intFilterNum; i++) { auto int_attr = CreateIntAttr(builder, req->intFilter[i].attr.id, req->intFilter[i].attr.num); - auto bin = CreateIntSearchFilter(builder, req->intFilter[i].searchOperator, int_attr); + auto bin = CreateIntSearchFilter(builder, req->intFilter[i].searchOperator, int_attr); davec.push_back(bin); } final_intfilter_vec = builder.CreateVector(davec); @@ -1577,7 +1827,7 @@ namespace rpcn for (u32 i = 0; i < req->binFilterNum; i++) { auto bin_attr = CreateBinAttr(builder, req->binFilter[i].attr.id, builder.CreateVector(req->binFilter[i].attr.ptr.get_ptr(), req->binFilter[i].attr.size)); - auto bin = CreateBinSearchFilter(builder, req->binFilter[i].searchOperator, bin_attr); + auto bin = CreateBinSearchFilter(builder, req->binFilter[i].searchOperator, bin_attr); davec.push_back(bin); } final_binfilter_vec = builder.CreateVector(davec); @@ -1892,7 +2142,7 @@ namespace rpcn auto fb_sendmessage = CreateSendMessageRequest(builder, nested_flatbuffer_vector, npids_vector); builder.Finish(fb_sendmessage); - const u8* buf = builder.GetBufferPointer(); + const u8* buf = builder.GetBufferPointer(); const usz bufsize = builder.GetSize(); std::vector data(bufsize + sizeof(u32)); @@ -1963,7 +2213,7 @@ namespace rpcn auto req_finished = CreateRecordScoreGameDataRequest(builder, board_id, pc_id, score); builder.Finish(req_finished); - const u8* buf = builder.GetBufferPointer(); + const u8* buf = builder.GetBufferPointer(); const usz bufsize = builder.GetSize(); std::vector data(COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize + sizeof(u32) + score_data.size()); @@ -2385,11 +2635,7 @@ namespace rpcn num = cur_attr->value.num; break; } - default: - { - fmt::throw_exception("Invalid attr type reached set_room_info_gui"); - break; - } + default: fmt::throw_exception("Invalid attr type reached set_room_info_gui"); } auto fb_attr = CreateMatchingAttr(builder, cur_attr->type, cur_attr->id, num, fb_vec_data); @@ -2468,7 +2714,7 @@ namespace rpcn bool rpcn_client::forge_request_with_com_id(const flatbuffers::FlatBufferBuilder& builder, const SceNpCommunicationId& com_id, CommandType command, u64 packet_id) { - const u8* buf = builder.GetBufferPointer(); + const u8* buf = builder.GetBufferPointer(); const usz bufsize = builder.GetSize(); std::vector data(COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize); @@ -2492,13 +2738,13 @@ namespace rpcn return forge_send(command, packet_id, data); } - std::vector rpcn_client::forge_request(u16 command, u64 packet_id, const std::vector& data) const + std::vector rpcn_client::forge_request(rpcn::CommandType command, u64 packet_id, const std::vector& data) const { const usz packet_size = data.size() + RPCN_HEADER_SIZE; std::vector packet(packet_size); - packet[0] = PacketType::Request; - reinterpret_cast&>(packet[1]) = command; + packet[0] = static_cast(PacketType::Request); + reinterpret_cast&>(packet[1]) = static_cast(command); reinterpret_cast&>(packet[3]) = ::narrow(packet_size); reinterpret_cast&>(packet[7]) = packet_id; @@ -2601,11 +2847,10 @@ namespace rpcn } } - void rpcn_client::handle_friend_notification(u16 command, std::vector data) + void rpcn_client::handle_friend_notification(rpcn::NotificationType ntype, std::vector data) { std::lock_guard lock(mutex_friends); - NotificationType ntype = static_cast(command); vec_stream vdata(data); const auto call_callbacks = [&](NotificationType ntype, const std::string& username, bool status) @@ -2666,7 +2911,7 @@ namespace rpcn case NotificationType::FriendStatus: // Set status of friend to Offline or Online { const bool online = !!vdata.get(); - const u64 timestamp = vdata.get(); + const u64 timestamp = vdata.get(); const std::string username = vdata.get_string(false); if (vdata.is_error()) { @@ -2740,7 +2985,7 @@ namespace rpcn // Unserialize the message vec_stream sdata(data); std::string sender = sdata.get_string(false); - auto* fb_mdata = sdata.get_flatbuffer(); + auto* fb_mdata = sdata.get_flatbuffer(); if (sdata.is_error()) { @@ -2755,12 +3000,12 @@ namespace rpcn } message_data mdata = { - .msgId = message_counter, - .mainType = fb_mdata->mainType(), - .subType = fb_mdata->subType(), + .msgId = message_counter, + .mainType = fb_mdata->mainType(), + .subType = fb_mdata->subType(), .msgFeatures = fb_mdata->msgFeatures(), - .subject = fb_mdata->subject()->str(), - .body = fb_mdata->body()->str()}; + .subject = fb_mdata->subject()->str(), + .body = fb_mdata->body()->str()}; strcpy_trunc(mdata.commId.data, fb_mdata->communicationId()->str()); mdata.data.assign(fb_mdata->data()->Data(), fb_mdata->data()->Data() + fb_mdata->data()->size()); @@ -2769,7 +3014,7 @@ namespace rpcn { std::lock_guard lock(mutex_messages); const u64 msg_id = message_counter++; - auto id_and_msg = stx::make_shared>(std::make_pair(std::move(sender), std::move(mdata))); + auto id_and_msg = stx::make_shared>(std::make_pair(std::move(sender), std::move(mdata))); messages.emplace(msg_id, id_and_msg); new_messages.push_back(msg_id); active_messages.insert(msg_id); @@ -2805,7 +3050,7 @@ namespace rpcn for (auto id : active_messages) { const auto& entry = ::at32(messages, id); - const auto& msg = entry->second; + const auto& msg = entry->second; if (msg.mainType == type_filter && (include_bootable || !(msg.msgFeatures & SCE_NP_BASIC_MESSAGE_FEATURES_BOOTABLE))) { vec_messages.push_back(std::make_pair(id, entry)); @@ -2813,9 +3058,9 @@ namespace rpcn } message_cbs.insert(message_cb_t{ - .cb_func = cb_func, - .cb_param = cb_param, - .type_filter = type_filter, + .cb_func = cb_func, + .cb_param = cb_param, + .type_filter = type_filter, .inc_bootable = include_bootable, }); } diff --git a/rpcs3/Emu/NP/rpcn_client.h b/rpcs3/Emu/NP/rpcn_client.h index e3c9fbec3a..2ada34b581 100644 --- a/rpcs3/Emu/NP/rpcn_client.h +++ b/rpcs3/Emu/NP/rpcn_client.h @@ -30,12 +30,15 @@ #ifdef __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wextern-c-compat" #endif #include #ifdef __clang__ #pragma GCC diagnostic pop #endif +#include "rpcn_types.h" + // COMID is sent as 9 chars - + '_' + 2 digits constexpr usz COMMUNICATION_ID_COMID_COMPONENT_SIZE = 9; constexpr usz COMMUNICATION_ID_SUBID_COMPONENT_SIZE = 2; @@ -180,153 +183,6 @@ protected: namespace rpcn { - enum CommandType : u16 - { - Login, - Terminate, - Create, - SendToken, - SendResetToken, - ResetPassword, - AddFriend, - RemoveFriend, - AddBlock, - RemoveBlock, - GetServerList, - GetWorldList, - CreateRoom, - JoinRoom, - LeaveRoom, - SearchRoom, - GetRoomDataExternalList, - SetRoomDataExternal, - GetRoomDataInternal, - SetRoomDataInternal, - GetRoomMemberDataInternal, - SetRoomMemberDataInternal, - SetUserInfo, - PingRoomOwner, - SendRoomMessage, - RequestSignalingInfos, - RequestTicket, - SendMessage, - GetBoardInfos, - RecordScore, - RecordScoreData, - GetScoreData, - GetScoreRange, - GetScoreFriends, - GetScoreNpid, - GetNetworkTime, - TusSetMultiSlotVariable, - TusGetMultiSlotVariable, - TusGetMultiUserVariable, - TusGetFriendsVariable, - TusAddAndGetVariable, - TusTryAndSetVariable, - TusDeleteMultiSlotVariable, - TusSetData, - TusGetData, - TusGetMultiSlotDataStatus, - TusGetMultiUserDataStatus, - TusGetFriendsDataStatus, - TusDeleteMultiSlotData, - ClearPresence, - SetPresence, - CreateRoomGUI, - JoinRoomGUI, - LeaveRoomGUI, - GetRoomListGUI, - SetRoomSearchFlagGUI, - GetRoomSearchFlagGUI, - SetRoomInfoGUI, - GetRoomInfoGUI, - QuickMatchGUI, - SearchJoinRoomGUI, - }; - - enum NotificationType : u16 - { - UserJoinedRoom, - UserLeftRoom, - RoomDestroyed, - UpdatedRoomDataInternal, - UpdatedRoomMemberDataInternal, - SignalP2PConnect, - _SignalP2PDisconnect, - FriendQuery, // Other user sent a friend request - FriendNew, // Add a friend to the friendlist(either accepted a friend request or friend accepted it) - FriendLost, // Remove friend from the friendlist(user removed friend or friend removed friend) - FriendStatus, // Set status of friend to Offline or Online - RoomMessageReceived, - MessageReceived, - FriendPresenceChanged, - SignalingInfo, - MemberJoinedRoomGUI, - MemberLeftRoomGUI, - RoomDisappearedGUI, - RoomOwnerChangedGUI, - UserKickedGUI, - QuickMatchCompleteGUI, - }; - - enum class rpcn_state - { - failure_no_failure, - failure_input, - failure_wolfssl, - failure_resolve, - failure_connect, - failure_id, - failure_id_already_logged_in, - failure_id_username, - failure_id_password, - failure_id_token, - failure_protocol, - failure_other, - }; - - enum PacketType : u8 - { - Request, - Reply, - Notification, - ServerInfo, - }; - - enum ErrorType : u8 - { - NoError, // No error - Malformed, // Query was malformed, critical error that should close the connection - Invalid, // The request type is invalid(wrong stage?) - InvalidInput, // The Input doesn't fit the constraints of the request - TooSoon, // Time limited operation attempted too soon - LoginError, // An error happened related to login - LoginAlreadyLoggedIn, // Can't log in because you're already logged in - LoginInvalidUsername, // Invalid username - LoginInvalidPassword, // Invalid password - LoginInvalidToken, // Invalid token - CreationError, // An error happened related to account creation - CreationExistingUsername, // Specific to Account Creation: username exists already - CreationBannedEmailProvider, // Specific to Account Creation: the email provider is banned - CreationExistingEmail, // Specific to Account Creation: that email is already registered to an account - RoomMissing, // User tried to join a non existing room - RoomAlreadyJoined, // User tried to join a room he's already part of - RoomFull, // User tried to join a full room - Unauthorized, // User attempted an unauthorized operation - DbFail, // Generic failure on db side - EmailFail, // Generic failure related to email - NotFound, // Object of the query was not found(room, user, etc) - Blocked, // The operation can't complete because you've been blocked - AlreadyFriend, // Can't add friend because already friend - ScoreNotBest, // A better score is already registered for that user/character_id - ScoreInvalid, // Score for player was found but wasn't what was expected - ScoreHasData, // Score already has data - CondFail, // Condition related to query failed - Unsupported, - __error_last - }; - using friend_cb_func = void (*)(void* param, NotificationType ntype, const std::string& username, bool status); using message_cb_func = void (*)(void* param, const shared_ptr> new_msg, u64 msg_id); @@ -359,7 +215,7 @@ namespace rpcn localized_string_id rpcn_state_to_localized_string_id(rpcn::rpcn_state state); std::string rpcn_state_to_string(rpcn::rpcn_state state); - bool is_error(ErrorType err); + void print_error(rpcn::CommandType command, rpcn::ErrorType error); class rpcn_client { @@ -392,7 +248,7 @@ namespace rpcn std::set> friend_cbs; friend_data friend_infos; - void handle_friend_notification(u16 command, std::vector data); + void handle_friend_notification(rpcn::NotificationType ntype, std::vector data); void handle_message(std::vector data); @@ -435,6 +291,7 @@ namespace rpcn rpcn_state wait_for_connection(); rpcn_state wait_for_authentified(); bool terminate_connection(); + void reset_state(); void get_friends(friend_data& friend_infos); void get_friends_and_register_cb(friend_data& friend_infos, friend_cb_func cb_func, void* cb_param); @@ -454,8 +311,8 @@ namespace rpcn std::optional> get_friend_presence_by_index(u32 index); std::optional> get_friend_presence_by_npid(const std::string& npid); - std::vector>> get_notifications(); - std::unordered_map>> get_replies(); + std::vector>> get_notifications(); + std::unordered_map>> get_replies(); std::unordered_map get_presence_updates(); std::map get_presence_states(); @@ -537,11 +394,11 @@ namespace rpcn static void write_communication_id(const SceNpCommunicationId& com_id, std::vector& data); - std::vector forge_request(u16 command, u64 packet_id, const std::vector& data) const; - bool forge_send(u16 command, u64 packet_id, const std::vector& data); + std::vector forge_request(rpcn::CommandType command, u64 packet_id, const std::vector& data) const; + bool forge_send(rpcn::CommandType command, u64 packet_id, const std::vector& data); bool forge_request_with_com_id(const flatbuffers::FlatBufferBuilder& builder, const SceNpCommunicationId& com_id, CommandType command, u64 packet_id); bool forge_request_with_data(const flatbuffers::FlatBufferBuilder& builder, CommandType command, u64 packet_id); - bool forge_send_reply(u16 command, u64 packet_id, const std::vector& data, std::vector& reply_data); + bool forge_send_reply(rpcn::CommandType command, u64 packet_id, const std::vector& data, std::vector& reply_data); bool error_and_disconnect(const std::string& error_mgs); bool error_and_disconnect_notice(const std::string& error_msg); @@ -556,11 +413,9 @@ namespace rpcn atomic_t server_info_received = false; u32 received_version = 0; - // UDP Signaling related - steady_clock::time_point last_ping_time{}, last_pong_time{}; - sockaddr_in addr_rpcn{}; - sockaddr_in addr_rpcn_udp{}; + sockaddr_in addr_rpcn_udp_ipv4{}; + sockaddr_in6 addr_rpcn_udp_ipv6{}; #ifdef _WIN32 SOCKET sockfd = 0; #else @@ -570,10 +425,10 @@ namespace rpcn atomic_t rpcn_request_counter = 0x100000001; // Counter used for commands whose result is not forwarded to NP handler(login, create, sendmessage, etc) shared_mutex mutex_notifs, mutex_replies, mutex_replies_sync, mutex_presence_updates; - std::vector>> notifications; // notif type / data - std::unordered_map>> replies; // req id / (command / data) - std::unordered_map>> replies_sync; // same but for sync replies(see handle_input()) - std::unordered_map presence_updates; // npid / presence data + std::vector>> notifications; // notif type / data + std::unordered_map>> replies; // req id / (command / data) + std::unordered_map>> replies_sync; // same but for sync replies(see handle_input()) + std::unordered_map presence_updates; // npid / presence data // Messages struct message_cb_t diff --git a/rpcs3/Emu/NP/rpcn_config.cpp b/rpcs3/Emu/NP/rpcn_config.cpp index 1f52d60a05..a112084da7 100644 --- a/rpcs3/Emu/NP/rpcn_config.cpp +++ b/rpcs3/Emu/NP/rpcn_config.cpp @@ -124,6 +124,11 @@ std::string cfg_rpcn::get_token() const return token.to_string(); } +bool cfg_rpcn::get_ipv6_support() const +{ + return ipv6_support.get(); +} + void cfg_rpcn::set_host(std::string_view host) { this->host.from_string(host); @@ -144,6 +149,11 @@ void cfg_rpcn::set_token(std::string_view token) this->token.from_string(token); } +void cfg_rpcn::set_ipv6_support(bool ipv6_support) +{ + this->ipv6_support.set(ipv6_support); +} + void cfg_rpcn::set_hosts(const std::vector>& vec_hosts) { std::string final_string; diff --git a/rpcs3/Emu/NP/rpcn_config.h b/rpcs3/Emu/NP/rpcn_config.h index b03bdd3acb..7c1317fbe0 100644 --- a/rpcs3/Emu/NP/rpcn_config.h +++ b/rpcs3/Emu/NP/rpcn_config.h @@ -10,6 +10,7 @@ struct cfg_rpcn : cfg::node cfg::string password{this, "Password", ""}; cfg::string token{this, "Token", ""}; cfg::string hosts{this, "Hosts", "Official RPCN Server|np.rpcs3.net|||RPCN Test Server|test-np.rpcs3.net"}; + cfg::_bool ipv6_support{this, "IPv6 support", true}; void load(); void save() const; @@ -18,12 +19,14 @@ struct cfg_rpcn : cfg::node std::string get_npid(); // not const because it can save if npid is requested and it has never been set std::string get_password() const; std::string get_token() const; + bool get_ipv6_support() const; std::vector> get_hosts(); // saves default if no valid server in the list void set_host(std::string_view host); void set_npid(std::string_view npid); void set_password(std::string_view password); void set_token(std::string_view token); + void set_ipv6_support(bool ipv6_support); bool add_host(std::string_view description, std::string_view host); bool del_host(std::string_view description, std::string_view host); diff --git a/rpcs3/Emu/NP/rpcn_types.h b/rpcs3/Emu/NP/rpcn_types.h new file mode 100644 index 0000000000..1e9fb9acf4 --- /dev/null +++ b/rpcs3/Emu/NP/rpcn_types.h @@ -0,0 +1,156 @@ +#pragma once + +#include "util/types.hpp" + +namespace rpcn +{ + enum class CommandType : u16 + { + Login, + Terminate, + Create, + SendToken, + SendResetToken, + ResetPassword, + ResetState, + AddFriend, + RemoveFriend, + AddBlock, + RemoveBlock, + GetServerList, + GetWorldList, + CreateRoom, + JoinRoom, + LeaveRoom, + SearchRoom, + GetRoomDataExternalList, + SetRoomDataExternal, + GetRoomDataInternal, + SetRoomDataInternal, + GetRoomMemberDataInternal, + SetRoomMemberDataInternal, + SetUserInfo, + PingRoomOwner, + SendRoomMessage, + RequestSignalingInfos, + RequestTicket, + SendMessage, + GetBoardInfos, + RecordScore, + RecordScoreData, + GetScoreData, + GetScoreRange, + GetScoreFriends, + GetScoreNpid, + GetNetworkTime, + TusSetMultiSlotVariable, + TusGetMultiSlotVariable, + TusGetMultiUserVariable, + TusGetFriendsVariable, + TusAddAndGetVariable, + TusTryAndSetVariable, + TusDeleteMultiSlotVariable, + TusSetData, + TusGetData, + TusGetMultiSlotDataStatus, + TusGetMultiUserDataStatus, + TusGetFriendsDataStatus, + TusDeleteMultiSlotData, + SetPresence, + CreateRoomGUI, + JoinRoomGUI, + LeaveRoomGUI, + GetRoomListGUI, + SetRoomSearchFlagGUI, + GetRoomSearchFlagGUI, + SetRoomInfoGUI, + GetRoomInfoGUI, + QuickMatchGUI, + SearchJoinRoomGUI, + }; + + enum class NotificationType : u16 + { + UserJoinedRoom, + UserLeftRoom, + RoomDestroyed, + UpdatedRoomDataInternal, + UpdatedRoomMemberDataInternal, + FriendQuery, // Other user sent a friend request + FriendNew, // Add a friend to the friendlist(either accepted a friend request or friend accepted it) + FriendLost, // Remove friend from the friendlist(user removed friend or friend removed friend) + FriendStatus, // Set status of friend to Offline or Online + RoomMessageReceived, + MessageReceived, + FriendPresenceChanged, + SignalingHelper, + MemberJoinedRoomGUI, + MemberLeftRoomGUI, + RoomDisappearedGUI, + RoomOwnerChangedGUI, + UserKickedGUI, + QuickMatchCompleteGUI, + }; + + enum class rpcn_state + { + failure_no_failure, + failure_input, + failure_wolfssl, + failure_resolve, + failure_connect, + failure_id, + failure_id_already_logged_in, + failure_id_username, + failure_id_password, + failure_id_token, + failure_protocol, + failure_other, + }; + + enum class PacketType : u8 + { + Request, + Reply, + Notification, + ServerInfo, + }; + + enum class ErrorType : u8 + { + NoError, // No error + Malformed, // Query was malformed, critical error that should close the connection + Invalid, // The request type is invalid(wrong stage?) + InvalidInput, // The Input doesn't fit the constraints of the request + TooSoon, // Time limited operation attempted too soon + LoginError, // An error happened related to login + LoginAlreadyLoggedIn, // Can't log in because you're already logged in + LoginInvalidUsername, // Invalid username + LoginInvalidPassword, // Invalid password + LoginInvalidToken, // Invalid token + CreationError, // An error happened related to account creation + CreationExistingUsername, // Specific to Account Creation: username exists already + CreationBannedEmailProvider, // Specific to Account Creation: the email provider is banned + CreationExistingEmail, // Specific to Account Creation: that email is already registered to an account + RoomMissing, // User tried to interact with a non existing room + RoomAlreadyJoined, // User tried to join a room he's already part of + RoomFull, // User tried to join a full room + RoomPasswordMismatch, // Room password didn't match + RoomPasswordMissing, // A password was missing during room creation + RoomGroupNoJoinLabel, // Tried to join a group room without a label + RoomGroupFull, // Room group is full + RoomGroupJoinLabelNotFound, // Join label was invalid in some way + RoomGroupMaxSlotMismatch, // Mismatch between max_slot and the listed slots in groups + Unauthorized, // User attempted an unauthorized operation + DbFail, // Generic failure on db side + EmailFail, // Generic failure related to email + NotFound, // Object of the query was not found(user, etc), use RoomMissing for rooms instead + Blocked, // The operation can't complete because you've been blocked + AlreadyFriend, // Can't add friend because already friend + ScoreNotBest, // A better score is already registered for that user/character_id + ScoreInvalid, // Score for player was found but wasn't what was expected + ScoreHasData, // Score already has data + CondFail, // Condition related to query failed + Unsupported, + }; +} // namespace rpcn diff --git a/rpcs3/Emu/NP/signaling_handler.cpp b/rpcs3/Emu/NP/signaling_handler.cpp index 0ff4a37388..2e4ac5df56 100644 --- a/rpcs3/Emu/NP/signaling_handler.cpp +++ b/rpcs3/Emu/NP/signaling_handler.cpp @@ -1,3 +1,4 @@ +#include "Emu/NP/ip_address.h" #include "stdafx.h" #include "Emu/Cell/PPUCallback.h" #include "signaling_handler.h" @@ -547,6 +548,13 @@ void signaling_handler::update_si_mapped_addr(std::shared_ptr& s { ensure(si); + // If the address given to us by op is a translation IP, just replace it with our public ip(v4) + if (np::is_ipv6_supported() && np::ip_address_translator::is_ipv6(new_addr)) + { + auto& nph = g_fxo->get>(); + new_addr = nph.get_public_ip_addr(); + } + if (si->mapped_addr != new_addr || si->mapped_port != new_port) { if (sign_log.trace) @@ -640,7 +648,15 @@ void signaling_handler::send_signaling_packet(signaling_packet& sp, u32 addr, u1 sign_log.trace("Sending %s packet to %s:%d", sp.command, ip_str, port); - if (send_packet_from_p2p_port(packet, dest) == -1) + if (np::is_ipv6_supported() && np::ip_address_translator::is_ipv6(dest.sin_addr.s_addr)) + { + auto& translator = g_fxo->get(); + const auto addr6 = translator.get_ipv6_sockaddr(dest.sin_addr.s_addr, dest.sin_port); + + if (!send_packet_from_p2p_port_ipv6(packet, addr6)) + sign_log.error("Failed to send signaling packet to %s:%d", ip_str, port); + } + else if (!send_packet_from_p2p_port_ipv4(packet, dest)) { sign_log.error("Failed to send signaling packet to %s:%d", ip_str, port); } diff --git a/rpcs3/Emu/NP/vport0.h b/rpcs3/Emu/NP/vport0.h index a3ca3bbdf3..927e1a5390 100644 --- a/rpcs3/Emu/NP/vport0.h +++ b/rpcs3/Emu/NP/vport0.h @@ -10,7 +10,8 @@ #include "Emu/Cell/lv2/sys_net/nt_p2p_port.h" -s32 send_packet_from_p2p_port(const std::vector& data, const sockaddr_in& addr); +bool send_packet_from_p2p_port_ipv4(const std::vector& data, const sockaddr_in& addr); +bool send_packet_from_p2p_port_ipv6(const std::vector& data, const sockaddr_in6& addr); std::vector get_sign_msgs(); std::vector> get_rpcn_msgs(); diff --git a/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.cpp b/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.cpp index 25588d3e5f..aed778e6da 100644 --- a/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.cpp +++ b/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.cpp @@ -383,7 +383,7 @@ namespace rsx } } - void sendmessage_dialog::callback_handler(u16 ntype, const std::string& username, bool status) + void sendmessage_dialog::callback_handler(rpcn::NotificationType ntype, const std::string& username, bool status) { std::lock_guard lock(m_mutex); diff --git a/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.h b/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.h index 2e4b09422e..508d296fc4 100644 --- a/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.h +++ b/rpcs3/Emu/RSX/Overlays/Network/overlay_sendmessage_dialog.h @@ -40,7 +40,7 @@ namespace rsx compiled_resource get_compiled() override; error_code Exec(message_data& msg_data, std::set& npids) override; - void callback_handler(u16 ntype, const std::string& username, bool status) override; + void callback_handler(rpcn::NotificationType ntype, const std::string& username, bool status) override; }; } } diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index f3e3b31f42..9459ba698d 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -267,7 +267,7 @@ enum class np_internet_status enabled, }; -enum np_psn_status +enum class np_psn_status { disabled, psn_fake, diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 07ca501ff3..9a916678ae 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -175,6 +175,7 @@ + @@ -618,6 +619,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index cf3626a7f5..de42637d4c 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1029,6 +1029,9 @@ Emu\NP + + Emu\NP + Emu\NP @@ -2683,6 +2686,9 @@ Emu\NP + + Emu\NP + Emu\GPU\RSX\Core diff --git a/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp b/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp index dfa9b49060..86691e4bc0 100644 --- a/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp @@ -7,12 +7,14 @@ #include #include #include +#include #include "qt_utils.h" #include "rpcn_settings_dialog.h" #include "Emu/System.h" #include "Emu/NP/rpcn_config.h" +#include "Emu/NP/ip_address.h" #include #include @@ -160,6 +162,9 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent) QPushButton* btn_test = new QPushButton(tr("Test Account")); QLabel* label_npid = new QLabel(); + QCheckBox* checkbox_disable_ipv6 = new QCheckBox("Disable IPv6"); + checkbox_disable_ipv6->setCheckState(g_cfg_rpcn.get_ipv6_support() ? Qt::Unchecked : Qt::Checked); + const auto update_npid_label = [label_npid]() { const std::string npid = g_cfg_rpcn.get_npid(); @@ -178,6 +183,7 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent) grp_buttons->setLayout(vbox_buttons); vbox_global->addWidget(grp_buttons); + vbox_global->addWidget(checkbox_disable_ipv6); setLayout(vbox_global); @@ -193,6 +199,10 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent) g_cfg_rpcn.set_host(host.toString().toStdString()); g_cfg_rpcn.save(); + + // Resets the state in case the support was limited by the RPCN server + if (!np::is_ipv6_supported()) + np::is_ipv6_supported(np::IPV6_SUPPORT::IPV6_UNKNOWN); }); connect(btn_add_server, &QAbstractButton::clicked, this, [this]() @@ -333,6 +343,12 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent) QMessageBox::information(this, tr("RPCN Account Valid!"), tr("Your account is valid!"), QMessageBox::Ok); }); + + connect(checkbox_disable_ipv6, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state) + { + g_cfg_rpcn.set_ipv6_support(state == Qt::Unchecked); + g_cfg_rpcn.save(); + }); } void rpcn_account_dialog::refresh_combobox() diff --git a/rpcs3/rpcs3qt/sendmessage_dialog_frame.cpp b/rpcs3/rpcs3qt/sendmessage_dialog_frame.cpp index 8e2350a790..7f794b67f2 100644 --- a/rpcs3/rpcs3qt/sendmessage_dialog_frame.cpp +++ b/rpcs3/rpcs3qt/sendmessage_dialog_frame.cpp @@ -156,7 +156,7 @@ void sendmessage_dialog_frame::slot_remove_friend(QString name) remove_friend(m_lst_friends, name); } -void sendmessage_dialog_frame::callback_handler(u16 ntype, const std::string& username, bool status) +void sendmessage_dialog_frame::callback_handler(rpcn::NotificationType ntype, const std::string& username, bool status) { QString qtr_username = QString::fromStdString(username); switch (ntype) diff --git a/rpcs3/rpcs3qt/sendmessage_dialog_frame.h b/rpcs3/rpcs3qt/sendmessage_dialog_frame.h index 40da17f5c0..d4aad5cd5d 100644 --- a/rpcs3/rpcs3qt/sendmessage_dialog_frame.h +++ b/rpcs3/rpcs3qt/sendmessage_dialog_frame.h @@ -16,7 +16,7 @@ public: sendmessage_dialog_frame() = default; ~sendmessage_dialog_frame(); error_code Exec(message_data& msg_data, std::set& npids) override; - void callback_handler(u16 ntype, const std::string& username, bool status) override; + void callback_handler(rpcn::NotificationType ntype, const std::string& username, bool status) override; private: void add_friend(QListWidget* list, const QString& name);