| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 | 
							- package quic
 
- import (
 
- 	"context"
 
- 	"sync"
 
- 	"time"
 
- 	"github.com/xtls/xray-core/transport/internet/stat"
 
- 	"github.com/lucas-clemente/quic-go"
 
- 	"github.com/xtls/xray-core/common"
 
- 	"github.com/xtls/xray-core/common/net"
 
- 	"github.com/xtls/xray-core/common/task"
 
- 	"github.com/xtls/xray-core/transport/internet"
 
- 	"github.com/xtls/xray-core/transport/internet/tls"
 
- )
 
- type sessionContext struct {
 
- 	rawConn *sysConn
 
- 	session quic.Session
 
- }
 
- var errSessionClosed = newError("session closed")
 
- func (c *sessionContext) openStream(destAddr net.Addr) (*interConn, error) {
 
- 	if !isActive(c.session) {
 
- 		return nil, errSessionClosed
 
- 	}
 
- 	stream, err := c.session.OpenStream()
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	conn := &interConn{
 
- 		stream: stream,
 
- 		local:  c.session.LocalAddr(),
 
- 		remote: destAddr,
 
- 	}
 
- 	return conn, nil
 
- }
 
- type clientSessions struct {
 
- 	access   sync.Mutex
 
- 	sessions map[net.Destination][]*sessionContext
 
- 	cleanup  *task.Periodic
 
- }
 
- func isActive(s quic.Session) bool {
 
- 	select {
 
- 	case <-s.Context().Done():
 
- 		return false
 
- 	default:
 
- 		return true
 
- 	}
 
- }
 
- func removeInactiveSessions(sessions []*sessionContext) []*sessionContext {
 
- 	activeSessions := make([]*sessionContext, 0, len(sessions))
 
- 	for _, s := range sessions {
 
- 		if isActive(s.session) {
 
- 			activeSessions = append(activeSessions, s)
 
- 			continue
 
- 		}
 
- 		if err := s.session.CloseWithError(0, ""); err != nil {
 
- 			newError("failed to close session").Base(err).WriteToLog()
 
- 		}
 
- 		if err := s.rawConn.Close(); err != nil {
 
- 			newError("failed to close raw connection").Base(err).WriteToLog()
 
- 		}
 
- 	}
 
- 	if len(activeSessions) < len(sessions) {
 
- 		return activeSessions
 
- 	}
 
- 	return sessions
 
- }
 
- func openStream(sessions []*sessionContext, destAddr net.Addr) *interConn {
 
- 	for _, s := range sessions {
 
- 		if !isActive(s.session) {
 
- 			continue
 
- 		}
 
- 		conn, err := s.openStream(destAddr)
 
- 		if err != nil {
 
- 			continue
 
- 		}
 
- 		return conn
 
- 	}
 
- 	return nil
 
- }
 
- func (s *clientSessions) cleanSessions() error {
 
- 	s.access.Lock()
 
- 	defer s.access.Unlock()
 
- 	if len(s.sessions) == 0 {
 
- 		return nil
 
- 	}
 
- 	newSessionMap := make(map[net.Destination][]*sessionContext)
 
- 	for dest, sessions := range s.sessions {
 
- 		sessions = removeInactiveSessions(sessions)
 
- 		if len(sessions) > 0 {
 
- 			newSessionMap[dest] = sessions
 
- 		}
 
- 	}
 
- 	s.sessions = newSessionMap
 
- 	return nil
 
- }
 
- func (s *clientSessions) openConnection(destAddr net.Addr, config *Config, tlsConfig *tls.Config, sockopt *internet.SocketConfig) (stat.Connection, error) {
 
- 	s.access.Lock()
 
- 	defer s.access.Unlock()
 
- 	if s.sessions == nil {
 
- 		s.sessions = make(map[net.Destination][]*sessionContext)
 
- 	}
 
- 	dest := net.DestinationFromAddr(destAddr)
 
- 	var sessions []*sessionContext
 
- 	if s, found := s.sessions[dest]; found {
 
- 		sessions = s
 
- 	}
 
- 	if true {
 
- 		conn := openStream(sessions, destAddr)
 
- 		if conn != nil {
 
- 			return conn, nil
 
- 		}
 
- 	}
 
- 	sessions = removeInactiveSessions(sessions)
 
- 	rawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
 
- 		IP:   []byte{0, 0, 0, 0},
 
- 		Port: 0,
 
- 	}, sockopt)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	quicConfig := &quic.Config{
 
- 		ConnectionIDLength: 12,
 
- 		KeepAlive:          true,
 
- 	}
 
- 	conn, err := wrapSysConn(rawConn.(*net.UDPConn), config)
 
- 	if err != nil {
 
- 		rawConn.Close()
 
- 		return nil, err
 
- 	}
 
- 	session, err := quic.DialContext(context.Background(), conn, destAddr, "", tlsConfig.GetTLSConfig(tls.WithDestination(dest)), quicConfig)
 
- 	if err != nil {
 
- 		conn.Close()
 
- 		return nil, err
 
- 	}
 
- 	context := &sessionContext{
 
- 		session: session,
 
- 		rawConn: conn,
 
- 	}
 
- 	s.sessions[dest] = append(sessions, context)
 
- 	return context.openStream(destAddr)
 
- }
 
- var client clientSessions
 
- func init() {
 
- 	client.sessions = make(map[net.Destination][]*sessionContext)
 
- 	client.cleanup = &task.Periodic{
 
- 		Interval: time.Minute,
 
- 		Execute:  client.cleanSessions,
 
- 	}
 
- 	common.Must(client.cleanup.Start())
 
- }
 
- func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
 
- 	tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
 
- 	if tlsConfig == nil {
 
- 		tlsConfig = &tls.Config{
 
- 			ServerName:    internalDomain,
 
- 			AllowInsecure: true,
 
- 		}
 
- 	}
 
- 	var destAddr *net.UDPAddr
 
- 	if dest.Address.Family().IsIP() {
 
- 		destAddr = &net.UDPAddr{
 
- 			IP:   dest.Address.IP(),
 
- 			Port: int(dest.Port),
 
- 		}
 
- 	} else {
 
- 		addr, err := net.ResolveUDPAddr("udp", dest.NetAddr())
 
- 		if err != nil {
 
- 			return nil, err
 
- 		}
 
- 		destAddr = addr
 
- 	}
 
- 	config := streamSettings.ProtocolSettings.(*Config)
 
- 	return client.openConnection(destAddr, config, tlsConfig, streamSettings.SocketSettings)
 
- }
 
- func init() {
 
- 	common.Must(internet.RegisterTransportDialer(protocolName, Dial))
 
- }
 
 
  |