Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network5/src/libraries/network/packet/Packet.cc @ 7777

Last change on this file since 7777 was 7777, checked in by scheusso, 13 years ago

some () structural changes
some functional changes (GamestateClient replaced through GamestateManager on client)
reliable packets get buffered until a recent gamestate arrived and got processed

  • Property svn:eol-style set to native
File size: 7.5 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Oliver Scheuss, (C) 2008
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29
30#include "Packet.h"
31
32#include <cassert>
33#include <cstring>
34#define WIN32_LEAN_AND_MEAN
35#include <enet/enet.h>
36#include <boost/static_assert.hpp>
37#include <boost/thread/mutex.hpp>
38
39#include "util/Debug.h"
40#include "Acknowledgement.h"
41#include "Chat.h"
42#include "ClassID.h"
43#include "DeleteObjects.h"
44#include "FunctionCalls.h"
45#include "FunctionIDs.h"
46#include "Gamestate.h"
47#include "Welcome.h"
48#include "network/Host.h"
49#include "network/ClientInformation.h"
50
51namespace orxonox{
52
53namespace packet{
54
55// Make sure we assume the right values
56BOOST_STATIC_ASSERT(static_cast<int>(PacketFlag::Reliable)    == static_cast<int>(ENET_PACKET_FLAG_RELIABLE));
57BOOST_STATIC_ASSERT(static_cast<int>(PacketFlag::Unsequenced) == static_cast<int>(ENET_PACKET_FLAG_UNSEQUENCED));
58BOOST_STATIC_ASSERT(static_cast<int>(PacketFlag::NoAllocate)  == static_cast<int>(ENET_PACKET_FLAG_NO_ALLOCATE));
59
60#define PACKET_FLAG_DEFAULT PacketFlag::NoAllocate
61#define _PACKETID           0
62
63std::map<size_t, Packet *> Packet::packetMap_;
64boost::mutex Packet::packetMapMutex_;
65
66Packet::Packet()
67{
68  flags_ = PACKET_FLAG_DEFAULT;
69  packetDirection_ = Direction::Outgoing;
70  peerID_=0;
71  data_=0;
72  enetPacket_=0;
73  bDataENetAllocated_ = false;
74}
75
76Packet::Packet(uint8_t *data, unsigned int peerID)
77{
78  flags_ = PACKET_FLAG_DEFAULT;
79  packetDirection_ = Direction::Incoming;
80  peerID_=peerID;
81  data_=data;
82  enetPacket_=0;
83  bDataENetAllocated_ = false;
84}
85
86
87Packet::Packet(const Packet &p){
88  enetPacket_=p.enetPacket_;
89  flags_=p.flags_;
90  packetDirection_ = p.packetDirection_;
91  peerID_ = p.peerID_;
92  if(p.data_){
93    data_ = new uint8_t[p.getSize()];
94    memcpy(data_, p.data_, p.getSize());
95  }else
96    data_=0;
97  bDataENetAllocated_ = p.bDataENetAllocated_;
98}
99
100/**
101@brief
102    Destroys a packet completely.
103
104    That also means destroying the ENetPacket if one exists. There
105*/
106Packet::~Packet(){
107  // Deallocate data_ memory if necessary.
108  if (this->bDataENetAllocated_){
109    // In this case ENet allocated data_ and will destroy it.
110  }
111  else if (this->data_) {
112    // This destructor was probably called as a consequence of ENet executing our callback.
113    // It simply serves us to be able to deallocate the packet content (data_) ourselves since
114    // we have created it in the first place.
115    delete[] this->data_;
116  }
117
118  // Destroy the ENetPacket if necessary.
119  // Note: For the case ENet used the callback to destroy the packet, we have already set
120  // enetPacket_ to NULL to avoid destroying it again.
121  if (this->enetPacket_){
122    // enetPacket_->data gets destroyed too by ENet if it was allocated by it.
123    enet_packet_destroy(enetPacket_);
124  }
125}
126
127bool Packet::send(orxonox::Host* host){
128  if(packetDirection_ != Direction::Outgoing && packetDirection_ != Direction::Bidirectional ){
129    assert(0);
130    return false;
131  }
132  if(!enetPacket_){
133    if(!data_){
134      assert(0);
135      return false;
136    }
137    // We deliver ENet the data address so that it doesn't memcpy everything again.
138    // --> We have to delete data_ ourselves!
139    enetPacket_ = enet_packet_create(getData(), getSize(), getFlags());
140    enetPacket_->freeCallback = &Packet::deletePacket;
141    // Add the packet to a global list so we can access it again once enet calls our
142    // deletePacket method. We can of course only give a one argument function to the ENet C library.
143    {
144      // Assures we don't create a packet and destroy it right after in another thread
145      // without having a reference in the packetMap_
146      Packet::packetMapMutex_.lock();
147      packetMap_[reinterpret_cast<size_t>(enetPacket_)] = this;
148      Packet::packetMapMutex_.unlock();
149    }
150  }
151#ifndef NDEBUG
152  switch( *(Type::Value *)(data_ + _PACKETID) )
153  {
154    case Type::Acknowledgement:
155    case Type::Chat:
156    case Type::ClassID:
157    case Type::Gamestate:
158    case Type::Welcome:
159    case Type::DeleteObjects:
160    case Type::FunctionIDs:
161    case Type::FunctionCalls:
162      break;
163    default:
164      assert(0); //there was some error, if this is the case
165      break;
166  }
167#endif
168//  ENetPacket *temp = enetPacket_;
169//  enetPacket_ = 0; // otherwise we have a double free because enet already handles the deallocation of the packet
170  if( this->flags_ & PacketFlag::Reliable )
171    host->addPacket( enetPacket_, peerID_, NETWORK_CHANNEL_DEFAULT);
172  else
173    host->addPacket( enetPacket_, peerID_, NETWORK_CHANNEL_UNRELIABLE);
174  return true;
175}
176
177Packet *Packet::createPacket(ENetPacket *packet, ENetPeer *peer){
178  uint8_t *data = packet->data;
179  assert(ClientInformation::findClient(&peer->address)->getID() != static_cast<unsigned int>(-2) || !Host::isServer());
180  unsigned int peerID = ClientInformation::findClient(&peer->address)->getID();
181  Packet *p = 0;
182//   COUT(6) << "packet type: " << *(Type::Value *)&data[_PACKETID] << std::endl;
183  switch( *(Type::Value *)(data + _PACKETID) )
184  {
185    case Type::Acknowledgement:
186//       COUT(5) << "ack" << std::endl;
187    p = new Acknowledgement( data, peerID );
188      break;
189    case Type::Chat:
190//       COUT(5) << "chat" << std::endl;
191      p = new Chat( data, peerID );
192      break;
193    case Type::ClassID:
194//       COUT(5) << "classid" << std::endl;
195      p = new ClassID( data, peerID );
196      break;
197    case Type::Gamestate:
198//       COUT(5) << "gamestate" << std::endl;
199      p = new Gamestate( data, peerID );
200      break;
201    case Type::Welcome:
202//       COUT(5) << "welcome" << std::endl;
203      p = new Welcome( data, peerID );
204      break;
205    case Type::DeleteObjects:
206//       COUT(5) << "deleteobjects" << std::endl;
207      p = new DeleteObjects( data, peerID );
208      break;
209    case Type::FunctionCalls:
210//       COUT(5) << "functionCalls" << std::endl;
211      p = new FunctionCalls( data, peerID );
212      break;
213    case Type::FunctionIDs:
214//       COUT(5) << "functionIDs" << std::endl;
215      p = new FunctionIDs( data, peerID );
216      break;
217    default:
218      assert(0);
219      break;
220  }
221
222  // Data was created by ENet
223  p->bDataENetAllocated_ = true;
224  p->enetPacket_ = packet;
225
226  return p;
227}
228
229/**
230@brief
231    ENet calls this method whenever it wants to destroy a packet that contains
232    data we allocated ourselves.
233*/
234void Packet::deletePacket(ENetPacket *enetPacket){
235  // Get our Packet from a global map with all Packets created in the send() method of Packet.
236  Packet::packetMapMutex_.lock();
237  std::map<size_t, Packet*>::iterator it = packetMap_.find(reinterpret_cast<size_t>(enetPacket));
238  assert(it != packetMap_.end());
239  // Make sure we don't delete it again in the destructor
240  it->second->enetPacket_ = 0;
241  delete it->second;
242  packetMap_.erase(it);
243  Packet::packetMapMutex_.unlock();
244//   COUT(6) << "PacketMap size: " << packetMap_.size() << std::endl;
245}
246
247} // namespace packet
248
249} // namespace orxonox
250
Note: See TracBrowser for help on using the repository browser.