Panda3D
|
00001 // Filename: pStatServer.cxx 00002 // Created by: drose (09Jul00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pStatServer.h" 00016 #include "pStatReader.h" 00017 #include "thread.h" 00018 #include "config_pstats.h" 00019 00020 //////////////////////////////////////////////////////////////////// 00021 // Function: PStatServer::Constructor 00022 // Access: Public 00023 // Description: 00024 //////////////////////////////////////////////////////////////////// 00025 PStatServer:: 00026 PStatServer() { 00027 _listener = new PStatListener(this); 00028 _next_udp_port = 0; 00029 } 00030 00031 //////////////////////////////////////////////////////////////////// 00032 // Function: PStatServer::Destructor 00033 // Access: Public 00034 // Description: 00035 //////////////////////////////////////////////////////////////////// 00036 PStatServer:: 00037 ~PStatServer() { 00038 delete _listener; 00039 } 00040 00041 00042 //////////////////////////////////////////////////////////////////// 00043 // Function: PStatServer::listen 00044 // Access: Public 00045 // Description: Establishes a port number that the manager will 00046 // listen on for TCP connections. This may be called 00047 // more than once to listen simulataneously on multiple 00048 // connections, as if that were at all useful. 00049 // 00050 // The default parameter, -1, indicates the use of 00051 // whatever port number has been indicated in the Config 00052 // file. 00053 // 00054 // This function returns true if the port was 00055 // successfully opened, or false if it could not open 00056 // the port. 00057 //////////////////////////////////////////////////////////////////// 00058 bool PStatServer:: 00059 listen(int port) { 00060 if (port < 0) { 00061 port = pstats_port; 00062 } 00063 00064 // Now try to listen to the port. 00065 PT(Connection) rendezvous = open_TCP_server_rendezvous(port, 5); 00066 00067 if (rendezvous.is_null()) { 00068 // Couldn't get it. 00069 return false; 00070 } 00071 00072 // Tell the listener about the new port. 00073 _listener->add_connection(rendezvous); 00074 00075 if (_next_udp_port == 0) { 00076 _next_udp_port = port + 1; 00077 } 00078 return true; 00079 } 00080 00081 00082 //////////////////////////////////////////////////////////////////// 00083 // Function: PStatServer::poll 00084 // Access: Public 00085 // Description: Checks for any network activity and handles it, if 00086 // appropriate, and then returns. This must be called 00087 // periodically unless is_thread_safe() is redefined to 00088 // return true on this class and also on all 00089 // PStatMonitors in use. 00090 // 00091 // Alternatively, a program may call main_loop() and 00092 // yield control of the program entirely to the 00093 // PStatServer. 00094 //////////////////////////////////////////////////////////////////// 00095 void PStatServer:: 00096 poll() { 00097 // Delete all the readers that we couldn't delete before. 00098 while (!_lost_readers.empty()) { 00099 PStatReader *reader = _lost_readers.back(); 00100 _lost_readers.pop_back(); 00101 00102 reader->lost_connection(); 00103 delete reader; 00104 } 00105 while (!_removed_readers.empty()) { 00106 PStatReader *reader = _removed_readers.back(); 00107 _removed_readers.pop_back(); 00108 delete reader; 00109 } 00110 00111 _listener->poll(); 00112 00113 Readers::const_iterator ri = _readers.begin(); 00114 while (ri != _readers.end()) { 00115 // Preincrement the iterator, in case we remove it as a result of 00116 // calling poll(). 00117 Readers::const_iterator rnext = ri; 00118 ++rnext; 00119 PStatReader *reader = (*ri).second; 00120 00121 reader->poll(); 00122 reader->idle(); 00123 00124 ri = rnext; 00125 } 00126 } 00127 00128 //////////////////////////////////////////////////////////////////// 00129 // Function: PStatServer::main_loop 00130 // Access: Public 00131 // Description: An alternative to repeatedly calling poll(), this 00132 // function yields control of the program to the 00133 // PStatServer. It does not return until the program 00134 // is done. 00135 // 00136 // If interrupt_flag is non-NULL, it is the address of a 00137 // bool variable that is initially false, and may be 00138 // asynchronously set true to indicate the loop should 00139 // terminate. 00140 //////////////////////////////////////////////////////////////////// 00141 void PStatServer:: 00142 main_loop(bool *interrupt_flag) { 00143 while (interrupt_flag == (bool *)NULL || !*interrupt_flag) { 00144 poll(); 00145 Thread::sleep(0.1); 00146 } 00147 } 00148 00149 //////////////////////////////////////////////////////////////////// 00150 // Function: PStatServer::add_reader 00151 // Access: Public 00152 // Description: Adds the newly-created PStatReader to the list of 00153 // currently active readers. 00154 //////////////////////////////////////////////////////////////////// 00155 void PStatServer:: 00156 add_reader(Connection *connection, PStatReader *reader) { 00157 _readers[connection] = reader; 00158 } 00159 00160 //////////////////////////////////////////////////////////////////// 00161 // Function: PStatServer::remove_reader 00162 // Access: Public 00163 // Description: Removes the indicated reader. 00164 //////////////////////////////////////////////////////////////////// 00165 void PStatServer:: 00166 remove_reader(Connection *connection, PStatReader *reader) { 00167 Readers::iterator ri; 00168 ri = _readers.find(connection); 00169 if (ri == _readers.end() || (*ri).second != reader) { 00170 nout << "Attempt to remove undefined reader.\n"; 00171 } else { 00172 _readers.erase(ri); 00173 _removed_readers.push_back(reader); 00174 } 00175 } 00176 00177 //////////////////////////////////////////////////////////////////// 00178 // Function: PStatServer::get_udp_port 00179 // Access: Public 00180 // Description: Returns a new port number that will probably be free 00181 // to use as a UDP port. The caller should be prepared 00182 // to accept the possibility that it will be already in 00183 // use by another process, however. 00184 //////////////////////////////////////////////////////////////////// 00185 int PStatServer:: 00186 get_udp_port() { 00187 if (_available_udp_ports.empty()) { 00188 return _next_udp_port++; 00189 } 00190 int udp_port = _available_udp_ports.front(); 00191 _available_udp_ports.pop_front(); 00192 return udp_port; 00193 } 00194 00195 //////////////////////////////////////////////////////////////////// 00196 // Function: PStatServer::release_udp_port 00197 // Access: Public 00198 // Description: Indicates that the given UDP port is once again free 00199 // for use. 00200 //////////////////////////////////////////////////////////////////// 00201 void PStatServer:: 00202 release_udp_port(int port) { 00203 _available_udp_ports.push_back(port); 00204 } 00205 00206 //////////////////////////////////////////////////////////////////// 00207 // Function: PStatServer::get_num_user_guide_bars 00208 // Access: Public 00209 // Description: Returns the current number of user-defined guide 00210 // bars. 00211 //////////////////////////////////////////////////////////////////// 00212 int PStatServer:: 00213 get_num_user_guide_bars() const { 00214 return _user_guide_bars.size(); 00215 } 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: PStatServer::get_user_guide_bar_height 00219 // Access: Public 00220 // Description: Returns the height of the nth user-defined guide bar. 00221 //////////////////////////////////////////////////////////////////// 00222 double PStatServer:: 00223 get_user_guide_bar_height(int n) const { 00224 nassertr(n >= 0 && n < (int)_user_guide_bars.size(), 0.0f); 00225 return _user_guide_bars[n]; 00226 } 00227 00228 //////////////////////////////////////////////////////////////////// 00229 // Function: PStatServer::move_user_guide_bar 00230 // Access: Public 00231 // Description: Adjusts the height of the nth user-defined guide bar. 00232 //////////////////////////////////////////////////////////////////// 00233 void PStatServer:: 00234 move_user_guide_bar(int n, double height) { 00235 nassertv(n >= 0 && n < (int)_user_guide_bars.size()); 00236 _user_guide_bars[n] = height; 00237 user_guide_bars_changed(); 00238 } 00239 00240 //////////////////////////////////////////////////////////////////// 00241 // Function: PStatServer::add_user_guide_bar 00242 // Access: Public 00243 // Description: Creates a new user guide bar and returns its index 00244 // number. 00245 //////////////////////////////////////////////////////////////////// 00246 int PStatServer:: 00247 add_user_guide_bar(double height) { 00248 int n = (int)_user_guide_bars.size(); 00249 _user_guide_bars.push_back(height); 00250 user_guide_bars_changed(); 00251 00252 return n; 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: PStatServer::remove_user_guide_bar 00257 // Access: Public 00258 // Description: Removes the user guide bar with the indicated index 00259 // number. All subsequent index numbers are adjusted 00260 // down one. 00261 //////////////////////////////////////////////////////////////////// 00262 void PStatServer:: 00263 remove_user_guide_bar(int n) { 00264 nassertv(n >= 0 && n < (int)_user_guide_bars.size()); 00265 _user_guide_bars.erase(_user_guide_bars.begin() + n); 00266 user_guide_bars_changed(); 00267 } 00268 00269 //////////////////////////////////////////////////////////////////// 00270 // Function: PStatServer::find_user_guide_bar 00271 // Access: Public 00272 // Description: Returns the index number of the first user guide bar 00273 // found whose height is within the indicated range, or 00274 // -1 if no user guide bars fall within the range. 00275 //////////////////////////////////////////////////////////////////// 00276 int PStatServer:: 00277 find_user_guide_bar(double from_height, double to_height) const { 00278 GuideBars::const_iterator gbi; 00279 for (gbi = _user_guide_bars.begin(); 00280 gbi != _user_guide_bars.end(); 00281 ++gbi) { 00282 double height = (*gbi); 00283 if (height >= from_height && height <= to_height) { 00284 return (int)(gbi - _user_guide_bars.begin()); 00285 } 00286 } 00287 00288 return -1; 00289 } 00290 00291 //////////////////////////////////////////////////////////////////// 00292 // Function: PStatServer::user_guide_bars_changed 00293 // Access: Priate 00294 // Description: Called when the user guide bars have been changed. 00295 //////////////////////////////////////////////////////////////////// 00296 void PStatServer:: 00297 user_guide_bars_changed() { 00298 Readers::iterator ri; 00299 for (ri = _readers.begin(); ri != _readers.end(); ++ri) { 00300 (*ri).second->get_monitor()->user_guide_bars_changed(); 00301 } 00302 } 00303 00304 //////////////////////////////////////////////////////////////////// 00305 // Function: PStatServer::is_thread_safe 00306 // Access: Public 00307 // Description: This should be redefined to return true in derived 00308 // classes that want to deal with multithreaded readers 00309 // and such. If this returns true, the manager will 00310 // create the listener in its own thread, and thus the 00311 // PStatReader constructors at least will run in a 00312 // different thread. 00313 // 00314 // This is not related to the question of whether the 00315 // reader can handle multiple different 00316 // PStatThreadDatas; it's strictly a question of whether 00317 // the readers themselves can run in a separate thread. 00318 //////////////////////////////////////////////////////////////////// 00319 bool PStatServer:: 00320 is_thread_safe() { 00321 return false; 00322 } 00323 00324 //////////////////////////////////////////////////////////////////// 00325 // Function: PStatServer::connection_reset 00326 // Access: Protected, Virtual 00327 // Description: Called when a lost connection is detected by the net 00328 // code, this should pass the word on to the interested 00329 // parties and clean up gracefully. 00330 //////////////////////////////////////////////////////////////////// 00331 void PStatServer:: 00332 connection_reset(const PT(Connection) &connection, bool okflag) { 00333 // Was this a client connection? Tell the reader about it if it 00334 // was. 00335 close_connection(connection); 00336 00337 Readers::iterator ri; 00338 ri = _readers.find(connection); 00339 if (ri != _readers.end()) { 00340 PStatReader *reader = (*ri).second; 00341 _readers.erase(ri); 00342 00343 // Unfortunately, we can't delete the reader right away, because 00344 // we might have been called from a method on the reader! We'll 00345 // have to save the reader pointer and delete it some time later. 00346 _lost_readers.push_back(reader); 00347 } 00348 }