sping 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -0
  3. data/lib/session.rb +16 -5
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7dc97d43dd1c7805574269a6ebbe8113c49c431bdfa46783b8e43ebef14063a5
4
- data.tar.gz: ffb03def610179c609ffd4046cd5a7da5659e73b83ae867a123a2fcf62309b72
3
+ metadata.gz: 6dda8939b3290683a544ac5ba7192ca3ceab50489b3dbd62a0dd04696f6a7786
4
+ data.tar.gz: de774cc1260933cdcd386e39cfd040e0af8510ba9e73e30f615e2f8da27c074f
5
5
  SHA512:
6
- metadata.gz: 637dc51c01d6f89bb26a6175d3ac0f0a16921398db3244164efea4b1de457cd3ef1329f3b4ee6eed69a1a57961a6c0d64c31fab7f4fb1fed150183212d830b96
7
- data.tar.gz: 5bc1661058eb425277ed0d37429b5b0e8376690a6665aeb85e8bda35b96b85fd3a4025f0b4cc2020aef7b9e1f847b24845b6db9e841705749a7db3a20e4e9ee3
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 1 to 2**32 - 1.
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
- raise TCPHandshakeError, 'Peer didn\'t invite us.' unless invite.chomp == 'INVITE'
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 = 5)
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
- if remote_last_acks.length == 32
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 = @last_acks.acks.map { |ack| ack['R'] }
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
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.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marek Küthe