go.dedis.ch/onet/v4@v4.0.0-pre1/simul/manage/count.go (about) 1 package manage 2 3 import ( 4 "sync" 5 "time" 6 7 "go.dedis.ch/onet/v4" 8 "go.dedis.ch/onet/v4/log" 9 "go.dedis.ch/onet/v4/network" 10 "golang.org/x/xerrors" 11 ) 12 13 /* 14 The count-protocol returns the number of nodes reachable in a given 15 timeout. To correctly wait for the whole tree, every node that receives 16 a message sends a message to the root before contacting its children. 17 As long as the root receives those messages, he knows the counting 18 still goes on. 19 */ 20 21 func init() { 22 network.RegisterMessage(PrepareCount{}) 23 network.RegisterMessage(Count{}) 24 network.RegisterMessage(NodeIsUp{}) 25 onet.GlobalProtocolRegister("Count", NewCount) 26 } 27 28 // ProtocolCount holds all channels. If a timeout occurs or the counting 29 // is done, the Count-channel receives the number of nodes reachable in 30 // the tree. 31 type ProtocolCount struct { 32 *onet.TreeNodeInstance 33 Replies int 34 Count chan int 35 Quit chan bool 36 timeout time.Duration 37 timeoutMu sync.Mutex 38 PrepareCountChan chan struct { 39 *onet.TreeNode 40 PrepareCount 41 } 42 CountChan chan []CountMsg 43 NodeIsUpChan chan struct { 44 *onet.TreeNode 45 NodeIsUp 46 } 47 } 48 49 // PrepareCount is sent so that every node can contact the root to say 50 // the counting is still going on. 51 type PrepareCount struct { 52 Timeout time.Duration 53 } 54 55 // NodeIsUp - if it is received by the root it will reset the counter. 56 type NodeIsUp struct{} 57 58 // Count sends the number of children to the parent node. 59 type Count struct { 60 Children int32 61 } 62 63 // CountMsg is wrapper around the Count-structure 64 type CountMsg struct { 65 *onet.TreeNode 66 Count 67 } 68 69 // NewCount returns a new protocolInstance 70 func NewCount(n *onet.TreeNodeInstance) (onet.ProtocolInstance, error) { 71 p := &ProtocolCount{ 72 TreeNodeInstance: n, 73 Quit: make(chan bool), 74 timeout: 1 * time.Second, 75 } 76 p.Count = make(chan int, 1) 77 t := n.Tree() 78 if t == nil { 79 return nil, xerrors.New("cannot find tree") 80 } 81 if err := p.RegisterChannelsLength(len(t.List()), 82 &p.CountChan, &p.PrepareCountChan, &p.NodeIsUpChan); err != nil { 83 log.Error("Couldn't reister channel:", err) 84 } 85 return p, nil 86 } 87 88 // Start the protocol 89 func (p *ProtocolCount) Start() error { 90 // Send an empty message 91 log.Lvl3("Starting to count") 92 p.FuncPC() 93 return nil 94 } 95 96 // Dispatch listens for all channels and waits for a timeout in case nothing 97 // happens for a certain duration 98 func (p *ProtocolCount) Dispatch() error { 99 running := true 100 for running { 101 log.Lvl3(p.Info(), "waiting for message for", p.Timeout()) 102 select { 103 case pc := <-p.PrepareCountChan: 104 log.Lvl3(p.Info(), "received from", pc.TreeNode.ServerIdentity.Address, 105 "timeout", pc.Timeout) 106 p.SetTimeout(pc.Timeout) 107 p.FuncPC() 108 case c := <-p.CountChan: 109 p.FuncC(c) 110 running = false 111 case _ = <-p.NodeIsUpChan: 112 if p.Parent() != nil { 113 err := p.SendTo(p.Parent(), &NodeIsUp{}) 114 if err != nil { 115 log.Lvl2(p.Info(), "couldn't send to parent", 116 p.Parent().Name(), err) 117 } 118 } else { 119 p.Replies++ 120 } 121 case <-time.After(time.Duration(p.Timeout())): 122 log.Lvl3(p.Info(), "timed out while waiting for", p.Timeout()) 123 if p.IsRoot() { 124 log.Lvl2("Didn't get all children in time:", p.Replies) 125 p.Count <- p.Replies 126 running = false 127 } 128 } 129 } 130 p.Done() 131 return nil 132 } 133 134 // FuncPC handles PrepareCount messages. These messages go down the tree and 135 // every node that receives one will reply with a 'NodeIsUp'-message 136 func (p *ProtocolCount) FuncPC() { 137 if !p.IsRoot() { 138 err := p.SendTo(p.Parent(), &NodeIsUp{}) 139 if err != nil { 140 log.Lvl2(p.Info(), "couldn't send to parent", 141 p.Parent().Name(), err) 142 } 143 } 144 if !p.IsLeaf() { 145 for _, child := range p.Children() { 146 go func(c *onet.TreeNode) { 147 log.Lvl3(p.Info(), "sending to", c.ServerIdentity.Address, c.ID, "timeout", p.timeout) 148 err := p.SendTo(c, &PrepareCount{Timeout: p.timeout}) 149 if err != nil { 150 log.Lvl2(p.Info(), "couldn't send to child", 151 c.Name()) 152 } 153 }(child) 154 } 155 } else { 156 p.CountChan <- nil 157 } 158 } 159 160 // FuncC creates a Count-message that will be received by all parents and 161 // count the total number of children 162 func (p *ProtocolCount) FuncC(cc []CountMsg) { 163 count := 1 164 for _, c := range cc { 165 count += int(c.Count.Children) 166 } 167 if !p.IsRoot() { 168 log.Lvl3(p.Info(), "Sends to", p.Parent().ID, p.Parent().ServerIdentity.Address) 169 if err := p.SendTo(p.Parent(), &Count{int32(count)}); err != nil { 170 log.Lvl2(p.Name(), "coouldn't send to parent", 171 p.Parent().Name()) 172 } 173 } else { 174 p.Count <- count 175 } 176 log.Lvl3(p.ServerIdentity().Address, "Done") 177 } 178 179 // SetTimeout sets the new timeout 180 func (p *ProtocolCount) SetTimeout(t time.Duration) { 181 p.timeoutMu.Lock() 182 p.timeout = t 183 p.timeoutMu.Unlock() 184 } 185 186 // Timeout returns the current timeout 187 func (p *ProtocolCount) Timeout() time.Duration { 188 p.timeoutMu.Lock() 189 defer p.timeoutMu.Unlock() 190 return p.timeout 191 }