CConnectionRepository

This commit is contained in:
David Rose 2004-05-19 20:19:36 +00:00
parent 0058660904
commit ec535f800a
11 changed files with 661 additions and 271 deletions

View File

@ -8,7 +8,7 @@
#define BUILDING_DLL BUILDING_DIRECT
#define COMPONENT_LIBS \
directbase dcparser showbase deadrec directd interval
directbase dcparser showbase deadrec directd interval distributed
#define OTHER_LIBS \
panda:m \

View File

@ -1,5 +1,3 @@
"""ServerRepository module: contains the ServerRepository class"""
from PandaModules import *
from ClusterMsgs import *
from MsgTypes import *

View File

@ -53,7 +53,7 @@ class ClientRepository(ConnectionRepository.ConnectionRepository):
self.relatedObjectMgr.abortAllRequests()
def sendDisconnect(self):
if self.tcpConn:
if self.isConnected():
# Tell the game server that we're going:
datagram = PyDatagram()
# Add message type
@ -287,8 +287,6 @@ class ClientRepository(ConnectionRepository.ConnectionRepository):
# Get the DO Id
doId = di.getArg(STUint32)
#print("Updating " + str(doId))
if self.rsDoReport:
self.rsUpdateObjs[doId] = self.rsUpdateObjs.get(doId, 0) + 1
# Find the DO
do = self.doId2do.get(doId)
@ -398,8 +396,7 @@ class ClientRepository(ConnectionRepository.ConnectionRepository):
self.lastHeartbeat = globalClock.getRealTime()
# This is important enough to consider flushing immediately
# (particularly if we haven't run readerPollTask recently).
if self.tcpConn:
self.tcpConn.considerFlush()
self.considerFlush()
def considerHeartbeat(self):
"""Send a heartbeat message if we haven't sent one recently."""

View File

@ -6,7 +6,7 @@ from PyDatagram import PyDatagram
import types
class ConnectionRepository(DirectObject.DirectObject):
class ConnectionRepository(DirectObject.DirectObject, CConnectionRepository):
"""
This is a base class for things that know how to establish a
connection (and exchange datagrams) with a gameserver. This
@ -19,6 +19,7 @@ class ConnectionRepository(DirectObject.DirectObject):
def __init__(self, config):
DirectObject.DirectObject.__init__(self)
CConnectionRepository.__init__(self)
self.config = config
@ -40,22 +41,11 @@ class ConnectionRepository(DirectObject.DirectObject):
# proxy is in place, but the NSPR interface if we don't have a
# proxy.
self.connectMethod = self.config.GetString('connect-method', 'default')
self.connectHttp = None
self.http = None
self.qcm = None
self.cw = None
self.tcpConn = None
self.recorder = None
# Reader statistics
self.rsDatagramCount = 0
self.rsUpdateObjs = {}
self.rsLastUpdate = 0
self.rsDoReport = self.config.GetBool('reader-statistics', 0)
self.rsUpdateInterval = self.config.GetDouble('reader-statistics-interval', 10)
def readDCFile(self, dcFileNames = None):
""" Reads in the dc files listed in dcFileNames, or if
@ -162,21 +152,21 @@ class ConnectionRepository(DirectObject.DirectObject):
known.
"""
if self.recorder and self.recorder.isPlaying():
## if self.recorder and self.recorder.isPlaying():
# If we have a recorder and it's already in playback mode,
# don't actually attempt to connect to a gameserver since
# we don't need to. Just let it play back the data.
self.notify.info("Not connecting to gameserver; using playback data instead.")
## # If we have a recorder and it's already in playback mode,
## # don't actually attempt to connect to a gameserver since
## # we don't need to. Just let it play back the data.
## self.notify.info("Not connecting to gameserver; using playback data instead.")
self.connectHttp = 1
self.tcpConn = SocketStreamRecorder()
self.recorder.addRecorder('gameserver', self.tcpConn)
## self.connectHttp = 1
## self.tcpConn = SocketStreamRecorder()
## self.recorder.addRecorder('gameserver', self.tcpConn)
self.startReaderPollTask()
if successCallback:
successCallback(*successArgs)
return
## self.startReaderPollTask()
## if successCallback:
## successCallback(*successArgs)
## return
hasProxy = 0
if self.checkHttp():
@ -212,31 +202,10 @@ class ConnectionRepository(DirectObject.DirectObject):
failureCallback, failureArgs)
else:
if self.qcm == None:
self.qcm = QueuedConnectionManager()
if self.cw == None:
self.cw = ConnectionWriter(self.qcm, 0)
self.qcr = QueuedConnectionReader(self.qcm, 0)
minLag = self.config.GetFloat('min-lag', 0.)
maxLag = self.config.GetFloat('max-lag', 0.)
if minLag or maxLag:
self.qcr.startDelay(minLag, maxLag)
# A big old 20 second timeout.
gameServerTimeoutMs = self.config.GetInt("game-server-timeout-ms",
20000)
# Try each of the servers in turn.
for url in serverList:
self.notify.info("Connecting to %s via NSPR interface." % (url.cStr()))
self.tcpConn = self.qcm.openTCPClientConnection(
url.getServer(), url.getPort(),
gameServerTimeoutMs)
if self.tcpConn:
self.tcpConn.setNoDelay(1)
self.qcr.addConnection(self.tcpConn)
if self.tryConnectNspr(url):
self.startReaderPollTask()
if successCallback:
successCallback(*successArgs)
@ -250,37 +219,31 @@ class ConnectionRepository(DirectObject.DirectObject):
"""Closes the previously-established connection.
"""
self.notify.info("Closing connection to server.")
if self.tcpConn != None:
if self.connectHttp:
self.tcpConn.close()
else:
self.qcm.closeConnection(self.tcpConn)
self.tcpConn = None
CConnectionRepository.disconnect(self)
self.stopReaderPollTask()
def httpConnectCallback(self, ch, serverList, serverIndex,
successCallback, successArgs,
failureCallback, failureArgs):
if ch.isConnectionReady():
self.tcpConn = ch.getConnection()
self.tcpConn.userManagesMemory = 1
self.setConnectionHttp(ch)
if self.recorder:
# If we have a recorder, we wrap the connect inside a
# SocketStreamRecorder, which will trap incoming data
# when the recorder is set to record mode. (It will
# also play back data when the recorder is in playback
# mode, but in that case we never get this far in the
# code, since we just create an empty
# SocketStreamRecorder without actually connecting to
# the gameserver.)
stream = SocketStreamRecorder(self.tcpConn, 1)
self.recorder.addRecorder('gameserver', stream)
## if self.recorder:
## # If we have a recorder, we wrap the connect inside a
## # SocketStreamRecorder, which will trap incoming data
## # when the recorder is set to record mode. (It will
## # also play back data when the recorder is in playback
## # mode, but in that case we never get this far in the
## # code, since we just create an empty
## # SocketStreamRecorder without actually connecting to
## # the gameserver.)
## stream = SocketStreamRecorder(self.tcpConn, 1)
## self.recorder.addRecorder('gameserver', stream)
# In this case, we pass ownership of the original
# connection to the SocketStreamRecorder object.
self.tcpConn.userManagesMemory = 0
self.tcpConn = stream
## # In this case, we pass ownership of the original
## # connection to the SocketStreamRecorder object.
## self.tcpConn.userManagesMemory = 0
## self.tcpConn = stream
self.startReaderPollTask()
if successCallback:
@ -334,68 +297,17 @@ class ConnectionRepository(DirectObject.DirectObject):
return Task.cont
def readerPollOnce(self):
# we simulate the network plug being pulled by setting tcpConn
# to None; enforce that condition
if not self.tcpConn:
return 0
if self.checkDatagram():
dg = PyDatagram()
self.getDatagram(dg)
self.handleDatagram(dg)
return 1
# Make sure any recently-sent datagrams are flushed when the
# time expires, if we're in collect-tcp mode.
self.tcpConn.considerFlush()
if self.rsDoReport:
self.reportReaderStatistics()
if self.connectHttp:
datagram = PyDatagram()
if self.tcpConn.receiveDatagram(datagram):
if self.rsDoReport:
self.rsDatagramCount += 1
self.handleDatagram(datagram)
return 1
# Unable to receive a datagram: did we lose the connection?
if self.tcpConn.isClosed():
self.tcpConn = None
self.stopReaderPollTask()
self.lostConnection()
return 0
else:
self.ensureValidConnection()
if self.qcr.dataAvailable():
datagram = NetDatagram()
if self.qcr.getData(datagram):
if self.rsDoReport:
self.rsDatagramCount += 1
self.handleDatagram(datagram)
return 1
return 0
def flush(self):
# Ensure the latest has been sent to the server.
if self.tcpConn:
self.tcpConn.flush()
def ensureValidConnection(self):
# Was the connection reset?
if self.connectHttp:
pass
else:
if self.qcm.resetConnectionAvailable():
resetConnectionPointer = PointerToConnection()
if self.qcm.getResetConnection(resetConnectionPointer):
resetConn = resetConnectionPointer.p()
self.qcm.closeConnection(resetConn)
# if we've simulated a network plug pull, restore the
# simulated plug
self.restoreNetworkPlug()
if self.tcpConn.this == resetConn.this:
self.tcpConn = None
self.stopReaderPollTask()
self.lostConnection()
else:
self.notify.warning("Lost unknown connection.")
# Unable to receive a datagram: did we lose the connection?
if not self.isConnected():
self.stopReaderPollTask()
self.lostConnection()
return 0
def lostConnection(self):
# This should be overrided by a derived class to handle an
@ -407,50 +319,22 @@ class ConnectionRepository(DirectObject.DirectObject):
# inherit from it need to make their own handleDatagram method
pass
def reportReaderStatistics(self):
now = globalClock.getRealTime()
if now - self.rsLastUpdate < self.rsUpdateInterval:
return
self.rsLastUpdate = now
self.notify.info("Received %s datagrams" % (self.rsDatagramCount))
if self.rsUpdateObjs:
self.notify.info("Updates: %s" % (self.rsUpdateObjs))
self.rsDatagramCount = 0
self.rsUpdateObjs = {}
def send(self, datagram):
#if self.notify.getDebug():
# print "ConnectionRepository sending datagram:"
# datagram.dumpHex(ostream)
if not self.tcpConn:
self.notify.warning("Unable to send message after connection is closed.")
return
if self.connectHttp:
if not self.tcpConn.sendDatagram(datagram):
self.notify.warning("Could not send datagram.")
else:
self.cw.send(datagram, self.tcpConn)
self.sendDatagram(datagram)
# debugging funcs for simulating a network-plug-pull
def pullNetworkPlug(self):
self.restoreNetworkPlug()
self.notify.warning('*** SIMULATING A NETWORK-PLUG-PULL ***')
self.hijackedTcpConn = self.tcpConn
self.tcpConn = None
self.setSimulatedDisconnect(1)
def networkPlugPulled(self):
return hasattr(self, 'hijackedTcpConn')
return self.getSimulatedDisconnect()
def restoreNetworkPlug(self):
if self.networkPlugPulled():
self.notify.info('*** RESTORING SIMULATED PULLED-NETWORK-PLUG ***')
self.tcpConn = self.hijackedTcpConn
del self.hijackedTcpConn
self.setSimulatedDisconnect(0)
def doFind(self, str):
""" returns list of distributed objects with matching str in value """

View File

@ -1,99 +0,0 @@
"""ServerRepository module: contains the ServerRepository class"""
from PandaModules import *
from TaskManagerGlobal import *
from MsgTypes import *
import Task
import DirectNotifyGlobal
from PyDatagram import PyDatagram
from PyDatagramIterator import PyDatagramIterator
class ServerRepository:
def __init__(self, tcpPort, udpPort):
self.qcm = QueuedConnectionManager()
self.qcl = QueuedConnectionListener(self.qcm, 0)
self.qcr = QueuedConnectionReader(self.qcm, 0)
self.cw = ConnectionWriter(self.qcm,0)
self.tcpRendezvous = self.qcm.openTCPServerRendezvous(tcpPort, 10)
print self.tcpRendezvous
self.qcl.addConnection(self.tcpRendezvous)
self.startListenerPollTask()
self.startReaderPollTask()
self.startResetPollTask()
def startListenerPollTask(self):
taskMgr.add(self.listenerPoll, "serverListenerPollTask")
def listenerPoll(self, task):
if self.qcl.newConnectionAvailable():
print "New connection is available"
rendezvous = PointerToConnection()
netAddress = NetAddress()
newConnection = PointerToConnection()
retVal = self.qcl.getNewConnection(rendezvous, netAddress,
newConnection)
if retVal:
# Crazy dereferencing
newConnection=newConnection.p()
self.qcr.addConnection(newConnection)
print "Got a connection!"
self.lastConnection = newConnection
else:
ServerRepository.notify.warning(
"getNewConnection returned false")
return Task.cont
def startReaderPollTask(self):
taskMgr.add(self.readerPollUntilEmpty, "serverReaderPollTask")
def readerPollUntilEmpty(self, task):
while self.readerPollOnce():
pass
return Task.cont
def readerPollOnce(self):
availGetVal = self.qcr.dataAvailable()
if availGetVal:
datagram = NetDatagram()
readRetVal = self.qcr.getData(datagram)
if readRetVal:
self.handleDatagram(datagram)
else:
ClientRepository.notify.warning("getData returned false")
return availGetVal
def handleDatagram(self, datagram):
print "Server got a datagram!"
dgi = PyDatagramIterator(datagram)
print dgi.getUint16()
print dgi.getString()
print dgi.getUint32()
print dgi.getUint16()
newDatagram = PyDatagram()
newDatagram.addUint16(LOGIN_RESPONSE)
newDatagram.addUint8(ord('s'))
self.cw.send(newDatagram, self.lastConnection)
def sendAvatarGenerate(self):
datagram = PyDatagram()
# Message type is 1
datagram.addUint16(ALL_OBJECT_GENERATE_WITH_REQUIRED)
# Avatar class type is 2
datagram.addUint8(2)
# A sample id
datagram.addUint32(10)
# The only required field is the zone field
datagram.addUint32(999)
self.cw.send(datagram, self.lastConnection)
def startResetPollTask(self):
return None
def resetPollUntilEmpty(self):
return None
def resetPollOnce(self):
return None

View File

@ -1,3 +1,18 @@
// For now, since we are not installing Python files, this file can
// remain empty.
#begin lib_target
#define BUILD_TARGET $[HAVE_PYTHON]
#define TARGET distributed
#define LOCAL_LIBS \
directbase
#define OTHER_LIBS \
downloader:c net:c panda:m express:c pandaexpress:m \
interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
#define SOURCES \
config_distributed.cxx config_distributed.h \
cConnectionRepository.cxx cConnectionRepository.I \
cConnectionRepository.h
#define IGATESCAN all
#end lib_target

View File

@ -0,0 +1,97 @@
// Filename: cConnectionRepository.I
// Created by: drose (17May04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifdef HAVE_NSPR
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::get_qcm
// Access: Published
// Description: Returns the QueuedConnectionManager object associated
// with the repository.
////////////////////////////////////////////////////////////////////
INLINE QueuedConnectionManager &CConnectionRepository::
get_qcm() {
return _qcm;
}
#endif // HAVE_NSPR
#ifdef HAVE_NSPR
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::get_cw
// Access: Published
// Description: Returns the ConnectionWriter object associated
// with the repository.
////////////////////////////////////////////////////////////////////
INLINE ConnectionWriter &CConnectionRepository::
get_cw() {
return _cw;
}
#endif // HAVE_NSPR
#ifdef HAVE_NSPR
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::get_qcr
// Access: Published
// Description: Returns the QueuedConnectionReader object associated
// with the repository.
////////////////////////////////////////////////////////////////////
INLINE QueuedConnectionReader &CConnectionRepository::
get_qcr() {
return _qcr;
}
#endif // HAVE_NSPR
INLINE ConnectionWriter &get_cw();
INLINE QueuedConnectionReader &get_qcr();
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::get_datagram
// Access: Published
// Description: Fills the datagram object with the datagram most
// recently retrieved by check_datagram().
////////////////////////////////////////////////////////////////////
INLINE void CConnectionRepository::
get_datagram(Datagram &dg) {
dg = _dg;
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::set_simulated_disconnect
// Access: Published
// Description: Sets the simulated disconnect flag. While this is
// true, no datagrams will be retrieved from or sent to
// the server. The idea is to simulate a temporary
// network outage.
////////////////////////////////////////////////////////////////////
INLINE void CConnectionRepository::
set_simulated_disconnect(bool simulated_disconnect) {
_simulated_disconnect = simulated_disconnect;
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::get_simulated_disconnect
// Access: Published
// Description: Returns the simulated disconnect flag. While this is
// true, no datagrams will be retrieved from or sent to
// the server. The idea is to simulate a temporary
// network outage.
////////////////////////////////////////////////////////////////////
INLINE bool CConnectionRepository::
get_simulated_disconnect() const {
return _simulated_disconnect;
}

View File

@ -0,0 +1,305 @@
// Filename: cConnectionRepository.cxx
// Created by: drose (17May04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "cConnectionRepository.h"
#include "config_distributed.h"
#include "httpChannel.h"
#include "urlSpec.h"
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
CConnectionRepository::
CConnectionRepository() :
#ifdef HAVE_SSL
_http_conn(NULL),
#endif
#ifdef HAVE_NSPR
_cw(&_qcm, 0),
_qcr(&_qcm, 0),
#endif
_simulated_disconnect(false)
{
#ifdef HAVE_NSPR
if (min_lag != 0.0 || max_lag != 0.0) {
_qcr.start_delay(min_lag, max_lag);
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
CConnectionRepository::
~CConnectionRepository() {
disconnect();
}
#ifdef HAVE_SSL
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::set_connection_http
// Access: Published
// Description: Once a connection has been established via the HTTP
// interface, gets the connection and uses it. The
// supplied HTTPChannel object must have a connection
// available via get_connection().
////////////////////////////////////////////////////////////////////
void CConnectionRepository::
set_connection_http(HTTPChannel *channel) {
disconnect();
nassertv(channel->is_connection_ready());
_http_conn = channel->get_connection();
}
#endif // HAVE_SSL
#ifdef HAVE_NSPR
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::try_connect_nspr
// Access: Published
// Description: Uses NSPR to try to connect to the server and port
// named in the indicated URL. Returns true if
// successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool CConnectionRepository::
try_connect_nspr(const URLSpec &url) {
disconnect();
_nspr_conn =
_qcm.open_TCP_client_connection(url.get_server(), url.get_port(),
game_server_timeout_ms);
if (_nspr_conn != (Connection *)NULL) {
_nspr_conn->set_no_delay(true);
_qcr.add_connection(_nspr_conn);
return true;
}
return false;
}
#endif // HAVE_NSPR
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::check_datagram
// Access: Published
// Description: Returns true if a new datagram is available, false
// otherwise. If the return value is true, the new
// datagram may be retrieved via get_datagram().
////////////////////////////////////////////////////////////////////
bool CConnectionRepository::
check_datagram() {
if (_simulated_disconnect) {
return false;
}
return do_check_datagram();
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::is_connected
// Access: Published
// Description: Returns true if the connection to the gameserver is
// established and still good, false if we are not
// connected. A false value means either (a) we never
// successfully connected, (b) we explicitly called
// disconnect(), or (c) we were connected, but the
// connection was spontaneously lost.
////////////////////////////////////////////////////////////////////
bool CConnectionRepository::
is_connected() {
#ifdef HAVE_NSPR
if (_nspr_conn) {
if (_qcm.reset_connection_available()) {
PT(Connection) reset_connection;
if (_qcm.get_reset_connection(reset_connection)) {
_qcm.close_connection(reset_connection);
if (reset_connection == _nspr_conn) {
// Whoops, lost our connection.
_nspr_conn = NULL;
return false;
}
}
}
return true;
}
#endif // HAVE_NSPR
#ifdef HAVE_SSL
if (_http_conn) {
if (!_http_conn->is_closed()) {
return true;
}
// Connection lost.
delete _http_conn;
_http_conn = NULL;
}
#endif // HAVE_SSL
return false;
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::send_datagram
// Access: Published
// Description: Queues the indicated datagram for sending to the
// server. It may not get send immediately if
// collect_tcp is in effect; call flush() to guarantee
// it is sent now.
////////////////////////////////////////////////////////////////////
bool CConnectionRepository::
send_datagram(const Datagram &dg) {
if (_simulated_disconnect) {
distributed_cat.warning()
<< "Unable to send datagram during simulated disconnect.\n";
return false;
}
#ifdef HAVE_NSPR
if (_nspr_conn) {
_cw.send(dg, _nspr_conn);
return true;
}
#endif // HAVE_NSPR
#ifdef HAVE_SSL
if (_http_conn) {
if (!_http_conn->send_datagram(dg)) {
distributed_cat.warning()
<< "Could not send datagram.\n";
return false;
}
return true;
}
#endif // HAVE_SSL
distributed_cat.warning()
<< "Unable to send datagram after connection is closed.\n";
return false;
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::consider_flush
// Access: Published
// Description: Sends the most recently queued data if enough time
// has elapsed. This only has meaning if
// set_collect_tcp() has been set to true.
////////////////////////////////////////////////////////////////////
bool CConnectionRepository::
consider_flush() {
if (_simulated_disconnect) {
return false;
}
#ifdef HAVE_NSPR
if (_nspr_conn) {
return _nspr_conn->consider_flush();
}
#endif // HAVE_NSPR
#ifdef HAVE_SSL
if (_http_conn) {
return _http_conn->consider_flush();
}
#endif // HAVE_SSL
return false;
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::flush
// Access: Published
// Description: Sends the most recently queued data now. This only
// has meaning if set_collect_tcp() has been set to
// true.
////////////////////////////////////////////////////////////////////
bool CConnectionRepository::
flush() {
if (_simulated_disconnect) {
return false;
}
#ifdef HAVE_NSPR
if (_nspr_conn) {
return _nspr_conn->flush();
}
#endif // HAVE_NSPR
#ifdef HAVE_SSL
if (_http_conn) {
return _http_conn->flush();
}
#endif // HAVE_SSL
return false;
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::disconnect
// Access: Published
// Description: Closes the connection to the server.
////////////////////////////////////////////////////////////////////
void CConnectionRepository::
disconnect() {
#ifdef HAVE_NSPR
if (_nspr_conn) {
_qcm.close_connection(_nspr_conn);
_nspr_conn = NULL;
}
#endif // HAVE_NSPR
#ifdef HAVE_SSL
if (_http_conn) {
_http_conn->close();
delete _http_conn;
_http_conn = NULL;
}
#endif // HAVE_SSL
_simulated_disconnect = false;
}
////////////////////////////////////////////////////////////////////
// Function: CConnectionRepository::do_check_datagram
// Access: Private
// Description: The private implementation of check_datagram(), this
// gets one datagram if it is available.
////////////////////////////////////////////////////////////////////
bool CConnectionRepository::
do_check_datagram() {
#ifdef HAVE_NSPR
if (_nspr_conn) {
_nspr_conn->consider_flush();
return (_qcr.data_available() && _qcr.get_data(_dg));
}
#endif // HAVE_NSPR
#ifdef HAVE_SSL
if (_http_conn) {
_http_conn->consider_flush();
return _http_conn->receive_datagram(_dg);
}
#endif // HAVE_SSL
return false;
}

View File

@ -0,0 +1,101 @@
// Filename: cConnectionRepository.h
// Created by: drose (17May04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef CCONNECTIONREPOSITORY_H
#define CCONNECTIONREPOSITORY_H
#include "directbase.h"
#include "pointerTo.h"
#ifdef HAVE_NSPR
#include "queuedConnectionManager.h"
#include "connectionWriter.h"
#include "queuedConnectionReader.h"
#include "connection.h"
#endif
class URLSpec;
class HTTPChannel;
class SocketStream;
////////////////////////////////////////////////////////////////////
// Class : CConnectionRepository
// Description : This class implements the C++ side of the
// ConnectionRepository object. In particular, it
// manages the connection to the server once it has been
// opened (but does not open it directly). It manages
// reading and writing datagrams on the connection and
// monitoring for unexpected disconnects as well as
// handling intentional disconnects.
//
// Certain server messages, like field updates, are
// handled entirely within the C++ layer, while server
// messages that are not understood by the C++ layer are
// returned up to the Python layer for processing.
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT CConnectionRepository {
PUBLISHED:
CConnectionRepository();
~CConnectionRepository();
#ifdef HAVE_SSL
void set_connection_http(HTTPChannel *channel);
#endif
#ifdef HAVE_NSPR
bool try_connect_nspr(const URLSpec &url);
INLINE QueuedConnectionManager &get_qcm();
INLINE ConnectionWriter &get_cw();
INLINE QueuedConnectionReader &get_qcr();
#endif
bool check_datagram();
INLINE void get_datagram(Datagram &dg);
bool is_connected();
bool send_datagram(const Datagram &dg);
bool consider_flush();
bool flush();
void disconnect();
INLINE void set_simulated_disconnect(bool simulated_disconnect);
INLINE bool get_simulated_disconnect() const;
private:
bool do_check_datagram();
#ifdef HAVE_SSL
SocketStream *_http_conn;
#endif
#ifdef HAVE_NSPR
QueuedConnectionManager _qcm;
ConnectionWriter _cw;
QueuedConnectionReader _qcr;
PT(Connection) _nspr_conn;
#endif
Datagram _dg;
bool _simulated_disconnect;
};
#include "cConnectionRepository.I"
#endif // CCONNECTIONREPOSITORY_H

View File

@ -0,0 +1,57 @@
// Filename: config_distributed.cxx
// Created by: drose (19May04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "config_distributed.h"
#include "dconfig.h"
Configure(config_distributed);
NotifyCategoryDef(distributed, "");
ConfigureFn(config_distributed) {
init_libdistributed();
}
// This represents the amount of time to block waiting for the TCP
// connection to the game server. It is only used when the connection
// method is NSPR.
const int game_server_timeout_ms = config_distributed.GetInt("game-server-timeout-ms", 20000);
// These represent the time in seconds by which to artificially lag
// inbound messages. It is only used when the connection method is
// NSPR.
const double min_lag = config_distributed.GetDouble("min-lag", 0.0);
const double max_lag = config_distributed.GetDouble("max-lag", 0.0);
////////////////////////////////////////////////////////////////////
// Function: init_libdistributed
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libdistributed() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
}

View File

@ -0,0 +1,35 @@
// Filename: config_distributed.h
// Created by: drose (19May04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_DISTRIBUTED_H
#define CONFIG_DISTRIBUTED_H
#include "directbase.h"
#include "notifyCategoryProxy.h"
#include "dconfig.h"
NotifyCategoryDecl(distributed, EXPCL_DIRECT, EXPTP_DIRECT);
extern const int game_server_timeout_ms;
extern const double min_lag;
extern const double max_lag;
extern EXPCL_DIRECT void init_libdistributed();
#endif