github.com/annwntech/go-micro/v2@v2.9.5/tunnel/listener.go (about)

     1  package tunnel
     2  
     3  import (
     4  	"io"
     5  	"sync"
     6  
     7  	"github.com/annwntech/go-micro/v2/logger"
     8  )
     9  
    10  type tunListener struct {
    11  	// address of the listener
    12  	channel string
    13  	// token is the tunnel token
    14  	token string
    15  	// the accept channel
    16  	accept chan *session
    17  	// the tunnel closed channel
    18  	tunClosed chan bool
    19  	// the listener session
    20  	session *session
    21  	// del func to kill listener
    22  	delFunc func()
    23  
    24  	sync.RWMutex
    25  	// the channel to close
    26  	closed chan bool
    27  }
    28  
    29  func (t *tunListener) process() {
    30  	// our connection map for session
    31  	conns := make(map[string]*session)
    32  
    33  	defer func() {
    34  		// close the sessions
    35  		for id, conn := range conns {
    36  			conn.Close()
    37  			delete(conns, id)
    38  		}
    39  		// unassign
    40  		conns = nil
    41  	}()
    42  
    43  	for {
    44  		select {
    45  		case <-t.closed:
    46  			return
    47  		case <-t.tunClosed:
    48  			t.Close()
    49  			return
    50  		// receive a new message
    51  		case m := <-t.session.recv:
    52  			var sessionId string
    53  			var linkId string
    54  
    55  			switch t.session.mode {
    56  			case Multicast:
    57  				sessionId = "multicast"
    58  				linkId = "multicast"
    59  			case Broadcast:
    60  				sessionId = "broadcast"
    61  				linkId = "broadcast"
    62  			default:
    63  				sessionId = m.session
    64  				linkId = m.link
    65  			}
    66  
    67  			// get a session
    68  			sess, ok := conns[sessionId]
    69  			if logger.V(logger.TraceLevel, log) {
    70  				log.Tracef("Tunnel listener received channel %s session %s type %s exists: %t", m.channel, m.session, m.typ, ok)
    71  			}
    72  			if !ok {
    73  				// we only process open and session types
    74  				switch m.typ {
    75  				case "open", "session":
    76  				default:
    77  					continue
    78  				}
    79  
    80  				// create a new session session
    81  				sess = &session{
    82  					// the session key
    83  					key: []byte(t.token + m.channel + sessionId),
    84  					// the id of the remote side
    85  					tunnel: m.tunnel,
    86  					// the channel
    87  					channel: m.channel,
    88  					// the session id
    89  					session: sessionId,
    90  					// tunnel token
    91  					token: t.token,
    92  					// is loopback conn
    93  					loopback: m.loopback,
    94  					// the link the message was received on
    95  					link: linkId,
    96  					// set the connection mode
    97  					mode: t.session.mode,
    98  					// close chan
    99  					closed: make(chan bool),
   100  					// recv called by the acceptor
   101  					recv: make(chan *message, 128),
   102  					// use the internal send buffer
   103  					send: t.session.send,
   104  					// error channel
   105  					errChan: make(chan error, 1),
   106  					// set the read timeout
   107  					readTimeout: t.session.readTimeout,
   108  				}
   109  
   110  				// save the session
   111  				conns[sessionId] = sess
   112  
   113  				select {
   114  				case <-t.closed:
   115  					return
   116  				// send to accept chan
   117  				case t.accept <- sess:
   118  				}
   119  			}
   120  
   121  			// an existing session was found
   122  
   123  			switch m.typ {
   124  			case "close":
   125  				// don't close multicast sessions
   126  				if sess.mode > Unicast {
   127  					continue
   128  				}
   129  
   130  				// received a close message
   131  				select {
   132  				// check if the session is closed
   133  				case <-sess.closed:
   134  					// no op
   135  					delete(conns, sessionId)
   136  				default:
   137  					// only close if unicast session
   138  					// close and delete session
   139  					close(sess.closed)
   140  					delete(conns, sessionId)
   141  				}
   142  
   143  				// continue
   144  				continue
   145  			case "session":
   146  				// operate on this
   147  			default:
   148  				// non operational type
   149  				continue
   150  			}
   151  
   152  			// send this to the accept chan
   153  			select {
   154  			case <-sess.closed:
   155  				delete(conns, sessionId)
   156  			case sess.recv <- m:
   157  				if logger.V(logger.TraceLevel, log) {
   158  					log.Tracef("Tunnel listener sent to recv chan channel %s session %s type %s", m.channel, sessionId, m.typ)
   159  				}
   160  			}
   161  		}
   162  	}
   163  }
   164  
   165  func (t *tunListener) Channel() string {
   166  	return t.channel
   167  }
   168  
   169  // Close closes tunnel listener
   170  func (t *tunListener) Close() error {
   171  	t.Lock()
   172  	defer t.Unlock()
   173  
   174  	select {
   175  	case <-t.closed:
   176  		return nil
   177  	default:
   178  		// close and delete
   179  		t.delFunc()
   180  		t.session.Close()
   181  		close(t.closed)
   182  	}
   183  	return nil
   184  }
   185  
   186  // Everytime accept is called we essentially block till we get a new connection
   187  func (t *tunListener) Accept() (Session, error) {
   188  	select {
   189  	// if the session is closed return
   190  	case <-t.closed:
   191  		return nil, io.EOF
   192  	case <-t.tunClosed:
   193  		// close the listener when the tunnel closes
   194  		return nil, io.EOF
   195  	// wait for a new connection
   196  	case c, ok := <-t.accept:
   197  		// check if the accept chan is closed
   198  		if !ok {
   199  			return nil, io.EOF
   200  		}
   201  		// return without accept
   202  		if c.mode != Unicast {
   203  			return c, nil
   204  		}
   205  		// send back the accept
   206  		if err := c.Accept(); err != nil {
   207  			return nil, err
   208  		}
   209  		return c, nil
   210  	}
   211  }