func (v *Server) handleConnection(connection internet.Connection) { defer connection.Close() timedReader := v2net.NewTimeOutReader(v.config.Timeout, connection) reader := bufio.NewReader(timedReader) defer reader.Release() writer := bufio.NewWriter(connection) defer writer.Release() auth, auth4, err := protocol.ReadAuthentication(reader) if err != nil && errors.Cause(err) != protocol.Socks4Downgrade { if errors.Cause(err) != io.EOF { log.Warning("Socks: failed to read authentication: ", err) } return } clientAddr := v2net.DestinationFromAddr(connection.RemoteAddr()) if err != nil && err == protocol.Socks4Downgrade { v.handleSocks4(clientAddr, reader, writer, auth4) } else { v.handleSocks5(clientAddr, reader, writer, auth) } }
func (s *Server) Process(ctx context.Context, network v2net.Network, conn internet.Connection) error { conn.SetReusable(false) timedReader := v2net.NewTimeOutReader(s.config.Timeout, conn) reader := bufio.OriginalReaderSize(timedReader, 2048) request, err := http.ReadRequest(reader) if err != nil { if errors.Cause(err) != io.EOF { log.Warning("HTTP: Failed to read http request: ", err) } return err } log.Info("HTTP: Request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]") defaultPort := v2net.Port(80) if strings.ToLower(request.URL.Scheme) == "https" { defaultPort = v2net.Port(443) } host := request.Host if len(host) == 0 { host = request.URL.Host } dest, err := parseHost(host, defaultPort) if err != nil { log.Warning("HTTP: Malformed proxy host (", host, "): ", err) return err } log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "") ctx = proxy.ContextWithDestination(ctx, dest) if strings.ToUpper(request.Method) == "CONNECT" { return s.handleConnect(ctx, request, reader, conn) } else { return s.handlePlainHTTP(ctx, request, reader, conn) } }
// PipeUntilEOF behaves the same as Pipe(). The only difference is PipeUntilEOF returns nil on EOF. func PipeUntilEOF(reader Reader, writer Writer) error { err := Pipe(reader, writer) if err != nil && errors.Cause(err) != io.EOF { return err } return nil }
// ReadFrom implements io.ReaderFrom.ReadFrom(). func (v *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) { totalBytes := int64(0) for { oriSize := v.buffer.Len() err := v.buffer.AppendSupplier(buf.ReadFrom(reader)) totalBytes += int64(v.buffer.Len() - oriSize) if err != nil { if errors.Cause(err) == io.EOF { return totalBytes, nil } return totalBytes, err } if err := v.Flush(); err != nil { return totalBytes, err } } }
func (v *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) { v.Lock() defer v.Unlock() if v.writer == nil { return 0, io.ErrClosedPipe } totalBytes := int64(0) for { oriSize := v.buffer.Len() err := v.buffer.AppendSupplier(buf.ReadFrom(reader)) totalBytes += int64(v.buffer.Len() - oriSize) if err != nil { if errors.Cause(err) == io.EOF { return totalBytes, nil } return totalBytes, err } v.FlushWithoutLock() } }
func (v *Server) handleConnection(conn internet.Connection) { defer conn.Close() timedReader := v2net.NewTimeOutReader(v.config.Timeout, conn) reader := bufio.OriginalReaderSize(timedReader, 2048) request, err := http.ReadRequest(reader) if err != nil { if errors.Cause(err) != io.EOF { log.Warning("HTTP: Failed to read http request: ", err) } return } log.Info("HTTP: Request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]") defaultPort := v2net.Port(80) if strings.ToLower(request.URL.Scheme) == "https" { defaultPort = v2net.Port(443) } host := request.Host if len(host) == 0 { host = request.URL.Host } dest, err := parseHost(host, defaultPort) if err != nil { log.Warning("HTTP: Malformed proxy host (", host, "): ", err) return } log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "") session := &proxy.SessionInfo{ Source: v2net.DestinationFromAddr(conn.RemoteAddr()), Destination: dest, Inbound: v.meta, } if strings.ToUpper(request.Method) == "CONNECT" { v.handleConnect(request, session, reader, conn) } else { v.handlePlainHTTP(request, session, reader, conn) } }
func (ws *wsconn) readNext(b []byte) (n int, err error) { if ws.readBuffer == nil { err = ws.getNewReadBuffer() if err != nil { return 0, err } } n, err = ws.readBuffer.Read(b) if err == nil { return n, err } if errors.Cause(err) == io.EOF { ws.readBuffer = nil if n == 0 { return ws.readNext(b) } return n, nil } return n, err }
func (v *VMessInboundHandler) Process(ctx context.Context, network net.Network, connection internet.Connection) error { connReader := net.NewTimeOutReader(8, connection) reader := bufio.NewReader(connReader) session := encoding.NewServerSession(v.clients) request, err := session.DecodeRequestHeader(reader) if err != nil { if errors.Cause(err) != io.EOF { log.Access(connection.RemoteAddr(), "", log.AccessRejected, err) log.Info("VMess|Inbound: Invalid request from ", connection.RemoteAddr(), ": ", err) } connection.SetReusable(false) return err } log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "") log.Info("VMess|Inbound: Received request for ", request.Destination()) connection.SetReusable(request.Option.Has(protocol.RequestOptionConnectionReuse)) ctx = proxy.ContextWithDestination(ctx, request.Destination()) ctx = protocol.ContextWithUser(ctx, request.User) ray := v.packetDispatcher.DispatchToOutbound(ctx) input := ray.InboundInput() output := ray.InboundOutput() userSettings := request.User.GetSettings() connReader.SetTimeOut(userSettings.PayloadReadTimeout) reader.SetBuffered(false) requestDone := signal.ExecuteAsync(func() error { return transferRequest(session, request, reader, input) }) writer := bufio.NewWriter(connection) response := &protocol.ResponseHeader{ Command: v.generateCommand(ctx, request), } if connection.Reusable() { response.Option.Set(protocol.ResponseOptionConnectionReuse) } responseDone := signal.ExecuteAsync(func() error { return transferResponse(session, request, response, output, writer) }) if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil { log.Info("VMess|Inbound: Connection ending with ", err) connection.SetReusable(false) input.CloseError() output.CloseError() return err } if err := writer.Flush(); err != nil { log.Info("VMess|Inbound: Failed to flush remain data: ", err) connection.SetReusable(false) return err } return nil }