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