Compilation strings

Because cnet must dynamically link compiled versions of protocols at run-time, cnet performs all necessary compilation and linking. You neither compile nor link protocols yourself, nor use make(3) to do it for you. Invoking cnet with a valid topology file will perform all necessary compilation and linking before commencing the simulation. cnet performs the rudimentary actions of make(3), compiling and linking files if the required target does not exist or is out-of-date with respect to sourcefiles.

Strings are used to declare the location (filenames) of the source and shared object codes for the Application and "Central" layers used in each simulation. These strings may be provided on the command line, via the -A, -C, and -J command-line options. The compilation string to compile the "Central" layers may also be specified with the compile node attribute in the topology file.

In their simplest form, compilation strings may present just a single C sourcefile name, such as "protocol.c". If necessary, cnet, will compile the file protocol.c into the object file protocol.o and then link this file to form the final shared object protocol.cnet. This final shared object file will then be used to provide the code for each node's relevant layer(s).

In its more complex form, a compilation string may also include compilation switches, a number of sourcefile names, and linker switches. For example, the compilation string

        "-DCOLLECTSTATS ftp.c tables.c -lm"

includes an embedded (actually C preprocessor) switch which is passed onto the compilation process, two sourcefile names and a linker switch (in this case to link with the mathematics library). Each source file is compiled (if necessary) to create its object file, and all object files are then linked together to form a single shared object. The shared object's name is derived from the first sourcefile found, in this case it will be ftp.cnet.

The embedded switches -l and -L, and any filenames ending in .o or .a, are recognized as (assumed to be) arguments for the linker. All other switches are assumed to be C-preprocessor and C-compiler switches.

Extension modules

By default, cnet goes to great efforts to ensure that each node's execution appears to be occurring in isolation - that each node appears as an independent computer, running its own operating system, and accessing its own memory. Each node's data segments (variables in protocols' code) are swapped in and out of their true locations as each node's events are scheduled for execution. This has the desirable effect that nodes can only communicate through their Physical Layer communications, and cannot communicate by leaving information in their variables. This is fairly novel, and makes protocol writing and execution more realistic.

However, the swapping of each node's data segments tens of thousands of times every second is expensive, and protocols requiring large segments (typically many, or large, global or static variables) execute more slowly. In addition, there are some occasions when nodes sharing some memory can be beneficial - such as the collation of a simulation's global statistics, user-specified WLAN propagation models, or the sharing of topological information such as the locations of buildings on a simulation map.

Extension modules enable simulations to add code and variables to cnet's "core", without requiring that cnet itself be recompiled. The code and data are accessible to all nodes and, in particular, modules' data is not swapped in and out between events.

Extension modules are specified by providing one or more instances of the -x command-line option. Each instance expects a module name (without any filename extension), or a compilation string providing the code of the module. If specified just by name, the CNETPATH and CNETFILEEXT environment variables are used to locate standard modules from a standard location. Otherwise the compilation string is used to compile and link the module.

The following code shows a (poorly written, with no error checking) module enabling nodes to share a single memory segment:

#include <cnet.h>
#include <stdlib.h>

void *my_shmem(size_t length)
    static void *shared  = NULL;

    if(shared == NULL)
        shared = calloc((unsigned)1, (size_t)length);
    return shared;

This source code may now be employed as an extension module with the command:

        cnet  -x my_shmem.c  -N  TOPOLOGY

and each node's protocol code may typically execute:

#include <cnet.h>

extern void *my_shmem(size_t length);

int *world_statistics = NULL;
int  my_statistic     = 0;

    world_statistics = my_shmem(NNODES * sizeof(int));
    world_statistics[nodeinfo.nodenumber] += my_statistic;

The memory allocated by my_shmem will always be accessible by each node, and each node may view all other nodes' statistics by accessing world_statistics. If the role of the my_shmem extension module is considered important enough, it may be made a "permanent" addition by moving the file my_shmem.cnet to a directory searched via CNETPATH.

 cnet v3.3.3, written by
 Last modified: Tue Oct 13 1:07PM 2015