1
#if !defined(RESIP_SDPCONTENTS_HXX)
2
#define RESIP_SDPCONTENTS_HXX
9
#include "resip/stack/Contents.hxx"
10
#include "resip/stack/Uri.hxx"
11
#include "rutil/Data.hxx"
12
#include "rutil/HashMap.hxx"
13
#include "rutil/HeapInstanceCounter.hxx"
23
RESIP_HeapCount(AttributeHelper);
25
AttributeHelper(const AttributeHelper& rhs);
26
AttributeHelper& operator=(const AttributeHelper& rhs);
28
bool exists(const Data& key) const;
29
const std::list<Data>& getValues(const Data& key) const;
30
EncodeStream& encode(EncodeStream& s) const;
31
void parse(ParseBuffer& pb);
32
void addAttribute(const Data& key, const Data& value = Data::Empty);
33
void clearAttribute(const Data& key);
35
std::list<std::pair<Data, Data> > mAttributeList; // used to ensure attribute ordering on encode
36
HashMap< Data, std::list<Data> > mAttributes;
41
@brief Provides an interface to process and generate SDP bodies (MIME content-type application/sdp).
43
* This class performs both the parsing and generation of SDP. Most
44
* interaction with the SDP will be through the Session object,
45
* accessible through the session() method.
48
class SdpContents : public Contents
51
RESIP_HeapCount(SdpContents);
52
typedef enum {IP4=1, IP6} AddrType;
53
static const SdpContents Empty;
57
/** @brief Provides an interface to read and modify SDP
66
/** @brief parameters for a specific codec are stored in this class.
72
Codec() : mName(), mRate(0), mPayloadType(-1) {}
74
/** @brief full constructor for a Codec.
76
* This constructor allows a rate and optional parameters to be specified.
78
* @param name a string identifying the codec
79
* @param rate number of samples/sec
80
* @param parameters optional list of parameters for the codec
81
* @param encodingParameters optional encoding parameters for the codec
84
Codec(const Data& name, unsigned long rate, const Data& parameters = Data::Empty, const Data& encodingParameters = Data::Empty);
86
/** @brief constructor for a Codec
88
* This constructor allows for payload type and rate parameters to be specified.
90
* @param name a string identifying the codec
91
* @param payloadType RTP payload type to associate with this codec
92
* @param rate sample rate of this codec
95
Codec(const Data& name, int payloadType, int rate=8000);
96
Codec(const Codec& rhs);
97
Codec& operator=(const Codec& codec);
99
void parse(ParseBuffer& pb,
100
const SdpContents::Session::Medium& medium,
102
void assignFormatParameters(const SdpContents::Session::Medium& medium);
104
/** @brief returns the name of the codec.
105
* @return name of the codec
107
const Data& getName() const;
108
/** @brief returns the name of the codec.
109
* @return name of the codec
113
/** @brief returns the RTP payload type associated with this codec.
114
* @return RTP payload type
116
int payloadType() const {return mPayloadType;}
117
/** @brief returns the RTP payload type associated with this codec.
118
* @return RTP payload type
120
int& payloadType() {return mPayloadType;}
122
/** @brief returns the parameters associated with this codec
123
* @return codec parameters
125
const Data& parameters() const {return mParameters;}
126
/** @brief returns the parameters associated with this codec
127
* @return codec parameters
129
Data& parameters() {return mParameters;}
131
/** @brief returns the encoding parameters associated with this codec
132
* @return encoding parameters
134
const Data& encodingParameters() const {return mEncodingParameters;}
135
/** @brief returns the encoding parameters associated with this codec
136
* @return encoding parameters
138
Data& encodingParameters() {return mEncodingParameters;}
140
static const Codec ULaw_8000;
141
static const Codec ALaw_8000;
142
static const Codec G729_8000;
143
static const Codec G723_8000;
144
static const Codec GSM_8000;
145
static const Codec TelephoneEvent;
146
static const Codec FrfDialedDigit;
147
static const Codec CN;
149
typedef HashMap<int, Codec> CodecMap;
150
// "static" payload types as defined in RFC 3551.
151
// Maps payload type (number) to Codec definition.
152
static CodecMap& getStaticCodecs();
154
friend bool operator==(const Codec&, const Codec&);
160
Data mParameters; // Format parameters
161
Data mEncodingParameters;
163
static std::auto_ptr<CodecMap> sStaticCodecs;
164
static bool sStaticCodecsCreated;
165
friend EncodeStream& operator<<(EncodeStream&, const Codec&);
168
/** @brief processes o= lines in SDP
173
/** @brief constructor for origin line
175
* @param user session user
176
* @param sessionId session ID
177
* @param version session version
178
* @param addr session address type (IP4 or IP6)
179
* @param address IP address of the session
182
Origin(const Data& user,
183
const UInt64& sessionId,
184
const UInt64& version,
186
const Data& address);
187
Origin(const Origin& rhs);
188
Origin& operator=(const Origin& rhs);
190
void parse(ParseBuffer& pb);
191
EncodeStream& encode(EncodeStream&) const;
193
/** @brief returns the session ID
196
const UInt64& getSessionId() const {return mSessionId;}
197
/** @brief returns the session ID
200
UInt64& getSessionId() { return mSessionId; }
202
/** @brief returns the session version
203
* @return session version
205
const UInt64& getVersion() const {return mVersion;}
206
/** @brief returns the session version
207
* @return session version
209
UInt64& getVersion() { return mVersion; }
210
/** @brief returns the user string for the session
211
* @return user string
213
const Data& user() const {return mUser;}
214
/** @brief returns the user string for the session
215
* @return user string
217
Data& user() {return mUser;}
219
/** @brief returns the session address type
221
* @return address type (IP4 or IP6)
223
AddrType getAddressType() const {return mAddrType;}
224
/** @brief returns the session address type
226
* @return address type (IP4 or IP6)
228
const Data& getAddress() const {return mAddress;}
230
/** @brief set the address for the session
232
* @param host IP address to associate with the session
233
* @param type type of addressing
235
void setAddress(const Data& host, AddrType type = IP4);
246
friend class Session;
249
/** @brief process e= (email) lines in the SDP
255
/** @brief constructor
257
* @param address email address
258
* @param freeText string describing the email address
261
Email(const Data& address,
262
const Data& freeText);
264
Email(const Email& rhs);
265
Email& operator=(const Email& rhs);
267
void parse(ParseBuffer& pb);
268
EncodeStream& encode(EncodeStream&) const;
270
/** @brief returns the email address
272
* @return email address
274
const Data& getAddress() const {return mAddress;}
275
/** @brief returns the string describing the email address
279
const Data& getFreeText() const {return mFreeText;}
287
friend class Session;
290
/** @brief process p= (phone number) lines in the SDP
296
/** @brief constructor
298
* @param number phone number
299
* @param freeText text string describing the phone number
302
Phone(const Data& number,
303
const Data& freeText);
304
Phone(const Phone& rhs);
305
Phone& operator=(const Phone& rhs);
307
void parse(ParseBuffer& pb);
308
EncodeStream& encode(EncodeStream&) const;
311
/** @brief return the phone number
313
* @return phone number
315
const Data& getNumber() const {return mNumber;}
316
/** @brief return text string describing the phone number
318
* @return text string describing the phone number
320
const Data& getFreeText() const {return mFreeText;}
328
friend class Session;
331
/** @brief Process c= (connection) lines in SDP
333
* This line specifies the IP address and address type used in the session
339
/** @brief constructor
341
* @param addType address type (IP4 or IP6)
342
* @param address IP address
343
* @param ttl time to live
346
Connection(AddrType addType,
348
unsigned long ttl = 0);
349
Connection(const Connection& rhs);
350
Connection& operator=(const Connection& rhs);
352
void parse(ParseBuffer& pb);
353
EncodeStream& encode(EncodeStream&) const;
355
/** @brief returns the connection address type
357
* @return address type (IP4 or IP6)
359
AddrType getAddressType() const {return mAddrType;}
361
/** @brief returns the connection address
365
const Data& getAddress() const {return mAddress;}
367
/** @brief set the address for the connection
369
* @param host IP address to associate with the connection
370
* @param type type of addressing
372
void setAddress(const Data& host, AddrType type = IP4);
373
unsigned long ttl() const {return mTTL;}
374
unsigned long& ttl() {return mTTL;}
383
friend class Session;
387
/** @brief Process optional b= (bandwidth) lines in SDP
393
/** @brief Constructor
395
* @param modifier alphanumeric word giving the meaning of the bandwidth figure
396
* @param kbPerSecond number of kilobits per second
399
Bandwidth(const Data& modifier,
400
unsigned long kbPerSecond);
401
Bandwidth(const Bandwidth& rhs);
402
Bandwidth& operator=(const Bandwidth& rhs);
404
void parse(ParseBuffer& pb);
405
EncodeStream& encode(EncodeStream&) const;
407
/** @brief returns the modifier string
409
* @return modifier string
411
const Data& modifier() const {return mModifier;}
412
/** @brief returns the modifier string
414
* @return modifier string
416
Data modifier() {return mModifier;}
417
/** @brief returns the number of kilobits/second maximum bandwidth
419
* @return maximum bandwidth in kilobits/second
421
unsigned long kbPerSecond() const {return mKbPerSecond;}
422
/** @brief returns the number of kilobits/second maximum bandwidth
424
* @return maximum bandwidth in kilobits/second
426
unsigned long& kbPerSecond() {return mKbPerSecond;}
431
unsigned long mKbPerSecond;
433
friend class Session;
437
/** @brief Process t= (start/stop time) lines in SDP
443
/** @brief Constructor
445
* The times given are the decimal part of an NTP timestamp. To convert these values to UNIX time,
446
* subtract decimal 2208988800 from the value.
448
* @param start start time
449
* @param stop stop time
452
Time(unsigned long start,
454
Time(const Time& rhs);
455
Time& operator=(const Time& rhs);
457
void parse(ParseBuffer& pb);
458
EncodeStream& encode(EncodeStream&) const;
460
/** @brief Repeat time. Not used for SIP
466
Repeat(unsigned long interval,
467
unsigned long duration,
468
std::list<int> offsets);
469
void parse(ParseBuffer& pb);
470
EncodeStream& encode(EncodeStream&) const;
472
unsigned long getInterval() const {return mInterval;}
473
unsigned long getDuration() const {return mDuration;}
474
const std::list<int> getOffsets() const {return mOffsets;}
478
unsigned long mInterval;
479
unsigned long mDuration;
480
std::list<int> mOffsets;
485
void addRepeat(const Repeat& repeat);
487
/** @brief return the start time
491
unsigned long getStart() const {return mStart;}
492
/** @brief return the stop time
496
unsigned long getStop() const {return mStop;}
497
const std::list<Repeat>& getRepeats() const {return mRepeats;}
501
unsigned long mStart;
503
std::list<Repeat> mRepeats;
505
friend class Session;
508
/** @brief process z= (timezone) lines
516
/** @brief specify the time at which a timezone shift will occur and the offset, in seconds
522
Adjustment(unsigned long time,
524
Adjustment(const Adjustment& rhs);
525
Adjustment& operator=(const Adjustment& rhs);
532
Timezones(const Timezones& rhs);
533
Timezones& operator=(const Timezones& rhs);
535
void parse(ParseBuffer& pb);
536
EncodeStream& encode(EncodeStream&) const;
538
void addAdjustment(const Adjustment& adjusment);
539
const std::list<Adjustment>& getAdjustments() const {return mAdjustments; }
541
std::list<Adjustment> mAdjustments;
544
/** @brief process k= (encryption key) line
550
typedef enum {NoEncryption = 0, Prompt, Clear, Base64, UriKey} KeyType;
551
Encryption(const KeyType& method,
553
Encryption(const Encryption& rhs);
554
Encryption& operator=(const Encryption& rhs);
557
void parse(ParseBuffer& pb);
558
EncodeStream& encode(EncodeStream&) const;
560
const KeyType& getMethod() const {return mMethod;}
561
const KeyType& method() const {return mMethod;}
562
KeyType& method() {return mMethod;}
563
const Data& getKey() const {return mKey;}
564
const Data& key() const {return mKey;}
565
Data& key() {return mKey;}
573
/** @brief process m= (media announcement) blocks
580
Medium(const Medium& rhs);
581
/** @brief Constructor
583
* @param name media type (audio, video, application, data, etc.)
584
* @param port UDP port that will receive RTP
585
* @param multicast a misnomer. If multicast > 1, the next (multicast)
586
* even ports will convey RTP and the next (multicast) odd ports will
587
* convey corresponding RTCP
588
* @param protocol the transport used to convey the media. Usually "RTP/AVP" for SIP.
591
Medium(const Data& name,
593
unsigned long multicast,
594
const Data& protocol);
595
Medium& operator=(const Medium& rhs);
597
void parse(ParseBuffer& pb);
598
EncodeStream& encode(EncodeStream&) const;
600
/** @brief add a format identifier to the m= line
602
* This will need to be called for each codec used in the SDP.
604
* @param format format identifier
607
void addFormat(const Data& format);
608
/** @brief set the media connection line. Optional if main SDP has c= line.
610
* @param connection connection line to use
612
void setConnection(const Connection& connection);
613
/** @brief add a media connection line. Optional if main SDP has c= line.
615
* @param connection connection line to use
617
void addConnection(const Connection& connection);
618
void setBandwidth(const Bandwidth& bandwidth);
619
void addBandwidth(const Bandwidth& bandwidth);
620
/** @brief add a media attribute line
622
* @param key attribute key
623
* @param value attribute value
626
void addAttribute(const Data& key, const Data& value = Data::Empty);
628
/** @brief return the media type
632
const Data& name() const {return mName;}
633
/** @brief return the media type
637
Data& name() {return mName;}
638
/** @brief return the base port
642
int port() const {return mPort;}
643
/** @brief return the base port
647
unsigned long& port() {return mPort;}
648
/** @brief change the base port
650
* @param port new base port
653
void setPort(int port);
654
/** @brief get the number of transport port pairs
656
* @return number of transport port pairs
658
int multicast() const {return mMulticast;}
659
/** @brief get the number of transport port pairs
661
* @return number of transport port pairs
663
unsigned long& multicast() {return mMulticast;}
664
/** @brief return the transport protocol
666
* @return transport protocol name
668
const Data& protocol() const {return mProtocol;}
669
/** @brief return the transport protocol
671
* @return transport protocol name
673
Data& protocol() {return mProtocol;}
675
// preferred codec/format interface
676
typedef std::list<Codec> CodecContainer;
677
/** preferred codec/format interface
678
@note internal storage of formats, rtpmap attributes, and
679
ftmp attributes are cleared out after codecs() is
680
called, since they get converted internally as Codec
683
const CodecContainer& codecs() const;
684
CodecContainer& codecs();
686
/** @brief remove all codecs from SDP **/
688
/** @brief add a codec to the m= line
690
* @param codec codec to add
693
void addCodec(const Codec& codec);
695
/** @brief return a list of codec formats
697
* These formats correspond to RTP payload type identifiers
699
* @note formats are cleared out and converted in codec
700
* objects when codecs() is called
701
* @return list of codec formats
703
const std::list<Data>& getFormats() const {return mFormats;}
705
/** @brief get optional i= (information) line contents
709
const Data& information() const {return mInformation;}
710
/** @brief get optional i= (information) line contents
714
Data& information() {return mInformation;}
715
/** @brief get a list of bandwidth lines
717
* @return list of Bandwidth objects
719
const std::list<Bandwidth>& bandwidths() const {return mBandwidths;}
720
std::list<Bandwidth>& bandwidths() {return mBandwidths;}
722
/** @brief get a list of Connection objects, including the Session's c= line.
724
* If the media's c= line is empty, use the Session's c= line.
726
* @return list of connections
728
const std::list<Connection> getConnections() const;
729
/** @brief get a list of Connection objects from the m= section. Does not include session c= line.
731
* @return list of connections
733
const std::list<Connection>& getMediumConnections() const {return mConnections;}
734
std::list<Connection>& getMediumConnections() {return mConnections;}
735
const Encryption& getEncryption() const {return mEncryption;}
736
const Encryption& encryption() const {return mEncryption;}
737
Encryption& encryption() {return mEncryption;}
738
/** @brief tests if an a= key is present in the media section
740
* @param key key to check
742
* @return true if key exists, false otherwise
744
bool exists(const Data& key) const;
745
/** @brief get the attribute values corresponding to the key
747
* @param key key to check
749
* @return list of values for given key
751
const std::list<Data>& getValues(const Data& key) const;
752
/** @brief erase all attributes for a given key
754
* @param key key to clear
757
void clearAttribute(const Data& key);
759
// Search through this mediums codecs to find and return the first match from the passed in list
760
// Note: The codecList item that matched the codec from the medium is passed back via pMatchingCodec
761
// if a non-NULL pointer is passed in. The codec returned if from this medium.
762
const Codec& findFirstMatchingCodecs(const CodecContainer& codecs, Codec* pMatchingCodec = 0) const;
763
// Search through this mediums codecs to find and return the first match from the passed in medium
764
// Note: The passed in medium's codec that matched the codec from this medium is passed back
765
// via pMatchingCodec if a non-NULL pointer is passed in. The codec returned if from this medium.
766
const Codec& findFirstMatchingCodecs(const Medium& medium, Codec* pMatchingCodec = 0) const;
768
/** @brief finds the telephone-event payload type
770
* @return payload type of telephone-event "codec"
772
int findTelephoneEventPayloadType() const;
775
void setSession(Session* session);
780
unsigned long mMulticast;
782
std::list<Data> mFormats;
783
CodecContainer mCodecs;
786
std::list<Connection> mConnections;
787
std::list<Bandwidth> mBandwidths;
788
Encryption mEncryption;
789
AttributeHelper mAttributeHelper;
792
typedef HashMap<int, Codec> RtpMap;
795
friend class Session;
798
/** @brief session constructor
800
* Create a new session from origin line, version, and session anme
802
* @param version session version
803
* @param origin Origin line
804
* @param name session name
808
const Origin& origin,
811
Session() : mVersion(0) {}
812
Session(const Session& rhs);
813
Session& operator=(const Session& rhs);
815
void parse(ParseBuffer& pb);
816
EncodeStream& encode(EncodeStream&) const;
818
/** @brief return session version
820
* @return session version
822
int version() const {return mVersion;}
823
/** @brief return session version
825
* @return session version
827
int& version() {return mVersion;}
828
/** @brief return session Origin line
830
* @return Origin line
832
const Origin& origin() const {return mOrigin;}
833
/** @brief return session Origin line
835
* @return Origin line
837
Origin& origin() {return mOrigin;}
838
/** @brief return session name
842
const Data& name() const {return mName;}
843
/** @brief return session name
847
Data& name() {return mName;}
848
/** @brief return session Information
850
* @return Information line
852
const Data& information() const {return mInformation;}
853
/** @brief return session Information
855
* @return Information line
857
Data& information() {return mInformation;}
858
/** @brief return session Uri
862
const Uri& uri() const {return mUri;}
863
/** @brief return session Uri
867
Uri& uri() {return mUri;}
868
/** @brief return session Email list
872
const std::list<Email>& getEmails() const {return mEmails;}
873
/** @brief return session Phone number list
875
* @return Phone number list
877
const std::list<Phone>& getPhones() const {return mPhones;}
878
/** @brief return session Connection
880
* @return Connection line
882
const Connection& connection() const {return mConnection;}
883
/** @brief return session Connection
885
* @return Connection line
887
Connection& connection() {return mConnection;} // !dlb! optional?
888
/** @brief check if a c= line is present for the session
890
* @return true if c= line is present
892
bool isConnection() const { return mConnection.mAddress != Data::Empty; }
893
/** @brief return session Bandwidth lines
895
* @return Bandwidth lines
897
const std::list<Bandwidth>& bandwidths() const {return mBandwidths;}
898
/** @brief return session Bandwidth lines
900
* @return Bandwidth lines
902
std::list<Bandwidth>& bandwidths() {return mBandwidths;}
903
/** @brief return session Time lines
907
const std::list<Time>& getTimes() const {return mTimes;}
908
/** @brief return session Time lines
912
std::list<Time>& getTimes() {return mTimes;}
913
const Timezones& getTimezones() const {return mTimezones;}
914
const Encryption& getEncryption() const {return mEncryption;}
915
const Encryption& encryption() const {return mEncryption;}
916
Encryption& encryption() {return mEncryption;}
917
typedef std::list<Medium> MediumContainer;
918
/** @brief return session Media lines
920
* @return Media lines
922
const MediumContainer& media() const {return mMedia;}
923
/** @brief return session Media lines
925
* @return Media lines
927
MediumContainer& media() {return mMedia;}
929
/** @brief add an e= (email) line to session
931
* @param email Email line to add
934
void addEmail(const Email& email);
935
/** @brief add a p= (phone number) line to session
937
* @param phone Phone line to add
940
void addPhone(const Phone& phone);
941
/** @brief add a b= (Bandwidth) line to session
943
* @param bandwidth Bandwidth line to add
946
void addBandwidth(const Bandwidth& bandwidth);
947
/** @brief add a t= (Time) line to session
949
* @param t Time line to add
952
void addTime(const Time& t);
953
/** @brief add an m= (Medium) section to session
955
* @param medium Medium section to add
958
void addMedium(const Medium& medium);
959
/** @brief remove all Medium sections from session
962
void clearMedium() { mMedia.clear(); }
963
/** @brief erase all attributes for a given key
965
* @param key key to clear
968
void clearAttribute(const Data& key);
969
/** @brief add a session attribute line
971
* @param key attribute key
972
* @param value attribute value
975
void addAttribute(const Data& key, const Data& value = Data::Empty);
976
/** @brief tests if an a= key is present in the session
978
* @param key key to check
980
* @return true if key exists, false otherwise
982
bool exists(const Data& key) const;
983
/** @brief get the attribute values corresponding to the key
985
* @param key key to check
987
* @return list of values for given key
989
const std::list<Data>& getValues(const Data& key) const;
995
MediumContainer mMedia;
997
// applies to all Media where unspecified
1000
std::list<Email> mEmails;
1001
std::list<Phone> mPhones;
1002
Connection mConnection;
1003
std::list<Bandwidth> mBandwidths;
1004
std::list<Time> mTimes;
1005
Timezones mTimezones;
1006
Encryption mEncryption;
1007
AttributeHelper mAttributeHelper;
1009
friend class SdpContents;
1013
SdpContents(const HeaderFieldValue& hfv, const Mime& contentTypes);
1014
virtual ~SdpContents();
1016
// !nash! there is no need for overriding copy ctor as every members gets copied
1017
//SdpContents(const SdpContents& rhs);
1018
SdpContents& operator=(const SdpContents& rhs);
1020
/** @brief duplicate an SdpContents object
1022
* @return pointer to a new SdpContents object
1024
virtual Contents* clone() const;
1026
/** @brief get the parsed SDP
1028
* @return parsed SDP object
1030
Session& session() {checkParsed(); return mSession;}
1031
const Session& session() const {checkParsed(); return mSession;}
1033
virtual EncodeStream& encodeParsed(EncodeStream& str) const;
1034
virtual void parse(ParseBuffer& pb);
1035
static const Mime& getStaticType() ;
1040
SdpContents(const Data& data, const Mime& contentTypes);
1044
static bool invokeSdpContentsInit = SdpContents::init();
1046
typedef SdpContents::Session::Codec Codec;
1048
bool operator==(const SdpContents::Session::Codec& lhs,
1049
const SdpContents::Session::Codec& rhs);
1051
EncodeStream& operator<<(EncodeStream& str, const SdpContents::Session::Codec& codec);
1057
/* ====================================================================
1058
* The Vovida Software License, Version 1.0
1060
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1062
* Redistribution and use in source and binary forms, with or without
1063
* modification, are permitted provided that the following conditions
1066
* 1. Redistributions of source code must retain the above copyright
1067
* notice, this list of conditions and the following disclaimer.
1069
* 2. Redistributions in binary form must reproduce the above copyright
1070
* notice, this list of conditions and the following disclaimer in
1071
* the documentation and/or other materials provided with the
1074
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
1075
* and "Vovida Open Communication Application Library (VOCAL)" must
1076
* not be used to endorse or promote products derived from this
1077
* software without prior written permission. For written
1078
* permission, please contact vocal@vovida.org.
1080
* 4. Products derived from this software may not be called "VOCAL", nor
1081
* may "VOCAL" appear in their name, without prior written
1082
* permission of Vovida Networks, Inc.
1084
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1085
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1086
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1087
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1088
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1089
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1090
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1091
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1092
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1093
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1094
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1095
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1098
* ====================================================================
1100
* This software consists of voluntary contributions made by Vovida
1101
* Networks, Inc. and many individuals on behalf of Vovida Networks,
1102
* Inc. For more information on Vovida Networks, Inc., please see
1103
* <http://www.vovida.org/>.