mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-23 07:23:01 +00:00
017f53b5fc
* Add session context outbounds as slice slice is needed for dialer proxy where two outbounds work on top of each other There are two sets of target addr for example It also enable Xtls to correctly do splice copy by checking both outbounds are ready to do direct copy * Fill outbound tag info * Splice now checks capalibility from all outbounds * Fix unit tests
164 lines
4.5 KiB
Go
164 lines
4.5 KiB
Go
package session
|
|
|
|
import (
|
|
"context"
|
|
_ "unsafe"
|
|
|
|
"github.com/xtls/xray-core/common/net"
|
|
"github.com/xtls/xray-core/features/routing"
|
|
)
|
|
|
|
//go:linkname IndependentCancelCtx context.newCancelCtx
|
|
func IndependentCancelCtx(parent context.Context) context.Context
|
|
|
|
type sessionKey int
|
|
|
|
const (
|
|
idSessionKey sessionKey = iota
|
|
inboundSessionKey
|
|
outboundSessionKey
|
|
contentSessionKey
|
|
muxPreferedSessionKey
|
|
sockoptSessionKey
|
|
trackedConnectionErrorKey
|
|
dispatcherKey
|
|
timeoutOnlyKey
|
|
allowedNetworkKey
|
|
handlerSessionKey
|
|
)
|
|
|
|
// ContextWithID returns a new context with the given ID.
|
|
func ContextWithID(ctx context.Context, id ID) context.Context {
|
|
return context.WithValue(ctx, idSessionKey, id)
|
|
}
|
|
|
|
// IDFromContext returns ID in this context, or 0 if not contained.
|
|
func IDFromContext(ctx context.Context) ID {
|
|
if id, ok := ctx.Value(idSessionKey).(ID); ok {
|
|
return id
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
|
|
return context.WithValue(ctx, inboundSessionKey, inbound)
|
|
}
|
|
|
|
func InboundFromContext(ctx context.Context) *Inbound {
|
|
if inbound, ok := ctx.Value(inboundSessionKey).(*Inbound); ok {
|
|
return inbound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ContextWithOutbounds(ctx context.Context, outbounds []*Outbound) context.Context {
|
|
return context.WithValue(ctx, outboundSessionKey, outbounds)
|
|
}
|
|
|
|
func OutboundsFromContext(ctx context.Context) []*Outbound {
|
|
if outbounds, ok := ctx.Value(outboundSessionKey).([]*Outbound); ok {
|
|
return outbounds
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ContextWithContent(ctx context.Context, content *Content) context.Context {
|
|
return context.WithValue(ctx, contentSessionKey, content)
|
|
}
|
|
|
|
func ContentFromContext(ctx context.Context) *Content {
|
|
if content, ok := ctx.Value(contentSessionKey).(*Content); ok {
|
|
return content
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ContextWithMuxPrefered returns a new context with the given bool
|
|
func ContextWithMuxPrefered(ctx context.Context, forced bool) context.Context {
|
|
return context.WithValue(ctx, muxPreferedSessionKey, forced)
|
|
}
|
|
|
|
// MuxPreferedFromContext returns value in this context, or false if not contained.
|
|
func MuxPreferedFromContext(ctx context.Context) bool {
|
|
if val, ok := ctx.Value(muxPreferedSessionKey).(bool); ok {
|
|
return val
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ContextWithSockopt returns a new context with Socket configs included
|
|
func ContextWithSockopt(ctx context.Context, s *Sockopt) context.Context {
|
|
return context.WithValue(ctx, sockoptSessionKey, s)
|
|
}
|
|
|
|
// SockoptFromContext returns Socket configs in this context, or nil if not contained.
|
|
func SockoptFromContext(ctx context.Context) *Sockopt {
|
|
if sockopt, ok := ctx.Value(sockoptSessionKey).(*Sockopt); ok {
|
|
return sockopt
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetForcedOutboundTagFromContext(ctx context.Context) string {
|
|
if ContentFromContext(ctx) == nil {
|
|
return ""
|
|
}
|
|
return ContentFromContext(ctx).Attribute("forcedOutboundTag")
|
|
}
|
|
|
|
func SetForcedOutboundTagToContext(ctx context.Context, tag string) context.Context {
|
|
if contentFromContext := ContentFromContext(ctx); contentFromContext == nil {
|
|
ctx = ContextWithContent(ctx, &Content{})
|
|
}
|
|
ContentFromContext(ctx).SetAttribute("forcedOutboundTag", tag)
|
|
return ctx
|
|
}
|
|
|
|
type TrackedRequestErrorFeedback interface {
|
|
SubmitError(err error)
|
|
}
|
|
|
|
func SubmitOutboundErrorToOriginator(ctx context.Context, err error) {
|
|
if errorTracker := ctx.Value(trackedConnectionErrorKey); errorTracker != nil {
|
|
errorTracker := errorTracker.(TrackedRequestErrorFeedback)
|
|
errorTracker.SubmitError(err)
|
|
}
|
|
}
|
|
|
|
func TrackedConnectionError(ctx context.Context, tracker TrackedRequestErrorFeedback) context.Context {
|
|
return context.WithValue(ctx, trackedConnectionErrorKey, tracker)
|
|
}
|
|
|
|
func ContextWithDispatcher(ctx context.Context, dispatcher routing.Dispatcher) context.Context {
|
|
return context.WithValue(ctx, dispatcherKey, dispatcher)
|
|
}
|
|
|
|
func DispatcherFromContext(ctx context.Context) routing.Dispatcher {
|
|
if dispatcher, ok := ctx.Value(dispatcherKey).(routing.Dispatcher); ok {
|
|
return dispatcher
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ContextWithTimeoutOnly(ctx context.Context, only bool) context.Context {
|
|
return context.WithValue(ctx, timeoutOnlyKey, only)
|
|
}
|
|
|
|
func TimeoutOnlyFromContext(ctx context.Context) bool {
|
|
if val, ok := ctx.Value(timeoutOnlyKey).(bool); ok {
|
|
return val
|
|
}
|
|
return false
|
|
}
|
|
|
|
func ContextWithAllowedNetwork(ctx context.Context, network net.Network) context.Context {
|
|
return context.WithValue(ctx, allowedNetworkKey, network)
|
|
}
|
|
|
|
func AllowedNetworkFromContext(ctx context.Context) net.Network {
|
|
if val, ok := ctx.Value(allowedNetworkKey).(net.Network); ok {
|
|
return val
|
|
}
|
|
return net.Network_Unknown
|
|
}
|