2017-05-02 23:33:51 +00:00
|
|
|
package connection
|
|
|
|
|
|
|
|
import (
|
2018-06-08 21:54:31 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
2018-05-09 19:02:25 +00:00
|
|
|
"sync"
|
2017-05-02 23:33:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ChannelManager encapsulates the logic for server and client side assignment
|
|
|
|
// and removal of channels.
|
|
|
|
type ChannelManager struct {
|
|
|
|
channels map[int32]*channels.Channel
|
|
|
|
nextFreeChannel int32
|
|
|
|
isClient bool
|
2018-05-09 19:40:07 +00:00
|
|
|
lock sync.Mutex // ChannelManager may be accessed by multiple thread, so we need to protect the map.
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewClientChannelManager construsts a new channel manager enforcing behaviour
|
|
|
|
// of a ricochet client
|
|
|
|
func NewClientChannelManager() *ChannelManager {
|
|
|
|
channelManager := new(ChannelManager)
|
|
|
|
channelManager.channels = make(map[int32]*channels.Channel)
|
|
|
|
channelManager.nextFreeChannel = 1
|
|
|
|
channelManager.isClient = true
|
|
|
|
return channelManager
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewServerChannelManager construsts a new channel manager enforcing behaviour
|
|
|
|
// from a ricochet server
|
|
|
|
func NewServerChannelManager() *ChannelManager {
|
|
|
|
channelManager := new(ChannelManager)
|
|
|
|
channelManager.channels = make(map[int32]*channels.Channel)
|
|
|
|
channelManager.nextFreeChannel = 2
|
|
|
|
channelManager.isClient = false
|
|
|
|
return channelManager
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenChannelRequest constructs a channel type ready for processing given a request
|
|
|
|
// from the client.
|
|
|
|
func (cm *ChannelManager) OpenChannelRequest(chandler channels.Handler) (*channels.Channel, error) {
|
|
|
|
// Some channels only allow us to open one of them per connection
|
|
|
|
if chandler.Singleton() && cm.Channel(chandler.Type(), channels.Outbound) != nil {
|
2017-07-04 18:29:11 +00:00
|
|
|
return nil, utils.AttemptToOpenMoreThanOneSingletonChannelError
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
channel := new(channels.Channel)
|
|
|
|
channel.ID = cm.nextFreeChannel
|
|
|
|
cm.nextFreeChannel += 2
|
|
|
|
channel.Type = chandler.Type()
|
2017-09-23 22:29:46 +00:00
|
|
|
channel.Handler = chandler
|
2017-05-02 23:33:51 +00:00
|
|
|
channel.Pending = true
|
|
|
|
channel.Direction = channels.Outbound
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Lock()
|
2017-05-02 23:33:51 +00:00
|
|
|
cm.channels[channel.ID] = channel
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Unlock()
|
2017-05-02 23:33:51 +00:00
|
|
|
return channel, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenChannelRequestFromPeer constructs a channel type ready for processing given a request
|
|
|
|
// from the remote peer.
|
|
|
|
func (cm *ChannelManager) OpenChannelRequestFromPeer(channelID int32, chandler channels.Handler) (*channels.Channel, error) {
|
|
|
|
if cm.isClient && (channelID%2) != 0 {
|
|
|
|
// Server is trying to open odd numbered channels
|
2017-07-04 18:29:11 +00:00
|
|
|
return nil, utils.ServerAttemptedToOpenEvenNumberedChannelError
|
2017-05-02 23:33:51 +00:00
|
|
|
} else if !cm.isClient && (channelID%2) == 0 {
|
|
|
|
// Server is trying to open odd numbered channels
|
2017-07-04 18:29:11 +00:00
|
|
|
return nil, utils.ClientAttemptedToOpenOddNumberedChannelError
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Lock()
|
2017-05-02 23:33:51 +00:00
|
|
|
_, exists := cm.channels[channelID]
|
|
|
|
if exists {
|
2018-05-09 20:48:41 +00:00
|
|
|
cm.lock.Unlock()
|
2017-07-04 18:29:11 +00:00
|
|
|
return nil, utils.ChannelIDIsAlreadyInUseError
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Unlock()
|
2017-05-02 23:33:51 +00:00
|
|
|
|
|
|
|
// Some channels only allow us to open one of them per connection
|
|
|
|
if chandler.Singleton() && cm.Channel(chandler.Type(), channels.Inbound) != nil {
|
2017-07-04 18:29:11 +00:00
|
|
|
return nil, utils.AttemptToOpenMoreThanOneSingletonChannelError
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
channel := new(channels.Channel)
|
|
|
|
channel.ID = channelID
|
|
|
|
channel.Type = chandler.Type()
|
2017-09-23 22:29:46 +00:00
|
|
|
channel.Handler = chandler
|
2017-05-02 23:33:51 +00:00
|
|
|
|
|
|
|
channel.Pending = true
|
|
|
|
channel.Direction = channels.Inbound
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Lock()
|
2017-05-02 23:33:51 +00:00
|
|
|
cm.channels[channelID] = channel
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Unlock()
|
2017-05-02 23:33:51 +00:00
|
|
|
return channel, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Channel finds an open or pending `type` channel in the direction `way` (Inbound
|
|
|
|
// or Outbound), and returns the associated state. Returns nil if no matching channel
|
|
|
|
// exists or if multiple matching channels exist.
|
|
|
|
func (cm *ChannelManager) Channel(ctype string, way channels.Direction) *channels.Channel {
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Lock()
|
2017-05-02 23:33:51 +00:00
|
|
|
var foundChannel *channels.Channel
|
|
|
|
for _, channel := range cm.channels {
|
2017-09-23 22:29:46 +00:00
|
|
|
if channel.Handler.Type() == ctype && channel.Direction == way {
|
2017-05-02 23:33:51 +00:00
|
|
|
if foundChannel == nil {
|
|
|
|
foundChannel = channel
|
|
|
|
} else {
|
|
|
|
// we have found multiple channels.
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Unlock()
|
2017-05-02 23:33:51 +00:00
|
|
|
return foundChannel
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetChannel finds and returns a given channel if it is found
|
|
|
|
func (cm *ChannelManager) GetChannel(channelID int32) (*channels.Channel, bool) {
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Lock()
|
2017-05-02 23:33:51 +00:00
|
|
|
channel, found := cm.channels[channelID]
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Unlock()
|
2017-05-02 23:33:51 +00:00
|
|
|
return channel, found
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveChannel removes a given channel id.
|
|
|
|
func (cm *ChannelManager) RemoveChannel(channelID int32) {
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Lock()
|
2017-05-02 23:33:51 +00:00
|
|
|
delete(cm.channels, channelID)
|
2018-05-09 19:02:25 +00:00
|
|
|
cm.lock.Unlock()
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|