You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

323 lines
6.2 KiB

package dcmux
import (
"encoding/binary"
"sync"
)
type Stream struct {
ID uint16
ClientID uint32
recvBuf []byte
closed bool
nextSeq uint32
outOfOrder map[uint32][]byte
}
type Multiplexer struct {
streams map[uint16]*Stream
nextID uint16
clientID uint32
onSend func([]byte) error
mu sync.RWMutex
maxStreams int
maxBufferSize int
activityCh chan struct{}
dataReady map[uint16]chan struct{}
dataReadyMu sync.Mutex
sendSeq map[uint16]uint32
sendSeqMu sync.Mutex
}
func New(clientID uint32, onSend func([]byte) error) *Multiplexer {
return &Multiplexer{
streams: make(map[uint16]*Stream),
nextID: 1,
clientID: clientID,
onSend: onSend,
maxStreams: 10000,
maxBufferSize: 16 * 1024 * 1024,
activityCh: make(chan struct{}, 1),
dataReady: make(map[uint16]chan struct{}),
sendSeq: make(map[uint16]uint32),
}
}
func (m *Multiplexer) OpenStream() uint16 {
m.mu.Lock()
defer m.mu.Unlock()
for {
sid := m.nextID
m.nextID++
if m.nextID == 0 {
m.nextID = 1
}
if _, exists := m.streams[sid]; !exists {
m.streams[sid] = &Stream{
ID: sid,
recvBuf: make([]byte, 0),
nextSeq: 0,
outOfOrder: make(map[uint32][]byte),
}
return sid
}
}
}
func (m *Multiplexer) SendData(sid uint16, data []byte) error {
m.mu.RLock()
stream, exists := m.streams[sid]
m.mu.RUnlock()
if !exists || stream.closed {
return nil
}
const chunkSize = 7168
for i := 0; i < len(data); i += chunkSize {
end := i + chunkSize
if end > len(data) {
end = len(data)
}
chunk := data[i:end]
m.sendSeqMu.Lock()
seq := m.sendSeq[sid]
m.sendSeq[sid]++
m.sendSeqMu.Unlock()
frame := make([]byte, 12+len(chunk))
binary.BigEndian.PutUint32(frame[0:4], m.clientID)
binary.BigEndian.PutUint16(frame[4:6], sid)
binary.BigEndian.PutUint16(frame[6:8], uint16(len(chunk)))
binary.BigEndian.PutUint32(frame[8:12], seq)
copy(frame[12:], chunk)
if err := m.onSend(frame); err != nil {
return err
}
}
return nil
}
func (m *Multiplexer) CloseStream(sid uint16) error {
m.mu.Lock()
defer m.mu.Unlock()
if stream, exists := m.streams[sid]; exists {
stream.closed = true
}
m.sendSeqMu.Lock()
delete(m.sendSeq, sid)
m.sendSeqMu.Unlock()
m.signalDataReady(sid)
frame := make([]byte, 12)
binary.BigEndian.PutUint32(frame[0:4], m.clientID)
binary.BigEndian.PutUint16(frame[4:6], sid)
binary.BigEndian.PutUint16(frame[6:8], 0)
binary.BigEndian.PutUint32(frame[8:12], 0)
return m.onSend(frame)
}
func (m *Multiplexer) HandleFrame(frame []byte) {
if len(frame) < 12 {
return
}
clientID := binary.BigEndian.Uint32(frame[0:4])
sid := binary.BigEndian.Uint16(frame[4:6])
length := binary.BigEndian.Uint16(frame[6:8])
seq := binary.BigEndian.Uint32(frame[8:12])
if length == 0 {
m.mu.Lock()
if stream, exists := m.streams[sid]; exists && stream.ClientID == clientID {
stream.closed = true
}
m.mu.Unlock()
m.signalDataReady(sid)
return
}
if len(frame) < 12+int(length) {
return
}
data := frame[12 : 12+length]
m.mu.Lock()
defer m.mu.Unlock()
stream, exists := m.streams[sid]
if !exists {
if len(m.streams) >= m.maxStreams {
return
}
stream = &Stream{
ID: sid,
ClientID: clientID,
recvBuf: make([]byte, 0),
nextSeq: 0,
outOfOrder: make(map[uint32][]byte),
}
m.streams[sid] = stream
} else if stream.ClientID != clientID {
stream.ClientID = clientID
stream.recvBuf = make([]byte, 0)
stream.closed = false
stream.nextSeq = 0
stream.outOfOrder = make(map[uint32][]byte)
}
if seq == stream.nextSeq {
if len(stream.recvBuf)+len(data) > m.maxBufferSize {
stream.closed = true
m.signalDataReady(sid)
return
}
stream.recvBuf = append(stream.recvBuf, data...)
stream.nextSeq++
for {
nextData, ok := stream.outOfOrder[stream.nextSeq]
if !ok {
break
}
if len(stream.recvBuf)+len(nextData) > m.maxBufferSize {
stream.closed = true
m.signalDataReady(sid)
return
}
stream.recvBuf = append(stream.recvBuf, nextData...)
delete(stream.outOfOrder, stream.nextSeq)
stream.nextSeq++
}
m.signalDataReady(sid)
return
}
if seq > stream.nextSeq && len(stream.outOfOrder) < 100 {
stream.outOfOrder[seq] = append([]byte(nil), data...)
}
}
func (m *Multiplexer) ReadStream(sid uint16) []byte {
m.mu.Lock()
defer m.mu.Unlock()
stream, exists := m.streams[sid]
if !exists || len(stream.recvBuf) == 0 {
return nil
}
data := stream.recvBuf
stream.recvBuf = make([]byte, 0)
return data
}
func (m *Multiplexer) StreamClosed(sid uint16) bool {
m.mu.RLock()
defer m.mu.RUnlock()
stream, exists := m.streams[sid]
return !exists || stream.closed
}
func (m *Multiplexer) GetStreams() []uint16 {
m.mu.RLock()
defer m.mu.RUnlock()
sids := make([]uint16, 0, len(m.streams))
for sid := range m.streams {
sids = append(sids, sid)
}
return sids
}
func (m *Multiplexer) WaitForData(sid uint16) <-chan struct{} {
m.dataReadyMu.Lock()
defer m.dataReadyMu.Unlock()
if _, ok := m.dataReady[sid]; !ok {
m.dataReady[sid] = make(chan struct{}, 1)
}
return m.dataReady[sid]
}
func (m *Multiplexer) WaitForActivity() <-chan struct{} {
return m.activityCh
}
func (m *Multiplexer) CleanupStream(sid uint16) {
m.mu.Lock()
delete(m.streams, sid)
m.mu.Unlock()
m.sendSeqMu.Lock()
delete(m.sendSeq, sid)
m.sendSeqMu.Unlock()
m.dataReadyMu.Lock()
defer m.dataReadyMu.Unlock()
if ch, ok := m.dataReady[sid]; ok {
close(ch)
delete(m.dataReady, sid)
}
}
func (m *Multiplexer) Reset() {
m.mu.Lock()
for _, stream := range m.streams {
stream.closed = true
}
m.streams = make(map[uint16]*Stream)
m.nextID = 1
m.mu.Unlock()
m.sendSeqMu.Lock()
m.sendSeq = make(map[uint16]uint32)
m.sendSeqMu.Unlock()
m.dataReadyMu.Lock()
for sid, ch := range m.dataReady {
close(ch)
delete(m.dataReady, sid)
}
m.dataReadyMu.Unlock()
m.signalActivity()
}
func (m *Multiplexer) signalDataReady(sid uint16) {
m.signalActivity()
m.dataReadyMu.Lock()
defer m.dataReadyMu.Unlock()
ch, ok := m.dataReady[sid]
if !ok {
return
}
select {
case ch <- struct{}{}:
default:
}
}
func (m *Multiplexer) signalActivity() {
select {
case m.activityCh <- struct{}{}:
default:
}
}