mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-26 20:21:35 +08:00
174 lines
3.8 KiB
Go
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
|
|
}
|