Ggep.h

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #ifndef GGEP_H
00024 #define GGEP_H
00025 
00026 // Open containing namespaces:
00027 namespace Gnutella {
00028 namespace Packets {
00029 namespace Extensions {
00031 
00033 
00043 class Ggep
00044 {
00045 public:
00046     enum HeaderFlag
00047     {
00048         LastExtension   = 0x80,
00049         Encoding        = 0x40,
00050         Compression     = 0x20,
00051         Reserved        = 0x10,
00052         IDLength        = 0x0f
00053     };
00054 
00055     Q_DECLARE_FLAGS(HeaderFlags, HeaderFlag)
00056 
00057     
00058 
00064     typedef QByteArray GgepId;
00065 
00066     static Ggep *           fromId (const GgepId &id, int flags, int dataSize);
00067     virtual                 ~Ggep();
00068     virtual Ggep *          copy() const = 0;
00069 
00070     void                    prepareRead (const QByteArray &rawData);
00071     void                    read (QDataStream &stream);
00072     int                     prepareWrite() const;
00073     void                    write (QDataStream &stream) const;
00074 
00075     // \todo GgepBlock may set the LastExtensionFlag too often and degrade the use of shared data.
00076     inline bool             isFlagSet (HeaderFlag flag) const;
00077     inline void             setFlag (HeaderFlag flag);
00078     inline void             resetFlag (HeaderFlag flag);
00079 
00080     GgepId                  id() const;
00081 
00082 protected:
00083                             Ggep (const GgepId &id, int flags = 0, int dataSize = 0);
00084     inline                  Ggep (const Ggep &other);
00085     Ggep &                  operator= (const Ggep &other);
00086 
00087     inline int              dataLength() const;
00088 
00089     virtual bool            prepareReadData (const QByteArray &rawData) = 0;    
00090     virtual void            readData (QDataStream &stream) = 0;                 
00091     virtual int             prepareWriteData() const = 0;                       
00092     virtual void            writeData (QDataStream &stream) const = 0;          
00093 
00094 private:
00095     void                    invalidateData();
00096 
00097     struct Data
00098     {
00099         QBasicAtomic            ref;
00100 
00101         bool                    isValid;
00102         HeaderFlags             flags;
00103         GgepId                  id;
00104     };
00105 
00106     // \todo How good is this separation of shared and private data?
00107     // Doesn't keeping the private data reduce the gain of the shared?
00108     // dataLength may change eventually on write, if the data in the
00109     // derived class has changed. Separate encodedData is needed only
00110     // in multithread environment. The class Packet has a payloadLength()
00111     // function that calls rawPayload() to force rebuilding the payload
00112     // and get the actual length. The generated bytes are cached. This
00113     // is not the case here in the extensions. We do not need to double
00114     // cache the same extension data. We just want to make it cheap to
00115     // copy Ggeps when passing them on into a GGEP block.
00116     struct Private // Put these fields in the shared data as well?What about reentrancy and thread safety.
00117     {
00118         mutable int                 dataLength;     
00119         mutable QByteArray          encodedData;    
00120     };
00121 
00122     Data                        *d;                 // Shared object data with reference counting.
00123     Private                     p;                  // Private object data.
00124 };
00125 
00126 Q_DECLARE_OPERATORS_FOR_FLAGS(Ggep::HeaderFlags)
00127 
00128 
00129 // inline functions
00131 
00132 inline Ggep::Ggep (const Ggep &other)
00133 : d (other.d), p (other.p)
00134 { d->ref.ref(); }
00135 
00136 inline bool Ggep::isFlagSet (HeaderFlag flag) const
00137 { return d->flags & flag; }
00138 
00139 inline void Ggep::setFlag (HeaderFlag flag)
00140 { invalidateData(); d->flags |= flag; }
00141 
00142 inline void Ggep::resetFlag (HeaderFlag flag)
00143 { invalidateData(); d->flags &= ~flag; }
00144 
00145 inline Ggep::GgepId Ggep::id() const
00146 { return d->id; }
00147 
00148 inline int Ggep::dataLength() const
00149 { return p.dataLength; }
00150 
00151 // Close containing namespaces:
00152 } // namespace Extensions
00153 } // namespace Packets
00154 } // namespace Gnutella
00156 
00157 #endif // _GGEP_H