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