示例#1
0
    def runFBA(self, quark):
        if not self.checkRom():
            return
        if not self.fba:
            self.sigStatusMessage.emit("Please configure Setting > Locate ggpofba.exe")
            return
        wine = ''
        args = []
        if IS_WINDOWS:
            args = [self.fba, quark, '-w']
        else:
            wine = findWine()
            if not wine:
                self.sigStatusMessage.emit("Please configure Setting > Locate wine")
                return
            if IS_LINUX:
                args = [packagePathJoin('ggpo', 'scripts', 'ggpofba.sh'), wine, self.fba, quark]
            else:
                args = [wine, self.fba, quark]

        logger().info(" ".join(args))
        try:
            # starting python from cmd.exe and redirect stderr and we got
            # python WindowsError(6, 'The handle is invalid')
            # apparently it's still not fixed
            if IS_WINDOWS:
                Popen(args)
            else:
                devnull = open(os.devnull, 'w')
                Popen(args, stdout=devnull, stderr=devnull)
                devnull.close()
        except OSError, ex:
            self.sigStatusMessage.emit("Error executing " + " ".join(args) + "\n" + repr(ex))
示例#2
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:
             logger().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,
         )
         return state, p1, p2, playerinfo, data
示例#3
0
 def sendJoinChannelRequest(self, channel=None):
     if channel:
         self.channel = channel
         Settings.setValue(Settings.SELECTED_CHANNEL, channel)
         if channel in self.channels:
             if channel != 'lobby':
                 self.rom = self.channels[channel]['rom']
         else:
             logger().error("Invalid channel {}".format(channel))
     self.sendAndRemember(Protocol.JOIN_CHANNEL, Protocol.packTLV(self.channel))
示例#4
0
 def selectLoop(self):
     while self.selectLoopRunning:
         inputs = []
         if self.udpConnected:
             inputs.append(self.udpSock)
         if self.tcpConnected:
             inputs.append(self.tcpSock)
         # windows doesn't allow select on 3 empty set
         if not inputs:
             time.sleep(1)
             continue
         inputready, outputready, exceptready = None, None, None
         # http://stackoverflow.com/questions/13414029/catch-interrupted-system-call-in-threading
         try:
             inputready, outputready, exceptready = select.select(inputs, [], [], self.selectTimeout)
         except select.error, ex:
             if ex[0] != errno.EINTR:
                 raise
         if not inputready:
             self.sendPingQueries()
         else:
             for stream in inputready:
                 if stream == self.tcpSock:
                     data = None
                     # noinspection PyBroadException
                     try:
                         data = stream.recv(8192)
                     except:
                         self.tcpConnected = False
                         self.selectLoopRunning = False
                         self.sigServerDisconnected.emit()
                         return
                     if data:
                         self.tcpData += data
                         self.handleTcpResponse()
                     else:
                         stream.close()
                         self.tcpConnected = False
                         self.selectLoopRunning = False
                         self.sigServerDisconnected.emit()
                 elif stream == self.udpSock:
                     dgram = None
                     # on windows xp
                     # Python exception: error: [Errno 10054]
                     # An existing connection was forcibly closed by the remote host
                     # noinspection PyBroadException
                     try:
                         dgram, addr = self.udpSock.recvfrom(64)
                     except:
                         pass
                     if dgram:
                         logger().info("UDP " + repr(dgram) + " from " + repr(addr))
                         self.handleUdpResponse(dgram, addr)
示例#5
0
 def run(cls, checkonly, statusMsgCallback=None, finishedCallback=None):
     if cls._thread:
         logger().error('Already has a download thread running')
     cls._thread = QtCore.QThread()
     cls._worker = SyncWorker(checkonly)
     cls._worker.moveToThread(cls._thread)
     if finishedCallback:
         cls._worker.sigFinished.connect(finishedCallback)
     cls._worker.sigFinished.connect(cls.cleanup)
     if statusMsgCallback:
         cls._worker.sigStatusMessage.connect(statusMsgCallback)
     cls._thread.started.connect(cls._worker.download)
     cls._thread.start()
示例#6
0
 def sendPingQuery(self, player):
     if not self.udpConnected:
         return
     if not player.ip:
         return
     if not player.port:
         player.port = 6009
     num1 = randint(500000, 30000000)
     num2 = randint(4000000, 900000000)
     secret = str(num1) + " " + str(num2)
     message = "GGPO PING " + secret
     logger().info("send GGPO PING {} to {}".format(secret, repr(player.ip)))
     self.sendudp(message, (player.ip, player.port, ))
     self.pinglist[secret] = (player.ip, player.player, time.time())
示例#7
0
    def dispatchInbandData(self, seq, data):
        if not seq in self.tcpCommandsWaitingForResponse:
            logger().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.sigStatusMessage.emit("Fail to spectate " + str(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)
                    logger().error("{} failed, data {}".format(codestr, repr(data)))
                    self.sigActionFailed.emit(codestr)
            else:
                logger().error("Unknown response for {}; seq {}; data {}".format(
                    Protocol.codeToString(origRequest), seq, repr(data)))
        else:
            logger().error("Not handling {} response; seq {}; data {}".format(
                Protocol.codeToString(origRequest), seq, repr(data)))
示例#8
0
 def parseListChannelsResponse(self, data):
     self.channels = {}
     if len(data) <= 8:
         logger().error('No channels found')
         self.sigChannelsLoaded.emit()
         return
     status1, data = Protocol.extractInt(data)
     status2, data = Protocol.extractInt(data)
     logger().info("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)
         unknown, data = Protocol.extractInt(data)
         # 'sfa3': {'title': 'Street Fighter Alpha 3', 'rom': 'sfa3:sfa3u', 'room': 'sfa3'},
         # 'sfa2': {'title': 'Street Fighter Alpha 2', 'rom': 'sfa2', 'room': 'sfa2'},
         channel = {
             'rom': romname.split(':')[0],
             'room': room,
             'title': title,
         }
         self.channels[room] = channel
     logger().info(repr(self.channels))
     self.sigChannelsLoaded.emit()
     if len(data) > 0:
         logger().error('Channel REMAINING DATA len {} {}'.format(len(data), repr(data)))
示例#9
0
    def __init__(self):
        super(Controller, self).__init__()
        self.selectTimeout = 1
        self.sequence = 0x1
        self.tcpSock = None
        self.tcpConnected = False
        self.tcpData = ''
        self.tcpReadState = self.STATE_TCP_READ_LEN
        self.tcpResponseLen = 0
        self.tcpCommandsWaitingForResponse = dict()
        self.udpSock = None
        self.udpConnected = False
        self.selectLoopRunning = True

        self.username = ''
        self.channel = 'lobby'
        self.rom = ''
        self.fba = None
        self.checkInstallation()
        self.unsupportedRom = ''
        self.checkUnsupportedRom()

        self.challengers = set()
        self.challenged = None
        self.channels = {}
        self.pinglist = {}
        self.players = {}
        self.available = {}
        self.playing = {}
        self.awayfromkb = {}
        self.ignored = Settings.pythonValue(Settings.IGNORED) or set()
        self.sigStatusMessage.connect(logger().info)
示例#10
0
 def parseSpectateResponse(self, data):
     p1, data = Protocol.extractTLV(data)
     p2, data = Protocol.extractTLV(data)
     # if the guy I challenged accepted, remove him as challenged
     if self.challenged and self.challenged in [p1, p2] and self.username in [p1, p2]:
         self.challenged = None
     # quark len(53) = 'quark:stream,ssf2t,challenge-07389-1393539605.46,7000'
     quark, data = Protocol.extractTLV(data)
     logger().info("Quark " + repr(quark))
     if quark.startswith('quark:served'):
         smooth = Settings.value(Settings.SMOOTHING)
         if smooth:
             match = re.search(r'[0-9]+', smooth)
             if match:
                 quark += ',{}'.format(match.group(0))
     self.runFBA(quark)
示例#11
0
 def handleUdpResponse(self, dgram, addr):
     if not dgram:
         return
     command = dgram[0:9]
     secret = dgram[10:]
     remoteip, remoteport = addr
     if command == "GGPO PING":
         self.sendudp("GGPO PONG {}".format(secret), addr)
         logger().info("send GGPO PONG {} to {}".format(secret, repr(addr)))
     if dgram[0:9] == "GGPO PONG":
         if secret in self.pinglist:
             ip = self.pinglist[secret][0]
             name = self.pinglist[secret][1]
             t1 = self.pinglist[secret][2]
             t2 = time.time()
             if ip == remoteip:
                 self.updatePlayerPing(name, int((t2 - t1) * 1000))
             del self.pinglist[secret]
示例#12
0
 def debuglogTriggered(value):
     if value:
         level = logging.INFO
     else:
         level = logging.ERROR
     Settings.setBoolean(Settings.DEBUG_LOG, value)
     for handler in logger().handlers:
         if isinstance(handler, logging.handlers.RotatingFileHandler):
             handler.setLevel(level)
             break
示例#13
0
 def parseAuthResponse(self, data):
     if len(data) < 4:
         logger().error("Unknown auth response {}".format(repr(data)))
         return
     result, data = Protocol.extractInt(data)
     if result == 0:
         self.selectTimeout = 15
         self.sigLoginSuccess.emit()
     # password incorrect, user incorrect
     #if result == 0x6 or result == 0x4:
     else:
         if self.tcpSock:
             self.tcpSock.close()
             self.tcpConnected = False
         if self.udpSock:
             self.udpSock.close()
             self.udpConnected = False
         self.sigLoginFailed.emit()
         self.sigStatusMessage.emit("Login failed {}".format(result))
示例#14
0
    def download(self):
        d = findUnsupportedGamesavesDir()
        if not d:
            self.sigStatusMessage.emit('Unsupported Savestates Directory is not set')
            self.sigFinished.emit(self.added, self.updated, self.nochange)
            return
        localJsonDigest = readLocalJsonDigest()
        # noinspection PyBroadException
        try:
            # gotta love CPython's GIL, yield thread
            time.sleep(0.05)
            response = urllib2.urlopen(self.SAVESTATES_INDEX_URL, timeout=3)
            games = json.load(response)

            for filename, shahash in games.items():
                if re.search(r'[^ .a-zA-Z0-9_-]', filename):
                    logger().error("Filename {} looks suspicious, ignoring".format(filename))
                    continue
                if filename in localJsonDigest:
                    if localJsonDigest[filename] == shahash:
                        self.nochange += 1
                        continue
                    else:
                        self.updated += 1
                else:
                    self.added += 1
                if not self.checkonly:
                    time.sleep(0.05)
                    localfile = os.path.join(d, filename)
                    fileurl = self.SAVESTATES_GITHUB_BASE_URL + urllib.quote(filename)
                    urllib.urlretrieve(fileurl, localfile)
                    self.sigStatusMessage.emit('Downloaded {}'.format(localfile))
            if not self.checkonly:
                if not self.added and not self.updated:
                    self.sigStatusMessage.emit('All files are up to date')
                else:
                    writeLocalJsonDigest()
                    self.sigStatusMessage.emit(
                        '{} files are current, added {}, updated {}'.format(
                            self.nochange, self.added, self.updated))
        except Exception, ex:
            logger().error(str(ex))
示例#15
0
 def dispatch(self, seq, data):
     logger().info('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:
         self.parseChallengeDeclinedResponse(data)
     elif seq == Protocol.CHALLENGE_RECEIVED:
         self.parseChallengeReceivedResponse(data)
     elif seq == Protocol.CHALLENGE_RETRACTED:
         self.parseChallengeCancelledResponse(data)
     elif seq == Protocol.JOINING_A_CHANNEL:
         self.parseJoinChannelResponse(data)
     elif seq == Protocol.SPECTATE_GRANTED:
         self.parseSpectateResponse(data)
     else:
         # in band response to our previous request
         self.dispatchInbandData(seq, data)
示例#16
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)
         self.addUser(
             player=p1,
             ip=ip,
             port=port,
             city=city,
             cc=cc,
             country=country,
         )
         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.sigPlayersLoaded.emit()
     if len(data) > 0:
         logger().error('List users - REMAINING DATA len {} {}'.format(len(data), repr(data)))
示例#17
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:
                 logger().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()
示例#18
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)
         if state == PlayerStates.PLAYING:
             self.parsePlayerStartGameResponse(p1, p2, playerinfo)
         elif state == PlayerStates.AVAILABLE:
             self.parsePlayerAvailableResponse(p1, playerinfo)
         elif state == PlayerStates.AFK:
             self.parsePlayerAFKResponse(p1, playerinfo)
         elif state == PlayerStates.QUIT:
             self.parsePlayerLeftResponse(p1)
         else:
             logger().error(
                 "Unknown state change payload state: {} {}".format(state, repr(data)))
         if state == PlayerStates.PLAYING:
             msg = p1 + ' ' + PlayerStates.codeToString(state) + ' ' + p2
         else:
             msg = p1 + ' ' + PlayerStates.codeToString(state)
         logger().info(msg)
         count -= 1
     if len(data) > 0:
         logger().error("stateChangesResponse, remaining data {}".format(repr(data)))
示例#19
0
 def sendAndForget(self, command, data=''):
     logger().info('Sending {} seq {} {}'.format(Protocol.codeToString(command), self.sequence, repr(data)))
     self.sendtcp(struct.pack('!I', command) + data)
示例#20
0
 def sendAndRemember(self, command, data=''):
     logger().info('Sending {} seq {} {}'.format(Protocol.codeToString(command), self.sequence, repr(data)))
     self.tcpCommandsWaitingForResponse[self.sequence] = command
     self.sendtcp(struct.pack('!I', command) + data)