mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-04-25 12:48:09 +08:00
100 lines
1.7 KiB
Go
100 lines
1.7 KiB
Go
package session
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Stream implements net.Conn
|
|
type Stream struct {
|
|
id uint32
|
|
|
|
sess *Session
|
|
|
|
pipeR *io.PipeReader
|
|
pipeW *io.PipeWriter
|
|
|
|
dieOnce sync.Once
|
|
dieHook func()
|
|
}
|
|
|
|
// newStream initiates a Stream struct
|
|
func newStream(id uint32, sess *Session) *Stream {
|
|
s := new(Stream)
|
|
s.id = id
|
|
s.sess = sess
|
|
s.pipeR, s.pipeW = io.Pipe()
|
|
return s
|
|
}
|
|
|
|
// Read implements net.Conn
|
|
func (s *Stream) Read(b []byte) (n int, err error) {
|
|
return s.pipeR.Read(b)
|
|
}
|
|
|
|
// Write implements net.Conn
|
|
func (s *Stream) Write(b []byte) (n int, err error) {
|
|
f := newFrame(cmdPSH, s.id)
|
|
f.data = b
|
|
n, err = s.sess.writeFrame(f)
|
|
return
|
|
}
|
|
|
|
// Close implements net.Conn
|
|
func (s *Stream) Close() error {
|
|
if s.sessionClose() {
|
|
// notify remote
|
|
return s.sess.streamClosed(s.id)
|
|
} else {
|
|
return io.ErrClosedPipe
|
|
}
|
|
}
|
|
|
|
// sessionClose close stream from session side, do not notify remote
|
|
func (s *Stream) sessionClose() (once bool) {
|
|
s.dieOnce.Do(func() {
|
|
s.pipeR.Close()
|
|
once = true
|
|
if s.dieHook != nil {
|
|
s.dieHook()
|
|
s.dieHook = nil
|
|
}
|
|
})
|
|
return
|
|
}
|
|
|
|
func (s *Stream) SetReadDeadline(t time.Time) error {
|
|
return os.ErrNotExist
|
|
}
|
|
|
|
func (s *Stream) SetWriteDeadline(t time.Time) error {
|
|
return os.ErrNotExist
|
|
}
|
|
|
|
func (s *Stream) SetDeadline(t time.Time) error {
|
|
return os.ErrNotExist
|
|
}
|
|
|
|
// LocalAddr satisfies net.Conn interface
|
|
func (s *Stream) LocalAddr() net.Addr {
|
|
if ts, ok := s.sess.conn.(interface {
|
|
LocalAddr() net.Addr
|
|
}); ok {
|
|
return ts.LocalAddr()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RemoteAddr satisfies net.Conn interface
|
|
func (s *Stream) RemoteAddr() net.Addr {
|
|
if ts, ok := s.sess.conn.(interface {
|
|
RemoteAddr() net.Addr
|
|
}); ok {
|
|
return ts.RemoteAddr()
|
|
}
|
|
return nil
|
|
}
|