reSIProcate/stack  9694
SipMessage.hxx
Go to the documentation of this file.
00001 #if !defined(RESIP_SIPMESSAGE_HXX)
00002 #define RESIP_SIPMESSAGE_HXX 
00003 
00004 #include <sys/types.h>
00005 
00006 #include <list>
00007 #include <vector>
00008 #include <utility>
00009 #include <memory> 
00010 
00011 #include "resip/stack/Contents.hxx"
00012 #include "resip/stack/Headers.hxx"
00013 #include "resip/stack/TransactionMessage.hxx"
00014 #include "resip/stack/ParserContainer.hxx"
00015 #include "resip/stack/ParserCategories.hxx"
00016 #include "resip/stack/SecurityAttributes.hxx"
00017 #include "resip/stack/Tuple.hxx"
00018 #include "resip/stack/Uri.hxx"
00019 #include "resip/stack/MessageDecorator.hxx"
00020 #include "rutil/BaseException.hxx"
00021 #include "rutil/Data.hxx"
00022 #include "rutil/DinkyPool.hxx"
00023 #include "rutil/StlPoolAllocator.hxx"
00024 #include "rutil/Timer.hxx"
00025 #include "rutil/HeapInstanceCounter.hxx"
00026 
00027 namespace resip
00028 {
00029 
00030 class Contents;
00031 class ExtensionHeader;
00032 class SecurityAttributes;
00033 class Transport;
00034 
00152 class SipMessage : public TransactionMessage
00153 {
00154    public:
00155       RESIP_HeapCount(SipMessage);
00156 #ifndef __SUNPRO_CC
00157       typedef std::list< std::pair<Data, HeaderFieldValueList*>, StlPoolAllocator<std::pair<Data, HeaderFieldValueList*>, PoolBase > > UnknownHeaders;
00158 #else
00159       typedef std::list< std::pair<Data, HeaderFieldValueList*> > UnknownHeaders;
00160 #endif
00161 
00162       explicit SipMessage(const Transport* fromWire = 0);
00164       SipMessage(const SipMessage& message);
00165 
00167       virtual Message* clone() const;
00168 
00169       SipMessage& operator=(const SipMessage& rhs);
00170       
00172       virtual const Data& getTransactionId() const;
00173 
00180       const Data& getRFC2543TransactionId() const;
00181       void setRFC2543TransactionId(const Data& tid);
00182       
00183       virtual ~SipMessage();
00184 
00192       static SipMessage* make(const Data& buffer, bool isExternal = false);
00193       void parseAllHeaders();
00194       
00195       static bool checkContentLength;
00196 
00200       class Exception : public BaseException
00201       {
00202          public:
00207             Exception(const Data& msg, const Data& file, const int line)
00208                : BaseException(msg, file, line) {}
00213             const char* name() const { return "SipMessage::Exception"; }
00214       };
00215 
00217       inline void setFromTU() 
00218       {
00219          mIsExternal = false;
00220       }
00221 
00223       inline void setFromExternal()
00224       {
00225          mIsExternal = true;
00226       }
00227       
00232       inline bool isExternal() const
00233       {
00234          return mIsExternal;
00235       }
00236       
00240       virtual bool isClientTransaction() const;
00241       
00246       virtual EncodeStream& encode(EncodeStream& str) const;      
00247       //sipfrags will not output Content Length if there is no body--introduce
00248       //friendship to hide this?
00249       virtual EncodeStream& encodeSipFrag(EncodeStream& str) const;
00250       EncodeStream& encodeEmbedded(EncodeStream& str) const;
00251       
00252       virtual EncodeStream& encodeBrief(EncodeStream& str) const;
00253       EncodeStream& encodeSingleHeader(Headers::Type type, EncodeStream& str) const;
00254 
00256       inline bool isRequest() const {return mRequest;}
00258       inline bool isResponse() const {return mResponse;}
00260       inline bool isInvalid() const{return mInvalid;}
00261       
00264       resip::MethodTypes method() const;
00266       const Data& methodStr() const;
00267       
00269       const resip::Data* getReason() const{return mReason;}
00270       
00272       const RequestLine& 
00273       header(const RequestLineType& l) const;
00274 
00276       RequestLine& 
00277       header(const RequestLineType& l);
00278 
00279       inline const RequestLine& 
00280       const_header(const RequestLineType& l) const
00281       {
00282          return header(l);
00283       }
00284 
00286       const StatusLine& 
00287       header(const StatusLineType& l) const;
00288 
00290       StatusLine& 
00291       header(const StatusLineType& l);
00292 
00293       inline const StatusLine& 
00294       const_header(const StatusLineType& l) const
00295       {
00296          return header(l);
00297       }
00298 
00300       bool exists(const HeaderBase& headerType) const;
00302       bool empty(const HeaderBase& headerType) const;
00306       inline void remove(const HeaderBase& headerType)
00307       {
00308          remove(headerType.getTypeNum());
00309       }
00310 
00311       void remove(Headers::Type type);
00312 
00313 #define defineHeader(_header, _name, _type, _rfc)                       \
00314       const H_##_header::Type& header(const H_##_header& headerType) const; \
00315             H_##_header::Type& header(const H_##_header& headerType); \
00316       inline const H_##_header::Type& const_header(const H_##_header& headerType) const \
00317       {\
00318          return header(headerType);\
00319       }
00320 
00321       
00322 #define defineMultiHeader(_header, _name, _type, _rfc)                  \
00323       const H_##_header##s::Type& header(const H_##_header##s& headerType) const; \
00324             H_##_header##s::Type& header(const H_##_header##s& headerType); \
00325       inline const H_##_header##s::Type& const_header(const H_##_header##s& headerType) const \
00326       {\
00327          return header(headerType);\
00328       }
00329       
00330       defineHeader(ContentDisposition, "Content-Disposition", Token, "RFC 3261");
00331       defineHeader(ContentEncoding, "Content-Encoding", Token, "RFC 3261");
00332       defineHeader(MIMEVersion, "Mime-Version", Token, "RFC 3261");
00333       defineHeader(Priority, "Priority", Token, "RFC 3261");
00334       defineHeader(Event, "Event", Token, "RFC 3265");
00335       defineHeader(SubscriptionState, "Subscription-State", Token, "RFC 3265");
00336       defineHeader(SIPETag, "SIP-ETag", Token, "RFC 3903");
00337       defineHeader(SIPIfMatch, "SIP-If-Match", Token, "RFC 3903");
00338       defineHeader(ContentId, "Content-ID", Token, "RFC 2045");
00339       defineMultiHeader(AllowEvents, "Allow-Events", Token, "RFC 3265");
00340       defineHeader(Identity, "Identity", StringCategory, "RFC 4474");
00341       defineMultiHeader(AcceptEncoding, "Accept-Encoding", Token, "RFC 3261");
00342       defineMultiHeader(AcceptLanguage, "Accept-Language", Token, "RFC 3261");
00343       defineMultiHeader(Allow, "Allow", Token, "RFC 3261");
00344       defineMultiHeader(ContentLanguage, "Content-Language", Token, "RFC 3261");
00345       defineMultiHeader(ProxyRequire, "Proxy-Require", Token, "RFC 3261");
00346       defineMultiHeader(Require, "Require", Token, "RFC 3261");
00347       defineMultiHeader(Supported, "Supported", Token, "RFC 3261");
00348       defineMultiHeader(Unsupported, "Unsupported", Token, "RFC 3261");
00349       defineMultiHeader(SecurityClient, "Security-Client", Token, "RFC 3329");
00350       defineMultiHeader(SecurityServer, "Security-Server", Token, "RFC 3329");
00351       defineMultiHeader(SecurityVerify, "Security-Verify", Token, "RFC 3329");
00352       defineMultiHeader(RequestDisposition, "Request-Disposition", Token, "RFC 3841");
00353       defineMultiHeader(Reason, "Reason", Token, "RFC 3326");
00354       defineMultiHeader(Privacy, "Privacy", PrivacyCategory, "RFC 3323");
00355       defineMultiHeader(PMediaAuthorization, "P-Media-Authorization", Token, "RFC 3313");
00356       defineHeader(ReferSub, "Refer-Sub", Token, "RFC 4488");
00357       defineHeader(AnswerMode, "Answer-Mode", Token, "draft-ietf-answermode-04");
00358       defineHeader(PrivAnswerMode, "Priv-Answer-Mode", Token, "draft-ietf-answermode-04");
00359 
00360       defineMultiHeader(Accept, "Accept", Mime, "RFC 3261");
00361       defineHeader(ContentType, "Content-Type", Mime, "RFC 3261");
00362 
00363       defineMultiHeader(CallInfo, "Call-Info", GenericUri, "RFC 3261");
00364       defineMultiHeader(AlertInfo, "Alert-Info", GenericUri, "RFC 3261");
00365       defineMultiHeader(ErrorInfo, "Error-Info", GenericUri, "RFC 3261");
00366       defineHeader(IdentityInfo, "Identity-Info", GenericUri, "RFC 4474");
00367 
00368       defineMultiHeader(RecordRoute, "Record-Route", NameAddr, "RFC 3261");
00369       defineMultiHeader(Route, "Route", NameAddr, "RFC 3261");
00370       defineMultiHeader(Contact, "Contact", NameAddr, "RFC 3261");
00371       defineHeader(From, "From", NameAddr, "RFC 3261");
00372       defineHeader(To, "To", NameAddr, "RFC 3261");
00373       defineHeader(ReplyTo, "Reply-To", NameAddr, "RFC 3261");
00374       defineHeader(ReferTo, "Refer-To", NameAddr, "RFC 3515");
00375       defineHeader(ReferredBy, "Referred-By", NameAddr, "RFC 3892");
00376       defineMultiHeader(Path, "Path", NameAddr, "RFC 3327");
00377       defineMultiHeader(AcceptContact, "Accept-Contact", NameAddr, "RFC 3841");
00378       defineMultiHeader(RejectContact, "Reject-Contact", NameAddr, "RFC 3841");
00379       defineMultiHeader(PAssertedIdentity, "P-Asserted-Identity", NameAddr, "RFC 3325");
00380       defineMultiHeader(PPreferredIdentity, "P-Preferred-Identity", NameAddr, "RFC 3325");
00381       defineHeader(PCalledPartyId, "P-Called-Party-ID", NameAddr, "RFC 3455");
00382       defineMultiHeader(PAssociatedUri, "P-Associated-URI", NameAddr, "RFC 3455");
00383       defineMultiHeader(ServiceRoute, "Service-Route", NameAddr, "RFC 3608");
00384       defineMultiHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"); // ?bwc? Not in 3323, should we keep?
00385       defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244");
00386 
00387       defineHeader(ContentTransferEncoding, "Content-Transfer-Encoding", StringCategory, "RFC 1521");
00388       defineHeader(Organization, "Organization", StringCategory, "RFC 3261");
00389       defineHeader(Server, "Server", StringCategory, "RFC 3261");
00390       defineHeader(Subject, "Subject", StringCategory, "RFC 3261");
00391       defineHeader(UserAgent, "User-Agent", StringCategory, "RFC 3261");
00392       defineHeader(Timestamp, "Timestamp", StringCategory, "RFC 3261");
00393 
00394       defineHeader(ContentLength, "Content-Length", UInt32Category, "RFC 3261");
00395       defineHeader(MaxForwards, "Max-Forwards", UInt32Category, "RFC 3261");
00396       defineHeader(MinExpires, "Min-Expires", UInt32Category, "RFC 3261");
00397       defineHeader(RSeq, "RSeq", UInt32Category, "RFC 3261");
00398 
00400       defineHeader(RetryAfter, "Retry-After", UInt32Category, "RFC 3261");
00401       defineHeader(FlowTimer, "Flow-Timer", UInt32Category, "RFC 5626");
00402 
00403       defineHeader(Expires, "Expires", ExpiresCategory, "RFC 3261");
00404       defineHeader(SessionExpires, "Session-Expires", ExpiresCategory, "RFC 4028");
00405       defineHeader(MinSE, "Min-SE", ExpiresCategory, "RFC 4028");
00406 
00407       defineHeader(CallID, "Call-ID", CallID, "RFC 3261");
00408       defineHeader(Replaces, "Replaces", CallID, "RFC 3891");
00409       defineHeader(InReplyTo, "In-Reply-To", CallID, "RFC 3261");
00410       defineHeader(Join, "Join", CallId, "RFC 3911");
00411       defineHeader(TargetDialog, "Target-Dialog", CallId, "RFC 4538");
00412 
00413       defineHeader(AuthenticationInfo, "Authentication-Info", Auth, "RFC 3261");
00414       defineMultiHeader(Authorization, "Authorization", Auth, "RFC 3261");
00415       defineMultiHeader(ProxyAuthenticate, "Proxy-Authenticate", Auth, "RFC 3261");
00416       defineMultiHeader(ProxyAuthorization, "Proxy-Authorization", Auth, "RFC 3261");
00417       defineMultiHeader(WWWAuthenticate, "Www-Authenticate", Auth, "RFC 3261");
00418 
00419       defineHeader(CSeq, "CSeq", CSeqCategory, "RFC 3261");
00420       defineHeader(Date, "Date", DateCategory, "RFC 3261");
00421       defineMultiHeader(Warning, "Warning", WarningCategory, "RFC 3261");
00422       defineMultiHeader(Via, "Via", Via, "RFC 3261");
00423       defineHeader(RAck, "RAck", RAckCategory, "RFC 3262");
00424 
00426       const StringCategories& header(const ExtensionHeader& symbol) const;
00427       StringCategories& header(const ExtensionHeader& symbol);
00428       bool exists(const ExtensionHeader& symbol) const;
00429       void remove(const ExtensionHeader& symbol);
00430 
00432       const HeaderFieldValueList* getRawHeader(Headers::Type headerType) const;
00433       void setRawHeader(const HeaderFieldValueList* hfvs, Headers::Type headerType);
00434       const UnknownHeaders& getRawUnknownHeaders() const {return mUnknownHeaders;}
00442       const HeaderFieldValue& getRawBody() const {return mContentsHfv;}
00443 
00452       void setRawBody(const HeaderFieldValue& body);
00453 
00462       Contents* getContents() const;
00464       std::auto_ptr<Contents> releaseContents();
00465 
00468       void setContents(const Contents* contents);
00471       void setContents(std::auto_ptr<Contents> contents);
00472 
00474       void setStartLine(const char* start, int len); 
00475 
00476       void setBody(const char* start, UInt32 len); 
00477       
00479       void addHeader(Headers::Type header,
00480                      const char* headerName, int headerLen, 
00481                      const char* start, int len);
00482 
00486       const Transport* getReceivedTransport() const { return mTransport; }
00487 
00488       // Returns the source tuple that the message was received from
00489       // only makes sense for messages received from the wire
00490       void setSource(const Tuple& tuple) { mSource = tuple; }
00493       const Tuple& getSource() const { return mSource; }
00494       
00496       void setDestination(const Tuple& tuple) { mDestination = tuple; }
00497       Tuple& getDestination() { return mDestination; }
00498 
00499       void addBuffer(char* buf);
00500 
00501       UInt64 getCreatedTimeMicroSec() {return mCreatedTime;}
00502 
00504       void setForceTarget(const Uri& uri);
00505       void clearForceTarget();
00506       const Uri& getForceTarget() const;
00507       bool hasForceTarget() const;
00508 
00509       const Data& getTlsDomain() const { return mTlsDomain; }
00510       void setTlsDomain(const Data& domain) { mTlsDomain = domain; }
00511 
00512       const std::list<Data>& getTlsPeerNames() const { return mTlsPeerNames; }
00513       void setTlsPeerNames(const std::list<Data>& tlsPeerNames) { mTlsPeerNames = tlsPeerNames; }
00514 
00515       Data getCanonicalIdentityString() const;
00516       
00517       SipMessage& mergeUri(const Uri& source);      
00518 
00519       void setSecurityAttributes(std::auto_ptr<SecurityAttributes>);
00520       const SecurityAttributes* getSecurityAttributes() const { return mSecurityAttributes.get(); }
00521 
00524       void addOutboundDecorator(std::auto_ptr<MessageDecorator> md){mOutboundDecorators.push_back(md.release());}
00525       void clearOutboundDecorators();
00526       void callOutboundDecorators(const Tuple &src, 
00527                                     const Tuple &dest,
00528                                     const Data& sigcompId);
00529       void rollbackOutboundDecorators();
00530       void copyOutboundDecoratorsToStackCancel(SipMessage& cancel);
00531       void copyOutboundDecoratorsToStackFailureAck(SipMessage& ack);
00532       bool mIsDecorated;
00533 
00534       bool mIsBadAck200;
00535 
00536    protected:
00537       // !bwc! Removes or zeros all pointers to heap-allocated memory this
00538       // class owns.
00539       void clear(bool leaveResponseStuff=false);
00540       // !bwc! Frees all heap-allocated memory owned.
00541       void freeMem(bool leaveResponseStuff=false);
00542       
00543       // !bwc! Initializes members. Will not free heap-allocated memory.
00544       // Will begin by calling clear().
00545       void init(const SipMessage& rhs);
00546    
00547    private:
00548       void compute2543TransactionHash() const;
00549 
00550       EncodeStream& 
00551       encode(EncodeStream& str, bool isSipFrag) const;      
00552 
00553       void copyFrom(const SipMessage& message);
00554 
00555       HeaderFieldValueList* ensureHeaders(Headers::Type type);
00556       inline HeaderFieldValueList* ensureHeaders(Headers::Type type) const // throws if not present
00557       {
00558          if(mHeaderIndices[type]>0)
00559          {
00560             return mHeaders[mHeaderIndices[type]];
00561          }
00562          throwHeaderMissing(type);
00563          return 0;
00564       }
00565 
00566       HeaderFieldValueList* ensureHeader(Headers::Type type);
00567       inline HeaderFieldValueList* ensureHeader(Headers::Type type) const // throws if not present
00568       {
00569          if(mHeaderIndices[type]>0)
00570          {
00571             return mHeaders[mHeaderIndices[type]];
00572          }
00573          throwHeaderMissing(type);
00574          return 0;
00575       }
00576 
00577       void throwHeaderMissing(Headers::Type type) const;
00578 
00579       inline HeaderFieldValueList* getEmptyHfvl()
00580       {
00581          void* ptr(mPool.allocate(sizeof(HeaderFieldValueList)));
00582          return new (ptr) HeaderFieldValueList(mPool);
00583       }
00584 
00585       inline HeaderFieldValueList* getCopyHfvl(const HeaderFieldValueList& hfvl)
00586       {
00587          void* ptr(mPool.allocate(sizeof(HeaderFieldValueList)));
00588          return new (ptr) HeaderFieldValueList(hfvl, mPool);
00589       }
00590 
00591       inline void freeHfvl(HeaderFieldValueList* hfvl)
00592       {
00593          if(hfvl)
00594          {
00595             hfvl->~HeaderFieldValueList();
00596             mPool.deallocate(hfvl);
00597          }
00598       }
00599 
00600       template<class T>
00601       ParserContainer<T>* makeParserContainer()
00602       {
00603          void* ptr(mPool.allocate(sizeof(ParserContainer<T>)));
00604          return new (ptr) ParserContainer<T>(mPool);
00605       }
00606 
00607       template<class T>
00608       ParserContainer<T>* makeParserContainer(HeaderFieldValueList* hfvs,
00609                                              Headers::Type type = Headers::UNKNOWN)
00610       {
00611          void* ptr(mPool.allocate(sizeof(ParserContainer<T>)));
00612          return new (ptr) ParserContainer<T>(hfvs, type, mPool);
00613       }
00614 
00615       // indicates this message came from the wire, set by the Transport
00616       bool mIsExternal;
00617 
00618       // !bwc! Would be nice to tweak this to automatically make SipMessage 4KB,
00619       // but I don't know how ugly it would be.
00620       DinkyPool<2968> mPool;
00621 
00622       typedef std::vector<HeaderFieldValueList*, 
00623                            StlPoolAllocator<HeaderFieldValueList*, 
00624                                           PoolBase > > TypedHeaders;
00625       // raw text corresponding to each typed header (not yet parsed)
00626       TypedHeaders mHeaders;
00627       
00628       // !bwc! Indices into mHeaders
00629       short mHeaderIndices[Headers::MAX_HEADERS];
00630 
00631       // raw text corresponding to each unknown header
00632       UnknownHeaders mUnknownHeaders;
00633   
00634       // !jf!
00635       const Transport* mTransport;
00636 
00637       // For messages received from the wire, this indicates where it came
00638       // from. Can be used to get to the Transport and/or reliable Connection
00639       Tuple mSource;
00640 
00641       // Used by the TU to specify where a message is to go
00642       Tuple mDestination;
00643       
00644       // Raw buffers coming from the Transport. message manages the memory
00645       std::vector<char*> mBufferList;
00646 
00647       // special case for the first line of message
00648       StartLine* mStartLine;
00649       char mStartLineMem[sizeof(RequestLine) > sizeof(StatusLine) ? sizeof(RequestLine) : sizeof(StatusLine)];
00650 
00651       // raw text for the contents (all of them)
00652       HeaderFieldValue mContentsHfv;
00653 
00654       // lazy parser for the contents
00655       mutable Contents* mContents;
00656 
00657       // cached value of a hash of the transaction id for a message received
00658       // from a 2543 sip element. as per rfc3261 see 17.2.3
00659       mutable Data mRFC2543TransactionId;
00660 
00661       // is a request or response
00662       bool mRequest;
00663       bool mResponse;
00664 
00665       bool mInvalid;
00666       resip::Data* mReason;
00667       
00668       UInt64 mCreatedTime;
00669 
00670       // used when next element is a strict router OR 
00671       // client forces next hop OOB
00672       Uri* mForceTarget;
00673 
00674       // domain associated with this message for tls cert
00675       Data mTlsDomain;
00676 
00677       // peers domain associate with this message (MTLS)
00678       std::list<Data> mTlsPeerNames; 
00679 
00680       std::auto_ptr<SecurityAttributes> mSecurityAttributes;
00681 
00682       std::vector<MessageDecorator*> mOutboundDecorators;
00683 
00684       friend class TransportSelector;
00685 };
00686 
00687 }
00688 
00689 #undef ensureHeaderTypeUseable
00690 #undef ensureSingleHeader
00691 #undef ensureMultiHeader
00692 #undef defineHeader
00693 #undef defineMultiHeader
00694 
00695 #endif
00696 
00697 /* ====================================================================
00698  * The Vovida Software License, Version 1.0 
00699  * 
00700  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00701  * 
00702  * Redistribution and use in source and binary forms, with or without
00703  * modification, are permitted provided that the following conditions
00704  * are met:
00705  * 
00706  * 1. Redistributions of source code must retain the above copyright
00707  *    notice, this list of conditions and the following disclaimer.
00708  * 
00709  * 2. Redistributions in binary form must reproduce the above copyright
00710  *    notice, this list of conditions and the following disclaimer in
00711  *    the documentation and/or other materials provided with the
00712  *    distribution.
00713  * 
00714  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00715  *    and "Vovida Open Communication Application Library (VOCAL)" must
00716  *    not be used to endorse or promote products derived from this
00717  *    software without prior written permission. For written
00718  *    permission, please contact vocal@vovida.org.
00719  *
00720  * 4. Products derived from this software may not be called "VOCAL", nor
00721  *    may "VOCAL" appear in their name, without prior written
00722  *    permission of Vovida Networks, Inc.
00723  * 
00724  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00725  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00726  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00727  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00728  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00729  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00730  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00731  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00732  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00733  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00734  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00735  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00736  * DAMAGE.
00737  * 
00738  * ====================================================================
00739  * 
00740  * This software consists of voluntary contributions made by Vovida
00741  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00742  * Inc.  For more information on Vovida Networks, Inc., please see
00743  * <http://www.vovida.org/>.
00744  *
00745  * vi: set shiftwidth=3 expandtab:
00746  */