Fix context api and document (#727)

* Fix Dial function crash instance when there is no instance context in the ctx

* check ctx to fix. (#841)

* Feat: core.ToContext(ctx, v) for ctx initialization (#852)

* remove exported API: toContext

* Remove unnecessary API

* rework document for API

* fix: make sure the ctx is propagated to connections by detached connection

Co-authored-by: Shelikhoo <xiaokangwang@outlook.com>
Co-authored-by: rurirei <72071920+rurirei@users.noreply.github.com>
This commit is contained in:
yuhan6665 2022-02-19 22:45:41 -05:00 committed by GitHub
parent cf1ee095a2
commit 496b2c02c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 3 deletions

View File

@ -17,6 +17,7 @@ import (
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/pubsub" "github.com/xtls/xray-core/common/signal/pubsub"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core"
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
@ -195,7 +196,7 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client
for _, req := range reqs { for _, req := range reqs {
s.addPendingRequest(req) s.addPendingRequest(req)
b, _ := dns.PackMessage(req.msg) b, _ := dns.PackMessage(req.msg)
udpCtx := context.Background() udpCtx := core.ToBackgroundDetachedContext(ctx)
if inbound := session.InboundFromContext(ctx); inbound != nil { if inbound := session.InboundFromContext(ctx); inbound != nil {
udpCtx = session.ContextWithInbound(udpCtx, inbound) udpCtx = session.ContextWithInbound(udpCtx, inbound)
} }

View File

@ -25,3 +25,28 @@ func MustFromContext(ctx context.Context) *Instance {
} }
return x return x
} }
/* toContext returns ctx from the given context, or creates an Instance if the context doesn't find that.
It is unsupported to use this function to create a context that is suitable to invoke Xray's internal component
in third party code, you shouldn't use //go:linkname to alias of this function into your own package and
use this function in your third party code.
For third party code, usage enabled by creating a context to interact with Xray's internal component is unsupported,
and may break at any time.
*/
func toContext(ctx context.Context, v *Instance) context.Context {
if FromContext(ctx) != v {
ctx = context.WithValue(ctx, xrayKey, v)
}
return ctx
}
/*ToBackgroundDetachedContext create a detached context from another context
Internal API
*/
func ToBackgroundDetachedContext(ctx context.Context) context.Context {
instance := MustFromContext(ctx)
return toContext(context.Background(), instance)
}

View File

@ -5,9 +5,10 @@ import (
"testing" "testing"
. "github.com/xtls/xray-core/core" . "github.com/xtls/xray-core/core"
_ "unsafe"
) )
func TestContextPanic(t *testing.T) { func TestFromContextPanic(t *testing.T) {
defer func() { defer func() {
r := recover() r := recover()
if r == nil { if r == nil {

View File

@ -15,7 +15,7 @@ import (
func CreateObject(v *Instance, config interface{}) (interface{}, error) { func CreateObject(v *Instance, config interface{}) (interface{}, error) {
ctx := v.ctx ctx := v.ctx
if v != nil { if v != nil {
ctx = context.WithValue(ctx, xrayKey, v) ctx = toContext(v.ctx, v)
} }
return common.CreateObject(ctx, config) return common.CreateObject(ctx, config)
} }
@ -46,10 +46,13 @@ func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
// //
// xray:api:stable // xray:api:stable
func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, error) { func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, error) {
ctx = toContext(ctx, v)
dispatcher := v.GetFeature(routing.DispatcherType()) dispatcher := v.GetFeature(routing.DispatcherType())
if dispatcher == nil { if dispatcher == nil {
return nil, newError("routing.Dispatcher is not registered in Xray core") return nil, newError("routing.Dispatcher is not registered in Xray core")
} }
r, err := dispatcher.(routing.Dispatcher).Dispatch(ctx, dest) r, err := dispatcher.(routing.Dispatcher).Dispatch(ctx, dest)
if err != nil { if err != nil {
return nil, err return nil, err
@ -70,6 +73,8 @@ func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, err
// //
// xray:api:beta // xray:api:beta
func DialUDP(ctx context.Context, v *Instance) (net.PacketConn, error) { func DialUDP(ctx context.Context, v *Instance) (net.PacketConn, error) {
ctx = toContext(ctx, v)
dispatcher := v.GetFeature(routing.DispatcherType()) dispatcher := v.GetFeature(routing.DispatcherType())
if dispatcher == nil { if dispatcher == nil {
return nil, newError("routing.Dispatcher is not registered in Xray core") return nil, newError("routing.Dispatcher is not registered in Xray core")