Skip to content

Commit 096bbd2

Browse files
committed
prototype of quic transport
1 parent 3eac22c commit 096bbd2

File tree

10 files changed

+551
-0
lines changed

10 files changed

+551
-0
lines changed

common/net/system.go

+1
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@ type TCPListener = net.TCPListener
5656
type UnixListener = net.UnixListener
5757

5858
var ResolveUnixAddr = net.ResolveUnixAddr
59+
var ResolveUDPAddr = net.ResolveUDPAddr
5960

6061
type Resolver = net.Resolver

transport/internet/quic/config.pb.go

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package quic
2+
3+
import (
4+
fmt "fmt"
5+
proto "github.com/golang/protobuf/proto"
6+
math "math"
7+
serial "v2ray.com/core/common/serial"
8+
)
9+
10+
// Reference imports to suppress errors if they are not otherwise used.
11+
var _ = proto.Marshal
12+
var _ = fmt.Errorf
13+
var _ = math.Inf
14+
15+
// This is a compile-time assertion to ensure that this generated file
16+
// is compatible with the proto package it is being compiled against.
17+
// A compilation error at this line likely means your copy of the
18+
// proto package needs to be updated.
19+
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
20+
21+
type Config struct {
22+
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
23+
Header *serial.TypedMessage `protobuf:"bytes,2,opt,name=header,proto3" json:"header,omitempty"`
24+
XXX_NoUnkeyedLiteral struct{} `json:"-"`
25+
XXX_unrecognized []byte `json:"-"`
26+
XXX_sizecache int32 `json:"-"`
27+
}
28+
29+
func (m *Config) Reset() { *m = Config{} }
30+
func (m *Config) String() string { return proto.CompactTextString(m) }
31+
func (*Config) ProtoMessage() {}
32+
func (*Config) Descriptor() ([]byte, []int) {
33+
return fileDescriptor_462e2eb906061b36, []int{0}
34+
}
35+
36+
func (m *Config) XXX_Unmarshal(b []byte) error {
37+
return xxx_messageInfo_Config.Unmarshal(m, b)
38+
}
39+
func (m *Config) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
40+
return xxx_messageInfo_Config.Marshal(b, m, deterministic)
41+
}
42+
func (m *Config) XXX_Merge(src proto.Message) {
43+
xxx_messageInfo_Config.Merge(m, src)
44+
}
45+
func (m *Config) XXX_Size() int {
46+
return xxx_messageInfo_Config.Size(m)
47+
}
48+
func (m *Config) XXX_DiscardUnknown() {
49+
xxx_messageInfo_Config.DiscardUnknown(m)
50+
}
51+
52+
var xxx_messageInfo_Config proto.InternalMessageInfo
53+
54+
func (m *Config) GetKey() string {
55+
if m != nil {
56+
return m.Key
57+
}
58+
return ""
59+
}
60+
61+
func (m *Config) GetHeader() *serial.TypedMessage {
62+
if m != nil {
63+
return m.Header
64+
}
65+
return nil
66+
}
67+
68+
func init() {
69+
proto.RegisterType((*Config)(nil), "v2ray.core.transport.internet.quic.Config")
70+
}
71+
72+
func init() {
73+
proto.RegisterFile("v2ray.com/core/transport/internet/quic/config.proto", fileDescriptor_462e2eb906061b36)
74+
}
75+
76+
var fileDescriptor_462e2eb906061b36 = []byte{
77+
// 226 bytes of a gzipped FileDescriptorProto
78+
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8e, 0xb1, 0x4b, 0x03, 0x31,
79+
0x14, 0x87, 0x49, 0x95, 0x03, 0xe3, 0x22, 0x37, 0x15, 0xa7, 0x72, 0x43, 0xe9, 0xf4, 0x22, 0xd7,
80+
0xdd, 0xc1, 0x4e, 0x0e, 0x82, 0x1e, 0xd5, 0xa1, 0x8b, 0xc4, 0xf4, 0x59, 0x83, 0x26, 0xef, 0x7c,
81+
0x49, 0x85, 0xfc, 0x4b, 0xfe, 0x95, 0x92, 0xc6, 0x3b, 0xc4, 0xa5, 0x53, 0x32, 0xfc, 0xbe, 0xef,
82+
0x7d, 0x72, 0xf9, 0xd5, 0xb2, 0x4e, 0x60, 0xc8, 0x29, 0x43, 0x8c, 0x2a, 0xb2, 0xf6, 0xa1, 0x27,
83+
0x8e, 0xca, 0xfa, 0x88, 0xec, 0x31, 0xaa, 0xcf, 0xbd, 0x35, 0xca, 0x90, 0x7f, 0xb5, 0x3b, 0xe8,
84+
0x99, 0x22, 0xd5, 0xcd, 0x00, 0x31, 0xc2, 0x08, 0xc0, 0x00, 0x40, 0x06, 0x2e, 0xaf, 0xfe, 0x89,
85+
0x0d, 0x39, 0x47, 0x5e, 0x05, 0x64, 0xab, 0x3f, 0x54, 0x4c, 0x3d, 0x6e, 0x9f, 0x1d, 0x86, 0xa0,
86+
0x77, 0x58, 0xac, 0xcd, 0x46, 0x56, 0xab, 0xc3, 0x95, 0xfa, 0x42, 0x9e, 0xbc, 0x63, 0x9a, 0x8a,
87+
0x99, 0x58, 0x9c, 0x75, 0xf9, 0x5b, 0x5f, 0xcb, 0xea, 0x0d, 0xf5, 0x16, 0x79, 0x3a, 0x99, 0x89,
88+
0xc5, 0x79, 0x3b, 0x87, 0x3f, 0x09, 0x45, 0x0d, 0x45, 0x0d, 0xeb, 0xac, 0xbe, 0x2b, 0xe6, 0xee,
89+
0x97, 0xba, 0x79, 0x94, 0x73, 0x43, 0x0e, 0x8e, 0x77, 0xdf, 0x8b, 0xcd, 0x69, 0x7e, 0xbf, 0x27,
90+
0xcd, 0x53, 0xdb, 0xe9, 0x04, 0xab, 0x3c, 0x5e, 0x8f, 0xe3, 0xdb, 0x61, 0xfc, 0xb0, 0xb7, 0xe6,
91+
0xa5, 0x3a, 0x94, 0x2f, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x9a, 0x6a, 0xd1, 0x56, 0x46, 0x01,
92+
0x00, 0x00,
93+
}

transport/internet/quic/config.proto

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
syntax = "proto3";
2+
3+
package v2ray.core.transport.internet.quic;
4+
option csharp_namespace = "V2Ray.Core.Transport.Internet.Quic";
5+
option go_package = "quic";
6+
option java_package = "com.v2ray.core.transport.internet.quic";
7+
option java_multiple_files = true;
8+
9+
import "v2ray.com/core/common/serial/typed_message.proto";
10+
11+
message Config {
12+
string key = 1;
13+
v2ray.core.common.serial.TypedMessage header = 2;
14+
}

transport/internet/quic/conn.go

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package quic
2+
3+
import (
4+
"time"
5+
6+
quic "github.com/lucas-clemente/quic-go"
7+
8+
"v2ray.com/core/common/net"
9+
"v2ray.com/core/transport/internet"
10+
)
11+
12+
type sysConn struct {
13+
conn net.PacketConn
14+
header internet.PacketHeader
15+
}
16+
17+
func (c *sysConn) ReadFrom(p []byte) (int, net.Addr, error) {
18+
if c.header == nil {
19+
return c.conn.ReadFrom(p)
20+
}
21+
22+
overhead := int(c.header.Size())
23+
buffer := getBuffer()
24+
defer putBuffer(buffer)
25+
26+
nBytes, addr, err := c.conn.ReadFrom(buffer[:len(p)+overhead])
27+
if err != nil {
28+
return 0, nil, err
29+
}
30+
31+
copy(p, buffer[overhead:nBytes])
32+
33+
return nBytes - overhead, addr, nil
34+
}
35+
36+
func (c *sysConn) WriteTo(p []byte, addr net.Addr) (int, error) {
37+
if c.header == nil {
38+
return c.conn.WriteTo(p, addr)
39+
}
40+
41+
buffer := getBuffer()
42+
defer putBuffer(buffer)
43+
44+
overhead := int(c.header.Size())
45+
c.header.Serialize(buffer)
46+
copy(buffer[overhead:], p)
47+
nBytes, err := c.conn.WriteTo(buffer[:len(p)+overhead], addr)
48+
if err != nil {
49+
return 0, err
50+
}
51+
return nBytes - overhead, nil
52+
}
53+
54+
func (c *sysConn) Close() error {
55+
return c.conn.Close()
56+
}
57+
58+
func (c *sysConn) LocalAddr() net.Addr {
59+
return c.conn.LocalAddr()
60+
}
61+
62+
func (c *sysConn) SetDeadline(t time.Time) error {
63+
return c.conn.SetDeadline(t)
64+
}
65+
66+
func (c *sysConn) SetReadDeadline(t time.Time) error {
67+
return c.conn.SetReadDeadline(t)
68+
}
69+
70+
func (c *sysConn) SetWriteDeadline(t time.Time) error {
71+
return c.conn.SetWriteDeadline(t)
72+
}
73+
74+
type interConn struct {
75+
stream quic.Stream
76+
local net.Addr
77+
remote net.Addr
78+
}
79+
80+
func (c *interConn) Read(b []byte) (int, error) {
81+
return c.stream.Read(b)
82+
}
83+
84+
func (c *interConn) Write(b []byte) (int, error) {
85+
return c.stream.Write(b)
86+
}
87+
88+
func (c *interConn) Close() error {
89+
return c.stream.Close()
90+
}
91+
92+
func (c *interConn) LocalAddr() net.Addr {
93+
return c.local
94+
}
95+
96+
func (c *interConn) RemoteAddr() net.Addr {
97+
return c.remote
98+
}
99+
100+
func (c *interConn) SetDeadline(t time.Time) error {
101+
return c.stream.SetDeadline(t)
102+
}
103+
104+
func (c *interConn) SetReadDeadline(t time.Time) error {
105+
return c.stream.SetReadDeadline(t)
106+
}
107+
108+
func (c *interConn) SetWriteDeadline(t time.Time) error {
109+
return c.stream.SetWriteDeadline(t)
110+
}

transport/internet/quic/dialer.go

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package quic
2+
3+
import (
4+
"context"
5+
"sync"
6+
7+
"v2ray.com/core/transport/internet/tls"
8+
9+
quic "github.com/lucas-clemente/quic-go"
10+
11+
"v2ray.com/core/common"
12+
"v2ray.com/core/common/net"
13+
"v2ray.com/core/transport/internet"
14+
)
15+
16+
type clientSessions struct {
17+
access sync.Mutex
18+
sessions map[net.Destination]quic.Session
19+
}
20+
21+
func (s *clientSessions) getSession(destAddr net.Addr, tlsConfig *tls.Config, sockopt *internet.SocketConfig) (quic.Session, error) {
22+
s.access.Lock()
23+
defer s.access.Unlock()
24+
25+
if s.sessions == nil {
26+
s.sessions = make(map[net.Destination]quic.Session)
27+
}
28+
29+
dest := net.DestinationFromAddr(destAddr)
30+
31+
if session, found := s.sessions[dest]; found {
32+
return session, nil
33+
}
34+
35+
conn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
36+
IP: []byte{0, 0, 0, 0},
37+
Port: 0,
38+
}, sockopt)
39+
if err != nil {
40+
return nil, err
41+
}
42+
43+
config := &quic.Config{
44+
Versions: []quic.VersionNumber{quic.VersionMilestone0_10_0},
45+
ConnectionIDLength: 12,
46+
KeepAlive: true,
47+
}
48+
49+
session, err := quic.DialContext(context.Background(), conn, destAddr, "", tlsConfig.GetTLSConfig(tls.WithDestination(dest)), config)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
s.sessions[dest] = session
55+
return session, nil
56+
}
57+
58+
var client clientSessions
59+
60+
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
61+
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
62+
if tlsConfig == nil {
63+
return nil, newError("TLS not enabled for QUIC")
64+
}
65+
66+
destAddr, err := net.ResolveUDPAddr("udp", dest.NetAddr())
67+
if err != nil {
68+
return nil, err
69+
}
70+
71+
session, err := client.getSession(destAddr, tlsConfig, streamSettings.SocketSettings)
72+
if err != nil {
73+
return nil, err
74+
}
75+
76+
conn, err := session.OpenStreamSync()
77+
if err != nil {
78+
return nil, err
79+
}
80+
81+
return &interConn{
82+
stream: conn,
83+
local: session.LocalAddr(),
84+
remote: destAddr,
85+
}, nil
86+
}
87+
88+
func init() {
89+
common.Must(internet.RegisterTransportDialer(protocolName, Dial))
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package quic
2+
3+
import "v2ray.com/core/common/errors"
4+
5+
type errPathObjHolder struct {}
6+
func newError(values ...interface{}) *errors.Error { return errors.New(values...).WithPathObj(errPathObjHolder{}) }

0 commit comments

Comments
 (0)