Panda3D

pStatReader.cxx

00001 // Filename: pStatReader.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 "pStatReader.h"
00016 #include "pStatServer.h"
00017 #include "pStatMonitor.h"
00018 
00019 #include "pStatClientControlMessage.h"
00020 #include "pStatServerControlMessage.h"
00021 #include "pStatFrameData.h"
00022 #include "pStatProperties.h"
00023 #include "datagram.h"
00024 #include "datagramIterator.h"
00025 #include "connectionManager.h"
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: PStatReader::Constructor
00029 //       Access: Public
00030 //  Description:
00031 ////////////////////////////////////////////////////////////////////
00032 PStatReader::
00033 PStatReader(PStatServer *manager, PStatMonitor *monitor) :
00034 #ifdef HAVE_THREADS
00035   ConnectionReader(manager, monitor->is_thread_safe() ? 1 : 0),
00036 #else  // HAVE_THREADS
00037   ConnectionReader(manager, 0),
00038 #endif  // HAVE_THREADS
00039   _manager(manager),
00040   _monitor(monitor),
00041   _writer(manager, 0)
00042 {
00043   set_tcp_header_size(4);
00044   _writer.set_tcp_header_size(4);
00045   _udp_port = 0;
00046   _client_data = new PStatClientData(this);
00047   _monitor->set_client_data(_client_data);
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: PStatReader::Destructor
00052 //       Access: Public
00053 //  Description:
00054 ////////////////////////////////////////////////////////////////////
00055 PStatReader::
00056 ~PStatReader() {
00057   _manager->release_udp_port(_udp_port);
00058 }
00059 
00060 ////////////////////////////////////////////////////////////////////
00061 //     Function: PStatReader::close
00062 //       Access: Public
00063 //  Description: This will be called by the PStatClientData in
00064 //               response to its close() call.  It will tell the
00065 //               server to let go of the reader so it can shut down
00066 //               its connection.
00067 ////////////////////////////////////////////////////////////////////
00068 void PStatReader::
00069 close() {
00070   _manager->remove_reader(_tcp_connection, this);
00071   lost_connection();
00072 }
00073 
00074 ////////////////////////////////////////////////////////////////////
00075 //     Function: PStatReader::set_tcp_connection
00076 //       Access: Public
00077 //  Description: This is intended to be called only once, immediately
00078 //               after construction, by the PStatListener that created
00079 //               it.  It tells the reader about the newly-established
00080 //               TCP connection to a client.
00081 ////////////////////////////////////////////////////////////////////
00082 void PStatReader::
00083 set_tcp_connection(Connection *tcp_connection) {
00084   _tcp_connection = tcp_connection;
00085   add_connection(_tcp_connection);
00086 
00087   _udp_port = _manager->get_udp_port();
00088   _udp_connection = _manager->open_UDP_connection(_udp_port);
00089   while (_udp_connection.is_null()) {
00090     // That UDP port was no good.  Try another.
00091     _udp_port = _manager->get_udp_port();
00092     _udp_connection = _manager->open_UDP_connection(_udp_port);
00093   }
00094 
00095   add_connection(_udp_connection);
00096 
00097   send_hello();
00098 }
00099 
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: PStatReader::lost_connection
00102 //       Access: Public
00103 //  Description: This is called by the PStatServer when it detects
00104 //               that the connection has been lost.  It should clean
00105 //               itself up and shut down nicely.
00106 ////////////////////////////////////////////////////////////////////
00107 void PStatReader::
00108 lost_connection() {
00109   _client_data->_is_alive = false;
00110   _monitor->lost_connection();
00111   _client_data.clear();
00112 
00113   _manager->close_connection(_tcp_connection);
00114   _manager->close_connection(_udp_connection);
00115   _tcp_connection.clear();
00116   _udp_connection.clear();
00117 }
00118 
00119 ////////////////////////////////////////////////////////////////////
00120 //     Function: PStatReader::idle
00121 //       Access: Public
00122 //  Description: Called each frame to do what needs to be done for the
00123 //               monitor's user-defined idle routines.
00124 ////////////////////////////////////////////////////////////////////
00125 void PStatReader::
00126 idle() {
00127   dequeue_frame_data();
00128   _monitor->idle();
00129 }
00130 
00131 ////////////////////////////////////////////////////////////////////
00132 //     Function: PStatReader::get_monitor
00133 //       Access: Public
00134 //  Description: Returns the monitor that this reader serves.
00135 ////////////////////////////////////////////////////////////////////
00136 PStatMonitor *PStatReader::
00137 get_monitor() {
00138   return _monitor;
00139 }
00140 
00141 ////////////////////////////////////////////////////////////////////
00142 //     Function: PStatReader::get_hostname
00143 //       Access: Private
00144 //  Description: Returns the current machine's hostname.
00145 ////////////////////////////////////////////////////////////////////
00146 string PStatReader::
00147 get_hostname() {
00148   if (_hostname.empty()) {
00149     _hostname = ConnectionManager::get_host_name();
00150     if (_hostname.empty()) {
00151       _hostname = "unknown";
00152     }
00153   }
00154   return _hostname;
00155 }
00156 
00157 ////////////////////////////////////////////////////////////////////
00158 //     Function: PStatReader::send_hello
00159 //       Access: Private
00160 //  Description: Sends the initial greeting message to the client.
00161 ////////////////////////////////////////////////////////////////////
00162 void PStatReader::
00163 send_hello() {
00164   PStatServerControlMessage message;
00165   message._type = PStatServerControlMessage::T_hello;
00166   message._server_hostname = get_hostname();
00167   message._server_progname = _monitor->get_monitor_name();
00168   message._udp_port = _udp_port;
00169 
00170   Datagram datagram;
00171   message.encode(datagram);
00172   _writer.send(datagram, _tcp_connection);
00173 }
00174 
00175 ////////////////////////////////////////////////////////////////////
00176 //     Function: PStatReader::receive_datagram
00177 //       Access: Private, Virtual
00178 //  Description: Called by the net code whenever a new datagram is
00179 //               detected on a either the TCP or UDP connection.
00180 ////////////////////////////////////////////////////////////////////
00181 void PStatReader::
00182 receive_datagram(const NetDatagram &datagram) {
00183   Connection *connection = datagram.get_connection();
00184 
00185   if (connection == _tcp_connection) {
00186     PStatClientControlMessage message;
00187     if (message.decode(datagram, _client_data)) {
00188       handle_client_control_message(message);
00189 
00190     } else if (message._type == PStatClientControlMessage::T_datagram) {
00191       handle_client_udp_data(datagram);
00192 
00193     } else {
00194       nout << "Got unexpected message from client.\n";
00195     }
00196 
00197   } else if (connection == _udp_connection) {
00198     handle_client_udp_data(datagram);
00199 
00200   } else {
00201     nout << "Got datagram from unexpected socket.\n";
00202   }
00203 }
00204 
00205 ////////////////////////////////////////////////////////////////////
00206 //     Function: PStatReader::handle_client_control_message
00207 //       Access: Private
00208 //  Description: Called when a control message has been received by
00209 //               the client over the TCP connection.
00210 ////////////////////////////////////////////////////////////////////
00211 void PStatReader::
00212 handle_client_control_message(const PStatClientControlMessage &message) {
00213   switch (message._type) {
00214   case PStatClientControlMessage::T_hello:
00215     {
00216       _client_data->set_version(message._major_version, message._minor_version);
00217       int server_major_version = get_current_pstat_major_version();
00218       int server_minor_version = get_current_pstat_minor_version();
00219 
00220       if (message._major_version != server_major_version ||
00221           (message._major_version == server_major_version &&
00222            message._minor_version > server_minor_version)) {
00223         _monitor->bad_version(message._client_hostname, message._client_progname,
00224                               message._major_version, message._minor_version,
00225                               server_major_version, server_minor_version);
00226         _monitor->close();
00227       } else {
00228         _monitor->hello_from(message._client_hostname, message._client_progname);
00229       }
00230     }
00231     break;
00232 
00233   case PStatClientControlMessage::T_define_collectors:
00234     {
00235       for (int i = 0; i < (int)message._collectors.size(); i++) {
00236         _client_data->add_collector(message._collectors[i]);
00237         _monitor->new_collector(message._collectors[i]->_index);
00238       }
00239     }
00240     break;
00241 
00242   case PStatClientControlMessage::T_define_threads:
00243     {
00244       for (int i = 0; i < (int)message._names.size(); i++) {
00245         int thread_index = message._first_thread_index + i;
00246         string name = message._names[i];
00247         _client_data->define_thread(thread_index, name);
00248         _monitor->new_thread(thread_index);
00249       }
00250     }
00251     break;
00252 
00253   default:
00254     nout << "Invalid control message received from client.\n";
00255   }
00256 }
00257 
00258 ////////////////////////////////////////////////////////////////////
00259 //     Function: PStatReader::handle_client_udp_data
00260 //       Access: Private
00261 //  Description: Called when a UDP datagram has been received by the
00262 //               client.  This should be a single frame's worth of
00263 //               data.
00264 ////////////////////////////////////////////////////////////////////
00265 void PStatReader::
00266 handle_client_udp_data(const Datagram &datagram) {
00267   if (!_monitor->is_client_known()) {
00268     // If we haven't heard a "hello" from the client yet, we don't
00269     // know what version data it will be sending us, so we can't
00270     // decode the data.  Chances are good we can't display it sensibly
00271     // yet anyway.  Ignore frame data until we get that hello.
00272     return;
00273   }
00274 
00275   DatagramIterator source(datagram);
00276 
00277   if (_client_data->is_at_least(2, 1)) {
00278     // Throw away the zero byte at the beginning.
00279     int initial_byte = source.get_uint8();
00280     nassertv(initial_byte == 0);
00281   }
00282 
00283   if (!_queued_frame_data.full()) {
00284     FrameData data;
00285     data._thread_index = source.get_uint16();
00286     data._frame_number = source.get_uint32();
00287     data._frame_data = new PStatFrameData;
00288     data._frame_data->read_datagram(source, _client_data);
00289     
00290     // Queue up the data till we're ready to handle it in a
00291     // single-threaded way.
00292     _queued_frame_data.push_back(data);
00293   }
00294 }
00295 
00296 ////////////////////////////////////////////////////////////////////
00297 //     Function: PStatReader::dequeue_frame_data
00298 //       Access: Private
00299 //  Description: Called during the idle loop to pull out all the frame
00300 //               data that we might have read while the threaded
00301 //               reader was running.
00302 ////////////////////////////////////////////////////////////////////
00303 void PStatReader::
00304 dequeue_frame_data() {
00305   while (!_queued_frame_data.empty()) {
00306     const FrameData &data = _queued_frame_data.front();
00307     nassertv(_client_data != (PStatClientData *)NULL); 
00308 
00309     // Check to see if any new collectors have level data.
00310     int num_levels = data._frame_data->get_num_levels();
00311     for (int i = 0; i < num_levels; i++) {
00312       int collector_index = data._frame_data->get_level_collector(i);
00313       if (!_client_data->get_collector_has_level(collector_index, data._thread_index)) {
00314         // This collector is now reporting level data, and it wasn't
00315         // before.
00316         _client_data->set_collector_has_level(collector_index, data._thread_index, true);
00317         _monitor->new_collector(collector_index);
00318       }
00319     }
00320 
00321     _client_data->record_new_frame(data._thread_index, 
00322                                    data._frame_number, 
00323                                    data._frame_data);
00324     _monitor->new_data(data._thread_index, data._frame_number);
00325 
00326     _queued_frame_data.pop_front();
00327   }
00328 }
00329 
 All Classes Functions Variables Enumerations