sping 1.0.4 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/errors.rb +25 -1
- data/lib/last_acks.rb +14 -7
- data/lib/session.rb +78 -11
- data/lib/session_manager.rb +46 -10
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7dc97d43dd1c7805574269a6ebbe8113c49c431bdfa46783b8e43ebef14063a5
|
4
|
+
data.tar.gz: ffb03def610179c609ffd4046cd5a7da5659e73b83ae867a123a2fcf62309b72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 637dc51c01d6f89bb26a6175d3ac0f0a16921398db3244164efea4b1de457cd3ef1329f3b4ee6eed69a1a57961a6c0d64c31fab7f4fb1fed150183212d830b96
|
7
|
+
data.tar.gz: 5bc1661058eb425277ed0d37429b5b0e8376690a6665aeb85e8bda35b96b85fd3a4025f0b4cc2020aef7b9e1f847b24845b6db9e841705749a7db3a20e4e9ee3
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
1
|
# sping
|
2
2
|
|
3
|
-
|
3
|
+
Program for measuring asymmetric latencies.
|
4
|
+
|
5
|
+
This is a reimplementation in Ruby of the reference implementation of the sping protocol in Go. The program provides both the client and server part to measure asymmetric latencies between two peers.
|
data/lib/errors.rb
CHANGED
@@ -1,20 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# sharable_constant_value: literal
|
3
3
|
|
4
|
+
# SPing / Splitted Ping is a protocol for measuring asymmetric latencies.
|
4
5
|
module SPing
|
6
|
+
# Generic SPing error.
|
5
7
|
class SPingError < StandardError; end
|
6
8
|
|
9
|
+
# Error that occurred while managing the sessions.
|
7
10
|
class SessionManagerError < SPingError; end
|
11
|
+
|
12
|
+
# Error that is thrown when there are not enough session IDs available to establish a
|
13
|
+
# connection to a peer or to accept new ones.
|
14
|
+
# This indicates either a programmer error or an overload of the server.
|
8
15
|
class OutOfSessions < SessionManagerError; end
|
9
16
|
|
17
|
+
# Error that occurs in connection with a session.
|
10
18
|
class SessionError < SPingError; end
|
19
|
+
|
20
|
+
# Error during the TCP handshake
|
11
21
|
class TCPHandshakeError < SessionError; end
|
12
22
|
|
23
|
+
# Error due to the peer (i.e. not self-inflicted).
|
13
24
|
class PeerError < SPingError; end
|
25
|
+
|
26
|
+
# Package was not coded correctly.
|
14
27
|
class InvalidPacketError < PeerError; end
|
28
|
+
|
29
|
+
# The package was coded correctly, but the content is invalid.
|
15
30
|
class InvalidMessageError < InvalidPacketError; end
|
31
|
+
|
32
|
+
# A packet has been received which cannot be clearly assigned to SPing
|
33
|
+
# and therefore cannot be processed further.
|
16
34
|
class UnknownPacketError < InvalidPacketError; end
|
35
|
+
|
36
|
+
# The peer has signaled an error.
|
17
37
|
class SignalizedError < PeerError; end
|
18
|
-
|
38
|
+
|
39
|
+
# The peer uses a version of sping that is not supported.
|
40
|
+
class UnsupportedVersionError < PeerError; end
|
41
|
+
|
42
|
+
# The package could not be assigned to a current session.
|
19
43
|
class UnknownSessionError < PeerError; end
|
20
44
|
end
|
data/lib/last_acks.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# sharable_constant_value: literal
|
3
3
|
|
4
|
+
# SPing / Splitted Ping is a protocol for measuring asymmetric latencies.
|
4
5
|
module SPing
|
6
|
+
# A kind of circular buffer, which consists of 32 acks at any given time. If no acks are available,
|
7
|
+
# empty ones are created. If a new ack is added (which would result in 33 acks), one is removed.
|
5
8
|
class LastAcks
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@size = size
|
9
|
+
# Creates a new circular buffer for acks
|
10
|
+
def initialize
|
11
|
+
# Array in which the acks are stored.
|
10
12
|
@acks = []
|
13
|
+
# Mutex, which ensures that the array is not accessed simultaneously.
|
11
14
|
@acks_mutex = Mutex.new
|
12
15
|
|
13
|
-
|
16
|
+
# Initiallize the circular buffer with 32 empty acks.
|
17
|
+
32.times do |index|
|
14
18
|
@acks[index] = {
|
15
19
|
'R' => 0,
|
16
20
|
'U' => Time.at(0),
|
@@ -19,17 +23,20 @@ module SPing
|
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
26
|
+
# Returns a copy of the last 32 acks.
|
27
|
+
# @return [Array] Last 32 Acks
|
22
28
|
def acks
|
23
29
|
@acks_mutex.synchronize do
|
24
30
|
return @acks.dup
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
34
|
+
# Adds a new ack and deletes the oldest one
|
35
|
+
# @param ack [Hash] New ack to be added
|
28
36
|
def add_ack(ack)
|
29
37
|
@acks_mutex.synchronize do
|
30
38
|
@acks << ack
|
31
|
-
|
32
|
-
@acks.shift if @acks.length > @size
|
39
|
+
@acks.shift
|
33
40
|
end
|
34
41
|
end
|
35
42
|
end
|
data/lib/session.rb
CHANGED
@@ -1,68 +1,118 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# sharable_constant_value: literal
|
3
3
|
|
4
|
+
# SPing / Splitted Ping is a protocol for measuring asymmetric latencies.
|
4
5
|
module SPing
|
6
|
+
# Inclusion of all possible SPing-specific errors.
|
5
7
|
require_relative 'errors'
|
6
8
|
|
9
|
+
# Models or represents a session with a peer.
|
7
10
|
class Session
|
8
|
-
|
9
|
-
|
11
|
+
# Time when the session was created. This is necessary so that the session GC knows when a
|
12
|
+
# non-initialized session can be deleted.
|
13
|
+
# @return [Time]
|
14
|
+
attr_reader :created
|
15
|
+
# Time when the last ping packet was received by the peer. This is important so that the session
|
16
|
+
# GC knows when a session is considered inactive and can be deleted.
|
17
|
+
# @return [Time]
|
18
|
+
attr_reader :last_rx
|
19
|
+
# Indicates whether the session has been initialized. true if we have initiated it.
|
20
|
+
# false if the peer has initiated it.
|
21
|
+
# @return [TrueClass, FalseClass]
|
22
|
+
attr_reader :madebyme
|
23
|
+
# Indicates whether a TCP handshake has been carried out (successfully).
|
24
|
+
# @return [TrueClass, FalseClass]
|
25
|
+
attr_reader :tcp_handshake_complete
|
26
|
+
# Indicates whether a UDP handshake has been carried out (successfully).
|
27
|
+
# @return [TrueClass, FalseClass]
|
28
|
+
attr_reader :udp_handshake_complete
|
29
|
+
# The session ID in the range from 1 to 2**32 - 1.
|
30
|
+
# @return [Integer]
|
31
|
+
attr_reader :session_id
|
10
32
|
|
11
33
|
require 'socket'
|
12
34
|
require 'timeout'
|
13
35
|
require 'msgpack'
|
14
36
|
require_relative 'last_acks'
|
15
37
|
|
38
|
+
# Creates a new session
|
39
|
+
# @param host [#to_s] Host of the peer
|
40
|
+
# @param port [#to_i] Port of the peer
|
41
|
+
# @param socket [UDPSocket] UDP socket via which the pings and the UDP handshake are to be sent.
|
42
|
+
# @param madebyme [TrueClass, FalseClass] Indicates whether we have initiated the session.
|
16
43
|
def initialize(host, port, socket, madebyme)
|
17
|
-
|
18
|
-
@
|
44
|
+
# Assign the passed parameters to instance variables.
|
45
|
+
@host = host.to_s
|
46
|
+
@port = port.to_i
|
19
47
|
@socket = socket
|
20
|
-
@created = Time.now
|
21
48
|
@madebyme = madebyme
|
22
49
|
|
50
|
+
# Initialize assignment of other instance variables
|
51
|
+
@created = Time.now
|
52
|
+
|
23
53
|
@tcp_handshake_complete = false
|
24
54
|
@udp_handshake_complete = false
|
25
55
|
|
26
56
|
@last_acks = SPing::LastAcks.new
|
27
57
|
end
|
28
58
|
|
59
|
+
# Initiates a TCP handshake.
|
60
|
+
# @param socket [TCPSocket] Socket via which the handshake is to be sent
|
61
|
+
# (and responses are to be expected).
|
62
|
+
# @param session_id [Integer] Session ID which is to be sent to the peer
|
63
|
+
# and which is to be used for the current session.
|
29
64
|
def do_tcp_handshake1(socket, session_id)
|
65
|
+
# Send the banner
|
30
66
|
socket.write "sping-0.3-https://codeberg.org/mark22k/sping\r\n"
|
67
|
+
# and make sure that it is no longer in the send buffer.
|
31
68
|
socket.flush
|
32
69
|
|
70
|
+
# See if the peer invites us to create a session with them.
|
33
71
|
invite = socket.readpartial 6
|
34
|
-
|
35
72
|
raise TCPHandshakeError, 'Peer didn\'t invite us.' unless invite.chomp == 'INVITE'
|
36
73
|
|
74
|
+
# Send the session ID
|
37
75
|
@session_id = session_id
|
38
|
-
|
39
76
|
socket.write "#{session_id}\r\n"
|
77
|
+
# and make sure that it is no longer in the send buffer.
|
40
78
|
socket.flush
|
41
79
|
|
80
|
+
# This means that the TCP handshake is successful. The socket can be closed
|
81
|
+
# and the corresponding instance variable can be set.
|
42
82
|
socket.close
|
43
83
|
|
44
84
|
@tcp_handshake_complete = true
|
45
85
|
end
|
46
86
|
|
87
|
+
# Receives a TCP handshake from a peer.
|
88
|
+
# The peer specified when the session is created is consulted for this purpose.
|
47
89
|
def do_tcp_handshake2
|
90
|
+
# Establish a connection and receive the banner.
|
48
91
|
socket = TCPSocket.new @host, @port
|
92
|
+
|
93
|
+
# If the banner is too large, close the socket and throw an error.
|
94
|
+
# The handshake was not successful.
|
49
95
|
banner = socket.readpartial 9001
|
50
96
|
if banner.length > 9000
|
51
97
|
socket.close
|
52
98
|
raise TCPHandshakeError, 'Host banner too big'
|
53
99
|
end
|
54
100
|
|
101
|
+
# If the banner does not match the SPing service, close the socket and
|
102
|
+
# throw an error. The handshake was not successful.
|
55
103
|
unless banner.start_with? 'sping-0.3-'
|
56
104
|
socket.close
|
57
|
-
raise TCPHandshakeError, 'Host banner not sping'
|
105
|
+
raise TCPHandshakeError, 'Host banner not sping or unsupported version of sping.'
|
58
106
|
end
|
59
107
|
|
60
108
|
@remote_version = banner.chomp
|
61
109
|
$logger.info "Peer uses the following program version: #{@remote_version.dump}"
|
62
110
|
|
111
|
+
# Invite the peer to start a session with us.
|
63
112
|
socket.write "INVITE\r\n"
|
64
113
|
socket.flush
|
65
114
|
|
115
|
+
# If the session ID is too long or none was received, close the socket and throw an error.
|
66
116
|
invite_buf = socket.readpartial 32
|
67
117
|
if invite_buf.length > 31 || invite_buf.empty?
|
68
118
|
socket.close
|
@@ -76,15 +126,21 @@ module SPing
|
|
76
126
|
@tcp_handshake_complete = true
|
77
127
|
end
|
78
128
|
|
129
|
+
# Sets the endpoint consisting of the host and port of the remote end. This is done
|
130
|
+
# each time a new packet is received and ensures that the current endpoint is always available.
|
131
|
+
# @param host [#to_s]
|
132
|
+
# @param port [#to_i]
|
79
133
|
def set_endpoint(host, port)
|
80
|
-
@host = host
|
81
|
-
@port = port
|
134
|
+
@host = host.to_s
|
135
|
+
@port = port.to_i
|
82
136
|
end
|
83
137
|
|
138
|
+
# Starts a thread which sends the UDP handshake at regular intervals.
|
139
|
+
# @param send_interval [#to_i] The interval at which the UDP handshakes are to be sent.
|
84
140
|
def start_udp_handshake_sender(send_interval = 5)
|
85
141
|
raise 'UDP handshake sender is already running.' if @udp_handshake_sender
|
86
142
|
|
87
|
-
@udp_handshake_sender = Thread.new(send_interval) do |th_send_interval|
|
143
|
+
@udp_handshake_sender = Thread.new(send_interval.to_i) do |th_send_interval|
|
88
144
|
loop do
|
89
145
|
send_udp_handshake
|
90
146
|
sleep th_send_interval
|
@@ -92,6 +148,7 @@ module SPing
|
|
92
148
|
end
|
93
149
|
end
|
94
150
|
|
151
|
+
# Send a single UDP handshake
|
95
152
|
def send_udp_handshake
|
96
153
|
packet = {
|
97
154
|
'Y' => 'h'.ord,
|
@@ -104,6 +161,7 @@ module SPing
|
|
104
161
|
@socket.send packet, 0, @host, @port
|
105
162
|
end
|
106
163
|
|
164
|
+
# Stop the UDP handshake sender. UDP handshakes are then no longer sent at any interval.
|
107
165
|
def stop_udp_handshake_sender
|
108
166
|
raise 'UDP handshake sender is not running and therefore cannot be terminated.' unless @udp_handshake_sender
|
109
167
|
|
@@ -111,11 +169,13 @@ module SPing
|
|
111
169
|
@udp_handshake_sender = nil
|
112
170
|
end
|
113
171
|
|
172
|
+
# Informs the session that a UDP handshake has been received.
|
114
173
|
def udp_handshake_recived
|
115
174
|
stop_udp_handshake_sender if @madebyme
|
116
175
|
@udp_handshake_complete = true
|
117
176
|
end
|
118
177
|
|
178
|
+
# Starts a thread which sends ping or time messages to the peer at one-second intervals.
|
119
179
|
def start_pinger
|
120
180
|
raise 'Pinger is already running.' if @pinger
|
121
181
|
|
@@ -127,6 +187,7 @@ module SPing
|
|
127
187
|
end
|
128
188
|
end
|
129
189
|
|
190
|
+
# Stops the thread, which sends ping or time messages to the peer at regular intervals.
|
130
191
|
def stop_pinger
|
131
192
|
raise 'Pinger sender is not running and therefore cannot be terminated.' unless @pinger
|
132
193
|
|
@@ -134,6 +195,7 @@ module SPing
|
|
134
195
|
@pinger = nil
|
135
196
|
end
|
136
197
|
|
198
|
+
# Sends a ping message to the peer.
|
137
199
|
def ping
|
138
200
|
current_id = (Time.now.to_i % 255) + 1
|
139
201
|
data = {
|
@@ -150,11 +212,16 @@ module SPing
|
|
150
212
|
@socket.send data, 0, @host, @port
|
151
213
|
end
|
152
214
|
|
215
|
+
# Stops all threads associated with the session. This means that the session to the peer is as good as dead.
|
153
216
|
def stop
|
154
217
|
@pinger&.kill
|
155
218
|
@udp_handshake_sender&.kill
|
156
219
|
end
|
157
220
|
|
221
|
+
# Handler that receives and processes a receiving ping packet or time message. The current statistics are output.
|
222
|
+
# @param packet [Hash]
|
223
|
+
# @param rxtime [Time]
|
224
|
+
# @param peeraddr [#to_s]
|
158
225
|
def handle_ping(packet, rxtime, peeraddr)
|
159
226
|
if !(packet.keys - %w[M Y E I T A S]).empty? ||
|
160
227
|
# M, Y are already checked in handle_packet from session manager
|
data/lib/session_manager.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# sharable_constant_value: literal
|
3
3
|
|
4
|
+
# SPing / Splitted Ping is a protocol for measuring asymmetric latencies.
|
4
5
|
module SPing
|
6
|
+
# Inclusion of all possible SPing-specific errors.
|
5
7
|
require_relative 'errors'
|
6
8
|
|
9
|
+
# Container, which contains a collection of sessions and manages them.
|
7
10
|
class SessionManager
|
8
11
|
require 'socket'
|
9
12
|
require 'timeout'
|
10
13
|
require_relative 'session'
|
11
14
|
|
15
|
+
# Creates a new Session Manager, which can (and will) manage a number of sessions.
|
16
|
+
# @param host [#to_s] Host to which messages are to be bound and from which messages are sent accordingly.
|
17
|
+
# @param port [#to_i] Port
|
12
18
|
def initialize(host = '::', port = 6924)
|
13
|
-
@host = host
|
14
|
-
@port = port
|
19
|
+
@host = host.to_s
|
20
|
+
@port = port.to_i
|
15
21
|
|
16
22
|
@sessions = {}
|
17
23
|
@sessions_mutex = Mutex.new
|
@@ -20,9 +26,12 @@ module SPing
|
|
20
26
|
@socket.bind @host, @port
|
21
27
|
end
|
22
28
|
|
29
|
+
# Initiates a new session with a peer.
|
30
|
+
# @param host [#to_s]
|
31
|
+
# @param port [#to_s, #to_i]
|
23
32
|
def new_session(host, port = 6924)
|
24
33
|
$logger.info "Add new session for host #{host} port #{port}."
|
25
|
-
session = SPing::Session.new host, port, @socket, true
|
34
|
+
session = SPing::Session.new host.to_s, port.to_i, @socket, true
|
26
35
|
|
27
36
|
counter = 0
|
28
37
|
loop do
|
@@ -48,6 +57,8 @@ module SPing
|
|
48
57
|
$logger.error "Out of session: #{e.message}"
|
49
58
|
end
|
50
59
|
|
60
|
+
# Stops all threads connected to a session ID and removes the session from the Session Manager administration.
|
61
|
+
# @param session_id [Integer] Session ID of the session to be removed.
|
51
62
|
def del_session(session_id)
|
52
63
|
$logger.debug "Delete session with session id #{session_id}"
|
53
64
|
|
@@ -57,18 +68,21 @@ module SPing
|
|
57
68
|
end
|
58
69
|
end
|
59
70
|
|
71
|
+
# Stops all sessions or the threads that are connected to them.
|
60
72
|
def stop_sessions
|
61
73
|
@sessions.each do |_session_id, session|
|
62
74
|
session.stop
|
63
75
|
end
|
64
76
|
end
|
65
77
|
|
78
|
+
# Waits and blocks until the Session Manager is no longer running.
|
66
79
|
def join
|
67
80
|
@runner&.join
|
68
81
|
@gc_thread&.join
|
69
82
|
@server_thread&.join
|
70
83
|
end
|
71
84
|
|
85
|
+
# Starts the Session Manager.
|
72
86
|
def run
|
73
87
|
raise 'Client is already running.' if @runner
|
74
88
|
raise 'GC is already running.' if @gc
|
@@ -88,6 +102,7 @@ module SPing
|
|
88
102
|
end
|
89
103
|
end
|
90
104
|
|
105
|
+
# Starts the server functionality of the Session Manager.
|
91
106
|
def run_server
|
92
107
|
raise 'Server is already running.' if @server_thread
|
93
108
|
raise 'Server already exist.' if @server
|
@@ -105,6 +120,7 @@ module SPing
|
|
105
120
|
return @server_thread
|
106
121
|
end
|
107
122
|
|
123
|
+
# Stops the server functionality of the Session Manager.
|
108
124
|
def stop_server
|
109
125
|
raise 'Server thread is not running.' unless @server_thread
|
110
126
|
|
@@ -117,6 +133,7 @@ module SPing
|
|
117
133
|
@server = nil
|
118
134
|
end
|
119
135
|
|
136
|
+
# Stops the Session Manager. The server functionality must be stopped separately.
|
120
137
|
def stop
|
121
138
|
raise 'Session manager is not running.' unless @runner
|
122
139
|
|
@@ -129,6 +146,12 @@ module SPing
|
|
129
146
|
@gc_thread = nil
|
130
147
|
end
|
131
148
|
|
149
|
+
private
|
150
|
+
|
151
|
+
# Generates a new session ID that was not yet in use at the time of the check.
|
152
|
+
# If none could be generated within half a minute - for example because all
|
153
|
+
# session IDs have already been assigned - an error is thrown.
|
154
|
+
# @return [Integer]
|
132
155
|
def generate_session_id
|
133
156
|
Timeout.timeout(30, OutOfSessions, 'No session ID could be generated which has not yet been used.') do
|
134
157
|
loop do
|
@@ -138,19 +161,23 @@ module SPing
|
|
138
161
|
end
|
139
162
|
end
|
140
163
|
|
141
|
-
|
142
|
-
|
164
|
+
# Removes obsolete sessions. This includes sessions that are older than one minute but
|
165
|
+
# have not been activated a double time. And sessions that have not
|
166
|
+
# received any packets for half a minute.
|
143
167
|
def do_gc
|
144
168
|
$logger.debug 'Remove outdated sessions.'
|
145
169
|
# rubocop:disable Style/HashEachMethods
|
146
|
-
# You cannot run through a map and edit it at the same time. Since this is
|
170
|
+
# You cannot run through a map and edit it at the same time. Since this is
|
171
|
+
# necessary due to the threading,
|
147
172
|
# a snapshot of the key variable is run through.
|
148
173
|
@sessions.keys.each do |session_id|
|
149
174
|
# rubocop:enable Style/HashEachMethods
|
150
175
|
|
151
176
|
session = @sessions[session_id]
|
152
|
-
# It is possible that sessions no longer exist here, as we may have
|
153
|
-
#
|
177
|
+
# It is possible that sessions no longer exist here, as we may have
|
178
|
+
# session IDs that have already been deleted.
|
179
|
+
# However, we can ignore this aspect here, as we are the only
|
180
|
+
# function that deletes sessions.
|
154
181
|
if !(session.tcp_handshake_complete && session.udp_handshake_complete)
|
155
182
|
# Handshake incomplete
|
156
183
|
if (Time.now.to_i - session.created.to_i) > 60
|
@@ -159,13 +186,16 @@ module SPing
|
|
159
186
|
del_session session_id
|
160
187
|
end
|
161
188
|
elsif (Time.now.to_i - session.last_rx.to_i) > 30
|
162
|
-
# 30 seconds have elapsed since the last ping from the peer was received.
|
189
|
+
# 30 seconds have elapsed since the last ping from the peer was received.
|
190
|
+
# The peer is probably dead.
|
163
191
|
$logger.debug "Session id #{session_id} without activity for over thirty seconds."
|
164
192
|
del_session session_id
|
165
193
|
end
|
166
194
|
end
|
167
195
|
end
|
168
196
|
|
197
|
+
# Receives a TCP handshake for a session and then has it
|
198
|
+
# managed by the Session Manager.
|
169
199
|
def request_session(session)
|
170
200
|
session.do_tcp_handshake2
|
171
201
|
|
@@ -179,6 +209,9 @@ module SPing
|
|
179
209
|
return nil
|
180
210
|
end
|
181
211
|
|
212
|
+
# Handler for a received packet. The function catches errors and outputs them.
|
213
|
+
# It also forwards the packet to the corresponding handler according to the
|
214
|
+
# session ID and type of packet.
|
182
215
|
def handle_packet(buf)
|
183
216
|
rxtime = Time.now
|
184
217
|
|
@@ -217,6 +250,7 @@ module SPing
|
|
217
250
|
$logger.error "Perr error: #{e.message}"
|
218
251
|
end
|
219
252
|
|
253
|
+
# Handler for a receiving UDP handshake.
|
220
254
|
def handle_udp_handshake(packet, peeraddr, peerport)
|
221
255
|
if !(packet.keys - %w[M Y V S]).empty? ||
|
222
256
|
# M, Y are already checked in handle_packet from session manager
|
@@ -227,7 +261,7 @@ module SPing
|
|
227
261
|
session_id = packet['S']
|
228
262
|
session = @sessions[session_id]
|
229
263
|
raise UnknownSessionError, 'UDP handshake received for uninitiated session.' unless session
|
230
|
-
raise
|
264
|
+
raise UnsupportedVersionError, "UDP handshake uses an unsupported version: #{packet['V']}" if packet['V'] != 3
|
231
265
|
|
232
266
|
session.set_endpoint peeraddr, peerport
|
233
267
|
|
@@ -249,6 +283,7 @@ module SPing
|
|
249
283
|
session.start_pinger
|
250
284
|
end
|
251
285
|
|
286
|
+
# Handler for a receiving ping or a receiving time message.
|
252
287
|
def handle_ping(packet, rxtime, peeraddr, peerport)
|
253
288
|
session_id = packet['S']
|
254
289
|
session = @sessions[session_id]
|
@@ -260,6 +295,7 @@ module SPing
|
|
260
295
|
session.handle_ping packet, rxtime, peeraddr
|
261
296
|
end
|
262
297
|
|
298
|
+
# Handler to establish a session for the request of a peer.
|
263
299
|
def handle_client(client)
|
264
300
|
host = client.peeraddr[3]
|
265
301
|
port = client.peeraddr[1]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sping
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marek Küthe
|
@@ -30,8 +30,9 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.7.2
|
33
|
-
description: This is a reimplementation of
|
34
|
-
in
|
33
|
+
description: This is a reimplementation in Ruby of the reference implementation of
|
34
|
+
the sping protocol in Go. The program provides both the client and server part to
|
35
|
+
measure asymmetric latencies between two peers.
|
35
36
|
email: m.k@mk16.de
|
36
37
|
executables:
|
37
38
|
- sping
|
@@ -72,5 +73,5 @@ requirements: []
|
|
72
73
|
rubygems_version: 3.4.22
|
73
74
|
signing_key:
|
74
75
|
specification_version: 4
|
75
|
-
summary:
|
76
|
+
summary: Program for measuring asymmetric latencies.
|
76
77
|
test_files: []
|