> <\body> ||>>> Copyright (C) 2021 Maxime Devos Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; \ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.A copy of the license is included in the section entitled \<#2018\>GNU Free Documentation License\<#2019\>. \; The latest \<#2018\>official\<#2019\> development version of scheme-GNUnet can be found at . It can be downloaded with . The following software needs to be installed first: <\itemize> The Autotools ( and ) (at least version 3) For the benefit of dead tree readers, the invisible hyperlinks above are reproduced as visible URLs below. <\itemize> A few patches to guile and guile-fibers are required (some bug fixes, some extra functionality), see . Users of can run in the checkout to create an environment where these dependencies are all present.Scheme-GNUnet uses the standard GNU build system, so to build Scheme-Gnunet, you only need to run <\shell-code> autoreconf -vif ./configure make make check After building, the documentation is available at and in PDF and HTML formats.To get started, you can run the example mini-application at and point your browser at : <\shell-code> $ guile -L . -C . -l examples/nse-web.scm When GNU Guix is present, after pulling the latest Scheme-GNUnet commit, the following command can be run to verify it is authentic: <\shell-code> guix git authenticate 431f336edd51e1f0fe059a6f6f2d4c3e9267b7bc "C1F3 3EE2 0C52 8FDB 7DD7 \ 011F 49E3 EE22 1917 25EE" If it isn't authentic, an error message such as the following will be written: <\shell-code> Authenticating commits 54a74dc to 431f336 (1 new commits)... [#########################################################] guix git: error: commit 431f336edd51e1f0fe059a6f6f2d4c3e9267b7bc not signed by an authorized key: C1F3 3EE2 0C52 8FDB 7DD7 \ 011F 49E3 EE22 1917 25EE \<#2018\>\<#2019\> is a recommended read.Scheme-GNUnet isn't that well-tested but still aims for being free of bugs and having many tests to prevents bugs from being introduced.When adding new code, consider writing test cases.Some things that can be tested and few methods for testing things: <\itemize> Run mutation tests.That is, replace in the source code > with =>, with , a variable reference with a variable reference , swap destination and source arguments and verify whether the tests detect these little mutations. Be exhaustive.If a procedure handles both foos and bars, write test cases that pass the procedure a foo and test cases that pass the procedure a bar.Sometimes Guile-QuickCheck can help with generating many test cases if the input has a regular structure yet many edge cases, see e.g. . Verify exception mechanisms!If a procedure is expected to handle I/O errors, simulate I/O errors and end-of-files in all the wrong places.If the procedure can raise exceptions, make sure these exceptions are raised when necessary. Tests are added in the directory and to the variable in and use .To run the test suite, run . Scheme-GNUnet is currently maintained on NotABug: .Issues and pull requests can be reported and submitted here.Alternatively, for discussion about developing Scheme-GNUnet, you can send mails to and for help about how to use Scheme-GNUnet, you can contact .These are public mailing lists, so don't send anything there you wouldn't mind the whole world to know. For security-sensitive issues, you can send a mail directly to the maintainer, maximedevos@telenet.be\|mailto:maximedevos@telenet.be>, optionally encrypted and signed with a GnuPG-compatible system.The maintainer's key fingerprint is C1F3 3EE2 0C52 8FDB 7DD7 011F 49E3 EE22 1917 25EE and a copy of the key can be downloaded from . The code of Scheme-GNUnet is available under the Affero General Public License (AGPL), version 3 or later; see individual source files for details.The documentaton is available under the GNU Free Documentation License, see the start of this manual and the likewise-named appendix for details.The AGPL has some unusual conditions w.r.t. applications interacting with the network, please read it carefully. Scheme-GNUnet doesn't have any example applications, except the half-baked , and .Over time, we hope we have something to write here, but for now, this chapter is empty. Scheme-GNUnet uses for concurrency, but supports POSIX-style threading as well, using the Guile module. More concretely, this means is used by default for starting asynchronuous computations and public procedures accept an optional argument accepting a procedure like or . \<#2018\>Conditions\<#2019\> can be used for synchronising concurrent computations, see the documentation of for details. Scheme-GNUnet has a variant of fibers conditions, named \<#2018\>repeated conditions\<#2019\>, in the module .It is unfortunately ill-documented. There are a number of modules for accessing GNUnet configurations.Firstly, there is , which is the module library code would typically use.For testing, one can create an empty configuration with the procedure configuration> from that module and from , using as hash function and as comparison function: <\scm-code> (import (gnu gnunet config db) \ \ \ \ \ \ \ \ (gnu gnunet config value-parser) \ \ \ \ \ \ \ \ (rnrs hashtables)) (define config (hash-\configuration (make-hashtable hash-key key=?)) The resulting configuration is initially empty, so set some in the , to configure the network-size estimation service: <\scm-code> (set-value! identity config "nse" "UNIXPATH" "/tmp/nse.sock") (set-value! number-\string config "cadet" "MAX_ROUTES" 5000) ;; TODO: IP address, time durations, booleans, ... Now read these values back: <\scm-code> (read-value value-\file-name config "nse" "UNIXPATH") ;; -\ /tmp/nse.sock (read-value value-\natural config "cadet" "MAX_ROUTES") ;; -\ 5000 What if the configuration doesn't have a value for the specified section and key?Then an results: <\scm-code> (read-value value-\natural config "kated" "MAX_ROUTES") ;; -\ ;; ice-9/boot-9.scm:1685:16: In procedure raise-exception: ;; ERROR: ;; \ \ 1. &undefined-key-error: ;; \ \ \ \ \ \ section: "kated" ;; \ \ \ \ \ \ key: "MAX_ROUTES" There are two \U possibly non-existent \U configuration files: the configuration and the configuration.The configuration typically contains the paths for services like NSE, CORE, A user may choose not to use the services by the system and instead use their own.To do so, the user needs to override the paths in the configuration. The module is responsible for determining the location of the configuration files to load and actually load configuration files.For determining the location of the configuration files, the procedures and can be used. <\warning> The C implementation's mechanism for user-system separation seems to work differently. <\explain> )> <|explain> This procedure determines the location of the user configuration file, as a string, or if it could not be determined.If the location of the user configuration file is known, but the file does not exist, it is returned anyway, as a string. If the environment variable is set, the location of the file in the directory is returned.If the environment variable is not set, the location of the file at in the home directory specified by the environment variable is returned, if that environment variable exists.If both are unset, is returned. The values of environment variables is determined with the procedure . <\explain> <|explain> This procedure determines the location of the system configuration file, as a string. Currently, this is always . Once the location of the configuration file is known, the file can be opened with the Scheme procedure , which returns an input port.Then the procedure can be used to determine all section-key-values triples in the configuration. <\explain> )> <|explain> Load the configuration from the input port . For each variable, call with the section name, variable name and a vector of the form , where a list of expansible objects. A variable assignment can refer to variables defined in the section and variables from the environment.The previously described procedure will expand such assignements. \ To expand variable assignments, use the procedure instead. <\explain> #:getenv=)> <|explain> Make a configuration object.To populate the configuration, all the procedure with a procedure as expected by .The values from are added to the confoiguration and every variable is expanded. To automatically load the defaults, the system configuration and the user configuration, use the thunk : <\explain> #:files=)> The list of files to load can be overriden by setting the undocumented keyword argument.> Applications (whether graphical or textual) are recommended to use by default, as it largely just works. The modules and can be used for formatting messages to be sent over the network or to a service.The macros and can be used to define new structures, like this: <\scm-code> (define-type /:msg:nse:estimate/example \ \ (structure/packed \ \ \ (properties '((message-symbol msg:nse:estimate))) \ \ \ (synopsis "Network size estimate") \ \ \ (documentation "Some explanation") \ \ \ (field (header /:message-header)) \ \ \ (field (size-estimate ieee-double/big) \ \ \ \ \ \ \ \ \ \ (synopsis "Timestamp for when the estimate was made")))) This example is taken from the module and oversimplified.All its components will gradually explained.First, what actually is a network structure?This question is ambigious, because \<#2018\>network structure\<#2019\> can refer to either the or the .The is a sequence of octets, i.e., a sequence of numbers in the closed range 0\U255.The describes how the is structured. As an example, consider figure .There, the value is and the type is . | | |0 12>| |1 65>>| |64 51 238 123 71 27 58 149>>|A network structure, both and .> This value has a with a \<#2018\>0 0 0 12\<#2019\> of type , so the is 12.The also has a \<#2018\>0 0 1 65\<#2019\> of type , so the type is 1+65=321>.The value also has a of type .The octets , \ interpreted as an IEEE double, form the number >. A network structure can optionally have embedded documentation.More specifically, network structures can optionally have the , and set.The is a short description of what the network structure represents, typically a one-liner.The can be more detailed, explaining how the structure works, can be used, is used and should be used.The form a free-formed association list. The synopsis, documentation and properties can be set on structured created with and individual fields and can be accessed with the procedures , and . The procedures , , and from or the like-named macros from can be used for reading and writing network structures.The macros from behave like the procedures from with some optimisations at expansion time.The procedures will be demonstrated with the network structure defined previously. First, create a memory slice with from .The required size can be determinded with .The role of will be explained later. <\scm-code> (import (gnu gnunet netstruct procedural) \ \ \ \ \ \ \ \ (gnu gnunet netstruct syntactic) \ \ \ \ \ \ \ \ (gnu gnunet utils bv-slice) \ \ \ \ \ \ \ \ (gnu gnunet util struct)) \; (define-type /:msg:nse:estimate/example \ \ (structure/packed \ \ \ (field (header /:message-header)) \ \ \ (field (size-estimate ieee-double/big)))) \; (define message \ \ (make-slice/read-write (sizeof /:msg:nse:estimate/example '()))) The fields of can be set with .The following code sets all the fields: <\scm-code> (set%! /:msg:nse:estimate/example '(header size) message \ \ \ \ \ \ \ (sizeof /:msg:nse:estimate/example '())) (set%! /:msg:nse:estimate/example '(header type) message 165) (set%! /:msg:nse:estimate/example '(size-estimate) message 19.2) The size of an individual field can be determined with .For example, the following code determines the size of the \<#2018\>size\<#2019\> field in the header: <\scm-code> (sizeof /:msg:nse:estimate/example '(header size)) ; 12 The fields can also be read: <\scm-code> (read% /:msg:nse:estimate/example '(header size) message) ; 12 (read% /:msg:nse:estimate/example '(header type) message) ; 165 (read% /:msg:nse:estimate/example '(size-estimate) message) ; 19.2 There are a number of pre-defined types.First, there is , a single octet that is interpreted as an integer in the closed range >.There are also types for > and >, which interprets octets as integers in the closed range -1|]>>.The types and are 8 octets long and represent floating-point numbers in IEEE 754 format (\<#2018\>binary64\<#2019\>). In contrast to C structures, Scheme-GNUnet network structures are always packed \V there are no \<#2018\>gaps\<#2019\> between fields. To connect with a GNUnet service \V this applies to both the C and Scheme implementation, the GNUnet service must bind a local domain socket<\footnote> The C implementation supports Internet sockets as well. somewhere on the file system and the client (possibly another service) must connect to it.Connections to a service can be made with the procedure from , like this: <\scm-code> (define mq (connect/fibers config "nse" handlers error-handler)) This is an asynchronuous operation: it will \<#2018\>complete\<#2019\> immediately and the connection will actually be formed in the background.When the connection has actually be formed, the is called with the symbol .To demonstrate, the following code asynchronuously connects to the NSE service, and prints the text when the connection has actually been formed. <\scm-code> ;; XXX test this, explain 'config' ... (define (error-handler error . args) \ \ (case error \ \ \ \ ((connection:connected) \ \ \ \ \ (format #t "connected!~%")) \ \ \ \ (else (format #t "unknown error: ~a ~a~%" error args)))) \; (define mq \ \ (connect/fibers config "nse" (message-handlers) error-handler)) When a message is received by the message queue, the corresponding message handler is invoked.Message handlers can be constructed with the macro and the procedure from , as follows: <\scm-code> (import (gnu gnunet mq handler) \ \ \ \ \ \ \ \ (gnu extractor enum) \ \ \ \ \ \ \ \ (gnu gnunet message protocols) \ \ \ \ \ \ \ \ (gnu gnunet util struct) \ \ \ \ \ \ \ \ (gnu gnunet utils bv-slice) \ \ \ \ \ \ \ \ (gnu gnunet netstruct syntactic)) \; (define handler/syntactic \ \ (message-handler \ \ \ (type (symbol-value message-type msg:util:dummy)) \ \ \ ((interpose code) code) \ \ \ ((well-formed? slice) \ \ \ \ (= (slice-length slice) \ \ \ \ \ \ \ (sizeof /:message-header '()))) \ \ \ ((handle! slice) \ \ \ \ (pk 'message: slice)))) \; (define handler/procedural \ \ (make-message-handler \ \ \ (symbol-value message-type msg:util:dummy) \ \ \ (lambda (thunk) (thunk)) \ \ \ (lambda (slice) \ \ \ \ \ (= (slice-length slice) \ \ \ \ \ \ \ \ (sizeof /:message-header '()))) \ \ \ (lambda (slice) \ \ \ \ \ (pk 'message: slice)))) As illustrated in the example code above, a message handler has four components: the of message it handles, an which will be explained later, the deciding if a message is well-formed and the . The verifier is passed a bytevector slice with the message and should return if the message is well-formed and if it isn't.It may assume that the length of the slice corresponds to the length the message header and is at least the length the message header and that the type in the message header corresponds to the type of the message handler.Messages will only be passed to the handler procedue if the verifiers returns . The handler procedure is passed a bytevector slice with the message, but only if the verifier considers it well-formed.The handler procedure and verifier are run from the .The interposer is passed a thunk to execute and may e.g. install exception handlers and parameterise parameters.It can change the current input, output and error ports for example. The module has a mapping of symbolic names of every message type known to scheme-GNUnet to their numeric value.To use it, the macro from is required and possibly index> as well.To determine the numeric value of the message type , one would write: <\scm-code> (define numeric-type \ \ (value-\index (symbol-value message-type msg:nse:estimate))) ?> The message queue implementation usually just sends and receives messages, but some exceptional situations cannot be communicated with or .For those, there is the procedure.This variadic procedure accepts a message queue to inject the error into, a (usually a symbol) describing the exceptional situation and rest arguments.It calls the of the message queue with the key and rest arguments.The following errors can currently be reported by the built-in message queue implementations: <\explain> <|explain> The connection to the server has been established. <\explain> <\explain> <|explain> The connection has been closed by the server. For people wondering about what happens if a connection becomes half-duplex: GNUnet does not have a notion of half-duplex message streams.If it is detected the underlying stream became half-duplex anyways, it will be treated as closed by scheme-GNUnet, resulting in this error.However, note that currently broken pipes cannot be reliably detected. <\explain> This can happen if the server was stopped while it was still sending the rest of the message.> <\explain> Sometimes, but not always, the message type and message size are available (as exact naturals).When they are not available, and are instead.This can only happen if the server or connection to the server is buggy.> <\explain> . <|explain> The received message of type (as an integer) does not have a corresponding message handler. is currently unspecified. <\explain> . is currently unspecified.> Consider automatically reconnecting after > and >, to allow the server to restart without having to manually restart every individual application.To report errors, see the section Error reporting. This section describes how injected errors and messages and sent messages are ordered with respect to each other in the default message queue implementation.Messages are handled or corresponding or errors are injected in the order that the messages are received.Before messages are read, is injected.This error is injected at most once. after all messages are read (and therefore after all handled messages or corresponding errors), the error , or is injected.Only one of those errors can be injected for the entire lifetime of the message queue. Be aware that is not here!For example, it is possible for a message to be received, the port closed, a message queued for sending, the closing of the port being detected by the write fiber, being injected from the write fiber and the read fiber handling the received message, and the read fiber exiting because the port is closed, in that order. Messages are sent (and received on the other side) in the order they were enqueued for sending.Likewise, the notify-sent callback of enqueued messages are called in order.If the notify-sent callback is called, it is before the message is received by the other side.The message and its notify-sent callback are only received by the other side and called after the message has been injected and has been injected.It is possible for the notify-sent callback to be called without the message being received by the other side, e.g. if the port was closed during the notify-sent callback. If a message is received by the other side, all previously-sent messages have be received before.If a notify-sent callback is invoked, all notify-sent callbacks of previous messages have been invoked before, except the messages that are eventually cancelled. The errors and are not fatal: later messages can still be read and handled.If is injected, no other errors are ever injected, whether in the past or in the future.This error can only be injected once. A message queue can be closed with the procedure from .In the default message queue implementation, this asynchronuously closes the port and stops associated fibers.Closing ports when they won't be used anymore is important for limiting resource consumption, especially for servers that can have many connections.Closing message queues is an idempotent operation: closing a message queue twice is the same as closing it once. If a message queue is closed before a connection could be formed, is injected instead of and . Errors can be reported with the procedure from the module .It can be called as , e.g. .By default, it reports the error to the current error port.If this is not desired, the output can be sent to another port by setting the parameter .If textual error reporting is not desired, the parameter can be set to a procedure with the same interface as .Such a procedure could e.g. open a GUI dialog, sent the message to the system logger or ignore the error. Error messages are translated for the current locale. GNUnet has a service that roughly estimates the size of the network \U i.e., the number of peers.The module can be used to interact with this service.The connection is made with the procedure , which is accepts a (see ) and some optional keyword arguments.This procedure can be called as .It returns a . The connection is made asynchronuously; the thunk will be called when the connection has actually been made.Whenever a new estimate becomes available, the (optional) procedure is called with the new .Alternatively, the procedure can be called on the server object to return the latest available estimate.If the doesn't have an estimate yet, that procedure will return instead of an estimate. When the connection is lost, the (optional) thunk is called and will retry connecting.To close the current connection, if any, and stop reconnecting, the idempotent procedure can be called on the server object. The estimate object has a number of accessors: <\explain> )> <\explain> )> and possibly infinite.This is not necessarily an (inexact) , as it is only an estimate.> <\explain> > <\explain> )> > correction.This is a positive flonum, possibly zero or infinite.> Assuming the network size is stable and the errors on the logarithmic estimate are normally distributed, the procedure can be used to put probablistic error bounds on the number of peers on the network. TODO <\the-index|idx> > > > > > > > > > > > > > > > > > <\initial> <\collection>