Coverage Report

Created: 2025-11-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/SipMessage.hxx
Line
Count
Source
1
#if !defined(RESIP_SIPMESSAGE_HXX)
2
#define RESIP_SIPMESSAGE_HXX 
3
4
#include <sys/types.h>
5
6
#include <list>
7
#include <vector>
8
#include <utility>
9
#include <memory> 
10
11
#include "resip/stack/Contents.hxx"
12
#include "resip/stack/Headers.hxx"
13
#include "resip/stack/TransactionMessage.hxx"
14
#include "resip/stack/ParserContainer.hxx"
15
#include "resip/stack/ParserCategories.hxx"
16
#include "resip/stack/SecurityAttributes.hxx"
17
#include "resip/stack/Tuple.hxx"
18
#include "resip/stack/Uri.hxx"
19
#include "resip/stack/MessageDecorator.hxx"
20
#include "resip/stack/Cookie.hxx"
21
#include "resip/stack/WsCookieContext.hxx"
22
#include "rutil/BaseException.hxx"
23
#include "rutil/Data.hxx"
24
#include "rutil/DinkyPool.hxx"
25
#include "rutil/StlPoolAllocator.hxx"
26
#include "rutil/Timer.hxx"
27
#include "rutil/HeapInstanceCounter.hxx"
28
29
namespace resip
30
{
31
32
class Contents;
33
class ExtensionHeader;
34
class SecurityAttributes;
35
36
/**
37
   @ingroup resip_crit
38
   @ingroup message_passing_tu
39
   @brief Represents a SIP message.
40
41
   This is the class that your app will spend the most time working with. This
42
   is because, in the UA core/Transaction User architecture, the vast majority
43
   of interaction is carried out through SIP messaging.
44
45
   When you get a SipMessage, generally the first thing you want to know is 
46
   whether it is a request or a response. This is done by calling 
47
   SipMessage::isRequest() or SipMessage::isResponse().
48
   
49
   Next, it is usually important to determine what the SIP method of the message 
50
   is. This is done by calling SipMessage::method() (this is a convenience 
51
   function that checks the method of the Request-Line if the message is a 
52
   request, or the method of the CSeq if a response).
53
   
54
   At this point, it may become useful to examine the start-line of the message.
55
56
   If the message is a request, you can get the Request-Line (represented by a 
57
   RequestLine&) by calling SipMessage::header(const RequestLineType&)
58
   @code
59
      RequestLine& rLine = sip.header(h_RequestLine);
60
   @endcode
61
62
   If the message is a response, you can get the Status-Line (represented by a StatusLine&) by calling SipMessage::header(const StatusLineType&)
63
   @code
64
      StatusLine& sLine = sip.header(h_StatusLine);
65
   @endcode
66
67
   From here, examination of the various headers is in order. The way the 
68
   underlying code works is very complicated, but fortunately relatively 
69
   painless to use. For each header type, there is a subclass of HeaderBase, and 
70
   a SipMessage::header() function that takes a reference to this subclass. On 
71
   top of this, there is a static instance of each of these subclasses. Examples 
72
   include h_To, h_From, h_CSeq, h_CallId, h_Routes, h_Contacts, h_RecordRoutes, 
73
   etc.
74
75
   @code
76
      NameAddr& to = sip.header(h_To);
77
      NameAddr& from = sip.header(h_From);
78
      CSeqCategory& cseq = sip.header(h_CSeq);
79
      CallId& callId = sip.header(h_CallId);
80
      ParserContainer<NameAddr>& routes = sip.header(h_Routes);
81
      ParserContainer<NameAddr>& contacts = sip.header(h_Contacts);
82
      ParserContainer<NameAddr>& rRoutes = sip.header(h_RecordRoutes);
83
   @endcode
84
85
   Generally speaking, the access token is named in a predictable fashion; all 
86
   non-alphanumeric characters are omitted, the first letter of each word is 
87
   capitalized, and the name is pluralized if the header is multi-valued (since 
88
   this stuff is all macro-generated, sometimes this pluralization isn't quite 
89
   right; h_AllowEventss, h_PAssertedIdentitys).
90
91
   When accessing a single-value header, you need to check whether it 
92
   exists first (unless you want it to be created implicitly). Also, since all
93
   header field values are lazily parsed (see LazyParser), you'll want to make 
94
   sure it is well-formed before attempting to access any portion of it.
95
96
   @code
97
      if(sip.exists(h_Event))
98
      {
99
         Token& event = sip.header(h_Event);
100
         if(event.isWellFormed())
101
         {
102
            // do stuff with event.
103
         }
104
         else
105
         {
106
            // complain bitterly
107
         }
108
      }
109
   @endcode
110
111
   When accessing a multi-value header, it is important to keep in mind that 
112
   it can be empty, even if it exists (for example, "Supported: " has a meaning 
113
   that is distinct from the lack of a Supported header).
114
115
   @code
116
      if(sip.exists(h_Contacts))
117
      {
118
         ParserContainer<NameAddr>& contacts = sip.header(h_Contacts);
119
         if(!contacts.empty())
120
         {
121
            NameAddr& frontContact = contacts.front();
122
            if(frontContact.isWellFormed())
123
            {
124
               // do stuff with frontContact
125
            }
126
            else
127
            {
128
               // complain bitterly
129
            }
130
         }
131
         else
132
         {
133
            // complain bitterly
134
         }
135
      }
136
   @endcode
137
138
   In some cases, you will need to access header-types that are not natively 
139
   supported by the stack (ie, don't have an access-token). ExtensionHeader will
140
   allow you to construct an access-token at runtime that will retrieve the
141
   header field value as a ParserContainer<StringCategory>. Here's an example:
142
143
   @code
144
      // We need to access the FooBar header field value here.
145
      static ExtensionHeader h_FooBar("FooBar");
146
      if(sip.exists(h_FooBar))
147
      {
148
         ParserContainer<StringCategory>& fooBars = sip.header(h_FooBar);
149
      }
150
   @endcode
151
152
*/
153
class SipMessage : public TransactionMessage
154
{
155
   public:
156
      RESIP_HeapCount(SipMessage);
157
#ifndef __SUNPRO_CC
158
      typedef std::list< std::pair<Data, HeaderFieldValueList*>, StlPoolAllocator<std::pair<Data, HeaderFieldValueList*>, PoolBase > > UnknownHeaders;
159
#else
160
      typedef std::list< std::pair<Data, HeaderFieldValueList*> > UnknownHeaders;
161
#endif
162
163
      explicit SipMessage(const Tuple *receivedTransport = 0);
164
      /// @todo .dlb. public, allows pass by value to compile.
165
      SipMessage(const SipMessage& message);
166
167
      /// @todo .dlb. sure would be nice to have overloaded return value here..
168
      virtual Message* clone() const;
169
170
      SipMessage& operator=(const SipMessage& rhs);
171
      
172
      /// Returns the transaction id from the branch or if 2543, the computed hash.
173
      virtual const Data& getTransactionId() const;
174
175
      /**
176
         @brief Calculates an MD5 hash over the Request-URI, To tag (for
177
         non-INVITE transactions), From tag, Call-ID, CSeq (including
178
         the method), and top Via header.  The hash is used for
179
         transaction matching.
180
      */
181
      const Data& getRFC2543TransactionId() const;
182
      void setRFC2543TransactionId(const Data& tid);
183
      
184
      virtual ~SipMessage();
185
186
      /** @brief Construct a SipMessage object from a string containing a SIP request
187
          or response.
188
          
189
          @param buffer a buffer containing a SIP message
190
          @param isExternal true for a message generated externally, false otherwise.
191
          @return constructed SipMessage object
192
      */
193
      static SipMessage* make(const Data& buffer, bool isExternal = false);
194
      void parseAllHeaders();
195
      
196
      static bool checkContentLength;
197
198
      /**
199
      @brief Base exception for SipMessage related exceptions
200
      */
201
      class Exception final : public BaseException
202
      {
203
         public:
204
            /**
205
            @brief constructor that records an exception message, the file and the line
206
            that the exception occured in.
207
            */
208
            Exception(const Data& msg, const Data& file, const int line)
209
0
               : BaseException(msg, file, line) {}
210
            /**
211
            @brief returns the class name of the exception instance
212
            @return the class name of the instance
213
            */
214
0
            const char* name() const noexcept override { return "SipMessage::Exception"; }
215
      };
216
217
      /// Mark message as internally generated
218
      inline void setFromTU() 
219
0
      {
220
0
         mIsExternal = false;
221
0
      }
222
223
      /// Mark message as externally generated
224
      inline void setFromExternal()
225
0
      {
226
0
         mIsExternal = true;
227
0
      }
228
      
229
      /** 
230
         @brief Check if SipMessage is to be treated as it came off the wire.
231
232
         @return true if the message came from an IP interface or if it was 
233
                 an internally generated response to an internally generated 
234
                 request (ie: 408), false otherwise.
235
      */
236
      inline bool isExternal() const
237
0
      {
238
0
         return mIsExternal;
239
0
      }
240
241
      /** 
242
         @brief Check if SipMessage came off the wire.
243
      
244
         @note differs from isExternal(), since isExternal() also returns true 
245
               for internally generated responses to internally generate requests 
246
               (ie: 408, etc.).  isFromWire only ever returns true if the message
247
               actually came off the wire.
248
249
         @return true if the message came from an IP interface, false otherwise.
250
      */
251
      inline bool isFromWire() const
252
0
      {
253
0
         return mReceivedTransportTuple.getType() != UNKNOWN_TRANSPORT;
254
0
      }
255
      
256
      /// @brief Check if SipMessage is a client transaction
257
      /// @return true if the message is external and is a response or
258
      /// an internally-generated request.
259
      virtual bool isClientTransaction() const;
260
      
261
      /** @brief Generate a string from the SipMessage object
262
      
263
      @return string representation of a SIP message.
264
      */
265
      virtual EncodeStream& encode(EncodeStream& str) const;      
266
      //sipfrags will not output Content Length if there is no body--introduce
267
      //friendship to hide this?
268
      virtual EncodeStream& encodeSipFrag(EncodeStream& str) const;
269
      EncodeStream& encodeEmbedded(EncodeStream& str) const;
270
      
271
      virtual EncodeStream& encodeBrief(EncodeStream& str) const;
272
      EncodeStream& encodeSingleHeader(Headers::Type type, EncodeStream& str) const;
273
274
      /// Returns true if message is a request, false otherwise
275
0
      inline bool isRequest() const {return mRequest;}
276
      /// Returns true if message is a response, false otherwise
277
0
      inline bool isResponse() const {return mResponse;}
278
      /// Returns true if message failed to parse, false otherwise      
279
0
      inline bool isInvalid() const{return mInvalid;}
280
      
281
      /// @brief returns the method type of the message
282
      /// @see MethodTypes
283
      resip::MethodTypes method() const;
284
      /// Returns a string containing the SIP method for the message
285
      const Data& methodStr() const;
286
      
287
      /// Returns a string containing the response reason text
288
0
      const resip::Data* getReason() const{return mReason;}
289
      
290
      /// Returns the RequestLine.  This is only valid for request messages.
291
      const RequestLine& 
292
      header(const RequestLineType& l) const;
293
294
      /// Returns the RequestLine.  This is only valid for request messages.
295
      RequestLine& 
296
      header(const RequestLineType& l);
297
298
      inline const RequestLine& 
299
      const_header(const RequestLineType& l) const
300
0
      {
301
0
         return header(l);
302
0
      }
303
304
      /// Returns the StatusLine.  This is only valid for response messages.
305
      const StatusLine& 
306
      header(const StatusLineType& l) const;
307
308
      /// Returns the StatusLine.  This is only valid for response messages.
309
      StatusLine& 
310
      header(const StatusLineType& l);
311
312
      inline const StatusLine& 
313
      const_header(const StatusLineType& l) const
314
0
      {
315
0
         return header(l);
316
0
      }
317
318
      /// Returns true if the given header field is present, false otherwise
319
      bool exists(const HeaderBase& headerType) const;
320
      /// Returns true if the header field is present and non-empty, false otherwise
321
      bool empty(const HeaderBase& headerType) const;
322
      /// @brief Prevents a header field from being present when the message is prepared
323
      /// for sending to a transport.  This does not free the memory that was 
324
      /// used by the header.
325
      inline void remove(const HeaderBase& headerType)
326
0
      {
327
0
         remove(headerType.getTypeNum());
328
0
      }
329
330
      void remove(Headers::Type type);
331
332
#define defineHeader(_header, _name, _type, _rfc)                       \
333
      const H_##_header::Type& header(const H_##_header& headerType) const; \
334
            H_##_header::Type& header(const H_##_header& headerType); \
335
      inline const H_##_header::Type& const_header(const H_##_header& headerType) const \
336
13.2k
      {\
337
13.2k
         return header(headerType);\
338
13.2k
      }
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentDisposition const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentEncoding const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MIMEVersion const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Priority const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Event const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SubscriptionState const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SIPETag const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SIPIfMatch const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentId const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReferSub const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AnswerMode const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PrivAnswerMode const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentType const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_IdentityInfo const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_From const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_To const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReplyTo const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReferTo const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReferredBy const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PCalledPartyId const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentTransferEncoding const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Organization const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketKey const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketKey1 const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketKey2 const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Origin const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Host const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketAccept const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Server const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Subject const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_UserAgent const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Timestamp const&) const
resip::SipMessage::const_header(resip::H_ContentLength const&) const
Line
Count
Source
336
13.2k
      {\
337
13.2k
         return header(headerType);\
338
13.2k
      }
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MaxForwards const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MinExpires const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RSeq const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RetryAfter const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_FlowTimer const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Expires const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SessionExpires const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MinSE const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_CallID const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Replaces const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_InReplyTo const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Join const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_TargetDialog const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AuthenticationInfo const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_CSeq const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Date const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RAck const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PChargingVector const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PChargingFunctionAddresses const&) const
339
340
      
341
#define defineMultiHeader(_header, _name, _type, _rfc)                  \
342
      const H_##_header##s::Type& header(const H_##_header##s& headerType) const; \
343
            H_##_header##s::Type& header(const H_##_header##s& headerType); \
344
      inline const H_##_header##s::Type& const_header(const H_##_header##s& headerType) const \
345
0
      {\
346
0
         return header(headerType);\
347
0
      }
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AllowEventss const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Identitys const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AcceptEncodings const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AcceptLanguages const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Allows const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentLanguages const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ProxyRequires const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Requires const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Supporteds const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Unsupporteds const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecurityClients const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecurityServers const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecurityVerifys const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RequestDispositions const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Reasons const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Privacys const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PMediaAuthorizations const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Accepts const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_CallInfos const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AlertInfos const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ErrorInfos const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RecordRoutes const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Routes const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Contacts const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Paths const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AcceptContacts const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RejectContacts const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PAssertedIdentitys const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PPreferredIdentitys const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PAssociatedUris const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ServiceRoutes const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RemotePartyIds const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_HistoryInfos const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Cookies const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Authorizations const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ProxyAuthenticates const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ProxyAuthorizations const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_WWWAuthenticates const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Warnings const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Vias const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PAccessNetworkInfos const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PVisitedNetworkIDs const&) const
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_UserToUsers const&) const
348
      
349
      defineHeader(ContentDisposition, "Content-Disposition", Token, "RFC 3261");
350
      defineHeader(ContentEncoding, "Content-Encoding", Token, "RFC 3261");
351
      defineHeader(MIMEVersion, "Mime-Version", Token, "RFC 3261");
352
      defineHeader(Priority, "Priority", Token, "RFC 3261");
353
      defineHeader(Event, "Event", Token, "RFC 3265");
354
      defineHeader(SubscriptionState, "Subscription-State", Token, "RFC 3265");
355
      defineHeader(SIPETag, "SIP-ETag", Token, "RFC 3903");
356
      defineHeader(SIPIfMatch, "SIP-If-Match", Token, "RFC 3903");
357
      defineHeader(ContentId, "Content-ID", Token, "RFC 2045");
358
      defineMultiHeader(AllowEvents, "Allow-Events", Token, "RFC 3265");
359
      defineMultiHeader(Identity, "Identity", StringCategory, "RFC 8224");   // Originally defined in RFC 4474 as a single header, but later modified by RFC8224 to be a multiheader
360
      defineMultiHeader(AcceptEncoding, "Accept-Encoding", Token, "RFC 3261");
361
      defineMultiHeader(AcceptLanguage, "Accept-Language", Token, "RFC 3261");
362
      defineMultiHeader(Allow, "Allow", Token, "RFC 3261");
363
      defineMultiHeader(ContentLanguage, "Content-Language", Token, "RFC 3261");
364
      defineMultiHeader(ProxyRequire, "Proxy-Require", Token, "RFC 3261");
365
      defineMultiHeader(Require, "Require", Token, "RFC 3261");
366
      defineMultiHeader(Supported, "Supported", Token, "RFC 3261");
367
      defineMultiHeader(Unsupported, "Unsupported", Token, "RFC 3261");
368
      defineMultiHeader(SecurityClient, "Security-Client", Token, "RFC 3329");
369
      defineMultiHeader(SecurityServer, "Security-Server", Token, "RFC 3329");
370
      defineMultiHeader(SecurityVerify, "Security-Verify", Token, "RFC 3329");
371
      defineMultiHeader(RequestDisposition, "Request-Disposition", Token, "RFC 3841");
372
      defineMultiHeader(Reason, "Reason", Token, "RFC 3326");
373
      defineMultiHeader(Privacy, "Privacy", PrivacyCategory, "RFC 3323");
374
      defineMultiHeader(PMediaAuthorization, "P-Media-Authorization", Token, "RFC 3313");
375
      defineHeader(ReferSub, "Refer-Sub", Token, "RFC 4488");
376
      defineHeader(AnswerMode, "Answer-Mode", Token, "draft-ietf-answermode-04");
377
      defineHeader(PrivAnswerMode, "Priv-Answer-Mode", Token, "draft-ietf-answermode-04");
378
379
      defineMultiHeader(Accept, "Accept", Mime, "RFC 3261");
380
      defineHeader(ContentType, "Content-Type", Mime, "RFC 3261");
381
382
      defineMultiHeader(CallInfo, "Call-Info", GenericUri, "RFC 3261");
383
      defineMultiHeader(AlertInfo, "Alert-Info", GenericUri, "RFC 3261");
384
      defineMultiHeader(ErrorInfo, "Error-Info", GenericUri, "RFC 3261");
385
      defineHeader(IdentityInfo, "Identity-Info", GenericUri, "RFC 4474");
386
387
      defineMultiHeader(RecordRoute, "Record-Route", NameAddr, "RFC 3261");
388
      defineMultiHeader(Route, "Route", NameAddr, "RFC 3261");
389
      defineMultiHeader(Contact, "Contact", NameAddr, "RFC 3261");
390
      defineHeader(From, "From", NameAddr, "RFC 3261");
391
      defineHeader(To, "To", NameAddr, "RFC 3261");
392
      defineHeader(ReplyTo, "Reply-To", NameAddr, "RFC 3261");
393
      defineHeader(ReferTo, "Refer-To", NameAddr, "RFC 3515");
394
      defineHeader(ReferredBy, "Referred-By", NameAddr, "RFC 3892");
395
      defineMultiHeader(Path, "Path", NameAddr, "RFC 3327");
396
      defineMultiHeader(AcceptContact, "Accept-Contact", NameAddr, "RFC 3841");
397
      defineMultiHeader(RejectContact, "Reject-Contact", NameAddr, "RFC 3841");
398
      defineMultiHeader(PAssertedIdentity, "P-Asserted-Identity", NameAddr, "RFC 3325");
399
      defineMultiHeader(PPreferredIdentity, "P-Preferred-Identity", NameAddr, "RFC 3325");
400
      defineHeader(PCalledPartyId, "P-Called-Party-ID", NameAddr, "RFC 3455");
401
      defineMultiHeader(PAssociatedUri, "P-Associated-URI", NameAddr, "RFC 3455");
402
      defineMultiHeader(ServiceRoute, "Service-Route", NameAddr, "RFC 3608");
403
      defineMultiHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"); // ?bwc? Not in 3323, should we keep?
404
      defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244");
405
406
      defineHeader(ContentTransferEncoding, "Content-Transfer-Encoding", StringCategory, "RFC 1521");
407
      defineHeader(Organization, "Organization", StringCategory, "RFC 3261");
408
      defineHeader(SecWebSocketKey, "Sec-WebSocket-Key", StringCategory, "RFC 6455");
409
      defineHeader(SecWebSocketKey1, "Sec-WebSocket-Key1", StringCategory, "draft-hixie- thewebsocketprotocol-76");
410
      defineHeader(SecWebSocketKey2, "Sec-WebSocket-Key2", StringCategory, "draft-hixie- thewebsocketprotocol-76");
411
      defineHeader(Origin, "Origin", StringCategory, "draft-hixie- thewebsocketprotocol-76");
412
      defineHeader(Host, "Host", StringCategory, "draft-hixie- thewebsocketprotocol-76");
413
      defineHeader(SecWebSocketAccept, "Sec-WebSocket-Accept", StringCategory, "RFC 6455");
414
      defineMultiHeader(Cookie, "Cookie", StringCategory, "RFC 6265");
415
      defineHeader(Server, "Server", StringCategory, "RFC 3261");
416
      defineHeader(Subject, "Subject", StringCategory, "RFC 3261");
417
      defineHeader(UserAgent, "User-Agent", StringCategory, "RFC 3261");
418
      defineHeader(Timestamp, "Timestamp", StringCategory, "RFC 3261");
419
420
      defineHeader(ContentLength, "Content-Length", UInt32Category, "RFC 3261");
421
      defineHeader(MaxForwards, "Max-Forwards", UInt32Category, "RFC 3261");
422
      defineHeader(MinExpires, "Min-Expires", UInt32Category, "RFC 3261");
423
      defineHeader(RSeq, "RSeq", UInt32Category, "RFC 3261");
424
425
/// @todo !dlb! this one is not quite right -- can have (comment) after field value
426
      defineHeader(RetryAfter, "Retry-After", UInt32Category, "RFC 3261");
427
      defineHeader(FlowTimer, "Flow-Timer", UInt32Category, "RFC 5626");
428
429
      defineHeader(Expires, "Expires", ExpiresCategory, "RFC 3261");
430
      defineHeader(SessionExpires, "Session-Expires", ExpiresCategory, "RFC 4028");
431
      defineHeader(MinSE, "Min-SE", ExpiresCategory, "RFC 4028");
432
433
      defineHeader(CallID, "Call-ID", CallID, "RFC 3261");
434
      defineHeader(Replaces, "Replaces", CallID, "RFC 3891");
435
      defineHeader(InReplyTo, "In-Reply-To", CallID, "RFC 3261");
436
      defineHeader(Join, "Join", CallId, "RFC 3911");
437
      defineHeader(TargetDialog, "Target-Dialog", CallId, "RFC 4538");
438
439
      defineHeader(AuthenticationInfo, "Authentication-Info", Auth, "RFC 3261");
440
      defineMultiHeader(Authorization, "Authorization", Auth, "RFC 3261");
441
      defineMultiHeader(ProxyAuthenticate, "Proxy-Authenticate", Auth, "RFC 3261");
442
      defineMultiHeader(ProxyAuthorization, "Proxy-Authorization", Auth, "RFC 3261");
443
      defineMultiHeader(WWWAuthenticate, "Www-Authenticate", Auth, "RFC 3261");
444
445
      defineHeader(CSeq, "CSeq", CSeqCategory, "RFC 3261");
446
      defineHeader(Date, "Date", DateCategory, "RFC 3261");
447
      defineMultiHeader(Warning, "Warning", WarningCategory, "RFC 3261");
448
      defineMultiHeader(Via, "Via", Via, "RFC 3261");
449
      defineHeader(RAck, "RAck", RAckCategory, "RFC 3262");
450
451
      defineMultiHeader(PAccessNetworkInfo, "P-Access-Network-Info", Token, "RFC 7315"); // section 5.4.
452
      defineHeader(PChargingVector, "P-Charging-Vector", Token, "RFC 3455");
453
      defineHeader(PChargingFunctionAddresses, "P-Charging-Function-Addresses", Token, "RFC 3455");
454
      defineMultiHeader(PVisitedNetworkID, "P-Visited-Network-ID", TokenOrQuotedStringCategory, "RFC 3455");
455
456
      defineMultiHeader(UserToUser, "User-to-User", TokenOrQuotedStringCategory, "draft-ietf-cuss-sip-uui-17");
457
458
      /// unknown header interface
459
      const StringCategories& header(const ExtensionHeader& symbol) const;
460
      StringCategories& header(const ExtensionHeader& symbol);
461
      bool exists(const ExtensionHeader& symbol) const;
462
      void remove(const ExtensionHeader& symbol);
463
464
      /// typeless header interface
465
      const HeaderFieldValueList* getRawHeader(Headers::Type headerType) const;
466
      void setRawHeader(const HeaderFieldValueList* hfvs, Headers::Type headerType);
467
0
      const UnknownHeaders& getRawUnknownHeaders() const {return mUnknownHeaders;}
468
      /**
469
         Return the raw body string (if it exists). The returned HFV
470
         and its underlying memory is owned by the SipMessage, and may
471
         be released when this SipMessage is manipulated.
472
473
         This is a low-level interface; see getContents() for higher level.
474
      **/
475
0
      const HeaderFieldValue& getRawBody() const {return mContentsHfv;}
476
477
      /**
478
         Remove any existing body/contents, and (if non-empty)
479
         set the body to {body}. It makes full copy of the body
480
         to stored within the SipMessage (since lifetime of
481
         the message is unpredictable).
482
483
         This is a low-level interface; see setContents() for higher level.
484
      **/
485
      void setRawBody(const HeaderFieldValue& body);
486
487
      /** @brief Retrieves the body of a SIP message.
488
        * 
489
        *   In the case of an INVITE request containing SDP, the body would 
490
        *   be an SdpContents.  For a MESSAGE request, the body may be PlainContents,
491
        *   CpimContents, or another subclass of Contents.
492
        * 
493
        * @return pointer to the contents of the SIP message
494
        **/
495
      Contents* getContents() const;
496
      /// Removes the contents from the message
497
      std::unique_ptr<Contents> releaseContents();
498
499
      /// @brief Set the contents of the message
500
      /// @param contents to store in the message
501
      void setContents(const Contents* contents);
502
      /// @brief Set the contents of the message
503
      /// @param contents to store in the message
504
      void setContents(std::unique_ptr<Contents> contents);
505
506
      /// @internal transport interface
507
      void setStartLine(const char* start, int len); 
508
509
      void setBody(const char* start, uint32_t len); 
510
      
511
      /// Add HeaderFieldValue given enum, header name, pointer start, content length
512
      void addHeader(Headers::Type header,
513
                     const char* headerName, int headerLen, 
514
                     const char* start, int len);
515
516
      // Returns the source tuple for the transport that the message was received from
517
      // only makes sense for messages received from the wire.  Differs from Source
518
      // since it contains the transport bind address instead of the actual source 
519
      // address.
520
0
      const Tuple& getReceivedTransportTuple() const { return mReceivedTransportTuple; }
521
522
      /// Set Tuple for transport from whence this message came
523
0
      void setReceivedTransportTuple(const Tuple& transportTuple) { mReceivedTransportTuple = transportTuple;}
524
525
      // Returns the source tuple that the message was received from
526
      // only makes sense for messages received from the wire
527
0
      void setSource(const Tuple& tuple) { mSource = tuple; }
528
      /// @brief Returns the source tuple that the message was received from
529
      /// only makes sense for messages received from the wire
530
0
      const Tuple& getSource() const { return mSource; }
531
      
532
      /// Used by the stateless interface to specify where to send a request/response
533
0
      void setDestination(const Tuple& tuple) { mDestination = tuple; }
534
0
      Tuple& getDestination() { return mDestination; }
535
536
      void addBuffer(char* buf);
537
538
0
      uint64_t getCreatedTimeMicroSec() const {return mCreatedTime;}
539
540
      /// deal with a notion of an "out-of-band" forced target for SIP routing
541
      void setForceTarget(const Uri& uri);
542
      void clearForceTarget();
543
      const Uri& getForceTarget() const;
544
      bool hasForceTarget() const;
545
546
0
      const Data& getTlsDomain() const { return mTlsDomain; }
547
0
      void setTlsDomain(const Data& domain) { mTlsDomain = domain; }
548
549
0
      const std::list<Data>& getTlsPeerNames() const { return mTlsPeerNames; }
550
0
      void setTlsPeerNames(const std::list<Data>& tlsPeerNames) { mTlsPeerNames = tlsPeerNames; }
551
552
0
      const CookieList& getWsCookies() const { return mWsCookies; }
553
0
      void setWsCookies(const CookieList& wsCookies) { mWsCookies = wsCookies; }
554
555
0
      std::shared_ptr<WsCookieContext> getWsCookieContext() const noexcept { return mWsCookieContext; }
556
0
      void setWsCookieContext(std::shared_ptr<WsCookieContext> wsCookieContext) noexcept { mWsCookieContext = wsCookieContext; }
557
558
      Data getCanonicalIdentityString() const;
559
      
560
      SipMessage& mergeUri(const Uri& source);      
561
562
      void setSecurityAttributes(std::unique_ptr<SecurityAttributes>) noexcept;
563
0
      const SecurityAttributes* getSecurityAttributes() const noexcept { return mSecurityAttributes.get(); }
564
565
      /// @brief Call a MessageDecorator to process the message before it is
566
      /// sent to the transport
567
0
      void addOutboundDecorator(std::unique_ptr<MessageDecorator> md){mOutboundDecorators.push_back(md.release());}
568
      void clearOutboundDecorators();
569
      void callOutboundDecorators(const Tuple &src, 
570
                                    const Tuple &dest,
571
                                    const Data& sigcompId);
572
      void rollbackOutboundDecorators();
573
      void copyOutboundDecoratorsToStackCancel(SipMessage& cancel);
574
      void copyOutboundDecoratorsToStackFailureAck(SipMessage& ack);
575
      bool mIsDecorated;
576
577
      bool mIsBadAck200;
578
579
   protected:
580
      // !bwc! Removes or zeros all pointers to heap-allocated memory this
581
      // class owns.
582
      void clear(bool leaveResponseStuff=false);
583
      // !bwc! Frees all heap-allocated memory owned.
584
      void freeMem(bool leaveResponseStuff=false);
585
      // Clears mHeaders and cleans up memory
586
      void clearHeaders();
587
      
588
      // !bwc! Initializes members. Will not free heap-allocated memory.
589
      // Will begin by calling clear().
590
      void init(const SipMessage& rhs);
591
   
592
   private:
593
      void compute2543TransactionHash() const;
594
595
      EncodeStream& 
596
      encode(EncodeStream& str, bool isSipFrag) const;      
597
598
      void copyFrom(const SipMessage& message);
599
600
      HeaderFieldValueList* ensureHeaders(Headers::Type type);
601
      inline HeaderFieldValueList* ensureHeaders(Headers::Type type) const // throws if not present
602
0
      {
603
0
         if(mHeaderIndices[type]>0)
604
0
         {
605
0
            return mHeaders[mHeaderIndices[type]];
606
0
         }
607
0
         throwHeaderMissing(type);
608
0
         return 0;
609
0
      }
610
611
      HeaderFieldValueList* ensureHeader(Headers::Type type);
612
      inline HeaderFieldValueList* ensureHeader(Headers::Type type) const // throws if not present
613
13.2k
      {
614
13.2k
         if(mHeaderIndices[type]>0)
615
13.2k
         {
616
13.2k
            return mHeaders[mHeaderIndices[type]];
617
13.2k
         }
618
0
         throwHeaderMissing(type);
619
0
         return 0;
620
13.2k
      }
621
622
      void throwHeaderMissing(Headers::Type type) const;
623
624
      inline HeaderFieldValueList* getEmptyHfvl()
625
23.4k
      {
626
23.4k
         void* ptr(mPool.allocate(sizeof(HeaderFieldValueList)));
627
23.4k
         return new (ptr) HeaderFieldValueList(mPool);
628
23.4k
      }
629
630
      inline HeaderFieldValueList* getCopyHfvl(const HeaderFieldValueList& hfvl)
631
0
      {
632
0
         void* ptr(mPool.allocate(sizeof(HeaderFieldValueList)));
633
0
         return new (ptr) HeaderFieldValueList(hfvl, mPool);
634
0
      }
635
636
      inline void freeHfvl(HeaderFieldValueList* hfvl)
637
23.4k
      {
638
23.4k
         if(hfvl)
639
23.4k
         {
640
23.4k
            hfvl->~HeaderFieldValueList();
641
23.4k
            mPool.deallocate(hfvl);
642
23.4k
         }
643
23.4k
      }
644
645
      template<class T>
646
      ParserContainer<T>* makeParserContainer()
647
      {
648
         void* ptr(mPool.allocate(sizeof(ParserContainer<T>)));
649
         return new (ptr) ParserContainer<T>(mPool);
650
      }
651
652
      template<class T>
653
      ParserContainer<T>* makeParserContainer(HeaderFieldValueList* hfvs,
654
                                             Headers::Type type = Headers::UNKNOWN)
655
253
      {
656
253
         void* ptr(mPool.allocate(sizeof(ParserContainer<T>)));
657
253
         return new (ptr) ParserContainer<T>(hfvs, type, mPool);
658
253
      }
Unexecuted instantiation: resip::ParserContainer<resip::StringCategory>* resip::SipMessage::makeParserContainer<resip::StringCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::Token>* resip::SipMessage::makeParserContainer<resip::Token>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::PrivacyCategory>* resip::SipMessage::makeParserContainer<resip::PrivacyCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::Mime>* resip::SipMessage::makeParserContainer<resip::Mime>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::GenericUri>* resip::SipMessage::makeParserContainer<resip::GenericUri>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::NameAddr>* resip::SipMessage::makeParserContainer<resip::NameAddr>(resip::HeaderFieldValueList*, resip::Headers::Type)
resip::ParserContainer<resip::UInt32Category>* resip::SipMessage::makeParserContainer<resip::UInt32Category>(resip::HeaderFieldValueList*, resip::Headers::Type)
Line
Count
Source
655
253
      {
656
253
         void* ptr(mPool.allocate(sizeof(ParserContainer<T>)));
657
253
         return new (ptr) ParserContainer<T>(hfvs, type, mPool);
658
253
      }
Unexecuted instantiation: resip::ParserContainer<resip::ExpiresCategory>* resip::SipMessage::makeParserContainer<resip::ExpiresCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::CallID>* resip::SipMessage::makeParserContainer<resip::CallID>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::Auth>* resip::SipMessage::makeParserContainer<resip::Auth>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::CSeqCategory>* resip::SipMessage::makeParserContainer<resip::CSeqCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::DateCategory>* resip::SipMessage::makeParserContainer<resip::DateCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::WarningCategory>* resip::SipMessage::makeParserContainer<resip::WarningCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::Via>* resip::SipMessage::makeParserContainer<resip::Via>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::RAckCategory>* resip::SipMessage::makeParserContainer<resip::RAckCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
Unexecuted instantiation: resip::ParserContainer<resip::TokenOrQuotedStringCategory>* resip::SipMessage::makeParserContainer<resip::TokenOrQuotedStringCategory>(resip::HeaderFieldValueList*, resip::Headers::Type)
659
660
      // indicates this message came from the wire or we want it to look like it 
661
      // came from the wire (ie. internally generated responses to an internally 
662
      // generated request), set by the Transport and setFromTu and setFromExternal APIs
663
      bool mIsExternal;
664
665
      // Sizing so that average SipMessages don't need to allocate heap memory
666
      // To profile current sizing, enable DINKYPOOL_PROFILING in SipMessage.cxx 
667
      // and look for DebugLog message in SipMessage destructor to know when heap
668
      // allocations are occuring and how much of the pool is used.
669
      DinkyPool<3732> mPool;
670
671
      typedef std::vector<HeaderFieldValueList*, 
672
                           StlPoolAllocator<HeaderFieldValueList*, 
673
                                          PoolBase > > TypedHeaders;
674
      // raw text corresponding to each typed header (not yet parsed)
675
      TypedHeaders mHeaders;
676
      
677
      // !bwc! Indices into mHeaders
678
      short mHeaderIndices[Headers::MAX_HEADERS];
679
680
      // raw text corresponding to each unknown header
681
      UnknownHeaders mUnknownHeaders;
682
683
      // For messages received from the wire, this indicates information about 
684
      // the transport the message was received on
685
      Tuple mReceivedTransportTuple;
686
687
      // For messages received from the wire, this indicates where it came
688
      // from. Can be used to get to the Transport and/or reliable Connection
689
      Tuple mSource;
690
691
      // Used by the TU to specify where a message is to go
692
      Tuple mDestination;
693
      
694
      // Raw buffers coming from the Transport. message manages the memory
695
      std::vector<char*> mBufferList;
696
697
      // special case for the first line of message
698
      StartLine* mStartLine;
699
      char mStartLineMem[sizeof(RequestLine) > sizeof(StatusLine) ? sizeof(RequestLine) : sizeof(StatusLine)];
700
701
      // raw text for the contents (all of them)
702
      HeaderFieldValue mContentsHfv;
703
704
      // lazy parser for the contents
705
      mutable Contents* mContents;
706
707
      // cached value of a hash of the transaction id for a message received
708
      // from a 2543 sip element. as per rfc3261 see 17.2.3
709
      mutable Data mRFC2543TransactionId;
710
711
      // is a request or response
712
      bool mRequest;
713
      bool mResponse;
714
715
      bool mInvalid;
716
      resip::Data* mReason;
717
      
718
      uint64_t mCreatedTime;
719
720
      // used when next element is a strict router OR 
721
      // client forces next hop OOB
722
      Uri* mForceTarget;
723
724
      // domain associated with this message for tls cert
725
      Data mTlsDomain;
726
727
      // peers domain associate with this message (MTLS)
728
      std::list<Data> mTlsPeerNames;
729
730
      // cookies associated with this message from the WebSocket Upgrade request
731
      CookieList mWsCookies;
732
733
      // parsed cookie authentication elements associated with this message from the WebSocket Upgrade request
734
      std::shared_ptr<WsCookieContext> mWsCookieContext;
735
736
      std::unique_ptr<SecurityAttributes> mSecurityAttributes;
737
738
      std::vector<MessageDecorator*> mOutboundDecorators;
739
740
      friend class TransportSelector;
741
};
742
743
}
744
745
#undef ensureHeaderTypeUseable
746
#undef ensureSingleHeader
747
#undef ensureMultiHeader
748
#undef defineHeader
749
#undef defineMultiHeader
750
751
#endif
752
753
/* ====================================================================
754
 * The Vovida Software License, Version 1.0 
755
 * 
756
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
757
 * 
758
 * Redistribution and use in source and binary forms, with or without
759
 * modification, are permitted provided that the following conditions
760
 * are met:
761
 * 
762
 * 1. Redistributions of source code must retain the above copyright
763
 *    notice, this list of conditions and the following disclaimer.
764
 * 
765
 * 2. Redistributions in binary form must reproduce the above copyright
766
 *    notice, this list of conditions and the following disclaimer in
767
 *    the documentation and/or other materials provided with the
768
 *    distribution.
769
 * 
770
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
771
 *    and "Vovida Open Communication Application Library (VOCAL)" must
772
 *    not be used to endorse or promote products derived from this
773
 *    software without prior written permission. For written
774
 *    permission, please contact vocal@vovida.org.
775
 *
776
 * 4. Products derived from this software may not be called "VOCAL", nor
777
 *    may "VOCAL" appear in their name, without prior written
778
 *    permission of Vovida Networks, Inc.
779
 * 
780
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
781
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
782
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
783
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
784
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
785
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
786
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
787
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
788
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
789
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
790
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
791
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
792
 * DAMAGE.
793
 * 
794
 * ====================================================================
795
 * 
796
 * This software consists of voluntary contributions made by Vovida
797
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
798
 * Inc.  For more information on Vovida Networks, Inc., please see
799
 * <http://www.vovida.org/>.
800
 *
801
 * vi: set shiftwidth=3 expandtab:
802
 */