mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 09:25:41 +08:00
general: several optimizations
This commit is contained in:
parent
f65a983da8
commit
167e6e5d29
@ -71,7 +71,7 @@ we can set up local listeners as proxy servers, and forward requests to internet
|
|||||||
Binary Download:
|
Binary Download:
|
||||||
- [https://github.com/nadoo/glider/releases](https://github.com/nadoo/glider/releases)
|
- [https://github.com/nadoo/glider/releases](https://github.com/nadoo/glider/releases)
|
||||||
|
|
||||||
Build from source code (requires **Go 1.14+** ):
|
Build from source code (requires **Go 1.15+** ):
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/nadoo/glider
|
git clone https://github.com/nadoo/glider
|
||||||
cd glider && go build
|
cd glider && go build
|
||||||
|
@ -2,22 +2,25 @@ package conn
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nadoo/glider/common/pool"
|
"github.com/nadoo/glider/common/pool"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TCPBufSize is the size of tcp buffer
|
// TCPBufSize is the size of tcp buffer.
|
||||||
TCPBufSize = 16 << 10
|
TCPBufSize = 16 << 10
|
||||||
|
|
||||||
// UDPBufSize is the size of udp buffer
|
// UDPBufSize is the size of udp buffer.
|
||||||
UDPBufSize = 64 << 10
|
UDPBufSize = 64 << 10
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conn is a base conn struct
|
// Conn is a connection with buffered reader.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
r *bufio.Reader
|
r *bufio.Reader
|
||||||
net.Conn
|
net.Conn
|
||||||
@ -43,35 +46,39 @@ func (c *Conn) Reader() *bufio.Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Relay relays between left and right.
|
// Relay relays between left and right.
|
||||||
func Relay(left, right net.Conn) (int64, int64, error) {
|
func Relay(left, right net.Conn) error {
|
||||||
type res struct {
|
var err, err1 error
|
||||||
N int64
|
var wg sync.WaitGroup
|
||||||
Err error
|
var wait = 5 * time.Second
|
||||||
}
|
|
||||||
ch := make(chan res)
|
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
b := pool.GetBuffer(TCPBufSize)
|
defer wg.Done()
|
||||||
n, err := io.CopyBuffer(right, left, b)
|
_, err1 = Copy(right, left)
|
||||||
pool.PutBuffer(b)
|
right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right
|
||||||
|
|
||||||
right.SetDeadline(time.Now()) // wake up the other goroutine blocking on right
|
|
||||||
left.SetDeadline(time.Now()) // wake up the other goroutine blocking on left
|
|
||||||
ch <- res{n, err}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
b := pool.GetBuffer(TCPBufSize)
|
_, err = Copy(left, right)
|
||||||
n, err := io.CopyBuffer(left, right, b)
|
left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left
|
||||||
pool.PutBuffer(b)
|
wg.Wait()
|
||||||
|
|
||||||
right.SetDeadline(time.Now()) // wake up the other goroutine blocking on right
|
if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+
|
||||||
left.SetDeadline(time.Now()) // wake up the other goroutine blocking on left
|
return err1
|
||||||
rs := <-ch
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
err = rs.Err
|
|
||||||
}
|
}
|
||||||
return n, rs.N, err
|
|
||||||
|
if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy copies from src to dst.
|
||||||
|
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
|
||||||
|
buf := pool.GetBuffer(TCPBufSize)
|
||||||
|
defer pool.PutBuffer(buf)
|
||||||
|
|
||||||
|
return io.CopyBuffer(dst, src, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelayUDP copys from src to dst at target with read timeout.
|
// RelayUDP copys from src to dst at target with read timeout.
|
||||||
|
@ -49,20 +49,20 @@ func (s *Server) Start() {
|
|||||||
|
|
||||||
// ListenAndServeUDP listen and serves on udp port.
|
// ListenAndServeUDP listen and serves on udp port.
|
||||||
func (s *Server) ListenAndServeUDP(wg *sync.WaitGroup) {
|
func (s *Server) ListenAndServeUDP(wg *sync.WaitGroup) {
|
||||||
c, err := net.ListenPacket("udp", s.addr)
|
pc, err := net.ListenPacket("udp", s.addr)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[dns] failed to listen on %s, error: %v", s.addr, err)
|
log.F("[dns] failed to listen on %s, error: %v", s.addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer c.Close()
|
defer pc.Close()
|
||||||
|
|
||||||
log.F("[dns] listening UDP on %s", s.addr)
|
log.F("[dns] listening UDP on %s", s.addr)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
reqBytes := pool.GetBuffer(UDPMaxLen)
|
reqBytes := pool.GetBuffer(UDPMaxLen)
|
||||||
|
|
||||||
n, caddr, err := c.ReadFrom(reqBytes[2:])
|
n, caddr, err := pc.ReadFrom(reqBytes[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[dns] local read error: %v", err)
|
log.F("[dns] local read error: %v", err)
|
||||||
pool.PutBuffer(reqBytes)
|
pool.PutBuffer(reqBytes)
|
||||||
@ -77,27 +77,28 @@ func (s *Server) ListenAndServeUDP(wg *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
binary.BigEndian.PutUint16(reqBytes[:2], reqLen)
|
binary.BigEndian.PutUint16(reqBytes[:2], reqLen)
|
||||||
|
|
||||||
go func() {
|
go s.ServePacket(pc, caddr, reqBytes[:2+n])
|
||||||
respBytes, err := s.Exchange(reqBytes[:2+n], caddr.String(), false)
|
}
|
||||||
defer func() {
|
}
|
||||||
pool.PutBuffer(reqBytes)
|
|
||||||
pool.PutBuffer(respBytes)
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err != nil {
|
// ServePacket serves dns packet conn.
|
||||||
log.F("[dns] error in exchange: %s", err)
|
func (s *Server) ServePacket(pc net.PacketConn, caddr net.Addr, reqBytes []byte) {
|
||||||
return
|
respBytes, err := s.Exchange(reqBytes, caddr.String(), false)
|
||||||
}
|
defer func() {
|
||||||
|
pool.PutBuffer(reqBytes)
|
||||||
|
pool.PutBuffer(respBytes)
|
||||||
|
}()
|
||||||
|
|
||||||
_, err = c.WriteTo(respBytes[2:], caddr)
|
if err != nil {
|
||||||
if err != nil {
|
log.F("[dns] error in exchange: %s", err)
|
||||||
log.F("[dns] error in local write: %s", err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = pc.WriteTo(respBytes[2:], caddr)
|
||||||
|
if err != nil {
|
||||||
|
log.F("[dns] error in local write: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenAndServeTCP listen and serves on tcp port.
|
// ListenAndServeTCP listen and serves on tcp port.
|
||||||
@ -122,7 +123,7 @@ func (s *Server) ListenAndServeTCP(wg *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeTCP serves a tcp connection.
|
// ServeTCP serves a dns tcp connection.
|
||||||
func (s *Server) ServeTCP(c net.Conn) {
|
func (s *Server) ServeTCP(c net.Conn) {
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
|
4
go.mod
4
go.mod
@ -10,8 +10,8 @@ require (
|
|||||||
github.com/xtaci/kcp-go/v5 v5.5.15
|
github.com/xtaci/kcp-go/v5 v5.5.15
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200821140526-fda516888d29 // indirect
|
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 // indirect
|
||||||
golang.org/x/tools v0.0.0-20200822203824-307de81be3f4 // indirect
|
golang.org/x/tools v0.0.0-20200823205832-c024452afbcd // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
8
go.sum
8
go.sum
@ -117,15 +117,15 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs=
|
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs=
|
||||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200821140526-fda516888d29 h1:mNuhGagCf3lDDm5C0376C/sxh6V7fy9WbdEu/YDNA04=
|
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4=
|
||||||
golang.org/x/sys v0.0.0-20200821140526-fda516888d29/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU=
|
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU=
|
||||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200822203824-307de81be3f4 h1:r0nbB2EeRbGpnVeqxlkgiBpNi/bednpSg78qzZGOuv0=
|
golang.org/x/tools v0.0.0-20200823205832-c024452afbcd h1:KNSumuk5eGuQV7zbOrDDZ3MIkwsQr0n5oKiH4oE0/hU=
|
||||||
golang.org/x/tools v0.0.0-20200822203824-307de81be3f4/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200823205832-c024452afbcd/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
@ -102,11 +102,7 @@ func (s *HTTP) servHTTPS(r *request, c net.Conn) {
|
|||||||
|
|
||||||
log.F("[http] %s <-> %s [c] via %s", c.RemoteAddr(), r.uri, dialer.Addr())
|
log.F("[http] %s <-> %s [c] via %s", c.RemoteAddr(), r.uri, dialer.Addr())
|
||||||
|
|
||||||
_, _, err = conn.Relay(c, rc)
|
if err = conn.Relay(c, rc); err != nil {
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
||||||
return // ignore i/o timeout
|
|
||||||
}
|
|
||||||
log.F("[http] relay error: %v", err)
|
log.F("[http] relay error: %v", err)
|
||||||
s.proxy.Record(dialer, false)
|
s.proxy.Record(dialer, false)
|
||||||
}
|
}
|
||||||
|
@ -113,11 +113,7 @@ func (s *RedirProxy) Serve(c net.Conn) {
|
|||||||
|
|
||||||
log.F("[redir] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr())
|
log.F("[redir] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr())
|
||||||
|
|
||||||
_, _, err = conn.Relay(c, rc)
|
if err = conn.Relay(c, rc); err != nil {
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
||||||
return // ignore i/o timeout
|
|
||||||
}
|
|
||||||
log.F("[redir] relay error: %v", err)
|
log.F("[redir] relay error: %v", err)
|
||||||
s.proxy.Record(dialer, false)
|
s.proxy.Record(dialer, false)
|
||||||
}
|
}
|
||||||
|
@ -141,11 +141,7 @@ func (s *Socks5) Serve(c net.Conn) {
|
|||||||
|
|
||||||
log.F("[socks5] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr())
|
log.F("[socks5] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr())
|
||||||
|
|
||||||
_, _, err = conn.Relay(c, rc)
|
if err = conn.Relay(c, rc); err != nil {
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
||||||
return // ignore i/o timeout
|
|
||||||
}
|
|
||||||
log.F("[socks5] relay error: %v", err)
|
log.F("[socks5] relay error: %v", err)
|
||||||
s.proxy.Record(dialer, false)
|
s.proxy.Record(dialer, false)
|
||||||
}
|
}
|
||||||
|
@ -160,11 +160,7 @@ func (s *SS) Serve(c net.Conn) {
|
|||||||
|
|
||||||
log.F("[ss] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr())
|
log.F("[ss] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr())
|
||||||
|
|
||||||
_, _, err = conn.Relay(c, rc)
|
if err = conn.Relay(c, rc); err != nil {
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
||||||
return // ignore i/o timeout
|
|
||||||
}
|
|
||||||
log.F("[ss] relay error: %v", err)
|
log.F("[ss] relay error: %v", err)
|
||||||
s.proxy.Record(dialer, false)
|
s.proxy.Record(dialer, false)
|
||||||
}
|
}
|
||||||
|
@ -90,12 +90,8 @@ func (s *TCPTun) Serve(c net.Conn) {
|
|||||||
|
|
||||||
log.F("[tcptun] %s <-> %s via %s", c.RemoteAddr(), s.raddr, dialer.Addr())
|
log.F("[tcptun] %s <-> %s via %s", c.RemoteAddr(), s.raddr, dialer.Addr())
|
||||||
|
|
||||||
_, _, err = conn.Relay(c, rc)
|
if err = conn.Relay(c, rc); err != nil {
|
||||||
if err != nil {
|
log.F("[tcptun] relay error: %v", err)
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
||||||
return // ignore i/o timeout
|
|
||||||
}
|
|
||||||
log.F("relay error: %v", err)
|
|
||||||
s.proxy.Record(dialer, false)
|
s.proxy.Record(dialer, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,11 @@ func (s *UDPTun) ListenAndServe() {
|
|||||||
|
|
||||||
nm.Store(raddr.String(), pc)
|
nm.Store(raddr.String(), pc)
|
||||||
|
|
||||||
go func() {
|
go func(c, pc net.PacketConn, raddr net.Addr) {
|
||||||
conn.RelayUDP(c, raddr, pc, 2*time.Minute)
|
conn.RelayUDP(c, raddr, pc, 2*time.Minute)
|
||||||
pc.Close()
|
pc.Close()
|
||||||
nm.Delete(raddr.String())
|
nm.Delete(raddr.String())
|
||||||
}()
|
}(c, pc, raddr)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
pc = v.(net.PacketConn)
|
pc = v.(net.PacketConn)
|
||||||
|
@ -25,8 +25,7 @@ func (w *chunkedWriter) Write(b []byte) (n int, err error) {
|
|||||||
buf := pool.GetBuffer(lenSize + chunkSize)
|
buf := pool.GetBuffer(lenSize + chunkSize)
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBuffer(buf)
|
||||||
|
|
||||||
left := len(b)
|
for left := len(b); left != 0; {
|
||||||
for left != 0 {
|
|
||||||
writeLen := left
|
writeLen := left
|
||||||
if writeLen > chunkSize {
|
if writeLen > chunkSize {
|
||||||
writeLen = chunkSize
|
writeLen = chunkSize
|
||||||
@ -49,6 +48,7 @@ func (w *chunkedWriter) Write(b []byte) (n int, err error) {
|
|||||||
|
|
||||||
type chunkedReader struct {
|
type chunkedReader struct {
|
||||||
io.Reader
|
io.Reader
|
||||||
|
buf [lenSize]byte
|
||||||
left int
|
left int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,13 +60,11 @@ func ChunkedReader(r io.Reader) io.Reader {
|
|||||||
func (r *chunkedReader) Read(b []byte) (int, error) {
|
func (r *chunkedReader) Read(b []byte) (int, error) {
|
||||||
if r.left == 0 {
|
if r.left == 0 {
|
||||||
// get length
|
// get length
|
||||||
buf := pool.GetBuffer(lenSize)
|
_, err := io.ReadFull(r.Reader, r.buf[:lenSize])
|
||||||
_, err := io.ReadFull(r.Reader, buf[:lenSize])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
r.left = int(binary.BigEndian.Uint16(buf[:lenSize]))
|
r.left = int(binary.BigEndian.Uint16(r.buf[:lenSize]))
|
||||||
pool.PutBuffer(buf)
|
|
||||||
|
|
||||||
// if left == 0, then this is the end
|
// if left == 0, then this is the end
|
||||||
if r.left == 0 {
|
if r.left == 0 {
|
||||||
|
@ -93,7 +93,6 @@ func (c *Conn) Write(b []byte) (n int, err error) {
|
|||||||
if c.writer == nil {
|
if c.writer == nil {
|
||||||
c.writer = FrameWriter(c.Conn)
|
c.writer = FrameWriter(c.Conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.writer.Write(b)
|
return c.writer.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +100,6 @@ func (c *Conn) Read(b []byte) (n int, err error) {
|
|||||||
if c.reader == nil {
|
if c.reader == nil {
|
||||||
c.reader = FrameReader(c.Conn)
|
c.reader = FrameReader(c.Conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.reader.Read(b)
|
return c.reader.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,20 +126,17 @@ func (w *frameWriter) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
|
|
||||||
type frameReader struct {
|
type frameReader struct {
|
||||||
io.Reader
|
io.Reader
|
||||||
buf []byte
|
buf [8]byte
|
||||||
leftBytes int64
|
left int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrameReader returns a chunked reader.
|
// FrameReader returns a chunked reader.
|
||||||
func FrameReader(r io.Reader) io.Reader {
|
func FrameReader(r io.Reader) io.Reader {
|
||||||
return &frameReader{
|
return &frameReader{Reader: r}
|
||||||
Reader: r,
|
|
||||||
buf: make([]byte, maxFrameHeaderSize), // NOTE: buf only used to save header bytes now
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *frameReader) Read(b []byte) (int, error) {
|
func (r *frameReader) Read(b []byte) (int, error) {
|
||||||
if r.leftBytes == 0 {
|
if r.left == 0 {
|
||||||
// get msg header
|
// get msg header
|
||||||
_, err := io.ReadFull(r.Reader, r.buf[:2])
|
_, err := io.ReadFull(r.Reader, r.buf[:2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,26 +146,26 @@ func (r *frameReader) Read(b []byte) (int, error) {
|
|||||||
// final := r.buf[0]&finalBit != 0
|
// final := r.buf[0]&finalBit != 0
|
||||||
// frameType := int(r.buf[0] & 0xf)
|
// frameType := int(r.buf[0] & 0xf)
|
||||||
// mask := r.buf[1]&maskBit != 0
|
// mask := r.buf[1]&maskBit != 0
|
||||||
r.leftBytes = int64(r.buf[1] & 0x7f)
|
r.left = int64(r.buf[1] & 0x7f)
|
||||||
switch r.leftBytes {
|
switch r.left {
|
||||||
case 126:
|
case 126:
|
||||||
_, err := io.ReadFull(r.Reader, r.buf[:2])
|
_, err := io.ReadFull(r.Reader, r.buf[:2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
r.leftBytes = int64(binary.BigEndian.Uint16(r.buf[0:]))
|
r.left = int64(binary.BigEndian.Uint16(r.buf[:2]))
|
||||||
case 127:
|
case 127:
|
||||||
_, err := io.ReadFull(r.Reader, r.buf[:8])
|
_, err := io.ReadFull(r.Reader, r.buf[:8])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
r.leftBytes = int64(binary.BigEndian.Uint64(r.buf[0:]))
|
r.left = int64(binary.BigEndian.Uint64(r.buf[:8]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readLen := int64(len(b))
|
readLen := int64(len(b))
|
||||||
if readLen > r.leftBytes {
|
if readLen > r.left {
|
||||||
readLen = r.leftBytes
|
readLen = r.left
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := r.Reader.Read(b[:readLen])
|
m, err := r.Reader.Read(b[:readLen])
|
||||||
@ -176,6 +173,6 @@ func (r *frameReader) Read(b []byte) (int, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.leftBytes -= int64(m)
|
r.left -= int64(m)
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user