diff --git a/core/deps/ggpo/include/ggponet.h b/core/deps/ggpo/include/ggponet.h index 39ed8fe9c..6da009ff5 100644 --- a/core/deps/ggpo/include/ggponet.h +++ b/core/deps/ggpo/include/ggponet.h @@ -113,7 +113,8 @@ typedef struct GGPOLocalEndpoint { GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_PLAYER_DISCONNECTED, 9) \ GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_TOO_MANY_SPECTATORS, 10) \ GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INVALID_REQUEST, 11) \ - GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_SIZE_DIFF, 12) + GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_SIZE_DIFF, 12) \ + GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_NETWORK_ERROR, 13) #define GGPO_ERRORLIST_ENTRY(name, value) name = value, typedef enum { diff --git a/core/deps/ggpo/lib/ggpo/backends/p2p.cpp b/core/deps/ggpo/lib/ggpo/backends/p2p.cpp index 88feacd60..4650c8b63 100644 --- a/core/deps/ggpo/lib/ggpo/backends/p2p.cpp +++ b/core/deps/ggpo/lib/ggpo/backends/p2p.cpp @@ -18,13 +18,14 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb, uint16 localport, int num_players, int input_size) : - _num_players(num_players), - _input_size(input_size), _sync(_local_connect_status), - _disconnect_timeout(DEFAULT_DISCONNECT_TIMEOUT), - _disconnect_notify_start(DEFAULT_DISCONNECT_NOTIFY_START), + _endpoints(nullptr), _num_spectators(0), - _next_spectator_frame(0) + _input_size(input_size), + _num_players(num_players), + _next_spectator_frame(0), + _disconnect_timeout(DEFAULT_DISCONNECT_TIMEOUT), + _disconnect_notify_start(DEFAULT_DISCONNECT_NOTIFY_START) { _callbacks = *cb; _synchronizing = true; @@ -47,7 +48,7 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb, _endpoints = new UdpProtocol[_num_players]; memset(_local_connect_status, 0, sizeof(_local_connect_status)); - for (int i = 0; i < ARRAY_SIZE(_local_connect_status); i++) { + for (unsigned i = 0; i < ARRAY_SIZE(_local_connect_status); i++) { _local_connect_status[i].last_frame = -1; } @@ -386,6 +387,9 @@ Peer2PeerBackend::OnUdpProtocolPeerEvent(UdpProtocol::Event &evt, int queue) case UdpProtocol::Event::Disconnected: DisconnectPlayer(QueueToPlayerHandle(queue)); break; + + default: + break; } } @@ -396,17 +400,14 @@ Peer2PeerBackend::OnUdpProtocolSpectatorEvent(UdpProtocol::Event &evt, int queue GGPOPlayerHandle handle = QueueToSpectatorHandle(queue); OnUdpProtocolEvent(evt, handle); - GGPOEvent info; - - switch (evt.type) { - case UdpProtocol::Event::Disconnected: + if (evt.type == UdpProtocol::Event::Disconnected) + { _spectators[queue].Disconnect(); + GGPOEvent info; info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER; info.u.disconnected.player = handle; _callbacks.on_event(&info); - - break; } } @@ -448,6 +449,9 @@ Peer2PeerBackend::OnUdpProtocolEvent(UdpProtocol::Event &evt, GGPOPlayerHandle h info.u.connection_resumed.player = handle; _callbacks.on_event(&info); break; + + default: + break; } } diff --git a/core/deps/ggpo/lib/ggpo/backends/spectator.cpp b/core/deps/ggpo/lib/ggpo/backends/spectator.cpp index 18e313045..7fe0688f8 100644 --- a/core/deps/ggpo/lib/ggpo/backends/spectator.cpp +++ b/core/deps/ggpo/lib/ggpo/backends/spectator.cpp @@ -155,12 +155,17 @@ SpectatorBackend::OnUdpProtocolEvent(UdpProtocol::Event &evt) break; case UdpProtocol::Event::Input: - GameInput& input = evt.u.input.input; + { + GameInput& input = evt.u.input.input; - _host.SetLocalFrameNumber(input.frame); - _host.SendInputAck(); - _inputs[input.frame % SPECTATOR_FRAME_BUFFER_SIZE] = input; + _host.SetLocalFrameNumber(input.frame); + _host.SendInputAck(); + _inputs[input.frame % SPECTATOR_FRAME_BUFFER_SIZE] = input; + } break; + + default: + break; } } diff --git a/core/deps/ggpo/lib/ggpo/network/udp.cpp b/core/deps/ggpo/lib/ggpo/network/udp.cpp index 5b5fbc421..5b3686937 100644 --- a/core/deps/ggpo/lib/ggpo/network/udp.cpp +++ b/core/deps/ggpo/lib/ggpo/network/udp.cpp @@ -60,12 +60,12 @@ void Udp::Init(uint16 port, Poll *poll, Callbacks *callbacks) { _callbacks = callbacks; - - _poll = poll; - _poll->RegisterLoop(this); + poll->RegisterLoop(this); Log("binding udp socket to port %d.\n", port); _socket = CreateSocket(port, 0); + if (_socket == INVALID_SOCKET) + throw GGPOException("Socket creation or bind failed", GGPO_ERRORCODE_NETWORK_ERROR); } void diff --git a/core/deps/ggpo/lib/ggpo/network/udp.h b/core/deps/ggpo/lib/ggpo/network/udp.h index 529313851..f0ab0f6f1 100644 --- a/core/deps/ggpo/lib/ggpo/network/udp.h +++ b/core/deps/ggpo/lib/ggpo/network/udp.h @@ -53,7 +53,6 @@ protected: // state management Callbacks *_callbacks; - Poll *_poll; }; #endif diff --git a/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp b/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp index 77ffc5e09..c206ce41b 100644 --- a/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp +++ b/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp @@ -22,24 +22,24 @@ static const int UDP_SHUTDOWN_TIMER = 5000; static const int MAX_SEQ_DISTANCE = (1 << 15); UdpProtocol::UdpProtocol() : - _local_frame_advantage(0), - _remote_frame_advantage(0), - _queue(-1), + _udp(NULL), _magic_number(0), + _queue(-1), _remote_magic_number(0), + _connected(false), _packets_sent(0), _bytes_sent(0), _stats_start_time(0), + _local_frame_advantage(0), + _remote_frame_advantage(0), _last_send_time(0), _shutdown_timeout(0), + _disconnect_event_sent(false), _disconnect_timeout(0), _disconnect_notify_start(0), _disconnect_notify_sent(false), - _disconnect_event_sent(false), - _connected(false), _next_send_seq(0), - _next_recv_seq(0), - _udp(NULL) + _next_recv_seq(0) { _last_sent_input.init(-1, NULL, 1); _last_received_input.init(-1, NULL, 1); @@ -47,7 +47,7 @@ UdpProtocol::UdpProtocol() : memset(&_state, 0, sizeof _state); memset(_peer_connect_status, 0, sizeof(_peer_connect_status)); - for (int i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) { + for (unsigned i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) { _peer_connect_status[i].last_frame = -1; } memset(&_peer_addr, 0, sizeof _peer_addr); @@ -123,7 +123,7 @@ UdpProtocol::SendPendingOutput() msg->u.input.start_frame = _pending_output.front().frame; msg->u.input.input_size = (uint8)_pending_output.front().size; - ASSERT(last.frame == -1 || last.frame + 1 == msg->u.input.start_frame); + ASSERT(last.frame == -1 || last.frame + 1 == (int)msg->u.input.start_frame); for (j = 0; j < _pending_output.size(); j++) { GameInput ¤t = _pending_output.item(j); if (memcmp(current.bits, last.bits, current.size) != 0) { @@ -249,7 +249,10 @@ UdpProtocol::OnLoopPoll(void *cookie) _udp = NULL; _shutdown_timeout = 0; } + break; + default: + break; } @@ -455,11 +458,8 @@ UdpProtocol::LogMsg(const char *prefix, UdpMsg *msg) void UdpProtocol::LogEvent(const char *prefix, const UdpProtocol::Event &evt) { - switch (evt.type) { - case UdpProtocol::Event::Synchronzied: + if (evt.type == UdpProtocol::Event::Synchronzied) Log("%s (event: Synchronzied).\n", prefix); - break; - } } bool @@ -545,7 +545,7 @@ UdpProtocol::OnInput(UdpMsg *msg, int len) * of the network. */ UdpMsg::connect_status* remote_status = msg->u.input.peer_connect_status; - for (int i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) { + for (unsigned i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) { ASSERT(remote_status[i].last_frame >= _peer_connect_status[i].last_frame); _peer_connect_status[i].disconnected = _peer_connect_status[i].disconnected || remote_status[i].disconnected; _peer_connect_status[i].last_frame = MAX(_peer_connect_status[i].last_frame, remote_status[i].last_frame); @@ -734,7 +734,7 @@ UdpProtocol::PumpSendQueue() // should really come up with a gaussian distributation based on the configured // value, but this will do for now. int jitter = (_send_latency * 2 / 3) + ((rand() % _send_latency) / 3); - if (Platform::GetCurrentTimeMS() < _send_queue.front().queue_time + jitter) { + if ((int)Platform::GetCurrentTimeMS() < _send_queue.front().queue_time + jitter) { break; } } @@ -754,7 +754,7 @@ UdpProtocol::PumpSendQueue() } _send_queue.pop(); } - if (_oo_packet.msg && _oo_packet.send_time < Platform::GetCurrentTimeMS()) { + if (_oo_packet.msg && _oo_packet.send_time < (int)Platform::GetCurrentTimeMS()) { Log("sending rogue oop!"); _udp->SendTo((char *)_oo_packet.msg, _oo_packet.msg->PacketSize(), 0, (struct sockaddr *)&_oo_packet.dest_addr, sizeof _oo_packet.dest_addr); diff --git a/core/network/ggpo.cpp b/core/network/ggpo.cpp index 8111f4f94..5482e8a82 100644 --- a/core/network/ggpo.cpp +++ b/core/network/ggpo.cpp @@ -375,7 +375,7 @@ void startSession(int localPort, int localPlayerNum) { WARN_LOG(NETWORK, "GGPO start sync session failed: %d", result); ggpoSession = nullptr; - return; + throw FlycastException("GGPO start sync session failed"); } ggpo_idle(ggpoSession, 0); ggpo::localPlayerNum = localPlayerNum; @@ -413,7 +413,7 @@ void startSession(int localPort, int localPlayerNum) { WARN_LOG(NETWORK, "GGPO start session failed: %d", result); ggpoSession = nullptr; - return; + throw FlycastException("GGPO network initialization failed"); } // automatically disconnect clients after 3000 ms and start our count-down timer @@ -429,7 +429,7 @@ void startSession(int localPort, int localPlayerNum) { WARN_LOG(NETWORK, "GGPO cannot add local player: %d", result); stopSession(); - return; + throw FlycastException("GGPO cannot add local player"); } ggpo_set_frame_delay(ggpoSession, localPlayer, config::GGPODelay.get()); @@ -458,6 +458,7 @@ void startSession(int localPort, int localPlayerNum) { WARN_LOG(NETWORK, "GGPO cannot add remote player: %d", result); stopSession(); + throw FlycastException("GGPO cannot add remote player"); } DEBUG_LOG(NETWORK, "GGPO session started"); #endif @@ -616,11 +617,16 @@ std::future startNetwork() miniupnp.Init(); miniupnp.AddPortMapping(SERVER_PORT, false); - if (config::ActAsServer) - startSession(SERVER_PORT, 0); - else - // Use SERVER_PORT-1 as local port if connecting to ourselves - startSession(config::NetworkServer.get().empty() || config::NetworkServer.get() == "127.0.0.1" ? SERVER_PORT - 1 : SERVER_PORT, 1); + try { + if (config::ActAsServer) + startSession(SERVER_PORT, 0); + else + // Use SERVER_PORT-1 as local port if connecting to ourselves + startSession(config::NetworkServer.get().empty() || config::NetworkServer.get() == "127.0.0.1" ? SERVER_PORT - 1 : SERVER_PORT, 1); + } catch (...) { + miniupnp.Term(); + throw; + } #endif } while (!synchronized && active()) diff --git a/core/network/miniupnp.cpp b/core/network/miniupnp.cpp index 2c83f5ebd..a605854da 100644 --- a/core/network/miniupnp.cpp +++ b/core/network/miniupnp.cpp @@ -49,6 +49,7 @@ bool MiniUPnP::Init() return false; } wanAddress[0] = 0; + initialized = true; if (UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, wanAddress) != 0) WARN_LOG(NETWORK, "Cannot determine external IP address"); DEBUG_LOG(NETWORK, "MiniUPnP: public IP is %s", wanAddress); @@ -57,12 +58,15 @@ bool MiniUPnP::Init() void MiniUPnP::Term() { + if (!initialized) + return; DEBUG_LOG(NETWORK, "MiniUPnP::Term"); for (const auto& port : mappedPorts) UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.first.c_str(), port.second ? "TCP" : "UDP", nullptr); mappedPorts.clear(); FreeUPNPUrls(&urls); + initialized = false; DEBUG_LOG(NETWORK, "MiniUPnP: terminated"); } diff --git a/core/network/miniupnp.h b/core/network/miniupnp.h index 6a8968c02..7490d2847 100644 --- a/core/network/miniupnp.h +++ b/core/network/miniupnp.h @@ -43,6 +43,7 @@ private: char lanAddress[32]; char wanAddress[32]; std::vector> mappedPorts; + bool initialized = false; }; #else diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 08a342680..0101e4439 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -2194,15 +2194,22 @@ static void gui_network_start() if (networkStatus.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) { - if (networkStatus.get()) - { - gui_state = GuiState::Closed; - ImGui::Text("STARTING..."); - } - else - { + try { + if (networkStatus.get()) + { + gui_state = GuiState::Closed; + ImGui::Text("STARTING..."); + } + else + { + gui_state = GuiState::Main; + emu.unloadGame(); + } + } catch (const FlycastException& e) { + NetworkHandshake::instance->stop(); gui_state = GuiState::Main; - settings.content.path.clear(); + emu.unloadGame(); + error_msg = e.what(); } } else @@ -2219,9 +2226,12 @@ static void gui_network_start() if (ImGui::Button("Cancel", ImVec2(100.f * scaling, 0.f))) { NetworkHandshake::instance->stop(); - networkStatus.get(); + try { + networkStatus.get(); + } catch (const FlycastException& e) { + } gui_state = GuiState::Main; - settings.content.path.clear(); + emu.unloadGame(); } ImGui::PopStyleVar();