Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/libraries/network/packet/Packet.cc @ 11006

Last change on this file since 11006 was 11006, checked in by landauf, 8 years ago

made some enums in network library strongly typed. for most other enums in network this isn't possible because they are often used like flags (converted to int and compared with binary operators).
packet::Type now uses uint8_t as underlying type which reduces the network traffic (by default the type was int)

  • Property svn:eol-style set to native
File size: 7.9 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/thread/mutex.hpp>
37
38#include "util/Output.h"
39#include "Acknowledgement.h"
40#include "Chat.h"
41#include "ClassID.h"
42#include "DeleteObjects.h"
43#include "FunctionCalls.h"
44#include "FunctionIDs.h"
45#include "Gamestate.h"
46#include "Welcome.h"
47#include "network/Host.h"
48// #include "network/ClientInformation.h"
49
50namespace orxonox{
51
52namespace packet{
53
54// Make sure we assume the right values
55static_assert(static_cast<int>(PacketFlag::Reliable)    == static_cast<int>(ENET_PACKET_FLAG_RELIABLE),    "check enum");
56static_assert(static_cast<int>(PacketFlag::Unsequenced) == static_cast<int>(ENET_PACKET_FLAG_UNSEQUENCED), "check enum");
57static_assert(static_cast<int>(PacketFlag::NoAllocate)  == static_cast<int>(ENET_PACKET_FLAG_NO_ALLOCATE), "check enum");
58
59#define PACKET_FLAG_DEFAULT PacketFlag::NoAllocate
60#define _PACKETID           0
61
62std::map<size_t, Packet *> Packet::packetMap_;
63boost::mutex Packet::packetMapMutex_;
64
65Packet::Packet()
66{
67  flags_ = PACKET_FLAG_DEFAULT;
68  packetDirection_ = Direction::Outgoing;
69  peerID_=0;
70  data_=nullptr;
71  enetPacket_=nullptr;
72  bDataENetAllocated_ = false;
73}
74
75Packet::Packet(uint8_t *data, unsigned int peerID)
76{
77  flags_ = PACKET_FLAG_DEFAULT;
78  packetDirection_ = Direction::Incoming;
79  peerID_=peerID;
80  data_=data;
81  enetPacket_=nullptr;
82  bDataENetAllocated_ = false;
83}
84
85
86Packet::Packet(const Packet &p)
87{
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_=nullptr;
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{
108  // Deallocate data_ memory if necessary.
109  if (this->bDataENetAllocated_)
110  {
111    // In this case ENet allocated data_ and will destroy it.
112  }
113  else if (this->data_)
114  {
115    // This destructor was probably called as a consequence of ENet executing our callback.
116    // It simply serves us to be able to deallocate the packet content (data_) ourselves since
117    // we have created it in the first place.
118    delete[] this->data_;
119  }
120
121  // Destroy the ENetPacket if necessary.
122  // Note: For the case ENet used the callback to destroy the packet, we have already set
123  // enetPacket_ to nullptr to avoid destroying it again.
124  if (this->enetPacket_)
125  {
126    // enetPacket_->data gets destroyed too by ENet if it was allocated by it.
127    enet_packet_destroy(enetPacket_);
128  }
129}
130
131bool Packet::send(orxonox::Host* host)
132{
133  if(packetDirection_ != Direction::Outgoing && packetDirection_ != Direction::Bidirectional )
134  {
135    assert(0);
136    return false;
137  }
138  if(!enetPacket_)
139  {
140    if(!data_){
141      assert(0);
142      return false;
143    }
144    // We deliver ENet the data address so that it doesn't memcpy everything again.
145    // --> We have to delete data_ ourselves!
146    enetPacket_ = enet_packet_create(getData(), getSize(), getFlags());
147    enetPacket_->freeCallback = &Packet::deletePacket;
148    // Add the packet to a global list so we can access it again once enet calls our
149    // deletePacket method. We can of course only give a one argument function to the ENet C library.
150    {
151      // Assures we don't create a packet and destroy it right after in another thread
152      // without having a reference in the packetMap_
153      Packet::packetMapMutex_.lock();
154      packetMap_[reinterpret_cast<size_t>(enetPacket_)] = this;
155      Packet::packetMapMutex_.unlock();
156    }
157  }
158#ifndef NDEBUG
159  switch( *(Type *)(data_ + _PACKETID) )
160  {
161    case Type::Acknowledgement:
162    case Type::Chat:
163    case Type::ClassID:
164    case Type::Gamestate:
165    case Type::Welcome:
166    case Type::DeleteObjects:
167    case Type::FunctionIDs:
168    case Type::FunctionCalls:
169      break;
170    default:
171      assert(0); //there was some error, if this is the case
172      break;
173  }
174#endif
175//  ENetPacket *temp = enetPacket_;
176//  enetPacket_ = nullptr; // otherwise we have a double free because enet already handles the deallocation of the packet
177  if( this->flags_ & PacketFlag::Reliable )
178    host->addPacket( enetPacket_, peerID_, NETWORK_CHANNEL_DEFAULT);
179  else
180    host->addPacket( enetPacket_, peerID_, NETWORK_CHANNEL_UNRELIABLE);
181  return true;
182}
183
184Packet *Packet::createPacket(ENetPacket* packet, uint32_t peerID)
185{
186  uint8_t *data = packet->data;
187//   assert(ClientInformation::findClient(&peer->address)->getID() != static_cast<unsigned int>(-2) || !Host::isServer());
188//   unsigned int peerID = ClientInformation::findClient(&peer->address)->getID();
189  // HACK
190//   if( peerID==static_cast<unsigned int>(-2))
191//     peerID = NETWORK_PEER_ID_SERVER;
192  Packet *p = nullptr;
193//   orxout(verbose_ultra, context::packets) << "packet type: " << *(Type *)&data[_PACKETID] << endl;
194  switch( *(Type *)(data + _PACKETID) )
195  {
196    case Type::Acknowledgement:
197//       orxout(verbose_more, context::packets) << "ack" << endl;
198    p = new Acknowledgement( data, peerID );
199      break;
200    case Type::Chat:
201//       orxout(verbose_more, context::packets) << "chat" << endl;
202      p = new Chat( data, peerID );
203      break;
204    case Type::ClassID:
205//       orxout(verbose_more, context::packets) << "classid" << endl;
206      p = new ClassID( data, peerID );
207      break;
208    case Type::Gamestate:
209//       orxout(verbose_more, context::packets) << "gamestate" << endl;
210      p = new Gamestate( data, peerID );
211      break;
212    case Type::Welcome:
213//       orxout(verbose_more, context::packets) << "welcome" << endl;
214      p = new Welcome( data, peerID );
215      break;
216    case Type::DeleteObjects:
217//       orxout(verbose_more, context::packets) << "deleteobjects" << endl;
218      p = new DeleteObjects( data, peerID );
219      break;
220    case Type::FunctionCalls:
221//       orxout(verbose_more, context::packets) << "functionCalls" << endl;
222      p = new FunctionCalls( data, peerID );
223      break;
224    case Type::FunctionIDs:
225//       orxout(verbose_more, context::packets) << "functionIDs" << endl;
226      p = new FunctionIDs( data, peerID );
227      break;
228    default:
229      assert(0);
230      break;
231  }
232
233  // Data was created by ENet
234  p->bDataENetAllocated_ = true;
235  p->enetPacket_ = packet;
236
237  return p;
238}
239
240/**
241@brief
242    ENet calls this method whenever it wants to destroy a packet that contains
243    data we allocated ourselves.
244*/
245void Packet::deletePacket(ENetPacket *enetPacket)
246{
247  // Get our Packet from a global map with all Packets created in the send() method of Packet.
248  Packet::packetMapMutex_.lock();
249  std::map<size_t, Packet*>::iterator it = packetMap_.find(reinterpret_cast<size_t>(enetPacket));
250  assert(it != packetMap_.end());
251  // Make sure we don't delete it again in the destructor
252  it->second->enetPacket_ = nullptr;
253  delete it->second;
254  packetMap_.erase(it);
255  Packet::packetMapMutex_.unlock();
256//   orxout(verbose_ultra, context::packets) << "PacketMap size: " << packetMap_.size() << endl;
257}
258
259} // namespace packet
260
261} // namespace orxonox
262
Note: See TracBrowser for help on using the repository browser.