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 #pylint: disable=C0302
2 # vim: smartindent tabstop=4 shiftwidth=4 expandtab
3 #C0302: too many lines in module
4 #
5 #
6 # This file is part of the Assimilation Project.
7 #
8 # Copyright (C) 2011, 2012 - Alan Robertson <alanr@unix.sh>
9 #
10 # The Assimilation software is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # The Assimilation software is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with the Assimilation Project software. If not, see http://www.gnu.org/licenses/
22 #
23 #
24 #pylint: disable=C0302,W0212
25 '''
26 A collection of classes which wrap our @ref C-Classes and provide Pythonic interfaces
27 to these C-classes.
28 '''
29 
30 #pylint: disable=W0611
31 from AssimCtypes import AddrFrame, CstringFrame, UnknownFrame, ConfigValue, IpPortFrame, \
32  FrameSet, PacketDecoder, guint8, IntFrame, ConfigContext, SignFrame, CompressFrame, \
33  proj_class_live_object_count, proj_class_dump_live_objects, CONFIGNAME_CMAPORT
34 #pylint: enable=W0611
35 from AssimCtypes import POINTER, cast, addressof, pointer, string_at, create_string_buffer, \
36  c_char_p, byref, memmove, badfree, \
37  g_free, GSList, GDestroyNotify, g_slist_length, g_slist_next, struct__GSList, \
38  g_slist_free, \
39  MALLOC, memmove, \
40  FRAMETYPE_SIG, \
41  Frame, AssimObj, NetAddr, SeqnoFrame, ReliableUDP, \
42  frame_new, addrframe_new, \
43  nvpairframe_new, frameset_new, frameset_append_frame, frameset_prepend_frame, \
44  seqnoframe_new, cstringframe_new, unknownframe_new, \
45  ipportframe_netaddr_new, ipportframe_ipv4_new, ipportframe_ipv6_new, \
46  frameset_construct_packet, frameset_get_flags, frameset_set_flags, frameset_clear_flags, \
47  frameset_dump, \
48  LLDP_TLV_END, LLDP_TLV_CHID, LLDP_TLV_PID, LLDP_TLV_TTL, LLDP_TLV_PORT_DESCR, \
49  LLDP_TLV_SYS_NAME, LLDP_TLV_SYS_DESCR, LLDP_TLV_SYS_CAPS, LLDP_TLV_MGMT_ADDR, \
50  LLDP_TLV_ORG_SPECIFIC, \
51  LLDP_ORG802_1_VLAN_PVID, LLDP_ORG802_1_VLAN_PORTPROTO, LLDP_ORG802_1_VLAN_NAME, \
52  LLDP_ORG802_1_VLAN_PROTOID, LLDP_ORG802_3_PHY_CONFIG, LLDP_ORG802_3_POWERVIAMDI, \
53  LLDP_ORG802_3_LINKAGG, LLDP_ORG802_3_MTU, \
54  LLDP_PIDTYPE_ALIAS, LLDP_PIDTYPE_IFNAME, LLDP_PIDTYPE_LOCAL, LLDP_CHIDTYPE_ALIAS, \
55  LLDP_CHIDTYPE_IFNAME, LLDP_CHIDTYPE_LOCAL, LLDP_CHIDTYPE_MACADDR, \
56  LLDP_CHIDTYPE_COMPONENT, LLDP_CHIDTYPE_NETADDR, \
57  CDP_TLV_DEVID, CDP_TLV_ADDRESS, CDP_TLV_PORTID, CDP_TLV_CAPS, CDP_TLV_VERS, CDP_TLV_POWER, \
58  CDP_TLV_PLATFORM, CDP_TLV_MTU, CDP_TLV_SYSTEM_NAME, CDP_TLV_MANAGEMENT_ADDR, CDP_TLV_DUPLEX, \
59  CDP_TLV_LOCATION, CDP_TLV_EXT_PORTID, CDP_TLV_NATIVEVLAN, CDP_TLV_VLREPLY, CDP_TLV_VLQUERY, \
60  ADDR_FAMILY_IPV4, ADDR_FAMILY_IPV6, ADDR_FAMILY_802, \
61  is_valid_lldp_packet, is_valid_cdp_packet, \
62  netaddr_ipv4_new, netaddr_ipv6_new, netaddr_dns_new, netaddr_mac48_new, netaddr_mac64_new, \
63  proj_class_classname, \
64  assimobj_new, intframe_new, signframe_new, packetdecoder_new, configcontext_new, \
65  configcontext_new_JSON_string, netio_new, netioudp_new, reliableudp_new,\
66  netio_is_dual_ipv4v6_stack, create_setconfig, create_sendexpecthb, \
67  get_lldptlv_first, \
68  get_lldptlv_next, \
69  get_lldptlv_type, \
70  get_lldptlv_len, \
71  get_lldptlv_body, \
72  get_lldptlv_next, \
73  get_cdptlv_first, \
74  get_cdptlv_next, \
75  get_cdptlv_type, \
76  get_cdptlv_len, \
77  get_cdptlv_body, \
78  tlv_get_guint8, tlv_get_guint16, tlv_get_guint24, tlv_get_guint32, tlv_get_guint64, \
79  CFG_EEXIST, CFG_CFGCTX, CFG_CFGCTX, CFG_STRING, CFG_NETADDR, CFG_FRAME, CFG_INT64, CFG_ARRAY, \
80  CFG_FLOAT, CFG_BOOL, DEFAULT_FSP_QID, CFG_NULL, \
81  COMPRESS_ZLIB, FRAMETYPE_COMPRESS, compressframe_new
82 
83 from consts import CMAconsts
84 
85 from frameinfo import FrameTypes, FrameSetTypes
86 import collections
87 import traceback
88 import sys, gc
89 
90 #pylint: disable=R0903
91 class cClass (object):
92  'Just a handy collection of POINTER() objects'
93  def __init__(self):
94  pass
95  NetAddr = POINTER(NetAddr)
96  Frame = POINTER(Frame)
97  AddrFrame = POINTER(AddrFrame)
98  IntFrame = POINTER(IntFrame)
99  SeqnoFrame = POINTER(SeqnoFrame)
100  CstringFrame = POINTER(CstringFrame)
101  UnknownFrame = POINTER(UnknownFrame)
102  SignFrame = POINTER(SignFrame)
103  FrameSet = POINTER(FrameSet)
104  ConfigContext = POINTER(ConfigContext)
105  ConfigValue = POINTER(ConfigValue)
106  IpPortFrame = POINTER(IpPortFrame)
107  CompressFrame = POINTER(CompressFrame)
108  guint8 = POINTER(guint8)
109  GSList = POINTER(GSList)
110 
111 def CCref(obj):
112  '''
113  Increment the reference count to an AssimObj (_not_ a pyAssimObj)
114  Need to call CCref under the following circumstances:
115  When we are creating an object that points to another underlying C-class object
116  which already has a permanent reference to it somewhere else
117  For example, if we're returning a pyNetAddr object that points to a NetAddr object
118  that's in a ConfigContext object. If we don't, then when our pyNetAddr object goes
119  out of scope, then the underlying NetAddr object will be freed, even though there's
120  a reference to it in the ConfigContext object. Conversely, if the ConfigContext
121  object goes out of scope first, then the our pyNetAddr object could become invalid.
122 
123  Do not call it when you've constructed a new object that there were no previous pointers
124  to.
125  '''
126  base = obj[0]
127  while (type(base) is not AssimObj):
128  base = base.baseclass
129  base.ref(obj)
130 
131 def CCunref(obj):
132  'Unref an AssimObj object (or subclass)'
133  base = obj[0]
134  while (hasattr(base, 'baseclass')):
135  base = base.baseclass
136  base.unref(obj)
137 
138 class pySwitchDiscovery(object):
139  '''
140  Class for interpreting switch discovery data via LLDP or CDP
141  Currently only LLDP is fully implemented.
142  '''
143  lldpnames = {
144  LLDP_TLV_END: ('END', True),
145  LLDP_TLV_CHID: ('ChassisId', True),
146  LLDP_TLV_PID: ('PortId', True),
147  LLDP_TLV_TTL: ('TTL', True),
148  LLDP_TLV_PORT_DESCR: ('PortDescription', False),
149  LLDP_TLV_SYS_NAME: ('SystemName', True),
150  LLDP_TLV_SYS_DESCR: ('SystemDescription', True),
151  LLDP_TLV_SYS_CAPS: ('SystemCapabilities', True),
152  LLDP_TLV_MGMT_ADDR: ('ManagementAddress', True),
153  LLDP_TLV_ORG_SPECIFIC: ('(OrgSpecific)', True),
154  }
155  lldp802_1names = {
156  LLDP_ORG802_1_VLAN_PVID: ('VlanPvId', False),
157  LLDP_ORG802_1_VLAN_PORTPROTO: ('VlanPortProtocol', False),
158  LLDP_ORG802_1_VLAN_NAME: ('VlanName', False),
159  LLDP_ORG802_1_VLAN_PROTOID: ('VlanProtocolId', False),
160  }
161  lldp802_3names = {
162  LLDP_ORG802_3_PHY_CONFIG: ('PhysicalConfiguration', False),
163  LLDP_ORG802_3_POWERVIAMDI: ('PowerViaMDI', False),
164  LLDP_ORG802_3_LINKAGG: ('LinkAggregation', False),
165  LLDP_ORG802_3_MTU: ('MTU', False),
166  }
167 
168  cdpnames = {
169  # System-wide capabilities
170  CDP_TLV_DEVID: ('ChassisId', True),
171  CDP_TLV_CAPS: ('SystemCapabilities', True),
172  CDP_TLV_VERS: ('SystemVersion', True),
173  CDP_TLV_PLATFORM: ('SystemPlatform', True),
174  CDP_TLV_ADDRESS: ('SystemAddress', True),
175  CDP_TLV_MANAGEMENT_ADDR: ('ManagementAddress', True),
176  CDP_TLV_SYSTEM_NAME: ('SystemName', True),
177  CDP_TLV_LOCATION: ('SystemDescription', True),
178  # Per-port capabilities follow
179  CDP_TLV_NATIVEVLAN: ('VlanName', False),
180  CDP_TLV_VLQUERY: ('VlanQuery', False),
181  CDP_TLV_VLREPLY: ('VlanReply', False),
182  CDP_TLV_PORTID: ('PortId', False),
183  CDP_TLV_EXT_PORTID: ('PortDescription', False),
184  CDP_TLV_DUPLEX: ('Duplex', False),
185  CDP_TLV_MTU: ('MTU', False),
186  CDP_TLV_POWER: ('PortPower', False),
187  }
188 
189  def __init__(self):
190  pass
191 
192  @staticmethod
193  def _byte0(pktstart):
194  'Return the first (zeroth) byte from a memory blob'
195  return int(cast(pktstart, cClass.guint8)[0])
196 
197  @staticmethod
198  def _byte1addr(pktstart):
199  'Return the address of byte 1 in a memory blob'
200  addr = addressof(pktstart.contents) + 1
201  return pointer(type(pktstart.contents).from_address(addr))
202 
203  @staticmethod
204  def _byteN(pktstart, n):
205  'Return the Nth byte from a memory blob'
206  return int(cast(pktstart, cClass.guint8)[n])
207 
208  @staticmethod
209  def _byteNaddr(pktstart, n):
210  'Return the address of the Nth byte in a memory blob'
211  addr = addressof(pktstart.contents) + n
212  return pointer(type(pktstart.contents).from_address(addr))
213 
214  @staticmethod
215  def _decode_netaddr(addrstart, addrlen):
216  'Return an appropriate pyNetAddr object corresponding to the given memory blob'
217  byte0 = pySwitchDiscovery._byte0(addrstart)
218  byte1addr = pySwitchDiscovery._byte1addr(addrstart)
219  Cnetaddr = None
220  if byte0 == ADDR_FAMILY_IPV6:
221  if addrlen != 17:
222  return None
223  Cnetaddr = netaddr_ipv6_new(byte1addr, 0)
224  elif byte0 == ADDR_FAMILY_IPV4:
225  if addrlen != 5:
226  return None
227  Cnetaddr = netaddr_ipv4_new(byte1addr, 0)
228  elif byte0 == ADDR_FAMILY_802:
229  if addrlen == 7:
230  Cnetaddr = netaddr_mac48_new(byte1addr)
231  elif addrlen == 9:
232  Cnetaddr = netaddr_mac64_new(byte1addr)
233  if Cnetaddr is not None:
234  return str(pyNetAddr(None, Cstruct=Cnetaddr))
235  return None
236 
237  @staticmethod
238  def decode_discovery(host, interface, wallclock, pktstart, pktend):
239  'Return a JSON packet corresponding to the given switch discovery packet'
240  if is_valid_lldp_packet(pktstart, pktend):
241  return pySwitchDiscovery._decode_lldp(host, interface, wallclock, pktstart, pktend)
242  if is_valid_cdp_packet(pktstart, pktend):
243  return pySwitchDiscovery._decode_cdp(host, interface, wallclock, pktstart, pktend)
244  raise ValueError('Malformed Switch Discovery Packet')
245 
246  @staticmethod
247  def _decode_lldp_chid(tlvptr, tlvlen):
248  'Decode the LLDP CHID field, and return an appropriate value'
249  chidtype = pySwitchDiscovery._byte0(tlvptr)
250 
251  if (chidtype == LLDP_CHIDTYPE_COMPONENT or chidtype == LLDP_CHIDTYPE_ALIAS
252  or chidtype == LLDP_CHIDTYPE_IFNAME or chidtype == LLDP_CHIDTYPE_LOCAL):
253  sloc = pySwitchDiscovery._byte1addr(tlvptr)
254  value = string_at(sloc, tlvlen-1)
255  elif chidtype == LLDP_CHIDTYPE_MACADDR:
256  byte1addr = pySwitchDiscovery._byte1addr(tlvptr)
257  Cmacaddr = None
258  if tlvlen == 7:
259  Cmacaddr = netaddr_mac48_new(byte1addr)
260  elif tlvlen == 9:
261  Cmacaddr = netaddr_mac64_new(byte1addr)
262  if Cmacaddr is not None:
263  value = pyNetAddr(None, Cstruct=Cmacaddr)
264  elif chidtype == LLDP_CHIDTYPE_NETADDR:
265  byte1addr = pySwitchDiscovery._byte1addr(tlvptr)
266  value = pySwitchDiscovery._decode_netaddr(byte1addr, tlvlen-1)
267  return value
268 
269  #pylint: disable=R0914,R0912
270  @staticmethod
271  def _decode_lldp(host, interface, wallclock, pktstart, pktend):
272  'Decode LLDP packet into a JSON discovery packet'
273  #print >> sys.stderr, 'DECODING LLDP PACKET!<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'
274  thisportinfo = pyConfigContext(init={
275  'ConnectsToHost': host,
276  'ConnectsToInterface': interface,
277  }
278  )
279  switchinfo = pyConfigContext(init = {'ports': pyConfigContext()})
280  metadata = pyConfigContext(init={
281  'discovertype': '__LinkDiscovery',
282  'description': 'Link Level Switch Discovery (lldp)',
283  'source': '_decode_lldp()',
284  'host': host,
285  'localtime': str(wallclock),
286  'data': switchinfo,
287  }
288  )
289  capnames = [ None, CMAconsts.ROLE_repeater
290  , CMAconsts.ROLE_bridge, CMAconsts.ROLE_AccessPoint
291  , CMAconsts.ROLE_router, CMAconsts.ROLE_phone
292  , CMAconsts.ROLE_DOCSIS, CMAconsts.ROLE_Station
293  ]
294 
295  sourcemacptr = pySwitchDiscovery._byteNaddr(cast(pktstart, cClass.guint8), 6)
296  if not sourcemacptr:
297  return metadata
298  Cmacaddr = netaddr_mac48_new(sourcemacptr)
299  sourcemac = pyNetAddr(None, Cstruct=Cmacaddr)
300 
301 
302  this = get_lldptlv_first(pktstart, pktend)
303  while this and this < pktend:
304  tlvtype = get_lldptlv_type(this, pktend)
305  tlvlen = get_lldptlv_len(this, pktend)
306  tlvptr = cast(get_lldptlv_body(this, pktend), cClass.guint8)
307  value = None
308  if tlvtype not in pySwitchDiscovery.lldpnames:
309  print >> sys.stderr, 'Cannot find tlvtype %d' % tlvtype
310  tlvtype = None
311  else:
312  (tlvname, isswitchinfo) = pySwitchDiscovery.lldpnames[tlvtype]
313 
314  if (tlvtype == LLDP_TLV_PORT_DESCR or tlvtype == LLDP_TLV_SYS_NAME or
315  tlvtype == LLDP_TLV_SYS_DESCR): #########################################
316  value = string_at(tlvptr, tlvlen)
317 
318  elif tlvtype == LLDP_TLV_PID: ###############################################
319  pidtype = pySwitchDiscovery._byte0(tlvptr)
320  if (pidtype == LLDP_PIDTYPE_ALIAS or pidtype == LLDP_PIDTYPE_IFNAME
321  or pidtype == LLDP_PIDTYPE_LOCAL):
322  sloc = pySwitchDiscovery._byte1addr(tlvptr)
323  value = string_at(sloc, tlvlen-1)
324 
325  elif tlvtype == LLDP_TLV_CHID: #############################################
326  value = pySwitchDiscovery._decode_lldp_chid(tlvptr, tlvlen)
327 
328  elif tlvtype == LLDP_TLV_MGMT_ADDR: #########################################
329  addrlen = pySwitchDiscovery._byte0(tlvptr)
330  byte1addr = pySwitchDiscovery._byte1addr(tlvptr)
331  value = pySwitchDiscovery._decode_netaddr(byte1addr, addrlen)
332 
333  elif tlvtype == LLDP_TLV_SYS_CAPS: #########################################
334  byte0 = pySwitchDiscovery._byte0(tlvptr)
335  byte1 = pySwitchDiscovery._byteN(tlvptr, 1)
336  byte2 = pySwitchDiscovery._byteN(tlvptr, 2)
337  byte3 = pySwitchDiscovery._byteN(tlvptr, 3)
338  caps0 = (byte0 << 8 | byte1)
339  caps1 = (byte2 << 8 | byte3)
340  value = pyConfigContext()
341  mask = 2
342  for j in range(1, 7):
343  if (caps0 & mask):
344  value[capnames[j]] = ((caps1 & mask) != 0)
345  mask <<= 1
346 
347 
348  elif tlvtype == LLDP_TLV_ORG_SPECIFIC: ######################################
349  print >> sys.stderr, (
350  'Found %d bytes of LLDP org-specific extensions (not processed)'
351  % tlvlen)
352 
353  if value is not None:
354  if tlvtype == LLDP_TLV_PID:
355  switchinfo['ports'][value] = thisportinfo
356  thisportinfo['PortId'] = value
357  numericpart = value
358  while len(numericpart) > 0 and not numericpart.isdigit():
359  numericpart = numericpart[1:]
360  if len > 0 and numericpart.isdigit():
361  thisportinfo['PORTNUM'] = int(numericpart)
362  else:
363  if isswitchinfo:
364  switchinfo[tlvname] = value
365  else:
366  thisportinfo[tlvname] = value
367  this = get_lldptlv_next(this, pktend)
368  thisportinfo['sourceMAC'] = sourcemac
369  return metadata
370 
371 
372  @staticmethod
373  def _decode_cdp(host, interface, wallclock, pktstart, pktend):
374  'Decode CDP packet into a JSON discovery packet'
375  thisportinfo = pyConfigContext(init={
376  'ConnectsToHost': host,
377  'ConnectsToInterface': interface,
378  }
379  )
380  switchinfo = pyConfigContext(init = {'ports': pyConfigContext()})
381  metadata = pyConfigContext(init={
382  'discovertype': '__LinkDiscovery',
383  'description': 'Link Level Switch Discovery (cdp)',
384  'source': '_decode_cdp()',
385  'host': host,
386  'localtime': str(wallclock),
387  'data': switchinfo,
388  }
389  )
390  sourcemacptr = pySwitchDiscovery._byteNaddr(cast(pktstart, cClass.guint8), 6)
391  if not sourcemacptr:
392  return metadata
393  Cmacaddr = netaddr_mac48_new(sourcemacptr)
394  sourcemac = pyNetAddr(None, Cstruct=Cmacaddr)
395  this = get_cdptlv_first(pktstart, pktend)
396  while this and this < pktend:
397  tlvtype = get_cdptlv_type(this, pktend)
398  tlvlen = get_cdptlv_len(this, pktend)
399  tlvptr = cast(get_cdptlv_body(this, pktend), cClass.guint8)
400  this = get_cdptlv_next(this, pktend)
401  value = None
402  if tlvtype not in pySwitchDiscovery.cdpnames:
403  tlvtype = ('TLV_0x%02x' % tlvtype)
404  isswitchinfo = True # Gotta do _something_...
405  else:
406  (tlvname, isswitchinfo) = pySwitchDiscovery.cdpnames[tlvtype]
407  if tlvtype == CDP_TLV_DEVID:
408  value = string_at(tlvptr, tlvlen)
409  elif tlvtype == CDP_TLV_ADDRESS:
410  # 4 byte count + 'count' addresses
411  value = pySwitchDiscovery.getcdpaddresses(tlvlen, tlvptr, pktend)
412  elif tlvtype == CDP_TLV_PORTID:
413  value = string_at(tlvptr, tlvlen)
414  elif tlvtype == CDP_TLV_CAPS:
415  #bytez = [ '%02x' % pySwitchDiscovery._byteN(tlvptr, j) for j in range(0, tlvlen)]
416  #print 'CAPBYTES = ', bytez
417  caps = pySwitchDiscovery.getNint(tlvptr, 4, pktend)
418  #print >> sys.stderr, ('CAPS IS: 0x%08x (%d bytes)' % (caps, tlvlen))
419  value = pySwitchDiscovery.construct_cdp_caps(caps)
420  elif tlvtype == CDP_TLV_VERS:
421  value = string_at(tlvptr, tlvlen)
422  elif tlvtype == CDP_TLV_PLATFORM:
423  value = string_at(tlvptr, tlvlen)
424  elif tlvtype == CDP_TLV_POWER:
425  tlen = tlvlen if tlvlen <= 2 else 2
426  value = pySwitchDiscovery.getNint(tlvptr, tlen, pktend)
427  elif tlvtype == CDP_TLV_MTU:
428  value = pySwitchDiscovery.getNint(tlvptr, tlvlen, pktend)
429  elif tlvtype == CDP_TLV_SYSTEM_NAME:
430  value = string_at(tlvptr, tlvlen)
431  elif tlvtype == CDP_TLV_MANAGEMENT_ADDR:
432  # 4 byte count + 'count' addresses
433  value = pySwitchDiscovery.getcdpaddresses(tlvlen, tlvptr, pktend)
434  elif tlvtype == CDP_TLV_DUPLEX:
435  value = 'half' if pySwitchDiscovery._byte0(tlvptr) == 0 else 'full'
436  elif tlvtype == CDP_TLV_LOCATION:
437  value = string_at(tlvptr, tlvlen)
438  elif tlvtype == CDP_TLV_EXT_PORTID:
439  value = string_at(tlvptr, tlvlen)
440  else:
441  value='0x'
442  for offset in range(0,tlvlen):
443  value += ('%02x' % pySwitchDiscovery._byteN(tlvptr, offset))
444 
445  if value is None:
446  print >> sys.stderr, ('Could not process value for %s field [0x%02x]'
447  % (tlvname, tlvtype))
448  else:
449  if tlvtype == CDP_TLV_PORTID:
450  switchinfo['ports'][value] = thisportinfo
451  thisportinfo['PortId'] = value
452  numericpart = value
453  while len(numericpart) > 0 and not numericpart.isdigit():
454  numericpart = numericpart[1:]
455  if len > 0 and numericpart.isdigit():
456  thisportinfo['PORTNUM'] = int(numericpart)
457  else:
458  if isswitchinfo:
459  switchinfo[tlvname] = value
460  else:
461  thisportinfo[tlvname] = value
462  #print >> sys.stderr, ('TLVNAME %s has value "%s" -- len: %d'
463  #% (tlvname, value, len(str(value))))
464  thisportinfo['sourceMAC'] = sourcemac
465  return metadata
466 
467 
468  @staticmethod
469  def getNint(tlvptr, tlvlen, pktend):
470  'Return an integer of any size that we support...'
471  intptr = tlvptr
472  if tlvlen == 1:
473  return tlv_get_guint8(intptr, pktend)
474  if tlvlen == 2:
475  return tlv_get_guint16(intptr, pktend)
476  if tlvlen == 3:
477  return tlv_get_guint24(intptr, pktend)
478  if tlvlen == 4:
479  return tlv_get_guint32(intptr, pktend)
480  if tlvlen == 8:
481  return tlv_get_guint64(intptr, pktend)
482  return None
483 
484  @staticmethod
485  def construct_cdp_caps(capval):
486  'Construct Capability value from the CDP capability integer'
487  capnames = [ CMAconsts.ROLE_router
488  , CMAconsts.ROLE_tb_bridge, CMAconsts.ROLE_srcbridge
489  , CMAconsts.ROLE_bridge, CMAconsts.ROLE_host
490  , CMAconsts.ROLE_igmp, CMAconsts.ROLE_repeater
491  ]
492  mask = 1
493  value = pyConfigContext()
494  for j in range(0, len(capnames)):
495  if (capval & mask):
496  #value[capnames[j]] = ((capval & mask) != 0)
497  value[capnames[j]] = True
498  mask <<= 1
499  return value
500 
501 
502  @staticmethod
503  def getcdpaddresses(tlvlen, tlvstart, pktend):
504  '''
505  Decode utterly bizarre CDP-specific address list format
506  4 bytes address count
507  'count' addresses in this form:
508  one bytes protocol length
509  'protocol length' bytes of protocol type
510  two bytes address length
511  'address length' bytes of address
512  IPv4:
513  protocol length = 1, protocol type = 0xCC
514  IPv6:
515  protocol length = 8 and address length = 16
516  protocol type == 0xAAAA0300000086DD ??
517  +-------+--------------------+----------+-----------------+
518  |Proto |Protocol Type | address | Actual address |
519  |Length |(protolength bytes) | length | (addresslength |
520  |1 byte |(1-255 bytes) | (2 bytes)| bytes) |
521  +-------+--------------------+----------+-----------------+
522 
523  Min length for an IPV4 address is 8 bytes
524  '''
525  minlength=8
526  retlist = []
527  offset = 0
528  count = pySwitchDiscovery.getNint(tlvstart, 4, pktend)
529  offset += 4
530  for j in range(0, count):
531  addr = None
532  if (offset+minlength) > tlvlen:
533  break
534  protolen = pySwitchDiscovery.getNint(pySwitchDiscovery._byteNaddr
535  ( cast(tlvstart, cClass.guint8), offset), 1, pktend)
536  offset += 2
537  if protolen < 1:
538  break
539  if offset >= tlvlen:
540  break
541  if protolen == 1:
542  prototype = pySwitchDiscovery._byteN(tlvstart, offset+protolen-1)
543  elif protolen == 16:
544  prototype = pySwitchDiscovery.getNint(
545  pySwitchDiscovery._byteNaddr(cast(tlvstart, cClass.guint8), offset+protolen-2)
546  , 2, pktend)
547  else:
548  prototype = 0xdeadbeef
549  offset += protolen
550  if offset > tlvlen:
551  break
552  addrlen = pySwitchDiscovery.getNint(pySwitchDiscovery._byteNaddr
553  ( cast(tlvstart, cClass.guint8), offset), 2, pktend)
554  if protolen == 1 and addrlen == 4 and prototype == 0xCC:
555  addrstr=''
556  for j in (offset+2, offset+3, offset, offset+1):
557  addrstr += chr(pySwitchDiscovery._byteN(tlvstart, j))
558  addr = netaddr_ipv4_new(c_char_p(addrstr), 0)
559  elif protolen == 8 and addrlen == 16 and prototype == 0x86DD:
560  # protocol type == 0xAAAA0300000086DD
561  addr = netaddr_ipv6_new(pySwitchDiscovery._byteNaddr(cast(tlvstart, cClass.guint8)
562  , offset), 0)
563  if addr is not None:
564  pyaddr = pyNetAddr(Cstruct=addr, addrstring=None)
565  retlist.append(pyaddr)
566  offset += addrlen
567 
568  if len(retlist) == 0:
569  return None
570  if len(retlist) == 1:
571  return retlist[0]
572  return retlist
573 
574 
575 
576 
577 class pyAssimObj(object):
578  'The base object for all the C-class objects'
579  def __init__(self, Cstruct=None):
580  'Create a base pyAssimObj object'
581  self._Cstruct = None
582  if (Cstruct is not None):
583  assert type(Cstruct) is not int
584  self._Cstruct = Cstruct
585  else:
586  self._Cstruct = assimobj_new(0)
587  #print 'ASSIMOBJ:init: %s' % (Cstruct)
588 
589  def cclassname(self):
590  "Return the 'C' class name for this object"
591  return proj_class_classname(self._Cstruct)
592 
593  def __str__(self):
594  'Convert this AssimObj into a printable string'
595  if not self._Cstruct:
596  return "[None]"
597  base = self._Cstruct[0]
598  while (type(base) is not AssimObj):
599  base = base.baseclass
600  cstringret = cast(base.toString(self._Cstruct), c_char_p)
601  ret = string_at(cstringret)
602  g_free(cstringret)
603  return ret
604 
605  #pylint: disable=W0603
606  def __del__(self):
607  'Free up the underlying Cstruct for this pyAssimObj object.'
608  if not self._Cstruct or self._Cstruct is None:
609  return
610  # I have no idea why the type(base) is not Frame doesn't work here...
611  # This 'hasattr' construct only works because we are a base C-class
612  global badfree
613  badfree = 0
614  CCunref(self._Cstruct)
615  if badfree != 0:
616  print >> sys.stderr, "Attempt to free something already freed(%s)" % str(self._Cstruct)
617  traceback.print_stack()
618  badfree = 0
619  self._Cstruct = None
620 
621  def refcount(self):
622  'Return the reference count for this object'
623  base = self._Cstruct[0]
624  while (hasattr(base, 'baseclass')):
625  base = base.baseclass
626  return base._refcount
627 
629  '''This class represents the Python version of our C-class @ref NetAddr
630  - represented by the struct _NetAddr.
631  '''
632  def __init__(self, addrstring, port=None, Cstruct=None):
633  '''This constructor needs a list of integers of the right length as its first argument.
634  The length of the list determines the type of address generated.
635  4 bytes == ipv4
636  6 bytes == MAC address
637  8 bytes == MAC address
638  16 bytes == ipv6 address
639  This is slightly sleazy but it should work for the forseeable future.
640  '''
641 
642  self._Cstruct = None # Silence error messages in failure cases
643 
644  if (Cstruct is not None):
645  assert type(Cstruct) is not int
646  pyAssimObj.__init__(self, Cstruct=Cstruct)
647  if port is not None:
648  self.setport(port)
649  return
650 
651  if port is None:
652  port = 0
653 
654  if isinstance(addrstring, unicode) or isinstance(addrstring, pyNetAddr):
655  addrstring = str(addrstring)
656  if isinstance(addrstring, str):
657  cs = netaddr_dns_new(addrstring)
658  if not cs:
659  raise ValueError('Illegal NetAddr initial value: "%s"' % addrstring)
660  if port != 0:
661  cs[0].setport(cs, port)
662  pyAssimObj.__init__(self, Cstruct=cs)
663  return
664 
665  self._init_from_binary(addrstring, port)
666 
667  def _init_from_binary(self, addrstring, port):
668  'Initialize an addrstring from a binary argument'
669  alen = len(addrstring)
670  addr = create_string_buffer(alen)
671  #print >> sys.stderr, "ADDRTYPE:", type(addr)
672  #print >> sys.stderr, "ADDRSTRINGTYPE:", type(addrstring)
673  for i in range(0, alen):
674  asi = addrstring[i]
675  #print >> sys.stderr, "ASI_TYPE: (%s,%s)" % (type(asi), asi)
676  if type(asi) is str:
677  addr[i] = asi
678  elif type(asi) is unicode:
679  addr[i] = str(asi)
680  else:
681  addr[i] = chr(asi)
682  #print >> sys.stderr, 'ADDR = %s' % addr
683  if alen == 4: # ipv4
684  NA = netaddr_ipv4_new(addr, port)
685  pyAssimObj.__init__(self, Cstruct=NA)
686  elif alen == 16: # ipv6
687  pyAssimObj.__init__(self, netaddr_ipv6_new(addr, port))
688  elif alen == 6: # "Normal" 48-bit MAC address
689  assert port == 0
690  pyAssimObj.__init__(self, netaddr_mac48_new(addr, port))
691  elif alen == 8: # Extended 64-bit MAC address
692  assert port == 0
693  pyAssimObj.__init__(self, netaddr_mac64_new(addr, port))
694  else:
695  raise ValueError('Invalid address length - not 4, 6, 8, or 16')
696 
697  def port(self):
698  'Return the port (if any) for this pyNetAddr object'
699  base = self._Cstruct[0]
700  while (type(base) is not NetAddr):
701  base = base.baseclass
702  return base.port(self._Cstruct)
703 
704  def setport(self, port):
705  'Return the port (if any) for this pyNetAddr object'
706  base = self._Cstruct[0]
707  while (type(base) is not NetAddr):
708  base = base.baseclass
709  base.setport(self._Cstruct, port)
710 
711  def addrtype(self):
712  'Return the type of address for this pyNetAddr object'
713  base = self._Cstruct[0]
714  while (type(base) is not NetAddr):
715  base = base.baseclass
716  return base.addrtype(self._Cstruct)
717 
718  def addrlen(self):
719  "Return the number of bytes necessary to represent this pyNetAddr object on the wire."
720  base = self._Cstruct[0]
721  while (type(base) is not NetAddr):
722  base = base.baseclass
723  return base._addrlen
724 
725  def islocal(self):
726  'Return True if this address is a local address'
727  base = self._Cstruct[0]
728  while (type(base) is not NetAddr):
729  base = base.baseclass
730  return base.islocal(self._Cstruct)
731 
732  def isanyaddr(self):
733  'Return True if this address is a local address'
734  base = self._Cstruct[0]
735  while (type(base) is not NetAddr):
736  base = base.baseclass
737  return base.isanyaddr(self._Cstruct)
738 
739  def toIPv6(self, port=None):
740  'Return an equivalent IPv6 address to the one that was given. Guaranteed to be a copy'
741  base = self._Cstruct[0]
742  while (type(base) is not NetAddr):
743  base = base.baseclass
744  newcs = cast(base.toIPv6(self._Cstruct), cClass.NetAddr)
745  return pyNetAddr(None, Cstruct=newcs, port=port)
746 
747  def __repr__(self):
748  'Return a canonical representation of this NetAddr'
749  base = self._Cstruct[0]
750  while (type(base) is not NetAddr):
751  base = base.baseclass
752  cstringret = base.canonStr(self._Cstruct)
753  ret = string_at(cstringret)
754  g_free(cstringret)
755  return ret
756 
757 
758  def __eq__(self, other):
759  "Return True if the two pyNetAddrs are equal"
760  if not other._Cstruct or not self._Cstruct:
761  return False
762  base = self._Cstruct[0]
763  while (type(base) is not NetAddr):
764  base = base.baseclass
765  return base.equal(self._Cstruct, other._Cstruct)
766 
767  def __hash__(self):
768  'Return a hash value for the given pyNetAddr'
769  if not self._Cstruct:
770  return 0
771  base = self._Cstruct[0]
772  while (type(base) is not NetAddr):
773  base = base.baseclass
774  return base.hash(self._Cstruct)
775 
776 
778  '''This class represents the Python version of our C-class @ref Frame
779  - represented by the struct _Frame.
780  This class is a base class for several different pyFrame subclasses.
781  Each of these various pyFrame subclasses have a corresponding C-class @ref Frame subclass.
782  The purpose of these pyFrames and their subclasses is to talk on the wire with our C code in our
783  nanoprobes.
784 
785  Deliberately leaving out the updatedata() C-class member function - at least for now.
786  I suspect that the Python code will only need the corresponding calls in a @ref FrameSet
787  - which would then update the corresponding @ref Frame member functions...
788  '''
789  #
790  # Our subclasses need to implement these methods:
791  # __init__ - subclass initializer
792  # from_Cstruct classmethod - call the corresponding xxxframe_tlvconstructor() function
793  # to act as a pseudo-constructor. This method/constructor is used to create
794  # Python objects from incoming packet data.
795  #
796  def __init__(self, initval, Cstruct=None):
797  "Initializer for the pyFrame object."
798  if Cstruct is None:
799  try:
800  frametype = initval.tlvtype
801  except(AttributeError):
802  frametype = int(initval)
803  # If we don't do this, then a subclass __init__ function must do it instead...
804  pyAssimObj.__init__(self, Cstruct=frame_new(frametype, 0))
805  else:
806  pyAssimObj.__init__(self, Cstruct=Cstruct)
807 
808  def frametype(self):
809  "Return the TLV type for the pyFrame object."
810  base = self._Cstruct[0]
811  while (type(base)is not Frame):
812  base = base.baseclass
813  return base.type
814 
815  def framelen(self):
816  "Return the length of this frame in bytes (TLV length)."
817  base = self._Cstruct[0]
818  while (type(base)is not Frame):
819  base = base.baseclass
820  return base.length
821 
822  def framevalue(self):
823  'Return a C-style pointer to the underlying raw TLV data (if any)'
824  base = self._Cstruct[0]
825  while (type(base)is not Frame):
826  base = base.baseclass
827  return cast(base.value, c_char_p)
828 
829  def frameend(self):
830  'Return a C-style pointer to the underlying raw TLV data (if any)'
831  base = self._Cstruct[0]
832  while (type(base)is not Frame):
833  base = base.baseclass
834  return cast(base.value+base.length, c_char_p)
835 
836  def dataspace(self):
837  'Return the amount of space this frame needs - including type and length'
838  base = self._Cstruct[0]
839  while (type(base) is not Frame):
840  base = base.baseclass
841  return base.dataspace(self._Cstruct)
842 
843  def isvalid(self):
844  "Return True if this Frame is valid"
845  base = self._Cstruct[0]
846  while (type(base) is not Frame):
847  base = base.baseclass
848 # pstart = pointer(cast(base.value, c_char_p))
849 # if pstart[0] is None:
850 # return False
851  return (int(base.isvalid(self._Cstruct, None, None)) != 0)
852 
853  def setvalue(self, value):
854  'Assign a chunk of memory to the Value portion of this Frame'
855  vlen = len(value)
856  if type(value) is str:
857  valbuf = create_string_buffer(vlen+1)
858  for i in range(0, vlen):
859  vi = value[i]
860  valbuf[i] = vi
861  valbuf[vlen] = chr(0)
862  vlen += 1
863  else:
864  valbuf = create_string_buffer(vlen)
865  for i in range(0, vlen):
866  vi = value[i]
867  valbuf[i] = int(vi)
868  base = self._Cstruct[0]
869  valptr = MALLOC(vlen)
870  memmove(valptr, valbuf, vlen)
871  while (type(base) is not Frame):
872  base = base.baseclass
873  base.setvalue(self._Cstruct, valptr, vlen, cast(None, GDestroyNotify))
874 
875  def dump(self, prefix):
876  'Dump out this Frame (using C-class "dump" member function)'
877  base = self._Cstruct[0]
878  while (type(base) is not Frame):
879  base = base.baseclass
880  base.dump(self._Cstruct, cast(prefix, c_char_p))
881 
882  def __str__(self):
883  'Convert this Frame to a string'
884  base = self._Cstruct[0]
885  while (type(base) is not AssimObj):
886  base = base.baseclass
887  cstringret = cast(base.toString(self._Cstruct), c_char_p)
888  ret = string_at(cstringret)
889  g_free(cstringret)
890  return '%s: %s' % (FrameTypes.get(self.frametype())[1] , ret)
891 
892  @staticmethod
893  def Cstruct2Frame(frameptr):
894  'Unmarshalls a binary blob (Cstruct) into a Frame'
895  frameptr = cast(frameptr, cClass.Frame)
896  CCref(frameptr)
897  frametype = frameptr[0].type
898  Cclassname = proj_class_classname(frameptr)
899  pyclassname = "py" + Cclassname
900  if Cclassname == 'NetAddr':
901  statement = "%s(%d, None, Cstruct=cast(frameptr, cClass.%s))" \
902  % (pyclassname, frametype, Cclassname)
903  elif Cclassname == Cclassname == 'IpPortFrame':
904  statement = "%s(%d, None, None, Cstruct=cast(frameptr, cClass.%s))" \
905  % (pyclassname, frametype, Cclassname)
906  else:
907  statement = "%s(%d, Cstruct=cast(frameptr, cClass.%s))" \
908  % (pyclassname, frametype, Cclassname)
909  #print >> sys.stderr, "EVAL:", statement
910  return eval(statement)
911 
913  '''This class represents the Python version of our C-class CompressFrame
914  - represented by the struct _CompressFrame. It is used to tell us that
915  what kind of compression we want in our communication stream.
916  '''
917  def __init__(self, frametype=FRAMETYPE_COMPRESS, compression_method=COMPRESS_ZLIB
918  , Cstruct=None):
919  self._Cstruct = None # Keep error legs from complaining.
920  if Cstruct is None:
921  self._Cstruct = compressframe_new(frametype, compression_method)
922  else:
923  self._Cstruct = Cstruct
924  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
925 
926 
928  '''This class represents the Python version of our C-class AddrFrame
929  - represented by the struct _AddrFrame.
930  '''
931  def __init__(self, frametype, addrstring=None, port=None, Cstruct=None):
932  "Initializer for the pyAddrFrame object."
933  self._Cstruct = None # Keep error legs from complaining.
934  if Cstruct is None:
935  if isinstance(addrstring, pyNetAddr):
936  self._pyNetAddr = addrstring
937  else:
938  self._pyNetAddr = pyNetAddr(addrstring, port=port)
939  Cstruct = addrframe_new(frametype, 0)
940  if addrstring is not None:
941  Cstruct[0].setnetaddr(Cstruct, self._pyNetAddr._Cstruct)
942  else:
943  assert port is None
944  assert addrstring is None
945  # Allow for prefixed address type - two bytes
946  addrlen = Cstruct[0].baseclass.length - 2
947  assert addrlen == 4 or addrlen == 6 or addrlen == 8 or addrlen == 16 \
948  , ("addrlen is %d" % addrlen)
949  addrstr = Cstruct[0].baseclass.value+2
950  addrstring = create_string_buffer(addrlen)
951  memmove(addrstring, addrstr, addrlen)
952  self._pyNetAddr = pyNetAddr(addrstring, port=None)
953  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
954 
955  def addrtype(self):
956  'Return the Address type for this AddrFrame'
957  return self._pyNetAddr.addrtype()
958 
959  def getnetaddr(self):
960  'Return the pyNetAddr for this AddrFrame'
961  return self._pyNetAddr
962 
963  def __str__(self):
964  return ("pyAddrFrame(%s, (%s))" \
965  % (FrameTypes.get(self.frametype())[1], str(self._pyNetAddr)))
966 
968  '''This class represents the Python version of our C-class IpPortFrame
969  - represented by the struct _IpPortFrame.
970  '''
971  def __init__(self, frametype, addrstring, port=None, Cstruct=None):
972  "Initializer for the pyIpPortFrame object."
973  self._Cstruct = None # Keep error legs from complaining.
974  if Cstruct is None:
975  if isinstance(addrstring, pyNetAddr):
976  self._pyNetAddr = addrstring
977  Cstruct = ipportframe_netaddr_new(frametype, addrstring._Cstruct)
978  if not Cstruct:
979  raise ValueError("invalid initializer")
980  self.port = addrstring.port()
981  else:
982  Cstruct = self._init_from_binary(frametype, addrstring, port)
983  else:
984  assert port is None
985  assert addrstring is None
986  addrlen = Cstruct[0].baseclass.length - 4 # Allow for prefixed port and address type
987  if addrlen != 4 and addrlen != 16:
988  raise ValueError("Bad addrlen: %d" % addrlen)
989  port = Cstruct[0].port
990  self.port = port
991  addrstr = Cstruct[0].baseclass.value+4
992  addrstring = create_string_buffer(addrlen)
993  memmove(addrstring, addrstr, addrlen)
994  self._pyNetAddr = pyNetAddr(addrstring, port=port)
995  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
996 
997  def _init_from_binary(self, frametype, addrstring, port):
998  'Initialize a pyIpAddrFrame from a binary argument'
999  addrlen = len(addrstring)
1000  self._pyNetAddr = pyNetAddr(addrstring, port=port)
1001  if self._pyNetAddr is None:
1002  raise ValueError("Invalid initializer.")
1003  addrstr = create_string_buffer(addrlen)
1004  for j in range(0, addrlen):
1005  addrstr[j] = chr(addrstring[j])
1006  if addrlen == 4:
1007  Cstruct = ipportframe_ipv4_new(frametype, port, addrstr)
1008  elif addrlen == 16:
1009  Cstruct = ipportframe_ipv6_new(frametype, port, addrstr)
1010  else:
1011  raise ValueError('Bad address length: %d' % addrlen)
1012  self.port = port
1013  if port == 0:
1014  raise ValueError("zero port")
1015  if not Cstruct:
1016  raise ValueError("invalid initializer")
1017  return Cstruct
1018 
1019  def addrtype(self):
1020  'Return the Address type of this pyIpPortFrame'
1021  return self._pyNetAddr.addrtype()
1022 
1023  def getnetaddr(self):
1024  'Return the NetAddr of this pyIpPortFrame'
1025  return self._pyNetAddr
1026 
1027  def getport(self):
1028  'Return the port of this pyIpPortFrame'
1029  return self._pyNetAddr.port()
1030 
1031 
1033  '''This class represents the Python version of our C-class CstringFrame
1034  - represented by the struct _CstringFrame.
1035  This class represents a Frame standard NUL-terminated C string.
1036  '''
1037  def __init__(self, frametype, initval=None, Cstruct=None):
1038  '''Constructor for pyCstringFrame object - initial value should be something
1039  that looks a lot like a Python string'''
1040  if Cstruct is None:
1041  Cstruct = cstringframe_new(frametype, 0)
1042  pyFrame.__init__(self, frametype, Cstruct)
1043  if initval is not None:
1044  self.setvalue(initval)
1045 
1046  def getstr(self):
1047  'Return the String part of this pyCstringFrame'
1048  base = self._Cstruct[0]
1049  while (not hasattr(base, 'value')):
1050  base = base.baseclass
1051  return string_at(base.value)
1052 
1054  '''This class represents the Python version of our IntFrame C-class
1055  - represented by the struct _IntFrame.
1056  This class represents an integer of 1, 2, 3, 4 or 8 bytes.
1057  '''
1058  def __init__(self, frametype, initval=None, intbytes=4, Cstruct=None):
1059  '''Constructor for pyIntFrame object
1060  - initial value should be something that looks a lot like an integer'''
1061  self._Cstruct = None
1062  if Cstruct is None:
1063  Cstruct = intframe_new(frametype, intbytes)
1064  if not Cstruct:
1065  raise ValueError("Invalid integer size (%d) in pyIntFrame constructor" % intbytes)
1066  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
1067  if initval is not None:
1068  self.setint(initval)
1069 
1070  def __int__(self):
1071  '''Return the integer value of this pyIntFrame. (implemented by the
1072  underlying IntFrame object)'''
1073  return self._Cstruct[0].getint(self._Cstruct)
1074 
1075  def __str__(self):
1076  'Return a string representation of this pyIntFrame (the integer value).'
1077  return ("pyIntFrame(%s, (%d))" % (FrameTypes.get(self.frametype())[1], int(self)))
1078 
1079  def getint(self):
1080  'Return the integer value of this pyIntFrame - same as __int__.'
1081  return int(self)
1082 
1083  def setint(self, intval):
1084  '''Set the value of this pyIntFrame to the given integer value.
1085  Note that this value is range checked by the underlying IntFrame implementation.
1086  '''
1087  self._Cstruct[0].setint(self._Cstruct, int(intval))
1088 
1089  def intlength(self):
1090  '''Return the number of bytes in the integer underlying this pyIntFrame object.
1091  (implemented by underlying IntFrame object)'''
1092  return self._Cstruct[0].intlength(self._Cstruct)
1093 
1095  "Class for a Frame type we don't recognize"
1096  def __init__(self, frametype, Cstruct=None):
1097  'Initializer for pyUnknownFrame'
1098  if Cstruct is None:
1099  Cstruct = unknownframe_new(frametype)
1100  pyFrame.__init__(self, frametype, Cstruct)
1101 
1103  'Class for a Sequence Number Frame - for reliable UDP packet transmission.'
1104  def __init__(self, frametype, initval=None, Cstruct=None):
1105  'Initializer for pySeqnoFrame'
1106  self._Cstruct = None
1107  # TODO(?): Need to allow for initialization of seqno frames.
1108  if Cstruct is None:
1109  Cstruct = seqnoframe_new(frametype, 0)
1110  if not Cstruct:
1111  raise ValueError("Constructor error for PySeqnoFrame()")
1112  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
1113  if initval is not None:
1114  self.setqid(initval[0])
1115  self.setreqid(initval[1])
1116 
1117  def setreqid(self, reqid):
1118  'Set the request ID portion of this SeqnoFrame'
1119  self._Cstruct[0].setreqid(self._Cstruct, reqid)
1120 
1121  def setqid(self, qid):
1122  'Set the Queue ID portion of this SeqnoFrame'
1123  self._Cstruct[0].setqid(self._Cstruct, qid)
1124 
1125  def getreqid(self):
1126  'Get the request ID portion of this SeqnoFrame'
1127  return self._Cstruct[0].getreqid(self._Cstruct)
1128 
1129  def getqid(self):
1130  'Get the Queue ID portion of this SeqnoFrame'
1131  return self._Cstruct[0].getqid(self._Cstruct)
1132 
1133  def __eq__(self, rhs):
1134  'Compare this pySeqnoFrame to another pySeqnoFrame'
1135  lhsbase = self._Cstruct[0]
1136  while (type(lhsbase) is not SeqnoFrame):
1137  lhsbase = lhsbase.baseclass
1138  return lhsbase.equal(self._Cstruct, rhs._Cstruct)
1139 
1140  def __str__(self):
1141  'Convert this pySeqnoFrame to a String'
1142  return ("pySeqNo(%s: (%d, %d))" \
1143  % (FrameTypes.get(self.frametype())[1], self.getqid(), self.getreqid()))
1144 
1146  '''Class for Digital Signature Frames
1147  - for authenticating data (subclasses will authenticate senders)'''
1148  def __init__(self, gchecksumtype, Cstruct=None):
1149  'Initializer for pySignFrame'
1150  self._Cstruct = None
1151  if Cstruct is None:
1152  Cstruct = signframe_new(gchecksumtype, 0)
1153  if not Cstruct:
1154  raise ValueError("Invalid checksum type (%s) for PySignFrame()" % gchecksumtype)
1155  pyFrame.__init__(self, initval=FRAMETYPE_SIG, Cstruct=Cstruct)
1156 
1158  'Class for a Frame containing a single name/value pair'
1159  def __init__(self, frametype, name, value, Cstruct=None):
1160  'Initializer for pyNVpairFrame'
1161  self._Cstruct = None
1162  if Cstruct is None:
1163  Cstruct = nvpairframe_new(frametype, name, value, 0)
1164  if not Cstruct:
1165  raise ValueError("Invalid NVpair initializer for pyNVPairFrame()")
1166  pyFrame.__init__(self, initval=frametype, Cstruct=Cstruct)
1167 
1168  def name(self):
1169  'Return the name portion of a pyNVpairFrame'
1170  return string_at(self._Cstruct[0].name)
1171 
1172  def value(self):
1173  'Return the name portion of a pyNVpairFrame'
1174  return string_at(self._Cstruct[0].value)
1175 
1176 
1177 
1178 #pylint: disable=R0921
1180  'Class for Frame Sets - for collections of Frames making up a logical packet'
1181  def __init__(self, framesettype, Cstruct=None):
1182  'Initializer for pyFrameSet'
1183  if Cstruct is None:
1184  Cstruct = frameset_new(framesettype)
1185  pyAssimObj.__init__(self, Cstruct=Cstruct)
1186 
1187  def append(self, frame):
1188  'Append a frame to the end of a @ref FrameSet'
1189  frameset_append_frame(self._Cstruct, frame._Cstruct)
1190 
1191  def prepend(self, frame):
1192  'Prepend a frame before the first frame in a @ref FrameSet'
1193  frameset_prepend_frame(self._Cstruct, frame._Cstruct)
1194 
1195  def construct_packet(self, signframe, cryptframe=None, compressframe=None):
1196  'Construct packet from curent frameset + special prefix frames'
1197  cf = None
1198  cmpf = None
1199  if cryptframe is not None:
1200  cf = cryptframe._Cstruct
1201  if compressframe is not None:
1202  cmpf = compressframe._Cstruct
1203  frameset_construct_packet(self._Cstruct, signframe._Cstruct, cf, cmpf)
1204 
1205  def get_framesettype(self):
1206  'Return frameset type of this FrameSet'
1207  return self._Cstruct[0].fstype
1208 
1209  def get_flags(self):
1210  'Return current flags for this FrameSet'
1211  return frameset_get_flags(self._Cstruct)
1212 
1213  def set_flags(self, flags):
1214  "'OR' the given flags into the set of flags for this FrameSet"
1215  return frameset_set_flags(self._Cstruct, int(flags))
1216 
1217  def clear_flags(self, flags):
1218  "Clear the given flags for this FrameSet"
1219  return frameset_clear_flags(self._Cstruct, int(flags))
1220 
1221  def dump(self):
1222  'Dump out the given frameset'
1223  frameset_dump(self._Cstruct)
1224 
1225  def getpacket(self):
1226  'Return the constructed packet for this pyFrameSet'
1227  if not self._Cstruct[0].packet:
1228  raise ValueError("No packet constructed for frameset")
1229  return (self._Cstruct[0].packet, self._Cstruct[0].pktend)
1230 
1231  def __len__(self):
1232  'Return the number of Frames in this pyFrameSet'
1233  # This next statement OUGHT to work - and indeed it returns the right value
1234  # But somehow, 'self' doesn't get freed like it ought to :-(
1235  # BUG??
1236  #return g_slist_length(self._Cstruct[0].framelist)
1237  # So, let's do this instead...
1238  curframe = self._Cstruct[0].framelist
1239  count = 0
1240  while curframe:
1241  count += 1
1242  curframe = g_slist_next(curframe)
1243  return int(count)
1244 
1245  def __delitem__(self, key):
1246  "Fail - we don't implement this"
1247  raise NotImplementedError("FrameSet does not implement __delitem__()")
1248 
1249  def __getitem__(self, key):
1250  "Fail - we don't implement this"
1251  raise NotImplementedError("FrameSet does not implement __getitem__()")
1252 
1253  def __setitem__(self, key, value):
1254  "Fail - we don't implement this"
1255  raise NotImplementedError("FrameSet does not implement __setitem__()")
1256 
1257  def iter(self):
1258  'Generator yielding the set of pyFrames in this pyFrameSet'
1259  curframe = self._Cstruct[0].framelist
1260  while curframe:
1261  cast(curframe[0].data, struct__GSList._fields_[0][1])
1262  yieldval = pyFrame.Cstruct2Frame(cast(curframe[0].data, cClass.Frame))
1263  #print >> sys.stderr, ("Constructed frame IS [%s]" % str(yieldval))
1264  if not yieldval.isvalid():
1265  print >> sys.stderr \
1266  , "OOPS! Constructed %d byte frame from iter() is not valid [%s]" \
1267  % (yieldval.framelen(), str(yieldval))
1268  raise ValueError("Constructed %d byte frame from iter() is not valid [%s]"
1269  % (yieldval.framelen(), str(yieldval)))
1270  #print "Yielding:", str(yieldval), "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
1271  yield yieldval
1272  curframe = g_slist_next(curframe)
1273 
1274  def __str__(self):
1275  'Convert this pyFrameSet to a String'
1276  result = '%s:{' % FrameSetTypes.get(self.get_framesettype())[0]
1277  comma = ''
1278  for frame in self.iter():
1279  result += '%s[%d]%s' % (comma, frame.framelen(), str(frame))
1280  comma = ', '
1281  result += "}"
1282  return result
1283 
1284 
1286  'Class for Decoding packets - for returning an array of FrameSets from a physical packet.'
1287  def __init__(self, Cstruct=None):
1288  'Initializer for pyPacketDecoder'
1289  if Cstruct is None:
1290  Cstruct = packetdecoder_new(0, None, 0)
1291  pyAssimObj.__init__(self, Cstruct=Cstruct)
1292 
1293  def fslist_from_pktdata(self, pktlocation):
1294  'Make a list of FrameSets out of a packet.'
1295  base = self._Cstruct[0]
1296  while (type(base)is not PacketDecoder):
1297  base = base.baseclass
1298  fs_gslistint = base.pktdata_to_framesetlist(self._Cstruct, pktlocation[0], pktlocation[1])
1299  return pyPacketDecoder.fslist_to_pyfs_array(fs_gslistint)
1300 
1301  @staticmethod
1302  def fslist_to_pyfs_array(listheadint):
1303  'Converts a GSList of FrameSets to a python array of pyFrameSets'
1304  fs_gslist = cast(listheadint, cClass.GSList)
1305  frameset_list = []
1306  curfs = fs_gslist
1307  while curfs:
1308  cfs = cast(curfs[0].data, cClass.FrameSet)
1309  fs = pyFrameSet(None, Cstruct=cfs)
1310  frameset_list.append(fs)
1311  curfs = g_slist_next(curfs)
1312  g_slist_free(fs_gslist)
1313  return frameset_list
1314 
1315 # R0904: Too many public methods
1316 #pylint: disable=R0904
1318  'Class for Holding configuration information - now a general JSON-compatible data bag'
1319  #pylint: disable=R0921
1320 
1321  def __init__(self, init=None, filename=None, Cstruct=None):
1322  'Initializer for pyConfigContext'
1323  self._Cstruct = None # Keep error legs from complaining.
1324  if not Cstruct:
1325  # Cstruct overrides init and filename
1326  if filename is not None:
1327  f = open(filename, 'r')
1328  # filename overrides init
1329  init = f.read()
1330  f.close()
1331  if (isinstance(init, str) or isinstance(init, unicode)):
1332  Cstruct = configcontext_new_JSON_string(str(init))
1333  if not Cstruct:
1334  raise ValueError('Bad JSON [%s]' % str(init))
1335  init = None
1336  else:
1337  Cstruct = configcontext_new(0)
1338  pyAssimObj.__init__(self, Cstruct=Cstruct)
1339  if init is not None:
1340  for key in init.keys():
1341  self[key] = init[key]
1342 
1343 
1344  def getint(self, name):
1345  'Return the integer associated with "name"'
1346  return self._Cstruct[0].getint(self._Cstruct, name)
1347 
1348  def setint(self, name, value):
1349  'Set the integer associated with "name"'
1350  self._Cstruct[0].setint(self._Cstruct, name, value)
1351 
1352  def getbool(self, name):
1353  'Return the boolean associated with "name"'
1354  return self._Cstruct[0].getbool(self._Cstruct, name) != 0
1355 
1356  def setbool(self, name, value):
1357  'Set the boolean associated with "name"'
1358  self._Cstruct[0].setbool(self._Cstruct, name, bool(value))
1359 
1360  def getfloat(self, name):
1361  'Return the floating point value associated with "name"'
1362  return self._Cstruct[0].getfloat(self._Cstruct, name)
1363 
1364  def setfloat(self, name, value):
1365  'Set the floating point value associated with "name"'
1366  self._Cstruct[0].setfloat(self._Cstruct, name, float(value))
1367 
1368  def getaddr(self, name):
1369  'Return the NetAddr associated with "name"'
1370  naddr = self._Cstruct[0].getaddr(self._Cstruct, name)
1371  if naddr:
1372  naddr = cast(naddr, cClass.NetAddr)
1373  # We're creating a new reference to the pre-existing NetAddr
1374  CCref(naddr)
1375  return pyNetAddr(None, Cstruct=naddr)
1376  raise IndexError("No such NetAddr value [%s]" % name)
1377 
1378  def setaddr(self, name, value):
1379  'Set the @ref NetAddr associated with "name"'
1380  self._Cstruct[0].setaddr(self._Cstruct, name, value._Cstruct)
1381 
1382  def getframe(self, name):
1383  'Return the Frame associated with "name"'
1384  faddr = self._Cstruct[0].getframe(self._Cstruct, name)
1385  if faddr:
1386  # Cstruct2Frame already calls CCref()
1387  return pyFrame.Cstruct2Frame(faddr)
1388  raise IndexError("No such Frame value [%s]" % name)
1389 
1390  def setframe(self, name, value):
1391  'Set the @ref Frame associated with "name"'
1392  self._Cstruct[0].setframe(self._Cstruct, name, value._Cstruct)
1393 
1394  def getconfig(self, name):
1395  'Return the pyConfigContext object associated with "name"'
1396  caddr = self._Cstruct[0].getconfig(self._Cstruct, name)
1397  if caddr:
1398  caddr = cast(caddr, cClass.ConfigContext)
1399  # We're creating a new reference to the pre-existing NetAddr
1400  CCref(caddr)
1401  return pyConfigContext(Cstruct=caddr)
1402  raise IndexError("No such ConfigContext value [%s]" % name)
1403 
1404  def setconfig(self, name, value):
1405  'Set the @ref ConfigContext associated with "name"'
1406  self._Cstruct[0].setconfig(self._Cstruct, name, value._Cstruct)
1407 
1408  def getstring(self, name):
1409  'Return the string associated with "name"'
1410  ret = self._Cstruct[0].getstring(self._Cstruct, name)
1411  if ret:
1412  return string_at(ret)
1413  raise IndexError("No such String value [%s]" % name)
1414 
1415  def setstring(self, name, value):
1416  'Set the string associated with "name"'
1417  self._Cstruct[0].setstring(self._Cstruct, name, value)
1418 
1419  def getarray(self, name):
1420  'Return the array value associated with "name"'
1421  curlist = cast(self._Cstruct[0].getarray(self._Cstruct, name), cClass.GSList)
1422  #print >> sys.stderr, "CURLIST(initial) = %s" % curlist
1423  ret = []
1424  while curlist:
1425  #print >> sys.stderr, "CURLIST = %s" % curlist
1426  #cfgval = pyConfigValue(cast(cClass.ConfigValue, curlist[0].data).get())
1427  data = cast(curlist[0].data, cClass.ConfigValue)
1428  #print >> sys.stderr, "CURLIST->data = %s" % data
1429  CCref(data)
1430  cfgval = pyConfigValue(data).get()
1431  #print >> sys.stderr, "CURLIST->data->get() = %s" % cfgval
1432  ret.append(cfgval)
1433  curlist = g_slist_next(curlist)
1434  return ret
1435 
1436  def setarray(self, name, value):
1437  'Set a ConfigContext key value to be a sequence of values from an iterable'
1438  self._Cstruct[0].setarray(self._Cstruct, name, None)
1439  for elem in value:
1440  if isinstance(elem, bool):
1441  self._Cstruct[0].appendbool(self._Cstruct, name, elem)
1442  continue
1443  if isinstance(elem, (int, long)):
1444  self._Cstruct[0].appendint(self._Cstruct, name, elem)
1445  continue
1446  if isinstance(elem, float):
1447  self._Cstruct[0].appendfloat(self._Cstruct, name, elem)
1448  continue
1449  if isinstance(elem, str):
1450  self._Cstruct[0].appendstring(self._Cstruct, name, elem)
1451  continue
1452  if isinstance(elem, pyNetAddr):
1453  self._Cstruct[0].appendaddr(self._Cstruct, name, elem)
1454  continue
1455  if isinstance(elem, pyConfigContext):
1456  self._Cstruct[0].appendconfig(self._Cstruct, name, elem._Cstruct)
1457  continue
1458  if isinstance(elem, dict):
1459  cfgctx = pyConfigContext.from_dict(elem)
1460  self._Cstruct[0].appendconfig(self._Cstruct, name, cfgctx._Cstruct)
1461  continue
1462  raise ValueError("Cannot append/include array elements of type %s" % type(elem))
1463 
1464  @staticmethod
1465  def from_dict(dictval):
1466  'Construct a pyConfigContext from a dict-like object'
1467  newobj = pyConfigContext()
1468  for key in dictval.keys():
1469  keyval = dictval[key]
1470  if hasattr(keyval, 'keys'):
1471  keyval = pyConfigContext.from_dict(dictval[key])
1472  newobj[key] = dictval[key]
1473  return newobj
1474 
1475  def keys(self):
1476  'Return the set of keys for this object'
1477  l = []
1478  keylist = cast(self._Cstruct[0].keys(self._Cstruct), POINTER(GSList))
1479  curkey = keylist
1480  while curkey:
1481  l.append(string_at(curkey[0].data))
1482  curkey = g_slist_next(curkey)
1483  g_slist_free(keylist)
1484  return l
1485 
1486  def __iter__(self):
1487  'Iterate over self.keys()'
1488  for key in self.keys():
1489  yield key
1490 
1491  def gettype(self, name):
1492  '''Return the enumeration type of this particular key
1493  @todo Convert these enums to python types'''
1494  #print >> sys.stderr, 'gettype(%s)' % str(name)
1495  return self._Cstruct[0].gettype(self._Cstruct, str(name))
1496 
1497  def get(self, key, alternative=None):
1498  '''return value if object contains the given key - 'alternative' if not'''
1499  if self._Cstruct[0].gettype(self._Cstruct, str(key)) == CFG_EEXIST:
1500  return alternative
1501  return self[key]
1502 
1503  # pylint R0911: too many returns (9)
1504  # pylint: disable=R0911
1505  def deepget(self, key, alternative=None):
1506  '''return value if object contains the given *structured* key - 'alternative' if not'''
1507  try:
1508  (prefix, suffix) = key.split('.', 1)
1509  except ValueError:
1510  suffix = None
1511  prefix = key
1512  if prefix not in self:
1513  # Note that very similar code exists in GraphNodes get member function
1514  if not prefix.endswith(']'):
1515  return alternative
1516  else:
1517  # Looks like we have an array index
1518  proper = prefix[0:len(prefix)-1]
1519  try:
1520  (preprefix, idx) = proper.split('[', 1)
1521  except ValueError:
1522  return alternative
1523  if preprefix not in self:
1524  return alternative
1525  try:
1526  array = self[preprefix]
1527  idx = int(idx) # Possible ValueError
1528  value = array[idx] # possible IndexError or TypeError
1529  if suffix is None:
1530  return value
1531  except (TypeError, IndexError, ValueError):
1532  return alternative
1533  return value.deepget(suffix, alternative)
1534 
1535  prefixvalue = self[prefix]
1536  if suffix is None:
1537  return prefixvalue
1538  if not isinstance(prefixvalue, pyConfigContext):
1539  return alternative
1540  gotten = prefixvalue.deepget(suffix, alternative)
1541  return gotten
1542 
1543  def has_key(self, key):
1544  'return True if it has the given key'
1545  return self.__contains__(key)
1546 
1547  def __contains__(self, key):
1548  'return True if our object contains the given key'
1549  ktype = self._Cstruct[0].gettype(self._Cstruct, str(key))
1550  return ktype != CFG_EEXIST
1551 
1552  def __len__(self):
1553  'Return the number of items in this pyConfigContext'
1554  keylist = cast(self._Cstruct[0].keys(self._Cstruct), POINTER(GSList))
1555  llen = g_slist_length(keylist)
1556  g_slist_free(keylist)
1557  return llen
1558 
1559  def __delitem__(self, key):
1560  "Delete the given item"
1561  self._Cstruct[0].delkey(self._Cstruct, str(key))
1562 
1563  def __getitem__(self, name):
1564  'Return a value associated with "name"'
1565  ktype = self.gettype(name)
1566  ret = None
1567  #print >> sys.stderr, '************ GETITEM[%s] => %d *********************' % (name, ktype)
1568  if ktype == CFG_EEXIST:
1569  traceback.print_stack()
1570  raise IndexError("No such value [%s] in [%s]" % (name, str(self)))
1571  elif ktype == CFG_CFGCTX:
1572  ret = self.getconfig(name)
1573  elif ktype == CFG_STRING:
1574  ret = self.getstring(name)
1575  elif ktype == CFG_NETADDR:
1576  ret = self.getaddr(name)
1577  elif ktype == CFG_FRAME:
1578  ret = self.getframe(name)
1579  elif ktype == CFG_INT64:
1580  ret = self.getint(name)
1581  elif ktype == CFG_BOOL:
1582  ret = self.getbool(name)
1583  elif ktype == CFG_ARRAY:
1584  #print >> sys.stderr, '************ GETITEM[%s] => getarray(%s) *********************' \
1585  # % (name, name)
1586  ret = self.getarray(name)
1587  return ret
1588 
1589  def __setitem__(self, name, value):
1590  'Set a value associated with "name" - in the appropriate table'
1591  if isinstance(value, str):
1592  return self.setstring(name, value)
1593  if isinstance(value, pyNetAddr):
1594  return self.setaddr(name, value)
1595  if isinstance(value, pyFrame):
1596  return self.setframe(name, value)
1597  if isinstance(value, pyConfigContext):
1598  return self.setconfig(name, value)
1599  if isinstance(value, dict):
1600  return self.setconfig(name, pyConfigContext(value))
1601  if isinstance(value, (list, tuple)) or hasattr(value, '__iter__'):
1602  return self.setarray(name, value)
1603  if isinstance(value, float):
1604  return self.setfloat(name, value)
1605  if isinstance(value, dict):
1606  return self.setconfig(name, pyConfigContext.from_dict(value))
1607  if isinstance(value, bool):
1608  return self.setbool(name, value)
1609  self.setint(name, int(value))
1610 
1612  'A Python wrapper for a C implementation of something like a Python Dictionary'
1613  def __init__(self, Cstruct):
1614  'Initializer for pyConfigValue - now a subclass of pyAssimObj'
1615  pyAssimObj.__init__(self, Cstruct=Cstruct)
1616 
1617  def __str__(self):
1618  'Convert the given pyConfigValue to a String'
1619  str(self.get())
1620 
1621  def get(self):
1622  'Return the value of this object'
1623  ret = None
1624  vtype = self._Cstruct[0].valtype
1625  if vtype == CFG_BOOL:
1626  ret = self._Cstruct[0].u.intvalue != 0
1627  elif vtype == CFG_INT64:
1628  ret = int(self._Cstruct[0].u.intvalue)
1629  elif vtype == CFG_STRING:
1630  ret = str(self._Cstruct[0].u.strvalue)
1631  elif vtype == CFG_FLOAT:
1632  ret = float(self._Cstruct[0].u.floatvalue)
1633  elif vtype == CFG_CFGCTX:
1634  # We're creating a new reference to the pre-existing NetAddr
1635  CCref(self._Cstruct[0].u.cfgctxvalue)
1636  ret = pyConfigContext(Cstruct=self._Cstruct[0].u.cfgctxvalue)
1637  elif vtype == CFG_NETADDR:
1638  ret = pyNetAddr(None, Cstruct=self._Cstruct[0].u.addrvalue)
1639  # We're creating a new reference to the pre-existing NetAddr
1640  CCref(ret._Cstruct)
1641  elif vtype == CFG_FRAME:
1642  # Cstruct2Frame calls CCref() - so we don't need to
1643  ret = pyFrame.Cstruct2Frame(self._Cstruct[0].u.framevalue)
1644  elif vtype == CFG_ARRAY:
1645  # An Array is a linked list (GSList) of ConfigValue objects...
1646  ret = []
1647  this = self._Cstruct[0].u.arrayvalue
1648  while this:
1649  dataptr = cast(this[0].data, struct__GSList._fields_[0][1])
1650  dataptr = cast(dataptr, cClass.ConfigValue)
1651  CCref(dataptr)
1652  thisobj = pyConfigValue(cast(dataptr, cClass.ConfigValue)).get()
1653  ret.append(thisobj)
1654  this = g_slist_next(this)
1655  elif vtype == CFG_NULL:
1656  return None
1657  if ret is None:
1658  raise ValueError('Invalid valtype (%s)in pyConfigValue object' % self._Cstruct.valtype)
1659  return ret
1660 
1662  'A Network I/O object - with a variety of subclasses'
1663  def __init__(self, configobj, packetdecoder, Cstruct=None):
1664  'Initializer for pyNetIO'
1665  self._Cstruct = None # Keep error legs from complaining.
1666  if Cstruct is None:
1667  Cstruct = netio_new(0, configobj._Cstruct, packetdecoder._Cstruct)
1668  self.config = configobj
1669  else:
1670  self._Cstruct = Cstruct
1671  base = self._Cstruct[0]
1672  while (not hasattr(base, '_configinfo')):
1673  base = base.baseclass
1674  self.config = pyConfigContext(Cstruct=base._configinfo)
1675  CCref(base._configinfo)
1676  pyAssimObj.__init__(self, Cstruct=Cstruct)
1677 
1678  def setblockio(self, mode):
1679  'Set this NetIO object to blocking IO mode'
1680  base = self._Cstruct[0]
1681  while (not hasattr(base, 'setblockio')):
1682  base = base.baseclass
1683  return base.setblockio(self._Cstruct, int(mode))
1684 
1685  def fileno(self):
1686  'Return the file descriptor for this pyNetIO object'
1687  base = self._Cstruct[0]
1688  while (not hasattr(base, 'getfd')):
1689  base = base.baseclass
1690  return base.getfd(self._Cstruct)
1691 
1692  def bindaddr(self, addr, silent=False):
1693  'Bind the socket underneath this NetIO object to the given address'
1694  base = self._Cstruct[0]
1695  while (not hasattr(base, 'bindaddr')):
1696  base = base.baseclass
1697  return base.bindaddr(self._Cstruct, addr._Cstruct, silent)
1698 
1699  def boundaddr(self):
1700  'Return the socket underlying this NetIO object'
1701  base = self._Cstruct[0]
1702  while (not hasattr(base, 'bindaddr')):
1703  base = base.baseclass
1704  boundaddr = base.boundaddr(self._Cstruct)
1705  # We're creating a new reference to the pre-existing NetAddr
1706  ret = pyNetAddr(None, Cstruct=boundaddr)
1707  CCref(boundaddr)
1708  return ret
1709 
1710  def mcastjoin(self, addr):
1711  'Join the underlying socket to the given multicast address'
1712  base = self._Cstruct[0]
1713  while (not hasattr(base, 'mcastjoin')):
1714  base = base.baseclass
1715  return base.mcastjoin(self._Cstruct, addr._Cstruct, None)
1716 
1717  def getmaxpktsize(self):
1718  'Return the max packet size for this pyNetIO'
1719  base = self._Cstruct[0]
1720  while (not hasattr(base, 'getmaxpktsize')):
1721  base = base.baseclass
1722  return base.getmaxpktsize(self._Cstruct)
1723 
1724  def setmaxpktsize(self, size):
1725  'Set the max packet size for this pyNetIO'
1726  base = self._Cstruct[0]
1727  while (not hasattr(base, 'setmaxpktsize')):
1728  base = base.baseclass
1729  return base.setmaxpktsize(self._Cstruct, int(size))
1730 
1731  def compressframe(self):
1732  'Return the compression frame for this pyNetIO - may be None'
1733  # Doesn't make a py class object out of it yet...
1734  base = self._Cstruct[0]
1735  while (not hasattr(base, 'compressframe')):
1736  base = base.baseclass
1737  return base.compressframe(self._Cstruct)
1738 
1739  def cryptframe(self):
1740  'Return the encryption frame for this pyNetIO - may be None'
1741  # Doesn't make a py class object out of it yet...
1742  base = self._Cstruct[0]
1743  while (not hasattr(base, 'cryptframe')):
1744  base = base.baseclass
1745  return base.cryptframe(self._Cstruct)
1746 
1747  def signframe(self):
1748  'Return the digital signature frame for this pyNetIO'
1749  base = self._Cstruct[0]
1750  while (not hasattr(base, 'signframe')):
1751  base = base.baseclass
1752  return pySignFrame(0, Cstruct=cast(base.signframe(self._Cstruct), cClass.SignFrame))
1753 
1754  def sendframesets(self, destaddr, framesetlist):
1755  'Send the (collection of) frameset(s) out on this pyNetIO'
1756  if destaddr.port() == 0:
1757  raise ValueError("Zero Port in sendframesets: destaddr=%s" % str(destaddr))
1758  if not isinstance(framesetlist, collections.Sequence):
1759  framesetlist = (framesetlist, )
1760  base = self._Cstruct[0]
1761  while (not hasattr(base, 'sendaframeset')):
1762  base = base.baseclass
1763  # We ought to eventually construct a GSList of them and then call sendframesets
1764  # But this is easy for now...
1765  for frameset in framesetlist:
1766  base.sendaframeset(self._Cstruct, destaddr._Cstruct, frameset._Cstruct)
1767 
1768  def sendreliablefs(self, destaddr, framesetlist, qid = DEFAULT_FSP_QID):
1769  'Reliably send the (collection of) frameset(s) out on this pyNetIO (if possible)'
1770  if destaddr.port() == 0:
1771  raise ValueError("Zero Port in sendreliablefs: destaddr=%s" % str(destaddr))
1772  if not isinstance(framesetlist, collections.Sequence):
1773  framesetlist = (framesetlist, )
1774  base = self._Cstruct[0]
1775  while (not hasattr(base, 'sendaframeset')):
1776  base = base.baseclass
1777  for frameset in framesetlist:
1778  success = base.sendareliablefs(self._Cstruct, destaddr._Cstruct, qid, frameset._Cstruct)
1779  if not success:
1780  raise IOError("sendareliablefs(%s, %s) failed." % (destaddr, frameset))
1781 
1782  def ackmessage(self, destaddr, frameset):
1783  'ACK (acknowledge) this frameset - (presumably sent reliably).'
1784 
1785  base = self._Cstruct[0]
1786  while (not hasattr(base, 'ackmessage')):
1787  base = base.baseclass
1788  base.ackmessage(self._Cstruct, destaddr._Cstruct, frameset._Cstruct)
1789 
1790  def closeconn(self, qid, destaddr):
1791  'Close (reset) our connection to this address'
1792  base = self._Cstruct[0]
1793  while (not hasattr(base, 'closeconn')):
1794  base = base.baseclass
1795  print >> sys.stderr, ('CLOSING CONNECTION (closeconn) TO %s' % str(destaddr))
1796  base.closeconn(self._Cstruct, qid, destaddr._Cstruct)
1797 
1798  def addalias(self, fromaddr, toaddr):
1799  'Close (reset) our connection to this address'
1800 
1801  base = self._Cstruct[0]
1802  while (not hasattr(base, 'addalias')):
1803  base = base.baseclass
1804  base.addalias(self._Cstruct, fromaddr._Cstruct, toaddr._Cstruct)
1805 
1806  def recvframesets(self):
1807  '''Receive a collection of framesets read from this pyNetIO - all from the same Address.
1808  @return The return value is a tuple (address, framesetlist). '''
1809  #GSList * _netio_recvframesets (NetIO *self,NetAddr **src)
1810 
1811  base = self._Cstruct[0]
1812  while (not hasattr(base, 'recvframesets')):
1813  base = base.baseclass
1814  netaddrint = netaddr_ipv4_new(create_string_buffer(4), 101)
1815  netaddr = cast(netaddrint, cClass.NetAddr)
1816  netaddr[0].baseclass.unref(netaddr) # We're about to replace it...
1817  # Basically we needed a pointer to pass, and this seemed like a good way to do it...
1818  # Maybe it was -- maybe it wasn't... It's a pretty expensive way to get this effect...
1819  fs_gslistint = base.recvframesets(self._Cstruct, byref(netaddr))
1820  fslist = pyPacketDecoder.fslist_to_pyfs_array(fs_gslistint)
1821  if netaddr and len(fslist) > 0:
1822  # recvframesets gave us that 'netaddr' for us to dispose of - there are no other refs
1823  # to it so we should NOT 'CCref' it. It's a new object - not a pointer to an old one.
1824  address = pyNetAddr(None, Cstruct=netaddr)
1825  else:
1826  address = None
1827  return (address, fslist)
1828 
1829  @staticmethod
1831  'Return True if our OS supports a dual IPv4/IPv6 stack'
1833 
1835  'UDP version of the pyNetIO abstract base class'
1836  def __init__(self, config, packetdecoder, Cstruct=None):
1837  'Initializer for pyNetIOudp'
1838  self._Cstruct = None # Keep error legs from complaining.
1839  if Cstruct is None:
1840  Cstruct = netioudp_new(0, config._Cstruct, packetdecoder._Cstruct)
1841  if not Cstruct:
1842  raise ValueError("Invalid parameters to pyNetIOudp constructor")
1843  pyNetIO.__init__(self, config, packetdecoder, Cstruct=Cstruct)
1844 
1846  'Reliable UDP version of the pyNetIOudp abstract base class'
1847  def __init__(self, config, packetdecoder, rexmit_timer_uS=0, Cstruct=None):
1848  'Initializer for pyReliableUDP'
1849  self._Cstruct = None # Keep error legs from complaining.
1850  if Cstruct is None:
1851  Cstruct = reliableudp_new(0, config._Cstruct, packetdecoder._Cstruct, rexmit_timer_uS)
1852  if not Cstruct:
1853  raise ValueError("Invalid parameters to pyReliableUDP constructor")
1854  pyNetIOudp.__init__(self, config, packetdecoder, Cstruct=Cstruct)
1855 
1856  def log_conn(self, destaddr, qid=DEFAULT_FSP_QID):
1857  'Log connection status/info to system logs'
1858  base = self._Cstruct[0]
1859  while (type(base) is not ReliableUDP):
1860  base = base.baseclass
1861  base.log_conn(self._Cstruct, qid, destaddr._Cstruct)
1862 
1863 class CMAlib(object):
1864  'Miscellaneous functions to create certain useful pyFrameSets'
1865 
1866  def __init__(self):
1867  'Do-nothing init function'
1868  pass
1869 
1870  @staticmethod
1872  'Create a setconfig FrameSet'
1873  fs = cast(create_setconfig(cfg._Cstruct), cClass.FrameSet)
1874  return pyFrameSet(None, Cstruct=fs)
1875 
1876  @staticmethod
1877  def create_sendexpecthb(cfg, msgtype, address):
1878  'Create a Send/Expect heartbeat FrameSet'
1879  ucfs = create_sendexpecthb(cfg._Cstruct, int(msgtype)
1880  , address._Cstruct, 1)
1881  fs = cast(ucfs, cClass.FrameSet)
1882  return pyFrameSet(None, Cstruct=fs)
1883 
1885  'Dump out live objects to help locate memory leaks'
1886  print >> sys.stderr, 'GC Garbage: [%s]' % str(gc.garbage)
1887  print >> sys.stderr, '***************LOOKING FOR pyAssimObjs***********'
1888  get_referrers = True
1889  cobjcount = 0
1890  gc.collect()
1891  for obj in gc.get_objects():
1892  if isinstance(obj, (pyAssimObj, pyCstringFrame)):
1893  cobjcount += 1
1894  cobj = 'None'
1895  if hasattr(obj, '_Cstruct') and obj._Cstruct is not None:
1896  cobj = ('0x%x' % addressof(getattr(obj, '_Cstruct')[0]))
1897  print >> sys.stderr, ('FOUND C object class(%s): %s -> %s'
1898  % (obj.__class__.__name__, str(obj)[:512], cobj))
1899  if get_referrers:
1900  for referrer in gc.get_referrers(obj):
1901  print >> sys.stderr, ('++++Referred to by(%s): %s'
1902  % (type(referrer), str(referrer)[:512]))
1903 
1904  print >> sys.stderr, ('%d python wrappers referring to %d C-objects'
1905  % (cobjcount, proj_class_live_object_count()))
1907 
1908 if __name__ == '__main__':
1909  import pcapy
1910  names= ('../pcap/cdp.pcap', '../pcap/cdp-BCM1100.pcap','../pcap/n0.eth2.cdp.pcap')
1911  for pcapname in names:
1912  print >> sys.stderr, 'PARSING', pcapname
1913  reader = pcapy.open_offline(pcapname)
1914  pcap = reader.next()
1915  pcapdata = pcap[1]
1916  testpktstart = create_string_buffer(pcapdata)
1917  endaddr = addressof(testpktstart) + len(pcapdata)
1918  cdp = pySwitchDiscovery._decode_cdp('host', pcapname, 0, testpktstart, endaddr)
1919  print >> sys.stderr, 'GOTTEN CDP:', str(cdp)
1920  print >> sys.stderr, '\n'
1921 
guint16 frameset_set_flags(FrameSet *fs, guint16 flagbits)
Set (OR in) the given set of FrameSet flags.
Definition: frameset.c:309
WINEXPORT const void * get_cdptlv_next(const void *tlv_vp, const void *tlv_vpend)
Locate the next CDP TLV triple (iterator).
Definition: cdp_min.c:254
void frameset_dump(const FrameSet *fs)
Dump out a FrameSet.
Definition: frameset.c:355
ConfigContext * configcontext_new_JSON_string(const char *jsontext)
Construct a ConfigContext object from the given JSON string.
WINEXPORT guint16 get_cdptlv_type(const void *tlv_vp, const void *pktend)
Return type from the given TLV triplet in a CDP packet.
Definition: cdp_min.c:179
SeqnoFrame * seqnoframe_new(guint16 frametype, int objsize)
Construct new SeqnoFrame object.
Definition: seqnoframe.c:205
WINEXPORT AddrFrame * addrframe_new(guint16 frame_type, gsize framesize)
Construct a new AddrFrame class - allowing for "derived" frame types...
Definition: addrframe.c:201
guint16 frameset_get_flags(FrameSet *fs)
Return the flags currently set on this FrameSet.
Definition: frameset.c:301
guint16 frameset_clear_flags(FrameSet *fs, guint16 flagbits)
Clear the given set of FrameSet flags (& ~flagbits)
Definition: frameset.c:319
WINEXPORT gboolean is_valid_cdp_packet(const void *packet, const void *pktend)
Check to see if this is a valid CDP packet.
Definition: cdp_min.c:93
NetIOudp * netioudp_new(gsize objsize, ConfigContext *config, PacketDecoder *decoder)
Construct new UDP NetIO object (and its socket, etc)
Definition: netioudp.c:49
guint8 tlv_get_guint8(const void *vitem, const void *bufend)
Retrieve an unsigned 8 bit integer from the given location with error checking.
Definition: tlvhelper.c:30
WINEXPORT IpPortFrame * ipportframe_ipv6_new(guint16 frame_type, guint16 port, gconstpointer addr)
Construct and initialize an IPv6 IpPortFrame class.
Definition: ipportframe.c:217
WINEXPORT IpPortFrame * ipportframe_netaddr_new(guint16 frame_type, NetAddr *addr)
Construct and initialize an IpPortFrame class from a IP NetAddr class.
Definition: ipportframe.c:234
guint64 tlv_get_guint64(const void *vitem, const void *bufend)
Retrieve an unsigned 64 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:107
NetAddr * netaddr_dns_new(const char *sysname_or_addr)
Create a NetAddr from a DNS name or an ipv4 or ipv6 constant string.
Definition: netaddr.c:943
IntFrame * intframe_new(guint16 frametype, int intbytes)
Construct new IntFrame object.
Definition: intframe.c:181
NetAddr * netaddr_mac64_new(gconstpointer macbuf)
Create new NetAddr from a MAC64 address.
Definition: netaddr.c:1017
FrameSet * frameset_new(guint16 frameset_type)
Construct a new frameset of the given type.
Definition: frameset.c:110
NetAddr * netaddr_ipv4_new(gconstpointer ipbuf, guint16 port)
Create new NetAddr from a IPv4 address.
Definition: netaddr.c:1024
UnknownFrame * unknownframe_new(guint16 frame_type)
Construct a new UnknownFrame - disallowing for "derived" frame types...
Definition: unknownframe.c:55
WINEXPORT const void * get_cdptlv_first(const void *pkt, const void *pktend)
Return the first CDP TLV triple in a CDP packet.
Definition: cdp_min.c:223
PacketDecoder * packetdecoder_new(guint objsize, const FrameTypeToFrame *framemap, gint mapsize)
Initialize our frame type map.
Definition: packetdecoder.c:76
NetAddr * netaddr_mac48_new(gconstpointer macbuf)
Create new NetAddr from a MAC48 address.
Definition: netaddr.c:1010
void frameset_append_frame(FrameSet *fs, Frame *f)
Append frame to the front of the end of the frame list.
Definition: frameset.c:143
guint8 get_lldptlv_type(const void *tlv_vp, const void *pktend)
Return the 'Type' of the given LLDP TLV entry The Type is the high order 7 bits from the zeroth byte ...
Definition: lldp_min.c:83
CompressFrame * compressframe_new(guint16 frame_type, guint16 compression_method)
WINEXPORT gsize get_cdptlv_len(const void *tlv_vp, const void *pktend)
Return size of the given TLV triplet.
Definition: cdp_min.c:189
guint32 tlv_get_guint32(const void *vitem, const void *bufend)
Retrieve an unsigned 32 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:81
Frame * frame_new(guint16 frame_type, gsize framesize)
Construct a new frame - allowing for "derived" frame types...
Definition: frame.c:124
gboolean netio_is_dual_ipv4v6_stack(void)
Definition: netio.c:751
void frameset_construct_packet(FrameSet *fs, SignFrame *sigframe, Frame *cryptframe, CompressFrame *compressframe)
Construct packet to go correspond to this frameset.
Definition: frameset.c:159
NetAddr * netaddr_ipv6_new(gconstpointer ipbuf, guint16 port)
Create new NetAddr from a IPv6 address.
Definition: netaddr.c:1032
guint32 tlv_get_guint24(const void *vitem, const void *bufend)
Retrieve an unsigned 24 bit (3-byte) integer from the given location with error checking and without ...
Definition: tlvhelper.c:131
guint32 proj_class_live_object_count(void)
Return the count of live C class objects.
Definition: proj_classes.c:406
SignFrame * signframe_new(GChecksumType sigtype, gsize framesize)
Construct a new SignFrame - allowing for "derived" frame types...
Definition: signframe.c:208
ReliableUDP * reliableudp_new(gsize objsize, ConfigContext *config, PacketDecoder *decoder, guint rexmit_timer_uS)
Construct new UDP NetIO object (and its socket, etc)
Definition: reliableudp.c:69
AssimObj * assimobj_new(guint objsize)
Definition: assimobj.c:74
const char * proj_class_classname(gconstpointer object)
Return the class name of one of our managed objects.
Definition: proj_classes.c:324
NVpairFrame * nvpairframe_new(guint16 frame_type, gchar *name, gchar *value, gsize framesize)
Construct a new NVpairFrame - allowing for "derived" frame types...
Definition: nvpairframe.c:97
const void * get_lldptlv_first(const void *packet, const void *pktend)
Definition: lldp_min.c:174
void frameset_prepend_frame(FrameSet *fs, Frame *f)
Prepend frame to the front of the frame list.
Definition: frameset.c:132
#define MALLOC(nbytes)
should it just call g_malloc?
Definition: projectcommon.h:26
WINEXPORT const void * get_cdptlv_body(const void *tlv_vp, const void *pktend)
Return the body (value) blob of a CDP TLV triplet.
Definition: cdp_min.c:212
gboolean is_valid_lldp_packet(const void *tlv_vp, const void *pktend)
Definition: lldp_min.c:116
WINEXPORT IpPortFrame * ipportframe_ipv4_new(guint16 frame_type, guint16 port, gconstpointer addr)
Construct and initialize an IPv4 IpPortFrame class.
Definition: ipportframe.c:199
NetIO * netio_new(gsize objsize, ConfigContext *config, PacketDecoder *decoder)
NetIO constructor.
Definition: netio.c:368
const void * get_lldptlv_next(const void *tlv_vp, const void *pktend)
Return pointer to the next LLDP TLV entry after the current location.
Definition: lldp_min.c:188
gsize get_lldptlv_len(const void *tlv_vp, const void *pktend)
Return the 'Length' of the given LLDP TLV entry.
Definition: lldp_min.c:93
void proj_class_dump_live_objects(void)
Dump all live C class objects (address and Class)
Definition: proj_classes.c:356
ConfigContext * configcontext_new(gsize objsize)
Construct a new ConfigContext object - with no values defaulted.
guint16 tlv_get_guint16(const void *vitem, const void *bufend)
Retrieve an unsigned 16 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:53
WINEXPORT CstringFrame * cstringframe_new(guint16 frame_type, gsize framesize)
Construct a new CstringFrame - allowing for "derived" frame types...
Definition: cstringframe.c:101
const void * get_lldptlv_body(const void *tlv_vp, const void *pktend)
Return the 'Value' of the given LLDP TLV entry.
Definition: lldp_min.c:106