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