1 /*
2
3 This file is a part of JRTPLIB
4 Copyright (c) 1999-2017 Jori Liesenborgs
5
6 Contact: jori.liesenborgs@gmail.com
7
8 This library was developed at the Expertise Centre for Digital Media
9 (http://www.edm.uhasselt.be), a research center of the Hasselt University
10 (http://www.uhasselt.be). The library is based upon work done for
11 my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
12
13 Permission is hereby granted, free of charge, to any person obtaining a
14 copy of this software and associated documentation files (the "Software"),
15 to deal in the Software without restriction, including without limitation
16 the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 and/or sell copies of the Software, and to permit persons to whom the
18 Software is furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included
21 in all copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29 IN THE SOFTWARE.
30
31 */
32
33 #include "rtppacket.h"
34 #include "rtpstructs.h"
35 #include "rtpdefines.h"
36 #include "rtperrors.h"
37 #include "rtprawpacket.h"
38 #ifdef RTP_SUPPORT_NETINET_IN
39 #include <netinet/in.h>
40 #endif // RTP_SUPPORT_NETINET_IN
41 #include <string.h>
42
43 #ifdef RTPDEBUG
44 #include <stdio.h>
45 #endif // RTPDEBUG
46
47 #include "rtpdebug.h"
48
49 namespace jrtplib
50 {
51
Clear()52 void RTPPacket::Clear()
53 {
54 hasextension = false;
55 hasmarker = false;
56 numcsrcs = 0;
57 payloadtype = 0;
58 extseqnr = 0;
59 timestamp = 0;
60 ssrc = 0;
61 packet = 0;
62 payload = 0;
63 packetlength = 0;
64 payloadlength = 0;
65 extid = 0;
66 extension = 0;
67 extensionlength = 0;
68 error = 0;
69 externalbuffer = false;
70 }
71
RTPPacket(RTPRawPacket & rawpack,RTPMemoryManager * mgr)72 RTPPacket::RTPPacket(RTPRawPacket &rawpack,RTPMemoryManager *mgr) : RTPMemoryObject(mgr),receivetime(rawpack.GetReceiveTime())
73 {
74 Clear();
75 error = ParseRawPacket(rawpack);
76 }
77
RTPPacket(uint8_t payloadtype,const void * payloaddata,size_t payloadlen,uint16_t seqnr,uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t * csrcs,bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void * extensiondata,size_t maxpacksize,RTPMemoryManager * mgr)78 RTPPacket::RTPPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
79 uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
80 bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
81 size_t maxpacksize, RTPMemoryManager *mgr) : RTPMemoryObject(mgr),receivetime(0,0)
82 {
83 Clear();
84 error = BuildPacket(payloadtype,payloaddata,payloadlen,seqnr,timestamp,ssrc,gotmarker,numcsrcs,
85 csrcs,gotextension,extensionid,extensionlen_numwords,extensiondata,0,maxpacksize);
86 }
87
RTPPacket(uint8_t payloadtype,const void * payloaddata,size_t payloadlen,uint16_t seqnr,uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t * csrcs,bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void * extensiondata,void * buffer,size_t buffersize,RTPMemoryManager * mgr)88 RTPPacket::RTPPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
89 uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
90 bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
91 void *buffer,size_t buffersize, RTPMemoryManager *mgr) : RTPMemoryObject(mgr),receivetime(0,0)
92 {
93 Clear();
94 if (buffer == 0)
95 error = ERR_RTP_PACKET_EXTERNALBUFFERNULL;
96 else if (buffersize <= 0)
97 error = ERR_RTP_PACKET_ILLEGALBUFFERSIZE;
98 else
99 error = BuildPacket(payloadtype,payloaddata,payloadlen,seqnr,timestamp,ssrc,gotmarker,numcsrcs,
100 csrcs,gotextension,extensionid,extensionlen_numwords,extensiondata,buffer,buffersize);
101 }
102
ParseRawPacket(RTPRawPacket & rawpack)103 int RTPPacket::ParseRawPacket(RTPRawPacket &rawpack)
104 {
105 uint8_t *packetbytes;
106 size_t packetlen;
107 uint8_t payloadtype;
108 RTPHeader *rtpheader;
109 bool marker;
110 int csrccount;
111 bool hasextension;
112 int payloadoffset,payloadlength;
113 int numpadbytes;
114 RTPExtensionHeader *rtpextheader;
115
116 if (!rawpack.IsRTP()) // If we didn't receive it on the RTP port, we'll ignore it
117 return ERR_RTP_PACKET_INVALIDPACKET;
118
119 // The length should be at least the size of the RTP header
120 packetlen = rawpack.GetDataLength();
121 if (packetlen < sizeof(RTPHeader))
122 return ERR_RTP_PACKET_INVALIDPACKET;
123
124 packetbytes = (uint8_t *)rawpack.GetData();
125 rtpheader = (RTPHeader *)packetbytes;
126
127 // The version number should be correct
128 if (rtpheader->version != RTP_VERSION)
129 return ERR_RTP_PACKET_INVALIDPACKET;
130
131 // We'll check if this is possibly a RTCP packet. For this to be possible
132 // the marker bit and payload type combined should be either an SR or RR
133 // identifier
134 marker = (rtpheader->marker == 0)?false:true;
135 payloadtype = rtpheader->payloadtype;
136 if (marker)
137 {
138 if (payloadtype == (RTP_RTCPTYPE_SR & 127)) // don't check high bit (this was the marker!!)
139 return ERR_RTP_PACKET_INVALIDPACKET;
140 if (payloadtype == (RTP_RTCPTYPE_RR & 127))
141 return ERR_RTP_PACKET_INVALIDPACKET;
142 }
143
144 csrccount = rtpheader->csrccount;
145 payloadoffset = sizeof(RTPHeader)+(int)(csrccount*sizeof(uint32_t));
146
147 if (rtpheader->padding) // adjust payload length to take padding into account
148 {
149 numpadbytes = (int)packetbytes[packetlen-1]; // last byte contains number of padding bytes
150 if (numpadbytes <= 0)
151 return ERR_RTP_PACKET_INVALIDPACKET;
152 }
153 else
154 numpadbytes = 0;
155
156 hasextension = (rtpheader->extension == 0)?false:true;
157 if (hasextension) // got header extension
158 {
159 rtpextheader = (RTPExtensionHeader *)(packetbytes+payloadoffset);
160 payloadoffset += sizeof(RTPExtensionHeader);
161
162 uint16_t exthdrlen = ntohs(rtpextheader->length);
163 payloadoffset += ((int)exthdrlen)*sizeof(uint32_t);
164 }
165 else
166 {
167 rtpextheader = 0;
168 }
169
170 payloadlength = packetlen-numpadbytes-payloadoffset;
171 if (payloadlength < 0)
172 return ERR_RTP_PACKET_INVALIDPACKET;
173
174 // Now, we've got a valid packet, so we can create a new instance of RTPPacket
175 // and fill in the members
176
177 RTPPacket::hasextension = hasextension;
178 if (hasextension)
179 {
180 RTPPacket::extid = ntohs(rtpextheader->extid);
181 RTPPacket::extensionlength = ((int)ntohs(rtpextheader->length))*sizeof(uint32_t);
182 RTPPacket::extension = ((uint8_t *)rtpextheader)+sizeof(RTPExtensionHeader);
183 }
184
185 RTPPacket::hasmarker = marker;
186 RTPPacket::numcsrcs = csrccount;
187 RTPPacket::payloadtype = payloadtype;
188
189 // Note: we don't fill in the EXTENDED sequence number here, since we
190 // don't have information about the source here. We just fill in the low
191 // 16 bits
192 RTPPacket::extseqnr = (uint32_t)ntohs(rtpheader->sequencenumber);
193
194 RTPPacket::timestamp = ntohl(rtpheader->timestamp);
195 RTPPacket::ssrc = ntohl(rtpheader->ssrc);
196 RTPPacket::packet = packetbytes;
197 RTPPacket::payload = packetbytes+payloadoffset;
198 RTPPacket::packetlength = packetlen;
199 RTPPacket::payloadlength = payloadlength;
200
201 // We'll zero the data of the raw packet, since we're using it here now!
202 rawpack.ZeroData();
203
204 return 0;
205 }
206
GetCSRC(int num) const207 uint32_t RTPPacket::GetCSRC(int num) const
208 {
209 if (num >= numcsrcs)
210 return 0;
211
212 uint8_t *csrcpos;
213 uint32_t *csrcval_nbo;
214 uint32_t csrcval_hbo;
215
216 csrcpos = packet+sizeof(RTPHeader)+num*sizeof(uint32_t);
217 csrcval_nbo = (uint32_t *)csrcpos;
218 csrcval_hbo = ntohl(*csrcval_nbo);
219 return csrcval_hbo;
220 }
221
BuildPacket(uint8_t payloadtype,const void * payloaddata,size_t payloadlen,uint16_t seqnr,uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t * csrcs,bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void * extensiondata,void * buffer,size_t maxsize)222 int RTPPacket::BuildPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
223 uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
224 bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
225 void *buffer,size_t maxsize)
226 {
227 if (numcsrcs > RTP_MAXCSRCS)
228 return ERR_RTP_PACKET_TOOMANYCSRCS;
229
230 if (payloadtype > 127) // high bit should not be used
231 return ERR_RTP_PACKET_BADPAYLOADTYPE;
232 if (payloadtype == 72 || payloadtype == 73) // could cause confusion with rtcp types
233 return ERR_RTP_PACKET_BADPAYLOADTYPE;
234
235 packetlength = sizeof(RTPHeader);
236 packetlength += sizeof(uint32_t)*((size_t)numcsrcs);
237 if (gotextension)
238 {
239 packetlength += sizeof(RTPExtensionHeader);
240 packetlength += sizeof(uint32_t)*((size_t)extensionlen_numwords);
241 }
242 packetlength += payloadlen;
243
244 if (maxsize > 0 && packetlength > maxsize)
245 {
246 packetlength = 0;
247 return ERR_RTP_PACKET_DATAEXCEEDSMAXSIZE;
248 }
249
250 // Ok, now we'll just fill in...
251
252 RTPHeader *rtphdr;
253
254 if (buffer == 0)
255 {
256 packet = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTPPACKET) uint8_t [packetlength];
257 if (packet == 0)
258 {
259 packetlength = 0;
260 return ERR_RTP_OUTOFMEM;
261 }
262 externalbuffer = false;
263 }
264 else
265 {
266 packet = (uint8_t *)buffer;
267 externalbuffer = true;
268 }
269
270 RTPPacket::hasmarker = gotmarker;
271 RTPPacket::hasextension = gotextension;
272 RTPPacket::numcsrcs = numcsrcs;
273 RTPPacket::payloadtype = payloadtype;
274 RTPPacket::extseqnr = (uint32_t)seqnr;
275 RTPPacket::timestamp = timestamp;
276 RTPPacket::ssrc = ssrc;
277 RTPPacket::payloadlength = payloadlen;
278 RTPPacket::extid = extensionid;
279 RTPPacket::extensionlength = ((size_t)extensionlen_numwords)*sizeof(uint32_t);
280
281 rtphdr = (RTPHeader *)packet;
282 rtphdr->version = RTP_VERSION;
283 rtphdr->padding = 0;
284 if (gotmarker)
285 rtphdr->marker = 1;
286 else
287 rtphdr->marker = 0;
288 if (gotextension)
289 rtphdr->extension = 1;
290 else
291 rtphdr->extension = 0;
292 rtphdr->csrccount = numcsrcs;
293 rtphdr->payloadtype = payloadtype&127; // make sure high bit isn't set
294 rtphdr->sequencenumber = htons(seqnr);
295 rtphdr->timestamp = htonl(timestamp);
296 rtphdr->ssrc = htonl(ssrc);
297
298 uint32_t *curcsrc;
299 int i;
300
301 curcsrc = (uint32_t *)(packet+sizeof(RTPHeader));
302 for (i = 0 ; i < numcsrcs ; i++,curcsrc++)
303 *curcsrc = htonl(csrcs[i]);
304
305 payload = packet+sizeof(RTPHeader)+((size_t)numcsrcs)*sizeof(uint32_t);
306 if (gotextension)
307 {
308 RTPExtensionHeader *rtpexthdr = (RTPExtensionHeader *)payload;
309
310 rtpexthdr->extid = htons(extensionid);
311 rtpexthdr->length = htons((uint16_t)extensionlen_numwords);
312
313 payload += sizeof(RTPExtensionHeader);
314 memcpy(payload,extensiondata,RTPPacket::extensionlength);
315
316 payload += RTPPacket::extensionlength;
317 }
318 memcpy(payload,payloaddata,payloadlen);
319 return 0;
320 }
321
322 #ifdef RTPDEBUG
Dump()323 void RTPPacket::Dump()
324 {
325 int i;
326
327 printf("Payload type: %d\n",(int)GetPayloadType());
328 printf("Extended sequence number: 0x%08x\n",GetExtendedSequenceNumber());
329 printf("Timestamp: 0x%08x\n",GetTimestamp());
330 printf("SSRC: 0x%08x\n",GetSSRC());
331 printf("Marker: %s\n",HasMarker()?"yes":"no");
332 printf("CSRC count: %d\n",GetCSRCCount());
333 for (i = 0 ; i < GetCSRCCount() ; i++)
334 printf(" CSRC[%02d]: 0x%08x\n",i,GetCSRC(i));
335 printf("Payload: %s\n",GetPayloadData());
336 printf("Payload length: %d\n",GetPayloadLength());
337 printf("Packet length: %d\n",GetPacketLength());
338 printf("Extension: %s\n",HasExtension()?"yes":"no");
339 if (HasExtension())
340 {
341 printf(" Extension ID: 0x%04x\n",GetExtensionID());
342 printf(" Extension data: %s\n",GetExtensionData());
343 printf(" Extension length: %d\n",GetExtensionLength());
344 }
345 }
346 #endif // RTPDEBUG
347
348 } // end namespace
349
350