Files
webrtc/internal/network/srtp.go
Woodrow Douglass f62abe50e8 Add RTCP Messages
*Avoid a type switch in srtp.go
*Add support for transport layer nack and
    slice loss indication messages
*Add String() functions for several RTCP
    packets to aid in debugging
*Add support for transparent profile
    extensions to ReceiverReport messages

Relates to #119
2018-12-04 14:46:33 -05:00

142 lines
3.4 KiB
Go

package network
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"github.com/pions/webrtc/internal/srtp"
"github.com/pions/webrtc/pkg/rtcp"
"github.com/pions/webrtc/pkg/rtp"
"github.com/pkg/errors"
)
const (
srtpMasterKeyLen = 16
srtpMasterKeySaltLen = 14
)
// TODO: Migrate to srtp.Conn
// CreateContextSRTP takes the exported keying material from DTLS and creates Client/Server contexts
func (m *Manager) CreateContextSRTP(keyingMaterial []byte) error {
offset := 0
clientWriteKey := append([]byte{}, keyingMaterial[offset:offset+srtpMasterKeyLen]...)
offset += srtpMasterKeyLen
serverWriteKey := append([]byte{}, keyingMaterial[offset:offset+srtpMasterKeyLen]...)
offset += srtpMasterKeyLen
clientWriteKey = append(clientWriteKey, keyingMaterial[offset:offset+srtpMasterKeySaltLen]...)
offset += srtpMasterKeySaltLen
serverWriteKey = append(serverWriteKey, keyingMaterial[offset:offset+srtpMasterKeySaltLen]...)
var err error
m.srtpInboundContextLock.Lock()
m.srtpInboundContext, err = srtp.CreateContext(serverWriteKey[0:16], serverWriteKey[16:] /* Profile */, "")
m.srtpInboundContextLock.Unlock()
if err != nil {
return errors.New("failed to build inbound SRTP context")
}
m.srtpOutboundContextLock.Lock()
m.srtpOutboundContext, err = srtp.CreateContext(clientWriteKey[0:16], clientWriteKey[16:] /* Profile */, "")
m.srtpOutboundContextLock.Unlock()
if err != nil {
return errors.New("failed to build outbound SRTP context")
}
return nil
}
func handleRTCP(getBufferTransports func(uint32) *TransportPair, buffer []byte) {
//decrypted packets can also be compound packets, so we have to nest our reader loop here.
compoundPacket := rtcp.NewReader(bytes.NewReader(buffer))
for {
_, rawrtcp, err := compoundPacket.ReadPacket()
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err)
return
}
var report rtcp.Packet
report, _, err = rtcp.Unmarshal(rawrtcp)
if err != nil {
fmt.Println(err)
return
}
f := func(ssrc uint32) {
bufferTransport := getBufferTransports(ssrc)
if bufferTransport != nil && bufferTransport.RTCP != nil {
select {
case bufferTransport.RTCP <- report:
default:
}
}
}
for _, ssrc := range report.DestinationSSRC() {
f(ssrc)
}
}
}
func (m *Manager) handleSRTP(buffer []byte) {
m.srtpInboundContextLock.Lock()
defer m.srtpInboundContextLock.Unlock()
if m.srtpInboundContext == nil {
fmt.Printf("Got RTP packet but no SRTP Context to handle it \n")
return
}
if len(buffer) > 4 {
var rtcpPacketType uint8
r := bytes.NewReader([]byte{buffer[1]})
if err := binary.Read(r, binary.BigEndian, &rtcpPacketType); err != nil {
fmt.Println("Failed to check packet for RTCP")
return
}
if rtcpPacketType >= 192 && rtcpPacketType <= 223 {
decrypted, err := m.srtpInboundContext.DecryptRTCP(buffer)
if err != nil {
fmt.Println(err)
fmt.Println(decrypted)
return
}
handleRTCP(m.getBufferTransports, decrypted)
return
}
}
packet := &rtp.Packet{}
if err := packet.Unmarshal(buffer); err != nil {
fmt.Println("Failed to unmarshal RTP packet")
return
}
if ok := m.srtpInboundContext.DecryptRTP(packet); !ok {
fmt.Println("Failed to decrypt packet")
return
}
bufferTransport := m.getOrCreateBufferTransports(packet.SSRC, packet.PayloadType)
if bufferTransport != nil && bufferTransport.RTP != nil {
select {
case bufferTransport.RTP <- packet:
default:
}
}
}