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  */
48 bool PStatServer::
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  */
81 void PStatServer::
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  */
123 void PStatServer::
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  */
134 void PStatServer::
135 add_reader(Connection *connection, PStatReader *reader) {
136  _readers[connection] = reader;
137 }
138 
139 /**
140  * Removes the indicated reader.
141  */
142 void PStatServer::
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  */
159 int PStatServer::
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  */
172 void PStatServer::
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  */
180 int PStatServer::
182  return _user_guide_bars.size();
183 }
184 
185 /**
186  * Returns the height of the nth user-defined guide bar.
187  */
188 double PStatServer::
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  */
197 void PStatServer::
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  */
207 int PStatServer::
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  */
220 void PStatServer::
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  */
232 int PStatServer::
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  */
268 bool PStatServer::
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 }
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...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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's user- defined idle routines.
int get_num_user_guide_bars() const
Returns the current number of user-defined guide bars.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void poll()
Explicitly polls the available sockets to see if any of them have any noise.
double get_user_guide_bar_height(int n) const
Returns the height of the nth user-defined guide bar.
This is the class that does all the work for handling communications from a single Panda client.
Definition: pStatReader.h:41
This is the TCP rendezvous socket listener.
Definition: pStatListener.h:29
void lost_connection()
This is called by the PStatServer when it detects that the connection has been lost.
Definition: pStatReader.cxx:94
void add_reader(Connection *connection, PStatReader *reader)
Adds the newly-created PStatReader to the list of currently active readers.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void remove_reader(Connection *connection, PStatReader *reader)
Removes the indicated reader.
void main_loop(bool *interrupt_flag=nullptr)
An alternative to repeatedly calling poll(), this function yields control of the program to the PStat...
void poll()
Checks for any network activity and handles it, if appropriate, and then returns.
Definition: pStatServer.cxx:82
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:192
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:49
Represents a single TCP or UDP socket for input or output.
Definition: connection.h:29
void release_udp_port(int port)
Indicates that the given UDP port is once again free for use.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.