package srtp
import (
"net"
"sync"
"time"
"github.com/pion/logging"
"github.com/pion/rtp"
)
const defaultSessionSRTPReplayProtectionWindow = 64
type SessionSRTP struct {
session
writeStream *WriteStreamSRTP
}
func NewSessionSRTP (conn net .Conn , config *Config ) (*SessionSRTP , error ) {
if config == nil {
return nil , errNoConfig
} else if conn == nil {
return nil , errNoConn
}
loggerFactory := config .LoggerFactory
if loggerFactory == nil {
loggerFactory = logging .NewDefaultLoggerFactory ()
}
localOpts := append (
[]ContextOption {},
config .LocalOptions ...,
)
remoteOpts := append (
[]ContextOption {
SRTPReplayProtection (defaultSessionSRTPReplayProtectionWindow ),
},
config .RemoteOptions ...,
)
srtpSession := &SessionSRTP {
session : session {
nextConn : conn ,
localOptions : localOpts ,
remoteOptions : remoteOpts ,
readStreams : map [uint32 ]readStream {},
newStream : make (chan readStream ),
acceptStreamTimeout : config .AcceptStreamTimeout ,
started : make (chan interface {}),
closed : make (chan interface {}),
bufferFactory : config .BufferFactory ,
log : loggerFactory .NewLogger ("srtp" ),
},
}
srtpSession .writeStream = &WriteStreamSRTP {srtpSession }
err := srtpSession .session .start (
config .Keys .LocalMasterKey , config .Keys .LocalMasterSalt ,
config .Keys .RemoteMasterKey , config .Keys .RemoteMasterSalt ,
config .Profile ,
srtpSession ,
)
if err != nil {
return nil , err
}
return srtpSession , nil
}
func (s *SessionSRTP ) OpenWriteStream () (*WriteStreamSRTP , error ) {
return s .writeStream , nil
}
func (s *SessionSRTP ) OpenReadStream (ssrc uint32 ) (*ReadStreamSRTP , error ) {
r , _ := s .session .getOrCreateReadStream (ssrc , s , newReadStreamSRTP )
if readStream , ok := r .(*ReadStreamSRTP ); ok {
return readStream , nil
}
return nil , errFailedTypeAssertion
}
func (s *SessionSRTP ) AcceptStream () (*ReadStreamSRTP , uint32 , error ) {
stream , ok := <-s .newStream
if !ok {
return nil , 0 , errStreamAlreadyClosed
}
readStream , ok := stream .(*ReadStreamSRTP )
if !ok {
return nil , 0 , errFailedTypeAssertion
}
return readStream , stream .GetSSRC (), nil
}
func (s *SessionSRTP ) Close () error {
return s .session .close ()
}
func (s *SessionSRTP ) write (b []byte ) (int , error ) {
packet := &rtp .Packet {}
if err := packet .Unmarshal (b ); err != nil {
return 0 , err
}
return s .writeRTP (&packet .Header , packet .Payload )
}
var bufferpool = sync .Pool {
New : func () interface {} {
return make ([]byte , 1492 )
},
}
func (s *SessionSRTP ) writeRTP (header *rtp .Header , payload []byte ) (int , error ) {
if _ , ok := <-s .session .started ; ok {
return 0 , errStartedChannelUsedIncorrectly
}
ibuf := bufferpool .Get ()
defer bufferpool .Put (ibuf )
buf := ibuf .([]byte )
headerLen , marshalSize := rtp .HeaderAndPacketMarshalSize (header , payload )
if len (buf ) < marshalSize +20 {
buf = make ([]byte , marshalSize +20 )
}
_ , err := rtp .MarshalPacketTo (buf , header , payload )
if err != nil {
return 0 , err
}
s .session .localContextMutex .Lock ()
encrypted , err := s .localContext .encryptRTP (buf , header , headerLen , buf [:marshalSize ])
s .session .localContextMutex .Unlock ()
if err != nil {
return 0 , err
}
return s .session .nextConn .Write (encrypted )
}
func (s *SessionSRTP ) setWriteDeadline (t time .Time ) error {
return s .session .nextConn .SetWriteDeadline (t )
}
func (s *SessionSRTP ) decrypt (buf []byte ) error {
header := &rtp .Header {}
headerLen , err := header .Unmarshal (buf )
if err != nil {
return err
}
r , isNew := s .session .getOrCreateReadStream (header .SSRC , s , newReadStreamSRTP )
if r == nil {
return nil
} else if isNew {
if !s .session .acceptStreamTimeout .IsZero () {
_ = s .session .nextConn .SetReadDeadline (time .Time {})
}
s .session .newStream <- r
}
readStream , ok := r .(*ReadStreamSRTP )
if !ok {
return errFailedTypeAssertion
}
decrypted , err := s .remoteContext .decryptRTP (buf , buf , header , headerLen )
if err != nil {
return err
}
_, err = readStream .write (decrypted )
if err != nil {
return err
}
return nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .