The Assimilation Monitoring Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
AssimCclasses.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 # vim: smartindent tabstop=4 shiftwidth=4 expandtab
3 #
4 #
5 # This file is part of the Assimilation Project.
6 #
7 # Copyright (C) 2011, 2012 - Alan Robertson <alanr@unix.sh>
8 #
9 # The Assimilation software is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # The Assimilation software is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with the Assimilation Project software. If not, see http://www.gnu.org/licenses/
21 #
22 #
23 '''
24 A collection of classes which wrap our @ref C-Classes and provide Pythonic interfaces to these C-classes.
25 '''
26 
27 from AssimCtypes import *
28 from frameinfo import FrameTypes, FrameSetTypes
29 import collections
30 import traceback
31 import sys
32 import gc
33 
34 class cClass:
35  NetAddr = POINTER(NetAddr)
36  Frame = POINTER(Frame)
37  AddrFrame = POINTER(AddrFrame)
38  IntFrame = POINTER(IntFrame)
39  SeqnoFrame = POINTER(SeqnoFrame)
40  CstringFrame = POINTER(CstringFrame)
41  UnknownFrame = POINTER(UnknownFrame)
42  SignFrame = POINTER(SignFrame)
43  FrameSet = POINTER(FrameSet)
44  ConfigContext = POINTER(ConfigContext)
45  ConfigValue = POINTER(ConfigValue)
46  IpPortFrame = POINTER(IpPortFrame)
47  guint8 = POINTER(guint8)
48  GSList = POINTER(GSList)
49 
50 def CCref(obj):
51  '''
52  Increment the reference count to an AssimObj (_not_ a pyAssimObj)
53  Need to call CCref under the following circumstances:
54  When we are creating an object that points to another underlying C-class object
55  which already has a permanent reference to it somewhere else
56  For example, if we're returning a pyNetAddr object that points to a NetAddr object
57  that's in a ConfigContext object. If we don't, then when our pyNetAddr object goes
58  out of scope, then the underlying NetAddr object will be freed, even though there's
59  a reference to it in the ConfigContext object. Conversely, if the ConfigContext
60  object goes out of scope first, then the our pyNetAddr object could become invalid.
61 
62  Do not call it when you've constructed a new object that there were no previous pointers
63  to.
64  '''
65  base = obj[0]
66  while (type(base) is not AssimObj):
67  base=base.baseclass
68  base.ref(obj)
69 
70 def CCunref(obj):
71  base = obj[0]
72  while (type(base) is not AssimObj):
73  base=base.baseclass
74  base.unref(obj)
75 
77  lldpnames = {
78  LLDP_TLV_END: ('END', True),
79  LLDP_TLV_CHID: ('ChassisId', True),
80  LLDP_TLV_PID: ('PortId', True),
81  LLDP_TLV_TTL: ('TTL', True),
82  LLDP_TLV_PORT_DESCR: ('PortDescription', False),
83  LLDP_TLV_SYS_NAME: ('SystemName', True),
84  LLDP_TLV_SYS_DESCR: ('SystemDescription', True),
85  LLDP_TLV_SYS_CAPS: ('SystemCapabilities', True),
86  LLDP_TLV_MGMT_ADDR: ('ManagementAddress', True),
87  LLDP_TLV_ORG_SPECIFIC: ('(OrgSpecific)', True),
88  }
89  lldp802_1names = {
90  LLDP_ORG802_1_VLAN_PVID: ('VlanPvId', False),
91  LLDP_ORG802_1_VLAN_PORTPROTO: ('VlanPortProtocol', False),
92  LLDP_ORG802_1_VLAN_NAME: ('VlanName', False),
93  LLDP_ORG802_1_VLAN_PROTOID: ('VlanProtocolId', False),
94  }
95  lldp802_3names = {
96  LLDP_ORG802_3_PHY_CONFIG: ('PhysicalConfiguration', False),
97  LLDP_ORG802_3_POWERVIAMDI: ('PowerViaMDI', False),
98  LLDP_ORG802_3_LINKAGG: ('LinkAggregation', False),
99  LLDP_ORG802_3_MTU: ('MTU', False),
100  }
101 
102  @staticmethod
103  def _byte0(pktstart):
104  return int(cast(pktstart, cClass.guint8)[0])
105 
106  @staticmethod
107  def _byte1addr(pktstart):
108  addr = addressof(pktstart.contents) + 1
109  return pointer(type(pktstart.contents).from_address(addr))
110 
111  @staticmethod
112  def _byteN(pktstart, n):
113  return int(cast(pktstart, cClass.guint8)[n])
114 
115  @staticmethod
116  def _byteNaddr(pktstart, n):
117  addr = addressof(pktstart.contents) + n
118  return pointer(type(pktstart.contents).from_address(addr))
119 
120  @staticmethod
121  def _decode_netaddr(addrstart, addrlen):
122  byte0 = SwitchDiscovery._byte0(addrstart)
123  byte1addr = SwitchDiscovery._byte1addr(addrstart)
124  Cnetaddr = None
125  if byte0 == ADDR_FAMILY_IPV6:
126  if addrlen != 17: return None
127  Cnetaddr = netaddr_ipv6_new(byte1addr, 0)
128  elif byte0 == ADDR_FAMILY_IPV4:
129  if addrlen != 5: return None
130  Cnetaddr = netaddr_ipv4_new(byte1addr, 0)
131  elif byte0 == ADDR_FAMILY_802:
132  if addrlen == 7:
133  Cnetaddr = netaddr_mac48_new(byte1addr)
134  elif addrlen == 9:
135  Cnetaddr = netaddr_mac64_new(byte1addr)
136  if Cnetaddr is not None:
137  return str(pyNetAddr(None, Cstruct=Cnetaddr))
138  return None
139 
140  @staticmethod
141  def decode_discovery(host, interface, wallclock, pktstart, pktend):
142  if is_valid_lldp_packet(pktstart, pktend):
143  return SwitchDiscovery._decode_lldp(host, interface, wallclock, pktstart, pktend)
144  if is_valid_cdp_packet(pktstart, pktend):
145  return SwitchDiscovery._decode_cdp(host, interface, wallclock, pktstart, pktend)
146  raise ValueError('Malformed Switch Discovery Packet')
147 
148  @staticmethod
149  def _decode_lldp(host, interface, wallclock, pktstart, pktend):
150  'Decode LLDP packet into a JSON discovery packet'
151  thisportinfo = pyConfigContext(init={
152  'ConnectsToHost': host,
153  'ConnectsToInterface': interface,
154  }
155  )
156  switchinfo = pyConfigContext(init = {'ports': pyConfigContext()})
157  metadata = pyConfigContext(init={
158  'discovertype': '#LinkDiscovery',
159  'description': 'Link Level Switch Discovery (lldp)',
160  'source': '_decode_lldp()',
161  'host': host,
162  'localtime': str(wallclock),
163  'data': switchinfo,
164  }
165  )
166 
167  sourcemacptr = SwitchDiscovery._byteNaddr(cast(pktstart, cClass.guint8), 6)
168  if not sourcemacptr:
169  return metadata
170  Cmacaddr = netaddr_mac48_new(sourcemacptr)
171  sourcemac = pyNetAddr(None, Cstruct=Cmacaddr)
172 
173 
174  this = get_lldptlv_first(pktstart, pktend)
175  while this and this < pktend:
176  tlvtype = get_lldptlv_type(this, pktend)
177  tlvlen = get_lldptlv_len(this, pktend)
178  tlvptr = cast(get_lldptlv_body(this, pktend), cClass.guint8)
179  value = None
180  if tlvtype not in SwitchDiscovery.lldpnames:
181  print >>sys.stderr, 'Cannot find tlvtype %d' % tlvtype
182  tlvtype = None
183  else:
184  (tlvname,isswitchinfo) = SwitchDiscovery.lldpnames[tlvtype]
185 
186  if (tlvtype == LLDP_TLV_PORT_DESCR or tlvtype == LLDP_TLV_SYS_NAME or
187  tlvtype == LLDP_TLV_SYS_DESCR): #########################################
188  value = string_at(tlvptr, tlvlen)
189 
190  elif tlvtype == LLDP_TLV_PID: ###############################################
191  pidtype = SwitchDiscovery._byte0(tlvptr)
192  if (pidtype == LLDP_PIDTYPE_ALIAS or pidtype == LLDP_PIDTYPE_IFNAME
193  or pidtype == LLDP_PIDTYPE_LOCAL):
194  sloc = SwitchDiscovery._byte1addr(tlvptr)
195  value = string_at(sloc, tlvlen-1)
196 
197  elif tlvtype == LLDP_TLV_CHID: #############################################
198  chidtype = SwitchDiscovery._byte0(tlvptr)
199 
200  if (chidtype == LLDP_CHIDTYPE_COMPONENT or chidtype == LLDP_CHIDTYPE_ALIAS
201  or chidtype == LLDP_CHIDTYPE_IFNAME or chidtype == LLDP_CHIDTYPE_LOCAL):
202  sloc = SwitchDiscovery._byte1addr(tlvptr)
203  value = string_at(sloc, tlvlen-1)
204  elif chidtype == LLDP_CHIDTYPE_MACADDR:
205  byte1addr = SwitchDiscovery._byte1addr(tlvptr)
206  Cmacaddr = None
207  if tlvlen == 7:
208  Cmacaddr = netaddr_mac48_new(byte1addr)
209  elif tlvlen == 9:
210  Cmacaddr = netaddr_mac64_new(byte1addr)
211  if Cmacaddr is not None:
212  value = pyNetAddr(None, Cstruct=Cmacaddr)
213  elif chidtype == LLDP_CHIDTYPE_NETADDR:
214  byte1addr = SwitchDiscovery._byte1addr(tlvptr)
215  value = SwitchDiscovery._decode_netaddr(byte1addr, tlvlen-1)
216 
217  elif tlvtype == LLDP_TLV_MGMT_ADDR: #########################################
218  addrlen = SwitchDiscovery._byte0(tlvptr)
219  byte1addr = SwitchDiscovery._byte1addr(tlvptr)
220  value = SwitchDiscovery._decode_netaddr(byte1addr, addrlen)
221 
222  elif tlvtype == LLDP_TLV_ORG_SPECIFIC: ######################################
223  print >>sys.stderr, 'Found LLDP org-specific extensions (not processed)'
224 
225  if value is not None:
226  if tlvtype == LLDP_TLV_PID:
227  switchinfo['ports'][value] = thisportinfo
228  numericpart = value
229  while len(numericpart) > 0 and not numericpart.isdigit():
230  numericpart = numericpart[1:]
231  if len > 0 and numericpart.isdigit():
232  thisportinfo['_PORTNO'] = int(numericpart)
233  else:
234  if isswitchinfo:
235  switchinfo[tlvname] = value
236  else:
237  thisportinfo[tlvname] = value
238  this = get_lldptlv_next(this, pktend)
239  thisportinfo['sourceMAC'] = sourcemac
240  return metadata
241 
242 
243  @staticmethod
244  def _decode_cdp(host, interface, wallclock, pktstart, pktend):
245  'Decode CDP packet into a JSON discovery packet'
246  thisportinfo = pyConfigContext(init={
247  'ConnectsToHost': host,
248  'ConnectsToInterface': interface,
249  }
250  )
251  switchinfo = pyConfigContext(init = {'ports': pyConfigContext()})
252  metadata = pyConfigContext(init={
253  'discovertype': '#LinkDiscovery',
254  'description': 'Link Level Switch Discovery (cdp)',
255  'source': '_decode_cdp()',
256  'host': host,
257  'localtime': str(wallclock),
258  'data': switchinfo,
259  }
260  )
261  return metadata
262 
263 
264 
265 
267  def __init__(self, Cstruct=None):
268  'Create a base pyAssimObj object'
269  self._Cstruct = None
270  if (Cstruct is not None):
271  assert type(Cstruct) is not int
272  self._Cstruct = Cstruct
273  else:
274  self._Cstruct = assimobj_new(0)
275  #print 'ASSIMOBJ:init: %s' % (Cstruct)
276 
277  def cclassname(self):
278  return proj_class_classname(self._Cstruct)
279 
280  def __str__(self):
281  'Convert this AssimObj into a printable string'
282  if not self._Cstruct:
283  return "[None]"
284  base = self._Cstruct[0]
285  while (type(base) is not AssimObj):
286  base=base.baseclass
287  cstringret = base.toString(self._Cstruct)
288  ret = string_at(cstringret)
289  g_free(cstringret)
290  return ret
291 
292  def __del__(self):
293  'Free up the underlying Cstruct for this pyAssimObj object.'
294  if not self._Cstruct or self._Cstruct is None:
295  return
296  base=self._Cstruct[0]
297  # I have no idea why the type(base) is not Frame doesn't work here...
298  # This 'hasattr' construct only works because we are a base C-class
299  global badfree
300  badfree=0
301  CCunref(self._Cstruct)
302  if badfree != 0:
303  print >>sys.stderr, "Attempt to free something already freed(%s)" % str(self._Cstruct)
304  traceback.print_stack()
305  badfree = 0
306  self._Cstruct = None
307 
308  def refcount(self):
309  base = self._Cstruct[0]
310  while (hasattr(base, 'baseclass')):
311  base=base.baseclass
312  return base._refcount
313 
315  '''This class represents the Python version of our C-class @ref NetAddr - represented by the struct _NetAddr.
316  '''
317  def __init__(self, addrstring, port=None, Cstruct=None):
318  '''This constructor needs a list of integers of the right length as its first argument.
319  The length of the list determines the type of address generated.
320  4 bytes == ipv4
321  6 bytes == MAC address
322  8 bytes == MAC address
323  16 bytes == ipv6 address
324  This is slightly sleazy but it should work for the forseeable future.
325  '''
326 
327  self._Cstruct = None # Silence error messages in failure cases
328 
329  if (Cstruct is not None):
330  assert type(Cstruct) is not int
331  pyAssimObj.__init__(self, Cstruct=Cstruct)
332  if port is not None:
333  self.setport(port)
334  return
335 
336  if port is None: port = 0
337 
338  if isinstance(addrstring, unicode) or isinstance(addrstring, pyNetAddr):
339  addrstring = str(addrstring)
340  if isinstance(addrstring, str):
341  cs = netaddr_string_new(addrstring)
342  if not cs:
343  raise ValueError('Illegal NetAddr initial value: "%s"' % addrstring)
344  if port != 0:
345  cs[0].setport(cs, port)
346  pyAssimObj.__init__(self, Cstruct=cs)
347  return
348 
349  alen = len(addrstring)
350  addr = create_string_buffer(alen)
351  #print >>sys.stderr, "ADDRTYPE:", type(addr)
352  #print >>sys.stderr, "ADDRSTRINGTYPE:", type(addrstring)
353  for i in range(0, alen):
354  asi = addrstring[i]
355  #print >>sys.stderr, "ASI_TYPE: (%s,%s)" % (type(asi), asi)
356  if type(asi) is str:
357  addr[i] = asi
358  elif type(asi) is unicode:
359  addr[i] = str(asi)
360  else:
361  addr[i] = chr(asi)
362  #print >>sys.stderr, 'ADDR = %s' % addr
363  if alen == 4: # ipv4
364  NA = netaddr_ipv4_new(addr, port)
365  pyAssimObj.__init__(self, Cstruct=NA)
366  elif alen == 16: # ipv6
367  pyAssimObj.__init__(self, netaddr_ipv6_new(addr, port))
368  elif alen == 6: # "Normal" 48-bit MAC address
369  assert port == 0
370  pyAssimObj.__init__(self, netaddr_mac48_new(addr, port))
371  elif alen == 8: # Extended 64-bit MAC address
372  assert port == 0
373  pyAssimObj.__init__(self, netaddr_mac64_new(addr, port))
374  else:
375  raise ValueError('Invalid address length - not 4, 6, 8, or 16')
376 
377  def port(self):
378  'Return the port (if any) for this pyNetAddr object'
379  base=self._Cstruct[0]
380  while (type(base) is not NetAddr):
381  base=base.baseclass
382  return base.port(self._Cstruct)
383 
384  def setport(self, port):
385  'Return the port (if any) for this pyNetAddr object'
386  base=self._Cstruct[0]
387  while (type(base) is not NetAddr):
388  base=base.baseclass
389  base.setport(self._Cstruct, port)
390 
391  def addrtype(self):
392  'Return the type of address for this pyNetAddr object'
393  base=self._Cstruct[0]
394  while (type(base) is not NetAddr):
395  base=base.baseclass
396  return base.addrtype(self._Cstruct)
397 
398  def addrlen(self):
399  "Return the number of bytes necessary to represent this pyNetAddr object on the wire."
400  base=self._Cstruct[0]
401  while (type(base) is not NetAddr):
402  base=base.baseclass
403  return base._addrlen
404 
405  def islocal(self):
406  'Return True if this address is a local address'
407  base=self._Cstruct[0]
408  while (type(base) is not NetAddr):
409  base=base.baseclass
410  return base.islocal(self._Cstruct)
411 
412  def toIPv6(self, port=None):
413  'Return an equivalent IPv6 address to the one that was given. Guaranteed to be a copy'
414  base=self._Cstruct[0]
415  while (type(base) is not NetAddr):
416  base=base.baseclass
417  newcs = cast(base.toIPv6(self._Cstruct), cClass.NetAddr)
418  return pyNetAddr(None, Cstruct=newcs, port=port)
419 
420  def __repr__(self):
421  'Return a canonical representation of this NetAddr'
422  base=self._Cstruct[0]
423  while (type(base) is not NetAddr):
424  base=base.baseclass
425  cstringret = base.canonStr(self._Cstruct)
426  ret = string_at(cstringret)
427  g_free(cstringret)
428  return ret
429 
430 
431  def __eq__(self, other):
432  "Return True if the two pyNetAddrs are equal"
433  if not other._Cstruct or not self._Cstruct:
434  return False
435  base=self._Cstruct[0]
436  while (type(base) is not NetAddr):
437  base=base.baseclass
438  return base.equal(self._Cstruct, other._Cstruct)
439 
440  def __hash__(self):
441  'Return a hash value for the given pyNetAddr'
442  if not self._Cstruct:
443  return 0
444  base=self._Cstruct[0]
445  while (type(base) is not NetAddr):
446  base=base.baseclass
447  return base.hash(self._Cstruct)
448 
449 
451  '''This class represents the Python version of our C-class @ref Frame - represented by the struct _Frame.
452  This class is a base class for several different pyFrame subclasses.
453  Each of these various pyFrame subclasses have a corresponding C-class @ref Frame subclass.
454  The purpose of these pyFrames and their subclasses is to talk on the wire with our C code in our
455  nanoprobes.
456 
457  Deliberately leaving out the updatedata() C-class member function - at least for mow.
458  I suspect that the Python code will only need the corresponding calls in a @ref FrameSet - which would
459  then update the corresponding @ref Frame member functions...
460  '''
461  #
462  # Our subclasses need to implement these methods:
463  # __init__ - subclass initializer
464  # from_Cstruct classmethod - call the corresponding xxxframe_tlvconstructor() function
465  # to act as a pseudo-constructor. This method/constructor is used to create
466  # Python objects from incoming packet data.
467  #
468  def __init__(self, initval, Cstruct=None):
469  "Initializer for the pyFrame object."
470  if Cstruct is None:
471  try:
472  frametype = initval.tlvtype
473  except:
474  frametype = int(initval)
475  # If we don't do this, then a subclass __init__ function must do it instead...
476  pyAssimObj.__init__(self, Cstruct=frame_new(frametype, 0))
477  else:
478  pyAssimObj.__init__(self, Cstruct=Cstruct)
479 
480  def frametype(self):
481  "Return the TLV type for the pyFrame object."
482  base=self._Cstruct[0]
483  while (type(base)is not Frame):
484  base=base.baseclass
485  return base.type
486 
487  def framelen(self):
488  "Return the length of this frame in bytes (TLV length)."
489  base=self._Cstruct[0]
490  while (type(base)is not Frame):
491  base=base.baseclass
492  return base.length
493 
494  def framevalue(self):
495  'Return a C-style pointer to the underlying raw TLV data (if any)'
496  base=self._Cstruct[0]
497  while (type(base)is not Frame):
498  base=base.baseclass
499  return cast(base.value, c_char_p)
500 
501  def frameend(self):
502  'Return a C-style pointer to the underlying raw TLV data (if any)'
503  base=self._Cstruct[0]
504  while (type(base)is not Frame):
505  base=base.baseclass
506  return cast(base.value+base.length, c_char_p)
507 
508  def dataspace(self):
509  'Return the amount of space this frame needs - including type and length'
510  base=self._Cstruct[0]
511  while (type(base) is not Frame):
512  base=base.baseclass
513  return base.dataspace(self._Cstruct)
514 
515  def isvalid(self):
516  "Return True if this Frame is valid"
517  base=self._Cstruct[0]
518  while (type(base) is not Frame):
519  base=base.baseclass
520  pstart = pointer(cast(base.value, c_char_p))
521 # if pstart[0] is None:
522 # return False
523  return (int(base.isvalid(self._Cstruct, None, None)) != 0)
524 
525  def setvalue(self, value):
526  'Assign a chunk of memory to the Value portion of this Frame'
527  vlen = len(value)
528  if type(value) is str:
529  valbuf = create_string_buffer(vlen+1)
530  for i in range(0, vlen):
531  vi = value[i]
532  valbuf[i] = vi
533  valbuf[vlen] = chr(0)
534  vlen += 1
535  else:
536  valbuf = create_string_buffer(vlen)
537  for i in range(0, vlen):
538  vi = value[i]
539  valbuf[i] = int(vi)
540  base=self._Cstruct[0]
541  valptr = MALLOC(vlen)
542  memmove(valptr, valbuf, vlen)
543  while (type(base) is not Frame):
544  base=base.baseclass
545  base.setvalue(self._Cstruct, valptr, vlen, cast(None, GDestroyNotify))
546 
547  def dump(self, prefix):
548  'Dump out this Frame (using C-class "dump" member function)'
549  base=self._Cstruct[0]
550  while (type(base) is not Frame):
551  base=base.baseclass
552  base.dump(self._Cstruct, cast(prefix, c_char_p))
553 
554  def __str__(self):
555  base = self._Cstruct[0]
556  while (type(base) is not AssimObj):
557  base=base.baseclass
558  cstringret = base.toString(self._Cstruct)
559  ret = string_at(cstringret)
560  g_free(cstringret)
561  return '%s: %s' % (FrameTypes.get(self.frametype())[1] , ret)
562 
563  @staticmethod
564  def Cstruct2Frame(frameptr):
565  frameptr = cast(frameptr, cClass.Frame)
566  CCref(frameptr)
567  frametype = frameptr[0].type
568  Cclassname = proj_class_classname(frameptr)
569  pyclassname = "py" + Cclassname
570  if Cclassname == 'NetAddr':
571  statement = "%s(%d, None, Cstruct=cast(frameptr, cClass.%s))" % (pyclassname, frametype, Cclassname)
572  elif Cclassname == Cclassname == 'IpPortFrame':
573  statement = "%s(%d, None, None, Cstruct=cast(frameptr, cClass.%s))" % (pyclassname, frametype, Cclassname)
574  else:
575  statement = "%s(%d, Cstruct=cast(frameptr, cClass.%s))" % (pyclassname, frametype, Cclassname)
576  #print >>sys.stderr, "EVAL:", statement
577  return eval(statement)
578 
580  '''This class represents the Python version of our C-class AddrFrame - represented by the struct _AddrFrame.
581  '''
582  def __init__(self, frametype, addrstring=None, port=None, Cstruct=None):
583  "Initializer for the pyAddrFrame object."
584  self._Cstruct = None # Keep error legs from complaining.
585  if Cstruct is None:
586  if isinstance(addrstring, pyNetAddr):
587  self._pyNetAddr = addrstring
588  else:
589  self._pyNetAddr = pyNetAddr(addrstring, port=port)
590  Cstruct=addrframe_new(frametype, 0)
591  if addrstring is not None:
592  Cstruct[0].setnetaddr(Cstruct, self._pyNetAddr._Cstruct)
593  else:
594  assert port is None
595  assert addrstring is None
596  addrlen = Cstruct[0].baseclass.length - 2 # Allow for prefixed address type - two bytes
597  assert addrlen == 4 or addrlen == 6 or addrlen == 8 or addrlen == 16, ("addrlen is %d" % addrlen)
598  addrstr = Cstruct[0].baseclass.value+2
599  addrstring = create_string_buffer(addrlen)
600  memmove(addrstring, addrstr, addrlen)
601  self._pyNetAddr = pyNetAddr(addrstring, port=None)
602  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
603 
604  def addrtype(self):
605  return self._pyNetAddr.addrtype()
606 
607  def getnetaddr(self):
608  return self._pyNetAddr
609 
610  def __str__(self):
611  return ("pyAddrFrame(%s, (%s))" % (FrameTypes.get(self.frametype())[1], str(self._pyNetAddr)))
612 
614  '''This class represents the Python version of our C-class IpPortFrame - represented by the struct _IpPortFrame.
615  '''
616  def __init__(self, frametype, addrstring, port=None, Cstruct=None):
617  "Initializer for the pyIpPortFrame object."
618  self._Cstruct = None # Keep error legs from complaining.
619  if Cstruct is None:
620  if isinstance(addrstring, pyNetAddr):
621  self._pyNetAddr = addrstring
622  Cstruct=ipportframe_netaddr_new(frametype, addrstring._Cstruct)
623  if not Cstruct:
624  raise ValueError("invalid initializer");
625  self.port = addrstring.port()
626  else:
627  addrlen = len(addrstring)
628  self._pyNetAddr = pyNetAddr(addrstring, port=port)
629  if self._pyNetAddr is None:
630  raise ValueError("Invalid initializer.");
631  addrstr = create_string_buffer(addrlen)
632  for j in range(0, addrlen):
633  addrstr[j] = chr(addrstring[j])
634  if addrlen == 4:
635  Cstruct=ipportframe_ipv4_new(frametype, port, addrstr)
636  elif addrlen == 16:
637  Cstruct=ipportframe_ipv6_new(frametype, port, addrstr)
638  else:
639  raise ValueError('Bad address length: %d' % addrlen)
640  self.port = port
641  if port == 0:
642  raise ValueError("zero port");
643  if not Cstruct:
644  raise ValueError("invalid initializer");
645 
646  else:
647  assert port is None
648  assert addrstring is None
649  addrlen = Cstruct[0].baseclass.length - 4 # Allow for prefixed port and address type
650  if addrlen != 4 and addrlen != 16:
651  raise ValueError("Bad addrlen: %d" % addrlen)
652  port = Cstruct[0].port
653  self.port = port
654  addrstr = Cstruct[0].baseclass.value+4
655  addrstring = create_string_buffer(addrlen)
656  memmove(addrstring, addrstr, addrlen)
657  self._pyNetAddr = pyNetAddr(addrstring, port=port)
658  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
659 
660  def addrtype(self):
661  return self._pyNetAddr.addrtype()
662 
663  def getnetaddr(self):
664  return self._pyNetAddr
665 
666 
668  '''This class represents the Python version of our C-class CstringFrame - represented by the struct _CstringFrame
669  This class represents a Frame standard NUL-terminated C string.
670  '''
671  def __init__(self, frametype, initval=None, Cstruct=None):
672  'Constructor for pyCstringFrame object - initial value should be something that looks a lot like a Python string'
673  if Cstruct is None:
674  Cstruct=cstringframe_new(frametype, 0)
675  pyFrame.__init__(self, frametype, Cstruct)
676  if initval is not None:
677  self.setvalue(initval)
678 
679  def getstr(self):
680  base = self._Cstruct[0]
681  while (not hasattr(base, 'value')):
682  base=base.baseclass
683  return string_at(base.value)
684 
686  '''This class represents the Python version of our IntFrame C-class - represented by the struct _IntFrame
687  This class represents an integer of 1, 2, 3, 4 or 8 bytes.
688  '''
689  def __init__(self, frametype, initval=None, intbytes=4, Cstruct=None):
690  'Constructor for pyIntFrame object - initial value should be something that looks a lot like an integer'
691  self._Cstruct = None
692  if Cstruct is None:
693  Cstruct=intframe_new(frametype, intbytes)
694  if not Cstruct:
695  raise ValueError, ("Invalid integer size (%d) in pyIntFrame constructor" % intbytes)
696  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
697  if initval is not None:
698  self.setint(initval)
699 
700  def __int__(self):
701  'Return the integer value of this pyIntFrame. (implemented by the underlying IntFrame object)'
702  return self._Cstruct[0].getint(self._Cstruct)
703 
704  def __str__(self):
705  'Return a string representation of this pyIntFrame (the integer value).'
706  return ("pyIntFrame(%s, (%d))" % (FrameTypes.get(self.frametype())[1], int(self)))
707 
708  def getint(self):
709  'Return the integer value of this pyIntFrame - same as __int__.'
710  return int(self)
711 
712  def setint(self, intval):
713  '''Set the value of this pyIntFrame to the given integer value.
714  Note that this value is range checked by the underlying IntFrame implementation.
715  '''
716  self._Cstruct[0].setint(self._Cstruct, int(intval))
717 
718  def intlength(self):
719  '''Return the number of bytes in the integer underlying this pyIntFrame object.
720  (implemented by underlying IntFrame object)'''
721  return self._Cstruct[0].intlength(self._Cstruct)
722 
724  "Class for a Frame type we don't recognize"
725  def __init__(self, frametype, Cstruct=None):
726  'Initializer for pyUnknownFrame'
727  if Cstruct is None:
728  Cstruct=unknownframe_new(frametype)
729  pyFrame.__init__(self, frametype, Cstruct)
730 
732  'Class for a Sequence Number Frame - for reliable UDP packet transmission.'
733  def __init__(self, frametype, initval=None, Cstruct=None):
734  'Initializer for pySeqnoFrame'
735  self._Cstruct = None
736  # TODO(?): Need to allow for initialization of seqno frames.
737  if Cstruct is None:
738  Cstruct=seqnoframe_new(frametype, 0)
739  if not Cstruct:
740  raise ValueError, "Constructor error for PySeqnoFrame()"
741  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
742  if initval is not None:
743  self.setqid(initval[0])
744  self.setreqid(initval[1])
745 
746  def setreqid(self, reqid):
747  self._Cstruct[0].setreqid(self._Cstruct, reqid)
748 
749  def setqid(self, qid):
750  self._Cstruct[0].setqid(self._Cstruct, qid)
751 
752  def getreqid(self):
753  return self._Cstruct[0].getreqid(self._Cstruct)
754 
755  def getqid(self):
756  return self._Cstruct[0].getqid(self._Cstruct)
757 
758  def __eq__(self, rhs):
759  'Compare this pySeqnoFrame to another pySeqnoFrame'
760  lhsbase = self._Cstruct[0]
761  while (type(lhsbase) is not SeqnoFrame):
762  lhsbase=lhsbase.baseclass
763  return lhsbase.equal(self._Cstruct, rhs._Cstruct)
764 
765  def __str__(self):
766  return ("pySeqNo(%s: (%d, %d))" % (FrameTypes.get(self.frametype())[1], self.getqid(), self.getreqid()))
767 
769  'Class for Digital Signature Frames - for authenticating data (subclasses will authenticate senders)'
770  def __init__(self, gchecksumtype, Cstruct=None):
771  'Initializer for pySignFrame'
772  self._Cstruct = None
773  if Cstruct is None:
774  Cstruct=signframe_new(gchecksumtype, 0)
775  if not Cstruct:
776  raise ValueError, ("Invalid checksum type (%s) for PySignFrame()" % gchecksumtype)
777  pyFrame.__init__(self, initval=FRAMETYPE_SIG, Cstruct=Cstruct)
778 
780  'Class for a Frame containing a single name/value pair'
781  def __init__(self, frametype, name, value, Cstruct=None):
782  'Initializer for pyNVpairFrame'
783  self._Cstruct = None
784  if Cstruct is None:
785  Cstruct=nvpairframe_new(frametype, name, value, 0)
786  if not Cstruct:
787  raise ValueError, ("Invalid NVpair initializer for pyNVPairFrame()")
788  pyFrame.__init__(self, initval=frametype, Cstruct=Cstruct)
789 
790  def name(self):
791  'Return the name portion of a pyNVpairFrame'
792  return string_at(self._Cstruct[0].name)
793 
794  def value(self):
795  'Return the name portion of a pyNVpairFrame'
796  return string_at(self._Cstruct[0].value)
797 
798 
799 
801  'Class for Frame Sets - for collections of Frames making up a logical packet'
802  def __init__(self, framesettype, Cstruct=None):
803  'Initializer for pyFrameSet'
804  if Cstruct is None:
805  Cstruct=frameset_new(framesettype)
806  pyAssimObj.__init__(self, Cstruct=Cstruct)
807 
808  def append(self, frame):
809  'Append a frame to the end of a @ref FrameSet'
810  frameset_append_frame(self._Cstruct, frame._Cstruct)
811 
812  def prepend(self, frame):
813  'Prepend a frame before the first frame in a @ref FrameSet'
814  frameset_prepend_frame(self._Cstruct, frame._Cstruct)
815 
816  def construct_packet(self, signframe, cryptframe=None, compressframe=None):
817  'Construct packet from curent frameset + special prefix frames'
818  cf = None
819  cmpf = None
820  if cryptframe is not None:
821  cf = cryptframe._Cstruct
822  if compressframe is not None:
823  cmpf = compressframe._Cstruct
824  frameset_construct_packet(self._Cstruct, signframe._Cstruct, cf, cmpf)
825 
826  def get_framesettype(self):
827  'Return frameset type of this FrameSet'
828  return self._Cstruct[0].fstype
829 
830  def get_flags(self):
831  'Return current flags for this FrameSet'
832  return frameset_get_flags(self._Cstruct)
833 
834  def set_flags(self, flags):
835  "'OR' the given flags into the set of flags for this FrameSet"
836  return frameset_set_flags(self._Cstruct, int(flags))
837 
838  def clear_flags(self, flags):
839  "Clear the given flags for this FrameSet"
840  return frameset_clear_flags(self._Cstruct, int(flags))
841 
842  def dump(self):
843  'Dump out the given frameset'
844  frameset_dump(self._Cstruct)
845 
846  def getpacket(self):
847  if not self._Cstruct[0].packet:
848  raise ValueError, "No packet constructed for frameset"
849  return (self._Cstruct[0].packet, self._Cstruct[0].pktend)
850 
851  def __len__(self):
852  curframe = self._Cstruct[0].framelist
853  count=0
854  while curframe:
855  count += 1
856  curframe=g_slist_next(curframe)
857  return count
858 
859  def iter(self):
860  'Generator yielding the set of pyFrames in this pyFrameSet'
861  curframe = self._Cstruct[0].framelist
862  while curframe:
863  cast(curframe[0].data, struct__GSList._fields_[0][1])
864  yieldval = pyFrame.Cstruct2Frame(cast(curframe[0].data, cClass.Frame))
865  if not yieldval.isvalid():
866  print "OOPS! Constructed frame from iter() is not valid"
867  #print "Yielding:", str(yieldval), "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
868  yield yieldval
869  curframe=g_slist_next(curframe)
870 
871  def __str__(self):
872  'Convert pyFrameSet to string'
873  result = '%s:{' % FrameSetTypes.get(self.get_framesettype())[0]
874  comma=''
875  for frame in self.iter():
876  result += '%s%s' % (comma, str(frame))
877  comma=', '
878  result += "}"
879  return result
880 
881 
883  'Class for Decoding packets - for returning an array of FrameSets from a physical packet.'
884  def __init__(self, FrameMap=None, Cstruct=None):
885  'Initializer for pyPacketDecoder'
886  if Cstruct is None:
887  Cstruct=packetdecoder_new(0, None, 0)
888  pyAssimObj.__init__(self, Cstruct=Cstruct)
889 
890  def fslist_from_pktdata(self, pktlocation):
891  'Make a list of FrameSets out of a packet.'
892  base=self._Cstruct[0]
893  while (type(base)is not PacketDecoder):
894  base=base.baseclass
895  fs_gslistint = base.pktdata_to_framesetlist(self._Cstruct, pktlocation[0], pktlocation[1])
896  return pyPacketDecoder.fslist_to_pyfs_array(fs_gslistint)
897 
898  @staticmethod
899  def fslist_to_pyfs_array(listheadint):
900  'Converts a GSList of FrameSets to a python array of pyFrameSets'
901  fs_gslist = cast(listheadint, POINTER(GSList))
902  frameset_list = []
903  curfs = fs_gslist
904  while curfs:
905  cfs = cast(curfs[0].data, cClass.FrameSet)
906  fs = pyFrameSet(None, Cstruct=cfs)
907  frameset_list.append(fs)
908  curfs = g_slist_next(curfs)
909  g_slist_free(fs_gslist)
910  return frameset_list
911 
913  'Class for Holding configuration information.'
914 
915  def __init__(self, init=None, Cstruct=None):
916  'Initializer for pyConfigContext'
917  self._Cstruct = None # Keep error legs from complaining.
918  if not Cstruct:
919  if (isinstance(init, str) or isinstance(init, unicode)):
920  Cstruct = configcontext_new_JSON_string(str(init))
921  if not Cstruct:
922  raise ValueError('Bad JSON [%s]' % str(init))
923  init = None
924  else:
925  Cstruct=configcontext_new(0)
926  pyAssimObj.__init__(self, Cstruct=Cstruct)
927  if init is not None:
928  for key in init.keys():
929  self[key] = init[key]
930 
931 
932  def getint(self, name):
933  'Return the integer associated with "name"'
934  return self._Cstruct[0].getint(self._Cstruct, name)
935 
936  def setint(self, name, value):
937  'Set the integer associated with "name"'
938  self._Cstruct[0].setint(self._Cstruct, name, value)
939 
940  def getbool(self, name):
941  'Return the boolean associated with "name"'
942  return self._Cstruct[0].getbool(self._Cstruct, name) != 0
943 
944  def setbool(self, name, value):
945  'Set the boolean associated with "name"'
946  self._Cstruct[0].setbool(self._Cstruct, name, int(value))
947 
948  def getaddr(self, name):
949  'Return the NetAddr associated with "name"'
950  naddr = self._Cstruct[0].getaddr(self._Cstruct, name)
951  if naddr:
952  naddr = cast(naddr, cClass.NetAddr)
953  # We're creating a new reference to the pre-existing NetAddr
954  CCref(naddr)
955  return pyNetAddr(None, Cstruct=naddr)
956  raise IndexError("No such NetAddr value [%s]" % name)
957 
958  def setaddr(self, name, value):
959  'Set the @ref NetAddr associated with "name"'
960  self._Cstruct[0].setaddr(self._Cstruct, name, value._Cstruct)
961 
962  def getframe(self, name):
963  'Return the Frame associated with "name"'
964  faddr = self._Cstruct[0].getframe(self._Cstruct, name)
965  if faddr:
966  # Cstruct2Frame already calls CCref()
967  return pyFrame.Cstruct2Frame(faddr)
968  raise IndexError("No such Frame value [%s]" % name)
969 
970  def setframe(self, name, value):
971  'Set the @ref Frame associated with "name"'
972  self._Cstruct[0].setframe(self._Cstruct, name, value._Cstruct)
973 
974  def getconfig(self, name):
975  'Return the pyConfigContext object associated with "name"'
976  caddr = self._Cstruct[0].getconfig(self._Cstruct, name)
977  if caddr:
978  caddr=cast(caddr, cClass.ConfigContext)
979  # We're creating a new reference to the pre-existing NetAddr
980  CCref(caddr)
981  return pyConfigContext(Cstruct=caddr)
982  raise IndexError("No such ConfigContext value [%s]" % name)
983 
984  def setconfig(self, name, value):
985  'Set the @ref ConfigContext associated with "name"'
986  self._Cstruct[0].setconfig(self._Cstruct, name, value._Cstruct)
987 
988  def getstring(self, name):
989  'Return the string associated with "name"'
990  ret = self._Cstruct[0].getstring(self._Cstruct, name)
991  if ret:
992  return string_at(ret)
993  raise IndexError("No such String value [%s]" % name)
994 
995  def setstring(self, name, value):
996  'Return the string associated with "name"'
997  self._Cstruct[0].setstring(self._Cstruct, name, value)
998 
999  def getarray(self, name):
1000  'Return the array value associated with "name"'
1001  curlist = cast(self._Cstruct[0].getarray(self._Cstruct, name), cClass.GSList)
1002  #print >>sys.stderr, "CURLIST(initial) = %s" % curlist
1003  ret = []
1004  while curlist:
1005  #print >>sys.stderr, "CURLIST = %s" % curlist
1006  #cfgval = pyConfigValue(cast(cClass.ConfigValue, curlist[0].data).get())
1007  data = cast(curlist[0].data, cClass.ConfigValue)
1008  #print >>sys.stderr, "CURLIST->data = %s" % data
1009  CCref(data)
1010  cfgval = pyConfigValue(data).get()
1011  #print >>sys.stderr, "CURLIST->data->get() = %s" % cfgval
1012  ret.append(cfgval)
1013  curlist=g_slist_next(curlist)
1014  return ret
1015 
1016  def keys(self):
1017  'Return the set of keys for this object'
1018  l = []
1019  keylist = cast(self._Cstruct[0].keys(self._Cstruct), POINTER(GSList))
1020  curkey = keylist
1021  while curkey:
1022  l.append(string_at(curkey[0].data))
1023  curkey=g_slist_next(curkey)
1024  g_slist_free(keylist)
1025  return l
1026 
1027  def has_key(self, key):
1028  'return True if it has the given key'
1029  ktype = self._Cstruct[0].gettype(self._Cstruct, str(key))
1030  return ktype != CFG_EEXIST
1031 
1032  def __contains__(self, key):
1033  'return True if our object contains the given key'
1034  ktype = self._Cstruct[0].gettype(self._Cstruct, str(key))
1035  return ktype != CFG_EEXIST
1036 
1037  def gettype(self, name):
1038  #print >>sys.stderr, 'gettype(%s)' % str(name)
1039  return self._Cstruct[0].gettype(self._Cstruct, str(name))
1040 
1041 
1042  def __getitem__(self, name):
1043  'Return a value associated with "name"'
1044  ktype = self.gettype(name)
1045  #print >>sys.stderr, '****************** GETITEM[%s] => %d ***************************' % (name, ktype)
1046  if ktype == CFG_EEXIST:
1047  traceback.print_stack()
1048  raise IndexError("No such value [%s] in [%s]" % (name, str(self)))
1049  if ktype == CFG_CFGCTX:
1050  return self.getconfig(name)
1051  if ktype == CFG_STRING:
1052  return self.getstring(name)
1053  if ktype == CFG_NETADDR:
1054  return self.getaddr(name)
1055  if ktype == CFG_FRAME:
1056  return self.getframe(name)
1057  if ktype == CFG_INT64:
1058  return self.getint(name)
1059  if ktype == CFG_BOOL:
1060  return self.getbool(name)
1061  if ktype == CFG_ARRAY:
1062  #print >>sys.stderr, '****************** GETITEM[%s] => getarray(%s) ***************************' % (name, name)
1063  return self.getarray(name)
1064  return None
1065 
1066  def __setitem__(self, name, value):
1067  'Set a value associated with "name" - in the appropriate table'
1068  if isinstance(value, str):
1069  return self.setstring(name, value)
1070  if isinstance(value, pyNetAddr):
1071  return self.setaddr(name, value)
1072  if isinstance(value, pyFrame):
1073  return self.setframe(name, value)
1074  if isinstance(value, pyConfigContext):
1075  return self.setconfig(name, value)
1076  self.setint(name, int(value))
1077 
1079  def __init__(self, Cstruct):
1080  'Initializer for pyConfigValue - now a subclass of pyAssimObj'
1081  self._Cstruct = Cstruct
1082 
1083  def __str__(self):
1084  str(self.get())
1085 
1086  def get(self):
1087  vtype = self._Cstruct[0].valtype
1088  if vtype == CFG_BOOL:
1089  return self._Cstruct[0].u.intvalue != 0
1090  if vtype == CFG_INT64:
1091  return int(self._Cstruct[0].u.intvalue)
1092  if vtype == CFG_STRING:
1093  return str(self._Cstruct[0].u.strvalue)
1094  if vtype == CFG_FLOAT:
1095  return float(self._Cstruct[0].u.floatvalue)
1096  if vtype == CFG_CFGCTX:
1097  # We're creating a new reference to the pre-existing NetAddr
1098  CCref(self._Cstruct[0].u.cfgctxvalue)
1099  return pyConfigContext(Cstruct=self._Cstruct[0].u.cfgctxvalue)
1100  if vtype == CFG_NETADDR:
1101  ret = pyNetAddr(None, Cstruct=self._Cstruct[0].u.addrvalue)
1102  # We're creating a new reference to the pre-existing NetAddr
1103  CCref(ret._Cstruct)
1104  return ret
1105  if vtype == CFG_FRAME:
1106  # Cstruct2Frame calls CCref() - so we don't need to
1107  ret = pyFrame.Cstruct2Frame(self._Cstruct[0].u.framevalue)
1108  return ret
1109  if vtype == CFG_ARRAY:
1110  # An Array is a linked list (GSList) of ConfigValue objects...
1111  ret = []
1112  this = self._Cstruct[0].u.arrayvalue
1113  while this:
1114  dataptr = cast(this[0].data, struct__GSList._fields_[0][1])
1115  dataptr = cast(dataptr, cClass.ConfigValue)
1116  CCref(dataptr)
1117  thisobj = pyConfigValue(cast(dataptr, cClass.ConfigValue)).get()
1118  ret.append(thisobj)
1119  this = g_slist_next(this)
1120  return ret
1121  raise ValueError('Invalid valtype (%s)in pyConfigValue object' % self._Cstruct.valtype)
1122 
1124  def __init__(self, configobj, packetdecoder, Cstruct=None):
1125  'Initializer for pyNetIO'
1126  self._Cstruct = None # Keep error legs from complaining.
1127  if Cstruct is None:
1128  Cstruct=netio_new(0, configobj._Cstruct, packetdecoder._Cstruct)
1129  self.config = configobj
1130  else:
1131  self._Cstruct = Cstruct
1132  base=self._Cstruct[0]
1133  while (not hasattr(base, '_configinfo')):
1134  base=base.baseclass
1135  self.config = pyConfigContext(Cstruct=base._configinfo)
1136  CCref(base._configinfo)
1137  pyAssimObj.__init__(self, Cstruct=Cstruct)
1138 
1139  def setblockio(self, mode):
1140  'Set this NetIO object to blocking IO mode'
1141  base = self._Cstruct[0]
1142  while (not hasattr(base, 'setblockio')):
1143  base=base.baseclass
1144  return base.setblockio(self._Cstruct, int(mode))
1145 
1146  def getfd(self):
1147  'Return the file descriptor for this pyNetIO object'
1148  base = self._Cstruct[0]
1149  while (not hasattr(base, 'getfd')):
1150  base=base.baseclass
1151  return base.getfd(self._Cstruct)
1152 
1153  def bindaddr(self, addr, silent=False):
1154  'Bind the socket underneath this NetIO object to the given address'
1155  base = self._Cstruct[0]
1156  while (not hasattr(base, 'bindaddr')):
1157  base=base.baseclass
1158  return base.bindaddr(self._Cstruct, addr._Cstruct, silent)
1159 
1160  def boundaddr(self):
1161  'Return the socket underlying this NetIO object'
1162  base = self._Cstruct[0]
1163  while (not hasattr(base, 'bindaddr')):
1164  base=base.baseclass
1165  boundaddr = base.boundaddr(self._Cstruct)
1166  # We're creating a new reference to the pre-existing NetAddr
1167  ret = pyNetAddr(None, Cstruct=boundaddr)
1168  CCref(boundaddr)
1169  return ret
1170 
1171  def mcastjoin(self, addr):
1172  'Join the underlying socket to the given multicast address'
1173  base = self._Cstruct[0]
1174  while (not hasattr(base, 'mcastjoin')):
1175  base=base.baseclass
1176  return base.mcastjoin(self._Cstruct, addr._Cstruct, None)
1177 
1178  def getmaxpktsize(self):
1179  'Return the max packet size for this pyNetIO'
1180  base = self._Cstruct[0]
1181  while (not hasattr(base, 'getmaxpktsize')):
1182  base=base.baseclass
1183  return base.getmaxpktsize(self._Cstruct)
1184 
1185  def setmaxpktsize(self, size):
1186  'Set the max packet size for this pyNetIO'
1187  base = self._Cstruct[0]
1188  while (not hasattr(base, 'setmaxpktsize')):
1189  base=base.baseclass
1190  return base.setmaxpktsize(self._Cstruct, int(size))
1191 
1192  def compressframe(self):
1193  'Return the compression frame for this pyNetIO - may be None'
1194  # Doesn't make a py class object out of it yet...
1195  base = self._Cstruct[0]
1196  while (not hasattr(base, 'compressframe')):
1197  base=base.baseclass
1198  return base.compressframe(self._Cstruct)
1199 
1200  def cryptframe(self):
1201  'Return the encryption frame for this pyNetIO - may be None'
1202  # Doesn't make a py class object out of it yet...
1203  base = self._Cstruct[0]
1204  while (not hasattr(base, 'cryptframe')):
1205  base=base.baseclass
1206  return base.cryptframe(self._Cstruct)
1207 
1208  def signframe(self):
1209  'Return the digital signature frame for this pyNetIO'
1210  base = self._Cstruct[0]
1211  while (not hasattr(base, 'signframe')):
1212  base=base.baseclass
1213  return pySignFrame(0,Cstruct=cast(base.signframe(self._Cstruct), cClass.SignFrame))
1214 
1215  def sendframesets(self, destaddr, framesetlist):
1216  'Send the (collection of) frameset(s) out on this pyNetIO'
1217  if destaddr.port() == 0:
1218  raise ValueError("Zero Port in sendframesets: destaddr=%s" % str(destaddr))
1219  if not isinstance(framesetlist, collections.Sequence):
1220  framesetlist = (framesetlist, )
1221  base = self._Cstruct[0]
1222  while (not hasattr(base, 'sendaframeset')):
1223  base=base.baseclass
1224  # We ought to eventually construct a GSList of them and then call sendframesets
1225  # But this is easy for now...
1226  for frameset in framesetlist:
1227  base.sendaframeset(self._Cstruct, destaddr._Cstruct, frameset._Cstruct)
1228 
1229  def sendreliablefs(self, destaddr, framesetlist, qid = DEFAULT_FSP_QID):
1230  'Reliably send the (collection of) frameset(s) out on this pyNetIO (if possible)'
1231  if destaddr.port() == 0:
1232  raise ValueError("Zero Port in sendreliablefs: destaddr=%s" % str(destaddr))
1233  if not isinstance(framesetlist, collections.Sequence):
1234  framesetlist = (framesetlist, )
1235  base = self._Cstruct[0]
1236  while (not hasattr(base, 'sendaframeset')):
1237  base=base.baseclass
1238  for frameset in framesetlist:
1239  success = base.sendareliablefs(self._Cstruct, destaddr._Cstruct, qid, frameset._Cstruct)
1240  if not success:
1241  raise IOError("sendareliablefs(%s, %s) failed." % (destaddr, frameset))
1242 
1243  def ackmessage(self, destaddr, frameset):
1244  'ACK (acknowledge) this frameset - (presumably sent reliably).'
1245 
1246  base = self._Cstruct[0]
1247  while (not hasattr(base, 'ackmessage')):
1248  base=base.baseclass
1249  base.ackmessage(self._Cstruct, destaddr._Cstruct, frameset._Cstruct)
1250 
1251  def closeconn(self, qid, destaddr):
1252  'Close (reset) our connection to this address'
1253 
1254  base = self._Cstruct[0]
1255  while (not hasattr(base, 'closeconn')):
1256  base=base.baseclass
1257  base.closeconn(self._Cstruct, qid, destaddr._Cstruct)
1258 
1259  def addalias(self, fromaddr, toaddr):
1260  'Close (reset) our connection to this address'
1261 
1262  base = self._Cstruct[0]
1263  while (not hasattr(base, 'closeconn')):
1264  base=base.baseclass
1265  base.addalias(self._Cstruct, fromaddr._Cstruct, toaddr._Cstruct)
1266 
1267  def recvframesets(self):
1268  '''Receive a collection of framesets read from this pyNetIO - all from the same Address.
1269  @return The return value is a tuple (address, framesetlist). '''
1270  #GSList * _netio_recvframesets (NetIO *self,NetAddr **src)
1271 
1272  base = self._Cstruct[0]
1273  while (not hasattr(base, 'recvframesets')):
1274  base=base.baseclass
1275  netaddrint = netaddr_ipv4_new(create_string_buffer(4), 101)
1276  netaddr = cast(netaddrint, cClass.NetAddr)
1277  netaddr[0].baseclass.unref(netaddr) # We're about to replace it...
1278  # Basically we needed a pointer to pass, and this seemed like a good way to do it...
1279  # Maybe it was -- maybe it wasn't... It's a pretty expensive way to get this effect...
1280  fs_gslistint = base.recvframesets(self._Cstruct, byref(netaddr))
1281  fslist = pyPacketDecoder.fslist_to_pyfs_array(fs_gslistint)
1282  if netaddr and len(fslist) > 0:
1283  # recvframesets gave us that 'netaddr' for us to dispose of - there are no other refs to it
1284  # so we should NOT 'CCref' it. It's a new object - not a pointer to an old one.
1285  address = pyNetAddr(None, Cstruct=netaddr)
1286  fs = fslist[0]
1287  else:
1288  address = None
1289  return (address, fslist)
1290 
1291  @staticmethod
1293  return netio_is_dual_ipv4v6stack()
1294 
1296  'UDP version of the pyNetIO abstract base class'
1297  def __init__(self, config, packetdecoder, Cstruct=None):
1298  'Initializer for pyNetIOudp'
1299  self._Cstruct = None # Keep error legs from complaining.
1300  if Cstruct is None:
1301  Cstruct=netioudp_new(0, config._Cstruct, packetdecoder._Cstruct)
1302  if not Cstruct:
1303  raise ValueError("Invalid parameters to pyNetIOudp constructor")
1304  pyNetIO.__init__(self, config, packetdecoder, Cstruct=Cstruct)
1305 
1307  'Reliable UDP version of the pyNetIOudp abstract base class'
1308  def __init__(self, config, packetdecoder, rexmit_timer_uS=0, Cstruct=None):
1309  'Initializer for pyReliableUDP'
1310  self._Cstruct = None # Keep error legs from complaining.
1311  if Cstruct is None:
1312  Cstruct=reliableudp_new(0, config._Cstruct, packetdecoder._Cstruct, rexmit_timer_uS)
1313  if not Cstruct:
1314  raise ValueError("Invalid parameters to pyReliableUDP constructor")
1315  pyNetIOudp.__init__(self, config, packetdecoder, Cstruct=Cstruct)
1316 
1317 class CMAlib:
1318  @staticmethod
1320  fs = cast(create_setconfig(cfg._Cstruct), cClass.FrameSet)
1321  return pyFrameSet(None, Cstruct=fs)
1322 
1323  @staticmethod
1324  def create_sendexpecthb(cfg, msgtype, address):
1325  ucfs = create_sendexpecthb(cfg._Cstruct, int(msgtype)
1326  , address._Cstruct, 1)
1327  fs = cast(ucfs, cClass.FrameSet)
1328  return pyFrameSet(None, Cstruct=fs)