open_toontown_panda3d/pandatool/src/pstatserver/pStatReader.cxx

232 lines
7.6 KiB
C++

// Filename: pStatReader.cxx
// Created by: drose (09Jul00)
//
////////////////////////////////////////////////////////////////////
#include "pStatReader.h"
#include "pStatServer.h"
#include "pStatMonitor.h"
#include <pStatClientControlMessage.h>
#include <pStatServerControlMessage.h>
#include <pStatFrameData.h>
#include <datagram.h>
#include <datagramIterator.h>
#include <connectionManager.h>
////////////////////////////////////////////////////////////////////
// Function: PStatReader::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PStatReader::
PStatReader(PStatServer *manager, PStatMonitor *monitor) :
ConnectionReader(manager, monitor->is_thread_safe() ? 1 : 0),
_manager(manager),
_monitor(monitor),
_writer(manager, 0)
{
_udp_port = 0;
_client_data = new PStatClientData(this);
_monitor->set_client_data(_client_data);
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PStatReader::
~PStatReader() {
_manager->release_udp_port(_udp_port);
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::close
// Access: Public
// Description: This will be called by the PStatClientData in
// response to its close() call. It will tell the
// server to let go of the reader so it can shut down
// its connection.
////////////////////////////////////////////////////////////////////
void PStatReader::
close() {
_manager->remove_reader(_tcp_connection, this);
lost_connection();
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::set_tcp_connection
// Access: Public
// Description: This is intended to be called only once, immediately
// after construction, by the PStatListener that created
// it. It tells the reader about the newly-established
// TCP connection to a client.
////////////////////////////////////////////////////////////////////
void PStatReader::
set_tcp_connection(Connection *tcp_connection) {
_tcp_connection = tcp_connection;
add_connection(_tcp_connection);
_udp_port = _manager->get_udp_port();
_udp_connection = _manager->open_UDP_connection(_udp_port);
while (_udp_connection.is_null()) {
// That UDP port was no good. Try another.
_udp_port = _manager->get_udp_port();
_udp_connection = _manager->open_UDP_connection(_udp_port);
}
add_connection(_udp_connection);
send_hello();
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::lost_connection
// Access: Public
// Description: This is called by the PStatServer when it detects
// that the connection has been lost. It should clean
// itself up and shut down nicely.
////////////////////////////////////////////////////////////////////
void PStatReader::
lost_connection() {
_client_data->_is_alive = false;
_monitor->lost_connection();
_client_data.clear();
_manager->close_connection(_tcp_connection);
_manager->close_connection(_udp_connection);
_tcp_connection.clear();
_udp_connection.clear();
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::idle
// Access: Public
// Description: Called each frame to do what needs to be done for the
// monitor's user-defined idle routines.
////////////////////////////////////////////////////////////////////
void PStatReader::
idle() {
_monitor->idle();
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::get_hostname
// Access: Private
// Description: Returns the current machine's hostname.
////////////////////////////////////////////////////////////////////
string PStatReader::
get_hostname() {
if (_hostname.empty()) {
_hostname = ConnectionManager::get_host_name();
if (_hostname.empty()) {
_hostname = "unknown";
}
}
return _hostname;
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::send_hello
// Access: Private
// Description: Sends the initial greeting message to the client.
////////////////////////////////////////////////////////////////////
void PStatReader::
send_hello() {
PStatServerControlMessage message;
message._type = PStatServerControlMessage::T_hello;
message._server_hostname = get_hostname();
message._server_progname = _monitor->get_monitor_name();
message._udp_port = _udp_port;
Datagram datagram;
message.encode(datagram);
_writer.send(datagram, _tcp_connection);
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::receive_datagram
// Access: Private, Virtual
// Description: Called by the net code whenever a new datagram is
// detected on a either the TCP or UDP connection.
////////////////////////////////////////////////////////////////////
void PStatReader::
receive_datagram(const NetDatagram &datagram) {
Connection *connection = datagram.get_connection();
if (connection == _tcp_connection) {
PStatClientControlMessage message;
if (message.decode(datagram)) {
handle_client_control_message(message);
} else {
nout << "Got unexpected message from client.\n";
}
} else if (connection == _udp_connection) {
handle_client_udp_data(datagram);
} else {
nout << "Got datagram from unexpected socket.\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::handle_client_control_message
// Access: Private
// Description: Called when a control message has been received by
// the client over the TCP connection.
////////////////////////////////////////////////////////////////////
void PStatReader::
handle_client_control_message(const PStatClientControlMessage &message) {
switch (message._type) {
case PStatClientControlMessage::T_hello:
_monitor->hello_from(message._client_hostname, message._client_progname);
break;
case PStatClientControlMessage::T_define_collectors:
{
for (int i = 0; i < (int)message._collectors.size(); i++) {
_client_data->add_collector(message._collectors[i]);
_monitor->new_collector(message._collectors[i]->_index);
}
}
break;
case PStatClientControlMessage::T_define_threads:
{
for (int i = 0; i < (int)message._names.size(); i++) {
int thread_index = message._first_thread_index + i;
string name = message._names[i];
_client_data->define_thread(thread_index, name);
_monitor->new_thread(thread_index);
}
}
break;
default:
nout << "Invalid control message received from client.\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: PStatReader::handle_client_udp_data
// Access: Private
// Description: Called when a UDP datagram has been received by the
// client. This should be a single frame's worth of
// data.
////////////////////////////////////////////////////////////////////
void PStatReader::
handle_client_udp_data(const Datagram &datagram) {
DatagramIterator source(datagram);
int thread_index = source.get_uint16();
int frame_number = source.get_uint32();
PStatFrameData *frame_data = new PStatFrameData;
frame_data->read_datagram(source);
_client_data->record_new_frame(thread_index, frame_number, frame_data);
_monitor->new_data(thread_index, frame_number);
}