Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,21 @@ jobs:
goarch: amd64
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version: ^1.25
- name: Cache go module
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: |
~/go/pkg/mod
key: go-${{ hashFiles('**/go.sum') }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v8
uses: golangci/golangci-lint-action@v9
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ jobs:
os-name: Windows
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version: ${{ matrix.go-version }}
- name: Build
Expand Down
41 changes: 23 additions & 18 deletions common/bufio/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bufio

import (
"net"
"sync"

"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
Expand Down Expand Up @@ -59,10 +60,8 @@ func (c *bindPacketConn) Upstream() any {
}

var (
_ N.NetPacketConn = (*UnbindPacketConn)(nil)
_ N.PacketReadWaitCreator = (*UnbindPacketConn)(nil)
_ N.ConnectedPacketBatchReadWaitCreator = (*UnbindPacketConn)(nil)
_ N.ConnectedPacketBatchWriteCreator = (*UnbindPacketConn)(nil)
_ N.NetPacketConn = (*UnbindPacketConn)(nil)
_ N.PacketReadWaitCreator = (*UnbindPacketConn)(nil)
)

type UnbindPacketConn struct {
Expand Down Expand Up @@ -117,14 +116,6 @@ func (c *UnbindPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) {
return &unbindPacketReadWaiter{readWaiter, c.addr}, true
}

func (c *UnbindPacketConn) CreateConnectedPacketBatchReadWaiter() (N.ConnectedPacketBatchReadWaiter, bool) {
return createSyscallConnectedPacketBatchReadWaiter(c.ExtendedConn, c.addr)
}

func (c *UnbindPacketConn) CreateConnectedPacketBatchWriter() (N.ConnectedPacketBatchWriter, bool) {
return createSyscallConnectedPacketBatchWriter(c.ExtendedConn)
}

func (c *UnbindPacketConn) Upstream() any {
return c.ExtendedConn
}
Expand All @@ -137,15 +128,16 @@ func NewServerPacketConn(conn net.PacketConn) N.ExtendedConn {

type serverPacketConn struct {
N.NetPacketConn
remoteAddr M.Socksaddr
remoteAccess sync.RWMutex
remoteAddr M.Socksaddr
}

func (c *serverPacketConn) Read(p []byte) (n int, err error) {
n, addr, err := c.NetPacketConn.ReadFrom(p)
if err != nil {
return
}
c.remoteAddr = M.SocksaddrFromNet(addr)
c.updateRemoteAddr(M.SocksaddrFromNet(addr).Unwrap())
return
}

Expand All @@ -154,20 +146,33 @@ func (c *serverPacketConn) ReadBuffer(buffer *buf.Buffer) error {
if err != nil {
return err
}
c.remoteAddr = destination
c.updateRemoteAddr(destination)
return nil
}

func (c *serverPacketConn) Write(p []byte) (n int, err error) {
return c.NetPacketConn.WriteTo(p, c.remoteAddr.UDPAddr())
return c.NetPacketConn.WriteTo(p, c.remoteDestination().UDPAddr())
}

func (c *serverPacketConn) WriteBuffer(buffer *buf.Buffer) error {
return c.NetPacketConn.WritePacket(buffer, c.remoteAddr)
return c.NetPacketConn.WritePacket(buffer, c.remoteDestination())
}

func (c *serverPacketConn) RemoteAddr() net.Addr {
return c.remoteAddr
return c.remoteDestination()
}

func (c *serverPacketConn) updateRemoteAddr(destination M.Socksaddr) {
c.remoteAccess.Lock()
c.remoteAddr = destination
c.remoteAccess.Unlock()
}

func (c *serverPacketConn) remoteDestination() M.Socksaddr {
c.remoteAccess.RLock()
destination := c.remoteAddr
c.remoteAccess.RUnlock()
return destination
}

func (c *serverPacketConn) Upstream() any {
Expand Down
139 changes: 139 additions & 0 deletions common/bufio/bind_batch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package bufio

import (
"sync"

"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)

func (c *UnbindPacketConn) CreateConnectedPacketBatchWriter() (N.ConnectedPacketBatchWriter, bool) {
var packetWriter N.PacketWriter
var destination func() M.Socksaddr
upstream := N.UnwrapWriter(c.ExtendedConn)
switch conn := upstream.(type) {
case *bindPacketConn:
packetWriter = conn.NetPacketConn
address := M.SocksaddrFromNet(conn.addr).Unwrap()
destination = func() M.Socksaddr { return address }
case *serverPacketConn:
packetWriter = conn.NetPacketConn
destination = conn.remoteDestination
default:
return createSyscallConnectedPacketBatchWriter(c.ExtendedConn)
}
writer, created := CreatePacketBatchWriter(packetWriter)
if !created {
return nil, false
}
return &boundConnectedPacketBatchWriter{writer: writer, destination: destination}, true
}

func (c *serverPacketConn) CreatePacketBatchWriter() (N.PacketBatchWriter, bool) {
return CreatePacketBatchWriter(c.NetPacketConn)
}

type boundConnectedPacketBatchWriter struct {
writer N.PacketBatchWriter
destination func() M.Socksaddr
access sync.Mutex
destinations []M.Socksaddr
}

func (w *boundConnectedPacketBatchWriter) WriteConnectedPacketBatch(buffers []*buf.Buffer) error {
count := 0
for _, buffer := range buffers {
if buffer.IsEmpty() {
buffer.Release()
continue
}
buffers[count] = buffer
count++
}
clear(buffers[count:])
if count == 0 {
return nil
}
buffers = buffers[:count]
w.access.Lock()
defer w.access.Unlock()
if cap(w.destinations) < len(buffers) {
w.destinations = make([]M.Socksaddr, len(buffers))
} else {
w.destinations = w.destinations[:len(buffers)]
}
destination := w.destination()
for index := range w.destinations {
w.destinations[index] = destination
}
return w.writer.WritePacketBatch(buffers, w.destinations)
}

func (w *boundConnectedPacketBatchWriter) Upstream() any { return w.writer }

func (c *UnbindPacketConn) CreateConnectedPacketBatchReadWaiter() (N.ConnectedPacketBatchReadWaiter, bool) {
upstream := N.UnwrapReader(c.ExtendedConn)
switch conn := upstream.(type) {
case *bindPacketConn:
reader, created := CreatePacketBatchReadWaiter(conn.NetPacketConn)
if !created {
return nil, false
}
return &bindConnectedPacketBatchReadWaiter{reader: reader, destination: c.addr}, true
case *serverPacketConn:
reader, created := CreatePacketBatchReadWaiter(conn.NetPacketConn)
if !created {
return nil, false
}
return &serverConnectedPacketBatchReadWaiter{conn: conn, reader: reader, destination: c.addr}, true
default:
return createSyscallConnectedPacketBatchReadWaiter(c.ExtendedConn, c.addr)
}
}

type bindConnectedPacketBatchReadWaiter struct {
reader N.PacketBatchReadWaiter
destination M.Socksaddr
}

func (r *bindConnectedPacketBatchReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) bool {
return r.reader.InitializeReadWaiter(options)
}

func (r *bindConnectedPacketBatchReadWaiter) WaitReadConnectedPackets() ([]*buf.Buffer, M.Socksaddr, error) {
buffers, _, err := r.reader.WaitReadPackets()
return buffers, r.destination, err
}

func (r *bindConnectedPacketBatchReadWaiter) Upstream() any { return r.reader }

type serverConnectedPacketBatchReadWaiter struct {
conn *serverPacketConn
reader N.PacketBatchReadWaiter
destination M.Socksaddr
}

func (r *serverConnectedPacketBatchReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) bool {
return r.reader.InitializeReadWaiter(options)
}

func (r *serverConnectedPacketBatchReadWaiter) WaitReadConnectedPackets() ([]*buf.Buffer, M.Socksaddr, error) {
buffers, destinations, err := r.reader.WaitReadPackets()
if err == nil {
r.conn.updateRemoteAddr(destinations[len(destinations)-1])
}
return buffers, r.destination, err
}

func (r *serverConnectedPacketBatchReadWaiter) Upstream() any { return r.reader }

var (
_ N.PacketBatchReadWaitCreator = (*serverPacketConn)(nil)
_ N.ConnectedPacketBatchWriteCreator = (*UnbindPacketConn)(nil)
_ N.ConnectedPacketBatchReadWaitCreator = (*UnbindPacketConn)(nil)
_ N.PacketBatchWriteCreator = (*serverPacketConn)(nil)
_ N.ConnectedPacketBatchWriter = (*boundConnectedPacketBatchWriter)(nil)
_ N.ConnectedPacketBatchReadWaiter = (*bindConnectedPacketBatchReadWaiter)(nil)
_ N.ConnectedPacketBatchReadWaiter = (*serverConnectedPacketBatchReadWaiter)(nil)
)
2 changes: 1 addition & 1 deletion common/bufio/bind_wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ func (w *serverPacketReadWaiter) WaitReadBuffer() (buffer *buf.Buffer, err error
if err != nil {
return
}
w.remoteAddr = destination
w.updateRemoteAddr(destination)
return
}
22 changes: 10 additions & 12 deletions common/bufio/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,12 @@ func NewCachedPacketConn(conn N.PacketConn, buffer *buf.Buffer, destination M.So
}

func (c *CachedPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
if c.buffer != nil {
_, err = buffer.ReadOnceFrom(c.buffer)
if err != nil {
return M.Socksaddr{}, err
}
c.buffer.DecRef()
c.buffer.Release()
c.buffer = nil
return c.destination, nil
packet := c.ReadCachedPacket()
if packet != nil {
defer packet.Buffer.Release()
defer N.PutPacketBuffer(packet)
_, err = buffer.Write(packet.Buffer.Bytes())
return packet.Destination, err
}
return c.PacketConn.ReadPacket(buffer)
}
Expand All @@ -198,9 +195,10 @@ func (c *CachedPacketConn) ReadCachedPacket() *N.PacketBuffer {
}
buffer := c.buffer
c.buffer = nil
if buffer != nil {
buffer.DecRef()
if buffer == nil {
return nil
}
buffer.DecRef()
packet := N.NewPacketBuffer()
*packet = N.PacketBuffer{
Buffer: buffer,
Expand All @@ -214,7 +212,7 @@ func (c *CachedPacketConn) Upstream() any {
}

func (c *CachedPacketConn) ReaderReplaceable() bool {
return c.buffer == nil
return c.taken.Load()
}

func (c *CachedPacketConn) WriterReplaceable() bool {
Expand Down
24 changes: 2 additions & 22 deletions common/bufio/copy_direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package bufio
import (
"errors"
"io"
"os"

"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
Expand Down Expand Up @@ -140,10 +139,6 @@ func copyPacketBatchWaitWithPool(session *packetCopySession, destinationConn N.P
if err != nil {
return handled, n, err
}
if len(buffers) == 0 || len(buffers) != len(destinations) {
buf.ReleaseMulti(buffers)
return handled, n, os.ErrInvalid
}
dataLens := make([]int, len(buffers))
for index, buffer := range buffers {
dataLens[index] = buffer.Len()
Expand Down Expand Up @@ -171,18 +166,11 @@ func copyPacketBatchWaitWithPool(session *packetCopySession, destinationConn N.P
func copyPacketBatchToConnectedWaitWithPool(session *packetCopySession, destinationConn N.ConnectedPacketBatchWriter, source N.PacketBatchReadWaiter, notFirstTime bool) (handled bool, n int64, err error) {
handled = true
for {
var (
buffers []*buf.Buffer
destinations []M.Socksaddr
)
buffers, destinations, err = source.WaitReadPackets()
var buffers []*buf.Buffer
buffers, _, err = source.WaitReadPackets()
if err != nil {
return handled, n, err
}
if len(buffers) == 0 || len(buffers) != len(destinations) {
buf.ReleaseMulti(buffers)
return handled, n, os.ErrInvalid
}
dataLens := make([]int, len(buffers))
for index, buffer := range buffers {
dataLens[index] = buffer.Len()
Expand Down Expand Up @@ -218,10 +206,6 @@ func copyConnectedPacketBatchWaitWithPool(session *packetCopySession, destinatio
if err != nil {
return handled, n, err
}
if len(buffers) == 0 {
buf.ReleaseMulti(buffers)
return handled, n, os.ErrInvalid
}
destinations := make([]M.Socksaddr, len(buffers))
dataLens := make([]int, len(buffers))
for index, buffer := range buffers {
Expand Down Expand Up @@ -256,10 +240,6 @@ func copyConnectedPacketBatchToConnectedWaitWithPool(session *packetCopySession,
if err != nil {
return handled, n, err
}
if len(buffers) == 0 {
buf.ReleaseMulti(buffers)
return handled, n, os.ErrInvalid
}
dataLens := make([]int, len(buffers))
for index, buffer := range buffers {
dataLens[index] = buffer.Len()
Expand Down
Loading
Loading