close Warning: BrowserModule failed with ConfigurationError: Look in the Trac log for more information.

Changes between Version 15 and Version 16 of OverSimDevelop


Ignore:
Timestamp:
Apr 17, 2009, 3:42:36 PM (15 years ago)
Author:
heep
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • OverSimDevelop

    v15 v16  
    1111----
    1212== '''Be careful: ==
    13 ==     This documentation covers only OMNeT++-3.3 compatible versions of OverSim !! ==
     13==     This documentation covers only OMNeT++-4.0 compatible versions of OverSim !! ==
    1414==     It is still under development and may be partly incorrect or outdated !! ==
     15==     ( For documentation about OMNeT++-3.x compatible versions of OverSim, see OverSimDevelopOld ) ==
     16
    1517---
    1618
    1719== 1. Implementing new overlay modules in !OverSim ==
    1820
    19 This is a guide to implement new overlay modules for !OverSim. It is aimed to be an introductory guide, for more in-depth information you should consult the doxygen documentation. This guide is divided as follows. In order to understand the place an overlay module takes inside nodes and how it interacts with them, first the module hierarchy for overlay hosts is described. Then we proceed to explain how overlay modules should declared using the NED language. Next, the basics for the module implementation are described using the base class BaseOverlay. Finally we explain how to make !OverSim compile and run your module.
    20 
    21 == 2. !OverSim nodes ==
     21This is a guide to implement new overlay modules for !OverSim. It is aimed to be an introductory guide, for more in-depth information you should consult the doxygen documentation. We'll explain the architecture using an example overlay module, and its corresponding application module.
     22
     23This guide is divided as follows. In order to understand the place an overlay module takes inside nodes and how it interacts with them, first the module hierarchy for overlay hosts is described. Then we proceed to explain overlay and application modules with an example overlay. Later, we describe how to make a configuration file to run the overlay, and, as the final chapter, how to compile and run the simulator.
     24
     25== 2. !OverSim Nodes ==
    2226
    2327!OverSim nodes are the equivalent of individual terminals in the simulation environment. Nodes are based on a multi-tiered module hierarchy similar to OSI network layers (e.g. transport, overlay, application). The most used node type is called SimpleOverlayHost, and its tiers are structured as follows:
     
    2731The UDP module is an implementation of the transport layer, and is in charge of communication between nodes. Above it is the overlay (KBR) tier, where the overlay module will be located. It communicates with other overlay nodes through the UDP layer, and exposes its services to the application layer above it. On the third tier is the application layer, which uses the services provided by the overlay module. Application modules may also use UDP directly if necessary. Other tiers may be activated above the application if required, these connect to the tier below and to the UDP module.
    2832
    29 == 2.1 Module declaration ==
    30 
    31 For module declarations, !OverSim uses the NED language, a topology description language. Modules should be declared in their own NED files (with extension .ned), and the file name should match the module name.
    32 
    33 Following is a declaration for an example overlay module called ''!MyOverlay'' in myOverlay.ned:
    34 
    35 {{{
    36 simple MyOverlay
     33== 2.1 Module Declaration ==
     34
     35For module declarations, !OverSim uses the NED language, a topology description language. Modules should be declared in their own NED files (with extension .ned), and the file name should match the module name (minus the extension!).
     36
     37First, we start with our overlay module. All overlay module files should be located in <OverSim>/src/overlay, so we'll create a folder called myoverlay, and inside, we'll create a file called MyOverlay.ned.
     38
     39Following is the declaration for MyOverlay:
     40
     41{{{
     42
     43// sets the package, the name must match the path to the module (from src/ upwards)
     44package oversim.overlay.myoverlay;
     45
     46// import BaseOverlay
     47import oversim.common.BaseOverlay;
     48
     49simple MyOverlay extends BaseOverlay
     50{
    3751    parameters:
    38         myParam1 : int,     
    39         myParam2 : string, 
    40           debugOutput: bool;  // obligatory!
     52        @class(MyOverlay)
     53        bool enableDrops;       // do we enable random packet drops for testing?
     54        double dropChance;      // chance that we drop a packet
     55}
     56}}}
     57
     58The parameters subsection is a list of module properties. These parameters must be set before the simulation (or the simulator will stop and ask you for a value each time a module is created!) and will be read-only while the simulation is running. As parameter types we can use booleans (bool), strings, integers, or doubles; custom types (either module declarations or C++ types) can also be used.
     59
     60Notice that, since we're writing an overlay module, we'll declare our module as inheriting from the parent class BaseOverlay. Therefore we'll use "extends BaseOverlay" in the module definition. Since we want to use our own code for our module, we'll add "@class(MyOverlay)" in the parameters section, to tell the simulator that MyOverlay is a class of its own.
     61
     62Now, we'll declare our application module in a similar way. Application files should be located in <OverSim>/src/applications, so we'll create a folder called myapplication (folder names are in lower case by convention) and there a file called MyApplication.ned.
     63
     64{{{
     65// sets the package, the name must match the path to the module (from src/ upwards)
     66package oversim.applications.myapplication;
     67
     68// import BaseApp
     69import oversim.common.BaseApp;
     70
     71simple MyApplication extends BaseApp
     72{
     73    parameters:
     74        @class(MyApplication);     // same as in MyOverlay
     75        int sendPeriod @unit(s);   // how much time to wait between sending packets (in seconds)
     76        int numToSend;             // how many packets will we send at the same time?
     77        int largestKey;            // largest key we can pick
     78}
     79}}}
     80
     81Numeric parameters, like sendPeriod, can use custom units (in this case, seconds).
     82
     83
     84=== 2.1.1 Simple and Compound Modules ===
     85
     86MyOverlay and MyApplication are examples of what is called a 'simple' module, because they don't contain any other modules inside them. Simple modules are declared using the keyword "simple" (for example, "simple MyOverlay"). Only simple modules can have its behaviour customized with C++ (see Section 4).
     87
     88On the other hand, modules with inner nested modules are called compound modules, and act only as containers. They are declared with the keyword "module". These are useful when we want to organize all the modules related to your overlay in a single place.
     89
     90It is encouraged to always use container modules as wrappers, even if they contain only a single module.
     91
     92An example overlay compound module is as follows:
     93
     94{{{
     95import oversim.common.IOverlay;
     96
     97module MyOverlayModules like IOverlay
     98{
    4199    gates:
    42         in: from_udp;    // gate from the UDP layer
    43         out: to_udp;     // gate to the UDP layer
    44         in: from_app;    // gate from the application
    45         out: to_app;     // gate to the application
    46         in: direct_in;   // gate for sendDirect
    47 endsimple
    48 }}}
    49 
    50 The module declaration is divided in two subsections: parameters and gates. The parameters subsection contains custom parameters established by the user, while the gates subsection establishes the connections to the other layers: from_udp and to_udp to the UDP layer, and from_app and to_app to the application layer. The direct_in gate is used for e.g. internal RPCs.
    51 
    52 Modules can be nested inside one another. Modules without any inner modules are called simple modules, and are declared using the keyword simple. Only simple modules can have its behaviour customized with C++ (see Section 3). On the other hand, modules with inner nested modules are called compound modules, and act only as containers; they are declared with the keyword module.
    53 
    54 An example compound module is as follows:
    55 
    56 {{{
    57 module MyOverlayContainer
     100        input udpIn;   // gate from the UDP layer
     101        output udpOut;    // gate to the UDP layer
     102        input appIn;   // gate from the application
     103        output appOut;    // gate to the application
     104
     105    submodules:
     106        myOverlay: MyOverlay;
     107
     108    connections allowunconnected:
     109        udpIn --> myOverlay.udpIn++;
     110        udpOut <-- myOverlay.udpOut++;
     111        appIn --> myOverlay.appIn;
     112        appOut <-- myOverlay.appOut;
     113}
     114}}}
     115
     116As you can see, the inner module "myOverlay" of type MyOverlay is nested inside MyOverlayModules. However, when we use MyOverlayModules, all messages that need to be sent to myOverlay will be sent to the wrapper instead. Therefore, we need to set up which gates we're going to use (input and output to the overlay and the UDP module), and then connect them to the overlay gates. There is no need to change the default entries in the sections "gates" and "connections" for other overlays (but keep the order! gates - submodules - connections).
     117
     118Notice that we used "like" instead of "extends". This is because IOverlay is simply an interface, not a parent class; we don't want to inherit from it. Additionaly, no "@class" is needed, since compound modules can't be extended with C++ code.
     119
     120Now we do the same thing for our application module:
     121
     122{{{
     123import oversim.common.ITier;
     124
     125module MyApplicationModules like ITier
     126{
    58127    gates:
    59         in: from_udp;   // gate from the UDP layer
    60         out: to_udp;    // gate to the UDP layer
    61         in: from_app;   // gate from the application
    62         out: to_app;    // gate to the application
    63    submodules:
    64         innerOverlay: MyOverlay;
    65     connections nocheck:  // connect our gates with the inner module
    66                 from_udp --> innerOveray.from_udp;
    67                 to_udp <-- innerOverlay.to_udp;
    68                 from_app --> innerOverlay.from_app;
    69                 to_app <-- innerOverlay.to_app;
    70 endmodule
    71 }}}
    72 
    73 == 2.2 Setting parameters ==
    74 
    75 The user can set custom values for module parameters in the file omnetpp.ini, or in default.ini for general default values, both located in the Simulation folder (see Section 4). Parameters are hierarchic, separated by dots for each layer. For example, setting a parameter for a specific overlay module in a node can be done as follows:
    76 {{{
    77 SimpleOverlay.overlayTerminal[5].overlay.myProt.myParam1 = 1024
    78 }}}
    79 
    80 In this example, we are working with the network SimpleOverlay. From there, we need node number 5, and then its overlay module. For that module, we'll set the parameter myParam1 to 1024.  This case, however, is too specific. We may not always work with the SimpleOverlay network. Or we may need that parameter to be set for all nodes. For those cases the wildcards * and ** are of use. For example:
    81 
    82 {{{
    83 *.overlayTerminal[5].overlay.myProt.myParam1 = 1024
    84 **.overlay.myProt.myParam1 = 1024
    85 }}}
    86 
    87 * replaces exactly one step of the hierarchy (or a part of a name), while ** replaces any number of steps. In the first case, * means that the parameter is set for any network (first step). In the second case, ** means the parameter is set for any network, and any node in it (first and second steps). Wildcards should be used sparingly, since it makes complicated for other users to calculate the scope, and may end up causing unexpected results (including rewriting other parameters).
    88 
    89 Should a module parameter not be set in either omnetpp.ini or default.ini, or match any wildcard, !OverSim will prompt the user to enter a value for each instance of the module. For simulations with a big amount of nodes, setting each parameter individually quickly becomes overwhelming. Therefore, it is recommended that every module parameter be assigned a default value in default.ini.
    90 
    91 == 3. Implementation using !BaseOverlay ==
    92 
    93 Overlay modules are implemented in C++ and should derive from the class BaseOverlay, which contains the necessary interface to work with other !OverSim modules.
    94 
    95 == 3.1 Important attributes ==
    96 
    97 {{{
    98 #!cpp
    99 cModule *thisTerminal;
    100 }}}
    101 Pointer to the overlay module.
    102 
    103 {{{
    104 #!cpp
    105 NodeHandle thisNode;
    106 }}}
    107 Information about the overlay node (IP address, port and overlay key).[[BR]]
    108 
    109 {{{
    110 #!cpp
    111 BootstrapOracle* bootstrapOracle;
    112 }}}
    113 Pointer to a database of registered overlay nodes, to be used for bootstrapping.[[BR]]
    114 
    115 {{{
    116 #!cpp
    117 NotificationBoard* notificationBoard;
    118 }}}
    119 Pointer to the notification board, which is used to generate node events.[[BR]]
    120 
    121 == 3.2 Initialization and finalization ==
    122 
    123 When the module has been created, the first function to be called is initialize(). This starts the internals of the module, and in turn calls initializeOverlay() which initializes the overlay. These initialization functions should only be used to start internal variables, like timers and statistic vectors, as there are no guarantees that module creation has been finished, or that any other overlay node (if any) has been created already. For that reason, bootstrapping should be first attempted after joinOverlay() has been called. When the overlay module is about to be destroyed or the simulation finishes, the overlay can use finishOverlay() to finalize itself.
    124 
    125 {{{
    126 #!cpp
    127 void initialize(int stage);
    128 }}}
    129 First function to be called, it initializes the bare bones of the overlay module. Fills in necessary parameters, initializes RPCs, sets watches and statistic vectors. When it's done it calls initializeOverlay().
    130 If the joinOnApplicationRequest parameter is not set, it automatically calls join() with a random key. Else the application should manually call the join() function to start the joining process.
    131 
    132 {{{
    133 #!cpp
    134 void initializeOverlay(int stage);
    135 }}}
    136 To be overriden by the overlay, this is the implementable overlay initialization function.
    137 
    138 {{{
    139 #!cpp
    140 void join(OverlayKey nodeID);
    141 }}}
    142 Begins the bootstrapping. This function needs only to be manually called when joinOnApplicationRequest is true. When finished it calls joinOverlay().
    143 
    144 {{{
    145 #!cpp
    146 void joinOverlay();
    147 }}}
    148 To be overriden by the overlay, to start bootstrapping. An overlay can obtain information about other nodes for bootstrapping through the bootstrapOracle functions getBootstrapNode() and getRandomNode(). When bootstrapping is finished the overlay should call setOverlayReady(true).
    149 
    150 {{{
    151 #!cpp
    152 void setOverlayReady(bool ready);
    153 }}}
    154 The overlay should call this function when it has finished bootstrapping and is in a ready state (or inversely, when it leaves that state).
    155 
    156 {{{
    157 #!cpp
    158 void finishOverlay();
    159 }}}
    160 To be overriden by the overlay, this function is called when the module is about to be destroyed, in order for the overlay to finalize itself.
    161 
    162 == 3.3 Messages ==
    163 
    164 The main way to communicate to other nodes will be through packets. To do that use the sendMessageToUDP, with the needed transport address (IP address plus port number) and message as parameters. To receive UDP messages the overlay needs to override handleUDPMessage. For communication with the application module, the functions sendMessageToApp and handleAppMessage can be used in a similar way.
    165 
    166 {{{
    167 #!cpp
    168 void sendMessageToUDP(const TransportAddress& dest, cMessage* msg);
    169 }}}
    170 Sends the given message to address dest.
    171 
    172 {{{
    173 #!cpp
    174 void handleUDPMessage(BaseOverlayMessage* msg);
    175 }}}
    176 Called when a non-RPC/non-BaseRouteMessage message from UDP arrives. May be overriden by the overlay.
    177 
    178 {{{
    179 #!cpp
    180 void sendMessageToApp(cMessage *msg);
    181 }}}
    182 Sends the given message to the application module (TBI)
    183 
    184 {{{
    185 #!cpp
    186 void handleAppMessage(cMessage* msg);
    187 }}}
    188 Called when a non-RPC/non-CommonAPI message from the application arrives. May be overriden by the overlay.
    189 
    190 
    191 == 3.4 Key Based Routing (KBR) ==
    192 
    193 To send a key through the overlay the function sendToKey is called. It uses a generic routing algorithm, using the results from findNode, to search for the corresponding node. The function findNode, the center of the KBR system, must be implemented by the overlay, and returns a list of nodes close to the given overlay key. handleFailedNode is called whenever a node given by findNode could not be reached.
    194 
    195 {{{
    196 #!cpp
    197 void sendToKey(const OverlayKey& key, BaseOverlayMessage* message,
    198                int numSiblings = 1,
    199                const std::vector<TransportAddress>& sourceRoute = TransportAddress::UNSPECIFIED_NODES,
    200                RoutingType routingType = DEFAULT_ROUTING);
    201 }}}
    202 Sends the given message to the overlay key.
    203 sourceRoute determines the route that the message will follow. If not specified, it sends the message using a generic routing algorithm using the node vector given by findNode.
    204 routingType specifies how the message will be routed.
    205 
    206 {{{
    207 #!cpp
    208 NodeVector* findNode(const OverlayKey& key, int numRedundantNodes, int numSiblings, BaseOverlayMessage* msg = NULL);
    209 }}}
    210 Must be overriden by the overlay, it returns the numSiblings closest nodes known to key in the routing topology. 
    211 
    212 {{{
    213 #!cpp
    214 bool isSiblingFor(const NodeHandle& node, const OverlayKey& key, int numSiblings, bool* err);
    215 }}}
    216 
    217 Must be overriden by the overlay, it determines whether the node parameter is among the numSiblings closest nodes to key. If numSiblings equals 1, then it answers whether the node is the closest to key. Note that this function should be consistent with findNode: if isSiblingFor returns true, an equivalent call to findNode should return the node parameter as part of the vector. The err parameter returns whether an error happened.
    218 
    219 {{{
    220 #!cpp
    221 bool handleFailedNode(const TransportAddress& failed);
    222 }}}
    223 Called whenever a node given by findNode was unreachable. May be overriden by the overlay.
    224 
    225 
    226 == 3.5 Remote Procedure Calls ==
    227 
    228 RPCs are remote procedure calls which are used by nodes to ask for information to each other. Two calls can be used to initiate an RPC query: sendRouteRpcCall, which sends an RPC to the given key, sendUdpRpcCall, which sends it to the given transport address, and sendInternalRpcCall, which sends it to the same node but a different tier. A node receiving an RPC manages it through handleRpc, and responds to it using sendRpcResponse(). In turn, the starting overlay node can use handleRpcResponse to manage returning RPC responses. handleRpcTimeout is called whenever an RPC could not be delivered. See Common/BaseRpc.h for a detailed explanation of the parameters.
    229 
    230 == 3.5.1 Sending Remote Procedure Calls ==
    231 
    232 {{{
    233 #!cpp
    234 inline uint32_t sendUdpRpcCall(const TransportAddress& dest,
    235                                BaseCallMessage* msg,
    236                                cPolymorphic* context = NULL,
    237                                simtime_t timeout = -1,
    238                                int retries = 0, int rpcId = -1,
    239                                RpcListener* rpcListener = NULL);
    240 }}}
    241 Sends the RPC message msg through UDP the address dest. 
    242 Context is a pointer to an arbitrary object which can be used to store additional state information.
    243 Timeout is the time to wait until a call is declared as lost, retries is the amount of times to retry a lost call.
    244 !RpcId is an RPC identifier to differentiate between calls.
    245 !RpcListener is a listener object that will be notified for responses and timout events.
    246 
    247 {{{
    248 #!cpp
    249 inline uint32_t sendRouteRpcCall(CompType destComp,
    250                                  const TransportAddress& dest,
    251                                  const OverlayKey& destKey,
    252                                  BaseCallMessage* msg,
    253                                  cPolymorphic* context = NULL,
    254                                  RoutingType routingType = DEFAULT_ROUTING,
    255                                  simtime_t timeout = -1,
    256                                  int retries = 0,
    257                                  int rpcId = -1,
    258                                  RpcListener* rpcListener = NULL);
    259 }}}
    260 
    261 Sends the RPC message through the overlay to the key destKey.
    262 !DestComp specifies the destination tier, and can be OVERLAY_COMP for the overlay, TIER1_COMP for the first application tier, TIER2_COMP and so on. The tier of the calling node can be obtained with getThisCompType().
    263 Context is a pointer to an arbitrary object which can be used to store additional state information.
    264 !RoutingType determines the routing algorithm.
    265 Timeout is the time to wait until a call is declared as lost, retries is the amount of times to retry a lost call.
    266 !RpcId is an RPC identifier to differentiate between calls.
    267 !RpcListener is a listener object that will be notified for responses and timout events.
    268 
    269 {{{
    270 #!cpp
    271 inline uint32_t sendInternalRpcCall(CompType destComp,
    272                                     BaseCallMessage* msg,
    273                                     cPolymorphic* context = NULL,
    274                                     simtime_t timeout = -1,
    275                                     int retries = 0,
    276                                     int rpcId = -1,
    277                                     RpcListener* rpcListener = NULL);
    278 }}}
    279 Sends the RPC message to the same node but the tier destComp.
    280 !DestComp specifies the destination tier, and can be OVERLAY_COMP for the overlay, TIER1_COMP for the first application tier, TIER2_COMP and so on. The tier of the calling node can be obtained with getThisCompType().
    281 Timeout is the time to wait until a call is declared as lost, retries is the amount of times to retry a lost call.
    282 !RpcId is an RPC identifier to differentiate between calls.
    283 !RpcListener is a listener object that will be notified for responses and timout events.
    284 
    285 == 3.5.2 Receiving Remote Procedure Calls ==
    286 
    287 {{{
    288 #!cpp
    289 bool handleRpc(BaseCallMessage* msg);
    290 }}}
    291 To be overriden by the overlay, it is called whenever an RPC is received.
    292 An alternative to using a switch to manage incoming RPCs is given by the macros in Common/RpcMacros.h, and can be used the following way:
    293 
    294 {{{
    295 #!cpp
    296     RPC_SWITCH_START( msg )
    297     RPC_DELEGATE( Join, rpcJoin );
    298     RPC_DELEGATE( Notify, rpcNotify );
    299     RPC_SWITCH_END( )
    300 }}}
    301 In this example, RPC_SWITCH_START inits the switch. RPC_DELEGATE casts the message to a structure with "Call" appended to the end of the first parameter (in these cases, !JoinCall and !NotifyCall) and sends it to the function in the second parameter (rpcJoin() and rpcNotifiy()). RPC_SWITCH_END ends the switch. RPC_HANDLED can be queried at any moment to see if the RPC has been already handled.
    302 
    303 {{{
    304 #!cpp
    305 void handleRpcTimeout(BaseCallMessage* msg, const TransportAddress& dest, int rpcId, const OverlayKey& destKey);
    306 }}}
    307 To be overriden by the overlay, it is called when an RPC times out.
    308 
    309 
    310 
    311 == 3.5.3 Replying to Remote Procedure Calls ==
    312 
    313 {{{
    314 #!cpp
    315 void sendRpcResponse(BaseCallMessage* call, BaseResponseMessage* response);
    316 }}}
    317 Must be called by the overlay to respond to a given RPC.
    318 
    319 {{{
    320 #!cpp
    321 void handleRpcResponse( BaseResponseMessage* msg, int rpcId, simtime_t rtt );
    322 }}}
    323 To be overriden by the overlay, it is called whenever an RPC response is received.
    324 
    325 == 3.5.4 Ping RPC Calls ==
    326 
    327 Ping RPC calls are convenience functions already implemented.
    328 
    329 {{{
    330 #!cpp
    331 void pingNode(const TransportAddress& dest,
    332               simtime_t timeout = -1,
    333               int retries = 0,
    334               cPolymorphic* context = NULL,
    335               const char* caption = "PING",
    336               RpcListener* rpcListener = NULL,
    337               int rpcId = -1,
    338               TransportType transportType = INVALID_TRANSPORT,
    339               bool overrideCache = false);
    340 }}}
    341 Pings the node dest. When a node replies, the callback function pingResponse is invoked.
    342 Parameters timeout, retries, rpcListener and rpcId are the same as sendRouteRpcCall.
    343 !OverrideCache determines whether the RTT value of the ping call should be cached. 
    344 
    345 {{{
    346 #!cpp
    347 void pingResponse(PingResponse* response, cPolymorphic* context, int rpcId, simtime_t rtt);
    348 }}}
    349 To be overriden by the overlay, it is called when a ping response arrives.
    350 Response is the RPC reply message.  Context, rpcIdare the same parameters as the calling pingNode. The rtt parameter returns the RTT value.
    351 
    352 {{{
    353 #!cpp
    354 void pingTimeout(PingCall* call, const TransportAddress& dest, cPolymorphic* context, int rpcId);
    355 }}}
    356 To be overriden by the overlay, it is called after a ping RPC times out.
    357 Call is the RPC call message.  Context, rpcIdare the same parameters as the calling pingNode.
    358 
    359 
    360 == 4. Setting up the network: the configuration file ==
    361 
    362 Now that the overlay module is implemented, we still need to set up a network in order to run that overlay. To do that, we need to edit the omnetpp.ini file, or set up a custom configuration file. The configuration file should be located in the Simulation folder.
    363 
    364 The first line of the configuration file is the inclusion of the default values. That is done by adding the following line:
     128        input udpIn;             // gate from the UDP layer
     129        output udpOut;           // gate to the UDP layer
     130        input from_lowerTier;    // gate from the lower tier
     131        input from_upperTier;    // gate from the upper tier
     132        output to_lowerTier;     // gate to the lower tier
     133        output to_upperTier;     // gate to the upper tier
     134        input trace_in;          // gate for trace file commands
     135
     136    submodules:
     137        myApplication: MyApplication;
     138
     139    connections allowunconnected:
     140        from_lowerTier --> myApplication.from_lowerTier;
     141        to_lowerTier <-- myApplication.to_lowerTier;
     142        udpIn --> myApplication.udpIn;
     143        udpOut <-- myApplication.udpOut;
     144        trace_in --> myApplication.trace_in;
     145}
     146}}}
     147
     148Notice that we now use the ITier interface. Additionaly, the sections "gates" and "connections" look a bit different, but there is still nothing you need to change.
     149
     150== 3. Messages ==
     151
     152For sending messages, we can use the basic cMessage class. However, we'll be needing a few custom fields for our application, so we'll use a customized message instead. Custom message declarations are like those of modules, but without sections: simply include the parameters directly. The framework will automatically create getter- and setter-functions for each of them.
     153
     154And like modules, messages should be declared in their own (.msg) files.
     155
     156In this case, let's see MyMessage.msg:
     157
     158{{{
     159
     160// Import the C++ TransportAddress class
     161
     162cplusplus {{
     163#include <TransportAddress.h>
     164}}
     165class noncobject TransportAddress;            // noncobject means it's not a message class.
     166
     167// First, we declare an enum for the message type:
     168// Enumerations in messages MUST have a value.
     169
     170enum MessageType {
     171    MYMSG_PING = 1;           // outgoing message
     172    MYMSG_PONG = 2;           // returning message
     173}
     174
     175// now we declare the message proper
     176
     177packet MyMessage {
     178    int type enum (MessageType);     // message type
     179    TransportAddress senderAddress;  // address of the node that sent the message
     180}
     181}}}
     182
     183In order to route packets in a realistic way, the "length" parameter of the message should be set to an appropiate value. This is done manually by using the setBitLength(bits) or setByteLength(bytes) function when sending the message. Forgetting to set this value will default the length to a size of 0, potentially making measurements such as latencies less meaningful.
     184
     185All messages can encapsulate any other message (just avoid recursivity!) by using the encapsulate() function. To decapsulate the message, use decapsulate(). To peek the encapsulated message without decapsulating it, use getEncapsulatedMsg(). The length of the message is automatically changed accordingly.
     186
     187Additionaly, each message that is created must be deleted exactly once. Messages that aren't deleted will cause memory leaks, and those that are deleted twice can cause a segmentation fault. It is the responsability of the programmer to know when a message should be deleted.
     188
     189== 4. Implementing the overlay and application modules ==
     190
     191In this section, we'll implement our overlay and application. But first, let's do a introduction about some of the important variable types used in OverSim.
     192
     193BaseOverlay:        Template overlay module class. All overlay modules should derive from it.[[BR]]
     194BaseApp:            Template application module class. All application modules should derive from it.[[BR]]
     195
     196OverlayKey:         Class to describe overlay keys. Internally it stores the key as an bit array. [[BR]]
     197                    Its value can be set in different ways when it's being initialized:[[BR]]
     198{{{
     199!OverlayKey();           // initializes the key as UNSPECIFIED. While in this value, most of the key operations are invalid! [[BR]]
     200!OverlayKey(5);          // initializes the value as an 32-bit integer.[[BR]]
     201!OverlayKey(buffer, 32); // initializes the value from the first 32 bytes of buffer.[[BR]]
     202!OverlayKey().random();  // initializes the value as a random bit array.[[BR]]
     203}}}
     204                    OverlayKey operations include equality (==), order (<, >) and range (isBetween(key1, key2)).[[BR]]
     205
     206IPvXAddress:        Generic IP address, can contain either an IPv4 address (IPAddress) or an IPv6 address (IPv6Address).[[BR]]
     207TransportAddress:   A structure containing bot an IPvXAddress (field "ip"), and a port (field "port").[[BR]]
     208NodeHandle:         A child class of TransportAddress, additionaly contains an OverlayKey (field "key"). In overlay modules, the NodeHandle value representing the node in which the module is can be retrieved with "thisNode". In application modules, thisNode also exists, but the "key" field may not be set![[BR]]
     209
     210Now, let's continue with the implementation.
     211
     212== 4.1 Implementing the Application ==
     213
     214First, we'll start with MyApplication, since the application interface is easier to understand. Our application will implement a simple PING-type program, in which a packet is sent to another node, and that node sends the packet back. When we start, we'll wait <sendPeriod> seconds, then we'll route <numToSend> packets to random keys through the overlay. When a node receives a packet, it will send it back to the owner through UDP. The process is repeated until the simulation ends.
     215
     216This is the declaration of MyApplication from MyApplication.h:
     217
     218{{{
     219class MyApplication : public BaseApp
     220{
     221    // module parameters
     222    simtime_t sendPeriod;     // we'll store the "sendPeriod" parameter here
     223    int numToSend;            // we'll store the "numToSend" parameter here
     224    int largestKey;           // we'll store the "largestKey" parameter here
     225
     226    // statistics
     227    int numSent;              //number of packets sent
     228    int numReceived;          //number of packets received
     229
     230    // our timer
     231    cMessage *timerMsg;
     232
     233    // application routines
     234    void initializeApp(int stage);                 // called when the module is being created
     235    void finishApp();                              // called when the module is about to be destroyed
     236    void handleTimerEvent(cMessage* msg);          // called when we received a timer message
     237    void deliver(OverlayKey& key, cMessage* msg);  // called when we receive a message from the overlay
     238    void handleUDPMessage(cMessage* msg);          // called when we receive a UDP message
     239};
     240}}}
     241
     242Now comes the implementation of MyApplication from MyApplication.cc:
     243
     244{{{
     245
     246// This line tells the simulator that MyApplication is going to be extended using C++ code.
     247// It *must* be present (only once) somewhere in your code, outside a function, for each module you'll be extending.
     248
     249Define_Module(MyApplication);
     250
     251// initializeApp is called when the module is being created.
     252// Use this function instead of the constructor for initializing variables.
     253void MyApplication::initializeApp(int stage) {
     254
     255    // initializeApp will be called twice, each with a different stage.
     256    // stage can be either MIN_STAGE_APP (this module is being created), or MAX_STAGE_APP (all modules were created).
     257    // We only care about MIN_STAGE_APP here.
     258
     259    if (stage != MIN_STAGE_APP) return;
     260
     261    // copy the module parameter values to our own variables
     262
     263    sendPeriod = par("sendPeriod");
     264    numToSend = par("numToSend");
     265    largestKey = par("largestKey");
     266
     267    // initialize our statistics variables
     268
     269    numSent = 0;
     270    numReceived = 0;
     271
     272    // tell the GUI to display our variables
     273
     274    WATCH(numSent);
     275    WATCH(numReceived);
     276
     277    // start our timer!
     278
     279    timerMsg = new cMessage("MyApplication Timer");
     280    scheduleAt(simTime() + sendPeriod, timerMsg);
     281}
     282
     283
     284// finalize is called when the module is being destroyed
     285
     286void MyApplication::finishApp() {
     287
     288    // first we'll delete our timer
     289
     290    delete timerMsg;
     291
     292    // finalize() is usually used to save the module's statistics.
     293    // We'll use globalStatistics->addStdDev(), which will calculate min, max, mean and deviation values.
     294    // The first parameter is a name for the value, you can use any name you like (use a name you can find quickly!).
     295    // In the end, the simulator will mix together all values, from all nodes, with the same name.
     296
     297    globalStatistics->addStdDev("MyApplication: Sent packets", numSent);
     298    globalStatistics->addStdDev("MyApplication: Received packets", numReceived);
     299}
     300
     301
     302// handleTimerEvent is called when a timer event triggers
     303
     304void MyApplication::handleTimerEvent(cMessage* msg) {
     305
     306    if (msg == timerMsg) {    // is this our timer?
     307
     308        scheduleAt(simTime() + sendPeriod, timerMsg); // reschedule our message
     309
     310        // if the simulator is still busy creating the network, let's wait a bit longer
     311        if (underlayConfigurator->isInInitPhase()) return;
     312
     313        for (int i = 0; i < numToSend; i++) {
     314
     315            OverlayKey randomKey(intuniform(1, largestKey)); // let's create a random key
     316
     317            MyMessage *myMessage;                            // the message we'll send
     318            myMessage = new MyMessage();
     319            myMessage->setType(MYMSG_PING);                  // set the message type to PING
     320            myMessage->setSenderAddress(thisNode);           // set the sender address to our own
     321            myMessage->setByteLength(100);                   // set the message length to 100 bytes
     322
     323            numSent++;                                       // update statistics
     324
     325            callRoute(randomKey, myMessage); // send it to the overlay
     326        }
     327
     328    } else {
     329
     330        delete msg; // who knows what this packet is?
     331
     332    }
     333}
     334
     335// deliver is called when we receive a message from the overlay.
     336// Unhandled or unknown packets can be safely deleted here.
     337
     338void MyApplication::deliver(OverlayKey& key, cMessage* msg) {
     339
     340    // we are only expecting messages of type MyMessage, throw away any other
     341
     342    MyMessage *myMsg = dynamic_cast<MyMessage*>(msg);
     343    if (myMsg == 0) {
     344        delete msg;     // unknown!
     345        return;
     346    }
     347
     348    // are we a PING? send a PONG!
     349
     350    if (myMsg->getType() == MYMSG_PING) {
     351
     352       myMsg->setType(MYMSG_PONG);                         // change type
     353       sendMessageToUDP(myMsg->getSenderAddress(), myMsg); // send it back to its owner
     354
     355    } else {
     356
     357       delete msg;     // unhandled!
     358
     359    }
     360}
     361
     362// handleUDPMessage is called when we receive a message from UDP.
     363// Unhandled or unknown packets can be safely deleted here.
     364
     365void MyApplication::handleUDPMessage(cMessage* msg) {
     366
     367    // we are only expecting messages of type MyMessage
     368
     369    MyMessage *myMsg = dynamic_cast<MyMessage*>(msg);
     370
     371    if (myMsg && myMsg->getType() == MYMSG_PONG) {
     372
     373       numReceived++;
     374
     375    }
     376
     377    // Whatever msg was, we won't need it anymore.
     378
     379    delete msg;
     380}
     381
     382}}}
     383
     384
     385== 4.2 Implementing the Overlay ==
     386
     387Now, we'll implement our overlay module. Our overlay will be rather simple, and based on only two concepts. First, an overlay key maps directly to the IP address of its holder (for example, key 16 will be held by 1.0.0.16). And second, routing a packet from key A to key B will consist of sending that packet to all nodes with keys between A and B (for example, sending a node from key 4 to key 1 will create a route of 4 - 3 - 2 - 1).
     388
     389This is the declaration of MyOverlay in MyOverlay.h
     390
     391{{{
     392class MyOverlay : public BaseOverlay {
     393public:
     394
     395    // Routing parameters
     396    int myKey;               // our overlay key
     397    NodeHandle prevNode;     // next node in chain
     398    NodeHandle nextNode;     // previous node in chain
     399
     400    //module parameters
     401    double dropChance;       // we'll store the "dropChance" parameter here
     402
     403    // statistics
     404    int numDropped;          // how many packets have we dropped?
     405
     406    // overlay routines
     407    void initializeOverlay(int stage);                      // called when the overlay is being initialized
     408    void setOwnNodeID();                                    // (optional) called to set the key of this node (random otherwise)
     409    void joinOverlay();                                     // called when the node is ready to join the overlay
     410    void finalizeOverlay();                                 // called when the module is about to be destroyed
     411
     412    // obligatory: called when we need the next hop to route a packet to the given key
     413    NodeVector* findNode(const OverlayKey& key,             // key to route to
     414                                 int numRedundantNodes,     // how many candidates for next hop we want (see getMaxNumSiblings)
     415                                 int numSiblings,           // how many siblings we'll return (?) (see getMaxRedundantNodes)
     416                                 BaseOverlayMessage* msg);  // message being routed
     417
     418    // obligatory: In general, called when we need to know whether node is amongst numSiblings closest nodes to key.
     419    // But normally it is called with node set to this node, and asking whether this node is responsible for key.
     420    bool isSiblingFor(const NodeHandle& node,               // which node (usually thisNode) we're referring to
     421                                 const OverlayKey& key,     // key in question
     422                                 int numSiblings,           // how many siblings we're querying about
     423                                 bool* err);                // set to false when we couldn't determine the range
     424
     425    // obligatory: Set the maximum number of siblings that can be queried about (usually 1)
     426    int getMaxNumSiblings();
     427
     428    // obligatory: Set the maximum number of redundant nodes that can be queried about (usually 1)
     429    int getMaxNumRedundantNodes();
     430
     431};
     432}}}
     433
     434Now comes the implementation of MyOverlay from MyOverlay.cc:
     435
     436{{{
     437// Important! This line must be present for each module you extend (see MyApplication)
     438Define_Module(MyOverlay);
     439
     440// To convert between IP addresses (which have bit 24 active), and keys (which don't), we'll need to set or remove this bit.
     441#define BIGBIT (1 << 24)
     442
     443// Called when the module is being initialized
     444void MyOverlay::initializeOverlay(int stage) {
     445
     446    if (stage != MIN_STAGE_OVERLAY) return;         // see BaseApp.cc
     447
     448    myKey = thisNode.ip.get4().getInt() & ~BIGBIT;  // get our key from our IP address
     449
     450    // initialize the rest of variables
     451    numDropped = 0;
     452    if (!(par("enableDrops"))) {
     453        dropChance = 0;
     454    } else {
     455        dropChance = par("dropChance");
     456    }
     457}
     458
     459// Called to set our own overlay key (optional)
     460void MyOverlay::setOwnNodeID() {
     461    thisNode.key = OverlayKey(myKey);   // create the corresponding overlay key
     462}
     463
     464// Called when the module is ready to join the overlay
     465void MyOverlay::joinOverlay() {
     466
     467    // Set the information of the previous step in the chain
     468    prevNode.ip = IPAddress(BIGBIT | (myKey - 1));
     469    prevNode.port = thisNode.port;
     470    prevNode.key = OverlayKey(myKey - 1);
     471
     472    // Set the information of the next step in the chain
     473    nextNode.ip = IPAddress(BIGBIT | (myKey + 1));
     474    nextNode.port = thisNode.port;
     475    nextNode.key = OverlayKey(myKey + 1);
     476
     477    // tell the simulator that we're ready
     478    setOverlayReady(true);
     479}
     480
     481// Return whether we know if the given node is responsible for the key
     482bool MyOverlay::isSiblingFor(const NodeHandle& node,
     483                                 const OverlayKey& key,
     484                                 int numSiblings,
     485                                 bool* err)
     486{
     487    if (node == thisNode && key == thisNode.key) { // is it our node and our key?
     488        return true;
     489    }
     490    return false;  // we don't know otherwise
     491}
     492
     493// Return the next step for the routing of the given message
     494NodeVector *MyOverlay::findNode(const OverlayKey& key,
     495                                 int numRedundantNodes,
     496                                 int numSiblings,
     497                                 BaseOverlayMessage* msg)
     498{
     499    NodeVector* nextHops;
     500
     501    if (uniform(0, 1) < dropChance) {          // do we drop the packet?
     502        nextHops = new NodeVector(0);          // if yes, return an empty node vector
     503        numDropped++;                          // (don't delete msg here! the overlay will delete it later)
     504        return nextHops;
     505    }
     506
     507    nextHops = new NodeVector(1);              // else, set the response vector with one node
     508
     509    if (key == thisNode.key) {                 // are we responsible? next step is this node
     510        nextHops->add(thisNode);
     511    } else if (key < thisNode.key) {           // is the key behind us? next step is the previous node
     512        nextHops->add(prevNode);
     513    } else {                                   // otherwise, the next step is the next node
     514        nextHops->add(nextNode);
     515    }
     516    return nextHops;
     517}
     518
     519// Called when the module is about to be destroyed
     520void MyOverlay::finalizeOverlay() {
     521    // remove this node from the overlay
     522    setOverlayReady(false);
     523
     524    // save the statistics (see MyApplication)
     525    globalStatistics->addStdDev("MyOverlay: Dropped packets", numDropped);
     526}
     527
     528// Return the max amount of siblings that can be queried about
     529int MyOverlay::getMaxNumSiblings() {
     530    return 1;
     531}
     532
     533// Return the max amount of redundant that can be queried about
     534int MyOverlay::getMaxNumRedundantNodes() {
     535    return 1;
     536}
     537}}}
     538
     539== 5. Configuring the Simulation ==
     540
     541Now that the overlay module is implemented, we still need to set up a network in order to run that overlay. To do that, we need to edit the omnetpp.ini file, or set up a custom configuration file. The configuration file should be located in the <OverSim>/simulation folder.
     542
     543== 5.1 Setting Parameters ==
     544
     545The user can set custom values for module parameters in the file omnetpp.ini (or whichever configuration file you use), or in default.ini for general default values, located in the <OverSim>/simulation folder. Parameters are hierarchic, separated by a dot for each layer. For example, setting a parameter for a specific overlay module in a node can be done as follows:
     546
     547{{{
     548SimpleOverlay.overlayTerminal[5].overlay.myOverlay.enableDrops = true
     549}}}
     550
     551In this example, we are working with the network SimpleOverlay. From there, we need node number 5, and then its overlay module. For that module, we'll use the submodule myOverlay, and set the parameter enableDrops to true.
     552
     553This case, however, is too specific. We may not always work with the SimpleOverlay network. Or we may need that parameter to be set for all nodes. For those cases the wildcards * and ** are of use. For example:
     554
     555{{{
     556*.overlayTerminal[5].overlay.myOverlay.enableDrops = true
     557**.overlay.myOverlay.enableDrops = true
     558}}}
     559
     560* replaces exactly one step of the hierarchy (or a part of a name), while ** replaces any number of steps. In the first case, * means that the parameter is set for any network (first step). In the second case, ** means the parameter is set for any network, and any node in it (first and second steps, and further). Wildcards should be used sparingly, since it makes complicated for other users to calculate the scope, and may end up causing unexpected results (including rewriting other parameters).
     561
     562Should a module parameter not be set in either configuration file, or match any wildcard, !OverSim will prompt the user to enter a value for each instance of the module. For simulations with a big amount of nodes, setting each parameter individually quickly becomes overwhelming. Therefore, it is recommended that every module parameter be assigned a default value in default.ini.
     563
     564== 5.2 Creating our Configuration File ==
     565
     566Let's create a configuration file in <OverSim>/simulations called mysim.ini.
     567
     568The default.ini file contains the default values for many overlay parameters, and therefore it's highly useful to include it in our file. Since the simulator will use the first value it sees, the default value should go at the end.
     569
     570Therefore, the last line of omnetpp.ini should look like this:
    365571{{{
    366572include ./default.ini
    367573}}}
    368574
    369 Each simulation environment class is defined as a run. A configuration file can contain different amounts of runs, each with a different number. We need to set up the network in that run. There are two base networks: SimpleUnderlay and Ipv4Underlay. !SimpleUnderlay is a simplified flat network where each node is assigned coordinates, packet latencies are calculated based on the distance of the source and destination node coordinates, and each nodes are directly connected to one another. Ipv4Underlay emulates real-life networks and contain hierarchies of nodes, routers, and backbones.  The network type is set with the first-tier parameter network. Network modules can be accessed under the names of !SimpleNetwork for !SimpleUnderlay and Ipv4Network for Ipv4Underlay.  The module in charge of building the network is called underlayConfigurator.
    370 
    371 Now, once the network type has been set, now we need to declare the node classes. We can declare each node to be made of the same components and attributes, or create different classes each with its own attributes. Each class is represented by a churnGenerator. For example, we can create a network with one type of node:
    372 
    373 {{{
    374 [Run 1]
    375 
    376 network = SimpleNetwork
    377 
    378 # The following applies to SimpleNetwork
    379 *.underlayConfigurator.churnGeneratorTypes = "LifetimeChurn"  // one node type
    380 
    381 # Since we only have one churn generator, the following applies to SimpleNetwork.churnGenerator[0]
    382 **.numTiers = 1                         // only one application tier
    383 **.tier1Type = "MyAppModule"            // module name of the application tier
    384 **.overlayType = "MyOverlay"            // module name of the overlay
    385 **.lifetimeMean = 10000                 // mean session time in seconds
    386 **.targetOverlayTerminalNum=10          // target number of nodes
    387 }}}
    388 
    389 The following applies for a network with 2 node classes: a server and a client. All other values are the default ones set in default.ini.
    390 
    391 {{{
    392 [Run 2]
    393 
    394 *.underlayConfigurator.churnGeneratorTypes = "LifetimeChurn NoChurn"  // two churn generators
    395 
    396 # First churn
    397 *.churnGenerator[0].tier1Type = "MyClientModule"  // module name of the application tier
    398 *.churnGenerator[0].overlayType = "MyOverlay"     // module name of the overlay
    399 
    400 # Second churn
    401 *.churnGenerator[1].tier1Type = "MyServerModule"  // module name of the application tier
    402 *.churnGenerator[1].overlayType = "MyOverlay"     // module name of the overlay
    403 }}}
    404 
    405 == 5. Compiling and running ==
    406 
    407 In order for !OverSim to find your files you need to to make the following changes:
    408 Edit makemakefiles in the root folder, and add an include to your directory in ALL_OVERSIM_INCLUDES.
    409 Change the “all:” section accordingly by adding your folder to the list.
    410 
    411 Now run {{{ ./makemake }}} and {{{ make }}} in the root folder. That should compile your new modules.
    412 
    413 In order to run it, you need to setup your simulation run in omnetpp.ini as explained in Section 4. Make sure that you selected default values for all parameters in default.ini, or you'll be prompted for a value when the simulation begins - for each instance of the parameter. To start !OverSim, enter the directory Simulations and run :
    414 {{{
    415 ../bin/OverSim [-f customConfigFile] [-r runNumber]
    416 }}}
    417 
    418 If you don't select a run number, if the GUI is enabled, you'll be prompted for a run number. If not, all the runs in omnetpp.ini (or the given custom config file) will be run.
     575Each set of parameters for a simulation environment is called a configuration. A simulation file can contain any amounts of configurations, each with a different name. In the same way, each configuration can contain any amount of overlay parameters as needed.
     576
     577Since many configurations might specify the same value for a given parameter, we can set a default value in the General section. For example, let's set the value of the base network as SimpleUnderlayNetwork.
     578
     579{{{
     580[General]
     581sim-time-limit = 1000s                                              // set all simulations to last 1000 seconds
     582network = "oversim.underlay.simpleunderlay.SimpleUnderlayNetwork"   // this is a module path! do not confuse with parameter paths.
     583}}}
     584
     585Now, unless specified otherwise, all configurations will use SimpleUnderlayNetwork as their network. Notice that the value of "network" is a module path, which represents the location of the ned file, and not a parameter path.
     586
     587Further on networks, there are two base networks: SimpleUnderlay and Ipv4Underlay. !SimpleUnderlay is a simplified flat network where each node is assigned coordinates, packet latencies are calculated based on the distance of the source and destination node coordinates, and each nodes are directly connected to one another. Ipv4Underlay emulates real-life networks and contain hierarchies of nodes, routers, and backbones. Network modules can be accessed under the names of !SimpleUnderlayNetwork for !SimpleUnderlay and Ipv4Network for Ipv4Underlay.
     588
     589Now, once the network type has been set, we can set the parameter values that we'll need. For example, let's create a configuration called "Example". There are two basic parts that should be configured: the churn type, and the node parameters.
     590
     591The churn type tells OverSim how often it should add or delete nodes from the network. There are many churn types (e.g. NoChurn for a static network, LifetimeChurn for creating nodes with a given lifetime distribution, and so on); for a complete list see the ned files in <OverSim>/src/common. In our example, we'll use the less interesting NoChurn, which disables churn in our network. There are plenty of examples in <OverSim>/simulations/omnetpp.ini for all churns.
     592
     593The second part are the node parameters. Two node parameters are obligatory: tier1Type (to specify the application module), and overlayType (for the overlay module). Further parameters can be specified for these application and overlay modules. For this example, we'll use the module MyOverlayModules, which we declared in a previous chapter.
     594
     595{{{
     596[Config ExampleConf]
     597description = MyOverlay test (SimpleUnderlayNetwork)
     598
     599// Configure the churn
     600*.underlayConfigurator.churnGeneratorTypes = "oversim.common.NoChurn"
     601**.targetOverlayTerminalNum = 10
     602
     603// Node parameters
     604**.overlayType = "oversim.overlay.myoverlay.MyOverlayModules"
     605**.tier1Type = "oversim.applications.myapplication.MyApplicationModules"
     606
     607**.myOverlay.enableDrops = true
     608**.myOverlay.dropChance = 0
     609
     610**.myApplication.sendPeriod = 1s
     611**.myApplication.numToSend = 1
     612**.myApplication.largestKey = 10
     613
     614}}}
     615
     616Like modules, configurations can also use inheritance. A configuration that inherits from a parent configuration receives all the parameters that were set there, but can change them if needed. For example, let's make two configurations that inherit from ExampleConf:
     617
     618{{{
     619
     620[Config ExampleA]
     621extends = ExampleConf
     622**.myOverlay.dropChance = 0.1
     623**.myApplication.sendPeriod = 1s
     624
     625[Config ExampleB]
     626extends = ExampleConf
     627**.myOverlay.dropChance = 0.5
     628**.myApplication.sendPeriod = 2s
     629
     630}}}
     631
     632Now, we see that both configurations are equal except for their different values for dropChance and sendPeriod. What happens if we need more simulations that have different values for both parameters, but retain the rest? For that, we can use runs.
     633
     634Let's, for example, create a configuration from ExampleConf, but where dropChance takes the values of 0.1, 0.3, 0.5, and 0.7.
     635
     636{{{
     637
     638[Config ExampleC]
     639extends = Example
     640**.myOverlay.dropChance = ${Drop=0.1, 0.3, 0.5, 0.7}
     641**.myApplication.sendPeriod = 1s
     642
     643}}}
     644
     645Here, we have a single configuration, ExampleC, with 4 runs: one for when dropChance is 0.1, the second for when dropChance is 0.3, and so on. In order to identify which dropChance we'll be using for a given run, we'll define a variable called Drop, which will contain the dropChance value. This is specified by the "Drop=" chain inside the dropChance definition. This variable can be used for other purposes, specified in the !User Manual.
     646
     647The results from each run will be saved in a different file (ExampleC-0.sca, ExampleC-1.sca, and so on for the scalar data). The parameter value that was taken for each file is saved within it (together with the variable), to avoid confusion.
     648
     649Additionaly, many parameters can have variable values, for example, we can set sendPeriod as follows:
     650
     651{{{
     652
     653...
     654**.application.sendPeriod = ${Period=1s, 2s, 5s}
     655
     656}}}
     657
     658In this case, we'll have 12 runs, once for each combination of dropChance and sendPeriod. Furthermore, each run can be repeated as many times as desired.
     659
     660{{{
     661
     662repeat = 3
     663
     664}}}
     665
     666With this, we'll have each of the 12 runs repeated 3 times, for a total of 36 runs. It is recommended to simplify your configurations into a single one by using runs, when possible.
     667
     668
     669== 6. Compiling and Running ==
     670
     671Unlike previous versions of !OverSim, now the framework will automatically find any new "cpp" and "ned" files and compile them.
     672
     673Now we need to build !OverSim. There are two types of builds: debug (no optimizations, include debug information) and release (optimizations, with reduced debug information). Go to the root folder and type one of the following:
     674
     675make MODE=release   # release mode
     676make MODE=debug     # debug mode
     677make                # also sets debug mode
     678
     679That should compile your new modules. To clear all compiled files, use make clean as usual.
     680
     681In order to run it, you need to setup your configuration in omnetpp.ini as explained in Section 4. Make sure that you selected default values for all parameters in default.ini, or you'll be prompted for a value when the simulation begins (for each module that uses that parameter!).
     682
     683There are two ways to start !OverSim: by using the GUI (Tkenv) or through the command line (Cmdenv). To run !OverSim, enter the directory <OverSim>/simulations and run :
     684
     685{{{
     686../src/OverSim [-u Tkenv | CmdEnv] [-f customConfigFile] -c configName [-r runNumber]
     687}}}
     688
     689The configuration is optional if the GUI is enabled, but you'll be prompted later for which configuration to run. If you don't specify a configuration for the command line (or a non-existing one), the simulator will fail silently and run a default simulation.
     690
     691
     692== 7. Remote Procedure Calls ==
     693
     694Remote Procedure Calls (RPCs) are a useful paradigm for when an application wants to execute a function, but where the context and / or the code are in another host, yet in a transparent way. Continuing our MyOverlay example, let's create an RPC function that retrieves the neighbors from another node.
     695
     696The MyOverlay header would look this way:
     697
     698{{{
     699class MyOverlay : public BaseOverlay {
     700    ...
     701    // The function that will be called from outside
     702   
     703    void getNeighbors(const OverlayKey& neighborKey);        // asynchronously request the neighbors of neighborKey
     704
     705    // Callback functions (that will be overwritten)
     706
     707    virtual void callbackNeighbors(
     708            const NodeHandle& neighborKey,
     709            const NodeHandle& prevNeighbor,
     710            const NodeHandle& nextNeighbor);                 // function to call to respond about the queried neighbors
     711    virtual void callbackTimeout(
     712            const OverlayKey &neighborKey);                  // function to call if the query times out
     713
     714    // Internal handling of RPCs
     715
     716    bool handleRpcCall(BaseCallMessage *msg);                // called when we receive an RPC from another node
     717    void handleRpcResponse(BaseResponseMessage* msg,         // called when we receive an RPC response from another node
     718                              cPolymorphic* context,
     719                              int rpcId,
     720                              simtime_t rtt);
     721    void handleRpcTimeout(BaseCallMessage* msg,                 // called when an RPC times out
     722                             const TransportAddress& dest,
     723                             cPolymorphic* context, int rpcId,
     724                             const OverlayKey&);
     725   
     726
     727};
     728}}}
     729
     730The RPC function will query another node about its neighbors. To communicate with that node, we'll need a couple of custom messages.
     731
     732The first message is the Call message, and inherits from BaseCallMessage. The address of the calling node is stored in BaseCallMessage, so it is not necessary to add it. However, we'll store the destination key, so we can identify the message quickly in case it times out. Note that the name of Call messages should end in "Call".
     733The second message is the Response message, and inherits from BaseResponseMessage. It will contain the key of the responding node, together with both of its neighbors. Note that the name of Response messages should end in "Response".
     734
     735
     736Here's how they look:
     737
     738{{{
     739
     740cplusplus {{
     741#include <NodeHandle.h>
     742#include <OverlayKey.h>
     743#include <CommonMessages_m.h>
     744}}
     745class noncobject NodeHandle;
     746class noncobject OverlayKey;
     747class BaseCallMessage;
     748class BaseResponseMessage;
     749
     750
     751packet MyNeighborCall extends BaseCallMessage
     752{
     753    OverlayKey destinationKey;
     754};
     755
     756packet MyNeighborResponse extends BaseResponseMessage
     757{
     758    NodeHandle respondingNode;
     759    NodeHandle prevNeighbor;
     760    NodeHandle nextNeighbor;
     761};
     762
     763}}}
     764
     765
     766First, we start with the getNeighbors() function, which creates the RPC message.
     767
     768{{{
     769    void MyOverlay::getNeighbors(const OverlayKey &neighborKey) {
     770        MyNeighborCall *msg = new MyNeighborCall();
     771        msg->setDestinationKey(neighborKey);
     772
     773        // The function we'll be using to send an RPC is sendRouteRpcCall.
     774        // The first value is to which tier we'll be talking. Can be either OVERLAY_COMP, TIER1_COMP, TIER2_COMP, and so on.
     775        // The second parameter is the node to which we'll send the message. Can be either an OverlayKey or a TransportAddress.
     776        // The third parameter is the message.
     777        sendRouteRpcCall(OVERLAY_COMP, neighborKey, msg);
     778    }
     779}}}
     780
     781Now, let's see how the RPC calls are implemented:
     782
     783{{{
     784
     785    // Handle an incoming Call message
     786    // Only delete msg if the RPC is handled here, and you won't respond using sendRpcResponse!
     787
     788    bool MyOverlay::handleRpcCall(BaseCallMessage *msg) {
     789       
     790        // There are many macros to simplify the handling of RPCs. The full list is in <OverSim>/src/common/RpcMacros.h.
     791       
     792        // start a switch
     793        RPC_SWITCH_START(msg);
     794       
     795        // enters the following block if the message is of type MyNeighborCall (note the shortened parameter!)
     796        RPC_ON_CALL(MyNeighbor) {
     797            MyNeighborCall *mrpc = (MyNeighborCall*)msg;          // get Call message
     798
     799            MyNeighborResponse *rrpc = new MyNeighborResponse();  // create response
     800            rrpc->setRespondingNode(thisNode);
     801            rrpc->setPrevNeighbor(prevNode);
     802            rrpc->setNextNeighbor(nextNode);
     803           
     804            // now send the response. sendRpcResponse can automatically tell where to send it to.
     805            // note that sendRpcResponse will delete mrpc (aka msg)!
     806            sendRpcResponse(mrpc, rrpc);
     807   
     808            RPC_HANDLED = true;  // set to true, since we did handle this RPC (default is false)
     809        }
     810
     811        // end the switch
     812        RPC_SWITCH_END();
     813
     814        // return whether we handled the message or not.
     815        // don't delete unhandled messages!
     816        return RPC_HANDLED;
     817    }
     818
     819    // Called when an RPC we sent has timed out.
     820    // Don't delete msg here!
     821
     822    void MyOverlay::handleRpcTimeout(BaseCallMessage* msg,
     823                             const TransportAddress& dest,
     824                             cPolymorphic* context, int rpcId,
     825                             const OverlayKey&)
     826    {
     827        // Same macros as in handleRpc
     828
     829        // start a switch
     830        RPC_SWITCH_START(msg);
     831       
     832        // enters the following block if the message is of type MyNeighborCall (note the shortened parameter!)
     833        RPC_ON_CALL(MyNeighbor) {
     834            MyNeighborCall *mrpc = (MyNeighborCall*)msg;          // get Call message
     835            callbackTimeout(mrpc->getDestinationKey());           // call our interface function
     836        }
     837        // end the switch
     838        RPC_SWITCH_END();
     839    }
     840
     841    // Called when we receive an RPC response from another node.
     842    // Don't delete msg here!
     843
     844    void MyOverlay::handleRpcResponse(BaseResponseMessage* msg,
     845                              cPolymorphic* context,
     846                              int rpcId,
     847                              simtime_t rtt)
     848    {
     849        // The macros are here similar. Just use RPC_ON_RESPONSE instead of RPC_ON_CALL.
     850
     851        // start a switch
     852        RPC_SWITCH_START(msg);
     853       
     854        // enters the following block if the message is of type MyNeighborResponse (note the shortened parameter!)
     855        RPC_ON_RESPONSE(MyNeighbor) {
     856            MyNeighborResponse *mrpc = (MyNeighborResponse*)msg;          // get Response message
     857            callbackNeighbors(mrpc->getRespondingNode(),
     858                        mrpc->getPrevNeighbor(),
     859                        mrpc->getNextNeighbor());                         // call our interface function
     860        }
     861        // end the switch
     862        RPC_SWITCH_END();
     863    }
     864
     865}}}
     866
    419867
    420868== Have fun! ==
     869