Fixed reconnect code; refactor tunnel tests.
This commit is contained in:
parent
67215ae5da
commit
c90e1ccb99
@ -4,7 +4,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -139,16 +138,17 @@ func (t *tun) monitor() {
|
|||||||
return
|
return
|
||||||
case <-reconnect.C:
|
case <-reconnect.C:
|
||||||
for _, node := range t.options.Nodes {
|
for _, node := range t.options.Nodes {
|
||||||
t.Lock()
|
|
||||||
if _, ok := t.links[node]; !ok {
|
if _, ok := t.links[node]; !ok {
|
||||||
|
t.Lock()
|
||||||
link, err := t.setupLink(node)
|
link, err := t.setupLink(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Tunnel failed to establish node link to %s: %v", node, err)
|
log.Debugf("Tunnel failed to setup node link to %s: %v", node, err)
|
||||||
|
t.Unlock()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.links[node] = link
|
t.links[node] = link
|
||||||
|
t.Unlock()
|
||||||
}
|
}
|
||||||
t.Unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,11 +190,9 @@ func (t *tun) process() {
|
|||||||
}
|
}
|
||||||
log.Debugf("Sending %+v to %s", newMsg, node)
|
log.Debugf("Sending %+v to %s", newMsg, node)
|
||||||
if err := link.Send(newMsg); err != nil {
|
if err := link.Send(newMsg); err != nil {
|
||||||
log.Debugf("Error sending %+v to %s: %v", newMsg, node, err)
|
log.Debugf("Tunnel error sending %+v to %s: %v", newMsg, node, err)
|
||||||
if err == io.EOF {
|
delete(t.links, node)
|
||||||
delete(t.links, node)
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
@ -211,12 +209,10 @@ func (t *tun) listen(link *link) {
|
|||||||
msg := new(transport.Message)
|
msg := new(transport.Message)
|
||||||
err := link.Recv(msg)
|
err := link.Recv(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Tunnel link %s receive error: %v", link.Remote(), err)
|
log.Debugf("Tunnel link %s receive error: %#v", link.Remote(), err)
|
||||||
if err == io.EOF {
|
t.Lock()
|
||||||
t.Lock()
|
delete(t.links, link.Remote())
|
||||||
delete(t.links, link.Remote())
|
t.Unlock()
|
||||||
t.Unlock()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,13 +349,10 @@ func (t *tun) keepalive(link *link) {
|
|||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Debugf("Error sending keepalive to link %v: %v", link.Remote(), err)
|
log.Debugf("Error sending keepalive to link %v: %v", link.Remote(), err)
|
||||||
if err == io.EOF {
|
t.Lock()
|
||||||
t.Lock()
|
delete(t.links, link.Remote())
|
||||||
delete(t.links, link.Remote())
|
t.Unlock()
|
||||||
t.Unlock()
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO: handle this error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,7 +421,7 @@ func (t *tun) connect() error {
|
|||||||
|
|
||||||
// delete the link
|
// delete the link
|
||||||
defer func() {
|
defer func() {
|
||||||
log.Debugf("Deleting connection from %s", sock.Remote())
|
log.Debugf("Tunnel deleting connection from %s", sock.Remote())
|
||||||
t.Lock()
|
t.Lock()
|
||||||
delete(t.links, sock.Remote())
|
delete(t.links, sock.Remote())
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
@ -527,8 +520,9 @@ func (t *tun) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
// close all the sockets
|
// close all the sockets
|
||||||
for _, s := range t.sockets {
|
for id, s := range t.sockets {
|
||||||
s.Close()
|
s.Close()
|
||||||
|
delete(t.sockets, id)
|
||||||
}
|
}
|
||||||
// close the connection
|
// close the connection
|
||||||
close(t.closed)
|
close(t.closed)
|
||||||
|
@ -9,13 +9,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// testAccept will accept connections on the transport, create a new link and tunnel on top
|
// testAccept will accept connections on the transport, create a new link and tunnel on top
|
||||||
func testAccept(t *testing.T, tun Tunnel, wg *sync.WaitGroup) {
|
func testAccept(t *testing.T, tun Tunnel, wait chan struct{}, wg *sync.WaitGroup) {
|
||||||
// listen on some virtual address
|
// listen on some virtual address
|
||||||
tl, err := tun.Listen("test-tunnel")
|
tl, err := tun.Listen("test-tunnel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// receiver ready; notify sender
|
||||||
|
wait <- struct{}{}
|
||||||
|
|
||||||
// accept a connection
|
// accept a connection
|
||||||
c, err := tl.Accept()
|
c, err := tl.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -46,7 +49,12 @@ func testAccept(t *testing.T, tun Tunnel, wg *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// testSend will create a new link to an address and then a tunnel on top
|
// testSend will create a new link to an address and then a tunnel on top
|
||||||
func testSend(t *testing.T, tun Tunnel) {
|
func testSend(t *testing.T, tun Tunnel, wait chan struct{}, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// wait for the listener to get ready
|
||||||
|
<-wait
|
||||||
|
|
||||||
// dial a new session
|
// dial a new session
|
||||||
c, err := tun.Dial("test-tunnel")
|
c, err := tun.Dial("test-tunnel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -95,8 +103,6 @@ func TestTunnel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer tunB.Close()
|
defer tunB.Close()
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 50)
|
|
||||||
|
|
||||||
// start tunA
|
// start tunA
|
||||||
err = tunA.Connect()
|
err = tunA.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -104,51 +110,190 @@ func TestTunnel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer tunA.Close()
|
defer tunA.Close()
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 50)
|
wait := make(chan struct{})
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
// start accepting connections
|
|
||||||
// on tunnel A
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go testAccept(t, tunA, &wg)
|
// start the listener
|
||||||
|
go testAccept(t, tunB, wait, &wg)
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 50)
|
wg.Add(1)
|
||||||
|
// start the client
|
||||||
// dial and send via B
|
go testSend(t, tunA, wait, &wg)
|
||||||
testSend(t, tunB)
|
|
||||||
|
|
||||||
// wait until done
|
// wait until done
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoopbackTunnel(t *testing.T) {
|
func TestLoopbackTunnel(t *testing.T) {
|
||||||
// create a new tunnel client
|
// create a new tunnel
|
||||||
tun := NewTunnel(
|
tun := NewTunnel(
|
||||||
Address("127.0.0.1:9096"),
|
Address("127.0.0.1:9096"),
|
||||||
Nodes("127.0.0.1:9096"),
|
Nodes("127.0.0.1:9096"),
|
||||||
)
|
)
|
||||||
|
|
||||||
// start tunB
|
// start tunnel
|
||||||
err := tun.Connect()
|
err := tun.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer tun.Close()
|
defer tun.Close()
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 50)
|
wait := make(chan struct{})
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
// start accepting connections
|
|
||||||
// on tunnel A
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go testAccept(t, tun, &wg)
|
// start the listener
|
||||||
|
go testAccept(t, tun, wait, &wg)
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 50)
|
wg.Add(1)
|
||||||
|
// start the client
|
||||||
// dial and send via B
|
go testSend(t, tun, wait, &wg)
|
||||||
testSend(t, tun)
|
|
||||||
|
// wait until done
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testBrokenTunAccept(t *testing.T, tun Tunnel, wait chan struct{}, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// listen on some virtual address
|
||||||
|
tl, err := tun.Listen("test-tunnel")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// receiver ready; notify sender
|
||||||
|
wait <- struct{}{}
|
||||||
|
|
||||||
|
// accept a connection
|
||||||
|
c, err := tl.Accept()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// accept the message and close the tunnel
|
||||||
|
// we do this to simulate loss of network connection
|
||||||
|
m := new(transport.Message)
|
||||||
|
if err := c.Recv(m); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tun.Close()
|
||||||
|
|
||||||
|
// re-start tunnel
|
||||||
|
err = tun.Connect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer tun.Close()
|
||||||
|
|
||||||
|
// listen on some virtual address
|
||||||
|
tl, err = tun.Listen("test-tunnel")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// receiver ready; notify sender
|
||||||
|
wait <- struct{}{}
|
||||||
|
|
||||||
|
// accept a connection
|
||||||
|
c, err = tl.Accept()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// accept the message
|
||||||
|
m = new(transport.Message)
|
||||||
|
if err := c.Recv(m); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify sender we have received the message
|
||||||
|
<-wait
|
||||||
|
}
|
||||||
|
|
||||||
|
func testBrokenTunSend(t *testing.T, tun Tunnel, wait chan struct{}, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// wait for the listener to get ready
|
||||||
|
<-wait
|
||||||
|
|
||||||
|
// dial a new session
|
||||||
|
c, err := tun.Dial("test-tunnel")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
m := transport.Message{
|
||||||
|
Header: map[string]string{
|
||||||
|
"test": "send",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the message
|
||||||
|
if err := c.Send(&m); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for the listener to get ready
|
||||||
|
<-wait
|
||||||
|
|
||||||
|
// give it time to reconnect
|
||||||
|
time.Sleep(2 * ReconnectTime)
|
||||||
|
|
||||||
|
// send the message
|
||||||
|
if err := c.Send(&m); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for the listener to receive the message
|
||||||
|
// c.Send merely enqueues the message to the link send queue and returns
|
||||||
|
// in order to verify it was received we wait for the listener to tell us
|
||||||
|
wait <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReconnectTunnel(t *testing.T) {
|
||||||
|
// create a new tunnel client
|
||||||
|
tunA := NewTunnel(
|
||||||
|
Address("127.0.0.1:9096"),
|
||||||
|
Nodes("127.0.0.1:9097"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// create a new tunnel server
|
||||||
|
tunB := NewTunnel(
|
||||||
|
Address("127.0.0.1:9097"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// start tunnel
|
||||||
|
err := tunB.Connect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we manually override the tunnel.ReconnectTime value here
|
||||||
|
// this is so that we make the reconnects faster than the default 5s
|
||||||
|
ReconnectTime = 200 * time.Millisecond
|
||||||
|
|
||||||
|
// start tunnel
|
||||||
|
err = tunA.Connect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wait := make(chan struct{})
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
// start tunnel listener
|
||||||
|
go testBrokenTunAccept(t, tunB, wait, &wg)
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
// start tunnel sender
|
||||||
|
go testBrokenTunSend(t, tunA, wait, &wg)
|
||||||
|
|
||||||
// wait until done
|
// wait until done
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user