Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/network/message_manager.cc @ 8058

Last change on this file since 8058 was 7954, checked in by patrick, 18 years ago

trunk: merged the network branche back to trunk.

File size: 9.0 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Christoph Renner
13   co-programmer: ...
14*/
15
16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
17
18#include "message_manager.h"
19
20using namespace std;
21
22MessageManager* MessageManager::singletonRef = NULL;
23
24
25/**
26 * standard constructor
27*/
28MessageManager::MessageManager ()
29{
30  this->setClassID( CL_MESSAGE_MANAGER, "MessageManager" );
31  newNumber = 1;
32  setSynchronized( true );
33}
34
35
36/**
37 * standard deconstructor
38*/
39MessageManager::~MessageManager ()
40{
41  for ( MessageQueue::iterator it = messageQueue.begin(); it != messageQueue.end(); it++ )
42  {
43    for ( std::list<NetworkMessage>::iterator it2 = it->second.messages.begin(); it2 != it->second.messages.end(); it2++ )
44    {
45      if ( it2->data )
46      {
47        delete it2->data;
48        it2->data = NULL;
49      }
50    }
51   
52    it->second.messages.clear();
53    it->second.toAck.clear();
54  }
55 
56  messageQueue.clear();
57}
58
59/**
60 * get the diff to last acked state of userId
61 *
62 * this class does not use the normal SynchronizeableVars for zynchronisation. instead
63 * it defines its own protocol
64 *
65 * @param userId user to create diff for
66 * @param data buffer to copy diff in
67 * @param maxLength max bytes to copy into data
68 * @param stateId id of current state
69 * @param fromStateId the reference state for the delta state
70 * @param priorityTH tells getStateDiff to not send element with priority \< priorityTH
71 * @return n bytes copied into data
72 */
73int MessageManager::getStateDiff( int userId, byte * data, int maxLength, int stateId, int fromStateId, int priorityTH )
74{
75  int i = 0;
76  int n;
77 
78  n = Converter::intToByteArray( messageQueue[userId].toAck.size(), data + i, maxLength );
79  i += n;
80  assert( n == INTSIZE );
81 
82  for ( std::list<int>::iterator it = messageQueue[userId].toAck.begin(); it != messageQueue[userId].toAck.end(); it++)
83  {
84    n = Converter::intToByteArray( *it, data + i, maxLength );
85    i += n;
86    assert( n == INTSIZE );
87  }
88 
89  messageQueue[userId].toAck.clear();
90 
91  n = Converter::intToByteArray( messageQueue[userId].messages.size(), data + i, maxLength );
92  i += n;
93  assert( n == INTSIZE );
94 
95  for ( std::list<NetworkMessage>::iterator it = messageQueue[userId].messages.begin(); it != messageQueue[userId].messages.end(); it++ )
96  {
97    n = Converter::intToByteArray( it->length, data + i, maxLength );
98    i += n;
99    assert( n == INTSIZE );
100   
101    n = Converter::intToByteArray( it->number, data + i, maxLength );
102    i += n;
103    assert( n == INTSIZE );
104   
105    n = Converter::intToByteArray( it->messageId, data + i, maxLength );
106    i += n;
107    assert( n == INTSIZE );
108   
109    assert( i + it->length <= maxLength );
110    memcpy( data + i, it->data, it->length );
111    i += it->length;
112  }
113 
114  return i;
115}
116
117/**
118 * sets a new state out of a diff created on another host
119 * @param userId hostId of user who send me that diff
120 * @param data pointer to diff
121 * @param length length of diff
122 * @param stateId id of current state
123 * @param fromStateId id of the base state id
124 * @return number bytes read
125 * @todo check for permissions
126 */
127int MessageManager::setStateDiff( int userId, byte * data, int length, int stateId, int fromStateId )
128{
129  int i = 0;
130  int n;
131 
132  int nAcks;
133 
134  assert( i + INTSIZE <= length );
135  n = Converter::byteArrayToInt( data + i, &nAcks );
136  assert( n == INTSIZE );
137  i += n;
138 
139  std::list<int> acks;
140 
141  int number;
142 
143  for ( int j = 0; j < nAcks; j++ )
144  {
145    assert( i + INTSIZE <= length );
146    n = Converter::byteArrayToInt( data + i, &number );
147    assert( n == INTSIZE );
148    i += n;
149   
150    acks.push_back( number );
151  }
152 
153  int nMessages;
154 
155  assert( i + INTSIZE <= length );
156  n = Converter::byteArrayToInt( data + i, &nMessages );
157  assert( n == INTSIZE );
158  i += n;
159
160  int messageLength, messageId;
161 
162  for ( int j = 0; j < nMessages; j++ )
163  {
164    assert( i + INTSIZE <= length );
165    n = Converter::byteArrayToInt( data + i, &messageLength );
166    assert( n == INTSIZE );
167    i += n;
168   
169    assert( i + INTSIZE <= length );
170    n = Converter::byteArrayToInt( data + i, &number );
171    assert( n == INTSIZE );
172    i += n;
173 
174    assert( i + INTSIZE <= length );
175    n = Converter::byteArrayToInt( data + i, &messageId );
176    assert( n == INTSIZE );
177    i += n;
178   
179    if ( number > 0 )
180      messageQueue[userId].toAck.push_back( number );
181   
182    assert( i + messageLength <= length );
183    assert( messageHandlerMap.find( (MessageId)messageId ) != messageHandlerMap.end() );
184    if ( std::find( messageQueue[userId].recievedMessages.begin(), messageQueue[userId].recievedMessages.end(), number )== messageQueue[userId].recievedMessages.end() )
185    {
186      if ( !(*(messageHandlerMap[(MessageId)messageId].cb))( (MessageId)messageId, data + i, messageLength, messageHandlerMap[(MessageId)messageId].someData, userId ) )
187      {
188        NetworkMessage msg;
189       
190        msg.data = new byte[messageLength];
191        memcpy( msg.data, data + i, messageLength );
192        msg.length = messageLength;
193        msg.messageId = (MessageId)messageId;
194        msg.number = userId;
195       
196        incomingMessabeBuffer.push_back( msg );
197      }
198      messageQueue[userId].recievedMessages.push_back( number );
199    }
200    i += messageLength;
201  }
202 
203 
204  for ( std::list<NetworkMessage>::iterator it = incomingMessabeBuffer.begin(); it != incomingMessabeBuffer.end();  )
205  {
206    if ( (*(messageHandlerMap[it->messageId].cb))( it->messageId, it->data, it->length, messageHandlerMap[it->messageId].someData, it->number ) )
207    {
208      std::list<NetworkMessage>::iterator delIt = it;
209      if ( it->data )
210        delete it->data;
211      it++;
212      incomingMessabeBuffer.erase( delIt );
213      continue;
214    }
215    it++;
216  }
217 
218  //walk throu message queue and remove acked messages
219  for ( std::list<NetworkMessage>::iterator it = messageQueue[userId].messages.begin(); it != messageQueue[userId].messages.end();  )
220  {
221    if ( std::find( acks.begin(), acks.end(), it->number) != acks.end() )
222    {
223      std::list<NetworkMessage>::iterator delIt = it;
224      it++;
225      messageQueue[userId].messages.erase( delIt );
226      continue;
227    }
228    it++;
229  }
230 
231  //TODO find bether way. maybe with timestamp
232  if ( messageQueue[userId].recievedMessages.size() > 1000 )
233  {
234    for ( int j = 0; j < messageQueue[userId].recievedMessages.size() - 1000; j++ )
235      messageQueue[userId].recievedMessages.erase( messageQueue[userId].recievedMessages.begin() );
236  }
237
238  return i;
239}
240
241/**
242 * clean up memory reserved for user
243 * @param userId userid
244 */
245void MessageManager::cleanUpUser( int userId )
246{
247  if ( messageQueue.find( userId ) == messageQueue.end() )
248    return;
249   
250  for ( std::list<NetworkMessage>::iterator it = messageQueue[userId].messages.begin(); it != messageQueue[userId].messages.end(); it++ )
251  {
252    if ( it->data )
253      delete it->data;
254    it->data = NULL;
255  }
256 
257  messageQueue[userId].toAck.clear();
258 
259  messageQueue.erase( userId );
260}
261
262/**
263 * registers function to handle messages with id messageId. someData is passed to callbackfuntion
264 * @param messageId message id to handle
265 * @param cb function pointer to callback function
266 * @param someData this pointer is passed to callback function without modification
267 * @return true on success
268 */
269bool MessageManager::registerMessageHandler( MessageId messageId, MessageCallback cb, void * someData )
270{
271  MessageHandler messageHandler;
272 
273  messageHandler.cb = cb;
274  messageHandler.messageId = messageId;
275  messageHandler.someData = someData;
276 
277  messageHandlerMap[messageId] = messageHandler;
278 
279  return true;
280}
281
282/**
283 * initializes buffers for user
284 * @param userId userId
285 */
286void MessageManager::initUser( int userId )
287{
288  // just do something so map creates a new entry
289  messageQueue[userId].toAck.clear();
290  //assert( messageQueue[userId].messages.size() == 0 );
291}
292
293/**
294 * send a message to one or more clients
295 * recieverType:
296 *               RT_ALL send to all users. reciever is ignored
297 *               RT_USER send only to reciever
298 *               RT_NOT_USER send to all but reciever
299 *
300 * @param messageId message id
301 * @param data pointer to data
302 * @param dataLength length of data
303 * @param recieverType
304 * @param reciever
305 */
306void MessageManager::sendMessage( MessageId messageId, byte * data, int dataLength, RecieverType recieverType, int reciever, MessagePriority messagePriority )
307{
308  for ( MessageQueue::iterator it = messageQueue.begin(); it != messageQueue.end(); it++ )
309  {
310    if ( 
311         recieverType == RT_ALL ||
312         recieverType == RT_USER && it->first == reciever ||
313         recieverType == RT_NOT_USER && it->first != reciever
314       )
315    {
316      NetworkMessage msg;
317     
318      msg.data = new byte[dataLength];
319      memcpy( msg.data, data, dataLength );
320      msg.length = dataLength;
321      msg.messageId = messageId;
322      msg.number = newNumber++;
323      msg.priority = messagePriority;
324     
325      it->second.messages.push_back( msg );
326    }
327  }
328}
329
330
Note: See TracBrowser for help on using the repository browser.