vendor.github.com.pion.srtp.v2.session.go Maven / Gradle / Ivy
The newest version!
// SPDX-FileCopyrightText: 2023 The Pion community
// SPDX-License-Identifier: MIT
package srtp
import (
"errors"
"io"
"net"
"sync"
"time"
"github.com/pion/logging"
"github.com/pion/transport/v2/packetio"
)
type streamSession interface {
Close() error
write([]byte) (int, error)
decrypt([]byte) error
}
type session struct {
localContextMutex sync.Mutex
localContext, remoteContext *Context
localOptions, remoteOptions []ContextOption
newStream chan readStream
acceptStreamTimeout time.Time
started chan interface{}
closed chan interface{}
readStreamsClosed bool
readStreams map[uint32]readStream
readStreamsLock sync.Mutex
log logging.LeveledLogger
bufferFactory func(packetType packetio.BufferPacketType, ssrc uint32) io.ReadWriteCloser
nextConn net.Conn
}
// Config is used to configure a session.
// You can provide either a KeyingMaterialExporter to export keys
// or directly pass the keys themselves.
// After a Config is passed to a session it must not be modified.
type Config struct {
Keys SessionKeys
Profile ProtectionProfile
BufferFactory func(packetType packetio.BufferPacketType, ssrc uint32) io.ReadWriteCloser
LoggerFactory logging.LoggerFactory
AcceptStreamTimeout time.Time
// List of local/remote context options.
// ReplayProtection is enabled on remote context by default.
// Default replay protection window size is 64.
LocalOptions, RemoteOptions []ContextOption
}
// SessionKeys bundles the keys required to setup an SRTP session
type SessionKeys struct {
LocalMasterKey []byte
LocalMasterSalt []byte
RemoteMasterKey []byte
RemoteMasterSalt []byte
}
func (s *session) getOrCreateReadStream(ssrc uint32, child streamSession, proto func() readStream) (readStream, bool) {
s.readStreamsLock.Lock()
defer s.readStreamsLock.Unlock()
if s.readStreamsClosed {
return nil, false
}
r, ok := s.readStreams[ssrc]
if ok {
return r, false
}
// Create the readStream.
r = proto()
if err := r.init(child, ssrc); err != nil {
return nil, false
}
s.readStreams[ssrc] = r
return r, true
}
func (s *session) removeReadStream(ssrc uint32) {
s.readStreamsLock.Lock()
defer s.readStreamsLock.Unlock()
if s.readStreamsClosed {
return
}
delete(s.readStreams, ssrc)
}
func (s *session) close() error {
if s.nextConn == nil {
return nil
} else if err := s.nextConn.Close(); err != nil {
return err
}
<-s.closed
return nil
}
func (s *session) start(localMasterKey, localMasterSalt, remoteMasterKey, remoteMasterSalt []byte, profile ProtectionProfile, child streamSession) error {
var err error
s.localContext, err = CreateContext(localMasterKey, localMasterSalt, profile, s.localOptions...)
if err != nil {
return err
}
s.remoteContext, err = CreateContext(remoteMasterKey, remoteMasterSalt, profile, s.remoteOptions...)
if err != nil {
return err
}
if err = s.nextConn.SetReadDeadline(s.acceptStreamTimeout); err != nil {
return err
}
go func() {
defer func() {
close(s.newStream)
s.readStreamsLock.Lock()
s.readStreamsClosed = true
s.readStreamsLock.Unlock()
close(s.closed)
}()
b := make([]byte, 8192)
for {
var i int
i, err = s.nextConn.Read(b)
if err != nil {
if !errors.Is(err, io.EOF) {
s.log.Error(err.Error())
}
return
}
if err = child.decrypt(b[:i]); err != nil {
s.log.Info(err.Error())
}
}
}()
close(s.started)
return nil
}