Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion pythonping/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ def __init__(self, target, payload_provider, timeout, interval, socket_options=(
# note that to make Communicator instances thread safe, the seed ID must be unique per thread
if self.seed_id is None:
self.seed_id = os.getpid() & 0xFFFF
self.sent_times = {}

def __del__(self):
pass
Expand All @@ -314,6 +315,11 @@ def send_ping(self, packet_id, sequence_number, payload):
:param payload: The payload of the ICMP message
:type payload: Union[str, bytes]
:rtype: ICMP"""

# Store sent time per packet by sequence number for elapsed time
sent_time = time.time()
self.sent_times[sequence_number] = sent_time

i = icmp.ICMP(
icmp.Types.EchoRequest,
payload=payload,
Expand Down Expand Up @@ -343,6 +349,15 @@ def listen_for(self, packet_id, timeout, payload_pattern=None, source_request=No

# Ensure we have not unpacked the packet we sent (RHEL will also listen to outgoing packets)
if response.id == packet_id and response.message_type != icmp.Types.EchoRequest.type_id:

# Store received time and retrieve sent time by packet sequence number
# to avoid incorrect latency calculations due to old replies arriving after new sends
received_time = time.time()
sent_time = self.sent_times.get(response.sequence_number, None)
if sent_time:
# Calculate accurate latency for the specific sequence number
time_elapsed = received_time - sent_time

if payload_pattern is None:
# To allow Windows-like behaviour (no payload inspection, but only match packet identifiers),
# simply allow for it to be an always true in the legacy usage case
Expand All @@ -351,7 +366,7 @@ def listen_for(self, packet_id, timeout, payload_pattern=None, source_request=No
payload_matched = (payload_pattern == response.payload)

if payload_matched:
return Response(Message('', response, source_socket[0]), timeout - time_left, source_request, repr_format=self.repr_format)
return Response(Message('', response, source_socket[0]), time_elapsed, source_request, repr_format=self.repr_format)
return Response(None, timeout, source_request, repr_format=self.repr_format)

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pexpect==4.0.8
pexpect==4.8.0