Hello community, here is the log from the commit of package 2ping for openSUSE:Factory checked in at 2018-10-08 17:49:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/2ping (Old) and /work/SRC/openSUSE:Factory/.2ping.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "2ping" Mon Oct 8 17:49:05 2018 rev:7 rq:640532 version:4.2 Changes: -------- --- /work/SRC/openSUSE:Factory/2ping/2ping.changes 2018-08-12 20:56:26.221596982 +0200 +++ /work/SRC/openSUSE:Factory/.2ping.new/2ping.changes 2018-10-08 17:50:52.986066430 +0200 @@ -1,0 +2,7 @@ +Mon Oct 08 05:58:03 UTC 2018 - s...@suspend.net + +- Update to version 4.2 + * Added SIGHUP handling of listener processes + * Added an example bash_completion script + * Better cleanup handling of peer information +------------------------------------------------------------------- Old: ---- 2ping-4.1.2.tar.gz 2ping-4.1.2.tar.gz.asc New: ---- 2ping-4.2.tar.gz 2ping-4.2.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ 2ping.spec ++++++ --- /var/tmp/diff_new_pack.AqgMpS/_old 2018-10-08 17:50:53.390065915 +0200 +++ /var/tmp/diff_new_pack.AqgMpS/_new 2018-10-08 17:50:53.390065915 +0200 @@ -12,12 +12,12 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # Name: 2ping -Version: 4.1.2 +Version: 4.2 Release: 0 Summary: Bi-directional ping utility License: GPL-2.0-or-later ++++++ 2ping-4.1.2.tar.gz -> 2ping-4.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/2ping.bash_completion new/2ping-4.2/2ping.bash_completion --- old/2ping-4.1.2/2ping.bash_completion 1970-01-01 01:00:00.000000000 +0100 +++ new/2ping-4.2/2ping.bash_completion 2018-08-11 23:06:16.000000000 +0200 @@ -0,0 +1,26 @@ +# 2ping(1) completion -*- shell-script -*- + +_2ping() +{ + local cur prev words cword + _init_completion -n = || return + + local ipvx + + case $prev in + -4|-6) + ipvx=$prev + ;; + esac + + if [[ $cur == -* ]]; then + COMPREPLY=( $( compgen -W '$( _parse_usage "$1" )' -- "$cur" ) ) + return + fi + + [[ $1 == *6 ]] && ipvx=-6 + _known_hosts_real $ipvx -- "$cur" +} && +complete -F _2ping 2ping 2ping6 + +# ex: filetype=sh diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/2ping.spec new/2ping-4.2/2ping.spec --- old/2ping-4.1.2/2ping.spec 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/2ping.spec 2018-08-11 23:06:16.000000000 +0200 @@ -1,5 +1,5 @@ Name: 2ping -Version: 4.1 +Version: 4.2 Release: 1%{?dist} Summary: Bi-directional ping utility License: GPLv2+ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/ChangeLog new/2ping-4.2/ChangeLog --- old/2ping-4.1.2/ChangeLog 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/ChangeLog 2018-08-11 23:06:16.000000000 +0200 @@ -1,3 +1,8 @@ +2ping 4.2 (2018-08-11) + * Added SIGHUP handling of listener processes + * Added an example bash_completion script + * Better cleanup handling of peer information + 2ping 4.1.2 (2018-08-09) * Fix UTF-8 tests when run with invalid locale (Debian Bug#897498) * Fix cleanup on non-encrypted sessions (GitHub rfinnie/2ping#5) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/MANIFEST.in new/2ping-4.2/MANIFEST.in --- old/2ping-4.1.2/MANIFEST.in 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/MANIFEST.in 2018-08-11 23:06:16.000000000 +0200 @@ -7,5 +7,6 @@ include 2ping include 2ping.spec include 2ping6 +include 2ping.bash_completion include tests/*.py include wireshark/* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/doc/2ping.1 new/2ping-4.2/doc/2ping.1 --- old/2ping-4.1.2/doc/2ping.1 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/doc/2ping.1 2018-08-11 23:06:16.000000000 +0200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pandoc 1.17.2 +.\" Automatically generated by Pandoc 1.19.2.4 .\" .TH "2PING" "1" "" "" "2ping" .hy @@ -7,7 +7,7 @@ 2ping \- A bi\-directional ping utility .SH SYNOPSIS .PP -2ping [\f[I]options\f[]] \f[I]\-\-listen\f[] | host/IP +2ping [\f[I]options\f[]] \f[I]\-\-listen\f[] | host/IP [host/IP [...]] .SH DESCRIPTION .PP \f[C]2ping\f[] is a bi\-directional ping utility. @@ -250,6 +250,8 @@ The listener will not send out ping requests at regular intervals, and will instead wait for the far end to initiate ping requests. A listener is required as the remote end for a client. +When run as a listener, a SIGHUP will reload the configuration on all +interfaces. .RS .RE .TP diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/doc/2ping.md new/2ping-4.2/doc/2ping.md --- old/2ping-4.1.2/doc/2ping.md 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/doc/2ping.md 2018-08-11 23:06:16.000000000 +0200 @@ -6,7 +6,7 @@ # SYNOPSIS -2ping [*options*] *--listen* | host/IP +2ping [*options*] *--listen* | host/IP [host/IP [...]] # DESCRIPTION @@ -144,6 +144,7 @@ : Start as a listener. The listener will not send out ping requests at regular intervals, and will instead wait for the far end to initiate ping requests. A listener is required as the remote end for a client. + When run as a listener, a SIGHUP will reload the configuration on all interfaces. --min-packet-size=*min* : Set the minimum total payload size to *min* bytes, default 128. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/setup.py new/2ping-4.2/setup.py --- old/2ping-4.1.2/setup.py 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/setup.py 2018-08-11 23:06:16.000000000 +0200 @@ -15,7 +15,7 @@ name='2ping', description='2ping a bi-directional ping utility', long_description=read('README'), - version='4.1', + version='4.2', license='GPLv2+', platforms=['Unix'], author='Ryan Finnie', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/twoping/__init__.py new/2ping-4.2/twoping/__init__.py --- old/2ping-4.1.2/twoping/__init__.py 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/twoping/__init__.py 2018-08-11 23:06:16.000000000 +0200 @@ -16,4 +16,4 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. -__version__ = '4.1' +__version__ = '4.2' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/twoping/best_poller.py new/2ping-4.2/twoping/best_poller.py --- old/2ping-4.1.2/twoping/best_poller.py 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/twoping/best_poller.py 2018-08-11 23:06:16.000000000 +0200 @@ -35,6 +35,13 @@ self.poller.register(fileno, select.EPOLLIN) self.f_dict[fileno] = f + def unregister(self, f): + fileno = f.fileno() + if fileno not in self.f_dict: + return + self.poller.unregister(fileno) + del(self.f_dict[fileno]) + def close(self): return self.poller.close() @@ -57,25 +64,32 @@ def __init__(self): self.poller = select.kqueue() - self.kevents = [] + self.kevents = {} self.f_dict = {} def register(self, f): fileno = f.fileno() if fileno not in self.f_dict: - self.kevents.append(select.kevent( + self.kevents[fileno] = select.kevent( fileno, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE, - )) + ) self.f_dict[fileno] = f + def unregister(self, f): + fileno = f.fileno() + if fileno not in self.f_dict: + return + del(self.kevents[fileno]) + del(self.f_dict[fileno]) + def close(self): return self.poller.close() def poll(self, timeout): try: - poll_res = self.poller.control(self.kevents, 10, timeout) + poll_res = self.poller.control(self.kevents.values(), 10, timeout) except (select.error, IOError, OSError) as e: if e.args[0] not in (errno.EINTR,): raise @@ -100,6 +114,13 @@ self.poller.register(fileno, select.POLLIN) self.f_dict[fileno] = f + def unregister(self, f): + fileno = f.fileno() + if fileno not in self.f_dict: + return + self.poller.unregister(fileno) + del(self.f_dict[fileno]) + def close(self): return self.poller.close() @@ -126,6 +147,12 @@ def register(self, f): self.f_dict[f.fileno()] = f + def unregister(self, f): + fileno = f.fileno() + if fileno not in self.f_dict: + return + del(self.f_dict[fileno]) + def close(self): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/twoping/cli.py new/2ping-4.2/twoping/cli.py --- old/2ping-4.1.2/twoping/cli.py 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/twoping/cli.py 2018-08-11 23:06:16.000000000 +0200 @@ -62,35 +62,11 @@ def __init__(self, sock): self.sock = sock - # In-flight outbound messages. Added in the following conditions: - # * Outbound packet with OpcodeReplyRequested sent. - # Removed in following conditions: - # * Inbound packet with OpcodeInReplyTo set to it. - # * Inbound packet with it in OpcodeInvestigationSeen or OpcodeInvestigationUnseen. - # * Cleanup after 10 minutes. - # If it remains for more than <10> seconds, it it sent as part of - # OpcodeInvestigate with the next outbound packet with OpcodeReplyRequested set. - self.sent_messages = {} - # Seen inbound messages. Added in the following conditions: - # * Inbound packet with OpcodeReplyRequested set. - # Referenced in the following conditions: - # * Inbound packet with it in OpcodeInvestigate. - # Removed in the following conditions: - # * Inbound packet with it in OpcodeCourtesyExpiration. - # * Cleanup after 10 minutes. - self.seen_messages = {} - # Courtesy messages waiting to be sent. Added in the following conditions: - # * Inbound packet with OpcodeInReplyTo set. - # Removed in the following conditions: - # * Outbound packet where there is room to send it as part of OpcodeCourtesyExpiration. - # * Cleanup after 2 minutes. - self.courtesy_messages = {} - # Current position of a peer tuple's incrementing ping integer. - self.ping_positions = {} # Used during client mode for the host tuple to send UDP packets to. self.client_host = None - # Current session of a 5-tuple for encrypted sessions - self.encrypted_sessions = {} + + # Dict of PeerState instances, indexed by peer tuple + self.peer_states = {} # Statistics self.pings_transmitted = 0 @@ -117,6 +93,44 @@ return self.sock.fileno() +class PeerState(): + def __init__(self, peer_tuple, sock_class): + self.peer_tuple = peer_tuple + self.sock_class = sock_class + + # In-flight outbound messages. Added in the following conditions: + # * Outbound packet with OpcodeReplyRequested sent. + # Removed in following conditions: + # * Inbound packet with OpcodeInReplyTo set to it. + # * Inbound packet with it in OpcodeInvestigationSeen or OpcodeInvestigationUnseen. + # * Cleanup after 10 minutes. + # If it remains for more than <10> seconds, it it sent as part of + # OpcodeInvestigate with the next outbound packet with OpcodeReplyRequested set. + self.sent_messages = {} + # Seen inbound messages. Added in the following conditions: + # * Inbound packet with OpcodeReplyRequested set. + # Referenced in the following conditions: + # * Inbound packet with it in OpcodeInvestigate. + # Removed in the following conditions: + # * Inbound packet with it in OpcodeCourtesyExpiration. + # * Cleanup after 10 minutes. + self.seen_messages = {} + # Courtesy messages waiting to be sent. Added in the following conditions: + # * Inbound packet with OpcodeInReplyTo set. + # Removed in the following conditions: + # * Outbound packet where there is room to send it as part of OpcodeCourtesyExpiration. + # * Cleanup after 2 minutes. + self.courtesy_messages = {} + # Current position of a peer tuple's incrementing ping integer. + self.ping_position = 0 + # Current encrypted session ID + self.encrypted_session_id = None + # Seen encrypted session IVs + self.encrypted_session_ivs = {} + # Last time a peer was sent to or received from + self.last_seen = clock() + + class TwoPing(): def __init__(self, args): now = clock() @@ -168,6 +182,8 @@ else: raise + self.is_reload = False + if self.args.send_monotonic_clock and (not clock_info.monotonic): self.args.send_monotonic_clock = False @@ -238,16 +254,10 @@ peer_tuple = (socket_address, peer_address, sock.type) # Preload state tables if the client has not been seen (or has been cleaned). - if peer_tuple not in sock_class.seen_messages: - sock_class.seen_messages[peer_tuple] = {} - if peer_tuple not in sock_class.sent_messages: - sock_class.sent_messages[peer_tuple] = {} - if peer_tuple not in sock_class.courtesy_messages: - sock_class.courtesy_messages[peer_tuple] = {} - if peer_tuple not in sock_class.ping_positions: - sock_class.ping_positions[peer_tuple] = 0 - if peer_tuple not in sock_class.encrypted_sessions: - sock_class.encrypted_sessions[peer_tuple] = None + if peer_tuple not in sock_class.peer_states: + sock_class.peer_states[peer_tuple] = PeerState(peer_tuple, sock_class) + peer_state = sock_class.peer_states[peer_tuple] + peer_state.last_seen = time_begin # Load/parse the packet. packet_in = packets.Packet() @@ -277,24 +287,20 @@ encrypted_packet_in = packet_in packet_in = packets.Packet() packet_in.load(data) - if sock_class.encrypted_sessions[peer_tuple] is None: - sock_class.encrypted_sessions[peer_tuple] = ( - time_begin, - [], - encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].session, - ) - if encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].session != sock_class.encrypted_sessions[peer_tuple][2]: + if peer_state.encrypted_session_id is None: + peer_state.encrypted_session_id = encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].session + if encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].session != peer_state.encrypted_session_id: self.errors_received += 1 sock_class.errors_received += 1 self.print_out( _('Encryption session mismatch from {address} (expected {expected}, got {got})').format( address=peer_address[0], - expected=repr(sock_class.encrypted_sessions[peer_tuple][2]), + expected=repr(peer_state.encrypted_session_id), got=repr(encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].session), ) ) return - if encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].iv in sock_class.encrypted_sessions[peer_tuple][1]: + if encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].iv in peer_state.encrypted_session_ivs: self.errors_received += 1 sock_class.errors_received += 1 self.print_out( @@ -304,7 +310,7 @@ ) ) return - sock_class.encrypted_sessions[peer_tuple][1].append(encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].iv) + peer_state.encrypted_session_ivs[encrypted_packet_in.opcodes[packets.OpcodeEncrypted.id].iv] = (time_begin,) if self.args.verbose: self.print_out('DECR: {}'.format(repr(packet_in))) @@ -351,9 +357,9 @@ if packets.OpcodeInReplyTo.id in packet_in.opcodes: replied_message_id = packet_in.opcodes[packets.OpcodeInReplyTo.id].message_id replied_message_id_int = nunpack(replied_message_id) - if replied_message_id_int in sock_class.sent_messages[peer_tuple]: - (sent_time, _unused, ping_position) = sock_class.sent_messages[peer_tuple][replied_message_id_int] - del(sock_class.sent_messages[peer_tuple][replied_message_id_int]) + if replied_message_id_int in peer_state.sent_messages: + (sent_time, _unused, ping_position) = peer_state.sent_messages[replied_message_id_int] + del(peer_state.sent_messages[replied_message_id_int]) calculated_rtt = (time_begin - sent_time) * 1000 self.pings_received += 1 sock_class.pings_received += 1 @@ -369,7 +375,7 @@ self.print_out( _('{bytes} bytes from {address}: ping_seq={seq} time={ms:0.03f} ms peertime={peerms:0.03f} ms').format( bytes=len(data), - address=peer_tuple[1][0], + address=peer_state.peer_tuple[1][0], seq=ping_position, ms=calculated_rtt, peerms=(packet_in.opcodes[packets.OpcodeRTTEnclosed.id].rtt_us / 1000.0), @@ -379,7 +385,7 @@ self.print_out( _('{bytes} bytes from {address}: ping_seq={seq} time={ms:0.03f} ms').format( bytes=len(data), - address=peer_tuple[1][0], + address=peer_state.peer_tuple[1][0], seq=ping_position, ms=calculated_rtt, ) @@ -390,22 +396,22 @@ ): notice = packet_in.opcodes[packets.OpcodeExtended.id].segments[packets.ExtendedNotice.id].text self.print_out(' ' + _('Peer notice: {notice}').format(notice=notice)) - sock_class.courtesy_messages[peer_tuple][replied_message_id_int] = (time_begin, replied_message_id) + peer_state.courtesy_messages[replied_message_id_int] = (time_begin, replied_message_id) # Check if any invesitgations results have come back. - self.check_investigations(sock_class, peer_tuple, packet_in) + self.check_investigations(peer_state, packet_in) # Process courtesy expirations if packets.OpcodeCourtesyExpiration.id in packet_in.opcodes: for message_id in packet_in.opcodes[packets.OpcodeCourtesyExpiration.id].message_ids: message_id_int = nunpack(message_id) - if message_id_int in sock_class.seen_messages[peer_tuple]: - del(sock_class.seen_messages[peer_tuple][message_id_int]) + if message_id_int in peer_state.seen_messages: + del(peer_state.seen_messages[message_id_int]) # If the peer requested a reply, prepare one. if packets.OpcodeReplyRequested.id in packet_in.opcodes: # Populate seen_messages. - sock_class.seen_messages[peer_tuple][nunpack(packet_in.message_id)] = time_begin + peer_state.seen_messages[nunpack(packet_in.message_id)] = (time_begin,) # Basic packet configuration. packet_out = self.base_packet() @@ -427,7 +433,7 @@ # Check for any investigations the peer requested. if packets.OpcodeInvestigate.id in packet_in.opcodes: for message_id in packet_in.opcodes[packets.OpcodeInvestigate.id].message_ids: - if nunpack(message_id) in sock_class.seen_messages[peer_tuple]: + if nunpack(message_id) in peer_state.seen_messages: if packets.OpcodeInvestigationSeen.id not in packet_out.opcodes: packet_out.opcodes[packets.OpcodeInvestigationSeen.id] = packets.OpcodeInvestigationSeen() packet_out.opcodes[packets.OpcodeInvestigationSeen.id].message_ids.append(message_id) @@ -442,12 +448,12 @@ packet_out.opcodes[packets.OpcodeReplyRequested.id] = packets.OpcodeReplyRequested() # Send any investigations we would like to know about. - self.start_investigations(sock_class, peer_tuple, packet_out) + self.start_investigations(peer_state, packet_out) # Any courtesy expirations we have waiting should be sent. - if len(sock_class.courtesy_messages[peer_tuple]) > 0: + if len(peer_state.courtesy_messages) > 0: packet_out.opcodes[packets.OpcodeCourtesyExpiration.id] = packets.OpcodeCourtesyExpiration() - for (courtesy_time, courtesy_message_id) in sock_class.courtesy_messages[peer_tuple].values(): + for (courtesy_time, courtesy_message_id) in peer_state.courtesy_messages.values(): packet_out.opcodes[packets.OpcodeCourtesyExpiration.id].message_ids.append(courtesy_message_id) # Calculate the host latency as late as possible. @@ -478,11 +484,11 @@ if packets.OpcodeReplyRequested.id in packet_out.opcodes: self.pings_transmitted += 1 sock_class.pings_transmitted += 1 - sock_class.ping_positions[peer_tuple] += 1 - sock_class.sent_messages[peer_tuple][nunpack(packet_out.message_id)] = ( + peer_state.ping_position += 1 + peer_state.sent_messages[nunpack(packet_out.message_id)] = ( time_send, packet_out.message_id, - sock_class.ping_positions[peer_tuple] + peer_state.ping_position ) # Examine the sent packet. @@ -493,8 +499,8 @@ if packets.OpcodeCourtesyExpiration.id in packet_out_examine.opcodes: for courtesy_message_id in packet_out_examine.opcodes[packets.OpcodeCourtesyExpiration.id].message_ids: courtesy_message_id_int = nunpack(courtesy_message_id) - if courtesy_message_id_int in sock_class.courtesy_messages[peer_tuple]: - del(sock_class.courtesy_messages[peer_tuple][courtesy_message_id_int]) + if courtesy_message_id_int in peer_state.courtesy_messages: + del(peer_state.courtesy_messages[courtesy_message_id_int]) if self.args.verbose: if self.args.encrypt: @@ -517,16 +523,16 @@ except socket.error as e: self.handle_socket_error(e, sock_class, peer_address=address) - def start_investigations(self, sock_class, peer_tuple, packet_check): - if len(sock_class.sent_messages[peer_tuple]) == 0: + def start_investigations(self, peer_state, packet_check): + if len(peer_state.sent_messages) == 0: return if packets.OpcodeInvestigate.id in packet_check.opcodes: iobj = packet_check.opcodes[packets.OpcodeInvestigate.id] else: iobj = None now = clock() - for message_id_str in sock_class.sent_messages[peer_tuple]: - (sent_time, message_id, _unused) = sock_class.sent_messages[peer_tuple][message_id_str] + for message_id_str in peer_state.sent_messages: + (sent_time, message_id, _unused) = peer_state.sent_messages[message_id_str] if now >= (sent_time + self.args.inquire_wait): if iobj is None: iobj = packets.OpcodeInvestigate() @@ -535,32 +541,32 @@ if iobj is not None: packet_check.opcodes[packets.OpcodeInvestigate.id] = iobj - def check_investigations(self, sock_class, peer_tuple, packet_check): + def check_investigations(self, peer_state, packet_check): found = {} # Inbound if packets.OpcodeInvestigationSeen.id in packet_check.opcodes: for message_id in packet_check.opcodes[packets.OpcodeInvestigationSeen.id].message_ids: message_id_int = nunpack(message_id) - if message_id_int not in sock_class.sent_messages[peer_tuple]: + if message_id_int not in peer_state.sent_messages: continue - (_unused, _unused, ping_seq) = sock_class.sent_messages[peer_tuple][message_id_int] - found[ping_seq] = ('inbound', peer_tuple[1][0]) - del(sock_class.sent_messages[peer_tuple][message_id_int]) + (_unused, _unused, ping_seq) = peer_state.sent_messages[message_id_int] + found[ping_seq] = ('inbound', peer_state.peer_tuple[1][0]) + del(peer_state.sent_messages[message_id_int]) self.lost_inbound += 1 - sock_class.lost_inbound += 1 + peer_state.sock_class.lost_inbound += 1 # Outbound if packets.OpcodeInvestigationUnseen.id in packet_check.opcodes: for message_id in packet_check.opcodes[packets.OpcodeInvestigationUnseen.id].message_ids: message_id_int = nunpack(message_id) - if message_id_int not in sock_class.sent_messages[peer_tuple]: + if message_id_int not in peer_state.sent_messages: continue - (_unused, _unused, ping_seq) = sock_class.sent_messages[peer_tuple][message_id_int] - found[ping_seq] = ('outbound', peer_tuple[1][0]) - del(sock_class.sent_messages[peer_tuple][message_id_int]) + (_unused, _unused, ping_seq) = peer_state.sent_messages[message_id_int] + found[ping_seq] = ('outbound', peer_state.peer_tuple[1][0]) + del(peer_state.sent_messages[message_id_int]) self.lost_outbound += 1 - sock_class.lost_outbound += 1 + peer_state.sock_class.lost_outbound += 1 if self.args.quiet: return @@ -585,6 +591,12 @@ )) def setup_listener(self): + # If called idempotently, destroy all listeners first + for sock_class in self.sock_classes: + self.poller.unregister(sock_class) + sock_class.sock.close() + + self.sock_classes = [] bound_addresses = [] if self.args.all_interfaces: if not has_netifaces: @@ -745,14 +757,14 @@ sock = sock_class.sock socket_address = sock.getsockname() peer_tuple = (socket_address, peer_address, sock.type) - if peer_tuple not in sock_class.sent_messages: - sock_class.sent_messages[peer_tuple] = {} - if peer_tuple not in sock_class.ping_positions: - sock_class.ping_positions[peer_tuple] = 0 + if peer_tuple not in sock_class.peer_states: + sock_class.peer_states[peer_tuple] = PeerState(peer_tuple, sock_class) + peer_state = sock_class.peer_states[peer_tuple] + peer_state.last_seen = clock() packet_out = self.base_packet() packet_out.opcodes[packets.OpcodeReplyRequested.id] = packets.OpcodeReplyRequested() - self.start_investigations(sock_class, peer_tuple, packet_out) + self.start_investigations(peer_state, packet_out) dump_out = packet_out.dump() # If enabled, encrypt the packet and wrap it in a stub packet. @@ -772,11 +784,11 @@ sock_class.packets_transmitted += 1 self.pings_transmitted += 1 sock_class.pings_transmitted += 1 - sock_class.ping_positions[peer_tuple] += 1 - sock_class.sent_messages[peer_tuple][nunpack(packet_out.message_id)] = ( + peer_state.ping_position += 1 + peer_state.sent_messages[nunpack(packet_out.message_id)] = ( now, packet_out.message_id, - sock_class.ping_positions[peer_tuple] + peer_state.ping_position ) packet_out_examine = packets.Packet() packet_out_examine.load(dump_out) @@ -807,6 +819,10 @@ def sigquit_handler(self, signum, frame): self.print_stats(short=True) + def sighup_handler(self, signum, frame): + self.print_debug('Received SIGHUP, scheduling reload') + self.is_reload = True + def stats_time(self, seconds): conversion = ( (1000, 'ms'), @@ -964,6 +980,8 @@ self.print_debug('Poller: {}'.format(self.poller.poller_type)) if hasattr(signal, 'SIGQUIT'): signal.signal(signal.SIGQUIT, self.sigquit_handler) + if hasattr(signal, 'SIGHUP'): + signal.signal(signal.SIGHUP, self.sighup_handler) try: if self.args.listen: @@ -1021,36 +1039,23 @@ def scheduled_cleanup_sock_class(self, sock_class): now = clock() - for peer_tuple in tuple(sock_class.sent_messages.keys()): - for message_id_int in tuple(sock_class.sent_messages[peer_tuple].keys()): - if now > (sock_class.sent_messages[peer_tuple][message_id_int][0] + 600.0): - del(sock_class.sent_messages[peer_tuple][message_id_int]) - self.print_debug('Cleanup: Removed sent_messages {} {}'.format(repr(peer_tuple), message_id_int)) - if len(sock_class.sent_messages[peer_tuple]) == 0: - del(sock_class.sent_messages[peer_tuple]) - self.print_debug('Cleanup: Removed sent_messages empty {}'.format(repr(peer_tuple))) - for peer_tuple in tuple(sock_class.seen_messages.keys()): - for message_id_int in tuple(sock_class.seen_messages[peer_tuple].keys()): - if now > (sock_class.seen_messages[peer_tuple][message_id_int] + 600.0): - del(sock_class.seen_messages[peer_tuple][message_id_int]) - self.print_debug('Cleanup: Removed seen_messages {} {}'.format(repr(peer_tuple), message_id_int)) - if len(sock_class.seen_messages[peer_tuple]) == 0: - del(sock_class.seen_messages[peer_tuple]) - self.print_debug('Cleanup: Removed seen_messages empty {}'.format(repr(peer_tuple))) - for peer_tuple in tuple(sock_class.courtesy_messages.keys()): - for message_id_int in tuple(sock_class.courtesy_messages[peer_tuple].keys()): - if now > (sock_class.courtesy_messages[peer_tuple][message_id_int][0] + 120.0): - del(sock_class.courtesy_messages[peer_tuple][message_id_int]) - self.print_debug('Cleanup: Removed courtesy_messages {} {}'.format(repr(peer_tuple), message_id_int)) - if len(sock_class.courtesy_messages[peer_tuple]) == 0: - del(sock_class.courtesy_messages[peer_tuple]) - self.print_debug('Cleanup: Removed courtesy_messages empty {}'.format(repr(peer_tuple))) - for peer_tuple in tuple(sock_class.encrypted_sessions.keys()): - if sock_class.encrypted_sessions[peer_tuple] is None: + for peer_tuple in tuple(sock_class.peer_states.keys()): + peer_state = sock_class.peer_states[peer_tuple] + if now > peer_state.last_seen + 600.0: + del(sock_class.peer_states[peer_tuple]) + self.print_debug('Cleanup: Removed {}'.format(repr(peer_tuple))) continue - if now > (sock_class.encrypted_sessions[peer_tuple][0] + 600.0): - del(sock_class.encrypted_sessions[peer_tuple]) - self.print_debug('Cleanup: Removed encrypted_sessions {}'.format(repr(peer_tuple))) + for table_name, max_time in ( + ('sent_messages', 600.0), + ('seen_messages', 600.0), + ('courtesy_messages', 120.0), + ('encrypted_session_ivs', 600.0), + ): + table = getattr(peer_state, table_name) + for table_key_name in tuple(table.keys()): + if now > (table[table_key_name][0] + max_time): + del(table[table_key_name]) + self.print_debug('Cleanup: Removed {} {} {}'.format(repr(peer_tuple), table_name, table_key_name)) def new_socket(self, family, type, bind): sock = socket.socket(family, type) @@ -1150,6 +1155,11 @@ if all_shutdown: self.shutdown() + if self.is_reload: + self.is_reload = False + if self.args.listen: + self.setup_listener() + def main(): args = parse_args() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/2ping-4.1.2/twoping/packets.py new/2ping-4.2/twoping/packets.py --- old/2ping-4.1.2/twoping/packets.py 2018-08-10 05:29:17.000000000 +0200 +++ new/2ping-4.2/twoping/packets.py 2018-08-11 23:06:16.000000000 +0200 @@ -169,7 +169,7 @@ return '<Batteries ({}): [{}]>'.format( len(self.batteries), ', '.join( - ['{}: {:0.03f}%'.format(x, (self.batteries[x] / 65535.0 * 100.0)) for x in sorted(self.batteries)] + ['{}: {:0.03%}'.format(x, self.batteries[x] / 65535.0) for x in sorted(self.batteries)] ), )