func (this *Shadowsocks) handleConnection(conn *hub.TCPConn) { defer conn.Close() buffer := alloc.NewSmallBuffer() defer buffer.Release() timedReader := v2net.NewTimeOutReader(16, conn) ivLen := this.config.Cipher.IVSize() _, err := io.ReadFull(timedReader, buffer.Value[:ivLen]) if err != nil { log.Access(conn.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Error("Shadowsocks: Failed to read IV: ", err) return } iv := buffer.Value[:ivLen] key := this.config.Key stream, err := this.config.Cipher.NewDecodingStream(key, iv) if err != nil { log.Error("Shadowsocks: Failed to create decoding stream: ", err) return } reader := crypto.NewCryptionReader(stream, timedReader) request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)), false) if err != nil { log.Access(conn.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Warning("Shadowsocks: Invalid request from ", conn.RemoteAddr(), ": ", err) return } userSettings := protocol.GetUserSettings(this.config.Level) timedReader.SetTimeOut(userSettings.PayloadReadTimeout) dest := v2net.TCPDestination(request.Address, request.Port) log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, serial.StringLiteral("")) log.Info("Shadowsocks: Tunnelling request to ", dest) packet := v2net.NewPacket(dest, nil, true) ray := this.packetDispatcher.DispatchToOutbound(packet) var writeFinish sync.Mutex writeFinish.Lock() go func() { if payload, ok := <-ray.InboundOutput(); ok { payload.SliceBack(ivLen) rand.Read(payload.Value[:ivLen]) stream, err := this.config.Cipher.NewEncodingStream(key, payload.Value[:ivLen]) if err != nil { log.Error("Shadowsocks: Failed to create encoding stream: ", err) return } stream.XORKeyStream(payload.Value[ivLen:], payload.Value[ivLen:]) conn.Write(payload.Value) payload.Release() writer := crypto.NewCryptionWriter(stream, conn) v2io.ChanToRawWriter(writer, ray.InboundOutput()) } writeFinish.Unlock() }() var payloadReader v2io.Reader if request.OTA { payloadAuth := NewAuthenticator(ChunkKeyGenerator(iv)) payloadReader = NewChunkReader(reader, payloadAuth) } else { payloadReader = v2io.NewAdaptiveReader(reader) } v2io.ReaderToChan(ray.InboundInput(), payloadReader) close(ray.InboundInput()) writeFinish.Lock() }