From 4b37c73acb9c667775d12fe5169099f8eb407104 Mon Sep 17 00:00:00 2001 From: AleaJactaEst Date: Fri, 31 May 2019 19:25:04 +0200 Subject: [PATCH] decode some message server, and reoganize code --- client.py | 683 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 572 insertions(+), 111 deletions(-) diff --git a/client.py b/client.py index 254e8d6..ff0aa25 100755 --- a/client.py +++ b/client.py @@ -45,6 +45,8 @@ import hashlib import time +INVALID_SLOT = 0xff + class BitStream(): def __init__(self): self._pos = 0 @@ -278,21 +280,7 @@ class BitStream(): self._read = readBefore return ret -def getTextMD5(dataRawXml): - log = logging.getLogger('myLogger') - dataNew = '' - for data in dataRawXml: - if data != '\r': # '\015' ignore caractère \r\n => - dataNew += data - else: - log.debug("***** data:%d" % (ord(data))) - m = hashlib.md5() - m.update(dataNew.encode('utf-8')) - #print(m.hexdigest()) - #print(m.digest()) - return m.digest() - -def Test(): +def TestBitStream(): a = BitStream() a.pushBool(True) a.pushBool(False) @@ -349,6 +337,94 @@ def Test(): print(b.readChar()) print(b.readString()) print(b.toBytes()) +NL_BITLEN = 32 +class CBitSet: + def __init__(self): + self.data = self.resize(1024) + self.NumBits = 0 + self.MaskLast = 0 + + def resize(self, numBits): + self.data = [ 0 for _ in range(0, (numBits +NL_BITLEN - 1) // NL_BITLEN) ] + self.NumBits = numBits + nLastBits = self.NumBits & (NL_BITLEN-1) + if nLastBits == 0: + self.MaskLast = ~0 + else: + self.MaskLast = (1 << nLastBits)-1 + self.clearAll() + + def clearData(self): + self.data = [] + self.NumBits = 0 + self.MaskLast = 0 + + def clearAll(self): + for i in range(0, len(self.data)): + self.data[i] = 0 + + def set(self, bitNumber, value): + mask = bitNumber & (NL_BITLEN-1) + mask = 1 << mask + if value: + self.data[bitNumber >> 5] |= mask + else: + self.data[bitNumber >> 5] &= ~mask + + def get(self, bitNumber): + mask= bitNumber&(NL_BITLEN-1); + mask= 1<> 5] & mask != 0 + + def setBit(self, bitNumber): + self.set(bitNumber, True) + + def clearBit(self, bitNumber): + self.set(bitNumber, False) + + def __str__(self): + return '.'.join([hex(x) for x in self.data]) + def writeSerial(self, msgout): +# v = 0 # currentVersion +# if v >= 0xff: +# msgout.pushUint8(0xff) +# msgout.pushUint8(v) +# else: +# msgout.pushUint8(v) + msgout.pushUint8(0) # currentVersion =0 + msgout.pushUint32(self.NumBits) + msgout.pushUint32(len(self.data)) # il est lié à 'self.NumBits' dommage que l'on envoie celui-la + for x in self.data: + msgout.pushUint32(x) + +def TestCBitSet(): + cBitSet = CBitSet() + cBitSet.resize(1024) + cBitSet.set(1, True) + cBitSet.set(3, True) + cBitSet.set(2, False) + cBitSet.set(13, True) + cBitSet.set(128, True) + cBitSet.set(1023, True) + print(cBitSet) + print(cBitSet.get(3)) + cBitSet.set(3, False) + print(cBitSet) + print(cBitSet.get(3)) + +def getTextMD5(dataRawXml): + log = logging.getLogger('myLogger') + dataNew = '' + for data in dataRawXml: + if data != '\r': # '\015' ignore caractère \r\n => + dataNew += data + else: + log.debug("***** data:%d" % (ord(data))) + m = hashlib.md5() + m.update(dataNew.encode('utf-8')) + #print(m.hexdigest()) + #print(m.digest()) + return m.digest() class CFileChild(): def __init__(self, name, pos, size): @@ -440,6 +516,30 @@ class TConnectionState(IntEnum): Disconnect = 8 # disconnect() called, or timeout, or connection closed by frontend Quit = 9 # quit() called +class TActionCode(IntEnum): + ACTION_POSITION_CODE = 0 + ACTION_GENERIC_CODE = 1 + ACTION_GENERIC_MULTI_PART_CODE = 2 + ACTION_SINT64 = 3 + ACTION_SYNC_CODE = 10 + ACTION_DISCONNECTION_CODE = 11 + ACTION_ASSOCIATION_CODE = 12 + ACTION_LOGIN_CODE = 13 + ACTION_TARGET_SLOT_CODE = 40 + ACTION_DUMMY_CODE = 99 + +class CLFECOMMON(IntEnum): + SYSTEM_LOGIN_CODE = 0 + SYSTEM_SYNC_CODE = 1 + SYSTEM_ACK_SYNC_CODE = 2 + SYSTEM_PROBE_CODE = 3 + SYSTEM_ACK_PROBE_CODE = 4 + SYSTEM_DISCONNECTION_CODE = 5 + SYSTEM_STALLED_CODE = 6 + SYSTEM_SERVER_DOWN_CODE = 7 + SYSTEM_QUIT_CODE = 8 + SYSTEM_ACK_QUIT_CODE = 9 + NumBitsInLongAck = 512 class Card(IntEnum): BEGIN_TOKEN = 0 @@ -546,37 +646,37 @@ class CArgV5(Union): ("f64", c_double), ("ex", CArgV4)] -# union -# { -# struct -# { -# uint32 i32_1; -# uint32 i32_2; -# } i; -# -# sint32 i32; -# sint64 i64; -# float f32; -# double f64; -# -# struct -# { -# uint32 ExType; -# union -# { -# struct -# { -# uint32 ex32_1; -# uint32 ex32_2; -# }; -# -# uint32 ExData32; -# uint64 ExData64; -# } ex; -# } ex; -# } _Value; - class CArg: + # union + # { + # struct + # { + # uint32 i32_1; + # uint32 i32_2; + # } i; + # + # sint32 i32; + # sint64 i64; + # float f32; + # double f64; + # + # struct + # { + # uint32 ExType; + # union + # { + # struct + # { + # uint32 ex32_1; + # uint32 ex32_2; + # }; + # + # uint32 ExData32; + # uint64 ExData64; + # } ex; + # } ex; + # } _Value; + def __init__(self): self._value = CArgV5() self._value.ii64 = 0 @@ -1478,7 +1578,223 @@ class CPersistentDataRecord: break + +class CAction: + def __init__(self, slot=INVALID_SLOT, code=0): + self.Code = code + self.PropertyCode = code + self.Slot = slot + self._Priority = 1 + self.Timeout = 0 + self.GameCycle = 0 + + def unpack(self, message): + raise RuntimeError + + def pack(self, message): + raise RuntimeError + + def serialIn(self, msgin): + raise RuntimeError + + def serialOut(self, msgout): + raise RuntimeError + + def size(self): + raise RuntimeError + + def getMaxSizeInBit(self): + raise RuntimeError + + def setPriority(self, prio): + raise RuntimeError + + def priority(self): + raise RuntimeError + + def getValue(self): + raise RuntimeError + + def setValue(self, value): + raise RuntimeError + + def isContinuous(self): + raise RuntimeError + + def reset(self): + raise RuntimeError + + def __str__(self): + return "[%d,%d]" % (self.Code , self.Slot) + +class CActionPosition(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionSync(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionDisconnection(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionAssociation(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionDummy(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionLogin(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionTargetSlot(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionGeneric(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + self._Message = None + + def unpack(self, message): + size = message.readUint32() + self._Message = message.readArrayUint8(size) + +class CActionGenericMultiPart(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + self.PartCont = [] + self.Number = 0 + self.Part = 0 + self.NbBlock = 0 + + def unpack(self, message): + self.Number = message.readUint8() + self.Part = message.readUint16() + self.NbBlock = message.readUint16() + + size = message.readUint32() + self.PartCont = message.readArrayUint8(size) + +class CActionSint64(CAction): + def __init__(self, slot, code): + super().__init__(slot, code) + +class CActionFactory: + def __init__(self): + self.RegisteredAction = [] + + def create(self, slot, code): + if code == TActionCode.ACTION_POSITION_CODE: + return CActionPosition(slot, code) + elif code == TActionCode.ACTION_GENERIC_CODE: + return CActionGeneric(slot, code) + elif code == TActionCode.ACTION_GENERIC_MULTI_PART_CODE: + return CActionGenericMultiPart(slot, code) + elif code == TActionCode.ACTION_SINT64: + return CActionSint64(slot, code) + elif code == TActionCode.ACTION_SYNC_CODE: + return CActionSync(slot, code) + elif code == TActionCode.ACTION_DISCONNECTION_CODE: + return CActionDisconnection(slot, code) + elif code == TActionCode.ACTION_ASSOCIATION_CODE: + return CActionAssociation(slot, code) + elif code == TActionCode.ACTION_LOGIN_CODE: + return CActionLogin(slot, code) + elif code == TActionCode.ACTION_TARGET_SLOT_CODE: + return CActionTargetSlot(slot, code) + elif code == TActionCode.ACTION_DUMMY_CODE: + return CActionDummy(slot, code) + else: + log = logging.getLogger('myLogger') + log.warning('create() try to create an unknown action (%u)' % code) + raise RuntimeError + + def unpack(self, msgin): + ''' + khanat-opennel-code/code/ryzom/common/src/game_share/action_factory.cpp : CAction *CActionFactory::unpack (NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ ) + ''' + actions = [] + if msgin.needRead() >= 8: + shortcode = msgin.readBool() + if shortcode: + code = msgin.readSerial(2) + else: + code = msgin.readUint8() + action = self.create(INVALID_SLOT, code) + if action: + try: + action.unpack (msgin); + except RuntimeError: + log = logging.getLogger('myLogger') + log.warning('Missing code to unpack (code :%u)' % code) + raise RuntimeError + actions.append(action) + else: + log = logging.getLogger('myLogger') + log.warning('Unpacking an action with unknown code, skip it (%u)' % code) + return actions + +class CImpulseDecoder: + ''' + see : khanat-opennel-code/code/ryzom/client/src/impulse_decoder.cpp + ''' + def __init__(self): + self.reset() + self._CActionFactory = CActionFactory() + + def decode(self, msgin, receivedPacket, receivedAck, nextSentPacket): + actions = [] + for level in range(0, 3): + if level == 0: + lAck = self._LastAck0 + channel = 0 + elif level == 1: + lAck = self._LastAck1 + channel = receivedPacket & 1 + elif level == 2: + lAck = self._LastAck2 + channel = receivedPacket & 3 + keep = True + checkOnce = False + num = 0 + # lastAck = lAck[channel] + while True: + next = msgin.readBool() + if not next: + break + if not checkOnce: + checkOnce = True + keep = receivedAck >= lAck[channel] + if keep: + lAck[channel] = nextSentPacket + num += 1 + action = self._CActionFactory.unpack(msgin) + if keep: + actions.append(action) + else: + pass + + return actions + + def reset(self): + self._LastAck0 = [-1] + self._LastAck1 = [-1, -1] + self._LastAck2 = [-1, -1, -1, -1] + class ClientNetworkConnection: + ''' + Partie client de la gestion de la communication reseau avec le serveur: + + client : + code/ryzom/client/src/network_connection.cpp + server : + khanat-opennel-code/code/ryzom/server/src/frontend_service/fe_receive_sub.cpp # void CFeReceiveSub::handleReceivedMsg( CClientHost *clienthost ) + ''' def __init__(self, khanat_host, khanat_port_frontend, @@ -1491,8 +1807,7 @@ class ClientNetworkConnection: self._ConnectionState = TConnectionState.NotInitialised self.UserAddr, self.UserKey, self.UserId = None, None, None self.frontend = (khanat_host, khanat_port_frontend) - self._sock = socket.socket(socket.AF_INET, # Internet - socket.SOCK_DGRAM) # UDP + self._sock = None self._CurrentReceivedNumber = 0 self._SystemMode = 0 self._LastReceivedAck = 0 @@ -1518,7 +1833,21 @@ class ClientNetworkConnection: self.checkMessageNumber = checkMessageNumber self._LastAckBit = 0 self._AckBitMask = 0 - self._LongAckBitField = 0 + self._LongAckBitField = CBitSet() + self._LatestSyncTime = 0 + self._ImpulseDecoder = CImpulseDecoder() + self._LongAckBitField.resize(1024) + + def connect(self): + try: + self._sock = socket.socket(socket.AF_INET, # Internet + socket.SOCK_DGRAM) # UDP + except: + self.log.error("Impossible to connect on khanat") + return False + self._ConnectionState = TConnectionState.Login + self._LatestSyncTime = int(time.clock_gettime(1)*1000) + return True def cookiesInit(self, UserAddr, UserKey, UserId): self.UserAddr = UserAddr @@ -1528,22 +1857,22 @@ class ClientNetworkConnection: def reset(self): self._CurrentSendNumber += 0 - def buildSystemHeader(self, msg): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::buildSystemHeader(NLMISC::CBitMemStream &msgout) - msg.pushSint32(self._CurrentSendNumber) - msg.pushBool(True) # systemMode + def buildSystemHeader(self, msgout): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::buildSystemHeader(NLMISC::CBitMemStream &msgout) + msgout.pushSint32(self._CurrentSendNumber) + msgout.pushBool(True) # systemMode def sendSystemLogin(self): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemLogin() if self._sock is None: raise ValueError - msg = BitStream() - self.buildSystemHeader(msg) - msg.pushUint8(0) # SYSTEM_LOGIN_CODE - msg.pushUint32(self.UserAddr) - msg.pushUint32(self.UserKey) - msg.pushUint32(self.UserId) - msg.pushString(self.LanguageCode) + msgout = BitStream() + self.buildSystemHeader(msgout) + msgout.pushUint8(CLFECOMMON.SYSTEM_LOGIN_CODE) + msgout.pushUint32(self.UserAddr) + msgout.pushUint32(self.UserKey) + msgout.pushUint32(self.UserId) + msgout.pushString(self.LanguageCode) - self._sock.sendto(msg.toBytes(), self.frontend) + self._sock.sendto(msgout.toBytes(), self.frontend) self._CurrentSendNumber += 1 self._ConnectionState = TConnectionState.Login @@ -1553,25 +1882,37 @@ class ClientNetworkConnection: if self._sock is None: raise ValueError self._QuitId += 1 - msg = BitStream() - self.buildSystemHeader(msg) - msg.pushUint8(8) # SYSTEM_LOGIN_CODE - msg.pushSint32(self._QuitId) # _QuitId - self._sock.sendto(msg.toBytes(), self.frontend) + msgout = BitStream() + self.buildSystemHeader(msgout) + msgout.pushUint8(CLFECOMMON.SYSTEM_QUIT_CODE) + msgout.pushSint32(self._QuitId) # _QuitId + self._sock.sendto(msgout.toBytes(), self.frontend) self._ConnectionState = TConnectionState.Quit def sendSystemAckSync(self): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemAckSync() if self._sock is None: raise ValueError - msg = BitStream() - self.buildSystemHeader(msg) - msg.pushUint8(2) # SYSTEM_ACK_SYNC_CODE - msg.pushSint32(self._LastReceivedNumber) - msg.pushSint32(self._LastAckInLongAck) - msg.pushSint32(self._LongAckBitField) # Signale le nombre de packet perdu - msg.pushSint32(self._LatestSync) - self.log.error("TODO") - # self._sock.sendto(msg.toBytes(), self.frontend) + self.log.debug("sendSystemAckSync") + msgout = BitStream() + self.buildSystemHeader(msgout) + msgout.pushUint8(CLFECOMMON.SYSTEM_ACK_SYNC_CODE) + msgout.pushSint32(self._LastReceivedNumber) + msgout.pushSint32(self._LastAckInLongAck) + self._LongAckBitField.writeSerial(msgout) # Signale le nombre de packet perdu + msgout.pushSint32(self._LatestSync) + + self.log.debug("%s" % msgout.message()) + self.log.debug("sendSystemAckSync -> send") + self._sock.sendto(msgout.toBytes(), self.frontend) + self._LatestSyncTime = self._UpdateTime + + def sendSystemDisconnection(self): + if self._sock is None: + raise ValueError + msgout = BitStream() + self.buildSystemHeader(msgout) + msgout.pushUint8(CLFECOMMON.SYSTEM_DISCONNECTION_CODE) + self._sock.sendto(msgout.toBytes(), self.frontend) def readDelta(self, msg): propertyCount = msg.readUint16() @@ -1587,8 +1928,12 @@ class ClientNetworkConnection: self.log.debug("serverTick:%d" % serverTick) #self.readDelta(msg) - # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::buildStream( CBitMemStream &msgin ) + def impulseDecode(self, msgin): + actions = self._ImpulseDecoder.decode(msgin, self._CurrentReceivedNumber, self._LastReceivedAck, self._CurrentSendNumber ) + self.log.debug(str(actions)) + def buildStream(self, buffersize=65536): + # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::buildStream( CBitMemStream &msgin ) data, addr = self._sock.recvfrom(buffersize) return data, addr @@ -1605,7 +1950,10 @@ class ClientNetworkConnection: self._LastReceivedPacketInBothModes = self._CurrentReceivedNumber - 1 if not self._SystemMode: + self.log.debug("Normal Mode") self._LastReceivedAck = msg.readSint32(); + else: + self.log.debug("System Mode") if self._CurrentReceivedNumber > self._LastReceivedNumber+1: self.log.debug("lost messages server->client [%d; %d]" %(self._LastReceivedPacketInBothModes + 1, self._CurrentReceivedNumber - 1)) @@ -1628,13 +1976,14 @@ class ClientNetworkConnection: self._AckBitMask = 0x00000000 self._LastAckBit = ackBit; for i in range(self._LastReceivedNumber+1, self._CurrentReceivedNumber+1): - if self._LongAckBitField & (i & (512-1)) > 1: - self._LongAckBitField = self._LongAckBitField ^ (i & (512-1)) - if ackBool: - self._LongAckBitField = self._LongAckBitField | (self._CurrentReceivedNumber & (512 - 1)) - self._LongAckBitField %= 512 + self._LongAckBitField.clearBit(i & 511) + self._LongAckBitField.set(self._CurrentReceivedNumber & 511, ackBool) + + if self._LastAckInLongAck <= (self._CurrentReceivedNumber-512): + self._LastAckInLongAck = self._CurrentReceivedNumber-511; + self._LastReceivedNumber = self._CurrentReceivedNumber - self.log.debug("_CurrentReceivedNumber:%d, _LastReceivedNumber:%d, ackBit:%d, _AckBitMask:%d _LongAckBitField:%d" % (self._CurrentReceivedNumber, self._LastReceivedNumber, ackBit, self._AckBitMask, self._LongAckBitField)) + self.log.debug("_CurrentReceivedNumber:%d, _LastReceivedNumber:%d, ackBit:%d, _AckBitMask:%d _LongAckBitField:%s" % (self._CurrentReceivedNumber, self._LastReceivedNumber, ackBit, self._AckBitMask, self._LongAckBitField)) return True def receiveSystemProbe(self, msg): @@ -1645,6 +1994,7 @@ class ClientNetworkConnection: self.log.debug("received STALLED") def receiveSystemSync(self, msg): + self._LatestSyncTime = self._UpdateTime self._Synchronize = msg.readUint32() stime = msg.readSint64() self._LatestSync = msg.readUint32() @@ -1670,8 +2020,113 @@ class ClientNetworkConnection: self._CurrentClientTime = self._UpdateTime - (self._LCT + self._MsPerTick) self.sendSystemAckSync() + def receiveNormalMessage(self, msgin): + self.log.debug("received normal message Packet (%d)" % (msgin.needRead())) + self.impulseDecode(msgin) + def disconnect(self): - pass + self.log.info("Disconnect") + self.sendSystemDisconnection() + self._sock.close() + selc._sock = None + self._ConnectionState = TConnectionState.Disconnect + + def stateLogin(self, msgin): + self.decodeHeader(msgin) + if self._SystemMode: + message = msgin.readUint8() + self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead())) + if message == CLFECOMMON.SYSTEM_SYNC_CODE: + self._ConnectionState = TConnectionState.Synchronize + self.log.debug("Login->synchronize") + self.receiveSystemSync(msgin) + return True + elif message == CLFECOMMON.SYSTEM_STALLED_CODE: + self.log.debug("received STALLED") + self._ConnectionState = TConnectionState.Stalled + self.receiveSystemStalled(msgin) + return True + elif message == CLFECOMMON.SYSTEM_PROBE_CODE: + self.log.debug("Login->probe") + self._ConnectionState = TConnectionState.Probe + self.receiveSystemProbe(msgin) + return True + elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE: + self.disconnect() + self.log.warning("BACK-END DOWN") + return False + else: + self.log.warning("CNET: received system %d in state Login" % message) + self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData())) + else: + self.log.warning("CNET: received normal in state Login") + return False + + def stateSynchronize(self, msgin): + self.decodeHeader(msgin) + if self._SystemMode: + message = msgin.readUint8() + self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead())) + if message == CLFECOMMON.SYSTEM_PROBE_CODE: + self.log.debug("synchronize->probe") + self._ConnectionState = TConnectionState.Probe + self.receiveSystemProbe(msgin) + return True + elif message == CLFECOMMON.SYSTEM_STALLED_CODE: + self.log.debug("received STALLED") + self._ConnectionState = TConnectionState.Stalled + self.receiveSystemStalled(msgin) + return True + elif message == CLFECOMMON.SYSTEM_SYNC_CODE: + self.log.debug("synchronize->synchronize") + self.receiveSystemSync(msgin) + elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE: + self.disconnect() + self.log.warning("BACK-END DOWN") + return False + else: + self.log.warning("CNET: received system %d in state Synchronize" % message) + self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData())) + else: + self._ConnectionState = TConnectionState.Connected + self.log.warning("CNET: synchronize->connected") + # _Changes.push_back(CChange(0, ConnectionReady)); + self.receiveNormalMessage(msgin); + return True + if self._UpdateTime - self._LatestSyncTime > 300: + self.sendSystemAckSync(); + return False + + def stateConnected(self, msgin): + self.decodeHeader(msgin) + if self._SystemMode: + message = msgin.readUint8() + self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead())) + if message == CLFECOMMON.SYSTEM_PROBE_CODE: + self.log.debug("Connected->probe") + self._ConnectionState = TConnectionState.Probe + self.receiveSystemProbe(msgin) + return True + elif message == CLFECOMMON.SYSTEM_SYNC_CODE: + self.log.debug("Connected->synchronize") + self.receiveSystemSync(msgin) + return True + elif message == CLFECOMMON.SYSTEM_STALLED_CODE: + self.log.debug("received STALLED") + self._ConnectionState = TConnectionState.Stalled + self.receiveSystemStalled(msgin) + return True + elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE: + self.disconnect() + self.log.warning("BACK-END DOWN") + return False + else: + self.log.warning("CNET: received system %d in state Connected" % message) + self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData())) + else: + self.receiveNormalMessage(msgin); + return True + return False def update(self): # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::update() @@ -1679,6 +2134,36 @@ class ClientNetworkConnection: #self._UpdateTicks = 0 self._ReceivedSync = False + if not self._sock: + return False + + stateBroke = True + while stateBroke: + buffer, addr = self.buildStream() + self.log.debug("received message: %s" % buffer) + msgin = BitStream() + msgin.fromBytes(buffer) + if self._ConnectionState == TConnectionState.Login: + self.log.debug("state:Login") + stateBroke = self.stateLogin(msgin) + elif self._ConnectionState == TConnectionState.Synchronize: + self.log.debug("state:Synchronize") + stateBroke = self.stateSynchronize(msgin) + elif self._ConnectionState == TConnectionState.Connected: + self.log.debug("state:Connected") + stateBroke = self.stateConnected(msgin) + elif self._ConnectionState == TConnectionState.Probe: + self.log.debug("state:Probe") + stateBroke = False + elif self._ConnectionState == TConnectionState.Stalled: + self.log.debug("state:Stalled") + stateBroke = False + elif self._ConnectionState == TConnectionState.Quit: + self.log.debug("state:Quit") + stateBroke = False + else: + stateBroke = False + def EmulateFirst(self, msgRawXml, databaseRawXml): self.msgXml = ET.fromstring(msgRawXml) #ET.dump(msgXml) @@ -1688,41 +2173,16 @@ class ClientNetworkConnection: self._MsgXmlMD5 = getTextMD5(msgRawXml) self._DatabaseXmlMD5 = getTextMD5(databaseRawXml) + self.connect() self.log.info("Client Login") self.sendSystemLogin() self.log.info("Receive Message") - for _ in range(0, 20): # while True: + for i in range(0, 20): # while True: + self.log.debug('loop %d' % i) self.update() - data, addr = self.buildStream() - self.log.debug("received message: %s" % data) - msg = BitStream() - msg.fromBytes(data) - self.decodeHeader(msg) - # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:bool CNetworkConnection::stateSynchronize() - message = msg.readUint8() - self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msg.sizeData(), msg.sizeRead(), msg.needRead())) - if message == 1: # SYSTEM_SYNC_CODE - self.log.debug("synchronize->synchronize") - self.receiveSystemSync(msg) - elif message == 3: # SYSTEM_PROBE_CODE - self.log.debug("synchronize->probe") - self._ConnectionState = TConnectionState.Probe - self.receiveSystemProbe(msg) - elif message == 6: # SYSTEM_STALLED_CODE - self.log.debug("received STALLED") - self._ConnectionState = TConnectionState.Stalled - self.receiveSystemStalled(msg) - elif message == 7: # SYSTEM_SERVER_DOWN_CODE - self.disconnect() - self.log.warning("BACK-END DOWN") - else: - self.log.warning("CNET: received system %d in state Synchronize" % message) - self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msg.sizeData(), msg.sizeRead(), msg.needRead(), msg.showLastData())) - # self.impulseCallBack(data) - - self.log.info("Client Logout") + self.log.info("Client Quit") self.sendSystemQuit() @@ -2041,5 +2501,6 @@ def main(): log.info("End") if __name__ == "__main__": - #Test() + #TestBitStream() + #TestCBitSet() main()