github.com/micro/go-micro/v2@v2.9.1/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/micro/go-micro/v2/logger"
    12  	"github.com/micro/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  }