1 /*
2
3 This is an example of how the RTPSecureSession can be used. That class
4 provides the code to encrypt/decrypt RTP and RTCP data using libsrtp.
5 The code below provides further initialization code so that the same
6 key is used for incoming and outgoing data.
7
8 Apart from the srtp stuff, the code to send/receive packets is very
9 similar to example6
10
11 */
12
13 #include "rtpconfig.h"
14 #include <iostream>
15
16 using namespace std;
17
18 #ifdef RTP_SUPPORT_SRTP
19
20 #include "rtpsecuresession.h"
21 #include "rtpudpv4transmitter.h"
22 #include "rtpipv4address.h"
23 #include "rtpsessionparams.h"
24 #include "rtperrors.h"
25 #include "rtplibraryversion.h"
26 #include "rtpsourcedata.h"
27 #include "rtprawpacket.h"
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <srtp/srtp.h>
31 #include <string>
32
33 using namespace jrtplib;
34
checkerror(int rtperr)35 void checkerror(int rtperr)
36 {
37 if (rtperr < 0)
38 {
39 cerr << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
40 exit(-1);
41 }
42 }
43
checkerror(bool ok)44 void checkerror(bool ok)
45 {
46 if (!ok)
47 exit(-1);
48 }
49
50 class MyRTPSession : public RTPSecureSession
51 {
52 public:
Init(const std::string & key)53 bool Init(const std::string &key)
54 {
55 if (!IsActive())
56 {
57 cerr << "The Create function must be called before this one!" << endl;
58 return false;
59 }
60
61 if (key.length() != 30)
62 {
63 cerr << "Key length must be 30";
64 return false;
65 }
66
67 int status = InitializeSRTPContext();
68 if (status < 0)
69 {
70 int srtpErr = GetLastLibSRTPError();
71 if (srtpErr < 0)
72 cerr << "libsrtp error: " << srtpErr << endl;
73 checkerror(status);
74 }
75
76 srtp_policy_t policyIn, policyOut;
77
78 memset(&policyIn, 0, sizeof(srtp_policy_t));
79 memset(&policyOut, 0, sizeof(srtp_policy_t));
80
81 crypto_policy_set_rtp_default(&policyIn.rtp);
82 crypto_policy_set_rtcp_default(&policyIn.rtcp);
83
84 crypto_policy_set_rtp_default(&policyOut.rtp);
85 crypto_policy_set_rtcp_default(&policyOut.rtcp);
86
87 policyIn.ssrc.type = ssrc_any_inbound;
88 policyIn.key = (uint8_t *)key.c_str();
89 policyIn.next = 0;
90
91 policyOut.ssrc.type = ssrc_specific;
92 policyOut.ssrc.value = GetLocalSSRC();
93 policyOut.key = (uint8_t *)key.c_str();
94 policyOut.next = 0;
95
96 srtp_t ctx = LockSRTPContext();
97 if (ctx == 0)
98 {
99 cerr << "Unable to get/lock srtp context" << endl;
100 return false;
101 }
102 err_status_t err = srtp_add_stream(ctx, &policyIn);
103 if (err == err_status_ok)
104 err = srtp_add_stream(ctx, &policyOut);
105 UnlockSRTPContext();
106
107 if (err != err_status_ok)
108 {
109 cerr << "libsrtp error while adding stream: " << err << endl;
110 return false;
111 }
112 return true;
113 }
114 protected:
OnValidatedRTPPacket(RTPSourceData * srcdat,RTPPacket * rtppack,bool isonprobation,bool * ispackethandled)115 void OnValidatedRTPPacket(RTPSourceData *srcdat, RTPPacket *rtppack, bool isonprobation, bool *ispackethandled)
116 {
117 printf("SSRC %x Got packet in OnValidatedRTPPacket from source 0x%04x!\n", GetLocalSSRC(), srcdat->GetSSRC());
118 DeletePacket(rtppack);
119 *ispackethandled = true;
120 }
121
OnRTCPSDESItem(RTPSourceData * srcdat,RTCPSDESPacket::ItemType t,const void * itemdata,size_t itemlength)122 void OnRTCPSDESItem(RTPSourceData *srcdat, RTCPSDESPacket::ItemType t, const void *itemdata, size_t itemlength)
123 {
124 char msg[1024];
125
126 memset(msg, 0, sizeof(msg));
127 if (itemlength >= sizeof(msg))
128 itemlength = sizeof(msg)-1;
129
130 memcpy(msg, itemdata, itemlength);
131 printf("SSRC %x Received SDES item (%d): %s from SSRC %x\n", GetLocalSSRC(), (int)t, msg, srcdat->GetSSRC());
132 }
133
OnErrorChangeIncomingData(int errcode,int libsrtperrorcode)134 void OnErrorChangeIncomingData(int errcode, int libsrtperrorcode)
135 {
136 printf("SSRC %x JRTPLIB Error: %s\n", GetLocalSSRC(), RTPGetErrorString(errcode).c_str());
137 if (libsrtperrorcode != err_status_ok)
138 printf("libsrtp error: %d\n", libsrtperrorcode);
139 printf("\n");
140 }
141 };
142
main(void)143 int main(void)
144 {
145 #ifdef RTP_SOCKETTYPE_WINSOCK
146 WSADATA dat;
147 WSAStartup(MAKEWORD(2,2),&dat);
148 #endif // RTP_SOCKETTYPE_WINSOCK
149
150 // Initialize the SRTP library
151 srtp_init();
152
153 // Let's create two session, of which one sends to the other
154 MyRTPSession sender, receiver;
155 uint16_t portbase1 = 5000;
156 uint16_t portbase2 = 5002;
157 uint32_t destip = ntohl(inet_addr("127.0.0.1"));
158 int status;
159
160 RTPUDPv4TransmissionParams transparams;
161 RTPSessionParams sessparams;
162
163 sessparams.SetOwnTimestampUnit(1.0/10.0);
164
165 transparams.SetPortbase(portbase1);
166 sessparams.SetCNAME("sender@host"); // Force a CNAME, so that it's clear in the SDES field who sent it
167 status = sender.Create(sessparams,&transparams);
168 checkerror(status);
169
170 transparams.SetPortbase(portbase2);
171 sessparams.SetCNAME("receiver@host"); // Same as above
172 status = receiver.Create(sessparams,&transparams);
173 checkerror(status);
174
175 printf("Sender is: %x\n", sender.GetLocalSSRC());
176 printf("Receiver is: %x\n\n", receiver.GetLocalSSRC());
177
178 // Sender adds receiver as destination and vice versa (so that the
179 // receiver's RTCP data will be received)
180 status = sender.AddDestination(RTPIPv4Address(destip, portbase2));
181 checkerror(status);
182 status = receiver.AddDestination(RTPIPv4Address(destip, portbase1));
183 checkerror(status);
184
185 // Set the same key for sender and receiver
186 string key = "012345678901234567890123456789";
187 status = sender.Init(key);
188 checkerror(status);
189 status = receiver.Init(key);
190 checkerror(status);
191
192 const int num = 20;
193 for (int i = 1 ; i <= num ; i++)
194 {
195 printf("\nSending packet %d/%d\n",i,num);
196
197 // send the packet
198 status = sender.SendPacket((void *)"1234567890",10,0,false,10);
199 checkerror(status);
200
201 // Either the background thread or the poll function itself will
202 // cause the OnValidatedRTPPacket and OnRTCPSDESItem functions to
203 // be called, so in this loop there's not much left to do.
204
205 #ifndef RTP_SUPPORT_THREAD
206 status = sender.Poll();
207 checkerror(status);
208 status = receiver.Poll();
209 checkerror(status);
210 #endif // RTP_SUPPORT_THREAD
211
212 RTPTime::Wait(RTPTime(1,0));
213 }
214
215 // Make sure we shut the threads down before doing srtp_shutdown
216 sender.Destroy();
217 receiver.Destroy();
218
219 // De-initialize the SRTP library
220 srtp_shutdown();
221
222 #ifdef RTP_SOCKETTYPE_WINSOCK
223 WSACleanup();
224 #endif // RTP_SOCKETTYPE_WINSOCK
225 return 0;
226 }
227
228 #else
229
main(void)230 int main(void)
231 {
232 cout << "SRTP support was not enabled at compile time" << endl;
233 return 0;
234 }
235
236 #endif // RTP_SUPPORT_SRTP
237