\documentclass[10pt]{article}
\usepackage[ansinew]{inputenc}
\usepackage{makeidx,amsmath,amssymb,exscale,multicol,epsfig,graphics,verbatim,ulem}
-\usepackage{epsfig,geometry,url,listings, subcaption}
+\usepackage{epsfig,geometry,url,listings,subcaption}
\usepackage{boxedminipage}
\usepackage[T1]{fontenc}%required
\usepackage{textcomp}
\geometry{headsep=3ex,hscale=0.9}
\usepackage{hyperref}
+\usepackage{color}
\hypersetup{pdftitle={GNUnet C Tutorial},
pdfsubject={GNUnet},
pdfauthor={Christian Grothoff <christian@grothoff.org>},
\begin{document}
+\lstset{ %
+language=C, % choose the language of the code
+basicstyle=\footnotesize, % the size of the fonts that are used for the code
+numbers=left, % where to put the line-numbers
+numberstyle=\footnotesize, % the size of the fonts that are used for the line-numbers
+stepnumber=1, % the step between two line-numbers. If it is 1 each line will be numbered
+numbersep=5pt, % how far the line-numbers are from the code
+backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color}
+showspaces=false, % show spaces adding particular underscores
+showstringspaces=false, % underline spaces within strings
+showtabs=false, % show tabs within strings adding particular underscores
+frame=single, % adds a frame around the code
+tabsize=2, % sets default tabsize to 2 spaces
+captionpos=b, % sets the caption-position to bottom
+breaklines=true, % sets automatic line breaking
+breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace
+escapeinside={\%*}{*)} % if you want to add a comment within your code
+}
+
+
\begin{center}
\large {A Tutorial for GNUnet 0.10.x (C version)}
\url{ftp://ftp.gnu.org/gnu/gnunet/gnunet-0.10.x.tar.gz.sig}
\end{center}
To verify the signature you should first import the GPG key used to sign the tarball
+\lstset{language=bash}
\begin{lstlisting}
$ gpg --keyserver keys.gnupg.net --recv-keys 48426C7E
\end{lstlisting}
And use this key to verify the tarball's signature
+\lstset{language=bash}
\begin{lstlisting}
$ gpg --verify gnunet-0.10.x.tar.gz.sig gnunet-0.10.x.tar.gz
\end{lstlisting}
After successfully verifying the integrity you can extract the tarball using
+\lstset{language=bash}
\begin{lstlisting}
$ tar xvzf gnunet-0.10.x.tar.gz
$ mv gnunet-0.10.x gnunet # we will use the directory "gnunet" in the remainder of this document
$ cd gnunet
\end{lstlisting}
+However, please note that stable versions can be very outdated, as a developer
+you are strongly encouraged to use the version from \url{https://gnunet.org/git/}.
\subsection{Installing Build Tool Chain and Dependencies}
\subsection{Compiling and Installing GNUnet}
First, you need to install at least {\tt libgnupgerror} version
-1.12\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.12.tar.bz2}}
+1.27\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.27.tar.bz2}}
and {\tt libgcrypt} version
-1.6\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.6.0.tar.bz2}}.
+1.7.6\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.7.6.tar.bz2}}.
\lstset{language=bash}
\begin{lstlisting}
-$ wget ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.12.tar.bz2
-$ tar xf libgpg-error-1.12.tar.bz2
-$ cd libgpg-error-1.12
+$ wget ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.27.tar.bz2
+$ tar xf libgpg-error-1.27.tar.bz2
+$ cd libgpg-error-1.27
$ ./configure
$ sudo make install
$ cd ..
\lstset{language=bash}
\begin{lstlisting}
-$ wget ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.6.0.tar.bz2
-$ tar xf libgcrypt-1.6.0.tar.bz2
-$ cd libgcrypt-1.6.0
+$ wget ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.7.6.tar.bz2
+$ tar xf libgcrypt-1.7.6.tar.bz2
+$ cd libgcrypt-1.7.6
$ ./configure
$ sudo make install
$ cd ..
You should check your installation to ensure that installing GNUnet
was successful up to this point. You should be able to access GNUnet's
binaries and run GNUnet's self check.
+\lstset{language=bash}
\begin{lstlisting}
$ which gnunet-arm
\end{lstlisting}
should return \lstinline|$PREFIX/bin/gnunet-arm|. It should be
located in your GNUnet installation and the output should not be
empty. If you see an output like:
+\lstset{language=bash}
\begin{lstlisting}
$ which gnunet-arm
$
check your {\tt PATH} variable to ensure GNUnet's {\tt bin} directory is included.
GNUnet provides tests for all of its subcomponents. Run
+\lstset{language=bash}
\begin{lstlisting}
$ make check
\end{lstlisting}
to execute tests for all components. {\tt make check} traverses all subdirectories in {\tt src}.
For every subdirectory you should get a message like this:
-\begin{lstlisting}
+\begin{verbatim}
make[2]: Entering directory `/home/$USER/gnunet/contrib'
PASS: test_gnunet_prefix
=============
1 test passed
=============
-\end{lstlisting}
-
-If you see a message like this:
-
-\begin{lstlisting}
-Mar 12 16:57:56-642482 resolver-api-19449 ERROR Must specify `HOSTNAME' for `resolver' in configuration!
-Mar 12 16:57:56-642573 test_program-19449 ERROR Assertion failed at resolver_api.c:204.
-/bin/bash: line 5: 19449 Aborted (core dumped) ${dir}$tst
-FAIL: test_program
-\end{lstlisting}
-double check the steps performed in ~\ref{sub:install}
+\end{verbatim}
\section{Background: GNUnet Architecture}
Since we want to start additional peers later, we need
some modifications from the default configuration. We need to create a separate service home and a file containing our modifications for this peer:
+\lstset{language=bash}
\begin{lstlisting}
$ mkdir ~/gnunet1/
$ touch peer1.conf
simplified usage we want to prevent the peer to connect to the GNUnet
network since this could lead to confusing output. This modifications
will replace the default settings:
-\begin{lstlisting}
+\begin{verbatim}
[PATHS]
GNUNET_HOME = ~/gnunet1/ # Use this directory to store GNUnet data
[hostlist]
SERVERS = # prevent bootstrapping
-\end{lstlisting}
+\end{verbatim}
\subsection{Start a peer}
$ ./gnunet-dht-monitor -c ~/peer1.conf -k KEY
\end{lstlisting}
Now open a separate terminal and change again to the \lstinline|gnunet/src/dht| directory:
+\lstset{language=bash}
\begin{lstlisting}
$ cd ~/gnunet/src/dht
$ ./gnunet-dht-put -c ~/peer1.conf -k KEY -d VALUE # put VALUE under KEY in the DHT
configuration file:
%
\lstset{language=bash}
+\lstset{language=bash}
\begin{lstlisting}
$ cat $PREFIX/share/gnunet/config.d/*.conf > peer2.conf
\end{lstlisting}
To setup peer 1 as bootstrapping server change the configuration of
the first one to be a hostlist server by adding the following lines to
\texttt{peer1.conf} to enable bootstrapping server:
- \begin{lstlisting}
+ \begin{verbatim}
[hostlist]
OPTIONS = -p
-\end{lstlisting}
+\end{verbatim}
Then change {\tt peer2.conf} and replace the ``\texttt{SERVERS}'' line in the ``\texttt{[hostlist]}'' section with
``\texttt{http://localhost:8080/}''. Restart both peers using:
Check that they are connected using {\tt gnunet-core -c peer1.conf}, which should give you the other peer's
peer identity:
+\lstset{language=bash}
\begin{lstlisting}
$ gnunet-core -c peer1.conf
Peer `9TVUCS8P5A7ILLBGO6 [...shortened...] 1KNBJ4NGCHP3JPVULDG'
With the testbed API, a sample test case can be structured as follows:
% <lynX> Is there a way to pick a more readable font for this include?
-\lstinputlisting[language=C]{testbed_test.c}
+\lstset{language=C}
+\lstinputlisting{testbed_test.c}
The source code for the above listing can be found at
\url{https://gnunet.org/git/gnunet.git/tree/doc/testbed_test.c}
or in the {\tt doc/} folder of your repository check-out.
to the parsed configuration (and the configuration file name that was
used, which is typically not needed):
-\lstset{language=c}
+\lstset{language=C}
\begin{lstlisting}
#include <gnunet/platform.h>
#include <gnunet/gnunet_util_lib.h>
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- /* main code here */
+ // main code here
ret = 0;
}
add a string-option and a binary flag (defaulting to {\tt NULL} and
{\tt GNUNET\_NO} respectively):
+\lstset{language=C}
\begin{lstlisting}
static char *string_option;
static int a_flag;
Before a client library can implement the application-specific protocol
with the service, a connection must be created:
-\lstset{language=c}
+\lstset{language=C}
\begin{lstlisting}
struct GNUNET_MQ_MessageHandlers handlers[] = {
// ...
in big endian format. This header defines the size and the type of the
message, the payload follows after this header.
-\lstset{language=c}
+\lstset{language=C}
\begin{lstlisting}
struct GNUNET_MessageHeader
{
-
- /**
- * The length of the struct (in bytes, including the length field itself),
- * in big-endian format.
- */
uint16_t size GNUNET_PACKED;
-
- /**
- * The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
- */
uint16_t type GNUNET_PACKED;
-
};
\end{lstlisting}
Existing message types are defined in {\tt gnunet\_protocols.h}\\
A common way to create a message is with an envelope:
-\lstset{language=c}
+\lstset{language=C}
\begin{lstlisting}
struct GNUNET_MQ_Envelope *env;
struct GNUNET_MessageHeader *msg;
env = GNUNET_MQ_msg_extra (msg, payload_size, GNUNET_MY_MESSAGE_TYPE);
memcpy (&msg[1], &payload, payload_size);
-/* Send message via message queue 'mq': */
+// Send message via message queue 'mq'
GNUNET_mq_send (mq, env);
\end{lstlisting}
\lstset{language=c}
\begin{lstlisting}
-/**
- * Function called with MyMessage messages from service.
- *
- * @param cls closure
- * @param msg message received
- */
static void
handle_fix (void *cls, const struct MyMessage *msg)
{
// process 'msg'
}
-/**
- * Function called with MyVarMessage messages from service.
- *
- * @param cls closure
- * @param msg message received
- * @return #GNUNET_OK if @a msg is well-formed
- */
static int
check_var (void *cls, const struct MyVarMessage *msg)
{
// check 'msg' is well-formed
- return GNUNET_OK; /* suppose yes */
+ return GNUNET_OK;
}
-/**
- * Function called with MyMessage messages from service.
- *
- * @param cls closure
- * @param msg message received
- */
static void
handle_var (void *cls, const struct MyVarMessage *msg)
{
\lstset{language=c}
\begin{lstlisting}
-/**
- * Launch service.
- *
- * @param cls closure
- * @param c configuration to use
- * @param service the initialized service
- */
static void
run (void *cls,
const struct GNUNET_CONFIGURATION_Handle *c,
{
}
-/**
- * Callback called when a client connects to the service.
- *
- * @param cls closure for the service
- * @param c the new client that connected to the service
- * @param mq the message queue used to send messages to the client
- * @return @a c
- */
static void *
client_connect_cb (void *cls,
struct GNUNET_SERVICE_Client *c,
return c;
}
-/**
- * Callback called when a client disconnected from the service
- *
- * @param cls closure for the service
- * @param c the client that disconnected
- * @param internal_cls should be equal to @a c
- */
static void
client_disconnect_cb (void *cls,
struct GNUNET_SERVICE_Client *c,
GNUNET_CORE_StartupCallback init,
GNUNET_CORE_ConnectEventHandler connects,
GNUNET_CORE_DisconnectEventHandler disconnects,
- GNUNET_CORE_MessageCallback inbound_notify,
- int inbound_hdr_only,
- GNUNET_CORE_MessageCallback outbound_notify,
- int outbound_hdr_only,
- const struct GNUNET_CORE_MessageHandler *handlers);
+ const struct GNUNET_MQ_MessageHandler *handlers);
\end{lstlisting}
\subsection{New P2P connections}
\lstset{language=C}
\begin{lstlisting}
-void
+void *
connects (void *cls,
- const struct GNUNET_PeerIdentity * peer)
+ const struct GNUNET_PeerIdentity *peer,
+ struct GNUNET_MQ_Handle *mq)
{
- /* Save identity for later use */
- /* Optional: start sending messages to peer */
+ return mq;
}
\end{lstlisting}
+Note that whatever you return from {\tt connects} is given as the
+{\it cls} argument to the message handlers for messages from
+the respective peer.
+
\exercise{Create a service that connects to the \texttt{CORE}. Then
start (and connect) two peers and print a message once your connect
callback is invoked.}
\subsection{Receiving P2P Messages}
-To receive messages from \texttt{CORE}, services register a set of handlers
-(parameter {\tt *handlers} in the \lstinline|GNUNET_CORE_connect| call that are called by \texttt{CORE}
-when a suitable message arrives.
+To receive messages from \texttt{CORE}, you pass the desired
+{\em handlers} to the {\tt GNUNET\_CORE\_connect()} function,
+just as we showed for services.
-\lstset{language=c}
-\begin{lstlisting}
-static int
-callback_function_for_type_one(void *cls,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- /* Do stuff */
- return GNUNET_OK; /* or GNUNET_SYSERR to close the connection */
-}
-
-/**
- * Functions to handle messages from core
- */
-static struct GNUNET_CORE_MessageHandler core_handlers[] = {
- {&callback_function_for_type_one, GNUNET_MESSAGE_TYPE_MYSERVICE_TYPE_ONE, 0},
- /* more handlers*/
- {NULL, 0, 0}
-};
-\end{lstlisting}
+It is your responsibility to process messages fast enough or
+to implement flow control. If an application does not process
+CORE messages fast enough, CORE will randomly drop messages
+to not keep a very long queue in memory.
\exercise{Start one peer with a new service that has a message
handler and start a second peer that only has your ``old'' service
\subsection{Sending P2P Messages}
-In response to events (connect, disconnect, inbound messages,
-timing, etc.) services can then use this API to transmit messages:
+You can transmit messages to other peers using the {\it mq} you were
+given during the {\tt connect} callback. Note that the {\it mq}
+automatically is released upon {\tt disconnect} and that you must
+not use it afterwards.
-\lstset{language=C}
-\begin{lstlisting}
-typedef size_t
-(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
- size_t size,
- void *buf)
-{
- /* Fill "*buf" with up to "size" bytes, must start with GNUNET_MessageHeader */
- return n; /* Total size of the message put in "*buf" */
-}
-
-struct GNUNET_CORE_TransmitHandle *
-GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle,
- int cork, uint32_t priority,
- struct GNUNET_TIME_Relative maxdelay,
- const struct GNUNET_PeerIdentity *target,
- size_t notify_size,
- GNUNET_CONNECTION_TransmitReadyNotify notify,
- void *notify_cls);
-\end{lstlisting}
+It is your responsibility to not over-fill the message queue, GNUnet
+will send the messages roughly in the order given as soon as possible.
\exercise{Write a service that upon connect sends messages as
fast as possible to the other peer (the other peer should run a
\lstset{language=C}
\begin{lstlisting}
-void
+static void
message_sent_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- /* Request has left local node */
+ // Request has left local node
}
struct GNUNET_DHT_PutHandle *
GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
const struct GNUNET_HashCode *key,
uint32_t desired_replication_level,
- enum GNUNET_DHT_RouteOption options, /* Route options, see next call */
+ enum GNUNET_DHT_RouteOption options,
enum GNUNET_BLOCK_Type type, size_t size, const void *data,
- struct GNUNET_TIME_Absolute exp, /* When does the data expire? */
- struct GNUNET_TIME_Relative timeout, /* How long to try to send the request */
- GNUNET_DHT_PutContinuation cont,
- void *cont_cls)
+ struct GNUNET_TIME_Absolute exp,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_DHT_PutContinuation cont, void *cont_cls)
\end{lstlisting}
\exercise{Store a value in the DHT periodically to make sure it is available
unsigned int put_path_length,
enum GNUNET_BLOCK_Type type, size_t size, const void *data)
{
- /* Do stuff with the data and/or route */
- /* Optionally: */
- GNUNET_DHT_get_stop (get_handle);
+ // Optionally:
+ GNUNET_DHT_get_stop (get_handle);
}
get_handle =
block_type,
&key,
replication,
- GNUNET_DHT_RO_NONE, /* Route options */
- NULL, /* xquery: not used here */
- 0, /* xquery size */
+ GNUNET_DHT_RO_NONE,
+ NULL,
+ 0,
&get_result_iterator,
cls)
\end{lstlisting}
block_plugin_SERVICE_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
struct GNUNET_BlockGroup *bg,
- const GNUNET_HashCode *query,
- const void *xquery,
- size_t xquery_size,
- const void *reply_block,
- size_t reply_block_size)
+ const GNUNET_HashCode *query,
+ const void *xquery,
+ size_t xquery_size,
+ const void *reply_block,
+ size_t reply_block_size)
{
- /* Verify type, block and bg */
+ // Verify type, block and bg
}
\end{lstlisting}
\begin{lstlisting}
static int
block_plugin_SERVICE_get_key (void *cls, enum GNUNET_BLOCK_Type type,
- const void *block, size_t block_size,
- struct GNUNET_HashCode *key)
+ const void *block, size_t block_size,
+ struct GNUNET_HashCode *key)
{
- /* Store the key in the key argument, return GNUNET_OK on success. */
+ // Store the key in the key argument, return GNUNET_OK on success.
}
\end{lstlisting}
{
static enum GNUNET_BLOCK_Type types[] =
{
- GNUNET_BLOCK_TYPE_SERVICE_BLOCKYPE, /* list of blocks we care about, from gnunet_block_lib.h */
- GNUNET_BLOCK_TYPE_ANY /* end of list */
+ GNUNET_BLOCK_TYPE_SERVICE_BLOCKYPE,
+ GNUNET_BLOCK_TYPE_ANY
};
struct GNUNET_BLOCK_PluginFunctions *api;
is called with all the information about the event.
\lstset{language=C}
\begin{lstlisting}
-void
+static void
get_callback (void *cls,
enum GNUNET_DHT_RouteOption options,
enum GNUNET_BLOCK_Type type,
{
}
-void
+
+static void
get_resp_callback (void *cls,
enum GNUNET_BLOCK_Type type,
const struct GNUNET_PeerIdentity *get_path,
{
}
-void
+
+static void
put_callback (void *cls,
enum GNUNET_DHT_RouteOption options,
enum GNUNET_BLOCK_Type type,
{
}
+
monitor_handle = GNUNET_DHT_monitor_start (dht_handle,
- block_type, /* GNUNET_BLOCK_TYPE_ANY for all */
- key, /* NULL for all */
- &get_callback,
- &get_resp_callback,
- &put_callback,
- cls);
+ block_type,
+ key,
+ &get_callback,
+ &get_resp_callback,
+ &put_callback,
+ cls);
\end{lstlisting}
#include <gnunet/gnunet_testbed_service.h>
#include <gnunet/gnunet_dht_service.h>
-/* Number of peers we want to start */
#define NUM_PEERS 20
static struct GNUNET_TESTBED_Operation *dht_op;
static struct GNUNET_DHT_Handle *dht_handle;
-static struct GNUNET_SCHEDULER_Task * shutdown_tid;
-
-/**
- * Closure to 'dht_ca' and 'dht_da' DHT adapters.
- */
struct MyContext
{
- /**
- * Argument we pass to GNUNET_DHT_connect.
- */
int ht_len;
} ctxt;
-/**
- * Global result for testcase.
- */
static int result;
-/**
- * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
- * Cleans up.
- */
static void
shutdown_task (void *cls)
{
- shutdown_tid = NULL;
if (NULL != dht_op)
{
- GNUNET_TESTBED_operation_done (dht_op); /* indirectly calls the dht_da() for closing
- down the connection to the DHT */
+ GNUNET_TESTBED_operation_done (dht_op);
dht_op = NULL;
dht_handle = NULL;
}
result = GNUNET_OK;
- GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
}
-/**
- * This is where the test logic should be, at least that
- * part of it that uses the DHT of peer "0".
- *
- * @param cls closure, for the example: NULL
- * @param op should be equal to "dht_op"
- * @param ca_result result of the connect operation, the
- * connection to the DHT service
- * @param emsg error message, if testbed somehow failed to
- * connect to the DHT.
- */
static void
service_connect_comp (void *cls,
struct GNUNET_TESTBED_Operation *op,
{
GNUNET_assert (op == dht_op);
dht_handle = ca_result;
- /* Service to DHT successful; here we'd usually do something
- with the DHT (ok, if successful) */
-
- /* for now, just indiscriminately terminate after 10s */
- GNUNET_SCHEDULER_cancel (shutdown_tid);
- shutdown_tid = GNUNET_SCHEDULER_add_delayed
- (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
- &shutdown_task, NULL);
+ // Do work here...
+ GNUNET_SCHEDULER_shutdown ();
}
-/**
- * Testbed has provided us with the configuration to access one
- * of the peers and it is time to do "some" connect operation to
- * "some" subsystem of the peer. For this example, we connect
- * to the DHT subsystem. Testbed doesn't know which subsystem,
- * so we need these adapters to do the actual connecting (and
- * possibly pass additional options to the subsystem connect
- * function, such as the "ht_len" argument for the DHT).
- *
- * @param cls closure
- * @param cfg peer configuration (here: peer[0]
- * @return NULL on error, otherwise some handle to access the
- * subsystem
- */
static void *
dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct MyContext *ctxt = cls;
- /* Use the provided configuration to connect to service */
dht_handle = GNUNET_DHT_connect (cfg, ctxt->ht_len);
return dht_handle;
}
-/**
- * Dual of 'dht_ca' to perform the 'disconnect'/cleanup operation
- * once we no longer need to access this subsystem.
- *
- * @param cls closure
- * @param op_result whatever we returned from 'dht_ca'
- */
static void
dht_da (void *cls, void *op_result)
{
struct MyContext *ctxt = cls;
- /* Disconnect from DHT service */
GNUNET_DHT_disconnect ((struct GNUNET_DHT_Handle *) op_result);
dht_handle = NULL;
}
-/**
- * Main function inovked from TESTBED once all of the
- * peers are up and running. This one then connects
- * just to the DHT service of peer 0.
- *
- * @param cls closure
- * @param h the run handle
- * @param peers started peers for the test
- * @param num_peers size of the 'peers' array
- * @param links_succeeded number of links between peers that were created
- * @param links_failed number of links testbed was unable to establish
- */
static void
test_master (void *cls,
struct GNUNET_TESTBED_RunHandle *h,
unsigned int links_succeeded,
unsigned int links_failed)
{
- /* Testbed is ready with peers running and connected in a pre-defined overlay
- topology */
-
- /* do something */
ctxt.ht_len = 10;
-
- /* connect to a peers service */
dht_op = GNUNET_TESTBED_service_connect
- (NULL, /* Closure for operation */
- peers[0], /* The peer whose service to connect to */
- "dht", /* The name of the service */
- service_connect_comp, /* callback to call after a handle to service
- is opened */
- NULL, /* closure for the above callback */
- dht_ca, /* callback to call with peer's configuration;
- this should open the needed service connection */
- dht_da, /* callback to be called when closing the
- opened service connection */
- &ctxt); /* closure for the above two callbacks */
- shutdown_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &shutdown_task, NULL);
+ (NULL, peers[0], "dht",
+ &service_connect_comp, NULL,
+ &dht_ca, &dht_da, &ctxt);
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
}
result = GNUNET_SYSERR;
ret = GNUNET_TESTBED_test_run
- ("awesome-test", /* test case name */
- "template.conf", /* template configuration */
- NUM_PEERS, /* number of peers to start */
- 0LL, /* Event mask - set to 0 for no event notifications */
- NULL, /* Controller event callback */
- NULL, /* Closure for controller event callback */
- &test_master, /* continuation callback to be called when testbed setup is
- complete */
- NULL); /* Closure for the test_master callback */
+ ("awesome-test", "template.conf",
+ NUM_PEERS, 0LL,
+ NULL, NULL, &test_master, NULL);
if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
return 1;
return 0;