Files
weave/router/gossip.go
T

163 lines
4.8 KiB
Go

package router
import (
"bytes"
"encoding/gob"
"fmt"
"log"
"time"
)
const GossipInterval = 30 * time.Second
type Gossip interface {
// specific message from one peer to another
// intermediate peers relay it using unicast topology.
GossipUnicast(dstPeerName PeerName, buf []byte) error
// send a message to every peer, relayed using broadcast topology.
GossipBroadcast(buf []byte) error
}
type Gossiper interface {
OnGossipUnicast(sender PeerName, msg []byte) error
OnGossipBroadcast(msg []byte) error
// Return state of everything we know; gets called periodically
Gossip() []byte
// merge in state and return "everything new I've just learnt",
// or nil if nothing in the received message was new
OnGossip(buf []byte) ([]byte, error)
}
type GossipChannel struct {
ourself *LocalPeer
name string
hash uint32
gossiper Gossiper
}
func (router *Router) NewGossip(channelName string, g Gossiper) Gossip {
channelHash := hash(channelName)
channel := &GossipChannel{router.Ourself, channelName, channelHash, g}
router.GossipChannels[channelHash] = channel
return channel
}
func (router *Router) SendAllGossip() {
for _, channel := range router.GossipChannels {
channel.SendGossipMsg(channel.gossiper.Gossip())
}
}
func (router *Router) SendAllGossipDown(conn Connection) {
for _, channel := range router.GossipChannels {
protocolMsg := channel.gossipMsg(channel.gossiper.Gossip())
conn.(ProtocolSender).SendProtocolMsg(protocolMsg)
}
}
func (router *Router) handleGossip(payload []byte, onok func(*GossipChannel, PeerName, []byte, *gob.Decoder) error) error {
decoder := gob.NewDecoder(bytes.NewReader(payload))
var channelHash uint32
if err := decoder.Decode(&channelHash); err != nil {
return err
}
channel, found := router.GossipChannels[channelHash]
if !found {
return fmt.Errorf("[gossip] received unknown channel with hash %v", channelHash)
}
var srcName PeerName
if err := decoder.Decode(&srcName); err != nil {
return err
}
if err := onok(channel, srcName, payload, decoder); err != nil {
return err
}
return nil
}
func deliverGossipUnicast(channel *GossipChannel, srcName PeerName, origPayload []byte, dec *gob.Decoder) error {
var destName PeerName
if err := dec.Decode(&destName); err != nil {
return err
}
if channel.ourself.Name == destName {
var payload []byte
if err := dec.Decode(&payload); err != nil {
return err
}
return channel.gossiper.OnGossipUnicast(srcName, payload)
} else {
return channel.relayGossipUnicast(destName, origPayload)
}
}
func deliverGossipBroadcast(channel *GossipChannel, srcName PeerName, origPayload []byte, dec *gob.Decoder) error {
var payload []byte
if err := dec.Decode(&payload); err != nil {
return err
}
if err := channel.gossiper.OnGossipBroadcast(payload); err != nil {
return err
}
return channel.relayGossipBroadcast(srcName, origPayload)
}
func deliverGossip(channel *GossipChannel, srcName PeerName, _ []byte, dec *gob.Decoder) error {
var payload []byte
if err := dec.Decode(&payload); err != nil {
return err
}
if newBuf, err := channel.gossiper.OnGossip(payload); err != nil {
return err
} else if newBuf != nil {
channel.SendGossipMsg(newBuf)
}
return nil
}
func (c *GossipChannel) SendGossipMsg(buf []byte) {
protocolMsg := c.gossipMsg(buf)
c.ourself.ForEachConnection(func(_ PeerName, conn Connection) {
conn.(ProtocolSender).SendProtocolMsg(protocolMsg)
})
}
func (c *GossipChannel) gossipMsg(buf []byte) ProtocolMsg {
return ProtocolMsg{ProtocolGossip, GobEncode(c.hash, c.ourself.Name, buf)}
}
func (c *GossipChannel) GossipUnicast(dstPeerName PeerName, buf []byte) error {
return c.relayGossipUnicast(dstPeerName, GobEncode(c.hash, c.ourself.Name, dstPeerName, buf))
}
func (c *GossipChannel) GossipBroadcast(buf []byte) error {
return c.relayGossipBroadcast(c.ourself.Name, GobEncode(c.hash, c.ourself.Name, buf))
}
func (c *GossipChannel) relayGossipUnicast(dstPeerName PeerName, msg []byte) error {
if relayPeerName, found := c.ourself.Router.Routes.Unicast(dstPeerName); !found {
c.log("unknown relay destination:", dstPeerName)
} else if conn, found := c.ourself.ConnectionTo(relayPeerName); !found {
c.log("unable to find connection to relay peer", relayPeerName)
} else {
conn.(ProtocolSender).SendProtocolMsg(ProtocolMsg{ProtocolGossipUnicast, msg})
}
return nil
}
func (c *GossipChannel) relayGossipBroadcast(srcName PeerName, msg []byte) error {
if srcPeer, found := c.ourself.Router.Peers.Fetch(srcName); !found {
c.log("unable to relay broadcast from unknown peer", srcName)
} else {
protocolMsg := ProtocolMsg{ProtocolGossipBroadcast, msg}
for _, conn := range c.ourself.NextBroadcastHops(srcPeer) {
conn.SendProtocolMsg(protocolMsg)
}
}
return nil
}
func (c *GossipChannel) log(args ...interface{}) {
log.Println(append(append([]interface{}{}, "[gossip "+c.name+"]:"), args...)...)
}