Planeshift

netpacket.h

Go to the documentation of this file.
00001 /*
00002  * netpacket.h
00003  *
00004  * Copyright (C) 2001 Atomic Blue ([email protected], http://www.atomicblue.org) 
00005  *
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation (version 2 of the License)
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017  *
00018  */
00019 #ifndef __NETPACKET_H__
00020 #define __NETPACKET_H__
00021 
00022 #include <csutil/csendian.h>
00023 #include <csutil/refcount.h>
00024 #include <csutil/hash.h>
00025 
00026 #include "net/packing.h"
00027 #include "net/message.h"
00028 
00033 enum
00034 {
00035   PKTSIZE_ACK    = 0,        // 0 pktsize means ACK pkt
00036   PKTMINRTO    = 250,        // Minimum of 250 mseconds till packet resend
00037   PKTMAXRTO = 60000,        // Maximum of 1 minute till packet resend
00038   PKTINITRTO = 3000,         // Initially assume 3 seconds till packet resend
00039   FLAG_MULTIPACKET = 0x02,   // priority bit 1 is multipacket on/off 
00041   MAXPACKETSIZE       = 1400    // 1400 bytes is max size of network packet
00042 };
00043 
00054 #pragma pack(1)
00055 struct psNetPacket
00056 {
00061     uint32_t    pktid;
00062 
00066     uint32_t    offset;
00067     uint32_t    msgsize;
00068     uint16_t    pktsize;
00069     
00072     uint8_t    flags;
00073         
00075     char    data[0];
00076 
00077     
00078     size_t GetPacketSize() const
00079     {
00080         if (pktsize == PKTSIZE_ACK)
00081             return sizeof(psNetPacket);
00082         else
00083             return sizeof(psNetPacket) + pktsize;
00084     };
00085 
00086     bool IsMultiPacket() const
00087     {
00088         return (flags & FLAG_MULTIPACKET)? true: false;
00089     }
00090     
00091     uint8_t GetPriority() const
00092     {
00093         return flags & PRIORITY_MASK;
00094     }
00095 
00096     uint8_t GetSequence() const
00097     {
00098         return flags>>2; // upper 6 bits of flags should be sequence id
00099     }
00100 
00101     void MarshallEndian() {
00102         // Pack up for transmission.  This endian-izes the packet.
00103         pktid = csLittleEndian::Convert((uint32)pktid);
00104         offset = csLittleEndian::Convert((uint32)offset);
00105         msgsize = csLittleEndian::Convert((uint32)msgsize);
00106         pktsize = csLittleEndian::Convert((uint16)pktsize);
00107     }
00108 
00109     void UnmarshallEndian() {
00110         // Unpack from transmission.  This deendian-izes the packet.
00111         pktid = csLittleEndian::UInt32(pktid);
00112         offset = csLittleEndian::UInt32(offset);
00113         msgsize = csLittleEndian::UInt32(msgsize);
00114         pktsize = csLittleEndian::UInt16(pktsize);
00115     }
00116 
00117     /*  The goal here is to verify fields that later parsing can't.
00118      *  Specifically we need to make sure the buffer can hold at least the 
00119      *  fields that must be present in every packet, and also that the reported
00120      *  packet length is less than or equal to the data provided in the buffer.
00121      *  (Really it should be the same length, but extra won't cause us to crash)
00122      */
00123     static struct psNetPacket *NetPacketFromBuffer(void *buffer,int buffer_length)
00124     {
00125         if ( !buffer )
00126             return NULL;
00127 
00128         struct psNetPacket *potentialpacket;
00129         
00130         if (buffer_length < (int)sizeof(struct psNetPacket))
00131             return NULL; // Buffer data too short for even the header
00132         
00133         potentialpacket=(struct psNetPacket *)buffer;
00134         
00135         if ((unsigned int)buffer_length < csLittleEndian::Convert(potentialpacket->pktsize) + sizeof(struct psNetPacket))
00136             return NULL; // Buffer data too short for the packet length reported in the header
00137         
00138         return potentialpacket;
00139     }
00140 
00141 };
00142 #pragma pack()
00143 
00144 
00145 //-----------------------------------------------------------------------------
00146 
00147 
00148 class PacketKey
00149 {
00150     uint32_t clientnum;
00151     uint32_t pktid;
00152 public:
00153     PacketKey(uint32_t Clientnum, uint32_t Pktid):clientnum(Clientnum), pktid(Pktid) { };
00154     
00155     bool operator < (const PacketKey& other) const
00156     {
00157         if (clientnum < other.clientnum)
00158             return true;
00159         if (clientnum > other.clientnum)
00160             return false;
00161         
00162         return (pktid < other.pktid);
00163     };
00164 };
00165 
00166 
00167 //-----------------------------------------------------------------------------
00168 
00169 
00170 template<> class csHashComputer<PacketKey> : public csHashComputerStruct<PacketKey> 
00171 {
00172 };
00173 
00174 
00175 //-----------------------------------------------------------------------------
00176 
00177 
00178 class psNetPacketEntry : public csSyncRefCount
00179 {
00180 public:
00182     uint32_t clientnum;
00183 
00184     csTicks  timestamp;
00185     
00187     bool retransmitted;
00188     
00190     csTicks RTO;
00191 
00195     psNetPacket* packet;
00196 
00200     psNetPacketEntry (psNetPacket* packet, uint32_t cnum, uint16_t sz);
00201     
00203     psNetPacketEntry (uint8_t pri, uint32_t cnum, uint32_t id,
00204                       uint32_t off, uint32_t totalsize, uint16_t sz,
00205               psMessageBytes *msg);
00206 
00208     psNetPacketEntry (uint8_t pri, uint32_t cnum,
00209                       uint32_t id, uint32_t off, uint32_t totalsize, uint16_t sz,
00210                       const char *bytes);
00211 
00212     psNetPacketEntry (psNetPacketEntry* )
00213     {
00214         CS_ASSERT(false);
00215     }
00216 
00217     ~psNetPacketEntry();
00218     
00219     bool Append(psNetPacketEntry* next);
00220     csPtr<psNetPacketEntry> GetNextPacket(psNetPacket* &packetdata);
00221 
00222 
00223     void* GetData()
00224     {
00225         return packet;
00226     }
00227 
00228     bool operator < (const psNetPacketEntry& other) const
00229     {
00230         if (clientnum < other.clientnum)
00231             return true;
00232         if (clientnum > other.clientnum)
00233             return false;
00234     
00235         if (packet->pktid < other.packet->pktid)
00236             return true;
00237         if (packet->pktid > other.packet->pktid)
00238             return false;
00239     
00240         if (packet->offset < other.packet->offset)
00241             return true;
00242 
00243         return false;
00244     };
00245 
00247     // Dummy functions required by GenericQueue
00249     void SetPending(bool /*flag*/)
00250     {   }
00251     bool GetPending()
00252     { return false; }
00253 };
00254 
00255 
00256 //-----------------------------------------------------------------------------
00257 
00258 
00259 template<>
00260 class csComparator<csRef<psNetPacketEntry> , csRef<psNetPacketEntry> >
00261 {
00262 public:
00263     static int Compare(csRef<psNetPacketEntry> const &r1, csRef<psNetPacketEntry> const &r2)
00264     {
00265         return csComparator<psNetPacketEntry, psNetPacketEntry>::Compare(*r1, *r2);
00266     }
00267 };
00268 
00271 #endif
00272