blob: 287dad263cd35c04ccf593e07aa39604c13ec00b [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 2001,2002 Federico Montesino <p5087@quintero.fie.us.es>
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation; either version 2 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program; if not, write to the Free Software
15// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16//
17// As a special exception, you may use this file as part of a free software
18// library without restriction. Specifically, if other files instantiate
19// templates or use macros or inline functions from this file, or you compile
20// this file and link it with other files to produce an executable, this
21// file does not by itself cause the resulting executable to be covered by
22// the GNU General Public License. This exception does not however
23// invalidate any other reasons why the executable file might be covered by
24// the GNU General Public License.
25//
26// This exception applies only to the code released under the name GNU
27// ccRTP. If you copy code from other releases into a copy of GNU
28// ccRTP, as the General Public License permits, the exception does
29// not apply to the code that you add in this way. To avoid misleading
30// anyone as to the status of such modified files, you must delete
31// this exception notice from them.
32//
33// If you write modifications of your own for GNU ccRTP, it is your choice
34// whether to permit this exception to apply to your modifications.
35// If you do not wish that, delete this exception notice.
36//
37
38/**
39 * @file members.cpp
40 * @shot MembershipBookkeeping class implementation
41 *
42 * @todo implement the reallocation mechanism (e.g., when the number
43 * of ssrcs per collision list goes up to 2, make the size
44 * approx. four times bigger (0.5 ssrcs per list now. when the number
45 * of ssrcs per list goes down to 0.5, decrease four times. Do not use
46 * 2 or 0.5, but `2 + something' and `0.5 - somehting'). Always
47 * jumping between prime numbers -> provide a table from 7 to many.
48 **/
49
50#include "private.h"
51#include <ccrtp/cqueue.h>
52
Alexandre Lisionddd731e2014-01-31 11:50:08 -050053NAMESPACE_COMMONCPP
Emeric Vigier2f625822012-08-06 11:09:52 -040054
55const uint32 MembershipBookkeeping::SyncSourceLink::SEQNUMMOD = (1<<16);
56
57MembershipBookkeeping::SyncSourceLink::~SyncSourceLink()
58{
59#ifdef CCXX_EXCEPTIONS
60 try {
61#endif
62 delete source;
63 delete prevConflict;
64 delete receiverInfo;
65 delete senderInfo;
66#ifdef CCXX_EXCEPTIONS
67 } catch (...) { }
68#endif
69}
70
71void
72MembershipBookkeeping::SyncSourceLink::initStats()
73{
74 lastPacketTime.tv_sec = lastPacketTime.tv_usec = 0;
75 lastRTCPPacketTime.tv_sec = lastRTCPPacketTime.tv_usec = 0;
76 lastRTCPSRTime.tv_sec = lastRTCPSRTime.tv_usec = 0;
77
78 senderInfo = NULL;
79 receiverInfo = NULL;
80
81 obsPacketCount = obsOctetCount = 0;
82 maxSeqNum = extendedMaxSeqNum = 0;
83 cumulativePacketLost = 0;
84 fractionLost = 0;
85 jitter = 0;
86 initialDataTimestamp = 0;
87 initialDataTime.tv_sec = initialDataTime.tv_usec = 0;
88 flag = false;
89
90 badSeqNum = SEQNUMMOD + 1;
91 probation = 0;
92 baseSeqNum = 0;
93 expectedPrior = 0;
94 receivedPrior = 0;
95 seqNumAccum = 0;
96}
97
98void
99MembershipBookkeeping::SyncSourceLink::computeStats()
100{
101 // See Appendix A.3
102
103 // compute cumulative packet lost.
104 setExtendedMaxSeqNum(getMaxSeqNum() + getSeqNumAccum());
105 uint32 expected =
106 (getExtendedMaxSeqNum() - getBaseSeqNum() + 1);
107 uint32 pc = getObservedPacketCount();
108 uint32 lost;
109 if ( 0 == pc )
110 lost = 0;
111 else
112 lost = expected - pc;
113 setCumulativePacketLost(lost);
114
115 // compute the fraction of packets lost during the last
116 // reporting interval.
117 uint32 expectedDelta = expected - expectedPrior;
118 expectedPrior = expected;
119 uint32 receivedDelta = getObservedPacketCount() -
120 receivedPrior;
121 receivedPrior = getObservedPacketCount();
122 uint32 lostDelta = expectedDelta - receivedDelta;
123 if ( expectedDelta == 0 || lostDelta <= 0 )
124 setFractionLost(0);
125 else
126 setFractionLost((lostDelta<<8) / expectedDelta );
127}
128
129void
130MembershipBookkeeping::SyncSourceLink::setPrevConflict(InetAddress& addr,
131tpport_t dataPort, tpport_t controlPort)
132{
133 delete prevConflict;
134 prevConflict =
135 new ConflictingTransportAddress(addr,dataPort,controlPort);
136}
137
138void
139MembershipBookkeeping::SyncSourceLink::
140recordInsertion(const IncomingRTPPktLink&)
141{}
142
143void
144MembershipBookkeeping::SyncSourceLink::
145setSenderInfo(unsigned char* si)
146{
147 if ( NULL == senderInfo )
148 senderInfo = reinterpret_cast<unsigned char*>
149 (new RTCPCompoundHandler::SenderInfo);
150 memcpy(senderInfo,si,sizeof(RTCPCompoundHandler::SenderInfo));
151}
152
153void
154MembershipBookkeeping::SyncSourceLink::
155setReceiverInfo(unsigned char* ri)
156{
157 if ( NULL == receiverInfo )
158 receiverInfo = reinterpret_cast<unsigned char*>
159 (new RTCPCompoundHandler::ReceiverInfo);
160 memcpy(receiverInfo,ri,sizeof(RTCPCompoundHandler::ReceiverInfo));
161}
162
163const size_t MembershipBookkeeping::defaultMembersHashSize = 11;
164const uint32 MembershipBookkeeping::SEQNUMMOD = (1<<16);
165
166#define HASH(a) ((a + (a >> 8)) % MembershipBookkeeping::sourceBucketsNum)
167
168// Initializes the array (hash table) and the global list of
169// SyncSourceLink objects
170MembershipBookkeeping::MembershipBookkeeping(uint32 initialSize):
171SyncSourceHandler(), ParticipantHandler(), ConflictHandler(), Members(),
172sourceBucketsNum(initialSize),
173sourceLinks( new SyncSourceLink* [sourceBucketsNum] ), first(NULL), last(NULL)
174{
175 for ( uint32 i = 0; i < sourceBucketsNum; i++ )
176 sourceLinks[i] = NULL;
177}
178
179void
180MembershipBookkeeping::endMembers()
181{
182 SyncSourceLink* s;
183 while( first ) {
184 s = first;
185 first = first->next;
186#ifdef CCXX_EXCEPTIONS
187 try {
188#endif
189 delete s;
190#ifdef CCXX_EXCEPTIONS
191 } catch (...) {}
192#endif
193 }
194 last = NULL;
195#ifdef CCXX_EXCEPTIONS
196 try {
197#endif
198 delete [] sourceLinks;
199#ifdef CCXX_EXCEPTIONS
200 } catch (...) {}
201#endif
202}
203
204bool
205MembershipBookkeeping::isRegistered(uint32 ssrc)
206{
207 bool result = false;
208 SyncSourceLink* sl = sourceLinks[ HASH(ssrc) ];
209
210 while ( sl != NULL ) {
211 if ( ssrc == sl->getSource()->getID() ) {
212 result = true;
213 break;
214 } else if ( ssrc < sl->getSource()->getID() ) {
215 break;
216 } else {
217 // keep on searching
218 sl = sl->getNextCollis();
219 }
220 }
221 return result;
222}
223
224// Gets or creates the source and its link structure.
225MembershipBookkeeping::SyncSourceLink*
226MembershipBookkeeping::getSourceBySSRC(uint32 ssrc, bool& created)
227{
228 uint32 hashing = HASH(ssrc);
229 SyncSourceLink* result = sourceLinks[hashing];
230 SyncSourceLink* prev = NULL;
231 created = false;
232
233 if ( NULL == result ) {
234 result = sourceLinks[hashing] =
235 new SyncSourceLink(this,new SyncSource(ssrc));
236 created = true;
237 } else {
238 while ( NULL != result ) {
239 if ( ssrc == result->getSource()->getID() ) {
240 // we found it!
241 break;
242 } else if ( ssrc > result->getSource()->getID() ) {
243 // keep on searching
244 prev = result;
245 result = result->getNextCollis();
246 } else {
247 // ( ssrc < result->getSource()->getID() )
248 // it isn't recorded here -> create it.
249 SyncSourceLink* newlink =
250 new SyncSourceLink(this,new SyncSource(ssrc));
251 if ( NULL != prev )
252 prev->setNextCollis(newlink);
253 else
254 sourceLinks[hashing] = newlink;
255 newlink->setNextCollis(result);
256 result = newlink;
257 created = true;
258 break;
259 }
260 }
261 if ( NULL == result ) {
262 // insert at the end of the collision list
263 result =
264 new SyncSourceLink(this,new SyncSource(ssrc));
265 created = true;
266 prev->setNextCollis(result);
267 }
268 }
269 if ( created ) {
270 if ( first )
271 last->setNext(result);
272 else
273 first = result;
274 last = result;
275 increaseMembersCount();
276 }
277
278 return result;
279}
280
281bool
282MembershipBookkeeping::BYESource(uint32 ssrc)
283{
284 bool found = false;
285 // If the source identified by ssrc is in the table, mark it
286 // as leaving the session. If it was not, do nothing.
287 if ( isRegistered(ssrc) ) {
288 found = true;
289 decreaseMembersCount(); // TODO really decrease right now?
290 }
291 return found;
292}
293
294bool
295MembershipBookkeeping::removeSource(uint32 ssrc)
296{
297 bool found = false;
298 SyncSourceLink* old = NULL,
299 * s = sourceLinks[ HASH(ssrc) ];
300 while ( s != NULL ){
301 if ( s->getSource()->getID() == ssrc ) {
302 // we found it
303 if ( old )
304 old->setNextCollis(s->getNextCollis());
305 if ( s->getPrev() )
306 s->getPrev()->setNext(s->getNext());
307 if ( s->getNext() )
308 s->getNext()->setPrev(s->getPrev());
309 decreaseMembersCount();
310 if ( s->getSource()->isSender() )
311 decreaseSendersCount();
312 delete s;
313 found = true;
314 break;
315 } else if ( s->getSource()->getID() > ssrc ) {
316 // it wasn't here
317 break;
318 } else {
319 // keep on searching
320 old = s;
321 s = s->getNextCollis();
322 }
323 }
324 return found;
325}
326
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500327END_NAMESPACE
Emeric Vigier2f625822012-08-06 11:09:52 -0400328
329/** EMACS **
330 * Local variables:
331 * mode: c++
332 * c-basic-offset: 4
333 * End:
334 */