修订代码;修复loglevel为debug时失效问题;dns请求加锁,已经可用

This commit is contained in:
hahahrfool
2022-04-01 12:31:47 +08:00
parent c6e8c18f95
commit e732ea3c3b
17 changed files with 192 additions and 78 deletions
+18
View File
@@ -0,0 +1,18 @@
api草案:
使用restful api + basic auth
功能列表
1. 生成toml配置文件功能
2. 查看本次程序开始运行起所使用的流量(双向)
3. 查看自某一天开始所用掉的总流量
4. 动态插入一个 新 inServer / outClient
5. 动态修改 某个 inServer/outClient 的 uuid
6. 动态调节 hy手动挡阻控模式 的发送速率
7. 动态删除一个 inServer /outClient
8. 动态控制每一个 inServer / outClient 的网速
坚决抵制添加其它花哨的专门供机场主使用的功能。你们机场主有不给我们开发者钱,凭啥给你干活。
+3
View File
@@ -9,6 +9,9 @@ default_uuid = "a684455c-b14f-11ea-bf0d-42010aaa0003"
[dns]
# dns解析仅仅是为了能够精准分流, 如果你不需要分流, 没有自定义dns需求,则不需要dns模块
servers = [
"udp://114.114.114.114:53" # 如果把该url指向我们dokodemo监听的端口,就可以达到通过节点请求dns的目的.
]
+24 -1
View File
@@ -43,7 +43,30 @@ require (
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
replace github.com/lucas-clemente/quic-go => github.com/tobyxdd/quic-go v0.25.1-0.20220224051149-310bd1bfaf1f
retract v1.1.1
retract v1.1.0
retract v1.0.9
retract v1.0.8
retract v1.0.7
retract v1.0.6
retract v1.0.5
retract v1.0.4
retract v1.0.3
retract v1.0.2
retract v1.0.1
retract v1.0.0
+3
View File
@@ -12,6 +12,7 @@ github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
@@ -142,6 +143,7 @@ github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je4
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
@@ -202,6 +204,7 @@ go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+1 -2
View File
@@ -1,5 +1,4 @@
/*
Package grpc implements methods for grpc
/*Package grpc implements methods for grpc
从stream.proto 生成 stream.pb.go 和 stream_grpc.pb.go:
+1 -1
View File
@@ -1,5 +1,5 @@
/*
Package httpLayer 提供http层的一些方法和定义.
Package httpLayer provides methods and definitions for http layer
比如fallback一般由httpLayer处理
*/
+40 -22
View File
@@ -321,7 +321,6 @@ func listenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client) {
ce.Write(
zap.String("protocol", proxy.GetFullName(inServer)),
zap.String("network", inServer.Network()),
zap.String("addr", inServer.AddrStr()),
)
//log.Printf("%s is listening %s on %s\n", , , )
@@ -342,7 +341,6 @@ func listenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client) {
ce.Write(
zap.String("protocol", proxy.GetFullName(inServer)),
zap.String("network", inServer.Network()),
zap.String("addr", inServer.AddrStr()),
)
//log.Printf("%s is listening %s on %s\n", proxy.GetFullName(inServer), network, inServer.AddrStr())
@@ -744,20 +742,33 @@ afterLocalServerHandshake:
////////////////////////////// DNS解析阶段 /////////////////////////////////////
//dns解析会试图解析域名并将ip放入 targetAddr中
// 因为在direct时,netLayer.Addr 拨号时,会优先选用ip拨号,而且我们下面的分流阶段 如果使用ip的话,
// 可以利用geoip文件, 可以做到国别分流.
if dnsMachine != nil && (targetAddr.Name != "" && len(targetAddr.IP) == 0) && targetAddr.Network != "unix" {
//log.Println("will query", targetAddr.Name)
if ce := utils.CanLogDebug("querying"); ce != nil {
ce.Write(zap.String("domain", targetAddr.Name))
}
ip := dnsMachine.Query(targetAddr.Name, dns.TypeA)
if ip == nil {
ip = dnsMachine.Query(targetAddr.Name, dns.TypeAAAA)
}
if ip != nil {
targetAddr.IP = ip
if ce2 := utils.CanLogDebug("dns query result"); ce2 != nil {
ce2.Write(zap.String("domain", targetAddr.Name), zap.String("ip", ip.String()))
}
}
}
////////////////////////////// 分流阶段 /////////////////////////////////////
var client proxy.Client = iics.defaultClient
routed := false
//尝试分流, 获取到真正要发向 的 outClient
if routePolicy != nil && !inServer.CantRoute() {
@@ -768,8 +779,7 @@ afterLocalServerHandshake:
}
if ce := utils.CanLogDebug("try routing"); ce != nil {
//log.Printf("try routing %v\n", desc)
ce.Write(zap.Any("desc", desc))
ce.Write(zap.Any("source", desc))
}
outtag := routePolicy.GetOutTag(desc)
@@ -777,9 +787,9 @@ afterLocalServerHandshake:
if outtag == "direct" {
client = directClient
iics.routedToDirect = true
routed = true
if ce := utils.CanLogInfo("routed to direct"); ce != nil {
//log.Printf("routed to direct %s\n", targetAddr.UrlString())
ce.Write(
zap.String("target", targetAddr.UrlString()),
)
@@ -789,17 +799,29 @@ afterLocalServerHandshake:
if tagC, ok := clientsTagMap[outtag]; ok {
client = tagC
if ce := utils.CanLogInfo("routed to"); ce != nil {
//log.Printf("routed to %s %s\n", outtag, proxy.GetFullName(client))
routed = true
if ce := utils.CanLogInfo("routed"); ce != nil {
ce.Write(
zap.String("outtag", outtag),
zap.String("client", proxy.GetFullName(client)),
zap.Any("source", desc),
zap.String("to outtag", outtag),
zap.String("P", proxy.GetFullName(client)),
zap.String("addr", client.AddrStr()),
)
}
}
}
}
if !routed {
if ce := utils.CanLogDebug("not routed, using default"); ce != nil {
ce.Write(
zap.Any("source", targetAddr.String()),
zap.String("client", proxy.GetFullName(client)),
zap.String("addr", client.AddrStr()),
)
}
}
////////////////////////////// 特殊处理阶段 /////////////////////////////////////
// 下面几段用于处理 tls lazy
@@ -999,13 +1021,14 @@ func dialClient(iics incomingInserverConnState, targetAddr netLayer.Addr, client
if ce := utils.CanLogDebug("request isn't the appointed domain"); ce != nil {
if uniqueTestDomain != "" && uniqueTestDomain != targetAddr.Name {
ce.Write(
zap.String("request", targetAddr.String()),
zap.String("uniqueTestDomain", uniqueTestDomain),
)
return nil, utils.NumErr{N: 1, Prefix: "dialClient err, "}
}
return nil, utils.NumErr{N: 1, Prefix: "dialClient err, "}
}
if ce := utils.CanLogInfo("Request"); ce != nil {
@@ -1100,7 +1123,10 @@ func dialClient(iics incomingInserverConnState, targetAddr netLayer.Addr, client
tlsConn, err := client.GetTLS_Client().Handshake(clientConn)
if err != nil {
log.Printf("failed in handshake outClient tls %s, Reason: %s\n", targetAddr.String(), err)
if ce := utils.CanLogErr("failed in handshake outClient tls"); ce != nil {
ce.Write(zap.String("target", targetAddr.String()), zap.Error(err))
}
return nil, utils.NumErr{N: 4, Prefix: "dialClient err, "}
}
@@ -1118,7 +1144,6 @@ advLayerStep:
clientConn, err = client.DialSubConnFunc()(dailedCommonConn)
if err != nil {
if ce := utils.CanLogErr("DialSubConnFunc failed"); ce != nil {
//log.Printf("DialSubConnFunc failed, %s\n", err)
ce.Write(
zap.Error(err),
)
@@ -1130,7 +1155,6 @@ advLayerStep:
grpcClientConn, err = grpc.ClientHandshake(clientConn, &realTargetAddr)
if err != nil {
if ce := utils.CanLogErr("grpc.ClientHandshake failed"); ce != nil {
//log.Printf("grpc.ClientHandshake failed, %s\n", err)
ce.Write(zap.Error(err))
}
@@ -1146,7 +1170,6 @@ advLayerStep:
clientConn, err = grpc.DialNewSubConn(client.Path(), grpcClientConn, &realTargetAddr)
if err != nil {
if ce := utils.CanLogErr("grpc.DialNewSubConn failed"); ce != nil {
//log.Printf("grpc.DialNewSubConn failed,%s\n", err)
ce.Write(zap.Error(err))
@@ -1171,8 +1194,7 @@ advLayerStep:
edBuf = edBuf[:ws.MaxEarlyDataLen]
n, e := wlc.Read(edBuf)
if e != nil {
if ce := utils.CanLogErr("reading ws early data"); ce != nil {
//log.Printf("err when reading ws early data %s\n", e)
if ce := utils.CanLogErr("failed to read ws early data"); ce != nil {
ce.Write(zap.Error(e))
}
return nil, utils.NumErr{N: 7, Prefix: "dialClient err, "}
@@ -1195,11 +1217,9 @@ advLayerStep:
wc, err = wsClient.Handshake(clientConn)
}
//wc, err := wsClient.Handshake(clientConn, ed)
if err != nil {
if ce := utils.CanLogErr("failed in handshake ws"); ce != nil {
//log.Printf("failed in handshake ws to %s , Reason: %s\n", targetAddr.String(), err)
ce.Write(
zap.String("target", targetAddr.String()),
zap.Error(err),
@@ -1217,8 +1237,6 @@ advLayerStep:
wrc, err := client.Handshake(clientConn, targetAddr)
if err != nil {
if ce := utils.CanLogErr("failed in handshake"); ce != nil {
//log.Printf("failed in handshake to %s , Reason: %s\n", targetAddr.String(), err)
ce.Write(
zap.String("target", targetAddr.String()),
zap.Error(err),
+65 -26
View File
@@ -3,6 +3,7 @@ package netLayer
import (
"net"
"net/netip"
"strings"
"sync"
"github.com/hahahrfool/v2ray_simple/utils"
@@ -10,12 +11,28 @@ import (
"go.uber.org/zap"
)
func DNSQuery(domain string, dns_type uint16, conn *dns.Conn, recursionCount int) net.IP {
var globalDnsQueryMutex sync.Mutex
//domain必须是 dns.Fqdn 函数 包过的, 本函数不检查是否包过。如果不包过就传入,会报错。
// dns_type 为 miekg/dns 包中定义的类型, 如 TypeA, TypeAAAA, TypeCNAME.
// conn是一个建立好的 dns.Conn, 必须非空, 本函数不检查.
// theMux是与 conn相匹配的mutex, 这是为了防止同时有多个请求导致无法对口;内部若判断为nil,会主动使用一个全局mux.
// recursionCount 使用者统一填0 即可,用于内部 遇到cname时进一步查询时防止无限递归.
func DNSQuery(domain string, dns_type uint16, conn *dns.Conn, theMux *sync.Mutex, recursionCount int) net.IP {
m := new(dns.Msg)
m.SetQuestion((domain), dns_type) //为了更快,不使用 dns.Fqdn, 请调用之前先确保ok
c := new(dns.Client)
if theMux == nil {
theMux = &globalDnsQueryMutex
}
theMux.Lock()
r, _, err := c.ExchangeWithConn(m, conn)
theMux.Unlock()
if r == nil {
if ce := utils.CanLogErr("dns query read err"); ce != nil {
ce.Write(zap.Error(err))
@@ -56,44 +73,52 @@ func DNSQuery(domain string, dns_type uint16, conn *dns.Conn, recursionCount int
if recursionCount > 2 {
//不准循环递归,否则就是bug;因为有可能两个域名cname相互指向对方,好坏
if ce := utils.CanLogDebug("dns query got cname bug recursionCount>2"); ce != nil {
ce.Write(zap.String("query", domain), zap.String("target", aa.Target))
if ce := utils.CanLogDebug("dns query got cname but recursionCount>2"); ce != nil {
ce.Write(zap.String("query", domain), zap.String("cname", aa.Target))
}
return nil
}
return DNSQuery(aa.Target, dns_type, conn, recursionCount+1)
return DNSQuery(dns.Fqdn(aa.Target), dns_type, conn, theMux, recursionCount+1)
}
}
return nil
}
// 给 miekg/dns.Conn 加一个互斥锁, 可保证同一时间仅有一个请求发生
// 这样就不会造成并发时的混乱
type DnsConn struct {
*dns.Conn
mutex sync.Mutex
}
//dns machine维持与多个dns服务器的连接(最好是udp这种无状态的),并可以发起dns请求
// 会缓存dns记录
type DNSMachine struct {
DefaultConn *dns.Conn
conns map[string]*dns.Conn
DefaultConn DnsConn
conns map[string]*DnsConn
cache map[string]net.IP
SpecialIPPollicy map[string][]netip.Addr
SpecialServerPollicy map[string]string //domain -> dns server name 的map
mux sync.RWMutex
mutex sync.RWMutex //读写 conns, cache, SpecialIPPollicy, SpecialServerPollicy 时所使用的 mutex
}
//并不初始化所有内部成员
func NewDnsMachine(defaultAddr *Addr) *DNSMachine {
//并不初始化所有内部成员, 只是创建并拨个号,若为nil则号也不拨
func NewDnsMachine(defaultDnsServerAddr *Addr) *DNSMachine {
var dm DNSMachine
if defaultAddr != nil {
if defaultDnsServerAddr != nil {
var conn net.Conn
var err error
if defaultAddr.IsUDP() {
conn, err = net.DialUDP("udp", nil, defaultAddr.ToUDPAddr())
if defaultDnsServerAddr.IsUDP() {
conn, err = net.DialUDP("udp", nil, defaultDnsServerAddr.ToUDPAddr())
} else {
conn, err = defaultAddr.Dial()
conn, err = defaultDnsServerAddr.Dial()
}
if err != nil {
@@ -104,15 +129,15 @@ func NewDnsMachine(defaultAddr *Addr) *DNSMachine {
dc := new(dns.Conn)
dc.Conn = conn
dm.DefaultConn = dc
dm.DefaultConn.Conn = dc
}
return &dm
}
func (dm *DNSMachine) SetDefaultConn(c net.Conn) {
dm.DefaultConn = new(dns.Conn)
dm.DefaultConn.Conn = c
dm.DefaultConn.Conn = new(dns.Conn)
dm.DefaultConn.Conn.Conn = c
}
//name为该dns服务器的名称
@@ -120,28 +145,38 @@ func (dm *DNSMachine) AddConnForServer(name string, c net.Conn) {
dc := new(dns.Conn)
dc.Conn = c
if dm.conns == nil {
dm.conns = make(map[string]*dns.Conn)
dm.conns = map[string]*DnsConn{}
}
dm.conns[name] = dc
dcc := &DnsConn{Conn: dc}
dm.conns[name] = dcc
}
//传入的domain必须是不带尾缀点号的domain, 即没有包过 Fqdn
func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) {
var cacheHit bool
defer func() {
if len(ip) > 0 {
//log.Println("will add to cache", domain, ip)
if cacheHit {
return
}
dm.mux.Lock()
if len(ip) > 0 {
if ce := utils.CanLogDebug("will add to dns cache"); ce != nil {
ce.Write(zap.String("domain", domain))
}
dm.mutex.Lock()
if dm.cache == nil {
dm.cache = make(map[string]net.IP)
}
domain = strings.TrimSuffix(domain, ".")
dm.cache[domain] = ip
dm.mux.Unlock()
dm.mutex.Unlock()
}
}()
dm.mux.RLock()
defer dm.mux.RUnlock()
dm.mutex.RLock()
defer dm.mutex.RUnlock()
//先从 cache找,有就直接返回
//然后,
@@ -152,6 +187,10 @@ func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) {
if dm.cache != nil {
if ip = dm.cache[domain]; ip != nil {
cacheHit = true
if ce := utils.CanLogDebug("hit dns cache"); ce != nil {
ce.Write(zap.String("domain", domain))
}
return
}
}
@@ -180,7 +219,7 @@ func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) {
}
}
theDNSServerConn := dm.DefaultConn
theDNSServerConn := &dm.DefaultConn
if dm.conns != nil && dm.SpecialServerPollicy != nil {
if sn := dm.SpecialServerPollicy[domain]; sn != "" {
@@ -192,5 +231,5 @@ func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) {
}
domain = dns.Fqdn(domain)
return DNSQuery(domain, dns_type, theDNSServerConn, 0)
return DNSQuery(domain, dns_type, theDNSServerConn.Conn, &theDNSServerConn.mutex, 0)
}
+18 -14
View File
@@ -1,4 +1,4 @@
/*Package proxy 定义了代理转发所需的必备组件.
/*Package proxy defines necessary components for proxy.
Layer Definition
@@ -24,21 +24,25 @@ New Model - VSI 新的VSI 模型
那么我们verysimple实际上就是 基于 “层” 的架构,或称 可分层结构.
9 tcp data
--------------------
8 vless/trojan/socks5
--------------------
7 ws/grpc
--------------------
6 http
--------------------
5 tls
--------------------
4 tcp
--------------------
9 client real tcp data
----------------------------------------
8 vless/trojan/socks5
----------------------------------------
7 ws/grpc/quic
----------------------------------------
6 http (headers)
----------------------------------------
5 tls
----------------------------------------
4 tcp/udp/unix domain socket
----------------------------------------
基本上5-8层都是可控的.
基本上5-8层都是可控的.第四层也可以给出一些参数进行控制,比如在tproxy时。
实际上quic属于一种超级协议,横跨传输层一直到高级层,不过为了分类方便,这里认为它也是一种 高级层.
也就是说,如果遇到横跨多个层的协议,我们认为它属于其中最高的层级。
对应的理想配置文件应该如下.
+1
View File
@@ -121,6 +121,7 @@ func (c *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWrit
//log.Println("尝试拨号 Cmd_CRUMFURS 信道")
//这段代码明显有问题,如果直接dial的话,那就是脱离tls的裸协议,所以这里以后需要处理一下
UMFURS_conn, err := target.Dial()
if err != nil {
if ce := utils.CanLogErr("尝试拨号 Cmd_CRUMFURS 信道时发生错误"); ce != nil {
+1 -1
View File
@@ -160,7 +160,7 @@ func testVLessUDP(version int, port string, t *testing.T) {
count := 0
for {
t.Log(" udp for! ")
//t.Log(" udp for! ")
// 读取数据
readNum, remoteAddr, err := fakeRealUDPServerListener.ReadFromUDP(readbuf)
if err != nil {
+1 -1
View File
@@ -1,4 +1,4 @@
//Package quic 实现高级层中的quic
//Package quic defines functions to listen and dial quic, with some customizable congestion settings.
package quic
import (
+1 -1
View File
@@ -1,5 +1,5 @@
/*
Package tlsLayer 提供tls层的各种支持. 也包括tls流量的嗅探功能
Package tlsLayer provides support for tlsLayer, including sniffing.
*/
package tlsLayer
+1 -1
View File
@@ -1,4 +1,4 @@
// Package utils provides utils that needed by all sub-packages in verysimle
// Package utils provides utilities that is used in all sub-packages in verysimple
package utils
import (
+5 -7
View File
@@ -47,7 +47,7 @@ func (c *Conn) Read(p []byte) (int, error) {
// https://www.rfc-editor.org/rfc/rfc6455#section-5.2
// (使用了 Extended payload length 字段)
// 肯定会有多读的情况,此时如果一次用 wsutil.ReadServerBinary()的话,那么服务器缓存就超大,不可能如此实现
// wsutil.ReadServerBinary内部使用了 io.ReadAll, 而ReadAll是会无限增长内存的
// ( wsutil.ReadServerBinary内部使用了 io.ReadAll, 而ReadAll是会无限增长内存的 )
// 所以我们肯定要分段读, 直接用 wsutil.Reader.Read 即可, 但是每个Read前必须要有 NextFrame调用
//
//关于读 的完整过程,建议参考 ws/example.autoban.go 里的 wsHandler 函数
@@ -70,7 +70,6 @@ func (c *Conn) Read(p []byte) (int, error) {
}
if h.OpCode.IsControl() {
//log.Println("Got control frame")
//return 0, nil
// 控制帧已经在我们的 OnIntermediate 里被处理了, 直接读取下一个数据即可
return c.Read(p)
@@ -88,8 +87,7 @@ func (c *Conn) Read(p []byte) (int, error) {
OpPong OpCode = 0xa
*/
//log.Println("OpCode not Binary", h.OpCode)
return 0, utils.ErrInErr{ErrDesc: "ws OpCode not Binary", Data: h.OpCode}
return 0, utils.ErrInErr{ErrDesc: "ws OpCode not OpBinary/OpContinuation", Data: h.OpCode}
}
//log.Println("Read next frame header ok,", h.Length, c.r.State.Fragmented(), "givenbuf len", len(p))
@@ -102,9 +100,9 @@ func (c *Conn) Read(p []byte) (int, error) {
// 但是后来发现,只有 fragmented的情况下,才会处理EOF,否则还是会传递到我们这里
// 也就是说,websocket虽然一个数据帧可以超大,但是 还有一种 分片功能,而如果不分片的话,gobwas就不处理EOF
//经过实测,如果数据比较小的话,就不会分片,此时就会出现EOF; 如果数据比较大,比如 4327,就要分片
//经过实测,如果数据比较小的话,就不会分片,此时就会出现EOF; 如果数据比较大,比如 4327,某客户端就可能选择分片
//这种产生EOF的情况, gobwas/ws包的一种特性,这样可以说每一次读取都能有明确的EOF边界,便于使用 io.ReadAll
//这种产生EOF的情况, gobwas/ws包的一种特性,这样可以说每一次读取都能有明确的EOF边界,便于使用 io.ReadAll
n, e := c.r.Read(p)
//log.Println("read data result", e, n, h.Length)
@@ -169,7 +167,7 @@ func (c *Conn) ReadFrom(r io.Reader) (written int64, err error) {
if rt, ok := c.Conn.(io.ReaderFrom); ok {
return rt.ReadFrom(r)
} else {
panic("uc.underlayIsBasic, but can't cast to ReadFrom")
panic("ws.Conn underlayIsBasic, but can't cast to ReadFrom")
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ import (
)
// 2048 /3 = 682.6666 ,
// 683 * 4 = 2732
// 683 * 4 = 2732, 若你不信,运行 we_test.go中的 TestBase64Len
const MaxEarlyDataLen_Base64 = 2732
type Server struct {
+8
View File
@@ -3,6 +3,7 @@ package ws_test
import (
"bytes"
"crypto/rand"
"encoding/base64"
"net"
"testing"
@@ -10,6 +11,13 @@ import (
"github.com/hahahrfool/v2ray_simple/ws"
)
func TestBase64Len(t *testing.T) {
var arr [2048]byte
str := base64.StdEncoding.EncodeToString(arr[:])
t.Log(len(str)) //2732
//t.Log((str)) //一堆A后面跟一个等号
}
// ws基本读写功能测试.
// 分别测试写入短数据和长数据
func TestWs(t *testing.T) {