daniel has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/43093?usp=email )


Change subject: pysim-smpp2sim: Add support for a TCP connection through proact 
channel
......................................................................

pysim-smpp2sim: Add support for a TCP connection through proact channel

This can be used to test SCP-81 (RAM over HTTP) without needing a
modem/network setup.

Related: OS#6881
Change-Id: Idc1f0c75d89ccd879dc9588b7a0b8688b6f76a66
---
M pySim-smpp2sim.py
1 file changed, 70 insertions(+), 18 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/93/43093/1

diff --git a/pySim-smpp2sim.py b/pySim-smpp2sim.py
index fa670e5..dbbef8c 100755
--- a/pySim-smpp2sim.py
+++ b/pySim-smpp2sim.py
@@ -53,7 +53,7 @@
 from pySim.exceptions import *
 from pySim.cat import ProactiveCommand, SendShortMessage, SMS_TPDU, 
SMSPPDownload, BearerDescription
 from pySim.cat import DeviceIdentities, Address, OtherAddress, 
UiccTransportLevel, BufferSize
-from pySim.cat import ChannelStatus, ChannelData, ChannelDataLength
+from pySim.cat import ChannelStatus, ChannelData, ChannelDataLength, 
EventDownload, EventList
 from pySim.utils import b2h, h2b

 logger = logging.getLogger(__name__)
@@ -71,24 +71,58 @@
         print("-> %s %s" % (cmd[:10], cmd[10:]))
         print("<- %s: %s" % (sw, resp))

-class TcpProtocol(protocol.Protocol):
-    def dataReceived(self, data):
-        pass
-
-    def connectionLost(self, reason):
-        pass
-
-
 def tcp_connected_callback(p: protocol.Protocol):
     """called by twisted TCP client."""
     logger.error("%s: connected!" % p)
+    for data in p.pending_tx:
+        p.transport.write(data)

-class ProactChannel:
-    """Representation of a single protective channel."""
+class ProactChannel(protocol.Protocol):
+    """Representation of a single proactive channel."""
     def __init__(self, channels: 'ProactChannels', chan_nr: int):
         self.channels = channels
         self.chan_nr = chan_nr
         self.ep = None
+        self.pending_tx = []
+        self.pending_rx = bytearray()
+
+    def write(self, data: bytes):
+        if self.connected:
+            self.transport.write(data)
+        else:
+            self.pending_tx.append(data)
+
+    def dataReceived(self, data: bytes):
+        logger.error(f"Got data (len={len(data)}): {data}")
+        self.pending_rx.extend(data)
+        # Send ENVELOPE with EventDownload Data available
+        event_list_ie = EventList(decoded=[ EventList.Event.data_available])
+        dev_ids = DeviceIdentities(decoded={'source_dev_id': 'network', 
'dest_dev_id': 'uicc'})
+        channel_status_ie = ChannelStatus(decoded='8100')
+        channel_data_len_ie = 
ChannelDataLength(decoded=min(255,len(self.pending_rx)))
+        event_dl = EventDownload(children=[event_list_ie, dev_ids, 
channel_status_ie, channel_data_len_ie])
+        # 3) send to the card
+        envelope_hex = b2h(event_dl.to_tlv())
+        logger.info("ENVELOPE Event: %s" % envelope_hex)
+        global g_ms
+        (data, sw) = g_ms.scc.envelope(envelope_hex)
+        logger.info("SW %s: %s" % (sw, data))
+        # FIXME: Handle result?!
+
+    def connectionLost(self, reason):
+        logger.error("connection lost: %s" % reason)
+        # Send ENVELOPE with EventDownload connection closed
+        event_list_ie = EventList(decoded=[ EventList.Event.channel_status])
+        dev_ids = DeviceIdentities(decoded={'source_dev_id': 'network', 
'dest_dev_id': 'uicc'})
+        channel_status_ie = ChannelStatus(decoded='0100')
+        event_dl = EventDownload(children=[event_list_ie, dev_ids, 
channel_status_ie])
+        # 3) send to the card
+        envelope_hex = b2h(event_dl.to_tlv())
+        logger.info("ENVELOPE Event: %s" % envelope_hex)
+        global g_ms
+        (data, sw) = g_ms.scc.envelope(envelope_hex)
+        logger.info("SW %s: %s" % (sw, data))
+        # FIXME: Handle result?!

     def close(self):
         """Close the channel."""
@@ -174,15 +208,13 @@
             raise ValueError('Unsupported protocol_type')
         if other_addr_ie.decoded.get('type_of_address', None) != 'ipv4':
             raise ValueError('Unsupported type_of_address')
-        ipv4_bytes = h2b(other_addr_ie.decoded['address'])
+        ipv4_bytes = other_addr_ie.decoded['address']
         ipv4_str = '%u.%u.%u.%u' % (ipv4_bytes[0], ipv4_bytes[1], 
ipv4_bytes[2], ipv4_bytes[3])
         port_nr = transp_lvl_ie.decoded['port_number']
-        print("%s:%u" % (ipv4_str, port_nr))
+        logger.error("OpenChannel opening with %s:%u" % (ipv4_str, port_nr))
         channel = self.channels.channel_create()
         channel.ep = endpoints.TCP4ClientEndpoint(reactor, ipv4_str, port_nr)
-        channel.prot = TcpProtocol()
-        d = endpoints.connectProtocol(channel.ep, channel.prot)
-        # FIXME: why is this never called despite the client showing the 
inbound connection?
+        d = endpoints.connectProtocol(channel.ep, channel)
         d.addCallback(tcp_connected_callback)

         # Terminal Response example: [
@@ -199,6 +231,11 @@

     def handle_CloseChannel(self, pcmd: ProactiveCommand):
         """Close a channel."""
+        # CloseChannel(CommandDetails({'command_number': 1,
+        #                              'type_of_command': 'close_channel',
+        #                              'command_qualifier': 0}),
+        # DeviceIdentities({'source_dev_id': 'uicc',
+        #                   'dest_dev_id': 'channel_1'}))
         logger.info("CloseChannel")
         logger.info(pcmd)

@@ -213,6 +250,17 @@
         #                  ]}
         logger.info("ReceiveData")
         logger.info(pcmd)
+        dev_id_ie = Proact._find_first_element_of_type(pcmd.children, 
DeviceIdentities)
+        chan_data_len_ie = Proact._find_first_element_of_type(pcmd.children, 
ChannelDataLength)
+        len_requested = chan_data_len_ie.decoded
+        chan_str = dev_id_ie.decoded['dest_dev_id']
+        chan_nr = 1 # FIXME
+        chan = self.channels.channels.get(chan_nr, None)
+
+        requested = chan.pending_rx[:len_requested]
+        chan.pending_rx = chan.pending_rx[len_requested:]
+        resp = self.prepare_response(pcmd) + [ChannelData(decoded=requested), 
ChannelDataLength(decoded=min(255, len(chan.pending_rx)))]
+
         # Terminal Response example: [
         #  {'command_details': {'command_number': 1,
         #                       'type_of_command': 'receive_data',
@@ -222,7 +270,8 @@
         #  {'channel_data': '16030100040e000000'},
         #  {'channel_data_length': 0}
         # ]
-        return self.prepare_response(pcmd) + []
+        resp = self.prepare_response(pcmd) + [ChannelData(decoded=requested), 
ChannelDataLength(decoded=min(255, len(chan.pending_rx)))]
+        return resp

     def handle_SendData(self, pcmd: ProactiveCommand):
         """Send/write data received from the SIM to the socket."""
@@ -240,7 +289,10 @@
         chan_str = dev_id_ie.decoded['dest_dev_id']
         chan_nr = 1 # FIXME
         chan = self.channels.channels.get(chan_nr, None)
-        # FIXME chan.prot.transport.write(h2b(chan_data_ie.decoded))
+        # FIXME
+        logger.error(f"Chan data received: {chan_data_ie.decoded}")
+        chan.write(chan_data_ie.decoded)
+        #chan.write(h2b(chan_data_ie.decoded))
         # Terminal Response example: [
         #  {'command_details': {'command_number': 1,
         #                       'type_of_command': 'send_data',

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/43093?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: Idc1f0c75d89ccd879dc9588b7a0b8688b6f76a66
Gerrit-Change-Number: 43093
Gerrit-PatchSet: 1
Gerrit-Owner: daniel <[email protected]>

Reply via email to