Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/lib/network/message_manager.cc @ 7681

Last change on this file since 7681 was 7681, checked in by rennerc, 18 years ago

finished and tested MessageManager

File size: 8.3 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      (*(messageHandlerMap[(MessageId)messageId].cb))( (MessageId)messageId, data + i, messageLength, messageHandlerMap[(MessageId)messageId].someData, userId );
187      messageQueue[userId].recievedMessages.push_back( number );
188    }
189    i += messageLength;
190  }
191 
192 
193  //walk throu message queue and remove acked messages
194  for ( std::list<NetworkMessage>::iterator it = messageQueue[userId].messages.begin(); it != messageQueue[userId].messages.end();  )
195  {
196    if ( std::find( acks.begin(), acks.end(), it->number) != acks.end() )
197    {
198      std::list<NetworkMessage>::iterator delIt = it;
199      it++;
200      messageQueue[userId].messages.erase( delIt );
201      continue;
202    }
203    it++;
204  }
205 
206  //TODO find bether way. maybe with timestamp
207  if ( messageQueue[userId].recievedMessages.size() > 1000 )
208  {
209    for ( int j = 0; j < messageQueue[userId].recievedMessages.size() - 1000; j++ )
210      messageQueue[userId].recievedMessages.erase( messageQueue[userId].recievedMessages.begin() );
211  }
212
213  return i;
214}
215
216/**
217 * clean up memory reserved for user
218 * @param userId userid
219 */
220void MessageManager::cleanUpUser( int userId )
221{
222  if ( messageQueue.find( userId ) == messageQueue.end() )
223    return;
224   
225  for ( std::list<NetworkMessage>::iterator it = messageQueue[userId].messages.begin(); it != messageQueue[userId].messages.end(); it++ )
226  {
227    if ( it->data )
228      delete it->data;
229    it->data = NULL;
230  }
231 
232  messageQueue[userId].toAck.clear();
233 
234  messageQueue.erase( userId );
235}
236
237/**
238 * registers function to handle messages with id messageId. someData is passed to callbackfuntion
239 * @param messageId message id to handle
240 * @param cb function pointer to callback function
241 * @param someData this pointer is passed to callback function without modification
242 * @return true on success
243 */
244bool MessageManager::registerMessageHandler( MessageId messageId, MessageCallback cb, void * someData )
245{
246  MessageHandler messageHandler;
247 
248  messageHandler.cb = cb;
249  messageHandler.messageId = messageId;
250  messageHandler.someData = someData;
251 
252  messageHandlerMap[messageId] = messageHandler;
253 
254  return true;
255}
256
257/**
258 * initializes buffers for user
259 * @param userId userId
260 */
261void MessageManager::initUser( int userId )
262{
263  // just do something so map creates a new entry
264  messageQueue[userId].toAck.clear();
265  assert( messageQueue[userId].messages.size() == 0 );
266}
267
268/**
269 * send a message to one or more clients
270 * recieverType:
271 *               RT_ALL send to all users. reciever is ignored
272 *               RT_USER send only to reciever
273 *               RT_NOT_USER send to all but reciever
274 *
275 * @param messageId message id
276 * @param data pointer to data
277 * @param dataLength length of data
278 * @param recieverType
279 * @param reciever
280 */
281void MessageManager::sendMessage( MessageId messageId, byte * data, int dataLength, RecieverType recieverType, int reciever, MessagePriority messagePriority )
282{
283  for ( MessageQueue::iterator it = messageQueue.begin(); it != messageQueue.end(); it++ )
284  {
285    if ( 
286         recieverType == RT_ALL ||
287         recieverType == RT_USER && it->first == reciever ||
288         recieverType == RT_NOT_USER && it->first != reciever
289       )
290    {
291      NetworkMessage msg;
292     
293      msg.data = new byte[dataLength];
294      memcpy( msg.data, data, dataLength );
295      msg.length = dataLength;
296      msg.messageId = messageId;
297      msg.number = newNumber++;
298      msg.priority = messagePriority;
299     
300      it->second.messages.push_back( msg );
301    }
302  }
303}
304
305
Note: See TracBrowser for help on using the repository browser.