/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project. All
................................................ contributions are welcome.
....Copyright(C).1995.Melvin.Smith.............. Enjoy.
------------------------------------------------------------------------------
Melvin Smith (aka Fusion) msmith@falcon.mercer.peachnet.edu
MUD++ development mailing list mudpp-list@spice.com
------------------------------------------------------------------------------
server.cc
*/
#include "server.h"
void sig_handler( int )
{
// Generate core
raise( SIGSEGV );
}
Server::~Server()
{
master->close();
}
Socket * Server::getSock()
{
return master;
}
// This is for booting "into" a previous servers process
// space and inheriting the open master descriptor. Skip
// all the master struct creation and just assign the
// descriptor to sock and clean up a few other things.
// This really needs some serious error handling. Also need
// to save the sock struct info in the reboot.tab file
// and recreate it from that.
// --Fusion
int Server::boot( int oldport, int olddesc )
{
signal( SIGPIPE, SIG_IGN );
signal( SIGBUS, sig_handler );
master = new Socket( "", oldport, olddesc );
printf( "SERVER: Rebooted succesfully - ready for connections.\n" );
printf( "SERVER: Port [%d]\n", master->getPort() );
topdesc = olddesc;
return 0;
}
int Server::boot( int tport )
{
signal( SIGPIPE, SIG_IGN );
signal( SIGBUS, sig_handler );
master = new Socket( tport );
if( master->error() )
{
perror( "SERVER: Socket::boot()" );
exit(0);
}
master->reuseAddr();
master->noDelay();
if( master->listen() )
{
perror( "SERVER: Socket::listen()" );
exit(0);
}
masterdesc = topdesc = master->getDesc();
masterport = master->getPort();
printf( "SERVER: Booted succesfully - ready for connections.\n" );
printf( "SERVER: Port [%d]\n", masterport );
return 0;
}
int Server::poll()
{
memcpy( &R_SET, &MASTER_SET, bitwidth );
memcpy( &W_SET, &MASTER_SET, bitwidth );
memcpy( &E_SET, &MASTER_SET, bitwidth );
FD_SET( masterdesc, &R_SET );
// if( select( topdesc+1, &R_SET, &W_SET, &E_SET, &null_time) == -1 )
if( select( topdesc+1, &R_SET, &W_SET, &E_SET, 0 ) == -1 )
{
printf("SERVER: select() error in Poll() - exiting.\n");
exit( errno );
}
return FD_ISSET( masterdesc, &R_SET );
}
// I high resolution sleep function
// Best to inline this to remove the overhead of the function call
void Server::sleep( long millisecs )
{
static struct timeval sleep_time;
sleep_time.tv_sec = 0;
sleep_time.tv_usec = millisecs;
if( select( 0, NULL, NULL, NULL, &sleep_time ) == -1 )
{
printf("SERVER: Error select() in Sleep()\n");
exit( errno );
}
}
// Do we want the numerical ip or try to get the name from the
// nameserver? If you have a slow nameserver dont use this.
void Server::useNameServer()
{
nameserver = 1;
}
int Server::newConnection()
{
FD_ZERO( &R_SET );
FD_SET( masterdesc, &R_SET );
if( select( masterdesc + 1, &R_SET, 0, 0, &null_time ) == -1 )
{
printf("SERVER: select() error in NewConnection() - exiting.\n");
exit( errno );
}
return FD_ISSET( masterdesc, &R_SET );
}
Socket * Server::accept()
{
int desc;
Socket *newSock = master->accept();
if( !newSock )
{
if( errno == EAGAIN || errno == EWOULDBLOCK )
return 0;
perror( "Server::accept()" );
exit(0);
return 0;
}
newSock->noDelay();
newSock->getPeerName();
newSock->resolveIP();
desc = newSock->getDesc();
if( desc > topdesc )
topdesc = desc;
FD_SET( desc, &MASTER_SET );
descripts++;
return newSock;
}
void Server::addSock( Socket * sock )
{
if( FD_ISSET( sock->getDesc(), &MASTER_SET ) )
{
printf( "SERVER: Error. Attempt to add existing descriptor.\n" );
exit(0);
}
FD_SET( sock->getDesc(), &MASTER_SET );
if( sock->getDesc() > topdesc )
topdesc = sock->getDesc();
descripts++;
}
void Server::remove( Socket * sock )
{
// I exit on the following two errors because if this happens
// you need to find out why.
int desc = sock->getDesc();
if( desc < 0 || desc >= maxdesc )
{
printf("SERVER: Close() - desc [%d] out of bounds.\n", desc);
exit( 0 );
}
if( ! FD_ISSET( desc, &MASTER_SET ) )
{
printf("SERVER: Invalid descriptor\n");
exit( 0 );
}
FD_CLR( desc, &MASTER_SET );
if( !--descripts )
{
topdesc = masterdesc;
return;
}
if( desc == topdesc )
{
for( desc = topdesc-1; !FD_ISSET( desc, &MASTER_SET ); desc-- )
;
topdesc = desc;
}
}
int Server::canRead( Socket * sock )
{
return FD_ISSET( sock->getDesc(), &R_SET );
}
int Server::canWrite( Socket * sock )
{
return FD_ISSET( sock->getDesc(), &W_SET );
}
int Server::error( Socket * sock )
{
int desc = sock->getDesc();
if( FD_ISSET( desc, &E_SET ) )
{
FD_CLR( desc, &R_SET );
FD_CLR( desc, &W_SET );
return FD_ISSET( desc, &E_SET );
}
return 0;
}