[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[minion-cvs] Flesh out inline documentation
Update of /home/minion/cvsroot/src/minion/lib/mixminion/server
In directory moria.mit.edu:/tmp/cvs-serv14411/lib/mixminion/server
Modified Files:
EventStats.py MMTPServer.py Modules.py PacketHandler.py
ServerMain.py ServerQueue.py
Log Message:
Flesh out inline documentation
Index: EventStats.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/EventStats.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- EventStats.py 15 Jul 2003 04:41:18 -0000 1.8
+++ EventStats.py 25 Aug 2003 21:05:34 -0000 1.9
@@ -56,17 +56,17 @@
"""Called whenever a packet is received via MMTP."""
self._log("ReceivedPacket", arg)
def receivedConnection(self, arg=None):
- """DOCDOC"""
+ """Called whenever we get an incoming MMTP connection."""
self._log("ReceivedConnection", arg)
def attemptedConnect(self, arg=None):
- """DOCDOC"""
+ """Called whenever we try to connect to an MMTP server."""
self._log("AttemptedConnect", arg)
def successfulConnect(self, arg=None):
- """DOCDOC"""
+ """Called whenever we successfully connect to an MMTP server."""
self._log("SuccessfulConnect", arg)
def failedConnect(self, arg=None):
- """DOCDOC"""
+ """Called whenever we fail to connect to an MMTP server."""
self._log("FailedConnect", arg)
def attemptedRelay(self, arg=None):
Index: MMTPServer.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/MMTPServer.py,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -d -r1.47 -r1.48
--- MMTPServer.py 21 Aug 2003 21:34:03 -0000 1.47
+++ MMTPServer.py 25 Aug 2003 21:05:34 -0000 1.48
@@ -43,7 +43,8 @@
warn = LOG.warn
error = LOG.error
-#DOCDOC
+# For windows -- list of errno values that we can expect when blocking IO
+# blocks on a connect.
IN_PROGRESS_ERRNOS = [ getattr(errno, ename)
for ename in [ "EINPROGRESS", "WSAEWOULDBLOCK"]
if hasattr(errno,ename) ]
@@ -81,7 +82,9 @@
writefds = self.writers.keys()
if not (readfds or writefds):
- #DOCDOC
+ # Windows 'select' doesn't timeout properly when we aren't
+ # selecting on any FDs. This should never happen to us,
+ # but we'll check for it anyway.
time.sleep(timeout)
return
@@ -352,9 +355,21 @@
# needs to be retried till the other guy sends an 'ack'
# back... but we don't want to keep retrying indefinitely, or
# else we can deadlock on a connection from ourself to
- # ourself.
+ # ourself. Thus, we do the following:
+ #
+
+ # We try to shutdown. This either acknowledges the other
+ # side's attempt to close the stream, or sends a request to
+ # close the stream.
+ # - If OpenSSL says we're finished, great!
+ # - If not, and we've already tried to shutdown, then freak out;
+ # that's not supposed to happen.
+ # - If we're not finished, and this *is* our first time trying,
+ # then start *reading* from the incoming socket. We should
+ # get an acknowledgement for our close request soon when read
+ # returns a 0. Then, calling shutdown again should mean we're
+ # done.
- #DOCDOC this insanity.
while 1:
done = self.__con.shutdown() # may throw want*
if not done and self.__awaitingShutdown:
@@ -377,8 +392,10 @@
raise _ml.TLSWantRead()
def __readTooMuch(self):
- """DOCDOC"""
- print "AAAARGH."
+ """Helper function -- called if we read too much data while we're
+ shutting down."""
+ LOG.error("Read over 128 bytes of unexpected data from closing "
+ "connection to %s", self.address)
self.__sock.close()
self.state = None
@@ -1013,6 +1030,8 @@
def shutdown(self, err=0, retriable=0):
self.active = 0
+ if err and self.finished == self.__setupFinished:
+ EventStats.log.failedConnect()
SimpleTLSConnection.shutdown(self, err=err, retriable=retriable)
def remove(self):
Index: Modules.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/Modules.py,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- Modules.py 21 Aug 2003 21:34:03 -0000 1.50
+++ Modules.py 25 Aug 2003 21:05:34 -0000 1.51
@@ -128,10 +128,10 @@
raise NotImplementedError("processMessage")
def sync(self):
- """DOCDOC"""
+ """Flush all pending data held by this module to disk."""
def close(self):
- """DOCDOC"""
+ """Release all resources held by this module."""
pass
class ImmediateDeliveryQueue:
@@ -459,19 +459,20 @@
queue.sendReadyMessages()
def getServerInfoBlocks(self):
- """DOCDOC"""
+ """Return a list of strings that should be appended to the server
+ descriptor of this server, based on the configuration of its
+ modules.
+ """
return [ m.getServerInfoBlock() for m in self.modules
if self.enabled.get(m.getName(),0) ]
def close(self):
- """DOCDOC"""
- #XXXX005 this method must be called on shutdown!
+ """Release all resources held by all modules."""
for module in self.enabled:
module.close()
def sync(self):
- """DOCDOC"""
- #XXXX005 this method must be called on reset!
+ """Flush all state held by all modules to disk."""
for module in self.enabled:
module.sync()
@@ -591,7 +592,12 @@
class _FragmentedDeliveryMessage:
+ """Helper class: obeys the interface of mixminion.server.PacketHandler.
+ DeliveryMessage, but contains a long message reassembled from
+ fragments."""
def __init__(self, ssfm):
+ """Create a _FragmentedDeliveryMessage object from an instance of
+ mixminion.Packet.ServerSideFragmentedMessage."""
self.m = ssfm
self.contents = None
def __getstate__(self):
@@ -624,7 +630,6 @@
else:
return encodeBase64(self.contents)
def getHeaders(self):
- """DOCDOC"""
if self.contents is None:
self.decode()
assert self.headers is not None
@@ -779,11 +784,24 @@
#----------------------------------------------------------------------
class MailBase:
- """DOCDOC"""
+ """Implementation class: contains code shared by modules that send email
+ messages (such as mbox and smtp)."""
+ ## Fields: (to be set by subclass)
+ # subject: Default subject to use for outgoing mail, if none is given
+ # in the message.
+ # fromTag: String to prepend to from name.
+ # returnAddress: Return address for mail; should be an rfc822-style
+ # mailbox.
+ # header: Text that should be appended after the headers and before
+ # the message itself. It must include the empty line that separates
+ # headers from body.
+ # maxMessageSize: Largest allowable size (after decompression, before
+ # base64) for outgoing messages.
def _formatEmailMessage(self, address, packet):
- """DOCDOC"""
- #DOCDOC implied fields
- # subject, fromTag, returnAddress, header, maxMessageSize
+ """Given a RFC822 mailbox (delivery address), and an instance of
+ DeliveryMessage, return a string containing a message to be sent
+ to a recipient, adding headers as needed.
+ """
if len(packet.getContents()) > self.maxMessageSize:
LOG.warn("Dropping over-long message (message is %sb; max is %sb)",
@@ -844,8 +862,6 @@
return self.retrySchedule
def getConfigSyntax(self):
- # Validate returnaddress! XXXX005
-
# FFFF There should be some way to say that fields are required
# FFFF if the module is enabled.
return { "Delivery/MBOX" :
@@ -972,8 +988,7 @@
#----------------------------------------------------------------------
class SMTPModule(DeliveryModule, MailBase):
- """Placeholder for real exit node implementation.
- For now, use MixmasterSMTPModule DOCDOC"""
+ """Common base class for SMTP mail."""
def __init__(self):
DeliveryModule.__init__(self)
def getServerInfoBlock(self):
@@ -1003,8 +1018,6 @@
return self.retrySchedule
def getConfigSyntax(self):
- # Validate returnaddress! XXXX005
-
return { "Delivery/SMTP" :
{ 'Enabled' : ('REQUIRE', _parseBoolean, "no"),
'Retry': ('ALLOW', _parseIntervalList,
@@ -1205,7 +1218,8 @@
MAIL_HEADERS = ["SUBJECT", "FROM", "IN-REPLY-TO", "REFERENCES"]
def checkMailHeaders(headers):
- """DOCDOC"""
+ """Check whether the decoded headers in a provided dict are permissible
+ for an outgoing email message. Raise ParseError if they are not."""
for k in headers.keys():
if k not in MAIL_HEADERS:
#XXXX this should raise parse error instead.
Index: PacketHandler.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/PacketHandler.py,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- PacketHandler.py 21 Aug 2003 21:34:03 -0000 1.21
+++ PacketHandler.py 25 Aug 2003 21:05:34 -0000 1.22
@@ -262,8 +262,12 @@
# type -- until decode is called, None. After decode is called,
# one of 'plain' (plaintext message), 'long' (overcompressed message),
# 'enc' (encrypted message), or 'err' (malformed message).
- # isfrag -- DOCDOC
- # dPayload -- DOCDOC
+ # headers -- a map from key to value for the delivery headers in
+ # this message's payload. In the case of a fragment, or a
+ # non-plaintext message, the map is empty.
+ # isfrag -- Is this packet a fragment of a complete message? If so, the
+ # type must be 'plain'.
+ # dPayload -- An instance of mixminion.Packet.Payload for this object.
def __init__(self, routingType, routingInfo, applicationKey,
tag, payload):
"""Construct a new DeliveryPacket."""
@@ -278,7 +282,7 @@
self.payload = payload
self.contents = None
self.type = None
- self.headers = None#DOCDOC
+ self.headers = None
self.isfrag = 0
self.dPayload = None
@@ -298,7 +302,7 @@
return self.contents
def getDecodedPayload(self):
- """DOCDOC"""
+ """Return an instance of mixminion.Packet.Payload for this packet."""
if self.type is None: self.decode()
return self.dPayload
@@ -314,7 +318,7 @@
return self.type == 'long'
def isFragment(self):
- """DOCDOC"""
+ """Return true iff this packet is part of a fragmented message."""
if self.type is None: self.decode()
return self.isfrag
@@ -384,7 +388,7 @@
return encodeBase64(self.contents)
def getHeaders(self):
- """DOCDOC"""
+ """Return a dict containing the headers for this message."""
if self.type is None:
self.decode()
assert self.headers is not None
@@ -413,4 +417,3 @@
tp = 'BIN'
return Packet.TextEncodedMessage(self.contents, tp, tag)
-
Index: ServerMain.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/ServerMain.py,v
retrieving revision 1.88
retrieving revision 1.89
diff -u -d -r1.88 -r1.89
--- ServerMain.py 21 Aug 2003 21:34:03 -0000 1.88
+++ ServerMain.py 25 Aug 2003 21:05:34 -0000 1.89
@@ -848,6 +848,7 @@
LOG.info("Checking for key rotation")
self.keyring.checkKeys()
self.generateKeys()
+ self.moduleManager.sync()
def doMix(self):
"""Called when the server's mix is about to fire. Picks some
@@ -900,8 +901,9 @@
self.cleaningThread.join()
self.processingThread.join()
self.moduleManager.join()
-
+
self.packetHandler.close()
+ self.moduleManager.close()
EventStats.log.save()
Index: ServerQueue.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/ServerQueue.py,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- ServerQueue.py 21 Aug 2003 21:34:03 -0000 1.31
+++ ServerQueue.py 25 Aug 2003 21:05:34 -0000 1.32
@@ -3,8 +3,7 @@
"""mixminion.server.ServerQueue
- Facility for fairly secure, directory-based, unordered queues.
- DOCDOC not any more.
+ Facilities for retriable delivery queues, and for mix pools.
"""
import os
@@ -23,16 +22,6 @@
__all__ = [ 'DeliveryQueue', 'TimedMixPool', 'CottrellMixPool',
'BinomialCottrellMixPool' ]
-# Mode to pass to open(2) for creating a new file, and dying if it already
-# exists.
-_NEW_MESSAGE_FLAGS = os.O_WRONLY+os.O_CREAT+os.O_EXCL
-# On windows or mac, binary != text.
-_NEW_MESSAGE_FLAGS += getattr(os, 'O_BINARY', 0)
-
-# Any inp_* files older than INPUT_TIMEOUT seconds old are assumed to be
-# trash.
-INPUT_TIMEOUT = 6000
-
class _DeliveryState:
"""Helper class: holds the state needed to schedule delivery or
eventual abandonment of a message in a DeliveryQueue."""
@@ -62,23 +51,25 @@
self.pending = None
self.nextAttempt = None
self.remove = 0
-
+
def isPending(self):
- """DOCDOC"""
+ """Return true iff we are currently trying to deliver this message."""
return self.pending is not None
def setPending(self, now=None):
- """DOCDOC"""
+ """Note that we are now trying to deliver this message, so that we
+ don't try to deliver it twice at the same time."""
if now is None:
now = time.time()
self.pending = now
def setNonPending(self):
- """DOCDOC"""
+ """Note that we are no longer trying to deliver this message, so that
+ we can try it again later."""
self.pending = None
def isRemovable(self):
- """DOCDOC"""
+ """Return true iff this message is old enough to be removed."""
return self.remove
def __getstate__(self):
@@ -263,7 +254,9 @@
def _rescan(self, now=None):
"""Helper: Rebuild the internal state of this queue from the
- underlying directory. DOCDOC trashes .pending and .sendable."""
+ underlying directory. After calling 'rescan',
+ _rebuildNextAttempt must be called to recalculate our
+ delivery schedule."""
try:
self._lock.acquire()
self.store.loadAllMetadata(lambda h: _DeliveryState())
@@ -273,11 +266,11 @@
self._lock.release()
def getAllMessages(self):
- """DOCDOC"""
+ """Return handles for all messages in the store."""
return self.store.getAllMessages()
def count(self):
- """DOCDOC"""
+ """Return the number of messages in the store."""
return self.store.count()
def _rebuildNextAttempt(self, now=None):