diff --git a/client.py b/client.py index ff0aa25..8e9b6e2 100755 --- a/client.py +++ b/client.py @@ -43,7 +43,7 @@ import struct import xml.etree.ElementTree as ET import hashlib import time - +import signal INVALID_SLOT = 0xff @@ -516,6 +516,7 @@ 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 @@ -528,6 +529,7 @@ class TActionCode(IntEnum): ACTION_TARGET_SLOT_CODE = 40 ACTION_DUMMY_CODE = 99 + class CLFECOMMON(IntEnum): SYSTEM_LOGIN_CODE = 0 SYSTEM_SYNC_CODE = 1 @@ -541,6 +543,7 @@ class CLFECOMMON(IntEnum): SYSTEM_ACK_QUIT_CODE = 9 NumBitsInLongAck = 512 + class Card(IntEnum): BEGIN_TOKEN = 0 END_TOKEN = 1 @@ -552,7 +555,6 @@ class Card(IntEnum): EXTEND_TOKEN = 7 - class TType(IntEnum): STRUCT_BEGIN = 0 STRUCT_END = 1 @@ -1811,7 +1813,6 @@ class ClientNetworkConnection: self._CurrentReceivedNumber = 0 self._SystemMode = 0 self._LastReceivedAck = 0 - self._LatestProbe = 0 self._LastReceivedNumber = 0 self._LastAckInLongAck = 0 self._MsgXmlMD5 = None @@ -1837,8 +1838,20 @@ class ClientNetworkConnection: self._LatestSyncTime = 0 self._ImpulseDecoder = CImpulseDecoder() self._LongAckBitField.resize(1024) + self._LatestProbeTime = 0 + self._LatestProbe = 0 + self._LatestProbes = [] + self._LatestQuitTime = 0 + self._ReceivedAckQuit = False + + def signal_exit(self, sig, frame): + self.log.warning("Receive signal to quit program") + self.sendSystemQuit() + sys.exit(0) def connect(self): + signal.signal(signal.SIGINT, self.signal_exit) + signal.signal(signal.SIGTERM, self.signal_exit) try: self._sock = socket.socket(socket.AF_INET, # Internet socket.SOCK_DGRAM) # UDP @@ -1890,8 +1903,6 @@ class ClientNetworkConnection: self._ConnectionState = TConnectionState.Quit def sendSystemAckSync(self): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemAckSync() - if self._sock is None: - raise ValueError self.log.debug("sendSystemAckSync") msgout = BitStream() self.buildSystemHeader(msgout) @@ -1900,12 +1911,21 @@ class ClientNetworkConnection: 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 sendSystemAckProbe(self): + self.log.debug("sendSystemAckProbe") + msgout = BitStream() + self.buildSystemHeader(msgout) + msgout.pushUint8(CLFECOMMON.SYSTEM_ACK_PROBE_CODE) + msgout.pushSint32(len(self._LatestProbes)) + for data in self._LatestProbes: + msgout.pushSint32(data) + self._LatestProbes = [] + self._sock.sendto(msgout.toBytes(), self.frontend) + + def sendSystemDisconnection(self): if self._sock is None: raise ValueError @@ -1987,8 +2007,10 @@ class ClientNetworkConnection: return True def receiveSystemProbe(self, msg): + self._LatestProbeTime = self._UpdateTime self._LatestProbe = msg.readSint32() self.log.debug("LatestProbe: %d" % self._LatestProbe) + self._LatestProbes.append(self._LatestProbe) def receiveSystemStalled(self, msg): self.log.debug("received STALLED") @@ -2024,6 +2046,11 @@ class ClientNetworkConnection: self.log.debug("received normal message Packet (%d)" % (msgin.needRead())) self.impulseDecode(msgin) + def receiveSystemAckQuit(self, msgin): + self.log.debug("received ACK_QUIT") + self._ReceivedAckQuit = True + + def disconnect(self): self.log.info("Disconnect") self.sendSystemDisconnection() @@ -2128,15 +2155,103 @@ class ClientNetworkConnection: return True return False + def stateProbe(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.log.debug("probe->synchronize") + self._ConnectionState = TConnectionState.Synchronize + self.receiveSystemSync(msgin) + return True + elif message == CLFECOMMON.SYSTEM_STALLED_CODE: + self.log.debug("probe->stalled") + self._ConnectionState = TConnectionState.Stalled + self.receiveSystemStalled(msgin) + return True + elif message == CLFECOMMON.SYSTEM_PROBE_CODE: + self.receiveSystemProbe(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 Probe" % 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("received normal in state Probe") + + if (len(self._LatestProbes) > 0) or (self._UpdateTime - self._LatestProbeTime > 300): + self.sendSystemAckProbe() + self._LatestProbeTime = self._UpdateTime + + return False + + def stateStalled(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.log.debug("stalled->synchronize") + self._ConnectionState = TConnectionState.Synchronize + self.receiveSystemSync(msgin) + return True + elif message == CLFECOMMON.SYSTEM_PROBE_CODE: + self.log.debug("stalled->probe") + self._ConnectionState = TConnectionState.Probe + self.receiveSystemProbe(msgin) + elif message == CLFECOMMON.SYSTEM_STALLED_CODE: + self.receiveSystemStalled(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 Stalled" % 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("received normal in state Stalled") + return False + + def stateQuit(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.log.debug("quit->synchronize") + self._ConnectionState = TConnectionState.Synchronize + self.receiveSystemSync(msgin) + return True + elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE: + self.disconnect() + self.log.warning("BACK-END DOWN") + return False + elif message == CLFECOMMON.SYSTEM_ACK_QUIT_CODE: + self.receiveSystemAckQuit(msgin) + else: + self.log.warning("CNET: received system %d in state Quit" % 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("received normal in state Quit") + if not self._ReceivedAckQuit and (self._UpdateTime - self._LatestQuitTime > 100): + self.sendSystemQuit() + self._LatestQuitTime = self._UpdateTime + return False + def update(self): # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::update() self._UpdateTime = int(time.clock_gettime(1)*1000) - #self._UpdateTicks = 0 self._ReceivedSync = False if not self._sock: return False + # TODO - REMOVE this counter (just to stop loop) + counterLoop = 0 + stateBroke = True while stateBroke: buffer, addr = self.buildStream() @@ -2154,15 +2269,18 @@ class ClientNetworkConnection: stateBroke = self.stateConnected(msgin) elif self._ConnectionState == TConnectionState.Probe: self.log.debug("state:Probe") - stateBroke = False + stateBroke = self.stateProbe(msgin) elif self._ConnectionState == TConnectionState.Stalled: self.log.debug("state:Stalled") - stateBroke = False + stateBroke = self.stateStalled(msgin) elif self._ConnectionState == TConnectionState.Quit: self.log.debug("state:Quit") - stateBroke = False + stateBroke = self.stateQuit(msgin) else: stateBroke = False + counterLoop += 1 + if counterLoop > 10: + break def EmulateFirst(self, msgRawXml, databaseRawXml): self.msgXml = ET.fromstring(msgRawXml) @@ -2178,7 +2296,7 @@ class ClientNetworkConnection: self.sendSystemLogin() self.log.info("Receive Message") - for i in range(0, 20): # while True: + for i in range(0, 2): # while True: self.log.debug('loop %d' % i) self.update()