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  }