Пример #1
0
 def StreamInit(self):
     """
     Send an initial stream header
     """
     self._owner.Connection.sendqueue = []
     self.Stream = simplexml.NodeBuilder()
     self.Stream.dispatch = self.dispatch
     self.Stream._dispatch_depth = 2
     self.Stream.stream_header_received = self._check_stream_start
     self.Stream.features = None
     self._metastream = Node('stream:stream')
     self._metastream.setNamespace(self._owner.Namespace)
     self._metastream.setAttr('version', '1.0')
     self._metastream.setAttr('xmlns:stream', NS_STREAMS)
     self._metastream.setAttr('to', self._owner.Server)
     if locale.getdefaultlocale()[0]:
         self._metastream.setAttr('xml:lang',
                 locale.getdefaultlocale()[0].split('_')[0])
     self._owner.send("%s%s>" % (XML_DECLARATION, str(self._metastream)[:-2]))
Пример #2
0
    def StreamInit(self):
        """
        Send an initial stream header
        """
        self.Stream = simplexml.NodeBuilder()
        self.Stream.dispatch = self.dispatch
        self.Stream._dispatch_depth = 2
        self.Stream.stream_header_received = self._check_stream_start
        self.Stream.features = self.old_features

        self._metastream = Node('stream:stream')
        self._metastream.setNamespace(self._owner.Namespace)
        self._metastream.setAttr('version', '1.0')
        self._metastream.setAttr('xmlns:stream', NS_STREAMS)
        self._metastream.setAttr('to', self._owner.Server)
        if locale.getdefaultlocale()[0]:
            self._metastream.setAttr('xml:lang',
                    locale.getdefaultlocale()[0].split('_')[0])

        self.restart = True
        self._owner.Connection.send_init(after_SASL=self.after_SASL)
Пример #3
0
class XMPPDispatcher(PlugIn):
    """
    Handles XMPP stream and is the first who takes control over a fresh stanza

    Is plugged into NonBlockingClient but can be replugged to restart handled
    stream headers (used by SASL f.e.).
    """

    def __init__(self):
        PlugIn.__init__(self)
        self.handlers = {}
        self._expected = {}
        self._defaultHandler = None
        self._pendingExceptions = []
        self._eventHandler = None
        self._cycleHandlers = []
        self._exported_methods=[self.RegisterHandler, self.RegisterDefaultHandler,
                self.RegisterEventHandler, self.UnregisterCycleHandler,
                self.RegisterCycleHandler, self.RegisterHandlerOnce,
                self.UnregisterHandler, self.RegisterProtocol,
                self.SendAndWaitForResponse, self.SendAndCallForResponse,
                self.getAnID, self.Event, self.send]

        # Let the dispatcher know if there is support for stream management
        self.sm = None

        # \ufddo -> \ufdef range
        c = u'\ufdd0'
        r = c.encode('utf8')
        while (c < u'\ufdef'):
            c = unichr(ord(c) + 1)
            r += '|' + c.encode('utf8')

        # \ufffe-\uffff, \u1fffe-\u1ffff, ..., \u10fffe-\u10ffff
        c = u'\ufffe'
        r += '|' + c.encode('utf8')
        r += '|' + unichr(ord(c) + 1).encode('utf8')
        while (c < u'\U0010fffe'):
            c = unichr(ord(c) + 0x10000)
            r += '|' + c.encode('utf8')
            r += '|' + unichr(ord(c) + 1).encode('utf8')

        self.invalid_chars_re = re.compile(r)

    def getAnID(self):
        global outgoingID
        outgoingID += 1
        return repr(outgoingID)

    def dumpHandlers(self):
        """
        Return set of user-registered callbacks in it's internal format. Used
        within the library to carry user handlers set over Dispatcher replugins
        """
        return self.handlers

    def restoreHandlers(self, handlers):
        """
        Restore user-registered callbacks structure from dump previously obtained
        via dumpHandlers. Used within the library to carry user handlers set over
        Dispatcher replugins.
        """
        self.handlers = handlers

    def _init(self):
        """
        Register default namespaces/protocols/handlers. Used internally
        """
        # FIXME: inject dependencies, do not rely that they are defined by our
        # owner
        self.RegisterNamespace('unknown')
        self.RegisterNamespace(NS_STREAMS)
        self.RegisterNamespace(self._owner.defaultNamespace)
        self.RegisterProtocol('iq', Iq)
        self.RegisterProtocol('presence', Presence)
        self.RegisterProtocol('message', Message)
        self.RegisterDefaultHandler(self.returnStanzaHandler)
        self.RegisterEventHandler(self._owner._caller._event_dispatcher)
        self.on_responses = {}

    def plugin(self, owner):
        """
        Plug the Dispatcher instance into Client class instance and send initial
        stream header. Used internally
        """
        self._init()
        self._owner.lastErrNode = None
        self._owner.lastErr = None
        self._owner.lastErrCode = None
        if hasattr(self._owner, 'StreamInit'):
            self._owner.StreamInit()
        else:
            self.StreamInit()

    def plugout(self):
        """
        Prepare instance to be destructed
        """
        self.Stream.dispatch = None
        self.Stream.features = None
        self.Stream.destroy()
        self._owner = None
        self.Stream = None

    def StreamInit(self):
        """
        Send an initial stream header
        """
        self._owner.Connection.sendqueue = []
        self.Stream = simplexml.NodeBuilder()
        self.Stream.dispatch = self.dispatch
        self.Stream._dispatch_depth = 2
        self.Stream.stream_header_received = self._check_stream_start
        self.Stream.features = None
        self._metastream = Node('stream:stream')
        self._metastream.setNamespace(self._owner.Namespace)
        self._metastream.setAttr('version', '1.0')
        self._metastream.setAttr('xmlns:stream', NS_STREAMS)
        self._metastream.setAttr('to', self._owner.Server)
        if locale.getdefaultlocale()[0]:
            self._metastream.setAttr('xml:lang',
                    locale.getdefaultlocale()[0].split('_')[0])
        self._owner.send("%s%s>" % (XML_DECLARATION, str(self._metastream)[:-2]))

    def _check_stream_start(self, ns, tag, attrs):
        if ns != NS_STREAMS or tag!='stream':
            raise ValueError('Incorrect stream start: (%s,%s). Terminating.'
                    % (tag, ns))

    def replace_non_character(self, data):
        return re.sub(self.invalid_chars_re, u'\ufffd'.encode('utf-8'), data)

    def ProcessNonBlocking(self, data):
        """
        Check incoming stream for data waiting

        :param data: data received from transports/IO sockets
        :return:
                1) length of processed data if some data were processed;
                2) '0' string if no data were processed but link is alive;
                3) 0 (zero) if underlying connection is closed.
        """
        # FIXME:
        # When an error occurs we disconnect the transport directly. Client's
        # disconnect method will never be called.
        # Is this intended?
        # also look at transports start_disconnect()
        data = self.replace_non_character(data)
        for handler in self._cycleHandlers:
            handler(self)
        if len(self._pendingExceptions) > 0:
            _pendingException = self._pendingExceptions.pop()
            raise _pendingException[0], _pendingException[1], _pendingException[2]
        try:
            self.Stream.Parse(data)
            # end stream:stream tag received
            if self.Stream and self.Stream.has_received_endtag():
                self._owner.disconnect(self.Stream.streamError)
                return 0
        except ExpatError:
            log.error('Invalid XML received from server. Forcing disconnect.')
            self._owner.Connection.disconnect()
            return 0
        except ValueError, e:
            log.debug('ValueError: %s' % str(e))
            self._owner.Connection.pollend()
            return 0
        if len(self._pendingExceptions) > 0:
            _pendingException = self._pendingExceptions.pop()
            raise _pendingException[0], _pendingException[1], _pendingException[2]
        if len(data) == 0:
            return '0'
        return len(data)
Пример #4
0
class BOSHDispatcher(XMPPDispatcher):

    def PlugIn(self, owner, after_SASL=False, old_features=None):
        self.old_features = old_features
        self.after_SASL = after_SASL
        XMPPDispatcher.PlugIn(self, owner)

    def StreamInit(self):
        """
        Send an initial stream header
        """
        self.Stream = simplexml.NodeBuilder()
        self.Stream.dispatch = self.dispatch
        self.Stream._dispatch_depth = 2
        self.Stream.stream_header_received = self._check_stream_start
        self.Stream.features = self.old_features

        self._metastream = Node('stream:stream')
        self._metastream.setNamespace(self._owner.Namespace)
        self._metastream.setAttr('version', '1.0')
        self._metastream.setAttr('xmlns:stream', NS_STREAMS)
        self._metastream.setAttr('to', self._owner.Server)
        if locale.getdefaultlocale()[0]:
            self._metastream.setAttr('xml:lang',
                    locale.getdefaultlocale()[0].split('_')[0])

        self.restart = True
        self._owner.Connection.send_init(after_SASL=self.after_SASL)

    def StreamTerminate(self):
        """
        Send a stream terminator
        """
        self._owner.Connection.send_terminator()

    def ProcessNonBlocking(self, data=None):
        if self.restart:
            fromstream = self._metastream
            fromstream.setAttr('from', fromstream.getAttr('to'))
            fromstream.delAttr('to')
            data = '%s%s>%s' % (XML_DECLARATION, str(fromstream)[:-2], data)
            self.restart = False
        return XMPPDispatcher.ProcessNonBlocking(self, data)

    def dispatch(self, stanza, session=None, direct=0):
        if stanza.getName() == 'body' and stanza.getNamespace() == NS_HTTP_BIND:

            stanza_attrs = stanza.getAttrs()
            if 'authid' in stanza_attrs:
                # should be only in init response
                # auth module expects id of stream in document attributes
                self.Stream._document_attrs['id'] = stanza_attrs['authid']
            self._owner.Connection.handle_body_attrs(stanza_attrs)

            children = stanza.getChildren()
            if children:
                for child in children:
                    # if child doesn't have any ns specified, simplexml (or expat)
                    # thinks it's of parent's (BOSH body) namespace, so we have to
                    # rewrite it to jabber:client
                    if child.getNamespace() == NS_HTTP_BIND:
                        child.setNamespace(self._owner.defaultNamespace)
                    XMPPDispatcher.dispatch(self, child, session, direct)
        else:
            XMPPDispatcher.dispatch(self, stanza, session, direct)
Пример #5
0
    def proccess_message(self, data, addr, running_in_thread=False):
        # data = json.loads(msg)
        if data['operation'] != 'DISCOVER':
            print("Data received: " + str(data))

        if data['operation'] == 'DISCOVER':
            if data['join']:
                # addr = str(data['sender'][1]), int(data['sender'][2])
                if addr != (self.node.ip, self.node.port):
                    answer = { 'operation': 'CONTACT', 'sender': list(self.node),
                            'key': data['key'] }

                    self.send_udp_msg(json.dumps(answer).encode(), addr)
                    self.update(tuple(data['sender']))
                    print(f"{data['sender']} joined")

            else:
                if addr != (self.node.ip, self.node.port):
                    ip, port = str(data['ip']), int(data['port'])
                    server_addr = (self.node.ip, self.tcp_server_port)
                    try: self.sendall(server_addr, ip, port)
                    except: pass

        elif data['operation'] == 'CONTACT':
            contact = tuple(data['sender'])
            self.update(contact)
            self.lookup_node(self.node.ID)

        # A peer has to perform a method specified by other peer by RPC
        elif data['operation'] == 'EXECUTE':
            result = None
            if data['method'] == 'FIND_NODE':
                result =  self.node.FIND_NODE(data['id'])
            elif data['method'] == 'FIND_VALUE':
                result = self.node.FIND_VALUE(data['id'])
                answer = {'operation': 'RESPONSE', 'result': result,
                            'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] }
                self.sendall(answer, addr[1])
                if 'sender' in data: self.update(tuple(data['sender']))
                return

            elif data['method'] == 'PING':
                result = self.node.PING()
            elif data['method'] == 'STORE':
                key, value = data['store_key'], data['store_value']
                publisher, sender = tuple(data['publisher']), tuple(data['sender'])
                result = self.node.STORE(key, value, publisher, sender, to_update=data['to_update'])
            elif data['method'] == 'LOOKUP':
                result = self.lookup_value(data["id"])
            elif data['method'] == 'PUBLISH':
                node = self.node.asTuple()
                self.publish(data, node, node)

            if result is not None:
                answer = {'operation': 'RESPONSE', 'result': result,
                            'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] }
                answer = utils.dumps_json(answer).encode()
                self.send_udp_msg(answer, addr)


                if 'sender' in data:
                    self.update(tuple(data['sender']))

        # A peer is requested to perform a RPC to other peer
        elif data['operation'] == 'RPC':
            msg = None

            if data['method'] == 'FIND_NODE':
                msg =  utils.build_FIND_NODE_msg(data['id'], self.node)
            elif data['method'] == 'FIND_VALUE':
                msg =  utils.build_FIND_VALUE_msg(data['id'], self.node)
            elif data['method'] == 'PING':
                msg =  utils.build_PING_msg(self.node)
            elif data['method'] == 'STORE':
                msg = utils.build_STORE_msg(data['storeKey'], data['store_value'], self.node, self.node)

            if msg is not None:
                # The address of the remote peer wich it will be used as the target of the RPC
                addr = (data['ip'], data['port'])
                msg = utils.dumps_json(msg).encode()
                self.send_udp_msg(msg, addr)


        # The peer receives the answer of a RPC made before
        elif data['operation'] == 'RESPONSE':
            self.set_response(data['key'], data)
            if not Node.Equals(data['sender'], self.node):
                self.update(data['sender'])
        if running_in_thread:
            exit_thread()
Пример #6
0
        def attend(client):
            while True:
                msg = self.recvall(client)

                if not msg:
                    break

                # print(f'RECEIVED MSG {msg}')
                data = {'method': None}
                try:
                    data = json.loads(msg)
                except:
                    pass

                if data['method'] == 'PUBLISH':
                    node = self.node.asTuple()
                    self.publish(data, node, node)
                elif data['method'] == 'LOOKUP':
                    answer = self.lookup_value(data['id'])

                    founded, result, file_bytes = answer[0], answer[1], answer[2]
                    if founded and result['value_type'] == 'file':

                        if not file_bytes: file_bytes = self.recv_file()
                        # try: client.sendall(file_bytes)
                        # except: pass
                        client.sendall(file_bytes)
                    else:
                        if not founded: result = None
                        client.sendall(utils.dumps_json(result).encode() + b'\r\n\r\n')
                    client.close()

                elif data['method'] == 'PING':
                    client.send(b'PING')
                elif data['method'] == 'STORE':
                    key, value = data['store_key'], data['store_value']
                    publisher, sender = tuple(data['publisher']), tuple(data['sender'])

                    real_value = None
                    if data['value_type'] == 'file':
                        real_value = self.recv_file()

                    self.node.STORE(key, value, publisher, sender, data['value_type'], real_value, data['to_update'])

                elif data['method'] == 'FIND_VALUE':
                    founded, result, file_bytes = self.node.FIND_VALUE(data['id'])
                    answer = {'operation': 'RESPONSE', 'result': (founded, result, file_bytes),
                                'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] }

                    # client.sendall(utils.dumps_json(answer).encode() + b'\r\n\r\n')
                    answer = utils.dumps_json(answer)
                    client.sendall(answer.encode() + b'\r\n\r\n')
                    if founded and result['value_type'] == 'file':
                        # files_bytes = utils.load_file(result['value'])
                        self._send_file(file_bytes, data['sender'][1])

                    if not Node.Equals(data['sender'], self.node):
                        self.update(data['sender'])

                elif data['method'] == 'UPDATE':
                    self._update(data['store_key'], data['store_value'], data['publisher'], data['sender'])

                elif data['method'] == 'FIND_NODE':
                    result = self.node.FIND_NODE(data['id'])
                    answer = {'operation': 'RESPONSE', 'result': result,
                                'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] }

                    # client.sendall(utils.dumps_json(answer).encode() + b'\r\n\r\n')
                    answer = utils.dumps_json(answer)
                    client.sendall(answer.encode() + b'\r\n\r\n')

                    if not Node.Equals(data['sender'], self.node):
                        self.update(data['sender'])
            exit_thread()
Пример #7
0
    def lookup_value(self, ID):
        to_query = self.node.get_n_closest(ID, self.node.alpha)

        pending = []
        heapq.heapify(pending)

        myinfo = (self.node.ID ^ ID, self.node.asTuple())
        enquired = [myinfo]
        alives = [myinfo]

        if len(to_query) == 0:
            founded, data, file_bytes = self.node.FIND_VALUE(ID)
            if founded: return (True, data, file_bytes)
            else: return (False, myinfo, None)
        else:
            founded, data, file_bytes = self.node.FIND_VALUE(ID)
            if founded: return (True, data, file_bytes)

        closest_node = heapq.nsmallest(1, to_query)[0][0]

        round = 1
        while True:

            for d,n in to_query:
                k_closest, data = [], None
                if not Node.Equals(n, self.node):
                    msg = utils.build_FIND_VALUE_msg(ID, self.node.asTuple())

                    sock = self.sendall(msg, n[1], close=False)
                    # data = self.get_response(msg['key'])
                    data = self.recvall(sock)
                    utils.close_connection(sock)

                    if data != None:
                        data = json.loads(data)
                        if data['result'][0]: return data['result']
                        # if data['result'][0]: return data
                        k_closest = [(t[0], tuple(t[1])) for t in data['result'][1]]
                        self.update(tuple(data['sender']))

                if (d,n) not in enquired:
                    enquired.append((d, n))

                if data != None and (d,n) not in alives:
                    alives.append((d, n))

                for t in k_closest:
                    if not t in enquired and not t in to_query and not t in pending:
                        pending.append(t)

            to_query.clear()

            if pending == []:
                break

            c = heapq.nsmallest(1, pending)[0][0]
            top = self.node.alpha if c <= closest_node else self.node.k
            closest_node = min(closest_node, c)
            for _ in range(top):
                try:
                    to_query.append(heapq.heappop(pending))
                except:
                    break
            round += 1

        return (False, heapq.nsmallest(self.node.k, enquired), None)
Пример #8
0
    def lookup_node(self, ID):
        ID = int(ID)
        to_query = self.node.get_n_closest(ID, self.node.alpha)

        pending = []
        heapq.heapify(pending)

        myinfo = (self.node.ID ^ ID, self.node.asTuple())
        enquired = [myinfo]
        alives = [myinfo]

        if len(to_query) == 0:
            return [(self.node.ID ^ ID, self.node.asTuple())]
            # return []

        closest_node = heapq.nsmallest(1, to_query)[0][0]

        round = 1
        while True:

            for d,n in to_query:
                k_closest, data = [], None
                if not Node.Equals(n, self.node):

                    # k_closest = n[1].FIND_NODE(ID, self.node.k)
                    msg = utils.build_FIND_NODE_msg(ID, self.node.asTuple())

                    ip, port = n[1], n[2]
                    # self.send_udp_msg(utils.dumps_json(msg).encode(), (ip, port))
                    # # data = self.get_answer(msg['key'])
                    # data = self.get_response(msg['key'])

                    sock = self.sendall(msg, n[1], close=False)
                    # data = self.get_response(msg['key'])
                    data = self.recvall(sock)
                    try:
                        data = json.loads(data)
                    except: data = None
                    utils.close_connection(sock)

                    if data:
                        k_closest = [(t[0], tuple(t[1])) for t in data['result']]
                        self.update(tuple(data['sender']))

                if (d,n) not in enquired:
                    enquired.append((d, n))

                if data != None and (d,n) not in alives:
                    alives.append((d, n))

                for t in k_closest:
                    if not t in enquired and not t in to_query and not t in pending:
                        pending.append(t)

            to_query.clear()

            if pending == []:
                break

            c = heapq.nsmallest(1, pending)[0][0]
           # print(c)
            #print(closest_node)
            top = self.node.alpha if c <= closest_node else self.node.k
            closest_node = min(closest_node, c)
            for _ in range(top):
                try:
                    to_query.append(heapq.heappop(pending))
                except:
                    break
            round += 1

        # return heapq.nsmallest(self.node.k, enquired)
        return heapq.nsmallest(self.node.k, alives)
Пример #9
0
#                 break

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('-uport', '--udp_port', type=int, default=8000)
    parser.add_argument('-id', '--id', type=int, default=-1)
    parser.add_argument('-tport', '--tcp_server_port', type=int, default=9000)
    parser.add_argument('-ip', '--ip', type=str, default=None)

    args = parser.parse_args()

    IP = args.ip
    if not IP:
        hostname = socket.gethostname()
        IP = socket.gethostbyname(hostname)

    import uuid
    ID = int(args.id)
    if ID == -1:
        ID = utils.get_key(uuid.uuid4().hex)

    node = Node(ID, IP, int(args.udp_port), B=160, k=20, alpha=3)

    peer = Peer(node, int(args.tcp_server_port))
    threading._start_new_thread(peer.join, ())
    threading._start_new_thread(peer.check_network, ())
    threading._start_new_thread(peer.attend_clients, ())
    threading._start_new_thread(peer.attend_new_nodes, ())
    peer.serve()