1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

First working prototype

This commit is contained in:
nordsoft
2022-10-27 00:52:39 +04:00
parent dd45d1a9cf
commit 21a1706627
4 changed files with 120 additions and 66 deletions

View File

@@ -61,7 +61,10 @@ void SocketLobby::requestReadySession(const QString & session)
void SocketLobby::send(const QString & msg) void SocketLobby::send(const QString & msg)
{ {
socket->write(qPrintable(msg)); int sz = msg.size();
QByteArray pack((const char *)&sz, sizeof(sz));
pack.append(qPrintable(msg));
socket->write(pack);
} }
void SocketLobby::connected() void SocketLobby::connected()

View File

@@ -4,12 +4,39 @@ from pickletools import bytes8
import socket import socket
import re import re
import uuid import uuid
import struct
from threading import Thread from threading import Thread
# server's IP address # server's IP address
SERVER_HOST = "0.0.0.0" SERVER_HOST = "0.0.0.0"
SERVER_PORT = 5002 # port we want to use SERVER_PORT = 5002 # port we want to use
def send_msg(sock, msg, doPack):
# For 1 byte (bool) send just that
# Prefix each message with a 4-byte length (network byte order)
if doPack and len(msg) > 1:
msg = struct.pack('<I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock):
# Read message length and unpack it into an integer
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('<I', raw_msglen)[0]
# Read the message data
return recvall(sock, msglen)
def recvall(sock, n):
# Helper function to recv n bytes or return None if EOF is hit
data = bytearray()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data.extend(packet)
return data
# initialize list/set of all connected client's sockets # initialize list/set of all connected client's sockets
client_sockets = dict() client_sockets = dict()
@@ -23,6 +50,8 @@ class GameConnection:
messageQueueOut = [] messageQueueOut = []
def __init__(self) -> None: def __init__(self) -> None:
self.server = None
self.client = None
pass pass
class Session: class Session:
@@ -188,62 +217,81 @@ def startSession(session: Session):
def dispatch(client: socket, sender: dict, arr: bytes): def dispatch(client: socket, sender: dict, arr: bytes):
if len(arr) == 0:
if arr == None or len(arr) == 0:
return return
msg = str(arr) #if len(sender["prevmessages"]):
print(msg) # arr = sender["prevmessages"] + arr
if msg[-1] == '\n' or (msg[-1] == '\'' and msg[-2] == '\n'): # sender["prevmessages"] = bytes()
sender["prevmessage"] += msg
return
else:
msg = f"{sender['prevmessage']}{msg}"
sender["prevmessage"] = ""
#check for game mode connection #check for game mode connection
_gameModeIdentifier = msg.partition('Aiya!') msg = str(arr)
if _gameModeIdentifier[0] != '' and _gameModeIdentifier[1] == 'Aiya!': if msg.find("Aiya!") != -1:
sender["aiya"] = True sender["pipe"] = True
if sender["aiya"]: if sender["pipe"]:
_uuid = msg.partition('$')[2] if sender["game"]:
match = re.search(r"\((\w+)\)", msg) sender["prevmessages"].append(arr)
_appType = '' else:
if match != None: sender["prevmessages"].append(struct.pack('<I', len(arr)) + arr)
_appType = match.group(1) match = re.search(r"\((\w+)\)", msg)
if not _uuid == '' and not _appType == '': _appType = ''
#search for uuid if match != None:
for session in sessions.values(): _appType = match.group(1)
if session.started: sender["apptype"] = _appType
if _uuid.find(session.host_uuid) != -1 and _appType == "server":
gc = session.addConnection(client, True) _uuid = arr.decode()
for qmsg in gc.messageQueueIn: if not _uuid == '' and not sender["apptype"] == '':
send(gc.server, qmsg) #search for uuid
sender["session"] = session for session in sessions.values():
sender["game"] = True if session.started:
if not gc.clientInit: if _uuid.find(session.host_uuid) != -1 and sender["apptype"] == "server":
gc.messageQueueOut.append(arr) gc = session.addConnection(client, True)
return #send_msg(gc.server, gc.messageQueueIn)
#gc.messageQueueIn = bytes()
sender["session"] = session
sender["game"] = True
#read boolean flag for the endian
sender["prevmessages"].append(client.recv(1))
#if not gc.clientInit:
# gc.messageQueueOut += arr
return
if _appType == "client": if sender["apptype"] == "client":
for p in session.players: for p in session.players:
if _uuid.find(client_sockets[p]["uuid"]) != -1: if _uuid.find(client_sockets[p]["uuid"]) != -1:
#client connection #client connection
gc = session.addConnection(client, False) gc = session.addConnection(client, False)
for qmsg in gc.messageQueueOut: #send_msg(gc.client, gc.messageQueueOut)
send(gc.client, qmsg) #gc.messageQueueOut = bytes()
sender["session"] = session sender["session"] = session
sender["game"] = True sender["game"] = True
if not gc.serverInit: #read boolean flag for the endian
gc.messageQueueIn.append(arr) sender["prevmessages"].append(client.recv(1))
return #if not gc.serverInit:
break # gc.messageQueueIn += arr
# return
break
#game mode #game mode
if sender["game"] and sender["session"].validPipe(client): if sender["pipe"] and sender["game"] and sender["session"].validPipe(client):
sender["session"].getPipe(client).send(arr) #send messages from queue
opposite = sender["session"].getPipe(client)
for x in client_sockets[opposite]["prevmessages"]:
client.sendall(x)
client_sockets[opposite]["prevmessages"].clear()
try:
for x in sender["prevmessages"]:
opposite.sendall(x)
except Exception as e:
print(f"[!] Error: {e}")
sender["prevmessages"].clear()
return
if sender["pipe"]:
return return
#lobby mode #lobby mode
msg = arr.decode() msg = arr.decode()
@@ -377,7 +425,11 @@ def listen_for_client(cs):
while True: while True:
try: try:
# keep listening for a message from `cs` socket # keep listening for a message from `cs` socket
msg = cs.recv(2048) if client_sockets[cs]["game"]:
msg = cs.recv(4096)
else:
msg = recv_msg(cs)
#msg = cs.recv(2048)
except Exception as e: except Exception as e:
# client no longer connected # client no longer connected
print(f"[!] Error: {e}") print(f"[!] Error: {e}")
@@ -392,7 +444,7 @@ while True:
client_socket, client_address = s.accept() client_socket, client_address = s.accept()
print(f"[+] {client_address} connected.") print(f"[+] {client_address} connected.")
# add the new connected client to connected sockets # add the new connected client to connected sockets
client_sockets[client_socket] = {"address": client_address, "auth": False, "username": "", "joined": False, "aiya": False, "prevmessage": "", "game": False} client_sockets[client_socket] = {"address": client_address, "auth": False, "username": "", "joined": False, "game": False, "pipe": False, "apptype": "", "prevmessages": []}
# start a new thread that listens for each client's messages # start a new thread that listens for each client's messages
t = Thread(target=listen_for_client, args=(client_socket,)) t = Thread(target=listen_for_client, args=(client_socket,))
# make the thread daemon so it ends whenever the main thread ends # make the thread daemon so it ends whenever the main thread ends

View File

@@ -170,7 +170,8 @@ void CVCMIServer::run()
#endif #endif
startAsyncAccept(); startAsyncAccept();
establishRemoteConnections(); if(!remoteConnectionsThread)
remoteConnectionsThread = vstd::make_unique<boost::thread>(&CVCMIServer::establishRemoteConnections, this);
#if defined(VCMI_ANDROID) #if defined(VCMI_ANDROID)
CAndroidVMHelper vmHelper; CAndroidVMHelper vmHelper;
@@ -216,23 +217,21 @@ void CVCMIServer::establishRemoteConnections()
void CVCMIServer::connectToRemote(const std::string & addr, int port) void CVCMIServer::connectToRemote(const std::string & addr, int port)
{ {
std::shared_ptr<CConnection> c; std::shared_ptr<CConnection> c;
int attempts = 10; try
while(!c && attempts--)
{ {
try logNetwork->info("Establishing connection...");
{ c = std::make_shared<CConnection>(addr, port, SERVER_NAME, uuid);
logNetwork->info("Establishing connection..."); }
c = std::make_shared<CConnection>(addr, port, SERVER_NAME, uuid); catch(...)
} {
catch(...) logNetwork->error("\nCannot establish remote connection!");
{
logNetwork->error("\nCannot establish connection! Retrying within 1 second");
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
} }
connections.insert(c); if(c)
c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c); {
connections.insert(c);
c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c);
}
} }
void CVCMIServer::threadAnnounceLobby() void CVCMIServer::threadAnnounceLobby()

View File

@@ -52,7 +52,7 @@ class CVCMIServer : public LobbyInfo
std::list<std::unique_ptr<CPackForLobby>> announceQueue; std::list<std::unique_ptr<CPackForLobby>> announceQueue;
boost::recursive_mutex mx; boost::recursive_mutex mx;
std::shared_ptr<CApplier<CBaseForServerApply>> applier; std::shared_ptr<CApplier<CBaseForServerApply>> applier;
std::unique_ptr<boost::thread> announceLobbyThread; std::unique_ptr<boost::thread> announceLobbyThread, remoteConnectionsThread;
public: public:
std::shared_ptr<CGameHandler> gh; std::shared_ptr<CGameHandler> gh;