mirror of
https://github.com/cbeuw/Cloak.git
synced 2024-10-23 15:46:25 +00:00
99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
package multiplex
|
|
|
|
import (
|
|
"net"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
// Copied from smux
|
|
errBrokenPipe = "broken pipe"
|
|
acceptBacklog = 1024
|
|
|
|
closeBacklog = 512
|
|
)
|
|
|
|
type Session struct {
|
|
id int
|
|
|
|
// Used in Stream.Write. Add multiplexing headers, encrypt and add TLS header
|
|
obfs func(*Frame) []byte
|
|
// Remove TLS header, decrypt and unmarshall multiplexing headers
|
|
deobfs func([]byte) *Frame
|
|
// This is supposed to read one TLS message, the same as GoQuiet's ReadTillDrain
|
|
obfsedReader func(net.Conn, []byte) (int, error)
|
|
|
|
nextStreamIDM sync.Mutex
|
|
nextStreamID uint32
|
|
|
|
streamsM sync.RWMutex
|
|
streams map[uint32]*Stream
|
|
|
|
// Switchboard manages all connections to remote
|
|
sb *switchboard
|
|
|
|
// For accepting new streams
|
|
acceptCh chan *Stream
|
|
// Once a stream.Close is called, it sends its streamID to this channel
|
|
// to be read by another stream to send the streamID to notify the remote
|
|
// that this stream is closed
|
|
closeQCh chan uint32
|
|
}
|
|
|
|
// TODO: put this in main maybe?
|
|
func MakeSession(id int, conns []net.Conn) *Session {
|
|
sesh := &Session{
|
|
id: id,
|
|
nextStreamID: 0,
|
|
streams: make(map[uint32]*Stream),
|
|
acceptCh: make(chan *Stream, acceptBacklog),
|
|
closeQCh: make(chan uint32, closeBacklog),
|
|
}
|
|
sesh.sb = makeSwitchboard(conns, sesh)
|
|
sesh.sb.run()
|
|
return sesh
|
|
}
|
|
|
|
func (sesh *Session) OpenStream() (*Stream, error) {
|
|
sesh.nextStreamIDM.Lock()
|
|
id := sesh.nextStreamID
|
|
sesh.nextStreamID += 1
|
|
sesh.nextStreamIDM.Unlock()
|
|
|
|
stream := makeStream(id, sesh)
|
|
|
|
sesh.streamsM.Lock()
|
|
sesh.streams[id] = stream
|
|
sesh.streamsM.Unlock()
|
|
return stream, nil
|
|
}
|
|
|
|
func (sesh *Session) AcceptStream() (*Stream, error) {
|
|
stream := <-sesh.acceptCh
|
|
return stream, nil
|
|
}
|
|
|
|
func (sesh *Session) delStream(id uint32) {
|
|
sesh.streamsM.RLock()
|
|
delete(sesh.streams, id)
|
|
sesh.streamsM.RUnlock()
|
|
}
|
|
|
|
func (sesh *Session) isStream(id uint32) bool {
|
|
sesh.streamsM.Lock()
|
|
_, ok := sesh.streams[id]
|
|
sesh.streamsM.Unlock()
|
|
return ok
|
|
}
|
|
|
|
func (sesh *Session) getStream(id uint32) *Stream {
|
|
sesh.streamsM.Lock()
|
|
defer sesh.streamsM.Unlock()
|
|
return sesh.streams[id]
|
|
}
|
|
|
|
func (sesh *Session) addStream(id uint32) {
|
|
stream := makeStream(id, sesh)
|
|
sesh.acceptCh <- stream
|
|
}
|