-
Notifications
You must be signed in to change notification settings - Fork 93
/
srtp_user.cc
209 lines (168 loc) · 7.49 KB
/
srtp_user.cc
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <uvgrtp/lib.hh>
#include <climits>
#include <iostream>
#include <cstring>
/* Encryption is also supported by uvgRTP. Encryption is facilitated
* by Secure RTP (SRTP) protocol. In order to use SRTP, the encryption
* context must be exchanged in some way. uvgRTP offers two main methods
* for exchanging the encryption contexts.
*
* This example presents the user implemented encryption key
* negotiation. In this scenario the encryption keys are exchanged
* by the application and handed over to uvgRTP. */
// network parameters of example
constexpr char SENDER_ADDRESS[] = "127.0.0.1";
constexpr uint16_t LOCAL_PORT = 8888;
constexpr char RECEIVER_ADDRESS[] = "127.0.0.1";
constexpr uint16_t REMOTE_PORT = 8890;
// encryption parameters of example
enum Key_length{SRTP_128 = 128, SRTP_196 = 196, SRTP_256 = 256};
constexpr Key_length KEY_SIZE = SRTP_256;
constexpr int KEY_SIZE_BYTES = KEY_SIZE/8;
constexpr int SALT_SIZE = 112;
constexpr int SALT_SIZE_BYTES = SALT_SIZE/8;
// demonstration parameters
constexpr auto EXAMPLE_DURATION = std::chrono::seconds(5);
constexpr int FRAME_RATE = 30; // fps
constexpr int SEND_TEST_PACKETS = (EXAMPLE_DURATION.count() - 1)*FRAME_RATE;
constexpr int PACKET_INTERVAL_MS = 1000/FRAME_RATE;
constexpr int RECEIVER_WAIT_TIME_MS = 100;
void process_frame(uvgrtp::frame::rtp_frame *frame);
void receive_func(uint8_t key[KEY_SIZE_BYTES], uint8_t salt[SALT_SIZE_BYTES]);
void wait_until_next_frame(std::chrono::steady_clock::time_point& start, int frame_index);
int main(void)
{
uvgrtp::context ctx;
// first we check if crypto has been included before attempting to use it
if (!ctx.crypto_enabled())
{
std::cerr << "Cannot run SRTP example if crypto is not included in uvgRTP!"
<< std::endl;
return EXIT_FAILURE;
}
/* Key and salt for the SRTP session of sender and receiver
*
* NOTE: uvgRTP supports 128, 196 and 256 bit keys and 112 bit salts */
uint8_t key[KEY_SIZE_BYTES] = { 0 };
uint8_t salt[SALT_SIZE_BYTES] = { 0 };
// initialize SRTP key and salt with dummy values
for (int i = 0; i < KEY_SIZE_BYTES; ++i)
key[i] = i;
for (int i = 0; i < SALT_SIZE_BYTES; ++i)
salt[i] = i * 2;
std::cout << "Starting uvgRTP SRTP user provided encryption key example. Using key:"
<< key << " and salt: " << salt << std::endl;
// Create separate thread for the receiver
std::thread receiver(receive_func, key, salt);
// Enable SRTP and let user manage the keys
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER | RCE_SRTP_KEYSIZE_256;
uvgrtp::session *sender_session = ctx.create_session(RECEIVER_ADDRESS);
uvgrtp::media_stream *send = sender_session->create_stream(LOCAL_PORT, REMOTE_PORT,
RTP_FORMAT_GENERIC, flags);
if (send)
{
/* When using user managed keys, before anything else can be done
* the add_srtp_ctx() must be called with the user SRTP key and salt.
*
* All calls to "send" that try to modify and or/use the newly
* created media stream before calling add_srtp_ctx() will fail
* if SRTP is enabled */
send->add_srtp_ctx(key, salt);
// All media is now encrypted/decrypted automatically
char* message = (char*)"Hello, world!";
size_t msg_len = strlen(message);
auto start = std::chrono::steady_clock::now();
for (unsigned int i = 0; i < SEND_TEST_PACKETS; ++i)
{
if ((i+1)%10 == 0 || i == 0) // print every 10 frames and first
std::cout << "Sending frame # " << i + 1 << '/' << SEND_TEST_PACKETS << std::endl;
uint8_t* message_data = new uint8_t[msg_len];
memcpy(message_data, message, msg_len);
if (send->push_frame((uint8_t *)message_data, msg_len, RTP_NO_FLAGS) != RTP_OK)
{
std::cerr << "Failed to send frame" << std::endl;
}
// wait until it is time to send the next frame. Included only for
// demostration purposes since you can use uvgRTP to send packets as fast as desired
wait_until_next_frame(start, i);
}
sender_session->destroy_stream(send);
}
else
{
std::cerr << "Failed to create SRTP sender" << std::endl;
}
if (receiver.joinable())
{
receiver.join();
}
if (sender_session)
ctx.destroy_session(sender_session);
return EXIT_SUCCESS;
}
void receive_func(uint8_t key[KEY_SIZE_BYTES], uint8_t salt[SALT_SIZE_BYTES])
{
/* See sending.cc for more details */
uvgrtp::context ctx;
uvgrtp::session *receiver_session = ctx.create_session(SENDER_ADDRESS);
/* Enable SRTP and let user manage keys */
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER;
/* With user-managed keys, you have the option to use 192- and 256-bit keys.
*
* If 192- or 256-bit key size is specified in the flags, add_srtp_ctx() expects
* the key parameter to be 24 or 32 bytes long, respectively. */
flags |= RCE_SRTP_KEYSIZE_256;
/* See sending.cc for more details about create_stream() */
uvgrtp::media_stream *recv = receiver_session->create_stream(REMOTE_PORT, LOCAL_PORT,
RTP_FORMAT_GENERIC, flags);
// Receive frames by pulling for EXAMPLE_DURATION milliseconds
if (recv)
{
/* Before anything else can be done,
* add_srtp_ctx() must be called with the SRTP key and salt.
*
* All calls to "recv" that try to modify and or/use the newly
* created media stream before calling add_srtp_ctx() will fail */
recv->add_srtp_ctx(key, salt);
std::cout << "Start receiving frames for " << EXAMPLE_DURATION.count() << " s" << std::endl;
auto start = std::chrono::steady_clock::now();
uvgrtp::frame::rtp_frame *frame = nullptr;
while (std::chrono::steady_clock::now() - start < EXAMPLE_DURATION)
{
/* You can specify a timeout for the operation and if the a frame is not received
* within that time limit, pull_frame() returns a nullptr
*
* The parameter tells how long time a frame is waited in milliseconds */
frame = recv->pull_frame(RECEIVER_WAIT_TIME_MS);
if (frame)
{
process_frame(frame);
}
}
receiver_session->destroy_stream(recv);
}
if (receiver_session)
{
ctx.destroy_session(receiver_session);
}
}
void process_frame(uvgrtp::frame::rtp_frame *frame)
{
std::string payload = std::string((char*)frame->payload, frame->payload_len);
std::cout << "Received SRTP frame. Payload: " << payload << std::endl;
/* When we receive a frame, the ownership of the frame belongs to us and
* when we're done with it, we need to deallocate the frame */
(void)uvgrtp::frame::dealloc_frame(frame);
}
void wait_until_next_frame(std::chrono::steady_clock::time_point &start, int frame_index)
{
// wait until it is time to send the next frame. Simulates a steady sending pace
// and included only for demostration purposes since you can use uvgRTP to send
// packets as fast as desired
auto time_since_start = std::chrono::steady_clock::now() - start;
auto next_frame_time = (frame_index + 1)*std::chrono::milliseconds(PACKET_INTERVAL_MS);
if (next_frame_time > time_since_start)
{
std::this_thread::sleep_for(next_frame_time - time_since_start);
}
}