1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * Layer 3 and Service example, front-end server.
21 * This front-end server expects pings, and forward them to
22 * the real ping server. When the ping server sends a pong back,
23 * the front-end server forwards it to the client.
25 * To run this program, ensure there is a file "frontend_service.cfg"
26 * containing the location of the naming service (NSHost, NSPort)
27 * in the working directory. The naming service must be running.
31 // We're building a server, using the NeL Service framework.
32 // We need the naming service to know where the ping service is, so we're using CNamingClient.
33 // We're using CCallbackClient when we talk to the naming service.
34 // We're using CCallbackServer when we talk to our clients.
35 #include "nel/net/service.h"
36 #include "nel/net/naming_client.h"
37 #include "nel/net/callback_client.h"
38 #include "nel/net/callback_server.h"
39 using namespace NLNET
;
45 // The front-end server is also a client of the ping service
46 CCallbackClient
*ToPingService
;
48 // Temp storage (a queue because the connection to the ping service is reliable, the order is preserved)
49 deque
<TSockId
> ClientIds
;
53 * Callback function called when receiving a "PING" message
56 * - msgin: the incoming message (coming from a client)
57 * - from: the "sockid" of the sender client
58 * - frontendserver: the CCallbackNetBase object (which really is a CCallbackServer object, for a server)
60 * Input (expected message from a client): PING
61 * - uint32: ping counter
63 * Output (sent message to the ping server): PONG
64 * - uint32: ping counter
66 void cbPing( CMessage
& msgin
, TSockId from
, CCallbackNetBase
& frontendserver
)
71 msgin
.serial( counter
);
72 ClientIds
.push_back( from
); // store client sockid
75 CMessage
msgout( "PING" );
76 msgout
.serial( counter
);
77 vector
<uint8
> vect( 400000 );
78 msgout
.serialCont( vect
);
79 ToPingService
->send( msgout
);
81 nlinfo( "Received PING number %u from %s", counter
, frontendserver
.hostAddress(from
).asString().c_str() );
86 * Disconnection callback, called when a client disconnects
88 void discCallback( TSockId from
, void *p
)
90 // Remove all occurences of from in the queue
91 deque
<TSockId
>::iterator iq
;
92 for ( iq
=ClientIds
.begin(); iq
!=ClientIds
.end(); )
96 iq
= ClientIds
.erase( iq
);
107 * Callback function called when receiving a "PONG" message
110 * - msgin: the incoming message (coming from the ping server)
111 * - from: the "sockid" of the sender (usually useless for a CCallbackClient)
112 * - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object)
114 * Input (expected message from the ping server): PONG
115 * - uint32: ping counter
116 * - TSockId: "sock id" of the client who sent the ping
118 * Output (sent message to a client): PONG
119 * - uint32: ping counter
121 void cbPong( CMessage
& msgin
, TSockId from
, CCallbackNetBase
& clientofthepingserver
)
126 // Input: process the reply of the ping service
127 msgin
.serial( counter
);
128 clientfrom
= ClientIds
.front(); // retrieve client sockid
129 ClientIds
.pop_front();
131 // Output: send the reply to the client
132 CCallbackServer
*server
= IService::getInstance()->getServer();
133 CMessage
msgout( "PONG" );
134 msgout
.serial( counter
);
135 server
->send( msgout
, clientfrom
);
137 nlinfo( "Sent PONG number %u to %s", counter
, clientfrom
->asString().c_str() );
142 * Callback array for messages received from a client
144 TCallbackItem CallbackArray
[] =
146 { "PING", cbPing
} // when receiving a "PING" message, call cbPing()
151 * Callback array for message received from the ping service
153 TCallbackItem PingServiceCallbackArray
[] =
155 { "PONG", cbPong
} // when receiving a "PONG" message, call cbPong()
160 * CFrontEndService, based on IService
162 class CFrontEndService
: public IService
171 // Connect to the ping service
172 ToPingService
= new CCallbackClient( IService::getRecordingState(), "PS.nmr" );
173 ToPingService
->addCallbackArray( PingServiceCallbackArray
, sizeof(PingServiceCallbackArray
)/sizeof(PingServiceCallbackArray
[0]) );
174 if ( ! CNamingClient::lookupAndConnect( "PS", *ToPingService
) )
176 nlerror( "Ping Service not available" );
179 // Disconnection callback for the clients
180 IService::getServer()->setDisconnectionCallback( discCallback
, NULL
);
188 ToPingService
->update( 20 ); // 20 ms max
189 return ToPingService
->connected(); // true continues, false stops the service
197 delete ToPingService
;
203 * Declare a service with the class CFrontEndService, the names "FS" (short) and "frontend_service" (long).
204 * The port is set to 37000 and the main callback array is CallbackArray.
206 NLNET_OLD_SERVICE_MAIN( CFrontEndService
, "FS", "frontend_service", 37000, CallbackArray
, "", "" )