Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/network/packet/Packet.cc @ 9525

Last change on this file since 9525 was 8807, checked in by landauf, 13 years ago

Replaced COUT with orxout in network library. Tried to set levels and contexts in a more or less useful way, but not really optimized. Used contexts network, packets, and master_server.
Please use endl instead of \n in the future (@smerkli) ;)

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