1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-11-04 17:27:23 -05:00
v2fly/transport/internet/quic/dialer.go

219 lines
4.5 KiB
Go
Raw Normal View History

2019-02-01 14:08:21 -05:00
// +build !confonly
2018-11-21 10:47:06 -05:00
package quic
import (
"context"
"sync"
2018-11-22 05:57:17 -05:00
"time"
2018-11-21 10:47:06 -05:00
"v2ray.com/core/common"
"v2ray.com/core/common/net"
2018-11-25 15:56:24 -05:00
"v2ray.com/core/common/task"
2019-01-17 09:33:18 -05:00
quic "v2ray.com/core/external/github.com/lucas-clemente/quic-go"
2018-11-21 10:47:06 -05:00
"v2ray.com/core/transport/internet"
2018-11-23 11:04:53 -05:00
"v2ray.com/core/transport/internet/tls"
2018-11-21 10:47:06 -05:00
)
2018-11-24 16:18:17 -05:00
type sessionContext struct {
2018-11-26 12:00:41 -05:00
rawConn *sysConn
session quic.Session
2018-11-25 15:56:24 -05:00
}
var errSessionClosed = newError("session closed")
func (c *sessionContext) openStream(destAddr net.Addr) (*interConn, error) {
2018-11-26 12:00:41 -05:00
if !isActive(c.session) {
2018-11-25 15:56:24 -05:00
return nil, errSessionClosed
}
stream, err := c.session.OpenStream()
if err != nil {
return nil, err
}
conn := &interConn{
2018-11-26 12:00:41 -05:00
stream: stream,
local: c.session.LocalAddr(),
remote: destAddr,
2018-11-25 15:56:24 -05:00
}
return conn, nil
}
2018-11-21 10:47:06 -05:00
type clientSessions struct {
access sync.Mutex
2018-11-24 16:18:17 -05:00
sessions map[net.Destination][]*sessionContext
2018-11-25 15:56:24 -05:00
cleanup *task.Periodic
2018-11-24 16:18:17 -05:00
}
func isActive(s quic.Session) bool {
select {
case <-s.Context().Done():
return false
default:
return true
}
2018-11-23 11:04:53 -05:00
}
2018-11-24 16:18:17 -05:00
func removeInactiveSessions(sessions []*sessionContext) []*sessionContext {
activeSessions := make([]*sessionContext, 0, len(sessions))
2018-11-23 11:04:53 -05:00
for _, s := range sessions {
2018-11-24 16:18:17 -05:00
if isActive(s.session) {
activeSessions = append(activeSessions, s)
2018-11-25 15:56:24 -05:00
continue
}
if err := s.session.Close(); err != nil {
2018-11-26 12:00:41 -05:00
newError("failed to close session").Base(err).WriteToLog()
2018-11-25 15:56:24 -05:00
}
if err := s.rawConn.Close(); err != nil {
2018-11-26 12:00:41 -05:00
newError("failed to close raw connection").Base(err).WriteToLog()
2018-11-23 11:04:53 -05:00
}
}
2018-11-24 16:18:17 -05:00
if len(activeSessions) < len(sessions) {
return activeSessions
2018-11-23 11:04:53 -05:00
}
return sessions
}
2018-11-25 15:56:24 -05:00
func openStream(sessions []*sessionContext, destAddr net.Addr) *interConn {
2018-11-23 11:04:53 -05:00
for _, s := range sessions {
2018-11-24 17:10:04 -05:00
if !isActive(s.session) {
continue
}
2018-11-25 15:56:24 -05:00
conn, err := s.openStream(destAddr)
2018-11-23 11:04:53 -05:00
if err != nil {
continue
}
2018-11-25 15:56:24 -05:00
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
}
2018-11-23 11:04:53 -05:00
}
2018-11-25 15:56:24 -05:00
s.sessions = newSessionMap
return nil
2018-11-21 10:47:06 -05:00
}
2018-11-23 11:04:53 -05:00
func (s *clientSessions) openConnection(destAddr net.Addr, config *Config, tlsConfig *tls.Config, sockopt *internet.SocketConfig) (internet.Connection, error) {
2018-11-21 10:47:06 -05:00
s.access.Lock()
defer s.access.Unlock()
if s.sessions == nil {
2018-11-24 16:18:17 -05:00
s.sessions = make(map[net.Destination][]*sessionContext)
2018-11-21 10:47:06 -05:00
}
dest := net.DestinationFromAddr(destAddr)
2018-11-24 16:18:17 -05:00
var sessions []*sessionContext
2018-11-23 11:04:53 -05:00
if s, found := s.sessions[dest]; found {
sessions = s
}
2018-11-25 15:56:24 -05:00
if true {
conn := openStream(sessions, destAddr)
if conn != nil {
return conn, nil
2018-11-24 17:10:04 -05:00
}
2018-11-21 10:47:06 -05:00
}
2018-11-24 17:10:04 -05:00
sessions = removeInactiveSessions(sessions)
2018-11-21 16:02:19 -05:00
rawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
2018-11-21 10:47:06 -05:00
IP: []byte{0, 0, 0, 0},
Port: 0,
}, sockopt)
if err != nil {
return nil, err
}
2018-11-21 16:02:19 -05:00
quicConfig := &quic.Config{
2018-11-28 17:14:41 -05:00
ConnectionIDLength: 12,
HandshakeTimeout: time.Second * 8,
IdleTimeout: time.Second * 30,
2018-11-21 10:47:06 -05:00
}
2018-11-21 16:02:19 -05:00
conn, err := wrapSysConn(rawConn, config)
2018-11-21 10:47:06 -05:00
if err != nil {
2018-11-21 16:02:19 -05:00
rawConn.Close()
return nil, err
}
session, err := quic.DialContext(context.Background(), conn, destAddr, "", tlsConfig.GetTLSConfig(tls.WithDestination(dest)), quicConfig)
if err != nil {
2018-11-24 16:18:17 -05:00
conn.Close()
2018-11-21 10:47:06 -05:00
return nil, err
}
2018-11-25 15:56:24 -05:00
context := &sessionContext{
2018-11-24 16:18:17 -05:00
session: session,
rawConn: conn,
2018-11-23 11:04:53 -05:00
}
2018-11-25 15:56:24 -05:00
s.sessions[dest] = append(sessions, context)
return context.openStream(destAddr)
2018-11-21 10:47:06 -05:00
}
var client clientSessions
2018-11-25 15:56:24 -05:00
func init() {
client.sessions = make(map[net.Destination][]*sessionContext)
client.cleanup = &task.Periodic{
Interval: time.Minute,
Execute: client.cleanSessions,
}
common.Must(client.cleanup.Start())
}
2018-11-21 10:47:06 -05:00
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
if tlsConfig == nil {
2018-11-21 16:02:19 -05:00
tlsConfig = &tls.Config{
ServerName: internalDomain,
AllowInsecure: true,
}
2018-11-21 10:47:06 -05:00
}
2018-11-25 15:56:24 -05:00
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
2018-11-21 10:47:06 -05:00
}
2018-11-21 16:02:19 -05:00
config := streamSettings.ProtocolSettings.(*Config)
2018-11-23 11:04:53 -05:00
return client.openConnection(destAddr, config, tlsConfig, streamSettings.SocketSettings)
2018-11-21 10:47:06 -05:00
}
func init() {
common.Must(internet.RegisterTransportDialer(protocolName, Dial))
}