You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
7.4 KiB
279 lines
7.4 KiB
#include "internal.h"
|
|
#include "internal.moc"
|
|
|
|
#include <tqptrlist.h>
|
|
#include <tdelocale.h>
|
|
#include "mp_interface.h"
|
|
|
|
#define DATA_ERROR(i) { dataError(i); return; }
|
|
#define READ_ERROR(i) { readError(i); return; }
|
|
#define WRITE_ERROR(i) { writeError(i); return; }
|
|
#define BROKE_ERROR(i) { brokeError(i); return; }
|
|
#define LAG_ERROR { lagError(); return; }
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void Local::dataError(uint i)
|
|
{
|
|
tqWarning("MP : Invalid data from board #%i", i);
|
|
}
|
|
|
|
void Local::readData(bool inverse)
|
|
{
|
|
// read data from local boards
|
|
for (uint i=0; i<ios.size(); i++) {
|
|
boards[i].ptr->dataOut(ios[i]->writing);
|
|
if (inverse) ios[i]->writingToReading();
|
|
}
|
|
}
|
|
|
|
void Local::writeData(bool inverse)
|
|
{
|
|
// write data to local boards
|
|
for (uint i=0; i<ios.size(); i++) {
|
|
if (inverse) ios[i]->writingToReading();
|
|
boards[i].ptr->dataIn(ios[i]->reading);
|
|
if ( !ios[i]->reading.readOk() ) DATA_ERROR(i);
|
|
}
|
|
}
|
|
|
|
void Local::treatData()
|
|
{
|
|
readData(TRUE);
|
|
interface->treatData();
|
|
// check reading stream
|
|
for (uint i=0; i<ios.size(); i++)
|
|
if ( !ios[i]->reading.readOk() ) DATA_ERROR(i);
|
|
writeData(TRUE);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
Server::Server(uint _interval)
|
|
: interval(_interval)
|
|
{
|
|
timer.start(interval);
|
|
}
|
|
|
|
void Server::congestion()
|
|
{
|
|
tqWarning("MP : congestion occurred !!");
|
|
}
|
|
|
|
void Server::serverTimeout()
|
|
{
|
|
ctimer.start(2*interval, TRUE);
|
|
timeout();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
Network::Network(MPInterface *_interface,
|
|
TQValueList<MPInterface::Data> &_boards,
|
|
const TQPtrList<RemoteHostData> &rhd)
|
|
: Local(_interface, _boards)
|
|
{
|
|
RemoteData rd;
|
|
TQPtrListIterator<RemoteHostData> it(rhd);
|
|
for (; it.current(); ++it) {
|
|
rd.socket = it.current()->socket;
|
|
rd.socket->notifier()->setEnabled(TRUE);
|
|
connect(rd.socket->notifier(), TQ_SIGNAL(activated(int)),
|
|
TQ_SLOT(notifier(int)));
|
|
uint nb = it.current()->bds.count();
|
|
Q_ASSERT( nb>=1 );
|
|
rd.array = new BufferArray(nb);
|
|
for (uint k=0; k<it.current()->bds.count(); k++)
|
|
rd.names += it.current()->bds[k].name;
|
|
remotes += rd;
|
|
}
|
|
}
|
|
|
|
Network::~Network()
|
|
{
|
|
for (uint i=0; i<remotes.count(); i++) {
|
|
delete remotes[i].socket;
|
|
delete remotes[i].array;
|
|
}
|
|
}
|
|
|
|
uint Network::nbPlayers() const
|
|
{
|
|
uint nb = Local::nbPlayers();
|
|
for (uint i=0; i<remotes.count(); i++) nb += remotes[i].array->size();
|
|
return nb;
|
|
}
|
|
|
|
TQString Network::playerName(uint i) const
|
|
{
|
|
uint l = Local::nbPlayers();
|
|
if ( i<l ) return Local::playerName(i);
|
|
for (uint k=0; k<remotes.count(); k++) {
|
|
uint ll = remotes[k].array->size();
|
|
if ( i<(l+ll) ) return remotes[k].names[i-l];
|
|
l += ll;
|
|
}
|
|
return TQString(); // dummy
|
|
}
|
|
|
|
IOBuffer *Network::ioBuffer(uint i) const
|
|
{
|
|
if ( i<Local::nbPlayers() ) return Local::ioBuffer(i);
|
|
i -= Local::nbPlayers();
|
|
for (uint k=0; k<remotes.count(); k++) {
|
|
if ( i<remotes[k].array->size() ) return (*remotes[k].array)[i];
|
|
i -= remotes[k].array->size();
|
|
}
|
|
Q_ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
void Network::readError(uint i)
|
|
{
|
|
disconnectHost(i, i18n("Unable to read socket"));
|
|
}
|
|
|
|
void Network::writeError(uint i)
|
|
{
|
|
disconnectHost(i, i18n("Unable to write to socket"));
|
|
}
|
|
|
|
void Network::brokeError(uint i)
|
|
{
|
|
disconnectHost(i, i18n("Link broken"));
|
|
}
|
|
|
|
void Network::disconnectHost(uint i, const TQString &msg)
|
|
{
|
|
delete remotes[i].socket;
|
|
delete remotes[i].array;
|
|
remotes.remove(remotes.at(i));
|
|
interface->hostDisconnected(i, msg);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
LocalServer::LocalServer(MPInterface *_interface,
|
|
TQValueList<MPInterface::Data> &_boards,
|
|
uint _interval)
|
|
: Local(_interface, _boards), Server(_interval)
|
|
{
|
|
connect(&timer, TQ_SIGNAL(timeout()), TQ_SLOT(timeoutSlot()));
|
|
connect(&ctimer, TQ_SIGNAL(timeout()), TQ_SLOT(congestionTimeoutSlot()));
|
|
serverTimeout();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
NetworkServer::NetworkServer(MPInterface *_interface,
|
|
TQValueList<MPInterface::Data> &_boards,
|
|
const TQPtrList<RemoteHostData> &rhd, uint _interval)
|
|
: Network(_interface, _boards, rhd), Server(_interval),
|
|
nbReceived(remotes.count())
|
|
{
|
|
connect(&timer, TQ_SIGNAL(timeout()), TQ_SLOT(timeoutSlot()));
|
|
connect(&ctimer, TQ_SIGNAL(timeout()), TQ_SLOT(congestionTimeoutSlot()));
|
|
// to catch unexpected data
|
|
for (uint i=0; i<remotes.count(); i++) remotes[i].received = TRUE;
|
|
nbReceived = remotes.count();
|
|
// let the client the time to create itself ...
|
|
// serverTimeout();
|
|
}
|
|
|
|
void NetworkServer::timeout()
|
|
{
|
|
if ( nbReceived<remotes.count() ) LAG_ERROR;
|
|
nbReceived = 0;
|
|
for (uint i=0; i<remotes.count(); i++) remotes[i].received = FALSE;
|
|
// send MF_ASK : asking for data from clients
|
|
for (uint i=0; i<remotes.count(); i++) {
|
|
remotes[i].socket->writingStream() << MF_Ask;
|
|
// debug("SERVER : send ask flag");
|
|
if ( !remotes[i].socket->write() ) WRITE_ERROR(i);
|
|
}
|
|
}
|
|
|
|
void NetworkServer::notifier(int fd)
|
|
{
|
|
uint i;
|
|
for (i=0; i<remotes.count(); i++)
|
|
if ( remotes[i].socket->fd()==fd ) break;
|
|
Q_ASSERT( i<remotes.count() );
|
|
|
|
if ( remotes[i].received ) READ_ERROR(i);
|
|
switch ( remotes[i].socket->read() ) {
|
|
case -1: READ_ERROR(i);
|
|
case 0: BROKE_ERROR(i);
|
|
}
|
|
|
|
remotes[i].received = TRUE;
|
|
nbReceived++;
|
|
|
|
ReadingStream &s = remotes[i].socket->readingStream();
|
|
// debug("SERVER : notifier + read (fd=%i i=%i size=%i)", fd, i,
|
|
// s.size());
|
|
s >> *remotes[i].array;
|
|
if ( !s.readOk() ) DATA_ERROR(i);
|
|
|
|
// all data from clients received
|
|
if ( nbReceived==remotes.count() ) treatData();
|
|
}
|
|
|
|
void NetworkServer::writeData(bool inverse)
|
|
{
|
|
Local::writeData(inverse);
|
|
for (uint i=0; i<remotes.count(); i++) {
|
|
WritingStream &s = remotes[i].socket->writingStream();
|
|
s << MF_Data;
|
|
s << *remotes[i].array;
|
|
s.writeRawBytes(globalStream()->buffer().data(),
|
|
globalStream()->size());
|
|
// debug("SERVER : write data (size= 1 + %i + %i=%i)",
|
|
// globalStream()->size(), s.size()-globalStream()->size()-1,
|
|
// s.size());
|
|
if ( !remotes[i].socket->write() ) WRITE_ERROR(i);
|
|
}
|
|
globalStream()->clear();
|
|
}
|
|
|
|
void NetworkServer::lagError()
|
|
{
|
|
for (uint i=0; i<remotes.count(); i++)
|
|
if ( !remotes[i].received )
|
|
disconnectHost(i, i18n("Client has not answered in time"));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void Client::notifier(int)
|
|
{
|
|
switch ( remotes[0].socket->read() ) {
|
|
case -1: READ_ERROR(0);
|
|
case 0: BROKE_ERROR(0);
|
|
}
|
|
ReadingStream &s = remotes[0].socket->readingStream();
|
|
MetaFlag mf;
|
|
s >> mf;
|
|
if ( !s.readOk() ) DATA_ERROR(0);
|
|
// debug("CLIENT : reading stream (size=%i flag=%i)", s.size(),
|
|
// (int)mf);
|
|
switch(mf) {
|
|
case MF_Ask:
|
|
// write data from local boards to server socket (cleaning
|
|
// of writing stream is done in write())
|
|
readData(FALSE);
|
|
remotes[0].socket->writingStream() << ios;
|
|
// debug("CLIENT : send ios (size=%i)",
|
|
// remotes[0].socket->writingStream().size());
|
|
if ( !remotes[0].socket->write() ) WRITE_ERROR(0);
|
|
break;
|
|
case MF_Data:
|
|
// read data from server to interface & local boards
|
|
// debug("CLIENT : before receive ios (at=%i)", s.device()->at());
|
|
s >> ios;
|
|
// debug("CLIENT : after receive ios (at=%i)", s.device()->at());
|
|
interface->dataFromServer(s);
|
|
// debug("CLIENT : after dataFromServer (at=%i)", s.device()->at());
|
|
if ( !s.readOk() ) DATA_ERROR(0);
|
|
writeData(FALSE);
|
|
break;
|
|
default: DATA_ERROR(0);
|
|
}
|
|
if ( !s.atEnd() ) tqWarning("CLIENT : remaining data");
|
|
}
|