Panda3D
 All Classes Functions Variables Enumerations
pStatServer.cxx
1 // Filename: pStatServer.cxx
2 // Created by: drose (09Jul00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pStatServer.h"
16 #include "pStatReader.h"
17 #include "thread.h"
18 #include "config_pstats.h"
19 
20 ////////////////////////////////////////////////////////////////////
21 // Function: PStatServer::Constructor
22 // Access: Public
23 // Description:
24 ////////////////////////////////////////////////////////////////////
25 PStatServer::
26 PStatServer() {
27  _listener = new PStatListener(this);
28  _next_udp_port = 0;
29 }
30 
31 ////////////////////////////////////////////////////////////////////
32 // Function: PStatServer::Destructor
33 // Access: Public
34 // Description:
35 ////////////////////////////////////////////////////////////////////
36 PStatServer::
37 ~PStatServer() {
38  delete _listener;
39 }
40 
41 
42 ////////////////////////////////////////////////////////////////////
43 // Function: PStatServer::listen
44 // Access: Public
45 // Description: Establishes a port number that the manager will
46 // listen on for TCP connections. This may be called
47 // more than once to listen simulataneously on multiple
48 // connections, as if that were at all useful.
49 //
50 // The default parameter, -1, indicates the use of
51 // whatever port number has been indicated in the Config
52 // file.
53 //
54 // This function returns true if the port was
55 // successfully opened, or false if it could not open
56 // the port.
57 ////////////////////////////////////////////////////////////////////
58 bool PStatServer::
59 listen(int port) {
60  if (port < 0) {
61  port = pstats_port;
62  }
63 
64  // Now try to listen to the port.
65  PT(Connection) rendezvous = open_TCP_server_rendezvous(port, 5);
66 
67  if (rendezvous.is_null()) {
68  // Couldn't get it.
69  return false;
70  }
71 
72  // Tell the listener about the new port.
73  _listener->add_connection(rendezvous);
74 
75  if (_next_udp_port == 0) {
76  _next_udp_port = port + 1;
77  }
78  return true;
79 }
80 
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: PStatServer::poll
84 // Access: Public
85 // Description: Checks for any network activity and handles it, if
86 // appropriate, and then returns. This must be called
87 // periodically unless is_thread_safe() is redefined to
88 // return true on this class and also on all
89 // PStatMonitors in use.
90 //
91 // Alternatively, a program may call main_loop() and
92 // yield control of the program entirely to the
93 // PStatServer.
94 ////////////////////////////////////////////////////////////////////
95 void PStatServer::
96 poll() {
97  // Delete all the readers that we couldn't delete before.
98  while (!_lost_readers.empty()) {
99  PStatReader *reader = _lost_readers.back();
100  _lost_readers.pop_back();
101 
102  reader->lost_connection();
103  delete reader;
104  }
105  while (!_removed_readers.empty()) {
106  PStatReader *reader = _removed_readers.back();
107  _removed_readers.pop_back();
108  delete reader;
109  }
110 
111  _listener->poll();
112 
113  Readers::const_iterator ri = _readers.begin();
114  while (ri != _readers.end()) {
115  // Preincrement the iterator, in case we remove it as a result of
116  // calling poll().
117  Readers::const_iterator rnext = ri;
118  ++rnext;
119  PStatReader *reader = (*ri).second;
120 
121  reader->poll();
122  reader->idle();
123 
124  ri = rnext;
125  }
126 }
127 
128 ////////////////////////////////////////////////////////////////////
129 // Function: PStatServer::main_loop
130 // Access: Public
131 // Description: An alternative to repeatedly calling poll(), this
132 // function yields control of the program to the
133 // PStatServer. It does not return until the program
134 // is done.
135 //
136 // If interrupt_flag is non-NULL, it is the address of a
137 // bool variable that is initially false, and may be
138 // asynchronously set true to indicate the loop should
139 // terminate.
140 ////////////////////////////////////////////////////////////////////
141 void PStatServer::
142 main_loop(bool *interrupt_flag) {
143  while (interrupt_flag == (bool *)NULL || !*interrupt_flag) {
144  poll();
145  Thread::sleep(0.1);
146  }
147 }
148 
149 ////////////////////////////////////////////////////////////////////
150 // Function: PStatServer::add_reader
151 // Access: Public
152 // Description: Adds the newly-created PStatReader to the list of
153 // currently active readers.
154 ////////////////////////////////////////////////////////////////////
155 void PStatServer::
156 add_reader(Connection *connection, PStatReader *reader) {
157  _readers[connection] = reader;
158 }
159 
160 ////////////////////////////////////////////////////////////////////
161 // Function: PStatServer::remove_reader
162 // Access: Public
163 // Description: Removes the indicated reader.
164 ////////////////////////////////////////////////////////////////////
165 void PStatServer::
166 remove_reader(Connection *connection, PStatReader *reader) {
167  Readers::iterator ri;
168  ri = _readers.find(connection);
169  if (ri == _readers.end() || (*ri).second != reader) {
170  nout << "Attempt to remove undefined reader.\n";
171  } else {
172  _readers.erase(ri);
173  _removed_readers.push_back(reader);
174  }
175 }
176 
177 ////////////////////////////////////////////////////////////////////
178 // Function: PStatServer::get_udp_port
179 // Access: Public
180 // Description: Returns a new port number that will probably be free
181 // to use as a UDP port. The caller should be prepared
182 // to accept the possibility that it will be already in
183 // use by another process, however.
184 ////////////////////////////////////////////////////////////////////
185 int PStatServer::
187  if (_available_udp_ports.empty()) {
188  return _next_udp_port++;
189  }
190  int udp_port = _available_udp_ports.front();
191  _available_udp_ports.pop_front();
192  return udp_port;
193 }
194 
195 ////////////////////////////////////////////////////////////////////
196 // Function: PStatServer::release_udp_port
197 // Access: Public
198 // Description: Indicates that the given UDP port is once again free
199 // for use.
200 ////////////////////////////////////////////////////////////////////
201 void PStatServer::
202 release_udp_port(int port) {
203  _available_udp_ports.push_back(port);
204 }
205 
206 ////////////////////////////////////////////////////////////////////
207 // Function: PStatServer::get_num_user_guide_bars
208 // Access: Public
209 // Description: Returns the current number of user-defined guide
210 // bars.
211 ////////////////////////////////////////////////////////////////////
212 int PStatServer::
214  return _user_guide_bars.size();
215 }
216 
217 ////////////////////////////////////////////////////////////////////
218 // Function: PStatServer::get_user_guide_bar_height
219 // Access: Public
220 // Description: Returns the height of the nth user-defined guide bar.
221 ////////////////////////////////////////////////////////////////////
222 double PStatServer::
224  nassertr(n >= 0 && n < (int)_user_guide_bars.size(), 0.0f);
225  return _user_guide_bars[n];
226 }
227 
228 ////////////////////////////////////////////////////////////////////
229 // Function: PStatServer::move_user_guide_bar
230 // Access: Public
231 // Description: Adjusts the height of the nth user-defined guide bar.
232 ////////////////////////////////////////////////////////////////////
233 void PStatServer::
234 move_user_guide_bar(int n, double height) {
235  nassertv(n >= 0 && n < (int)_user_guide_bars.size());
236  _user_guide_bars[n] = height;
237  user_guide_bars_changed();
238 }
239 
240 ////////////////////////////////////////////////////////////////////
241 // Function: PStatServer::add_user_guide_bar
242 // Access: Public
243 // Description: Creates a new user guide bar and returns its index
244 // number.
245 ////////////////////////////////////////////////////////////////////
246 int PStatServer::
247 add_user_guide_bar(double height) {
248  int n = (int)_user_guide_bars.size();
249  _user_guide_bars.push_back(height);
250  user_guide_bars_changed();
251 
252  return n;
253 }
254 
255 ////////////////////////////////////////////////////////////////////
256 // Function: PStatServer::remove_user_guide_bar
257 // Access: Public
258 // Description: Removes the user guide bar with the indicated index
259 // number. All subsequent index numbers are adjusted
260 // down one.
261 ////////////////////////////////////////////////////////////////////
262 void PStatServer::
264  nassertv(n >= 0 && n < (int)_user_guide_bars.size());
265  _user_guide_bars.erase(_user_guide_bars.begin() + n);
266  user_guide_bars_changed();
267 }
268 
269 ////////////////////////////////////////////////////////////////////
270 // Function: PStatServer::find_user_guide_bar
271 // Access: Public
272 // Description: Returns the index number of the first user guide bar
273 // found whose height is within the indicated range, or
274 // -1 if no user guide bars fall within the range.
275 ////////////////////////////////////////////////////////////////////
276 int PStatServer::
277 find_user_guide_bar(double from_height, double to_height) const {
278  GuideBars::const_iterator gbi;
279  for (gbi = _user_guide_bars.begin();
280  gbi != _user_guide_bars.end();
281  ++gbi) {
282  double height = (*gbi);
283  if (height >= from_height && height <= to_height) {
284  return (int)(gbi - _user_guide_bars.begin());
285  }
286  }
287 
288  return -1;
289 }
290 
291 ////////////////////////////////////////////////////////////////////
292 // Function: PStatServer::user_guide_bars_changed
293 // Access: Priate
294 // Description: Called when the user guide bars have been changed.
295 ////////////////////////////////////////////////////////////////////
296 void PStatServer::
297 user_guide_bars_changed() {
298  Readers::iterator ri;
299  for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
300  (*ri).second->get_monitor()->user_guide_bars_changed();
301  }
302 }
303 
304 ////////////////////////////////////////////////////////////////////
305 // Function: PStatServer::is_thread_safe
306 // Access: Public
307 // Description: This should be redefined to return true in derived
308 // classes that want to deal with multithreaded readers
309 // and such. If this returns true, the manager will
310 // create the listener in its own thread, and thus the
311 // PStatReader constructors at least will run in a
312 // different thread.
313 //
314 // This is not related to the question of whether the
315 // reader can handle multiple different
316 // PStatThreadDatas; it's strictly a question of whether
317 // the readers themselves can run in a separate thread.
318 ////////////////////////////////////////////////////////////////////
319 bool PStatServer::
321  return false;
322 }
323 
324 ////////////////////////////////////////////////////////////////////
325 // Function: PStatServer::connection_reset
326 // Access: Protected, Virtual
327 // Description: Called when a lost connection is detected by the net
328 // code, this should pass the word on to the interested
329 // parties and clean up gracefully.
330 ////////////////////////////////////////////////////////////////////
331 void PStatServer::
332 connection_reset(const PT(Connection) &connection, bool okflag) {
333  // Was this a client connection? Tell the reader about it if it
334  // was.
335  close_connection(connection);
336 
337  Readers::iterator ri;
338  ri = _readers.find(connection);
339  if (ri != _readers.end()) {
340  PStatReader *reader = (*ri).second;
341  _readers.erase(ri);
342 
343  // Unfortunately, we can't delete the reader right away, because
344  // we might have been called from a method on the reader! We'll
345  // have to save the reader pointer and delete it some time later.
346  _lost_readers.push_back(reader);
347  }
348 }
int add_user_guide_bar(double height)
Creates a new user guide bar and returns its index number.
void remove_user_guide_bar(int n)
Removes the user guide bar with the indicated index number.
double get_user_guide_bar_height(int n) const
Returns the height of the nth user-defined guide bar.
bool close_connection(const PT(Connection)&connection)
Terminates a UDP or TCP socket previously opened.
int get_udp_port()
Returns a new port number that will probably be free to use as a UDP port.
void idle()
Called each frame to do what needs to be done for the monitor&#39;s user-defined idle routines...
void poll()
Explicitly polls the available sockets to see if any of them have any noise.
int find_user_guide_bar(double from_height, double to_height) const
Returns the index number of the first user guide bar found whose height is within the indicated range...
This is the class that does all the work for handling communications from a single Panda client...
Definition: pStatReader.h:44
This is the TCP rendezvous socket listener.
Definition: pStatListener.h:32
void lost_connection()
This is called by the PStatServer when it detects that the connection has been lost.
void add_reader(Connection *connection, PStatReader *reader)
Adds the newly-created PStatReader to the list of currently active readers.
void remove_reader(Connection *connection, PStatReader *reader)
Removes the indicated reader.
void poll()
Checks for any network activity and handles it, if appropriate, and then returns. ...
Definition: pStatServer.cxx:96
void move_user_guide_bar(int n, double height)
Adjusts the height of the nth user-defined guide bar.
static void sleep(double seconds)
Suspends the current thread for at least the indicated amount of time.
Definition: thread.I:236
int get_num_user_guide_bars() const
Returns the current number of user-defined guide bars.
virtual bool is_thread_safe()
This should be redefined to return true in derived classes that want to deal with multithreaded reade...
bool add_connection(Connection *connection)
Adds a new socket to the list of sockets the ConnectionReader will monitor.
bool listen(int port=-1)
Establishes a port number that the manager will listen on for TCP connections.
Definition: pStatServer.cxx:59
void main_loop(bool *interrupt_flag=NULL)
An alternative to repeatedly calling poll(), this function yields control of the program to the PStat...
Represents a single TCP or UDP socket for input or output.
Definition: connection.h:32
void release_udp_port(int port)
Indicates that the given UDP port is once again free for use.