package core import ( "context" "sync" "v2ray.com/core/common" "v2ray.com/core/common/buf" "v2ray.com/core/common/errors" "v2ray.com/core/common/net" ) // Link is a utility for connecting between an inbound and an outbound proxy handler. type Link struct { Reader buf.Reader Writer buf.Writer } // Dispatcher is a feature that dispatches inbound requests to outbound handlers based on rules. // Dispatcher is required to be registered in a V2Ray instance to make V2Ray function properly. type Dispatcher interface { Feature // Dispatch returns a Ray for transporting data for the given request. Dispatch(ctx context.Context, dest net.Destination) (*Link, error) } type syncDispatcher struct { sync.RWMutex Dispatcher } func (d *syncDispatcher) Dispatch(ctx context.Context, dest net.Destination) (*Link, error) { d.RLock() defer d.RUnlock() if d.Dispatcher == nil { return nil, newError("Dispatcher not set.").AtError() } return d.Dispatcher.Dispatch(ctx, dest) } func (d *syncDispatcher) Start() error { d.RLock() defer d.RUnlock() if d.Dispatcher == nil { return newError("Dispatcher not set.").AtError() } return d.Dispatcher.Start() } func (d *syncDispatcher) Close() error { d.RLock() defer d.RUnlock() return common.Close(d.Dispatcher) } func (d *syncDispatcher) Set(disp Dispatcher) { if disp == nil { return } d.Lock() defer d.Unlock() common.Close(d.Dispatcher) // nolint: errorcheck d.Dispatcher = disp } var ( // ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route. ErrNoClue = errors.New("not enough information for making a decision") ) // Router is a feature to choose an outbound tag for the given request. type Router interface { Feature // PickRoute returns a tag of an OutboundHandler based on the given context. PickRoute(ctx context.Context) (string, error) } type syncRouter struct { sync.RWMutex Router } func (r *syncRouter) PickRoute(ctx context.Context) (string, error) { r.RLock() defer r.RUnlock() if r.Router == nil { return "", ErrNoClue } return r.Router.PickRoute(ctx) } func (r *syncRouter) Start() error { r.RLock() defer r.RUnlock() if r.Router == nil { return nil } return r.Router.Start() } func (r *syncRouter) Close() error { r.RLock() defer r.RUnlock() return common.Close(r.Router) } func (r *syncRouter) Set(router Router) { if router == nil { return } r.Lock() defer r.Unlock() common.Close(r.Router) // nolint: errcheck r.Router = router }