2018-10-05 22:44:20 +00:00
|
|
|
package multiplex
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2019-08-14 09:04:27 +00:00
|
|
|
"io"
|
2019-07-23 10:06:49 +00:00
|
|
|
"net"
|
|
|
|
"time"
|
|
|
|
|
2018-10-05 22:44:20 +00:00
|
|
|
"sync"
|
2018-10-23 19:47:58 +00:00
|
|
|
"sync/atomic"
|
2023-03-06 16:51:05 +00:00
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
2018-10-05 22:44:20 +00:00
|
|
|
)
|
|
|
|
|
2019-01-06 01:40:27 +00:00
|
|
|
var ErrBrokenStream = errors.New("broken stream")
|
2018-10-05 22:44:20 +00:00
|
|
|
|
2020-10-18 14:36:40 +00:00
|
|
|
// Stream implements net.Conn. It represents an optionally-ordered, full-duplex, self-contained connection.
|
|
|
|
// If the session it belongs to runs in ordered mode, it provides ordering guarantee regardless of the underlying
|
|
|
|
// connection used.
|
|
|
|
// If the underlying connections the session uses are reliable, Stream is reliable. If they are not, Stream does not
|
|
|
|
// guarantee reliability.
|
2018-10-05 22:44:20 +00:00
|
|
|
type Stream struct {
|
|
|
|
id uint32
|
|
|
|
|
|
|
|
session *Session
|
|
|
|
|
2020-10-18 14:36:40 +00:00
|
|
|
// a buffer (implemented as an asynchronous buffered pipe) to put data we've received from recvFrame but hasn't
|
2020-12-31 23:53:22 +00:00
|
|
|
// been read by the consumer through Read or WriteTo.
|
2019-08-22 10:48:10 +00:00
|
|
|
recvBuf recvBuffer
|
2019-08-05 12:32:53 +00:00
|
|
|
|
2020-12-22 13:16:48 +00:00
|
|
|
writingM sync.Mutex
|
|
|
|
writingFrame Frame // we do the allocation here to save repeated allocations in Write and ReadFrom
|
2018-10-07 17:09:45 +00:00
|
|
|
|
2019-08-20 21:43:04 +00:00
|
|
|
// atomic
|
2019-07-28 10:58:45 +00:00
|
|
|
closed uint32
|
2019-08-04 09:38:49 +00:00
|
|
|
|
2020-10-18 14:36:40 +00:00
|
|
|
// When we want order guarantee (i.e. session.Unordered is false),
|
|
|
|
// we assign each stream a fixed underlying connection.
|
|
|
|
// If the underlying connections the session uses provide ordering guarantee (most likely TCP),
|
|
|
|
// recvBuffer (implemented by streamBuffer under ordered mode) will not receive out-of-order packets
|
|
|
|
// so it won't have to use its priority queue to sort it.
|
2019-08-20 21:43:04 +00:00
|
|
|
// This is not used in unordered connection mode
|
2020-12-28 01:10:24 +00:00
|
|
|
assignedConn net.Conn
|
2020-04-14 12:31:24 +00:00
|
|
|
|
2020-10-18 14:36:40 +00:00
|
|
|
readFromTimeout time.Duration
|
2018-10-05 22:44:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-12 11:51:00 +00:00
|
|
|
func makeStream(sesh *Session, id uint32) *Stream {
|
2018-10-05 22:44:20 +00:00
|
|
|
stream := &Stream{
|
2020-04-12 11:51:00 +00:00
|
|
|
id: id,
|
|
|
|
session: sesh,
|
2020-12-22 13:16:48 +00:00
|
|
|
writingFrame: Frame{
|
|
|
|
StreamID: id,
|
|
|
|
Seq: 0,
|
|
|
|
Closing: closingNothing,
|
|
|
|
},
|
2018-10-05 22:44:20 +00:00
|
|
|
}
|
2019-08-05 12:32:53 +00:00
|
|
|
|
2020-12-31 23:53:22 +00:00
|
|
|
if sesh.Unordered {
|
|
|
|
stream.recvBuf = NewDatagramBufferedPipe()
|
|
|
|
} else {
|
|
|
|
stream.recvBuf = NewStreamBuffer()
|
|
|
|
}
|
|
|
|
|
2018-10-05 22:44:20 +00:00
|
|
|
return stream
|
|
|
|
}
|
|
|
|
|
2019-07-28 10:58:45 +00:00
|
|
|
func (s *Stream) isClosed() bool { return atomic.LoadUint32(&s.closed) == 1 }
|
|
|
|
|
2020-10-18 13:42:47 +00:00
|
|
|
// receive a readily deobfuscated Frame so its payload can later be Read
|
2020-12-22 19:39:13 +00:00
|
|
|
func (s *Stream) recvFrame(frame *Frame) error {
|
2020-12-31 23:53:22 +00:00
|
|
|
toBeClosed, err := s.recvBuf.Write(frame)
|
2020-01-22 21:12:32 +00:00
|
|
|
if toBeClosed {
|
2020-04-20 22:54:41 +00:00
|
|
|
err = s.passiveClose()
|
|
|
|
if errors.Is(err, errRepeatStreamClosing) {
|
|
|
|
log.Debug(err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
2020-01-22 21:12:32 +00:00
|
|
|
}
|
|
|
|
return err
|
2019-08-11 23:48:20 +00:00
|
|
|
}
|
2019-08-05 13:33:20 +00:00
|
|
|
|
2019-08-20 21:43:04 +00:00
|
|
|
// Read implements io.Read
|
2019-07-28 10:58:45 +00:00
|
|
|
func (s *Stream) Read(buf []byte) (n int, err error) {
|
2019-08-06 10:19:47 +00:00
|
|
|
//log.Tracef("attempting to read from stream %v", s.id)
|
2018-10-16 20:13:19 +00:00
|
|
|
if len(buf) == 0 {
|
2020-04-08 17:16:54 +00:00
|
|
|
return 0, nil
|
2018-10-05 22:44:20 +00:00
|
|
|
}
|
2019-08-14 09:04:27 +00:00
|
|
|
|
2020-12-31 23:53:22 +00:00
|
|
|
n, err = s.recvBuf.Read(buf)
|
2020-04-13 15:39:19 +00:00
|
|
|
log.Tracef("%v read from stream %v with err %v", n, s.id, err)
|
2019-08-30 19:39:23 +00:00
|
|
|
if err == io.EOF {
|
|
|
|
return n, ErrBrokenStream
|
2018-10-16 20:13:19 +00:00
|
|
|
}
|
2019-08-30 19:39:23 +00:00
|
|
|
return
|
2020-04-12 11:43:24 +00:00
|
|
|
}
|
2019-08-30 19:39:23 +00:00
|
|
|
|
2020-10-18 14:36:40 +00:00
|
|
|
// WriteTo continuously write data Stream has received into the writer w.
|
2020-04-12 11:43:24 +00:00
|
|
|
func (s *Stream) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
// will keep writing until the underlying buffer is closed
|
2020-12-31 23:53:22 +00:00
|
|
|
n, err := s.recvBuf.WriteTo(w)
|
2020-04-12 22:01:30 +00:00
|
|
|
log.Tracef("%v read from stream %v with err %v", n, s.id, err)
|
2020-04-12 15:34:49 +00:00
|
|
|
if err == io.EOF {
|
|
|
|
return n, ErrBrokenStream
|
|
|
|
}
|
|
|
|
return n, nil
|
2018-10-05 22:44:20 +00:00
|
|
|
}
|
|
|
|
|
2020-12-24 11:35:29 +00:00
|
|
|
func (s *Stream) obfuscateAndSend(buf []byte, payloadOffsetInBuf int) error {
|
2020-12-26 00:49:36 +00:00
|
|
|
cipherTextLen, err := s.session.obfuscate(&s.writingFrame, buf, payloadOffsetInBuf)
|
2020-12-24 11:35:29 +00:00
|
|
|
s.writingFrame.Seq++
|
2020-04-12 22:01:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-12-28 01:10:24 +00:00
|
|
|
_, err = s.session.sb.send(buf[:cipherTextLen], &s.assignedConn)
|
2020-04-12 22:01:30 +00:00
|
|
|
if err != nil {
|
|
|
|
if err == errBrokenSwitchboard {
|
|
|
|
s.session.SetTerminalMsg(err.Error())
|
|
|
|
s.session.passiveClose()
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-08-20 21:43:04 +00:00
|
|
|
// Write implements io.Write
|
2019-07-28 10:58:45 +00:00
|
|
|
func (s *Stream) Write(in []byte) (n int, err error) {
|
2020-04-12 00:34:21 +00:00
|
|
|
s.writingM.Lock()
|
|
|
|
defer s.writingM.Unlock()
|
2019-07-28 10:58:45 +00:00
|
|
|
if s.isClosed() {
|
2019-01-06 01:40:27 +00:00
|
|
|
return 0, ErrBrokenStream
|
2018-10-05 22:44:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-10 17:48:36 +00:00
|
|
|
for n < len(in) {
|
|
|
|
var framePayload []byte
|
|
|
|
if len(in)-n <= s.session.maxStreamUnitWrite {
|
2020-10-18 14:36:40 +00:00
|
|
|
// if we can fit remaining data of in into one frame
|
2020-04-10 17:48:36 +00:00
|
|
|
framePayload = in[n:]
|
|
|
|
} else {
|
2020-10-18 14:36:40 +00:00
|
|
|
// if we have to split
|
|
|
|
if s.session.Unordered {
|
|
|
|
// but we are not allowed to
|
2020-04-11 21:37:15 +00:00
|
|
|
err = io.ErrShortBuffer
|
|
|
|
return
|
|
|
|
}
|
2020-04-10 17:48:36 +00:00
|
|
|
framePayload = in[n : s.session.maxStreamUnitWrite+n]
|
|
|
|
}
|
2020-12-22 13:16:48 +00:00
|
|
|
s.writingFrame.Payload = framePayload
|
2020-12-24 11:35:29 +00:00
|
|
|
buf := s.session.streamObfsBufPool.Get().(*[]byte)
|
|
|
|
err = s.obfuscateAndSend(*buf, 0)
|
|
|
|
s.session.streamObfsBufPool.Put(buf)
|
2020-04-10 17:48:36 +00:00
|
|
|
if err != nil {
|
2020-04-12 22:01:30 +00:00
|
|
|
return
|
2019-10-08 22:11:16 +00:00
|
|
|
}
|
2020-04-12 22:01:30 +00:00
|
|
|
n += len(framePayload)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2018-10-05 22:44:20 +00:00
|
|
|
|
2020-10-18 14:36:40 +00:00
|
|
|
// ReadFrom continuously read data from r and send it off, until either r returns error or nothing has been read
|
|
|
|
// for readFromTimeout amount of time
|
2020-04-12 22:01:30 +00:00
|
|
|
func (s *Stream) ReadFrom(r io.Reader) (n int64, err error) {
|
|
|
|
for {
|
2020-10-18 14:36:40 +00:00
|
|
|
if s.readFromTimeout != 0 {
|
2020-04-14 12:31:24 +00:00
|
|
|
if rder, ok := r.(net.Conn); !ok {
|
|
|
|
log.Warn("ReadFrom timeout is set but reader doesn't implement SetReadDeadline")
|
|
|
|
} else {
|
2020-10-18 14:36:40 +00:00
|
|
|
rder.SetReadDeadline(time.Now().Add(s.readFromTimeout))
|
2020-04-14 12:31:24 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-24 11:35:29 +00:00
|
|
|
buf := s.session.streamObfsBufPool.Get().(*[]byte)
|
|
|
|
read, er := r.Read((*buf)[frameHeaderLength : frameHeaderLength+s.session.maxStreamUnitWrite])
|
2020-04-12 22:01:30 +00:00
|
|
|
if er != nil {
|
|
|
|
return n, er
|
|
|
|
}
|
2020-12-23 22:33:01 +00:00
|
|
|
|
|
|
|
// the above read may have been unblocked by another goroutine calling stream.Close(), so we need
|
|
|
|
// to check that here
|
2020-04-12 22:01:30 +00:00
|
|
|
if s.isClosed() {
|
2020-04-13 15:39:19 +00:00
|
|
|
return n, ErrBrokenStream
|
|
|
|
}
|
|
|
|
|
|
|
|
s.writingM.Lock()
|
2020-12-24 11:35:29 +00:00
|
|
|
s.writingFrame.Payload = (*buf)[frameHeaderLength : frameHeaderLength+read]
|
|
|
|
err = s.obfuscateAndSend(*buf, frameHeaderLength)
|
2020-04-13 15:39:19 +00:00
|
|
|
s.writingM.Unlock()
|
2020-12-24 11:35:29 +00:00
|
|
|
s.session.streamObfsBufPool.Put(buf)
|
2020-04-13 15:39:19 +00:00
|
|
|
|
2020-04-10 17:48:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2020-04-12 22:01:30 +00:00
|
|
|
n += int64(read)
|
2020-04-10 17:48:36 +00:00
|
|
|
}
|
2018-10-05 22:44:20 +00:00
|
|
|
}
|
|
|
|
|
2019-10-14 14:34:14 +00:00
|
|
|
func (s *Stream) passiveClose() error {
|
|
|
|
return s.session.closeStream(s, false)
|
2018-10-27 22:35:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// active close. Close locally and tell the remote that this stream is being closed
|
2019-07-28 10:58:45 +00:00
|
|
|
func (s *Stream) Close() error {
|
2020-04-13 15:39:19 +00:00
|
|
|
s.writingM.Lock()
|
|
|
|
defer s.writingM.Unlock()
|
|
|
|
|
2019-10-14 14:34:14 +00:00
|
|
|
return s.session.closeStream(s, true)
|
2018-10-23 19:47:58 +00:00
|
|
|
}
|
2019-07-23 10:06:49 +00:00
|
|
|
|
2019-07-28 10:58:45 +00:00
|
|
|
func (s *Stream) LocalAddr() net.Addr { return s.session.addrs.Load().([]net.Addr)[0] }
|
|
|
|
func (s *Stream) RemoteAddr() net.Addr { return s.session.addrs.Load().([]net.Addr)[1] }
|
2019-07-23 10:06:49 +00:00
|
|
|
|
2020-12-31 23:53:22 +00:00
|
|
|
func (s *Stream) SetWriteToTimeout(d time.Duration) { s.recvBuf.SetWriteToTimeout(d) }
|
|
|
|
func (s *Stream) SetReadDeadline(t time.Time) error { s.recvBuf.SetReadDeadline(t); return nil }
|
2020-10-18 14:36:40 +00:00
|
|
|
func (s *Stream) SetReadFromTimeout(d time.Duration) { s.readFromTimeout = d }
|
2020-10-18 13:42:47 +00:00
|
|
|
|
|
|
|
var errNotImplemented = errors.New("Not implemented")
|
|
|
|
|
2020-10-18 14:36:40 +00:00
|
|
|
// the following functions are purely for implementing net.Conn interface.
|
|
|
|
// they are not used
|
|
|
|
// TODO: implement the following
|
2020-10-18 13:42:47 +00:00
|
|
|
func (s *Stream) SetDeadline(t time.Time) error { return errNotImplemented }
|
2019-07-28 10:58:45 +00:00
|
|
|
func (s *Stream) SetWriteDeadline(t time.Time) error { return errNotImplemented }
|