Main Page | Class Hierarchy | Class List | File List | Class Members

QAvatarManager.cxx

00001 
00002 //
00003 // $Id: QAvatarManager.cxx,v 1.9 2004/03/26 21:20:02 scharver Exp $
00004 //
00005 // Author: Chris Scharver
00006 // Email: scharver@evl.uic.edu
00007 // Copyright (c) 2003 Electronic Visualization Laboratory,
00008 //                    University of Illinois at Chicago
00009 //
00010 // Permission is hereby granted, free of charge, to any person
00011 // obtaining a copy of this software and associated documentation
00012 // files (the "Software"), to deal in the Software without
00013 // restriction, including without limitation the rights to use, copy,
00014 // modify, merge, publish, distribute, sublicense, and/or sell copies
00015 // of the Software, and to permit persons to whom the Software is
00016 // furnished to do so, subject to the following conditions:
00017 //
00018 // The above copyright notice and this permission notice shall be
00019 // included in all copies or substantial portions of the Software.
00020 //
00021 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00022 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00023 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00024 // NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00025 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00026 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00027 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00028 // DEALINGS IN THE SOFTWARE.
00029 //
00031 
00032 #include <QUANTA/QUANTAnet_datapack_c.hxx>
00033 #include <QUANTA/QUANTAnet_tcpReflector_c.hxx>
00034 #include <QUANTA/QUANTAnet_udp_c.hxx>
00035 
00036 #include <QAvatarManager.h>
00037 #include <QAvatarFactory.h>
00038 #include <QAvatarListener.h>
00039 
00040 #include <assert.h>
00041 #include <string.h>
00042 
00043 #ifdef USE_STL_NAMESPACE
00044 #include <iostream>
00045 using std::cerr;
00046 using std::cout;
00047 using std::endl;
00048 #else /* USE_STL_NAMESPACE */
00049 #include <iostream.h>
00050 #endif /* USE_STL_NAMESPACE */
00051 
00052 const char QAvatarManager::AUX_MSG = 'a';
00053 const char QAvatarManager::BYE_MSG = 'b';
00054 const char QAvatarManager::HELLO_MSG = 'h';
00055 const char QAvatarManager::TRACKER_MSG = 't';
00056 
00057 QAvatarManager::QAvatarManager(QAvatarFactory* factory)
00058   : m_avatarDB(NULL), m_selfAvatar(NULL),
00059     m_avatarFactory(factory),
00060     m_hailingTCP(NULL),
00061     m_trackerUDP(NULL),
00062     m_hailingBuffer(NULL), m_trackerBuffer(NULL),
00063     m_noNetworking(false), m_trackerDelay(0.25), //1.0 / 15.0),
00064     m_tempBuffer(NULL)
00065 {
00066   m_hailingTCP = new QUANTAnet_tcpReflectorClient_c;
00067   m_trackerUDP = new QUANTAnet_udp_c;
00068   // Generate an avatar ID based on the current time.
00069   double theTime = QUANTAnet_socketbase_c::getTimeInSecs();
00070   char idStr[256];
00071   sprintf(idStr,"%lf", theTime);
00072 
00073   // Hash the time into a unique 4 byte number.
00074   QUANTAmisc_hashWord_t hashVal = QUANTAmisc_hash(idStr, strlen(idStr)+1);
00075   long selfAvatarID = hashVal;
00076   m_selfAvatar = m_avatarFactory->createAvatar(selfAvatarID);
00077   assert(m_selfAvatar != NULL);
00078   m_avatarDB = new QUANTAmisc_hashDict<QAvatar*, long>;
00079 
00080   m_selfAvatar->lock();
00081   if ((m_selfAvatar->getHelloDataSize() == 0)
00082       || (m_selfAvatar->getTrackerDataSize() == 0)) {
00083     cerr << "WARNING: QAvatarManager detected uninitialized avatar "
00084          << "hello or tracker data size." << endl;
00085   }
00086 
00087   // Allocate memory for packing and sending hello and trackerdata.
00088   m_hailingBufSize = QUANTAnet_datapack_c::sizeof_char()
00089     + QUANTAnet_datapack_c::sizeof_long()
00090     + (m_selfAvatar->getHelloDataSize() > m_selfAvatar->getAuxDataSize()
00091        ? m_selfAvatar->getHelloDataSize() : m_selfAvatar->getAuxDataSize());
00092   cout << "AVATAR hailing size: " << m_hailingBufSize << endl;
00093   m_hailingBuffer = new char[m_hailingBufSize];
00094   m_trackerBufSize = QUANTAnet_datapack_c::sizeof_char()
00095     + QUANTAnet_datapack_c::sizeof_long()
00096     + m_selfAvatar->getTrackerDataSize();
00097   cout << "AVATAR tracker size: " << m_trackerBufSize << endl;
00098   m_trackerBuffer = new char[m_trackerBufSize];
00099   m_tempBuffer = new char[m_selfAvatar->getHelloDataSize()];
00100   m_selfAvatar->unlock();
00101 }
00102 
00103 QAvatarManager::~QAvatarManager()
00104 {
00105   // Close the TCP and UDP connections.
00106   m_hailingTCP->close();
00107   m_trackerUDP->close();
00108 
00109   delete m_selfAvatar;
00110   delete m_avatarDB;
00111   delete m_hailingTCP;
00112   delete m_trackerUDP;
00113   delete[] m_hailingBuffer;
00114   delete[] m_trackerBuffer;
00115   delete[] m_tempBuffer;
00116 }
00117 
00118 void
00119 QAvatarManager::checkForTimeouts()
00120 {
00121   // Every 60 seconds check for dead avatars.
00122   m_avatarDB->lock();
00123   int numItems;
00124   QAvatar** avatarList = m_avatarDB->buildListOfEntries(&numItems);
00125   QAvatar* theAvatar;
00126   if (numItems) {
00127     for (int i = 0; i < numItems; i++) {
00128       theAvatar = avatarList[i];
00129       // If there are avatars that have not been refreshed in
00130       // 2 minutes purge them.
00131       if ((QUANTAnet_socketbase_c::getTimeInSecs()
00132            - theAvatar->getLastUpdateTime()) > 120) {
00133         m_avatarDB->remove(theAvatar->getID());
00134         cout << "AVATAR " << avatarList[i]->getID() << " timed out" << endl;
00135         // Call user callback
00136         this->notifyBye(theAvatar);
00137         delete theAvatar;
00138       }
00139     }
00140   }
00141   m_avatarDB->unlock();
00142 
00143   if (numItems)
00144     delete[] avatarList;
00145 }
00146 
00147 bool
00148 QAvatarManager::connect(const char* server, const unsigned short& hailingPort,
00149                         const unsigned short& trackerPort)
00150 {
00151   // Open the TCP channel for avatar hailing.
00152   if (m_hailingTCP->connectToServer(server, hailingPort)
00153       == QUANTAnet_tcpReflectorClient_c::OK) {
00154     cout << "AVATAR hailing channel connected to "
00155          << server << ':'<< hailingPort << endl;
00156   } else {
00157     m_noNetworking = true;
00158     cerr << "AVATAR TCP CONNECT FAILED" << endl;
00159     return false;
00160   }
00161 
00162   // Open the UDP channel for tracker information.
00163   m_trackerUDP->setSendAddress(server, trackerPort);
00164   if (m_trackerUDP->init() == QUANTAnet_udp_c::OK) {
00165     cout << "AVATAR tracker channel connected to "
00166          << server << ':'<< trackerPort << endl;
00167   } else {
00168     m_noNetworking = true;
00169     cerr << "AVATAR UDP CONNECT FAILED" << endl;
00170     return false;
00171   }
00172   return true;
00173 }
00174 
00175 QAvatar*
00176 QAvatarManager::getSelfAvatar()
00177 {
00178   assert(m_selfAvatar != NULL);
00179   return m_selfAvatar;
00180 }
00181 
00182 void
00183 QAvatarManager::attach(QAvatarListener* listener)
00184 {
00185   if (listener != NULL)
00186     m_listeners.push_back(listener);
00187 }
00188 
00189 void
00190 QAvatarManager::detach(QAvatarListener* listener)
00191 {
00192   if (listener != NULL)
00193     m_listeners.remove(listener);
00194 }
00195 
00196 void
00197 QAvatarManager::process()
00198 {
00199   if (m_noNetworking)
00200     return;
00201 
00202   char* hailData = NULL;
00203   int dataSize;
00204   int udpBytesRead;
00205 
00206   int status  = m_hailingTCP->read(&hailData, &dataSize,
00207                                    QUANTAnet_tcpReflectorClient_c::NON_BLOCKING);
00208   if (hailData) {
00209     this->handleHailingData(hailData, dataSize);
00210     delete[] hailData;
00211   }
00212 
00213   char* buf = new char[m_trackerBufSize];
00214 
00215   udpBytesRead = m_trackerUDP->receive(buf, m_trackerBufSize,
00216                                        QUANTAnet_udp_c::NON_BLOCKING);
00217   if (udpBytesRead > 0)
00218     this->handleTrackerData(buf, udpBytesRead);
00219   delete[] buf;
00220 
00221   this->checkForTimeouts();
00222 }
00223 
00224 bool
00225 QAvatarManager::sendAux()
00226 {
00227   if (m_noNetworking)
00228     return false;
00229 
00230   QUANTAnet_datapack_c datapack;
00231   datapack.initPack(m_hailingBuffer, m_hailingBufSize);
00232   datapack.packChar(QAvatarManager::AUX_MSG);
00233   datapack.packLong(m_selfAvatar->getID());
00234   m_selfAvatar->lock();
00235   datapack.pack(m_selfAvatar->getAuxData(), m_selfAvatar->getAuxDataSize());
00236   m_selfAvatar->unlock();
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::sendBye()
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::BYE_MSG);
00255   datapack.packLong(m_selfAvatar->getID());
00256 
00257   int bufSize = datapack.getBufferFilledSize();
00258   if (m_hailingTCP->write(m_hailingBuffer, &bufSize)
00259       == QUANTAnet_tcpReflectorClient_c::OK)
00260     return true;
00261 
00262   return false;
00263 }
00264 
00265 bool
00266 QAvatarManager::sendHello()
00267 {
00268   if (m_noNetworking)
00269     return false;
00270 
00271   QUANTAnet_datapack_c datapack;
00272   datapack.initPack(m_hailingBuffer, m_hailingBufSize);
00273   datapack.packChar(QAvatarManager::HELLO_MSG);
00274   datapack.packLong(m_selfAvatar->getID());
00275   m_selfAvatar->lock();
00276   datapack.pack(m_selfAvatar->getHelloData(),
00277                 m_selfAvatar->getHelloDataSize());
00278   m_selfAvatar->unlock();
00279 
00280   int bufSize = datapack.getBufferFilledSize();
00281 
00282   if (m_hailingTCP->write(m_hailingBuffer, &bufSize)
00283       == QUANTAnet_tcpReflectorClient_c::OK)
00284     return true;
00285 
00286   return false;
00287 }
00288 
00289 bool
00290 QAvatarManager::sendTracker()
00291 {
00292   if (m_noNetworking)
00293     return false;
00294 
00295   double currentTime = QUANTAnet_socketbase_c::getTimeInSecs();
00296   if ((currentTime - m_lastTimeTrackerSent) < m_trackerDelay) {
00297     return true;
00298   }
00299 
00300   QUANTAnet_datapack_c datapack;
00301   datapack.initPack(m_trackerBuffer, m_trackerBufSize);
00302   datapack.packChar(QAvatarManager::TRACKER_MSG);
00303   datapack.packLong(m_selfAvatar->getID());
00304   m_selfAvatar->lock();
00305   datapack.pack(m_selfAvatar->getTrackerData(),
00306                 m_selfAvatar->getTrackerDataSize());
00307   m_selfAvatar->unlock();
00308 
00309   int bufSize = datapack.getBufferFilledSize();
00310 
00311   if (m_trackerUDP->send(m_trackerBuffer, bufSize, QUANTAnet_udp_c::NON_BLOCKING)
00312       != -1) {
00313     m_lastTimeTrackerSent = currentTime;
00314     return true;
00315   } else {
00316     cerr << "AVATAR tracker data was not sent!" << endl;
00317   }
00318 
00319   return false;
00320 }
00321 
00322 void
00323 QAvatarManager::setTrackerUpdateDelay(const double& delay)
00324 {
00325   assert(delay >= 0.0);
00326   m_trackerDelay = delay;
00327 }
00328 
00329 void
00330 QAvatarManager::handleHailingData(char* dataBuf, const size_t& dataSize)
00331 {
00332   if (dataSize == 0)
00333     return;
00334 
00335   cout << "AVATAR: HailingCB" << endl;
00336   m_avatarDB->lock();
00337  
00338   QUANTAnet_datapack_c datapack;
00339   
00340   // Extract command and avatar id
00341   datapack.initUnpack(dataBuf, dataSize);
00342   char command;
00343   datapack.unpackChar(&command);
00344   long avatarID;
00345   datapack.unpackLong(&avatarID);
00346  
00347   // Look for the avatar.
00348   QAvatar* theQAvatar;
00349   m_avatarDB->find(avatarID, theQAvatar);
00350 
00351   if (command == QAvatarManager::HELLO_MSG) {
00352     if (!theQAvatar) {
00353 
00354       // The avatar does not yet exist in the database, so therefore
00355       // it's a new avatar!
00356       theQAvatar = m_avatarFactory->createAvatar(avatarID);
00357       //, itsTrackerDataSize, itsHelloDataSize, itsAuxDataSize);
00358 
00359       if (!theQAvatar) {
00360         cerr << "AVATAR: Unable to allocate new entry for avatar." << endl;
00361       }
00362 
00363       // Refresh the timer so that this avatar does not get garbage collected.
00364       theQAvatar->markUpdateTime();
00365 
00366       // Store avatar in avatar database
00367       m_avatarDB->enter(avatarID, theQAvatar);
00368 
00369       // Unpack the avatar's hello data.
00370       datapack.unpack(m_tempBuffer, m_selfAvatar->getHelloDataSize());
00371       theQAvatar->setHelloData(m_tempBuffer, m_selfAvatar->getHelloDataSize());
00372 
00373       cout << "AVATAR: new avatar "<<  avatarID << " arrived" << endl;
00374 
00375       // Notify listers that the avatar has arrived.
00376       this->notifyArrive(theQAvatar);
00377 
00378       // Set a flag so that a hello message can be sent out.
00379       if (command == QAvatarManager::HELLO_MSG) {
00380         this->sendHello();
00381       }
00382 
00383     } else {
00384 
00385       // Make certain that this avatar does not get garbage collected.
00386       theQAvatar->markUpdateTime();
00387 
00388       // Grab the hello data.
00389       datapack.unpack(m_tempBuffer, m_selfAvatar->getHelloDataSize());
00390 
00391       // Is it different from previous value?
00392       if (memcmp(m_tempBuffer, theQAvatar->getHelloData(), m_selfAvatar->getHelloDataSize())) {
00393 
00394         // Update the avatar's hello data.
00395         theQAvatar->setHelloData(m_tempBuffer, m_selfAvatar->getHelloDataSize());
00396 
00397         // Send notification of new hello data.
00398         this->notifyHello(theQAvatar);
00399       }
00400     }
00401 
00402   } else if (command == QAvatarManager::BYE_MSG) {
00403 
00404     if (!theQAvatar) {
00405       m_avatarDB->unlock();
00406       return;
00407     }
00408 
00409     // Remove the avatar from the database, notify all listeners that
00410     // it has left, and then finally delete it.
00411     m_avatarDB->remove(avatarID);
00412     this->notifyBye(theQAvatar);
00413     delete theQAvatar;
00414 
00415   } else if (command == QAvatarManager::AUX_MSG) {
00416 
00417     if (!theQAvatar) {
00418       m_avatarDB->unlock();
00419       return;
00420     }
00421 
00422     // Make certain that this avatar does not get garbage collected.
00423     theQAvatar->markUpdateTime();
00424 
00425     datapack.unpack(m_tempBuffer, m_selfAvatar->getAuxDataSize());
00426     theQAvatar->setAuxData(m_tempBuffer, m_selfAvatar->getAuxDataSize());
00427 
00428     // Call user callback.
00429     this->notifyAux(theQAvatar);
00430   }
00431 
00432   m_avatarDB->unlock();
00433 }
00434 
00435 void
00436 QAvatarManager::handleTrackerData(char* dataBuf, const size_t& dataSize)
00437 {
00438   // This is an opportunity to send out a hello message based on
00439   // whether someone had already sent us a hello message.
00440   // Use the avatarDB's lock as the mutex for requireSendAHCHello
00441   //      avatarDB->lock();
00442   //      avatarDB->unlock();
00443  
00444   // Grab the command and avatar id.
00445   QUANTAnet_datapack_c datapack;
00446  
00447   datapack.initUnpack(dataBuf, dataSize);
00448   char command;
00449   datapack.unpackChar(&command);
00450   long avatarID;
00451   datapack.unpackLong(&avatarID);
00452 
00453   // Look for the avatar.
00454   QAvatar* theQAvatar;
00455   m_avatarDB->lock();
00456   m_avatarDB->find(avatarID, theQAvatar);
00457   m_avatarDB->unlock();
00458 
00459   // If the avatar is not in the DB, then ignore the packer.
00460   if (!theQAvatar) {
00461     return;
00462   }
00463 
00464   // Otherwise, retrieve the avatar tracker data.
00465   if (command == QAvatarManager::TRACKER_MSG) {
00466     theQAvatar->markUpdateTime();
00467 
00468     datapack.unpack(m_tempBuffer, m_selfAvatar->getTrackerDataSize());
00469     theQAvatar->setTrackerData(m_tempBuffer, m_selfAvatar->getTrackerDataSize());
00470 
00471     this->notifyTracker(theQAvatar);
00472   }
00473 }
00474 
00475 void
00476 QAvatarManager::notifyArrive(QAvatar* theQAvatar)
00477 {
00478   for (ListenerList::iterator i = m_listeners.begin();
00479       i != m_listeners.end(); i++) {
00480     (*i)->avatarArrive(theQAvatar);
00481   }
00482 }
00483 
00484 void
00485 QAvatarManager::notifyAux(QAvatar* theQAvatar)
00486 {
00487   for (ListenerList::iterator i = m_listeners.begin();
00488       i != m_listeners.end(); i++) {
00489     (*i)->avatarAux(theQAvatar);
00490   }
00491 }
00492 
00493 void
00494 QAvatarManager::notifyBye(QAvatar* theQAvatar)
00495 {
00496   for (ListenerList::iterator i = m_listeners.begin();
00497       i != m_listeners.end(); i++) {
00498     (*i)->avatarBye(theQAvatar);
00499   }
00500 }
00501 
00502 void
00503 QAvatarManager::notifyHello(QAvatar* theQAvatar)
00504 {
00505   for (ListenerList::iterator i = m_listeners.begin();
00506       i != m_listeners.end(); i++) {
00507     (*i)->avatarHello(theQAvatar);
00508   }
00509 }
00510 
00511 void
00512 QAvatarManager::notifyTracker(QAvatar* theQAvatar)
00513 {
00514   for (ListenerList::iterator i = m_listeners.begin();
00515       i != m_listeners.end(); i++) {
00516     (*i)->avatarTracker(theQAvatar);
00517   }
00518 }

Generated on Tue Apr 13 16:42:26 2004 for QAvatar by doxygen 1.3.6