sping 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -0
- data/lib/session.rb +16 -5
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6dda8939b3290683a544ac5ba7192ca3ceab50489b3dbd62a0dd04696f6a7786
|
4
|
+
data.tar.gz: de774cc1260933cdcd386e39cfd040e0af8510ba9e73e30f615e2f8da27c074f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e100242edcfe0e85965c6520dc9e95bdcab2c1aea58e5df338eb1dba9efb2dca1b6de0c453a333aa83553b9187d62b731f6fbd4dd81510ee600572b7f0d8e3a5
|
7
|
+
data.tar.gz: 0d01578a50563b1e7f1de1219423e00f66ecffec49ccf25b74e0052df858dc317c71bea80dcec2e17762d66b4b7b97322d8a389484dc72ae158157de605098b0
|
data/README.md
CHANGED
@@ -3,3 +3,16 @@
|
|
3
3
|
Program for measuring asymmetric latencies.
|
4
4
|
|
5
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.
|
6
|
+
|
7
|
+
## Protocol
|
8
|
+
|
9
|
+
The protocol consists of three phases:
|
10
|
+
1. A TCP handshake
|
11
|
+
2. A UDP handshake
|
12
|
+
2. Sending the pings
|
13
|
+
|
14
|
+
The TCP handshake is performed first. Here the peers negotiate a session ID. To do this, the client sends a request to the server and then invites it to a session. If the server accepts the invitation, it sends a session ID to the client. This is used to uniquely identify the connection between the peers. For example, a peer may change its port or IP address. The session ID is used so that the peers can continue to identify each other. The session is activated at the end of the TCP handshake.
|
15
|
+
|
16
|
+
A UDP handshake is then performed. In this, the client sends a UDP packet, which is encoded with [MessagePack](https://msgpack.org/), to the server. The server sends the packet back to the client for confirmation. One of the purposes of this is to punch a hole in a firewall so that it allows UDP packets between the peers. After a successful UDP handshake, the session is double activated. Only then does the sending of ping packets begin.
|
17
|
+
|
18
|
+
Finally, the peers send pings to each other (in this case UDP packets containing time messages). These time messages contain, among other things, the time at which the message was sent, but also the last 32 time messages received from the peer. This information can be used to determine both the asymmetric latency and the asymmetric packet loss.
|
data/lib/session.rb
CHANGED
@@ -26,7 +26,7 @@ module SPing
|
|
26
26
|
# Indicates whether a UDP handshake has been carried out (successfully).
|
27
27
|
# @return [TrueClass, FalseClass]
|
28
28
|
attr_reader :udp_handshake_complete
|
29
|
-
# The session ID in the range from
|
29
|
+
# The session ID in the range from 0 to 2**32 - 1.
|
30
30
|
# @return [Integer]
|
31
31
|
attr_reader :session_id
|
32
32
|
|
@@ -49,6 +49,7 @@ module SPing
|
|
49
49
|
|
50
50
|
# Initialize assignment of other instance variables
|
51
51
|
@created = Time.now
|
52
|
+
@double_activated = nil
|
52
53
|
|
53
54
|
@tcp_handshake_complete = false
|
54
55
|
@udp_handshake_complete = false
|
@@ -69,7 +70,10 @@ module SPing
|
|
69
70
|
|
70
71
|
# See if the peer invites us to create a session with them.
|
71
72
|
invite = socket.readpartial 6
|
72
|
-
|
73
|
+
unless invite.chomp == 'INVITE'
|
74
|
+
socket.write "I_DONT_UNDERSTAND\r\n"
|
75
|
+
raise TCPHandshakeError, 'Peer didn\'t invite us.'
|
76
|
+
end
|
73
77
|
|
74
78
|
# Send the session ID
|
75
79
|
@session_id = session_id
|
@@ -137,7 +141,7 @@ module SPing
|
|
137
141
|
|
138
142
|
# Starts a thread which sends the UDP handshake at regular intervals.
|
139
143
|
# @param send_interval [#to_i] The interval at which the UDP handshakes are to be sent.
|
140
|
-
def start_udp_handshake_sender(send_interval =
|
144
|
+
def start_udp_handshake_sender(send_interval = 1)
|
141
145
|
raise 'UDP handshake sender is already running.' if @udp_handshake_sender
|
142
146
|
|
143
147
|
@udp_handshake_sender = Thread.new(send_interval.to_i) do |th_send_interval|
|
@@ -173,6 +177,7 @@ module SPing
|
|
173
177
|
def udp_handshake_recived
|
174
178
|
stop_udp_handshake_sender if @madebyme
|
175
179
|
@udp_handshake_complete = true
|
180
|
+
@double_activated = Time.now
|
176
181
|
end
|
177
182
|
|
178
183
|
# Starts a thread which sends ping or time messages to the peer at one-second intervals.
|
@@ -278,11 +283,17 @@ module SPing
|
|
278
283
|
rx_loss = 0
|
279
284
|
exchanges = 0
|
280
285
|
|
281
|
-
|
286
|
+
last_local_acks = @last_acks.acks
|
287
|
+
|
288
|
+
# A calculation can only take place when enough data is available, i.e. when:
|
289
|
+
# - We have sent 32 time messages (this is the case after 32 seconds)
|
290
|
+
# - The peer has sent 32 time messages (this is the case after 32 seconds)
|
291
|
+
# - If there is a time message (this is the case when we are in this function)
|
292
|
+
if @double_activated && (Time.now - @double_activated).to_i > 32
|
282
293
|
# We have enough data
|
283
294
|
exchanges = 32
|
284
295
|
remote_acks = remote_last_acks.map { |ack| ack['R'] }
|
285
|
-
local_acks =
|
296
|
+
local_acks = last_local_acks.map { |ack| ack['R'] }
|
286
297
|
|
287
298
|
tip_id = (Time.now.to_i % 255) + 1
|
288
299
|
starting = tip_id - 32
|