From 3af2944170f6b18954f7f0e0949547e0f941aef4 Mon Sep 17 00:00:00 2001 From: netrsr Date: Thu, 24 Jun 2021 12:55:39 +0200 Subject: [PATCH] integration done --- client_client.py | 40 +++++++++++++++------------ daemon_file.py | 72 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 38 deletions(-) diff --git a/client_client.py b/client_client.py index 8a7a9ec..df63256 100644 --- a/client_client.py +++ b/client_client.py @@ -12,6 +12,7 @@ import config import sctp import json +import os import threading import random @@ -20,28 +21,28 @@ class Client(): def __init__(self): self.client_list = dict() self.username = '' + self.stcp_sock = object - @staticmethod - def sctp_handler(client_port: int): + + def sctp_handler(self, client_port: int): # SCTP socket creation sock = sctp.sctpsocket_udp(socket.AF_INET) - # get notifications on assoc state - tmp = sctp.event_subscribe(sock) - tmp.set_association(1) - tmp.set_data_io(1) + self.stcp_sock = sock sock.autoclose = 0 sock.bind(('', client_port)) + sock.sctp_send(msg=b'0', to=(config.SERVER_IP, config.SCTP_PORT)) while True: try: fromaddr, flags, msgret, notif = sock.sctp_recv(2048) - if notif.state == 3: - print(f'Client {sock.getpaddr(notif.assoc_id)} is down.') - elif notif.state == 0: - print.info(f'Client {sock.getpaddr(notif.assoc_id)} is up.') + print(f'CLIENT: Received an update of client base') + + client_list = json.loads(msgret.decode('utf-8')) + self.client_list = client_list except: pass + @staticmethod def multicast_handler(client_port: int): # create the datagram socket @@ -101,8 +102,7 @@ def tcp_handler(self, _port: int): def tcp_listener(_port: int): s = socket.socket() # host = socket.gethostname() - host = '0.0.0.0' - s.bind((host, _port)) + s.bind(('', _port)) s.listen(5) print('TCP listener started on port', _port) @@ -124,9 +124,12 @@ def tcp_listener(_port: int): @staticmethod def do_list(clients: List): print("Available clients:") - for client in clients: - print(f'address: {client["ip"]}:{client["port"]}, nickname: {client["nickname"]}') + if not client['online']: + print(f'address: {client["ip"]}:{client["port"]}, nickname: {client["nickname"]} *offline*') + else: + print(f'address: {client["ip"]}:{client["port"]}, nickname: {client["nickname"]} *online*') + @staticmethod def do_connect(address: Dict, _username: str) -> bool: @@ -173,7 +176,6 @@ def handle_actions(self, clients: List, _username: str): client = {} # check if client_address is an IP:port string or client name cli_filtered = list(filter(lambda c: c['nickname'] == client_address, clients)) - print(cli_filtered) if len(cli_filtered): # client name found -> assign client client['ip'] = cli_filtered[0]['ip'] # TODO: change this +1 @@ -195,7 +197,8 @@ def handle_actions(self, clients: List, _username: str): if action == 'exit': print('Exiting...') - sys.exit(1) + self.stcp_sock.close() + os._exit(1) if __name__ == '__main__': @@ -211,11 +214,14 @@ def handle_actions(self, clients: List, _username: str): port = random.randint(50_000, 65_000) # pass selected port to the TCP thread, in order to listen on the same port # thread in the background as daemon - th = threading.Thread(target=s.tcp_handler, args=(port,), daemon=True) + th = threading.Thread(target=s.tcp_handler, args=(port,)) th.start() s.multicast_handler(port) th.join() + th_ = threading.Thread(target=s.sctp_handler, args=(port,)) + th_.start() + print(s.client_list) # TODO: smart port allocation diff --git a/daemon_file.py b/daemon_file.py index 4b458a6..424b47f 100644 --- a/daemon_file.py +++ b/daemon_file.py @@ -9,14 +9,9 @@ from daemon import runner -client_base = {"clients": [ - { - "ip": "192.168.0.1", - "port": 2250, - "nickname": "pepka", - "online": True - } -]} +client_base = {"clients": []} + +cli_assoc = dict() class App(): @@ -29,6 +24,9 @@ def __init__(self): self.pidfile_timeout = 5 def run(self): + thread = threading.Thread(target=self.sctp_handler, args=(), daemon=True) + # run thread in the background as daemon + thread.start() while True: # main thread self.multicast_handler() @@ -72,28 +70,64 @@ def tcp_handler(address): sock.close() @staticmethod - def sctp_handler(address): - logger.info(f'Starting STCP session for {address}') + def update_client_base(socket): + for client in client_base['clients']: + if client['online'] == True: + _ = (client['ip'], client['port']) + logger.info(f'Sending client base update to...{_[0]}:{_[1]}') + # do not send the client its own information + _tmp = {"clients": + [ + x for x in client_base['clients'] if x['ip']!= client['ip'] or x['port']!= client['port'] + ] + } + if _tmp['clients']: + # convert dict structure to bytes + logger.info(_tmp) + msg = json.dumps(_tmp).encode('utf-8') + socket.sctp_send(msg, to=_) + + def sctp_handler(self): + logger.info(f'Starting STCP session') # SCTP socket creation sock = sctp.sctpsocket_udp(socket.AF_INET) # get notifications on assoc state tmp = sctp.event_subscribe(sock) tmp.set_association(1) - tmp.set_data_io(1) - sock.autoclose = 0 sock.bind(('', config.SCTP_PORT)) - sock.sctp_send(msg=b'0', to=address) + sock.listen(5) while True: try: fromaddr, flags, msgret, notif = sock.sctp_recv(2048) if notif.state == 3: - logger.info(f'Client {sock.getpaddr(notif.assoc_id)} is down.') - elif notif.state == 0: - logger.info(f'Client {sock.getpaddr(notif.assoc_id)} is up.') + _ = cli_assoc[notif.assoc_id] + del cli_assoc[notif.assoc_id] + logger.info(f'Client {_[0]}:{_[1]} is down.') + + for client in client_base['clients']: + if client['ip'] == _[0] and client['port'] == _[1] and client['online']==True: + client['online'] = False + + self.update_client_base(sock) + + else: + _ = sock.getpaddrs(notif.assoc_id)[1] + logger.info(f'Client {_[0]}:{_[1]} is up.') + # assign association id to the client + cli_assoc[notif.assoc_id] = _ + + for client in client_base['clients']: + if client['ip'] == _[0] and client['port'] == _[1] and client['online']==False: + client['online'] = True + + self.update_client_base(sock) + except: pass + + def multicast_handler(self): server_address = ('', config.MULTICAST_PORT) @@ -113,15 +147,11 @@ def multicast_handler(self): logger.info(f'Listening for multicast messages') data, address = sock.recvfrom(1024) logger.info(f'Received multicast message from {address}') - # call TCP session thread = threading.Thread(target=self.tcp_handler, args=(address,), daemon=True) # run thread in the background as daemon thread.start() - # call SCTP session - _thread = threading.Thread(target=self.sctp_handler, args=(address,), daemon=True) - # run thread in the background as daemon - _thread.start() + if __name__ == '__main__':