remove context in struct

pull/861/head
Darien Raymond 2018-02-08 15:39:46 +01:00
parent a1ae4aa515
commit efcb567273
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
44 changed files with 379 additions and 270 deletions

View File

@ -72,7 +72,7 @@ func (c *Commander) Start() error {
return nil return nil
} }
func (c *Commander) Close() { func (c *Commander) Close() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
@ -80,6 +80,8 @@ func (c *Commander) Close() {
c.server.Stop() c.server.Stop()
c.server = nil c.server = nil
} }
return nil
} }
func init() { func init() {

View File

@ -3,6 +3,7 @@ package commander
import ( import (
"context" "context"
"net" "net"
"sync"
"v2ray.com/core/common/signal" "v2ray.com/core/common/signal"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
@ -43,12 +44,24 @@ func (l *OutboundListener) Addr() net.Addr {
type CommanderOutbound struct { type CommanderOutbound struct {
tag string tag string
listener *OutboundListener listener *OutboundListener
access sync.RWMutex
closed bool
} }
func (co *CommanderOutbound) Dispatch(ctx context.Context, r ray.OutboundRay) { func (co *CommanderOutbound) Dispatch(ctx context.Context, r ray.OutboundRay) {
co.access.RLock()
if co.closed {
r.OutboundInput().CloseError()
r.OutboundOutput().CloseError()
co.access.RUnlock()
return
}
closeSignal := signal.NewNotifier() closeSignal := signal.NewNotifier()
c := ray.NewConnection(r.OutboundInput(), r.OutboundOutput(), ray.ConnCloseSignal(closeSignal)) c := ray.NewConnection(r.OutboundInput(), r.OutboundOutput(), ray.ConnCloseSignal(closeSignal))
co.listener.add(c) co.listener.add(c)
co.access.RUnlock()
<-closeSignal.Wait() <-closeSignal.Wait()
return return
@ -59,7 +72,17 @@ func (co *CommanderOutbound) Tag() string {
} }
func (co *CommanderOutbound) Start() error { func (co *CommanderOutbound) Start() error {
co.access.Lock()
co.closed = false
co.access.Unlock()
return nil return nil
} }
func (co *CommanderOutbound) Close() {} func (co *CommanderOutbound) Close() error {
co.access.Lock()
co.closed = true
co.listener.Close()
co.access.Unlock()
return nil
}

View File

@ -49,7 +49,7 @@ func (*DefaultDispatcher) Start() error {
} }
// Close implements app.Application. // Close implements app.Application.
func (*DefaultDispatcher) Close() {} func (*DefaultDispatcher) Close() error { return nil }
// Dispatch implements core.Dispatcher. // Dispatch implements core.Dispatcher.
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (ray.InboundRay, error) { func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (ray.InboundRay, error) {

View File

@ -83,7 +83,8 @@ func (s *Server) Start() error {
return nil return nil
} }
func (*Server) Close() { func (*Server) Close() error {
return nil
} }
func (s *Server) GetCached(domain string) []net.IP { func (s *Server) GetCached(domain string) []net.IP {

View File

@ -103,11 +103,13 @@ func (g *Instance) Handle(msg log.Message) {
} }
// Close implement app.Application.Close(). // Close implement app.Application.Close().
func (g *Instance) Close() { func (g *Instance) Close() error {
g.Lock() g.Lock()
defer g.Unlock() defer g.Unlock()
g.active = false g.active = false
return nil
} }
func init() { func init() {

View File

@ -51,7 +51,8 @@ func (m *Instance) Start() error {
} }
// Close implements app.Application.Close(). // Close implements app.Application.Close().
func (m *Instance) Close() { func (m *Instance) Close() error {
return nil
} }
func init() { func init() {

View File

@ -119,7 +119,9 @@ func (*feature) Start() error {
return nil return nil
} }
func (*feature) Close() {} func (*feature) Close() error {
return nil
}
func init() { func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {

View File

@ -76,10 +76,11 @@ func (h *AlwaysOnInboundHandler) Start() error {
return nil return nil
} }
func (h *AlwaysOnInboundHandler) Close() { func (h *AlwaysOnInboundHandler) Close() error {
for _, worker := range h.workers { for _, worker := range h.workers {
worker.Close() worker.Close()
} }
return nil
} }
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) { func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {

View File

@ -5,17 +5,18 @@ import (
"sync" "sync"
"time" "time"
"v2ray.com/core"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/app/proxyman/mux" "v2ray.com/core/app/proxyman/mux"
"v2ray.com/core/common/dice" "v2ray.com/core/common/dice"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/signal"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
) )
type DynamicInboundHandler struct { type DynamicInboundHandler struct {
tag string tag string
ctx context.Context v *core.Instance
cancel context.CancelFunc
proxyConfig interface{} proxyConfig interface{}
receiverConfig *proxyman.ReceiverConfig receiverConfig *proxyman.ReceiverConfig
portMutex sync.Mutex portMutex sync.Mutex
@ -24,18 +25,26 @@ type DynamicInboundHandler struct {
worker []worker worker []worker
lastRefresh time.Time lastRefresh time.Time
mux *mux.Server mux *mux.Server
task *signal.PeriodicTask
} }
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) { func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
ctx, cancel := context.WithCancel(ctx) v := core.FromContext(ctx)
if v == nil {
return nil, newError("V is not in context.")
}
h := &DynamicInboundHandler{ h := &DynamicInboundHandler{
ctx: ctx,
tag: tag, tag: tag,
cancel: cancel,
proxyConfig: proxyConfig, proxyConfig: proxyConfig,
receiverConfig: receiverConfig, receiverConfig: receiverConfig,
portsInUse: make(map[net.Port]bool), portsInUse: make(map[net.Port]bool),
mux: mux.NewServer(ctx), mux: mux.NewServer(ctx),
v: v,
}
h.task = &signal.PeriodicTask{
Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
Execute: h.refresh,
} }
return h, nil return h, nil
@ -59,9 +68,7 @@ func (h *DynamicInboundHandler) allocatePort() net.Port {
} }
} }
func (h *DynamicInboundHandler) waitAnyCloseWorkers(ctx context.Context, cancel context.CancelFunc, workers []worker, duration time.Duration) { func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
time.Sleep(duration)
cancel()
ports2Del := make([]net.Port, len(workers)) ports2Del := make([]net.Port, len(workers))
for idx, worker := range workers { for idx, worker := range workers {
ports2Del[idx] = worker.Port() ports2Del[idx] = worker.Port()
@ -80,7 +87,6 @@ func (h *DynamicInboundHandler) refresh() error {
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2 timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue() concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
ctx, cancel := context.WithTimeout(h.ctx, timeout)
workers := make([]worker, 0, concurrency) workers := make([]worker, 0, concurrency)
address := h.receiverConfig.Listen.AsAddress() address := h.receiverConfig.Listen.AsAddress()
@ -89,11 +95,12 @@ func (h *DynamicInboundHandler) refresh() error {
} }
for i := uint32(0); i < concurrency; i++ { for i := uint32(0); i < concurrency; i++ {
port := h.allocatePort() port := h.allocatePort()
p, err := proxy.CreateInboundHandler(ctx, h.proxyConfig) rawProxy, err := h.v.CreateObject(h.proxyConfig)
if err != nil { if err != nil {
newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog() newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog()
continue continue
} }
p := rawProxy.(proxy.Inbound)
nl := p.Network() nl := p.Network()
if nl.HasNetwork(net.Network_TCP) { if nl.HasNetwork(net.Network_TCP) {
worker := &tcpWorker{ worker := &tcpWorker{
@ -134,33 +141,19 @@ func (h *DynamicInboundHandler) refresh() error {
h.worker = workers h.worker = workers
h.workerMutex.Unlock() h.workerMutex.Unlock()
go h.waitAnyCloseWorkers(ctx, cancel, workers, timeout) time.AfterFunc(timeout, func() {
h.closeWorkers(workers)
})
return nil return nil
} }
func (h *DynamicInboundHandler) monitor() {
timer := time.NewTicker(time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()))
defer timer.Stop()
for {
select {
case <-h.ctx.Done():
return
case <-timer.C:
h.refresh()
}
}
}
func (h *DynamicInboundHandler) Start() error { func (h *DynamicInboundHandler) Start() error {
err := h.refresh() return h.task.Start()
go h.monitor()
return err
} }
func (h *DynamicInboundHandler) Close() { func (h *DynamicInboundHandler) Close() error {
h.cancel() return h.task.Close()
} }
func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) { func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {

View File

@ -99,7 +99,7 @@ func (m *Manager) Start() error {
return nil return nil
} }
func (m *Manager) Close() { func (m *Manager) Close() error {
m.access.Lock() m.access.Lock()
defer m.access.Unlock() defer m.access.Unlock()
@ -111,6 +111,8 @@ func (m *Manager) Close() {
for _, handler := range m.untaggedHandler { for _, handler := range m.untaggedHandler {
handler.Close() handler.Close()
} }
return nil
} }
func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (core.InboundHandler, error) { func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (core.InboundHandler, error) {

View File

@ -9,8 +9,10 @@ import (
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/signal"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tcp" "v2ray.com/core/transport/internet/tcp"
@ -19,7 +21,7 @@ import (
type worker interface { type worker interface {
Start() error Start() error
Close() Close() error
Port() net.Port Port() net.Port
Proxy() proxy.Inbound Proxy() proxy.Inbound
} }
@ -34,13 +36,11 @@ type tcpWorker struct {
dispatcher core.Dispatcher dispatcher core.Dispatcher
sniffers []proxyman.KnownProtocols sniffers []proxyman.KnownProtocols
ctx context.Context hub internet.Listener
cancel context.CancelFunc
hub internet.Listener
} }
func (w *tcpWorker) callback(conn internet.Connection) { func (w *tcpWorker) callback(conn internet.Connection) {
ctx, cancel := context.WithCancel(w.ctx) ctx, cancel := context.WithCancel(context.Background())
if w.recvOrigDest { if w.recvOrigDest {
dest, err := tcp.GetOriginalDestination(conn) dest, err := tcp.GetOriginalDestination(conn)
if err != nil { if err != nil {
@ -70,45 +70,24 @@ func (w *tcpWorker) Proxy() proxy.Inbound {
} }
func (w *tcpWorker) Start() error { func (w *tcpWorker) Start() error {
ctx, cancel := context.WithCancel(context.Background()) ctx := internet.ContextWithStreamSettings(context.Background(), w.stream)
w.ctx = ctx hub, err := internet.ListenTCP(ctx, w.address, w.port, func(conn internet.Connection) {
w.cancel = cancel go w.callback(conn)
ctx = internet.ContextWithStreamSettings(ctx, w.stream) })
conns := make(chan internet.Connection, 16)
hub, err := internet.ListenTCP(ctx, w.address, w.port, conns)
if err != nil { if err != nil {
return newError("failed to listen TCP on ", w.port).AtWarning().Base(err) return newError("failed to listen TCP on ", w.port).AtWarning().Base(err)
} }
go w.handleConnections(conns)
w.hub = hub w.hub = hub
return nil return nil
} }
func (w *tcpWorker) handleConnections(conns <-chan internet.Connection) { func (w *tcpWorker) Close() error {
for {
select {
case <-w.ctx.Done():
w.hub.Close()
L:
for {
select {
case conn := <-conns:
conn.Close()
default:
break L
}
}
return
case conn := <-conns:
go w.callback(conn)
}
}
}
func (w *tcpWorker) Close() {
if w.hub != nil { if w.hub != nil {
w.cancel() common.Close(w.hub)
common.Close(w.proxy)
} }
return nil
} }
func (w *tcpWorker) Port() net.Port { func (w *tcpWorker) Port() net.Port {
@ -121,8 +100,7 @@ type udpConn struct {
output func([]byte) (int, error) output func([]byte) (int, error)
remote net.Addr remote net.Addr
local net.Addr local net.Addr
ctx context.Context done *signal.Done
cancel context.CancelFunc
} }
func (c *udpConn) updateActivity() { func (c *udpConn) updateActivity() {
@ -135,7 +113,7 @@ func (c *udpConn) Read(buf []byte) (int, error) {
defer in.Release() defer in.Release()
c.updateActivity() c.updateActivity()
return copy(buf, in.Bytes()), nil return copy(buf, in.Bytes()), nil
case <-c.ctx.Done(): case <-c.done.C():
return 0, io.EOF return 0, io.EOF
} }
} }
@ -150,6 +128,7 @@ func (c *udpConn) Write(buf []byte) (int, error) {
} }
func (c *udpConn) Close() error { func (c *udpConn) Close() error {
common.Close(c.done)
return nil return nil
} }
@ -189,8 +168,7 @@ type udpWorker struct {
tag string tag string
dispatcher core.Dispatcher dispatcher core.Dispatcher
ctx context.Context done *signal.Done
cancel context.CancelFunc
activeConn map[connId]*udpConn activeConn map[connId]*udpConn
} }
@ -215,6 +193,7 @@ func (w *udpWorker) getConnection(id connId) (*udpConn, bool) {
IP: w.address.IP(), IP: w.address.IP(),
Port: int(w.port), Port: int(w.port),
}, },
done: signal.NewDone(),
} }
w.activeConn[id] = conn w.activeConn[id] = conn
@ -230,16 +209,15 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
conn, existing := w.getConnection(id) conn, existing := w.getConnection(id)
select { select {
case conn.input <- b: case conn.input <- b:
case <-conn.done.C():
b.Release()
default: default:
b.Release() b.Release()
} }
if !existing { if !existing {
go func() { go func() {
ctx := w.ctx ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
conn.ctx = ctx
conn.cancel = cancel
if originalDest.IsValid() { if originalDest.IsValid() {
ctx = proxy.ContextWithOriginalTarget(ctx, originalDest) ctx = proxy.ContextWithOriginalTarget(ctx, originalDest)
} }
@ -251,8 +229,8 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog() newError("connection ends").Base(err).WriteToLog()
} }
conn.Close()
w.removeConn(id) w.removeConn(id)
cancel()
}() }()
} }
} }
@ -265,9 +243,7 @@ func (w *udpWorker) removeConn(id connId) {
func (w *udpWorker) Start() error { func (w *udpWorker) Start() error {
w.activeConn = make(map[connId]*udpConn, 16) w.activeConn = make(map[connId]*udpConn, 16)
ctx, cancel := context.WithCancel(context.Background()) w.done = signal.NewDone()
w.ctx = ctx
w.cancel = cancel
h, err := udp.ListenUDP(w.address, w.port, udp.ListenOption{ h, err := udp.ListenUDP(w.address, w.port, udp.ListenOption{
Callback: w.callback, Callback: w.callback,
ReceiveOriginalDest: w.recvOrigDest, ReceiveOriginalDest: w.recvOrigDest,
@ -280,11 +256,13 @@ func (w *udpWorker) Start() error {
return nil return nil
} }
func (w *udpWorker) Close() { func (w *udpWorker) Close() error {
if w.hub != nil { if w.hub != nil {
w.hub.Close() w.hub.Close()
w.cancel() w.done.Close()
common.Close(w.proxy)
} }
return nil
} }
func (w *udpWorker) monitor() { func (w *udpWorker) monitor() {
@ -293,7 +271,7 @@ func (w *udpWorker) monitor() {
for { for {
select { select {
case <-w.ctx.Done(): case <-w.done.C():
return return
case <-timer.C: case <-timer.C:
nowSec := time.Now().Unix() nowSec := time.Now().Unix()
@ -301,7 +279,7 @@ func (w *udpWorker) monitor() {
for addr, conn := range w.activeConn { for addr, conn := range w.activeConn {
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 { if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 {
delete(w.activeConn, addr) delete(w.activeConn, addr)
conn.cancel() conn.Close()
} }
} }
w.Unlock() w.Unlock()

View File

@ -291,7 +291,8 @@ func (s *Server) Start() error {
return nil return nil
} }
func (s *Server) Close() { func (s *Server) Close() error {
return nil
} }
type ServerWorker struct { type ServerWorker struct {

View File

@ -103,12 +103,12 @@ func (m *SessionManager) CloseIfNoSession() bool {
return true return true
} }
func (m *SessionManager) Close() { func (m *SessionManager) Close() error {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
if m.closed { if m.closed {
return return nil
} }
m.closed = true m.closed = true
@ -119,6 +119,7 @@ func (m *SessionManager) Close() {
} }
m.sessions = nil m.sessions = nil
return nil
} }
// Session represents a client connection in a Mux connection. // Session represents a client connection in a Mux connection.
@ -131,10 +132,11 @@ type Session struct {
} }
// Close closes all resources associated with this session. // Close closes all resources associated with this session.
func (s *Session) Close() { func (s *Session) Close() error {
s.output.Close() s.output.Close()
s.input.Close() s.input.Close()
s.parent.Remove(s.ID) s.parent.Remove(s.ID)
return nil
} }
// NewReader creates a buf.Reader based on the transfer type of this Session. // NewReader creates a buf.Reader based on the transfer type of this Session.

View File

@ -100,7 +100,7 @@ func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
return nil return nil
} }
func (w *Writer) Close() { func (w *Writer) Close() error {
meta := FrameMetadata{ meta := FrameMetadata{
SessionID: w.id, SessionID: w.id,
SessionStatus: SessionStatusEnd, SessionStatus: SessionStatusEnd,
@ -110,4 +110,5 @@ func (w *Writer) Close() {
common.Must(frame.Reset(meta.AsSupplier())) common.Must(frame.Reset(meta.AsSupplier()))
w.writer.WriteMultiBuffer(buf.NewMultiBufferValue(frame)) w.writer.WriteMultiBuffer(buf.NewMultiBufferValue(frame))
return nil
} }

View File

@ -39,7 +39,7 @@ func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error)
func (*Manager) Start() error { return nil } func (*Manager) Start() error { return nil }
// Close implements core.Feature // Close implements core.Feature
func (*Manager) Close() {} func (*Manager) Close() error { return nil }
// GetDefaultHandler implements core.OutboundHandlerManager. // GetDefaultHandler implements core.OutboundHandlerManager.
func (m *Manager) GetDefaultHandler() core.OutboundHandler { func (m *Manager) GetDefaultHandler() core.OutboundHandler {

View File

@ -114,7 +114,9 @@ func (*Router) Start() error {
return nil return nil
} }
func (*Router) Close() {} func (*Router) Close() error {
return nil
}
func init() { func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {

View File

@ -40,15 +40,15 @@ func (c *syncClock) Start() error {
return c.Clock.Start() return c.Clock.Start()
} }
func (c *syncClock) Close() { func (c *syncClock) Close() error {
c.RLock() c.RLock()
defer c.RUnlock() defer c.RUnlock()
if c.Clock == nil { if c.Clock == nil {
return return nil
} }
c.Clock.Close() return c.Clock.Close()
} }
func (c *syncClock) Set(clock Clock) { func (c *syncClock) Set(clock Clock) {

View File

@ -44,15 +44,15 @@ func (c *syncCommander) Start() error {
return c.Commander.Start() return c.Commander.Start()
} }
func (c *syncCommander) Close() { func (c *syncCommander) Close() error {
c.RLock() c.RLock()
defer c.RUnlock() defer c.RUnlock()
if c.Commander == nil { if c.Commander == nil {
return return nil
} }
c.Commander.Close() return c.Commander.Close()
} }
func (c *syncCommander) Set(commander Commander) { func (c *syncCommander) Set(commander Commander) {

View File

@ -1,10 +1,23 @@
package common package common
// Closable is the interface for objects that can release its resources.
type Closable interface {
// Close release all resources used by this object, including goroutines.
Close() error
}
// Close closes the obj if it is a Closable.
func Close(obj interface{}) error {
if c, ok := obj.(Closable); ok {
return c.Close()
}
return nil
}
// Runnable is the interface for objects that can start to work and stop on demand. // Runnable is the interface for objects that can start to work and stop on demand.
type Runnable interface { type Runnable interface {
// Start starts the runnable object. Upon the method returning nil, the object begins to function properly. // Start starts the runnable object. Upon the method returning nil, the object begins to function properly.
Start() error Start() error
// Close stops the object being working. Closable
Close()
} }

48
common/signal/done.go Normal file
View File

@ -0,0 +1,48 @@
package signal
import (
"sync"
)
type Done struct {
access sync.Mutex
c chan struct{}
closed bool
}
func NewDone() *Done {
return &Done{
c: make(chan struct{}),
}
}
func (d *Done) Done() bool {
select {
case <-d.c:
return true
default:
return false
}
}
func (d *Done) C() chan struct{} {
return d.c
}
func (d *Done) Wait() {
<-d.c
}
func (d *Done) Close() error {
d.access.Lock()
defer d.access.Unlock()
if d.closed {
return nil
}
d.closed = true
close(d.c)
return nil
}

View File

@ -1,22 +1,22 @@
package signal package signal
type Notifier struct { type Notifier struct {
c chan bool c chan struct{}
} }
func NewNotifier() *Notifier { func NewNotifier() *Notifier {
return &Notifier{ return &Notifier{
c: make(chan bool, 1), c: make(chan struct{}, 1),
} }
} }
func (n *Notifier) Signal() { func (n *Notifier) Signal() {
select { select {
case n.c <- true: case n.c <- struct{}{}:
default: default:
} }
} }
func (n *Notifier) Wait() <-chan bool { func (n *Notifier) Wait() <-chan struct{} {
return n.c return n.c
} }

View File

@ -1,23 +1,23 @@
package signal package signal
type Semaphore struct { type Semaphore struct {
token chan bool token chan struct{}
} }
func NewSemaphore(n int) *Semaphore { func NewSemaphore(n int) *Semaphore {
s := &Semaphore{ s := &Semaphore{
token: make(chan bool, n), token: make(chan struct{}, n),
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
s.token <- true s.token <- struct{}{}
} }
return s return s
} }
func (s *Semaphore) Wait() <-chan bool { func (s *Semaphore) Wait() <-chan struct{} {
return s.token return s.token
} }
func (s *Semaphore) Signal() { func (s *Semaphore) Signal() {
s.token <- true s.token <- struct{}{}
} }

60
common/signal/task.go Normal file
View File

@ -0,0 +1,60 @@
package signal
import (
"sync"
"time"
)
type PeriodicTask struct {
Interval time.Duration
Execute func() error
access sync.Mutex
timer *time.Timer
closed bool
}
func (t *PeriodicTask) checkedExecute() error {
t.access.Lock()
defer t.access.Unlock()
if t.closed {
return nil
}
if err := t.Execute(); err != nil {
return err
}
t.timer = time.AfterFunc(t.Interval, func() {
t.checkedExecute()
})
return nil
}
func (t *PeriodicTask) Start() error {
t.access.Lock()
t.closed = false
t.access.Unlock()
if err := t.checkedExecute(); err != nil {
t.closed = true
return err
}
return nil
}
func (t *PeriodicTask) Close() error {
t.access.Lock()
defer t.access.Unlock()
t.closed = true
if t.timer != nil {
t.timer.Stop()
t.timer = nil
}
return nil
}

View File

@ -10,14 +10,14 @@ type ActivityUpdater interface {
} }
type ActivityTimer struct { type ActivityTimer struct {
updated chan bool updated chan struct{}
timeout chan time.Duration timeout chan time.Duration
closing chan bool closing chan struct{}
} }
func (t *ActivityTimer) Update() { func (t *ActivityTimer) Update() {
select { select {
case t.updated <- true: case t.updated <- struct{}{}:
default: default:
} }
} }
@ -72,8 +72,8 @@ func (t *ActivityTimer) run(ctx context.Context, cancel context.CancelFunc) {
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer { func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
timer := &ActivityTimer{ timer := &ActivityTimer{
timeout: make(chan time.Duration, 1), timeout: make(chan time.Duration, 1),
updated: make(chan bool, 1), updated: make(chan struct{}, 1),
closing: make(chan bool), closing: make(chan struct{}),
} }
timer.timeout <- timeout timer.timeout <- timeout
go timer.run(ctx, cancel) go timer.run(ctx, cancel)

14
dns.go
View File

@ -1,7 +1,11 @@
package core package core
import "net" import (
import "sync" "net"
"sync"
"v2ray.com/core/common"
)
// DNSClient is a V2Ray feature for querying DNS information. // DNSClient is a V2Ray feature for querying DNS information.
type DNSClient interface { type DNSClient interface {
@ -36,13 +40,11 @@ func (d *syncDNSClient) Start() error {
return d.DNSClient.Start() return d.DNSClient.Start()
} }
func (d *syncDNSClient) Close() { func (d *syncDNSClient) Close() error {
d.RLock() d.RLock()
defer d.RUnlock() defer d.RUnlock()
if d.DNSClient != nil { return common.Close(d.DNSClient)
d.DNSClient.Close()
}
} }
func (d *syncDNSClient) Set(client DNSClient) { func (d *syncDNSClient) Set(client DNSClient) {

View File

@ -21,6 +21,7 @@ type InboundHandler interface {
// OutboundHandler is the interface for handlers that process outbound connections. // OutboundHandler is the interface for handlers that process outbound connections.
type OutboundHandler interface { type OutboundHandler interface {
common.Runnable
Tag() string Tag() string
Dispatch(ctx context.Context, outboundRay ray.OutboundRay) Dispatch(ctx context.Context, outboundRay ray.OutboundRay)
} }
@ -75,13 +76,11 @@ func (m *syncInboundHandlerManager) Start() error {
return m.InboundHandlerManager.Start() return m.InboundHandlerManager.Start()
} }
func (m *syncInboundHandlerManager) Close() { func (m *syncInboundHandlerManager) Close() error {
m.RLock() m.RLock()
defer m.RUnlock() defer m.RUnlock()
if m.InboundHandlerManager != nil { return common.Close(m.InboundHandlerManager)
m.InboundHandlerManager.Close()
}
} }
func (m *syncInboundHandlerManager) Set(manager InboundHandlerManager) { func (m *syncInboundHandlerManager) Set(manager InboundHandlerManager) {
@ -154,13 +153,11 @@ func (m *syncOutboundHandlerManager) Start() error {
return m.OutboundHandlerManager.Start() return m.OutboundHandlerManager.Start()
} }
func (m *syncOutboundHandlerManager) Close() { func (m *syncOutboundHandlerManager) Close() error {
m.RLock() m.RLock()
defer m.RUnlock() defer m.RUnlock()
if m.OutboundHandlerManager != nil { return common.Close(m.OutboundHandlerManager)
m.OutboundHandlerManager.Close()
}
} }
func (m *syncOutboundHandlerManager) Set(manager OutboundHandlerManager) { func (m *syncOutboundHandlerManager) Set(manager OutboundHandlerManager) {

View File

@ -3,6 +3,8 @@ package core
import ( import (
"sync" "sync"
"time" "time"
"v2ray.com/core/common"
) )
// TimeoutPolicy contains limits for connection timeout. // TimeoutPolicy contains limits for connection timeout.
@ -96,13 +98,11 @@ func (m *syncPolicyManager) Start() error {
return m.PolicyManager.Start() return m.PolicyManager.Start()
} }
func (m *syncPolicyManager) Close() { func (m *syncPolicyManager) Close() error {
m.RLock() m.RLock()
defer m.RUnlock() defer m.RUnlock()
if m.PolicyManager != nil { return common.Close(m.PolicyManager)
m.PolicyManager.Close()
}
} }
func (m *syncPolicyManager) Set(manager PolicyManager) { func (m *syncPolicyManager) Set(manager PolicyManager) {

View File

@ -48,8 +48,9 @@ func TestRequestSerialization(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
sessionHistory := NewSessionHistory() sessionHistory := NewSessionHistory()
userValidator := vmess.NewTimedUserValidator(ctx, protocol.DefaultIDHash) userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user) userValidator.Add(user)
defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory) server := NewServerSession(userValidator, sessionHistory)
actualRequest, err := server.DecodeRequestHeader(buffer) actualRequest, err := server.DecodeRequestHeader(buffer)

View File

@ -30,28 +30,34 @@ type sessionId struct {
type SessionHistory struct { type SessionHistory struct {
sync.RWMutex sync.RWMutex
cache map[sessionId]time.Time cache map[sessionId]time.Time
token *signal.Semaphore task *signal.PeriodicTask
timer *time.Timer
} }
func NewSessionHistory() *SessionHistory { func NewSessionHistory() *SessionHistory {
h := &SessionHistory{ h := &SessionHistory{
cache: make(map[sessionId]time.Time, 128), cache: make(map[sessionId]time.Time, 128),
token: signal.NewSemaphore(1),
} }
h.task = &signal.PeriodicTask{
Interval: time.Second * 30,
Execute: func() error {
h.removeExpiredEntries()
return nil
},
}
common.Must(h.task.Start())
return h return h
} }
// Close implements common.Closable.
func (h *SessionHistory) Close() error {
return h.task.Close()
}
func (h *SessionHistory) add(session sessionId) { func (h *SessionHistory) add(session sessionId) {
h.Lock() h.Lock()
defer h.Unlock() defer h.Unlock()
h.cache[session] = time.Now().Add(time.Minute * 3) h.cache[session] = time.Now().Add(time.Minute * 3)
select {
case <-h.token.Wait():
h.timer = time.AfterFunc(time.Minute*3, h.removeExpiredEntries)
default:
}
} }
func (h *SessionHistory) has(session sessionId) bool { func (h *SessionHistory) has(session sessionId) bool {
@ -75,11 +81,6 @@ func (h *SessionHistory) removeExpiredEntries() {
delete(h.cache, session) delete(h.cache, session)
} }
} }
if h.timer != nil {
h.timer.Stop()
h.timer = nil
}
} }
type ServerSession struct { type ServerSession struct {

View File

@ -90,7 +90,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
handler := &Handler{ handler := &Handler{
policyManager: v.PolicyManager(), policyManager: v.PolicyManager(),
inboundHandlerManager: v.InboundHandlerManager(), inboundHandlerManager: v.InboundHandlerManager(),
clients: vmess.NewTimedUserValidator(ctx, protocol.DefaultIDHash), clients: vmess.NewTimedUserValidator(protocol.DefaultIDHash),
detours: config.Detour, detours: config.Detour,
usersByEmail: newUserByEmail(config.User, config.GetDefaultValue()), usersByEmail: newUserByEmail(config.User, config.GetDefaultValue()),
sessionHistory: encoding.NewSessionHistory(), sessionHistory: encoding.NewSessionHistory(),
@ -105,6 +105,14 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
return handler, nil return handler, nil
} }
// Close implements common.Closable.
func (h *Handler) Close() error {
common.Close(h.clients)
common.Close(h.sessionHistory)
common.Close(h.usersByEmail)
return nil
}
// Network implements proxy.Inbound.Network(). // Network implements proxy.Inbound.Network().
func (*Handler) Network() net.NetworkList { func (*Handler) Network() net.NetworkList {
return net.NetworkList{ return net.NetworkList{

View File

@ -8,17 +8,17 @@ package vmess
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg vmess -path Proxy,VMess //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg vmess -path Proxy,VMess
import ( import (
"context"
"sync" "sync"
"time" "time"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/signal"
) )
const ( const (
updateIntervalSec = 10 updateInterval = 10 * time.Second
cacheDurationSec = 120 cacheDurationSec = 120
) )
type idEntry struct { type idEntry struct {
@ -34,6 +34,7 @@ type TimedUserValidator struct {
ids []*idEntry ids []*idEntry
hasher protocol.IDHash hasher protocol.IDHash
baseTime protocol.Timestamp baseTime protocol.Timestamp
task *signal.PeriodicTask
} }
type indexTimePair struct { type indexTimePair struct {
@ -41,16 +42,23 @@ type indexTimePair struct {
timeInc uint32 timeInc uint32
} }
func NewTimedUserValidator(ctx context.Context, hasher protocol.IDHash) protocol.UserValidator { func NewTimedUserValidator(hasher protocol.IDHash) protocol.UserValidator {
tus := &TimedUserValidator{ tuv := &TimedUserValidator{
validUsers: make([]*protocol.User, 0, 16), validUsers: make([]*protocol.User, 0, 16),
userHash: make(map[[16]byte]indexTimePair, 512), userHash: make(map[[16]byte]indexTimePair, 512),
ids: make([]*idEntry, 0, 512), ids: make([]*idEntry, 0, 512),
hasher: hasher, hasher: hasher,
baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*3), baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*3),
} }
go tus.updateUserHash(ctx, updateIntervalSec*time.Second) tuv.task = &signal.PeriodicTask{
return tus Interval: updateInterval,
Execute: func() error {
tuv.updateUserHash()
return nil
},
}
tuv.task.Start()
return tuv
} }
func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, idx int, entry *idEntry) { func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, idx int, entry *idEntry) {
@ -78,24 +86,19 @@ func (v *TimedUserValidator) removeExpiredHashes(expire uint32) {
} }
} }
func (v *TimedUserValidator) updateUserHash(ctx context.Context, interval time.Duration) { func (v *TimedUserValidator) updateUserHash() {
for { now := time.Now()
select { nowSec := protocol.Timestamp(now.Unix() + cacheDurationSec)
case now := <-time.After(interval): v.Lock()
nowSec := protocol.Timestamp(now.Unix() + cacheDurationSec) defer v.Unlock()
v.Lock()
for _, entry := range v.ids {
v.generateNewHashes(nowSec, entry.userIdx, entry)
}
expire := protocol.Timestamp(now.Unix() - cacheDurationSec*3) for _, entry := range v.ids {
if expire > v.baseTime { v.generateNewHashes(nowSec, entry.userIdx, entry)
v.removeExpiredHashes(uint32(expire - v.baseTime)) }
}
v.Unlock() expire := protocol.Timestamp(now.Unix() - cacheDurationSec*3)
case <-ctx.Done(): if expire > v.baseTime {
return v.removeExpiredHashes(uint32(expire - v.baseTime))
}
} }
} }
@ -145,3 +148,8 @@ func (v *TimedUserValidator) Get(userHash []byte) (*protocol.User, protocol.Time
} }
return nil, 0, false return nil, 0, false
} }
// Close implements common.Closable.
func (v *TimedUserValidator) Close() error {
return v.task.Close()
}

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"sync" "sync"
"v2ray.com/core/common"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
@ -45,13 +46,11 @@ func (d *syncDispatcher) Start() error {
return d.Dispatcher.Start() return d.Dispatcher.Start()
} }
func (d *syncDispatcher) Close() { func (d *syncDispatcher) Close() error {
d.RLock() d.RLock()
defer d.RUnlock() defer d.RUnlock()
if d.Dispatcher != nil { return common.Close(d.Dispatcher)
d.Dispatcher.Close()
}
} }
func (d *syncDispatcher) Set(disp Dispatcher) { func (d *syncDispatcher) Set(disp Dispatcher) {
@ -101,13 +100,11 @@ func (r *syncRouter) Start() error {
return r.Router.Start() return r.Router.Start()
} }
func (r *syncRouter) Close() { func (r *syncRouter) Close() error {
r.RLock() r.RLock()
defer r.RUnlock() defer r.RUnlock()
if r.Router != nil { return common.Close(r.Router)
r.Router.Close()
}
} }
func (r *syncRouter) Set(router Router) { func (r *syncRouter) Set(router Router) {

View File

@ -36,6 +36,6 @@ func (s *Server) Start() (net.Destination, error) {
return net.TCPDestination(net.LocalHostIP, net.Port(s.Port)), nil return net.TCPDestination(net.LocalHostIP, net.Port(s.Port)), nil
} }
func (s *Server) Close() { func (s *Server) Close() error {
s.server.Close() return s.server.Close()
} }

View File

@ -69,6 +69,6 @@ func (server *Server) handleConnection(conn net.Conn) {
conn.Close() conn.Close()
} }
func (server *Server) Close() { func (server *Server) Close() error {
server.listener.Close() return server.listener.Close()
} }

View File

@ -46,7 +46,7 @@ func (server *Server) handleConnection(conn *net.UDPConn) {
} }
} }
func (server *Server) Close() { func (server *Server) Close() error {
server.accepting = false server.accepting = false
server.conn.Close() return server.conn.Close()
} }

View File

@ -23,7 +23,6 @@ type ConnectionID struct {
// Listener defines a server listening for connections // Listener defines a server listening for connections
type Listener struct { type Listener struct {
sync.Mutex sync.Mutex
ctx context.Context
sessions map[ConnectionID]*Connection sessions map[ConnectionID]*Connection
hub *udp.Hub hub *udp.Hub
tlsConfig *tls.Config tlsConfig *tls.Config
@ -31,10 +30,10 @@ type Listener struct {
reader PacketReader reader PacketReader
header internet.PacketHeader header internet.PacketHeader
security cipher.AEAD security cipher.AEAD
addConn internet.AddConnection addConn internet.ConnHandler
} }
func NewListener(ctx context.Context, address net.Address, port net.Port, addConn internet.AddConnection) (*Listener, error) { func NewListener(ctx context.Context, address net.Address, port net.Port, addConn internet.ConnHandler) (*Listener, error) {
networkSettings := internet.TransportSettingsFromContext(ctx) networkSettings := internet.TransportSettingsFromContext(ctx)
kcpSettings := networkSettings.(*Config) kcpSettings := networkSettings.(*Config)
@ -54,7 +53,6 @@ func NewListener(ctx context.Context, address net.Address, port net.Port, addCon
Security: security, Security: security,
}, },
sessions: make(map[ConnectionID]*Connection), sessions: make(map[ConnectionID]*Connection),
ctx: ctx,
config: kcpSettings, config: kcpSettings,
addConn: addConn, addConn: addConn,
} }
@ -86,12 +84,6 @@ func (l *Listener) OnReceive(payload *buf.Buffer, src net.Destination, originalD
l.Lock() l.Lock()
defer l.Unlock() defer l.Unlock()
select {
case <-l.ctx.Done():
return
default:
}
if l.hub == nil { if l.hub == nil {
return return
} }
@ -136,23 +128,16 @@ func (l *Listener) OnReceive(payload *buf.Buffer, src net.Destination, originalD
netConn = tlsConn netConn = tlsConn
} }
if !l.addConn(context.Background(), netConn) { l.addConn(netConn)
return
}
l.sessions[id] = conn l.sessions[id] = conn
} }
conn.Input(segments) conn.Input(segments)
} }
func (l *Listener) Remove(id ConnectionID) { func (l *Listener) Remove(id ConnectionID) {
select { l.Lock()
case <-l.ctx.Done(): delete(l.sessions, id)
return l.Unlock()
default:
l.Lock()
delete(l.sessions, id)
l.Unlock()
}
} }
// Close stops listening on the UDP address. Already Accepted connections are not closed. // Close stops listening on the UDP address. Already Accepted connections are not closed.
@ -197,7 +182,7 @@ func (w *Writer) Close() error {
return nil return nil
} }
func ListenKCP(ctx context.Context, address net.Address, port net.Port, addConn internet.AddConnection) (internet.Listener, error) { func ListenKCP(ctx context.Context, address net.Address, port net.Port, addConn internet.ConnHandler) (internet.Listener, error) {
return NewListener(ctx, address, port, addConn) return NewListener(ctx, address, port, addConn)
} }

View File

@ -3,10 +3,10 @@ package tcp
import ( import (
"context" "context"
gotls "crypto/tls" gotls "crypto/tls"
"strings"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/retry"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tls" "v2ray.com/core/transport/internet/tls"
) )
@ -17,11 +17,11 @@ type Listener struct {
tlsConfig *gotls.Config tlsConfig *gotls.Config
authConfig internet.ConnectionAuthenticator authConfig internet.ConnectionAuthenticator
config *Config config *Config
addConn internet.AddConnection addConn internet.ConnHandler
} }
// ListenTCP creates a new Listener based on configurations. // ListenTCP creates a new Listener based on configurations.
func ListenTCP(ctx context.Context, address net.Address, port net.Port, addConn internet.AddConnection) (internet.Listener, error) { func ListenTCP(ctx context.Context, address net.Address, port net.Port, handler internet.ConnHandler) (internet.Listener, error) {
listener, err := net.ListenTCP("tcp", &net.TCPAddr{ listener, err := net.ListenTCP("tcp", &net.TCPAddr{
IP: address.IP(), IP: address.IP(),
Port: int(port), Port: int(port),
@ -36,7 +36,7 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, addConn
l := &Listener{ l := &Listener{
listener: listener, listener: listener,
config: tcpSettings, config: tcpSettings,
addConn: addConn, addConn: handler,
} }
if config := tls.ConfigFromContext(ctx, tls.WithNextProto("h2")); config != nil { if config := tls.ConfigFromContext(ctx, tls.WithNextProto("h2")); config != nil {
@ -54,27 +54,17 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, addConn
} }
l.authConfig = auth l.authConfig = auth
} }
go l.keepAccepting(ctx) go l.keepAccepting()
return l, nil return l, nil
} }
func (v *Listener) keepAccepting(ctx context.Context) { func (v *Listener) keepAccepting() {
for { for {
select { conn, err := v.listener.Accept()
case <-ctx.Done():
return
default:
}
var conn net.Conn
err := retry.ExponentialBackoff(5, 200).On(func() error {
rawConn, err := v.listener.Accept()
if err != nil {
return err
}
conn = rawConn
return nil
})
if err != nil { if err != nil {
if strings.Contains(err.Error(), "closed") {
break
}
newError("failed to accepted raw connections").Base(err).AtWarning().WriteToLog() newError("failed to accepted raw connections").Base(err).AtWarning().WriteToLog()
continue continue
} }
@ -86,7 +76,7 @@ func (v *Listener) keepAccepting(ctx context.Context) {
conn = v.authConfig.Server(conn) conn = v.authConfig.Server(conn)
} }
v.addConn(context.Background(), internet.Connection(conn)) v.addConn(internet.Connection(conn))
} }
} }

View File

@ -2,7 +2,6 @@ package internet
import ( import (
"context" "context"
"time"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
) )
@ -19,16 +18,16 @@ func RegisterTransportListener(protocol TransportProtocol, listener ListenFunc)
return nil return nil
} }
type AddConnection func(context.Context, Connection) bool type ConnHandler func(Connection)
type ListenFunc func(ctx context.Context, address net.Address, port net.Port, addConn AddConnection) (Listener, error) type ListenFunc func(ctx context.Context, address net.Address, port net.Port, handler ConnHandler) (Listener, error)
type Listener interface { type Listener interface {
Close() error Close() error
Addr() net.Addr Addr() net.Addr
} }
func ListenTCP(ctx context.Context, address net.Address, port net.Port, conns chan<- Connection) (Listener, error) { func ListenTCP(ctx context.Context, address net.Address, port net.Port, handler ConnHandler) (Listener, error) {
settings := StreamSettingsFromContext(ctx) settings := StreamSettingsFromContext(ctx)
protocol := settings.GetEffectiveProtocol() protocol := settings.GetEffectiveProtocol()
transportSettings, err := settings.GetEffectiveTransportSettings() transportSettings, err := settings.GetEffectiveTransportSettings()
@ -47,26 +46,7 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, conns ch
if listenFunc == nil { if listenFunc == nil {
return nil, newError(protocol, " listener not registered.").AtError() return nil, newError(protocol, " listener not registered.").AtError()
} }
listener, err := listenFunc(ctx, address, port, func(ctx context.Context, conn Connection) bool { listener, err := listenFunc(ctx, address, port, handler)
select {
case <-ctx.Done():
conn.Close()
return false
case conns <- conn:
return true
default:
select {
case <-ctx.Done():
conn.Close()
return false
case conns <- conn:
return true
case <-time.After(time.Second * 5):
conn.Close()
return false
}
}
})
if err != nil { if err != nil {
return nil, newError("failed to listen on address: ", address, ":", port).Base(err) return nil, newError("failed to listen on address: ", address, ":", port).Base(err)
} }

View File

@ -25,7 +25,9 @@ func (d *TestDispatcher) Start() error {
return nil return nil
} }
func (d *TestDispatcher) Close() {} func (d *TestDispatcher) Close() error {
return nil
}
func TestSameDestinationDispatching(t *testing.T) { func TestSameDestinationDispatching(t *testing.T) {
assert := With(t) assert := With(t)

View File

@ -60,10 +60,11 @@ func (q *PayloadQueue) Dequeue(queue <-chan Payload) {
} }
} }
func (q *PayloadQueue) Close() { func (q *PayloadQueue) Close() error {
for _, queue := range q.queue { for _, queue := range q.queue {
close(queue) close(queue)
} }
return nil
} }
type ListenOption struct { type ListenOption struct {
@ -116,9 +117,10 @@ func ListenUDP(address net.Address, port net.Port, option ListenOption) (*Hub, e
return hub, nil return hub, nil
} }
func (h *Hub) Close() { func (h *Hub) Close() error {
h.cancel() h.cancel()
h.conn.Close() h.conn.Close()
return nil
} }
func (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) { func (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) {

View File

@ -44,24 +44,22 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
remoteAddr.(*net.TCPAddr).IP = forwardedAddrs[0].IP() remoteAddr.(*net.TCPAddr).IP = forwardedAddrs[0].IP()
} }
h.ln.addConn(h.ln.ctx, newConnection(conn, remoteAddr)) h.ln.addConn(newConnection(conn, remoteAddr))
} }
type Listener struct { type Listener struct {
sync.Mutex sync.Mutex
ctx context.Context
listener net.Listener listener net.Listener
tlsConfig *tls.Config tlsConfig *tls.Config
config *Config config *Config
addConn internet.AddConnection addConn internet.ConnHandler
} }
func ListenWS(ctx context.Context, address net.Address, port net.Port, addConn internet.AddConnection) (internet.Listener, error) { func ListenWS(ctx context.Context, address net.Address, port net.Port, addConn internet.ConnHandler) (internet.Listener, error) {
networkSettings := internet.TransportSettingsFromContext(ctx) networkSettings := internet.TransportSettingsFromContext(ctx)
wsSettings := networkSettings.(*Config) wsSettings := networkSettings.(*Config)
l := &Listener{ l := &Listener{
ctx: ctx,
config: wsSettings, config: wsSettings,
addConn: addConn, addConn: addConn,
} }

View File

@ -209,12 +209,13 @@ func (s *Stream) WriteMultiBuffer(data buf.MultiBuffer) error {
} }
// Close closes the stream for writing. Read() still works until EOF. // Close closes the stream for writing. Read() still works until EOF.
func (s *Stream) Close() { func (s *Stream) Close() error {
s.access.Lock() s.access.Lock()
s.close = true s.close = true
s.readSignal.Signal() s.readSignal.Signal()
s.writeSignal.Signal() s.writeSignal.Signal()
s.access.Unlock() s.access.Unlock()
return nil
} }
// CloseError closes the Stream with error. Read() will return an error afterwards. // CloseError closes the Stream with error. Read() will return an error afterwards.

View File

@ -1,6 +1,9 @@
package ray package ray
import "v2ray.com/core/common/buf" import (
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
)
// OutboundRay is a transport interface for outbound connections. // OutboundRay is a transport interface for outbound connections.
type OutboundRay interface { type OutboundRay interface {
@ -34,7 +37,7 @@ type Ray interface {
} }
type RayStream interface { type RayStream interface {
Close() common.Closable
CloseError() CloseError()
} }

View File

@ -101,7 +101,7 @@ func (s *Instance) ID() uuid.UUID {
} }
// Close shutdown the V2Ray instance. // Close shutdown the V2Ray instance.
func (s *Instance) Close() { func (s *Instance) Close() error {
s.access.Lock() s.access.Lock()
defer s.access.Unlock() defer s.access.Unlock()
@ -109,6 +109,8 @@ func (s *Instance) Close() {
for _, f := range s.features { for _, f := range s.features {
f.Close() f.Close()
} }
return nil
} }
// Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown. // Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown.