ggpo: detect input size mismatch and abort gracefully
This commit is contained in:
parent
3b7a940e9b
commit
4c53fcecfa
|
@ -112,7 +112,8 @@ typedef struct GGPOLocalEndpoint {
|
|||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_DROPPED, 8) \
|
||||
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_INVALID_REQUEST, 11) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_SIZE_DIFF, 12)
|
||||
|
||||
#define GGPO_ERRORLIST_ENTRY(name, value) name = value,
|
||||
typedef enum {
|
||||
|
|
|
@ -35,6 +35,17 @@ typedef char int8;
|
|||
typedef short int16;
|
||||
typedef int int32;
|
||||
|
||||
#include "ggponet.h"
|
||||
#include <stdexcept>
|
||||
|
||||
class GGPOException : public std::runtime_error {
|
||||
public:
|
||||
GGPOException(const std::string& what, GGPOErrorCode ggpoError)
|
||||
: std::runtime_error(what), ggpoError(ggpoError) {}
|
||||
|
||||
GGPOErrorCode ggpoError;
|
||||
};
|
||||
|
||||
/*
|
||||
* Additional headers
|
||||
*/
|
||||
|
@ -48,8 +59,6 @@ typedef int int32;
|
|||
|
||||
#include "log.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Macros
|
||||
*/
|
||||
|
|
|
@ -218,7 +218,8 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
|||
{
|
||||
Log("adding delayed input frame number %d to queue.\n", frame_number);
|
||||
|
||||
ASSERT(input.size == _prediction.size);
|
||||
if (input.size != _prediction.size)
|
||||
throw GGPOException("Input size differs from peer", GGPO_ERRORCODE_INPUT_SIZE_DIFF);
|
||||
|
||||
ASSERT(_last_added_frame == GameInput::NullFrame || frame_number == _last_added_frame + 1);
|
||||
|
||||
|
|
|
@ -35,9 +35,8 @@ ggpo_log(GGPOSession *ggpo, const char *fmt, ...)
|
|||
void
|
||||
ggpo_logv(GGPOSession *ggpo, const char *fmt, va_list args)
|
||||
{
|
||||
if (ggpo) {
|
||||
if (ggpo)
|
||||
ggpo->Logv(fmt, args);
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
|
@ -48,12 +47,17 @@ ggpo_start_session(GGPOSession **session,
|
|||
int input_size,
|
||||
unsigned short localport)
|
||||
{
|
||||
*session= (GGPOSession *)new Peer2PeerBackend(cb,
|
||||
game,
|
||||
localport,
|
||||
num_players,
|
||||
input_size);
|
||||
return GGPO_OK;
|
||||
try {
|
||||
*session= (GGPOSession *)new Peer2PeerBackend(cb,
|
||||
game,
|
||||
localport,
|
||||
num_players,
|
||||
input_size);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_session: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
|
@ -61,10 +65,14 @@ ggpo_add_player(GGPOSession *ggpo,
|
|||
GGPOPlayer *player,
|
||||
GGPOPlayerHandle *handle)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->AddPlayer(player, handle);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->AddPlayer(player, handle);
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,8 +85,13 @@ ggpo_start_synctest(GGPOSession **ggpo,
|
|||
int input_size,
|
||||
int frames)
|
||||
{
|
||||
*ggpo = (GGPOSession *)new SyncTestBackend(cb, game, frames, num_players);
|
||||
return GGPO_OK;
|
||||
try {
|
||||
*ggpo = (GGPOSession *)new SyncTestBackend(cb, game, frames, num_players);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_synctest: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
|
@ -86,19 +99,27 @@ ggpo_set_frame_delay(GGPOSession *ggpo,
|
|||
GGPOPlayerHandle player,
|
||||
int frame_delay)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SetFrameDelay(player, frame_delay);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_frame_delay: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->SetFrameDelay(player, frame_delay);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_idle(GGPOSession *ggpo, int timeout)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->DoPoll(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_idle: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->DoPoll(timeout);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
|
@ -107,10 +128,14 @@ ggpo_add_local_input(GGPOSession *ggpo,
|
|||
void *values,
|
||||
int size)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->AddLocalInput(player, values, size);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_local_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->AddLocalInput(player, values, size);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
|
@ -119,37 +144,53 @@ ggpo_synchronize_input(GGPOSession *ggpo,
|
|||
int size,
|
||||
int *disconnect_flags)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SyncInput(values, size, disconnect_flags);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_synchronize_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->SyncInput(values, size, disconnect_flags);
|
||||
}
|
||||
|
||||
GGPOErrorCode ggpo_disconnect_player(GGPOSession *ggpo,
|
||||
GGPOPlayerHandle player)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->DisconnectPlayer(player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_disconnect_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->DisconnectPlayer(player);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_advance_frame(GGPOSession *ggpo)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->IncrementFrame();
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_advance_frame: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->IncrementFrame();
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_client_chat(GGPOSession *ggpo, char *text)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->Chat(text);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_client_chat: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->Chat(text);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
|
@ -157,10 +198,14 @@ ggpo_get_network_stats(GGPOSession *ggpo,
|
|||
GGPOPlayerHandle player,
|
||||
GGPONetworkStats *stats)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->GetNetworkStats(stats, player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_get_network_stats: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->GetNetworkStats(stats, player);
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,19 +222,27 @@ ggpo_close_session(GGPOSession *ggpo)
|
|||
GGPOErrorCode
|
||||
ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SetDisconnectTimeout(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_timeout: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->SetDisconnectTimeout(timeout);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout)
|
||||
{
|
||||
if (!ggpo) {
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SetDisconnectNotifyStart(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_notify_start: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
return ggpo->SetDisconnectNotifyStart(timeout);
|
||||
}
|
||||
|
||||
GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
|
||||
|
@ -201,13 +254,18 @@ GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
|
|||
char *host_ip,
|
||||
unsigned short host_port)
|
||||
{
|
||||
*session= (GGPOSession *)new SpectatorBackend(cb,
|
||||
game,
|
||||
local_port,
|
||||
num_players,
|
||||
input_size,
|
||||
host_ip,
|
||||
host_port);
|
||||
return GGPO_OK;
|
||||
try {
|
||||
*session= (GGPOSession *)new SpectatorBackend(cb,
|
||||
game,
|
||||
local_port,
|
||||
num_players,
|
||||
input_size,
|
||||
host_ip,
|
||||
host_port);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_spectating: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -478,7 +478,6 @@ UdpProtocol::OnSyncRequest(UdpMsg *msg, int len)
|
|||
return false;
|
||||
}
|
||||
// FIXME
|
||||
//bool requeueSyncRequest = _last_send_time && _last_send_time + 20 < Platform::GetCurrentTimeMS();
|
||||
if (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS && msg->hdr.sequence_number == 0) {
|
||||
Log("Sync request 0 received... Re-queueing sync packet.\n");
|
||||
SendSyncRequest();
|
||||
|
|
|
@ -450,7 +450,12 @@ void getInput(MapleInputState inputState[4])
|
|||
u32 inputSize = sizeof(u32) + config::GGPOAnalogAxes;
|
||||
std::vector<u8> inputs(inputSize * MAX_PLAYERS);
|
||||
// should not call any callback
|
||||
ggpo_synchronize_input(ggpoSession, (void *)&inputs[0], inputs.size(), nullptr);
|
||||
GGPOErrorCode error = ggpo_synchronize_input(ggpoSession, (void *)&inputs[0], inputs.size(), nullptr);
|
||||
if (error != GGPO_OK)
|
||||
{
|
||||
stopSession();
|
||||
throw FlycastException("GGPO error");
|
||||
}
|
||||
|
||||
for (int player = 0; player < MAX_PLAYERS; player++)
|
||||
{
|
||||
|
@ -486,10 +491,20 @@ bool nextFrame()
|
|||
if (ggpoSession == nullptr)
|
||||
return false;
|
||||
// will call save_game_state
|
||||
ggpo_advance_frame(ggpoSession);
|
||||
GGPOErrorCode error = ggpo_advance_frame(ggpoSession);
|
||||
|
||||
// may rollback
|
||||
ggpo_idle(ggpoSession, 0);
|
||||
if (error == GGPO_OK)
|
||||
error = ggpo_idle(ggpoSession, 0);
|
||||
if (error != GGPO_OK)
|
||||
{
|
||||
stopSession();
|
||||
if (error == GGPO_ERRORCODE_INPUT_SIZE_DIFF)
|
||||
throw FlycastException("GGPO analog settings are different from peer");
|
||||
else if (error != GGPO_OK)
|
||||
throw FlycastException("GGPO error");
|
||||
}
|
||||
|
||||
// may call save_game_state
|
||||
do {
|
||||
u32 input = ~kcode[localPlayerNum];
|
||||
|
@ -519,8 +534,7 @@ bool nextFrame()
|
|||
WARN_LOG(NETWORK, "ggpo_add_local_input failed %d", result);
|
||||
if (result != GGPO_ERRORCODE_PREDICTION_THRESHOLD)
|
||||
{
|
||||
ggpo_close_session(ggpoSession);
|
||||
ggpoSession = nullptr;
|
||||
stopSession();
|
||||
throw FlycastException("GGPO error");
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
|
|
Loading…
Reference in New Issue