Introduction

This developer handbook is intended as first introduction to GNUnet for new developers that want to extend the GNUnet framework. After the introduction, each of the GNUnet subsystems (directories in the src/ tree) is (supposed to be) covered in its own chapter. In addition to this documentation, GNUnet developers should be aware of the services available on the GNUnet server to them.

New developers can have a look a the GNUnet tutorials for C and java available in the src/ directory of the repository or under the following links:

In addition to this book, the GNUnet server contains various resources for GNUnet developers. They are all conveniently reachable via the "Developer" entry in the navigation menu. Some additional tools (such as static analysis reports) require a special developer access to perform certain operations. If you feel you need access, you should contact Christian Grothoff, GNUnet's maintainer.

The public subsystems on the GNUnet server that help developers are:

  • The Version control system keeps our code and enables distributed development. Only developers with write access can commit code, everyone else is encouraged to submit patches to the developer mailinglist.
  • The GNUnet bugtracking system is used to track feature requests, open bug reports and their resolutions. Anyone can report bugs, only developers can claim to have fixed them.
  • A buildbot is used to check GNUnet builds automatically on a range of platforms. Builds are triggered automatically after 30 minutes of no changes to Git.
  • The current quality of our automated test suite is assessed using Code coverage analysis. This analysis is run daily; however the webpage is only updated if all automated tests pass at that time. Testcases that improve our code coverage are always welcome.
  • We try to automatically find bugs using a static analysis scan. This scan is run daily; however the webpage is only updated if all automated tests pass at the time. Note that not everything that is flagged by the analysis is a bug, sometimes even good code can be marked as possibly problematic. Nevertheless, developers are encouraged to at least be aware of all issues in their code that are listed.
  • We use Gauger for automatic performance regression visualization. Details on how to use Gauger are here.
  • We use junit to automatically test gnunet-java. Automatically generated, current reports on the test suite are here.
  • We use Cobertura to generate test coverage reports for gnunet-java. Current reports on test coverage are here.

Project overview

The GNUnet project consists at this point of several sub-projects. This section is supposed to give an initial overview about the various sub-projects. Note that this description also lists projects that are far from complete, including even those that have literally not a single line of code in them yet.

GNUnet sub-projects in order of likely relevance are currently:

svn/gnunet
Core of the P2P framework, including file-sharing, VPN and chat applications; this is what the developer handbook covers mostly
svn/gnunet-gtk/
Gtk+-based user interfaces, including gnunet-fs-gtk (file-sharing), gnunet-statistics-gtk (statistics over time), gnunet-peerinfo-gtk (information about current connections and known peers), gnunet-chat-gtk (chat GUI) and gnunet-setup (setup tool for "everything")
svn/gnunet-fuse/
Mounting directories shared via GNUnet's file-sharing on Linux
svn/gnunet-update/
Installation and update tool
svn/gnunet-ext/
Template for starting 'external' GNUnet projects
svn/gnunet-java/
Java APIs for writing GNUnet services and applications
svn/gnunet-www/
Code and media helping drive the GNUnet website
svn/eclectic/
Code to run GNUnet nodes on testbeds for research, development, testing and evaluation
svn/gnunet-qt/
qt-based GNUnet GUI (dead?)
svn/gnunet-cocoa/
cocoa-based GNUnet GUI (dead?)

We are also working on various supporting libraries and tools:

svn/Extractor/
GNU libextractor (meta data extraction)
svn/libmicrohttpd/
GNU libmicrohttpd (embedded HTTP(S) server library)
svn/gauger/
Tool for performance regression analysis
svn/monkey/
Tool for automated debugging of distributed systems
svn/libmwmodem/
Library for accessing satellite connection quality reports

Finally, there are various external projects (see links for a list of those that have a public website) which build on top of the GNUnet framework.

Code overview

This section gives a brief overview of the GNUnet source code. Specifically, we sketch the function of each of the subdirectories in the gnunet/src/ directory. The order given is roughly bottom-up (in terms of the layers of the system).

util/ --- libgnunetutil
Library with general utility functions, all GNUnet binaries link against this library. Anything from memory allocation and data structures to cryptography and inter-process communication. The goal is to provide an OS-independent interface and more 'secure' or convenient implementations of commonly used primitives. The API is spread over more than a dozen headers, developers should study those closely to avoid duplicating existing functions.
hello/ --- libgnunethello
HELLO messages are used to describe under which addresses a peer can be reached (for example, protocol, IP, port). This library manages parsing and generating of HELLO messages.
block/ --- libgnunetblock
The DHT and other components of GNUnet store information in units called 'blocks'. Each block has a type and the type defines a particular format and how that binary format is to be linked to a hash code (the key for the DHT and for databases). The block library is a wapper around block plugins which provide the necessary functions for each block type.
statistics/
The statistics service enables associating values (of type uint64_t) with a componenet name and a string. The main uses is debugging (counting events), performance tracking and user entertainment (what did my peer do today?).
arm/
The automatic-restart-manager (ARM) service is the GNUnet master service. Its role is to start gnunet-services, to re-start them when they crashed and finally to shut down the system when requested.
peerinfo/
The peerinfo service keeps track of which peers are known to the local peer and also tracks the validated addresses for each peer (in the form of a HELLO message) for each of those peers. The peer is not necessarily connected to all peers known to the peerinfo service. Peerinfo provides persistent storage for peer identities --- peers are not forgotten just because of a system restart.
datacache/ --- libgnunetdatacache
The datacache library provides (temporary) block storage for the DHT. Existing plugins can store blocks in Sqlite, Postgres or MySQL databases. All data stored in the cache is lost when the peer is stopped or restarted (datacache uses temporary tables).
datastore/
The datastore service stores file-sharing blocks in databases for extended periods of time. In contrast to the datacache, data is not lost when peers restart. However, quota restrictions may still cause old, expired or low-priority data to be eventually discarded. Existing plugins can store blocks in Sqlite, Postgres or MySQL databases.
template/
Template for writing a new service. Does nothing.
ats/
The automatic transport selection (ATS) service is responsible for deciding which address (i.e. which transport plugin) should be used for communication with other peers, and at what bandwidth.
nat/ --- libgnunetnat
Library that provides basic functions for NAT traversal. The library supports NAT traversal with manual hole-punching by the user, UPnP and ICMP-based autonomous NAT traversal. The library also includes an API for testing if the current configuration works and the gnunet-nat-server which provides an external service to test the local configuration.
fragmentation/ --- libgnunetfragmentation
Some transports (UDP and WLAN, mostly) have restrictions on the maximum transfer unit (MTU) for packets. The fragmentation library can be used to break larger packets into chunks of at most 1k and transmit the resulting fragments reliabily (with acknowledgement, retransmission, timeouts, etc.).
transport/
The transport service is responsible for managing the basic P2P communication. It uses plugins to support P2P communication over TCP, UDP, HTTP, HTTPS and other protocols.The transport service validates peer addresses, enforces bandwidth restrictions, limits the total number of connections and enforces connectivity restrictions (i.e. friends-only).
peerinfo-tool/
This directory contains the gnunet-peerinfo binary which can be used to inspect the peers and HELLOs known to the peerinfo service.
core/
The core service is responsible for establishing encrypted, authenticated connections with other peers, encrypting and decrypting messages and forwarding messages to higher-level services that are interested in them.
testing/ --- libgnunettesting
The testing library allows starting (and stopping) peers for writing testcases.
It also supports automatic generation of configurations for peers ensuring that the ports and paths are disjoint. libgnunettesting is also the foundation for the testbed service
testbed/
The testbed service is used for creating small or large scale deployments of GNUnet peers for evaluation of protocols. It facilitates peer depolyments on multiple hosts (for example, in a cluster) and establishing varous network topologies (both underlay and overlay).
nse/
The network size estimation (NSE) service implements a protocol for (securely) estimating the current size of the P2P network.
dht/
The distributed hash table (DHT) service provides a distributed implementation of a hash table to store blocks under hash keys in the P2P network.
hostlist/
The hostlist service allows learning about other peers in the network by downloading HELLO messages from an HTTP server, can be configured to run such an HTTP server and also implements a P2P protocol to advertise and automatically learn about other peers that offer a public hostlist server.
topology/
The topology service is responsible for maintaining the mesh topology. It tries to maintain connections to friends (depending on the configuration) and also tries to ensure that the peer has a decent number of active connections at all times. If necessary, new connections are added. All peers should run the topology service, otherwise they may end up not being connected to any other peer (unless some other service ensures that core establishes the required connections). The topology service also tells the transport service which connections are permitted (for friend-to-friend networking)
fs/
The file-sharing (FS) service implements GNUnet's file-sharing application. Both anonymous file-sharing (using gap) and non-anonymous file-sharing (using dht) are supported.
cadet/
The CADET service provides a general-purpose routing abstraction to create end-to-end encrypted tunnels in mesh networks. We wrote a paper documenting key aspects of the design.
tun/ --- libgnunettun
Library for building IPv4, IPv6 packets and creating checksums for UDP, TCP and ICMP packets. The header defines C structs for common Internet packet formats and in particular structs for interacting with TUN (virtual network) interfaces.
mysql/ --- libgnunetmysql
Library for creating and executing prepared MySQL statements and to manage the connection to the MySQL database. Essentially a lightweight wrapper for the interaction between GNUnet components and libmysqlclient.
dns/
Service that allows intercepting and modifying DNS requests of the local machine. Currently used for IPv4-IPv6 protocol translation (DNS-ALG) as implemented by "pt/" and for the GNUnet naming system. The service can also be configured to offer an exit service for DNS traffic.
vpn/
The virtual public network (VPN) service provides a virtual tunnel interface (VTUN) for IP routing over GNUnet. Needs some other peers to run an "exit" service to work. Can be activated using the "gnunet-vpn" tool or integrated with DNS using the "pt" daemon.
exit/
Daemon to allow traffic from the VPN to exit this peer to the Internet or to specific IP-based services of the local peer. Currently, an exit service can only be restricted to IPv4 or IPv6, not to specific ports and or IP address ranges. If this is not acceptable, additional firewall rules must be added manually. exit currently only works for normal UDP, TCP and ICMP traffic; DNS queries need to leave the system via a DNS service.
pt/
protocol translation daemon. This daemon enables 4-to-6, 6-to-4, 4-over-6 or 6-over-4 transitions for the local system. It essentially uses "DNS" to intercept DNS replies and then maps results to those offered by the VPN, which then sends them using mesh to some daemon offering an appropriate exit service.
identity/
Management of egos (alter egos) of a user; identities are essentially named ECC private keys and used for zones in the GNU name system and for namespaces in file-sharing, but might find other uses later
revocation/
Key revocation service, can be used to revoke the private key of an identity if it has been compromised
namecache/
Cache for resolution results for the GNU name system; data is encrypted and can be shared among users, loss of the data should ideally only result in a performance degradation (persistence not required)
namestore/
Database for the GNU name system with per-user private information, persistence required
gns/
GNU name system, a GNU approach to DNS and PKI.
dv/
A plugin for distance-vector (DV)-based routing. DV consists of a service and a transport plugin to provide peers with the illusion of a direct P2P connection for connections that use multiple (typically up to 3) hops in the actual underlay network.
regex/
Service for the (distributed) evaluation of regular expressions.
scalarproduct/
The scalar product service offers an API to perform a secure multiparty computation which calculates a scalar product between two peers without exposing the private input vectors of the peers to each other.
consensus/
The consensus service will allow a set of peers to agree on a set of values via a distributed set union computation.
rest/
The rest API allows access to GNUnet services using RESTful interaction. The services provide plugins that can exposed by the rest server.
experimentation/
The experimentation daemon coordinates distributed experimentation to evaluate transport and ats properties

System Architecture

GNUnet developers like legos. The blocks are indestructible, can be stacked together to construct complex buildings and it is generally easy to swap one block for a different one that has the same shape. GNUnet's architecture is based on legos:

service lego block

This chapter documents the GNUnet lego system, also known as GNUnet's system architecture.

The most common GNUnet component is a service. Services offer an API (or several, depending on what you count as "an API") which is implemented as a library. The library communicates with the main process of the service using a service-specific network protocol. The main process of the service typically doesn't fully provide everything that is needed -- it has holes to be filled by APIs to other services.

A special kind of component in GNUnet are user interfaces and daemons. Like services, they have holes to be filled by APIs of other services. Unlike services, daemons do not implement their own network protocol and they have no API:

daemon lego block

The GNUnet system provides a range of services, daemons and user interfaces, which are then combined into a layered GNUnet instance (also known as a peer).

service stack

Note that while it is generally possible to swap one service for another compatible service, there is often only one implementation. However, during development we often have a "new" version of a service in parallel with an "old" version. While the "new" version is not working, developers working on other parts of the service can continue their development by simply using the "old" service. Alternative design ideas can also be easily investigated by swapping out individual components. This is typically achieved by simply changing the name of the "BINARY" in the respective configuration section.

Key properties of GNUnet services are that they must be separate processes and that they must protect themselves by applying tight error checking against the network protocol they implement (thereby achieving a certain degree of robustness).

On the other hand, the APIs are implemented to tolerate failures of the service, isolating their host process from errors by the service. If the service process crashes, other services and daemons around it should not also fail, but instead wait for the service process to be restarted by ARM.

AttachmentSize
Image icon daemon_lego_block.png12.9 KB
Image icon service_lego_block.png19.56 KB
Image icon service_stack.png23.32 KB

Subsystem stability

This page documents the current stability of the various GNUnet subsystems. Stability here describes the expected degree of compatibility with future versions of GNUnet. For each subsystem we distinguish between compatibility on the P2P network level (communication protocol between peers), the IPC level (communication between the service and the service library) and the API level (stability of the API). P2P compatibility is relevant in terms of which applications are likely going to be able to communicate with future versions of the network. IPC communication is relevant for the implementation of language bindings that re-implement the IPC messages. Finally, API compatibility is relevant to developers that hope to be able to avoid changes to applications build on top of the APIs of the framework.

The following table summarizes our current view of the stability of the respective protocols or APIs:

Subsystem P2P IPC C API
util n/a n/a stable
arm n/a stable stable
ats n/a unstable testing
block n/a n/a stable
cadet testing testing testing
consensus experimental experimental experimental
core stable stable stable
datacache n/a n/a stable
datastore n/a stable stable
dht stable stable stable
dns stable stable stable
dv testing testing n/a
exit testing n/a n/a
fragmentation stable n/a stable
fs stable stable stable
gns stable stable stable
hello n/a n/a testing
hostlist stable stable n/a
identity stable stable n/a
multicast experimental experimental experimental
mysql stable n/a stable
namestore n/a stable stable
nat n/a n/a stable
nse stable stable stable
peerinfo n/a stable stable
psyc experimental experimental experimental
pt n/a n/a n/a
regex stable stable stable
revocation stable stable stable
social experimental experimental experimental
statistics n/a stable stable
testbed n/a testing testing
testing n/a n/a testing
topology n/a n/a n/a
transport stable stable stable
tun n/a n/a stable
vpn testing n/a n/a

Here is a rough explanation of the values:

stable
no incompatible changes are planned at this time; for IPC/APIs, if there are incompatible changes, they will be minor and might only require minimal changes to existing code; for P2P, changes will be avoided if at all possible for the 0.10.x-series
testing
no incompatible changes are planned at this time, but the code is still known to be in flux; so while we have no concrete plans, our expectation is that there will still be minor modifications; for P2P, changes will likely be extensions that should not break existing code
unstable
changes are planned and will happen; however, they will not be totally radical and the result should still resemble what is there now; nevertheless, anticipated changes will break protocol/API compatibility
experimental
changes are planned and the result may look nothing like what the API/protocol looks like today
unknown
someone should think about where this subsystem is headed
n/a
this subsystem does not have an API/IPC-protocol/P2P-protocol

Naming conventions and coding style guide

Here you can find some rules to help you write code for GNUnet.

Naming conventions

include files

  • _lib: library without need for a process
  • _service: library that needs a service process
  • _plugin: plugin definition
  • _protocol: structs used in network protocol
  • exceptions:
    • gnunet_config.h --- generated
    • platform.h --- first included
    • plibc.h --- external library
    • gnunet_common.h --- fundamental routines
    • gnunet_directories.h --- generated
    • gettext.h --- external library

binaries

  • gnunet-service-xxx: service process (has listen socket)
  • gnunet-daemon-xxx: daemon process (no listen socket)
  • gnunet-helper-xxx[-yyy]: SUID helper for module xxx
  • gnunet-yyy: command-line tool for end-users
  • libgnunet_plugin_xxx_yyy.so: plugin for API xxx
  • libgnunetxxx.so: library for API xxx

logging

  • services and daemons use their directory name in GNUNET_log_setup (i.e. 'core') and log using plain 'GNUNET_log'.
  • command-line tools use their full name in GNUNET_log_setup (i.e. 'gnunet-publish') and log using plain 'GNUNET_log'.
  • service access libraries log using 'GNUNET_log_from' and use 'DIRNAME-api' for the component (i.e. 'core-api')
  • pure libraries (without associated service) use 'GNUNET_log_from' with the component set to their library name (without lib or '.so'), which should also be their directory name (i.e. 'nat')
  • plugins should use 'GNUNET_log_from' with the directory name and the plugin name combined to produce the component name (i.e. 'transport-tcp').
  • logging should be unified per-file by defining a LOG macro with the appropriate arguments, along these lines:
    #define LOG(kind,...) GNUNET_log_from (kind, "example-api",__VA_ARGS__)

configuration

  • paths (that are substituted in all filenames) are in PATHS (have as few as possible)
  • all options for a particular module (src/MODULE) are under [MODULE]
  • options for a plugin of a module are under [MODULE-PLUGINNAME]

exported symbols

  • must start with "GNUNET_modulename_" and be defined in "modulename.c"
  • exceptions: those defined in gnunet_common.h

private (library-internal) symbols (including structs and macros)

  • must NOT start with any prefix
  • must not be exported in a way that linkers could use them or
    other libraries might see them via headers; they must be either
    declared/defined in C source files or in headers that are in
    the respective directory under src/modulename/ and NEVER be
    declared in src/include/.

testcases

  • must be called "test_module-under-test_case-description.c"
  • "case-description" maybe omitted if there is only one test

performance tests

  • must be called "perf_module-under-test_case-description.c"
  • "case-description" maybe omitted if there is only one performance test
  • Must only be run if HAVE_BENCHMARKS is satisfied

src/ directories

  • gnunet-NAME: end-user applications (i.e., gnunet-search, gnunet-arm)
  • gnunet-service-NAME: service processes with accessor library (i.e., gnunet-service-arm)
  • libgnunetNAME: accessor library (_service.h-header) or standalone library (_lib.h-header)
  • gnunet-daemon-NAME: daemon process without accessor library (i.e., gnunet-daemon-hostlist) and no GNUnet management port
  • libgnunet_plugin_DIR_NAME: loadable plugins (i.e., libgnunet_plugin_transport_tcp)

Coding style

  • GNU guidelines generally apply
  • Indentation is done with spaces, two per level, no tabs
  • C99 struct initialization is fine
  • declare only one variable per line, so
      int i;
      int j;
    

    instead of

      int i,j;
    

    This helps keep diffs small and forces developers to think precisely about the type of every variable. Note that char * is different from const char* and int is different from unsigned int or uint32_t. Each variable type should be chosen with care.

  • While goto should generally be avoided, having a goto to the end of a function to a block of clean up statements (free, close, etc.) can be acceptable.
  • Conditions should be written with constants on the left (to avoid accidental assignment) and with the 'true' target being either the 'error' case or the significantly simpler continuation. For example:
     if (0 != stat ("filename," &sbuf)) 
    { 
      error(); 
    } 
    else
    { 
      /* handle normal case here */
    }
    

    instead of

     if (stat ("filename," &sbuf) == 0) 
    { 
      /* handle normal case here */
    } 
    else
    { 
      error(); 
    }
    

    If possible, the error clause should be terminated with a 'return' (or 'goto' to some cleanup routine) and in this case, the 'else' clause should be omitted:

     if (0 != stat ("filename," &sbuf)) 
    { 
      error(); 
      return;
    } 
    /* handle normal case here */
    

    This serves to avoid deep nesting. The 'constants on the left' rule applies to all constants (including. GNUNET_SCHEDULER_NO_TASK), NULL, and enums). With the two above rules (constants on left, errors in 'true' branch), there is only one way to write most branches correctly.

  • Combined assignments and tests are allowed if they do not hinder code clarity. For example, one can write:
     if (NULL == (value = lookup_function()))
    { 
      error(); 
      return;
    } 
    
  • Use break and continue wherever possible to avoid deep(er) nesting. Thus, we would write:
    next = head;
    while (NULL != (pos = next))
    { 
      next = pos->next;
      if (! should_free (pos))
         continue; 
      GNUNET_CONTAINER_DLL_remove (head, tail, pos);
      GNUNET_free (pos);
    } 
    

    instead of

    next = head;
    while (NULL != (pos = next))
    { 
      next = pos->next;
      if (should_free (pos))
      {
        /* unnecessary nesting! */
        GNUNET_CONTAINER_DLL_remove (head, tail, pos);
        GNUNET_free (pos);
      }
    } 
    
  • We primarily use for and while loops. A while loop is used if the method for advancing in the loop is not a straightforward increment operation. In particular, we use:
    next = head;
    while (NULL != (pos = next))
    { 
      next = pos->next;
      if (! should_free (pos))
         continue; 
      GNUNET_CONTAINER_DLL_remove (head, tail, pos);
      GNUNET_free (pos);
    } 
    

    to free entries in a list (as the iteration changes the structure of the list due to the free; the equivalent for loop does no longer follow the simple for paradigm of for(INIT;TEST;INC)). However, for loops that do follow the simple for paradigm we do use for, even if it involves linked lists:

    /* simple iteration over a linked list */
    for (pos = head; NULL != pos; pos = pos->next)
    { 
       use (pos);
    } 
    
  • The first argument to all higher-order functions in GNUnet must be declared to be of type void * and is reserved for a closure. We do not use inner functions, as trampolines would conflict with setups that use non-executable stacks.
    The first statement in a higher-order function, which unusually should be part of the variable declarations, should assign the cls argument to the precise expected type. For example:
    int
    callback (void *cls, char *args)
    { 
       struct Foo *foo = cls;
       int other_variables;
    
       /* rest of function */
    } 
    
  • It is good practice to write complex if expressions instead of using deeply nested if statements. However, except for addition and multiplication, all operators should use parens. This is fine:
    if ( (1 == foo) || 
         ((0 == bar) && (x != y)) )
      return x;
    

    However, this is not:

    if (1 == foo) 
      return x;
    if (0 == bar && x != y)
      return x;
    

    Note that splitting the if statement above is debateable as the return x is a very trivial statement. However, once the logic after the branch becomes more complicated (and is still identical), the "or" formulation should be used for sure.

  • There should be two empty lines between the end of the function and the comments describing the following function. There should be a single empty line after the initial variable declarations of a function. If a function has no local variables, there should be no initial empty line. If a long function consists of several complex steps, those steps might be separated by an empty line (possibly followed by a comment describing the following step). The code should not contain empty lines in arbitrary places; if in doubt, it is likely better to NOT have an empty line (this way, more code will fit on the screen).

Build-system

If you have code that is likely not to compile or build rules you might want to not trigger for most developers, use "if HAVE_EXPERIMENTAL" in your Makefile.am. Then it is OK to (temporarily) add non-compiling (or known-to-not-port) code.

If you want to compile all testcases but NOT run them, run configure with the
--enable-test-suppression option.

If you want to run all testcases, including those that take a while, run configure with the
--enable-expensive-testcases option.

If you want to compile and run benchmarks, run configure with the
--enable-benchmarks option.

If you want to obtain code coverage results, run configure with the
--enable-coverage option and run the coverage.sh script in contrib/.

Developing extensions for GNUnet using the gnunet-ext template

For developers who want to write extensions for GNUnet we provide the gnunet-ext template to provide an easy to use skeleton.

gnunet-ext contains the build environment and template files for the development of GNUnet services, command line tools, APIs and tests.

First of all you have to obtain gnunet-ext from SVN:

svn co https://gnunet.org/svn/gnunet-ext

The next step is to bootstrap and configure it. For configure you have to provide the path containing GNUnet with --with-gnunet=/path/to/gnunet and the prefix where you want the install the extension using --prefix=/path/to/install

./bootstrap
./configure --prefix=/path/to/install --with-gnunet=/path/to/gnunet

When your GNUnet installation is not included in the default linker search path, you have to add /path/to/gnunet to the file /etc/ld.so.conf and run ldconfig or your add it to the environmental variable LD_LIBRARY_PATH by using

export LD_LIBRARY_PATH=/path/to/gnunet/lib