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

avatarserver.cxx

00001 
00002 //
00003 // $Id: avatarserver.cxx,v 1.8 2004/04/02 21:44:16 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 /* This demonstrates the use of the CAVERNplus_tcpReflector_c class.
00033  * This server accepts N client connections.
00034  * It receives data from the clients and reflects it to all other connected clie
00035 nts.
00036  */
00037 
00038 #include <QUANTA/QUANTAnet_tcpReflector_c.hxx>
00039 #include <QUANTA/QUANTAnet_udpReflector_c.hxx>
00040 #include <QUANTA/QUANTAts_barrier_c.hxx>
00041 #include <QUANTA/QUANTAts_rwlock_c.hxx>
00042 #include <QUANTA/QUANTAts_thread_c.hxx>
00043 
00044 #include <signal.h>
00045 #ifdef USE_STL_NAMESPACE
00046 #include <iostream>
00047 using std::cout;
00048 using std::endl;
00049 #else /* USE_STL_NAMESPACE */
00050 #include <iostream.h>
00051 #endif /* USE_STL_NAMESPACE */
00052 
00054 void stopServer(int);
00056 void* tcpThreadFunc(void*);
00057 void* udpThreadFunc(void*);
00058 
00059 QUANTAnet_tcpReflector_c* hailingserver;
00060 QUANTAnet_udpReflector_c* trackerserver;
00061 
00063 
00064 
00065 volatile bool keepRunning = true;
00067 QUANTAts_barrier_c* runningBarrier;
00069 QUANTAts_rwlock_c* runningLock;
00071 
00072 int
00073 main(int argc, char** argv)
00074 {
00075   QUANTAinit();
00076 
00077   // The default TCP port is 7000. The UDP port is always the next
00078   // availabel port number. Another port may be specified from the
00079   // launch arguments.
00080   short tcpPort = 7000;
00081   if (argc > 1) {
00082     tcpPort = strtol(argv[1], NULL, 0);
00083   }
00084   short udpPort = tcpPort+1;
00085 
00086   // Install signal handlers for catching the ctrl-c (SIGINT).
00087   signal(SIGINT, stopServer);
00088   signal(SIGTERM, stopServer);
00089 
00090   // Create the thread synchronization primitives.
00091   runningBarrier = new QUANTAts_barrier_c(2);
00092   runningLock = new QUANTAts_rwlock_c;
00093   // To watch debugging output from the locking object, uncomment the
00094   // following two lines.
00095   //runningLock->showDebug(true);
00096   //runningLock->setDebugMessage("runningLock");
00097 
00098   hailingserver = new QUANTAnet_tcpReflector_c;
00099   hailingserver->setBlockingTimeout(5);
00100   if (hailingserver->init(tcpPort, 64) != QUANTAnet_tcpReflector_c::OK) {
00101     cout << "avatarserver cannot open TCP listening port" << tcpPort << endl;
00102     exit(1) ;
00103   }
00104 
00105   trackerserver = new QUANTAnet_udpReflector_c;
00106   trackerserver->setTimeOutTime(5);
00107   trackerserver->setIncomingPort(udpPort) ;
00108   if (trackerserver->init() != QUANTAnet_udpReflector_c::OK) {
00109     cout << "avatarserver annot open UDP listening port" << udpPort << endl;
00110     exit(1) ;
00111   }
00112 
00113   // Create the TCP thread. The UDP reflector internally creates its
00114   // own thread, so it does not need a separate thread.
00115   QUANTAts_thread_c tcpThread;
00116   tcpThread.create(tcpThreadFunc, hailingserver);
00117   //threadID_2.create(udpThreadFunc, trackerserver);
00118 
00119   cout << "avatarserver listening on ports " << tcpPort
00120        << " (TCP) and "  << udpPort << " (UDP)." << endl;
00121 
00122   // Block until the other threads reach the barrier. This makes the
00123   // main process just wait without any performance penalty.
00124   runningBarrier->wait();
00125 
00126   // Just to be safe, wait until the tcpThread has finished.
00127   tcpThread.join();
00128 
00129   // It should now be safe to properly clean up everything. This is
00130   // important for the servers since their destructors should properly
00131   // shut everything down. Any connected clients should receive proper
00132   // notification from the server.
00133   delete hailingserver;
00134   delete trackerserver;
00135   delete runningBarrier;
00136   delete runningLock;
00137 
00138   cout << "avatarserver exiting" << endl;
00139   return 0;
00140 }
00141 
00142 void
00143 stopServer(int dummy)
00144 {
00145   cout << "Ctrl-C caught..." << endl;
00146   int retval = runningLock->writeLock();
00147   if (retval == 0) {
00148     cout << "\navatarserver shutting down..." << endl;
00149     keepRunning = false;
00150     runningLock->unlock();
00151     signal(SIGINT, SIG_DFL);
00152   } else {
00153     cout << "\nERROR trying to obtain runningLock! "
00154          << strerror(retval) << endl;
00155   }
00156 }
00157 
00158 void*
00159 tcpThreadFunc(void* objPtr)
00160 {
00161   // This is the Double-Checking Pattern that prevents dead-lock and
00162   // properly ensure that a variable is available for reading. As long
00163   // as runTCP is true, this function tries to read whether it should
00164   // keepRunning. It calls the TCP reflector's blocking process().
00165   bool runTCP = true;
00166   while (runTCP) {
00167     if (runningLock->readLock() == 0) {
00168       if (keepRunning) {
00169         // It's important to go ahead and release the lock immediately
00170         // in the event that the process call blocks.
00171         runningLock->unlock();
00172         reinterpret_cast<QUANTAnet_tcpReflector_c*>(objPtr)->process();
00173       } else {
00174         runTCP = false;
00175       }
00176     }
00177   }
00178   // When finished, wait for the barrier. This signals to the main
00179   // process that the thread function is not doing any more
00180   // processing.
00181   runningBarrier->wait();
00182   return NULL;
00183 }
00184 
00185 void*
00186 udpThreadFunc(void* objPtr)
00187 {
00188 #if 1
00189   // Do nothing since the UDP reflector manages its own thread.
00190 #else
00191   bool runUDP = true;
00192   while (runUDP) {
00193     if (runningLock->readLock() == 0) {
00194       if (keepRunning) {
00195         runningLock->unlock();
00196         reinterpret_cast<QUANTAnet_udpReflector_c*>(objPtr)->process();
00197       } else {
00198         runUDP = false;
00199       }
00200     }
00201   }
00202 #endif
00203   runningBarrier->wait();
00204   return NULL;
00205 }

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