From 96e0649ea5717668603841ba9c4c6b654d6ad132 Mon Sep 17 00:00:00 2001
From: swee <meow@swee.codes>
Date: Wed, 5 Feb 2025 12:24:40 -0800
Subject: [PATCH] Update server.py

---
 server.py | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/server.py b/server.py
index 5f2b0f2..bab8d7b 100644
--- a/server.py
+++ b/server.py
@@ -33,7 +33,7 @@ def isalphanumeric(text:str, channel=False):
 def getident(hostt:str, clientport:int, ssll:bool):
     try:
         identsender = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        identsender.settimeout(5)
+        identsender.settimeout(2)
         responsee = ""
         try:
             identsender.connect((hostt, 113))
@@ -193,6 +193,7 @@ if ssl_option:
         sockets_ssl[i].listen(1)
 opened=True
 lower_chans = {} # Channel names in lowercase
+"""
 def pinger(nick, connection):
     global property_list
     while nick in property_list:
@@ -219,6 +220,7 @@ def pinger(nick, connection):
                 connection.shutdown(socket.SHUT_WR)
                 connection.close()
                 break
+"""
 def session(connection, client, ip, isssl=False):
     global property_list
     global channels_list
@@ -239,8 +241,22 @@ def session(connection, client, ip, isssl=False):
     pendingCommands = "" # list of commands that were executed before verification
     unfinished = False
     textt = ""
+    last_ping = time.time()
+    ping_pending = False
     pendingSend = "" # Text that should be sent to the client
     IRCv3Features = [] # List of Acknowledged IRCv3 features.
+    def ping(): # Ping
+        if pending != "*":
+            if (time.time() - last_ping) > 30 and not ping_pending:
+                print(f"Sending ping msg to {pending}")
+                ping_pending = True
+                time.sleep(0.5)
+                connection.sendall(bytes(f"PING {server}\r\n","UTF-8"))
+            else ping_pending and (time.time() - last_ping) > ping_timeout:
+                cause = f"Ping timeout: {ping_timeout} seconds"
+                print(f"{pending} timed out.")
+                return True
+        return False
     def tags(): # Get IRCv3 tags
         tags = ""
         if "server-time" in IRCv3Features:
@@ -292,7 +308,9 @@ def session(connection, client, ip, isssl=False):
                     break
             except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
                 print("Skipable error occurred.")
-                pass
+            except socket.timeout:
+                print("Socket timed out, ticking...")
+                data = bytes("", "UTF-8")
             except SSL.ZeroReturnError:
                 print(traceback.format_exc())
                 cause = "Remote host closed the connection"
@@ -304,6 +322,8 @@ def session(connection, client, ip, isssl=False):
             print("Received data: {}".format(data))
             try:
                 textt += data.decode()
+                if ping():
+                    break
                 if textt[-1] == "\n":
                     for text in textt.replace("\r", "").split("\n"):
                         for i in socketListeners:
@@ -366,12 +386,11 @@ def session(connection, client, ip, isssl=False):
                             cleanup_manual()
                             print(f"User {pending} successfully logged in.")
                             nickname_list[pending] = connection
-                            property_list[pending] = {"host": hostname, "username": clident if clident != None else f"~{username }", "realname": realname, "modes": "iw", "last_ping": time.time(), "ping_pending": False, "away": False, "identified": False, "ssl": isssl, "v3cap": IRCv3Features}
+                            property_list[pending] = {"host": hostname, "username": clident if clident != None else f"~{username }", "realname": realname, "modes": "iw", "away": False, "identified": False, "ssl": isssl, "v3cap": IRCv3Features}
                             lower_nicks[pending.lower()] = pending
                             for i in socketListeners:
                                 if "onValidate" in dir(i):
                                     i.onValidate(socket=connection, ip=client[0], v3cap=IRCv3Features)
-                            threading.Thread(target=pinger, args=[pending, connection]).start()
                             if clident == None:
                                 rident = f"~{username}"
                             connection.sendall(bytes(f"{tags()}:{server} 001 {pending} :Welcome to the {displayname} Internet Relay Chat Network {pending}\r\n", "UTF-8"))
@@ -490,8 +509,8 @@ def session(connection, client, ip, isssl=False):
                                     e = text.split(" ")[1]
                                     if e == server or e == f":{server}":
                                         print(pending + " replied to PING.")
-                                        property_list[pending]["last_ping"] = time.time()
-                                        property_list[pending]["ping_pending"] = False
+                                        last_ping = time.time()
+                                        ping_pending = False
                                 elif command == "NICK":
                                     if len(args) == 0:
                                         connection.sendall(bytes(f"{tags()}:{server} 461 {pending} {command} :Not enough parameters\r\n","UTF-8"))
@@ -528,11 +547,7 @@ def session(connection, client, ip, isssl=False):
                                             nickname_list[pending2] = nickname_list.pop(pending)
                                             del lower_nicks[pending.lower()]
                                             lower_nicks[pending2.lower()] = pending2
-                                            print("starting pinger...")
                                             pending = pending2
-                                            property_list[pending2]["ping_pending"] = False
-                                            property_list[pending2]["last_ping"] = time.time()
-                                            threading.Thread(target=pinger, args=[pending, connection]).start()
                                             print(f"User {pending} set nick")
                                             print("Broadcasting nickname change...")
                                 elif command == "PART":
@@ -848,6 +863,7 @@ def ssl_session(sock):
                 ctx.use_privatekey_file(ssl_pkey)
                 ctx.use_certificate_chain_file(ssl_cert)
                 conn = SSL.Connection(ctx, connection)
+                conn.settimeout(5)
                 conn.set_accept_state()
                 conn.do_handshake()
                 threading.Thread(target=session, daemon=True, args=[conn, client, ip_to, True]).start()