gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/tunnel/link.go (about)

     1  package tunnel
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io"
     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  type link struct {
    16  	transport.Socket
    17  
    18  	// transport to use for connections
    19  	transport transport.Transport
    20  
    21  	sync.RWMutex
    22  
    23  	// stops the link
    24  	closed chan bool
    25  	// link state channel for testing link
    26  	state chan *packet
    27  	// send queue for sending packets
    28  	sendQueue chan *packet
    29  	// receive queue for receiving packets
    30  	recvQueue chan *packet
    31  	// unique id of this link e.g uuid
    32  	// which we define for ourselves
    33  	id string
    34  	// whether its a loopback connection
    35  	// this flag is used by the transport listener
    36  	// which accepts inbound quic connections
    37  	loopback bool
    38  	// whether its actually connected
    39  	// dialled side sets it to connected
    40  	// after sending the message. the
    41  	// listener waits for the connect
    42  	connected bool
    43  	// the last time we received a keepalive
    44  	// on this link from the remote side
    45  	lastKeepAlive time.Time
    46  	// channels keeps a mapping of channels and last seen
    47  	channels map[string]time.Time
    48  	// the weighted moving average roundtrip
    49  	length int64
    50  	// weighted moving average of bits flowing
    51  	rate float64
    52  	// keep an error count on the link
    53  	errCount int
    54  }
    55  
    56  // packet send over link
    57  type packet struct {
    58  	// message to send or received
    59  	message *transport.Message
    60  
    61  	// status returned when sent
    62  	status chan error
    63  
    64  	// receive related error
    65  	err error
    66  }
    67  
    68  var (
    69  	// the 4 byte 0 packet sent to determine the link state
    70  	linkRequest = []byte{0, 0, 0, 0}
    71  	// the 4 byte 1 filled packet sent to determine link state
    72  	linkResponse = []byte{1, 1, 1, 1}
    73  
    74  	ErrLinkConnectTimeout = errors.New("link connect timeout")
    75  )
    76  
    77  func newLink(s transport.Socket) *link {
    78  	l := &link{
    79  		Socket:        s,
    80  		id:            uuid.New().String(),
    81  		lastKeepAlive: time.Now(),
    82  		closed:        make(chan bool),
    83  		channels:      make(map[string]time.Time),
    84  		state:         make(chan *packet, 64),
    85  		sendQueue:     make(chan *packet, 128),
    86  		recvQueue:     make(chan *packet, 128),
    87  	}
    88  
    89  	// process inbound/outbound packets
    90  	go l.process()
    91  	// manage the link state
    92  	go l.manage()
    93  
    94  	return l
    95  }
    96  
    97  func (l *link) connect(addr string) error {
    98  	c, err := l.transport.Dial(addr)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	l.Lock()
   104  	l.Socket = c
   105  	l.Unlock()
   106  
   107  	return nil
   108  }
   109  
   110  func (l *link) accept(sock transport.Socket) error {
   111  	l.Lock()
   112  	l.Socket = sock
   113  	l.Unlock()
   114  	return nil
   115  }
   116  
   117  func (l *link) setLoopback(v bool) {
   118  	l.Lock()
   119  	l.loopback = v
   120  	l.Unlock()
   121  }
   122  
   123  // setRate sets the bits per second rate as a float64
   124  func (l *link) setRate(bits int64, delta time.Duration) {
   125  	// rate of send in bits per nanosecond
   126  	rate := float64(bits) / float64(delta.Nanoseconds())
   127  
   128  	// default the rate if its zero
   129  	if l.rate == 0 {
   130  		// rate per second
   131  		l.rate = rate * 1e9
   132  	} else {
   133  		// set new rate per second
   134  		l.rate = 0.8*l.rate + 0.2*(rate*1e9)
   135  	}
   136  }
   137  
   138  // setRTT sets a nanosecond based moving average roundtrip time for the link
   139  func (l *link) setRTT(d time.Duration) {
   140  	l.Lock()
   141  	defer l.Unlock()
   142  
   143  	if l.length <= 0 {
   144  		l.length = d.Nanoseconds()
   145  		return
   146  	}
   147  
   148  	// https://fishi.devtail.io/weblog/2015/04/12/measuring-bandwidth-and-round-trip-time-tcp-connection-inside-application-layer/
   149  	length := 0.8*float64(l.length) + 0.2*float64(d.Nanoseconds())
   150  	// set new length
   151  	l.length = int64(length)
   152  }
   153  
   154  func (l *link) delChannel(ch string) {
   155  	l.Lock()
   156  	delete(l.channels, ch)
   157  	l.Unlock()
   158  }
   159  
   160  func (l *link) getChannel(ch string) time.Time {
   161  	l.RLock()
   162  	defer l.RUnlock()
   163  	return l.channels[ch]
   164  }
   165  
   166  func (l *link) setChannel(channels ...string) {
   167  	l.Lock()
   168  	for _, ch := range channels {
   169  		l.channels[ch] = time.Now()
   170  	}
   171  	l.Unlock()
   172  }
   173  
   174  // set the keepalive time
   175  func (l *link) keepalive() {
   176  	l.Lock()
   177  	l.lastKeepAlive = time.Now()
   178  	l.Unlock()
   179  }
   180  
   181  // process deals with the send queue
   182  func (l *link) process() {
   183  	// receive messages
   184  	go func() {
   185  		for {
   186  			m := new(transport.Message)
   187  			err := l.recv(m)
   188  			if err != nil {
   189  				l.Lock()
   190  				l.errCount++
   191  				l.Unlock()
   192  			}
   193  
   194  			// process new received message
   195  
   196  			pk := &packet{message: m, err: err}
   197  
   198  			// this is our link state packet
   199  			if m.Header["Micro-Method"] == "link" {
   200  				// process link state message
   201  				select {
   202  				case l.state <- pk:
   203  				case <-l.closed:
   204  					return
   205  				default:
   206  				}
   207  				continue
   208  			}
   209  
   210  			// process all messages as is
   211  
   212  			select {
   213  			case l.recvQueue <- pk:
   214  			case <-l.closed:
   215  				return
   216  			}
   217  		}
   218  	}()
   219  
   220  	// send messages
   221  
   222  	for {
   223  		select {
   224  		case pk := <-l.sendQueue:
   225  			// send the message
   226  			select {
   227  			case pk.status <- l.send(pk.message):
   228  			case <-l.closed:
   229  				return
   230  			}
   231  		case <-l.closed:
   232  			return
   233  		}
   234  	}
   235  }
   236  
   237  // manage manages the link state including rtt packets and channel mapping expiry
   238  func (l *link) manage() {
   239  	// tick over every minute to expire and fire rtt packets
   240  	t := time.NewTicker(time.Minute)
   241  	defer t.Stop()
   242  
   243  	// get link id
   244  	linkId := l.Id()
   245  
   246  	// used to send link state packets
   247  	send := func(b []byte) error {
   248  		return l.Send(&transport.Message{
   249  			Header: map[string]string{
   250  				"Micro-Method":  "link",
   251  				"Micro-Link-Id": linkId,
   252  			}, Body: b,
   253  		})
   254  	}
   255  
   256  	// set time now
   257  	now := time.Now()
   258  
   259  	// send the initial rtt request packet
   260  	send(linkRequest)
   261  
   262  	for {
   263  		select {
   264  		// exit if closed
   265  		case <-l.closed:
   266  			return
   267  		// process link state rtt packets
   268  		case p := <-l.state:
   269  			if p.err != nil {
   270  				continue
   271  			}
   272  			// check the type of message
   273  			switch {
   274  			case bytes.Equal(p.message.Body, linkRequest):
   275  				log.Tracef("Link %s received link request", linkId)
   276  
   277  				// send response
   278  				if err := send(linkResponse); err != nil {
   279  					l.Lock()
   280  					l.errCount++
   281  					l.Unlock()
   282  				}
   283  			case bytes.Equal(p.message.Body, linkResponse):
   284  				// set round trip time
   285  				d := time.Since(now)
   286  				log.Tracef("Link %s received link response in %v", linkId, d)
   287  				// set the RTT
   288  				l.setRTT(d)
   289  			}
   290  		case <-t.C:
   291  			// drop any channel mappings older than 2 minutes
   292  			var kill []string
   293  			killTime := time.Minute * 2
   294  
   295  			l.RLock()
   296  			for ch, t := range l.channels {
   297  				if d := time.Since(t); d > killTime {
   298  					kill = append(kill, ch)
   299  				}
   300  			}
   301  			l.RUnlock()
   302  
   303  			// if nothing to kill don't bother with a wasted lock
   304  			if len(kill) == 0 {
   305  				continue
   306  			}
   307  
   308  			// kill the channels!
   309  			l.Lock()
   310  			for _, ch := range kill {
   311  				delete(l.channels, ch)
   312  			}
   313  			l.Unlock()
   314  
   315  			// fire off a link state rtt packet
   316  			now = time.Now()
   317  			send(linkRequest)
   318  		}
   319  	}
   320  }
   321  
   322  func (l *link) send(m *transport.Message) error {
   323  	if m.Header == nil {
   324  		m.Header = make(map[string]string)
   325  	}
   326  	// send the message
   327  	return l.Socket.Send(m)
   328  }
   329  
   330  // recv a message on the link
   331  func (l *link) recv(m *transport.Message) error {
   332  	if m.Header == nil {
   333  		m.Header = make(map[string]string)
   334  	}
   335  	// receive the transport message
   336  	return l.Socket.Recv(m)
   337  }
   338  
   339  // Delay is the current load on the link
   340  func (l *link) Delay() int64 {
   341  	return int64(len(l.sendQueue) + len(l.recvQueue))
   342  }
   343  
   344  // Current transfer rate as bits per second (lower is better)
   345  func (l *link) Rate() float64 {
   346  	l.RLock()
   347  	defer l.RUnlock()
   348  	return l.rate
   349  }
   350  
   351  func (l *link) Loopback() bool {
   352  	l.RLock()
   353  	defer l.RUnlock()
   354  	return l.loopback
   355  }
   356  
   357  // Length returns the roundtrip time as nanoseconds (lower is better).
   358  // Returns 0 where no measurement has been taken.
   359  func (l *link) Length() int64 {
   360  	l.RLock()
   361  	defer l.RUnlock()
   362  	return l.length
   363  }
   364  
   365  func (l *link) Id() string {
   366  	l.RLock()
   367  	defer l.RUnlock()
   368  	return l.id
   369  }
   370  
   371  func (l *link) Close() error {
   372  	l.Lock()
   373  	defer l.Unlock()
   374  
   375  	select {
   376  	case <-l.closed:
   377  		return nil
   378  	default:
   379  		l.Socket.Close()
   380  		close(l.closed)
   381  	}
   382  
   383  	return nil
   384  }
   385  
   386  // Send sencs a message on the link
   387  func (l *link) Send(m *transport.Message) error {
   388  	// create a new packet to send over the link
   389  	p := &packet{
   390  		message: m,
   391  		status:  make(chan error, 1),
   392  	}
   393  
   394  	// get time now
   395  	now := time.Now()
   396  
   397  	// queue the message
   398  	select {
   399  	case l.sendQueue <- p:
   400  		// in the send queue
   401  	case <-l.closed:
   402  		return io.EOF
   403  	}
   404  
   405  	// error to use
   406  	var err error
   407  
   408  	// wait for response
   409  	select {
   410  	case <-l.closed:
   411  		return io.EOF
   412  	case err = <-p.status:
   413  	}
   414  
   415  	l.Lock()
   416  	defer l.Unlock()
   417  
   418  	// there's an error increment the counter and bail
   419  	if err != nil {
   420  		l.errCount++
   421  		return err
   422  	}
   423  
   424  	// reset the counter
   425  	l.errCount = 0
   426  
   427  	// calculate the data sent
   428  	dataSent := len(m.Body)
   429  
   430  	// set header length
   431  	for k, v := range m.Header {
   432  		dataSent += (len(k) + len(v))
   433  	}
   434  
   435  	// calculate based on data
   436  	if dataSent > 0 {
   437  		// bit sent
   438  		bits := dataSent * 1024
   439  
   440  		// set the rate
   441  		l.setRate(int64(bits), time.Since(now))
   442  	}
   443  
   444  	return nil
   445  }
   446  
   447  // Accept accepts a message on the socket
   448  func (l *link) Recv(m *transport.Message) error {
   449  	select {
   450  	case <-l.closed:
   451  		// check if there's any messages left
   452  		select {
   453  		case pk := <-l.recvQueue:
   454  			// check the packet receive error
   455  			if pk.err != nil {
   456  				return pk.err
   457  			}
   458  			*m = *pk.message
   459  		default:
   460  			return io.EOF
   461  		}
   462  	case pk := <-l.recvQueue:
   463  		// check the packet receive error
   464  		if pk.err != nil {
   465  			return pk.err
   466  		}
   467  		*m = *pk.message
   468  	}
   469  	return nil
   470  }
   471  
   472  // State can return connected, closed, error
   473  func (l *link) State() string {
   474  	select {
   475  	case <-l.closed:
   476  		return "closed"
   477  	default:
   478  		l.RLock()
   479  		defer l.RUnlock()
   480  		if l.errCount > 3 {
   481  			return "error"
   482  		}
   483  		return "connected"
   484  	}
   485  }