github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/p2pserver/discover/udp_circle.go (about)

     1  package discover
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"time"
     8  
     9  	comm "github.com/sixexorg/magnetic-ring/common"
    10  	"github.com/sixexorg/magnetic-ring/log"
    11  )
    12  
    13  const (
    14  	maxNeighborsCircle = 10
    15  	REQPEERORGNUM      = 200
    16  )
    17  
    18  // Errors
    19  var (
    20  	errCirclePacketTooSmall = errors.New("circle data too small")
    21  	// errBadHash          = errors.New("bad hash")
    22  	// errExpired          = errors.New("expired")
    23  	// errUnsolicitedReply = errors.New("unsolicited reply")
    24  	errUnknownCircle = errors.New("unknown circle")
    25  	// errTimeout          = errors.New("RPC timeout")
    26  	// errClockWarp        = errors.New("reply deadline too far in the future")
    27  	// errClosed           = errors.New("socket closed")
    28  )
    29  
    30  // RPC request structures
    31  type (
    32  	sendcircle struct {
    33  		Version    uint
    34  		From, To   rpcEndpoint
    35  		SrcOrgID   comm.Address
    36  		OwnID      uint64
    37  		BAdd       bool
    38  		Expiration uint64
    39  	}
    40  
    41  	// pong is the reply to ping.
    42  	rtncircle struct {
    43  		// This field should mirror the UDP envelope address
    44  		// of the ping packet, which provides a way to discover the
    45  		// the external address (after NAT).
    46  		To rpcEndpoint
    47  
    48  		ReplyTok   []byte // This contains the hash of the ping packet.
    49  		Expiration uint64 // Absolute timestamp at which the packet becomes invalid.
    50  	}
    51  
    52  	sendConnect struct {
    53  		Version         uint
    54  		From, To        rpcEndpoint
    55  		OwnID, RemoteID uint64
    56  		BConnect        bool
    57  		BStellarNode    bool
    58  		Expiration      uint64
    59  	}
    60  
    61  	rtnConnect struct {
    62  		// This field should mirror the UDP envelope address
    63  		// of the ping packet, which provides a way to discover the
    64  		// the external address (after NAT).
    65  		To rpcEndpoint
    66  
    67  		ReplyTok   []byte // This contains the hash of the ping packet.
    68  		Expiration uint64 // Absolute timestamp at which the packet becomes invalid.
    69  	}
    70  
    71  	findcircle struct {
    72  		// Target     CirclseID // doesn't need to be an actual public key
    73  		Target     comm.Address
    74  		Expiration uint64
    75  	}
    76  
    77  	neighborscircle struct {
    78  		Nodes      []rpcNode
    79  		Num        uint64
    80  		Expiration uint64
    81  	}
    82  
    83  	reqPeerOrg struct {
    84  		Target     NodeID // doesn't need to be an actual public key
    85  		Expiration uint64
    86  	}
    87  
    88  	rntPeerOrg struct {
    89  		Num        uint64
    90  		OwnID      uint64
    91  		Orgs       []comm.Address
    92  		Expiration uint64
    93  	}
    94  
    95  	reqPeerConnect struct {
    96  		Target     NodeID // doesn't need to be an actual public key
    97  		Expiration uint64
    98  	}
    99  
   100  	// reply to findnode
   101  	rntPeerConnect struct {
   102  		Num        uint64
   103  		OwnID      uint64
   104  		RemoteID   []uint64
   105  		Expiration uint64
   106  	}
   107  
   108  	connectCircuOrg struct {
   109  		From        rpcEndpoint
   110  		OrgID       comm.Address
   111  		ConnectNode rpcNode
   112  		Expiration  uint64
   113  	}
   114  
   115  	rtnCircuOrg struct {
   116  		Expiration uint64
   117  	}
   118  )
   119  
   120  func (t *udp) sendcircle(ndoe, srcnode *Node, SrcOrgID comm.Address, ownid uint64, badd bool) error {
   121  	// TODO: maybe check for ReplyTo field in callback to measure RTT
   122  	//fmt.Println(" ****** udp sendcircle start ...... badd:",badd)
   123  	toid, toaddr := ndoe.ID, ndoe.addr()
   124  	errc := t.pending(toid, rtncirclePacket, func(interface{}) bool { return true })
   125  	t.send(toaddr, sendcirclePacket, &sendcircle{
   126  		Version: Version,
   127  		From:    t.ourEndpoint,
   128  		// To:         makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB
   129  		BAdd:       badd,
   130  		OwnID:      ownid,
   131  		SrcOrgID:   SrcOrgID,
   132  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   133  	})
   134  	errs := <-errc
   135  	return errs
   136  }
   137  
   138  func (t *udp) findcircle(toid NodeID, toaddr *net.UDPAddr, target comm.Address) ([]*Node, error) {
   139  	//fmt.Println(" ******* udp findcircle ...... ")
   140  	nodes := make([]*Node, 0)
   141  	nreceived := uint64(0)
   142  	total := uint64(0)
   143  	errc := t.pending(toid, neighborscirclePacket, func(r interface{}) bool {
   144  		reply := r.(*neighborscircle)
   145  		//fmt.Println(" ***** len(reply.Nodes):",len(reply.Nodes))
   146  		//fmt.Println(" ***** reply.Nodes:",reply.Nodes)
   147  		total = reply.Num
   148  		for _, rn := range reply.Nodes {
   149  			nreceived++
   150  			// n, err := t.nodeFromRPC(toaddr, rn)
   151  			n, err := t.nodeFromRPC2(toaddr, rn)
   152  
   153  			if err != nil {
   154  				log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err)
   155  				//fmt.Println(" *** findcircle received", "ip", rn.IP, "addr", toaddr, "err", err)
   156  				continue
   157  			}
   158  			nodes = append(nodes, n)
   159  		}
   160  		return nreceived >= total
   161  	})
   162  	t.send(toaddr, findcirclePacket, &findcircle{
   163  		Target:     target,
   164  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   165  	})
   166  	err := <-errc
   167  	return nodes, err
   168  }
   169  
   170  func (t *udp) sendConnectInfo(ndoe, srcnode *Node, ownid, remoteid uint64, bconnect, bstellar bool) error {
   171  	// TODO: maybe check for ReplyTo field in callback to measure RTT
   172  	//fmt.Println(" ****** udp sendConnect start ...... bconnect:",bconnect)
   173  	//defer fmt.Println(" ****** udp sendConnect end ...... bconnect:", bconnect)
   174  
   175  	toid, toaddr := ndoe.ID, ndoe.addr()
   176  	errc := t.pending(toid, rtnconnectPacket, func(interface{}) bool { return true })
   177  	eerr := t.send(toaddr, sendConnectPacket, &sendConnect{
   178  		Version:      Version,
   179  		From:         t.ourEndpoint,
   180  		OwnID:        ownid,
   181  		RemoteID:     remoteid,
   182  		BConnect:     bconnect,
   183  		BStellarNode: bstellar,
   184  		Expiration:   uint64(time.Now().Add(expiration).Unix()),
   185  	})
   186  
   187  	if eerr!=nil {
   188  		fmt.Println("🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞-->",eerr)
   189  	}
   190  
   191  	return <-errc
   192  }
   193  
   194  func (t *udp) reqPeerOrg(toid NodeID, toaddr *net.UDPAddr, node *Node) (*rtnTabPeerOrg, error) {
   195  	//fmt.Println(" ******* udp reqPeerOrg ...... ")
   196  	orgs := new(rtnTabPeerOrg)
   197  	orgs.orgsId = make([]comm.Address, 0)
   198  	orgs.node = node
   199  
   200  	receiveNum := uint64(0)
   201  	total := uint64(0)
   202  
   203  	errc := t.pending(toid, rntPeerOrgPacket, func(r interface{}) bool {
   204  		reply := r.(*rntPeerOrg)
   205  		//fmt.Println(" ***** len(reply.Nodes):",len(reply.Orgs))
   206  		total = reply.Num
   207  		orgs.ownId = reply.OwnID
   208  		// for _, rn := range reply.Orgs {
   209  		orgs.orgsId = append(orgs.orgsId, reply.Orgs...)
   210  		receiveNum = receiveNum + uint64(len(reply.Orgs))
   211  		// }
   212  		return receiveNum >= total
   213  	})
   214  	t.send(toaddr, reqPeerOrgPacket, &reqPeerOrg{
   215  		Target:     toid,
   216  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   217  	})
   218  	err := <-errc
   219  	//fmt.Println(" *8888888* udp reqPeerConnect orgs:",*orgs)
   220  	return orgs, err
   221  }
   222  
   223  func (t *udp) reqPeerConnect(toid NodeID, toaddr *net.UDPAddr, node *Node) (*rtnTabPeerConnect, error) {
   224  	//fmt.Println(" ******* udp reqPeerConnect ...... ")
   225  	receiveNum := uint64(0)
   226  	total := uint64(0)
   227  	result := new(rtnTabPeerConnect)
   228  	result.remotesID = make([]uint64, 0)
   229  	result.node = node
   230  
   231  	errc := t.pending(toid, rntPeerConnectPacket, func(r interface{}) bool {
   232  		reply := r.(*rntPeerConnect)
   233  		//fmt.Println(" ***** reqPeerConnect len(reply.Peer):",len(reply.RemoteID))
   234  		total = reply.Num
   235  		result.ownId = reply.OwnID
   236  		for _, rn := range reply.RemoteID {
   237  			result.remotesID = append(result.remotesID, rn)
   238  			receiveNum = receiveNum + 1
   239  		}
   240  		return receiveNum >= total
   241  	})
   242  	t.send(toaddr, reqPeerConnectPacket, &reqPeerConnect{
   243  		Target:     toid,
   244  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   245  	})
   246  	err := <-errc
   247  	//fmt.Println(" *8888888* udp reqPeerConnect result:",*result)
   248  	return result, err
   249  }
   250  
   251  func (t *udp) connectCircuOrg(ndoe, connectnode *Node, orgid comm.Address) error {
   252  	// TODO: maybe check for ReplyTo field in callback to measure RTT
   253  	//fmt.Println(" ****** udp connectCircuOrg start ...... ")
   254  	defer fmt.Println(" ****** udp connectCircuOrg end ...... ")
   255  	toid, toaddr := ndoe.ID, ndoe.addr()
   256  	errc := t.pending(toid, rtnCircuOrgPacket, func(interface{}) bool { return true })
   257  	t.send(toaddr, connectCircuOrgPacket, &connectCircuOrg{
   258  		From:        t.ourEndpoint,
   259  		OrgID:       orgid,
   260  		ConnectNode: nodeToRPC(connectnode), //
   261  		Expiration:  uint64(time.Now().Add(expiration).Unix()),
   262  	})
   263  	return <-errc
   264  }
   265  
   266  func (req *sendcircle) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   267  	if expired(req.Expiration) {
   268  		return errExpired
   269  	}
   270  	t.send(from, rtncirclePacket, &rtncircle{
   271  		To:         makeEndpoint(from, req.From.TCP),
   272  		ReplyTok:   mac,
   273  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   274  	})
   275  
   276  	// // add circle
   277  	// fmt.Println(" ***** sendcircle handle from:",from)
   278  	// fmt.Println(" ***** sendcircle handle fromID:",fromID)
   279  	// fmt.Println(" ***** sendcircle handle req.From:",req.From)
   280  	n := NewNode(fromID, from.IP, uint16(from.Port), req.From.TCP)
   281  	if req.SrcOrgID == t.stellarNodeID {
   282  		go t.stellarNode(n, req.SrcOrgID, req.OwnID, req.BAdd)
   283  	} else {
   284  		go t.setOrgs(n, req.SrcOrgID, req.OwnID, req.BAdd)
   285  	}
   286  
   287  	return nil
   288  }
   289  
   290  func (req *sendcircle) name() string { return "sendcircle/v4" }
   291  
   292  func (req *rtncircle) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   293  	if expired(req.Expiration) {
   294  		return errExpired
   295  	}
   296  	if !t.handleReply(fromID, rtncirclePacket, req) {
   297  		return errUnsolicitedReply
   298  	}
   299  	return nil
   300  }
   301  
   302  func (req *rtncircle) name() string { return "rtncircle/v4" }
   303  
   304  func (req *findcircle) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   305  	//fmt.Println(" ****** findcircle handle ...... ")
   306  	if expired(req.Expiration) {
   307  		return errExpired
   308  	}
   309  	// if t.db.node(fromID) == nil {
   310  	// 	return errUnknownNode
   311  	// }
   312  
   313  	var err error
   314  	targetData := make([]*Node, 0)
   315  	if req.Target == t.stellarNodeID {
   316  		targetData, err = t.getStellar()
   317  	} else {
   318  		targetData, err = t.getCircle(req.Target, maxNeighborsCircle)
   319  	}
   320  
   321  	if err != nil {
   322  		return errUnknownCircle
   323  	}
   324  
   325  	if len(targetData) <= 0 {
   326  		return errCirclePacketTooSmall
   327  	}
   328  
   329  	p := neighborscircle{
   330  		Num:        uint64(len(targetData)),
   331  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   332  	}
   333  	// Send neighbors in chunks with at most maxNeighbors per packet
   334  	// to stay below the 1280 byte limit.
   335  	for i, n := range targetData {
   336  		// errip := netutil.CheckRelayIP(from.IP, n.IP)
   337  		// if errip != nil {
   338  		// 	fmt.Printf(" ***** CheckRelayIP from.IP:%v,n.IP:%v\n",from.IP,n.IP)
   339  		// 	fmt.Println(" ****** CheckRelayIP error errip:",errip)
   340  		// 	continue
   341  		// }
   342  		p.Nodes = append(p.Nodes, nodeToRPC(n))
   343  		if len(p.Nodes) == maxNeighbors || i == len(targetData)-1 {
   344  			t.send(from, neighborscirclePacket, &p)
   345  			p.Nodes = p.Nodes[:0]
   346  		}
   347  	}
   348  	return nil
   349  }
   350  
   351  func (req *findcircle) name() string { return "FINDCIRCLE/v4" }
   352  
   353  func (req *neighborscircle) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   354  	if expired(req.Expiration) {
   355  		return errExpired
   356  	}
   357  	//fmt.Println(" ******** neighborscircle handle len(req.Nodes):",len(req.Nodes))
   358  	err := t.handleReply(fromID, neighborscirclePacket, req)
   359  	if !err {
   360  		//fmt.Println(" ****** neighborscircle handle err:",err)
   361  		return errUnsolicitedReply
   362  	}
   363  	return nil
   364  }
   365  
   366  func (req *neighborscircle) name() string { return "NEIGHBORSCIRCLE/v4" }
   367  
   368  func (req *sendConnect) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   369  	if expired(req.Expiration) {
   370  		return errExpired
   371  	}
   372  	t.send(from, rtnconnectPacket, &rtnConnect{
   373  		To:         makeEndpoint(from, req.From.TCP),
   374  		ReplyTok:   mac,
   375  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   376  	})
   377  
   378  	// add circle
   379  	// fmt.Println(" ***** sendConnect handle from:",from)
   380  	// fmt.Println(" ***** sendConnect handle fromID:",fromID)
   381  	// fmt.Println(" ***** sendConnect handle req.From:",req.From)
   382  	if !req.BStellarNode {
   383  		n := NewNode(fromID, from.IP, uint16(from.Port), req.From.TCP)
   384  		go t.setConnect(req.OwnID, req.RemoteID, req.BConnect, n) //
   385  		if !req.BConnect {
   386  			go t.setConnect(req.RemoteID, req.OwnID, req.BConnect, n) //
   387  		} else if req.BConnect {
   388  			// go t.setConnect(req.RemoteID,req.OwnID,req.BConnect,nil) //
   389  		}
   390  	} else {
   391  		t.stellarInspectDis(req.RemoteID)
   392  	}
   393  
   394  	return nil
   395  }
   396  
   397  func (req *sendConnect) name() string { return "sendConnect/v4" }
   398  
   399  func (req *rtnConnect) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   400  	if expired(req.Expiration) {
   401  		return errExpired
   402  	}
   403  	if !t.handleReply(fromID, rtnconnectPacket, req) {
   404  		return errUnsolicitedReply
   405  	}
   406  	return nil
   407  }
   408  
   409  func (req *rtnConnect) name() string { return "rtnConnect/v4" }
   410  
   411  func (req *reqPeerOrg) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   412  	//fmt.Println(" ****** reqPeerOrg handle ...... ")
   413  	if expired(req.Expiration) {
   414  		return errExpired
   415  	}
   416  
   417  	ownID, orgsId := t.callPeerOrgInfo()
   418  
   419  	p := rntPeerOrg{
   420  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   421  		Num:        uint64(len(orgsId)),
   422  		OwnID:      ownID,
   423  	}
   424  	// Send neighbors in chunks with at most maxNeighbors per packet
   425  	// to stay below the 1280 byte limit.
   426  	if len(orgsId) > 0 {
   427  		for i, n := range orgsId {
   428  			p.Orgs = append(p.Orgs, n)
   429  			if len(p.Orgs) == maxPeerOrg || i == len(orgsId)-1 {
   430  				t.send(from, rntPeerOrgPacket, &p)
   431  				p.Orgs = p.Orgs[:0]
   432  			}
   433  		}
   434  	} else if len(orgsId) <= 0 {
   435  		t.send(from, rntPeerOrgPacket, &p)
   436  	}
   437  	return nil
   438  }
   439  
   440  func (req *reqPeerOrg) name() string { return "reqPeerOrg/v4" }
   441  
   442  func (req *rntPeerOrg) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   443  	if expired(req.Expiration) {
   444  		return errExpired
   445  	}
   446  	// fmt.Println(" ******** rntPeerOrg handle len(req.Nodes):",len(req.))
   447  	err := t.handleReply(fromID, rntPeerOrgPacket, req)
   448  	if !err {
   449  		//fmt.Println(" ****** rntPeerOrg handle err:",err)
   450  		return errUnsolicitedReply
   451  	}
   452  	return nil
   453  }
   454  
   455  func (req *rntPeerOrg) name() string { return "rntPeerOrg/v4" }
   456  
   457  func (req *reqPeerConnect) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   458  	fmt.Println(" ****** reqPeerConnect handle ...... ")
   459  	if expired(req.Expiration) {
   460  		return errExpired
   461  	}
   462  	// targetData := new(rtnTabPeerConnect)
   463  	// var err error
   464  	ownID, remotesID := t.callPeerConnectInfo()
   465  
   466  	p := rntPeerConnect{
   467  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   468  		Num:        uint64(len(remotesID)),
   469  		OwnID:      ownID,
   470  	}
   471  	// Send neighbors in chunks with at most maxNeighbors per packet
   472  	// to stay below the 1280 byte limit.
   473  	if len(remotesID) > 0 {
   474  		for i, n := range remotesID {
   475  			p.RemoteID = append(p.RemoteID, n)
   476  			if len(p.RemoteID) == maxPeerOrg || i == len(remotesID)-1 {
   477  				t.send(from, rntPeerConnectPacket, &p)
   478  				p.RemoteID = p.RemoteID[:0]
   479  			}
   480  		}
   481  	} else if len(remotesID) <= 0 {
   482  		t.send(from, rntPeerConnectPacket, &p)
   483  	}
   484  	return nil
   485  }
   486  
   487  func (req *reqPeerConnect) name() string { return "reqPeerConnect/v4" }
   488  
   489  func (req *rntPeerConnect) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   490  	if expired(req.Expiration) {
   491  		return errExpired
   492  	}
   493  	// fmt.Println(" ******** rntPeerOrg handle len(req.Nodes):",len(req.))
   494  	err := t.handleReply(fromID, rntPeerConnectPacket, req)
   495  	if !err {
   496  		fmt.Println(" ****** rntPeerConnect handle err:", err)
   497  		return errUnsolicitedReply
   498  	}
   499  	return nil
   500  }
   501  
   502  func (req *rntPeerConnect) name() string { return "rntPeerConnect/v4" }
   503  
   504  // circu
   505  func (req *connectCircuOrg) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   506  	fmt.Println(" ****** connectCircuOrg handle ...... ")
   507  	if expired(req.Expiration) {
   508  		return errExpired
   509  	}
   510  
   511  	n := NewNode(fromID, from.IP, uint16(from.Port), req.From.TCP) // bootnode
   512  	destnode, err := t.nodeFromRPC(n.addr(), req.ConnectNode)      //dest node
   513  	if err == nil {
   514  		t.callSendConnectOrg(destnode, req.OrgID)
   515  	}
   516  
   517  	p := rtnCircuOrg{Expiration: uint64(time.Now().Add(expiration).Unix())}
   518  
   519  	t.send(from, rtnCircuOrgPacket, &p)
   520  	return nil
   521  }
   522  
   523  func (req *connectCircuOrg) name() string { return "connectCircuOrg/v4" }
   524  
   525  func (req *rtnCircuOrg) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   526  	if expired(req.Expiration) {
   527  		return errExpired
   528  	}
   529  	// fmt.Println(" ******** rntPeerOrg handle len(req.Nodes):",len(req.))
   530  	err := t.handleReply(fromID, rtnCircuOrgPacket, req)
   531  	if !err {
   532  		fmt.Println(" ****** rtnCircuOrg handle err:", err)
   533  		return errUnsolicitedReply
   534  	}
   535  	return nil
   536  }
   537  
   538  func (req *rtnCircuOrg) name() string { return "rtnCircuOrg/v4" }