blob: 0b4082bb79b0385e6ed18dad785fed380a319898 [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
53#ifdef CCXX_NAMESPACES
54namespace ost {
55#endif
56
57const uint32 MembershipBookkeeping::SyncSourceLink::SEQNUMMOD = (1<<16);
58
59MembershipBookkeeping::SyncSourceLink::~SyncSourceLink()
60{
61#ifdef CCXX_EXCEPTIONS
62 try {
63#endif
64 delete source;
65 delete prevConflict;
66 delete receiverInfo;
67 delete senderInfo;
68#ifdef CCXX_EXCEPTIONS
69 } catch (...) { }
70#endif
71}
72
73void
74MembershipBookkeeping::SyncSourceLink::initStats()
75{
76 lastPacketTime.tv_sec = lastPacketTime.tv_usec = 0;
77 lastRTCPPacketTime.tv_sec = lastRTCPPacketTime.tv_usec = 0;
78 lastRTCPSRTime.tv_sec = lastRTCPSRTime.tv_usec = 0;
79
80 senderInfo = NULL;
81 receiverInfo = NULL;
82
83 obsPacketCount = obsOctetCount = 0;
84 maxSeqNum = extendedMaxSeqNum = 0;
85 cumulativePacketLost = 0;
86 fractionLost = 0;
87 jitter = 0;
88 initialDataTimestamp = 0;
89 initialDataTime.tv_sec = initialDataTime.tv_usec = 0;
90 flag = false;
91
92 badSeqNum = SEQNUMMOD + 1;
93 probation = 0;
94 baseSeqNum = 0;
95 expectedPrior = 0;
96 receivedPrior = 0;
97 seqNumAccum = 0;
98}
99
100void
101MembershipBookkeeping::SyncSourceLink::computeStats()
102{
103 // See Appendix A.3
104
105 // compute cumulative packet lost.
106 setExtendedMaxSeqNum(getMaxSeqNum() + getSeqNumAccum());
107 uint32 expected =
108 (getExtendedMaxSeqNum() - getBaseSeqNum() + 1);
109 uint32 pc = getObservedPacketCount();
110 uint32 lost;
111 if ( 0 == pc )
112 lost = 0;
113 else
114 lost = expected - pc;
115 setCumulativePacketLost(lost);
116
117 // compute the fraction of packets lost during the last
118 // reporting interval.
119 uint32 expectedDelta = expected - expectedPrior;
120 expectedPrior = expected;
121 uint32 receivedDelta = getObservedPacketCount() -
122 receivedPrior;
123 receivedPrior = getObservedPacketCount();
124 uint32 lostDelta = expectedDelta - receivedDelta;
125 if ( expectedDelta == 0 || lostDelta <= 0 )
126 setFractionLost(0);
127 else
128 setFractionLost((lostDelta<<8) / expectedDelta );
129}
130
131void
132MembershipBookkeeping::SyncSourceLink::setPrevConflict(InetAddress& addr,
133tpport_t dataPort, tpport_t controlPort)
134{
135 delete prevConflict;
136 prevConflict =
137 new ConflictingTransportAddress(addr,dataPort,controlPort);
138}
139
140void
141MembershipBookkeeping::SyncSourceLink::
142recordInsertion(const IncomingRTPPktLink&)
143{}
144
145void
146MembershipBookkeeping::SyncSourceLink::
147setSenderInfo(unsigned char* si)
148{
149 if ( NULL == senderInfo )
150 senderInfo = reinterpret_cast<unsigned char*>
151 (new RTCPCompoundHandler::SenderInfo);
152 memcpy(senderInfo,si,sizeof(RTCPCompoundHandler::SenderInfo));
153}
154
155void
156MembershipBookkeeping::SyncSourceLink::
157setReceiverInfo(unsigned char* ri)
158{
159 if ( NULL == receiverInfo )
160 receiverInfo = reinterpret_cast<unsigned char*>
161 (new RTCPCompoundHandler::ReceiverInfo);
162 memcpy(receiverInfo,ri,sizeof(RTCPCompoundHandler::ReceiverInfo));
163}
164
165const size_t MembershipBookkeeping::defaultMembersHashSize = 11;
166const uint32 MembershipBookkeeping::SEQNUMMOD = (1<<16);
167
168#define HASH(a) ((a + (a >> 8)) % MembershipBookkeeping::sourceBucketsNum)
169
170// Initializes the array (hash table) and the global list of
171// SyncSourceLink objects
172MembershipBookkeeping::MembershipBookkeeping(uint32 initialSize):
173SyncSourceHandler(), ParticipantHandler(), ConflictHandler(), Members(),
174sourceBucketsNum(initialSize),
175sourceLinks( new SyncSourceLink* [sourceBucketsNum] ), first(NULL), last(NULL)
176{
177 for ( uint32 i = 0; i < sourceBucketsNum; i++ )
178 sourceLinks[i] = NULL;
179}
180
181void
182MembershipBookkeeping::endMembers()
183{
184 SyncSourceLink* s;
185 while( first ) {
186 s = first;
187 first = first->next;
188#ifdef CCXX_EXCEPTIONS
189 try {
190#endif
191 delete s;
192#ifdef CCXX_EXCEPTIONS
193 } catch (...) {}
194#endif
195 }
196 last = NULL;
197#ifdef CCXX_EXCEPTIONS
198 try {
199#endif
200 delete [] sourceLinks;
201#ifdef CCXX_EXCEPTIONS
202 } catch (...) {}
203#endif
204}
205
206bool
207MembershipBookkeeping::isRegistered(uint32 ssrc)
208{
209 bool result = false;
210 SyncSourceLink* sl = sourceLinks[ HASH(ssrc) ];
211
212 while ( sl != NULL ) {
213 if ( ssrc == sl->getSource()->getID() ) {
214 result = true;
215 break;
216 } else if ( ssrc < sl->getSource()->getID() ) {
217 break;
218 } else {
219 // keep on searching
220 sl = sl->getNextCollis();
221 }
222 }
223 return result;
224}
225
226// Gets or creates the source and its link structure.
227MembershipBookkeeping::SyncSourceLink*
228MembershipBookkeeping::getSourceBySSRC(uint32 ssrc, bool& created)
229{
230 uint32 hashing = HASH(ssrc);
231 SyncSourceLink* result = sourceLinks[hashing];
232 SyncSourceLink* prev = NULL;
233 created = false;
234
235 if ( NULL == result ) {
236 result = sourceLinks[hashing] =
237 new SyncSourceLink(this,new SyncSource(ssrc));
238 created = true;
239 } else {
240 while ( NULL != result ) {
241 if ( ssrc == result->getSource()->getID() ) {
242 // we found it!
243 break;
244 } else if ( ssrc > result->getSource()->getID() ) {
245 // keep on searching
246 prev = result;
247 result = result->getNextCollis();
248 } else {
249 // ( ssrc < result->getSource()->getID() )
250 // it isn't recorded here -> create it.
251 SyncSourceLink* newlink =
252 new SyncSourceLink(this,new SyncSource(ssrc));
253 if ( NULL != prev )
254 prev->setNextCollis(newlink);
255 else
256 sourceLinks[hashing] = newlink;
257 newlink->setNextCollis(result);
258 result = newlink;
259 created = true;
260 break;
261 }
262 }
263 if ( NULL == result ) {
264 // insert at the end of the collision list
265 result =
266 new SyncSourceLink(this,new SyncSource(ssrc));
267 created = true;
268 prev->setNextCollis(result);
269 }
270 }
271 if ( created ) {
272 if ( first )
273 last->setNext(result);
274 else
275 first = result;
276 last = result;
277 increaseMembersCount();
278 }
279
280 return result;
281}
282
283bool
284MembershipBookkeeping::BYESource(uint32 ssrc)
285{
286 bool found = false;
287 // If the source identified by ssrc is in the table, mark it
288 // as leaving the session. If it was not, do nothing.
289 if ( isRegistered(ssrc) ) {
290 found = true;
291 decreaseMembersCount(); // TODO really decrease right now?
292 }
293 return found;
294}
295
296bool
297MembershipBookkeeping::removeSource(uint32 ssrc)
298{
299 bool found = false;
300 SyncSourceLink* old = NULL,
301 * s = sourceLinks[ HASH(ssrc) ];
302 while ( s != NULL ){
303 if ( s->getSource()->getID() == ssrc ) {
304 // we found it
305 if ( old )
306 old->setNextCollis(s->getNextCollis());
307 if ( s->getPrev() )
308 s->getPrev()->setNext(s->getNext());
309 if ( s->getNext() )
310 s->getNext()->setPrev(s->getPrev());
311 decreaseMembersCount();
312 if ( s->getSource()->isSender() )
313 decreaseSendersCount();
314 delete s;
315 found = true;
316 break;
317 } else if ( s->getSource()->getID() > ssrc ) {
318 // it wasn't here
319 break;
320 } else {
321 // keep on searching
322 old = s;
323 s = s->getNextCollis();
324 }
325 }
326 return found;
327}
328
329#ifdef CCXX_NAMESPACES
330}
331#endif
332
333/** EMACS **
334 * Local variables:
335 * mode: c++
336 * c-basic-offset: 4
337 * End:
338 */