ggpo: report UDP bind error. Better error reporting for net init

fix ggpo lib warnings
This commit is contained in:
Flyinghead 2021-09-30 17:24:17 +02:00
parent 699dcdaf5b
commit a6248905a0
10 changed files with 85 additions and 55 deletions

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -53,7 +53,6 @@ protected:
// state management
Callbacks *_callbacks;
Poll *_poll;
};
#endif

View File

@ -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 &current = _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);

View File

@ -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<bool> 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())

View File

@ -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");
}

View File

@ -43,6 +43,7 @@ private:
char lanAddress[32];
char wanAddress[32];
std::vector<std::pair<std::string, bool>> mappedPorts;
bool initialized = false;
};
#else

View File

@ -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();