Panda3D

Loading...
Searching...
No Matches
pStatReader.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 pStatReader.cxx
10 * @author drose
11 * @date 2000-07-09
12 */
13
14#include "pStatReader.h"
15#include "pStatServer.h"
16#include "pStatMonitor.h"
17
18#include "pStatClientControlMessage.h"
19#include "pStatServerControlMessage.h"
20#include "pStatFrameData.h"
21#include "pStatProperties.h"
22#include "datagram.h"
23#include "datagramIterator.h"
24#include "connectionManager.h"
25
26/**
27 *
28 */
29PStatReader::
30PStatReader(PStatServer *manager, PStatMonitor *monitor) :
31#ifdef HAVE_THREADS
32 ConnectionReader(manager, monitor->is_thread_safe() ? 1 : 0),
33#else // HAVE_THREADS
34 ConnectionReader(manager, 0),
35#endif // HAVE_THREADS
36 _manager(manager),
37 _monitor(monitor),
38 _writer(manager, 0)
39{
40 set_tcp_header_size(4);
41 _writer.set_tcp_header_size(4);
42 _udp_port = 0;
43 _client_data = new PStatClientData(this);
44 _monitor->set_client_data(_client_data);
45}
46
47/**
48 *
49 */
50PStatReader::
51~PStatReader() {
52 _manager->release_udp_port(_udp_port);
53}
54
55/**
56 * This will be called by the PStatClientData in response to its close() call.
57 * It will tell the server to let go of the reader so it can shut down its
58 * connection.
59 */
60 void PStatReader::
61 close() {
62 _manager->remove_reader(_tcp_connection, this);
63 lost_connection();
64}
65
66/**
67 * This is intended to be called only once, immediately after construction, by
68 * the PStatListener that created it. It tells the reader about the newly-
69 * established TCP connection to a client.
70 */
71 void PStatReader::
72 set_tcp_connection(Connection *tcp_connection) {
73 _tcp_connection = tcp_connection;
74 add_connection(_tcp_connection);
75
76 _udp_port = _manager->get_udp_port();
77 _udp_connection = _manager->open_UDP_connection(_udp_port);
78 while (_udp_connection.is_null()) {
79 // That UDP port was no good. Try another.
80 _udp_port = _manager->get_udp_port();
81 _udp_connection = _manager->open_UDP_connection(_udp_port);
82 }
83
84 add_connection(_udp_connection);
85
86 send_hello();
87}
88
89/**
90 * This is called by the PStatServer when it detects that the connection has
91 * been lost. It should clean itself up and shut down nicely.
92 */
93 void PStatReader::
94 lost_connection() {
95 _client_data->_is_alive = false;
96 _monitor->lost_connection();
97 _client_data.clear();
98
99 _manager->close_connection(_tcp_connection);
100 _manager->close_connection(_udp_connection);
101 _tcp_connection.clear();
102 _udp_connection.clear();
103}
104
105/**
106 * Called each frame to do what needs to be done for the monitor's user-
107 * defined idle routines.
108 */
109 void PStatReader::
110 idle() {
111 dequeue_frame_data();
112 _monitor->idle();
113}
114
115/**
116 * Returns the monitor that this reader serves.
117 */
118 PStatMonitor *PStatReader::
119 get_monitor() {
120 return _monitor;
121}
122
123/**
124 * Returns the current machine's hostname.
125 */
126std::string PStatReader::
127get_hostname() {
128 if (_hostname.empty()) {
129 _hostname = ConnectionManager::get_host_name();
130 if (_hostname.empty()) {
131 _hostname = "unknown";
132 }
133 }
134 return _hostname;
135}
136
137/**
138 * Sends the initial greeting message to the client.
139 */
140 void PStatReader::
141send_hello() {
142 PStatServerControlMessage message;
143 message._type = PStatServerControlMessage::T_hello;
144 message._server_hostname = get_hostname();
145 message._server_progname = _monitor->get_monitor_name();
146 message._udp_port = _udp_port;
147
148 Datagram datagram;
149 message.encode(datagram);
150 _writer.send(datagram, _tcp_connection);
151}
152
153/**
154 * Called by the net code whenever a new datagram is detected on a either the
155 * TCP or UDP connection.
156 */
157 void PStatReader::
158receive_datagram(const NetDatagram &datagram) {
159 Connection *connection = datagram.get_connection();
160
161 if (connection == _tcp_connection) {
162 PStatClientControlMessage message;
163 if (message.decode(datagram, _client_data)) {
164 handle_client_control_message(message);
165
166 } else if (message._type == PStatClientControlMessage::T_datagram) {
167 handle_client_udp_data(datagram);
168
169 } else {
170 nout << "Got unexpected message from client.\n";
171 }
172
173 } else if (connection == _udp_connection) {
174 handle_client_udp_data(datagram);
175
176 } else {
177 nout << "Got datagram from unexpected socket.\n";
178 }
179}
180
181/**
182 * Called when a control message has been received by the client over the TCP
183 * connection.
184 */
185 void PStatReader::
186handle_client_control_message(const PStatClientControlMessage &message) {
187 switch (message._type) {
188 case PStatClientControlMessage::T_hello:
189 {
190 _client_data->set_version(message._major_version, message._minor_version);
191 int server_major_version = get_current_pstat_major_version();
192 int server_minor_version = get_current_pstat_minor_version();
193
194 if (message._major_version != server_major_version ||
195 (message._major_version == server_major_version &&
196 message._minor_version > server_minor_version &&
197 (message._major_version != 3 || message._minor_version > 2))) {
198 _monitor->bad_version(message._client_hostname, message._client_progname,
199 message._major_version, message._minor_version,
200 server_major_version, server_minor_version);
201 _monitor->close();
202 } else {
203 _monitor->hello_from(message._client_hostname, message._client_progname);
204 }
205 }
206 break;
207
208 case PStatClientControlMessage::T_define_collectors:
209 {
210 for (int i = 0; i < (int)message._collectors.size(); i++) {
211 _client_data->add_collector(message._collectors[i]);
212 _monitor->new_collector(message._collectors[i]->_index);
213 }
214 }
215 break;
216
217 case PStatClientControlMessage::T_define_threads:
218 {
219 for (int i = 0; i < (int)message._names.size(); i++) {
220 int thread_index = message._first_thread_index + i;
221 std::string name = message._names[i];
222 _client_data->define_thread(thread_index, name);
223 _monitor->new_thread(thread_index);
224 }
225 }
226 break;
227
228 case PStatClientControlMessage::T_expire_thread:
229 // Ignore for now.
230 break;
231
232 default:
233 nout << "Invalid control message received from client.\n";
234 }
235}
236
237/**
238 * Called when a UDP datagram has been received by the client. This should be
239 * a single frame's worth of data.
240 */
241 void PStatReader::
242handle_client_udp_data(const Datagram &datagram) {
243 if (!_monitor->is_client_known()) {
244 // If we haven't heard a "hello" from the client yet, we don't know what
245 // version data it will be sending us, so we can't decode the data.
246 // Chances are good we can't display it sensibly yet anyway. Ignore frame
247 // data until we get that hello.
248 return;
249 }
250
251 DatagramIterator source(datagram);
252
253 if (_client_data->is_at_least(2, 1)) {
254 // Throw away the zero byte at the beginning.
255 int initial_byte = source.get_uint8();
256 nassertv(initial_byte == 0);
257 }
258
259 if (!_queued_frame_data.full()) {
260 FrameData data;
261 data._thread_index = source.get_uint16();
262 data._frame_number = source.get_uint32();
263 data._frame_data = new PStatFrameData;
264 data._frame_data->read_datagram(source, _client_data);
265
266 // Queue up the data till we're ready to handle it in a single-threaded
267 // way.
268 _queued_frame_data.push_back(data);
269 }
270}
271
272/**
273 * Called during the idle loop to pull out all the frame data that we might
274 * have read while the threaded reader was running.
275 */
276 void PStatReader::
277dequeue_frame_data() {
278 while (!_queued_frame_data.empty()) {
279 const FrameData &data = _queued_frame_data.front();
280 nassertv(_client_data != nullptr);
281
282 // Check to see if any new collectors have level data.
283 int num_levels = data._frame_data->get_num_levels();
284 for (int i = 0; i < num_levels; i++) {
285 int collector_index = data._frame_data->get_level_collector(i);
286 if (!_client_data->get_collector_has_level(collector_index, data._thread_index)) {
287 // This collector is now reporting level data, and it wasn't before.
288 _client_data->set_collector_has_level(collector_index, data._thread_index, true);
289 _monitor->new_collector(collector_index);
290 }
291 }
292
293 _client_data->record_new_frame(data._thread_index,
294 data._frame_number,
295 data._frame_data);
296 _monitor->new_data(data._thread_index, data._frame_number);
297
298 _queued_frame_data.pop_front();
299 }
300}
ConnectionManager::get_host_name
get_host_name
Returns the name of this particular machine on the network, if available, or the empty string if the ...
Definition connectionManager.h:111
ConnectionReader
This is an abstract base class for a family of classes that listen for activity on a socket and respo...
Definition connectionReader.h:50
ConnectionReader::add_connection
bool add_connection(Connection *connection)
Adds a new socket to the list of sockets the ConnectionReader will monitor.
Definition connectionReader.cxx:176
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
NetDatagram
A specific kind of Datagram, especially for sending across or receiving from a network.
Definition netDatagram.h:40
PStatClientControlMessage
This kind of message is sent from the client to the server on the TCP socket to establish critical co...
Definition pStatClientControlMessage.h:30
PStatClientControlMessage::decode
bool decode(const Datagram &datagram, PStatClientVersion *version)
Extracts the message from the indicated datagram.
Definition pStatClientControlMessage.cxx:78
PStatClientData
The data associated with a particular client, but not with any one particular frame or thread: the li...
Definition pStatClientData.h:36
PStatMonitor
This is an abstract class that presents the interface to any number of different front-ends for the s...
Definition pStatMonitor.h:39
PStatReader::lost_connection
void lost_connection()
This is called by the PStatServer when it detects that the connection has been lost.
Definition pStatReader.cxx:94
PStatReader::set_tcp_connection
void set_tcp_connection(Connection *tcp_connection)
This is intended to be called only once, immediately after construction, by the PStatListener that cr...
Definition pStatReader.cxx:72
PStatReader::idle
void idle()
Called each frame to do what needs to be done for the monitor's user- defined idle routines.
Definition pStatReader.cxx:110
PStatReader::close
void close()
This will be called by the PStatClientData in response to its close() call.
Definition pStatReader.cxx:61
PStatReader::get_monitor
PStatMonitor * get_monitor()
Returns the monitor that this reader serves.
Definition pStatReader.cxx:119
PStatServerControlMessage::encode
void encode(Datagram &datagram) const
Writes the message into the indicated datagram.
Definition pStatServerControlMessage.cxx:32
PStatServer
The overall manager of the network connections.
Definition pStatServer.h:36
connectionManager.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatClientControlMessage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatFrameData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatMonitor.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_current_pstat_major_version
int get_current_pstat_major_version()
Returns the current major version number of the PStats protocol.
Definition pStatProperties.cxx:45
get_current_pstat_minor_version
int get_current_pstat_minor_version()
Returns the current minor version number of the PStats protocol.
Definition pStatProperties.cxx:58
pStatProperties.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatServerControlMessage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatServer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.