예제 #1
0
 def handleTcpResponse(self):
     if self.tcpReadState == self.STATE_TCP_READ_LEN:
         if len(self.tcpData) >= 4:
             self.tcpResponseLen, self.tcpData = Protocol.extractInt(
                 self.tcpData
             )
             self.tcpReadState = self.STATE_TCP_READ_DATA
             self.handleTcpResponse()
     elif self.tcpReadState == self.STATE_TCP_READ_DATA:
         if len(self.tcpData) >= self.tcpResponseLen:
             # tcpResponseLen should be >= 4
             if self.tcpResponseLen < 4:
                 logging.error(
                     'Cannot handle TLV payload of less than 4 bytes'
                 )
                 self.tcpData = self.tcpData[self.tcpResponseLen:]
                 self.tcpResponseLen = 0
                 self.tcpReadState = self.STATE_TCP_READ_LEN
                 self.handleTcpResponse()
             else:
                 data = self.tcpData[:self.tcpResponseLen]
                 self.tcpData = self.tcpData[self.tcpResponseLen:]
                 seq = Protocol.unpackInt(data[0:4])
                 self.tcpResponseLen = 0
                 self.tcpReadState = self.STATE_TCP_READ_LEN
                 self.dispatch(seq, data[4:])
                 self.handleTcpResponse()
예제 #2
0
 def sendAuth(self, username, password):
     self.username = username
     try:
         port = self.udpSock.getsockname()[1]
     except:
         port = 6009
         # raise
     authdata = Protocol.packTLV(username) + Protocol.packTLV(password) + Protocol.packInt(port) + Protocol.packInt(self.__versionNum__)
     self.sendAndRemember(Protocol.AUTH, authdata)
예제 #3
0
    def dispatchInbandData(self, seq, data):
        if seq not in self.tcpCommandsWaitingForResponse:
            logging.error("Sequence {} data {} not matched".format(seq, data))
            return

        origRequest = self.tcpCommandsWaitingForResponse[seq]
        del self.tcpCommandsWaitingForResponse[seq]

        if origRequest == Protocol.AUTH:
            self.parseAuthResponse(data)
        elif origRequest == Protocol.MOTD:
            self.parseMotdResponse(data)
        elif origRequest == Protocol.LIST_CHANNELS:
            self.parseListChannelsResponse(data)
        elif origRequest == Protocol.LIST_USERS:
            self.parseListUsersResponse(data)
        elif origRequest == Protocol.SPECTATE:
            status, data = Protocol.extractInt(data)
            if status != 0:
                self.emitList.append(
                    {
                        'state': 'error',
                        'message': f'Failed to spectate {status}'
                    }
                )
        elif origRequest in [Protocol.WELCOME, Protocol.JOIN_CHANNEL, Protocol.TOGGLE_AFK,
                             Protocol.SEND_CHALLENGE, Protocol.CHAT, Protocol.ACCEPT_CHALLENGE,
                             Protocol.DECLINE_CHALLENGE, Protocol.CANCEL_CHALLENGE]:
            if len(data) == 4:
                status, data = Protocol.extractInt(data)
                if status != 0:
                    codestr = Protocol.codeToString(origRequest)
                    logging.error(
                        "{} failed, data {}".format(codestr, repr(data))
                    )
                    if codestr == "SEND_CHALLENGE":
                        self.emitList.append(
                            {
                                'state': 'error',
                                'message': 'SEND_CHALLANGE failed'
                            }
                        )
                    elif codestr == "CANCEL_CHALLENGE":
                        pass
                    else:
                        self.emitList.append(
                            {
                                'state': 'error',
                                'message': f'codestr: {codestr}'
                            }
                        )
            else:
                logging.error("Unknown response for {}; seq {}; data {}".format(
                    Protocol.codeToString(origRequest), seq, repr(data)))
        else:
            logging.error("Not handling {} response; seq {}; data {}".format(
                Protocol.codeToString(origRequest), seq, repr(data)))
예제 #4
0
 def parseListChannelsResponse(self, data):
     if len(data) <= 8:
         logging.error('No channels found')
         self.stateChannelIsLoaded = True
         return
     status1, data = Protocol.extractInt(data)
     status2, data = Protocol.extractInt(data)
     logging.debug("Load channels header " + repr(status1) + repr(status2))
     while len(data) > 4:
         room, data = Protocol.extractTLV(data)
         romname, data = Protocol.extractTLV(data)
         title, data = Protocol.extractTLV(data)
         users, data = Protocol.extractInt(data)
         port, data = Protocol.extractInt(data)
         index, data = Protocol.extractInt(data)
         channel = {
             'rom': romname.decode("utf-8").split(':')[0],
             'room': room.decode("utf-8"),
             'title': title.decode("utf-8"),
             'users': users,
             'port': port,
         }
         self.channels[room.decode("utf-8")] = channel
     logging.debug(repr(self.channels))
     self.stateChannelIsLoaded = True
     if len(data) > 0:
         logging.error('Channel REMAINING DATA len {} {}'.format(
             len(data), repr(data))
         )
예제 #5
0
 def parseMotdResponse(self, data):
     if not data:
         return
     status, data = Protocol.extractInt(data)
     channel, data = Protocol.extractTLV(data)
     topic, data = Protocol.extractTLV(data)
     msg, data = Protocol.extractTLV(data)
     self.emitList.append(
         {
             'state': 'motdReceived',
             'channel': str(channel),
             'topic': str(topic),
             'message': str(msg)
         }
     )
예제 #6
0
 def parseChatResponse(self, data):
     name, data = Protocol.extractTLV(data)
     msg, data = Protocol.extractTLV(data)
     try:
         msg = msg.decode('utf-8')
         name = name.decode('utf-8')
     except ValueError:
         pass
     logging.debug(u"<{}> {}".format(name, msg))
     self.emitList.append(
         {
             'state': 'chatReceived',
             'message': str(msg),
             'name': str(name)
         }
     )
예제 #7
0
 def parseStateChangesResponse(self, data):
     count, data = Protocol.extractInt(data)
     while count > 0 and len(data) >= 4:
         state, p1, p2, playerinfo, data = self.__class__.extractStateChangesResponse(
             data
         )
         msg = f'State: {state}, p1: {p1}, p2: {p2}, playerInfo: {playerinfo}, data: {data}'
         logging.debug(msg)
         count -= 1
예제 #8
0
 def parseAuthResponse(self, data):
     if len(data) < 4:
         logging.error("Unknown auth response {}".format(repr(data)))
         return
     result, data = Protocol.extractInt(data)
     if result == 0:
         self.selectTimeout = 15
         self.emitList.append(
             {
                 'state': 'logingSuccess'
             }
         )
     else:
         if self.tcpSock:
             self.tcpSock.close()
             self.tcpConnected = False
         self.emitList.append(
             {
                 'state': 'statusMessage',
                 'message': f'login failed {result}'
             }
         )
         if result == 6:
             self.emitList.append(
                 {
                     'state': 'statusMessage',
                     'message': 'login failed wrong password'
                 }
             )
         elif result == 9:
             self.emitList.append(
                 {
                     'state': 'statusMessage',
                     'message': 'too many connections'
                 }
             )
         elif result == 4:
             self.emitList.append(
                 {
                     'state': 'statusMessage',
                     'message': 'Username doesns exist in database'
                 }
             )
         elif result == 8:
             self.emitList.append(
                 {
                     'state': 'statusMessage',
                     'message': 'Clone connection closed, please login again'
                 }
             )
         else:
             self.emitList.append(
                 {
                     'state': 'statusMessage',
                     'message': f'login failed {result}'
                 }
             )
예제 #9
0
    def sendJoinChannelRequest(self, channel=None):
        if channel:
            self.channel = channel
            if channel in self.channels:
                if channel != 'lobby':
                    self.rom = self.channels[channel]['rom']
                else:
                    self.rom = ''
            else:
                logging.error("Invalid channel {}".format(channel))

        if (int(self.channelport) != int(self.channels[channel]['port'])):
            self.switchingServer = True
            self.channelport = int(self.channels[channel]['port'])
            self.tcpSock.close()
            self.sequence = 0x1
            self.connectTcp()
            self.sendWelcome()
            self.sendAuth(self.username, self.password)
        self.sendAndRemember(Protocol.JOIN_CHANNEL,
                             Protocol.packTLV(self.channel)
                             )
예제 #10
0
 def dispatch(self, seq, data):
     logging.debug(
         'Dispatch ' + Protocol.outOfBandCodeToString(seq) + ' ' + repr(data)
     )
     # out of band data
     if seq == Protocol.CHAT_DATA:
         self.parseChatResponse(data)
     elif seq == Protocol.PLAYER_STATE_CHANGE:
         self.parseStateChangesResponse(data)
     elif seq == Protocol.CHALLENGE_DECLINED:
         pass
     elif seq == Protocol.CHALLENGE_RECEIVED:
         pass
     elif seq == Protocol.CHALLENGE_RETRACTED:
         pass
     elif seq == Protocol.JOINING_A_CHANNEL:
         self.parseJoinChannelResponse(data)
     elif seq == Protocol.SPECTATE_GRANTED:
         pass
     else:
         # in band response to our previous request
         self.dispatchInbandData(seq, data)
예제 #11
0
 def sendChat(self, line):
     if self.channel == 'unsupported' and self.unsupportedRom:
         line = '[' + self.unsupportedRom + '] ' + line
     self.sendAndRemember(Protocol.CHAT, Protocol.packTLV(line))
예제 #12
0
 def sendAndForget(self, command, data=b''):
     logging.debug('Sending {} seq {} {}'.format(
         Protocol.codeToString(command), self.sequence, repr(data))
     )
     self.sendtcp(struct.pack('!I', command) + data)
예제 #13
0
 def parseListUsersResponse(self, data):
     self.resetPlayers()
     if not data:
         return
     status, data = Protocol.extractInt(data)
     status2, data = Protocol.extractInt(data)
     while len(data) > 8:
         p1, data = Protocol.extractTLV(data)
         # if len(data) <= 4: break
         state, data = Protocol.extractInt(data)
         p2, data = Protocol.extractTLV(data)
         ip, data = Protocol.extractTLV(data)
         unk1, data = Protocol.extractInt(data)
         unk2, data = Protocol.extractInt(data)
         city, data = Protocol.extractTLV(data)
         cc, data = Protocol.extractTLV(data)
         if cc:
             cc = cc.lower()
         country, data = Protocol.extractTLV(data)
         port, data = Protocol.extractInt(data)
         spectators, data = Protocol.extractInt(data)
         self.addUser(
             player=p1,
             ip=ip,
             port=port,
             city=city,
             cc=cc,
             country=country,
             spectators=spectators+1,
         )
         if state == PlayerStates.AVAILABLE:
             self.available[p1] = True
         elif state == PlayerStates.AFK:
             self.awayfromkb[p1] = True
         elif state == PlayerStates.PLAYING:
             if not p2:
                 p2 = 'null'
             self.playing[p1] = p2
     self.emitList.append(
         {
             'state': 'playersLoaded',
         }
     )
     if len(data) > 0:
         logging.error(
             'List users - REMAINING DATA len {} {}'.format(len(data), repr(data))
         )
예제 #14
0
 def extractStateChangesResponse(data):
     if len(data) >= 4:
         code, data = Protocol.extractInt(data)
         p1, data = Protocol.extractTLV(data)
         if code == 0:
             p2 = ''
             return PlayerStates.QUIT, p1, p2, None, data
         elif code != 1:
             logging.error(
                 "Unknown player state change code {}".format(code)
             )
         state, data = Protocol.extractInt(data)
         p2, data = Protocol.extractTLV(data)
         if not p2:
             p2 = "null"
         ip, data = Protocol.extractTLV(data)
         # \xff\xff\xff\x9f
         # \x00\x00\x00&
         unknown1, data = Protocol.extractInt(data)
         unknown2, data = Protocol.extractInt(data)
         city, data = Protocol.extractTLV(data)
         cc, data = Protocol.extractTLV(data)
         if cc:
             cc = cc.lower()
         country, data = Protocol.extractTLV(data)
         # \x00\x00\x17y
         marker, data = Protocol.extractInt(data)
         playerinfo = dict(
             player=p1,
             ip=ip,
             city=city,
             cc=cc,
             country=country,
             spectators=0,
         )
         return state, p1, p2, playerinfo, data