mirror of
https://github.com/libretro/netplay-mitm-server.git
synced 2024-11-27 11:10:26 +00:00
delay MODE until after any pending savestate transfer, add license headers
This commit is contained in:
parent
200fef9bc2
commit
9bd72893a5
15
main.cpp
15
main.cpp
@ -1,3 +1,18 @@
|
||||
/* netplay-mitm-server - A man-in-the-middle server implementation for RetroArch netplay.
|
||||
* Copyright (C) 2017 - Brad Parker
|
||||
*
|
||||
* netplay-mitm-server is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* netplay-mitm-server is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with netplay-mitm-server.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include "ramitm.h"
|
||||
|
||||
|
140
ramitm.cpp
140
ramitm.cpp
@ -1,5 +1,17 @@
|
||||
/* (C) Copyright 2017 - Brad Parker */
|
||||
/* License: GPL */
|
||||
/* netplay-mitm-server - A man-in-the-middle server implementation for RetroArch netplay.
|
||||
* Copyright (C) 2017 - Brad Parker
|
||||
*
|
||||
* netplay-mitm-server is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* netplay-mitm-server is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with netplay-mitm-server.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ramitm.h"
|
||||
#include <stdio.h>
|
||||
@ -39,6 +51,14 @@ size_t strlcpy(char *dest, const char *source, size_t size)
|
||||
return src_size;
|
||||
}
|
||||
|
||||
static void dump_uints(const char *data, int bytes) {
|
||||
for(uint i = 0; i < bytes / sizeof(uint32_t); i++) {
|
||||
printf(" %08X", ntohl(((uint32_t*)data)[i]));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
RAMITM::RAMITM(QObject *parent) :
|
||||
QObject(parent)
|
||||
,m_sock(new QTcpServer(this))
|
||||
@ -73,6 +93,43 @@ RAMITM::RAMITM(QObject *parent) :
|
||||
connect(m_sock, SIGNAL(newConnection()), this, SLOT(newConnection()));
|
||||
}
|
||||
|
||||
void RAMITM::sendMODE(QTcpSocket *sock) {
|
||||
mode_buf_s mode;
|
||||
|
||||
memset(&mode, 0, sizeof(mode));
|
||||
|
||||
mode.cmd[0] = htonl(CMD_MODE);
|
||||
mode.cmd[1] = htonl(sizeof(mode) - sizeof(mode.cmd));
|
||||
|
||||
mode.frame_num = htonl(m_frameNumber);
|
||||
mode.player_num = htons(m_sockets.indexOf(sock));
|
||||
|
||||
foreach(QTcpSocket *player, m_sockets) {
|
||||
if(!player->property("sync_sent").toBool()) {
|
||||
// don't send MODE to other players that haven't finished their handshake yet
|
||||
continue;
|
||||
}
|
||||
|
||||
if(player == sock) {
|
||||
mode.target = htons(3); // bit0 == is MODE being sent to the affected player, bit1 == is the user now playing or spectating
|
||||
}else{
|
||||
mode.target = htons(2);
|
||||
}
|
||||
|
||||
CLIENT_LOGF(sock, "MODE for player %d:", m_sockets.indexOf(player));
|
||||
|
||||
for(uint i = 0; i < sizeof(mode) / sizeof(uint32_t); ++i) {
|
||||
printf(" %08X", ntohl(((uint32_t*)&mode)[i]));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
player->write((const char *)&mode, sizeof(mode));
|
||||
}
|
||||
|
||||
CLIENT_LOG(sock, "sent MODE to all users");
|
||||
}
|
||||
|
||||
void RAMITM::start() {
|
||||
int port = 55435;
|
||||
|
||||
@ -133,16 +190,6 @@ void RAMITM::readyRead() {
|
||||
|
||||
//printf("readyRead: %lli bytes available, state is %d for host %s\n", sock->bytesAvailable(), state, QC_STR(sock->peerAddress().toString()));
|
||||
|
||||
/*int bytes = sock->bytesAvailable();
|
||||
|
||||
for(int i = 0; i < bytes; i++) {
|
||||
char a;
|
||||
sock->read(&a, 1);
|
||||
printf(" %08X", a);
|
||||
}
|
||||
|
||||
printf("\n");*/
|
||||
|
||||
// check for end of mandatory state handling before accepting any new commands
|
||||
if(state >= STATE_NONE) {
|
||||
if(sock->bytesAvailable() < 8) {
|
||||
@ -482,6 +529,7 @@ void RAMITM::readyRead() {
|
||||
|
||||
QTcpSocket *master = m_sockets.at(0);
|
||||
|
||||
master->setProperty("savestate_pending", true);
|
||||
master->write((const char *)&req, sizeof(req));
|
||||
|
||||
CLIENT_LOG(sock, "requested savestate from the master");
|
||||
@ -497,41 +545,19 @@ void RAMITM::readyRead() {
|
||||
sock->read(cmd[1]);
|
||||
}
|
||||
|
||||
mode_buf_s mode;
|
||||
QTcpSocket *master = m_sockets.at(0);
|
||||
|
||||
memset(&mode, 0, sizeof(mode));
|
||||
bool savestate_pending = master->property("savestate_pending").toBool();
|
||||
|
||||
mode.cmd[0] = htonl(CMD_MODE);
|
||||
mode.cmd[1] = htonl(sizeof(mode) - sizeof(mode.cmd));
|
||||
|
||||
mode.frame_num = htonl(m_frameNumber);
|
||||
mode.player_num = htons(m_sockets.indexOf(sock));
|
||||
|
||||
foreach(QTcpSocket *player, m_sockets) {
|
||||
if(!player->property("sync_sent").toBool()) {
|
||||
// don't send MODE to other players that haven't finished their handshake yet
|
||||
continue;
|
||||
}
|
||||
|
||||
if(player == sock) {
|
||||
mode.target = htons(3); // bit0 == is MODE being sent to the affected player, bit1 == is the user now playing or spectating
|
||||
}else{
|
||||
mode.target = htons(2);
|
||||
}
|
||||
|
||||
CLIENT_LOGF(sock, "MODE for player %d (0-based):", m_sockets.indexOf(player));
|
||||
|
||||
for(uint i = 0; i < sizeof(mode); ++i) {
|
||||
printf(" %08X", ((char*)&mode)[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
player->write((const char *)&mode, sizeof(mode));
|
||||
if(!savestate_pending) {
|
||||
sendMODE(sock);
|
||||
CLIENT_LOG(sock, "received PLAY");
|
||||
}else{
|
||||
// track which player sent the original PLAY command so the 'you' bit in MODE can be set accordingly
|
||||
sock->setProperty("sent_play", true);
|
||||
CLIENT_LOG(sock, "received PLAY, waiting for savestate transfer to finish before sending MODE");
|
||||
}
|
||||
|
||||
CLIENT_LOG(sock, "received PLAY and sent MODE to all users");
|
||||
|
||||
sock->setProperty("state", STATE_NONE);
|
||||
|
||||
break;
|
||||
@ -598,7 +624,13 @@ void RAMITM::readyRead() {
|
||||
|
||||
CLIENT_LOGF(sock, "successfully received savestate of %lu bytes with original size %u\n", state_serial_size, ntohl(loadsave.orig_size));
|
||||
|
||||
loadsave.frame_num = htonl(m_frameNumber);
|
||||
QTcpSocket *master = m_sockets.at(0);
|
||||
master->setProperty("savestate_pending", false);
|
||||
|
||||
//loadsave.frame_num = htonl(m_frameNumber);
|
||||
m_frameNumber = ntohl(loadsave.frame_num);
|
||||
|
||||
CLIENT_LOGF(sock, "setting server frame count to savestate value: %u\n", m_frameNumber);
|
||||
|
||||
foreach(QTcpSocket *player, m_sockets) {
|
||||
if(player != sock) {
|
||||
@ -609,6 +641,22 @@ void RAMITM::readyRead() {
|
||||
}
|
||||
}
|
||||
|
||||
foreach(QTcpSocket *player, m_sockets) {
|
||||
bool sent_play = player->property("sent_play").toBool();
|
||||
|
||||
// find which player sent the original PLAY, so we know who to set the 'you' bit for in the MODE command
|
||||
if(sent_play) {
|
||||
sendMODE(player);
|
||||
player->setProperty("sent_play", false);
|
||||
}
|
||||
}
|
||||
|
||||
CLIENT_LOGF(sock, "incrementing server frame count to %u (was %u)\n", m_frameNumber + 1, m_frameNumber);
|
||||
|
||||
++m_frameNumber;
|
||||
|
||||
sock->setProperty("state", STATE_NONE);
|
||||
|
||||
break;
|
||||
}
|
||||
case STATE_RECV_INPUT:
|
||||
@ -639,6 +687,7 @@ void RAMITM::readyRead() {
|
||||
if(m_sockets.indexOf(sock) == 0) {
|
||||
// this is the first (master) connection
|
||||
// server follows the first connection's frame number
|
||||
CLIENT_LOGF(sock, "got INPUT from master, setting server frame count to %u (was %u)\n", ntohl(input.frame_num), m_frameNumber);
|
||||
m_frameNumber = ntohl(input.frame_num);
|
||||
}
|
||||
|
||||
@ -659,6 +708,8 @@ void RAMITM::readyRead() {
|
||||
|
||||
if(m_sockets.indexOf(sock) == 0) {
|
||||
// send NOINPUT to everyone, but only when getting an INPUT from the master client, as we are keeping our frames in sync with it
|
||||
CLIENT_LOGF(sock, "sending NOINPUT to player %d:", m_sockets.indexOf(player));
|
||||
dump_uints((const char *)&noinput, sizeof(noinput));
|
||||
player->write((const char *)&noinput, sizeof(noinput));
|
||||
}
|
||||
}
|
||||
@ -674,6 +725,7 @@ void RAMITM::readyRead() {
|
||||
{
|
||||
// Increment server frame number ahead of master client sending a new INPUT with the same frame number.
|
||||
// This allows sending MODE to new players as the first event of the next frame, before the master's INPUT.
|
||||
CLIENT_LOGF(sock, "end of frame for master (sent both INPUT and NOINPUT), incrementing server frame count to %u (was %u)\n", m_frameNumber + 1, m_frameNumber);
|
||||
++m_frameNumber;
|
||||
}
|
||||
|
||||
|
17
ramitm.h
17
ramitm.h
@ -1,3 +1,18 @@
|
||||
/* netplay-mitm-server - A man-in-the-middle server implementation for RetroArch netplay.
|
||||
* Copyright (C) 2017 - Brad Parker
|
||||
*
|
||||
* netplay-mitm-server is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* netplay-mitm-server is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with netplay-mitm-server.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RAMITM_H
|
||||
#define __RAMITM_H
|
||||
|
||||
@ -106,6 +121,8 @@ private slots:
|
||||
void error(QAbstractSocket::SocketError socketError);
|
||||
|
||||
private:
|
||||
void sendMODE(QTcpSocket *sock);
|
||||
|
||||
QTcpServer *m_sock;
|
||||
char m_header[HEADER_LEN];
|
||||
info_buf_s m_info;
|
||||
|
Loading…
Reference in New Issue
Block a user