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 }