r115 - in /debtorrent/trunk: ./ DebTorrent/ DebTorrent/BT1/

camrdale-guest at users.alioth.debian.org camrdale-guest at users.alioth.debian.org
Mon Jun 18 05:49:26 UTC 2007


Author: camrdale-guest
Date: Mon Jun 18 05:49:26 2007
New Revision: 115

URL: http://svn.debian.org/wsvn/debtorrent/?sc=1&rev=115
Log:
More documentation.

Modified:
    debtorrent/trunk/DebTorrent/BT1/Downloader.py
    debtorrent/trunk/DebTorrent/BT1/DownloaderFeedback.py
    debtorrent/trunk/DebTorrent/BT1/Filter.py
    debtorrent/trunk/DebTorrent/BT1/fakeopen.py
    debtorrent/trunk/DebTorrent/RateMeasure.py
    debtorrent/trunk/DebTorrent/RawServer.py
    debtorrent/trunk/DebTorrent/SocketHandler.py
    debtorrent/trunk/DebTorrent/download_bt1.py
    debtorrent/trunk/DebTorrent/iprangeparse.py
    debtorrent/trunk/DebTorrent/parsedir.py
    debtorrent/trunk/DebTorrent/selectpoll.py
    debtorrent/trunk/DebTorrent/subnetparse.py
    debtorrent/trunk/DebTorrent/torrentlistparse.py
    debtorrent/trunk/TODO

Modified: debtorrent/trunk/DebTorrent/BT1/Downloader.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Downloader.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Downloader.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Downloader.py Mon Jun 18 05:49:26 2007
@@ -822,7 +822,7 @@
 #            self.picker.seed_seen_recently()
         self.disconnectedseeds[id]=clock()
 
-#	def expire_disconnected_seeds(self):
+#    def expire_disconnected_seeds(self):
 
     def num_disconnected_seeds(self):
         """Expire old disconnected seeds and calculate the recent number.

Modified: debtorrent/trunk/DebTorrent/BT1/DownloaderFeedback.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/DownloaderFeedback.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/DownloaderFeedback.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/DownloaderFeedback.py Mon Jun 18 05:49:26 2007
@@ -1,8 +1,16 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Gather and display statistics about the download.
+
+ at type INIT_STATE: C{tuple} of C{string}
+ at var INIT_STATE: the state to display, 'L'/'R' = locally/remotely initiated, 
+    '+' = encrypted
+
+"""
 
 from cStringIO import StringIO
 from urllib import quote
@@ -17,9 +25,81 @@
 INIT_STATE = (('R','R+'),('L','L+'))
 
 class DownloaderFeedback:
+    """Gather and display statistics about the download.
+    
+    @type choker: L{Choker.Choker}
+    @ivar choker: the Choker instance for the download
+    @type httpdl: L{HTTPDownloder.HTTPDownloader}
+    @ivar httpdl: the HTTP downloader instance used by the download
+    @type add_task: C{method}
+    @ivar add_task: the method to call to schedule future tasks
+    @type upfunc: C{method}
+    @ivar upfunc: the method to call to get the upload rate
+    @type downfunc: C{method}
+    @ivar downfunc: the method to call to get the download rate
+    @type ratemeasure: L{DebTorrent.RateMeasure.RateMeasure}
+    @ivar ratemeasure: the download rate measurement for the download
+    @type leftfunc: C{method}
+    @ivar leftfunc: the method to call to determine the amount of data 
+            left to download
+    @type file_length: C{long}
+    @ivar file_length: the total length of the download
+    @type finflag: C{threading.Event}
+    @ivar finflag: flag to indicate when the download is complete
+    @type sp: C{threading.Event}
+    @ivar sp: whether to include the per-connection info in the gathered data
+    @type statistics: L{Statistics.Statistics}
+    @ivar statistics: the statistics gatherer for the download
+    @type lastids: C{list} of C{string}
+    @ivar lastids: the peer IDs that were found the last time
+    @type spewdata: unknown
+    @ivar spewdata: not used
+    @type doneprocessing: C{threading.Event}
+    @ivar doneprocessing: flag that is set when the previous display is complete
+    @type displayfunc: C{method}
+    @ivar displayfunc: the method to call to display the gathered data
+    @type interval: C{int}
+    @ivar interval: the number of seconds between displays of the gathered data
+    
+    """
+    
     def __init__(self, choker, httpdl, add_task, upfunc, downfunc,
             ratemeasure, leftfunc, file_length, finflag, sp, statistics,
             statusfunc = None, interval = None):
+        """Initialize the instance.
+        
+        @type choker: L{Choker.Choker}
+        @param choker: the Choker instance for the download
+        @type httpdl: L{HTTPDownloder.HTTPDownloader}
+        @param httpdl: the HTTP downloader instance used by the download
+        @type add_task: C{method}
+        @param add_task: the method to call to schedule future tasks
+        @type upfunc: C{method}
+        @param upfunc: the method to call to get the upload rate
+        @type downfunc: C{method}
+        @param downfunc: the method to call to get the download rate
+        @type ratemeasure: L{DebTorrent.RateMeasure.RateMeasure}
+        @param ratemeasure: the download rate measurement for the download
+        @type leftfunc: C{method}
+        @param leftfunc: the method to call to determine the amount of data 
+            left to download
+        @type file_length: C{long}
+        @param file_length: the total length of the download
+        @type finflag: C{threading.Event}
+        @param finflag: flag to indicate when the download is complete
+        @type sp: C{threading.Event}
+        @param sp: unknown
+        @type statistics: L{Statistics.Statistics}
+        @param statistics: the statistics gatherer for the download
+        @type statusfunc: C{method}
+        @param statusfunc: the method to call to automatically display the gathered data
+            (optional, default is to not automatically display anything)
+        @type interval: C{int}
+        @param interval: the number of seconds between displays of the gathered data
+            (optional, but must be set if the L{statusfunc} is set)
+        
+        """
+        
         self.choker = choker
         self.httpdl = httpdl
         self.add_task = add_task
@@ -40,6 +120,13 @@
         
 
     def _rotate(self):
+        """Rotate the list of connections so it starts roughly where it did before.
+        
+        @rtype: C{list} of L{Connecter.Connection}
+        @return: the connections from peers to the client
+        
+        """
+        
         cs = self.choker.connections
         for id in self.lastids:
             for i in xrange(len(cs)):
@@ -48,6 +135,13 @@
         return cs
 
     def spews(self):
+        """Get information about the currently connected peers.
+        
+        @rtype: C{list} of C{dictionary}
+        @return: information about all the current peer connections
+        
+        """
+        
         l = []
         cs = self._rotate()
         self.lastids = [c.get_id() for c in cs]
@@ -101,6 +195,15 @@
 
 
     def gather(self, displayfunc = None):
+        """Gather the information about the download.
+        
+        @type displayfunc: unknown
+        @param displayfunc: not used (optional)
+        @rtype: C{dictionary}
+        @return: various information about the download
+        
+        """
+        
         s = {'stats': self.statistics.update()}
         if self.sp.isSet():
             s['spew'] = self.spews()
@@ -126,6 +229,13 @@
 
 
     def display(self, displayfunc):
+        """Gather the information about the download and display it.
+        
+        @type displayfunc: C{method}
+        @param displayfunc: the method to call with the gathered information
+        
+        """
+        
         if not self.doneprocessing.isSet():
             return
         self.doneprocessing.clear()
@@ -148,10 +258,20 @@
 
 
     def autodisplay(self, displayfunc, interval):
+        """Initialize the automatic displayer.
+        
+        @type displayfunc: C{method}
+        @param displayfunc: the method to call to display the gathered data
+        @type interval: C{int}
+        @param interval: the number of seconds between displays of the gathered data
+        
+        """
+        
         self.displayfunc = displayfunc
         self.interval = interval
         self._autodisplay()
 
     def _autodisplay(self):
+        """Call the displayer and reschedule."""
         self.add_task(self._autodisplay, self.interval)
         self.display(self.displayfunc)

Modified: debtorrent/trunk/DebTorrent/BT1/Filter.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Filter.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Filter.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Filter.py Mon Jun 18 05:49:26 2007
@@ -1,15 +1,54 @@
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
 
+"""Does nothing."""
+
 class Filter:
+    """Does nothing.
+    
+    @type callback: unknown
+    @ivar callback: unknown
+    
+    """
+    
     def __init__(self, callback):
+        """Initialize the instance.
+        
+        @type callback: unknown
+        @param callback: unknown
+        
+        """
+        
         self.callback = callback
 
     def check(self, ip, paramslist, headers):
+        """Returns None.
+        
+        @type ip: unknown
+        @param ip: unknown
+        @type paramslist: unknown
+        @param paramslist: unknown
+        @type headers: unknown
+        @param headers: unknown
+        @rtype: unknown
+        @return: None
+        
+        """
 
         def params(key, default = None, l = paramslist):
+            """Unknown
+            
+            @type key: unknown
+            @param key: unknown
+            @type default: unknown
+            @param default: unknown
+            @type l: unknown
+            @param l: unknown
+            
+            """
+            
             if l.has_key(key):
                 return l[key][0]
             return default

Modified: debtorrent/trunk/DebTorrent/BT1/fakeopen.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/fakeopen.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/fakeopen.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/fakeopen.py Mon Jun 18 05:49:26 2007
@@ -1,27 +1,66 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Fake file handling objects (not used)."""
 
 from string import join
 
 class FakeHandle:
+    """Fake file handles stored in memory.
+    
+    @type name: C{string}
+    @ivar name: the file name
+    @type fakeopen: L{FakeOpen}
+    @ivar fakeopen: the collection of all fake files
+    @type pos: C{int}
+    @ivar pos: the current position within the file
+    
+    """
+    
     def __init__(self, name, fakeopen):
+        """Initialize the instance.
+        
+        @type name: C{string}
+        @param name: the file name
+        @type fakeopen: L{FakeOpen}
+        @param fakeopen: the collection of all fake files
+        
+        """
+        
         self.name = name
         self.fakeopen = fakeopen
         self.pos = 0
     
     def flush(self):
+        """Does nothing."""
         pass
     
     def close(self):
+        """Does nothing."""
         pass
     
     def seek(self, pos):
+        """Seek to a position within the file.
+        
+        @type pos: C{int}
+        @param pos: the position to seek to
+        
+        """
         self.pos = pos
     
     def read(self, amount = None):
+        """Read data from the file.
+        
+        @type amount: C{int}
+        @param amount: the amount of data to read
+        @rtype: C{string}
+        @return: the read data
+        
+        """
+        
         old = self.pos
         f = self.fakeopen.files[self.name]
         if self.pos >= len(f):
@@ -34,6 +73,13 @@
             return join(f[old:self.pos], '')
     
     def write(self, s):
+        """Write data to the file.
+        
+        @type s: C{string}
+        @param s: the data to write
+        
+        """
+        
         f = self.fakeopen.files[self.name]
         while len(f) < self.pos:
             f.append(chr(0))
@@ -41,23 +87,66 @@
         self.pos += len(s)
 
 class FakeOpen:
+    """Fake file objects.
+    
+    @type files: C{dictionary} of {C{string}: C{list} of C{char}}
+    @ivar files: the stored file data, keys are file names, values are lists 
+        of characters that are the data
+    
+    """
+    
     def __init__(self, initial = {}):
+        """Initialize the instance.
+        
+        @type initial: C{dictionary}
+        @param initial: the initial files to create
+        
+        """
+        
         self.files = {}
         for key, value in initial.items():
             self.files[key] = list(value)
     
     def open(self, filename, mode):
-        """currently treats everything as rw - doesn't support append"""
+        """Open a new or existing file.
+        
+        Treats everything as read/write, doesn't support append.
+        
+        @type filename: C{string}
+        @param filename: the file name to open
+        @type mode: C{string}
+        @param mode: the file mode to open (not used)
+        
+        """
         self.files.setdefault(filename, [])
         return FakeHandle(filename, self)
 
     def exists(self, file):
+        """Check if the file exists.
+        
+        @type file: C{string}
+        @param file: the file name to check
+        @rtype: C{boolean}
+        @return: whether the file exists
+        
+        """
+        
         return self.files.has_key(file)
 
     def getsize(self, file):
+        """Get the current size of the file.
+        
+        @type file: C{string}
+        @param file: the file name to check
+        @rtype: C{int}
+        @return: the file size
+        
+        """
+        
         return len(self.files[file])
 
 def test_normal():
+    """Test the fake file handling objects."""
     f = FakeOpen({'f1': 'abcde'})
     assert f.exists('f1')
     assert not f.exists('f2')

Modified: debtorrent/trunk/DebTorrent/RateMeasure.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/RateMeasure.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/RateMeasure.py (original)
+++ debtorrent/trunk/DebTorrent/RateMeasure.py Mon Jun 18 05:49:26 2007
@@ -1,8 +1,15 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Simple measurement of the download rate.
+
+ at type FACTOR: C{float}
+ at var FACTOR: the factor to use to adjust for TCP overhead
+
+"""
 
 from clock import clock
 try:
@@ -14,7 +21,31 @@
 FACTOR = 0.999
 
 class RateMeasure:
+    """Simple measurement of the download rate.
+    
+    @type last: C{float}
+    @ivar last: the last time the rate was updated
+    @type time: C{float}
+    @ivar time: the amount of time that has elapsed since data first came in
+    @type got: C{float}
+    @ivar got: the amount of data that's come in so far
+    @type remaining: C{float}
+    @ivar remaining: the number of seconds remaining from the last calculation
+    @type broke: C{boolean}
+    @ivar broke: unused
+    @type got_anything: C{boolean}
+    @ivar got_anything: whether any data has been received yet
+    @type last_checked: C{float}
+    @ivar last_checked: the last time the finishing time was calculated
+    @type rate: C{int}
+    @ivar rate: the last calculated download rate
+    @type lastten: C{boolean}
+    @ivar lastten: whether the download is in the last ten seconds
+    
+    """
+    
     def __init__(self):
+        """Initialize the instance."""
         self.last = None
         self.time = 1.0
         self.got = 0.0
@@ -26,6 +57,13 @@
         self.lastten = False
 
     def data_came_in(self, amount):
+        """Add new data received to the rate.
+        
+        @type amount: C{int}
+        @param amount: the amount of data received
+        
+        """
+        
         if not self.got_anything:
             self.got_anything = True
             self.last = clock()
@@ -33,9 +71,26 @@
         self.update(amount)
 
     def data_rejected(self, amount):
+        """Add new data received to the rate.
+        
+        @type amount: C{int}
+        @param amount: the amount of data received
+        
+        """
+        
         pass
 
     def get_time_left(self, left):
+        """Calculate the amount of time left to complete the download.
+        
+        @type left: C{long}
+        @param left: the amount of data still to be downloaded
+        @rtype: C{float}
+        @return: the number of seconds left in the download
+            (or None if no data has been received)
+        
+        """
+        
         t = clock()
         if not self.got_anything:
             return None
@@ -62,6 +117,13 @@
         return self.remaining
 
     def update(self, amount):
+        """Update the rate with new received data.
+        
+        @type amount: C{int}
+        @param amount: the amount of data received
+        
+        """
+        
         t = clock()
         t1 = int(t)
         l1 = int(self.last)

Modified: debtorrent/trunk/DebTorrent/RawServer.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/RawServer.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/RawServer.py (original)
+++ debtorrent/trunk/DebTorrent/RawServer.py Mon Jun 18 05:49:26 2007
@@ -1,8 +1,15 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Manage connections to and tasks to be run on the server.
+
+ at type READSIZE: C{int}
+ at var READSIZE: the maximum amount of data to read from any sockets
+
+"""
 
 from bisect import insort
 from SocketHandler import SocketHandler, UPnP_ERROR
@@ -22,6 +29,7 @@
 
 
 def autodetect_ipv6():
+    """Detect whether IPv6 connections are supported (not used)."""
     try:
         assert sys.version_info >= (2,3)
         assert socket.has_ipv6
@@ -31,24 +39,96 @@
     return 1
 
 def autodetect_socket_style():
-	if sys.platform.find('linux') < 0:
-		return 1
-	else:
-		try:
-			f = open('/proc/sys/net/ipv6/bindv6only','r')
-			dual_socket_style = int(f.read())
-			f.close()
-			return int(not dual_socket_style)
-		except:
-			return 0
+    """Determine if an IPv6 server socket will also field IPv4 connections."""
+    if sys.platform.find('linux') < 0:
+        return 1
+    else:
+        try:
+            f = open('/proc/sys/net/ipv6/bindv6only','r')
+            dual_socket_style = int(f.read())
+            f.close()
+            return int(not dual_socket_style)
+        except:
+            return 0
 
 
 READSIZE = 32768
 
 class RawServer:
+    """Manage connections and tasks like a server.
+    
+    Mostly just manages the tasks, any socket related duties are passed on to 
+    the L{SocketHandler.SocketHandler} instance.
+    
+    @type timeout_check_interval: unknown
+    @ivar timeout_check_interval: unknown
+    @type timeout: unknown
+    @ivar timeout: unknown
+    @type servers: unknown
+    @ivar servers: unknown
+    @type single_sockets: unknown
+    @ivar single_sockets: unknown
+    @type dead_from_write: unknown
+    @ivar dead_from_write: unknown
+    @type doneflag: C{threading.Event}
+    @ivar doneflag: flag to indicate the program is to be shutdown
+    @type noisy: C{boolean}
+    @ivar noisy: whether to report exceptions in running the task
+    @type failfunc: C{method}
+    @ivar failfunc: method to call to report failures
+    @type errorfunc: C{method}
+    @ivar errorfunc: method to call to report exceptions
+    @type exccount: unknown
+    @ivar exccount: unknown
+    @type funcs: unknown
+    @ivar funcs: unknown
+    @type externally_added: unknown
+    @ivar externally_added: unknown
+    @type finished: unknown
+    @ivar finished: unknown
+    @type tasks_to_kill: unknown
+    @ivar tasks_to_kill: unknown
+    @type excflag: C{threading.Event}
+    @ivar excflag: the flag to use to indicate an exception has occurred
+    @type sockethandler: L{SocketHandler.SocketHandler}
+    @ivar sockethandler: the handler to use to manage all open sockets
+    
+    """
+    
     def __init__(self, doneflag, timeout_check_interval, timeout, noisy = True,
                  ipv6_enable = True, failfunc = lambda x: None, errorfunc = None,
                  sockethandler = None, excflag = Event()):
+        """Initialize the instance and start the socket handler.
+        
+        @type doneflag: C{threading.Event}
+        @param doneflag: flag to indicate the program is to be shutdown
+        @type timeout_check_interval: C{float}
+        @param timeout_check_interval: seconds to wait between checking if any 
+            connections have timed out
+        @type timeout: C{float}
+        @param timeout: seconds to wait between closing sockets on which 
+            nothing has been received on
+        @type noisy: C{boolean}
+        @param noisy: whether to report exceptions in running the task
+            (optional, defaults to True)
+        @type ipv6_enable: C{boolean}
+        @param ipv6_enable: allow the client to connect to peers via IPv6
+            (optional, defaults to True)
+        @type failfunc: C{method}
+        @param failfunc: method to call to report failures
+            (optional, defaults to not reporting)
+        @type errorfunc: C{method}
+        @param errorfunc: method to call to report exceptions
+            (optional, defaults to not reporting)
+        @type sockethandler: L{SocketHandler.SocketHandler}
+        @param sockethandler: the handler to use to manage all open sockets
+            (optional, defaults to creating a new one)
+        @type excflag: C{threading.Event}
+        @param excflag: the flag to use to indicate an exception has occurred
+            (optional, defaults to using a new flag)
+        
+        """
+        
         self.timeout_check_interval = timeout_check_interval
         self.timeout = timeout
         self.servers = {}
@@ -71,45 +151,165 @@
         self.add_task(self.scan_for_timeouts, timeout_check_interval)
 
     def get_exception_flag(self):
+        """Get the flag used to indicate exceptions.
+        
+        @rtype: C{threading.Event}
+        @return: the exception flag
+        
+        """
+        
         return self.excflag
 
     def _add_task(self, func, delay, id = None):
+        """Add the task to the sorted list of tasks to execute.
+        
+        @type func: C{method}
+        @param func: the task to be run
+        @type delay: C{int}
+        @param delay: the number of seconds to delay before running the task
+        @type id: unknown
+        @param id: an identifier to later find the task by
+        
+        """
+        
         assert float(delay) >= 0
         insort(self.funcs, (clock() + delay, func, id))
 
     def add_task(self, func, delay = 0, id = None):
+        """Add the task to the list of tasks to schedule.
+        
+        @type func: C{method}
+        @param func: the task to be run
+        @type delay: C{int}
+        @param delay: the number of seconds to delay before running the task
+        @type id: unknown
+        @param id: an identifier to later find the task by
+        
+        """
+        
         assert float(delay) >= 0
         self.externally_added.append((func, delay, id))
 
     def scan_for_timeouts(self):
+        """Scan the open sockets for any timeouts."""
         self.add_task(self.scan_for_timeouts, self.timeout_check_interval)
         self.sockethandler.scan_for_timeouts()
 
     def bind(self, port, bind = '', reuse = False,
                         ipv6_socket_style = 1, upnp = False):
+        """Bind to listen on a single port.
+        
+        @type port: C{int}
+        @param port: the port to listen on
+        @type bind: C{string}
+        @param bind: the IP address to bind to (optional, defaults to all)
+        @type reuse: C{boolean}
+        @param reuse: whether to use SO_REUSEADDR to bind (optional, defaults 
+            to False). This allows the bind to work if the socket is still
+            open in the TIME_WAIT state from a recently shutdown server.
+        @type ipv6_socket_style: C{int}
+        @param ipv6_socket_style: whether an IPv6 server socket will also 
+            field IPv4 connections (optional, defaults to yes)
+        @type upnp: C{boolean}
+        @param upnp: whether to attempt to use UPnP to open the port in a 
+            firewall (optional, defaults to False)
+        
+        """
+        
         self.sockethandler.bind(port, bind, reuse, ipv6_socket_style, upnp)
 
     def find_and_bind(self, minport, maxport, bind = '', reuse = False,
                       ipv6_socket_style = 1, upnp = 0, randomizer = False):
+        """Bind to listen on a single port within a range.
+        
+        @type minport: C{int}
+        @param minport: the minimum port to listen on
+        @type maxport: C{int}
+        @param maxport: the maximum port to listen on
+        @type bind: C{string}
+        @param bind: the addresses to bind to (optional, defaults to the 
+            default IPv6 and IPv4 addreses). Parsed as a comma seperated 
+            list (can be IP addresses or hostnames).
+        @type reuse: C{boolean}
+        @param reuse: whether to use SO_REUSEADDR to bind (optional, defaults 
+            to False). This allows the bind to work if the socket is still
+            open in the TIME_WAIT state from a recently shutdown server.
+        @type ipv6_socket_style: C{int}
+        @param ipv6_socket_style: whether an IPv6 server socket will also 
+            field IPv4 connections (optional, defaults to yes)
+        @type upnp: C{boolean}
+        @param upnp: whether to attempt to use UPnP to open the port in a 
+            firewall (optional, defaults to False)
+        @type randomizer: C{boolean}
+        @param randomizer: whether to randomize the range or use it sequentially
+        @rtype: C{int}
+        @return: the port that was bound to
+        
+        """
+        
         return self.sockethandler.find_and_bind(minport, maxport, bind, reuse,
                                  ipv6_socket_style, upnp, randomizer)
 
     def start_connection_raw(self, dns, socktype, handler = None):
+        """Initiate a new connection to a peer (setting the type of socket).
+        
+        @type dns: (C{string}, C{int})
+        @param dns: the IP address and port number to contact the peer on
+        @type socktype: C{int}
+        @param socktype: the type of socket to open
+        @type handler: unknown
+        @param handler: the data handler to use to process data on the connection
+            (optional, defaults to using the defualt handler)
+        @rtype: L{SocketHandler.SingleSocket}
+        @return: the new connection made to the peer
+        
+        """
+        
         return self.sockethandler.start_connection_raw(dns, socktype, handler)
 
     def start_connection(self, dns, handler = None, randomize = False):
+        """Initiate a new connection to a peer.
+        
+        @type dns: (C{string}, C{int})
+        @param dns: the IP address and port number to contact the peer on
+        @type handler: unknown
+        @param handler: the data handler to use to process data on the connection
+            (optional, defaults to using the defualt handler)
+        @type randomize: C{boolean}
+        @param randomize: whether to randomize the possible sockets or 
+            choose one sequentially
+        @rtype: L{SocketHandler.SingleSocket}
+        @return: the new connection made to the peer
+        
+        """
+        
         return self.sockethandler.start_connection(dns, handler, randomize)
 
     def get_stats(self):
+        """Get some information about the bound interfaces and ports.
+        
+        @rtype: C{dictionary}
+        @return: info about the bound interfaces
+        
+        """
+        
         return self.sockethandler.get_stats()
 
     def pop_external(self):
+        """Add the waiting externally added tasks to the list of tasks to process."""
         while self.externally_added:
             (a, b, c) = self.externally_added.pop(0)
             self._add_task(a, b, c)
 
 
     def listen_forever(self, handler):
+        """Start the server listening on sockets and processing tasks.
+        
+        @type handler: unknown
+        @param handler: the default data handler to use to process data on connections
+        
+        """
+        
         self.sockethandler.set_handler(handler)
         try:
             while not self.doneflag.isSet():
@@ -164,12 +364,21 @@
             self.finished.set()
 
     def is_finished(self):
+        """Check if the server is done listening.
+        
+        @rtype: C{boolean}
+        @return: whether the server is done listeneing
+        
+        """
+        
         return self.finished.isSet()
 
     def wait_until_finished(self):
+        """Wait until the server is done listeneing."""
         self.finished.wait()
 
     def _kill_tasks(self):
+        """Remove the pending list of tasks to remove from those tasks still pending."""
         if self.tasks_to_kill:
             new_funcs = []
             for (t, func, id) in self.funcs:
@@ -179,9 +388,24 @@
             self.tasks_to_kill = []
 
     def kill_tasks(self, id):
+        """Remove tasks from the list of those pending to execute.
+        
+        @type id: unknown
+        @param id: an identifier find the tasks by
+        
+        """
+        
         self.tasks_to_kill.append(id)
 
     def exception(self, kbint = False):
+        """Print an exception that has occurred.
+        
+        @type kbint: C{boolean}
+        @param kbint: whether the exception was from a KeyboardInterrupt 
+            (optional, defaults to False)
+        
+        """
+        
         if not kbint:
             self.excflag.set()
         self.exccount += 1
@@ -195,7 +419,18 @@
                 self.errorfunc(data.getvalue())
 
     def set_handler(self, handler, port = None):
+        """Set the handler to use for a port (or the default handler).
+        
+        @type handler: unknown
+        @param handler: the data handler to use to process data on the port
+        @type port: C{int}
+        @param port: the port to use the handler for
+            (optional, defaults to setting the default handler)
+        
+        """
+        
         self.sockethandler.set_handler(handler, port)
 
     def shutdown(self):
+        """Shutdown the socket handler."""
         self.sockethandler.shutdown()

Modified: debtorrent/trunk/DebTorrent/SocketHandler.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/SocketHandler.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/SocketHandler.py (original)
+++ debtorrent/trunk/DebTorrent/SocketHandler.py Mon Jun 18 05:49:26 2007
@@ -1,8 +1,17 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Handle all sockets.
+
+ at type all: C{int}
+ at var all: all events to check for, both input and output
+ at type UPnP_ERROR: C{string}
+ at var UPnP_ERROR: the error string used for UPnP errors
+
+"""
 
 import socket
 from errno import EWOULDBLOCK, ECONNREFUSED, EHOSTUNREACH
@@ -30,7 +39,44 @@
 UPnP_ERROR = "unable to forward port via UPnP"
 
 class SingleSocket:
+    """Manage a single socket.
+    
+    @type socket_handler: L{SocketHandler}
+    @ivar socket_handler: the collection of all sockets
+    @type socket: C{socket.socket}
+    @ivar socket: the socket to manage
+    @type handler: unknown
+    @ivar handler: the handler to use for all communications on the socket
+    @type buffer: C{list} of C{string}
+    @ivar buffer: the list of data waiting to be written on the socket
+    @type last_hit: C{float}
+    @ivar last_hit: the last time data was received on the socket
+    @type fileno: C{int}
+    @ivar fileno: the file number of the socket
+    @type connected: C{boolean}
+    @ivar connected: whether this socket has received an event yet
+    @type skipped: C{int}
+    @ivar skipped: the number of consecutive writes to the socket that have failed
+    @type ip: C{string}
+    @ivar ip: the IP address to use if one can't be obtained from the socket
+    
+    """
+    
     def __init__(self, socket_handler, sock, handler, ip = None):
+        """
+        
+        @type socket_handler: L{SocketHandler}
+        @param socket_handler: the collection of all sockets
+        @type sock: C{socket.socket}
+        @param sock: the socket to manage
+        @type handler: unknown
+        @param handler: the handler to use for all communications on the socket
+        @type ip: C{string}
+        @param ip: the IP address to use if one can't be obtained from the socket
+            (optional, defaults to 'unknown')
+        
+        """
+        
         self.socket_handler = socket_handler
         self.socket = sock
         self.handler = handler
@@ -49,6 +95,17 @@
                 self.ip = ip
         
     def get_ip(self, real=False):
+        """Get the IP address of the socket.
+        
+        @type real: C{boolean}
+        @param real: whether to try and get the IP address directly from the 
+            socket or trust the one supplied when the instance was created 
+            (optional, defaults to False)
+        @rtype: C{string}
+        @return: the IP address
+        
+        """
+        
         if real:
             try:
                 self.ip = self.socket.getpeername()[0]
@@ -57,16 +114,7 @@
         return self.ip
         
     def close(self):
-        '''
-        for x in xrange(5,0,-1):
-            try:
-                f = inspect.currentframe(x).f_code
-                print (f.co_filename,f.co_firstlineno,f.co_name)
-                del f
-            except:
-                pass
-        print ''
-        '''
+        """Close the socket."""
         assert self.socket
         self.connected = False
         sock = self.socket
@@ -77,12 +125,37 @@
         sock.close()
 
     def shutdown(self, val):
+        """Shutdown the socket.
+        
+        @type val: C{int}
+        @param val: the type of event to shutdown the socket for.
+            0 = reading, 1 = writing, 2 = reading and writing.
+        
+        """
+        
         self.socket.shutdown(val)
 
     def is_flushed(self):
+        """Check if the socket is flushed (no data is waiting to be sent).
+        
+        @rtype: C{boolean}
+        @return: whether the socket is flushed
+        
+        """
+        
         return not self.buffer
 
     def write(self, s):
+        """Write data out on the socket.
+        
+        Adds the data to the buffer of data waiting to be written, then tries 
+        to write the waiting data out.
+        
+        @type s: C{string}
+        @param s: the data to write
+        
+        """
+        
 #        self.check.write(s)
         assert self.socket is not None
         self.buffer.append(s)
@@ -90,6 +163,13 @@
             self.try_write()
 
     def try_write(self):
+        """Try to write waiting data on the socket.
+        
+        Will try to write all buffered data on the socket. If a send fails,
+        the attempt will stop. 3 consecutive failed attempts will cause the
+        socket to be declared dead.
+        
+        """
         if self.connected:
             dead = False
             try:
@@ -121,10 +201,62 @@
             self.socket_handler.poll.register(self.socket, POLLIN)
 
     def set_handler(self, handler):
+        """Set the handler to use for this socket.
+        
+        @type handler: unknown
+        @param handler: the handler to use for all communications on the socket
+        
+        """
+        
         self.handler = handler
 
 class SocketHandler:
+    """The collection of all open sockets.
+    
+    @type timeout: C{float}
+    @ivar timeout: seconds to wait between closing sockets on which 
+            nothing has been received on
+    @type ipv6_enable: C{boolean}
+    @ivar ipv6_enable: allow the client to connect to peers via IPv6
+    @type readsize: C{int}
+    @ivar readsize: the maximum amount of data to read from a socket
+    @type poll: C{select.poll}
+    @ivar poll: the poll object to use to poll the sockets
+    @type single_sockets: C{dictionary} of {C{int}: L{SingleSocket}}
+    @ivar single_sockets: the collection of all open sockets, keys are the 
+        socket's file number
+    @type dead_from_write: C{list} of L{SingleSocket}
+    @ivar dead_from_write: the sockets that have failed due to writing
+    @type max_connects: C{int}
+    @ivar max_connects: the maximum number of sockets to have open at atime
+    @type port_forwarded: C{int}
+    @ivar port_forwarded: the port that was forwarded by UPnP
+    @type servers: C{dictionary} of {C{int}: C{socket.socket}}
+    @ivar servers: the socket listeners, keys are the file numbers
+    @type interfaces: C{list} of C{string}
+    @ivar interfaces: the interfaces that have been bound to
+    @type ports: C{list} of C{int}
+    @ivar ports: the ports that are being listened on
+    @type handlers: C{dictionary} of {C{int}: unknown}
+    @ivar handlers: the handlers that are used for the listened ports, 
+        keys are the ports
+    
+    """
+    
     def __init__(self, timeout, ipv6_enable, readsize = 100000):
+        """Initialize the instance.
+        
+        @type timeout: C{float}
+        @param timeout: seconds to wait between closing sockets on which 
+            nothing has been received on
+        @type ipv6_enable: C{boolean}
+        @param ipv6_enable: allow the client to connect to peers via IPv6
+        @type readsize: C{int}
+        @param readsize: the maximum amount of data to read from a socket
+            (optional, defaults to 100000)
+        
+        """
+        
         self.timeout = timeout
         self.ipv6_enable = ipv6_enable
         self.readsize = readsize
@@ -140,6 +272,7 @@
         self.handlers = {}
 
     def scan_for_timeouts(self):
+        """Check the sockets for timeouts."""
         t = clock() - self.timeout
         tokill = []
         for s in self.single_sockets.values():
@@ -150,6 +283,27 @@
                 self._close_socket(k)
 
     def bind(self, port, bind = '', reuse = False, ipv6_socket_style = 1, upnp = 0):
+        """Bind to listen on a single port.
+        
+        @type port: C{int}
+        @param port: the port to listen on
+        @type bind: C{string}
+        @param bind: the IP address to bind to (optional, defaults to all)
+        @type reuse: C{boolean}
+        @param reuse: whether to use SO_REUSEADDR to bind (optional, defaults 
+            to False). This allows the bind to work if the socket is still
+            open in the TIME_WAIT state from a recently shutdown server.
+        @type ipv6_socket_style: C{int}
+        @param ipv6_socket_style: whether an IPv6 server socket will also 
+            field IPv4 connections (optional, defaults to yes)
+        @type upnp: C{boolean}
+        @param upnp: whether to attempt to use UPnP to open the port in a 
+            firewall (optional, defaults to False)
+        @raise socket.error: if the port can not be bound or UPnP fails
+        
+        """
+        
+
         port = int(port)
         addrinfos = []
         # Don't reinitialize to allow multiple binds
@@ -218,6 +372,34 @@
 
     def find_and_bind(self, minport, maxport, bind = '', reuse = False,
                       ipv6_socket_style = 1, upnp = 0, randomizer = False):
+        """Bind to listen on a single port within a range.
+        
+        @type minport: C{int}
+        @param minport: the minimum port to listen on
+        @type maxport: C{int}
+        @param maxport: the maximum port to listen on
+        @type bind: C{string}
+        @param bind: the addresses to bind to (optional, defaults to the 
+            default IPv6 and IPv4 addreses). Parsed as a comma seperated 
+            list (can be IP addresses or hostnames).
+        @type reuse: C{boolean}
+        @param reuse: whether to use SO_REUSEADDR to bind (optional, defaults 
+            to False). This allows the bind to work if the socket is still
+            open in the TIME_WAIT state from a recently shutdown server.
+        @type ipv6_socket_style: C{int}
+        @param ipv6_socket_style: whether an IPv6 server socket will also 
+            field IPv4 connections (optional, defaults to yes)
+        @type upnp: C{boolean}
+        @param upnp: whether to attempt to use UPnP to open the port in a 
+            firewall (optional, defaults to False)
+        @type randomizer: C{boolean}
+        @param randomizer: whether to randomize the range or use it sequentially
+        @rtype: C{int}
+        @return: the port that was bound to
+        @raise socket.error: if none of the ports in the range can be bound
+        
+        """
+
         e = 'maxport less than minport - no ports to check'
         if maxport-minport < 50 or not randomizer:
             portrange = range(minport, maxport+1)
@@ -241,6 +423,16 @@
 
 
     def set_handler(self, handler, port = None):
+        """Set the handler to use for a port (or the default handler).
+        
+        @type handler: unknown
+        @param handler: the data handler to use to process data on the port
+        @type port: C{int}
+        @param port: the port to use the handler for
+            (optional, defaults to setting the default handler)
+        
+        """
+        
         if port is None:
             self.handler = handler
         else:
@@ -248,6 +440,21 @@
 
 
     def start_connection_raw(self, dns, socktype = socket.AF_INET, handler = None):
+        """Initiate a new connection to a peer (setting the type of socket).
+        
+        @type dns: (C{string}, C{int})
+        @param dns: the IP address and port number to contact the peer on
+        @type socktype: C{int}
+        @param socktype: the type of socket to open
+        @type handler: unknown
+        @param handler: the data handler to use to process data on the connection
+            (optional, defaults to using the defualt handler)
+        @rtype: L{SocketHandler.SingleSocket}
+        @return: the new connection made to the peer
+        @raise socket.error: if the connection fails
+        
+        """
+        
         if handler is None:
             handler = self.handler
         sock = socket.socket(socktype, socket.SOCK_STREAM)
@@ -265,6 +472,22 @@
 
 
     def start_connection(self, dns, handler = None, randomize = False):
+        """Initiate a new connection to a peer.
+        
+        @type dns: (C{string}, C{int})
+        @param dns: the IP address and port number to contact the peer on
+        @type handler: unknown
+        @param handler: the data handler to use to process data on the connection
+            (optional, defaults to using the defualt handler)
+        @type randomize: C{boolean}
+        @param randomize: whether to randomize the possible sockets or 
+            choose one sequentially
+        @rtype: L{SocketHandler.SingleSocket}
+        @return: the new connection made to the peer
+        @raise socket.error: if the connection fails
+        
+        """
+        
         if handler is None:
             handler = self.handler
         if sys.version_info < (2,2):
@@ -295,9 +518,17 @@
 
 
     def _sleep(self):
+        """Sleep for one second."""
         sleep(1)
         
     def handle_events(self, events):
+        """Handle any events that have occurred on the open sockets.
+        
+        @type events: C{list} of (C{int}, C{int})
+        @param events: the socket file descriptors and event types that have occurred on them
+        
+        """
+        
         for sock, event in events:
             s = self.servers.get(sock)
             if s:
@@ -345,6 +576,7 @@
                         s.handler.connection_flushed(s)
 
     def close_dead(self):
+        """Close sockets that have failed to be written."""
         while self.dead_from_write:
             old = self.dead_from_write
             self.dead_from_write = []
@@ -353,10 +585,27 @@
                     self._close_socket(s)
 
     def _close_socket(self, s):
+        """Close an open socket.
+        
+        @type s: L{SingleSocket}
+        @param s: the socket to close
+        
+        """
+        
         s.close()
         s.handler.connection_lost(s)
 
     def do_poll(self, t):
+        """Poll the open sockets.
+        
+        If the poll returns None (which it shouldn't), then 5% of the open 
+        sockets will be closed.
+        
+        @type t: C{float}
+        @param t: seconds to wait for an event before timing out
+        
+        """
+        
         r = self.poll.poll(t*timemult)
         if r is None:
             connects = len(self.single_sockets)
@@ -371,12 +620,20 @@
         return r     
 
     def get_stats(self):
+        """Get some information about the bound interfaces and ports.
+        
+        @rtype: C{dictionary}
+        @return: info about the bound interfaces
+        
+        """
+        
         return { 'interfaces': self.interfaces,
                  'port': self.ports,
                  'upnp': self.port_forwarded is not None }
 
 
     def shutdown(self):
+        """Close all open sockets and servers."""
         for ss in self.single_sockets.values():
             try:
                 ss.close()

Modified: debtorrent/trunk/DebTorrent/download_bt1.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/download_bt1.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/download_bt1.py (original)
+++ debtorrent/trunk/DebTorrent/download_bt1.py Mon Jun 18 05:49:26 2007
@@ -115,7 +115,7 @@
     ('ipv6_enabled', 0,
          'allow the client to connect to peers via IPv6'),
     ('ipv6_binds_v4', autodetect_socket_style(),
-        "set if an IPv6 server socket won't also field IPv4 connections"),
+        "set if an IPv6 server socket will also field IPv4 connections"),
     ('upnp_nat_access', 1,
         'attempt to autoconfigure a UPnP router to forward a server port ' +
         '(0 = disabled, 1 = mode 1 [fast], 2 = mode 2 [slow])'),

Modified: debtorrent/trunk/DebTorrent/iprangeparse.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/iprangeparse.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/iprangeparse.py (original)
+++ debtorrent/trunk/DebTorrent/iprangeparse.py Mon Jun 18 05:49:26 2007
@@ -167,7 +167,7 @@
         @type ip_beg: C{string}
         @param ip_beg: the beginning IP address for the range
         @type ip_end: C{string}
-        @param ip_end: the neding Ip address for the range
+        @param ip_end: the ending IP address for the range
             (optional, defaults to the beginning IP address)
         
         """
@@ -311,7 +311,7 @@
         
         The file to parse must have lines in the format 'whatever:whatever:ip-ip'.
         The 'whatever' will be ignored, and the IP addresses must be in IPv4 
-        format. If the rang is only a single IP address, omit the '-' and the 
+        format. If the range is only a single IP address, omit the '-' and the 
         second 'ip'. Empty lines will be ignored, as will lines beginning with
         '#' which can be used for comments.
         

Modified: debtorrent/trunk/DebTorrent/parsedir.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/parsedir.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/parsedir.py (original)
+++ debtorrent/trunk/DebTorrent/parsedir.py Mon Jun 18 05:49:26 2007
@@ -43,7 +43,7 @@
     @type directory: C{string}
     @param directory: the directory to parse (somewhat recursively)
     @type parsed: C{dictionary}
-    @param parsed: the torrent files that were previously found
+    @param parsed: the cache of all torrent files that were ever found
     @type files: C{dictionary}
     @param files: the files that were previously found
     @type blocked: C{dictionary}
@@ -58,8 +58,9 @@
     @param errfunc: the method to call to print status/warning/error messages
         (optional, defaults to the L{_errfunc} function)
     @rtype: (C{dictionary}, C{dictionary}, C{dictionary}, C{dictionary}, C{dictionary})
-    @return: all the torrents found, all the files found, all the files blocked,
-        the new torrents that were found, the torrents that are now missing
+    @return: the cache of all torrents ever found, all the files found, all 
+        the files blocked, the new torrents that were found, the torrents 
+        that are now missing
     
     """
     

Modified: debtorrent/trunk/DebTorrent/selectpoll.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/selectpoll.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/selectpoll.py (original)
+++ debtorrent/trunk/DebTorrent/selectpoll.py Mon Jun 18 05:49:26 2007
@@ -1,8 +1,25 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Provides socket polling for operating systems that don't support it.
+
+This class is similar to the C{select} module in the standard library, and
+provides the needed functionality for operating systems that don't support
+it in the C{select} module.
+
+ at type POLLIN: C{int}
+ at var POLLIN: There is data to read
+ at type POLLOUT: C{int}
+ at var POLLOUT: Ready for output: writing will not block
+ at type POLLERR: C{int}
+ at var POLLERR: Error condition of some sort
+ at type POLLHUP: C{int}
+ at var POLLHUP: Hung up
+
+"""
 
 from select import select, error
 from time import sleep
@@ -14,11 +31,30 @@
 POLLHUP = 16
 
 class poll:
+    """Polling object to poll open sockets for events.
+    
+    @type rlist: C{list} of C{int}
+    @ivar rlist: the socket file descriptors waiting for data
+    @type wlist: C{list} of C{int}
+    @ivar wlist: the socket file descriptors waiting to send data
+    
+    """
+    
     def __init__(self):
+        """Initialize the instance."""
         self.rlist = []
         self.wlist = []
         
     def register(self, f, t):
+        """Register a socket for polling.
+        
+        @type f: C{int} or C{socket.socket}
+        @param f: the file descriptor, or the socket to get the file descriptor from
+        @type t: C{int}
+        @param t: the events to poll for
+        
+        """
+        
         if type(f) != IntType:
             f = f.fileno()
         if (t & POLLIN):
@@ -31,12 +67,28 @@
             remove(self.wlist, f)
 
     def unregister(self, f):
+        """Unregister a socket from being polled.
+        
+        @type f: C{int} or C{socket.socket}
+        @param f: the file descriptor, or the socket to get the file descriptor from
+        
+        """
+        
         if type(f) != IntType:
             f = f.fileno()
         remove(self.rlist, f)
         remove(self.wlist, f)
 
     def poll(self, timeout = None):
+        """Poll the registered sockets for events.
+        
+        @type timeout: unknown
+        @param timeout: unknown
+        @rtype: C{list} of (C{int}, C{int})
+        @return: the socket file descriptors and event types that have occurred on them
+        
+        """
+        
         if self.rlist or self.wlist:
             try:
                 r, w, e = select(self.rlist, self.wlist, [], timeout)
@@ -53,16 +105,39 @@
         return result
 
 def remove(list, item):
+    """Efficiently remove items from a sorted list.
+
+    If the item is not in the liost, does nothing.
+    
+    @type list: C{list} of C{int}
+    @param list: the list
+    @type item: C{int}
+    @param item: the item to remove
+    
+    """
+    
     i = bisect(list, item)
     if i > 0 and list[i-1] == item:
         del list[i-1]
 
 def insert(list, item):
+    """Efficiently insert items into a sorted list.
+    
+    If the item is already in the list, does nothing.
+    
+    @type list: C{list} of C{int}
+    @param list: the list
+    @type item: C{int}
+    @param item: the item to insert
+    
+    """
+    
     i = bisect(list, item)
     if i == 0 or list[i-1] != item:
         list.insert(i, item)
 
 def test_remove():
+    """Test the remove function."""
     x = [2, 4, 6]
     remove(x, 2)
     assert x == [4, 6]
@@ -89,6 +164,7 @@
     assert x == []
 
 def test_insert():
+    """Test the insert function."""
     x = [2, 4]
     insert(x, 1)
     assert x == [1, 2, 4]

Modified: debtorrent/trunk/DebTorrent/subnetparse.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/subnetparse.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/subnetparse.py (original)
+++ debtorrent/trunk/DebTorrent/subnetparse.py Mon Jun 18 05:49:26 2007
@@ -1,8 +1,20 @@
 # Written by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Deal with all types of IP addresses and IP address subnets.
+
+ at type hexbinmap: C{dictionary}
+ at var hexbinmap: mapping from the hex characters to their binary string representation
+ at type chrbinmap: C{dictionary}
+ at var chrbinmap: mapping from the first 256 numbers to their binary string representation
+ at type ipv4addrmask: C{long}
+ at var ipv4addrmask: the address mask used to determine if the IP address 
+    in C{long} format is v4 encapsulated in a v6 address
+
+"""
 
 from bisect import bisect, insort
 
@@ -47,6 +59,15 @@
 
 
 def to_bitfield_ipv4(ip):
+    """Convert an IPv4 address to it's binary string representation.
+    
+    @type ip: C{string}
+    @param ip: the IPv4 address to convert
+    @rtype: C{string}
+    @return: the binary string of the IPv4 address
+    
+    """
+    
     ip = ip.split('.')
     if len(ip) != 4:
         raise ValueError, "bad address"
@@ -56,6 +77,15 @@
     return ''.join(b)
 
 def to_bitfield_ipv6(ip):
+    """Convert an IPv6 address to it's binary string representation.
+    
+    @type ip: C{string}
+    @param ip: the IPv6 address to convert
+    @rtype: C{string}
+    @return: the binary string of the IPv6 address
+    
+    """
+    
     b = ''
     doublecolon = False
 
@@ -95,7 +125,26 @@
 ipv4addrmask = to_bitfield_ipv6('::ffff:0:0')[:96]
 
 class IP_List:
+    """Stores multiple IP address subnets.
+    
+    @type ipv4list: C{list} of C{string}
+    @ivar ipv4list: the binary strings representing the start of the IPv4 
+        address that is in the subnet
+    @type ipv6list: C{list} of C{string}
+    @ivar ipv6list: the binary strings representing the start of the IPv6 
+        address that is in the subnet
+    
+    """
+    
     def __init__(self, entrylist=None):
+        """Initialize the instance.
+        
+        @type entrylist: C{list} of (C{string}, C{int})
+        @param entrylist: the IP address and subnet length of the IP address 
+            subnets to start with (optional, defaults to None)
+        
+        """
+        
         self.ipv4list = []
         self.ipv6list = []
         if entrylist:
@@ -106,10 +155,27 @@
 
 
     def __nonzero__(self):
+        """Check whether there are any IP address subnets stored.
+        
+        @rtype: C{boolean}
+        @return: whether there are IP address subnets stored
+        
+        """
+        
         return bool(self.ipv4list or self.ipv6list)
 
 
     def _append(self, ip, depth = 256):
+        """Add a new IP address subnet to the end.
+        
+        @type ip: C{string}
+        @param ip: an IP address in the subnet
+        @type depth: C{int}
+        @param depth: the length of the address subnet header
+            (optional, defaults to the entire IP address)
+        
+        """
+        
         if ip.find(':') < 0:        # IPv4
             self.ipv4list.append(to_bitfield_ipv4(ip)[:depth])
         else:
@@ -120,6 +186,16 @@
                 self.ipv6list.append(b[:depth])
 
     def append(self, ip, depth = 256):
+        """Add a new IP address subnet in the correct order.
+        
+        @type ip: C{string}
+        @param ip: an IP address in the subnet
+        @type depth: C{int}
+        @param depth: the length of the address subnet header
+            (optional, defaults to the entire IP address)
+        
+        """
+        
         if ip.find(':') < 0:        # IPv4
             insort(self.ipv4list,to_bitfield_ipv4(ip)[:depth])
         else:
@@ -131,6 +207,15 @@
 
 
     def includes(self, ip):
+        """Determine whether the IP address is included in any of the subnets.
+        
+        @type ip: C{string}
+        @param ip: the IP address to check
+        @rtype: C{boolean}
+        @return: whether the IP address is in one of the ranges
+       
+        """
+        
         if not (self.ipv4list or self.ipv6list):
             return False
         if ip.find(':') < 0:        # IPv4
@@ -152,6 +237,18 @@
 
 
     def read_fieldlist(self, file):   # reads a list from a file in the format 'ip/len <whatever>'
+        """Parse a file for lists of IP address subnets to add.
+        
+        The file to parse must have lines in the format 'ip/len <whatever>'.
+        The 'whatever' will be ignored. If the subnet is only a single IP 
+        address, omit the '/' and the 'len'. Empty lines will be ignored, as 
+        will lines beginning with '#' which can be used for comments.
+        
+        @type file: C{string}
+        @param file: the name of the file to parse
+        
+        """
+        
         f = open(file, 'r')
         while True:
             line = f.readline()
@@ -185,6 +282,7 @@
 
 
     def set_intranet_addresses(self):
+        """Add the (RFC 1918) private subnets and local subnets."""
         self.append('127.0.0.1',8)
         self.append('10.0.0.0',8)
         self.append('172.16.0.0',12)
@@ -195,9 +293,19 @@
         self.append('fec0::',16)
 
     def set_ipv4_addresses(self):
+        """Add the IPv6 address subnet used to store IPv4 addresses."""
         self.append('::ffff:0:0',96)
 
 def ipv6_to_ipv4(ip):
+    """Convert an IPv6 address in the transition format to an IPv4 address.
+    
+    @type ip: C{string}
+    @param ip: the IP address to convert
+    @rtype: C{string}
+    @return: the IPv4 address
+   
+    """
+    
     ip = to_bitfield_ipv6(ip)
     if not ip.startswith(ipv4addrmask):
         raise ValueError, "not convertible to IPv4"
@@ -211,15 +319,41 @@
     return x
 
 def to_ipv4(ip):
+    """Determine whether the IP address is in the IPv4 format.
+    
+    @type ip: C{string}
+    @param ip: the IP address to check
+    @rtype: C{boolean}
+    @return: whether the IP address is for IPv4
+   
+    """
+    
     if is_ipv4(ip):
         _valid_ipv4(ip)
         return ip
     return ipv6_to_ipv4(ip)
 
 def is_ipv4(ip):
+    """Determine whether the IP address is in the IPv4 format.
+    
+    @type ip: C{string}
+    @param ip: the IP address to check
+    @rtype: C{boolean}
+    @return: whether the IP address is for IPv4
+   
+    """
+    
     return ip.find(':') < 0
 
 def _valid_ipv4(ip):
+    """Determine whether the IP address is a valid IPv4 address.
+    
+    @type ip: C{string}
+    @param ip: the IP address to check
+    @raise ValueError: if the address is not in the proper IPv4 format
+   
+    """
+    
     ip = ip.split('.')
     if len(ip) != 4:
         raise ValueError
@@ -227,6 +361,15 @@
         chr(int(i))
 
 def is_valid_ip(ip):
+    """Determine whether the IP address is a valid IPv4 or IPv6 address.
+    
+    @type ip: C{string}
+    @param ip: the IP address to check
+    @rtype: C{boolean}
+    @return: whether the IP address is valid
+   
+    """
+    
     try:
         if not ip:
             return False

Modified: debtorrent/trunk/DebTorrent/torrentlistparse.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/torrentlistparse.py?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/torrentlistparse.py (original)
+++ debtorrent/trunk/DebTorrent/torrentlistparse.py Mon Jun 18 05:49:26 2007
@@ -1,8 +1,10 @@
 # Written by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Parse a file for a list of torrent hashes."""
 
 from binascii import unhexlify
 
@@ -13,9 +15,20 @@
     False = 0
 
 
-# parses a list of torrent hashes, in the format of one hash per line in hex format
+def parsetorrentlist(filename, parsed):
+    """Parse a file for a list of torrent hashes.
+    
+    The format is one hash per line in hex format (40 characters).
 
-def parsetorrentlist(filename, parsed):
+    @type filename: C{string}
+    @param filename: the file to parse
+    @type parsed: C{dictionary}
+    @param parsed: the cache of all the torrents ever found
+    @rtype: (C{dictionary}, C{dictionary}, C{dictionary})
+    @return: the cache of all the torrents found, the new torrents that were 
+        found, the torrents that are now missing
+    
+    """
     new_parsed = {}
     added = {}
     removed = parsed

Modified: debtorrent/trunk/TODO
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/TODO?rev=115&op=diff
==============================================================================
--- debtorrent/trunk/TODO (original)
+++ debtorrent/trunk/TODO Mon Jun 18 05:49:26 2007
@@ -74,19 +74,15 @@
 later versions, and these statistics may not be needed.
 
 
-Proposal for modifications to apt-ftparchive
+Switch to using the poll() system call instead of the select module
 
-Modifications need to be made to the debian archive management program 
-apt-ftparchive to support some of the upcoming features of debtorrent. Primarily, 
-the large files in a Packages file need to be broken up into sub-pieces, and 
-SHA1 hashes of the sub-pieces created. These would need to be cached, so as to 
-minimize the computation needed to generate a Packages file. Then, the tracker
-address needs to be added to Release files, along with any other needed metainfo. 
-Finally, large Packages files need to be broken down into smaller sub-pieces, and 
-SHA1 sums generated for the sub-pieces generated. These could be stored in the 
-Release file, or in separate files (Packages.pieces). For each of these, some 
-numbers are needed on the amount of data needed to be added to the files, and 
-how much computation will be required to generate it.
+The poll() system call, supported on most Unix systems, provides better 
+scalability for network servers that service many, many clients at the same 
+time. poll() scales better because the system call only requires listing the 
+file descriptors of interest, while select() builds a bitmap, turns on bits 
+for the fds of interest, and then afterward the whole bitmap has to be 
+linearly scanned again. select() is O(highest file descriptor), while poll() 
+is O(number of file descriptors).
 
 
 Consider Sources




More information about the Debtorrent-commits mailing list