Ejemplo n.º 1
0
 def handleJoiningReceive(stream: SendStream, socket: ClientSocket):
     command = stream.readBytes()
     if command == b'host':
         socket.unregister()
         session = Session(stream, socket)
         openSessions[session.id] = session
     elif command == b'join':
         sessionId = stream.readInt()
         session = openSessions.get(sessionId, None)
         if session:
             error = session.addClient(socket)
             if not error:
                 return
         else:
             error = 'The session has been canceled.'
         sendStream = SendStream()
         sendStream.writeBytes(b'cancel')
         sendStream.writeString(error)
         sendStream.send(socket.socket)
     elif command == b'client':
         freeSessions = [
             x for x in openSessions.values()
             if len(x.clients) < x.maxPlayers and socket.secret == x.secret
         ]
         sendStream = socket.sendStream
         sendStream.writeBytes(b'addsessions')
         sendStream.writeInt(len(freeSessions))
         for session in freeSessions:
             sendStream.writeInt(session.id)
             sendStream.writeString(session.hostName)
             sendStream.writeString(session.gameName)
         sendStream.send()
 def __init__(self):
     super().__init__()
     self.clientSocket = ClientSocket(QSslSocket())
     self.socket = self.clientSocket.socket
     self.sendStream = self.clientSocket.sendStream
     self.clientSocket.setReceiveHandler(self.handleConnectorReceive)
     self.socket.setCaCertificates(
         [QSslCertificate(base64.b64decode(certificate))])
     self.socket.encrypted.connect(self.handleConnected)
     self.socket.error.connect(self.handleError)
     self.socket.connectToHostEncrypted(Client.serverSettings.address,
                                        listenPort, QIODevice.ReadWrite,
                                        QSslSocket.IPv4Protocol)
Ejemplo n.º 3
0
 def addClient(self, socket: ClientSocket):
     if self.clients.get(socket.name, None):  # client name already used
         return 'The client name ' + socket.name + ' is already used in this session.'
     if len(self.clients) + 1 > self.maxPlayers:
         return 'The maximum client count has been reached for this session.'
     if len(self.clients) + 1 == self.maxPlayers:
         self.announceLater()
     joiningClients.remove(socket)
     socket.setDisconnectHandler(self.handleClientDisconnect)
     socket.setReceiveHandler(self.handleClientReceive)
     self.clients[socket.name] = socket
     sendStream = self.hostSocket.sendStream
     sendStream.writeBytes(b'join')
     sendStream.writeString(socket.name)
     sendStream.send()
     return None
Ejemplo n.º 4
0
 def handleClientDisconnect(self, socket: ClientSocket):
     del self.clients[socket.name]
     if self.state == Session.StateOpen:
         if len(self.clients) < self.maxPlayers:
             self.announceLater()
         stream = SendStream()
         stream.writeBytes(b'disjoin')
         stream.writeString(socket.name)
         stream.send(self.hostSocket.socket)
     elif self.state == Session.StateInit:
         if socket in self.init.missingClientHashes:
             self.init.missingClientCount -= 1
             del self.init.missingClientHashes[socket]
         self.handleClientLeftDuringInit(socket)
     else:  # game phase
         sendStream = SendStream()
         sendStream.writeBytes(b'left')
         sendStream.writeString(socket.name)
         for socket in self.clients.values():
             socket.send(sendStream)
         if not self.clients and self.id in activeSessions:
             del activeSessions[self.id]
Ejemplo n.º 5
0
    def __init__(self, stream: SendStream, hostSocket: ClientSocket):
        self.gameName = stream.readString()
        self.minPlayers = stream.readInt()
        self.maxPlayers = stream.readInt()
        self.playerCanLeave = stream.readBool()
        returnId = stream.readBool()
        self.hostSocket = hostSocket
        self.hostName = hostSocket.name
        self.secret = hostSocket.secret
        self.clients = {hostSocket.name: hostSocket}  # map names to sockets
        self.state = Session.StateOpen
        self.lastAnnounced = None
        self.announcePending = False
        self.init = None  # holds during the init state some objects
        Session.IdCounter += 1
        self.id = Session.IdCounter

        if returnId:
            hostSocket.sendStream.writeBytes(b'id')
            hostSocket.sendStream.writeInt(self.id)

        hostSocket.setReceiveHandler(self.handleHostReceive)
        hostSocket.setDisconnectHandler(self.handleHostDisconnect)
        self.announce()
Ejemplo n.º 6
0
 def handleClientReceive(self, stream: SendStream, socket: ClientSocket):
     try:
         command = stream.readBytes()
         if command == b'update':
             finished = stream.readBool()
             stream.readBytes()  # state
             data = stream.data()
             for othername, othersocket in self.clients.items():
                 if othername != socket.name:
                     writeData(othersocket.socket, data)
                     if finished:
                         othersocket.setDisconnectHandler(None)
                         othersocket.disconnectWhenWritten()
             if finished:
                 socket.setDisconnectHandler(None)
                 socket.disconnect()
                 del activeSessions[self.id]
         elif command == b'message':
             stream.readString()  # title
             stream.readString()  # text
             data = stream.data()
             for othername, othersocket in self.clients.items():
                 if othername != socket.name:
                     writeData(othersocket.socket, data)
         elif command == b'disjoin':
             if len(self.clients) == self.maxPlayers:
                 self.announceLater()
             self.handleClientDisconnect(socket)
             socket.register(joiningClients)
             socket.setReceiveHandler(self.handleJoiningReceive)
         elif command == b'data':
             count = stream.readInt()
             if not self.init:
                 socket.socket.disconnect()
                 return
             missingClientHashes = []
             for i in range(count):
                 missingClientHashes.append(stream.readBytes())
             if self.init.missingFileHashes is None:
                 self.sendMissingClientData(socket, missingClientHashes)
             else:
                 self.init.missingClientHashes[socket] = missingClientHashes
     except Exception as e:
         self.abortSession()
         log('session error 3 : ' + str(e) + ' - ' + traceback.format_exc())
         raise HandledError()
Ejemplo n.º 7
0
 def handleReceive(socket = socket, timerId = timerId):
     if timerId:
         self.killTimer(timerId)
     unvalidatedSockets.remove(socket)
     socket.disconnected.disconnect(handleDisconnect)
     def blockAddress():
         address = socket.peerAddress()
         remaining = blockedAddresses.setdefault(address, 3)
         blockedAddresses[address] -= 1
         if remaining == 1:  # was last trial
             socket.write(b"your address '" + address.toString().encode() + b"' has been blocked\n")
             log("block address '" + address.toString() + "'")
         socket.disconnectFromHost()
     try:
         secretLen = int(socket.read(1))
     except:
         blockAddress()
         return
     secret = socket.read(secretLen)
     if secret == b'ctrl4eip':
         blockedAddresses.pop(socket.peerAddress(), None)
         controlHandlers.add(ControlHandler(socket))
         socket.readyRead.disconnect(handleReceive)
     elif secret == sessionClientSecret:
         blockedAddresses.pop(socket.peerAddress(), None)
         clientSocket = ClientSocket(socket)
         clientSocket.register(validatedSockets)
         clientSocket.setReceiveHandler(handleValidatedReceive)
         socket.readyRead.disconnect(handleReceive)
         clientSocket.handleReceive()
     else:
         address = socket.peerAddress()
         remaining = blockedAddresses.setdefault(address, 3)
         blockedAddresses[address] -= 1
         if remaining == 1: # was last trial
             socket.write(b"your address '" + address.toString().encode() + b"' has been blocked\n")
             log("block address '" + address.toString() + "'")
         socket.disconnectFromHost()
         return
Ejemplo n.º 8
0
def handleValidatedReceive(stream : SendStream, socket : ClientSocket):
    socket.unregister()
    protocolVersion = stream.readInt()
    if protocolVersion != sessionProtocolVersion:
        if protocolVersion < sessionProtocolVersion:
            text = 'Client uses outdated protocol version. Please update the client.'
        else:
            text = 'Client uses newer protocol version. Please inform the server provider that the server is outdated.'
        stream = socket.sendStream
        stream.writeBytes(b'error')
        stream.writeString(text)
        stream.send()
        socket.disconnectWhenWritten()
        raise HandledError()
    socket.name = stream.readString()
    socket.secret = stream.readString()
    Session.startHandling(stream, socket)
Ejemplo n.º 9
0
 def handleHostDisconnect(self, socket: ClientSocket):
     self.announceLater()
     del self.clients[self.hostName]
     if self.state == Session.StateOpen:
         stream = SendStream()
         stream.writeBytes(b'cancel')
         stream.writeString('The host has been disconnected.')
         for socket in self.clients.values():
             socket.send(stream)
             socket.register(joiningClients)
             socket.setReceiveHandler(self.handleJoiningReceive)
         self.state = Session.StateDone
         del openSessions[self.id]
     elif self.init:
         if self.init.missingFileHashes:  # host disconnected before sending files
             self.handleErrorWhenOpen('Connection to host has been lost.')
         else:
             self.handleClientLeftDuringInit(socket)
     else:
         pass  # this case should not occur
Ejemplo n.º 10
0
 def startHandling(cls, stream: SendStream, socket: ClientSocket):
     socket.register(joiningClients)
     socket.setReceiveHandler(cls.handleJoiningReceive)
     if not stream.atEnd():
         cls.handleJoiningReceive(stream, socket)
class ClientConnector(QObject):
    def __init__(self):
        super().__init__()
        self.clientSocket = ClientSocket(QSslSocket())
        self.socket = self.clientSocket.socket
        self.sendStream = self.clientSocket.sendStream
        self.clientSocket.setReceiveHandler(self.handleConnectorReceive)
        self.socket.setCaCertificates(
            [QSslCertificate(base64.b64decode(certificate))])
        self.socket.encrypted.connect(self.handleConnected)
        self.socket.error.connect(self.handleError)
        self.socket.connectToHostEncrypted(Client.serverSettings.address,
                                           listenPort, QIODevice.ReadWrite,
                                           QSslSocket.IPv4Protocol)

    def disconnect(self):
        self.socket.disconnectFromHost()

    def handleConnected(self):
        self.socket.write(
            str(len(sessionClientSecret)).encode() + sessionClientSecret)
        self.sendStream.writeInt(sessionProtocolVersion)
        self.sendStream.writeString(Client.serverSettings.name)
        self.sendStream.writeString(Client.serverSettings.secret)
        self.sendStream.send()
        self.connected.emit()

    def host(self, returnId=False):
        self.sendStream.writeBytes(b'host')
        self.sendStream.writeString(Client.gameObject.gameName)
        self.sendStream.writeInt(Client.gameObject.minPlayerCount)
        self.sendStream.writeInt(Client.gameObject.maxPlayerCount)
        self.sendStream.writeBool(Client.gameObject.playerCanLeave)
        self.sendStream.writeBool(returnId)
        self.sendStream.send()

    def getSessions(self):
        self.sendStream.writeBytes(b'client')
        self.sendStream.send()

    def join(self, sessionId):
        self.sendStream.writeBytes(b'join')
        self.sendStream.writeInt(sessionId)
        self.sendStream.send()

    def disjoin(self):
        self.sendStream.writeBytes(b'disjoin')
        self.sendStream.send()

    def startSession(self):
        self.sendStream.writeBytes(b'start')
        self.sendStream.writeInt(0)  # no files
        self.sendStream.send()

    def sendGameData(self, data, state):
        self.sendStream.writeBytes(b'data')
        self.sendStream.writeInt(0)  # no files
        self.sendStream.writeBytes(data)
        self.sendStream.writeBytes(state)
        self.sendStream.send()

    def sendUpdate(self, finished, state):
        self.sendStream.writeBytes(b'update')
        self.sendStream.writeBool(finished)
        self.sendStream.writeBytes(state)
        self.sendStream.send()

    def sendMessage(self, title, text):
        self.sendStream.writeBytes(b'message')
        self.sendStream.writeString(title)
        self.sendStream.writeString(text)
        self.sendStream.send()

    connected = pyqtSignal()
    sessionIdReceived = pyqtSignal(int)
    sessionsAdded = pyqtSignal(list)
    sessionRemoved = pyqtSignal(int)
    sessionCanceled = pyqtSignal(str)
    playerJoined = pyqtSignal(str)
    playerDisjoined = pyqtSignal(str)
    playerLeft = pyqtSignal(str)
    errorOccurred = pyqtSignal(str)
    gameDataRequested = pyqtSignal()
    gameDataReceived = pyqtSignal(bytes, bytes)
    updateReceived = pyqtSignal(bool, bytes)
    messageReceived = pyqtSignal(str, str)

    def handleError(self, error):
        self.socket.disconnectFromHost()
        if type(error) != str:
            if error == QSslSocket.SocketTimeoutError:
                error = 'A timeout error occurred.'
            elif error == QSslSocket.ConnectionRefusedError:
                error = 'The connection has been refused.'
            else:
                error = 'Socket error {} occurred.'.format(int(error))
        self.errorOccurred.emit(error)

    def handleConnectorReceive(self, stream: SendStream, socket: ClientSocket):
        command = stream.readBytes()
        if command == b'id':
            self.sessionIdReceived.emit(stream.readInt())
        elif command == b'error':
            self.handleError(stream.readString())
        elif command == b'join':
            self.playerJoined.emit(stream.readString())
        elif command == b'disjoin':
            self.playerDisjoined.emit(stream.readString())
        elif command == b'left':
            self.playerLeft.emit(stream.readString())
        elif command == b'cancel':
            self.sessionCanceled.emit(stream.readString())
        elif command == b'rmsession':
            self.sessionRemoved.emit(stream.readInt())
        elif command == b'addsessions':
            sessions = []
            for i in range(stream.readInt()):
                id = stream.readInt()
                host = stream.readString()
                game = stream.readString()
                sessions.append(Session(game, host, id))
            self.sessionsAdded.emit(sessions)
        elif command == b'start':
            fileMap = dict()
            for i in range(stream.readInt()):
                fileName = stream.readString()
                fileHash = stream.readBytes()
                fileMap[fileHash] = fileName
            # no file support
            self.sendStream.writeBytes(b'data')
            self.sendStream.writeInt(0)
            self.sendStream.send()
        elif command == b'missing':
            missingHashes = []
            for i in range(stream.readInt()):
                missingHashes.append(stream.readBytes())
            self.gameDataRequested.emit()
        elif command == b'data':
            files = []
            for i in range(stream.readInt()):
                files.append(stream.readBytes())
            data = stream.readBytes()
            state = stream.readBytes()
            self.gameDataReceived.emit(data, state)
        elif command == b'update':
            finished = stream.readBool()
            state = stream.readBytes()
            self.updateReceived.emit(finished, state)
        elif command == b'message':
            title = stream.readString()
            text = stream.readString()
            self.messageReceived.emit(title, text)