mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-07 09:41:07 +08:00

grpcSimple包的服务端和客户端现在都已完成,且兼容v2ray等内核。 grpcSimple包 简洁、高效,更加科学。暂不支持multiMode。 若 grpc_full 给出,则使用grpc包,否则默认使用 grpcSimple包。 若 noquic给出,则不使用 quic,否则 默认使用 quic。 修复 ws early 失效问题;
170 lines
3.0 KiB
Go
170 lines
3.0 KiB
Go
package grpcSimple
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/binary"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"sync"
|
|
|
|
"github.com/e1732a364fed/v2ray_simple/utils"
|
|
"go.uber.org/zap"
|
|
"golang.org/x/net/http2"
|
|
)
|
|
|
|
type Server struct {
|
|
Config
|
|
|
|
http2.Server
|
|
|
|
path string
|
|
}
|
|
|
|
func (s *Server) GetPath() string {
|
|
return s.ServiceName
|
|
}
|
|
|
|
func (*Server) IsMux() bool {
|
|
return true
|
|
}
|
|
|
|
func (*Server) IsSuper() bool {
|
|
return false
|
|
}
|
|
func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn) {
|
|
go s.Server.ServeConn(underlay, &http2.ServeConnOpts{
|
|
Handler: http.HandlerFunc(func(rw http.ResponseWriter, rq *http.Request) {
|
|
|
|
//log.Println("request headers", rq.Header)
|
|
|
|
//TODO: support fallback
|
|
|
|
if rq.URL.Path != s.path {
|
|
if ce := utils.CanLogWarn("grpc Server got wrong path"); ce != nil {
|
|
ce.Write(zap.String("path", rq.URL.Path))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if ct := rq.Header.Get("Content-Type"); ct != "application/grpc" {
|
|
if ce := utils.CanLogWarn("GRPC Server got wrong Content-Type"); ce != nil {
|
|
ce.Write(zap.String("type", ct))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
//https://dzone.com/articles/learning-about-the-headers-used-for-grpc-over-http
|
|
|
|
headerMap := rw.Header()
|
|
headerMap.Add("Content-Type", "application/grpc") //necessary
|
|
rw.WriteHeader(http.StatusOK)
|
|
|
|
cc := make(chan int)
|
|
sc := &ServerConn{
|
|
br: bufio.NewReader(rq.Body),
|
|
Writer: rw,
|
|
Closer: rq.Body,
|
|
closeChan: cc,
|
|
}
|
|
|
|
sc.timeouter = timeouter{
|
|
closeFunc: func() {
|
|
sc.Close()
|
|
},
|
|
}
|
|
newSubConnChan <- sc
|
|
<-cc //necessary
|
|
}),
|
|
})
|
|
}
|
|
|
|
type ServerConn struct {
|
|
io.Closer
|
|
io.Writer
|
|
|
|
remain int
|
|
br *bufio.Reader
|
|
|
|
once sync.Once
|
|
closeChan chan int
|
|
|
|
timeouter
|
|
}
|
|
|
|
func (g *ServerConn) Close() error {
|
|
g.once.Do(func() {
|
|
close(g.closeChan)
|
|
g.Closer.Close()
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (g *ServerConn) Read(b []byte) (n int, err error) {
|
|
|
|
if g.remain > 0 {
|
|
|
|
size := g.remain
|
|
if len(b) < size {
|
|
size = len(b)
|
|
}
|
|
|
|
n, err = io.ReadFull(g.br, b[:size])
|
|
g.remain -= n
|
|
return
|
|
}
|
|
|
|
_, err = g.br.Discard(6)
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
}
|
|
|
|
protobufPayloadLen, err := binary.ReadUvarint(g.br)
|
|
if err != nil {
|
|
return 0, ErrInvalidLength
|
|
}
|
|
|
|
size := int(protobufPayloadLen)
|
|
if len(b) < size {
|
|
size = len(b)
|
|
}
|
|
|
|
n, err = io.ReadFull(g.br, b[:size])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
remain := int(protobufPayloadLen) - n
|
|
if remain > 0 {
|
|
g.remain = remain
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func (g *ServerConn) Write(b []byte) (n int, err error) {
|
|
|
|
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()
|
|
defer utils.PutBuf(buf)
|
|
buf.Write(grpcHeader)
|
|
buf.Write(protobufHeader[:varuintSize+1])
|
|
buf.Write(b)
|
|
|
|
_, err = g.Writer.Write(buf.Bytes())
|
|
|
|
if err == nil {
|
|
g.Writer.(http.Flusher).Flush() //necessary
|
|
|
|
}
|
|
|
|
return len(b), err
|
|
}
|