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