Beispiel #1
0
    def __init__(self, manager, socket, id, config, ratelimiter):
        AnomosNeighborProtocol.__init__(self)
        self.socket = socket
        self.incoming_stream_id = 0
        self.partial_recv = ''

        self.id = id
        self.manager = manager
        self.streams = {}  # {StreamID : EndPoint or Relayer object}
        #if self.socket.started_locally:
        self.next_stream_id = 0
        #else:
        #    self.next_stream_id = 1
        self.pmq = PartialMessageQueue()
        self.config = config
        self.ratelimiter = ratelimiter

        self.socket.set_collector(self)
        #Prepare to read messages
        self._reader = self._read_messages()
        self._message = ''
Beispiel #2
0
    def __init__(self, manager, socket, id, config, ratelimiter):
        AnomosNeighborProtocol.__init__(self)
        self.socket = socket
        self.incoming_stream_id = 0
        self.partial_recv = ''

        self.id = id
        self.manager = manager
        self.streams = {} # {StreamID : EndPoint or Relayer object}
        #if self.socket.started_locally:
        self.next_stream_id = 0
        #else:
        #    self.next_stream_id = 1
        self.pmq = PartialMessageQueue()
        self.config = config
        self.ratelimiter = ratelimiter

        self.socket.set_collector(self)
        #Prepare to read messages
        self._reader = self._read_messages()
        self._message = ''
Beispiel #3
0
class NeighborLink(AnomosNeighborProtocol):
    """ NeighborLink handles the socket between two neighbors and keeps
        track of the objects used to manage the active streams between
        those neighbors. """
    def __init__(self, manager, socket, id, config, ratelimiter):
        AnomosNeighborProtocol.__init__(self)
        self.socket = socket
        self.incoming_stream_id = 0
        self.partial_recv = ''

        self.id = id
        self.manager = manager
        self.streams = {} # {StreamID : EndPoint or Relayer object}
        #if self.socket.started_locally:
        self.next_stream_id = 0
        #else:
        #    self.next_stream_id = 1
        self.pmq = PartialMessageQueue()
        self.config = config
        self.ratelimiter = ratelimiter

        self.socket.set_collector(self)
        #Prepare to read messages
        self._reader = self._read_messages()
        self._message = ''

    def get_reader(self):
        return self._reader

    def collect_incoming_data(self, data):
        self._message += data

    def _read_messages(self):
        """ Read messages off the line and relay or process them
            depending on connection type """
        while True:
            yield 2 # Stream ID
            stream = toint(self._message)
            handler = self.get_stream_handler(stream)
            self._message = ''
            yield 4   # Message Length
            l = toint(self._message)
            if l > self.config['max_message_length']:
                log.warning("Received message longer than max length")
            #    return
            self._message = ''
            yield l # Payload
            if handler == self:
                # Grab the stream ID to initialize the received stream
                self.incoming_stream_id = stream
            handler.got_message(self._message)
            self._message = ''

    ## Stream Management ##
    def start_endpoint_stream(self, torrent, aeskey, data=None):
        """ Starts an EndPoint stream
            @param torrent: Torrent to be uploaded/downloaded
            @param aeskey: AES-256 key to be used for transfer communication
            @param data: Tracking Code to be sent
            @type torrent: Anomos.Torrent.Torrent
            @type aeskey: Anomos.crypto.AESKey
            @type data: String
            @return: Newly created EndPoint object"""
        if data is None: # Incoming stream
            nxtid = self.incoming_stream_id
            self.next_stream_id = nxtid + 1
        else: # Localy initialized stream
            nxtid = self.next_stream_id
            self.next_stream_id += 1
        self.streams[nxtid] = \
                    EndPoint(nxtid, self, torrent, aeskey, data)
        self.manager.schedule(180, self.streams[nxtid].completion_timeout)
        log.info("Starting endpoint")
        return self.streams[nxtid]

    def start_relay_stream(self, nid, data=None, orelay=None):
        """ Starts one half of a relay stream. The first half started
            will have orelay=None, the second will have orelay=<first relay object>
            @param nid: The Neighbor ID for the other-half of this Relayer
            @param data: The Tracking Code to be forwarded
            @param orelay: The Relayer object corresponding to this ones other-half
            @type nid: char
            @type data: String
            @type orelay: Anomos.Relayer.Relayer
            @return: Newly created Relayer object"""
        if orelay is None: # Incoming stream
            nxtid = self.incoming_stream_id
            self.next_stream_id = nxtid + 1
        else: # Locally initialized stream
            nxtid = self.next_stream_id
            self.next_stream_id += 1
        self.streams[nxtid] = \
                    Relayer(nxtid, self, nid, data, orelay)
        self.manager.schedule(180, self.streams[nxtid].completion_timeout)
        return self.streams[nxtid]

    def close_all_streams(self):
        for s in self.streams.values():
            if not s.closed:
                s.close()

    def end_stream(self, id):
        """ Terminate the stream with specified stream id. Should be
            called by the stream object which is to be terminated to ensure
            proper shutdown of that stream.
            @param id: Stream id of stream to end
            @type id: int in range 0 to 2**16"""
        self.pmq.remove_by_sid(id)
        if self.streams.has_key(id):
            del self.streams[id]

    def get_stream_handler(self, id):
        """ Return the handler associated with streamid, otherwise
            return a reference to self (because receiving an unassociated
            stream id implies it's a new one).
            @param id: Stream id to fetch
            @type id: int in range 0 to 2**16"""
        return self.streams.get(id, self)

    def socket_flushed(self):
        """ Inform all streams that the connection is
            flushed so they may requeue themselves if
            they need to """
        for stream in self.streams.itervalues():
            stream.socket_flushed()

    def send_immediately(self, message):
        self.socket.push(message)

    def queue_message(self, streamid, message):
        t = self.streams.has_key(streamid)
        if not t or (t and not self.streams[streamid].sent_break):
            self.pmq.queue_message(streamid, message)
        if self.socket.flushed():
            self.socket_flushed()

    def in_queue(self, id):
        return self.pmq.msgs.has_key(id) and len(self.pmq.msgs[id]) > 0

    def send_partial(self, sid, numbytes):
        """ Requests numbytes from the PartialMessageQueue
            to be sent.
            @return: Actual number of bytes sent."""
        msgs = self.pmq.dequeue_partial(sid, numbytes)
        if len(msgs) == 0:
            return 0
        #TODO: There should really be some kind of error handling here
        #      if this write fails.
        snt = 0
        for i in range(len(msgs)):
            f = self.format_message(sid, msgs[i])
            self.socket.push(f)
            snt += len(f)
        return snt

    def socket_closed(self):
        self.close_all_streams()
        self.manager.lost_neighbor(self.id)
        # Socket reference must be removed here or socket waits
        # CLOSE_WAIT state until this object is garbage collected
        self.socket = None

    def get_loc(self):
        return self.socket.addr

    def uniq_id(self):
        return "%02x:*" % (ord(self.id))
Beispiel #4
0
class NeighborLink(AnomosNeighborProtocol):
    """ NeighborLink handles the socket between two neighbors and keeps
        track of the objects used to manage the active streams between
        those neighbors. """
    def __init__(self, manager, socket, id, config, ratelimiter):
        AnomosNeighborProtocol.__init__(self)
        self.socket = socket
        self.incoming_stream_id = 0
        self.partial_recv = ''

        self.id = id
        self.manager = manager
        self.streams = {}  # {StreamID : EndPoint or Relayer object}
        #if self.socket.started_locally:
        self.next_stream_id = 0
        #else:
        #    self.next_stream_id = 1
        self.pmq = PartialMessageQueue()
        self.config = config
        self.ratelimiter = ratelimiter

        self.socket.set_collector(self)
        #Prepare to read messages
        self._reader = self._read_messages()
        self._message = ''

    def get_reader(self):
        return self._reader

    def collect_incoming_data(self, data):
        self._message += data

    def _read_messages(self):
        """ Read messages off the line and relay or process them
            depending on connection type """
        while True:
            yield 2  # Stream ID
            stream = toint(self._message)
            handler = self.get_stream_handler(stream)
            self._message = ''
            yield 4  # Message Length
            l = toint(self._message)
            if l > self.config['max_message_length']:
                log.warning("Received message longer than max length")
            #    return
            self._message = ''
            yield l  # Payload
            if handler == self:
                # Grab the stream ID to initialize the received stream
                self.incoming_stream_id = stream
            handler.got_message(self._message)
            self._message = ''

    ## Stream Management ##
    def start_endpoint_stream(self, torrent, aeskey, data=None):
        """ Starts an EndPoint stream
            @param torrent: Torrent to be uploaded/downloaded
            @param aeskey: AES-256 key to be used for transfer communication
            @param data: Tracking Code to be sent
            @type torrent: Anomos.Torrent.Torrent
            @type aeskey: Anomos.crypto.AESKey
            @type data: String
            @return: Newly created EndPoint object"""
        if data is None:  # Incoming stream
            nxtid = self.incoming_stream_id
            self.next_stream_id = nxtid + 1
        else:  # Localy initialized stream
            nxtid = self.next_stream_id
            self.next_stream_id += 1
        self.streams[nxtid] = \
                    EndPoint(nxtid, self, torrent, aeskey, data)
        self.manager.schedule(180, self.streams[nxtid].completion_timeout)
        log.info("Starting endpoint")
        return self.streams[nxtid]

    def start_relay_stream(self, nid, data=None, orelay=None):
        """ Starts one half of a relay stream. The first half started
            will have orelay=None, the second will have orelay=<first relay object>
            @param nid: The Neighbor ID for the other-half of this Relayer
            @param data: The Tracking Code to be forwarded
            @param orelay: The Relayer object corresponding to this ones other-half
            @type nid: char
            @type data: String
            @type orelay: Anomos.Relayer.Relayer
            @return: Newly created Relayer object"""
        if orelay is None:  # Incoming stream
            nxtid = self.incoming_stream_id
            self.next_stream_id = nxtid + 1
        else:  # Locally initialized stream
            nxtid = self.next_stream_id
            self.next_stream_id += 1
        self.streams[nxtid] = \
                    Relayer(nxtid, self, nid, data, orelay)
        self.manager.schedule(180, self.streams[nxtid].completion_timeout)
        return self.streams[nxtid]

    def close_all_streams(self):
        for s in self.streams.values():
            if not s.closed:
                s.close()

    def end_stream(self, id):
        """ Terminate the stream with specified stream id. Should be
            called by the stream object which is to be terminated to ensure
            proper shutdown of that stream.
            @param id: Stream id of stream to end
            @type id: int in range 0 to 2**16"""
        self.pmq.remove_by_sid(id)
        if self.streams.has_key(id):
            del self.streams[id]

    def get_stream_handler(self, id):
        """ Return the handler associated with streamid, otherwise
            return a reference to self (because receiving an unassociated
            stream id implies it's a new one).
            @param id: Stream id to fetch
            @type id: int in range 0 to 2**16"""
        return self.streams.get(id, self)

    def socket_flushed(self):
        """ Inform all streams that the connection is
            flushed so they may requeue themselves if
            they need to """
        for stream in self.streams.itervalues():
            stream.socket_flushed()

    def send_immediately(self, message):
        self.socket.push(message)

    def queue_message(self, streamid, message):
        t = self.streams.has_key(streamid)
        if not t or (t and not self.streams[streamid].sent_break):
            self.pmq.queue_message(streamid, message)
        if self.socket.flushed():
            self.socket_flushed()

    def in_queue(self, id):
        return self.pmq.msgs.has_key(id) and len(self.pmq.msgs[id]) > 0

    def send_partial(self, sid, numbytes):
        """ Requests numbytes from the PartialMessageQueue
            to be sent.
            @return: Actual number of bytes sent."""
        msgs = self.pmq.dequeue_partial(sid, numbytes)
        if len(msgs) == 0:
            return 0
        #TODO: There should really be some kind of error handling here
        #      if this write fails.
        snt = 0
        for i in range(len(msgs)):
            f = self.format_message(sid, msgs[i])
            self.socket.push(f)
            snt += len(f)
        return snt

    def socket_closed(self):
        self.close_all_streams()
        self.manager.lost_neighbor(self.id)
        # Socket reference must be removed here or socket waits
        # CLOSE_WAIT state until this object is garbage collected
        self.socket = None

    def get_loc(self):
        return self.socket.addr

    def uniq_id(self):
        return "%02x:*" % (ord(self.id))