glider/proxy/conn.go

207 lines
4.1 KiB
Go
Raw Permalink Normal View History

2020-10-01 22:38:34 +08:00
package proxy
2017-07-13 21:55:41 +08:00
import (
"bufio"
2020-08-25 22:14:08 +08:00
"errors"
2017-07-13 21:55:41 +08:00
"io"
"net"
2020-08-25 22:14:08 +08:00
"os"
"runtime"
2020-08-25 22:14:08 +08:00
"sync"
2017-07-13 21:55:41 +08:00
"time"
2020-04-19 17:03:39 +08:00
"github.com/nadoo/glider/pkg/pool"
2017-07-13 21:55:41 +08:00
)
var (
2020-08-25 22:14:08 +08:00
// TCPBufSize is the size of tcp buffer.
TCPBufSize = 32 << 10
2020-04-19 17:03:39 +08:00
2020-08-25 22:14:08 +08:00
// UDPBufSize is the size of udp buffer.
UDPBufSize = 2 << 10
2020-04-19 17:03:39 +08:00
)
2020-08-25 22:14:08 +08:00
// Conn is a connection with buffered reader.
type Conn struct {
2017-07-13 21:55:41 +08:00
r *bufio.Reader
net.Conn
}
// NewConn returns a new conn.
2018-12-14 00:02:25 +08:00
func NewConn(c net.Conn) *Conn {
2020-10-11 18:46:15 +08:00
if conn, ok := c.(*Conn); ok {
return conn
}
2020-11-03 22:52:50 +08:00
return &Conn{pool.GetBufReader(c), c}
2017-07-13 21:55:41 +08:00
}
// Reader returns the internal bufio.Reader.
2020-10-26 21:43:56 +08:00
func (c *Conn) Reader() *bufio.Reader { return c.r }
func (c *Conn) Read(p []byte) (int, error) { return c.r.Read(p) }
// Peek returns the next n bytes without advancing the reader.
2020-10-26 21:43:56 +08:00
func (c *Conn) Peek(n int) ([]byte, error) { return c.r.Peek(n) }
// WriteTo implements io.WriterTo.
func (c *Conn) WriteTo(w io.Writer) (n int64, err error) { return c.r.WriteTo(w) }
2018-12-14 00:02:25 +08:00
// Close closes the Conn.
func (c *Conn) Close() error {
pool.PutBufReader(c.r)
return c.Conn.Close()
}
// Relay relays between left and right.
2020-08-25 22:14:08 +08:00
func Relay(left, right net.Conn) error {
var err, err1 error
var wg sync.WaitGroup
var wait = 5 * time.Second
2017-07-13 21:55:41 +08:00
2020-08-25 22:14:08 +08:00
wg.Add(1)
2017-07-13 21:55:41 +08:00
go func() {
2020-08-25 22:14:08 +08:00
defer wg.Done()
_, err1 = Copy(right, left)
right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right
2017-07-13 21:55:41 +08:00
}()
2020-08-25 22:14:08 +08:00
_, err = Copy(left, right)
left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left
wg.Wait()
2020-04-19 17:03:39 +08:00
if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) {
2020-08-25 22:14:08 +08:00
return err1
}
2017-07-13 21:55:41 +08:00
2020-08-25 22:14:08 +08:00
if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
return err
2017-07-13 21:55:41 +08:00
}
2020-08-25 22:14:08 +08:00
return nil
}
2020-10-26 21:43:56 +08:00
// Copy copies from src to dst.
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
dst = underlyingWriter(dst)
switch runtime.GOOS {
case "linux", "windows", "dragonfly", "freebsd", "solaris":
if _, ok := dst.(*net.TCPConn); ok && worthTry(src) {
if wt, ok := src.(io.WriterTo); ok {
return wt.WriteTo(dst)
}
if rt, ok := dst.(io.ReaderFrom); ok {
return rt.ReadFrom(src)
}
}
}
return CopyBuffer(dst, src)
}
func underlyingWriter(c io.Writer) io.Writer {
if wrap, ok := c.(*Conn); ok {
return wrap.Conn
}
return c
}
func worthTry(src io.Reader) bool {
2020-09-03 00:12:00 +08:00
switch v := src.(type) {
case *net.TCPConn, *net.UnixConn:
2020-09-03 00:12:00 +08:00
return true
case *io.LimitedReader:
return worthTry(v.R)
case *Conn:
return worthTry(v.Conn)
2020-09-03 00:12:00 +08:00
case *os.File:
fi, err := v.Stat()
if err != nil {
return false
}
return fi.Mode().IsRegular()
default:
return false
}
}
2020-10-01 21:33:59 +08:00
// CopyN copies n bytes (or until an error) from src to dst.
func CopyN(dst io.Writer, src io.Reader, n int64) (written int64, err error) {
written, err = Copy(dst, io.LimitReader(src, n))
if written == n {
return n, nil
}
if written < n && err == nil {
// src stopped early; must have been EOF.
err = io.EOF
}
return
}
2020-09-03 00:12:00 +08:00
// CopyBuffer copies from src to dst with a userspace buffer.
func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
size := TCPBufSize
if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N {
if l.N < 1 {
size = 1
} else {
size = int(l.N)
}
}
buf := pool.GetBuffer(size)
2020-08-25 22:14:08 +08:00
defer pool.PutBuffer(buf)
2020-09-03 00:12:00 +08:00
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw > 0 {
written += int64(nw)
}
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
}
}
return written, err
2017-07-13 21:55:41 +08:00
}
2018-01-08 18:14:57 +08:00
// CopyUDP copys from src to dst at target with read timeout.
// if step sets to non-zero value,
// the read timeout will be increased from 0 to timeout by step in every read operation.
2022-03-06 12:58:20 +08:00
func CopyUDP(dst net.PacketConn, writeTo net.Addr, src net.PacketConn, timeout time.Duration, step time.Duration) error {
buf := pool.GetBuffer(UDPBufSize)
defer pool.PutBuffer(buf)
2020-04-19 17:03:39 +08:00
var t time.Duration
2018-01-08 18:14:57 +08:00
for {
if t += step; t == 0 || t > timeout {
t = timeout
}
src.SetReadDeadline(time.Now().Add(t))
2022-03-06 12:58:20 +08:00
n, addr, err := src.ReadFrom(buf)
2018-01-08 18:14:57 +08:00
if err != nil {
return err
}
2022-03-06 12:58:20 +08:00
if writeTo != nil {
addr = writeTo
}
_, err = dst.WriteTo(buf[:n], addr)
2018-01-08 18:14:57 +08:00
if err != nil {
return err
}
}
}