Commit Graph
82 Commits
Author SHA1 Message Date
Matthias Radestock 40d127d9a4 make connection heartbeating independent of periodic gossip
This was a convenient but rather suspect coupling. In particular, it
will break if the period gossip logic changes s.t. it no longer sends
gossip on all connections every interval.
2015-04-09 11:44:13 +01:00
Matthias Radestock e639007b62 eliminate AddConnection/RemoveConnection race
We were invoking AddConnection in a separate goroutine, and this could
result in RemoveConnection getting invoked first, resulting in bogus
entries in our connection map, which would effectively prevent
connectivity to the other peer until the stale entry got removed
through a lost tie break. And if, per chance, the remote end ran into
exactly the same race condition, then connectivity between that peer
and ourself was broken permanently.

Hitting this race condition required a combination of a) no UDP
heartbeat being received for HeartbeatTimeout(30s) - this causes the
actorLoop to terminate and RemoveConnection to be invoked, and b) the
AddConnection invocation getting delayed for at least that long.
2015-04-09 06:34:35 +01:00
Matthias Radestock fdea7d93f9 refactor: improve abstraction in connection gossip handling
- turn previously free-floating functions into methods on GossipChannel
- move gossip message type dispatch from connection into router
2015-04-03 19:38:01 +01:00
Matthias Radestock d708cb7d4e prevent PMTUVerfied handling from blocking
...due to blocking on sending the pmtu to the forwarder, because the
forwarder has terminated.

Fixes #464.
2015-03-29 14:04:28 +01:00
Matthias Radestock fc22f9664e refactor: improve encapsulation of Forwarder 2015-03-29 12:14:32 +01:00
Matthias Radestock b6448fa196 more idiomatic closing of forwarders, by closing a 'finished' channel
The previous scheme set the reference to main channel to nil and then
drained it. That was racy and hence could lead to deadlock in the
following scenario:

1. multiple senders obtain the main channel from the stored reference
2. main channel reference is set to nil
3. main channel is drained
4. multiple senders send to main channel

So the issue here is that the entire forwarder stopping sequence
occurs between senders obtaining of the reference to the main channel,
and then sending on that channel. If more senders sent than there is
capacity in the channel then this leads to deadlock.
2015-03-28 20:58:42 +00:00
Matthias Radestock 4dbb3d97e0 cosmetic: remove dead code 2015-03-28 20:33:06 +00:00
Matthias Radestock 33520ea230 include peer nickname in display output whenever possible 2015-03-27 05:25:28 +00:00
Matthias Radestock b83f4c9ee9 gofmt 2015-03-26 13:31:11 +00:00
Matthias Radestock 31efd76797 eliminate potential deadlock/dealy in connection.Shutdown
Treat the no-error case the same as the error case...
- use the standard sendAction to communicate with the actor, which
  ensures that we don't block when the actor has terminated
- run in a goroutine to prevent delaying the caller when the actor's
  channel is backed up.
2015-03-26 13:25:23 +00:00
Matthias Radestock 48c73598c4 convert the connection actor to use closures
The only slight trickiness is Shutdown. Generally connections shut
down when an error is encountered, but we also need to be able to shut
down connections w/o an error. Rather than making all the actor
methods return a (terminated bool, error) tuple, we signal the
non-error shutdown by sending nil as the action (instead of a
closure).
2015-03-25 05:14:17 +00:00
Bryan Boreham d87e13b999 Re-order Connection fields more consistently 2015-03-11 14:01:07 +00:00
Bryan Boreham 89fce7f98a Add an 'outbound' field on each connection,
and only attempt new connections to the remote side of outbound connections.
2015-03-11 11:56:47 +00:00
Matthias Radestock 6f89ead9bd log all connection lifecycle events on local peer
There were situations, such as deleting another connection as result
of it losing a tie-break, where lifecycle events of connections on the
local peer weren't logged.

Fixing that entails moving the logging closer to (i.e. right after)
the state change action. This in turn requires promotion of logging to
the Connection interface instead of it LocalConnection. Which in turn
requires a change from 'log' to 'Log', for consistency with other
interface methods.

Fixes #449.
2015-03-10 14:42:18 +00:00
Bryan Boreham 6437caddf2 Reworded comment 2015-02-27 15:02:30 +00:00
Bryan Boreham 139758256b Make clear that tcp-send methods are not handlers and may be called outside of queryLoop 2015-02-27 14:52:47 +00:00
Bryan Boreham 657125fd54 Send to tcpSender on the calling thread, so the Actor channel doesn't get clogged up 2015-02-27 14:12:32 +00:00
Adam Harrison d031e8d246 Merge branch 'master' into 373_detect_udp_connectivity_breakage
Conflicts:
	router/connection.go
2015-02-24 18:53:39 +00:00
Adam Harrison 7618ae033c Simplify to single heartbeat timer 2015-02-24 18:31:18 +00:00
Bryan Boreham 78d2a3e466 Add 'finished' chan to stop callers blocking on closed connection 2015-02-24 10:48:52 +00:00
Adam Harrison 0a0ed7a871 Tear down connections on prolonged loss of UDP heartbeat 2015-02-23 15:29:11 +00:00
Matthias Radestock e2818f883c refactor: move and simplify handshake logic 2015-02-04 16:49:57 +00:00
Matthias Radestock f25696c245 prevent premature gc of peers from topology
Topology gossip can be received on a connection before that connection
has been marked as 'established'. If we do not include unestablished
connections in topology gossip, then parts of the topology can be
removed by gc, since they are deemed unreachable, which can cause
subsequent incremental topology gossips to be rejected due to them
containing references to peers that have been removed by the gc.

Including unestablished connections in topology gossip requires:

- removing the check for 'established' connections in the encoding of
  peers for topology gossip,
- adding the 'established' flag to the internal representation of
  remote connections,
- adding the 'established' flag to to encoding of connections in
  topology gossip,
- treating the *addition* of a connection as an update to the local
  peer.

The latter entails

- bumping the peer version on connection addition (as well as on
  marking 'established' as previously),
- bumping the peer version *unconditionally* on connection deletion
  (rather than only when the connection was 'established', as
  previously),
- moving the initial sending of complete topology on the connection,
  and the broadcasting of a topology update containing the two peers
  at the ends of the connection, from the connection 'established'
  logic to the connection addition logic,
- broadcasting just an topology update for the local peer when a
  connection gets marked as 'established',
- broadcasting a topology update for the local peer *unconditionally*
  when a connection is removed (rather than only doing this when the
  connection was 'established', as previously).
2015-02-01 16:52:39 +00:00
Matthias Radestock b43e5debb1 gofmt 2015-02-01 16:50:43 +00:00
Matthias Radestock 2d135f3da0 prevent premature peer gc
Caused by a race between adding the connection to our map and
receiving a topology gossip on it.

We remove the race by making AddConnection synchronous and invoking it
prior to entering the tcp receive loop.

Fixes #367.
2015-01-31 22:29:07 +00:00
Matthias Radestock c1dd2e3a09 tear down connections that have no (initial) udp connectivity
Prior to the introduction of gossip, a tcp connection would not see
regular communication until it had been marked as 'established',
because the topology communication scheme would periodically send
'FetchAll' only after that. So in the absence of udp connectivity we'd
time out. The timeout could of course occur for other reasons, namely
disrupted tcp connectivity, but the combination of a timeout and 'not
established' pointed to a lack of udp connectivity as a likely
cause. So that's what we checked for.

In the new gossip-based topology communication, however, gossip (of
anything, not just topology) occurs as soon as we have tcp
connectivity. Therefore we will no longer encounter a timeout when
just udp connectivity is disrupted. Which makes our check invalid.

So instead we introduce a one-shot timer, created on handshake
completion and cancelled when we mark the connection as
'established'. When the timer fires, and the connection still hasn't
been established, we shut down the connection with an error indicating
lack of udp connectivity.
2015-01-29 12:41:52 +00:00
Bryan Boreham 5dc9b085a0 Replace previous topology communication with gossip-based mechanism 2015-01-27 12:45:40 +00:00
Bryan Boreham 18df01a4bf Basic gossip implementation 2015-01-27 12:45:40 +00:00
Matthias Radestock 3baa3c09a4 revamp error handling on tcp connection receive loop
- treat crypto decoding errors as errors instead of warnings
- introduce helper for handling protocol messages
- put conn.Shutdown in one place
2015-01-22 16:21:48 +00:00
Matthias Radestock 6253be6ecf cosmetic: nuke stray whitespace 2015-01-22 14:49:00 +00:00
Matthias Radestock 8af2a1c25d refactor: make tie breaking part of the Connection interface
and thus eliminate all knowledge of LocalConnection from the
LocalPeer.handle* methods
2015-01-21 21:44:22 +00:00
Matthias Radestock 99525ebf85 refactor: LocalConnection.CheckFatal be gone!
use Shutdown instead, which is in the Connection interface, thus
further reducing dependency on LocalConnection.
2015-01-21 21:23:59 +00:00
Matthias Radestock 9a27299562 cosmetic: consistent method order 2015-01-21 20:55:51 +00:00
Matthias Radestock fe07a41dc3 refactor: make LocalConnection uid 'private'
which makes sense now that we've abstracted tie breaking
2015-01-21 20:46:45 +00:00
Matthias Radestock 9302105a2e refactor: abstract away connection tie breaking
So we don't need to carry that logic in LocalPeer
2015-01-21 20:42:27 +00:00
Matthias Radestock ac95d5ab29 rename and lift ProtocolMsg into API 2015-01-20 23:23:59 +00:00
Matthias Radestock 1181a0cb33 better APIs for sending protocol messages
no longer tagging requiring the caller to construct them
2015-01-20 22:31:16 +00:00
Matthias Radestock 644697977b refactor: make protocol message tags a separate type 2015-01-20 21:51:18 +00:00
Matthias Radestock 74563c6e3a cosmetic: move connection types from types.go to connection.go 2015-01-20 20:44:35 +00:00
Matthias Radestock 5dd62b2ecf bound check on protocol message receipt
and some refactoring to extract protocol message payload in common place
2015-01-20 20:06:29 +00:00
Matthias Radestock 1b3d65476c refactor: simplify 2015-01-20 11:51:01 +00:00
Matthias Radestock c7701a20b5 refactor: if->switch 2015-01-19 17:01:20 +00:00
Matthias Radestock 1a85990bdc cosmetic: move a comment 2015-01-19 14:51:59 +00:00
Matthias Radestock 48c8f9ea01 refactor: separate object creation from activation 2015-01-19 13:23:25 +00:00
Matthias Radestock 1b229fcc30 gofmt 2015-01-17 19:20:48 +00:00
Matthias Radestock d69854d9c5 cosmetic: turn some if-then-else into 'switch' 2015-01-17 19:19:47 +00:00
Matthias Radestock 247ebaaf19 ignore heartbeats from the 'wrong' connection
The router may receive heartbeat packets that originated from (the
other end of) a different connection with the remote peer than the
current one. If we don't detect that, we may erroneously tell the
remote peer to mark the connection as 'established'. Which can lead to
a crash.

To enable detection, we include the connection UID - which is the same
at both ends - in the heartbeat frame. That way we can simply ignore
heartbeats with a different connection UID than the current connection
to the remote peer.

Previously heartbeat frames were zero length. In order to include the
64 bit connection UID we could just send 8 octets instead. However,
that would potentially trip up the Ethernet decoder at the other end,
and in any case we might as well make heartbeats fit the format of
other special frames, namely having an all-zero Ethernet header. This
in fact results in a simplification of the special frame handling,
since heartbeats are no longer *extra* special.

Fixes #352.
2015-01-17 18:45:19 +00:00
Matthias Radestock a3e9556e75 optimisation: create heartbeat frame only once per connection 2015-01-17 17:29:54 +00:00
Matthias Radestock 95e5ebdb5e tweaks to handling of ConnectionEstablished
1) stop the fast heartbeater asap; reducing the liklihood of getting
an extraneous beat
2) uniformely deal with 'avoiding initial wait for timer ticks'; this
entails sending a FetchAll immediately
3) because of (2) there is now no point initiating a FetchAll from the
tcp reader
2015-01-16 15:54:48 +00:00
Matthias Radestock 49f61c8d4c correct comment
This should have been part of #349.
2015-01-15 20:12:04 +00:00