From c81e0e2ad802d7ec03fee449fb959b6df09134cd Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Sun, 26 Jun 2022 00:02:02 +0700 Subject: [PATCH] SEDbgMuxApp: employ DbgMuxFrameDisp, implement basic handlers --- peer.py | 3 +- sedbgmux.py | 136 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 85 insertions(+), 54 deletions(-) diff --git a/peer.py b/peer.py index 5265dd2..8e4811c 100644 --- a/peer.py +++ b/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(): diff --git a/sedbgmux.py b/sedbgmux.py index 1badd46..a94fe1e 100755 --- a/sedbgmux.py +++ b/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,