github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/gateway/nodes.go (about)

     1  package gateway
     2  
     3  import (
     4  	"errors"
     5  	"net"
     6  	"time"
     7  
     8  	"github.com/NebulousLabs/Sia/crypto"
     9  	"github.com/NebulousLabs/Sia/encoding"
    10  	"github.com/NebulousLabs/Sia/modules"
    11  )
    12  
    13  const (
    14  	maxSharedNodes = 10
    15  	maxAddrLength  = 100
    16  	minPeers       = 3
    17  )
    18  
    19  // addNode adds an address to the set of nodes on the network.
    20  func (g *Gateway) addNode(addr modules.NetAddress) error {
    21  	if _, exists := g.nodes[addr]; exists {
    22  		return errors.New("node already added")
    23  	} else if net.ParseIP(addr.Host()) == nil {
    24  		return errors.New("address is not routable: " + string(addr))
    25  	} else if addr.IsValid() != nil {
    26  		return errors.New("address is not valid: " + string(addr))
    27  	}
    28  	g.nodes[addr] = struct{}{}
    29  	return nil
    30  }
    31  
    32  func (g *Gateway) removeNode(addr modules.NetAddress) error {
    33  	if _, exists := g.nodes[addr]; !exists {
    34  		return errors.New("no record of that node")
    35  	}
    36  	delete(g.nodes, addr)
    37  	g.log.Println("INFO: removed node", addr)
    38  	return nil
    39  }
    40  
    41  func (g *Gateway) randomNode() (modules.NetAddress, error) {
    42  	if len(g.nodes) > 0 {
    43  		r, _ := crypto.RandIntn(len(g.nodes))
    44  		for node := range g.nodes {
    45  			if r <= 0 {
    46  				return node, nil
    47  			}
    48  			r--
    49  		}
    50  	}
    51  
    52  	return "", errNoPeers
    53  }
    54  
    55  // shareNodes is the receiving end of the ShareNodes RPC. It writes up to 10
    56  // randomly selected nodes to the caller.
    57  func (g *Gateway) shareNodes(conn modules.PeerConn) error {
    58  	id := g.mu.RLock()
    59  	var nodes []modules.NetAddress
    60  	for node := range g.nodes {
    61  		if len(nodes) == maxSharedNodes {
    62  			break
    63  		}
    64  		nodes = append(nodes, node)
    65  	}
    66  	g.mu.RUnlock(id)
    67  	return encoding.WriteObject(conn, nodes)
    68  }
    69  
    70  // requestNodes is the calling end of the ShareNodes RPC.
    71  func (g *Gateway) requestNodes(conn modules.PeerConn) error {
    72  	var nodes []modules.NetAddress
    73  	if err := encoding.ReadObject(conn, &nodes, maxSharedNodes*maxAddrLength); err != nil {
    74  		return err
    75  	}
    76  	id := g.mu.Lock()
    77  	for _, node := range nodes {
    78  		err := g.addNode(node)
    79  		if err != nil {
    80  			g.log.Printf("WARN: peer '%v' send the invalid addr '%v'", conn.RemoteAddr(), node)
    81  		}
    82  	}
    83  	g.save()
    84  	g.mu.Unlock(id)
    85  	return nil
    86  }
    87  
    88  // relayNode is the recipient end of the RelayNode RPC. It reads a node, adds
    89  // it to the Gateway's node list, and relays it to each of the Gateway's
    90  // peers. If the node is already in the node list, it is not relayed.
    91  func (g *Gateway) relayNode(conn modules.PeerConn) error {
    92  	// read address
    93  	var addr modules.NetAddress
    94  	if err := encoding.ReadObject(conn, &addr, maxAddrLength); err != nil {
    95  		return err
    96  	}
    97  	// add node
    98  	err := func() error {
    99  		// We wrap this logic in an anonymous function so we can defer Unlock to
   100  		// avoid managing locks across branching.
   101  		id := g.mu.Lock()
   102  		defer g.mu.Unlock(id)
   103  		if err := g.addNode(addr); err != nil {
   104  			return err
   105  		}
   106  		if err := g.save(); err != nil {
   107  			return err
   108  		}
   109  		return nil
   110  	}()
   111  	if err != nil {
   112  		return err
   113  	}
   114  	// relay
   115  	peers := g.Peers()
   116  	go g.Broadcast("RelayNode", addr, peers)
   117  	return nil
   118  }
   119  
   120  // sendAddress is the calling end of the RelayNode RPC.
   121  func (g *Gateway) sendAddress(conn modules.PeerConn) error {
   122  	// don't send if we aren't connectible
   123  	if g.Address().IsValid() != nil {
   124  		return errors.New("can't send address without knowing external IP")
   125  	}
   126  	return encoding.WriteObject(conn, g.Address())
   127  }
   128  
   129  // threadedNodeManager tries to keep the Gateway's node list healthy. As long
   130  // as the Gateway has fewer than minNodeListSize nodes, it asks a random peer
   131  // for more nodes. It also continually pings nodes in order to establish their
   132  // connectivity. Unresponsive nodes are aggressively removed.
   133  func (g *Gateway) threadedNodeManager() {
   134  	for {
   135  		select {
   136  		case <-time.After(5 * time.Second):
   137  		case <-g.closeChan:
   138  			return
   139  		}
   140  
   141  		id := g.mu.RLock()
   142  		numNodes := len(g.nodes)
   143  		peer, err := g.randomPeer()
   144  		g.mu.RUnlock(id)
   145  		if err != nil {
   146  			// can't do much until we have peers
   147  			continue
   148  		}
   149  
   150  		if numNodes < minNodeListLen {
   151  			g.RPC(peer, "ShareNodes", g.requestNodes)
   152  		}
   153  
   154  		// find an untested node to check
   155  		id = g.mu.RLock()
   156  		node, err := g.randomNode()
   157  		g.mu.RUnlock(id)
   158  		if err != nil {
   159  			continue
   160  		}
   161  
   162  		// try to connect
   163  		conn, err := net.DialTimeout("tcp", string(node), dialTimeout)
   164  		if err != nil {
   165  			id = g.mu.Lock()
   166  			g.removeNode(node)
   167  			g.save()
   168  			g.mu.Unlock(id)
   169  			continue
   170  		}
   171  		// if connection succeeds, supply an unacceptable version to ensure
   172  		// they won't try to add us as a peer
   173  		encoding.WriteObject(conn, "0.0.0")
   174  		conn.Close()
   175  		// sleep for an extra 10 minutes after success; we don't want to spam
   176  		// connectable nodes
   177  		select {
   178  		case <-time.After(10 * time.Minute):
   179  		case <-g.closeChan:
   180  			return
   181  		}
   182  	}
   183  }