207 lines
5.7 KiB
C++
207 lines
5.7 KiB
C++
|
// 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, "", "" )
|