Files
Archive/brook/quic.go
2024-03-05 02:32:38 -08:00

174 lines
3.8 KiB
Go

// Copyright (c) 2016-present Cloud <cloud@txthinking.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 3 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package brook
import (
"context"
"crypto/tls"
"net"
"time"
"github.com/quic-go/quic-go"
)
func QUICDialUDP(src, dst, addr string, tc *tls.Config, idleTime int) (net.Conn, error) {
var rc *net.UDPConn
var err error
if src == "" || dst == "" {
rc, err = ListenUDP("udp", nil)
}
if src != "" && dst != "" {
rc, err = NATListenUDP("udp", src, dst)
}
if err != nil {
return nil, err
}
raddr, err := Resolve("udp", addr)
if err != nil {
rc.Close()
return nil, err
}
rc1, err := quic.Dial(context.Background(), rc, raddr, tc, &quic.Config{MaxIdleTimeout: time.Duration(idleTime) * time.Second, EnableDatagrams: true})
if err != nil {
rc.Close()
return nil, err
}
return &QUICConn{
UDPConn: rc,
Conn: rc1,
LAddr: rc1.LocalAddr(),
RAddr: rc1.RemoteAddr(),
}, nil
}
func QUICDialTCP(src, dst, addr string, tc *tls.Config, idleTime int) (net.Conn, error) {
var rc *net.UDPConn
var err error
if src == "" || dst == "" {
rc, err = ListenUDP("udp", nil)
}
if src != "" && dst != "" {
rc, err = NATListenUDP("udp", src, dst)
}
if err != nil {
return nil, err
}
raddr, err := Resolve("udp", addr)
if err != nil {
rc.Close()
return nil, err
}
rc1, err := quic.Dial(context.Background(), rc, raddr, tc, &quic.Config{MaxIdleTimeout: time.Duration(idleTime) * time.Second})
if err != nil {
rc.Close()
return nil, err
}
s, err := rc1.OpenStreamSync(context.Background())
if err != nil {
rc1.CloseWithError(0, err.Error())
rc.Close()
return nil, err
}
return &QUICConn{
UDPConn: rc,
Conn: rc1,
Stream: s,
LAddr: &net.TCPAddr{
IP: rc1.LocalAddr().(*net.UDPAddr).IP,
Port: rc1.LocalAddr().(*net.UDPAddr).Port,
Zone: rc1.LocalAddr().(*net.UDPAddr).Zone,
},
RAddr: &net.TCPAddr{
IP: rc1.RemoteAddr().(*net.UDPAddr).IP,
Port: rc1.RemoteAddr().(*net.UDPAddr).Port,
Zone: rc1.RemoteAddr().(*net.UDPAddr).Zone,
},
}, nil
}
type QUICConn struct {
UDPConn *net.UDPConn
Conn quic.Connection
Stream quic.Stream
LAddr net.Addr
RAddr net.Addr
}
func (c *QUICConn) Read(b []byte) (int, error) {
if c.Stream != nil {
return c.Stream.Read(b)
}
b1, err := c.Conn.ReceiveDatagram(context.Background())
if err != nil {
return 0, err
}
i := copy(b, b1)
return i, nil
}
func (c *QUICConn) Write(b []byte) (int, error) {
if c.Stream != nil {
return c.Stream.Write(b)
}
if err := c.Conn.SendDatagram(b); err != nil {
return 0, err
}
return len(b), nil
}
func (c *QUICConn) Close() error {
if c.Stream != nil {
c.Stream.CancelRead(0)
c.Stream.Close()
}
if c.Conn != nil {
c.Conn.CloseWithError(0, "close")
}
if c.UDPConn != nil {
c.UDPConn.Close()
}
return nil
}
func (c *QUICConn) LocalAddr() net.Addr {
return c.LAddr
}
func (c *QUICConn) RemoteAddr() net.Addr {
return c.RAddr
}
func (c *QUICConn) SetDeadline(t time.Time) error {
if c.Stream != nil {
return c.Stream.SetDeadline(t)
}
// prefer quic.Config.MaxIdleTimeout
return nil
}
func (c *QUICConn) SetReadDeadline(t time.Time) error {
if c.Stream != nil {
return c.Stream.SetReadDeadline(t)
}
return nil
}
func (c *QUICConn) SetWriteDeadline(t time.Time) error {
if c.Stream != nil {
return c.Stream.SetWriteDeadline(t)
}
return nil
}