mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 17:38:41 +00:00
XUDP protocol: Add Global ID & UoT Migration
The first UoT protocol that supports UoT Migration Thank @yuhan6665 for testing
This commit is contained in:
parent
67affe3753
commit
be23d5d3b7
39 changed files with 506 additions and 99 deletions
|
@ -2,6 +2,7 @@ package mux
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/xudp"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
|
@ -99,7 +101,7 @@ func handle(ctx context.Context, s *Session, output buf.Writer) {
|
|||
}
|
||||
|
||||
writer.Close()
|
||||
s.Close()
|
||||
s.Close(false)
|
||||
}
|
||||
|
||||
func (w *ServerWorker) ActiveConnections() uint32 {
|
||||
|
@ -131,6 +133,81 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||
}
|
||||
ctx = log.ContextWithAccessMessage(ctx, msg)
|
||||
}
|
||||
|
||||
if meta.GlobalID != [8]byte{} {
|
||||
mb, err := NewPacketReader(reader, &meta.Target).ReadMultiBuffer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
XUDPManager.Lock()
|
||||
x := XUDPManager.Map[meta.GlobalID]
|
||||
if x == nil {
|
||||
x = &XUDP{GlobalID: meta.GlobalID}
|
||||
XUDPManager.Map[meta.GlobalID] = x
|
||||
XUDPManager.Unlock()
|
||||
} else {
|
||||
if x.Status == Initializing { // nearly impossible
|
||||
XUDPManager.Unlock()
|
||||
if xudp.Show {
|
||||
fmt.Printf("XUDP hit: %v err: conflict\n", meta.GlobalID)
|
||||
}
|
||||
// It's not a good idea to return an err here, so just let client wait.
|
||||
// Client will receive an End frame after sending a Keep frame.
|
||||
return nil
|
||||
}
|
||||
x.Status = Initializing
|
||||
XUDPManager.Unlock()
|
||||
x.Mux.Close(false) // detach from previous Mux
|
||||
b := buf.New()
|
||||
b.Write(mb[0].Bytes())
|
||||
b.UDP = mb[0].UDP
|
||||
if err = x.Mux.output.WriteMultiBuffer(mb); err != nil {
|
||||
x.Interrupt()
|
||||
mb = buf.MultiBuffer{b}
|
||||
} else {
|
||||
b.Release()
|
||||
mb = nil
|
||||
}
|
||||
if xudp.Show {
|
||||
fmt.Printf("XUDP hit: %v err: %v\n", meta.GlobalID, err)
|
||||
}
|
||||
}
|
||||
if mb != nil {
|
||||
ctx = session.ContextWithTimeoutOnly(ctx, true)
|
||||
// Actually, it won't return an error in Xray-core's implementations.
|
||||
link, err := w.dispatcher.Dispatch(ctx, meta.Target)
|
||||
if err != nil {
|
||||
err = newError("failed to dispatch request to ", meta.Target).Base(err)
|
||||
if xudp.Show {
|
||||
fmt.Printf("XUDP new: %v err: %v\n", meta.GlobalID, err)
|
||||
}
|
||||
return err // it will break the whole Mux connection
|
||||
}
|
||||
link.Writer.WriteMultiBuffer(mb) // it's meaningless to test a new pipe
|
||||
x.Mux = &Session{
|
||||
input: link.Reader,
|
||||
output: link.Writer,
|
||||
}
|
||||
if xudp.Show {
|
||||
fmt.Printf("XUDP new: %v err: %v\n", meta.GlobalID, err)
|
||||
}
|
||||
}
|
||||
x.Mux = &Session{
|
||||
input: x.Mux.input,
|
||||
output: x.Mux.output,
|
||||
parent: w.sessionManager,
|
||||
ID: meta.SessionID,
|
||||
transferType: protocol.TransferTypePacket,
|
||||
XUDP: x,
|
||||
}
|
||||
go handle(ctx, x.Mux, w.link.Writer)
|
||||
x.Status = Active
|
||||
if !w.sessionManager.Add(x.Mux) {
|
||||
x.Mux.Close(false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
link, err := w.dispatcher.Dispatch(ctx, meta.Target)
|
||||
if err != nil {
|
||||
if meta.Option.Has(OptionData) {
|
||||
|
@ -157,8 +234,7 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||
rr := s.NewReader(reader, &meta.Target)
|
||||
if err := buf.Copy(rr, s.output); err != nil {
|
||||
buf.Copy(rr, buf.Discard)
|
||||
common.Interrupt(s.input)
|
||||
return s.Close()
|
||||
return s.Close(false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -182,15 +258,8 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
|
|||
|
||||
if err != nil && buf.IsWriteError(err) {
|
||||
newError("failed to write to downstream writer. closing session ", s.ID).Base(err).WriteToLog()
|
||||
|
||||
// Notify remote peer to close this session.
|
||||
closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
|
||||
closingWriter.Close()
|
||||
|
||||
drainErr := buf.Copy(rr, buf.Discard)
|
||||
common.Interrupt(s.input)
|
||||
s.Close()
|
||||
return drainErr
|
||||
s.Close(false)
|
||||
return buf.Copy(rr, buf.Discard)
|
||||
}
|
||||
|
||||
return err
|
||||
|
@ -198,12 +267,7 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
|
|||
|
||||
func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||
if s, found := w.sessionManager.Get(meta.SessionID); found {
|
||||
if meta.Option.Has(OptionError) {
|
||||
common.Interrupt(s.input)
|
||||
common.Interrupt(s.output)
|
||||
}
|
||||
common.Interrupt(s.input)
|
||||
s.Close()
|
||||
s.Close(false)
|
||||
}
|
||||
if meta.Option.Has(OptionData) {
|
||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue