SEDbgMuxApp: employ DbgMuxFrameDisp, implement basic handlers
This commit is contained in:
parent
91abeb7220
commit
c81e0e2ad8
3
peer.py
3
peer.py
|
@ -112,12 +112,12 @@ class DbgMuxPeer:
|
|||
# Init frame dispatcher
|
||||
self.disp = DbgMuxFrameDisp(self._rx_queue,
|
||||
self._tx_queue)
|
||||
# TODO: self.disp.start()
|
||||
|
||||
def start(self) -> None:
|
||||
self._shutdown.clear()
|
||||
self._rx_thread.start()
|
||||
self._tx_thread.start()
|
||||
self.disp.start()
|
||||
|
||||
def stop(self) -> None:
|
||||
# Set the shutdown event
|
||||
|
@ -125,6 +125,7 @@ class DbgMuxPeer:
|
|||
# Wait for both threads to terminate
|
||||
self._tx_thread.join()
|
||||
self._rx_thread.join()
|
||||
self.disp.stop()
|
||||
|
||||
def _rx_worker(self) -> None:
|
||||
while not self._shutdown.is_set():
|
||||
|
|
136
sedbgmux.py
136
sedbgmux.py
|
@ -23,11 +23,74 @@ import argparse
|
|||
import cmd2
|
||||
import enum
|
||||
import sys
|
||||
import time
|
||||
|
||||
from transport import TransportModem
|
||||
from proto import DbgMuxFrame
|
||||
from peer import DbgMuxPeer
|
||||
|
||||
from construct import Container
|
||||
from handlers import DbgMuxFrameHandler
|
||||
from handlers import DbgMuxConnUdpBridge
|
||||
from handlers import DbgMuxConnInteractiveTerminal
|
||||
|
||||
|
||||
class CommonFrameHandler(DbgMuxFrameHandler):
|
||||
''' Handles some common messages '''
|
||||
|
||||
def __init__(self, cmd2):
|
||||
self.cmd2 = cmd2
|
||||
|
||||
def _handle_frame(self, frame: Container) -> None:
|
||||
if frame['MsgType'] == DbgMuxFrame.MsgType.Ident:
|
||||
log.info("Identified target: '%s', IMEI=%s",
|
||||
frame['Msg']['Ident'][:-15],
|
||||
frame['Msg']['Ident'][-15:])
|
||||
elif frame['MsgType'] == DbgMuxFrame.MsgType.DPAnnounce:
|
||||
log.info("Data Provider available (DPRef=0x%04x): '%s'",
|
||||
frame['Msg']['DPRef'], frame['Msg']['Name'])
|
||||
elif frame['MsgType'] == DbgMuxFrame.MsgType.FlowControl:
|
||||
log.warning("Rx FlowControl message, which is not yet supported")
|
||||
elif frame['MsgType'] == DbgMuxFrame.MsgType.ConnEstablished \
|
||||
and frame['Msg']['ConnRef'] == 0xffff:
|
||||
log.warning("Connection establishment failed, "
|
||||
"no such DPRef=0x%04x?", frame['Msg']['DPRef'])
|
||||
elif frame['MsgType'] == DbgMuxFrame.MsgType.ConnTerminated \
|
||||
and frame['Msg']['ConnRef'] == 0xffff:
|
||||
log.warning("Connection termination failed, "
|
||||
"no such DPRef=0x%04x?", frame['Msg']['DPRef'])
|
||||
elif frame['MsgType'] == DbgMuxFrame.MsgType.Ack:
|
||||
raise StopIteration
|
||||
else: # To be consumed by other handlers
|
||||
return
|
||||
self.send(DbgMuxFrame.MsgType.Ack)
|
||||
raise StopIteration
|
||||
|
||||
|
||||
class PingPongHandler(DbgMuxFrameHandler):
|
||||
''' Handles DbgMuxFrame.MsgType.Pong '''
|
||||
|
||||
def __init__(self):
|
||||
self.expect_pong: bool = False
|
||||
|
||||
def ping(self, payload: str):
|
||||
log.info('Tx Ping with payload \'%s\'', payload)
|
||||
self.send(DbgMuxFrame.MsgType.Ping, payload)
|
||||
self.expect_pong = True
|
||||
# TODO: start a timer?
|
||||
|
||||
def handle_pong(self, payload: str):
|
||||
if not self.expect_pong:
|
||||
log.warning('Rx unexpected Pong, sending ACK anyway')
|
||||
return
|
||||
log.info('Rx Pong with payload \'%s\'', payload)
|
||||
self.expect_pong = False
|
||||
|
||||
def _handle_frame(self, frame: Container) -> None:
|
||||
if frame['MsgType'] == DbgMuxFrame.MsgType.Pong:
|
||||
self.handle_pong(frame['Msg'])
|
||||
self.send(DbgMuxFrame.MsgType.Ack)
|
||||
raise StopIteration
|
||||
|
||||
class SEDbgMuxApp(cmd2.Cmd):
|
||||
DESC = 'DebugMux client for [Sony] Ericsson phones and modems'
|
||||
|
@ -48,6 +111,10 @@ class SEDbgMuxApp(cmd2.Cmd):
|
|||
self.transport = TransportModem(self.argv)
|
||||
self.peer = DbgMuxPeer(self.transport)
|
||||
|
||||
# Register DebugMux frame handlers
|
||||
self.peer.disp.register(CommonFrameHandler(self), 'Common')
|
||||
self.peer.disp.register(PingPongHandler(), 'PingPong')
|
||||
|
||||
# Modem connection state
|
||||
self.set_connected(False)
|
||||
|
||||
|
@ -88,23 +155,8 @@ class SEDbgMuxApp(cmd2.Cmd):
|
|||
def do_enquiry(self, opts) -> None:
|
||||
''' Enquiry target identifier and available Data Providers '''
|
||||
self.peer.send(DbgMuxFrame.MsgType.Enquiry)
|
||||
while True:
|
||||
f = self.peer.recv()
|
||||
if f['MsgType'] == DbgMuxFrame.MsgType.Ident:
|
||||
log.info("Identified target: '%s', IMEI=%s",
|
||||
f['Msg']['Ident'][:-15],
|
||||
f['Msg']['Ident'][-15:])
|
||||
elif f['MsgType'] == DbgMuxFrame.MsgType.DPAnnounce:
|
||||
log.info("Data Provider available (DPRef=0x%04x): '%s'",
|
||||
f['Msg']['DPRef'], f['Msg']['Name'])
|
||||
|
||||
# No more data in the buffer
|
||||
# FIXME: layer violation!
|
||||
if self.transport._sl.in_waiting == 0:
|
||||
break
|
||||
|
||||
# ACKnowledge reception of the info
|
||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
||||
# The responce to be handled by CommonFrameHandler
|
||||
time.sleep(0.5)
|
||||
|
||||
ping_parser = cmd2.Cmd2ArgumentParser()
|
||||
ping_parser.add_argument('-p', '--payload',
|
||||
|
@ -115,52 +167,30 @@ class SEDbgMuxApp(cmd2.Cmd):
|
|||
@cmd2.with_category(CATEGORY_DBGMUX)
|
||||
def do_ping(self, opts) -> None:
|
||||
''' Send a Ping to the target, expect Pong '''
|
||||
log.info('Tx Ping with payload \'%s\'', opts.payload)
|
||||
self.peer.send(DbgMuxFrame.MsgType.Ping, opts.payload)
|
||||
|
||||
f = self.peer.recv()
|
||||
assert f['MsgType'] == DbgMuxFrame.MsgType.Pong
|
||||
log.info('Rx Pong with payload \'%s\'', f['Msg'])
|
||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
||||
hinst = self.peer.disp.find_by_name('PingPong')
|
||||
hinst.ping(opts.payload)
|
||||
|
||||
establish_parser = cmd2.Cmd2ArgumentParser()
|
||||
establish_parser.add_argument('DPRef',
|
||||
type=lambda v: int(v, 16),
|
||||
help='DPRef of a Data Provider in hex')
|
||||
establish_parser.add_argument('mode',
|
||||
choices=['interactive', 'udp-bridge'],
|
||||
help='Connection mode')
|
||||
|
||||
@cmd2.with_argparser(establish_parser)
|
||||
@cmd2.with_category(CATEGORY_DBGMUX)
|
||||
def do_establish(self, opts) -> None:
|
||||
''' Establish connection with a Data Provider '''
|
||||
log.info("Establishing connection with DPRef=0x%04x", opts.DPRef)
|
||||
self.peer.send(DbgMuxFrame.MsgType.ConnEstablish,
|
||||
dict(DPRef=opts.DPRef))
|
||||
|
||||
f = self.peer.recv()
|
||||
assert f['MsgType'] == DbgMuxFrame.MsgType.ConnEstablished
|
||||
if f['Msg']['ConnRef'] == 0xffff:
|
||||
log.warning("Connection failed: unknown DPRef=0x%04x?", opts.DPRef)
|
||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
||||
return
|
||||
|
||||
log.info("Connection established (ConnRef=0x%04x)",
|
||||
f['Msg']['ConnRef'])
|
||||
|
||||
# Read the messages
|
||||
while True:
|
||||
f = self.peer.recv()
|
||||
|
||||
if f['MsgType'] != DbgMuxFrame.MsgType.ConnData:
|
||||
log.warning('Unexpected frame: %s', f)
|
||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
||||
continue
|
||||
try: # FIXME: there can be binary data
|
||||
self.stdout.write(f['Msg']['Data'].decode())
|
||||
except: # ... ignore it for now
|
||||
continue
|
||||
|
||||
# ACKnowledge reception of a frame
|
||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
||||
if opts.mode == 'interactive':
|
||||
ch = DbgMuxConnInteractiveTerminal()
|
||||
self.peer.disp.register(ch)
|
||||
ch.establish(opts.DPRef)
|
||||
ch.attach()
|
||||
elif opts.mode == 'udp-bridge':
|
||||
ch = DbgMuxConnUdpBridge()
|
||||
self.peer.disp.register(ch)
|
||||
ch.establish(opts.DPRef)
|
||||
|
||||
|
||||
ap = argparse.ArgumentParser(prog='sedbgmux', description=SEDbgMuxApp.DESC,
|
||||
|
|
Loading…
Reference in New Issue