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