v2ray-core/transport/internet/quic/dialer.go

154 lines
3.4 KiB
Go
Raw Normal View History

2018-11-21 15:47:06 +00:00
package quic
import (
"context"
"sync"
2018-11-22 10:57:17 +00:00
"time"
2018-11-21 15:47:06 +00:00
quic "github.com/lucas-clemente/quic-go"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
2018-11-23 16:04:53 +00:00
"v2ray.com/core/transport/internet/tls"
2018-11-21 15:47:06 +00:00
)
type clientSessions struct {
access sync.Mutex
2018-11-23 16:04:53 +00:00
sessions map[net.Destination][]quic.Session
}
func removeInactiveSessions(sessions []quic.Session) []quic.Session {
lastActive := 0
for _, s := range sessions {
active := true
select {
case <-s.Context().Done():
active = false
default:
}
if active {
sessions[lastActive] = s
lastActive++
}
}
if lastActive < len(sessions) {
2018-11-23 19:47:36 +00:00
for i := lastActive; i < len(sessions); i++ {
2018-11-23 16:04:53 +00:00
sessions[i] = nil
}
sessions = sessions[:lastActive]
}
return sessions
}
func openStream(sessions []quic.Session) (quic.Stream, net.Addr, error) {
for _, s := range sessions {
stream, err := s.OpenStream()
if err != nil {
newError("failed to create stream").Base(err).WriteToLog()
continue
}
return stream, s.LocalAddr(), nil
}
return nil, nil, nil
2018-11-21 15:47:06 +00:00
}
2018-11-23 16:04:53 +00:00
func (s *clientSessions) openConnection(destAddr net.Addr, config *Config, tlsConfig *tls.Config, sockopt *internet.SocketConfig) (internet.Connection, error) {
2018-11-21 15:47:06 +00:00
s.access.Lock()
defer s.access.Unlock()
if s.sessions == nil {
2018-11-23 16:04:53 +00:00
s.sessions = make(map[net.Destination][]quic.Session)
2018-11-21 15:47:06 +00:00
}
dest := net.DestinationFromAddr(destAddr)
2018-11-23 16:04:53 +00:00
var sessions []quic.Session
if s, found := s.sessions[dest]; found {
sessions = s
}
sessions = removeInactiveSessions(sessions)
s.sessions[dest] = sessions
stream, local, err := openStream(sessions)
if err != nil {
return nil, err
}
if stream != nil {
return &interConn{
stream: stream,
local: local,
remote: destAddr,
}, nil
2018-11-21 15:47:06 +00:00
}
2018-11-21 21:02:19 +00:00
rawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
2018-11-21 15:47:06 +00:00
IP: []byte{0, 0, 0, 0},
Port: 0,
}, sockopt)
if err != nil {
return nil, err
}
2018-11-21 21:02:19 +00:00
quicConfig := &quic.Config{
2018-11-22 10:57:17 +00:00
ConnectionIDLength: 12,
HandshakeTimeout: time.Second * 4,
2018-11-23 16:04:53 +00:00
IdleTimeout: time.Second * 60,
2018-11-23 22:51:07 +00:00
MaxReceiveStreamFlowControlWindow: 512 * 1024,
2018-11-23 16:04:53 +00:00
MaxReceiveConnectionFlowControlWindow: 2 * 1024 * 1024,
2018-11-22 10:57:17 +00:00
MaxIncomingUniStreams: -1,
2018-11-21 15:47:06 +00:00
}
2018-11-21 21:02:19 +00:00
conn, err := wrapSysConn(rawConn, config)
2018-11-21 15:47:06 +00:00
if err != nil {
2018-11-21 21:02:19 +00:00
rawConn.Close()
return nil, err
}
session, err := quic.DialContext(context.Background(), conn, destAddr, "", tlsConfig.GetTLSConfig(tls.WithDestination(dest)), quicConfig)
if err != nil {
rawConn.Close()
2018-11-21 15:47:06 +00:00
return nil, err
}
2018-11-23 16:04:53 +00:00
s.sessions[dest] = append(sessions, session)
stream, err = session.OpenStream()
if err != nil {
return nil, err
}
return &interConn{
stream: stream,
local: session.LocalAddr(),
remote: destAddr,
}, nil
2018-11-21 15:47:06 +00:00
}
var client clientSessions
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
if tlsConfig == nil {
2018-11-21 21:02:19 +00:00
tlsConfig = &tls.Config{
ServerName: internalDomain,
AllowInsecure: true,
}
2018-11-21 15:47:06 +00:00
}
destAddr, err := net.ResolveUDPAddr("udp", dest.NetAddr())
if err != nil {
return nil, err
}
2018-11-21 21:02:19 +00:00
config := streamSettings.ProtocolSettings.(*Config)
2018-11-23 16:04:53 +00:00
return client.openConnection(destAddr, config, tlsConfig, streamSettings.SocketSettings)
2018-11-21 15:47:06 +00:00
}
func init() {
common.Must(internet.RegisterTransportDialer(protocolName, Dial))
}