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

QAvatarManager.cxx

00001 
00002 //
00003 // $Id: QAvatarManager.cxx,v 1.4 2004/01/09 22:22:39 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 <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   // Generate an avatar ID based on the current time.
00058   double theTime = QUANTAnet_socketbase_c::getTimeInSecs();
00059   char idStr[256];
00060   sprintf(idStr,"%lf", theTime);
00061 
00062   // Hash the time into a unique 4 byte number.
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   // Allocate memory for packing and sending hello and trackerdata.
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   // Every 60 seconds check for dead avatars.
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       // If there are avatars that have not been refreshed in
00117       // 2 minutes purge them.
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         // Call user callback
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   // Open the TCP channel for avatar hailing.
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   // Open the UDP channel for tracker information.
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   // Extract command and avatar id
00320   datapack.initUnpack(dataBuf, dataSize);
00321   char command;
00322   datapack.unpackChar(&command);
00323   long avatarID;
00324   datapack.unpackLong(&avatarID);
00325  
00326   // Look for the avatar.
00327   QAvatar* theQAvatar;
00328   m_avatarDB->find(avatarID, theQAvatar);
00329 
00330   if (command == QAvatarManager::HELLO_MSG) {
00331     if (!theQAvatar) {
00332 
00333       // The avatar does not yet exist in the database, so therefore
00334       // it's a new avatar!
00335       theQAvatar = m_avatarFactory->createAvatar(avatarID);
00336       //, itsTrackerDataSize, itsHelloDataSize, itsAuxDataSize);
00337 
00338       if (!theQAvatar) {
00339         printf("AVATAR: Unable to allocate new entry for avatar.\n");
00340       }
00341 
00342       // Refresh the timer so that this avatar does not get garbage collected.
00343       theQAvatar->markUpdateTime();
00344 
00345       // Store avatar in avatar database
00346       m_avatarDB->enter(avatarID, theQAvatar);
00347 
00348       // Unpack the avatar's hello data.
00349       datapack.unpack(m_tempBuffer, 1024);
00350       theQAvatar->setHelloData(m_tempBuffer, 1024);
00351 
00352       printf("AVATAR: new avatar arrived %d\n", avatarID);
00353 
00354       // Notify listers that the avatar has arrived.
00355       this->notifyArrive(theQAvatar);
00356 
00357       // Set a flag so that a hello message can be sent out.
00358       if (command == QAvatarManager::HELLO_MSG) {
00359   this->sendHello();
00360       }
00361 
00362     } else {
00363 
00364       // Make certain that this avatar does not get garbage collected.
00365       theQAvatar->markUpdateTime();
00366 
00367       // Grab the hello data.
00368       datapack.unpack(m_tempBuffer, 1024);
00369 
00370       // Is it different from previous value?
00371       if (memcmp(m_tempBuffer, theQAvatar->getHelloData(), 1024)) {
00372 
00373         // Update the avatar's hello data.
00374   theQAvatar->setHelloData(m_tempBuffer, 1024);
00375 
00376         // Send notification of new hello data.
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     // Remove the avatar from the database, notify all listeners that
00389     // it has left, and then finally delete it.
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     // Make certain that this avatar does not get garbage collected.
00402     theQAvatar->markUpdateTime();
00403 
00404     datapack.unpack(m_tempBuffer, 1024);
00405     theQAvatar->setAuxData(m_tempBuffer, 1024);
00406 
00407     // Call user callback.
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   // This is an opportunity to send out a hello message based on
00418   // whether someone had already sent us a hello message.
00419   // Use the avatarDB's lock as the mutex for requireSendAHCHello
00420   //      avatarDB->lock();
00421   //      avatarDB->unlock();
00422  
00423   // Grab the command and avatar id.
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   // Look for the avatar.
00433   QAvatar* theQAvatar;
00434   m_avatarDB->lock();
00435   m_avatarDB->find(avatarID, theQAvatar);
00436   m_avatarDB->unlock();
00437 
00438   // If the avatar is not in the DB, then ignore the packer.
00439   if (!theQAvatar) {
00440     return;
00441   }
00442 
00443   // Otherwise, retrieve the avatar tracker data.
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 }

Generated on Sat Jan 17 18:00:19 2004 for QAvatar by doxygen 1.3.4