github.com/xraypb/xray-core@v1.6.6/common/mux/server.go (about)

     1  package mux
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  
     7  	"github.com/xraypb/xray-core/common"
     8  	"github.com/xraypb/xray-core/common/buf"
     9  	"github.com/xraypb/xray-core/common/errors"
    10  	"github.com/xraypb/xray-core/common/log"
    11  	"github.com/xraypb/xray-core/common/net"
    12  	"github.com/xraypb/xray-core/common/protocol"
    13  	"github.com/xraypb/xray-core/common/session"
    14  	"github.com/xraypb/xray-core/core"
    15  	"github.com/xraypb/xray-core/features/routing"
    16  	"github.com/xraypb/xray-core/transport"
    17  	"github.com/xraypb/xray-core/transport/pipe"
    18  )
    19  
    20  type Server struct {
    21  	dispatcher routing.Dispatcher
    22  }
    23  
    24  // NewServer creates a new mux.Server.
    25  func NewServer(ctx context.Context) *Server {
    26  	s := &Server{}
    27  	core.RequireFeatures(ctx, func(d routing.Dispatcher) {
    28  		s.dispatcher = d
    29  	})
    30  	return s
    31  }
    32  
    33  // Type implements common.HasType.
    34  func (s *Server) Type() interface{} {
    35  	return s.dispatcher.Type()
    36  }
    37  
    38  // Dispatch implements routing.Dispatcher
    39  func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
    40  	if dest.Address != muxCoolAddress {
    41  		return s.dispatcher.Dispatch(ctx, dest)
    42  	}
    43  
    44  	opts := pipe.OptionsFromContext(ctx)
    45  	uplinkReader, uplinkWriter := pipe.New(opts...)
    46  	downlinkReader, downlinkWriter := pipe.New(opts...)
    47  
    48  	_, err := NewServerWorker(ctx, s.dispatcher, &transport.Link{
    49  		Reader: uplinkReader,
    50  		Writer: downlinkWriter,
    51  	})
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	return &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, nil
    57  }
    58  
    59  // DispatchLink implements routing.Dispatcher
    60  func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
    61  	if dest.Address != muxCoolAddress {
    62  		return s.dispatcher.DispatchLink(ctx, dest, link)
    63  	}
    64  	_, err := NewServerWorker(ctx, s.dispatcher, link)
    65  	return err
    66  }
    67  
    68  // Start implements common.Runnable.
    69  func (s *Server) Start() error {
    70  	return nil
    71  }
    72  
    73  // Close implements common.Closable.
    74  func (s *Server) Close() error {
    75  	return nil
    76  }
    77  
    78  type ServerWorker struct {
    79  	dispatcher     routing.Dispatcher
    80  	link           *transport.Link
    81  	sessionManager *SessionManager
    82  }
    83  
    84  func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) {
    85  	worker := &ServerWorker{
    86  		dispatcher:     d,
    87  		link:           link,
    88  		sessionManager: NewSessionManager(),
    89  	}
    90  	go worker.run(ctx)
    91  	return worker, nil
    92  }
    93  
    94  func handle(ctx context.Context, s *Session, output buf.Writer) {
    95  	writer := NewResponseWriter(s.ID, output, s.transferType)
    96  	if err := buf.Copy(s.input, writer); err != nil {
    97  		newError("session ", s.ID, " ends.").Base(err).WriteToLog(session.ExportIDToError(ctx))
    98  		writer.hasError = true
    99  	}
   100  
   101  	writer.Close()
   102  	s.Close()
   103  }
   104  
   105  func (w *ServerWorker) ActiveConnections() uint32 {
   106  	return uint32(w.sessionManager.Size())
   107  }
   108  
   109  func (w *ServerWorker) Closed() bool {
   110  	return w.sessionManager.Closed()
   111  }
   112  
   113  func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
   114  	if meta.Option.Has(OptionData) {
   115  		return buf.Copy(NewStreamReader(reader), buf.Discard)
   116  	}
   117  	return nil
   118  }
   119  
   120  func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
   121  	newError("received request for ", meta.Target).WriteToLog(session.ExportIDToError(ctx))
   122  	{
   123  		msg := &log.AccessMessage{
   124  			To:     meta.Target,
   125  			Status: log.AccessAccepted,
   126  			Reason: "",
   127  		}
   128  		if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
   129  			msg.From = inbound.Source
   130  			msg.Email = inbound.User.Email
   131  		}
   132  		ctx = log.ContextWithAccessMessage(ctx, msg)
   133  	}
   134  	link, err := w.dispatcher.Dispatch(ctx, meta.Target)
   135  	if err != nil {
   136  		if meta.Option.Has(OptionData) {
   137  			buf.Copy(NewStreamReader(reader), buf.Discard)
   138  		}
   139  		return newError("failed to dispatch request.").Base(err)
   140  	}
   141  	s := &Session{
   142  		input:        link.Reader,
   143  		output:       link.Writer,
   144  		parent:       w.sessionManager,
   145  		ID:           meta.SessionID,
   146  		transferType: protocol.TransferTypeStream,
   147  	}
   148  	if meta.Target.Network == net.Network_UDP {
   149  		s.transferType = protocol.TransferTypePacket
   150  	}
   151  	w.sessionManager.Add(s)
   152  	go handle(ctx, s, w.link.Writer)
   153  	if !meta.Option.Has(OptionData) {
   154  		return nil
   155  	}
   156  
   157  	rr := s.NewReader(reader, &meta.Target)
   158  	if err := buf.Copy(rr, s.output); err != nil {
   159  		buf.Copy(rr, buf.Discard)
   160  		common.Interrupt(s.input)
   161  		return s.Close()
   162  	}
   163  	return nil
   164  }
   165  
   166  func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
   167  	if !meta.Option.Has(OptionData) {
   168  		return nil
   169  	}
   170  
   171  	s, found := w.sessionManager.Get(meta.SessionID)
   172  	if !found {
   173  		// Notify remote peer to close this session.
   174  		closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
   175  		closingWriter.Close()
   176  
   177  		return buf.Copy(NewStreamReader(reader), buf.Discard)
   178  	}
   179  
   180  	rr := s.NewReader(reader, &meta.Target)
   181  	err := buf.Copy(rr, s.output)
   182  
   183  	if err != nil && buf.IsWriteError(err) {
   184  		newError("failed to write to downstream writer. closing session ", s.ID).Base(err).WriteToLog()
   185  
   186  		// Notify remote peer to close this session.
   187  		closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
   188  		closingWriter.Close()
   189  
   190  		drainErr := buf.Copy(rr, buf.Discard)
   191  		common.Interrupt(s.input)
   192  		s.Close()
   193  		return drainErr
   194  	}
   195  
   196  	return err
   197  }
   198  
   199  func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {
   200  	if s, found := w.sessionManager.Get(meta.SessionID); found {
   201  		if meta.Option.Has(OptionError) {
   202  			common.Interrupt(s.input)
   203  			common.Interrupt(s.output)
   204  		}
   205  		s.Close()
   206  	}
   207  	if meta.Option.Has(OptionData) {
   208  		return buf.Copy(NewStreamReader(reader), buf.Discard)
   209  	}
   210  	return nil
   211  }
   212  
   213  func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedReader) error {
   214  	var meta FrameMetadata
   215  	err := meta.Unmarshal(reader)
   216  	if err != nil {
   217  		return newError("failed to read metadata").Base(err)
   218  	}
   219  
   220  	switch meta.SessionStatus {
   221  	case SessionStatusKeepAlive:
   222  		err = w.handleStatusKeepAlive(&meta, reader)
   223  	case SessionStatusEnd:
   224  		err = w.handleStatusEnd(&meta, reader)
   225  	case SessionStatusNew:
   226  		err = w.handleStatusNew(ctx, &meta, reader)
   227  	case SessionStatusKeep:
   228  		err = w.handleStatusKeep(&meta, reader)
   229  	default:
   230  		status := meta.SessionStatus
   231  		return newError("unknown status: ", status).AtError()
   232  	}
   233  
   234  	if err != nil {
   235  		return newError("failed to process data").Base(err)
   236  	}
   237  	return nil
   238  }
   239  
   240  func (w *ServerWorker) run(ctx context.Context) {
   241  	input := w.link.Reader
   242  	reader := &buf.BufferedReader{Reader: input}
   243  
   244  	defer w.sessionManager.Close()
   245  
   246  	for {
   247  		select {
   248  		case <-ctx.Done():
   249  			return
   250  		default:
   251  			err := w.handleFrame(ctx, reader)
   252  			if err != nil {
   253  				if errors.Cause(err) != io.EOF {
   254  					newError("unexpected EOF").Base(err).WriteToLog(session.ExportIDToError(ctx))
   255  					common.Interrupt(input)
   256  				}
   257  				return
   258  			}
   259  		}
   260  	}
   261  }