mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-07 09:41:07 +08:00
126 lines
2.6 KiB
Go
126 lines
2.6 KiB
Go
package grpcSimple
|
||
|
||
import (
|
||
"bufio"
|
||
"bytes"
|
||
"encoding/binary"
|
||
"io"
|
||
"net"
|
||
"time"
|
||
|
||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||
)
|
||
|
||
// Modified from: https://github.com/Dreamacro/clash/blob/master/transport/gun/gun.go
|
||
// License: MIT
|
||
|
||
func commonWrite(b []byte) *bytes.Buffer {
|
||
protobufHeader := [binary.MaxVarintLen64 + 1]byte{0x0A}
|
||
varuintSize := binary.PutUvarint(protobufHeader[1:], uint64(len(b)))
|
||
grpcHeader := make([]byte, 5)
|
||
grpcPayloadLen := uint32(varuintSize + 1 + len(b))
|
||
binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen)
|
||
|
||
buf := utils.GetBuf()
|
||
|
||
buf.Write(grpcHeader)
|
||
buf.Write(protobufHeader[:varuintSize+1])
|
||
buf.Write(b)
|
||
return buf
|
||
}
|
||
|
||
type commonPart struct {
|
||
remain int
|
||
br *bufio.Reader
|
||
|
||
la, ra net.Addr
|
||
}
|
||
|
||
func (c *commonPart) LocalAddr() net.Addr { return c.la }
|
||
func (c *commonPart) RemoteAddr() net.Addr { return c.ra }
|
||
|
||
func (c *commonPart) Read(b []byte) (n int, err error) {
|
||
|
||
if c.remain > 0 {
|
||
|
||
size := c.remain
|
||
if len(b) < size {
|
||
size = len(b)
|
||
}
|
||
|
||
n, err = io.ReadFull(c.br, b[:size])
|
||
c.remain -= n
|
||
return
|
||
}
|
||
|
||
_, err = c.br.Discard(6)
|
||
if err != nil {
|
||
|
||
return 0, err
|
||
}
|
||
|
||
protobufPayloadLen, err := binary.ReadUvarint(c.br)
|
||
if err != nil {
|
||
return 0, utils.ErrInErr{ErrDesc: "grpc Read, binary.ReadUvarint failed", ErrDetail: err, ExtraIs: []error{utils.ErrInvalidData}}
|
||
}
|
||
|
||
size := int(protobufPayloadLen)
|
||
if len(b) < size {
|
||
size = len(b)
|
||
}
|
||
|
||
n, err = io.ReadFull(c.br, b[:size])
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
remain := int(protobufPayloadLen) - n
|
||
if remain > 0 {
|
||
c.remain = remain
|
||
}
|
||
return n, nil
|
||
}
|
||
|
||
//timeouter 修改自 clash的gun.go, 是一种简单且不完美的deadline实现。
|
||
// clash的代码没有考虑到 设置 time.Time{} 空结构时要stop timer,我们加上了。
|
||
//
|
||
// timeouter一旦超时,就会直接关闭连接,这是无法恢复的。而且 读和写共用同一个deadline。
|
||
// 如果要求高的话,还是建议使用 netLayer.EasyDeadline.
|
||
// 但因为比较极简,所以我们保留了下来。
|
||
type timeouter struct {
|
||
deadline *time.Timer
|
||
|
||
closeFunc func()
|
||
}
|
||
|
||
func (g *timeouter) SetReadDeadline(t time.Time) error { return g.SetDeadline(t) }
|
||
func (g *timeouter) SetWriteDeadline(t time.Time) error { return g.SetDeadline(t) }
|
||
|
||
func (g *timeouter) SetDeadline(t time.Time) error {
|
||
|
||
var d time.Duration
|
||
|
||
if g.deadline != nil {
|
||
|
||
if t == (time.Time{}) {
|
||
g.deadline.Stop()
|
||
g.deadline = nil
|
||
return nil
|
||
}
|
||
|
||
d = time.Until(t)
|
||
g.deadline.Reset(d)
|
||
|
||
} else {
|
||
if t == (time.Time{}) {
|
||
return nil
|
||
}
|
||
|
||
d = time.Until(t)
|
||
g.deadline = time.AfterFunc(d, g.closeFunc)
|
||
}
|
||
|
||
return nil
|
||
|
||
}
|