|
reSIProcate/stack
9694
|
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 */
1.7.5.1