Commits

Szymon Wróblewski  committed b4dea11

more universal structtype, updated protocol commands, extended peer module

  • Participants
  • Parent commits 937e6ec

Comments (0)

Files changed (3)

File ppenet/peer.py

 import random
 import protocol
+from structtype import structtype
 
 DEFAULT_ROUND_TRIP_TIME = 500
 DEFAULT_PACKET_THROTTLE = 32
         self.incoming_unreliable_commands = []
 
 
+Acknowledgement = structtype('Acknowledgement', (
+    'acknowledgement_list',
+    'sent_time',
+    'command',
+), default=0, field_defaults={'acknowledgement_list': []})
+
+OutgoingCommand = structtype('OutgoingCommand', (
+    'outgoing_command_list',
+    'reliable_sequence_number',
+    'unreliable_sequence_number',
+    'sent_time',
+    'round_trip_timeout',
+    'round_trip_timeout_limit',
+    'fragment_offset',
+    'fragment_length',
+    'send_attempts',
+    'command',
+    'packet',
+), default=0, field_defaults={'outgoing_command_list': []})
+
+IncomingCommand = structtype('IncomingCommand', (
+    'incoming_command_list',
+    'reliable_sequence_number',
+    'unreliable_sequence_number',
+    'command',
+    'fragment_count',
+    'fragments_remaining',
+    'fragments',
+    'packet',
+), default=0, field_defaults={'incoming_command_list': []})
+
+
 class Peer(object):
-    def __init__(self, host, address, peer_id, channel_count, data=None):
+    def __init__(self, host, peer_id, channel_count):
         self.host = host
         self.outgoing_peer_id = protocol.MAXIMUM_PEER_ID
         self.incoming_peer_id = peer_id
         self.connect_id = 0
         self.outgoing_session_id = self.incoming_session_id = 0xFF
-        self.address = address
-        self.data = data
+        self.address = None
+        self.data = None
         self.state = State.DISCONNECTED
-        self.channels = []
+        self.channels = {}
         self.channel_count = 0
         self.incoming_bandwidth = 0
         self.outgoing_bandwidth = 0
         self.unsequenced_window = []  # probably bytearray or memoryview
         self.event_data = 0
 
-    def connect(self, address):
+    def connect(self, address, data=None):
         host = self.host
         self.state = State.CONNECTING
         self.address = address
                           * protocol.MAXIMUM_WINDOW_SIZE
         self.window_size = max(min(window_size, protocol.MAXIMUM_WINDOW_SIZE),
                                protocol.MINIMUM_WINDOW_SIZE)
-        protocol.CommandHeader(
+        connect = protocol.Connect(
             protocol.Command.CONNECT | protocol.Flag.COMMAND_ACKNOWLEDGE,
             0xFF,
-            0
-        )
+            0,
+            self.incoming_peer_id,
+            self.incoming_session_id,
+            self.outgoing_session_id,
+            self.mtu,
+            self.window_size,
+            self.channel_count,
+            self.incoming_bandwidth,
+            self.outgoing_bandwidth,
+            self.packet_throttle_interval,
+            self.packet_throttle_acceleration,
+            self.packet_throttle_deceleration,
+            self.connect_id,
+            self.data)
 
+    def _queue_outgoing_command(self, command):
+        #try:
+        #    self.channels[]
+        pass
+

File ppenet/protocol.py

 import socket
 from structtype import structtype
 
-
 MINIMUM_MTU = 576
 MAXIMUM_MTU = 4096
 MAXIMUM_PACKET_COMMANDS = 32
     'reliable_sequence_number',
 ), '!BBH', default=0)
 
-Acknowledge = structtype('Acknowledge', (
-    'header',
+Acknowledge = structtype('Acknowledge', CommandHeader.field_names + (
     'received_reliable_sequence_number',
     'received_sent_time'
-), '!%dsHH' % int(CommandHeader.size), default=0)
+), CommandHeader.format + 'HH', default=0)
 
-Connect = structtype('Connect', (
-    'header',
+Connect = structtype('Connect', CommandHeader.field_names + (
     'outgoing_peer_id',
     'incoming_session_id',
     'outgoing_session_id',
     'packet_throttle_deceleration',
     'connect_id',
     'data',
-), '!%dsHBB10I' % CommandHeader.size, default=0)
+), CommandHeader.format + 'HBB10I', default=0)
 
-VerifyConnect = structtype('VerifyConnect', (
-    'header',
+VerifyConnect = structtype('VerifyConnect', CommandHeader.field_names + (
     'outgoing_peer_id',
     'incoming_session_id',
     'outgoing_session_id',
     'packet_throttle_acceleration',
     'packet_throttle_deceleration',
     'connect_id',
-), '!%dsHBB9I' % CommandHeader.size, default=0)
+), CommandHeader.format + 'HBB9I', default=0)
 
-BandwidthLimit = structtype('BandwidthLimit', (
-    'header',
+BandwidthLimit = structtype('BandwidthLimit', CommandHeader.field_names + (
     'incoming_bandwidth',
     'outgoing_bandwidth',
-), '!%dsII' % CommandHeader.size, default=0)
+), CommandHeader.format + 'II', default=0)
 
-ThrottleConfigure = structtype('ThrottleConfigure', (
-    'header',
+ThrottleConfigure = structtype('ThrottleConfigure', CommandHeader.field_names + (
     'packet_throttle_interval',
     'packet_throttle_acceleration',
     'packet_throttle_deceleration',
-), '!%dsIII' % CommandHeader.size, default=0)
+), CommandHeader.format + '3I', default=0)
 
-Disconnect = structtype('Disconnect', (
-    'header',
+Disconnect = structtype('Disconnect', CommandHeader.field_names + (
     'data',
-), '!%dsI' % CommandHeader.size, default=0)
+), CommandHeader.format + 'I', default=0)
 
-Ping = structtype('Ping', (
-    'header',
-), '!%ds' % CommandHeader.size, default=0)
+Ping = structtype('Ping', CommandHeader.field_names,
+                  CommandHeader.format, default=0)
 
-SendReliable = structtype('SendReliable', (
-    'header',
+SendReliable = structtype('SendReliable', CommandHeader.field_names + (
     'data_length',
-), '!%dsH' % CommandHeader.size, default=0)
+), CommandHeader.format + 'H', default=0)
 
-SendUnreliable = structtype('SendUnreliable', (
-    'header',
+SendUnreliable = structtype('SendUnreliable', CommandHeader.field_names + (
     'unreliable_sequence_number',
     'data_length',
-), '!%dsHH' % CommandHeader.size, default=0)
+), CommandHeader.format + 'HH', default=0)
 
-SendUnsequenced = structtype('SendUnsequenced', (
-    'header',
+SendUnsequenced = structtype('SendUnsequenced', CommandHeader.field_names + (
     'unsequenced_group',
     'data_length',
-), '!%dsHH' % CommandHeader.size, default=0)
+), CommandHeader.format + 'HH', default=0)
 
-SendFragment = structtype('SendFragment', (
-    'header',
+SendFragment = structtype('SendFragment', CommandHeader.field_names + (
     'start_sequence_number',
     'data_length',
     'fragment_count',
     'fragment_number',
     'total_length',
     'fragment_offset',
-), '!%dsHH4I' % CommandHeader.size, default=0)
+), CommandHeader.format + 'HH4I', default=0)

File ppenet/structtype.py

 from keyword import iskeyword
 
 
-def structtype(typename, field_names, format, verbose=False, **default_kwds):
-    '''Returns a new class with named fields.
+def structtype(typename, field_names, format=None, verbose=False, **default_kwds):
+    '''Returns a new class with named fields and abilities of struct.Struct.
 
     @keyword field_defaults: A mapping from (a subset of) field names to
         default values.
         init_defaults = tuple(field_defaults[f] for f in default_fields)
     if default_kwds:
         raise ValueError('Invalid keyword arguments: %s' % default_kwds)
+    # Check format parameter
+    if format:
+        try:
+            struct.pack(format, *(init_defaults if init_defaults\
+                                  else (0,) * len(field_names)))
+        except:
+            raise ValueError('Invalid format arguments: %s' % format)
+
     # Create and fill-in the class template
     numfields = len(field_names)
     argtxt = ', '.join(field_names)
     inittxt = '; '.join('self.%s=%s' % (f, f) for f in field_names)
     itertxt = '; '.join('yield self.%s' % f for f in field_names)
     eqtxt = ' and '.join('self.%s==other.%s' % (f, f) for f in field_names)
+    structtxt = '''
+    __struct = struct.Struct('%(format)s')
+    format = __struct.format
+    size = __struct.size
+
+    def pack(self):
+        return self.__struct.pack(%(tupletxt)s)
+
+    def pack_into(self, buffer, offset=0):
+        return self.__struct.pack_into(buffer, offset, %(tupletxt)s)
+
+    def unpack(self, string):
+        %(tupletxt)s = self.__struct.unpack(string)
+
+    def unpack_from(self, buffer, offset=0):
+        %(tupletxt)s = self.__struct.unpack_from(buffer, offset)
+    ''' % {'format': format, 'tupletxt': tupletxt[1:-1]} if format else ''
     template = dedent('''
         class %(typename)s(object):
             '%(typename)s(%(argtxt)s)'
 
             __slots__  = %(field_names)r
-            __struct = struct.Struct('%(format)s')
-            format = __struct.format
-            size = __struct.size
+            field_names = __slots__
 
             def __init__(self, %(argtxt)s):
                 %(inittxt)s
             def __setstate__(self, state):
                 %(tupletxt)s = state
 
-            def pack(self):
-                return self.__struct.pack(*%(tupletxt)s)
-
-            def pack_into(self, buffer, offset=0):
-                return self.__struct.pack_into(buffer, offset, *%(tupletxt)s)
-
-            def unpack(self, string):
-                %(tupletxt)s =self.__struct.unpack(string)
-
-            def unpack_from(self, buffer, offset=0):
-                %(tupletxt)s = self.__struct.unpack_from(buffer, offset)
+            %(structtxt)s
     ''') % locals()
     # Execute the template string in a temporary namespace
     namespace = {'struct': struct}