Esempio n. 1
0
def connect(redis_conn, key):
    """
    Establishes connection with a node to:
    1) Send version message
    2) Receive version and verack message
    3) Send getaddr message
    4) Receive addr message containing list of peering nodes
    Stores state and height for node in Redis.
    """
    handshake_msgs = []
    addr_msgs = []

    redis_conn.hset(key, 'state', "")  # Set Redis hash for a new node

    (address, port, services) = key[5:].split("-", 2)
    services = int(services)
    height = redis_conn.get('height')
    if height:
        height = int(height)

    proxy = None
    if address.endswith(".onion"):
        proxy = SETTINGS['tor_proxy']

    conn = Connection((address, int(port)), (SETTINGS['source_address'], 0),
                      socket_timeout=SETTINGS['socket_timeout'],
                      proxy=proxy,
                      protocol_version=SETTINGS['protocol_version'],
                      to_services=services,
                      from_services=SETTINGS['services'],
                      user_agent=SETTINGS['user_agent'],
                      height=height,
                      relay=SETTINGS['relay'])
    try:
        logging.debug("Connecting to %s", conn.to_addr)
        conn.open()
        handshake_msgs = conn.handshake()
        addr_msgs = conn.getaddr()
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("%s: %s", conn.to_addr, err)
    finally:
        conn.close()

    gevent.sleep(0.3)
    redis_pipe = redis_conn.pipeline()
    if len(handshake_msgs) > 0:
        version_msg = handshake_msgs[0]
        from_services = version_msg.get('services', 0)
        if from_services != services:
            logging.debug("%s Expected %d, got %d for services", conn.to_addr,
                          services, from_services)
            key = "node:{}-{}-{}".format(address, port, from_services)
        height_key = "height:{}-{}-{}".format(address, port, from_services)
        redis_pipe.setex(height_key, SETTINGS['max_age'],
                         version_msg.get('height', 0))
        now = int(time.time())
        peers = enumerate_node(redis_pipe, addr_msgs, now)
        logging.debug("%s Peers: %d", conn.to_addr, peers)
        redis_pipe.hset(key, 'state', "up")
    redis_pipe.execute()
Esempio n. 2
0
def connect(redis_conn, key):
    """
    Establishes connection with a node to:
    1) Send version message
    2) Receive version and verack message
    3) Send getaddr message
    4) Receive addr message containing list of peering nodes
    Stores state and height for node in Redis.
    """
    handshake_msgs = []
    addr_msgs = []

    redis_conn.hset(key, 'state', "")  # Set Redis hash for a new node

    (address, port, services) = key[5:].split("-", 2)
    height = redis_conn.get('height')
    if height:
        height = int(height)

    conn = Connection((address, int(port)),
                      (SETTINGS['source_address'], 0),
                      socket_timeout=SETTINGS['socket_timeout'],
                      proxy=SETTINGS['proxy'],
                      protocol_version=SETTINGS['protocol_version'],
                      to_services=int(services),
                      from_services=SETTINGS['services'],
                      user_agent=SETTINGS['user_agent'],
                      height=height,
                      relay=SETTINGS['relay'])
    try:
        logging.debug("Connecting to %s", conn.to_addr)
        conn.open()
        handshake_msgs = conn.handshake()
        addr_msgs = conn.getaddr()
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("%s: %s", conn.to_addr, err)
    finally:
        conn.close()

    gevent.sleep(0.3)
    redis_pipe = redis_conn.pipeline()
    if len(handshake_msgs) > 0:
        height_key = "height:{}-{}-{}".format(address, port, services)
        redis_pipe.setex(height_key, SETTINGS['max_age'],
                         handshake_msgs[0].get('height', 0))
        now = int(time.time())
        peers = enumerate_node(redis_pipe, addr_msgs, now)
        logging.debug("%s Peers: %d", conn.to_addr, peers)
        redis_pipe.hset(key, 'state', "up")
    redis_pipe.execute()
Esempio n. 3
0
    def _getaddr(self, node, port):
        """
        Establishes connection with a node to:
        1) Send version message
        2) Receive version and verack message
        3) Send getaddr message
        4) Receive addr message containing list of adjacent nodes
        """
        to_addr = (node, port)
        conn = Connection(to_addr,
                          socket_timeout=SETTINGS['socket_timeout'],
                          user_agent=SETTINGS['user_agent'],
                          start_height=SETTINGS['start_height'])

        error = ""
        handshake_msgs = []
        addr_msg = {}
        try:
            conn.open()
            handshake_msgs = conn.handshake()
            addr_msg = conn.getaddr()
        except (ProtocolError, socket.error) as err:
            error = str(err)
            logging.debug("{}: {} dropped".format(err, to_addr))
        finally:
            conn.close()

        nodes = None
        degree = 0

        # Record version information for the remote node
        if len(handshake_msgs) > 0:
            if not self.database.has_node(node, table="nodes_version"):
                self.database.add_node_version(node, handshake_msgs[0])

            nodes = []
            if 'addr_list' in addr_msg:
                nodes = self.get_nodes_from_addr_list(addr_msg['addr_list'])
                degree = len(nodes)

        # Cache the result in database for reuse in subsequent getaddr()
        # calls for the same node.
        self.database.add_node_getaddr(node, nodes, error, degree)

        return nodes
Esempio n. 4
0
    def _getaddr(self, node, port):
        """
        Establishes connection with a node to:
        1) Send version message
        2) Receive version and verack message
        3) Send getaddr message
        4) Receive addr message containing list of adjacent nodes
        """
        to_addr = (node, port)
        conn = Connection(to_addr, socket_timeout=SETTINGS['socket_timeout'],
                          user_agent=SETTINGS['user_agent'],
                          start_height=SETTINGS['start_height'])

        error = ""
        handshake_msgs = []
        addr_msg = {}
        try:
            conn.open()
            handshake_msgs = conn.handshake()
            addr_msg = conn.getaddr()
        except (ProtocolError, socket.error) as err:
            error = str(err)
            logging.debug("{}: {} dropped".format(err, to_addr))
        finally:
            conn.close()

        nodes = None
        degree = 0

        # Record version information for the remote node
        if len(handshake_msgs) > 0:
            if not self.database.has_node(node, table="nodes_version"):
                self.database.add_node_version(node, handshake_msgs[0])

            nodes = []
            if 'addr_list' in addr_msg:
                nodes = self.get_nodes_from_addr_list(addr_msg['addr_list'])
                degree = len(nodes)

        # Cache the result in database for reuse in subsequent getaddr()
        # calls for the same node.
        self.database.add_node_getaddr(node, nodes, error, degree)

        return nodes
Esempio n. 5
0
def task():
    """
    Assigned to a worker to retrieve (pop) a node from the reachable set and
    attempt to establish and maintain connection with the node.
    """
    node = REDIS_CONN.spop('reachable')
    if node is None:
        return
    (address, port, services, height) = eval(node)
    node = (address, port)

    if REDIS_CONN.sadd('open', node) == 0:
        logging.debug("Connection exists: %s", node)
        return

    handshake_msgs = []
    conn = Connection(node, (SETTINGS['source_address'], 0),
                      socket_timeout=SETTINGS['socket_timeout'],
                      protocol_version=SETTINGS['protocol_version'],
                      to_services=services,
                      from_services=SETTINGS['services'],
                      user_agent=SETTINGS['user_agent'],
                      height=height,
                      relay=SETTINGS['relay'])
    try:
        conn.open()
        handshake_msgs = conn.handshake()
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("Closing %s (%s)", node, err)
        conn.close()

    if len(handshake_msgs) == 0:
        REDIS_CONN.srem('open', node)
        return

    Keepalive(conn=conn, version_msg=handshake_msgs[0]).keepalive()
    conn.close()
    REDIS_CONN.srem('open', node)
Esempio n. 6
0
def task():
    """
    Assigned to a worker to retrieve (pop) a node from the reachable set and
    attempt to establish and maintain connection with the node.
    """
    node = REDIS_CONN.spop('reachable')
    if node is None:
        return
    (address, port, services, height) = eval(node)
    node = (address, port)

    if REDIS_CONN.sadd('open', node) == 0:
        logging.debug("Connection exists: %s", node)
        return

    handshake_msgs = []
    conn = Connection(node, (SETTINGS['source_address'], 0),
                      socket_timeout=SETTINGS['socket_timeout'],
                      protocol_version=SETTINGS['protocol_version'],
                      to_services=services,
                      from_services=SETTINGS['services'],
                      user_agent=SETTINGS['user_agent'],
                      height=height,
                      relay=SETTINGS['relay'])
    try:
        conn.open()
        handshake_msgs = conn.handshake()
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("Closing %s (%s)", node, err)
        conn.close()

    if len(handshake_msgs) == 0:
        REDIS_CONN.srem('open', node)
        return

    Keepalive(conn=conn, version_msg=handshake_msgs[0]).keepalive()
    conn.close()
    REDIS_CONN.srem('open', node)
Esempio n. 7
0
def connect(redis_conn, key):
    """
    Establishes connection with a node to:
    1) Send version message
    2) Receive version and verack message
    3) Send getaddr message
    4) Receive addr message containing list of peering nodes
    Stores state and height for node in Redis.
    """
    handshake_msgs = []
    addr_msgs = []

    redis_conn.set(key, "")  # Set Redis key for a new node

    (address, port, services) = key[5:].split("-", 2)
    services = int(services)
    height = redis_conn.get('height')
    if height:
        height = int(height)

    proxy = None
    if address.endswith(".onion"):
        proxy = CONF['tor_proxy']

    conn = Connection((address, int(port)), (CONF['source_address'], 0),
                      magic_number=CONF['magic_number'],
                      socket_timeout=CONF['socket_timeout'],
                      proxy=proxy,
                      protocol_version=CONF['protocol_version'],
                      to_services=services,
                      from_services=CONF['services'],
                      user_agent=CONF['user_agent'],
                      height=height,
                      relay=CONF['relay'])
    print(address)
    print(int(port))
    print(CONF['magic_number'])
    print(CONF['socket_timeout'])
    print(proxy)
    print(CONF['protocol_version'])
    print(CONF['services'])
    print(CONF['user_agent'])
    print(height)
    print(CONF['relay'])
    try:
        logging.debug("Connecting to %s", conn.to_addr)
        conn.open()
        handshake_msgs = conn.handshake()
        print("OK")
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("%s: %s", conn.to_addr, err)
        print("just die")

    redis_pipe = redis_conn.pipeline()
    if len(handshake_msgs) > 0:
        try:
            conn.getaddr(block=False)
        except (ProtocolError, ConnectionError, socket.error) as err:
            logging.debug("%s: %s", conn.to_addr, err)
        else:
            addr_wait = 0
            while addr_wait < CONF['socket_timeout']:
                addr_wait += 1
                gevent.sleep(0.3)
                try:
                    msgs = conn.get_messages(commands=['addr'])
                except (ProtocolError, ConnectionError, socket.error) as err:
                    logging.debug("%s: %s", conn.to_addr, err)
                    break
                if msgs and any([msg['count'] > 1 for msg in msgs]):
                    addr_msgs = msgs
                    break

        version_msg = handshake_msgs[0]
        from_services = version_msg.get('services', 0)
        if from_services != services:
            logging.debug("%s Expected %d, got %d for services", conn.to_addr,
                          services, from_services)
            key = "node:{}-{}-{}".format(address, port, from_services)
        height_key = "height:{}-{}-{}".format(address, port, from_services)
        redis_pipe.setex(height_key, CONF['max_age'],
                         version_msg.get('height', 0))
        now = int(time.time())
        (peers, excluded) = enumerate_node(redis_pipe, addr_msgs, now)
        logging.debug("%s Peers: %d (Excluded: %d)", conn.to_addr, peers,
                      excluded)
        redis_pipe.set(key, "")
        redis_pipe.sadd('up', key)
    conn.close()
    redis_pipe.execute()
Esempio n. 8
0
def connect(network, address, port, to_services, network_data, user_agent=None, explicit_p2p=False, p2p_nodes=True,
            from_services=None, keepalive=False, attempt=1):
    now = datetime.datetime.utcnow()
    results = {'network': network, 'address': address, 'port': port, 'timestamp': now, 'seen': 0, 'attempt': attempt}

    try:
        handshake_msgs = []
        new_addrs = []

        proxy = None
        if address.endswith(".onion"):
            proxy = CONF['tor_proxy']

        conn = Connection((address, port),
                          (CONF['source_address'], 0),
                          magic_number=network_data['magic_number'],
                          socket_timeout=CONF['socket_timeout'],
                          proxy=proxy,
                          protocol_version=int(network_data['protocol_version']),
                          min_protocol_version=network_data['min_protocol_version'],
                          to_services=int(to_services),
                          from_services=int(from_services or network_data['services']),
                          user_agent=user_agent or CONF['user_agent'],
                          height=int(network_data['height']),
                          relay=CONF['relay'])

        try:
            conn.open()
        except (ProtocolError, ConnectionError, socket.error) as err:
            results['error'] = str(err)
            logging.debug("connection failed %s %s", type(err), err)
        else:
            try:
                handshake_msgs = conn.handshake()
                assert handshake_msgs
                results['seen'] = 1
                results['height'] = int(handshake_msgs[0]['height'])
                results['version'] = int(handshake_msgs[0]['version'])
                results['user_agent'] = handshake_msgs[0]['user_agent'].decode()
                results['services'] = int(handshake_msgs[0]['services'])
            except (ProtocolError, ConnectionError, socket.error, AssertionError) as err:
                results['error'] = str(err)
                logging.debug("handshake failed %s", err)

            msgs = []
            if len(handshake_msgs) > 0 and (p2p_nodes or explicit_p2p):
                getaddr = True
                chance = CONF['getaddr_prop']
                if chance < 1.0 and p2p_nodes and not explicit_p2p and not "--seed" in sys.argv:
                    if np.random.rand() > chance:
                        getaddr = False

                if getaddr:
                    try:
                        conn.getaddr(block=False)
                        msgs = msgs + conn.get_messages(commands=[b"addr"])
                        time.sleep(5)
                        msgs = msgs + conn.get_messages(commands=[b"addr"])
                    except (ProtocolError, ConnectionError, socket.error) as err:
                        logging.debug("getaddr failed %s", err)
            if keepalive:
                Keepalive(conn, 10).keepalive(addr=True if p2p_nodes else False)
            for msg in msgs:
                if msg['count'] > 1:
                    ts = now.timestamp()
                    for addr in msg['addr_list']:
                        if ts - addr['timestamp'] < 12 * 60 * 60:  # within 6 hours
                            new_addrs.append(addr)
        conn.close()
        return results, new_addrs
    except Exception as err:
        logging.warning("unspecified connection error: %s", err)
        return {}, []
Esempio n. 9
0
def task():
    """
    Assigned to a worker to retrieve (pop) a node from the reachable set and
    attempt to establish and maintain connection with the node.
    """
    node = REDIS_CONN.spop('reachable')
    if node is None:
        return
    (address, port, services, height) = eval(node)
    node = (address, port)

    # Check if prefix has hit its limit
    cidr_key = None
    if ":" in address and CONF['ipv6_prefix'] < 128:
        cidr = ip_to_network(address, CONF['ipv6_prefix'])
        cidr_key = 'ping:cidr:{}'.format(cidr)
        nodes = REDIS_CONN.incr(cidr_key)
        logging.info("+CIDR %s: %d", cidr, nodes)
        if nodes > CONF['nodes_per_ipv6_prefix']:
            logging.info("CIDR limit reached: %s", cidr)
            nodes = REDIS_CONN.decr(cidr_key)
            logging.info("-CIDR %s: %d", cidr, nodes)
            return

    if REDIS_CONN.sadd('open', node) == 0:
        logging.info("Connection exists: %s", node)
        if cidr_key:
            nodes = REDIS_CONN.decr(cidr_key)
            logging.info("-CIDR %s: %d", cidr, nodes)
        return

    proxy = None
    if address.endswith(".onion"):
        proxy = random.choice(CONF['tor_proxies'])

    handshake_msgs = []
    conn = Connection(node,
                      (CONF['source_address'], 0),
                      magic_number=CONF['magic_number'],
                      socket_timeout=CONF['socket_timeout'],
                      proxy=proxy,
                      protocol_version=CONF['protocol_version'],
                      to_services=services,
                      from_services=CONF['services'],
                      user_agent=CONF['user_agent'],
                      height=height,
                      relay=CONF['relay'])
    try:
        logging.debug("Connecting to %s", conn.to_addr)
        conn.open()
        handshake_msgs = conn.handshake()
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("Closing %s (%s)", node, err)
        conn.close()

    if len(handshake_msgs) == 0:
        if cidr_key:
            nodes = REDIS_CONN.decr(cidr_key)
            logging.info("-CIDR %s: %d", cidr, nodes)
        REDIS_CONN.srem('open', node)
        return

    if address.endswith(".onion"):
        # Map local port to .onion node
        local_port = conn.socket.getsockname()[1]
        logging.info("Local port %s: %d", conn.to_addr, local_port)
        REDIS_CONN.set('onion:{}'.format(local_port), conn.to_addr)

    Keepalive(conn=conn, version_msg=handshake_msgs[0]).keepalive()
    conn.close()
    if cidr_key:
        nodes = REDIS_CONN.decr(cidr_key)
        logging.info("-CIDR %s: %d", cidr, nodes)
    REDIS_CONN.srem('open', node)
Esempio n. 10
0
def task():
    """
    Assigned to a worker to retrieve (pop) a node from the reachable set and
    attempt to establish and maintain connection with the node.
    """
    node = REDIS_CONN.spop('reachable')
    if node is None:
        return
    (address, port, services, height) = eval(node)
    node = (address, port)

    # Check if prefix has hit its limit
    cidr_key = None
    if ":" in address and SETTINGS['ipv6_prefix'] < 128:
        cidr = ip_to_network(address, SETTINGS['ipv6_prefix'])
        cidr_key = 'ping:cidr:{}'.format(cidr)
        nodes = REDIS_CONN.incr(cidr_key)
        logging.info("+CIDR %s: %d", cidr, nodes)
        if nodes > SETTINGS['nodes_per_ipv6_prefix']:
            logging.info("CIDR limit reached: %s", cidr)
            nodes = REDIS_CONN.decr(cidr_key)
            logging.info("-CIDR %s: %d", cidr, nodes)
            return

    if REDIS_CONN.sadd('open', node) == 0:
        logging.info("Connection exists: %s", node)
        if cidr_key:
            nodes = REDIS_CONN.decr(cidr_key)
            logging.info("-CIDR %s: %d", cidr, nodes)
        return

    proxy = None
    if address.endswith(".onion"):
        proxy = SETTINGS['tor_proxy']

    handshake_msgs = []
    conn = Connection(node, (SETTINGS['source_address'], 0),
                      socket_timeout=SETTINGS['socket_timeout'],
                      proxy=proxy,
                      protocol_version=SETTINGS['protocol_version'],
                      to_services=services,
                      from_services=SETTINGS['services'],
                      user_agent=SETTINGS['user_agent'],
                      height=height,
                      relay=SETTINGS['relay'])
    try:
        logging.debug("Connecting to %s", conn.to_addr)
        conn.open()
        handshake_msgs = conn.handshake()
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("Closing %s (%s)", node, err)
        conn.close()

    if len(handshake_msgs) == 0:
        if cidr_key:
            nodes = REDIS_CONN.decr(cidr_key)
            logging.info("-CIDR %s: %d", cidr, nodes)
        REDIS_CONN.srem('open', node)
        return

    if address.endswith(".onion"):
        # Map local port to .onion node
        local_port = conn.socket.getsockname()[1]
        logging.info("%s: 127.0.0.1:%d", conn.to_addr, local_port)
        REDIS_CONN.set('onion:{}'.format(local_port), conn.to_addr)

    Keepalive(conn=conn, version_msg=handshake_msgs[0]).keepalive()
    conn.close()
    if cidr_key:
        nodes = REDIS_CONN.decr(cidr_key)
        logging.info("-CIDR %s: %d", cidr, nodes)
    REDIS_CONN.srem('open', node)
Esempio n. 11
0
def connect(redis_conn, key):
    """
    Establishes connection with a node to:
    1) Send version message
    2) Receive version and verack message
    3) Send getaddr message
    4) Receive addr message containing list of peering nodes
    Stores state and height for node in Redis.
    """
    handshake_msgs = []
    addr_msgs = []

    redis_conn.set(key, "")  # Set Redis key for a new node

    (address, port, services) = key[5:].split("-", 2)
    services = int(services)
    height = redis_conn.get('height')
    if height:
        height = int(height)

    proxy = None
    if address.endswith(".onion"):
        proxy = CONF['tor_proxy']

    conn = Connection((address, int(port)),
                      (CONF['source_address'], 0),
                      magic_number=CONF['magic_number'],
                      socket_timeout=CONF['socket_timeout'],
                      proxy=proxy,
                      protocol_version=CONF['protocol_version'],
                      to_services=services,
                      from_services=CONF['services'],
                      user_agent=CONF['user_agent'],
                      height=height,
                      relay=CONF['relay'])
    try:
        logging.debug("Connecting to %s", conn.to_addr)
        conn.open()
        handshake_msgs = conn.handshake()
    except (ProtocolError, ConnectionError, socket.error) as err:
        logging.debug("%s: %s", conn.to_addr, err)

    redis_pipe = redis_conn.pipeline()
    if len(handshake_msgs) > 0:
        try:
            conn.getaddr(block=False)
        except (ProtocolError, ConnectionError, socket.error) as err:
            logging.debug("%s: %s", conn.to_addr, err)
        else:
            addr_wait = 0
            while addr_wait < CONF['socket_timeout']:
                addr_wait += 1
                gevent.sleep(0.3)
                try:
                    msgs = conn.get_messages(commands=['addr'])
                except (ProtocolError, ConnectionError, socket.error) as err:
                    logging.debug("%s: %s", conn.to_addr, err)
                    break
                if msgs and any([msg['count'] > 1 for msg in msgs]):
                    addr_msgs = msgs
                    break

        version_msg = handshake_msgs[0]
        from_services = version_msg.get('services', 0)
        if from_services != services:
            logging.debug("%s Expected %d, got %d for services", conn.to_addr,
                          services, from_services)
            key = "node:{}-{}-{}".format(address, port, from_services)
        height_key = "height:{}-{}-{}".format(address, port, from_services)
        redis_pipe.setex(height_key, CONF['max_age'],
                         version_msg.get('height', 0))
        now = int(time.time())
        (peers, excluded) = enumerate_node(redis_pipe, addr_msgs, now)
        logging.debug("%s Peers: %d (Excluded: %d)",
                      conn.to_addr, peers, excluded)
        redis_pipe.set(key, "")
        redis_pipe.sadd('up', key)
    conn.close()
    redis_pipe.execute()
Esempio n. 12
0
class ClientHandler:

    LOGIN_MSG = 'Choose a nickname.'
    HELLO_MSG = 'You are in, {}!'
    NICK_TAKEN_MSG = 'Nickname {} is taken, choose another one.'

    SHUTDOWN_MSG = 'Server shut down and you were disconnected.'

    def __init__(self, sock, addr, server):
        self.server = server
        self.conn = Connection(sock, addr)
        self.inbox = Queue(maxsize=MAX_CLIENT_QUEUE)
        self.nickname = None
        self.channel = None

    @property
    def addr(self):
        return self.conn.addr

    def init(self):
        try:
            self.conn.send_msg(self.LOGIN_MSG)

            while True:
                try:
                    nickname = self.conn.recv_msg()

                    self.server.register_client(nickname, self)
                    self.server.addr_client[self.addr] = self

                    self.nickname = nickname
                    self.conn.send_msg(self.HELLO_MSG.format(nickname))
                    break
                except NickTakenError:
                    self.conn.send_msg(self.NICK_TAKEN_MSG.format(nickname))
        except OSError:
            self.shutdown()

        # Connection fully established.
        self.server.subscribe(self.nickname, 'default')
        self.channel = self.server.channels['default']
        self.in_channel()

    def shutdown(self):
        try:
            self.conn.send_msg(self.SHUTDOWN_MSG)
            self.conn.close()
        except OSError:
            pass  # yeah, really

        self.channel.unsub(self.nickname)
        self.server.remove_client(self.nickname)

    def in_channel(self):
        receiver = threading.Thread(target=self.process_inbox, daemon=True)
        receiver.start()

        try:
            while True:
                msg = self.conn.recv_msg()
                msg = '{}: {}'.format(self.nickname, msg)
                self.channel.publish(('tcp', msg), self.nickname)
        except ConnectionError:
            self.shutdown()

    def process_inbox(self):
        try:
            while True:
                kin, msg = self.inbox.get()
                if kin == 'udp':
                    send_udp(msg, self.addr)
                else:
                    self.conn.send_msg(msg)
        except ConnectionError:
            self.shutdown()

    def push(self, msg):
        self.inbox.put(msg)

    def handle_udp(self, msg):
        self.channel.publish(('udp', msg), self.nickname)
Esempio n. 13
0
class Client:
    def __init__(self, server_host='127.0.0.1', server_port=8000, client_host='127.0.0.1', client_port=8001):
        self.server_addr = (server_host, server_port)
        self.client_addr = (client_host, client_port)
        self.conn = None

    def run(self):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            s.bind(self.client_addr)
            s.connect(self.server_addr)
            self.conn = Connection(s, self.server_addr)

            receiver = threading.Thread(target=self.receive, daemon=True)
            receiver.start()
            udp_receiver = threading.Thread(target=self.receive_udp, daemon=True)
            udp_receiver.start()

            try:
                while True:
                    msg = input()

                    if msg == 'U' or msg == 'M':
                        with open('ascii.txt', 'r', encoding='ascii') as ascii_art:
                            content = ascii_art.read()

                        if msg == 'U':
                            addr = self.server_addr
                        else:
                            addr = MULTICAST_ADDR
                        send_udp(content, addr, self.client_addr)
                    else:
                        self.conn.send_msg(msg)
            except KeyboardInterrupt:
                print('Received Ctrl+C.')
            except ConnectionError:
                print('Connection to server closed.')

    def receive(self):
        try:
            while True:
                msg = self.conn.recv_msg()
                print('>>> {}'.format(msg))
        except ConnectionError:
            self.conn.close()

    def receive_udp(self):
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as u_sock:
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as m_sock:
                u_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                u_sock.bind(self.client_addr)

                host = socket.gethostbyname(socket.gethostname())
                m_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                m_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
                                  socket.inet_aton(MULTICAST_ADDR[0]) + socket.inet_aton(host))
                m_sock.bind(MULTICAST_ADDR)

                ev_loop = select.epoll()
                u_fd, m_fd = u_sock.fileno(), m_sock.fileno()
                ev_loop.register(u_fd, select.EPOLLIN)
                ev_loop.register(m_fd, select.EPOLLIN)

                try:
                    while True:
                        events = ev_loop.poll()
                        for file_no, event in events:
                            if event | select.EPOLLIN:
                                if file_no == u_fd:
                                    msg = u_sock.recv(MAX_UDP_SIZE)
                                else:
                                    msg, addr = m_sock.recvfrom(MAX_UDP_SIZE)
                                    if addr == self.client_addr:
                                        continue
                                print(msg.decode())
                except ConnectionError:
                    self.conn.close()