go.dedis.ch/onet/v4@v4.0.0-pre1/network/local.go (about) 1 package network 2 3 import ( 4 "sync" 5 "time" 6 7 "golang.org/x/xerrors" 8 ) 9 10 // NewLocalRouter returns a fresh router which uses only local queues. It uses 11 // the default local manager. 12 // If you need multiple independent local-queues, use NewLocalRouterWithManager. 13 // In case of an error it is returned together with a nil-Router. 14 func NewLocalRouter(sid *ServerIdentity, s Suite) (*Router, error) { 15 r, err := NewLocalRouterWithManager(defaultLocalManager, sid, s) 16 if err != nil { 17 return nil, xerrors.Errorf("local router: %v", err) 18 } 19 return r, nil 20 } 21 22 // NewLocalRouterWithManager is the same as NewLocalRouter but takes a specific 23 // LocalManager. This is useful to run parallel different local overlays. 24 // In case of an error it is returned together with a nil-Router. 25 func NewLocalRouterWithManager(lm *LocalManager, sid *ServerIdentity, s Suite) (*Router, error) { 26 h, err := NewLocalHostWithManager(lm, sid.Address, s) 27 if err != nil { 28 return nil, xerrors.Errorf("local router: %v", err) 29 } 30 r := NewRouter(sid, h) 31 r.UnauthOk = true 32 return r, nil 33 } 34 35 // LocalManager keeps a reference to all opened local connections. 36 // It also keeps track of who is "listening", so it's possible to mimic 37 // Conn & Listener. 38 type LocalManager struct { 39 // conns maps a remote endpoint to the remote connection. 40 conns map[endpoint]*LocalConn 41 sync.Mutex 42 // The listening-functions used when a new connection-request arrives. 43 listening map[Address]func(Conn) 44 45 // connection-counter for giving unique IDs to each connection. 46 counter uint64 47 // close on this channel indicates that connection retries should stop 48 stopping chan bool 49 stopped bool 50 // a waitgroup to check that all serving goroutines are done 51 wg sync.WaitGroup 52 } 53 54 // NewLocalManager returns a fresh new manager that can be used by LocalConn, 55 // LocalListener & LocalHost. 56 func NewLocalManager() *LocalManager { 57 return &LocalManager{ 58 conns: make(map[endpoint]*LocalConn), 59 listening: make(map[Address]func(Conn)), 60 stopping: make(chan bool), 61 } 62 } 63 64 // defaultLocalManager can be used if you need only one LocalManager. 65 var defaultLocalManager = NewLocalManager() 66 67 // endpoint represents one endpoint of a connection. 68 type endpoint struct { 69 // addr is the Address of this endpoint. 70 addr Address 71 // uid is a unique identifier of the remote endpoint 72 // it's unique for each direction: 73 // 127.0.0.1:2000 -> 127.0.0.1:7869 => 14 74 // 127.0.0.1:7869 <- 127.0.0.1:2000 => 15 75 uid uint64 76 } 77 78 // LocalReset resets the map of connections + listeners for the defaultLocalManager. 79 func LocalReset() { 80 defaultLocalManager = NewLocalManager() 81 82 } 83 84 // isListening returns true if the remote address is listening for connections. 85 func (lm *LocalManager) isListening(remote Address) bool { 86 lm.Lock() 87 defer lm.Unlock() 88 _, ok := lm.listening[remote] 89 return ok 90 } 91 92 // setListening marks the address as being able to accept incoming connections. 93 // For each incoming connection, fn will be called in a go routine. 94 func (lm *LocalManager) setListening(addr Address, fn func(Conn)) { 95 lm.Lock() 96 defer lm.Unlock() 97 lm.listening[addr] = fn 98 } 99 100 // unsetListening marks the address as *not* being able to accept incoming 101 // connections. 102 func (lm *LocalManager) unsetListening(addr Address) { 103 lm.Lock() 104 defer lm.Unlock() 105 delete(lm.listening, addr) 106 } 107 108 // connect checks if the remote address is listening. Then it creates 109 // the two connections, and launches the listening function in a go routine. 110 // It returns the outgoing connection, or nil followed by an error, if any. 111 func (lm *LocalManager) connect(local, remote Address, s Suite) (*LocalConn, error) { 112 lm.Lock() 113 defer lm.Unlock() 114 if lm.stopped { 115 return nil, xerrors.New("system is stopped") 116 } 117 118 fn, ok := lm.listening[remote] 119 if !ok { 120 return nil, xerrors.Errorf("%s can't connect to %s: it's not listening", local, remote) 121 } 122 123 outEndpoint := endpoint{local, lm.counter} 124 lm.counter++ 125 126 incEndpoint := endpoint{remote, lm.counter} 127 lm.counter++ 128 129 outgoing := newLocalConn(lm, outEndpoint, incEndpoint, s) 130 incoming := newLocalConn(lm, incEndpoint, outEndpoint, s) 131 132 // map the endpoint to the connection 133 lm.conns[outEndpoint] = outgoing 134 lm.conns[incEndpoint] = incoming 135 136 go fn(incoming) 137 return outgoing, nil 138 } 139 140 // send gets the connection denoted by this endpoint and calls queueMsg 141 // with the packet as argument to it. 142 // It returns ErrClosed if it does not find the connection. 143 func (lm *LocalManager) send(e endpoint, msg []byte) error { 144 lm.Lock() 145 defer lm.Unlock() 146 q, ok := lm.conns[e] 147 if !ok { 148 return xerrors.Errorf("closing: %w", ErrClosed) 149 } 150 151 q.incomingQueue <- msg 152 return nil 153 } 154 155 // close gets the connection denoted by this endpoint and closes it if 156 // it is present. 157 func (lm *LocalManager) close(conn *LocalConn) error { 158 lm.Lock() 159 defer lm.Unlock() 160 _, ok := lm.conns[conn.local] 161 if !ok { 162 // connection already closed 163 return xerrors.Errorf("closing: %w", ErrClosed) 164 } 165 // delete this conn 166 delete(lm.conns, conn.local) 167 conn.closeChannels() 168 // and delete the remote one + close it 169 remote, ok := lm.conns[conn.remote] 170 if !ok { 171 return nil 172 } 173 delete(lm.conns, conn.remote) 174 remote.closeChannels() 175 return nil 176 } 177 178 // len returns how many local connections are open. 179 func (lm *LocalManager) count() int { 180 lm.Lock() 181 defer lm.Unlock() 182 return len(lm.conns) 183 } 184 185 // Stop tells any connections that are sleeping on retry 186 // to stop sleeping and return an error. 187 func (lm *LocalManager) Stop() { 188 lm.Lock() 189 lm.stopped = true 190 close(lm.stopping) 191 lm.Unlock() 192 for _, v := range lm.conns { 193 lm.close(v) 194 } 195 196 lm.wg.Wait() 197 } 198 199 // LocalConn is a connection that sends and receives messages to other 200 // connections locally. 201 type LocalConn struct { 202 local endpoint 203 remote endpoint 204 205 // the channel where incoming messages are dispatched 206 incomingQueue chan []byte 207 // the channel where messages stored can be retrieved with Receive() 208 outgoingQueue chan []byte 209 // the channel used to communicate the stopping of the operations 210 closeCh chan bool 211 // the confirmation channel for the go routine 212 closeConfirm chan bool 213 214 // counter to keep track of how many bytes read / written this connection 215 // has seen. 216 counterSafe 217 // the localManager responsible for that connection. 218 manager *LocalManager 219 220 // the suite used to unmarshal 221 suite Suite 222 } 223 224 // newLocalConn initializes the fields of a LocalConn but doesn't 225 // connect. It should not be used from the outside, most user want 226 // to use NewLocalConn. 227 func newLocalConn(lm *LocalManager, local, remote endpoint, s Suite) *LocalConn { 228 lc := &LocalConn{ 229 remote: remote, 230 local: local, 231 manager: lm, 232 incomingQueue: make(chan []byte, LocalMaxBuffer), 233 outgoingQueue: make(chan []byte, LocalMaxBuffer), 234 closeCh: make(chan bool), 235 closeConfirm: make(chan bool), 236 suite: s, 237 } 238 lm.wg.Add(1) 239 go lc.start(&lm.wg) 240 return lc 241 } 242 243 // NewLocalConnWithManager is similar to NewLocalConn but takes a specific 244 // LocalManager. 245 func NewLocalConnWithManager(lm *LocalManager, local, remote Address, s Suite) (*LocalConn, error) { 246 for i := 0; i < MaxRetryConnect; i++ { 247 c, err := lm.connect(local, remote, s) 248 if err == nil { 249 return c, nil 250 } else if i == MaxRetryConnect-1 { 251 return nil, xerrors.Errorf("connect: %v", err) 252 } 253 time.Sleep(WaitRetry) 254 } 255 return nil, xerrors.New("Could not connect") 256 } 257 258 func (lc *LocalConn) start(wg *sync.WaitGroup) { 259 for { 260 select { 261 case buff := <-lc.incomingQueue: 262 lc.outgoingQueue <- buff 263 case <-lc.closeCh: 264 // to signal that the conn is closed 265 close(lc.outgoingQueue) 266 close(lc.incomingQueue) 267 lc.closeConfirm <- true 268 wg.Done() 269 return 270 } 271 } 272 } 273 274 // Send takes a context (that is not used in any way) and a message that 275 // will be sent to the remote endpoint. 276 // If there is an error in the connection, it will be returned. 277 func (lc *LocalConn) Send(msg Message) (uint64, error) { 278 buff, err := Marshal(msg) 279 if err != nil { 280 return 0, xerrors.Errorf("marshal: %v", err) 281 } 282 sentLen := uint64(len(buff)) 283 lc.updateTx(sentLen) 284 err = lc.manager.send(lc.remote, buff) 285 if err != nil { 286 return sentLen, xerrors.Errorf("sending: %w", err) 287 } 288 return sentLen, nil 289 } 290 291 // Receive takes a context (that is not used) and waits for a packet to 292 // be ready. It returns the received packet. 293 // In case of an error the packet is nil and the error is returned. 294 func (lc *LocalConn) Receive() (*Envelope, error) { 295 buff, opened := <-lc.outgoingQueue 296 if !opened { 297 return nil, xerrors.Errorf("closing: %w", ErrClosed) 298 } 299 lc.updateRx(uint64(len(buff))) 300 301 id, body, err := Unmarshal(buff, lc.suite) 302 if err != nil { 303 return nil, xerrors.Errorf("unmarshaling: %v", err) 304 } 305 306 return &Envelope{ 307 MsgType: id, 308 Msg: body, 309 Size: Size(len(buff)), 310 }, nil 311 } 312 313 // Local returns the local address. 314 func (lc *LocalConn) Local() Address { 315 return lc.local.addr 316 } 317 318 // Remote returns the remote address. 319 func (lc *LocalConn) Remote() Address { 320 return lc.remote.addr 321 } 322 323 // Close shuts down the connection on the local and the remote 324 // side. 325 // If the connection is not open, it returns an error. 326 func (lc *LocalConn) Close() error { 327 select { 328 case _, o := <-lc.closeCh: 329 if !o { 330 return xerrors.Errorf("closing: %w", ErrClosed) 331 } 332 default: 333 } 334 err := lc.manager.close(lc) 335 if err != nil { 336 return xerrors.Errorf("closing: %v", err) 337 } 338 return nil 339 } 340 341 func (lc *LocalConn) closeChannels() { 342 close(lc.closeCh) 343 <-lc.closeConfirm 344 close(lc.closeConfirm) 345 } 346 347 // Type implements the Conn interface 348 func (lc *LocalConn) Type() ConnType { 349 return Local 350 } 351 352 // connQueue manages the message queue of a LocalConn. 353 // Messages are pushed and retrieved in a FIFO-queue. 354 // All operations are thread-safe. 355 // The messages are marshalled and stored in the queue as a slice of bytes. 356 type connQueue struct { 357 wg sync.WaitGroup 358 } 359 360 // LocalMaxBuffer is the number of packets that can be sent simultaneously to the 361 // same address. 362 const LocalMaxBuffer = 200 363 364 // LocalListener implements Listener and uses LocalConn to communicate. It 365 // behaves as much as possible as a real golang net.Listener but using LocalConn 366 // as the underlying communication layer. 367 type LocalListener struct { 368 // addr is the addr we're listening to. 369 addr Address 370 // whether the listening started or not. 371 listening bool 372 // suite given to connections 373 suite Suite 374 375 sync.Mutex 376 377 // quit is used to stop the listening routine. 378 quit chan bool 379 380 // the LocalManager used. 381 manager *LocalManager 382 } 383 384 // NewLocalListener returns a fresh LocalListener using the defaultLocalManager. 385 // In case of an error the LocalListener is nil and the error is returned. 386 func NewLocalListener(addr Address, s Suite) (*LocalListener, error) { 387 listener, err := NewLocalListenerWithManager(defaultLocalManager, addr, s) 388 if err != nil { 389 return nil, xerrors.Errorf("local listener: %v", err) 390 } 391 return listener, nil 392 } 393 394 // NewLocalListenerWithManager returns a new LocalListener using the 395 // given LocalManager. 396 // In case of an error, the LocalListener is nil and the error is returned. 397 // An error occurs in case the address is invalid or the manager is already 398 // listening on that address. 399 func NewLocalListenerWithManager(lm *LocalManager, addr Address, s Suite) (*LocalListener, error) { 400 l := &LocalListener{ 401 quit: make(chan bool), 402 manager: lm, 403 suite: s, 404 } 405 if addr.ConnType() != Local { 406 return nil, xerrors.New("Wrong address type for local listener") 407 } 408 if l.manager.isListening(addr) { 409 return nil, xerrors.Errorf("%s is already listening: can't listen again", addr) 410 } 411 l.addr = addr 412 return l, nil 413 } 414 415 // Listen calls fn every time a connection-request is received. This call blocks until Stop() is 416 // called on the listener. 417 // It returns an error if the LocalListener is already listening. 418 func (ll *LocalListener) Listen(fn func(Conn)) error { 419 ll.Lock() 420 if ll.listening { 421 ll.Unlock() 422 return xerrors.Errorf("Already listening on %s", ll.addr) 423 } 424 ll.quit = make(chan bool) 425 ll.manager.setListening(ll.addr, fn) 426 ll.listening = true 427 ll.Unlock() 428 429 <-ll.quit 430 return nil 431 } 432 433 // Stop shuts down listening. 434 // It always returns nil whether ll is listening or not. 435 func (ll *LocalListener) Stop() error { 436 ll.Lock() 437 defer ll.Unlock() 438 if !ll.listening { 439 return nil 440 } 441 442 ll.manager.unsetListening(ll.addr) 443 close(ll.quit) 444 ll.listening = false 445 return nil 446 } 447 448 // Address returns the address used to listen. 449 func (ll *LocalListener) Address() Address { 450 ll.Lock() 451 defer ll.Unlock() 452 return ll.addr 453 } 454 455 // Listening returns true if this Listener is listening for incoming connections. 456 func (ll *LocalListener) Listening() bool { 457 ll.Lock() 458 defer ll.Unlock() 459 return ll.listening 460 } 461 462 // LocalHost implements the Host interface. It uses LocalConn and LocalListener as 463 // the underlying means of communication. 464 type LocalHost struct { 465 addr Address 466 suite Suite 467 *LocalListener 468 lm *LocalManager 469 } 470 471 // NewLocalHost returns a new Host using Local communication. It listens 472 // on the given addr. 473 // If an error happened during setup, it returns a nil LocalHost and the error. 474 func NewLocalHost(addr Address, s Suite) (*LocalHost, error) { 475 host, err := NewLocalHostWithManager(defaultLocalManager, addr, s) 476 if err != nil { 477 return nil, xerrors.Errorf("local host: %v", err) 478 } 479 return host, nil 480 } 481 482 // NewLocalHostWithManager is similar to NewLocalHost but takes a 483 // LocalManager used for communication. 484 // If an error happened during setup, it returns a nil LocalHost and the error. 485 func NewLocalHostWithManager(lm *LocalManager, addr Address, s Suite) (*LocalHost, error) { 486 lh := &LocalHost{ 487 addr: addr, 488 lm: lm, 489 suite: s, 490 } 491 var err error 492 lh.LocalListener, err = NewLocalListenerWithManager(lm, addr, s) 493 if err != nil { 494 return nil, xerrors.Errorf("local host: %v", err) 495 } 496 return lh, nil 497 498 } 499 500 // Connect sets up a connection to addr. It retries up to 501 // MaxRetryConnect while waiting between each try. 502 // In case of an error, it will return a nil Conn. 503 func (lh *LocalHost) Connect(si *ServerIdentity) (Conn, error) { 504 if si.Address.ConnType() != Local { 505 return nil, xerrors.New("Can't connect to non-Local address") 506 } 507 var finalErr error 508 for i := 0; i < MaxRetryConnect; i++ { 509 c, err := NewLocalConnWithManager(lh.lm, lh.addr, si.Address, lh.suite) 510 if err == nil { 511 return c, nil 512 } 513 finalErr = xerrors.Errorf("local connection: %v", err) 514 select { 515 case <-time.After(WaitRetry): 516 // sleep done, go try again 517 case <-lh.lm.stopping: 518 // stop sleeping and return immediately 519 return nil, finalErr 520 } 521 } 522 return nil, finalErr 523 524 } 525 526 // NewLocalAddress returns an Address of type Local with the given raw addr. 527 func NewLocalAddress(addr string) Address { 528 return NewAddress(Local, addr) 529 }