aboutsummaryrefslogtreecommitdiff
path: root/doc/gnunet-c-tutorial.texi
diff options
context:
space:
mode:
authorng0 <ng0@infotropique.org>2017-08-24 13:20:39 +0000
committerng0 <ng0@infotropique.org>2017-08-24 13:20:39 +0000
commit834f1ec8209254fb66dc2908d39852761f015c8f (patch)
treee2cab1f02106812a3c46d19fb9cd775b49d0ded1 /doc/gnunet-c-tutorial.texi
parent4c4d52c50cca5ff22ec12839ba6c629f705fef00 (diff)
downloadgnunet-834f1ec8209254fb66dc2908d39852761f015c8f.tar.gz
gnunet-834f1ec8209254fb66dc2908d39852761f015c8f.zip
doc: Start of half-manual conversion from LaTeX to Texinfo for gnunet-c-tutorial.
Diffstat (limited to 'doc/gnunet-c-tutorial.texi')
-rw-r--r--doc/gnunet-c-tutorial.texi1489
1 files changed, 1489 insertions, 0 deletions
diff --git a/doc/gnunet-c-tutorial.texi b/doc/gnunet-c-tutorial.texi
new file mode 100644
index 000000000..0c01cceab
--- /dev/null
+++ b/doc/gnunet-c-tutorial.texi
@@ -0,0 +1,1489 @@
1\input texinfo
2@c %**start of header
3@setfilename gnunet-c-tutorial.info
4@documentencoding UTF-8
5@settitle GNUnet C Tutorial
6@c %**end of header
7
8@copying
9Copyright @copyright{} 2001-2017 GNUnet e.V.
10
11Permission is granted to copy, distribute and/or modify this document
12under the terms of the GNU Free Documentation License, Version 1.3 or
13any later version published by the Free Software Foundation; with no
14Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
15copy of the license is included in the section entitled ``GNU Free
16Documentation License''.
17
18A copy of the license is also available from the Free Software
19Foundation Web site at @url{http://www.gnu.org/licenses/fdl.html}.
20
21Alternately, this document is also available under the General
22Public License, version 3 or later, as published by the Free Software
23Foundation. A copy of the license is included in the section entitled
24``GNU General Public License''.
25
26A copy of the license is also available from the Free Software
27Foundation Web site at @url{http://www.gnu.org/licenses/gpl.html}.
28@end copying
29
30@titlepage
31@title GNUnet C Tutorial
32@subtitle A Tutorial for GNUnet 0.10.x (C version)
33@author The GNUnet Developers
34
35@page
36@vskip 0pt plus 1filll
37
38@insertcopying
39@end titlepage
40
41@contents
42
43@c **** TODO
44@c 1. Update content?
45@c 2. Either reference main documentation or
46@c 3. Merge this into main documentation
47
48@node Top
49@top Introduction
50
51This tutorials explains how to install GNUnet on a GNU/Linux system and gives an introduction on how
52GNUnet can be used to develop a Peer-to-Peer application. Detailed installation instructions for
53various operating systems and a detailed list of all dependencies can be found on our website at
54@uref{https://gnunet.org/installation}.
55
56Please read this tutorial carefully since every single step is
57important and do not hesitate to contact the GNUnet team if you have
58any questions or problems! Check here how to contact the GNUnet
59team: @uref{https://gnunet.org/contact_information}
60
61
62@section Installing GNUnet
63
64First of all you have to install a current version of GNUnet. You can download a
65tarball of a stable version from GNU FTP mirrors or obtain the latest development
66version from our Git repository.
67
68Most of the time you should prefer to download the stable version since with the
69latest development version things can be broken, functionality can be changed or tests
70can fail. You should only use the development version if you know that you require a
71certain feature or a certain issue has been fixed since the last release.
72
73@subsection Obtaining a stable version
74
75You can download the latest stable version of GNUnet from GNU FTP mirrors:
76@uref{ftp://ftp.gnu.org/gnu/gnunet/gnunet-0.10.x.tar.gz}
77You should also download the signature file and verify the integrity of the tarball.
78@uref{ftp://ftp.gnu.org/gnu/gnunet/gnunet-0.10.x.tar.gz.sig}
79To verify the signature you should first import the GPG key used to sign the tarball
80@example
81$ gpg --keyserver keys.gnupg.net --recv-keys 48426C7E
82@end example
83And use this key to verify the tarball's signature
84@example
85$ gpg --verify gnunet-0.10.x.tar.gz.sig gnunet-0.10.x.tar.gz
86@end example
87After successfully verifying the integrity you can extract the tarball using
88@example
89$ tar xvzf gnunet-0.10.x.tar.gz
90## we will use the directory "gnunet" in the remainder of this document
91$ mv gnunet-0.10.x gnunet
92$ cd gnunet
93@end example
94
95However, please note that stable versions can be very outdated, as a developer
96you are strongly encouraged to use the version from @uref{https://gnunet.org/git/}.
97
98@subsection Installing Build Tool Chain and Dependencies
99
100To successfully compile GNUnet you need the tools to build GNUnet and the required dependencies.
101Please have a look at @uref{https://gnunet.org/dependencies} for a list of required dependencies
102and @uref{https://gnunet.org/generic_installation} for specific instructions for your operating system.
103
104Please check the notes at the end of the configure process about required dependencies.
105
106For GNUnet bootstrapping support and the http(s) plugin you should install libgnurl.
107For the filesharing service you should install at least one of the datastore backends mysql,
108sqlite or postgresql.
109
110@subsection Obtaining the latest version from Git
111
112The latest development version can obtained from our Git repository. To obtain
113the code you need Git installed and checkout the repository using:
114@example
115$ git clone https://gnunet.org/git/gnunet
116@end example
117After cloning the repository you have to execute
118@example
119$ cd gnunet
120$ ./bootstrap
121@end example
122
123The remainder of this tutorial assumes that you have Git Master checked out.
124
125@subsection Compiling and Installing GNUnet
126
127First, you need to install at least libgnupgerror version 1.27
128@uref{ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.27.tar.bz2}
129and libgcrypt version 1.7.6 @uref{ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.7.6.tar.bz2}.
130
131@example
132$ wget ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.27.tar.bz2
133$ tar xf libgpg-error-1.27.tar.bz2
134$ cd libgpg-error-1.27
135$ ./configure
136$ sudo make install
137$ cd ..
138@end example
139
140@example
141$ wget ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.7.6.tar.bz2
142$ tar xf libgcrypt-1.7.6.tar.bz2
143$ cd libgcrypt-1.7.6
144$ ./configure
145$ sudo make install
146$ cd ..
147@end example
148
149@c sub:install
150Assuming all dependencies are installed, the following commands will
151compile and install GNUnet in your home directory. You can specify the
152directory where GNUnet will be installed by changing the
153--prefix value when calling ./configure. If
154you do not specifiy a prefix, GNUnet is installed in the directory
155/usr/local. When developing new applications you may want
156to enable verbose logging by adding --enable-logging=verbose:
157
158@example
159$ ./configure --prefix=$PREFIX --enable-logging
160$ make
161$ make install
162@end example
163
164After installing GNUnet you have to add your GNUnet installation to your path
165environmental variable. In addition you have to create the .config
166directory in your home directory where GNUnet stores its data and an empty
167GNUnet configuration file:
168
169@example
170$ export PATH=$PATH:$PREFIX/bin
171$ echo export PATH=$PREFIX/bin:\\$PATH >> ~/.bashrc
172$ mkdir ~/.config/
173$ touch ~/.config/gnunet.conf
174@example
175
176@subsection Common Issues - Check your GNUnet installation
177
178You should check your installation to ensure that installing GNUnet
179was successful up to this point. You should be able to access GNUnet's
180binaries and run GNUnet's self check.
181@example
182$ which gnunet-arm
183@end example
184should return $PREFIX/bin/gnunet-arm. It should be
185located in your GNUnet installation and the output should not be
186empty. If you see an output like:
187@example
188$ which gnunet-arm
189@end example
190check your PATH variable to ensure GNUnet's bin directory is included.
191
192GNUnet provides tests for all of its subcomponents. Run
193@example
194$ make check
195@end example
196to execute tests for all components. make check traverses all subdirectories in src.
197For every subdirectory you should get a message like this:
198
199@example
200make[2]: Entering directory `/home/$USER/gnunet/contrib'
201PASS: test_gnunet_prefix
202=============
2031 test passed
204=============
205@example
206
207
208@section Background: GNUnet Architecture
209
210GNUnet is organized in layers and services. Each service is composed of a
211main service implementation and a client library for other programs to use
212the service's functionality, described by an API. This approach is shown in
213figure~\ref{fig:service}. Some services provide an additional command line
214tool to enable the user to interact with the service.
215
216Very often it is other GNUnet services that will use these APIs to build the
217higher layers of GNUnet on top of the lower ones. Each layer expands or extends
218the functionality of the service below (for instance, to build a mesh on top of
219a DHT). See figure ~\ref{fig:interaction} for an illustration of this approach.
220
221\begin{figure}[!h]
222 \begin{center}
223% \begin{subfigure}
224 \begin{subfigure}[b]{0.3\textwidth}
225 \centering
226 \includegraphics[width=\textwidth]{figs/Service.pdf}
227 \caption{Service with API and network protocol}
228 \label{fig:service}
229 \end{subfigure}
230 ~~~~~~~~~~
231 \begin{subfigure}[b]{0.3\textwidth}
232 \centering
233 \includegraphics[width=\textwidth]{figs/System.pdf}
234 \caption{Service interaction}
235 \label{fig:interaction}
236 \end{subfigure}
237 \end{center}
238 \caption{GNUnet's layered system architecture}
239\end{figure}
240
241The main service implementation runs as a standalone process in the operating
242system and the client code runs as part of the client program, so crashes of a
243client do not affect the service process or other clients. The service and the
244clients communicate via a message protocol to be defined and implemented by
245the programmer.
246
247
248@section First Steps with GNUnet
249
250@subsection Configure your peer
251
252First of all we need to configure your peer. Each peer is started with a configuration containing settings for GNUnet itself and its services. This configuration is based on the default configuration shipped with GNUnet and can be modified. The default configuration is located in the $PREFIX/share/gnunet/config.d directory. When starting a peer, you can specify a customized configuration using the the $-c$ command line switch when starting the ARM service and all other services. When using a modified configuration the default values are loaded and only values specified in the configuration file will replace the default values.
253
254Since we want to start additional peers later, we need
255some modifications from the default configuration. We need to create a separate service home and a file containing our modifications for this peer:
256@example
257$ mkdir ~/gnunet1/
258$ touch peer1.conf
259@end example
260
261Now add the following lines to peer1.conf to use this directory. For
262simplified usage we want to prevent the peer to connect to the GNUnet
263network since this could lead to confusing output. This modifications
264will replace the default settings:
265@example
266[PATHS]
267GNUNET_HOME = ~/gnunet1/ # Use this directory to store GNUnet data
268[hostlist]
269SERVERS = # prevent bootstrapping
270@end example
271
272@subsection Start a peer
273Each GNUnet instance (called peer) has an identity (peer ID) based on a
274cryptographic public private key pair. The peer ID is the printable hash of the
275public key.
276
277GNUnet services are controlled by a master service the so called Automatic Restart Manager (ARM).
278ARM starts, stops and even restarts services automatically or on demand when a client connects.
279You interact with the ARM service using the gnunet-arm tool.
280GNUnet can then be started with gnunet-arm -s and stopped with
281gnunet-arm -e. An additional service not automatically started
282can be started using gnunet-arm -i <service name> and stopped
283using gnunet-arm -k <servicename>.
284
285Once you have started your peer, you can use many other GNUnet commands
286to interact with it. For example, you can run:
287@example
288$ gnunet-peerinfo -s
289@end example
290to obtain the public key of your peer.
291You should see an output containing the peer ID similar to:
292@example
293I am peer `0PA02UVRKQTS2C .. JL5Q78F6H0B1ACPV1CJI59MEQUMQCC5G'.
294@end example
295
296
297@subsection Monitor a peer
298
299In this section, we will monitor the behaviour of our peer's DHT service with respect to a
300specific key. First we will start GNUnet and then start the DHT service and use the DHT monitor tool
301to monitor the PUT and GET commands we issue ussing the gnunet-dht-put and
302gnunet-dht-get commands. Using the ``monitor'' line given below, you can observe the behavior of
303your own peer's DHT with respect to the specified KEY:
304
305@example
306$ gnunet-arm -c ~/peer1.conf -s # start gnunet with all default services
307$ gnunet-arm -c ~/peer1.conf -i dht # start DHT service
308$ cd ~/gnunet/src/dht;
309$ ./gnunet-dht-monitor -c ~/peer1.conf -k KEY
310@end example
311Now open a separate terminal and change again to the gnunet/src/dht directory:
312@example
313$ cd ~/gnunet/src/dht
314$ ./gnunet-dht-put -c ~/peer1.conf -k KEY -d VALUE # put VALUE under KEY in the DHT
315$ ./gnunet/src/dht/gnunet-dht-get -c ~/peer1.conf -k KEY # get key KEY from the DHT
316$ gnunet-statistics -c ~/peer1.conf # print statistics about current GNUnet state
317$ gnunet-statistics -c ~/peer1.conf -s dht # print statistics about DHT service
318@end example
319
320
321@subsection Starting Two Peers by Hand}
322
323This section describes how to start two peers on the same machine by hand.
324The process is rather painful, but the description is somewhat instructive.
325In practice, you might prefer the automated method described in
326Section sec:testbed.
327
328@subsubsection Setup a second peer
329We will now start a second peer on your machine.
330For the second peer, you will need to manually create a modified
331configuration file to avoid conflicts with ports and directories.
332A peers configuration file is by default located in ~/.gnunet/gnunet.conf.
333This file is typically very short or even empty as only the differences to the
334defaults need to be specified. The defaults are located in
335many files in the $PREFIX/share/gnunet/config.d directory.
336
337To configure the second peer, use the files
338$PREFIX/share/gnunet/config.d as a template for your main
339configuration file:
340@example
341$ cat $PREFIX/share/gnunet/config.d/*.conf > peer2.conf
342@end example
343Now you have to edit peer2.conf and change:
344\begin{itemize}
345 \itemsep0em
346 \item{\texttt{GNUNET\_TEST\_HOME} under \texttt{PATHS}}
347 \item{Every (uncommented) value for ``\texttt{PORT}'' (add 10000) in any
348 section (the option may be commented out if \texttt{PORT} is
349 prefixed by "\#", in this case, UNIX domain sockets are used
350 and the PORT option does not need to be touched) }
351 \item{Every value for ``\texttt{UNIXPATH}'' in any section (e.g. by adding a "-p2" suffix)}
352\end{itemize}
353to a fresh, unique value. Make sure that the PORT numbers stay
354below 65536. From now on, whenever you interact with the second
355peer, you need to specify -c peer2.conf as an additional
356command line argument.
357
358Now, generate the 2nd peer's private key:
359
360@example
361$ gnunet-peerinfo -s -c peer2.conf
362@end example
363
364This may take a while, generate entropy using your keyboard or mouse
365as needed. Also, make sure the output is different from the
366gnunet-peerinfo output for the first peer (otherwise you made an
367error in the configuration).
368
369@subsubsection Start the second peer and connect the peers
370
371Then, you can start a second peer using:
372\lstset{language=bash}
373\begin{lstlisting}
374$ gnunet-arm -c peer2.conf -s
375$ gnunet-arm -c peer2.conf -i dht
376$ ~/gnunet/src/dht/gnunet-dht-put -c peer2.conf -k KEY -d VALUE
377$ ~/gnunet/src/dht/gnunet-dht-get -c peer2.conf -k KEY
378\end{lstlisting}
379If you want the two peers to connect, you have multiple options:
380\begin{itemize}
381\itemsep0em
382 \item UDP neighbour discovery (automatic)
383 \item Setup a bootstrap server
384 \item Connect manually
385\end{itemize}
386To setup peer 1 as bootstrapping server change the configuration of
387the first one to be a hostlist server by adding the following lines to
388\texttt{peer1.conf} to enable bootstrapping server:
389 \begin{verbatim}
390[hostlist]
391OPTIONS = -p
392\end{verbatim}
393
394Then change {\tt peer2.conf} and replace the ``\texttt{SERVERS}'' line in the ``\texttt{[hostlist]}'' section with
395``\texttt{http://localhost:8080/}''. Restart both peers using:
396@example
397$ gnunet-arm -c peer1.conf -e # stop first peer
398$ gnunet-arm -c peer1.conf -s # start first peer
399$ gnunet-arm -c peer2.conf -s # start second peer
400@end example
401
402Note that if you start your peers without changing these settings, they
403will use the ``global'' hostlist servers of the GNUnet P2P network and
404likely connect to those peers. At that point, debugging might become
405tricky as you're going to be connected to many more peers and would
406likely observe traffic and behaviors that are not explicitly controlled
407by you.
408
409@subsubsection How to connect manually
410
411If you want to use the \texttt{peerinfo} tool to connect your peers, you should:
412\begin{itemize}
413\itemsep0em
414 \item{Set {\tt FORCESTART = NO} in section {\tt hostlist} (to not connect to the global GNUnet)}
415 \item{Start both peers running {\tt gnunet-arm -c peer1.conf -s} and {\tt gnunet-arm -c peer2.conf -s}}
416 \item{Get \texttt{HELLO} message of the first peer running {\tt gnunet-peerinfo -c peer1.conf -g}}
417 \item{Give the output to the second peer by running {\tt gnunet-peerinfo -c peer2.conf -p '<output>'}}
418\end{itemize}
419
420Check that they are connected using {\tt gnunet-core -c peer1.conf}, which should give you the other peer's
421peer identity:
422@example
423$ gnunet-core -c peer1.conf
424Peer `9TVUCS8P5A7ILLBGO6 [...shortened...] 1KNBJ4NGCHP3JPVULDG'
425@end example
426
427@subsection Starting Peers Using the Testbed Service
428@c \label{sec:testbed}
429
430GNUnet's testbed service is used for testing scenarios where a number of peers
431are to be started. The testbed can manage peers on a single host or on multiple
432hosts in a distributed fashion. On a single affordable computer, it should be
433possible to run around tens of peers without drastically increasing the load on the
434system.
435
436The testbed service can be access through its API
437\texttt{include/gnunet\_testbed\_service.h}. The API provides many routines for
438managing a group of peers. It also provides a helper function
439\texttt{GNUNET\_TESTBED\_test\_run()} to quickly setup a minimalistic testing
440environment on a single host.
441
442This function takes a configuration file which will be used as a template
443configuration for the peers. The testbed takes care of modifying relevant
444options in the peers' configuration such as SERVICEHOME, PORT, UNIXPATH to
445unique values so that peers run without running into conflicts. It also checks
446and assigns the ports in configurations only if they are free.
447
448Additionally, the testbed service also reads its options from the same
449configuration file. Various available options and details about them can be
450found in the testbed default configuration file \texttt{src/testbed/testbed.conf}.
451
452With the testbed API, a sample test case can be structured as follows:
453% <lynX> Is there a way to pick a more readable font for this include?
454\lstset{language=C}
455\lstinputlisting{testbed_test.c}
456The source code for the above listing can be found at
457@uref{https://gnunet.org/git/gnunet.git/tree/doc/testbed_test.c}
458or in the {\tt doc/} folder of your repository check-out.
459After installing GNUnet, the above source code can be compiled as:
460\lstset{language=bash}
461\begin{lstlisting}
462$ export CPPFLAGS="-I/path/to/gnunet/headers"
463$ export LDFLAGS="-L/path/to/gnunet/libraries"
464$ gcc $CPPFLAGS $LDFLAGS -o testbed-test testbed_test.c -lgnunettestbed -lgnunetdht -lgnunetutil
465$ touch template.conf # Generate (empty) configuration
466$ ./testbed-test # run it (press CTRL-C to stop)
467\end{lstlisting}
468The \texttt{CPPFLAGS} and \texttt{LDFLAGS} are necessary if GNUnet is installed
469into a different directory other than \texttt{/usr/local}.
470
471All of testbed API's peer management functions treat management actions as
472operations and return operation handles. It is expected that the operations
473begin immediately, but they may get delayed (to balance out load on the system).
474The program using the API then has to take care of marking the operation as
475``done'' so that its associated resources can be freed immediately and other
476waiting operations can be executed. Operations will be canceled if they are
477marked as ``done'' before their completion.
478
479An operation is treated as completed when it succeeds or fails. Completion of
480an operation is either conveyed as events through \textit{controller event
481 callback} or through respective operation completion callbacks. In functions
482which support completion notification through both controller event callback and
483operation completion callback, first the controller event callback will be
484called. If the operation is not marked as done in that callback or if the
485callback is given as NULL when creating the operation, the operation completion
486callback will be called. The API documentation shows which event are to be
487expected in the controller event notifications. It also documents any
488exceptional behaviour.
489
490Once the peers are started, test cases often need to connect some of the peers'
491services. Normally, opening a connect to a peer's service requires the peer's
492configuration. While using testbed, the testbed automatically generates
493per-peer configuration. Accessing those configurations directly through file
494system is discouraged as their locations are dynamically created and will be
495different among various runs of testbed. To make access to these configurations
496easy, testbed API provides the function
497\texttt{GNUNET\_TESTBED\_service\_connect()}. This function fetches the
498configuration of a given peer and calls the \textit{Connect Adapter}.
499In the example code, it is the \texttt{dht\_ca}. A connect adapter is expected
500to open the connection to the needed service by using the provided configuration
501and return the created service connection handle. Successful connection to the
502needed service is signaled through \texttt{service\_connect\_comp\_cb}.
503
504A dual to connect adapter is the \textit{Disconnect Adapter}. This callback is
505called after the connect adapter has been called when the operation from
506\texttt{GNUNET\_TESTBED\_service\_connect()} is marked as ``done''. It has to
507disconnect from the service with the provided service handle (\texttt{op\_result}).
508
509\exercise{Find out how many peers you can run on your system.}
510
511\exercise{Find out how to create a 2D torus topology by changing the
512 options in the configuration file.\footnote{See @uref{https://gnunet.org/supported-topologies}}
513 Then use the DHT API to store and retrieve values in the
514 network.}
515
516
517@section Developing Applications
518
519@subsection gnunet-ext}
520To develop a new peer-to-peer application or to extend GNUnet we provide
521a template build system for writing GNUnet extensions in C. It can be
522obtained as follows:
523
524\lstset{language=bash}
525\begin{lstlisting}
526$ git clone https://gnunet.org/git/gnunet-ext
527$ cd gnunet-ext/
528$ ./bootstrap
529$ ./configure --prefix=$PREFIX --with-gnunet=$PREFIX
530$ make
531$ make install
532$ make check
533\end{lstlisting}
534% $
535
536The GNUnet ext template includes examples and a working buildsystem for a new GNUnet service.
537A common GNUnet service consists of the following parts which will be discussed in detail in the
538remainder of this document. The functionality of a GNUnet service is implemented in:
539
540\begin{itemize}
541\itemsep0em
542 \item the GNUnet service (\lstinline|gnunet-ext/src/ext/gnunet-service-ext.c|)
543 \item the client API (\lstinline|gnunet-ext/src/ext/ext_api.c|)
544 \item the client application using the service API (\lstinline|gnunet-ext/src/ext/gnunet-ext.c|)
545
546
547\end{itemize}
548
549The interfaces for these entities are defined in:
550\begin{itemize}
551\itemsep0em
552 \item client API interface (\lstinline|gnunet-ext/src/ext/ext.h|)
553 \item the service interface (\lstinline|gnunet-ext/src/include/gnunet_service_SERVICE.h|)
554 \item the P2P protocol (\lstinline|gnunet-ext/src/include/gnunet_protocols_ext.h|)
555\end{itemize}
556
557
558In addition the \texttt{ext} systems provides:
559\begin{itemize}
560\itemsep0em
561 \item a test testing the API (\lstinline|gnunet-ext/src/ext/test_ext_api.c|)
562 \item a configuration template for the service (\lstinline|gnunet-ext/src/ext/ext.conf.in|)
563\end{itemize}
564
565
566@subsection Adapting the Template}
567
568The first step for writing any extension with a new service is to
569ensure that the {\tt ext.conf.in} file contains entries for the
570\texttt{UNIXPATH}, \texttt{PORT} and \texttt{BINARY} for the service in a section named after
571the service.
572
573If you want to adapt the template rename the {\tt ext.conf.in} to match your
574services name, you have to modify the \texttt{AC\_OUTPUT} section in {\tt configure.ac}
575in the \texttt{gnunet-ext} root.
576
577@section Writing a Client Application
578
579When writing any client application (for example, a command-line
580tool), the basic structure is to start with the {\tt
581 GNUNET\_PROGRAM\_run} function. This function will parse
582command-line options, setup the scheduler and then invoke the {\tt
583 run} function (with the remaining non-option arguments) and a handle
584to the parsed configuration (and the configuration file name that was
585used, which is typically not needed):
586
587\lstset{language=C}
588\begin{lstlisting}
589#include <gnunet/platform.h>
590#include <gnunet/gnunet_util_lib.h>
591
592static int ret;
593
594static void
595run (void *cls,
596 char *const *args,
597 const char *cfgfile,
598 const struct GNUNET_CONFIGURATION_Handle *cfg)
599{
600 // main code here
601 ret = 0;
602}
603
604int
605main (int argc, char *const *argv)
606{
607 struct GNUNET_GETOPT_CommandLineOption options[] = {
608 GNUNET_GETOPT_OPTION_END
609 };
610 return (GNUNET_OK ==
611 GNUNET_PROGRAM_run (argc,
612 argv,
613 "binary-name",
614 gettext_noop ("binary description text"),
615 options, &run, NULL)) ? ret : 1;
616}
617\end{lstlisting}
618
619@subsection Handling command-line options}
620
621Options can then be added easily by adding global variables and
622expanding the {\tt options} array. For example, the following would
623add a string-option and a binary flag (defaulting to {\tt NULL} and
624{\tt GNUNET\_NO} respectively):
625
626\lstset{language=C}
627\begin{lstlisting}
628static char *string_option;
629static int a_flag;
630
631// ...
632 struct GNUNET_GETOPT_CommandLineOption options[] = {
633 GNUNET_GETOPT_option_string ('s', "name", "SOMESTRING",
634 gettext_noop ("text describing the string_option NAME"),
635 &string_option},
636 GNUNET_GETOPT_option_flag ('f', "flag",
637 gettext_noop ("text describing the flag option"),
638 &a_flag),
639 GNUNET_GETOPT_OPTION_END
640 };
641 string_option = NULL;
642 a_flag = GNUNET_SYSERR;
643// ...
644\end{lstlisting}
645
646Issues such as displaying some helpful text describing options using
647the {\tt --help} argument and error handling are taken care of when
648using this approach. Other {\tt GNUNET\_GETOPT\_}-functions can be used
649to obtain integer value options, increment counters, etc. You can
650even write custom option parsers for special circumstances not covered
651by the available handlers. To check if an argument was specified by the
652user you initialize the variable with a specific value (e.g. NULL for
653a string and GNUNET\_SYSERR for a integer) and check after parsing
654happened if the values were modified.
655
656Inside the {\tt run} method, the program would perform the
657application-specific logic, which typically involves initializing and
658using some client library to interact with the service. The client
659library is supposed to implement the IPC whereas the service provides
660more persistent P2P functions.
661
662\exercise{Add a few command-line options and print them inside
663of {\tt run}. What happens if the user gives invalid arguments?}
664
665@subsection Writing a Client Library}
666
667The first and most important step in writing a client library is to
668decide on an API for the library. Typical API calls include
669connecting to the service, performing application-specific requests
670and cleaning up. Many examples for such service APIs can be found
671in the {\tt gnunet/src/include/gnunet\_*\_service.h} files.
672
673Then, a client-service protocol needs to be designed. This typically
674involves defining various message formats in a header that will be
675included by both the service and the client library (but is otherwise
676not shared and hence located within the service's directory and not
677installed by {\tt make install}). Each message must start with a {\tt
678 struct GNUNET\_MessageHeader} and must be shorter than 64k. By
679convention, all fields in IPC (and P2P) messages must be in big-endian
680format (and thus should be read using {\tt ntohl} and similar
681functions and written using {\tt htonl} and similar functions).
682Unique message types must be defined for each message struct in the
683{\tt gnunet\_protocols.h} header (or an extension-specific include
684file).
685
686\subsubsection{Connecting to the Service}
687
688Before a client library can implement the application-specific protocol
689with the service, a connection must be created:
690
691\lstset{language=C}
692\begin{lstlisting}
693 struct GNUNET_MQ_MessageHandlers handlers[] = {
694 // ...
695 GNUNET_MQ_handler_end ()
696 };
697 struct GNUNET_MQ_Handle *mq;
698
699 mq = GNUNET_CLIENT_connect (cfg, "service-name", handlers, &error_cb, NULL);
700\end{lstlisting}
701
702As a result a {\tt GNUNET\_MQ\_Handle} is returned
703which can to used henceforth to transmit messages to
704the service.
705The complete MQ API can be found in {\tt gnunet\_mq\_lib.h}.
706The {\tt hanlders} array in the example above is incomplete.
707Here is where you will define which messages you expect to
708receive from the service, and which functions handle them.
709The {\tt error\_cb} is a function that is to be called whenever
710there are errors communicating with the service.
711
712\subsubsection{Sending messages}
713
714In GNUnet, messages are always sent beginning with a {\tt struct GNUNET\_MessageHeader}
715in big endian format. This header defines the size and the type of the
716message, the payload follows after this header.
717
718\lstset{language=C}
719\begin{lstlisting}
720struct GNUNET_MessageHeader
721{
722 uint16_t size GNUNET_PACKED;
723 uint16_t type GNUNET_PACKED;
724};
725\end{lstlisting}
726
727Existing message types are defined in {\tt gnunet\_protocols.h}\\
728A common way to create a message is with an envelope:
729
730\lstset{language=C}
731\begin{lstlisting}
732struct GNUNET_MQ_Envelope *env;
733struct GNUNET_MessageHeader *msg;
734
735env = GNUNET_MQ_msg_extra (msg, payload_size, GNUNET_MY_MESSAGE_TYPE);
736memcpy (&msg[1], &payload, payload_size);
737// Send message via message queue 'mq'
738GNUNET_mq_send (mq, env);
739\end{lstlisting}
740
741\exercise{Define a message struct that includes a 32-bit
742unsigned integer in addition to the standard GNUnet MessageHeader.
743Add a C struct and define a fresh protocol number for your message.
744(Protocol numbers in gnunet-ext are defined in \lstinline|gnunet-ext/src/include/gnunet_protocols_ext.h|)}
745
746\exercise{Find out how you can determine the number of messages in a message queue.}
747
748\exercise{Find out how you can determine when a message you have queued was actually transmitted.}
749
750\exercise{Define a helper function to transmit a 32-bit
751unsigned integer (as payload) to a service using some given client
752handle.}
753
754
755\subsubsection{Receiving Replies from the Service}
756
757Clients can receive messages from the service using the handlers
758specified in the {\tt handlers} array we specified when connecting
759to the service. Entries in the the array are usually created using
760one of two macros, depending on whether the message is fixed size
761or variable size. Variable size messages are managed using two
762callbacks, one to check that the message is well-formed, the other
763to actually process the message. Fixed size messages are fully
764checked by the MQ-logic, and thus only need to provide the handler
765to process the message. Note that the prefixes {\tt check\_}
766and {\tt handle\_} are mandatory.
767
768\lstset{language=c}
769\begin{lstlisting}
770static void
771handle_fix (void *cls, const struct MyMessage *msg)
772{
773 // process 'msg'
774}
775
776static int
777check_var (void *cls, const struct MyVarMessage *msg)
778{
779 // check 'msg' is well-formed
780 return GNUNET_OK;
781}
782
783static void
784handle_var (void *cls, const struct MyVarMessage *msg)
785{
786 // process 'msg'
787}
788
789struct GNUNET_MQ_MessageHandler handlers[] = {
790 GNUNET_MQ_hd_fixed_size (fix,
791 GNUNET_MESSAGE_TYPE_MY_FIX,
792 struct MyMessage,
793 NULL),
794 GNUNET_MQ_hd_fixed_size (var,
795 GNUNET_MESSAGE_TYPE_MY_VAR,
796 struct MyVarMessage,
797 NULL),
798
799 GNUNET_MQ_handler_end ()
800};
801\end{lstlisting}
802
803\exercise{Expand your helper function to receive a response message
804 (for example, containing just the {\tt struct GNUnet MessageHeader}
805 without any payload). Upon receiving the service's response, you
806 should call a callback provided to your helper function's API.}
807
808\exercise{Figure out where you can pass values to the closures ({\tt cls}).}
809
810
811@subsection Writing a user interface}
812
813Given a client library, all it takes to access a service now is to
814combine calls to the client library with parsing command-line
815options.
816
817\exercise{Call your client API from your {\tt run()} method in your
818 client application to send a request to the service. For example,
819 send a 32-bit integer value based on a number given at the
820 command-line to the service.}
821
822
823
824@section Writing a Service
825
826Before you can test the client you've written so far, you'll need to also
827implement the corresponding service.
828
829
830@subsection Code Placement}
831
832New services are placed in their own subdirectory under {\tt gnunet/src}.
833This subdirectory should contain the API implementation file {\tt SERVICE\_api.c},
834the description of the client-service protocol {\tt SERVICE.h} and P2P protocol
835{\tt SERVICE\_protocol.h}, the implementation of the service itself
836{\tt gnunet-service-SERVICE.h} and several files for tests, including test code
837and configuration files.
838
839@subsection Starting a Service}
840
841The key API definition for creating a service is the {\tt GNUNET\_SERVICE\_MAIN} macro:
842\lstset{language=C}
843\begin{lstlisting}
844GNUNET_SERVICE_MAIN
845("service-name",
846 GNUNET_SERVICE_OPTION_NONE,
847 &run,
848 &client_connect_cb,
849 &client_disconnect_cb,
850 NULL,
851 GNUNET_MQ_hd_fixed_size (...),
852 GNUNET_MQ_hd_var_size (...),
853 GNUNET_MQ_handler_end ());
854\end{lstlisting}
855
856In addition to the service name and flags, the macro takes three
857functions, typically called {\tt run}, {\tt client\_connect\_cb} and
858{\tt client\_disconnect\_cb} as well as an array of message handlers
859that will be called for incoming messages from clients.
860
861A minimal version of the three central service funtions would look
862like this:
863
864\lstset{language=c}
865\begin{lstlisting}
866static void
867run (void *cls,
868 const struct GNUNET_CONFIGURATION_Handle *c,
869 struct GNUNET_SERVICE_Handle *service)
870{
871}
872
873static void *
874client_connect_cb (void *cls,
875 struct GNUNET_SERVICE_Client *c,
876 struct GNUNET_MQ_Handle *mq)
877{
878 return c;
879}
880
881static void
882client_disconnect_cb (void *cls,
883 struct GNUNET_SERVICE_Client *c,
884 void *internal_cls)
885{
886 GNUNET_assert (c == internal_cls);
887}
888\end{lstlisting}
889
890\exercise{Write a stub service that processes no messages at all
891 in your code. Create a default configuration for it, integrate it
892 with the build system and start the service from {\tt
893 gnunet-service-arm} using {\tt gnunet-arm -i NAME}.}
894
895\exercise{Figure out how to set the closure ({\tt cls}) for handlers
896 of a service.}
897
898\exercise{Figure out how to send messages from the service back to the
899 client.}
900
901Each handler function in the service {\bf must} eventually (possibly in some
902asynchronous continuation) call {\tt GNUNET\_SERVICE\_client\_continue()}.
903Only after this call additional messages from the same client may
904be processed. This way, the service can throttle processing messages
905from the same client.
906
907\exercise{Change the service to ``handle'' the message from your
908 client (for now, by printing a message). What happens if you
909 forget to call {\tt GNUNET\_SERVICE\_client\_continue()}?}
910
911
912@section Interacting directly with other Peers using the CORE Service
913
914FIXME: This section still needs to be updated to the lastest API!
915
916One of the most important services in GNUnet is the \texttt{CORE} service
917managing connections between peers and handling encryption between peers.
918
919One of the first things any service that extends the P2P protocol typically does
920is connect to the \texttt{CORE} service using:
921
922\lstset{language=C}
923\begin{lstlisting}
924#include <gnunet/gnunet_core_service.h>
925
926struct GNUNET_CORE_Handle *
927GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
928 void *cls,
929 GNUNET_CORE_StartupCallback init,
930 GNUNET_CORE_ConnectEventHandler connects,
931 GNUNET_CORE_DisconnectEventHandler disconnects,
932 const struct GNUNET_MQ_MessageHandler *handlers);
933\end{lstlisting}
934
935@subsection New P2P connections}
936
937Before any traffic with a different peer can be exchanged, the peer must be
938known to the service. This is notified by the \texttt{CORE} {\tt connects} callback,
939which communicates the identity of the new peer to the service:
940
941\lstset{language=C}
942\begin{lstlisting}
943void *
944connects (void *cls,
945 const struct GNUNET_PeerIdentity *peer,
946 struct GNUNET_MQ_Handle *mq)
947{
948 return mq;
949}
950\end{lstlisting}
951
952Note that whatever you return from {\tt connects} is given as the
953{\it cls} argument to the message handlers for messages from
954the respective peer.
955
956\exercise{Create a service that connects to the \texttt{CORE}. Then
957start (and connect) two peers and print a message once your connect
958callback is invoked.}
959
960@subsection Receiving P2P Messages}
961
962To receive messages from \texttt{CORE}, you pass the desired
963{\em handlers} to the {\tt GNUNET\_CORE\_connect()} function,
964just as we showed for services.
965
966It is your responsibility to process messages fast enough or
967to implement flow control. If an application does not process
968CORE messages fast enough, CORE will randomly drop messages
969to not keep a very long queue in memory.
970
971\exercise{Start one peer with a new service that has a message
972handler and start a second peer that only has your ``old'' service
973without message handlers. Which ``connect'' handlers are invoked when
974the two peers are connected? Why?}
975
976
977@subsection Sending P2P Messages}
978
979You can transmit messages to other peers using the {\it mq} you were
980given during the {\tt connect} callback. Note that the {\it mq}
981automatically is released upon {\tt disconnect} and that you must
982not use it afterwards.
983
984It is your responsibility to not over-fill the message queue, GNUnet
985will send the messages roughly in the order given as soon as possible.
986
987\exercise{Write a service that upon connect sends messages as
988fast as possible to the other peer (the other peer should run a
989service that ``processes'' those messages). How fast is the
990transmission? Count using the STATISTICS service on both ends. Are
991messages lost? How can you transmit messages faster? What happens if
992you stop the peer that is receiving your messages?}
993
994
995@subsection End of P2P connections}
996
997If a message handler returns {\tt GNUNET\_SYSERR}, the remote peer shuts down or
998there is an unrecoverable network disconnection, CORE notifies the service that
999the peer disconnected. After this notification no more messages will be received
1000from the peer and the service is no longer allowed to send messages to the peer.
1001The disconnect callback looks like the following:
1002
1003\lstset{language=C}
1004\begin{lstlisting}
1005void
1006disconnects (void *cls,
1007 const struct GNUNET_PeerIdentity * peer)
1008{
1009 /* Remove peer's identity from known peers */
1010 /* Make sure no messages are sent to peer from now on */
1011}
1012\end{lstlisting}
1013
1014\exercise{Fix your service to handle peer disconnects.}
1015
1016@section Storing peer-specific data using the PEERSTORE service
1017
1018GNUnet's PEERSTORE service offers a persistorage for arbitrary peer-specific data.
1019Other GNUnet services can use the PEERSTORE to store, retrieve and monitor data records.
1020Each data record stored with PEERSTORE contains the following fields:
1021
1022\begin{itemize}
1023\itemsep0em
1024 \item subsystem: Name of the subsystem responsible for the record.
1025 \item peerid: Identity of the peer this record is related to.
1026 \item key: a key string identifying the record.
1027 \item value: binary record value.
1028 \item expiry: record expiry date.
1029\end{itemize}
1030
1031The first step is to start a connection to the PEERSTORE service:
1032\begin{lstlisting}
1033#include "gnunet_peerstore_service.h"
1034
1035peerstore_handle = GNUNET_PEERSTORE_connect (cfg);
1036\end{lstlisting}
1037The service handle \lstinline|peerstore_handle| will be needed for all subsequent
1038PEERSTORE operations.
1039
1040@subsection Storing records}
1041
1042To store a new record, use the following function:
1043\begin{lstlisting}
1044struct GNUNET_PEERSTORE_StoreContext *
1045GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
1046 const char *sub_system,
1047 const struct GNUNET_PeerIdentity *peer,
1048 const char *key,
1049 const void *value,
1050 size_t size,
1051 struct GNUNET_TIME_Absolute expiry,
1052 enum GNUNET_PEERSTORE_StoreOption options,
1053 GNUNET_PEERSTORE_Continuation cont,
1054 void *cont_cls);
1055\end{lstlisting}
1056
1057The \lstinline|options| parameter can either be \lstinline|GNUNET_PEERSTORE_STOREOPTION_MULTIPLE|
1058which means that multiple values can be stored under the same key combination (subsystem, peerid, key),
1059or \lstinline|GNUNET_PEERSTORE_STOREOPTION_REPLACE| which means that PEERSTORE will replace any
1060existing values under the given key combination (subsystem, peerid, key) with the new given value.
1061
1062The continuation function \lstinline|cont| will be called after the store request is successfully
1063sent to the PEERSTORE service. This does not guarantee that the record is successfully stored, only
1064that it was received by the service.
1065
1066The \lstinline|GNUNET_PEERSTORE_store| function returns a handle to the store operation. This handle
1067can be used to cancel the store operation only before the continuation function is called:
1068\begin{lstlisting}
1069void
1070GNUNET_PEERSTORE_store_cancel (struct GNUNET_PEERSTORE_StoreContext *sc);
1071\end{lstlisting}
1072
1073@subsection Retrieving records}
1074
1075To retrieve stored records, use the following function:
1076\begin{lstlisting}
1077struct GNUNET_PEERSTORE_IterateContext *
1078GNUNET_PEERSTORE_iterate (struct GNUNET_PEERSTORE_Handle *h,
1079 const char *sub_system,
1080 const struct GNUNET_PeerIdentity *peer,
1081 const char *key,
1082 struct GNUNET_TIME_Relative timeout,
1083 GNUNET_PEERSTORE_Processor callback,
1084 void *callback_cls);
1085\end{lstlisting}
1086The values of \lstinline|peer| and \lstinline|key| can be \lstinline|NULL|. This allows the
1087iteration over values stored under any of the following key combinations:
1088\begin{itemize}
1089\itemsep0em
1090 \item (subsystem)
1091 \item (subsystem, peerid)
1092 \item (subsystem, key)
1093 \item (subsystem, peerid, key)
1094\end{itemize}
1095
1096The \lstinline|callback| function will be called once with each retrieved record and once
1097more with a \lstinline|NULL| record to signal the end of results.
1098
1099The \lstinline|GNUNET_PEERSTORE_iterate| function returns a handle to the iterate operation. This
1100handle can be used to cancel the iterate operation only before the callback function is called with
1101a \lstinline|NULL| record.
1102
1103@subsection Monitoring records}
1104
1105PEERSTORE offers the functionality of monitoring for new records stored under a specific key
1106combination (subsystem, peerid, key). To start the monitoring, use the following function:
1107\begin{lstlisting}
1108struct GNUNET_PEERSTORE_WatchContext *
1109GNUNET_PEERSTORE_watch (struct GNUNET_PEERSTORE_Handle *h,
1110 const char *sub_system,
1111 const struct GNUNET_PeerIdentity *peer,
1112 const char *key,
1113 GNUNET_PEERSTORE_Processor callback,
1114 void *callback_cls);
1115\end{lstlisting}
1116
1117Whenever a new record is stored under the given key combination, the \lstinline|callback| function
1118will be called with this new record. This will continue until the connection to the PEERSTORE service
1119is broken or the watch operation is canceled:
1120\begin{lstlisting}
1121void
1122GNUNET_PEERSTORE_watch_cancel (struct GNUNET_PEERSTORE_WatchContext *wc);
1123\end{lstlisting}
1124
1125@subsection Disconnecting from PEERSTORE}
1126
1127When the connection to the PEERSTORE service is no longer needed, disconnect using the following
1128function:
1129\begin{lstlisting}
1130void
1131GNUNET_PEERSTORE_disconnect (struct GNUNET_PEERSTORE_Handle *h, int sync_first);
1132\end{lstlisting}
1133
1134If the \lstinline|sync_first| flag is set to \lstinline|GNUNET_YES|, the API will delay the
1135disconnection until all store requests are received by the PEERSTORE service. Otherwise,
1136it will disconnect immediately.
1137
1138
1139@section Using the DHT
1140
1141The DHT allows to store data so other peers in the P2P network can
1142access it and retrieve data stored by any peers in the network.
1143This section will explain how to use the DHT. Of course, the first
1144thing to do is to connect to the DHT service:
1145\lstset{language=C}
1146\begin{lstlisting}
1147dht_handle = GNUNET_DHT_connect (cfg, parallel_requests);
1148\end{lstlisting}
1149The second parameter indicates how many requests in parallel to expect.
1150It is not a hard limit, but a good approximation will make the DHT more
1151efficient.
1152
1153@subsection Storing data in the DHT}
1154Since the DHT is a dynamic environment (peers join and leave frequently)
1155the data that we put in the DHT does not stay there indefinitely. It is
1156important to ``refresh'' the data periodically by simply storing it again,
1157in order to make sure other peers can access it.
1158
1159The put API call offers a callback to signal that the PUT request has been
1160sent. This does not guarantee that the data is accessible to others peers,
1161or even that is has been stored, only that the service has requested to
1162a neighboring peer the retransmission of the PUT request towards its final
1163destination. Currently there is no feedback about whether or not the data
1164has been sucessfully stored or where it has been stored. In order to improve
1165the availablilty of the data and to compensate for possible errors, peers leaving
1166and other unfavorable events, just make several PUT requests!
1167
1168\lstset{language=C}
1169\begin{lstlisting}
1170static void
1171message_sent_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1172{
1173 // Request has left local node
1174}
1175
1176struct GNUNET_DHT_PutHandle *
1177GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
1178 const struct GNUNET_HashCode *key,
1179 uint32_t desired_replication_level,
1180 enum GNUNET_DHT_RouteOption options,
1181 enum GNUNET_BLOCK_Type type, size_t size, const void *data,
1182 struct GNUNET_TIME_Absolute exp,
1183 struct GNUNET_TIME_Relative timeout,
1184 GNUNET_DHT_PutContinuation cont, void *cont_cls)
1185\end{lstlisting}
1186
1187\exercise{Store a value in the DHT periodically to make sure it is available
1188over time. You might consider using the function GNUNET\_SCHEDULER\_add\_delayed and
1189call GNUNET\_DHT\_put from inside a helper function.}
1190
1191
1192@subsection Obtaining data from the DHT}
1193As we saw in the previous example, the DHT works in an asynchronous mode.
1194Each request to the DHT is executed ``in the background'' and the API
1195calls return immediately. In order to receive results from the DHT, the
1196API provides a callback. Once started, the request runs in the service,
1197the service will try to get as many results as possible (filtering out
1198duplicates) until the timeout expires or we explicitly stop the request.
1199It is possible to give a ``forever'' timeout with
1200{\tt GNUNET\_TIME\_UNIT\_FOREVER\_REL}.
1201
1202If we give a route option {\tt GNUNET\_DHT\_RO\_RECORD\_ROUTE} the callback
1203will get a list of all the peers the data has travelled, both on the PUT
1204path and on the GET path.
1205\lstset{language=C}
1206\begin{lstlisting}
1207static void
1208get_result_iterator (void *cls, struct GNUNET_TIME_Absolute expiration,
1209 const struct GNUNET_HashCode *key,
1210 const struct GNUNET_PeerIdentity *get_path,
1211 unsigned int get_path_length,
1212 const struct GNUNET_PeerIdentity *put_path,
1213 unsigned int put_path_length,
1214 enum GNUNET_BLOCK_Type type, size_t size, const void *data)
1215{
1216 // Optionally:
1217 GNUNET_DHT_get_stop (get_handle);
1218}
1219
1220get_handle =
1221 GNUNET_DHT_get_start (dht_handle,
1222 block_type,
1223 &key,
1224 replication,
1225 GNUNET_DHT_RO_NONE,
1226 NULL,
1227 0,
1228 &get_result_iterator,
1229 cls)
1230\end{lstlisting}
1231
1232\exercise{Store a value in the DHT and after a while retrieve it. Show the IDs of all
1233the peers the requests have gone through. In order to convert a peer ID to a string, use
1234the function GNUNET\_i2s. Pay attention to the route option parameters in both calls!}
1235
1236@subsection Implementing a block plugin}
1237
1238In order to store data in the DHT, it is necessary to provide a block
1239plugin. The DHT uses the block plugin to ensure that only well-formed
1240requests and replies are transmitted over the network.
1241
1242The block plugin should be put in a file {\tt
1243 plugin\_block\_SERVICE.c} in the service's respective directory. The
1244mandatory functions that need to be implemented for a block plugin are
1245described in the following sections.
1246
1247\subsubsection{Validating requests and replies}
1248
1249The evaluate function should validate a reply or a request. It returns
1250a {\tt GNUNET\_BLOCK\_EvaluationResult}, which is an enumeration. All
1251possible answers are in {\tt gnunet\_block\_lib.h}. The function will
1252be called with a {\tt reply\_block} argument of {\tt NULL} for
1253requests. Note that depending on how {\tt evaluate} is called, only
1254some of the possible return values are valid. The specific meaning of
1255the {\tt xquery} argument is application-specific. Applications that
1256do not use an extended query should check that the {\tt xquery\_size}
1257is zero. The block group is typically used to filter duplicate
1258replies.
1259
1260\lstset{language=C}
1261\begin{lstlisting}
1262static enum GNUNET_BLOCK_EvaluationResult
1263block_plugin_SERVICE_evaluate (void *cls,
1264 enum GNUNET_BLOCK_Type type,
1265 struct GNUNET_BlockGroup *bg,
1266 const GNUNET_HashCode *query,
1267 const void *xquery,
1268 size_t xquery_size,
1269 const void *reply_block,
1270 size_t reply_block_size)
1271{
1272 // Verify type, block and bg
1273}
1274\end{lstlisting}
1275
1276Note that it is mandatory to detect duplicate replies in this function
1277and return the respective status code. Duplicate detection is
1278typically done using the Bloom filter block group provided by {\tt
1279 libgnunetblockgroup.so}. Failure to do so may cause replies to
1280circle in the network.
1281
1282\subsubsection{Deriving a key from a reply}
1283
1284The DHT can operate more efficiently if it is possible to derive a key
1285from the value of the corresponding block. The {\tt get\_key}
1286function is used to obtain the key of a block --- for example, by
1287means of hashing. If deriving the key is not possible, the function
1288should simply return {\tt GNUNET\_SYSERR} (the DHT will still work
1289just fine with such blocks).
1290
1291\lstset{language=C}
1292\begin{lstlisting}
1293static int
1294block_plugin_SERVICE_get_key (void *cls, enum GNUNET_BLOCK_Type type,
1295 const void *block, size_t block_size,
1296 struct GNUNET_HashCode *key)
1297{
1298 // Store the key in the key argument, return GNUNET_OK on success.
1299}
1300\end{lstlisting}
1301
1302\subsubsection{Initialization of the plugin}
1303
1304The plugin is realized as a shared C library. The library must export
1305an initialization function which should initialize the plugin. The
1306initialization function specifies what block types the plugin cares
1307about and returns a struct with the functions that are to be used for
1308validation and obtaining keys (the ones just defined above).
1309
1310\lstset{language=C}
1311\begin{lstlisting}
1312void *
1313libgnunet_plugin_block_SERVICE_init (void *cls)
1314{
1315 static enum GNUNET_BLOCK_Type types[] =
1316 {
1317 GNUNET_BLOCK_TYPE_SERVICE_BLOCKYPE,
1318 GNUNET_BLOCK_TYPE_ANY
1319 };
1320 struct GNUNET_BLOCK_PluginFunctions *api;
1321
1322 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
1323 api->evaluate = &block_plugin_SERICE_evaluate;
1324 api->get_key = &block_plugin_SERVICE_get_key;
1325 api->types = types;
1326 return api;
1327}
1328\end{lstlisting}
1329
1330\subsubsection{Shutdown of the plugin}
1331
1332Following GNUnet's general plugin API concept, the plugin must
1333export a second function for cleaning up. It usually does very
1334little.
1335
1336\lstset{language=C}
1337\begin{lstlisting}
1338void *
1339libgnunet_plugin_block_SERVICE_done (void *cls)
1340{
1341 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1342
1343 GNUNET_free (api);
1344 return NULL;
1345}
1346\end{lstlisting}
1347
1348
1349\subsubsection{Integration of the plugin with the build system}
1350
1351In order to compile the plugin, the {\tt Makefile.am} file for the
1352service \texttt{SERVICE} should contain a rule similar to this:
1353
1354\lstset{language=make}
1355\begin{lstlisting}
1356 plugindir = $(libdir)/gnunet
1357
1358 plugin_LTLIBRARIES = \
1359 libgnunet_plugin_block_ext.la
1360 libgnunet_plugin_block_ext_la_SOURCES = \
1361 plugin_block_ext.c
1362 libgnunet_plugin_block_ext_la_LIBADD = \
1363 $(prefix)/lib/libgnunethello.la \
1364 $(prefix)/lib/libgnunetblock.la \
1365 $(prefix)/lib/libgnunetutil.la
1366 libgnunet_plugin_block_ext_la_LDFLAGS = \
1367 $(GN_PLUGIN_LDFLAGS)
1368 libgnunet_plugin_block_ext_la_DEPENDENCIES = \
1369 $(prefix)/lib/libgnunetblock.la
1370\end{lstlisting}
1371% $
1372
1373
1374\exercise{Write a block plugin that accepts all queries
1375and all replies but prints information about queries and replies
1376when the respective validation hooks are called.}
1377
1378
1379
1380@subsection Monitoring the DHT
1381It is possible to monitor the functioning of the local DHT service. When monitoring
1382the DHT, the service will alert the monitoring program of any events,
1383both started locally or received for routing from another peer. The are three different
1384types of events possible: a GET request, a PUT request or a response (a reply to
1385a GET).
1386
1387Since the different events have different associated data, the API gets 3
1388different callbacks (one for each message type) and optional type and key parameters,
1389to allow for filtering of messages. When an event happens, the appropiate callback
1390is called with all the information about the event.
1391\lstset{language=C}
1392\begin{lstlisting}
1393static void
1394get_callback (void *cls,
1395 enum GNUNET_DHT_RouteOption options,
1396 enum GNUNET_BLOCK_Type type,
1397 uint32_t hop_count,
1398 uint32_t desired_replication_level,
1399 unsigned int path_length,
1400 const struct GNUNET_PeerIdentity *path,
1401 const struct GNUNET_HashCode * key)
1402{
1403}
1404
1405
1406static void
1407get_resp_callback (void *cls,
1408 enum GNUNET_BLOCK_Type type,
1409 const struct GNUNET_PeerIdentity *get_path,
1410 unsigned int get_path_length,
1411 const struct GNUNET_PeerIdentity *put_path,
1412 unsigned int put_path_length,
1413 struct GNUNET_TIME_Absolute exp,
1414 const struct GNUNET_HashCode * key,
1415 const void *data,
1416 size_t size)
1417{
1418}
1419
1420
1421static void
1422put_callback (void *cls,
1423 enum GNUNET_DHT_RouteOption options,
1424 enum GNUNET_BLOCK_Type type,
1425 uint32_t hop_count,
1426 uint32_t desired_replication_level,
1427 unsigned int path_length,
1428 const struct GNUNET_PeerIdentity *path,
1429 struct GNUNET_TIME_Absolute exp,
1430 const struct GNUNET_HashCode * key,
1431 const void *data,
1432 size_t size)
1433{
1434}
1435
1436
1437monitor_handle = GNUNET_DHT_monitor_start (dht_handle,
1438 block_type,
1439 key,
1440 &get_callback,
1441 &get_resp_callback,
1442 &put_callback,
1443 cls);
1444\end{lstlisting}
1445
1446
1447@section Debugging with gnunet-arm
1448
1449Even if services are managed by {\tt gnunet-arm}, you can start them with
1450{\tt gdb} or {\tt valgrind}. For example, you could add the following lines
1451to your configuration file to start the DHT service in a {\tt gdb} session in a
1452fresh {\tt xterm}:
1453
1454\begin{verbatim}
1455[dht]
1456PREFIX=xterm -e gdb --args
1457\end{verbatim}
1458
1459Alternatively, you can stop a service that was started via ARM and run it manually:
1460
1461\lstset{language=bash}
1462\begin{lstlisting}
1463$ gnunet-arm -k dht
1464$ gdb --args gnunet-service-dht -L DEBUG
1465$ valgrind gnunet-service-dht -L DEBUG
1466\end{lstlisting}
1467% $
1468
1469Assuming other services are well-written, they will automatically re-integrate the
1470restarted service with the peer.
1471
1472GNUnet provides a powerful logging mechanism providing log levels \texttt{ERROR},
1473\texttt{WARNING}, \texttt{INFO} and \texttt{DEBUG}. The current log level is
1474configured using the \lstinline|$GNUNET_FORCE_LOG| environmental variable.
1475The \texttt{DEBUG} level is only available if \lstinline|--enable-logging=verbose| was used when
1476running \texttt{configure}. More details about logging can be found under
1477@uref{https://gnunet.org/logging}.
1478
1479You should also probably enable the creation of core files, by setting
1480{\tt ulimit}, and echo'ing 1 into {\tt /proc/sys/kernel/core\_uses\_pid}.
1481Then you can investigate the core dumps with {\tt gdb}, which is often
1482the fastest method to find simple errors.
1483
1484\exercise{Add a memory leak to your service and obtain a trace
1485pointing to the leak using {\tt valgrind} while running the service
1486from {\tt gnunet-service-arm}.}
1487
1488
1489\end{document}