From 1b2b5b6cb1148a90eae047cb730927061a9169b4 Mon Sep 17 00:00:00 2001 From: V2Ray Date: Thu, 17 Sep 2015 23:00:17 +0200 Subject: [PATCH] Combine VMess response with first packet for performance --- net/address.go | 4 ++- net/freedom/freedom.go | 1 + net/vmess/vmessin.go | 65 ++++++++++++++++++++++-------------------- net/vmess/vmessout.go | 23 ++++++++------- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/net/address.go b/net/address.go index a5518c9d..f041c95c 100644 --- a/net/address.go +++ b/net/address.go @@ -18,10 +18,12 @@ type Address struct { } func IPAddress(ip []byte, port uint16) Address { + ipCopy := make([]byte, len(ip)) + copy(ipCopy, ip) // TODO: check IP length return Address{ Type: AddrTypeIP, - IP: net.IP(ip), + IP: net.IP(ipCopy), Domain: "", Port: port, } diff --git a/net/freedom/freedom.go b/net/freedom/freedom.go index f721e6c4..3c9e95d8 100644 --- a/net/freedom/freedom.go +++ b/net/freedom/freedom.go @@ -23,6 +23,7 @@ func (vconn *FreedomConnection) Start(ray core.OutboundRay) error { output := ray.OutboundOutput() conn, err := net.Dial("tcp", vconn.dest.String()) if err != nil { + close(output) return log.Error("Failed to open tcp: %s : %v", vconn.dest.String(), err) } log.Debug("Sending outbound tcp: %s", vconn.dest.String()) diff --git a/net/vmess/vmessin.go b/net/vmess/vmessin.go index 6d543736..6c71ac63 100644 --- a/net/vmess/vmessin.go +++ b/net/vmess/vmessin.go @@ -60,27 +60,6 @@ func (handler *VMessInboundHandler) HandleConnection(connection net.Conn) error } log.Debug("Received request for %s", request.Address.String()) - response := vmessio.NewVMessResponse(request) - nBytes, err := connection.Write(response[:]) - if err != nil { - return log.Error("Failed to write VMess response (%d bytes): %v", nBytes, err) - } - - requestKey := request.RequestKey[:] - requestIV := request.RequestIV[:] - responseKey := md5.Sum(requestKey) - responseIV := md5.Sum(requestIV) - - requestReader, err := v2io.NewAesDecryptReader(requestKey, requestIV, connection) - if err != nil { - return log.Error("Failed to create decrypt reader: %v", err) - } - - responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], connection) - if err != nil { - return log.Error("Failed to create encrypt writer: %v", err) - } - ray := handler.vPoint.NewInboundConnectionAccepted(request.Address) input := ray.InboundInput() output := ray.InboundOutput() @@ -88,8 +67,27 @@ func (handler *VMessInboundHandler) HandleConnection(connection net.Conn) error readFinish := make(chan bool) writeFinish := make(chan bool) - go handler.dumpInput(requestReader, input, readFinish) - go handler.dumpOutput(responseWriter, output, writeFinish) + go handleInput(request, connection, input, readFinish) + + responseKey := md5.Sum(request.RequestKey[:]) + responseIV := md5.Sum(request.RequestIV[:]) + + response := vmessio.NewVMessResponse(request) + responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], connection) + if err != nil { + return log.Error("Failed to create encrypt writer: %v", err) + } + + // Optimize for small response packet + buffer := make([]byte, 0, 1024) + buffer = append(buffer, response[:]...) + data, open := <-output + if open { + buffer = append(buffer, data...) + } + responseWriter.Write(buffer) + + go handleOutput(request, responseWriter, output, writeFinish) <-writeFinish if tcpConn, ok := connection.(*net.TCPConn); ok { @@ -101,17 +99,22 @@ func (handler *VMessInboundHandler) HandleConnection(connection net.Conn) error return nil } -func (handler *VMessInboundHandler) dumpInput(reader io.Reader, input chan<- []byte, finish chan<- bool) { - v2net.ReaderToChan(input, reader) - close(input) - log.Debug("VMessIn closing input") - finish <- true +func handleInput(request *vmessio.VMessRequest, reader io.Reader, input chan<- []byte, finish chan<- bool) { + defer close(input) + defer close(finish) + + requestReader, err := v2io.NewAesDecryptReader(request.RequestKey[:], request.RequestIV[:], reader) + if err != nil { + log.Error("Failed to create decrypt reader: %v", err) + return + } + + v2net.ReaderToChan(input, requestReader) } -func (handler *VMessInboundHandler) dumpOutput(writer io.Writer, output <-chan []byte, finish chan<- bool) { +func handleOutput(request *vmessio.VMessRequest, writer io.Writer, output <-chan []byte, finish chan<- bool) { v2net.ChanToWriter(writer, output) - log.Debug("VMessOut closing output") - finish <- true + close(finish) } type VMessInboundHandlerFactory struct { diff --git a/net/vmess/vmessout.go b/net/vmess/vmessout.go index 482953f2..81e96e11 100644 --- a/net/vmess/vmessout.go +++ b/net/vmess/vmessout.go @@ -79,8 +79,10 @@ func startCommunicate(request *vmessio.VMessRequest, dest v2net.Address, ray cor close(output) return err } + + log.Debug("VMessOut: Tunneling request for %s", request.Address.String()) + defer conn.Close() - defer close(output) requestFinish := make(chan bool) responseFinish := make(chan bool) @@ -115,24 +117,25 @@ func handleRequest(conn *net.TCPConn, request *vmessio.VMessRequest, input <-cha func handleResponse(conn *net.TCPConn, request *vmessio.VMessRequest, output chan<- []byte, finish chan<- bool) error { defer close(finish) + defer close(output) responseKey := md5.Sum(request.RequestKey[:]) responseIV := md5.Sum(request.RequestIV[:]) - response := vmessio.VMessResponse{} - nBytes, err := conn.Read(response[:]) - if err != nil { - log.Error("Failed to read VMess response (%d bytes): %v", nBytes, err) - return err - } - log.Debug("Got response %v", response) - // TODO: check response - decryptResponseReader, err := v2io.NewAesDecryptReader(responseKey[:], responseIV[:], conn) if err != nil { log.Error("Failed to create decrypt reader: %v", err) return err } + response := vmessio.VMessResponse{} + nBytes, err := decryptResponseReader.Read(response[:]) + if err != nil { + log.Error("Failed to read VMess response (%d bytes): %v", nBytes, err) + return err + } + log.Debug("Got response %v", response) + // TODO: check response + v2net.ReaderToChan(output, decryptResponseReader) return nil }