mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 20:47:38 +03:00
69 lines
1.6 KiB
Go
69 lines
1.6 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
var errDisconnect = errors.New("traffic logger requested disconnect")
|
|
|
|
func copyBufferLog(dst io.Writer, src io.Reader, log func(n uint64) bool) error {
|
|
buf := make([]byte, 32*1024)
|
|
for {
|
|
nr, er := src.Read(buf)
|
|
if nr > 0 {
|
|
if !log(uint64(nr)) {
|
|
// Log returns false, which means that the client should be disconnected
|
|
return errDisconnect
|
|
}
|
|
_, ew := dst.Write(buf[0:nr])
|
|
if ew != nil {
|
|
return ew
|
|
}
|
|
}
|
|
if er != nil {
|
|
if er == io.EOF {
|
|
// EOF should not be considered as an error
|
|
return nil
|
|
}
|
|
return er
|
|
}
|
|
}
|
|
}
|
|
|
|
func copyTwoWayEx(id string, serverRw, remoteRw io.ReadWriter, l TrafficLogger, stats *StreamStats) error {
|
|
errChan := make(chan error, 2)
|
|
go func() {
|
|
errChan <- copyBufferLog(serverRw, remoteRw, func(n uint64) bool {
|
|
stats.LastActiveTime.Store(time.Now())
|
|
stats.Rx.Add(n)
|
|
return l.LogTraffic(id, 0, n)
|
|
})
|
|
}()
|
|
go func() {
|
|
errChan <- copyBufferLog(remoteRw, serverRw, func(n uint64) bool {
|
|
stats.LastActiveTime.Store(time.Now())
|
|
stats.Tx.Add(n)
|
|
return l.LogTraffic(id, n, 0)
|
|
})
|
|
}()
|
|
// Block until one of the two goroutines returns
|
|
return <-errChan
|
|
}
|
|
|
|
// copyTwoWay is the "fast-path" version of copyTwoWayEx that does not log traffic or update stream stats.
|
|
// It uses the built-in io.Copy instead of our own copyBufferLog.
|
|
func copyTwoWay(serverRw, remoteRw io.ReadWriter) error {
|
|
errChan := make(chan error, 2)
|
|
go func() {
|
|
_, err := io.Copy(serverRw, remoteRw)
|
|
errChan <- err
|
|
}()
|
|
go func() {
|
|
_, err := io.Copy(remoteRw, serverRw)
|
|
errChan <- err
|
|
}()
|
|
// Block until one of the two goroutines returns
|
|
return <-errChan
|
|
}
|