00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #include <QAvatarManager.h>
00033 #include <QAvatarFactory.h>
00034 #include <QAvatarListener.h>
00035 #include <QUANTA/QUANTAnet_datapack_c.hxx>
00036 #include <QUANTA/QUANTAnet_tcpReflector_c.hxx>
00037 #include <QUANTA/QUANTAnet_udp_c.hxx>
00038
00039 #include <assert.h>
00040 #include <string.h>
00041
00042 #include <iostream>
00043 using std::cerr;
00044 using std::endl;
00045
00046 const char QAvatarManager::AUX_MSG = 'a';
00047 const char QAvatarManager::BYE_MSG = 'b';
00048 const char QAvatarManager::HELLO_MSG = 'h';
00049 const char QAvatarManager::TRACKER_MSG = 't';
00050
00051 QAvatarManager::QAvatarManager(QAvatarFactory* factory)
00052 : m_selfAvatar(NULL), m_avatarFactory(factory),
00053 m_noNetworking(false), m_trackerDelay(1.0 / 15.0),
00054 m_hailingTCP(new QUANTAnet_tcpReflectorClient_c),
00055 m_trackerUDP(new QUANTAnet_udp_c)
00056 {
00057
00058 double theTime = QUANTAnet_socketbase_c::getTimeInSecs();
00059 char idStr[256];
00060 sprintf(idStr,"%lf", theTime);
00061
00062
00063 QUANTAmisc_hashWord_t hashVal = QUANTAmisc_hash(idStr, strlen(idStr));
00064 long selfAvatarID = hashVal;
00065 m_selfAvatar = m_avatarFactory->createAvatar(selfAvatarID);
00066 assert(m_selfAvatar != NULL);
00067 m_avatarDB = new QUANTAmisc_hashDict<QAvatar*, long>;
00068
00069 m_selfAvatar->lock();
00070 if ((m_selfAvatar->getHelloDataSize() == 0)
00071 || (m_selfAvatar->getTrackerDataSize() == 0)) {
00072 cerr << "WARNING: QAvatarManager detected uninitialized avatar "
00073 << "hello or tracker data size." << endl;
00074 }
00075
00076
00077 m_hailingBufSize = QUANTAnet_datapack_c::sizeof_char()
00078 + QUANTAnet_datapack_c::sizeof_long()
00079 + (m_selfAvatar->getHelloDataSize() > m_selfAvatar->getAuxDataSize()
00080 ? m_selfAvatar->getHelloDataSize() : m_selfAvatar->getAuxDataSize());
00081 cerr << "AVATAR hailing size: " << m_hailingBufSize << endl;
00082 m_hailingBuffer = new char[m_hailingBufSize];
00083 m_trackerBufSize = QUANTAnet_datapack_c::sizeof_char()
00084 + QUANTAnet_datapack_c::sizeof_long()
00085 + m_selfAvatar->getTrackerDataSize();
00086 cerr << "AVATAR tracker size: " << m_trackerBufSize << endl;
00087 m_trackerBuffer = new char[m_trackerBufSize];
00088 m_tempBuffer = new char[m_selfAvatar->getHelloDataSize()];
00089 m_selfAvatar->unlock();
00090 }
00091
00092 QAvatarManager::~QAvatarManager()
00093 {
00094 delete m_selfAvatar;
00095 delete m_avatarDB;
00096 m_hailingTCP->close();
00097 delete m_hailingTCP;
00098 m_trackerUDP->close();
00099 delete m_trackerUDP;
00100 delete[] m_hailingBuffer;
00101 delete[] m_trackerBuffer;
00102 delete[] m_tempBuffer;
00103 }
00104
00105 void
00106 QAvatarManager::checkForTimeouts()
00107 {
00108
00109 m_avatarDB->lock();
00110 int numItems;
00111 QAvatar** avatarList = m_avatarDB->buildListOfEntries(&numItems);
00112 QAvatar* theAvatar;
00113 if (numItems) {
00114 for (int i = 0; i < numItems; i++) {
00115 theAvatar = avatarList[i];
00116
00117
00118 if ((QUANTAnet_socketbase_c::getTimeInSecs()
00119 - theAvatar->getLastUpdateTime()) > 120) {
00120 m_avatarDB->remove(theAvatar->getID());
00121 cerr << "AVATAR " << avatarList[i]->getID() << "timed out" << endl;
00122
00123 this->notifyBye(theAvatar);
00124 delete theAvatar;
00125 }
00126 }
00127 }
00128 m_avatarDB->unlock();
00129
00130 if (numItems)
00131 delete[] avatarList;
00132 }
00133
00134 bool
00135 QAvatarManager::connect(const char* server, const unsigned short& hailingPort,
00136 const unsigned short& trackerPort)
00137 {
00138
00139 if (m_hailingTCP->connectToServer(server, hailingPort)
00140 != QUANTAnet_tcpReflectorClient_c::OK) {
00141 m_noNetworking = true;
00142 printf("TCP CONNECT FAILED\n");
00143 return false;
00144 }
00145
00146
00147 if (m_trackerUDP->init() != QUANTAnet_udp_c::OK) {
00148 m_noNetworking = true;
00149 printf("UDP CONNECT FAILED\n");
00150 return false;
00151 }
00152 m_trackerUDP->setSendAddress(server, trackerPort);
00153 return true;
00154 }
00155
00156 QAvatar*
00157 QAvatarManager::getSelfAvatar()
00158 {
00159 assert(m_selfAvatar != NULL);
00160 return m_selfAvatar;
00161 }
00162
00163 void
00164 QAvatarManager::attach(QAvatarListener* listener)
00165 {
00166 if (listener != NULL)
00167 m_listeners.push_back(listener);
00168 }
00169
00170 void
00171 QAvatarManager::detach(QAvatarListener* listener)
00172 {
00173 if (listener != NULL)
00174 m_listeners.remove(listener);
00175 }
00176
00177 void
00178 QAvatarManager::process()
00179 {
00180 if (m_noNetworking)
00181 return;
00182
00183 char* hailData = NULL;
00184 int dataSize;
00185 int udpBytesRead;
00186
00187 int status = m_hailingTCP->read(&hailData, &dataSize,
00188 QUANTAnet_tcpReflectorClient_c::NON_BLOCKING);
00189 if (hailData) {
00190 this->handleHailingData(hailData, dataSize);
00191 delete[] hailData;
00192 }
00193
00194 char* buf = new char[m_trackerBufSize];
00195
00196 udpBytesRead = m_trackerUDP->receive(buf, m_trackerBufSize,
00197 QUANTAnet_udp_c::NON_BLOCKING);
00198 if (udpBytesRead > 0)
00199 this->handleTrackerData(buf, udpBytesRead);
00200 delete[] buf;
00201
00202 this->checkForTimeouts();
00203 }
00204
00205 bool
00206 QAvatarManager::sendAux()
00207 {
00208 if (m_noNetworking)
00209 return false;
00210
00211 QUANTAnet_datapack_c datapack;
00212 datapack.initPack(m_hailingBuffer, m_hailingBufSize);
00213 datapack.packChar(QAvatarManager::AUX_MSG);
00214 datapack.packLong(m_selfAvatar->getID());
00215 m_selfAvatar->lock();
00216 datapack.pack(m_selfAvatar->getAuxData(), m_selfAvatar->getAuxDataSize());
00217 m_selfAvatar->unlock();
00218
00219 int bufSize = datapack.getBufferFilledSize();
00220 if (m_hailingTCP->write(m_hailingBuffer, &bufSize)
00221 == QUANTAnet_tcpReflectorClient_c::OK)
00222 return true;
00223
00224 return false;
00225 }
00226
00227 bool
00228 QAvatarManager::sendBye()
00229 {
00230 if (m_noNetworking)
00231 return false;
00232
00233 QUANTAnet_datapack_c datapack;
00234 datapack.initPack(m_hailingBuffer, m_hailingBufSize);
00235 datapack.packChar(QAvatarManager::BYE_MSG);
00236 datapack.packLong(m_selfAvatar->getID());
00237
00238 int bufSize = datapack.getBufferFilledSize();
00239 if (m_hailingTCP->write(m_hailingBuffer, &bufSize)
00240 == QUANTAnet_tcpReflectorClient_c::OK)
00241 return true;
00242
00243 return false;
00244 }
00245
00246 bool
00247 QAvatarManager::sendHello()
00248 {
00249 if (m_noNetworking)
00250 return false;
00251
00252 QUANTAnet_datapack_c datapack;
00253 datapack.initPack(m_hailingBuffer, m_hailingBufSize);
00254 datapack.packChar(QAvatarManager::HELLO_MSG);
00255 datapack.packLong(m_selfAvatar->getID());
00256 m_selfAvatar->lock();
00257 datapack.pack(m_selfAvatar->getHelloData(),
00258 m_selfAvatar->getHelloDataSize());
00259 m_selfAvatar->unlock();
00260
00261 int bufSize = datapack.getBufferFilledSize();
00262
00263 if (m_hailingTCP->write(m_hailingBuffer, &bufSize)
00264 == QUANTAnet_tcpReflectorClient_c::OK)
00265 return true;
00266
00267 return false;
00268 }
00269
00270 bool
00271 QAvatarManager::sendTracker()
00272 {
00273 if (m_noNetworking)
00274 return false;
00275
00276 double currentTime = QUANTAnet_socketbase_c::getTimeInSecs();
00277 if ((currentTime - m_lastTimeTrackerSent) < m_trackerDelay) {
00278 return true;
00279 }
00280
00281 QUANTAnet_datapack_c datapack;
00282 datapack.initPack(m_trackerBuffer, m_trackerBufSize);
00283 datapack.packChar(QAvatarManager::TRACKER_MSG);
00284 datapack.packLong(m_selfAvatar->getID());
00285 m_selfAvatar->lock();
00286 datapack.pack(m_selfAvatar->getTrackerData(),
00287 m_selfAvatar->getTrackerDataSize());
00288 m_selfAvatar->unlock();
00289
00290 int bufSize = datapack.getBufferFilledSize();
00291
00292 if (m_trackerUDP->send(m_trackerBuffer, bufSize, QUANTAnet_udp_c::BLOCKING)
00293 == QUANTAnet_udp_c::OK) {
00294 m_lastTimeTrackerSent = currentTime;
00295 return true;
00296 }
00297
00298 return false;
00299 }
00300
00301 void
00302 QAvatarManager::setTrackerUpdateDelay(const double& delay)
00303 {
00304 assert(delay >= 0.0);
00305 m_trackerDelay = delay;
00306 }
00307
00308 void
00309 QAvatarManager::handleHailingData(char* dataBuf, const size_t& dataSize)
00310 {
00311 if (dataSize == 0)
00312 return;
00313
00314 printf("AVATAR: HailingCB\n");
00315 m_avatarDB->lock();
00316
00317 QUANTAnet_datapack_c datapack;
00318
00319
00320 datapack.initUnpack(dataBuf, dataSize);
00321 char command;
00322 datapack.unpackChar(&command);
00323 long avatarID;
00324 datapack.unpackLong(&avatarID);
00325
00326
00327 QAvatar* theQAvatar;
00328 m_avatarDB->find(avatarID, theQAvatar);
00329
00330 if (command == QAvatarManager::HELLO_MSG) {
00331 if (!theQAvatar) {
00332
00333
00334
00335 theQAvatar = m_avatarFactory->createAvatar(avatarID);
00336
00337
00338 if (!theQAvatar) {
00339 printf("AVATAR: Unable to allocate new entry for avatar.\n");
00340 }
00341
00342
00343 theQAvatar->markUpdateTime();
00344
00345
00346 m_avatarDB->enter(avatarID, theQAvatar);
00347
00348
00349 datapack.unpack(m_tempBuffer, 1024);
00350 theQAvatar->setHelloData(m_tempBuffer, 1024);
00351
00352 printf("AVATAR: new avatar arrived %d\n", avatarID);
00353
00354
00355 this->notifyArrive(theQAvatar);
00356
00357
00358 if (command == QAvatarManager::HELLO_MSG) {
00359 this->sendHello();
00360 }
00361
00362 } else {
00363
00364
00365 theQAvatar->markUpdateTime();
00366
00367
00368 datapack.unpack(m_tempBuffer, 1024);
00369
00370
00371 if (memcmp(m_tempBuffer, theQAvatar->getHelloData(), 1024)) {
00372
00373
00374 theQAvatar->setHelloData(m_tempBuffer, 1024);
00375
00376
00377 this->notifyHello(theQAvatar);
00378 }
00379 }
00380
00381 } else if (command == QAvatarManager::BYE_MSG) {
00382
00383 if (!theQAvatar) {
00384 m_avatarDB->unlock();
00385 return;
00386 }
00387
00388
00389
00390 m_avatarDB->remove(avatarID);
00391 this->notifyBye(theQAvatar);
00392 delete theQAvatar;
00393
00394 } else if (command == QAvatarManager::AUX_MSG) {
00395
00396 if (!theQAvatar) {
00397 m_avatarDB->unlock();
00398 return;
00399 }
00400
00401
00402 theQAvatar->markUpdateTime();
00403
00404 datapack.unpack(m_tempBuffer, 1024);
00405 theQAvatar->setAuxData(m_tempBuffer, 1024);
00406
00407
00408 this->notifyAux(theQAvatar);
00409 }
00410
00411 m_avatarDB->unlock();
00412 }
00413
00414 void
00415 QAvatarManager::handleTrackerData(char* dataBuf, const size_t& dataSize)
00416 {
00417
00418
00419
00420
00421
00422
00423
00424 QUANTAnet_datapack_c datapack;
00425
00426 datapack.initUnpack(dataBuf, dataSize);
00427 char command;
00428 datapack.unpackChar(&command);
00429 long avatarID;
00430 datapack.unpackLong(&avatarID);
00431
00432
00433 QAvatar* theQAvatar;
00434 m_avatarDB->lock();
00435 m_avatarDB->find(avatarID, theQAvatar);
00436 m_avatarDB->unlock();
00437
00438
00439 if (!theQAvatar) {
00440 return;
00441 }
00442
00443
00444 if (command == QAvatarManager::TRACKER_MSG) {
00445 theQAvatar->markUpdateTime();
00446
00447 datapack.unpack(m_tempBuffer, 1024);
00448 this->notifyTracker(theQAvatar);
00449 }
00450 }
00451
00452 void
00453 QAvatarManager::notifyArrive(QAvatar* theQAvatar)
00454 {
00455 for (ListenerList::iterator i = m_listeners.begin();
00456 i != m_listeners.end(); i++) {
00457 (*i)->avatarArrive(theQAvatar);
00458 }
00459 }
00460
00461 void
00462 QAvatarManager::notifyAux(QAvatar* theQAvatar)
00463 {
00464 for (ListenerList::iterator i = m_listeners.begin();
00465 i != m_listeners.end(); i++) {
00466 (*i)->avatarAux(theQAvatar);
00467 }
00468 }
00469
00470 void
00471 QAvatarManager::notifyBye(QAvatar* theQAvatar)
00472 {
00473 for (ListenerList::iterator i = m_listeners.begin();
00474 i != m_listeners.end(); i++) {
00475 (*i)->avatarBye(theQAvatar);
00476 }
00477 }
00478
00479 void
00480 QAvatarManager::notifyHello(QAvatar* theQAvatar)
00481 {
00482 for (ListenerList::iterator i = m_listeners.begin();
00483 i != m_listeners.end(); i++) {
00484 (*i)->avatarHello(theQAvatar);
00485 }
00486 }
00487
00488 void
00489 QAvatarManager::notifyTracker(QAvatar* theQAvatar)
00490 {
00491 for (ListenerList::iterator i = m_listeners.begin();
00492 i != m_listeners.end(); i++) {
00493 (*i)->avatarTracker(theQAvatar);
00494 }
00495 }