Planeshift
|
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