From 270c45aead51e9bff14a6ac591cea6ad3244380d Mon Sep 17 00:00:00 2001
From: King's Way <io@stdio.io>
Date: Fri, 18 Jun 2021 18:40:29 +0800
Subject: [PATCH 1/3] More accurate packet loss rate and faster convergence

---
 clients/client-linux.py  | 25 +++++++++++++------------
 clients/client-psutil.py | 26 ++++++++++++++------------
 2 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/clients/client-linux.py b/clients/client-linux.py
index 8fa8bb2..ce15b5a 100755
--- a/clients/client-linux.py
+++ b/clients/client-linux.py
@@ -15,6 +15,7 @@ PORT = 35601
 PASSWORD = "USER_DEFAULT_PASSWORD"
 INTERVAL = 1
 PORBEPORT = 80
+PING_PACKET_HISTORY_LEN = 100
 CU = "cu.tz.cloudcpp.com"
 CT = "ct.tz.cloudcpp.com"
 CM = "cm.tz.cloudcpp.com"
@@ -28,6 +29,10 @@ import sys
 import json
 import subprocess
 import threading
+try:
+    from queue import Queue     # python3
+except ImportError:
+    from Queue import Queue     # python2
 
 def get_uptime():
     with open('/proc/uptime', 'r') as f:
@@ -156,27 +161,23 @@ netSpeed = {
 
 def _ping_thread(host, mark, port):
     lostPacket = 0
-    allPacket = 0
-    startTime = time.time()
+    packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
 
     while True:
+        if packet_queue.full():
+            if packet_queue.get() == 0:
+                lostPacket -= 1
         try:
             b = timeit.default_timer()
             socket.create_connection((host, port), timeout=1).close()
             pingTime[mark] = int((timeit.default_timer()-b)*1000)
+            packet_queue.put(1)
         except:
             lostPacket += 1
-        finally:
-            allPacket += 1
+            packet_queue.put(0)
 
-        if allPacket > 100:
-            lostRate[mark] = float(lostPacket) / allPacket
-
-        endTime = time.time()
-        if endTime - startTime > 3600:
-            lostPacket = 0
-            allPacket = 0
-            startTime = endTime
+        if packet_queue.qsize() > 30:
+            lostRate[mark] = float(lostPacket) / packet_queue.qsize()
 
         time.sleep(INTERVAL)
 
diff --git a/clients/client-psutil.py b/clients/client-psutil.py
index 799ce56..278f5f8 100755
--- a/clients/client-psutil.py
+++ b/clients/client-psutil.py
@@ -16,6 +16,7 @@ PORT = 35601
 PASSWORD = "USER_DEFAULT_PASSWORD"
 INTERVAL = 1
 PORBEPORT = 80
+PING_PACKET_HISTORY_LEN = 100
 CU = "cu.tz.cloudcpp.com"
 CT = "ct.tz.cloudcpp.com"
 CM = "cm.tz.cloudcpp.com"
@@ -28,6 +29,11 @@ import json
 import psutil
 import sys
 import threading
+import threading
+try:
+    from queue import Queue     # python3
+except ImportError:
+    from Queue import Queue     # python2
 
 def get_uptime():
     return int(time.time() - psutil.boot_time())
@@ -140,27 +146,23 @@ netSpeed = {
 
 def _ping_thread(host, mark, port):
     lostPacket = 0
-    allPacket = 0
-    startTime = time.time()
+    packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
 
     while True:
+        if packet_queue.full():
+            if packet_queue.get() == 0:
+                lostPacket -= 1
         try:
             b = timeit.default_timer()
             socket.create_connection((host, port), timeout=1).close()
             pingTime[mark] = int((timeit.default_timer() - b) * 1000)
+            packet_queue.put(1)
         except:
             lostPacket += 1
-        finally:
-            allPacket += 1
+            packet_queue.put(0)
 
-        if allPacket > 100:
-            lostRate[mark] = float(lostPacket) / allPacket
-
-        endTime = time.time()
-        if endTime - startTime > 3600:
-            lostPacket = 0
-            allPacket = 0
-            startTime = endTime
+        if packet_queue.qsize() > 30:
+            lostRate[mark] = float(lostPacket) / packet_queue.qsize()
 
         time.sleep(INTERVAL)
 

From 05f9784b1ef592092a2affb13b551e35ed495d48 Mon Sep 17 00:00:00 2001
From: King's Way <io@stdio.io>
Date: Fri, 18 Jun 2021 19:18:51 +0800
Subject: [PATCH 2/3] ping_thread, prefer ipv4 first

---
 clients/client-linux.py  | 23 +++++++++++++++++------
 clients/client-psutil.py | 23 +++++++++++++++++------
 2 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/clients/client-linux.py b/clients/client-linux.py
index ce15b5a..c3ef97f 100755
--- a/clients/client-linux.py
+++ b/clients/client-linux.py
@@ -14,7 +14,8 @@ USER = "s01"
 PORT = 35601
 PASSWORD = "USER_DEFAULT_PASSWORD"
 INTERVAL = 1
-PORBEPORT = 80
+PROBEPORT = 80
+PROBE_PROTOCOL_PREFER = "ipv4"  # ipv4, ipv6
 PING_PACKET_HISTORY_LEN = 100
 CU = "cu.tz.cloudcpp.com"
 CT = "ct.tz.cloudcpp.com"
@@ -121,7 +122,7 @@ def ip_status():
     ip_check = 0
     for i in [CU, CT, CM]:
         try:
-            socket.create_connection((i, PORBEPORT), timeout=1).close()
+            socket.create_connection((i, PROBEPORT), timeout=1).close()
         except:
             ip_check += 1
     if ip_check >= 2:
@@ -163,13 +164,23 @@ def _ping_thread(host, mark, port):
     lostPacket = 0
     packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
 
+    IP = host
+    if host.count(':') < 1:     # if not plain ipv6 address, means ipv4 address or hostname
+        try:
+            if PROBE_PROTOCOL_PREFER == 'ipv4':
+                IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
+            else:
+                IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
+        except Exception:
+                pass
+
     while True:
         if packet_queue.full():
             if packet_queue.get() == 0:
                 lostPacket -= 1
         try:
             b = timeit.default_timer()
-            socket.create_connection((host, port), timeout=1).close()
+            socket.create_connection((IP, port), timeout=1).close()
             pingTime[mark] = int((timeit.default_timer()-b)*1000)
             packet_queue.put(1)
         except:
@@ -212,7 +223,7 @@ def get_realtime_date():
         kwargs={
             'host': CU,
             'mark': '10010',
-            'port': PORBEPORT
+            'port': PROBEPORT
         }
     )
     t2 = threading.Thread(
@@ -220,7 +231,7 @@ def get_realtime_date():
         kwargs={
             'host': CT,
             'mark': '189',
-            'port': PORBEPORT
+            'port': PROBEPORT
         }
     )
     t3 = threading.Thread(
@@ -228,7 +239,7 @@ def get_realtime_date():
         kwargs={
             'host': CM,
             'mark': '10086',
-            'port': PORBEPORT
+            'port': PROBEPORT
         }
     )
     t4 = threading.Thread(
diff --git a/clients/client-psutil.py b/clients/client-psutil.py
index 278f5f8..307f3dd 100755
--- a/clients/client-psutil.py
+++ b/clients/client-psutil.py
@@ -15,7 +15,8 @@ USER = "s01"
 PORT = 35601
 PASSWORD = "USER_DEFAULT_PASSWORD"
 INTERVAL = 1
-PORBEPORT = 80
+PROBEPORT = 80
+PROBE_PROTOCOL_PREFER = "ipv4"  # ipv4, ipv6
 PING_PACKET_HISTORY_LEN = 100
 CU = "cu.tz.cloudcpp.com"
 CT = "ct.tz.cloudcpp.com"
@@ -106,7 +107,7 @@ def ip_status():
     ip_check = 0
     for i in [CU, CT, CM]:
         try:
-            socket.create_connection((i, PORBEPORT), timeout=1).close()
+            socket.create_connection((i, PROBEPORT), timeout=1).close()
         except:
             ip_check += 1
     if ip_check >= 2:
@@ -148,13 +149,23 @@ def _ping_thread(host, mark, port):
     lostPacket = 0
     packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
 
+    IP = host
+    if host.count(':') < 1:     # if not plain ipv6 address, means ipv4 address or hostname
+        try:
+            if PROBE_PROTOCOL_PREFER == 'ipv4':
+                IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
+            else:
+                IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
+        except Exception:
+                pass
+
     while True:
         if packet_queue.full():
             if packet_queue.get() == 0:
                 lostPacket -= 1
         try:
             b = timeit.default_timer()
-            socket.create_connection((host, port), timeout=1).close()
+            socket.create_connection((IP, port), timeout=1).close()
             pingTime[mark] = int((timeit.default_timer() - b) * 1000)
             packet_queue.put(1)
         except:
@@ -193,7 +204,7 @@ def get_realtime_date():
         kwargs={
             'host': CU,
             'mark': '10010',
-            'port': PORBEPORT
+            'port': PROBEPORT
         }
     )
     t2 = threading.Thread(
@@ -201,7 +212,7 @@ def get_realtime_date():
         kwargs={
             'host': CT,
             'mark': '189',
-            'port': PORBEPORT
+            'port': PROBEPORT
         }
     )
     t3 = threading.Thread(
@@ -209,7 +220,7 @@ def get_realtime_date():
         kwargs={
             'host': CM,
             'mark': '10086',
-            'port': PORBEPORT
+            'port': PROBEPORT
         }
     )
     t4 = threading.Thread(

From fdf5f03a13d48ec64401a2c95743650ca4ce6d30 Mon Sep 17 00:00:00 2001
From: King's Way <io@stdio.io>
Date: Sat, 3 Jul 2021 15:26:39 +0800
Subject: [PATCH 3/3] take 'Connection Refused' as a successful ping probe

---
 clients/client-linux.py  | 14 ++++++++++----
 clients/client-psutil.py | 11 ++++++++---
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/clients/client-linux.py b/clients/client-linux.py
index c3ef97f..c946300 100755
--- a/clients/client-linux.py
+++ b/clients/client-linux.py
@@ -28,6 +28,7 @@ import re
 import os
 import sys
 import json
+import errno
 import subprocess
 import threading
 try:
@@ -181,11 +182,16 @@ def _ping_thread(host, mark, port):
         try:
             b = timeit.default_timer()
             socket.create_connection((IP, port), timeout=1).close()
-            pingTime[mark] = int((timeit.default_timer()-b)*1000)
+            pingTime[mark] = int((timeit.default_timer() - b) * 1000)
             packet_queue.put(1)
-        except:
-            lostPacket += 1
-            packet_queue.put(0)
+        except socket.error as error:
+            if error.errno == errno.ECONNREFUSED:
+                pingTime[mark] = int((timeit.default_timer() - b) * 1000)
+                packet_queue.put(1)
+            #elif error.errno == errno.ETIMEDOUT:
+            else:
+                lostPacket += 1
+                packet_queue.put(0)
 
         if packet_queue.qsize() > 30:
             lostRate[mark] = float(lostPacket) / packet_queue.qsize()
diff --git a/clients/client-psutil.py b/clients/client-psutil.py
index 307f3dd..80a9810 100755
--- a/clients/client-psutil.py
+++ b/clients/client-psutil.py
@@ -168,9 +168,14 @@ def _ping_thread(host, mark, port):
             socket.create_connection((IP, port), timeout=1).close()
             pingTime[mark] = int((timeit.default_timer() - b) * 1000)
             packet_queue.put(1)
-        except:
-            lostPacket += 1
-            packet_queue.put(0)
+        except socket.error as error:
+            if error.errno == errno.ECONNREFUSED:
+                pingTime[mark] = int((timeit.default_timer() - b) * 1000)
+                packet_queue.put(1)
+            #elif error.errno == errno.ETIMEDOUT:
+            else:
+                lostPacket += 1
+                packet_queue.put(0)
 
         if packet_queue.qsize() > 30:
             lostRate[mark] = float(lostPacket) / packet_queue.qsize()