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