Ejemplo n.º 1
0
 def listMessages(self):
     """Return a map from pretty-printed message ID to dicts mapping:
            'size' to the size of the message, in bytes
            'nym' to the pseudonym receiving the message
            'have' to the number of packets we have so far
            'need' to the number of additional packets we need.
     """
     result = {}
     for msgid in self.states.keys():
         state = self.states[msgid]
         have, need = state.getCompleteness()
         result[disp64(msgid,12)] = {
             'size' : state.params.length,
             'nym' : state.nym,
             'have' : have,
             'need' : need
             }
     return result
Ejemplo n.º 2
0
 def listMessages(self):
     """Return a map from pretty-printed message ID to dicts mapping:
            'size' to the size of the message, in bytes
            'nym' to the pseudonym receiving the message
            'have' to the number of packets we have so far
            'need' to the number of additional packets we need.
     """
     result = {}
     for msgid in self.states.keys():
         state = self.states[msgid]
         have, need = state.getCompleteness()
         result[disp64(msgid, 12)] = {
             'size': state.params.length,
             'nym': state.nym,
             'have': have,
             'need': need
         }
     return result
Ejemplo n.º 3
0
    def addFragment(self, fragmentPacket, nym=None, now=None, verbose=0):
        """Given an instance of mixminion.Packet.FragmentPayload, record
           the fragment if appropriate and update the state of the
           fragment pool if necessary.  Returns the message ID that was
           updated, or None if the fragment was redundant or misformed.

              fragmentPacket -- the new fragment to add.
              nym -- a string representing the identity that received this
                  fragment.  [Tracking nyms is important, to prevent an
                  attack where we send 2 fragments to 'MarkTwain' and 2
                  fragments to 'SClemens', and see that the message is
                  reconstructed.]
              verbose -- if true, log information at the INFO level;
                  otherwise, log at DEBUG.
        """
        if verbose:
            say = LOG.info
        else:
            say = LOG.debug
        if now is None:
            now = time.time()
        today = previousMidnight(now)

        # If the message has already been rejected or completed, we can
        # drop this packet.
        s = self.db.getStatusAndTime(fragmentPacket.msgID)
        if s:
            say("Dropping fragment of %s message %r",
                s[0].lower(), disp64(fragmentPacket.msgID,12))
            return None

        # Otherwise, create a new metadata object for this fragment...
        meta = FragmentMetadata(messageid=fragmentPacket.msgID,
                                 idx=fragmentPacket.index,
                                 size=fragmentPacket.msgLen,
                                 isChunk=0,
                                 chunkNum=None,
                                 overhead=fragmentPacket.getOverhead(),
                                 insertedDate=today,
                                 nym=nym,
                                 digest=sha1(fragmentPacket.data))
        # ... and allocate or find the MessageState for this message.
        state = self._getState(meta)
        try:
            # Check whether we can/should add this message, but do not
            # add it.
            state.addFragment(None, meta, noop=1)
            # No exception was thrown; queue the message.
            h = self.store.queueMessageAndMetadata(fragmentPacket.data, meta)
            # And *now* update the message state.
            state.addFragment(h, meta)
            say("Stored fragment %s of message %s",
                fragmentPacket.index+1, disp64(fragmentPacket.msgID,12))
            return fragmentPacket.msgID
        except MismatchedFragment, s:
            # Remove the other fragments, mark msgid as bad.
            LOG.warn("Found inconsistent fragment %s in message %s: %s",
                     fragmentPacket.index+1, disp64(fragmentPacket.msgID,12),
                     s)
            self._deleteMessageIDs({ meta.messageid : 1}, "REJECTED", now)
            return None
Ejemplo n.º 4
0
    def addFragment(self, fragmentPacket, nym=None, now=None, verbose=0):
        """Given an instance of mixminion.Packet.FragmentPayload, record
           the fragment if appropriate and update the state of the
           fragment pool if necessary.  Returns the message ID that was
           updated, or None if the fragment was redundant or misformed.

              fragmentPacket -- the new fragment to add.
              nym -- a string representing the identity that received this
                  fragment.  [Tracking nyms is important, to prevent an
                  attack where we send 2 fragments to 'MarkTwain' and 2
                  fragments to 'SClemens', and see that the message is
                  reconstructed.]
              verbose -- if true, log information at the INFO level;
                  otherwise, log at DEBUG.
        """
        if verbose:
            say = LOG.info
        else:
            say = LOG.debug
        if now is None:
            now = time.time()
        today = previousMidnight(now)

        # If the message has already been rejected or completed, we can
        # drop this packet.
        s = self.db.getStatusAndTime(fragmentPacket.msgID)
        if s:
            say("Dropping fragment of %s message %r", s[0].lower(),
                disp64(fragmentPacket.msgID, 12))
            return None

        # Otherwise, create a new metadata object for this fragment...
        meta = FragmentMetadata(messageid=fragmentPacket.msgID,
                                idx=fragmentPacket.index,
                                size=fragmentPacket.msgLen,
                                isChunk=0,
                                chunkNum=None,
                                overhead=fragmentPacket.getOverhead(),
                                insertedDate=today,
                                nym=nym,
                                digest=sha1(fragmentPacket.data))
        # ... and allocate or find the MessageState for this message.
        state = self._getState(meta)
        try:
            # Check whether we can/should add this message, but do not
            # add it.
            state.addFragment(None, meta, noop=1)
            # No exception was thrown; queue the message.
            h = self.store.queueMessageAndMetadata(fragmentPacket.data, meta)
            # And *now* update the message state.
            state.addFragment(h, meta)
            say("Stored fragment %s of message %s", fragmentPacket.index + 1,
                disp64(fragmentPacket.msgID, 12))
            return fragmentPacket.msgID
        except MismatchedFragment, s:
            # Remove the other fragments, mark msgid as bad.
            LOG.warn("Found inconsistent fragment %s in message %s: %s",
                     fragmentPacket.index + 1, disp64(fragmentPacket.msgID,
                                                      12), s)
            self._deleteMessageIDs({meta.messageid: 1}, "REJECTED", now)
            return None
Ejemplo n.º 5
0
class FragmentPool:
    """Class to hold and manage fragmented messages as they are
       reconstructed."""

    ## Fields:
    # states -- map from messageid to MessageState.  Reconstructed by
    #    rescan().
    # db -- instance of FragmentDB.
    # store -- instance of StringMetadataStore.  The messages are either
    #    the contents of invidual fragments or reconstructed chunks.
    #    The metadata are instances of FragmentMetadata.
    def __init__(self, dir):
        """Open a FragmentPool storing fragments in 'dir' and records of
           old messages in 'dir_db'.
           """
        self.store = mixminion.Filestore.StringMetadataStore(dir, create=1)
        self.db = FragmentDB(dir + "_db")
        self.rescan()

    def cleanQueue(self, deleteFn=None):
        """Expunge all removed fragments from disk. See Filestore.cleanQueue"""
        self.store.cleanQueue(deleteFn)

    def sync(self):
        """Flush pending changes to disk."""
        self.db.sync()

    def close(self):
        """Release open resources for this pool."""
        self.db.close()
        del self.db
        del self.store
        del self.states

    def addFragment(self, fragmentPacket, nym=None, now=None, verbose=0):
        """Given an instance of mixminion.Packet.FragmentPayload, record
           the fragment if appropriate and update the state of the
           fragment pool if necessary.  Returns the message ID that was
           updated, or None if the fragment was redundant or misformed.

              fragmentPacket -- the new fragment to add.
              nym -- a string representing the identity that received this
                  fragment.  [Tracking nyms is important, to prevent an
                  attack where we send 2 fragments to 'MarkTwain' and 2
                  fragments to 'SClemens', and see that the message is
                  reconstructed.]
              verbose -- if true, log information at the INFO level;
                  otherwise, log at DEBUG.
        """
        if verbose:
            say = LOG.info
        else:
            say = LOG.debug
        if now is None:
            now = time.time()
        today = previousMidnight(now)

        # If the message has already been rejected or completed, we can
        # drop this packet.
        s = self.db.getStatusAndTime(fragmentPacket.msgID)
        if s:
            say("Dropping fragment of %s message %r", s[0].lower(),
                disp64(fragmentPacket.msgID, 12))
            return None

        # Otherwise, create a new metadata object for this fragment...
        meta = FragmentMetadata(messageid=fragmentPacket.msgID,
                                idx=fragmentPacket.index,
                                size=fragmentPacket.msgLen,
                                isChunk=0,
                                chunkNum=None,
                                overhead=fragmentPacket.getOverhead(),
                                insertedDate=today,
                                nym=nym,
                                digest=sha1(fragmentPacket.data))
        # ... and allocate or find the MessageState for this message.
        state = self._getState(meta)
        try:
            # Check whether we can/should add this message, but do not
            # add it.
            state.addFragment(None, meta, noop=1)
            # No exception was thrown; queue the message.
            h = self.store.queueMessageAndMetadata(fragmentPacket.data, meta)
            # And *now* update the message state.
            state.addFragment(h, meta)
            say("Stored fragment %s of message %s", fragmentPacket.index + 1,
                disp64(fragmentPacket.msgID, 12))
            return fragmentPacket.msgID
        except MismatchedFragment, s:
            # Remove the other fragments, mark msgid as bad.
            LOG.warn("Found inconsistent fragment %s in message %s: %s",
                     fragmentPacket.index + 1, disp64(fragmentPacket.msgID,
                                                      12), s)
            self._deleteMessageIDs({meta.messageid: 1}, "REJECTED", now)
            return None
        except UnneededFragment:
            # Discard this fragment; we don't need it.
            say("Dropping unneeded fragment %s of message %s",
                fragmentPacket.index + 1, disp64(fragmentPacket.msgID, 12))
            return None