khanat-opennel-code/code/nel/samples/net/net_layer3/frontend_service.cpp

207 lines
5.9 KiB
C++
Raw Normal View History

2010-09-24 08:27:31 +00:00
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/*
* Layer 3 and Service example, front-end server.
*
* This front-end server expects pings, and forward them to
* the real ping server. When the ping server sends a pong back,
* the front-end server forwards it to the client.
*
* To run this program, ensure there is a file "frontend_service.cfg"
* containing the location of the naming service (NSHost, NSPort)
* in the working directory. The naming service must be running.
*/
// We're building a server, using the NeL Service framework.
// We need the naming service to know where the ping service is, so we're using CNamingClient.
// We're using CCallbackClient when we talk to the naming service.
// We're using CCallbackServer when we talk to our clients.
#include "nel/net/service.h"
#include "nel/net/naming_client.h"
#include "nel/net/callback_client.h"
#include "nel/net/callback_server.h"
using namespace NLNET;
#include <deque>
using namespace std;
// The front-end server is also a client of the ping service
CCallbackClient *ToPingService;
// Temp storage (a queue because the connection to the ping service is reliable, the order is preserved)
deque<TSockId> ClientIds;
/*
* Callback function called when receiving a "PING" message
*
* Arguments:
* - msgin: the incoming message (coming from a client)
* - from: the "sockid" of the sender client
* - frontendserver: the CCallbackNetBase object (which really is a CCallbackServer object, for a server)
*
* Input (expected message from a client): PING
* - uint32: ping counter
*
* Output (sent message to the ping server): PONG
* - uint32: ping counter
*/
void cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& frontendserver )
{
uint32 counter;
// Input
msgin.serial( counter );
ClientIds.push_back( from ); // store client sockid
// Output
CMessage msgout( "PING" );
msgout.serial( counter );
vector<uint8> vect( 400000 );
msgout.serialCont( vect );
ToPingService->send( msgout );
nlinfo( "Received PING number %u from %s", counter, frontendserver.hostAddress(from).asString().c_str() );
}
/*
* Disconnection callback, called when a client disconnects
*/
void discCallback( TSockId from, void *p )
{
// Remove all occurences of from in the queue
deque<TSockId>::iterator iq;
for ( iq=ClientIds.begin(); iq!=ClientIds.end(); )
{
if ( *iq == from )
{
iq = ClientIds.erase( iq );
}
else
{
iq++;
}
}
}
/*
* Callback function called when receiving a "PONG" message
*
* Arguments:
* - msgin: the incoming message (coming from the ping server)
* - from: the "sockid" of the sender (usually useless for a CCallbackClient)
* - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object)
*
* Input (expected message from the ping server): PONG
* - uint32: ping counter
* - TSockId: "sock id" of the client who sent the ping
*
* Output (sent message to a client): PONG
* - uint32: ping counter
*/
void cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& clientofthepingserver )
{
uint32 counter;
TSockId clientfrom;
// Input: process the reply of the ping service
msgin.serial( counter );
clientfrom = ClientIds.front(); // retrieve client sockid
ClientIds.pop_front();
// Output: send the reply to the client
CCallbackServer *server = IService::getInstance()->getServer();
CMessage msgout( "PONG" );
msgout.serial( counter );
server->send( msgout, clientfrom );
nlinfo( "Sent PONG number %u to %s", counter, clientfrom->asString().c_str() );
}
/*
* Callback array for messages received from a client
*/
TCallbackItem CallbackArray[] =
{
{ "PING", cbPing } // when receiving a "PING" message, call cbPing()
};
/*
* Callback array for message received from the ping service
*/
TCallbackItem PingServiceCallbackArray[] =
{
{ "PONG", cbPong } // when receiving a "PONG" message, call cbPong()
};
/*
* CFrontEndService, based on IService
*/
class CFrontEndService : public IService
{
public:
/*
* Initialization
*/
void init()
{
// Connect to the ping service
ToPingService = new CCallbackClient( IService::getRecordingState(), "PS.nmr" );
ToPingService->addCallbackArray( PingServiceCallbackArray, sizeof(PingServiceCallbackArray)/sizeof(PingServiceCallbackArray[0]) );
if ( ! CNamingClient::lookupAndConnect( "PS", *ToPingService ) )
{
nlerror( "Ping Service not available" );
}
// Disconnection callback for the clients
IService::getServer()->setDisconnectionCallback( discCallback, NULL );
}
/*
* Update
*/
bool update()
{
ToPingService->update( 20 ); // 20 ms max
return ToPingService->connected(); // true continues, false stops the service
}
/*
* Finalization
*/
void release()
{
delete ToPingService;
}
};
/*
* Declare a service with the class CFrontEndService, the names "FS" (short) and "frontend_service" (long).
* The port is set to 37000 and the main callback array is CallbackArray.
*/
NLNET_OLD_SERVICE_MAIN( CFrontEndService, "FS", "frontend_service", 37000, CallbackArray, "", "" )