From f73d2fb2d96bc3fbc8bc4cce452e3c19689de01e Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Fri, 26 Jan 2018 22:52:32 +0100 Subject: Added initial version of peer teardown There is a double lock issue with device.Close which has yet to be resolved. --- src/device.go | 111 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 24 deletions(-) (limited to 'src/device.go') diff --git a/src/device.go b/src/device.go index 5f8e91b..f1c09c6 100644 --- a/src/device.go +++ b/src/device.go @@ -9,7 +9,7 @@ import ( ) type Device struct { - isUp AtomicBool // device is up (TUN interface up)? + isUp AtomicBool // device is (going) up isClosed AtomicBool // device is closed? (acting as guard) log *Logger // collection of loggers for levels idCounter uint // for assigning debug ids to peers @@ -18,6 +18,11 @@ type Device struct { device TUNDevice mtu int32 } + state struct { + mutex deadlock.Mutex + changing AtomicBool + current bool + } pool struct { messageBuffers sync.Pool } @@ -46,37 +51,86 @@ type Device struct { mac CookieChecker } -func (device *Device) Up() { - device.mutex.Lock() - defer device.mutex.Unlock() +func deviceUpdateState(device *Device) { - device.net.mutex.Lock() - defer device.net.mutex.Unlock() + // check if state already being updated (guard) - if device.isUp.Swap(true) { + if device.state.changing.Swap(true) { return } - unsafeUpdateBind(device) + // compare to current state of device + + device.state.mutex.Lock() + + newIsUp := device.isUp.Get() + + if newIsUp == device.state.current { + device.state.mutex.Unlock() + device.state.changing.Set(false) + return + } + + device.state.mutex.Unlock() + + // change state of device + + switch newIsUp { + case true: + + // start listener + + if err := device.BindUpdate(); err != nil { + device.isUp.Set(false) + break + } + + // start every peer + + for _, peer := range device.peers { + peer.Start() + } + + case false: + + // stop listening + + device.BindClose() - for _, peer := range device.peers { - peer.Start() + // stop every peer + + for _, peer := range device.peers { + peer.Stop() + } } + + // update state variables + // and check for state change in the mean time + + device.state.current = newIsUp + device.state.changing.Set(false) + deviceUpdateState(device) } -func (device *Device) Down() { - device.mutex.Lock() - defer device.mutex.Unlock() +func (device *Device) Up() { + + // closed device cannot be brought up - if !device.isUp.Swap(false) { + if device.isClosed.Get() { return } - closeBind(device) + device.state.mutex.Lock() + device.isUp.Set(true) + device.state.mutex.Unlock() + deviceUpdateState(device) +} - for _, peer := range device.peers { - peer.Stop() - } +func (device *Device) Down() { + device.state.mutex.Lock() + device.isUp.Set(false) + device.state.mutex.Unlock() + deviceUpdateState(device) } /* Warning: @@ -87,7 +141,6 @@ func removePeerUnsafe(device *Device, key NoisePublicKey) { if !ok { return } - peer.Stop() device.routingTable.RemovePeer(peer) delete(device.peers, key) } @@ -231,20 +284,30 @@ func (device *Device) RemovePeer(key NoisePublicKey) { func (device *Device) RemoveAllPeers() { device.mutex.Lock() defer device.mutex.Unlock() - for key := range device.peers { - removePeerUnsafe(device, key) + + for key, peer := range device.peers { + peer.Stop() + peer, ok := device.peers[key] + if !ok { + return + } + device.routingTable.RemovePeer(peer) + delete(device.peers, key) } } func (device *Device) Close() { + device.log.Info.Println("Device closing") if device.isClosed.Swap(true) { return } - device.log.Info.Println("Closing device") - device.RemoveAllPeers() device.signal.stop.Broadcast() device.tun.device.Close() - closeBind(device) + device.BindClose() + device.isUp.Set(false) + println("remove") + device.RemoveAllPeers() + device.log.Info.Println("Interface closed") } func (device *Device) Wait() chan struct{} { -- cgit v1.2.3