github.com/annwntech/go-micro/v2@v2.9.5/tunnel/default.go (about) 1 package tunnel 2 3 import ( 4 "errors" 5 "math/rand" 6 "strings" 7 "sync" 8 "time" 9 10 "github.com/google/uuid" 11 "github.com/annwntech/go-micro/v2/logger" 12 "github.com/annwntech/go-micro/v2/transport" 13 ) 14 15 var ( 16 // DiscoverTime sets the time at which we fire discover messages 17 DiscoverTime = 30 * time.Second 18 // KeepAliveTime defines time interval we send keepalive messages to outbound links 19 KeepAliveTime = 30 * time.Second 20 // ReconnectTime defines time interval we periodically attempt to reconnect dead links 21 ReconnectTime = 5 * time.Second 22 ) 23 24 // tun represents a network tunnel 25 type tun struct { 26 options Options 27 28 sync.RWMutex 29 30 // the unique id for this tunnel 31 id string 32 33 // tunnel token for session encryption 34 token string 35 36 // to indicate if we're connected or not 37 connected bool 38 39 // the send channel for all messages 40 send chan *message 41 42 // close channel 43 closed chan bool 44 45 // a map of sessions based on Micro-Tunnel-Channel 46 sessions map[string]*session 47 48 // outbound links 49 links map[string]*link 50 51 // listener 52 listener transport.Listener 53 } 54 55 // create new tunnel on top of a link 56 func newTunnel(opts ...Option) *tun { 57 rand.Seed(time.Now().UnixNano()) 58 options := DefaultOptions() 59 for _, o := range opts { 60 o(&options) 61 } 62 63 return &tun{ 64 options: options, 65 id: options.Id, 66 token: options.Token, 67 send: make(chan *message, 128), 68 closed: make(chan bool), 69 sessions: make(map[string]*session), 70 links: make(map[string]*link), 71 } 72 } 73 74 // Init initializes tunnel options 75 func (t *tun) Init(opts ...Option) error { 76 t.Lock() 77 for _, o := range opts { 78 o(&t.options) 79 } 80 t.Unlock() 81 return nil 82 } 83 84 // getSession returns a session from the internal session map. 85 // It does this based on the Micro-Tunnel-Channel and Micro-Tunnel-Session 86 func (t *tun) getSession(channel, session string) (*session, bool) { 87 // get the session 88 t.RLock() 89 s, ok := t.sessions[channel+session] 90 t.RUnlock() 91 return s, ok 92 } 93 94 // delSession deletes a session if it exists 95 func (t *tun) delSession(channel, session string) { 96 t.Lock() 97 if s, ok := t.sessions[channel+session]; ok { 98 s.Close() 99 } 100 delete(t.sessions, channel+session) 101 t.Unlock() 102 } 103 104 // listChannels returns a list of listening channels 105 func (t *tun) listChannels() []string { 106 t.RLock() 107 108 //nolint:prealloc 109 var channels []string 110 for _, session := range t.sessions { 111 if session.session != "listener" { 112 continue 113 } 114 channels = append(channels, session.channel) 115 } 116 117 t.RUnlock() 118 119 return channels 120 } 121 122 // newSession creates a new session and saves it 123 func (t *tun) newSession(channel, sessionId string) (*session, bool, error) { 124 125 // new session 126 s := &session{ 127 tunnel: t.id, 128 channel: channel, 129 session: sessionId, 130 token: t.token, 131 closed: make(chan bool), 132 recv: make(chan *message, 128), 133 send: t.send, 134 errChan: make(chan error, 1), 135 key: []byte(t.token + channel + sessionId), 136 } 137 gcm, err := newCipher(s.key) 138 if err != nil { 139 return nil, false, err 140 } 141 s.gcm = gcm 142 143 // save session 144 t.Lock() 145 _, ok := t.sessions[channel+sessionId] 146 if ok { 147 // session already exists 148 t.Unlock() 149 return nil, false, nil 150 } 151 152 t.sessions[channel+sessionId] = s 153 t.Unlock() 154 155 // return session 156 return s, true, nil 157 } 158 159 // TODO: use tunnel id as part of the session 160 func (t *tun) newSessionId() string { 161 return uuid.New().String() 162 } 163 164 // announce will send a message to the link to tell the other side of a channel mapping we have. 165 // This usually happens if someone calls Dial and sends a discover message but otherwise we 166 // periodically send these messages to asynchronously manage channel mappings. 167 func (t *tun) announce(channel, session string, link *link) { 168 // create the "announce" response message for a discover request 169 msg := &transport.Message{ 170 Header: map[string]string{ 171 "Micro-Tunnel": "announce", 172 "Micro-Tunnel-Id": t.id, 173 "Micro-Tunnel-Channel": channel, 174 "Micro-Tunnel-Session": session, 175 "Micro-Tunnel-Link": link.id, 176 }, 177 } 178 179 // if no channel is present we've been asked to discover all channels 180 if len(channel) == 0 { 181 // get the list of channels 182 channels := t.listChannels() 183 184 // if there are no channels continue 185 if len(channels) == 0 { 186 return 187 } 188 189 // create a list of channels as comma separated list 190 channel = strings.Join(channels, ",") 191 // set channels as header 192 msg.Header["Micro-Tunnel-Channel"] = channel 193 } else { 194 // otherwise look for a single channel mapping 195 // looking for existing mapping as a listener 196 _, exists := t.getSession(channel, "listener") 197 if !exists { 198 return 199 } 200 } 201 202 if logger.V(logger.TraceLevel, log) { 203 log.Debugf("Tunnel sending announce for discovery of channel(s) %s", channel) 204 } 205 // send back the announcement 206 if err := link.Send(msg); err != nil { 207 if logger.V(logger.DebugLevel, log) { 208 log.Debugf("Tunnel failed to send announcement for channel(s) %s message: %v", channel, err) 209 } 210 } 211 } 212 213 // manage monitors outbound links and attempts to reconnect to the failed ones 214 func (t *tun) manage(reconnect time.Duration) { 215 r := time.NewTicker(reconnect) 216 defer r.Stop() 217 218 for { 219 select { 220 case <-t.closed: 221 return 222 case <-r.C: 223 t.manageLinks() 224 } 225 } 226 } 227 228 // manageLink sends channel discover requests periodically and 229 // keepalive messages to link 230 func (t *tun) manageLink(link *link) { 231 keepalive := time.NewTicker(KeepAliveTime) 232 defer keepalive.Stop() 233 discover := time.NewTicker(DiscoverTime) 234 defer discover.Stop() 235 236 wait := func(d time.Duration) { 237 // jitter 238 j := rand.Int63n(int64(d.Seconds() / 2.0)) 239 time.Sleep(time.Duration(j) * time.Second) 240 } 241 242 for { 243 select { 244 case <-t.closed: 245 return 246 case <-link.closed: 247 return 248 case <-discover.C: 249 // wait half the discover time 250 wait(DiscoverTime) 251 252 // send a discovery message to the link 253 if logger.V(logger.DebugLevel, log) { 254 log.Debugf("Tunnel sending discover to link: %v", link.Remote()) 255 } 256 if err := t.sendMsg("discover", link); err != nil { 257 if logger.V(logger.DebugLevel, log) { 258 log.Debugf("Tunnel failed to send discover to link %s: %v", link.Remote(), err) 259 } 260 } 261 case <-keepalive.C: 262 // wait half the keepalive time 263 wait(KeepAliveTime) 264 265 // send keepalive message 266 if logger.V(logger.DebugLevel, log) { 267 log.Debugf("Tunnel sending keepalive to link: %v", link.Remote()) 268 } 269 if err := t.sendMsg("keepalive", link); err != nil { 270 if logger.V(logger.DebugLevel, log) { 271 log.Debugf("Tunnel error sending keepalive to link %v: %v", link.Remote(), err) 272 } 273 t.delLink(link.Remote()) 274 return 275 } 276 } 277 } 278 } 279 280 // manageLinks is a function that can be called to immediately to link setup 281 // it purges dead links while generating new links for any nodes not connected 282 func (t *tun) manageLinks() { 283 delLinks := make(map[*link]string) 284 connected := make(map[string]bool) 285 286 t.RLock() 287 288 // get list of nodes from options 289 nodes := t.options.Nodes 290 291 // check the link status and purge dead links 292 for node, link := range t.links { 293 // check link status 294 switch link.State() { 295 case "closed", "error": 296 delLinks[link] = node 297 default: 298 connected[node] = true 299 } 300 } 301 302 t.RUnlock() 303 304 // build a list of links to connect to 305 var connect []string 306 307 for _, node := range nodes { 308 // check if we're connected 309 if _, ok := connected[node]; ok { 310 continue 311 } 312 // add nodes to connect o 313 connect = append(connect, node) 314 } 315 316 // delete the dead links 317 if len(delLinks) > 0 { 318 t.Lock() 319 320 for link, node := range delLinks { 321 if logger.V(logger.DebugLevel, log) { 322 log.Debugf("Tunnel deleting dead link for %s", node) 323 } 324 // check if the link exists 325 l, ok := t.links[node] 326 if ok { 327 // close and delete 328 l.Close() 329 delete(t.links, node) 330 } 331 332 // if the link does not match our own 333 if l != link { 334 // close our link just in case 335 link.Close() 336 } 337 } 338 339 t.Unlock() 340 } 341 342 var wg sync.WaitGroup 343 344 // establish new links 345 346 for _, node := range connect { 347 wg.Add(1) 348 349 go func(node string) { 350 defer wg.Done() 351 352 // create new link 353 // if we're using quic it should be a max 10 second handshake period 354 link, err := t.setupLink(node) 355 if err != nil { 356 if logger.V(logger.DebugLevel, log) { 357 log.Debugf("Tunnel failed to setup node link to %s: %v", node, err) 358 } 359 return 360 } 361 362 t.Lock() 363 364 // just check nothing else was setup in the interim 365 if _, ok := t.links[node]; ok { 366 link.Close() 367 t.Unlock() 368 return 369 } 370 371 // save the link 372 t.links[node] = link 373 374 t.Unlock() 375 }(node) 376 } 377 378 // wait for all threads to finish 379 wg.Wait() 380 } 381 382 // process outgoing messages sent by all local sessions 383 func (t *tun) process() { 384 // manage the send buffer 385 // all pseudo sessions throw everything down this 386 for { 387 select { 388 case msg := <-t.send: 389 // build a list of links to send to 390 var sendTo []*link 391 var err error 392 393 t.RLock() 394 395 // build the list of links ot send to 396 for _, link := range t.links { 397 // get the values we need 398 link.RLock() 399 id := link.id 400 connected := link.connected 401 loopback := link.loopback 402 _, exists := link.channels[msg.channel] 403 link.RUnlock() 404 405 // if the link is not connected skip it 406 if !connected { 407 if logger.V(logger.DebugLevel, log) { 408 log.Debugf("Link for node %s not connected", id) 409 } 410 err = ErrLinkDisconnected 411 continue 412 } 413 414 // if the link was a loopback accepted connection 415 // and the message is being sent outbound via 416 // a dialled connection don't use this link 417 if loopback && msg.outbound { 418 err = ErrLinkLoopback 419 continue 420 } 421 422 // if the message was being returned by the loopback listener 423 // send it back up the loopback link only 424 if msg.loopback && !loopback { 425 err = ErrLinkRemote 426 continue 427 } 428 429 // check the multicast mappings 430 if msg.mode == Multicast { 431 // channel mapping not found in link 432 if !exists { 433 continue 434 } 435 } else { 436 // if we're picking the link check the id 437 // this is where we explicitly set the link 438 // in a message received via the listen method 439 if len(msg.link) > 0 && id != msg.link { 440 err = ErrLinkNotFound 441 continue 442 } 443 } 444 445 // add to link list 446 sendTo = append(sendTo, link) 447 } 448 449 t.RUnlock() 450 451 // no links to send to 452 if len(sendTo) == 0 { 453 if logger.V(logger.DebugLevel, log) { 454 log.Debugf("No links to send message type: %s channel: %s", msg.typ, msg.channel) 455 } 456 t.respond(msg, err) 457 continue 458 } 459 460 // send the message 461 go t.sendTo(sendTo, msg) 462 case <-t.closed: 463 return 464 } 465 } 466 } 467 468 // send response back for a message to the caller 469 func (t *tun) respond(msg *message, err error) { 470 select { 471 case msg.errChan <- err: 472 default: 473 } 474 } 475 476 // sendTo sends a message to the chosen links 477 func (t *tun) sendTo(links []*link, msg *message) error { 478 // the function that sends the actual message 479 send := func(link *link, msg *transport.Message) error { 480 if err := link.Send(msg); err != nil { 481 if logger.V(logger.DebugLevel, log) { 482 log.Debugf("Tunnel error sending %+v to %s: %v", msg.Header, link.Remote(), err) 483 } 484 t.delLink(link.Remote()) 485 return err 486 } 487 return nil 488 } 489 490 newMsg := &transport.Message{ 491 Header: make(map[string]string), 492 } 493 494 // set the data 495 if msg.data != nil { 496 for k, v := range msg.data.Header { 497 newMsg.Header[k] = v 498 } 499 newMsg.Body = msg.data.Body 500 } 501 502 // set message head 503 newMsg.Header["Micro-Tunnel"] = msg.typ 504 // set the tunnel id on the outgoing message 505 newMsg.Header["Micro-Tunnel-Id"] = msg.tunnel 506 // set the tunnel channel on the outgoing message 507 newMsg.Header["Micro-Tunnel-Channel"] = msg.channel 508 // set the session id 509 newMsg.Header["Micro-Tunnel-Session"] = msg.session 510 511 // error channel for call 512 errChan := make(chan error, len(links)) 513 514 // execute in parallel 515 sendTo := func(l *link, m *transport.Message, errChan chan error) { 516 errChan <- send(l, m) 517 } 518 519 // send the message 520 for _, link := range links { 521 // send the message via the current link 522 if logger.V(logger.TraceLevel, log) { 523 log.Tracef("Tunnel sending %+v to %s", newMsg.Header, link.Remote()) 524 } 525 526 // blast it in a go routine since its multicast/broadcast 527 if msg.mode > Unicast { 528 // make a copy 529 m := &transport.Message{ 530 Header: make(map[string]string), 531 Body: make([]byte, len(newMsg.Body)), 532 } 533 copy(m.Body, newMsg.Body) 534 for k, v := range newMsg.Header { 535 m.Header[k] = v 536 } 537 538 go sendTo(link, m, errChan) 539 540 continue 541 } 542 543 // otherwise send as unicast 544 if err := send(link, newMsg); err != nil { 545 // put in the error chan if it failed 546 errChan <- err 547 continue 548 } 549 550 // sent successfully so just return 551 t.respond(msg, nil) 552 return nil 553 } 554 555 // either all unicast attempts failed or we're 556 // checking the multicast/broadcast attempts 557 558 var err error 559 560 // check all the errors 561 for i := 0; i < len(links); i++ { 562 err = <-errChan 563 // success 564 if err == nil { 565 break 566 } 567 } 568 569 // return error. it's non blocking 570 t.respond(msg, err) 571 return err 572 } 573 574 func (t *tun) delLink(remote string) { 575 t.Lock() 576 577 // get the link 578 for id, link := range t.links { 579 if link.id != remote { 580 continue 581 } 582 // close and delete 583 if logger.V(logger.DebugLevel, log) { 584 log.Debugf("Tunnel deleting link node: %s remote: %s", id, link.Remote()) 585 } 586 link.Close() 587 delete(t.links, id) 588 } 589 590 t.Unlock() 591 } 592 593 // process incoming messages 594 func (t *tun) listen(link *link) { 595 // remove the link on exit 596 defer func() { 597 t.delLink(link.Remote()) 598 }() 599 600 // let us know if its a loopback 601 var loopback bool 602 var connected bool 603 604 // set the connected value 605 link.RLock() 606 connected = link.connected 607 link.RUnlock() 608 609 for { 610 // process anything via the net interface 611 msg := new(transport.Message) 612 if err := link.Recv(msg); err != nil { 613 log.Debugf("Tunnel link %s receive error: %v", link.Remote(), err) 614 return 615 } 616 617 // TODO: figure out network authentication 618 // for now we use tunnel token to encrypt/decrypt 619 // session communication, but we will probably need 620 // some sort of network authentication (token) to avoid 621 // having rogue actors spamming the network 622 623 // message type 624 mtype := msg.Header["Micro-Tunnel"] 625 // the tunnel id 626 id := msg.Header["Micro-Tunnel-Id"] 627 // the tunnel channel 628 channel := msg.Header["Micro-Tunnel-Channel"] 629 // the session id 630 sessionId := msg.Header["Micro-Tunnel-Session"] 631 632 // if its not connected throw away the link 633 // the first message we process needs to be connect 634 if !connected && mtype != "connect" { 635 if logger.V(logger.DebugLevel, log) { 636 log.Debugf("Tunnel link %s not connected", link.id) 637 } 638 return 639 } 640 641 // this state machine block handles the only message types 642 // that we know or care about; connect, close, open, accept, 643 // discover, announce, session, keepalive 644 switch mtype { 645 case "connect": 646 if logger.V(logger.DebugLevel, log) { 647 log.Debugf("Tunnel link %s received connect message", link.Remote()) 648 } 649 650 link.Lock() 651 652 // check if we're connecting to ourselves? 653 if id == t.id { 654 link.loopback = true 655 loopback = true 656 } 657 658 // set to remote node 659 link.id = link.Remote() 660 // set as connected 661 link.connected = true 662 connected = true 663 664 link.Unlock() 665 666 // save the link once connected 667 t.Lock() 668 t.links[link.Remote()] = link 669 t.Unlock() 670 671 // send back an announcement of our channels discovery 672 go t.announce("", "", link) 673 // ask for the things on the other wise 674 go t.sendMsg("discover", link) 675 // nothing more to do 676 continue 677 case "close": 678 // if there is no channel then we close the link 679 // as its a signal from the other side to close the connection 680 if len(channel) == 0 { 681 if logger.V(logger.DebugLevel, log) { 682 log.Debugf("Tunnel link %s received close message", link.Remote()) 683 } 684 return 685 } 686 687 if logger.V(logger.DebugLevel, log) { 688 log.Debugf("Tunnel link %s received close message for %s", link.Remote(), channel) 689 } 690 // the entire listener was closed by the remote side so we need to 691 // remove the channel mapping for it. should we also close sessions? 692 if sessionId == "listener" { 693 link.delChannel(channel) 694 // TODO: find all the non listener unicast sessions 695 // and close them. think aboud edge cases first 696 continue 697 } 698 699 // assuming there's a channel and session 700 // try get the dialing socket 701 s, exists := t.getSession(channel, sessionId) 702 if exists && !loopback { 703 // only delete the session if its unicast 704 // otherwise ignore close on the multicast 705 if s.mode == Unicast { 706 // only delete this if its unicast 707 // but not if its a loopback conn 708 t.delSession(channel, sessionId) 709 continue 710 } 711 } 712 // otherwise its a session mapping of sorts 713 case "keepalive": 714 if logger.V(logger.DebugLevel, log) { 715 log.Debugf("Tunnel link %s received keepalive", link.Remote()) 716 } 717 // save the keepalive 718 link.keepalive() 719 continue 720 // a new connection dialled outbound 721 case "open": 722 if logger.V(logger.DebugLevel, log) { 723 log.Debugf("Tunnel link %s received open %s %s", link.id, channel, sessionId) 724 } 725 // we just let it pass through to be processed 726 // an accept returned by the listener 727 case "accept": 728 s, exists := t.getSession(channel, sessionId) 729 // just set accepted on anything not unicast 730 if exists && s.mode > Unicast { 731 s.accepted = true 732 continue 733 } 734 // if its already accepted move on 735 if exists && s.accepted { 736 continue 737 } 738 // otherwise we're going to process to accept 739 // a continued session 740 case "session": 741 // process message 742 if logger.V(logger.TraceLevel, log) { 743 log.Tracef("Tunnel received %+v from %s", msg.Header, link.Remote()) 744 } 745 // an announcement of a channel listener 746 case "announce": 747 if logger.V(logger.TraceLevel, log) { 748 log.Tracef("Tunnel received %+v from %s", msg.Header, link.Remote()) 749 } 750 // process the announcement 751 channels := strings.Split(channel, ",") 752 753 // update mapping in the link 754 link.setChannel(channels...) 755 756 // this was an announcement not intended for anything 757 // if the dialing side sent "discover" then a session 758 // id would be present. We skip in case of multicast. 759 switch sessionId { 760 case "listener", "multicast", "": 761 continue 762 } 763 764 // get the session that asked for the discovery 765 s, exists := t.getSession(channel, sessionId) 766 if exists { 767 // don't bother it's already discovered 768 if s.discovered { 769 continue 770 } 771 772 msg := &message{ 773 typ: "announce", 774 tunnel: id, 775 channel: channel, 776 session: sessionId, 777 link: link.id, 778 } 779 780 // send the announce back to the caller 781 select { 782 case <-s.closed: 783 case s.recv <- msg: 784 } 785 } 786 continue 787 case "discover": 788 // send back an announcement 789 go t.announce(channel, sessionId, link) 790 continue 791 default: 792 // blackhole it 793 continue 794 } 795 796 // strip tunnel message header 797 for k := range msg.Header { 798 if strings.HasPrefix(k, "Micro-Tunnel") { 799 delete(msg.Header, k) 800 } 801 } 802 803 // if the session id is blank there's nothing we can do 804 // TODO: check this is the case, is there any reason 805 // why we'd have a blank session? Is the tunnel 806 // used for some other purpose? 807 if len(channel) == 0 || len(sessionId) == 0 { 808 continue 809 } 810 811 var s *session 812 var exists bool 813 814 // If its a loopback connection then we've enabled link direction 815 // listening side is used for listening, the dialling side for dialling 816 switch { 817 case loopback, mtype == "open": 818 s, exists = t.getSession(channel, "listener") 819 // only return accept to the session 820 case mtype == "accept": 821 if logger.V(logger.DebugLevel, log) { 822 log.Debugf("Tunnel received accept message for channel: %s session: %s", channel, sessionId) 823 } 824 s, exists = t.getSession(channel, sessionId) 825 if exists && s.accepted { 826 continue 827 } 828 default: 829 // get the session based on the tunnel id and session 830 // this could be something we dialed in which case 831 // we have a session for it otherwise its a listener 832 s, exists = t.getSession(channel, sessionId) 833 if !exists { 834 // try get it based on just the tunnel id 835 // the assumption here is that a listener 836 // has no session but its set a listener session 837 s, exists = t.getSession(channel, "listener") 838 } 839 } 840 841 // bail if no session or listener has been found 842 if !exists { 843 if logger.V(logger.TraceLevel, log) { 844 log.Tracef("Tunnel skipping no channel: %s session: %s exists", channel, sessionId) 845 } 846 // drop it, we don't care about 847 // messages we don't know about 848 continue 849 } 850 851 // is the session closed? 852 select { 853 case <-s.closed: 854 // closed 855 delete(t.sessions, channel) 856 continue 857 default: 858 // otherwise process 859 } 860 if logger.V(logger.TraceLevel, log) { 861 log.Tracef("Tunnel using channel: %s session: %s type: %s", s.channel, s.session, mtype) 862 } 863 // construct a new transport message 864 tmsg := &transport.Message{ 865 Header: msg.Header, 866 Body: msg.Body, 867 } 868 869 // construct the internal message 870 imsg := &message{ 871 tunnel: id, 872 typ: mtype, 873 channel: channel, 874 session: sessionId, 875 mode: s.mode, 876 data: tmsg, 877 link: link.id, 878 loopback: loopback, 879 errChan: make(chan error, 1), 880 } 881 882 // append to recv backlog 883 // we don't block if we can't pass it on 884 select { 885 case s.recv <- imsg: 886 default: 887 } 888 } 889 } 890 891 func (t *tun) sendMsg(method string, link *link) error { 892 return link.Send(&transport.Message{ 893 Header: map[string]string{ 894 "Micro-Tunnel": method, 895 "Micro-Tunnel-Id": t.id, 896 }, 897 }) 898 } 899 900 // setupLink connects to node and returns link if successful 901 // It returns error if the link failed to be established 902 func (t *tun) setupLink(node string) (*link, error) { 903 if logger.V(logger.DebugLevel, log) { 904 log.Debugf("Tunnel setting up link: %s", node) 905 } 906 c, err := t.options.Transport.Dial(node) 907 if err != nil { 908 if logger.V(logger.DebugLevel, log) { 909 log.Debugf("Tunnel failed to connect to %s: %v", node, err) 910 } 911 return nil, err 912 } 913 if logger.V(logger.DebugLevel, log) { 914 log.Debugf("Tunnel connected to %s", node) 915 } 916 // create a new link 917 link := newLink(c) 918 919 // set link id to remote side 920 link.Lock() 921 link.id = c.Remote() 922 link.Unlock() 923 924 // send the first connect message 925 if err := t.sendMsg("connect", link); err != nil { 926 link.Close() 927 return nil, err 928 } 929 930 // we made the outbound connection 931 // and sent the connect message 932 link.connected = true 933 934 // process incoming messages 935 go t.listen(link) 936 937 // manage keepalives and discovery messages 938 go t.manageLink(link) 939 940 return link, nil 941 } 942 943 func (t *tun) setupLinks() { 944 var wg sync.WaitGroup 945 946 for _, node := range t.options.Nodes { 947 wg.Add(1) 948 949 go func(node string) { 950 defer wg.Done() 951 952 // we're not trying to fix existing links 953 if _, ok := t.links[node]; ok { 954 return 955 } 956 957 // create new link 958 link, err := t.setupLink(node) 959 if err != nil { 960 if logger.V(logger.DebugLevel, log) { 961 log.Debugf("Tunnel failed to setup node link to %s: %v", node, err) 962 } 963 return 964 } 965 966 // save the link 967 t.links[node] = link 968 }(node) 969 } 970 971 // wait for all threads to finish 972 wg.Wait() 973 } 974 975 // connect the tunnel to all the nodes and listen for incoming tunnel connections 976 func (t *tun) connect() error { 977 l, err := t.options.Transport.Listen(t.options.Address) 978 if err != nil { 979 return err 980 } 981 982 // save the listener 983 t.listener = l 984 985 go func() { 986 // accept inbound connections 987 err := l.Accept(func(sock transport.Socket) { 988 if logger.V(logger.DebugLevel, log) { 989 log.Debugf("Tunnel accepted connection from %s", sock.Remote()) 990 } 991 // create a new link 992 link := newLink(sock) 993 994 // manage the link 995 go t.manageLink(link) 996 997 // listen for inbound messages. 998 // only save the link once connected. 999 // we do this inside liste 1000 t.listen(link) 1001 }) 1002 1003 t.RLock() 1004 defer t.RUnlock() 1005 1006 // still connected but the tunnel died 1007 if err != nil && t.connected { 1008 log.Errorf("Tunnel listener died: %v", err) 1009 } 1010 }() 1011 1012 return nil 1013 } 1014 1015 // Connect the tunnel 1016 func (t *tun) Connect() error { 1017 t.Lock() 1018 defer t.Unlock() 1019 1020 // already connected 1021 if t.connected { 1022 // do it immediately 1023 t.setupLinks() 1024 // setup links 1025 return nil 1026 } 1027 1028 // connect the tunnel: start the listener 1029 if err := t.connect(); err != nil { 1030 return err 1031 } 1032 1033 // set as connected 1034 t.connected = true 1035 // create new close channel 1036 t.closed = make(chan bool) 1037 1038 // process outbound messages to be sent 1039 // process sends to all links 1040 go t.process() 1041 1042 // call setup before managing them 1043 t.setupLinks() 1044 1045 // manage the links 1046 go t.manage(ReconnectTime) 1047 1048 return nil 1049 } 1050 1051 func (t *tun) close() error { 1052 // close all the sessions 1053 for id, s := range t.sessions { 1054 s.Close() 1055 delete(t.sessions, id) 1056 } 1057 1058 // close all the links 1059 for node, link := range t.links { 1060 link.Send(&transport.Message{ 1061 Header: map[string]string{ 1062 "Micro-Tunnel": "close", 1063 "Micro-Tunnel-Id": t.id, 1064 }, 1065 }) 1066 link.Close() 1067 delete(t.links, node) 1068 } 1069 1070 // close the listener 1071 // this appears to be blocking 1072 return t.listener.Close() 1073 } 1074 1075 // pickLink will pick the best link based on connectivity, delay, rate and length 1076 func (t *tun) pickLink(links []*link) *link { 1077 var metric float64 1078 var chosen *link 1079 1080 // find the best link 1081 for i, link := range links { 1082 // don't use disconnected or errored links 1083 if link.State() != "connected" { 1084 continue 1085 } 1086 1087 // skip the loopback 1088 if link.Loopback() { 1089 continue 1090 } 1091 1092 // get the link state info 1093 d := float64(link.Delay()) 1094 l := float64(link.Length()) 1095 r := link.Rate() 1096 1097 // metric = delay x length x rate 1098 m := d * l * r 1099 1100 // first link so just and go 1101 if i == 0 { 1102 metric = m 1103 chosen = link 1104 continue 1105 } 1106 1107 // we found a better metric 1108 if m < metric { 1109 metric = m 1110 chosen = link 1111 } 1112 } 1113 1114 // if there's no link we're just going to mess around 1115 if chosen == nil { 1116 i := rand.Intn(len(links)) 1117 return links[i] 1118 } 1119 1120 // we chose the link with; 1121 // the lowest delay e.g least messages queued 1122 // the lowest rate e.g the least messages flowing 1123 // the lowest length e.g the smallest roundtrip time 1124 return chosen 1125 } 1126 1127 func (t *tun) Address() string { 1128 t.RLock() 1129 defer t.RUnlock() 1130 1131 if !t.connected { 1132 return t.options.Address 1133 } 1134 1135 return t.listener.Addr() 1136 } 1137 1138 // Close the tunnel 1139 func (t *tun) Close() error { 1140 t.Lock() 1141 defer t.Unlock() 1142 1143 if !t.connected { 1144 return nil 1145 } 1146 1147 if logger.V(logger.DebugLevel, log) { 1148 log.Debug("Tunnel closing") 1149 } 1150 1151 select { 1152 case <-t.closed: 1153 return nil 1154 default: 1155 close(t.closed) 1156 t.connected = false 1157 } 1158 1159 // send a close message 1160 // we don't close the link 1161 // just the tunnel 1162 return t.close() 1163 } 1164 1165 // Dial an address 1166 func (t *tun) Dial(channel string, opts ...DialOption) (Session, error) { 1167 // get the options 1168 options := DialOptions{ 1169 Timeout: DefaultDialTimeout, 1170 Wait: true, 1171 } 1172 1173 for _, o := range opts { 1174 o(&options) 1175 } 1176 1177 if logger.V(logger.DebugLevel, log) { 1178 log.Debugf("Tunnel dialing %s", channel) 1179 } 1180 1181 // create a new session 1182 c, ok, err := t.newSession(channel, t.newSessionId()) 1183 if err != nil { 1184 if logger.V(logger.DebugLevel, log) { 1185 log.Error(err) 1186 } 1187 return nil, err 1188 } else if !ok { 1189 return nil, errors.New("error dialing " + channel) 1190 } 1191 1192 // set remote 1193 c.remote = channel 1194 // set local 1195 c.local = "local" 1196 // outbound session 1197 c.outbound = true 1198 // set the mode of connection unicast/multicast/broadcast 1199 c.mode = options.Mode 1200 // set the dial timeout 1201 c.dialTimeout = options.Timeout 1202 // set read timeout set to never 1203 c.readTimeout = time.Duration(-1) 1204 // set the link 1205 c.link = options.Link 1206 1207 var links []*link 1208 // did we measure the rtt 1209 var measured bool 1210 1211 t.RLock() 1212 1213 // non multicast so we need to find the link 1214 for _, link := range t.links { 1215 // use the link specified it its available 1216 if len(c.link) > 0 && link.id != c.link { 1217 continue 1218 } 1219 1220 // get the channel 1221 lastMapped := link.getChannel(channel) 1222 1223 // we have at least one channel mapping 1224 if !lastMapped.IsZero() { 1225 links = append(links, link) 1226 c.discovered = true 1227 } 1228 } 1229 1230 t.RUnlock() 1231 1232 // link option was specified to pick the link 1233 if len(options.Link) > 0 { 1234 // link not found and one was specified so error out 1235 if len(links) == 0 { 1236 // delete session and return error 1237 t.delSession(c.channel, c.session) 1238 if logger.V(logger.DebugLevel, log) { 1239 log.Debugf("Tunnel deleting session %s %s: %v", c.session, c.channel, ErrLinkNotFound) 1240 } 1241 return nil, ErrLinkNotFound 1242 } 1243 1244 // assume discovered because we picked 1245 c.discovered = true 1246 1247 // link asked for and found and now 1248 // we've been asked not to wait so return 1249 if !options.Wait { 1250 c.accepted = true 1251 return c, nil 1252 } 1253 } 1254 1255 // discovered so set the link if not multicast 1256 if c.discovered && c.mode == Unicast { 1257 // pick a link if not specified 1258 if len(c.link) == 0 { 1259 // pickLink will pick the best link 1260 link := t.pickLink(links) 1261 // set the link 1262 c.link = link.id 1263 } 1264 } 1265 1266 // if its not already discovered we need to attempt to do so 1267 if !c.discovered { 1268 // piggy back roundtrip 1269 nowRTT := time.Now() 1270 1271 // attempt to discover the link 1272 err := c.Discover() 1273 if err != nil { 1274 t.delSession(c.channel, c.session) 1275 if logger.V(logger.DebugLevel, log) { 1276 log.Debugf("Tunnel deleting session %s %s: %v", c.session, c.channel, err) 1277 } 1278 return nil, err 1279 } 1280 1281 // set roundtrip 1282 d := time.Since(nowRTT) 1283 1284 // set the link time 1285 t.RLock() 1286 link, ok := t.links[c.link] 1287 t.RUnlock() 1288 1289 if ok { 1290 // set the rountrip time 1291 link.setRTT(d) 1292 // set measured to true 1293 measured = true 1294 } 1295 } 1296 1297 // return early if its not unicast 1298 // we will not wait for "open" for multicast 1299 // and we will not wait it told not to 1300 if c.mode != Unicast || !options.Wait { 1301 return c, nil 1302 } 1303 1304 // Note: we go no further for multicast or broadcast. 1305 // This is a unicast session so we call "open" and wait 1306 // for an "accept" 1307 1308 // reset now in case we use it 1309 now := time.Now() 1310 1311 // try to open the session 1312 if err := c.Open(); err != nil { 1313 // delete the session 1314 t.delSession(c.channel, c.session) 1315 if logger.V(logger.DebugLevel, log) { 1316 log.Debugf("Tunnel deleting session %s %s: %v", c.session, c.channel, err) 1317 } 1318 return nil, err 1319 } 1320 1321 // set time take to open 1322 d := time.Since(now) 1323 1324 // if we haven't measured the roundtrip do it now 1325 if !measured { 1326 // set the link time 1327 t.RLock() 1328 link, ok := t.links[c.link] 1329 t.RUnlock() 1330 1331 if ok { 1332 // set the rountrip time 1333 link.setRTT(d) 1334 } 1335 } 1336 1337 return c, nil 1338 } 1339 1340 // Accept a connection on the address 1341 func (t *tun) Listen(channel string, opts ...ListenOption) (Listener, error) { 1342 if logger.V(logger.DebugLevel, log) { 1343 log.Debugf("Tunnel listening on %s", channel) 1344 } 1345 options := ListenOptions{ 1346 // Read timeout defaults to never 1347 Timeout: time.Duration(-1), 1348 } 1349 1350 for _, o := range opts { 1351 o(&options) 1352 } 1353 1354 // create a new session by hashing the address 1355 c, ok, err := t.newSession(channel, "listener") 1356 if err != nil { 1357 if logger.V(logger.ErrorLevel, log) { 1358 log.Error(err) 1359 } 1360 return nil, err 1361 } else if !ok { 1362 return nil, errors.New("already listening on " + channel) 1363 } 1364 1365 // delete function removes the session when closed 1366 delFunc := func() { 1367 t.delSession(channel, "listener") 1368 } 1369 1370 // set remote. it will be replaced by the first message received 1371 c.remote = "remote" 1372 // set local 1373 c.local = channel 1374 // set mode 1375 c.mode = options.Mode 1376 // set the timeout 1377 c.readTimeout = options.Timeout 1378 1379 tl := &tunListener{ 1380 channel: channel, 1381 // tunnel token 1382 token: t.token, 1383 // the accept channel 1384 accept: make(chan *session, 128), 1385 // the channel to close 1386 closed: make(chan bool), 1387 // tunnel closed channel 1388 tunClosed: t.closed, 1389 // the listener session 1390 session: c, 1391 // delete session 1392 delFunc: delFunc, 1393 } 1394 1395 // this kicks off the internal message processor 1396 // for the listener so it can create pseudo sessions 1397 // per session if they do not exist or pass messages 1398 // to the existign sessions 1399 go tl.process() 1400 1401 // return the listener 1402 return tl, nil 1403 } 1404 1405 func (t *tun) Links() []Link { 1406 t.RLock() 1407 links := make([]Link, 0, len(t.links)) 1408 1409 for _, link := range t.links { 1410 links = append(links, link) 1411 } 1412 1413 t.RUnlock() 1414 1415 return links 1416 } 1417 1418 func (t *tun) String() string { 1419 return "mucp" 1420 }