Coverage Report

Created: 2025-06-13 06:12

/src/resiprocate/resip/stack/Helper.hxx
Line
Count
Source (jump to first uncovered line)
1
#if !defined(RESIP_HELPER_HXX)
2
#define RESIP_HELPER_HXX 
3
4
#include <time.h>
5
6
#include "resip/stack/NonceHelper.hxx"
7
#include "resip/stack/Symbols.hxx"
8
#include "resip/stack/Uri.hxx"
9
#include "resip/stack/MethodTypes.hxx"
10
#include "rutil/BaseException.hxx"
11
#include "rutil/Data.hxx"
12
#include "resip/stack/Contents.hxx"
13
#include "resip/stack/SecurityAttributes.hxx"
14
#include "resip/stack/SdpContents.hxx"
15
16
namespace resip
17
{
18
19
class SipMessage;
20
class NameAddr;
21
class SecurityAttributes;
22
class Security;
23
24
class UnsupportedAuthenticationScheme : public BaseException
25
{
26
   public:
27
      UnsupportedAuthenticationScheme(const Data& msg, const Data& file, const int line)
28
0
         : BaseException(msg, file, line) {}
29
      
30
0
      const char* name() const noexcept override { return "UnsupportedAuthenticationScheme"; }
31
};
32
33
34
/**
35
   @ingroup resip_crit
36
   @brief An aggregation of useful static functions.
37
38
   These are mostly involved with
39
      - The manufacture of SIP messages (requests and responses). This is of 
40
      particular importance to app-writers.
41
      - Digest auth related functions.
42
*/
43
class Helper
44
{
45
   public:
46
47
      /// bytes in to-tag& from-tag, should prob. live somewhere else
48
      const static int tagSize;  
49
50
      /** 
51
          Used by Registration, Publication and Subscription refreshes, to
52
          calculate the time at which a refresh should be performed (which
53
          is some time, that is a bit smaller than the Expiration interval).
54
          The recommended calculation from the RFC's is the minimnum of the 
55
          Exipiration interval less 5 seconds and nine tenths of the exipiration 
56
          interval.
57
      */
58
      template<typename T>
59
      static T aBitSmallerThan(T secs)
60
      {
61
         return resipMax(T(0), resipMin(T(secs-5), T(9*secs/10)));
62
      }
63
64
      /** 
65
          Converts an interger in a character string containing the
66
          hexidecimal representation of the integer.  Note:  The 
67
          string buffer provided should be at least 8 characters long.
68
          This function will NOT NULL terminate the string.
69
70
          @param _d     A pointer to the character buffer to write
71
                        the hex string
72
73
          @param _s     The integer value to convert.
74
75
          @param _l     Boolean flag to include leading 0 zeros or 
76
                        not.
77
      */
78
      static void integer2hex(char* _d, unsigned int _s, bool _l = true);
79
80
      /** 
81
          Converts a character string containing a hexidecimal value
82
          into an unsigned int.  Note:  Parsing stops after the first
83
          non-hex character, or after 8 characters have been processed.
84
85
          @param _s     A pointer to the character buffer to convert.
86
87
          @returns      The integer value of the coverted hex string.
88
      */
89
      static unsigned int hex2integer(const char* _s);
90
91
      /**
92
           Used to jitter the expires in a SUBSCRIBE or REGISTER expires header
93
94
           @param input            Value to jitter
95
96
           @param lowerPercentage  The lower range of the random percentage by which 
97
                                   to jitter the value by.
98
99
           @param upperPercentage  The upper range of the random percentage by which
100
                                   to jitter the value by.  Must be greater than or equal 
101
                                   to lowerPercentage
102
103
           @param minimum          Only jitter the input if greater than minimum
104
       */
105
      static int jitterValue(int input, int lowerPercentage, int upperPercentage, int minimum=0);
106
107
      /**
108
          Make an invite request - Empty Contact and Via is added and will be populated 
109
          by the stack when sent.
110
            
111
          @param target Ends up in the RequestURI and To header
112
113
          @param from   Ends up in the From header
114
      */
115
      static SipMessage* makeInvite(const NameAddr& target, const NameAddr& from);
116
      
117
      /**
118
          Make an invite request using a overridden contact header - Empty Via is added 
119
          and will be populated by the stack when sent.
120
            
121
          @param target Ends up in the RequestURI and To header
122
123
          @param from   Ends up in the From header
124
125
          @param contact Ends up in the Contact header.  Stack will not change this
126
                         when sent.
127
      */
128
      static SipMessage* makeInvite(const NameAddr& target, const NameAddr& from, const NameAddr& contact);
129
      
130
      /**
131
          Make a response to a provided request.  Adds a To tag, Contact and Record-Route
132
          headers appropriately.
133
            
134
          @param response SipMessage populated with the appropriate response
135
136
          @param request  SipMessage request from which to generate the response
137
138
          @param responseCode Response code to use on status line.
139
140
          @param reason   Optional reason string to use on status line.  If not provided
141
                          then a default reason string will be added for well defined
142
                          response codes.
143
144
          @param hostname Optional hostname to use in Warning header.  Only used if
145
                          warning is also provided.
146
147
          @param warning  Optional warning text.  If present a Warning header is added
148
                          and hostname is used in warning header.
149
      */
150
      static void makeResponse(SipMessage& response, 
151
                               const SipMessage& request, 
152
                               int responseCode, 
153
                               const Data& reason = Data::Empty,
154
                               const Data& hostname = Data::Empty,
155
                               const Data& warning=Data::Empty);
156
157
      /**
158
          Make a response to a provided request with an overridden Contact.  
159
          Adds a To tag, Contact and Record-Route headers appropriately.
160
            
161
          @param response SipMessage populated with the appropriate response
162
163
          @param request  SipMessage request from which to generate the response
164
165
          @param responseCode Response code to use on status line.
166
167
          @param myContact Contact header to add to response.
168
169
          @param reason   Optional reason string to use on status line.  If not provided
170
                          then a default reason string will be added for well defined
171
                          response codes.
172
173
          @param hostname Optional hostname to use in Warning header.  Only used if
174
                          warning is also provided.
175
176
          @param warning  Optional warning text.  If present a Warning header is added
177
                          and hostname is used in warning header.
178
      */
179
      static void makeResponse(SipMessage& response, 
180
                               const SipMessage& request, 
181
                               int responseCode, 
182
                               const NameAddr& myContact, 
183
                               const Data& reason = Data::Empty,
184
                               const Data& hostname = Data::Empty,
185
                               const Data& warning=Data::Empty);
186
187
      /**
188
          Make a new response to a provided request.  Adds a To tag, Contact and 
189
          Record-Route headers appropriately.  Caller owns the returned pointer and
190
          is responsible for deleting it.
191
            
192
          @param request  SipMessage request from which to generate the response
193
194
          @param responseCode Response code to use on status line.
195
196
          @param reason   Optional reason string to use on status line.  If not provided
197
                          then a default reason string will be added for well defined
198
                          response codes.
199
200
          @param hostname Optional hostname to use in Warning header.  Only used if
201
                          warning is also provided.
202
203
          @param warning  Optional warning text.  If present a Warning header is added
204
                          and hostname is used in warning header
205
206
          @returns SipMessage populated with the appropriate response.
207
                   Caller must deallocate.
208
      */
209
      static SipMessage* makeResponse(const SipMessage& request,
210
                                      int responseCode,
211
                                      const Data& reason = Data::Empty, 
212
                                      const Data& hostname = Data::Empty,
213
                                      const Data& warning=Data::Empty);
214
215
      /**
216
          Make a new response to a provided request with an overridden Contact.  
217
          Adds a To tag, Contact and Record-Route headers appropriately.
218
          Caller owns the returned pointer and is responsible for deleting it.
219
220
          @param request  SipMessage request from which to generate the response
221
222
          @param responseCode Response code to use on status line.
223
224
          @param myContact Contact header to add to response.
225
226
          @param reason   Optional reason string to use on status line.  If not provided
227
                          then a default reason string will be added for well defined
228
                          response codes.
229
230
          @param hostname Optional hostname to use in Warning header.  Only used if
231
                          warning is also provided.
232
233
          @param warning  Optional warning text.  If present a Warning header is added
234
                          and hostname is used in warning header.
235
236
          @returns SipMessage populated with the appropriate response.
237
                   Caller must deallocate.
238
      */
239
      static SipMessage* makeResponse(const SipMessage& request, 
240
                                      int responseCode, 
241
                                      const NameAddr& myContact, 
242
                                      const Data& reason = Data::Empty,
243
                                      const Data& hostname = Data::Empty,
244
                                      const Data& warning=Data::Empty);
245
246
      static void makeRawResponse(Data& rawBuffer,
247
                                    const SipMessage& request, 
248
                                    int responseCode,
249
                                    const Data& additionalHeaders=Data::Empty,
250
                                    const Data& body=Data::Empty);
251
252
      /**
253
          Make a 405 response to a provided request.  Allows header is added
254
          with specified methods, or with all methods the stack knows about.
255
          Caller owns the returned pointer and is responsible for deleting it.
256
257
          @param request  SipMessage request from which to generate the response
258
259
          @param allowedMethods Array of integers representing a list of Method 
260
                                Types to add to the generated Allows header. 
261
                                See MethodTypes.hxx.
262
263
          @param nMethods Number of methods specified in the allowedMethods 
264
                          integer array.  Specify -1 to have this method fill
265
                          in the Allows header automatically with each method
266
                          supported by the stack.
267
268
          @returns SipMessage populated with the appropriate response.    
269
                   Caller must deallocate.
270
      */
271
      static SipMessage* make405(const SipMessage& request,
272
                                 const int* allowedMethods = 0,
273
                                 int nMethods = -1);
274
275
      /**
276
          Returns the default reason string for a particular response code.
277
278
          @param responseCode  Response code to get reason for
279
280
          @param reason Data where the reason string associated with the 
281
                   responseCode will be set.
282
      */
283
      static void getResponseCodeReason(int responseCode, Data& reason);
284
285
      /**
286
          Make a new request with a overridden Contact.  To, maxforward=70, requestline 
287
          created, cseq method set, cseq sequence is 1, from and from tag set, contact 
288
          set, CallId created.  Caller owns the returned pointer and is responsible for 
289
          deleting it.
290
291
          @note While contact is only necessary for requests that establish a dialog,
292
                those are the requests most likely created by this method, others will
293
                be generated by the dialog.
294
295
          @param target Ends up in the RequestURI and To header
296
297
          @param from   Ends up in the From header
298
299
          @param contact Ends up in the Contact header.  Stack will not change this
300
                         when sent.
301
302
          @param method Type of request to create.  Methos is used in the Request Line
303
                        and the CSeq.
304
305
          @returns SipMessage request created.  Caller must deallocate.         
306
      */
307
      static SipMessage* makeRequest(const NameAddr& target, const NameAddr& from, const NameAddr& contact, MethodTypes method);
308
309
      /**
310
          Make a new request.  To, maxforward=70, requestline created, cseq method set, 
311
          cseq sequence is 1, from and from tag set, CallId created.  Caller owns the 
312
          returned pointer and is responsible for deleting it.
313
314
          @note An empty contact header is added.  This signals to the stack that it
315
                should be populated by the transports when sent.
316
317
          @param target Ends up in the RequestURI and To header
318
319
          @param from   Ends up in the From header
320
321
          @param method Type of request to create.  Methos is used in the Request Line
322
                        and the CSeq.
323
324
          @returns SipMessage request created.  Caller must deallocate.         
325
      */
326
      static SipMessage* makeRequest(const NameAddr& target, const NameAddr& from, MethodTypes method);
327
328
      /**
329
          Make a new Cancel request for the specified request.  Caller owns the 
330
          returned pointer and is responsible for deleting it.
331
332
          @param request Request for which the Cancel will apply. ie. Invite request.
333
334
          @returns Created Cancel request.  Caller must deallocate.         
335
      */
336
      static SipMessage* makeCancel(const SipMessage& request);
337
      
338
      /// Create a Register request with an overriden Contact.  See makeRequest.
339
      static SipMessage* makeRegister(const NameAddr& to, const NameAddr& from, const NameAddr& contact);
340
341
      /// Create a Register request with an empty Contact.  See makeRequest.
342
      static SipMessage* makeRegister(const NameAddr& to, const NameAddr& from);
343
344
      /// Create a Register request with an overriden Contact, transport is added to Request URI.  See makeRequest.
345
      static SipMessage* makeRegister(const NameAddr& to, const Data& transport, const NameAddr& contact);
346
347
      /// Create a Register request with an empty Contact, transport is added to Request URI.  See makeRequest.
348
      static SipMessage* makeRegister(const NameAddr& to, const Data& transport);
349
350
      /// Create a Subscribe request with an overriden Contact.  See makeRequest.
351
      static SipMessage* makeSubscribe(const NameAddr& target, const NameAddr& from, const NameAddr& contact);
352
353
      /// Create a Subscribe request with an empty Contact.  See makeRequest.
354
      static SipMessage* makeSubscribe(const NameAddr& target, const NameAddr& from);
355
356
      /// Create a Message request with an overriden Contact.  See makeRequest.
357
      static SipMessage* makeMessage(const NameAddr& target, const NameAddr& from, const NameAddr& contact);
358
359
      /// Create a Message request with an empty Contact.  See makeRequest.
360
      static SipMessage* makeMessage(const NameAddr& target, const NameAddr& from);
361
362
      /// Create a Publish request with an overriden Contact.  See makeRequest.
363
      static SipMessage* makePublish(const NameAddr& target, const NameAddr& from, const NameAddr& contact);
364
365
      /// Create a Publish request with an empty Contact.  See makeRequest.
366
      static SipMessage* makePublish(const NameAddr& target, const NameAddr& from);
367
368
      /**
369
          This interface should be used by the stack (TransactionState) to create an
370
          AckMsg to a failure response.  See RFC3261 section 17.1.1.3.  Caller owns the 
371
          returned pointer and is responsible for deleting it.
372
          
373
          @note The branch in this ACK needs to be the one from the request. 
374
                For TU generated ACK, see Dialog::makeAck(...)
375
376
          @param request Request that this ACK applies to.
377
378
          @param response Response that we are ACKing - required so that we can get the To tag
379
                          into the generated ACK.
380
381
          @returns Created Ack request.  Caller must deallocate.         
382
       */
383
      static SipMessage* makeFailureAck(const SipMessage& request, const SipMessage& response);
384
385
      /** 
386
          Creates and returns a unique branch parameter.  Generated branch will contain
387
          the RFC3261 magic cookie + 4 randome hex characters + "C1" + 2 random hex characters.
388
389
          @deprecated Not used by stack.
390
      */
391
      static Data computeUniqueBranch();
392
      static Data computeProxyBranch(const SipMessage& request);
393
394
      static Data computeCallId();
395
      static Data computeTag(int numBytes);
396
397
      enum AuthResult {Failed = 1, Authenticated, Expired, BadlyFormed};
398
399
      static AuthResult authenticateRequest(const SipMessage& request, 
400
                                            const Data& realm,
401
                                            const Data& password,
402
                                            int expiresDelta = 0);
403
404
      static AuthResult authenticateRequestWithA1(const SipMessage& request, 
405
                                                  const Data& realm,
406
                                                  const Data& hA1,
407
                                                  int expiresDelta = 0);
408
      
409
      static std::pair<AuthResult,Data> 
410
                advancedAuthenticateRequest(const SipMessage& request, 
411
                                            const Data& realm,
412
                                            const Data& a1,
413
                                            int expiresDelta = 0,
414
                                            bool proxyAuthorization = true);
415
      
416
      // create a 407 response with Proxy-Authenticate header filled in
417
      static SipMessage* makeProxyChallenge(const SipMessage& request, 
418
                                            const Data& realm,
419
                                            bool useAuth = true,
420
                                            bool stale = false);
421
422
      //create a 401 response with WWW-Authenticate header filled in
423
      static SipMessage* makeWWWChallenge(const SipMessage& request, 
424
                                            const Data& realm,
425
                                            bool useAuth = true,
426
                                            bool stale = false);
427
428
      // create a 401 or 407 response with Proxy-Authenticate or Authenticate header 
429
      // filled in
430
      static SipMessage* makeChallenge(const SipMessage& request, 
431
                                       const Data& realm,
432
                                       bool useAuth = true,
433
                                       bool stale = false,
434
                                       bool proxy = false);
435
436
      static Data qopOption(const Auth& challenge);
437
      static void updateNonceCount(unsigned int& nonceCount, Data& nonceCountString);
438
      static bool algorithmAndQopSupported(const Auth& challenge);
439
      
440
441
      // adds authorization headers in reponse to the 401 or 407--currently
442
      // only supports md5.
443
      static SipMessage& addAuthorization(SipMessage& request,
444
                                          const SipMessage& challenge,
445
                                          const Data& username,
446
                                          const Data& password,
447
                                          const Data& cnonce,
448
                                          unsigned int& nonceCount);
449
450
      static Auth makeChallengeResponseAuth(const SipMessage& request,
451
                                            const Data& username,
452
                                            const Data& password,
453
                                            const Auth& challenge,
454
                                            const Data& cnonce,
455
                                            unsigned int& nonceCount,
456
                                            Data& nonceCountString);      
457
458
      static void makeChallengeResponseAuth(const SipMessage& request,
459
                                            const Data& username,
460
                                            const Data& password,
461
                                            const Auth& challenge,
462
                                            const Data& cnonce,
463
                                            const Data& authQop,
464
                                            const Data& nonceCountString,
465
                                            Auth& auth);
466
467
      static Auth makeChallengeResponseAuthWithA1(const SipMessage& request,
468
                                                  const Data& username,
469
                                                  const Data& passwordHashA1,
470
                                                  const Auth& challenge,
471
                                                  const Data& cnonce,
472
                                                  unsigned int& nonceCount,
473
                                                  Data& nonceCountString);      
474
475
      static void makeChallengeResponseAuthWithA1(const SipMessage& request,
476
                                                  const Data& username,
477
                                                  const Data& passwordHashA1,
478
                                                  const Auth& challenge,
479
                                                  const Data& cnonce,
480
                                                  const Data& authQop,
481
                                                  const Data& nonceCountString,
482
                                                  Auth& auth);
483
484
      static Data makeResponseMD5WithA1(const Data& a1,
485
                                        const Data& method, const Data& digestUri, const Data& nonce,
486
                                        const Data& qop = Data::Empty, const Data& cnonce = Data::Empty, 
487
                                        const Data& cnonceCount = Data::Empty, const Contents *entityBody = 0);
488
489
      static Data makeResponseMD5(const Data& username, const Data& password, const Data& realm, 
490
                                  const Data& method, const Data& digestUri, const Data& nonce,
491
                                  const Data& qop = Data::Empty, const Data& cnonce = Data::Empty, 
492
                                  const Data& cnonceCount = Data::Empty, const Contents *entityBody = 0);
493
      
494
      /// Note: Helper assumes control of NonceHelper object and will delete when global scope is cleaned up      
495
      static void setNonceHelper(NonceHelper *nonceHelper);
496
      static NonceHelper* getNonceHelper();
497
      static Data makeNonce(const SipMessage& request, const Data& timestamp);
498
499
      static Uri makeUri(const Data& aor, const Data& scheme=Symbols::DefaultSipScheme);
500
501
      static void processStrictRoute(SipMessage& request);
502
503
      // return the port that the response should be sent to using rules from 
504
      // RFC 3261 - 18.2.2
505
      static int getPortForReply(SipMessage& request);
506
507
      static void massageRoute(const SipMessage& request, NameAddr& route);
508
509
      static Uri fromAor(const Data& aor, const Data& scheme=Symbols::DefaultSipScheme);
510
511
      // Do basic checks to validate a received message off the wire
512
      // If the basic check fails, and reason is non-null, reason will be set
513
      // to the reason the check failed. This function does not take ownership
514
      // of reason.
515
      static bool validateMessage(const SipMessage& message,resip::Data* reason=0);
516
517
      // GRUU support -- reversibly and opaquely combine instance id and aor
518
      static Data gruuUserPart(const Data& instanceId,
519
                               const Data& aor,
520
                               const Data& key);
521
522
      // GRUU support -- extract instance id and aor from user portion
523
      static std::pair<Data,Data> fromGruuUserPart(const Data& gruuUserPart,
524
                                                   const Data& key);
525
526
      struct ContentsSecAttrs
527
      {
528
            ContentsSecAttrs() = default;
529
            ContentsSecAttrs(std::unique_ptr<Contents> contents,
530
                             std::unique_ptr<SecurityAttributes> attributes);
531
            ContentsSecAttrs(const ContentsSecAttrs&) = delete;
532
            ContentsSecAttrs(ContentsSecAttrs&&) = default;
533
            ~ContentsSecAttrs() = default;
534
535
            ContentsSecAttrs& operator=(const ContentsSecAttrs&) = delete;
536
            ContentsSecAttrs& operator=(ContentsSecAttrs&&) = default;
537
538
            mutable std::unique_ptr<Contents> mContents;
539
            mutable std::unique_ptr<SecurityAttributes> mAttributes;
540
      };
541
542
      static ContentsSecAttrs extractFromPkcs7(const SipMessage& message, Security& security);
543
544
      
545
      enum FailureMessageEffect{ DialogTermination, TransactionTermination, UsageTermination, 
546
                                 RetryAfter, OptionalRetryAfter, ApplicationDependant };
547
      
548
      static FailureMessageEffect determineFailureMessageEffect(const SipMessage& response,
549
          const std::set<int>* additionalTransactionTerminatingResponses = NULL);
550
551
      // Just simply walk the contents tree and return the first SdpContents in
552
      // the tree.
553
      static std::unique_ptr<SdpContents> getSdp(Contents* tree);
554
555
      /** Looks at SIP headers and message source for a mismatch to make an
556
          assumption that the sender is behind a NAT device.
557
558
          @param request Request message that we use for checking.
559
560
          @privateToPublicOnly If enabled then we ensure that the via is private
561
                               address and that the source was a public address.
562
                               This allows us to ignore cases of private-private NAT'ing
563
                               or false detections, when a server behind a load balancer
564
                               is sending us requests and using the load balancer address
565
                               in the Via, instead of the real of the adapter.
566
      */
567
      static bool isClientBehindNAT(const SipMessage& request, bool privateToPublicOnly=true);
568
569
      /** Look at Via headers, and find the first public IP address closest to the sending
570
          client.
571
572
          @param request Request message that we use for checking.
573
574
          @note If no public IP's are found, then an empty Tuple is returned.  This
575
                can be tested by checking if Tuple::getType() returns UNKNOWN_TRANSPORT.
576
      */
577
      static Tuple getClientPublicAddress(const SipMessage& request);
578
579
   private:
580
      class NonceHelperPtr
581
      {
582
         public:
583
2
            NonceHelperPtr() : mNonceHelper(0) {}
584
0
            ~NonceHelperPtr() { delete mNonceHelper; }
585
            NonceHelper *mNonceHelper;
586
      };
587
      static NonceHelperPtr mNonceHelperPtr;
588
};
589
590
}
591
592
#endif
593
594
/* ====================================================================
595
 * The Vovida Software License, Version 1.0 
596
 * 
597
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
598
 * 
599
 * Redistribution and use in source and binary forms, with or without
600
 * modification, are permitted provided that the following conditions
601
 * are met:
602
 * 
603
 * 1. Redistributions of source code must retain the above copyright
604
 *    notice, this list of conditions and the following disclaimer.
605
 * 
606
 * 2. Redistributions in binary form must reproduce the above copyright
607
 *    notice, this list of conditions and the following disclaimer in
608
 *    the documentation and/or other materials provided with the
609
 *    distribution.
610
 * 
611
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
612
 *    and "Vovida Open Communication Application Library (VOCAL)" must
613
 *    not be used to endorse or promote products derived from this
614
 *    software without prior written permission. For written
615
 *    permission, please contact vocal@vovida.org.
616
 *
617
 * 4. Products derived from this software may not be called "VOCAL", nor
618
 *    may "VOCAL" appear in their name, without prior written
619
 *    permission of Vovida Networks, Inc.
620
 * 
621
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
622
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
623
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
624
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
625
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
626
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
627
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
628
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
629
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
630
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
631
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
632
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
633
 * DAMAGE.
634
 * 
635
 * ====================================================================
636
 * 
637
 * This software consists of voluntary contributions made by Vovida
638
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
639
 * Inc.  For more information on Vovida Networks, Inc., please see
640
 * <http://www.vovida.org/>.
641
 *
642
 */