== '''The Ping-Pong Example''' == To help getting into using Ariba, we provide a short example of how to use the architecture. For this, assume a simple service whose simply and only intention is to exchange data packets between two participating nodes, just like playing ping pong. You will find the whole code within the package under ''sample/pingpong''. The source files divide into the main code (''PingPong.h/.cpp'') and the used message format (declared in ''PingPongMessage.h/.cpp''). In Addition, ''main.cpp'' acts as the entry point to the ping-pong example. We will first give a high-level introduction about what the example does and later dig deeper into the code. '''What it does''' As already mentioned, the example service simply exchanges packets between two participating network nodes. This is accomplished by using the ''Ariba'' abstraction to create a communication context and hide underlay details. The participants form a ''SpoVNet'' instance in which the first one (as the initiator) creates the instance, while the second joins. As soon as the second has successfully joined the instance, it starts sending packets to the initiator periodically. When such a packet reaches the latter, he responds by also sending a packet back. This procedure repeats, until a button is pressed. '''How it does it''' Let's take a look at the code now. Writing a service is pretty simple when using ''Ariba'' because most difficulties and annoyances that could come up when struggling with writing network code are taken from the developer. We start with the ''main.cpp''. {{{ 01 #include 02 #include "ariba/utility/startup/StartupWrapper.h" 03 #include "PingPong.h" 04 05 using std::string; 06 using ariba::utility::StartupWrapper; 07 using ariba::application::pingpong::PingPong; 08 09 int main( int argc, char** argv ) { 10 11 string config = "../etc/settings.cnf"; 12 if (argc >= 2) config = argv[1]; 13 14 StartupWrapper::initConfig( config ); 15 StartupWrapper::initSystem(); 16 17 // this will do the main functionality and block 18 PingPong ping; 19 ping.setMode( !Configuration::instance().read("GENERAL_Initiator") ); 20 StartupWrapper::startup(&ping, true); 21 22 // this will run blocking until is hit 23 24 StartupWrapper::shutdown(); 25 return 0; 26 } }}} The ''main.cpp'' serves us as an entry point to the application. In the first lines we include class definitions we need here (e.g. strings because we want to handle some). Also, we include the StartupWrapper class that comes with ''Ariba''. It provides some handy helpers for initialization. Finally, we need to include the ''PingPong.h'', because this is the actual thing we want to execute. Then, we declare the used namespaces (lines 05-07) to be able to use the functionalities. Now we get to the main method, being our starting point. After determining the location of our config file, we initialize the system by passing the config file's location to the StartupWrapper and telling the same to start the architecture up (lines 11-15). Now we are ready to start the ping-pong service, which we first create (line 18). Then we declare the role of the node (initiator or joiner), which is written down in the config file as a bool value. Finally, we start the service up by calling the specific method in the StartupWrapper. Now the service will run until we press the enter button. Now we look into the ''PingPong.cpp'', containing the actual ping pong code. We leave out .h files here because they only do definitions. Everyone intending to use ''Ariba'' should be familiar with the subject matter. The first parts look like this: {{{ 01 #include "PingPong.h" 02 03 namespace ariba { 04 namespace application { 05 namespace pingpong { 06 07 use_logging_cpp(PingPong); 08 ServiceID PingPong::PINGPONG_ID = ServiceID(111); 09 10 PingPong::PingPong() : pingid( 0 ) { 11 } 12 13 PingPong::~PingPong(){ 14 } 15 16 void PingPong::setMode(bool startingNode){ 17 startping = startingNode; 18 } 19 20 void PingPong::startup(UnderlayAbstraction* _abstraction){ 21 abstraction = _abstraction; 22 23 logging_info( "starting up PingPong service ... " ); 24 25 SpoVNetID spovnetid (Identifier(5000)); 26 27 NodeID nodeid = (Configuration::instance().exists("BASE_nodeid") ? 28 NodeID(Identifier(Configuration::instance().read("BASE_nodeid"))) : 29 NodeID::UNSPECIFIED); 30 31 IPv4Locator* locallocator = (Configuration::instance().exists("BASE_localLocator") ? 32 &(IPv4Locator::fromString(Configuration::instance().read("BASE_localLocator"))) : 33 NULL); 34 35 uint16_t localport = Configuration::instance().exists("BASE_port") ? 36 Configuration::instance().read("BASE_port") : 37 ARIBA_DEFAULT_PORT; 38 39 if( !startping ) 40 context = abstraction->createSpoVNet( spovnetid, nodeid, locallocator, localport ); 41 else 42 context = abstraction->joinSpoVNet ( spovnetid, nodeid, locallocator, localport ); 43 44 overlay = &context->getOverlay(); 45 overlay->bind( this, PingPong::PINGPONG_ID ); 46 47 logging_info( "PingPong started up" ); 48 49 // trigger the creation of the pathload measurement module 50 //PathloadMeasurement::instance( overlay ); 51 } }}} First we include the .h file, define the namespace, turn logging functionality on (line 07) and set the ID of the Service. Every service using ''Ariba'' is connected to a specific ID that may be chosen initially and arbitrarily. This ID serves ''Ariba'' to distinguish between several services that may use it concurrently. Via ''setMode'' (lines 16-18) one can indicate which node in the example should start the packet sending process. This method is called in main.cpp after getting this information from the config file.