Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/pstatserver/pStatServer.cxx

Go to the documentation of this file.
00001 // Filename: pStatServer.cxx
00002 // Created by:  drose (09Jul00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "pStatServer.h"
00020 #include "pStatReader.h"
00021 
00022 #include <config_pstats.h>
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: PStatServer::Constructor
00026 //       Access: Public
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 PStatServer::
00030 PStatServer() {
00031   _listener = new PStatListener(this);
00032   _next_udp_port = 0;
00033 }
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: PStatServer::Destructor
00037 //       Access: Public
00038 //  Description:
00039 ////////////////////////////////////////////////////////////////////
00040 PStatServer::
00041 ~PStatServer() {
00042   delete _listener;
00043 }
00044 
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: PStatServer::listen
00048 //       Access: Public
00049 //  Description: Establishes a port number that the manager will
00050 //               listen on for TCP connections.  This may be called
00051 //               more than once to listen simulataneously on multiple
00052 //               connections, as if that were at all useful.
00053 //
00054 //               The default parameter, -1, indicates the use of
00055 //               whatever port number has been indicated in the Config
00056 //               file.
00057 //
00058 //               This function returns true if the port was
00059 //               successfully opened, or false if it could not open
00060 //               the port.
00061 ////////////////////////////////////////////////////////////////////
00062 bool PStatServer::
00063 listen(int port) {
00064   if (port < 0) {
00065     port = pstats_port;
00066   }
00067 
00068   // Now try to listen to the port.
00069   PT(Connection) rendezvous = open_TCP_server_rendezvous(port, 5);
00070 
00071   if (rendezvous.is_null()) {
00072     // Couldn't get it.
00073     return false;
00074   }
00075 
00076   // Tell the listener about the new port.
00077   _listener->add_connection(rendezvous);
00078 
00079   if (_next_udp_port == 0) {
00080     _next_udp_port = port + 1;
00081   }
00082   return true;
00083 }
00084 
00085 
00086 ////////////////////////////////////////////////////////////////////
00087 //     Function: PStatServer::poll
00088 //       Access: Public
00089 //  Description: Checks for any network activity and handles it, if
00090 //               appropriate, and then returns.  This must be called
00091 //               periodically unless is_thread_safe() is redefined to
00092 //               return true on this class and also on all
00093 //               PStatMonitors in use.
00094 //
00095 //               Alternatively, a program may call main_loop() and
00096 //               yield control of the program entirely to the
00097 //               PStatServer.
00098 ////////////////////////////////////////////////////////////////////
00099 void PStatServer::
00100 poll() {
00101   // Delete all the readers that we couldn't delete before.
00102   while (!_lost_readers.empty()) {
00103     PStatReader *reader = _lost_readers.back();
00104     _lost_readers.pop_back();
00105 
00106     reader->lost_connection();
00107     delete reader;
00108   }
00109   while (!_removed_readers.empty()) {
00110     PStatReader *reader = _removed_readers.back();
00111     _removed_readers.pop_back();
00112     delete reader;
00113   }
00114 
00115   _listener->poll();
00116 
00117   Readers::const_iterator ri;
00118   for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
00119     (*ri).second->poll();
00120     (*ri).second->idle();
00121   }
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: PStatServer::main_loop
00126 //       Access: Public
00127 //  Description: An alternative to repeatedly calling poll(), this
00128 //               function yields control of the program to the
00129 //               PStatServer.  It does not return until the program
00130 //               is done.
00131 //
00132 //               If interrupt_flag is non-NULL, it is the address of a
00133 //               bool variable that is initially false, and may be
00134 //               asynchronously set true to indicate the loop should
00135 //               terminate.
00136 ////////////////////////////////////////////////////////////////////
00137 void PStatServer::
00138 main_loop(bool *interrupt_flag) {
00139   while (interrupt_flag == (bool *)NULL || !*interrupt_flag) {
00140     poll();
00141     // Not great.  This will totally blow in a threaded environment.
00142     // We need a portable way to sleep or block.
00143     PRIntervalTime sleep_timeout = PR_MillisecondsToInterval(100);
00144     PR_Sleep(sleep_timeout);
00145   }
00146 }
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: PStatServer::add_reader
00150 //       Access: Public
00151 //  Description: Adds the newly-created PStatReader to the list of
00152 //               currently active readers.
00153 ////////////////////////////////////////////////////////////////////
00154 void PStatServer::
00155 add_reader(Connection *connection, PStatReader *reader) {
00156   _readers[connection] = reader;
00157 }
00158 
00159 ////////////////////////////////////////////////////////////////////
00160 //     Function: PStatServer::remove_reader
00161 //       Access: Public
00162 //  Description: Removes the indicated reader.
00163 ////////////////////////////////////////////////////////////////////
00164 void PStatServer::
00165 remove_reader(Connection *connection, PStatReader *reader) {
00166   Readers::iterator ri;
00167   ri = _readers.find(connection);
00168   if (ri == _readers.end() || (*ri).second != reader) {
00169     nout << "Attempt to remove undefined reader.\n";
00170   } else {
00171     _readers.erase(ri);
00172     _removed_readers.push_back(reader);
00173   }
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: PStatServer::get_udp_port
00178 //       Access: Public
00179 //  Description: Returns a new port number that will probably be free
00180 //               to use as a UDP port.  The caller should be prepared
00181 //               to accept the possibility that it will be already in
00182 //               use by another process, however.
00183 ////////////////////////////////////////////////////////////////////
00184 int PStatServer::
00185 get_udp_port() {
00186   if (_available_udp_ports.empty()) {
00187     return _next_udp_port++;
00188   }
00189   int udp_port = _available_udp_ports.front();
00190   _available_udp_ports.pop_front();
00191   return udp_port;
00192 }
00193 
00194 ////////////////////////////////////////////////////////////////////
00195 //     Function: PStatServer::release_udp_port
00196 //       Access: Public
00197 //  Description: Indicates that the given UDP port is once again free
00198 //               for use.
00199 ////////////////////////////////////////////////////////////////////
00200 void PStatServer::
00201 release_udp_port(int port) {
00202   _available_udp_ports.push_back(port);
00203 }
00204 
00205 ////////////////////////////////////////////////////////////////////
00206 //     Function: PStatServer::is_thread_safe
00207 //       Access: Public
00208 //  Description: This should be redefined to return true in derived
00209 //               classes that want to deal with multithreaded readers
00210 //               and such.  If this returns true, the manager will
00211 //               create the listener in its own thread, and thus the
00212 //               PStatReader constructors at least will run in a
00213 //               different thread.
00214 //
00215 //               This is not related to the question of whether the
00216 //               reader can handle multiple different
00217 //               PStatThreadDatas; it's strictly a question of whether
00218 //               the readers themselves can run in a separate thread.
00219 ////////////////////////////////////////////////////////////////////
00220 bool PStatServer::
00221 is_thread_safe() {
00222   return false;
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: PStatServer::connection_reset
00227 //       Access: Private
00228 //  Description: Called when a lost connection is detected by the net
00229 //               code, this should pass the word on to the interested
00230 //               parties and clean up gracefully.
00231 ////////////////////////////////////////////////////////////////////
00232 void PStatServer::
00233 connection_reset(const PT(Connection) &connection) {
00234   // Was this a client connection?  Tell the reader about it if it
00235   // was.
00236   close_connection(connection);
00237 
00238   Readers::iterator ri;
00239   ri = _readers.find(connection);
00240   if (ri != _readers.end()) {
00241     PStatReader *reader = (*ri).second;
00242     _readers.erase(ri);
00243 
00244     // Unfortunately, we can't delete the reader right away, because
00245     // we might have been called from a method on the reader!  We'll
00246     // have to safe the reader pointer and delete it some time later.
00247     _lost_readers.push_back(reader);
00248   }
00249 }

Generated on Fri May 2 03:21:39 2003 for Panda-Tool by doxygen1.3