update spykhanat.py (it can generate yaml file with detail message decoded)

This commit is contained in:
AleaJactaEst 2020-04-11 23:52:41 +02:00
parent 390c448bde
commit 5c506cfa32
11 changed files with 807 additions and 52 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*.pcap
*.yaml
*.yml
*.log
*.err

View file

@ -117,7 +117,7 @@ class ClientKhanat:
'Referer': 'http://' + self.khanat_host+':'+ str(self.khanat_port_login) + '/ams/index.php?page=register',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20100101 Firefox/6.0',
'Content-Type': 'application/x-www-form-urlencoded'}
'': 'application/x-www-form-urlencoded'}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
params = urllib.parse.urlencode({'Username': self.login, 'Password': self.password, 'ConfirmPass': self.password, 'Email': self.login+'@khaganat.net', 'TaC': 'on', 'function': 'add_user'})

View file

@ -22,6 +22,9 @@
# sudo tcpdump -i docker0 -w capture2.pcap
# ./spykhanat.py --pcap-file=../capture2.pcap --msg-xml=../khanat-opennel-code/code/ryzom/common/data_common/msg.xml
# install pcapfile
# pip install pypcapfile
import argparse
import logging
from pcapfile import savefile
@ -39,8 +42,9 @@ from tools import DecodeImpulse
from tools import World
from tools import CGenericMultiPartTemp
from tools import CImpulseDecoder
from tools import CStringManager
#from tools import CStringManager
from tools import CAction
from tools import Impulse
import xml.etree.ElementTree as ET
from datetime import datetime
@ -56,6 +60,14 @@ LOGGER = 'SpyKhanat'
#ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
#print(ip_packet)
def write_yaml_str_or_array(outyaml, nbspace, value):
if type(value) == str:
outyaml.write(" " * nbspace + "- %s\n" % (value))
else:
for key in value:
outyaml.write(" " * nbspace + "- %s\n" % (key))
outyaml.write(" " * nbspace + str(type(value)) + "\n")
class SpyPcap():
def __init__(self, khanat_host_service, pcap_file, msg_xml, filter_host_service, show_raw_packet, show_message_decoded, outyaml=None):
if khanat_host_service:
@ -73,11 +85,13 @@ class SpyPcap():
self.actionFactory = CActionFactory.CActionFactory(None)
self.client_state = {}
self.decodeImpulse = DecodeImpulse.DecodeImpulse()
self.decodeImpulseSimple = Impulse.DecodeImpulseSimple()
fp = open(msg_xml , 'rt')
msgRawXml = fp.read()
self.msgXml = ET.fromstring(msgRawXml)
self.decodeImpulse.loadMsg(self.msgXml)
self.decodeImpulseSimple.loadMsg(self.msgXml)
self.outyaml = outyaml
def readRaw(self):
@ -156,7 +170,8 @@ class SpyPcap():
'AckBitMask': 0,
'RegisteredAction': {},
'world': World.World(),
'GenericMultiPartTemp': CGenericMultiPartTemp.GenericMultiPartTemp(),
'GenericMultiPartTempServer': CGenericMultiPartTemp.GenericMultiPartTemp(),
'GenericMultiPartTempClient': CGenericMultiPartTemp.GenericMultiPartTemp(),
'CImpulseDecoder': None,
'CActionFactory': None,
'LastAck0': [-1],
@ -211,18 +226,14 @@ class SpyPcap():
self.add_registered_action(clientid, action)
return actions
# def decode_client_receive_normal_message(self, msgin, clientid, dst):
# actions = self.client_state[clientid]['CImpulseDecoder'].decode(msgin, self.client_state[clientid]['CurrentReceivedNumber'], self.client_state[clientid]['LastReceivedAck'], self.client_state[clientid]['CurrentSendNumber'] )
# logging.getLogger(LOGGER).info("[Client -> Server] actions:%s" % str(actions))
# # decodeVisualProperties( msgin );
def decode_client_send_normal_message(self, msgin, clientid, dst, sequenceid, name):
def decode_client_send_normal_message(self, msgin, clientid, dst, sequenceid, name, Reference):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:2029 void CNetworkConnection::sendNormalMessage()
khanat-opennel-code/code/ryzom/common/src/game_share/action_block.cpp:36 void CActionBlock::serial(CBitMemStream &msg)
'''
#actions = self.client_state[clientid]['CImpulseDecoder'].decode(msgin, self.client_state[clientid]['CurrentReceivedNumber'], self.client_state[clientid]['LastReceivedAck'], self.client_state[clientid]['CurrentSendNumber'] )
actions = []
impulses = []
noerror = True
msgin.disable_LogErrorOnStreamOverflow()
while noerror:
@ -231,7 +242,7 @@ class SpyPcap():
num = msgin.readUint8("num")
logging.getLogger(LOGGER).debug("[Client -> Server] Cycle:%u num:%u" % (cycle, num))
for i in range(0, num):
actions.append(self.client_state[clientid]['CActionFactory'].unpack(msgin))
actions.append(self.client_state[clientid]['CActionFactory'].unpack(msgin, Reference, name))
pass
except BitStream.OverflowError:
noerror = False
@ -240,24 +251,33 @@ class SpyPcap():
raise e
msgin.enable_LogErrorOnStreamOverflow()
ids = 0
for action in actions:
try:
impulse = action.decodeImpulseSimple(
self.decodeImpulseSimple,
self.client_state[clientid]['world'],
self.client_state[clientid]['GenericMultiPartTempClient'],
Reference = name
) #, Reference = Parent, Name = "%s_%d" % (target, 0))
if impulse:
impulses.append(impulse)
except Impulse.ImpulseNoElement:
pass
ids += 1
logging.getLogger(LOGGER).debug("[Client -> Server] detail actions [%d] => %s" % ( len(actions), ', '.join([str(x) for x in actions])))
# decodeVisualProperties( msgin );
if self.outyaml and actions:
self.outyaml.write("\nblock_%s_udp_%d:\n" %(name, sequenceid))
id = 0
for action in actions:
self.outyaml.write(" action_%s_udp_%d_%d:\n" %(name, sequenceid, id))
params = action.get_parameter()
for key in params:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
id += 1
return actions, impulses
def decode_client_message(self, msgin, clientid, dst, sequenceid, name):
def decode_client_message(self, msgin, clientid, dst, sequenceid, name, Parent, Source):
target = "%s_%s" % (Source, Parent[7:])
CurrentReceivedNumber = msgin.readSint32('CurrentReceivedNumber')
SystemMode = msgin.readBool('SystemMode')
logging.getLogger(LOGGER).debug("[Client -> Server] {CurrentReceivedNumber:%d, SystemMode:%d, src:%s, dst:%s}" % (CurrentReceivedNumber, SystemMode, clientid, dst))
self.initialize_client(clientid)
self.client_state[clientid]['CurrentReceivedNumber'] = CurrentReceivedNumber
actions = []
impulses = []
if not SystemMode:
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:2029 void CNetworkConnection::sendNormalMessage()
@ -267,8 +287,8 @@ class SpyPcap():
AckBitMask = msgin.readUint32('AckBitMask')
self.client_state[clientid]['AckBitMask'] = AckBitMask
logging.getLogger(LOGGER).info("[Client -> Server] Normal Mode {CurrentReceivedNumber:%d, src:%s, dst:%s, LastReceivedAck:%d}" % (CurrentReceivedNumber, clientid, dst, LastReceivedAck))
#self.decode_server(msgin, _CurrentReceivedNumber, _CurrentReceivedNumber-1)
self.decode_client_send_normal_message(msgin, clientid, dst, sequenceid, name)
# self.decode_server(msgin, _CurrentReceivedNumber, _CurrentReceivedNumber-1)
actions, _ = self.decode_client_send_normal_message(msgin, clientid, dst, sequenceid, "%s_%d" % (target, 0), Parent)
else:
message = msgin.readUint8('message')
try:
@ -282,10 +302,14 @@ class SpyPcap():
LanguageCode = msgin.readString('LanguageCode')
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, UserAddr:%d, UserId:%d, UserAddr:%d LanguageCode:%s}" %
(typeMessage, CurrentReceivedNumber, clientid, dst, UserAddr, UserKey, UserId, LanguageCode))
action = CAction.CActionFake('SYSTEM_LOGIN_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
LatestProbe = msgin.readSint32('LatestProbe')
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s probe:%d {CurrentReceivedNumber:%d, src:%s, dst:%s}" % (typeMessage,
LatestProbe, CurrentReceivedNumber, clientid, dst))
action = CAction.CActionFake('SYSTEM_PROBE_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
elif message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
Synchronize = msgin.readUint32('Synchronize')
stime = msgin.readSint64('stime')
@ -296,6 +320,8 @@ class SpyPcap():
md5Database = bytes(DatabaseData)
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, Synchronize:%d, stime:%d, LatestSync:%d, MsgData:%s, DatabaseData:%s}" % (
typeMessage, CurrentReceivedNumber, clientid, dst, Synchronize, stime, LatestSync, binascii.hexlify(md5Msg).decode(), binascii.hexlify(md5Database).decode()))
action = CAction.CActionFake('SYSTEM_SYNC_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
elif message == Enum.CLFECOMMON.SYSTEM_ACK_SYNC_CODE:
LastReceivedNumber = msgin.readSint32('LastReceivedNumber')
LastAckInLongAck = msgin.readSint32('LastAckInLongAck')
@ -304,22 +330,31 @@ class SpyPcap():
LatestSync = msgin.readSint32('LatestSync')
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, LastReceivedNumber:%d, LastAckInLongAck:%d, LatestSync:%d, LongAckBitField:%s}" % (
typeMessage, CurrentReceivedNumber, clientid, dst, LastReceivedNumber, LastAckInLongAck, LatestSync, LongAckBitField))
action = CAction.CActionFake('SYSTEM_ACK_SYNC_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
elif message == Enum.CLFECOMMON.SYSTEM_ACK_PROBE_CODE:
SizeLatestProbes = msgin.readSint32('SizeLatestProbes')
LatestProbes = []
for data in range(0, SizeLatestProbes):
LatestProbes.append(msgin.readSint32('LatestProbes'))
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s (%d) {CurrentReceivedNumber:%d, src:%s, dst:%s, SizeLatestProbes:%d, LatestProbes:%s}" % (typeMessage, message, CurrentReceivedNumber, clientid, dst, SizeLatestProbes, str(LatestProbes)))
action = CAction.CActionFake('SYSTEM_ACK_PROBE_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
else:
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s (%d) {CurrentReceivedNumber:%d, src:%s, dst:%s}" % (typeMessage, message, CurrentReceivedNumber, clientid, dst))
logging.getLogger(LOGGER).debug("[Client -> Server] msg:%s" % msgin.showAllData())
return actions, impulses
def decode_khanat_message(self, msgin, src, dst, sequenceid, clientname):
def decode_khanat_message(self, msgin, src, dst, sequenceid, clientname, Parent, Source):
target = "%s_%s" % (Source, Parent[7:])
actions = []
impulses = []
CurrentSendNumber = msgin.readSint32('CurrentSendNumber')
logging.getLogger(LOGGER).debug("[Server -> Client] {CurrentSendNumber:%d, src:%s, dst:%s}" % (CurrentSendNumber, src, dst))
SystemMode = msgin.readBool('SystemMode')
self.initialize_client(dst)
self.client_state[dst]['CurrentSendNumber'] = CurrentSendNumber
id = 0
if not SystemMode:
_LastReceivedAck = msgin.readSint32('LastReceivedAck');
logging.getLogger(LOGGER).debug("[Server -> Client] Normal Mode {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d}" % (CurrentSendNumber, src, dst, _LastReceivedAck))
@ -331,29 +366,80 @@ class SpyPcap():
# Decode the actions received in the impulsions
logging.getLogger(LOGGER).debug('=' * 80)
actionsbis = []
for action in actions:
referenceBis = "%s_%d" % (target, id)
action.add_reference(Parent)
action.set_name(referenceBis)
logging.getLogger(LOGGER).debug('-' * 80)
logging.getLogger(LOGGER).debug('Analyse actions:%s', action)
if action.Code == Enum.TActionCode.ACTION_DISCONNECTION_CODE:
#action.add_reference(Parent)
logging.getLogger(LOGGER).info("Action : ACTION_DISCONNECTION_CODE")
actionsbis.append(CAction.CActionFake('ACTION_DISCONNECTION_CODE', self.client_state[dst]['GenericMultiPartTempServer'].data[id].read())) # , Reference = Parent, Name = "%s_%d" % (target, 0)
elif action.Code == Enum.TActionCode.ACTION_GENERIC_CODE:
action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTemp'])
#action.add_reference(Parent)
#action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTempServer']) #, Reference = Parent, Name = "%s_%d" % (target, 0))
try:
impulse = action.decodeImpulseSimple(
self.decodeImpulseSimple,
self.client_state[dst]['world'],
self.client_state[dst]['GenericMultiPartTempServer'],
Reference = [Parent, ],
Name = "%s_%d" % (target, 0)
) #, Reference = Parent, Name = "%s_%d" % (target, 0))
logging.getLogger(LOGGER).info("impulse:%s" % str(impulse))
if impulse:
impulses.append(impulse)
except Impulse.ImpulseNoElement:
pass
logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_CODE : {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, action:%s}" % (CurrentSendNumber, src, dst, _LastReceivedAck, action))
elif action.Code == Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTemp'])
#action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTempServer'], Reference = referenceBis) #, Reference = Parent, Name = "%s_%d" % (target, 0))
try:
impulse = action.decodeImpulseSimple(
self.decodeImpulseSimple,
self.client_state[dst]['world'],
self.client_state[dst]['GenericMultiPartTempServer'],
Reference = Parent,
Name = "%s_%d" % (target, 0)
) #, Reference = Parent, Name = "%s_%d" % (target, 0))
logging.getLogger(LOGGER).info("impulse:%s" % str(impulse))
if impulse:
impulses.append(impulse)
except Impulse.ImpulseNoElement:
pass
logging.getLogger(LOGGER).debug("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE : %s" % action)
for id in self.client_state[dst]['GenericMultiPartTemp'].data:
if self.client_state[dst]['GenericMultiPartTemp'].data[id].isAvailable():
logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, id:%d, msg:%s}" % (CurrentSendNumber, src, dst, _LastReceivedAck, id, self.client_state[dst]['GenericMultiPartTemp'].data[id].read().showAllData()))
for id in self.client_state[dst]['GenericMultiPartTempServer'].data:
if self.client_state[dst]['GenericMultiPartTempServer'].data[id].isAvailable():
logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, id:%d, msg:%s}" % (
CurrentSendNumber, src, dst, _LastReceivedAck, id,
self.client_state[dst]['GenericMultiPartTempServer'].data[id].read().showAllData()))
temp = CAction.CActionFake('ACTION_GENERIC_MULTI_PART_CODE',
self.client_state[dst]['GenericMultiPartTempServer'].data[id].read(),
# {'coucou': ', '.join(self.client_state[dst]['GenericMultiPartTemp'].data[id].Reference)},
# Reference = self.client_state[dst]['GenericMultiPartTemp'].data[id].Reference,
Name = "inpulse_%s_%s" % (Parent[7:], 0)
)
temp.Reference = self.client_state[dst]['GenericMultiPartTempServer'].data[id].Reference
actionsbis.append(temp)
elif action.Code == Enum.TActionCode.ACTION_DUMMY_CODE:
#action.add_reference(Parent)
logging.getLogger(LOGGER).info("Action : ACTION_DUMMY_CODE")
actionsbis.append(CAction.CActionFake('ACTION_DUMMY_CODE', self.client_state[dst]['GenericMultiPartTempServer'].data[id].read(), Reference=Parent, Name = "%s_%d" % (target, 0)))
self.add_registered_action(dst, action)
id += 1
# # remove all old actions that are acked
# while self._Actions and self._Actions[0].FirstPacket != 0 and self._Actions[0].FirstPacket < self._LastReceivedAck:
# logging.getLogger(LOGGER).debug("remove old action [%d/%d] : %s" % (self._Actions[0].FirstPacket, self._LastReceivedAck, self._Actions[0]))
# self._Actions.pop(0)
for action in actionsbis:
actions.append(action)
logging.getLogger(LOGGER).info("impulses:%s" % str(impulses))
else:
message = msgin.readUint8('message')
#referenceBis = "%s_%d" % (Parent, id)
logging.getLogger(LOGGER).debug("[Server -> Client] System Mode {CurrentSendNumber:%d, src:%s, dst:%s, message:%d" % (CurrentSendNumber, src, dst, message))
if message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
logging.getLogger(LOGGER).debug("[Server -> Client] Synchronize")
@ -363,20 +449,30 @@ class SpyPcap():
MsgData = msgin.readArrayUint8(16, 'MsgData')
DatabaseData = msgin.readArrayUint8(16, 'DatabaseData')
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / Synchronize {CurrentSendNumber:%d, src:%s, dst:%s, message:%d, Synchronize:%d, stime:%d, LatestSync:%d, MsgData:%s, DatabaseData:%s}" % (CurrentSendNumber, src, dst, message, Synchronize, stime, LatestSync, str(MsgData), str(DatabaseData)))
action = CAction.CActionFake('SYSTEM_SYNC_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
logging.getLogger(LOGGER).debug("[Server -> Client] Stalled")
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / Stalled {CurrentSendNumber:%d, src:%s, dst:%s, message:%d}" % (CurrentSendNumber, src, dst, message))
action = CAction.CActionFake('SYSTEM_STALLED_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
logging.getLogger(LOGGER).debug("[Server -> Client] Probe")
LatestProbe = msgin.readSint32('LatestProbe')
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / Probe {CurrentSendNumber:%d, src:%s, dst:%s, message:%d, LatestProbe:%d}" % (CurrentSendNumber, src, dst, message, LatestProbe))
action = CAction.CActionFake('SYSTEM_PROBE_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / BACK-END DOWN {CurrentSendNumber:%d, src:%s, dst:%s, message:%d}" % (CurrentSendNumber, src, dst, message))
action = CAction.CActionFake('SYSTEM_SERVER_DOWN_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
else:
logging.getLogger(LOGGER).warning("CNET: received system %d in state Login" % message)
#cActionFactory = CAction.CActionFactory(None)
#cActionFactory.unpack(msgin)
logging.getLogger(LOGGER).debug("[Server -> Client] msg:%s" % msgin.showAllData())
#logging.getLogger(LOGGER).info("impulses:%s" % str(impulses))
return actions, impulses
def read(self):
file = open( self.pcap_file , 'rb')
@ -386,6 +482,9 @@ class SpyPcap():
serverid = 1
list_host = {}
sequenceid = 1
sequencenum = 1
if self.outyaml:
self.outyaml.write("# Generated : %s\n\n" % (datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
for pkt in pcapfile.packets:
eth_frame = ethernet.Ethernet(pkt.raw())
@ -397,8 +496,17 @@ class SpyPcap():
data = udp_packet.payload
if udp_packet.src_port == 53 or udp_packet.dst_port == 53:
continue
if udp_packet.src_port == 5353 and ip_packet.src.decode() == "224.0.0.251":
continue
if udp_packet.dst_port == 5353 and ip_packet.dst.decode() == "224.0.0.251":
continue
if not self.filter_host_service or self.filter_host_service.match("%s:%d" % (ip_packet.src.decode(), udp_packet.src_port)) or self.filter_host_service.match("%s:%d" % (ip_packet.dst.decode(), udp_packet.dst_port)):
Reference = "packet_%d" % sequenceid
logging.getLogger(LOGGER).debug("-" * 80)
actions_clients = []
actions_servers = []
inpulses_servers = []
inpulses_clients = []
if self.show_raw_packet:
logging.getLogger(LOGGER).debug("[raw packet] timestamp:%s [%s] src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"),
@ -435,20 +543,21 @@ class SpyPcap():
if (self.khanat_host_service and self.khanat_host_service.match(src)) or ( not self.khanat_host_service and khanat_host == src):
_provenance = 'Server -> Client'
logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData()))
self.decode_khanat_message(msgin, src, dst, sequenceid, list_host[dst])
actions_servers, inpulses_servers = self.decode_khanat_message(msgin, src, dst, sequenceid, list_host[dst], Reference, list_host[src])
else:
_provenance = 'Client -> Server'
logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData()))
self.decode_client_message(msgin, src, dst, sequenceid, list_host[dst])
moredata='message decoded'
actions_clients, inpulses_clients = self.decode_client_message(msgin, src, dst, sequenceid, list_host[dst], Reference, list_host[src])
if not msgin.checkOnlyZeroAtEnd(): # msgin.needRead() > 7:
moredata = "message partially decoded"
else:
moredata = 'message decoded'
if self.show_message_decoded:
logging.getLogger(LOGGER).debug("[%s] (%s) %s" % (_provenance, moredata, msgin.showAllData()))
if self.outyaml:
self.outyaml.write("\nudp_%d:\n sequence: %d\n time: %s\n source: %s\n destination: %s\n function: %s\n adress_source: %s\n adress_destination: %s\n state: %s\n message:\n" % (
sequenceid,
sequenceid,
self.outyaml.write("\n%s:\n sequence: %d\n time: %s\n source: %s\n destination: %s\n function: %s\n adress_source: %s\n adress_destination: %s\n state: %s\n message:\n" % (
Reference,
sequencenum,
datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"),
list_host[src],
list_host[dst],
@ -459,7 +568,99 @@ class SpyPcap():
))
for key in msgin.extractAllData():
self.outyaml.write(" - %s\n" % key)
if actions_servers:
self.outyaml.write("\nblock_%s_%d:\n" %(list_host[src], sequenceid))
id = 0
for action in actions_servers:
params = action.get_parameter()
self.outyaml.write(" %s:\n" % (action.get_name()))
# if "parent" in params:
# self.outyaml.write(" parent: %s\n" % (params['parent']))
# elif "Reference" in params:
# #self.outyaml.write(" parents: %s\n" % (', '.join(params['Reference'])))
# self.outyaml.write(" parents:\n")
# for key in params['Reference']:
# self.outyaml.write(" - %s\n" % (key))
# else:
# self.outyaml.write(" parent: udp_%s\n" % (sequenceid))
self.outyaml.write(" receivedby: client\n")
self.outyaml.write(" sequence: %s\n" % (sequencenum))
self.outyaml.write(" source: %s\n" % (list_host[src]))
self.outyaml.write(" destination: %s\n" % (list_host[dst]))
for key in params:
if key == 'Message':
self.outyaml.write(" %s:\n" % (key))
for key2 in params[key]:
self.outyaml.write(" - %s\n" % key2)
elif key == "Reference":
self.outyaml.write(" parents:\n")
for key in params['Reference']:
self.outyaml.write(" - %s\n" % (key))
#elif key != 'parent':
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
#self.outyaml.write(" %s: %s\n" % (key, params[key]))
id += 1
if inpulses_servers:
self.outyaml.write("\ninpulseserver_%s_%d:\n" %(list_host[src], sequenceid))
id = 0
#print("-"*30)
#print(inpulses_servers)
for inpulse in inpulses_servers:
#print("-"*80)
#print(inpulse)
params = inpulse.get_parameter()
self.outyaml.write(" %s:\n" % (inpulse.get_name()))
for key in params:
if key == 'Message':
self.outyaml.write(" %s:\n" % (key))
for key2 in params[key]:
self.outyaml.write(" - %s\n" % key2)
elif key == "Reference":
self.outyaml.write(" parents:\n")
for key in params['Reference']:
self.outyaml.write(" - %s\n" % (key))
#elif key != 'parent':
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
#self.outyaml.write(" %s: %s\n" % (key, params[key]))
id += 1
#print("-"*30)
if actions_clients:
self.outyaml.write("\nblock_%s_%d:\n" %(list_host[src], sequenceid))
id = 0
for action in actions_clients:
self.outyaml.write(" %s:\n" % (action.get_name()))
self.outyaml.write(" receivedby: server\n")
self.outyaml.write(" sequence: %s\n" % (sequencenum))
self.outyaml.write(" source: %s\n" % (list_host[src]))
self.outyaml.write(" destination: %s\n" % (list_host[dst]))
params = action.get_parameter()
for key in params:
if key == 'Message':
self.outyaml.write(" %s:\n" % (key))
for key2 in params[key]:
self.outyaml.write(" - %s\n" % key2)
elif key == "Reference":
self.outyaml.write(" parents:\n")
for key in params['Reference']:
self.outyaml.write(" - %s\n" % (key))
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
#self.outyaml.write(" %s: %s\n" % (key, params[key]))
id += 1
# if inpulses_clients:
# self.outyaml.write("\ninpulseclient_%s_%d:\n" %(list_host[src], sequenceid))
# id = 0
# for inpulse in inpulses_clients:
# params = inpulse.get_parameter()
# self.outyaml.write(" %s:\n" % (inpulse.get_name()))
# id += 1
sequenceid += 1
sequencenum += 1
for client in self.client_state:
logging.getLogger(LOGGER).debug("%s [server tick:%d, client tick:%d]" %(client, self.client_state[client]['CurrentSendNumber'], self.client_state[client]['CurrentReceivedNumber']))
@ -470,13 +671,14 @@ def main():
logger = []
logger.append(logging.getLogger(LOGGER))
logger.append(logging.getLogger(CImpulseDecoder.LOGGER))
#logger.append(logging.getLogger(DecodeImpuls.LOGGER))
#logger.append(logging.getLogger(BitStream.LOGGER))
logger.append(logging.getLogger(CStringManager.LOGGER))
logger.append(logging.getLogger(CAction.LOGGER))
logger.append(logging.getLogger(CActionFactory.LOGGER))
logger.append(logging.getLogger(BitStream.LOGGER))
# logger.append(logging.getLogger(CImpulseDecoder.LOGGER))
# #logger.append(logging.getLogger(DecodeImpuls.LOGGER))
# #logger.append(logging.getLogger(BitStream.LOGGER))
# logger.append(logging.getLogger(CStringManager.LOGGER))
# logger.append(logging.getLogger(CAction.LOGGER))
# logger.append(logging.getLogger(CActionFactory.LOGGER))
# logger.append(logging.getLogger(BitStream.LOGGER))
logger.append(logging.getLogger(Impulse.LOGGER))
CImpulseDecoder
# logger.append(logging.getLogger('CGenericMultiPartTemp'))

View file

@ -23,6 +23,7 @@ from ctypes import *
import sys
import inspect
import copy
import struct
LOGGER='BitStream'

View file

@ -22,6 +22,7 @@
import logging
from tools import TPropIndex
from tools import TPVPMode
from tools import Enum
LOGGER='CActionFactory'
INVALID_SLOT = 0xff
@ -35,9 +36,23 @@ class CAction:
self.Timeout = 0
self.GameCycle = 0
self.world = world
self.Reference = []
self.Name = ""
def set_name(self, name):
self.Name = name
def get_name(self):
return self.Name
def add_reference(self, ref):
self.Reference.append(ref)
def get_reference(self):
return self.Reference
def get_parameter(self):
return {"Type": "CAction", "Code": self.Code, "Slot": self.Slot, "PropertyCode": self.PropertyCode, "GameCycle": self.GameCycle}
return {"Type": "CAction", "Code": self.Code, "Slot": self.Slot, "PropertyCode": self.PropertyCode, "GameCycle": self.GameCycle, "Reference": self.Reference}
def unpack(self, message):
raise RuntimeError
@ -216,7 +231,11 @@ class CActionGeneric(CAction):
def get_parameter(self):
ret = super().get_parameter()
ret["Type"] = "CActionGeneric"
ret["Message"] = self._Message.showAllData()
if not self._Message.checkOnlyZeroAtEnd():
ret["state"] = "message partially decoded"
else:
ret["state"] = 'message decoded'
ret["Message"] = self._Message.extractAllData()
return ret
def set(self, message):
@ -239,6 +258,11 @@ class CActionGeneric(CAction):
decodeImpulse.execute(self._Message, world)
self.decoded = True
def decodeImpulseSimple(self, decodeImpulseSimple, world, cGenericMultiPartTemp, Reference = None, Name = ""):
ret = decodeImpulseSimple.execute(self._Message, world, Reference, Name)
self.decoded = True
return ret
def __str__(self):
if self.decoded:
return "CActionGeneric" + super().__str__() + ' => ' + self._Message.showAllData()
@ -265,6 +289,7 @@ class CActionGenericMultiPart(CAction):
def get_parameter(self):
ret = super().get_parameter()
ret["Name"] = self.Name
ret["Type"] = "CActionGenericMultiPart"
ret["Number"] = "%d" % self.Number
ret["Part"] = "%d" % self.Part
@ -315,13 +340,21 @@ class CActionGenericMultiPart(CAction):
self.Part = 0
self.NbBlock = 0
def genericAction(self, decodeImpulse, world, cGenericMultiPartTemp):
def genericAction(self, decodeImpulse, world, cGenericMultiPartTemp, Reference, Name):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::genericAction (CActionGenericMultiPart *agmp)
'''
logging.getLogger(LOGGER).debug("Number:%d Part:%d NbBlock:%d" % (self.Number, self.Part, self.NbBlock))
cGenericMultiPartTemp.addGenericMultiPartTemp(self.Number)
cGenericMultiPartTemp.setGenericMultiPartTemp(self.Number, self.Part, self.NbBlock, self.PartCont, decodeImpulse, world)
cGenericMultiPartTemp.setGenericMultiPartTemp(self.Number, self.Part, self.NbBlock, self.PartCont, decodeImpulse, world, Reference, Name)
def decodeImpulseSimple(self, decodeImpulseSimple, world, cGenericMultiPartTemp, Reference = None, Name = ""):
logging.getLogger(LOGGER).debug("Number:%d Part:%d NbBlock:%d" % (self.Number, self.Part, self.NbBlock))
cGenericMultiPartTemp.addGenericMultiPartTemp(self.Number)
ret = cGenericMultiPartTemp.setGenericMultiPartTemp(self.Number, self.Part, self.NbBlock, self.PartCont, decodeImpulseSimple, world, Reference, Name)
#ret = decodeImpulseSimple.execute(self._Message, world)
self.decoded = True
return ret
def __str__(self):
return "CActionGenericMultiPart" + super().__str__() + "[" + str(self.Number) + ',' + str(self.Part) + ',' + str(self.NbBlock) + ',read:' + self.PartCont.showAllData() + ',write:' + self.PartCont.showAllDataWrite() + ']'
@ -445,3 +478,27 @@ class CActionBlock:
def __str__(self):
return "CActionBlock [Cycle:" + str(self.Cycle) + ', FirstPacket:' + str(self.FirstPacket) + ', Data:' + ', '.join([ str(x) for x in self.Actions]) + "]"
class CActionFake():
def __init__(self, Type, msgin, addon = None, Reference=None, Name=""):
self.Type = Type
self.Code = Enum.TActionCode.ACTION_NONE
self._Message = msgin
self.addon = addon
self.Reference = [ Reference ]
self.Name = Name
def get_name(self):
return self.Name
def get_parameter(self):
ret = {"Type": "CActionFake.%s" % self.Type}
if not self._Message.checkOnlyZeroAtEnd():
ret["state"] = "message partially decoded"
else:
ret["state"] = 'message decoded'
if self.addon:
for key in self.addon:
ret[key] = str(self.addon[key])
ret["Reference"] = self.Reference
ret["Message"] = self._Message.extractAllData()
return ret

View file

@ -91,7 +91,7 @@ class CActionFactory:
action.Slot = slot
return action
def unpack(self, msgin):
def unpack(self, msgin, Reference = None, Name = None):
'''
khanat-opennel-code/code/ryzom/common/src/game_share/action_factory.cpp : CAction *CActionFactory::unpack (NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ )
'''
@ -113,6 +113,10 @@ class CActionFactory:
else:
log = logging.getLogger('myLogger')
log.warning('Unpacking an action with unknown code, skip it (%u)' % code)
if Reference:
action.add_reference(Reference)
if Name:
action.set_name(Name)
return action

View file

@ -32,12 +32,19 @@ class CGenericMultiPartTemp():
self.BlockReceived = []
self.MsgDecoded = None
self.FirstRead = False
self.Reference = []
self.Name = None
def set(self, Number, Part, NbBlock, PartCont, decodeImpulse, world):
def set(self, Number, Part, NbBlock, PartCont, decodeImpulse, world, Reference = None, Name = None):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::CGenericMultiPartTemp::set (CActionGenericMultiPart *agmp, CNetworkConnection *parent)
'''
logging.getLogger(LOGGER).debug("set Number:%d Part:%d NbBlock:%d" % (Number, Part, NbBlock))
ret = None
if not self.Name:
self.Name = Name
if Reference:
self.Reference.append(Reference)
if self.NbBlock == 0xFFFFFFFF:
# Initialize
self.NbBlock = NbBlock
@ -49,7 +56,7 @@ class CGenericMultiPartTemp():
while len(self.BlockReceived) < NbBlock:
self.BlockReceived.append(False)
if self.BlockReceived[Part]:
logging.getLogger(LOGGER).warning('This part is already received, discard it %d' % Part)
logging.getLogger(LOGGER).debug('This part is already received, discard it %d' % Part)
return
self.Temp[Part] = PartCont
self.BlockReceived[Part] = True
@ -64,11 +71,12 @@ class CGenericMultiPartTemp():
self.NbBlock == 0xFFFFFFFF
for data in self.Temp:
bms.pushBitStream(data)
decodeImpulse.execute(bms, world)
ret = decodeImpulse.execute(bms, world)
logging.getLogger(LOGGER).debug("CGenericMultiPartTemp : data : %s" % bms.showAllData())
self.MsgDecoded = bms
else:
logging.getLogger(LOGGER).debug("CGenericMultiPartTemp : Wait other block")
return ret
def isAvailable(self):
if self.MsgDecoded and not self.FirstRead:
@ -87,5 +95,5 @@ class GenericMultiPartTemp():
def addGenericMultiPartTemp(self, Number):
self.data.setdefault(Number, CGenericMultiPartTemp())
def setGenericMultiPartTemp(self, Number, Part, NbBlock, PartCont, decodeImpulse, world):
self.data[Number].set(Number, Part, NbBlock, PartCont, decodeImpulse, world)
def setGenericMultiPartTemp(self, Number, Part, NbBlock, PartCont, decodeImpulse, world, Reference = None, Name = None):
self.data[Number].set(Number, Part, NbBlock, PartCont, decodeImpulse, world, Reference, Name)

View file

@ -38,7 +38,7 @@ class CImpulseDecoder:
def decode(self, msgin, receivedPacket, receivedAck, nextSentPacket):
'''
khanat-opennel-code/code/ryzom/client/src/impulse_decoder.cpp:38 oid CImpulseDecoder::decode(CBitMemStream &inbox, TPacketNumber receivedPacket, TPacketNumber receivedAck, TPacketNumber nextSentPacket, vector<CLFECOMMON::CAction *> &actions)
khanat-opennel-code/code/ryzom/client/src/impulse_decoder.cpp:38 void CImpulseDecoder::decode(CBitMemStream &inbox, TPacketNumber receivedPacket, TPacketNumber receivedAck, TPacketNumber nextSentPacket, vector<CLFECOMMON::CAction *> &actions)
'''
logging.getLogger(LOGGER).debug("*" * 80)
logging.getLogger(LOGGER).debug("receivedPacket:%d receivedAck:%d nextSentPacket:%d" %(receivedPacket, receivedAck, nextSentPacket))

View file

@ -351,6 +351,11 @@ class DecodeImpulse():
def impulseDatabaseInitPlayer(self, msgin, world):
logging.getLogger(LOGGER).debug("TODO")
def impulseSetConnectionAskName(self, msgin, world):
# _ = msgin.readUtf8String('Name')
_ = msgin.readUString('Name')
_ = msgin.readUint32('HomeSessionId')
def initializeNetwork(self):
self.GenericMsgHeaderMngr.setdefault('DB_UPD_PLR', self.impulseDatabaseUpdatePlayer)
self.GenericMsgHeaderMngr.setdefault('DB_INIT:PLR', self.impulseDatabaseInitPlayer)
@ -493,6 +498,9 @@ class DecodeImpulse():
self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SVR_EVENT_MIS_AVL", self.impulseServerEventForMissionAvailability )
self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SET_TIMER", self.impulseSetNpcIconTimer )
# Send by client
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:ASK_NAME", self.impulseSetConnectionAskName )
def sizeElement(self, keys = None):
head = self.msgXml
if not keys:
@ -540,6 +548,7 @@ class DecodeImpulse():
nbBit = getPowerOf2.getPowerOf2(len(head))
id = msgin.readSerial(nbBit, name='MsgXML', typeName='Number', emulate=True)
logging.getLogger(LOGGER).debug("XML DECODE : %3d -> %s" % (nbBit, ':'.join(listpath)) )
ele = head[id]
name = ele.attrib['name']
listpath.append(name)

View file

@ -539,6 +539,8 @@ class TActionCode(IntEnum):
ACTION_LOGIN_CODE = 13
ACTION_TARGET_SLOT_CODE = 40
ACTION_DUMMY_CODE = 99
ACTION_NONE = 999
class Card(IntEnum):
BEGIN_TOKEN = 0
@ -550,6 +552,7 @@ class Card(IntEnum):
FLAG_TOKEN = 6
EXTEND_TOKEN = 7
class TType(IntEnum):
STRUCT_BEGIN = 0
STRUCT_END = 1
@ -563,3 +566,14 @@ class TType(IntEnum):
FLOAT64 = 9
EXTEND_TYPE = 10
NB_TYPE = 11
class NPC_ICON(IntEnum): # TNPCMissionGiverState
AwaitingFirstData = 0
NotAMissionGiver = 1
ListHasOutOfReachMissions = 2
ListHasAlreadyTakenMissions = 3
ListHasAvailableMission = 4
AutoHasUnavailableMissions = 5
AutoHasAvailableMission = 6
NbMissionGiverStates = 7

455
tools/Impulse.py Normal file
View file

@ -0,0 +1,455 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module Impulse
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from tools import getPowerOf2
from tools import BitStream
# from tools import Enum
LOGGER='Impulse'
class ImpulseNoElement(Exception):
pass
class ImpulseBase:
def __init__(self):
self.name = ""
self.id = ""
self.param = {}
#self.Reference = []
def set_name(self, name):
self.name = name.replace(':', '_')
def get_name(self):
return self.name
def add_reference(self, ref):
#self.Reference.append(ref)
self.param.setdefault('Reference', [])
self.param['Reference'].append(ref)
def get_reference(self):
return self.param['Reference']
def get_parameter(self):
return self.param
def add_parameter(self, key, value):
self.param.setdefault(key, [])
self.param[key].append(value)
def add_value(self, key, value):
self.param.setdefault(key, "")
self.param[key] = value
def read(self, name, msgin, world):
logging.getLogger(LOGGER).error("Not define")
class ImpulseBotchatSetFilters(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('qualityMin', msgin.readUint32('qualityMin'))
self.param.setdefault('qualityMax', msgin.readUint32('qualityMax'))
self.param.setdefault('priceMin', msgin.readUint32('priceMin'))
self.param.setdefault('priceMax', msgin.readUint32('priceMax'))
self.param.setdefault('classMin', msgin.readUint8('classMin'))
self.param.setdefault('classMax', msgin.readUint8('classMax'))
self.param.setdefault('itemPart', msgin.readUint8('itemPart'))
self.param.setdefault('itemType', msgin.readUint8('itemType'))
class ImpulseConnectionAskName(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('Name', msgin.readUString('Name'))
self.param.setdefault('HomeSessionId', msgin.readUint32('HomeSessionId'))
class ImpulseConnectionCreateChar(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('Slot', msgin.readUint8('Slot'))
self.param.setdefault('SheetId', msgin.readUint32('SheetId'))
self.param.setdefault('CSessionId', msgin.readUint32('CSessionId'))
self.param.setdefault('name', msgin.readUString('name'))
self.param.setdefault('People', msgin.readUint8('People'))
self.param.setdefault('Sex', msgin.readUint8('Sex'))
self.param.setdefault('NbPointFighter', msgin.readUint8('NbPointFighter'))
self.param.setdefault('NbPointCaster', msgin.readUint8('NbPointCaster'))
self.param.setdefault('NbPointCrafter', msgin.readUint8('NbPointCrafter'))
self.param.setdefault('NbPointHarvester', msgin.readUint8('NbPointHarvester'))
self.param.setdefault('StartPoint', msgin.readSint32('StartPoint'))
self.param.setdefault('HairType', msgin.readSint8('HairType'))
self.param.setdefault('HairColor', msgin.readSint8('HairColor'))
self.param.setdefault('GabaritHeight', msgin.readSint8('GabaritHeight'))
self.param.setdefault('GabaritTorsoWidth', msgin.readSint8('GabaritTorsoWidth'))
self.param.setdefault('GabaritArmsWidth', msgin.readSint8('GabaritArmsWidth'))
self.param.setdefault('GabaritLegsWidth', msgin.readSint8('GabaritLegsWidth'))
self.param.setdefault('GabaritBreastSize', msgin.readSint8('GabaritBreastSize'))
self.param.setdefault('MorphTarget1', msgin.readSint8('MorphTarget1'))
self.param.setdefault('MorphTarget2', msgin.readSint8('MorphTarget2'))
self.param.setdefault('MorphTarget3', msgin.readSint8('MorphTarget3'))
self.param.setdefault('MorphTarget4', msgin.readSint8('MorphTarget4'))
self.param.setdefault('MorphTarget5', msgin.readSint8('MorphTarget5'))
self.param.setdefault('MorphTarget6', msgin.readSint8('MorphTarget6'))
self.param.setdefault('MorphTarget7', msgin.readSint8('MorphTarget7'))
self.param.setdefault('MorphTarget8', msgin.readSint8('MorphTarget8'))
self.param.setdefault('EyesColor', msgin.readSint8('EyesColor'))
self.param.setdefault('Tattoo', msgin.readSint8('Tattoo'))
self.param.setdefault('JacketColor', msgin.readSint8('JacketColor'))
self.param.setdefault('TrousersColor', msgin.readSint8('TrousersColor'))
self.param.setdefault('HatColor', msgin.readSint8('HatColor'))
self.param.setdefault('ArmsColor', msgin.readSint8('ArmsColor'))
self.param.setdefault('HandsColor', msgin.readSint8('HandsColor'))
self.param.setdefault('FeetColor', msgin.readSint8('FeetColor'))
class ImpulseConnectionReady(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('LanguageCode', msgin.readString('LanguageCode'))
class ImpulseConnectionSelectChar(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('SelectCharMsg', msgin.readUint8('SelectCharMsg'))
class ImpulseConnectionUserChar(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('X', msgin.readSint32('X'))
self.param.setdefault('Y', msgin.readSint32('Y'))
self.param.setdefault('Z', msgin.readSint32('Z'))
self.param.setdefault('Heading', msgin.readFloat('Heading'))
self.param.setdefault('season', msgin.readSerial(3, 'season'))
self.param.setdefault('userRole', msgin.readSerial(3, 'userRole'))
self.param.setdefault('highestMainlandSessionId', msgin.readUint32('highestMainlandSessionId'))
self.param.setdefault('firstConnectedTime', msgin.readUint32('firstConnectedTime'))
self.param.setdefault('playedTime', msgin.readUint32('playedTime'))
class ImpulseConnectionShardId(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('shardId', msgin.readUint32('shardId'))
self.param.setdefault('webHost', msgin.readString('webHost'))
class ImpulseConnectionValidName(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('valide', msgin.readUint8('valide'))
class ImpulseDebugPing(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('localTime', msgin.readUint32('localTime'))
class ImpulseGuildFemaleTitles(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('UseFemaleTitles', msgin.readSerial(1, 'UseFemaleTitles'))
class ImpulseNpsIconSetDesc(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
'''
khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp:20976 void CCharacter::sendNpcMissionGiverIconDesc( const std::vector<uint32>& npcKeys )
'''
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('nb8', msgin.readUint8('nb8'))
nb8 = self.param['nb8']
for i in range(0, nb8):
self.param.setdefault('%d:npcAlias' % nb8, msgin.readUint32('npcAlias'))
self.param.setdefault('%d:state' % nb8, msgin.readUint32('state'))
class ImpulsePhraseDownload(ImpulseBase):
def __init__(self):
super().__init__()
def readSerialPhrase(self, msgin, id):
self.param.setdefault(id, msgin.readUtf8String(id))
size = msgin.readSint32(id + ':len')
self.param.setdefault(id + ':len', size)
for i in range(0, size):
self.param.setdefault('%s:compBricks:%d' % (id, i), msgin.readUint16('%s:compBricks:%d' % (id, i)))
def readSerialPhrases(self, msgin, id):
"""
khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp:13586 void CCharacter::sendPhrasesToClient()
khanat-opennel-code/code/nel/include/nel/misc/stream.h:1089 void serialVector(T &cont)
khanat-opennel-code/code/ryzom/common/src/game_share/sphrase_com.cpp:57 void CSPhraseCom::serial(NLMISC::IStream &impulse)
"""
size = msgin.readSint32(id + ':len')
self.param.setdefault(id + ':len', size)
for i in range(0, size):
#self.param.setdefault('%d:Phrase' % i, msgin.readUtf8String('%d:Phrase:Name' % i))
#self.param.setdefault('%d:Phrase' % i, msgin.readString('%d:Phrase' % i))
self.readSerialPhrase(msgin, '%d:Phrase' % i)
self.param.setdefault('%d:KnownSlot' % i, msgin.readUint16('%d:KnownSlot' % i))
self.param.setdefault('%d:PhraseSheetId:id' % i, msgin.readUint32('%d:PhraseSheetId:id' % i))
self.param.setdefault('%d:PhraseSheetId:Type' % i, msgin.readUint32('%d:PhraseSheetId:IdInfos:Type' % i))
self.param.setdefault('%d:PhraseSheetId:Type' % i, msgin.readUint32('%d:PhraseSheetId:IdInfos:Id' % i))
def readSerialMemorizedPhrases(self, msgin, id):
size = msgin.readSint32(id + ':len')
self.param.setdefault(id + ':len', size)
for i in range(0, size):
self.param.setdefault('%d:MemoryLineId' % i, msgin.readUint8('MemoryLineId'))
self.param.setdefault('%d:MemorySlotId' % i, msgin.readUint8('MemorySlotId'))
self.param.setdefault('%d:PhraseId' % i, msgin.readUint16('PhraseId'))
def read(self, name, msgin, world):
"""
khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp:13586 void CCharacter::sendPhrasesToClient()
"""
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
return
#self.param.setdefault(id + 'phrases', msgin.readString('phrases'))
#self.param.setdefault(id + 'memorizedPhrases', msgin.readString('memorizedPhrases'))
self.readSerialPhrases(msgin, 'knownPhrases')
self.readSerialMemorizedPhrases(msgin, 'memorizedPhrases')
logging.getLogger(LOGGER).error("[Client -> Server] msg:%s" % msgin.showAllData())
raise ValueError
class ImpulsePosition(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('X', msgin.readSint32('X'))
self.param.setdefault('Y', msgin.readSint32('Y'))
self.param.setdefault('Z', msgin.readSint32('Z'))
self.param.setdefault('Heading', msgin.readFloat('Heading'))
class ImpulseSringDynString(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('phraseId', msgin.readUint32('phraseId'))
class ImpulseSringManagerReloadCache(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('timestamp', msgin.readUint32('timestamp'))
class ImpulseSringManagerPhraseSend(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('dynId', msgin.readUint32('dynId'))
self.param.setdefault('StringId', msgin.readUint32('StringId'))
try:
id = 0
while True:
self.param.setdefault('StringId:%d' % id, msgin.readUint32('StringId'))
id += 1
except:
pass
class ImpulseSringManagerStringResp(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('stringId', msgin.readUint32('stringId'))
self.param.setdefault('strUtf8', msgin.readUtf8String('strUtf8'))
class ImpulseSringManagerStringRq(ImpulseBase):
def __init__(self):
super().__init__()
def read(self, name, msgin, world):
logging.getLogger(LOGGER).debug("read")
self.name = name.replace(':', '_')
self.param.setdefault('stringId', msgin.readUint32('stringId'))
class DecodeImpulseSimple:
def __init__(self):
'''
khanat-opennel-code/code/ryzom/client/src/net_manager.cpp # void initializeNetwork()
'''
self.msgXml = None
self.databaseXml = None
self.GenericMsgHeaderMngr = {}
self.initializeNetwork()
def initializeNetwork(self):
# Send by client
self.GenericMsgHeaderMngr.setdefault( "BOTCHAT:SET_FILTERS", ImpulseBotchatSetFilters )
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:ASK_NAME", ImpulseConnectionAskName )
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:CREATE_CHAR", ImpulseConnectionCreateChar )
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:READY", ImpulseConnectionReady )
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:SELECT_CHAR", ImpulseConnectionSelectChar )
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:SHARD_ID", ImpulseConnectionShardId )
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:USER_CHAR", ImpulseConnectionUserChar )
self.GenericMsgHeaderMngr.setdefault( "CONNECTION:VALID_NAME", ImpulseConnectionValidName )
self.GenericMsgHeaderMngr.setdefault( "DEBUG:PING", ImpulseDebugPing )
self.GenericMsgHeaderMngr.setdefault( "GUILD:USE_FEMALE_TITLES", ImpulseGuildFemaleTitles )
self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SET_DESC", ImpulseNpsIconSetDesc )
self.GenericMsgHeaderMngr.setdefault( "PHRASE:DOWNLOAD", ImpulsePhraseDownload )
self.GenericMsgHeaderMngr.setdefault( "POSITION", ImpulsePosition )
self.GenericMsgHeaderMngr.setdefault( "STRING:DYN_STRING", ImpulseSringDynString )
self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:RELOAD_CACHE", ImpulseSringManagerReloadCache )
self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:PHRASE_SEND", ImpulseSringManagerPhraseSend )
self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:STRING_RESP", ImpulseSringManagerStringResp )
self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:STRING_RQ", ImpulseSringManagerStringRq )
def execute(self, msgin, world, references = [], name=""):
'''
khanat-opennel-code/code/ryzom/client/src/net_manager.cpp:3746 void impulseCallBack(NLMISC::CBitMemStream &impulse, sint32 packet, void *arg)
khanat-opennel-code/code/ryzom/common/src/game_share/generic_xml_msg_mngr.cpp:121 void CGenericXmlMsgHeaderManager::execute(CBitMemStream &strm)
khanat-opennel-code/code/ryzom/common/src/game_share/generic_xml_msg_mngr.h:431 CNode *select(NLMISC::CBitMemStream &strm)
uint32 index = 0;
q uint NbBits;
strm.serialAndLog2(index, node->NbBits);
'''
logging.getLogger(LOGGER).debug("execute")
head = self.msgXml
listpath = []
while True:
nbBit = getPowerOf2.getPowerOf2(len(head))
#logging.getLogger(LOGGER).error("nbBit : %d " % nbBit)
#for child in head:
# print(child.tag, child.attrib)
try:
id = msgin.readSerial(nbBit, name='MsgXML', typeName='Number', emulate=True)
except BitStream.OverflowError:
raise ImpulseNoElement
if id is None:
raise ImpulseNoElement
try:
ele = head[id]
except IndexError as e:
logging.getLogger(LOGGER).error("Error to decode message: %s" % msgin.showAllData() )
raise e
command = ele.attrib['name']
listpath.append(command)
fullname = ':'.join(listpath)
id = msgin.readSerial(nbBit, name='MsgXML', typeName='XML <' + command + '>')
if fullname in self.GenericMsgHeaderMngr:
logging.getLogger(LOGGER).debug("Found : %s" % fullname)
impulse = self.GenericMsgHeaderMngr[fullname]()
impulse.read(fullname, msgin, world)
logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() )
impulse.add_value("command", fullname)
for reference in references:
impulse.add_reference(reference)
impulse.add_value("Message", msgin.extractAllData())
return impulse
else:
#logging.getLogger(LOGGER).debug("Non trouve")
for ele in head:
if ele.attrib['name'] == command:
head = ele
break
if head != ele:
logging.getLogger(LOGGER).error("Impossible to found %s" % fullname )
logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() )
return None
# End While
logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() )
return None
def loadMsg(self, msgXml):
logging.getLogger(LOGGER).debug("msgXml")
self.msgXml = msgXml
def loadDatabase(self, databaseXml):
self.databaseXml = databaseXml