forked from pion/srtp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsession_srtp.go
149 lines (122 loc) · 4.04 KB
/
session_srtp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package srtp
import (
"fmt"
"net"
"github.com/pions/rtp"
)
// SessionSRTP implements io.ReadWriteCloser and provides a bi-directional SRTP session
// SRTP itself does not have a design like this, but it is common in most applications
// for local/remote to each have their own keying material. This provides those patterns
// instead of making everyone re-implement
type SessionSRTP struct {
session
writeStream *WriteStreamSRTP
}
// NewSessionSRTP creates a SRTP session using conn as the underlying transport.
func NewSessionSRTP(conn net.Conn, config *Config) (*SessionSRTP, error) {
s := &SessionSRTP{
session: session{
nextConn: conn,
readStreams: map[uint32]readStream{},
newStream: make(chan readStream),
started: make(chan interface{}),
closed: make(chan interface{}),
},
}
s.writeStream = &WriteStreamSRTP{s}
err := s.session.start(
config.Keys.LocalMasterKey, config.Keys.LocalMasterSalt,
config.Keys.RemoteMasterKey, config.Keys.RemoteMasterSalt,
config.Profile,
s,
)
if err != nil {
return nil, err
}
return s, nil
}
// Start initializes any crypto context and allows reading/writing to begin
func (s *SessionSRTP) Start(localMasterKey, localMasterSalt, remoteMasterKey, remoteMasterSalt []byte, profile ProtectionProfile, nextConn net.Conn) error {
s.session.nextConn = nextConn
return s.session.start(localMasterKey, localMasterSalt, remoteMasterKey, remoteMasterSalt, profile, s)
}
// OpenWriteStream returns the global write stream for the Session
func (s *SessionSRTP) OpenWriteStream() (*WriteStreamSRTP, error) {
return s.writeStream, nil
}
// OpenReadStream opens a read stream for the given SSRC, it can be used
// if you want a certain SSRC, but don't want to wait for AcceptStream
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, fmt.Errorf("failed to open ReadStreamSRCTP, type assertion failed")
}
// AcceptStream returns a stream to handle RTCP for a single SSRC
func (s *SessionSRTP) AcceptStream() (*ReadStreamSRTP, uint32, error) {
stream, ok := <-s.newStream
if !ok {
return nil, 0, fmt.Errorf("SessionSRTP has been closed")
}
readStream, ok := stream.(*ReadStreamSRTP)
if !ok {
return nil, 0, fmt.Errorf("newStream was found, but failed type assertion")
}
return readStream, stream.GetSSRC(), nil
}
// Close ends the session
func (s *SessionSRTP) Close() error {
return s.session.close()
}
func (s *SessionSRTP) write(b []byte) (int, error) {
packet := &rtp.Packet{}
err := packet.Unmarshal(b)
if err != nil {
return 0, nil
}
return s.writeRTP(&packet.Header, packet.Payload)
}
func (s *SessionSRTP) writeRTP(header *rtp.Header, payload []byte) (int, error) {
if _, ok := <-s.session.started; ok {
return 0, fmt.Errorf("started channel used incorrectly, should only be closed")
}
s.session.localContextMutex.Lock()
defer s.session.localContextMutex.Unlock()
encrypted, err := s.localContext.encryptRTP(nil, header, payload)
if err != nil {
return 0, err
}
return s.session.nextConn.Write(encrypted)
}
func (s *SessionSRTP) decrypt(buf []byte) error {
h := &rtp.Header{}
if err := h.Unmarshal(buf); err != nil {
return err
}
r, isNew := s.session.getOrCreateReadStream(h.SSRC, s, newReadStreamSRTP)
if r == nil {
return nil // Session has been closed
} else if isNew {
s.session.newStream <- r // Notify AcceptStream
}
readStream, ok := r.(*ReadStreamSRTP)
if !ok {
return fmt.Errorf("failed to get/create ReadStreamSRTP")
}
// Ensure that readStream.Close() isn't called while in flight
readStream.mu.Lock()
defer readStream.mu.Unlock()
readBuf := <-readStream.readCh
decrypted, err := s.remoteContext.decryptRTP(readBuf, buf, h)
if err != nil {
return err
} else if len(decrypted) > len(readBuf) {
return fmt.Errorf("input buffer was not long enough to contain decrypted RTP")
}
readStream.readRetCh <- readResultSRTP{
len: len(decrypted),
header: h,
}
return nil
}