From owner-p4-projects@FreeBSD.ORG Mon Aug 3 02:53:54 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 366821065675; Mon, 3 Aug 2009 02:53:54 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CEEC01065670 for ; Mon, 3 Aug 2009 02:53:53 +0000 (UTC) (envelope-from zjriggl@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id BB8E18FC13 for ; Mon, 3 Aug 2009 02:53:53 +0000 (UTC) (envelope-from zjriggl@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n732rrto036113 for ; Mon, 3 Aug 2009 02:53:53 GMT (envelope-from zjriggl@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n732rrg5036111 for perforce@freebsd.org; Mon, 3 Aug 2009 02:53:53 GMT (envelope-from zjriggl@FreeBSD.org) Date: Mon, 3 Aug 2009 02:53:53 GMT Message-Id: <200908030253.n732rrg5036111@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to zjriggl@FreeBSD.org using -f From: Zachariah Riggle To: Perforce Change Reviews Cc: Subject: PERFORCE change 166949 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 03 Aug 2009 02:53:55 -0000 http://perforce.freebsd.org/chv.cgi?CH=166949 Change 166949 by zjriggl@zjriggl_tcpregression on 2009/08/03 02:53:10 Periodic submit Affected files ... .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/echoServer.py#5 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/loggable.py#5 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/logging.conf#5 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/StringField.py#3 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/__init__.py#8 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/backup.tar#3 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/checksum.py#2 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/decorators.py#4 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/field.py#2 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/hwAddress.py#4 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/ipAddress.py#5 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/networkPort.py#4 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/payload.py#4 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/pseudoipv4.py#3 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/segmentBuffer.py#3 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/sniffLocalhost.py#5 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/tcpConstructor.py#6 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/tcpFilter.py#7 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/tcprecvdaemon.py#3 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/tcpstatemachine.py#8 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/test.html#5 edit .. //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/testconfig.py#7 edit Differences ... ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/echoServer.py#5 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/loggable.py#5 (text+ko) ==== @@ -6,12 +6,13 @@ logging.config.fileConfig( "logging.conf" ) ( logging.FIELD_CHANGE, - logging.RESPONSE_GENERATION, - logging.PACKET_TRANSMIT, + logging.RESPONSE_GENERATION ) = range( logging.DEBUG - 2, logging.DEBUG ) + +( logging.PACKET_TRANSMIT, logging.PACKET_RECEIVED, logging.PACKET_SENT, logging.VALIDATE, - logging.STATE_CHANGE ) = range( logging.INFO - 7, logging.INFO ) + logging.STATE_CHANGE ) = range( logging.INFO - 5, logging.INFO ) logging.addLevelName( logging.FIELD_CHANGE, "FIELD" ) logging.addLevelName( logging.RESPONSE_GENERATION, "\033[1;36mGENERATE\033[1;m" ) @@ -19,7 +20,9 @@ logging.addLevelName( logging.PACKET_RECEIVED, "\033[1;31mRECVD\033[1;m" ) logging.addLevelName( logging.PACKET_SENT, "\033[1;31mSENT\033[1;m" ) logging.addLevelName( logging.VALIDATE, "VALIDATE" ) -logging.addLevelName( logging.STATE_CHANGE, "STATE" ) +logging.addLevelName( logging.STATE_CHANGE, "\033[1;37;44mSTATE\033[1;m" ) + +# 1;37;44 # print '\033[1;36mGENERATE\033[1;m' # print '\033[1;36mCyan like Caribbean\033[1;m' ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/logging.conf#5 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/StringField.py#3 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/__init__.py#8 (text+ko) ==== @@ -3,7 +3,7 @@ import struct import socket import sys - +import re from pcs.packets.ipv4 import ipv4 from pcs.packets.tcp import tcp from pcs.packets.tcpv6 import tcpv6 @@ -41,3 +41,14 @@ def inet_atol( ipString ): return inet_ntol( socket.inet_aton( ipString ) ) + +def wireSharkFormatBytes(x): + twoBits = r"(\w\w)" + octet = "((%s ){8})" % twoBits + twoBytes = "((%s ){2})" % octet + + x = re.sub(twoBits,r"\1 ",x) + x = re.sub(octet,r"\1 ",x) + x = re.sub(twoBytes,r"\1\n",x) + return x + ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/backup.tar#3 (binary) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/checksum.py#2 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/decorators.py#4 (text+ko) ==== @@ -186,7 +186,7 @@ ''' ops = func() or {} - name=ops.get('prefix','_')+func.__name__ # property name + name=ops.get('name') or ops.get('prefix','_')+func.__name__ # property name fget=ops.get('fget',lambda self:getattr(self, name)) fset=ops.get('fset',lambda self,value:setattr(self,name,value)) fdel=ops.get('fdel',lambda self:delattr(self,name)) @@ -241,7 +241,7 @@ return property (fget, fset, fdel, func.__doc__) -def uint(max=2**32): +def uint(limit=2**32): ''' >>> from pcsextension.decorators import * >>> lim = 5 @@ -272,4 +272,4 @@ fset = lambda self,value: setattr(self, name, (value % max)) fdel = lambda self: delattr(self, value) return property(fget, fset, fdel) - return unsignedInteger + return unsignedInteger ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/field.py#2 (text+ko) ==== @@ -5,69 +5,118 @@ ''' class Field( object ): + ''' + Base class for an extensible field class. Allows the field to be represented + in various formats with ease, as needed by the developer. This allows byte- + order and representation issues to be alleviated, as well as string-of-bytes + representation to be simplified for any byte order. + ''' name = "" value = None width = 8 networkByteOrder = False - def __init__( self, default = 0, width = None, networkByteOrder = False ): + def __init__( self, default = 0, width = 8, networkByteOrder = False ): self.width = width self.networkByteOrder = networkByteOrder + if isinstance( default, int ): self.setInteger( default ) if isinstance( default, str ): self.setAscii( default ) + if isinstance( default, Field): + self.setNetworkBytes(default.getNetworkBytes()) def setAscii( self, x ): + ''' + Set the value, given its textual representation, e.g. '12345' or '127.0.0.1' + ''' pass def getAscii( self ): + ''' + @see setAscii + ''' return "" def setInteger( self, x ): + ''' + Set the value, given its numeric representation in host-byte-order, e.g. 12345. + ''' pass def getInteger( self ): + ''' + @see setInteger + ''' return 0 def setNetworkInteger( self, x ): + ''' + Set the value, given its numeric representation in network-byte-order, e.g. 14640 + ''' pass def getNetworkInteger( self ): + ''' + @see setNetworkInteger + ''' return 0 def setBytes( self, x ): + ''' + Set the value as a string of bytes in host-byte-order, e.g. '\x30\x39' + ''' pass def getBytes( self ): + ''' + @see setBytes + ''' return "" - def getBytesShifted( self, shiftedBits ): - pass - def setNetworkBytes( self, x ): + ''' + Sets the value as a string of bytes in network-byte-order, e.g. '\x39\x30' + ''' pass def getNetworkBytes( self ): + ''' + @see setNetworkBytes + ''' return "" - def getNetworkBytesShifted( self, shiftedBits ): - return getNetworkBytes() - def setPCS( self, x ): + ''' + Sets the value in the format native to the PCS (Packet Construction + Set) library. For example, network-byte-order integer for TCP ports, + or byte-string for Ethernet addresses. + ''' pass - def getPCS( self, x ): + def getPCS( self ): + ''' + @see setPCS + ''' return self.getNetworkBytes() def encode( self ): + ''' + Returns the same value as getBytes/getNetworkBytes as instructed by + __init__ or the networkByteOrder property. + ''' if self.networkByteOrder: return self.getNetworkBytes() else: return self.getBytes() def decode( self, bytes ): + ''' + Calls setBytes/setNetworkBytes as instructed by __init__ or the + networkByteOrder property. + ''' if self.networkByteOrder: self.setNetworkBytes( bytes ) else: @@ -88,41 +137,15 @@ return False def bound( self ): - if width == None: + ''' + Ensures that the value returned by getBytes() is no longer than + self.width bits and that the value returned by getInteger is no + larger than an integer of self.width bits would allow. + ''' + if self.width == None: return - elif width == 8: - if ( width == 8 and len( self.getBytes() ) > width * 8 ) or \ - ( getInteger() > ( ( 2 ** self.width ) - 1 ) ): - raise Exception, "Value exceeds bit-width" - - def __add__( self, x ): - - if isinstance( x, Field ): - f = Field( width = self.width + x.width ) - bytes = self.getNetworkBytes() - nextBytes = x.getNetworkBytes() - - # If either of the widths are NOT even mod 8 - # ord - # chr - if self.width % 8 != 0: - - lastByte = bytes[:-1] - - # Will the field fit in the remaining bits of the last byte - # In the below example 'X' = the appended bytes, 'O' = existing, current bytes - # Bit 1 2 3 4 5 6 7 8 - # O O O - # X X X X X - # O O O X X X X X - if x.width <= ( 8 - self.width ): - nextBits = ord( nextBytes[0] ) >> self.width - nextBits = nextBits | ord( lastByte ) - joined = struct.pack( "!B%d", nextBits ) - f.setNetworkBytes( self.getNetworkBytes()[:-1] + joined ) - - # The field will not fit in the remaining space - - else: - f.setNetworkBytes( self.getNetworkBytes() + x.getNetworkBytes() ) + elif self.width == 8: + if ( self.width == 8 and len( self.getBytes() ) > self.width * 8 ) or \ + ( self.getInteger() > ( ( 2 ** self.width ) - 1 ) ): + raise Exception, "Value exceeds bit-width %i" % self.width ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/hwAddress.py#4 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/ipAddress.py#5 (text+ko) ==== @@ -20,6 +20,12 @@ def __init__( self, default = 0, width = None, networkByteOrder = False, version = AF_INET ): self.version = version Field.__init__( self, width = width, default = default, networkByteOrder = networkByteOrder ) + + # Override the default Field.__init__ behavior. If the string's length is 4, it is obviously + # a byte-string as opposed to an IP address. + if type(default) == str: + if len(default) == 4: + self.nbo = default def setAscii( self, x ): self.nbo = inet_pton( self.version, x ) ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/networkPort.py#4 (text+ko) ==== @@ -30,10 +30,10 @@ return str( self.ho ) def setBytes( self, bytes ): - self.ho = unpack( "H", bytes ) + self.ho = unpack( "H", bytes )[0] def setNetworkBytes( self, bytes ): - self.ho = unpack( "!H", bytes ) + self.ho = unpack( "!H", bytes )[0] def getBytes( self ): return pack( "H", self.ho ) @@ -51,7 +51,11 @@ self.ho = ntohs( x ) def getNetworkInteger( self ): + print "%s %s" % (type(self.ho), self.ho) return htons( self.ho ) + + def getPCS(self): + return self.getInteger() def __eq__( self, x ): if isinstance( x, int ): ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/payload.py#4 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/pcsextension/pseudoipv4.py#3 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/segmentBuffer.py#3 (text+ko) ==== @@ -4,7 +4,9 @@ @author: zach ''' -class segmentBuffer(list): +from pcsextension.decorators import prop + +class segmentBuffer(object): ''' The segmentBuffer class allows pseudo-random access to a list, given an initial offset, and maximum offset. The benefit of this is that we get @@ -14,103 +16,219 @@ using 4GB+ of memory, or use the segmentBuffer class. Example: - >>> x = segmentBuffer(base=100,max=110) - >>> x += ['a','b','c'] - >>> len(x) - 3 - >>> x[100:102] - ['a','b','c'] - - >>> y = segmentBuffer(base = 5, max=10) - >>> y += range(0,10) - >>> y - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - >>> y[5] + >>> from segmentBuffer import * + >>> sb = segmentBuffer(base=10, limit=15) + >>> sb += range(8) + >>> sb[10] # The first item is at [10] 0 - >>> y[5:4] - [0, 1, 2, 3, 4, 5, 6, 7, 8] - >>> y[5:5] - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - - + >>> sb[11] # The second item is at [11] + 1 + >>> sb # However, the items are in the proper order + [0, 1, 2, 3, 4, 5, 6, 7] + >>> sb[10:] # And are properly sliced + [0, 1, 2, 3, 4, 5, 6, 7] + >>> sb[10:2] # And the slices wrap-around at limit + [0, 1, 2, 3, 4, 5, 6] + >>> sb[2:10] # And slices stop when it hits a gap. + [7] + >>> sb == sb[10:] # Truth works just fine. + True + >>> sb += 2 # The offset is incremented easily + >>> sb # Notice that the first two items are deleted + [2, 3, 4, 5, 6, 7] + >>> len(sb) # The length indeed goes down 8->2 + 6 + >>> sb += range(100,200) + >>> len(sb) # Adding 100 items keeps the correct length + 15 + >>> sb # Only items up to the limit are added + [2, 3, 4, 5, 6, 7, 100, 101, 102, 103, 104, 105, 106, 107, 108] + >>> sb2 = sb + range(300,400) + >>> sb is sb2 # Addition operator returns a new object. + False + >>> sb2 += 3 # The other object can be incremented + >>> [i for i in sb if i not in sb2] + [2, 3, 4] # Just an example to show the difference + >>> sb[12:15] # This shows that the items were taken off the front + [2, 3, 4] + >>> sb[12:2] + [2, 3, 4, 5, 6] + >>> sb2[12:2] # The indexes for the remaining items do not change + [5, 6] # Although the deleted items are gone. + >>> sb + [2, 3, 4, 5, 6, 7, 100, 101, 102, 103, 104, 105, 106, 107, 108] + >>> sb2 + [5, 6, 7, 100, 101, 102, 103, 104, 105, 106, 107, 108] ''' __MAX = (2**31) - 1 + limit = __MAX + buffer = [] + + @prop + def base(): + ''' + Base index. Advancing the base index will remote items from the front of the list. + The base can only be incremented in value, and will be wrapped at 'limit'. + + ''' + return {'fset': lambda self,x: self.setBase(x)} _base = 0 - _max = __MAX + + @prop + def nextIndex(): + return {'fget': lambda self: self.getNextIndex(),# (len(self) + self.base), + 'fset': None} + + def getNextIndex(self): + return len(self)+self.base + + def setBase(self, x): + ''' + Modifies the base. Erases any existing items up to, but excluding, the + new base. + ''' + # print "Setting base to %i" % x + # print "... %s if %s < %s else %s" % (self._getIndex(x), x, len(self), len(self)) + # deleteUpToOffset = self._getIndex(x) if x < len(self) else len(self) + deleteUpToOffset = min(self._getIndex(x),len(self)) + # print "Deleting up to offset %s" % deleteUpToOffset + self._base = x % self.limit + # print "_base is now %i" % self._base + # print "Buffer before delete: %s" % self.buffer + del self.buffer[0:deleteUpToOffset] + # print "Buffer after delete: %s" % self.buffer + + def __contains__(self,x): + return self.buffer.__contains__(x) + + def __iadd__(self,x): + ''' + Adding an integer has the effect of advancing the 'base', and + deleting the leading elements. 'base' is modulo'd by 'limit' so + that it will properly wrap around to zero if needed, while retaining + the same indexes for items that are not deleted. + + NOTE: If the list is full, no more items can be 'added'. + ''' + if type(x) in (int,long): + self.base += x + elif type(x) in (list,tuple,segmentBuffer): + + self.buffer += x + + # Prevent the list from being extended too long. + if len(self) > self.limit: + # Note that we are referring to the 'limit'th item directly, not + # its redirected index. This is because we are actually deleting + # items beyond the boundary that should not exist. + del self.buffer[self.limit:self.__MAX] + + + # retVal = segmentBuffer(base=self.base, limit=self.limit) + # retVal.buffer = self.buffer[:] + + return self + + def __add__(self,x): + tmp = segmentBuffer(self) + tmp += x + return tmp + + def __len__(self): + return self.buffer.__len__() def __eq__(self, x): - if not isinstance(x,list) and not isinstance(x,tuple): + ''' + Compares to a list or tuple object. + For whatever reason, list.__eq__ doesn't evaluate properly. + ''' + # Only compare to list, tuples, or the same class + if type(x) not in (list,tuple,type(self)): return False + # If we're not the same length, DEF not the same. if len(self) != len(x): return False - for i in range(0,len(self)): - if self[i] != x[i]: + # If we are comparing against a list or tuple, compare it to + # our internal buffer. + comparisonList = self.buffer + + # Otherwise, we are comparing against a segmentBuffer. Compare + # it to ourself. + if type(x) == type(self): + + # Check the other fields + if x.limit != self.limit or x.base != self.base: + return False + + comparisonList = self + + # Iterate over each item + for i in range(len(self)): + if comparisonList[i] != x[i]: return False - + + # Haven't found any differences. return True - def __init__(self, base=None, max=None): - list.__init__(self) + def __init__(self, copyList=None, base=0, limit=2**32): + if type(copyList) == segmentBuffer: + self.buffer = copyList.buffer[:] + self.base = copyList.base + self.limit = copyList.limit + + # Don't proceed to set other values below. Just use the + # copied values. + return + elif type(copyList) in (list,tuple): + self.buffer = copyList + else: + self.buffer = [] - if base > 0: - self._base = base - if max > 0: - self._max = max + if base >= 0: + self.base = base + if limit >= 0: + self.limit = limit def __delslice__(self, i, j): - # print "delslice(%s,%s)" % (i,j) - for item in range(i,j): - del self[item] + for (ii,jj) in self._getIndices(i, j): + self.buffer.__delslice__(ii,jj) def __delitem__(self,i): - # print "delitem(%s)" % (i) - index = self._getIndex(i) - if index is None: - raise IndexError, "list index out of range" - - list.__delitem__(self, index) + self.buffer.__delitem__(index) def __getslice__(self, i, j): - # # print "getslice(%s,%s)" % (i,j) # return [list.__getitem__(self,item) for item in self._getIndices(i, j)] # return [self[item] for item in range(i,j) ] - retVal = [] - for (a,b) in self._getIndices(i, j): - retVal += list.__getslice__(self, a, b) - return retVal + retVal = [] + for (a,b) in self._getIndices(i, j): + retVal += self.buffer.__getslice__(a, b) + return retVal def __getitem__(self,i): index = self._getIndex(i) if index is None: index = self.__MAX - return list.__getitem__(self,index) + return self.buffer.__getitem__(index) def __setslice__(self, i, j, k): - # print "setslice(%s,%s,%s)" % (i,j,k) - #for x,i in enumerate(self._getIndices(i, j)): - # self.__setitem__(x,k[i]) - indices = self._getIndices(i, j) - offset = 0 - print indices - for (a,b) in indices: num = b-a - list.__setslice__(self, a, b, k[offset:offset+num]) + self.buffer.__setslice__(a, b, k[offset:offset+num]) offset += num def __setitem__(self, i, x): index = self._getIndex(i) if index is None: index = self.__MAX - list.__setitem__(self, index, x) + self.buffer.__setitem__(index, x) def _getIndices(self, i, j): @@ -133,7 +251,7 @@ # else: # jj = self._getIndex(j) # if jj is None: -# jj = self._max - self._base +# jj = self.limit - self.base retVal = () @@ -160,92 +278,70 @@ Retrieves the actual index of an item. ''' - # For this method, assume that base=5, max=10. - print "getIndex(%i)" % i + # For this method, assume that base=5, limit=10. retVal = None # Special cases defined for quickness. # The base is always at ZERO offset. - if i == self._base: + if i == self.base: return 0 - # 'Max' is the "END" of the list, AND it is the 0th item. + # 'limit' is the "END" of the list, AND it is the 0th item. # '__MAX' is the absolute maximum value, and is the value provided # when we are given an empty-ended slice, i.e [3:] - elif i == self._max or i == self.__MAX: - return (self._max - self._base) - + elif i == self.limit: + return (self.limit - self.base) + elif i == self.__MAX: + return len(self) # elif i == self.__MAX: -# return self._getIndex(self._max) +# return self._getIndex(self.limit) # i.e. self[12], should refer to self[2]. # i.e. self[10], should refer to self[0] - elif self._max < i: - return self._getIndex(i - self._max) - # retVal = self._getIndex(i - self._max) + elif self.limit < i: + return self._getIndex(i - self.limit) + # retVal = self._getIndex(i - self.limit) # i.e. self[6] is stored at [1], or i-base. - elif self._base < i < self._max: - retVal = i - self._base + elif self.base < i < self.limit: + retVal = i - self.base - # i.e. self[2] is stored at [10+2], or max+i - elif 0 <= i < self._base: - retVal = self._getIndex(self._max) + i + # i.e. self[2] is stored at [10+2], or limit+i + elif 0 <= i < self.base: + retVal = self._getIndex(self.limit) + i # i.e. self[-1] is stored at the real self[-1]. elif i < 0: - retVal = self._getIndex(self._max + i) # Note we are adding a negative + retVal = len(self) + i + + if retVal > len(self): + return None return retVal -# -# if i == self.__MAX: -# # return self._getIndex(self._max - 1) + 1 -# return len(self) -# -# if i == self._max: -# return self._max - self._base -# -# # Negative indices count from the back... -# if i < 0: -# # Make sure it's not TOO negative... -# if abs(i) > self._max: -# retVal = self._getIndex(i + self._max) -# else: -# retVal = len(self) + i # Note that we "add" a negative -# -# elif self._max <= i: -# # retVal = None # Still none... -# return -# -# # If it's less than the base, then the index 0 is the max'th item, and -# # go from there. -# elif i < self._base: -# # Wrap... -# retVal = self._getIndex(self._max) + i -# -# # If it's over the max, decrement and re-do. -# # elif self._max <= i: -# # retVal = self._getIndex(i - self._max) -# -# # The N'th item is offset from the base. -# elif self._base <= i < self._max: -# retVal = i - self._base -# -# else: -# print 'error: could not calculate index for %s' % i -# # print "%s -> %s" % (i,retVal) -# -# # Don't return an out-of-bounds index... -# if retVal >= len(self): -# # print "OOB" -# return None -# -# return retVal + #def __repr__(self): + # # return str( [self[i] for i in self._getIndices(0,len(self))] ) + # return str( self.buffer[:] ) + # # return self.__repr__() + def __repr__(self): - print 'repr!!' - # return str( [self[i] for i in self._getIndices(0,len(self))] ) - return str( self[:] ) + return '%s(limit=%i,base=%i,copyList=%s+%s)' % \ + (self.__class__.__name__, self.limit, self.base, self[self.base:0], self[self.limit:] if self._getIndex(0) is not None else []) + + def __iter__(self): + return self.buffer.__iter__() + + def update(self, newBuffer): + + if newBuffer is self: + return self + + if type(newBuffer) == type(self): + # return '... is new buffer' + return newBuffer - def __str__(self): - print 'str!!' - return self.__repr__()+ if type(newBuffer) in (list,tuple): + # return '... is just a list or tuple' + self.buffer = newBuffer[:] + + return self + ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/sniffLocalhost.py#5 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/tcpConstructor.py#6 (text+ko) ==== ==== //depot/projects/soc2009/zjriggl_tcpregression/src/tcpregression/tcpFilter.py#7 (text+ko) ==== @@ -10,23 +10,31 @@ from pcs.packets.tcp import tcp from pcs.packets.tcpv6 import tcpv6 from pcs.packets.ethernet import ethernet +from pcsextension import wireSharkFormatBytes from pcsextension.ipAddress import IpAddress from pcsextension.networkPort import NetworkPort from pcsextension import findIpLayer, findTcpLayer +from pcsextension.decorators import prop import pprint +import binascii +from threading import RLock class tcpFilter( object ): log = None pcapHandle = None doRead = False - + lock = RLock() + @prop def interface(): - return {'doc': 'Interface used with the TCP Filter. If this interface is different from the' - ' current interface, the current one is closed, and the new one is opened automatically.', - 'fset': lambda self, x: self.openInterface( x ) } - self._interface = None - + ''' + Interface used with the TCP Filter. If this interface is different + from the current interface, the current one is closed, and the new + one is opened automatically. + ''' + return {'fset': lambda self, x: self.openInterface( x ) } + _interface = None + def __init__( self, interfaceName ): self.log = tcplog( self ) self.interface = interfaceName @@ -34,73 +42,143 @@ def openInterface( self, interfaceName ): # Is it already opened with this interface? if self.interface is interfaceName: - log.info( 'Tried to re - open same interface: % s' % self.interface ) - return - else: - self._interface = interfaceName + self.log.debug( 'Tried to re-open same interface: % s' % self.interface ) # Open the interface try: - self.pcapHandle = PcapConnector( self.interface ) - self.log.info( "Opened %s" % self.interface ) - # self.pcapHandle = IP4Connector(); + self.pcapHandle = PcapConnector( interfaceName ) + self.log.info( "Opened %s" % interfaceName ) + self._interface = interfaceName except: - self.log.error( "Could not open interface %s" % self.interface ) + self.log.error( "Could not open interface %s" % interfaceName ) + + def getPcapConnector(self): + ''' + Returns the PCAP handle. + ''' + return self.pcapHandle def read( self ): + ''' + Reads a packet in the form of a string of bytes from the PCAP handle. + ''' return self.pcapHandle.readpkt() def write( self, bytes ): - self.log.pktsent( pprint.pformat( bytes ) ) - self.pcapHandle.write( bytes, len( bytes ) ) + ''' + Writes a string of bytes to the PCAP handle. + ''' + return self.pcapHandle.write( bytes, len( bytes ) ) + + def setBlocking(self, block=False): + ''' + Sets the blocking mode on the PCAP handle. + ''' + self.log.debug("Setting blocking mode to %s" % block) + self.pcapHandle.file.setnonblock(block) + + def packetDestinedForIP(self, packet, ip): + ''' + Returns True if the provided packet has a IP layer and its destination + is the provided IP address. + Returns False otherwise. + ''' + # If the IP address is a string ("127.0.0.1") or byte array ('\x7f\x00\x00\x01') + # we need to convert it into an integer representation of the same. + ip = IpAddress(ip).getPCS() + + ipLayer = findIpLayer(packet) + if ipLayer is None: + return False + + if ip == ipLayer.dst: + return True + + return False + + def packetDestinedForPort(self, packet, port): + ''' + Returns True if the provided packet has a TCP layer and its destination + is the provided port. + Returns False otherwise. + ''' + port = NetworkPort( port ).getPCS() + + tcpLayer = findTcpLayer( packet ) + if tcpLayer is None: + return False + + if port == tcpLayer.dport: + return True + + return False + - def readFilteredByIP( self, ip ): + def readFilteredByIP( self, ip, block=True ): """ - Reads packets until a packet is found going either to or from the specified IP address - is discovered. Returns the first matching packet. + Reads packets until a packet is found that is destined to the specified + IP address is discovered. Returns the first matching packet. @param ip IpAddress or dotted-quad string - @return A pcs.Packet object + @return A pcs.Packet object, or None if there are no packets on the + queue and non-blocking IO is used. """ - -# if isinstance(ipAddress,int): -# ipAddress = intToBytes(ipAddress) - - # If the IP address is a string ("127.0.0.1") or byte array ('\x7f\x00\x00\x01') - # we need to convert it into an integer representation of the same. - if isinstance( ip, str ): - tmp = IpAddress() - tmp.setAscii( ip ) - ip = tmp - + + self.log.debug("Waiting on lock") + self.lock.acquire(blocking=True) + self.log.debug("Have lock") + self.setBlocking(block) + + packet = None + while True: + print "loop" packet = self.read() + + # None will only return [1] on error or [2] if using asynchronous + # I/O and there are no waiting packets. + if packet is None or self.packetDestinedForIP(packet, ip): + break + + self.lock.release() + self.log.debug("Released lock") + + if packet is None: + self.log.debug("Returning NONE") + + return packet - ipLayer = findIpLayer( packet ) - - if ipLayer == None: - continue - - # srcIP.setPCS( ipLayer.src ) - # dstIP.setPCS( ipLayer.dst ) - - if ipLayer.src == ip.getPCS() or ipLayer.dst == ip.getPCS(): - return packet - - def readFilteredByTuple( self, ipAddress, port ): + def readFilteredByTuple( self, ipAddress, port, block=True ): """ - Reads packets until a packet is found going either to or from [1] the specified - IP address and [2] the specified port. Returns the first matching packet. + Reads packets until a packet is found that is destined to: + [1] the specified IP address + [2] the specified port. + Returns the first matching packet. + @param IpAddress object or dotted-quad string ('127.0.0.1') @param NetworkPort object or integer port number. - @return A pcs.Packet object. >>> TRUNCATED FOR MAIL (1000 lines) <<<