Files
v2ray_simple/netLayer/udpConn.go
hahahrfool 548675e002 添加自定义网络层功能;添加udp网络层支持
配置中,listen和dial中,可添加 network = "udp" 字段,不添加则默认tcp
2022-03-21 21:19:31 +08:00

158 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package netLayer
import (
"errors"
"io"
"net"
"time"
"github.com/hahahrfool/v2ray_simple/utils"
)
var (
ErrTimeout = errors.New("timeout")
)
//UDPConn 实现了 net.Conn
type UDPConn struct {
peerAddr *net.UDPAddr
realConn *net.UDPConn
inMsgChan chan []byte
readDeadline PipeDeadline
writeDeadline PipeDeadline
unread []byte
isClient bool
}
func DialUDP(raddr *net.UDPAddr) (net.Conn, error) {
conn, err := net.DialUDP("udp", nil, raddr)
if err != nil {
return nil, err
}
return NewUDPConn(raddr, conn, true), nil
}
func NewUDPConn(raddr *net.UDPAddr, conn *net.UDPConn, isClient bool) *UDPConn {
inDataChan := make(chan []byte, 50)
theUDPConn := &UDPConn{raddr, conn, inDataChan, MakePipeDeadline(),
MakePipeDeadline(), []byte{}, isClient}
//不设置缓存的话,会导致发送过快 而导致丢包
conn.SetReadBuffer(64 * 1024)
conn.SetWriteBuffer(64 * 1024)
if isClient {
//客户端要自己循环读取udp
go func() {
for {
buf := utils.GetPacket()
n, _, err := conn.ReadFromUDP(buf)
inDataChan <- buf[:n] //该数据会被ReadMsg和 Read读到
if err != nil {
break
}
}
}()
}
return theUDPConn
}
func (uc *UDPConn) ReadMsg() (b []byte, err error) {
select {
case msg, ok := <-uc.inMsgChan:
if !ok {
return nil, io.EOF
}
return msg, nil
case <-uc.readDeadline.Wait():
return nil, ErrTimeout
}
}
func (uc *UDPConn) GetReadChan() chan []byte {
return uc.inMsgChan
}
func (uc *UDPConn) Read(buf []byte) (n int, err error) {
if len(uc.unread) > 0 {
n = copy(buf, uc.unread)
uc.unread = uc.unread[n:]
return
}
var msg []byte
msg, err = uc.ReadMsg()
if err != nil {
return 0, err
}
n = copy(buf, msg)
diff := len(msg) - n
if diff > 0 { //最好不要分段读否则我们将不会把缓存放回pool总之建议buf直接使用 utils.GetPacket
uc.unread = append(uc.unread, msg[n:]...)
} else {
utils.PutPacket(msg)
}
return
}
func (uc *UDPConn) Write(buf []byte) (n int, err error) {
select {
case <-uc.writeDeadline.Wait():
return 0, ErrTimeout
default:
if uc.isClient {
time.Sleep(time.Millisecond) //不能发送太快,否则会出现丢包,实测简单1毫秒即可避免
/*
一些常见的丢包后出现的错误:
tls
bad mac
ws
non-zero rsv bits with no extension negotiated, Data: 0
裸奔curl客户端:
curl: (56) LibreSSL SSL_read: error:1404C3FC:SSL routines:ST_OK:sslv3 alert bad record mac, errno 0
*/
//if use writeToUDP at client end, we will get err Write write udp 127.0.0.1:50361->:60006: use of WriteTo with pre-connected connection
return uc.realConn.Write(buf)
} else {
return uc.realConn.WriteToUDP(buf, uc.peerAddr)
}
}
}
func (*UDPConn) Close() error { return nil }
func (b *UDPConn) LocalAddr() net.Addr { return b.realConn.LocalAddr() }
func (b *UDPConn) RemoteAddr() net.Addr { return b.peerAddr }
func (b *UDPConn) RemoteUDPAddr() *net.UDPAddr { return b.peerAddr }
func (b *UDPConn) SetWriteDeadline(t time.Time) error {
b.writeDeadline.Set(t)
return nil
}
func (b *UDPConn) SetReadDeadline(t time.Time) error {
b.readDeadline.Set(t)
return nil
}
func (b *UDPConn) SetDeadline(t time.Time) error {
b.readDeadline.Set(t)
b.writeDeadline.Set(t)
return nil
}