/[resiprocate]/main/resip/stack/test/testSdp.cxx
ViewVC logotype

Contents of /main/resip/stack/test/testSdp.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9367 - (show annotations) (download)
Wed Feb 1 16:12:20 2012 UTC (7 years, 9 months ago) by sgodin
File MIME type: text/plain
File size: 22253 byte(s)
-merge work from resip-b-TKLC-perf_work branch

Merge Notes:

Various optimizations of Data
=============================

Made Data smaller, without sacrificing functionality. Data is 20 (56 vs 36) 
bytes smaller on 64-bit libs, and 4 (36 vs 32) bytes smaller on 32-bit libs. 
This was accomplished by making mSize, mCapacity, and mShareEnum 4-bytes on 
64-bit platforms (mShareEnum could be one byte, but it turns out this imposes a 
detectable performance penalty), and by having mShareEnum do double-duty as a 
null-terminator for mPreBuffer (Borrow==0), instead of requiring an extra byte 
at the end of mPreBuffer.

Several very simple functions have been inlined.

Functionality enhancements to a couple of functions:

- Data::md5() has been changed to Data::md5(Data::EncodingType type=HEX); this 
allows the output of md5() to be encoded as hex or Base64, or not encoded at all 
(binary).

- Data::replace(const Data& match, const Data& target) has been updated to 
Data::replace(const Data& match, const Data& target, int max=INT_MAX); this 
allows the maximum number of replacements to be specified.

Lastly, a few specialized hashing and comparison functions have been added:

- Data::caseInsensitiveTokenHash(); this is a case-insensitive hash that assumes 
that the Data is an RFC 3261 token (eg; branch params). This character set has 
the property that no character is equal to any other character when bit 6 is 
masked out, except for the alphabetical characters. (For alphabetical 
characters, bit 6 specifies whether the character is upper/lower case) This 
means that we can mask out bit 6, and then use a case-sensitive hash algorithm 
on the resulting characters, without hurting the collision properties of the 
hash, and get a case-insensitive hash as a result. This hash function is based 
on the Hsieh hash.

- bool Data::caseInsensitiveTokenCompare(const Data& rhs); this is an equality 
comparison that assumes that both Datas are RFC 3261 tokens (eg; branch 
parameters). This function takes advantage of the same properties of the RFC 
3261 token character set as caseInsensitiveTokenHash(), by using a bitmask 
instead of a true lowercase() operation. This ends up being faster than 
strncasecmp().

- Data& schemeLowercase(); this is a variant of lowercase() that assumes the 
Data is an RFC 3261 scheme. This character set has the property that setting bit 
6 is a no-op, except for alphabetical characters (0-9, '+', '-', and '.' all 
already have bit 6 set). Setting bit 6 on a alphabetical character is equivalent 
to lower-casing the character. Note: There is no corresponding schemeUppercase() 
function, because clearing bit 6 will convert 0-9, '+', '-', and '.' into 
unprintable characters (well, '-' is turned into a CR, but you get the point).



Performance improvements to ParseBuffer
=======================================

- Most functions that returned a Pointer now return a much more lightweight
   CurrentPosition object.
- Allow some of the simpler functions to be inlined
- Integer parsing code is more efficient, and overflow detection is better


Performance enhancements to DnsUtil
===================================

- DnsUtil::inet_ntop(): For some reason, the stock system inet_ntop 
  is dreadfully inefficient on OS X. A dirt-simple hand-rolled 
  implementation was 5-6 times as fast. This is shocking. The Linux 
  implementation is plenty efficient, though, so we're using 
  preprocessor to activate the hand-rolled code.

- DnsUtil::isIpV4Address(): The implementation uses 
  sscanf(), which is pretty expensive. Hand-rolled some code that 
  is much faster.


Reduced the memory footprint associated with storing URIs
=========================================================
- Removed the AOR cacheing stuff from Uri; it was horrifically inefficient. Checking
  for staleness of the cache was nearly as expensive as regenerating the AOR from 
  scratch. Not to mention that the AOR cacheing stuff took up a whopping 148 bytes
  of space on 64-bit platforms (4 Datas, and an int).

- Reworked the host canonicalization cache to take up less space, and be faster.
  Previously, the canonicalized host was put in a separate Data. We now canonicalize
  in-place, and use a bool to denote whether canonicalization has been performed yet.
  This saves us 32 bytes.

- Changed Data Uri::mEmbeddedHeadersText to an auto_ptr<>, since in most cases Uris don't
  use it. Also use auto_ptr for mEmbeddedHeaders (was already a pointer, for consistency).


Change how branch parameters are encoded.
=========================================

Old format: z9hG4bK-d8754z-<branch>-<transportseq>-<clientData>-<sigcompCompartment>-d8754z-

New Format: z9hG4bK-524287-<transportseq>-<clientData>-<sigcompComprtment>-<branch>

This format encodes faster, parses faster (with _much_ simpler code), and takes up
less space on the wire. We may decide to tweak the new resip cookie; I chose 
something that we can use memcmp instead of strncasecmp with, but the token character
set has a bunch of characters that aren't alphanumeric we could use.

Also, some other small optimizations; avoid copies associated with calling
Data::base64encode()/base64decode() on empty Datas, and reorder the SIP cookie
comparisons to be more efficient.


State shedding modifications to TransactionState
================================================
In a number of cases, we were preserving state (in the form of SipMessages
and DnsResults) in cases where we did not really need them any more. For
example, once we have transmitted a response, there is no need
to preserve the full SipMessage for this response (the raw retransmit buffer
is sufficient). Also, INVITE requests do not need to be maintained once
a final response comes in (since there is no possibility that we'll need to
send a simulated 408 or 503 to the TU, nor will we need to construct a CANCEL
request using the INVITE, nor will we need to retransmit). Similarly, once we
have received a final response for a NIT transaction, we no longer need to
maintain the original request or the retransmit buffer. Lastly, if we are
using a reliable transport, we do not need to maintain retransmit buffers
(although we may need to maintain full original requests for simulated
responses and such).

This change has basically no impact on reliable NIT performance, but a huge
impact on non-reliable and INVITE performance. Prior to this change, either
NIT UDP or INVITE TCP testStack would exhaust main memory on my laptop (with
4GB of main memory), bringing progress to a complete halt on runs longer than
15 seconds or so. I did not bother trying INVITE UDP, but that works now too.


Reduction in buffer reallocations while encoding a SipMessage
=============================================================
TransportSelector now keeps a moving average of the outgoing message size,
which is used to preallocate the buffers into which SipMessages are encoded.

This ends up making a small difference in testStack when linked against google
malloc, but a larger difference when linked against OS X's (horrible) standard
malloc.


Multiple Threads in the Stack
=============================
Allow transaction processing, transport processing, and DNS processing to be 
broken off into separate threads.

- SipStack::run() causes the creation and run of three threads; a 
TransactionControllerThread, and TransportSelectorThread, and a DnsThread. You 
continue to use stuff like StackThread and EventStackThread to give cycles to 
the rest of the stack (mainly processing app timers and statistics logging); the 
SipStack is smart enough to unhook these three things from the normal event loop 
API when they have their own threads. In other words, to use the new 
multi-threaded mode, all you have to do is throw in a call to SipStack::run() 
before you fire up your normal SipStack processing, and a 
SipStack::shutdownAndJoinThreads() when you're done.

- In the Connection read/write code, process reads/writes until EAGAIN, or we 
run out of stuff to send. Gives a healthy performance boost on connection-based 
transports.

- In TransactionController, put transaction timers in their own fifo. This 
prevents timers from firing late when the state machine fifo gets congested. 
Also, process at most 16 TransactionMessages from the state machine fifo at a 
time, to prevent starving other parts of the system.

- Unhook the TransactionController's processing loop from that of the 
TransportSelector. This simplifies this API considerably, but required the 
addition of a new feature to Fifo. Fifo can now take an (optional) 
AsyncProcessHandler* that will be notified when the fifo goes from empty to 
non-empty. Actually pretty useful.

- Allow setPollGrp() to be called multiple times on the various classes that 
have this function. This allows the FdPollGrp to be re-set when the SipStack 
enters multithreaded mode.

- Added a "multithreadedstack" --thread-type option to testStack. Exercise this 
option in testStackStd.sh

- Added the ability to run any of the existing Transport objects in their own 
thread, by a combination of a new transport flag 
(RESIP_TRANSPORT_FLAG_OWNTHREAD), and a new TransportThread class. Added support 
for this mode to testStack using the --tf option. Also exercised this feature in 
testStackStd.sh.

- Installed SelectInterruptors at the TransportSelector, each Transport object, 
and the DnsStub (this last one required moving SelectInterruptor to rutil). This 
is critical to making multithreaded mode work in a performant manner, and 
imposes almost no performance penalty due to the way they are invoked.

- SipStack now creates its own SelectInterruptor if one is not supplied 
externally. This is because it is critical to be able to wake the 
TransactionController up when new work comes down from the TU, or from the 
transports.


New congestion-management framework
===================================
Notable features include:
* Allow testStack, tfm/repro/sanityTests, and repro to be run with a congestion 
   manager with the --use-congestion-manager flag.

* Efficient wait-time estimation in AbstractFifo; keeps track of how rapidly
   messages are consumed, allowing good estimates of how long a new message will
   take to be serviced. More efficient than the time-depth logic in 
   TimeLimitFifo, and a better predictor too.

* The ability to shed load at the transport level when the TransactionController
   is congested, in a very efficient manner, using new functionality in Helper
   and SipMessage (Helper::makeRawResponse() and 
   SipMessage::encodeSingleHeader())

* The ability to shed load coming from the TU when the TransactionController is 
   congested. This is crucial when congestion is being caused by a TU trying to 
   do too much.

* Changed the way load-shedding is handled for TransactionUsers to use the new
   API

* A flexible congestion-management API, allowing load-shedding decisions to be
   made in an arbitrary fashion.

* A generalized CongestionManager implementation that is powerful enough to be
   useful.

* The TransactionController will now defer retransmissions of requests if 
   sufficiently congested (ie; the response is probably stuck in mStateMacFifo)

* The TransactionController now determines its hostname with a single call to 
   DnsUtil::getLocalHostName() on construction, for use in 503s. Previously, it 
   would make this call every time a 503 was sent; this call blocks sometimes!

* Don't call DnsResult::blacklistLast() on a Retry-After: 0

* Several fixes the the processing loop in testStack that were causing 
   starvation of one type of work or another when congestion occurred.


Other Misc Enhancements
=======================
-Small efficiency improvement in Random::getCryptoRandom(int)
 Random::getCryptoRandom(unsigned int len) was implemented by calling 
 Random::getCryptoRandom() repeatedly, and collecting the return values 
 in a buffer. In the openssl case, we now use a single call to RAND_bytes().
-Use a priority_queue instead of a multiset for storing timers.
-Slight refactoring of Timer so that transaction timers and payload timers (ie; 
 timers that carry a Message*) are separate classes. Transaction timers no longer 
 have an unused Message* member, and payload timers no longer have the unused 
 transaction-id, Timer::Type, and duration. This saves a _lot_ of memory for apps 
 that use lots of app timers with long lifetimes.
-Less wasteful population of Call-IDs: 
 When generating Call-IDs, Helper was computing an md5 hash of the hostname and 
 some salt, hex-encoding it, and then Base64 encoding the hex data. We now Base64 
 encode the md5 hash directly. This is less computationally expensive, requires 
 less memory because the resulting string is half the size, and requires fewer 
 bytes on the wire.
-Make TransactionMap case-insensitive; Data::caseInsensitiveTokenHash() is fast
 enough that performance actually increases a little.
-std::bitset-based parsing in a number of places.
-Don't check whether the encoding tables are initted for every single
 character; check once before the encode operation begins. Also, checking
 the value of a static bool to determine whether an init has been carried
 out is pointless; that bool might not be initted yet, and it could have
 any value. The static init code now copes with both accesses to the encoding
 tables during static initialization, and from multiple threads during runtime.
-Don't bother generating a transaction identifier unless the parse fails
 to extract one.
-Some refactoring of the FdPollGrp stuff. Now is compatible with cares, using
 a bit of a hack. Also compatible with being driven with the old buildFdSet()/
 select()/process(FdSet&) call sequence, although this is now deprecated.
 Fixing these compatibility problems allowed us to switch over to using FdPollGrp
 in all cases, instead of having dual mode everywhere.
-Buffer classes for Fifo to reduce lock contention. Using them in a few places, will
 use them in more once we phase out TimeLimitFifo with the new congestion management
 code.
-Use the --ignore-case option for generation of ParameterHash.cxx, instead of the
 nasty sed rewriting we are using now. Should also be slightly faster, since gperf
 handles case-insensitive hashing more efficiently than our hack was.
-Adding a local memory pool to SipMessage, to cut down (dramatically) on
 heap allocation overhead. Some minor refactoring to free up wasted space
 in SipMessage as well (makes more room for the pool). Changing the way
 the start-line is stored to no longer use a full-blown ParserContainer+
 HeaderFieldValueList. Lots of opportunistic doxygen merging.
 Up to 20K NIT transactions per second on my machine, roughly a doubling
 in performance.


Bug Fixes
=========
-Use getaddrinfo() instead of the non-threadsafe gethostbyname().
-Remove unused (and non-threadsafe) Timer::mTimerCount/Timer::mId.
 Previously, all timers were assigned a "unique" (not really, more on that in a 
 moment) integer identifier. There is no place in the resip codebase that 
 actually uses this identifier in any way. For transaction timers, this 
 identifier is in principle unnecessary, since there is more than sufficient 
 identifier information present already (the transaction id and timer type). When 
 passing a Message* into the timer queue, a unique identifier already exists; the 
 Message* itself (if potential use of this Message* bugs you, you can always turn 
 it into a handle by applying some sort of transformation to it). This identifier 
 is unnecessary in every case I can think of. In addition, the values are 
 assigned simply by incrementing a global variable (Timer::mTimerCount), with no 
 threadsafety measures whatsoever, so it is not even guaranteed to be unique. 
 Because of all this, it has been removed. As a bonus, this saves some memory; 8 
 bytes per timer on 64-bit platforms, which adds up to around 3MB when testStack 
 steady state has close to 400000 timers in the timer queues at any given point. 
 This could be an even larger amount for TUs that schedule lots of long-lifetime 
 timers (Timer C, for instance).
-Get rid of a wasteful double-encode, in Message.cxx
-minor windows build fixes to avoid file in use errors when building dum test projects
-fix testDigestAuthentiation for recent lowercase nonce change
-fixed a nasty bug in NameAddr - where unknown parameters uri parameters on a 
 NameAddr/Uri with no angle brackets are treated as NameAddr parameters.  When this is
 done, the memory for these parameters was only a temporary Data object.
-fix bug in Data.  If Data is wrapping memory allocated externally (ie. Share mode = BORROW)
 and you start appending to it.  It is possible that the append method will write a NULL
 character off the end of the buffer.  Changed the resize condition to make the buffer
 larger 1 character sooner, to accommodate for this.
1 #include "rutil/Logger.hxx"
2 #include "rutil/DataStream.hxx"
3 #include "resip/stack/SdpContents.hxx"
4 #include "resip/stack/HeaderFieldValue.hxx"
5 #include "rutil/ParseBuffer.hxx"
6
7 #include <iostream>
8 #include "TestSupport.hxx"
9 #include "tassert.h"
10
11 using namespace resip;
12 using namespace std;
13
14 #define RESIPROCATE_SUBSYSTEM Subsystem::TEST
15
16 int
17 main(int argc, char* argv[])
18 {
19 Log::Level l = Log::Debug;
20
21 if (argc > 1)
22 {
23 switch(*argv[1])
24 {
25 case 'd': l = Log::Debug;
26 break;
27 case 'i': l = Log::Info;
28 break;
29 case 's': l = Log::Stack;
30 break;
31 case 'c': l = Log::Crit;
32 break;
33 }
34
35 }
36
37 Log::initialize(Log::Cout, l, argv[0]);
38 CritLog(<<"Test Driver Starting");
39
40 {
41 Data txt("v=0\r\n"
42 "o=VGW 1251901012 1251901012 IN IP4 10.1.83.143\r\n"
43 "s=VGW\r\n"
44 "c=IN IP4 10.1.83.143\r\n"
45 "t=0 0\r\n"
46 "a=sendrecv\r\n"
47 "a=x-ActiveSpeaker:on\r\n"
48 "m=audio 45894 RTP/AVP 103 \r\n"
49 "a=rtpmap:103 ISAC/16000/1\r\n"
50 "a=fmtp:103 mode=30, type=fixed, bitrate=32000\r\n"
51 "a=silenceSupp:off - - - -\r\n");
52 HeaderFieldValue hfv(txt.data(), txt.size());
53 Mime type("application", "sdp");
54 SdpContents sdp(hfv, type);
55
56 assert(sdp.session().media().size() == 1);
57 assert(sdp.session().media().front().codecs().size() == 1);
58 CritLog(<< "space at end of m line test passed");
59 }
60
61 {
62 Data txt("v=0\r\n"
63 "o=- 333525334858460 333525334858460 IN IP4 192.168.0.156\r\n"
64 "s=test123\r\n"
65 "c=IN IP4 192.168.0.156\r\n"
66 "t=4058038202 0\r\n"
67 "m=audio 41466 RTP/AVP 0 101\r\n"
68 "a=ptime:20\r\n"
69 "a=rtpmap:0 PCMU/8000\r\n"
70 "a=rtpmap:101 telephone-event/8000\r\n"
71 "a=fmtp:101 0-11\r\n");
72
73 HeaderFieldValue hfv(txt.data(), txt.size());
74 Mime type("application", "sdp");
75 SdpContents sdp(hfv, type);
76
77 assert(sdp.session().media().size() == 1);
78 resip::SdpContents::Session::Codec testCodec("PCMU", 8000, "", "1");
79 for (std::list<resip::SdpContents::Session::Medium>::const_iterator i = sdp.session().media().begin(); i != sdp.session().media().end(); i++)
80 {
81 const std::list<resip::SdpContents::Session::Codec> &codecs = i->codecs();
82 assert(testCodec == codecs.front());
83 }
84
85 //assert(sdp.session.getAttributes().count == 2);
86 CritLog(<< "ftmp test: " << sdp);
87 }
88
89 {
90 Data txt("v=0\r\n"
91 "o=- 333525334858460 333525334858460 IN IP4 192.168.0.156\r\n"
92 "s=test123\r\n"
93 "e=unknown@invalid.net\r\n"
94 "p=+972 683 1000\r\n"
95 "t=4058038202 0\r\n"
96 "m=audio 41466 RTP/AVP 0 101\r\n"
97 "c=IN IP4 192.168.0.156\r\n"
98 "a=fmtp:101 0-11\r\n"
99 "a=ptime:20\r\n"
100 "a=rtpmap:101 telephone-event/8000\r\n");
101
102 HeaderFieldValue hfv(txt.data(), txt.size());
103 Mime type("application", "sdp");
104 SdpContents sdp(hfv, type);
105 assert(sdp.session().getPhones().size() == 1);
106 assert(sdp.session().getEmails().size() == 1);
107
108 assert(Data::from(sdp) == txt);
109
110 CritLog(<< "Email + Phone Test Ok");
111 }
112
113 {
114 Data txt("v=0\r\n"
115 "o=ViPr 1 1 IN IP4 72.29.231.47\r\n"
116 "s=eyeBeam\r\n"
117 "i=\"q2\"<sip:q2@host1.marc.sipit.net>\r\n"
118 "e=NoEmail@NoEmail.com\r\n"
119 "t=0 0\r\n"
120 "a=X-app:ViPr 11 ViPrTerminal\r\n"
121 "a=X-GUID:4a8f41cc8a50_72.29.231.47_\r\n"
122 "a=X-CollabStatus: CollabState_Idle\r\n"
123 "m=audio 50958 RTP/AVP 0\r\n"
124 "i=\"q2\"<sip:q2@host1.marc.sipit.net>\r\n"
125 "c=IN IP4 72.29.231.47\r\n"
126 "a=rtpmap:0 PCMU/8000/1\r\n"
127 "a=sendrecv\r\n"
128 "a=X-app:ViPr 11 ViPrTerminal\r\n"
129 "m=video 0 RTP/AVP 32\r\n"
130 "c=IN IP4 72.29.231.47\r\n");
131
132
133 HeaderFieldValue hfv(txt.data(), txt.size());
134 Mime type("application", "sdp");
135 SdpContents sdp(hfv, type);
136 CritLog ( << sdp.session().media().size());
137 assert(sdp.session().media().size() == 2);
138
139 CritLog(<< "Marconi Test Ok");
140 }
141
142 {
143 Data txt("v=0\r\n"
144 "o=ff_AT_tye.idv.tw 170748954 170754822 IN IP4 202.5.224.96\r\n"
145 "s=X-Lite\r\n"
146 "c=IN IP4 202.5.224.96\r\n"
147 "t=0 0\r\n"
148 "m=audio 12000 RTP/AVP 98 101\r\n"
149 "a=fmtp:101 0-15\r\n"
150 "a=rtpmap:98 iLBC/8000\r\n"
151 "a=rtpmap:101 telephone-event/8000\r\n");
152
153 HeaderFieldValue hfv(txt.data(), txt.size());
154 Mime type("application", "sdp");
155 SdpContents sdp(hfv, type);
156 assert(sdp.session().connection().getAddress() == "202.5.224.96");
157 assert(sdp.session().media().front().port() == 12000);
158 assert(sdp.session().media().front().getValues("fmtp").front() == "101 0-15");
159 assert(sdp.session().media().front().getValues("rtpmap").front() == "98 iLBC/8000");
160 assert(*++sdp.session().media().front().getValues("rtpmap").begin() == "101 telephone-event/8000");
161
162 assert(sdp.session().media().front().codecs().front().getName() == "iLBC");
163
164 CritLog(<< "Ok");
165 }
166
167 //exit(0);
168
169 {
170 Data txt("v=0\r\n"
171 "o=CiscoSystemsSIP-GW-UserAgent 2087 3916 IN IP4 64.124.66.33\r\n"
172 "s=SIP Call\r\n"
173 "c=IN IP4 64.124.66.33\r\n"
174 "t=0 0\r\n"
175 "m=audio 12004 RTP/AVP 0 19\r\n"
176 "c=IN IP4 64.124.66.33\r\n"
177 "a=rtpmap:0 PCMU/8000\r\n"
178 "a=rtpmap:19 CN/8000\r\n");
179
180 HeaderFieldValue hfv(txt.data(), txt.size());
181 Mime type("application", "sdp");
182 SdpContents sdp(hfv, type);
183 assert(sdp.session().connection().getAddress() == "64.124.66.33");
184 assert(sdp.session().media().front().port() == 12004);
185 }
186
187 {
188 Data txt("v=0\r\n"
189 "o=1900 369696545 369696545 IN IP4 192.168.2.15\r\n"
190 "s=X-Lite\r\n"
191 "c=IN IP4 192.168.2.15\r\n"
192 "t=0 0\r\n"
193 "m=audio 8000 RTP/AVP 8 3 98 97 101\r\n"
194 "a=rtpmap:8 pcma/8000\r\n"
195 "a=rtpmap:3 gsm/8000\r\n"
196 "a=rtpmap:98 iLBC\r\n"
197 "a=rtpmap:97 speex/8000\r\n"
198 "a=rtpmap:101 telephone-event/8000\r\n"
199 "a=fmtp:101 0-15\r\n");
200
201 HeaderFieldValue hfv(txt.data(), txt.size());
202 Mime type("application", "sdp");
203 SdpContents sdp(hfv, type);
204
205 assert(sdp.session().media().front().codecs().size() == 5);
206 }
207
208 {
209 Data txt("v=0\r\n"
210 "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n"
211 "s=-\r\n"
212 "c=IN IP4 pc33.atlanta.com\r\n"
213 "t=0 0\r\n"
214 "m=audio 3456 RTP/AVP 0 1 3 99\r\n"
215 "a=rtpmap:0 PCMU/8000\r\n");
216 HeaderFieldValue hfv(txt.data(), txt.size());
217 Mime type("application", "sdp");
218 SdpContents sdp(hfv, type);
219
220 HeaderFieldValue hfv2(txt.data(), txt.size());
221 SdpContents sdp2(hfv2, type);
222
223 sdp.session();
224 sdp2.session();
225
226 Data sdpO = Data::from(sdp);
227 sdp = sdp2;
228 Data sdpO2 = Data::from(sdp);
229
230 cerr << "!! " << sdp << endl;
231 assert(sdpO == sdpO2);
232 }
233
234 tassert_init(4);
235 {
236 Data txt("v=0\r\n"
237 "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n"
238 "s=-\r\n"
239 "c=IN IP4 pc33.atlanta.com\r\n"
240 "t=0 0\r\n"
241 "m=audio 3456 RTP/AVP 0 1 3 99\r\n"
242 "a=rtpmap:0 PCMU/8000\r\n");
243
244 HeaderFieldValue hfv(txt.data(), txt.size());
245 Mime type("application", "sdp");
246 SdpContents sdp(hfv, type);
247
248 tassert_reset();
249
250 tassert(sdp.session().version() == 0);
251 tassert(sdp.session().origin().user() == "alice");
252 tassert(!sdp.session().media().empty());
253
254 //this fails, but should probably not parse(t before c not in sdp)
255 tassert(sdp.session().media().front().getValues("rtpmap").front() == "0 PCMU/8000");
256 tassert_verify(1);
257
258 }
259
260 {
261 const char* txt =
262 ("v=0\r\n"
263 "o=UserA 2890844526 2890844527 IN IP4 here.com\r\n"
264 "s=Session SDP\r\n"
265 "c=IN IP4 pc33.atlanta.com\r\n"
266 "t=5 17\r\n"
267 "m=audio 49172 RTP/AVP 0\r\n"
268 "a=rtpmap:0 PCMU/8000\r\n"
269 "\r\n");
270
271 HeaderFieldValue hfv(txt, strlen(txt));
272 Mime type("application", "sdp");
273 SdpContents sdp(hfv, type);
274 tassert_reset();
275 tassert(sdp.session().version() == 0);
276 tassert(sdp.session().origin().user() == "UserA");
277 tassert(sdp.session().origin().getSessionId() == 2890844526UL);
278 tassert(sdp.session().origin().getVersion() == 2890844527UL);
279 tassert(sdp.session().origin().getAddressType() == SdpContents::IP4);
280 tassert(sdp.session().origin().getAddress() == "here.com");
281
282 tassert(sdp.session().name() == "Session SDP");
283
284 tassert(sdp.session().connection().getAddressType() == SdpContents::IP4);
285 tassert(sdp.session().connection().getAddress() == "pc33.atlanta.com");
286 tassert(sdp.session().connection().ttl() == 0);
287
288 tassert(sdp.session().getTimes().front().getStart() == 5);
289 tassert(sdp.session().getTimes().front().getStop() == 17);
290 tassert(sdp.session().getTimes().front().getRepeats().empty());
291 tassert(sdp.session().getTimezones().getAdjustments().empty());
292
293 tassert(sdp.session().media().front().name() == "audio");
294 tassert(sdp.session().media().front().port() == 49172);
295 tassert(sdp.session().media().front().multicast() == 1);
296 tassert(sdp.session().media().front().protocol() == "RTP/AVP");
297 tassert(sdp.session().media().front().getFormats().front() == "0");
298
299 tassert(sdp.session().media().front().getValues("rtpmap").front() == "0 PCMU/8000");
300 tassert(sdp.session().media().front().exists("fuzzy") == false);
301 tassert_verify(2);
302
303 }
304
305 {
306 const char* txt = ("v=0\r\n"
307 "o=CiscoSystemsSIP-GW-UserAgent 3559 3228 IN IP4 192.168.2.122\r\n"
308 "s=SIP Call\r\n"
309 "c=IN IP4 192.168.2.122\r\n"
310 "t=0 0\r\n"
311 "m=audio 17124 RTP/AVP 18\r\n"
312 "a=rtpmap:18 G729/8000\r\n");
313
314 HeaderFieldValue hfv(txt, strlen(txt));
315 Mime type("application", "sdp");
316 SdpContents sdp(hfv, type);
317 tassert_reset();
318 tassert(sdp.session().version() == 0);
319 tassert(sdp.session().origin().user() == "CiscoSystemsSIP-GW-UserAgent");
320 tassert(sdp.session().origin().getSessionId() == 3559);
321 tassert(sdp.session().origin().getVersion() == 3228);
322 tassert(sdp.session().origin().getAddressType() == SdpContents::IP4);
323 tassert(sdp.session().origin().getAddress() == "192.168.2.122");
324
325 tassert(sdp.session().name() == "SIP Call");
326
327 tassert(sdp.session().connection().getAddressType() == SdpContents::IP4);
328 tassert(sdp.session().connection().getAddress() == "192.168.2.122");
329 tassert(sdp.session().connection().ttl() == 0);
330
331 tassert(sdp.session().getTimes().front().getStart() == 0);
332 tassert(sdp.session().getTimes().front().getStop() == 0);
333 tassert(sdp.session().getTimes().front().getRepeats().empty());
334 tassert(sdp.session().getTimezones().getAdjustments().empty());
335
336 tassert(sdp.session().media().front().name() == "audio");
337 tassert(sdp.session().media().front().port() == 17124);
338 tassert(sdp.session().media().front().multicast() == 1);
339 tassert(sdp.session().media().front().protocol() == "RTP/AVP");
340 tassert(sdp.session().media().front().getFormats().front() == "18");
341
342 tassert(sdp.session().media().front().getValues("rtpmap").front() == "18 G729/8000");
343 tassert(sdp.session().media().front().exists("fuzzy") == false);
344 tassert_verify(3);
345 }
346
347 #if 0 // .slg. removing this test case - attribute order is currently not guaranteed to be mainted
348 {
349 tassert_reset();
350 SdpContents sdp;
351 unsigned long tm = 4058038202u;
352 Data address("192.168.2.220");
353 int port = 5061;
354
355 unsigned long sessionId((unsigned long) tm);
356
357 SdpContents::Session::Origin origin("-", sessionId, sessionId, SdpContents::IP4, address);
358
359 SdpContents::Session session(0, origin, "VOVIDA Session");
360
361 session.connection() = SdpContents::Session::Connection(SdpContents::IP4, address);
362 session.addTime(SdpContents::Session::Time(tm, 0));
363
364 SdpContents::Session::Medium medium("audio", port, 0, "RTP/AVP");
365 medium.addFormat("0");
366 medium.addFormat("101");
367
368 medium.addAttribute("rtpmap", "0 PCMU/8000");
369 medium.addAttribute("rtpmap", "101 telephone-event/8000");
370 medium.addAttribute("ptime", "160");
371 medium.addAttribute("fmtp", "101 0-11");
372
373 session.addMedium(medium);
374
375 sdp.session() = session;
376
377 Data shouldBeLike("v=0\r\n"
378 "o=- 4058038202 4058038202 IN IP4 192.168.2.220\r\n"
379 "s=VOVIDA Session\r\n"
380 "c=IN IP4 192.168.2.220\r\n"
381 "t=4058038202 0\r\n"
382 "m=audio 5061 RTP/AVP 0 101\r\n"
383 "a=fmtp:101 0-11\r\n"
384 "a=ptime:160\r\n"
385 "a=rtpmap:0 PCMU/8000\r\n"
386 "a=rtpmap:101 telephone-event/8000\r\n");
387
388 Data encoded(Data::from(sdp));
389
390 //cout << encoded;
391 //cout << shouldBeLike;
392 assert(encoded == shouldBeLike);
393 tassert_verify(4);
394 }
395 tassert_report();
396 #endif
397
398 {
399 Data txt("v=0\r\n"
400 "o=ray.zibman 846934093 1 IN IP4 66.152.249.120\r\n"
401 "s=phone-call\r\n"
402 "c=IN IP4 66.152.249.120\r\n"
403 "b=CT 1000\r\n" // should be CT:1000
404 "t=0 0\r\n"
405 "m=audio 12002 RTP/AVP 0 101\r\n"
406 "a=rtpmap:0 PCMU/8000\r\n"
407 "a=rtpmap:101 telephone-event/8000\r\n"
408 "a=fmtp:101 0-16\r\n");
409
410 HeaderFieldValue hfv(txt.data(), txt.size());
411 Mime type("application", "sdp");
412 SdpContents sdp(hfv, type);
413
414 try
415 {
416 assert(sdp.session().media().front().codecs().size() == 2);
417 assert(false);
418 }
419 catch (ParseException& e)
420 {
421 // bad bandwidth
422 }
423 }
424
425 {
426 Data txt("v=0\r\n"
427 "o=anonymous 1076575175 1076575175 IN IP4 192.168.1.100\r\n"
428 "s=eConf 4.0\r\n"
429 "i=eConf 4.0\r\n"
430 "b=AS:256\r\n"
431 "t=0 0\r\n"
432 "m=audio 6000 RTP/AVP 102 104 9 4 0 8 98\r\n"
433 "a=fmtp:98 0-15\r\n"
434 "a=rtpmap:102 X-G72x1/16000\r\n"
435 "a=rtpmap:104 X-G72x24/16000\r\n"
436 "a=rtpmap:9 G722/8000\r\n"
437 "a=rtpmap:4 G723/8000\r\n"
438 "a=rtpmap:0 PCMU/8000\r\n"
439 "a=rtpmap:8 PCMA/8000\r\n"
440 "a=rtpmap:98 telephone-event/8000\r\n"
441 "a=sendrecv\r\n"
442 "m=video 6002 RTP/AVP 97 98 34 31\r\n"
443 "b=AS:192\r\n"
444 "a=fmtp:97 QCIF=1/MaxBR=1920/\r\n"
445 "a=framerate:25.0\r\n"
446 "a=fmtp:34 QCIF=1/MaxBR=1920\r\n"
447 "a=fmtp:31 QCIF=1/MaxBR=1920\r\n"
448 "a=rtpmap:97 H263-1998/90000\r\n"
449 "a=rtpmap:98 MP4V-ES/90000\r\n"
450 "a=rtpmap:34 H263/90000\r\n"
451 "a=rtpmap:31 H261/90000\r\n"
452 "a=sendrecv\r\n");
453
454 HeaderFieldValue hfv(txt.data(), txt.size());
455 Mime type("application", "sdp");
456 SdpContents sdp(hfv, type);
457
458 assert(sdp.session().information() == "eConf 4.0");
459 assert(sdp.session().media().size() == 2);
460 }
461
462 #if 0 //.dcm. -- we don't validate, so this failure isn't something we are
463 //planning to fix afaik
464 {
465 Data txt("v=0\r\n"
466 "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n"
467 "s=-\r\n"
468 "t=0 0\r\n"
469 "c=IN IP4 pc33.atlanta.com\r\n"
470 "m=audio 3456 RTP/AVP 0 1 3 99\r\n"
471 "a=rtpmap:0 PCMU/8000\r\n");
472
473 HeaderFieldValue hfv(txt.data(), txt.size());
474 Mime type("application", "sdp");
475 SdpContents sdp(hfv, type);
476
477 tassert(sdp.session().version() == 0);
478 tassert(sdp.session().origin().user() == "alice");
479 tassert(!sdp.session().media().empty());
480 //this fails, but should probably not parse(t before c not in sdp)
481 tassert(sdp.session().media().front().getValues("rtpmap").front() == "0 PCMU/8000");
482 tassert_verify(5);
483 }
484 #endif
485
486
487 {
488 Data txt("v=0\r\n"
489 "o=CiscoSystemsSIP-GW-UserAgent 4316 2064 IN IP4 65.39.205.114\r\n"
490 "s=SIP Call\r\n"
491 "c=IN IP4 65.39.205.114\r\n"
492 "t=0 0\r\n"
493 "m=audio 36928 RTP/AVP 0\r\n"
494 "c=IN IP4 65.39.205.114\r\n"
495 "a=rtpmap:0 PCMU/8000\r\n"
496 "m=video 36924 RTP/AVP\r\n"
497 "c=IN IP4 65.39.205.114\r\n");
498
499 HeaderFieldValue hfv(txt.data(), txt.size());
500 Mime type("application", "sdp");
501 SdpContents sdp(hfv, type);
502
503 assert(sdp.session().media().size() == 2);
504 }
505
506 {
507 Data txt("v=0\r\n"
508 "o=test 846934093 1 IN IP4 10.10.10.10\r\n"
509 "s=SIP Call\r\n"
510 "c=IN IP4 10.10.10.10\r\n"
511 "t=0 0\r\n"
512 "m=audio 12002 RTP/AVP 9 101\r\n"
513 "a=rtpmap:101 telephone-event/8000\r\n"
514 "a=fmtp:9 annexb=no\r\n"
515 "a=fmtp:101 0-16\r\n");
516
517 HeaderFieldValue hfv(txt.data(), txt.size());
518 Mime type("application", "sdp");
519 SdpContents sdp(hfv, type);
520
521 assert(sdp.session().media().front().codecs().size() == 2);
522 assert(sdp.session().media().front().codecs().front().payloadType() == 9);
523 assert(sdp.session().media().front().codecs().front().parameters() == "annexb=no");
524 assert(sdp.session().media().front().codecs().back().payloadType() == 101);
525 assert(sdp.session().media().front().codecs().back().parameters() == "0-16");
526 }
527
528 {
529 Data txt("v=0\r\n"
530 "o=Dialogic_IPCCLib 147345984 147345984 IN IP4 58.185.204.251\r\n"
531 "s=Dialogic_SIP_CCLIB\r\n"
532 "i=session information\r\n"
533 "c=IN IP4 58.185.204.251\r\n"
534 "t=0 0\r\n"
535 "m=audio 49172 RTP/AVP 0 101\r\n"
536 "a=rtpmap:0 PCMU/8000\r\n"
537 "a=fmtp\r\n"
538 "a=rtpmap:101 telephone-event/8000\r\n"
539 "m=video 57364 RTP/AVP 34\r\n"
540 "b=AS:42\r\n"
541 "a=rtpmap:34 H263/90\r\n");
542
543
544 HeaderFieldValue hfv(txt.data(), txt.size());
545 Mime type("application", "sdp");
546 SdpContents sdp(hfv, type);
547
548 assert(sdp.session().media().size() == 2);
549 assert(sdp.session().media().front().getValues("fmtp").front() == "");
550 assert(sdp.session().media().front().codecs().size() == 2); // 0 and 101
551 assert(sdp.session().media().front().codecs().front().parameters().size() == 0);
552 assert(sdp.session().media().front().codecs().back().parameters().size() == 0);
553
554 CritLog(<< "Received bad Dialogic fmtp line Ok");
555 }
556
557 return 0;
558 }
559
560 /* ====================================================================
561 * The Vovida Software License, Version 1.0
562 *
563 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
564 *
565 * Redistribution and use in source and binary forms, with or without
566 * modification, are permitted provided that the following conditions
567 * are met:
568 *
569 * 1. Redistributions of source code must retain the above copyright
570 * notice, this list of conditions and the following disclaimer.
571 *
572 * 2. Redistributions in binary form must reproduce the above copyright
573 * notice, this list of conditions and the following disclaimer in
574 * the documentation and/or other materials provided with the
575 * distribution.
576 *
577 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
578 * and "Vovida Open Communication Application Library (VOCAL)" must
579 * not be used to endorse or promote products derived from this
580 * software without prior written permission. For written
581 * permission, please contact vocal@vovida.org.
582 *
583 * 4. Products derived from this software may not be called "VOCAL", nor
584 * may "VOCAL" appear in their name, without prior written
585 * permission of Vovida Networks, Inc.
586 *
587 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
588 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
589 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
590 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
591 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
592 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
593 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
594 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
595 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
596 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
597 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
598 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
599 * DAMAGE.
600 *
601 * ====================================================================
602 *
603 * This software consists of voluntary contributions made by Vovida
604 * Networks, Inc. and many individuals on behalf of Vovida Networks,
605 * Inc. For more information on Vovida Networks, Inc., please see
606 * <http://www.vovida.org/>.
607 *
608 */

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27