func (p *Router) getDirectSession(id utils.NodeID) *session { if id.Match(p.id) { return nil } p.sessionMutex.RLock() if s, ok := p.sessions[id]; ok { p.sessionMutex.RUnlock() return s } p.sessionMutex.RUnlock() var info *utils.NodeInfo p.dhtMutex.RLock() info = p.mainDht.GetNodeInfo(id) if info == nil { for _, d := range p.groupDht { info = d.GetNodeInfo(id) if info != nil { break } } } p.dhtMutex.RUnlock() if info == nil { return nil } addr, err := utp.ResolveAddr("utp", info.Addr.String()) if err != nil { p.logger.Error("%v", err) return nil } conn, err := utp.DialUTPTimeout("utp", nil, addr, 100*time.Millisecond) if err != nil { p.logger.Error("%v %v", addr, err) return nil } s, err := newSesion(conn, p.key) if err != nil { conn.Close() p.logger.Error("%v", err) return nil } else { go p.readSession(s) p.addSession(s) } return s }
func (p *Router) Join(group utils.NodeID) error { if p.getGroupDht(group) == nil { d := dht.NewDHT(10, p.ID(), group, p.listener.RawConn, p.logger) for _, n := range p.mainDht.LoadNodes(group.String()) { if !n.ID.Match(p.id) { d.Discover(n.Addr) } } p.dhtMutex.Lock() p.groupDht[group] = d p.dhtMutex.Unlock() p.mainDht.StoreNodes(group.String(), []utils.NodeInfo{ utils.NodeInfo{ID: p.id, Addr: p.listener.Addr()}, }) return nil } return errors.New("already joined") }
func (p *Router) getSessions(id utils.NodeID) []*session { var sessions []*session if bytes.Equal(id.NS[:], utils.GlobalNamespace[:]) { s := p.getDirectSession(id) if s != nil { sessions = append(sessions, s) } } else { if d, ok := p.groupDht[id]; ok { for _, n := range p.mainDht.LoadNodes(id.String()) { if !n.ID.Match(p.id) { d.Discover(n.Addr) } } for _, n := range d.FingerNodes() { s := p.getDirectSession(n.ID) if s != nil { sessions = append(sessions, s) } } } } return sessions }
func (p *DHT) FindNearestNode(findid utils.NodeID) []utils.NodeInfo { reqch := make(chan utils.NodeInfo, 100) endch := make(chan struct{}, 100) f := func(id utils.NodeID, command dhtRPCCommand) { defer func() { endch <- struct{}{} }() ret, err := p.sendAndWaitPacket(id, command) if err == nil { if _, ok := ret.command.Args["nodes"]; ok { var nodes []utils.NodeInfo ret.command.getArgs("nodes", &nodes) for _, n := range nodes { if n.ID.Digest.Cmp(p.id.Digest) != 0 { p.table.insert(n) reqch <- n } } } } } var res []utils.NodeInfo nodes := p.table.nearestNodes(findid) if len(nodes) == 0 { return res } for _, n := range nodes { reqch <- n } count := 0 requested := make(map[utils.NodeID]utils.NodeInfo) loop: for { select { case node := <-reqch: if _, ok := requested[node.ID]; !ok { requested[node.ID] = node c := p.newRPCCommand("find-node", map[string]interface{}{ "id": string(findid.Bytes()), }) go f(node.ID, c) count++ } case <-endch: count-- if count == 0 { break loop } } } for _, v := range requested { res = append(res, v) } sorter := utils.NodeInfoSorter{Nodes: res, ID: findid} sort.Sort(sorter) if len(sorter.Nodes) > p.k { return sorter.Nodes[:p.k] } return sorter.Nodes }