修订文档,代码

This commit is contained in:
e1732a364fed
2000-01-01 00:00:00 +00:00
parent 07328e0387
commit 143e8bb5ad
4 changed files with 64 additions and 52 deletions

View File

@@ -169,6 +169,10 @@ CRUMFURS 信道与普通UDP信道一样要传 udp长度头。
此时从socks5读出的每一个udp链接视其raddr而定如果raddr是没遇到过的地址则我们会新建立一个新信道
### 代码参考
阅读 prox/vless/udpConn.go 以及 netLayer/relay_udp.go 的 RelayUDP_separate 函数
## 连接池
我们可以通过使用新协议命令来做到 非mux的 连接池技术可以在每个vless 头部添加 “是否关闭连接”的信息

View File

@@ -8,6 +8,8 @@ import (
// implements NetDeadliner. Must call InitEasyDeadline before use.
// Can be embed to a struct to make it have SetWriteDeadline, SetReadDeadline and SetDeadline method.
// And MUST use select and ReadTimeoutChan or WriteTimeoutChan when reading or writing.
//
// see IOWrapper for reference.
type EasyDeadline struct {
readDeadline PipeDeadline
writeDeadline PipeDeadline

View File

@@ -189,6 +189,8 @@ func relayUDP_rc_toLC(rc, lc MsgConn, downloadByteCount *uint64, mutex *sync.RWM
// 不过分离信道只能用于代理,不能用于 direct, 因为direct为了实现fullcone, 对所有rc连接都用的同一个udp端口。
// 阻塞. 返回从 rc 下载的总字节数. 拷贝完成后自动关闭双端连接.
func RelayUDP_separate(rc, lc MsgConn, firstAddr *Addr, downloadByteCount, uploadByteCount *uint64, dialfunc func(raddr Addr) MsgConn) uint64 {
//一般而言lc为 socks5 的MsgConnrc 为 vless v1 客户端的 MsgConn
var lc_mutex sync.RWMutex
var mainhash HashableAddr
@@ -239,7 +241,6 @@ func RelayUDP_separate(rc, lc MsgConn, firstAddr *Addr, downloadByteCount, uploa
go func() {
_, rcwrong := relayUDP_rc_toLC(rc, lc, downloadByteCount, &lc_mutex)
//rc到lc转发结束一定也是因为读取/写入失败, 如果是rc的错误, 则我们要删掉rc, 释放资源
//一般而言lc为 socks5 的MsgConnrc 为 vless v1 的 MsgConn
if rcwrong {
lc_mutex.Lock()
@@ -297,65 +298,65 @@ func RelayUDP_separate(rc, lc MsgConn, firstAddr *Addr, downloadByteCount, uploa
return count2
}
/*
relay udp 有两种针对不同通道的技术
// /*
// relay udp 有两种针对不同通道的技术
一种是针对单来源通道的技术通常是udp in tcp的情况此时我们用MsgConn + RelayUDP 方法很方便
// 一种是针对单来源通道的技术通常是udp in tcp的情况此时我们用MsgConn + RelayUDP 方法很方便
另一种是直接读udp的技术目前我们用很多代码来适配它也能包装MsgConn里但是非常不美观繁琐。
因为udp是多来源的我们为了确定单一来源就要全局读然后定义一个map, 为每一个来源的地址存储一个MsgConn
// 另一种是直接读udp的技术目前我们用很多代码来适配它也能包装MsgConn里但是非常不美观繁琐。
// 因为udp是多来源的我们为了确定单一来源就要全局读然后定义一个map, 为每一个来源的地址存储一个MsgConn
我们重新定义一个MsgProducer 和 MsgConsumer就方便很多. 这是针对多来源的转发。
// 我们重新定义一个MsgProducer 和 MsgConsumer就方便很多. 这是针对多来源的转发。
如此,一个 UDPConn就相当于一个 MsgProducer, 它的to 可以由 tproxy 或者 msg内部的数据提取出来
// 如此,一个 UDPConn就相当于一个 MsgProducer, 它的to 可以由 tproxy 或者 msg内部的数据提取出来
不过这种抽象一样需要map进行记忆才能区分不同来源的from。针对不同的from要使用以前对它发信号所使用的端口。
// 不过这种抽象一样需要map进行记忆才能区分不同来源的from。针对不同的from要使用以前对它发信号所使用的端口。
所以两种技术可能是等价的。
*/
func RelayMsg(rc, lc MsgHub, downloadByteCount, uploadByteCount *uint64) uint64 {
go CopyMsgFromP2C(lc, rc, uploadByteCount)
// 所以两种技术可能是等价的。
// */
// func RelayMsg(rc, lc MsgHub, downloadByteCount, uploadByteCount *uint64) uint64 {
// go CopyMsgFromP2C(lc, rc, uploadByteCount)
var dbc uint64
CopyMsgFromP2C(rc, lc, &dbc)
// var dbc uint64
// CopyMsgFromP2C(rc, lc, &dbc)
if downloadByteCount != nil {
atomic.AddUint64(downloadByteCount, dbc)
}
return dbc
// if downloadByteCount != nil {
// atomic.AddUint64(downloadByteCount, dbc)
// }
// return dbc
}
// }
func CopyMsgFromP2C(p MsgProducer, c MsgConsumer, countPtr *uint64) {
var bc uint64
// func CopyMsgFromP2C(p MsgProducer, c MsgConsumer, countPtr *uint64) {
// var bc uint64
for {
msg, from, to, err := p.ProduceMsg()
if err != nil {
break
}
err = c.ConsumeMsg(msg, from, to)
if err != nil {
break
}
bc += uint64(len(msg))
}
// for {
// msg, from, to, err := p.ProduceMsg()
// if err != nil {
// break
// }
// err = c.ConsumeMsg(msg, from, to)
// if err != nil {
// break
// }
// bc += uint64(len(msg))
// }
if countPtr != nil {
atomic.AddUint64(countPtr, bc)
}
// if countPtr != nil {
// atomic.AddUint64(countPtr, bc)
// }
}
// }
type MsgHub interface {
MsgProducer
MsgConsumer
}
// type MsgHub interface {
// MsgProducer
// MsgConsumer
// }
type MsgProducer interface {
ProduceMsg() (msg []byte, from, to Addr, err error)
}
// type MsgProducer interface {
// ProduceMsg() (msg []byte, from, to Addr, err error)
// }
type MsgConsumer interface {
ConsumeMsg(msg []byte, from, to Addr) (err error)
}
// type MsgConsumer interface {
// ConsumeMsg(msg []byte, from, to Addr) (err error)
// }

View File

@@ -10,6 +10,11 @@ import (
"github.com/e1732a364fed/v2ray_simple/utils"
)
const (
flag_orig = 0
flag_new_source = 1
)
type UDPConn struct {
net.Conn
@@ -56,7 +61,7 @@ func (u *UDPConn) WriteMsgTo(p []byte, raddr netLayer.Addr) error {
}
defer utils.PutBuf(writeBuf)
//v0很垃圾不支持fullcone而是无视raddr始终向最开始的raddr发送。
//v0设计有问题不支持fullcone无视raddr始终向最开始的raddr发送。
if u.version == 0 {
if !u.isClientEnd && !u.notFirst {
@@ -84,11 +89,11 @@ func (u *UDPConn) WriteMsgTo(p []byte, raddr netLayer.Addr) error {
// umfurs信息将会提示客户端 下一次发送到此地址时,拨号一个新的 udp信道.
if u.raddr.GetHashable() == raddr.GetHashable() {
writeBuf.WriteByte(0)
writeBuf.WriteByte(flag_orig)
return u.writeDataTo(writeBuf, p)
} else {
writeBuf.WriteByte(1)
writeBuf.WriteByte(flag_new_source)
WriteAddrTo(writeBuf, raddr)
return u.writeDataTo(writeBuf, p)
@@ -192,10 +197,10 @@ func (u *UDPConn) ReadMsgFrom() ([]byte, netLayer.Addr, error) {
switch b1 {
default:
return nil, netLayer.Addr{}, utils.ErrInErr{ErrDesc: "Vless udp_multi client read first byte unexpected", ErrDetail: utils.ErrInvalidData, Data: b1}
case 0:
case flag_orig:
bs, err := u.readData_with_len()
return bs, u.raddr, err
case 1:
case flag_new_source:
raddr, err := netLayer.V2rayGetAddrFrom(u.bufr)
if err != nil {
return nil, raddr, err