mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-23 01:27:04 +00:00
https://github.com/XTLS/Xray-core/pull/5414#issuecomment-3796734827 https://github.com/XTLS/Xray-core/pull/5581#issuecomment-3797134147 https://github.com/XTLS/Xray-core/pull/5645#issuecomment-3899873945 https://github.com/XTLS/Xray-core/pull/6745#issuecomment-5627420177 https://github.com/XTLS/Xray-core/pull/6748#issuecomment-5740443122 --------- Co-authored-by: Risaro <62798663+Risaro@users.noreply.github.com>
140 lines
2.6 KiB
Go
140 lines
2.6 KiB
Go
package xdrive
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/xtls/xray-core/common/net"
|
|
)
|
|
|
|
var placeholderAddr = &net.TCPAddr{IP: net.IP{127, 0, 0, 1}, Port: 0}
|
|
|
|
type Conn struct {
|
|
cancel context.CancelFunc
|
|
writer *walWriter
|
|
reader *walReader
|
|
onClose func()
|
|
|
|
readBuf []byte
|
|
|
|
deadlineMu sync.Mutex
|
|
readDeadline time.Time
|
|
writeDeadline time.Time
|
|
|
|
closeOnce sync.Once
|
|
closeErr error
|
|
}
|
|
|
|
func newConn(ctx context.Context, storage Storage, writePrefix, readPrefix string, p params, onClose func()) *Conn {
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
return &Conn{
|
|
cancel: cancel,
|
|
writer: newWALWriter(ctx, storage, writePrefix, p),
|
|
reader: newWALReader(ctx, storage, readPrefix, p),
|
|
onClose: onClose,
|
|
}
|
|
}
|
|
|
|
func (c *Conn) Read(b []byte) (int, error) {
|
|
if len(c.readBuf) == 0 {
|
|
data, err := c.receive()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
c.readBuf = data
|
|
}
|
|
n := copy(b, c.readBuf)
|
|
c.readBuf = c.readBuf[n:]
|
|
return n, nil
|
|
}
|
|
|
|
func (c *Conn) receive() ([]byte, error) {
|
|
deadline := c.getDeadline(true)
|
|
if deadline.IsZero() {
|
|
data, ok := <-c.reader.ch
|
|
if !ok {
|
|
return nil, c.reader.Err()
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
if !time.Now().Before(deadline) {
|
|
return nil, os.ErrDeadlineExceeded
|
|
}
|
|
timer := time.NewTimer(time.Until(deadline))
|
|
defer timer.Stop()
|
|
|
|
select {
|
|
case data, ok := <-c.reader.ch:
|
|
if !ok {
|
|
return nil, c.reader.Err()
|
|
}
|
|
return data, nil
|
|
case <-timer.C:
|
|
return nil, os.ErrDeadlineExceeded
|
|
}
|
|
}
|
|
|
|
func (c *Conn) Write(b []byte) (int, error) {
|
|
if deadline := c.getDeadline(false); !deadline.IsZero() && !time.Now().Before(deadline) {
|
|
return 0, os.ErrDeadlineExceeded
|
|
}
|
|
n, err := c.writer.Write(b)
|
|
if err == nil {
|
|
c.reader.Wake()
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
func (c *Conn) Close() error {
|
|
c.closeOnce.Do(func() {
|
|
c.closeErr = c.writer.Close()
|
|
c.cancel()
|
|
if c.onClose != nil {
|
|
c.onClose()
|
|
}
|
|
})
|
|
return c.closeErr
|
|
}
|
|
|
|
func (c *Conn) LocalAddr() net.Addr {
|
|
return placeholderAddr
|
|
}
|
|
|
|
func (c *Conn) RemoteAddr() net.Addr {
|
|
return placeholderAddr
|
|
}
|
|
|
|
func (c *Conn) getDeadline(read bool) time.Time {
|
|
c.deadlineMu.Lock()
|
|
defer c.deadlineMu.Unlock()
|
|
if read {
|
|
return c.readDeadline
|
|
}
|
|
return c.writeDeadline
|
|
}
|
|
|
|
func (c *Conn) SetDeadline(t time.Time) error {
|
|
c.deadlineMu.Lock()
|
|
defer c.deadlineMu.Unlock()
|
|
c.readDeadline = t
|
|
c.writeDeadline = t
|
|
return nil
|
|
}
|
|
|
|
func (c *Conn) SetReadDeadline(t time.Time) error {
|
|
c.deadlineMu.Lock()
|
|
defer c.deadlineMu.Unlock()
|
|
c.readDeadline = t
|
|
return nil
|
|
}
|
|
|
|
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
|
c.deadlineMu.Lock()
|
|
defer c.deadlineMu.Unlock()
|
|
c.writeDeadline = t
|
|
return nil
|
|
}
|