gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet-go] branch master updated: Code and documentation changes based


From: gnunet
Subject: [gnunet-go] branch master updated: Code and documentation changes based on review feedback.
Date: Wed, 12 Feb 2020 18:06:22 +0100

This is an automated email from the git hooks/post-receive script.

bernd-fix pushed a commit to branch master
in repository gnunet-go.

The following commit(s) were added to refs/heads/master by this push:
     new 169fda0  Code and documentation changes based on review feedback.
169fda0 is described below

commit 169fda0a59d7e51a1b29985d12df3fcdb9584de9
Author: Bernd Fix <address@hidden>
AuthorDate: Wed Feb 12 18:01:12 2020 +0100

    Code and documentation changes based on review feedback.
---
 COPYING                                  |   1 +
 src/cmd/gnunet-service-gns-go/main.go    |  26 ++++-
 src/gnunet/config/config.go              |  39 ++++---
 src/gnunet/config/config_test.go         |  18 +++
 src/gnunet/config/gnunet-config.json     |   4 +-
 src/gnunet/core/peer.go                  |  18 +++
 src/gnunet/crypto/gns.go                 |  18 +++
 src/gnunet/crypto/gns_test.go            |  18 +++
 src/gnunet/crypto/hash.go                |  18 +++
 src/gnunet/crypto/key_derivation.go      |  18 +++
 src/gnunet/crypto/key_derivation_test.go |  18 +++
 src/gnunet/crypto/key_exchange.go        |  18 +++
 src/gnunet/crypto/key_exchange_test.go   |  18 +++
 src/gnunet/crypto/keys_test.go           |  18 +++
 src/gnunet/crypto/signature.go           |  18 +++
 src/gnunet/crypto/symmetric.go           |  18 +++
 src/gnunet/enums/dht.go                  |  18 +++
 src/gnunet/enums/gns.go                  |  18 +++
 src/gnunet/enums/signature.go            |  18 +++
 src/gnunet/go.mod                        |   6 +-
 src/gnunet/go.sum                        |  19 +++-
 src/gnunet/message/const.go              |  18 +++
 src/gnunet/message/factory.go            |  22 ++++
 src/gnunet/message/message.go            |  18 +++
 src/gnunet/message/msg_core.go           |  18 +++
 src/gnunet/message/msg_dht.go            |  18 +++
 src/gnunet/message/msg_gns.go            | 149 +++++++++++++++++++++++++
 src/gnunet/message/msg_namecache.go      | 100 +++++++++++++++++
 src/gnunet/message/msg_transport.go      |  18 +++
 src/gnunet/message/types.go              |  18 +++
 src/gnunet/modules.go                    |  18 +++
 src/gnunet/service/client.go             |  18 +++
 src/gnunet/service/gns/block.go          | 185 -------------------------------
 src/gnunet/service/gns/block_handler.go  |  48 +++++---
 src/gnunet/service/gns/box.go            |  18 +++
 src/gnunet/service/gns/dns.go            |  83 +++++++++++++-
 src/gnunet/service/gns/module.go         |  99 ++++++++++-------
 src/gnunet/service/gns/service.go        | 161 ++++++++++++++++++---------
 src/gnunet/service/namecache/module.go   |  23 +++-
 src/gnunet/service/service.go            |  32 +++++-
 src/gnunet/transport/channel.go          |  38 ++++++-
 src/gnunet/transport/channel_netw.go     |  18 +++
 src/gnunet/transport/channel_test.go     |  18 +++
 src/gnunet/transport/connection.go       |  18 +++
 src/gnunet/transport/session.go          |  18 +++
 src/gnunet/util/address.go               |  18 +++
 src/gnunet/util/array.go                 |  18 +++
 src/gnunet/util/base32.go                |  18 +++
 src/gnunet/util/base32_test.go           |  18 +++
 src/gnunet/util/format.go                |  18 +++
 src/gnunet/util/fs.go                    |  43 +++++++
 src/gnunet/util/id.go                    |  18 +++
 src/gnunet/util/misc.go                  |  18 +++
 src/gnunet/util/peer_id.go               |  18 +++
 src/gnunet/util/rnd.go                   |  18 +++
 src/gnunet/util/time.go                  |  18 +++
 56 files changed, 1431 insertions(+), 331 deletions(-)

diff --git a/COPYING b/COPYING
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/COPYING
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/src/cmd/gnunet-service-gns-go/main.go 
b/src/cmd/gnunet-service-gns-go/main.go
index cc9486f..5f4062a 100644
--- a/src/cmd/gnunet-service-gns-go/main.go
+++ b/src/cmd/gnunet-service-gns-go/main.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package main
 
 import (
@@ -14,7 +32,13 @@ import (
 )
 
 func main() {
+       defer func() {
+               logger.Println(logger.INFO, "[gns] Bye.")
+               // flush last messages
+               logger.Flush()
+       }()
        logger.Println(logger.INFO, "[gns] Starting service...")
+
        var (
                cfgFile  string
                srvEndp  string
@@ -76,6 +100,4 @@ loop:
 
        // terminating service
        srv.Stop()
-       // wait for logger to flush last messages
-       time.Sleep(5 * time.Second)
 }
diff --git a/src/gnunet/config/config.go b/src/gnunet/config/config.go
index eaadd98..01dadea 100644
--- a/src/gnunet/config/config.go
+++ b/src/gnunet/config/config.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package config
 
 import (
@@ -7,9 +25,6 @@ import (
        "regexp"
        "strings"
 
-       "gnunet/util"
-
-       "github.com/bfix/gospel/crypto/ed25519"
        "github.com/bfix/gospel/logger"
 )
 
@@ -18,21 +33,9 @@ import (
 
 // GNSConfig
 type GNSConfig struct {
-       Endpoint     string            `json:"endpoint"`     // end-point of 
GNS service
-       DHTReplLevel int               `json:"dhtReplLevel"` // DHT replication 
level
-       RootZones    map[string]string `json:"rootZones"`    // pre-configured 
root zones
-}
-
-// GetRootZoneKey returns the zone key (PKEY) for a pre-configured root with 
given name.
-func (gns *GNSConfig) GetRootZoneKey(name string) *ed25519.PublicKey {
-       // lookup key in the dictionary
-       if dStr, ok := gns.RootZones[name]; ok {
-               if data, err := util.DecodeStringToBinary(dStr, 32); err == nil 
{
-                       return ed25519.NewPublicKeyFromBytes(data)
-               }
-       }
-       // no pkey found.
-       return nil
+       Endpoint     string `json:"endpoint"`     // end-point of GNS service
+       DHTReplLevel int    `json:"dhtReplLevel"` // DHT replication level
+       MaxDepth     int    `json:"maxDepth"`     // maximum recursion depth in 
resolution
 }
 
 ///////////////////////////////////////////////////////////////////////
diff --git a/src/gnunet/config/config_test.go b/src/gnunet/config/config_test.go
index ec35d08..3afd3a7 100644
--- a/src/gnunet/config/config_test.go
+++ b/src/gnunet/config/config_test.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package config
 
 import (
diff --git a/src/gnunet/config/gnunet-config.json 
b/src/gnunet/config/gnunet-config.json
index 13bbe7c..d6670c4 100644
--- a/src/gnunet/config/gnunet-config.json
+++ b/src/gnunet/config/gnunet-config.json
@@ -9,9 +9,7 @@
        "gns": {
                "endpoint": 
"unix+${RT_SYS}/gnunet-service-gns-go.sock+perm=0770",
                "dhtReplLevel": 10,
-               "rootZones": {
-                       "home": 
"ACAB23DC3SEECJORPHQNVRH965A6N74B1M37S721IG4RBQ15PJLL"
-               }
+               "maxDepth": 250
        },
        "namecache": {
                "endpoint": "unix+${RT_SYS}/gnunet-service-namecache.sock"
diff --git a/src/gnunet/core/peer.go b/src/gnunet/core/peer.go
index d0b3a4c..f81bab8 100644
--- a/src/gnunet/core/peer.go
+++ b/src/gnunet/core/peer.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package core
 
 import (
diff --git a/src/gnunet/crypto/gns.go b/src/gnunet/crypto/gns.go
index c6a8cd6..8b33057 100644
--- a/src/gnunet/crypto/gns.go
+++ b/src/gnunet/crypto/gns.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/gns_test.go b/src/gnunet/crypto/gns_test.go
index e0b9bf3..ae39a2b 100644
--- a/src/gnunet/crypto/gns_test.go
+++ b/src/gnunet/crypto/gns_test.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/hash.go b/src/gnunet/crypto/hash.go
index 0fe7c7e..bc715d4 100644
--- a/src/gnunet/crypto/hash.go
+++ b/src/gnunet/crypto/hash.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/key_derivation.go 
b/src/gnunet/crypto/key_derivation.go
index 976db2a..1481f70 100644
--- a/src/gnunet/crypto/key_derivation.go
+++ b/src/gnunet/crypto/key_derivation.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/key_derivation_test.go 
b/src/gnunet/crypto/key_derivation_test.go
index ee9a57c..4692c19 100644
--- a/src/gnunet/crypto/key_derivation_test.go
+++ b/src/gnunet/crypto/key_derivation_test.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/key_exchange.go 
b/src/gnunet/crypto/key_exchange.go
index 1403249..5ff51ea 100644
--- a/src/gnunet/crypto/key_exchange.go
+++ b/src/gnunet/crypto/key_exchange.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/key_exchange_test.go 
b/src/gnunet/crypto/key_exchange_test.go
index 93e95a2..3696cae 100644
--- a/src/gnunet/crypto/key_exchange_test.go
+++ b/src/gnunet/crypto/key_exchange_test.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/keys_test.go b/src/gnunet/crypto/keys_test.go
index 69d70ca..8dae1f1 100644
--- a/src/gnunet/crypto/keys_test.go
+++ b/src/gnunet/crypto/keys_test.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/crypto/signature.go b/src/gnunet/crypto/signature.go
index ba8e535..ca4c4a3 100644
--- a/src/gnunet/crypto/signature.go
+++ b/src/gnunet/crypto/signature.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 // SignaturePurpose is the GNUnet data structure used as header for signed 
data.
diff --git a/src/gnunet/crypto/symmetric.go b/src/gnunet/crypto/symmetric.go
index 5607d3a..c217c6d 100644
--- a/src/gnunet/crypto/symmetric.go
+++ b/src/gnunet/crypto/symmetric.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package crypto
 
 import (
diff --git a/src/gnunet/enums/dht.go b/src/gnunet/enums/dht.go
index 8f004d7..06a43d5 100644
--- a/src/gnunet/enums/dht.go
+++ b/src/gnunet/enums/dht.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package enums
 
 // DHT flags and settings
diff --git a/src/gnunet/enums/gns.go b/src/gnunet/enums/gns.go
index 1d45fff..b9adfc2 100644
--- a/src/gnunet/enums/gns.go
+++ b/src/gnunet/enums/gns.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package enums
 
 // GNS constants
diff --git a/src/gnunet/enums/signature.go b/src/gnunet/enums/signature.go
index cb60f65..82b00bd 100644
--- a/src/gnunet/enums/signature.go
+++ b/src/gnunet/enums/signature.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package enums
 
 // Signature purpose constants
diff --git a/src/gnunet/go.mod b/src/gnunet/go.mod
index fce27da..83720fd 100644
--- a/src/gnunet/go.mod
+++ b/src/gnunet/go.mod
@@ -2,4 +2,8 @@ module gnunet
 
 go 1.12
 
-require github.com/bfix/gospel v0.0.0-20190831192707-26682cc943e5
+require (
+       github.com/bfix/gospel v0.0.0-20190922182041-6fcd6d4fd449
+       github.com/miekg/dns v1.1.26
+       golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392
+)
diff --git a/src/gnunet/go.sum b/src/gnunet/go.sum
index e1de475..e9ece97 100644
--- a/src/gnunet/go.sum
+++ b/src/gnunet/go.sum
@@ -1,10 +1,25 @@
-github.com/bfix/gospel v0.0.0-20190831192707-26682cc943e5 
h1:vPrWvbQmjjEaWseuni9K7ffKzYLBLPbK27oHw5DvTAY=
-github.com/bfix/gospel v0.0.0-20190831192707-26682cc943e5/go.mod 
h1:RQYETFV9SP+VriIsHVqCntRpSbbRvCBnNTtbUl9NAKA=
+github.com/bfix/gospel v0.0.0-20190922182041-6fcd6d4fd449 
h1:oIq3s14sMh1sq791v9VpR+GJvhVGbvuOWlfTjruRTDQ=
+github.com/bfix/gospel v0.0.0-20190922182041-6fcd6d4fd449/go.mod 
h1:RQYETFV9SP+VriIsHVqCntRpSbbRvCBnNTtbUl9NAKA=
+github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU=
+github.com/miekg/dns v1.1.26/go.mod 
h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 
h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
 golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 
h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod 
h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478 
h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 
h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe 
h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/src/gnunet/message/const.go b/src/gnunet/message/const.go
index 245af80..b706478 100644
--- a/src/gnunet/message/const.go
+++ b/src/gnunet/message/const.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
diff --git a/src/gnunet/message/factory.go b/src/gnunet/message/factory.go
index 5f599b7..f6a8783 100644
--- a/src/gnunet/message/factory.go
+++ b/src/gnunet/message/factory.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
@@ -59,6 +77,10 @@ func NewEmptyMessage(msgType uint16) (Message, error) {
                return NewNamecacheLookupMsg(nil), nil
        case NAMECACHE_LOOKUP_BLOCK_RESPONSE:
                return NewNamecacheLookupResultMsg(), nil
+       case NAMECACHE_BLOCK_CACHE:
+               return NewNamecacheCacheMsg(nil), nil
+       case NAMECACHE_BLOCK_CACHE_RESPONSE:
+               return NewNamecacheCacheResponseMsg(), nil
        }
        return nil, errors.New(fmt.Sprintf("Unknown message type %d", msgType))
 }
diff --git a/src/gnunet/message/message.go b/src/gnunet/message/message.go
index e792ae8..fb9b4b0 100644
--- a/src/gnunet/message/message.go
+++ b/src/gnunet/message/message.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
diff --git a/src/gnunet/message/msg_core.go b/src/gnunet/message/msg_core.go
index 538fcea..d6d427b 100644
--- a/src/gnunet/message/msg_core.go
+++ b/src/gnunet/message/msg_core.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
diff --git a/src/gnunet/message/msg_dht.go b/src/gnunet/message/msg_dht.go
index b1d28ba..925cb71 100644
--- a/src/gnunet/message/msg_dht.go
+++ b/src/gnunet/message/msg_dht.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
diff --git a/src/gnunet/message/msg_gns.go b/src/gnunet/message/msg_gns.go
index b01c410..fb84502 100644
--- a/src/gnunet/message/msg_gns.go
+++ b/src/gnunet/message/msg_gns.go
@@ -1,14 +1,39 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
        "fmt"
 
+       "gnunet/crypto"
        "gnunet/enums"
        "gnunet/util"
 
+       "github.com/bfix/gospel/crypto/ed25519"
+       "github.com/bfix/gospel/data"
        "github.com/bfix/gospel/logger"
 )
 
+var (
+       ErrBlockNotDecrypted = fmt.Errorf("GNS block not decrypted")
+)
+
 //----------------------------------------------------------------------
 // GNS_LOOKUP
 //----------------------------------------------------------------------
@@ -73,6 +98,130 @@ func (msg *GNSLookupMsg) Header() *MessageHeader {
 // GNS_LOOKUP_RESULT
 //----------------------------------------------------------------------
 
+// GNSRecordSet ist the GNUnet data structure for a list of resource records
+// in a GNSBlock. As part of GNUnet messages, the record set is padded so that
+// the binary size of (records||padding) is the smallest power of two.
+type GNSRecordSet struct {
+       Count   uint32               `order:"big"`  // number of resource 
records
+       Records []*GNSResourceRecord `size:"Count"` // list of resource records
+       Padding []byte               `size:"*"`     // padding
+}
+
+// NewGNSRecordSet returns an empty resource record set.
+func NewGNSRecordSet() *GNSRecordSet {
+       return &GNSRecordSet{
+               Count:   0,
+               Records: make([]*GNSResourceRecord, 0),
+               Padding: make([]byte, 0),
+       }
+}
+
+// AddRecord to append a resource record to the set.
+func (rs *GNSRecordSet) AddRecord(rec *GNSResourceRecord) {
+       rs.Count++
+       rs.Records = append(rs.Records, rec)
+}
+
+// SignedBlockData: signed and encrypted list of resource records stored
+// in a GNSRecordSet
+type SignedBlockData struct {
+       Purpose *crypto.SignaturePurpose // Size and purpose of signature (8 
bytes)
+       Expire  util.AbsoluteTime        // Expiration time of the block.
+       EncData []byte                   `size:"*"` // encrypted GNSRecordSet
+
+       // transient data (not serialized)
+       data []byte // decrypted GNSRecord set
+}
+
+// GNSBlock is the result of GNS lookups for a given label in a zone.
+// An encrypted and signed container for GNS resource records that represents
+// the "atomic" data structure associated with a GNS label in a given zone.
+type GNSBlock struct {
+       Signature  []byte `size:"64"` // Signature of the block.
+       DerivedKey []byte `size:"32"` // Derived key used for signing
+       Block      *SignedBlockData
+
+       // transient data (not serialized)
+       checked   bool // block integrity checked
+       verified  bool // block signature verified (internal)
+       decrypted bool // block data decrypted (internal)
+}
+
+// String returns the human-readable representation of a GNSBlock
+func (b *GNSBlock) String() string {
+       return fmt.Sprintf("GNSBlock{Verified=%v,Decrypted=%v,data=[%d]}",
+               b.verified, b.decrypted, len(b.Block.EncData))
+}
+
+// Records returns the list of resource records in a block.
+func (b *GNSBlock) Records() ([]*GNSResourceRecord, error) {
+       // check if block is decrypted
+       if !b.decrypted {
+               return nil, ErrBlockNotDecrypted
+       }
+       // parse block data into record set
+       rs := NewGNSRecordSet()
+       if err := data.Unmarshal(rs, b.Block.data); err != nil {
+               return nil, err
+       }
+       return rs.Records, nil
+}
+
+// Verify the integrity of the block data from a signature.
+func (b *GNSBlock) Verify(zoneKey *ed25519.PublicKey, label string) (err 
error) {
+       // Integrity check performed
+       b.checked = true
+
+       // verify derived key
+       dkey := ed25519.NewPublicKeyFromBytes(b.DerivedKey)
+       dkey2 := crypto.DerivePublicKey(zoneKey, label, "gns")
+       if !dkey.Q.Equals(dkey2.Q) {
+               return fmt.Errorf("Invalid signature key for GNS Block")
+       }
+       // verify signature
+       var (
+               sig *ed25519.EcSignature
+               buf []byte
+               ok  bool
+       )
+       if sig, err = ed25519.NewEcSignatureFromBytes(b.Signature); err != nil {
+               return
+       }
+       if buf, err = data.Marshal(b.Block); err != nil {
+               return
+       }
+       if ok, err = dkey.EcVerify(buf, sig); err == nil && !ok {
+               err = fmt.Errorf("Signature verification failed for GNS block")
+       }
+       b.verified = true
+       return
+}
+
+// Decrypt block data with a key/iv combination derived from (PKEY,label)
+func (b *GNSBlock) Decrypt(zoneKey *ed25519.PublicKey, label string) (err 
error) {
+       // decrypt payload
+       b.Block.data, err = crypto.DecryptBlock(b.Block.EncData, zoneKey, label)
+       b.decrypted = true
+       return
+}
+
+// NewGNSBlock instantiates an empty GNS block
+func NewGNSBlock() *GNSBlock {
+       return &GNSBlock{
+               Signature:  make([]byte, 64),
+               DerivedKey: make([]byte, 32),
+               Block: &SignedBlockData{
+                       Purpose: new(crypto.SignaturePurpose),
+                       Expire:  *new(util.AbsoluteTime),
+                       EncData: nil,
+                       data:    nil,
+               },
+               checked:   false,
+               verified:  false,
+               decrypted: false,
+       }
+}
+
 // GNSResourceRecord is the GNUnet-specific representation of resource
 // records (not to be confused with DNS resource records).
 type GNSResourceRecord struct {
diff --git a/src/gnunet/message/msg_namecache.go 
b/src/gnunet/message/msg_namecache.go
index 9e3312d..1f69eed 100644
--- a/src/gnunet/message/msg_namecache.go
+++ b/src/gnunet/message/msg_namecache.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
@@ -82,3 +100,85 @@ func (m *NamecacheLookupResultMsg) String() string {
 func (msg *NamecacheLookupResultMsg) Header() *MessageHeader {
        return &MessageHeader{msg.MsgSize, msg.MsgType}
 }
+
+//----------------------------------------------------------------------
+// NAMECACHE_CACHE_BLOCK
+//----------------------------------------------------------------------
+
+// NamecacheCacheMsg
+type NamecacheCacheMsg struct {
+       MsgSize    uint16            `order:"big"` // total size of message
+       MsgType    uint16            `order:"big"` // NAMECACHE_CACHE_BLOCK 
(433)
+       Id         uint32            `order:"big"` // Request Id
+       Expire     util.AbsoluteTime // Expiration time
+       Signature  []byte            `size:"64"` // ECDSA signature
+       DerivedKey []byte            `size:"32"` // Derived public key
+       EncData    []byte            `size:"*"`  // Encrypted block data
+}
+
+// NewNamecacheLookupMsg creates a new default message.
+func NewNamecacheCacheMsg(block *GNSBlock) *NamecacheCacheMsg {
+       msg := &NamecacheCacheMsg{
+               MsgSize:    108,
+               MsgType:    NAMECACHE_BLOCK_CACHE,
+               Id:         0,
+               Expire:     *new(util.AbsoluteTime),
+               Signature:  make([]byte, 64),
+               DerivedKey: make([]byte, 32),
+               EncData:    make([]byte, 0),
+       }
+       if block != nil {
+               msg.Expire = block.Block.Expire
+               copy(msg.Signature, block.Signature)
+               copy(msg.DerivedKey, block.DerivedKey)
+               size := len(block.Block.EncData)
+               msg.EncData = make([]byte, size)
+               copy(msg.EncData, block.Block.EncData)
+               msg.MsgSize += uint16(size)
+       }
+       return msg
+}
+
+// String returns a human-readable representation of the message.
+func (m *NamecacheCacheMsg) String() string {
+       return fmt.Sprintf("NewNamecacheCacheMsg{id=%d,expire=%s}",
+               m.Id, m.Expire)
+}
+
+// Header returns the message header in a separate instance.
+func (msg *NamecacheCacheMsg) Header() *MessageHeader {
+       return &MessageHeader{msg.MsgSize, msg.MsgType}
+}
+
+//----------------------------------------------------------------------
+// NAMECACHE_BLOCK_CACHE_RESPONSE
+//----------------------------------------------------------------------
+
+// NamecacheCacheResponseMsg
+type NamecacheCacheResponseMsg struct {
+       MsgSize uint16 `order:"big"` // total size of message
+       MsgType uint16 `order:"big"` // NAMECACHE_LOOKUP_BLOCK_RESPONSE (432)
+       Id      uint32 `order:"big"` // Request Id
+       Result  int32  `order:"big"` // Result code
+}
+
+// NewNamecacheCacheResponseMsg creates a new default message.
+func NewNamecacheCacheResponseMsg() *NamecacheCacheResponseMsg {
+       return &NamecacheCacheResponseMsg{
+               MsgSize: 12,
+               MsgType: NAMECACHE_BLOCK_CACHE_RESPONSE,
+               Id:      0,
+               Result:  0,
+       }
+}
+
+// String returns a human-readable representation of the message.
+func (m *NamecacheCacheResponseMsg) String() string {
+       return fmt.Sprintf("NamecacheCacheResponseMsg{id=%d,result=%d}",
+               m.Id, m.Result)
+}
+
+// Header returns the message header in a separate instance.
+func (msg *NamecacheCacheResponseMsg) Header() *MessageHeader {
+       return &MessageHeader{msg.MsgSize, msg.MsgType}
+}
diff --git a/src/gnunet/message/msg_transport.go 
b/src/gnunet/message/msg_transport.go
index 54e63f2..b2e4346 100644
--- a/src/gnunet/message/msg_transport.go
+++ b/src/gnunet/message/msg_transport.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 import (
diff --git a/src/gnunet/message/types.go b/src/gnunet/message/types.go
index e3ab9b4..31504c0 100644
--- a/src/gnunet/message/types.go
+++ b/src/gnunet/message/types.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package message
 
 // GNUnet message types
diff --git a/src/gnunet/modules.go b/src/gnunet/modules.go
index bbb2563..bc2993e 100644
--- a/src/gnunet/modules.go
+++ b/src/gnunet/modules.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 //======================================================================
 // Standalone (all-in-one) implementation of GNUnet:
 // -------------------------------------------------
diff --git a/src/gnunet/service/client.go b/src/gnunet/service/client.go
index 3bae7da..1e54c2d 100644
--- a/src/gnunet/service/client.go
+++ b/src/gnunet/service/client.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package service
 
 import (
diff --git a/src/gnunet/service/gns/block.go b/src/gnunet/service/gns/block.go
deleted file mode 100644
index 9d83f99..0000000
--- a/src/gnunet/service/gns/block.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package gns
-
-import (
-       "fmt"
-
-       "gnunet/crypto"
-       "gnunet/enums"
-       "gnunet/message"
-       "gnunet/util"
-
-       "github.com/bfix/gospel/crypto/ed25519"
-       "github.com/bfix/gospel/data"
-)
-
-var (
-       ErrBlockNotDecrypted = fmt.Errorf("GNS block not decrypted")
-)
-
-//======================================================================
-// GNS block: An encrypted and signed container for GNS resource records
-// that represents the "atomic" data structure associated with a GNS
-// label in a given zone.
-//======================================================================
-
-// SignedBlockData: signed and encrypted list of resource records stored
-// in a GNSRecordSet
-type SignedBlockData struct {
-       Purpose *crypto.SignaturePurpose // Size and purpose of signature (8 
bytes)
-       Expire  util.AbsoluteTime        // Expiration time of the block.
-       EncData []byte                   `size:"*"` // encrypted GNSRecordSet
-
-       // transient data (not serialized)
-       data []byte // unencrypted GNSRecord set
-}
-
-// GNSBlock is the result of GNS lookups for a given label in a zone.
-type GNSBlock struct {
-       Signature  []byte `size:"64"` // Signature of the block.
-       DerivedKey []byte `size:"32"` // Derived key used for signing
-       Block      *SignedBlockData
-
-       // transient data (not serialized)
-       checked   bool // block integrity checked
-       verified  bool // block signature verified (internal)
-       decrypted bool // block data decrypted (internal)
-}
-
-// String returns the human-readable representation of a GNSBlock
-func (b *GNSBlock) String() string {
-       return fmt.Sprintf("GNSBlock{Verified=%v,Decrypted=%v,data=[%d]}",
-               b.verified, b.decrypted, len(b.Block.EncData))
-}
-
-// Records returns the list of resource records in a block.
-func (b *GNSBlock) Records() ([]*message.GNSResourceRecord, error) {
-       // check if block is decrypted
-       if !b.decrypted {
-               return nil, ErrBlockNotDecrypted
-       }
-       // parse block data into record set
-       rs := NewGNSRecordSet()
-       if err := data.Unmarshal(rs, b.Block.data); err != nil {
-               return nil, err
-       }
-       return rs.Records, nil
-}
-
-// Verify the integrity of the block data from a signature.
-func (b *GNSBlock) Verify(zoneKey *ed25519.PublicKey, label string) (err 
error) {
-       // Integrity check performed
-       b.checked = true
-
-       // verify derived key
-       dkey := ed25519.NewPublicKeyFromBytes(b.DerivedKey)
-       dkey2 := crypto.DerivePublicKey(zoneKey, label, "gns")
-       if !dkey.Q.Equals(dkey2.Q) {
-               return fmt.Errorf("Invalid signature key for GNS Block")
-       }
-       // verify signature
-       var (
-               sig *ed25519.EcSignature
-               buf []byte
-               ok  bool
-       )
-       if sig, err = ed25519.NewEcSignatureFromBytes(b.Signature); err != nil {
-               return
-       }
-       if buf, err = data.Marshal(b.Block); err != nil {
-               return
-       }
-       if ok, err = dkey.EcVerify(buf, sig); err == nil && !ok {
-               err = fmt.Errorf("Signature verification failed for GNS block")
-       }
-       b.verified = true
-       return
-}
-
-// Decrypt block data with a key/iv combination derived from (PKEY,label)
-func (b *GNSBlock) Decrypt(zoneKey *ed25519.PublicKey, label string) (err 
error) {
-       // decrypt payload
-       b.Block.data, err = crypto.DecryptBlock(b.Block.EncData, zoneKey, label)
-       b.decrypted = true
-       return
-}
-
-// NewGNSBlock instantiates an empty GNS block
-func NewGNSBlock() *GNSBlock {
-       return &GNSBlock{
-               Signature:  make([]byte, 64),
-               DerivedKey: make([]byte, 32),
-               Block: &SignedBlockData{
-                       Purpose: new(crypto.SignaturePurpose),
-                       Expire:  *new(util.AbsoluteTime),
-                       EncData: nil,
-                       data:    nil,
-               },
-               checked:   false,
-               verified:  false,
-               decrypted: false,
-       }
-}
-
-//----------------------------------------------------------------------
-// GNSRecordSet
-//----------------------------------------------------------------------
-
-// GNSRecordSet ist the GNUnet data structure for a list of resource records
-// in a GNSBlock. As part of GNUnet messages, the record set is padded so that
-// the binary size of (records||padding) is the smallest power of two.
-type GNSRecordSet struct {
-       Count   uint32                       `order:"big"`  // number of 
resource records
-       Records []*message.GNSResourceRecord `size:"Count"` // list of resource 
records
-       Padding []byte                       `size:"*"`     // padding
-}
-
-// NewGNSRecordSet returns an empty resource record set.
-func NewGNSRecordSet() *GNSRecordSet {
-       return &GNSRecordSet{
-               Count:   0,
-               Records: make([]*message.GNSResourceRecord, 0),
-               Padding: make([]byte, 0),
-       }
-}
-
-// AddRecord to append a resource record to the set.
-func (rs *GNSRecordSet) AddRecord(rec *message.GNSResourceRecord) {
-       rs.Count++
-       rs.Records = append(rs.Records, rec)
-}
-
-//======================================================================
-// List of resource records types (for GNS/DNS queries)
-//======================================================================
-
-// RRTypeList is a list of integers representing RR types.
-type RRTypeList []int
-
-// Initialize a new type list with given type values
-func NewRRTypeList(args ...int) (res RRTypeList) {
-       for _, val := range args {
-               // if GNS_TYPE_ANY is encountered, it becomes the sole type
-               if val == enums.GNS_TYPE_ANY {
-                       res = make(RRTypeList, 1)
-                       res[0] = val
-                       return
-               }
-               res = append(res, val)
-       }
-       return
-}
-
-// HasType returns true if the type is included in the list
-func (tl RRTypeList) HasType(t int) bool {
-       // return true if type is GNS_TYPE_ANY
-       if tl[0] == enums.GNS_TYPE_ANY {
-               return true
-       }
-       // check for type in list
-       for _, val := range tl {
-               if val == t {
-                       return true
-               }
-       }
-       return false
-}
diff --git a/src/gnunet/service/gns/block_handler.go 
b/src/gnunet/service/gns/block_handler.go
index c3372f2..1b04bc6 100644
--- a/src/gnunet/service/gns/block_handler.go
+++ b/src/gnunet/service/gns/block_handler.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package gns
 
 import (
@@ -61,7 +79,7 @@ type BlockHandler interface {
 
        // Records returns a list of RR of the given types associated with
        // the custom handler
-       Records(kind RRTypeList) *GNSRecordSet
+       Records(kind RRTypeList) *message.GNSRecordSet
 
        // Name returns the human-readable name of the handler
        Name() string
@@ -236,8 +254,8 @@ func (h *PkeyHandler) Coexist(cm util.CounterMap) bool {
 }
 
 // Records returns a list of RR of the given type associated with this handler
-func (h *PkeyHandler) Records(kind RRTypeList) *GNSRecordSet {
-       rs := NewGNSRecordSet()
+func (h *PkeyHandler) Records(kind RRTypeList) *message.GNSRecordSet {
+       rs := message.NewGNSRecordSet()
        if kind.HasType(enums.GNS_TYPE_PKEY) {
                rs.AddRecord(h.rec)
        }
@@ -311,8 +329,8 @@ func (h *Gns2DnsHandler) Coexist(cm util.CounterMap) bool {
 }
 
 // Records returns a list of RR of the given type associated with this handler
-func (h *Gns2DnsHandler) Records(kind RRTypeList) *GNSRecordSet {
-       rs := NewGNSRecordSet()
+func (h *Gns2DnsHandler) Records(kind RRTypeList) *message.GNSRecordSet {
+       rs := message.NewGNSRecordSet()
        if kind.HasType(enums.GNS_TYPE_GNS2DNS) {
                for _, rec := range h.recs {
                        rs.AddRecord(rec)
@@ -381,8 +399,8 @@ func (h *BoxHandler) Coexist(cm util.CounterMap) bool {
 }
 
 // Records returns a list of RR of the given type associated with this handler
-func (h *BoxHandler) Records(kind RRTypeList) *GNSRecordSet {
-       rs := NewGNSRecordSet()
+func (h *BoxHandler) Records(kind RRTypeList) *message.GNSRecordSet {
+       rs := message.NewGNSRecordSet()
        for _, box := range h.boxes {
                if kind.HasType(int(box.Type)) {
                        // valid box found: assemble new resource record.
@@ -451,8 +469,8 @@ func (h *LehoHandler) Coexist(cm util.CounterMap) bool {
 }
 
 // Records returns a list of RR of the given type associated with this handler
-func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet {
-       rs := NewGNSRecordSet()
+func (h *LehoHandler) Records(kind RRTypeList) *message.GNSRecordSet {
+       rs := message.NewGNSRecordSet()
        if kind.HasType(enums.GNS_TYPE_LEHO) {
                rs.AddRecord(h.rec)
        }
@@ -504,13 +522,13 @@ func (h *CnameHandler) AddRecord(rec 
*message.GNSResourceRecord, labels []string
 // Coexist return a flag indicating how a resource record of a given type
 // is to be treated (see BlockHandler interface)
 func (h *CnameHandler) Coexist(cm util.CounterMap) bool {
-       // anything goes
-       return true
+       // only a single CNAME allowed
+       return len(cm) == 1 && cm.Num(enums.GNS_TYPE_DNS_CNAME) == 1
 }
 
 // Records returns a list of RR of the given type associated with this handler
-func (h *CnameHandler) Records(kind RRTypeList) *GNSRecordSet {
-       rs := NewGNSRecordSet()
+func (h *CnameHandler) Records(kind RRTypeList) *message.GNSRecordSet {
+       rs := message.NewGNSRecordSet()
        if kind.HasType(enums.GNS_TYPE_DNS_CNAME) {
                rs.AddRecord(h.rec)
        }
@@ -563,8 +581,8 @@ func (h *VpnHandler) Coexist(cm util.CounterMap) bool {
 }
 
 // Records returns a list of RR of the given type associated with this handler
-func (h *VpnHandler) Records(kind RRTypeList) *GNSRecordSet {
-       rs := NewGNSRecordSet()
+func (h *VpnHandler) Records(kind RRTypeList) *message.GNSRecordSet {
+       rs := message.NewGNSRecordSet()
        if kind.HasType(enums.GNS_TYPE_VPN) {
                rs.AddRecord(h.rec)
        }
diff --git a/src/gnunet/service/gns/box.go b/src/gnunet/service/gns/box.go
index e2d3609..306ca68 100644
--- a/src/gnunet/service/gns/box.go
+++ b/src/gnunet/service/gns/box.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package gns
 
 import (
diff --git a/src/gnunet/service/gns/dns.go b/src/gnunet/service/gns/dns.go
index 18e2b78..28e9813 100644
--- a/src/gnunet/service/gns/dns.go
+++ b/src/gnunet/service/gns/dns.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package gns
 
 import (
@@ -22,6 +40,57 @@ var (
        ErrNoDNSResults = fmt.Errorf("No valid DNS results")
 )
 
+//----------------------------------------------------------------------
+// List of resource records types (for GNS/DNS queries)
+//----------------------------------------------------------------------
+
+// RRTypeList is a list of integers representing RR types.
+type RRTypeList []int
+
+// Initialize a new type list with given type values
+func NewRRTypeList(args ...int) (res RRTypeList) {
+       for _, val := range args {
+               // if GNS_TYPE_ANY is encountered, it becomes the sole type
+               if val == enums.GNS_TYPE_ANY {
+                       res = make(RRTypeList, 1)
+                       res[0] = val
+                       return
+               }
+               res = append(res, val)
+       }
+       // if no types are passed, mode ANY is set.
+       if len(res) == 0 {
+               res = make(RRTypeList, 1)
+               res[0] = enums.GNS_TYPE_ANY
+               return
+       }
+       return
+}
+
+// IsAny returns true if no type is filtered.
+func (tl RRTypeList) IsAny() bool {
+       return tl[0] == enums.GNS_TYPE_ANY
+}
+
+// HasType returns true if the type is included in the list
+func (tl RRTypeList) HasType(t int) bool {
+       // return true if type is GNS_TYPE_ANY
+       if tl[0] == enums.GNS_TYPE_ANY {
+               return true
+       }
+       // check for type in list
+       for _, val := range tl {
+               if val == t {
+                       return true
+               }
+       }
+       return false
+}
+
+//----------------------------------------------------------------------
+// Helper functions
+//----------------------------------------------------------------------
+
 // Convert DNS name from its binary representation [RFC1034]:
 // A string is a sequence of a (len,chars...) tupels terminated by a (len=0,).
 // The name parts are concatenated with "." as separator.
@@ -45,7 +114,7 @@ func DNSNameFromBytes(b []byte, offset int) (int, string) {
        return pos + 1, str
 }
 
-func QueryDNS(id int, name string, server net.IP, kind RRTypeList) 
*GNSRecordSet {
+func QueryDNS(id int, name string, server net.IP, kind RRTypeList) 
*message.GNSRecordSet {
        // get default nameserver if not defined.
        if server == nil {
                server = net.IPv4(8, 8, 8, 8)
@@ -90,7 +159,7 @@ func QueryDNS(id int, name string, server net.IP, kind 
RRTypeList) *GNSRecordSet
                        logger.Printf(logger.ERROR, "[dns][%d] No results\n", 
id)
                        return nil
                }
-               set := NewGNSRecordSet()
+               set := message.NewGNSRecordSet()
                for _, record := range in.Answer {
                        // check if answer record is of requested type
                        if kind.HasType(int(record.Header().Rrtype)) {
@@ -126,14 +195,18 @@ func QueryDNS(id int, name string, server net.IP, kind 
RRTypeList) *GNSRecordSet
        return nil
 }
 
+//----------------------------------------------------------------------
+// GNSModule methods
+//----------------------------------------------------------------------
+
 // ResolveDNS resolves a name in DNS. Multiple DNS servers are queried in
 // parallel; the first result delivered by any of the servers is returned
 // as the result list of matching resource records.
-func (gns *GNSModule) ResolveDNS(name string, servers []string, kind 
RRTypeList, pkey *ed25519.PublicKey) (set *GNSRecordSet, err error) {
+func (gns *GNSModule) ResolveDNS(name string, servers []string, kind 
RRTypeList, pkey *ed25519.PublicKey, depth int) (set *message.GNSRecordSet, err 
error) {
        logger.Printf(logger.DBG, "[dns] Resolution of '%s' starting...\n", 
name)
 
        // start DNS queries concurrently
-       res := make(chan *GNSRecordSet)
+       res := make(chan *message.GNSRecordSet)
        running := 0
        for _, srv := range servers {
                // check if srv is an IPv4/IPv6 address
@@ -142,7 +215,7 @@ func (gns *GNSModule) ResolveDNS(name string, servers 
[]string, kind RRTypeList,
                if addr == nil {
                        // no, it is a name... try to resolve an IP address 
from the name
                        query := NewRRTypeList(enums.GNS_TYPE_DNS_A, 
enums.GNS_TYPE_DNS_AAAA)
-                       if set, err = gns.ResolveUnknown(srv, pkey, query); err 
!= nil {
+                       if set, err = gns.ResolveUnknown(srv, nil, pkey, query, 
depth+1); err != nil {
                                logger.Printf(logger.ERROR, "[dns] Can't 
resolve NS server '%s': %s\n", srv, err.Error())
                                continue
                        }
diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go
index b5583ac..5626432 100644
--- a/src/gnunet/service/gns/module.go
+++ b/src/gnunet/service/gns/module.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package gns
 
 import (
@@ -20,7 +38,8 @@ import (
 
 // Error codes
 var (
-       ErrUnknownTLD = fmt.Errorf("Unknown TLD in name")
+       ErrUnknownTLD           = fmt.Errorf("Unknown TLD in name")
+       ErrGNSRecursionExceeded = fmt.Errorf("GNS recursion depth exceeded")
 )
 
 //----------------------------------------------------------------------
@@ -92,15 +111,18 @@ func NewQuery(pkey *ed25519.PublicKey, label string) 
*Query {
 type GNSModule struct {
        // Use function references for calls to methods in other modules:
        //
-       LookupLocal  func(query *Query) (*GNSBlock, error)
-       StoreLocal   func(query *Query, block *GNSBlock) error
-       LookupRemote func(query *Query) (*GNSBlock, error)
-       GetLocalZone func(name string) (*ed25519.PublicKey, error)
+       LookupLocal  func(query *Query) (*message.GNSBlock, error)
+       StoreLocal   func(block *message.GNSBlock) error
+       LookupRemote func(query *Query) (*message.GNSBlock, error)
 }
 
 // Resolve a GNS name with multiple labels. If pkey is not nil, the name
 // is interpreted as "relative to current zone".
-func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind 
RRTypeList, mode int) (set *GNSRecordSet, err error) {
+func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind 
RRTypeList, mode int, depth int) (set *message.GNSRecordSet, err error) {
+       // check for recursion depth
+       if depth > config.Cfg.GNS.MaxDepth {
+               return nil, ErrGNSRecursionExceeded
+       }
        // get the labels in reverse order
        names := util.ReverseStringList(strings.Split(path, "."))
        logger.Printf(logger.DBG, "[gns] Resolver called for %v\n", names)
@@ -108,39 +130,28 @@ func (gns *GNSModule) Resolve(path string, pkey 
*ed25519.PublicKey, kind RRTypeL
        // check for relative path
        if pkey != nil {
                //resolve relative path
-               return gns.ResolveRelative(names, pkey, kind, mode)
+               return gns.ResolveRelative(names, pkey, kind, mode, depth)
        }
        // resolve absolute path
-       return gns.ResolveAbsolute(names, kind, mode)
+       return gns.ResolveAbsolute(names, kind, mode, depth)
 }
 
 // Resolve a fully qualified GNS absolute name (with multiple labels).
-func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode 
int) (set *GNSRecordSet, err error) {
+func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode 
int, depth int) (set *message.GNSRecordSet, err error) {
        // get the zone key for the TLD
-       // (1) check if TLD is a PKEY
        pkey := gns.GetZoneKey(labels[0])
        if pkey == nil {
-               // (2) check if TLD is in our local config
-               pkey = config.Cfg.GNS.GetRootZoneKey(labels[0])
-       }
-       if pkey == nil {
-               // (3) check if TLD is one of our identities
-               pkey, err = gns.GetLocalZone(labels[0])
-       }
-       if pkey == nil {
-               if err == nil {
-                       err = ErrUnknownTLD
-               }
-               // (4) we can't resolve this TLD
+               // we can't resolve this TLD
+               err = ErrUnknownTLD
                return
        }
        // continue with resolution relative to a zone.
-       return gns.ResolveRelative(labels[1:], pkey, kind, mode)
+       return gns.ResolveRelative(labels[1:], pkey, kind, mode, depth)
 }
 
 // Resolve relative path (to a given zone) recursively by processing simple
 // (PKEY,Label) lookups in sequence and handle intermediate GNS record types
-func (gns *GNSModule) ResolveRelative(labels []string, pkey 
*ed25519.PublicKey, kind RRTypeList, mode int) (set *GNSRecordSet, err error) {
+func (gns *GNSModule) ResolveRelative(labels []string, pkey 
*ed25519.PublicKey, kind RRTypeList, mode int, depth int) (set 
*message.GNSRecordSet, err error) {
        // Process all names in sequence
        var (
                records []*message.GNSResourceRecord // final resource records 
from resolution
@@ -150,15 +161,25 @@ func (gns *GNSModule) ResolveRelative(labels []string, 
pkey *ed25519.PublicKey,
                logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in 
'%s'\n", labels[0], util.EncodeBinaryToString(pkey.Bytes()))
 
                // resolve next level
-               var block *GNSBlock
-               if block, err = gns.Lookup(pkey, labels[0], mode == 
enums.GNS_LO_DEFAULT); err != nil {
+               var block *message.GNSBlock
+               if block, err = gns.Lookup(pkey, labels[0], mode); err != nil {
                        // failed to resolve name
                        return
                }
                // set new mode after processing right-most label in 
LOCAL_MASTER mode
                if mode == enums.GNS_LO_LOCAL_MASTER {
+                       // if we have no results at this point, return NXDOMAIN
+                       if block == nil {
+                               // return record set with no entries as signal 
for NXDOMAIN
+                               set = message.NewGNSRecordSet()
+                               return
+                       }
                        mode = enums.GNS_LO_DEFAULT
                }
+               // signal NO_DATA if no block is found
+               if block == nil {
+                       return
+               }
                // post-process block by inspecting contained resource records 
for
                // special GNS types
                if records, err = block.Records(); err != nil {
@@ -204,7 +225,7 @@ func (gns *GNSModule) ResolveRelative(labels []string, pkey 
*ed25519.PublicKey,
                                lbls += "."
                        }
                        fqdn := lbls + inst.Query
-                       if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, 
pkey); err != nil {
+                       if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, 
pkey, depth); err != nil {
                                logger.Println(logger.ERROR, "[gns] GNS2DNS 
resolution failed.")
                                return
                        }
@@ -224,10 +245,10 @@ func (gns *GNSModule) ResolveRelative(labels []string, 
pkey *ed25519.PublicKey,
                        inst := hdlr.(*CnameHandler)
                        // if we are at the end of the path and the requested 
type
                        // includes GNS_TYPE_DNS_CNAME, the records are 
returned...
-                       if len(labels) == 1 && 
kind.HasType(enums.GNS_TYPE_DNS_CNAME) {
+                       if len(labels) == 1 && 
kind.HasType(enums.GNS_TYPE_DNS_CNAME) && !kind.IsAny() {
                                break
                        }
-                       if set, err = gns.ResolveUnknown(inst.name, pkey, 
kind); err != nil {
+                       if set, err = gns.ResolveUnknown(inst.name, labels, 
pkey, kind, depth+1); err != nil {
                                logger.Println(logger.ERROR, "[gns] CNAME 
resolution failed.")
                                return
                        }
@@ -238,7 +259,7 @@ func (gns *GNSModule) ResolveRelative(labels []string, pkey 
*ed25519.PublicKey,
        }
        // Assemble resulting resource record set by filtering for requested 
types.
        // Records might get transformed by active block handlers.
-       set = NewGNSRecordSet()
+       set = message.NewGNSRecordSet()
        for _, rec := range records {
                // is this the record type we are looking for?
                if kind.HasType(int(rec.Type)) {
@@ -267,19 +288,22 @@ func (gns *GNSModule) ResolveRelative(labels []string, 
pkey *ed25519.PublicKey,
 // relative to the zone PKEY. If the name is an absolute GNS name (ending in
 // a PKEY TLD), it is also resolved with GNS. All other names are resolved
 // via DNS queries.
-func (gns *GNSModule) ResolveUnknown(name string, pkey *ed25519.PublicKey, 
kind RRTypeList) (set *GNSRecordSet, err error) {
+func (gns *GNSModule) ResolveUnknown(name string, labels []string, pkey 
*ed25519.PublicKey, kind RRTypeList, depth int) (set *message.GNSRecordSet, err 
error) {
        // relative GNS-based server name?
        if strings.HasSuffix(name, ".+") {
                // resolve server name relative to current zone
                name = strings.TrimSuffix(name, ".+")
-               if set, err = gns.Resolve(name, pkey, kind, 
enums.GNS_LO_DEFAULT); err != nil {
+               for _, label := range util.ReverseStringList(labels) {
+                       name += "." + label
+               }
+               if set, err = gns.Resolve(name, pkey, kind, 
enums.GNS_LO_DEFAULT, depth+1); err != nil {
                        return
                }
        } else {
                // check for absolute GNS name (with PKEY as TLD)
                if zk := gns.GetZoneKey(name); zk != nil {
                        // resolve absolute GNS name (name ends in a PKEY)
-                       if set, err = gns.Resolve(util.StripPathRight(name), 
zk, kind, enums.GNS_LO_DEFAULT); err != nil {
+                       if set, err = gns.Resolve(util.StripPathRight(name), 
zk, kind, enums.GNS_LO_DEFAULT, depth+1); err != nil {
                                return
                        }
                } else {
@@ -306,7 +330,7 @@ func (gns *GNSModule) GetZoneKey(path string) 
*ed25519.PublicKey {
 }
 
 // Lookup name in GNS.
-func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote 
bool) (block *GNSBlock, err error) {
+func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, mode int) 
(block *message.GNSBlock, err error) {
 
        // create query (lookup key)
        query := NewQuery(pkey, label)
@@ -318,7 +342,7 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label 
string, remote bool)
                return
        }
        if block == nil {
-               if remote {
+               if mode == enums.GNS_LO_DEFAULT {
                        // get the block from a remote lookup
                        if block, err = gns.LookupRemote(query); err != nil || 
block == nil {
                                if err != nil {
@@ -326,15 +350,12 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, 
label string, remote bool)
                                        block = nil
                                } else {
                                        logger.Println(logger.DBG, "[gns] 
remote Lookup: no block found")
-                                       err = fmt.Errorf("No block found")
                                }
                                // lookup fails completely -- no result
                                return
                        }
                        // store RRs from remote locally.
-                       gns.StoreLocal(query, block)
-               } else {
-                       err = fmt.Errorf("No block found")
+                       gns.StoreLocal(block)
                }
        }
        return
diff --git a/src/gnunet/service/gns/service.go 
b/src/gnunet/service/gns/service.go
index dd516ff..f21a797 100644
--- a/src/gnunet/service/gns/service.go
+++ b/src/gnunet/service/gns/service.go
@@ -1,8 +1,28 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package gns
 
 import (
        "encoding/hex"
+       "fmt"
        "io"
+       "sync"
 
        "gnunet/config"
        "gnunet/crypto"
@@ -17,6 +37,13 @@ import (
        "github.com/bfix/gospel/logger"
 )
 
+// Error codes
+var (
+       ErrInvalidID           = fmt.Errorf("Invalid/unassociated ID")
+       ErrBlockExpired        = fmt.Errorf("Block expired")
+       ErrInvalidResponseType = fmt.Errorf("Invald response type")
+)
+
 //----------------------------------------------------------------------
 // "GNUnet Name System" service implementation
 //----------------------------------------------------------------------
@@ -33,7 +60,6 @@ func NewGNSService() service.Service {
        inst.LookupLocal = inst.LookupNamecache
        inst.StoreLocal = inst.StoreNamecache
        inst.LookupRemote = inst.LookupDHT
-       inst.GetLocalZone = inst.GetPrivateZone
        return inst
 }
 
@@ -48,7 +74,9 @@ func (s *GNSService) Stop() error {
 }
 
 // Serve a client channel.
-func (s *GNSService) ServeClient(mc *transport.MsgChannel) {
+func (s *GNSService) ServeClient(wg *sync.WaitGroup, mc *transport.MsgChannel) 
{
+       defer wg.Done()
+loop:
        for {
                // receive next message from client
                msg, err := mc.Receive()
@@ -58,7 +86,7 @@ func (s *GNSService) ServeClient(mc *transport.MsgChannel) {
                        } else {
                                logger.Printf(logger.ERROR, "[gns] 
Message-receive failed: %s\n", err.Error())
                        }
-                       break
+                       break loop
                }
                logger.Printf(logger.INFO, "[gns] Received msg: %v\n", msg)
 
@@ -74,57 +102,58 @@ func (s *GNSService) ServeClient(mc *transport.MsgChannel) 
{
                        resp = respX
 
                        // perform lookup on block (locally and remote)
-                       // TODO: run code in a go routine concurrently (would 
need
-                       //       access to the message channel to send 
responses)
-                       pkey := ed25519.NewPublicKeyFromBytes(m.Zone)
-                       label := m.GetName()
-                       kind := NewRRTypeList(int(m.Type))
-                       recset, err := s.Resolve(label, pkey, kind, 
int(m.Options))
-                       if err != nil {
-                               logger.Printf(logger.ERROR, "[gns] Failed to 
lookup block: %s\n", err.Error())
-                               break
-                       }
-                       // handle records
-                       if recset != nil {
-                               logger.Printf(logger.DBG, "[gns] Received 
record set with %d entries\n", recset.Count)
-
-                               // get records from block
-                               if recset.Count == 0 {
-                                       logger.Println(logger.WARN, "[gns] No 
records in block")
-                                       break
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+
+                               pkey := ed25519.NewPublicKeyFromBytes(m.Zone)
+                               label := m.GetName()
+                               kind := NewRRTypeList(int(m.Type))
+                               recset, err := s.Resolve(label, pkey, kind, 
int(m.Options), 0)
+                               if err != nil {
+                                       logger.Printf(logger.ERROR, "[gns] 
Failed to lookup block: %s\n", err.Error())
+                                       return
                                }
-                               // process records
-                               for i, rec := range recset.Records {
-                                       logger.Printf(logger.DBG, "[gns] Record 
#%d: %v\n", i, rec)
-
-                                       // is this the record type we are 
looking for?
-                                       if rec.Type == m.Type || int(m.Type) == 
enums.GNS_TYPE_ANY {
-                                               // add it to the response 
message
-                                               respX.AddRecord(rec)
+                               // handle records
+                               if recset != nil {
+                                       logger.Printf(logger.DBG, "[gns] 
Received record set with %d entries\n", recset.Count)
+
+                                       // get records from block
+                                       if recset.Count == 0 {
+                                               logger.Println(logger.WARN, 
"[gns] No records in block")
+                                               return
+                                       }
+                                       // process records
+                                       for i, rec := range recset.Records {
+                                               logger.Printf(logger.DBG, 
"[gns] Record #%d: %v\n", i, rec)
+
+                                               // is this the record type we 
are looking for?
+                                               if rec.Type == m.Type || 
int(m.Type) == enums.GNS_TYPE_ANY {
+                                                       // add it to the 
response message
+                                                       respX.AddRecord(rec)
+                                               }
                                        }
                                }
-                       }
+                               // send response
+                               if err := mc.Send(resp); err != nil {
+                                       logger.Printf(logger.ERROR, "[gns] 
Failed to send response: %s\n", err.Error())
+                               }
+                       }()
 
                default:
                        
//----------------------------------------------------------
                        // UNKNOWN message type received
                        
//----------------------------------------------------------
                        logger.Printf(logger.ERROR, "[gns] Unhandled message of 
type (%d)\n", msg.Header().MsgType)
-                       continue
-               }
-
-               // send response
-               if err := mc.Send(resp); err != nil {
-                       logger.Printf(logger.ERROR, "[gns] Failed to send 
response: %s\n", err.Error())
+                       break loop
                }
-
        }
        // close client connection
        mc.Close()
 }
 
 // LookupNamecache
-func (s *GNSService) LookupNamecache(query *Query) (block *GNSBlock, err 
error) {
+func (s *GNSService) LookupNamecache(query *Query) (block *message.GNSBlock, 
err error) {
        logger.Printf(logger.DBG, "[gns] LookupNamecache(%s)...\n", 
hex.EncodeToString(query.Key.Bits))
 
        // assemble Namecache request
@@ -145,6 +174,7 @@ func (s *GNSService) LookupNamecache(query *Query) (block 
*GNSBlock, err error)
                // check for matching IDs
                if m.Id != req.Id {
                        logger.Println(logger.ERROR, "[gns] Got response for 
unknown ID")
+                       err = ErrInvalidID
                        break
                }
                // check if block was found
@@ -155,14 +185,15 @@ func (s *GNSService) LookupNamecache(query *Query) (block 
*GNSBlock, err error)
                // check if record has expired
                if m.Expire.Expired() {
                        logger.Printf(logger.ERROR, "[gns] block expired at 
%s\n", m.Expire)
+                       err = ErrBlockExpired
                        break
                }
 
                // assemble GNSBlock from message
-               block = new(GNSBlock)
+               block = new(message.GNSBlock)
                block.Signature = m.Signature
                block.DerivedKey = m.DerivedKey
-               sb := new(SignedBlockData)
+               sb := new(message.SignedBlockData)
                sb.Purpose = new(crypto.SignaturePurpose)
                sb.Purpose.Purpose = enums.SIG_GNS_RECORD_SIGN
                sb.Purpose.Size = uint32(16 + len(m.EncData))
@@ -177,18 +208,51 @@ func (s *GNSService) LookupNamecache(query *Query) (block 
*GNSBlock, err error)
                if err = block.Decrypt(query.Zone, query.Label); err != nil {
                        break
                }
+       default:
+               logger.Printf(logger.ERROR, "[gns] Got invalid response type 
(%d)\n", m.Header().MsgType)
+               err = ErrInvalidResponseType
        }
        return
 }
 
 // StoreNamecache
-func (s *GNSService) StoreNamecache(query *Query, block *GNSBlock) error {
-       logger.Println(logger.WARN, "[gns] StoreNamecache() not implemented 
yet!")
-       return nil
+func (s *GNSService) StoreNamecache(block *message.GNSBlock) (err error) {
+       logger.Println(logger.DBG, "[gns] StoreNamecache()...")
+
+       // assemble Namecache request
+       req := message.NewNamecacheCacheMsg(block)
+       req.Id = uint32(util.NextID())
+
+       // get response from Namecache service
+       var resp message.Message
+       if resp, err = service.ServiceRequestResponse("gns", "Namecache", 
config.Cfg.Namecache.Endpoint, req); err != nil {
+               return
+       }
+
+       // handle message depending on its type
+       logger.Println(logger.DBG, "[gns] Handling response from Namecache 
service")
+       switch m := resp.(type) {
+       case *message.NamecacheCacheResponseMsg:
+               // check for matching IDs
+               if m.Id != req.Id {
+                       logger.Println(logger.ERROR, "[gns] Got response for 
unknown ID")
+                       err = ErrInvalidID
+                       break
+               }
+               // check result
+               if m.Result == 0 {
+                       return nil
+               }
+               return fmt.Errorf("Failed with rc=%d", m.Result)
+       default:
+               logger.Printf(logger.ERROR, "[gns] Got invalid response type 
(%d)\n", m.Header().MsgType)
+               err = ErrInvalidResponseType
+       }
+       return
 }
 
 // LookupDHT
-func (s *GNSService) LookupDHT(query *Query) (block *GNSBlock, err error) {
+func (s *GNSService) LookupDHT(query *Query) (block *message.GNSBlock, err 
error) {
        logger.Printf(logger.DBG, "[gns] LookupDHT(%s)...\n", 
hex.EncodeToString(query.Key.Bits))
 
        // assemble DHT request
@@ -231,7 +295,7 @@ func (s *GNSService) LookupDHT(query *Query) (block 
*GNSBlock, err error) {
                }
 
                // get GNSBlock from message
-               block = NewGNSBlock()
+               block = message.NewGNSBlock()
                if err = data.Unmarshal(block, m.Data); err != nil {
                        logger.Printf(logger.ERROR, "[gns] can't read GNS 
block: %s\n", err.Error())
                        break
@@ -246,14 +310,9 @@ func (s *GNSService) LookupDHT(query *Query) (block 
*GNSBlock, err error) {
 
                // we got a result from DHT that was not in the namecache,
                // so store it there now.
-               if err = s.StoreNamecache(query, block); err != nil {
+               if err = s.StoreNamecache(block); err != nil {
                        logger.Printf(logger.ERROR, "[gns] can't store block in 
Namecache: %s\n", err.Error())
                }
        }
        return
 }
-
-// GetPrivateZone
-func (s *GNSService) GetPrivateZone(name string) (*ed25519.PublicKey, error) {
-       return nil, nil
-}
diff --git a/src/gnunet/service/namecache/module.go 
b/src/gnunet/service/namecache/module.go
index 85f7601..6a10625 100644
--- a/src/gnunet/service/namecache/module.go
+++ b/src/gnunet/service/namecache/module.go
@@ -1,6 +1,25 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package namecache
 
 import (
+       "gnunet/message"
        "gnunet/service/gns"
 )
 
@@ -16,10 +35,10 @@ import (
 type NamecacheModule struct {
 }
 
-func (nc *NamecacheModule) Get(query *gns.Query) (*gns.GNSBlock, error) {
+func (nc *NamecacheModule) Get(query *gns.Query) (*message.GNSBlock, error) {
        return nil, nil
 }
 
-func (nc *NamecacheModule) Put(query *gns.Query, block *gns.GNSBlock) error {
+func (nc *NamecacheModule) Put(block *message.GNSBlock) error {
        return nil
 }
diff --git a/src/gnunet/service/service.go b/src/gnunet/service/service.go
index 6aab226..d484a95 100644
--- a/src/gnunet/service/service.go
+++ b/src/gnunet/service/service.go
@@ -1,7 +1,26 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package service
 
 import (
        "fmt"
+       "sync"
 
        "gnunet/transport"
 
@@ -14,7 +33,7 @@ import (
 // Channel semantics in the specification string.
 type Service interface {
        Start(spec string) error
-       ServeClient(ch *transport.MsgChannel)
+       ServeClient(wg *sync.WaitGroup, ch *transport.MsgChannel)
        Stop() error
 }
 
@@ -24,6 +43,7 @@ type ServiceImpl struct {
        hdlr    chan transport.Channel
        ctrl    chan bool
        srvc    transport.ChannelServer
+       wg      *sync.WaitGroup
        name    string
        running bool
 }
@@ -35,6 +55,7 @@ func NewServiceImpl(name string, srv Service) *ServiceImpl {
                hdlr:    make(chan transport.Channel),
                ctrl:    make(chan bool),
                srvc:    nil,
+               wg:      new(sync.WaitGroup),
                name:    name,
                running: false,
        }
@@ -56,7 +77,9 @@ func (si *ServiceImpl) Start(spec string) (err error) {
        si.running = true
 
        // handle clients
+       si.wg.Add(1)
        go func() {
+               defer si.wg.Done()
        loop:
                for si.running {
                        select {
@@ -68,7 +91,8 @@ func (si *ServiceImpl) Start(spec string) (err error) {
                                switch ch := in.(type) {
                                case transport.Channel:
                                        logger.Printf(logger.INFO, "[%s] Client 
connected.\n", si.name)
-                                       go 
si.impl.ServeClient(transport.NewMsgChannel(ch))
+                                       si.wg.Add(1)
+                                       go si.impl.ServeClient(si.wg, 
transport.NewMsgChannel(ch))
                                }
                        case <-si.ctrl:
                                break loop
@@ -92,5 +116,7 @@ func (si *ServiceImpl) Stop() error {
        si.ctrl <- true
        logger.Printf(logger.INFO, "[%s] Service terminating.\n", si.name)
 
-       return si.impl.Stop()
+       err := si.impl.Stop()
+       si.wg.Wait()
+       return err
 }
diff --git a/src/gnunet/transport/channel.go b/src/gnunet/transport/channel.go
index 4005759..092ab8a 100644
--- a/src/gnunet/transport/channel.go
+++ b/src/gnunet/transport/channel.go
@@ -1,14 +1,35 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package transport
 
 import (
        "encoding/hex"
        "errors"
        "fmt"
+       "path"
        "strings"
 
+       "gnunet/message"
+       "gnunet/util"
+
        "github.com/bfix/gospel/data"
        "github.com/bfix/gospel/logger"
-       "gnunet/message"
 )
 
 // Error codes
@@ -79,12 +100,19 @@ var channelServerImpl = map[string]ChannelServerFactory{
 }
 
 // NewChannelServer
-func NewChannelServer(spec string, hdlr chan<- Channel) (ChannelServer, error) 
{
+func NewChannelServer(spec string, hdlr chan<- Channel) (cs ChannelServer, err 
error) {
        parts := strings.Split(spec, "+")
+
        if fac, ok := channelServerImpl[parts[0]]; ok {
-               inst := fac()
-               err := inst.Open(spec, hdlr)
-               return inst, err
+               // check if the basedir for the spec exists...
+               if err = util.EnforceDirExists(path.Dir(parts[1])); err != nil {
+                       return
+               }
+               // instantiate server implementation
+               cs = fac()
+               // create the domain socket and listen to it.
+               err = cs.Open(spec, hdlr)
+               return
        }
        return nil, ErrChannelNotImplemented
 }
diff --git a/src/gnunet/transport/channel_netw.go 
b/src/gnunet/transport/channel_netw.go
index ecfd8e2..c56c089 100644
--- a/src/gnunet/transport/channel_netw.go
+++ b/src/gnunet/transport/channel_netw.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package transport
 
 import (
diff --git a/src/gnunet/transport/channel_test.go 
b/src/gnunet/transport/channel_test.go
index c59e3e1..41831b3 100644
--- a/src/gnunet/transport/channel_test.go
+++ b/src/gnunet/transport/channel_test.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package transport
 
 import (
diff --git a/src/gnunet/transport/connection.go 
b/src/gnunet/transport/connection.go
index 1cf0317..e2cfae2 100644
--- a/src/gnunet/transport/connection.go
+++ b/src/gnunet/transport/connection.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package transport
 
 import (
diff --git a/src/gnunet/transport/session.go b/src/gnunet/transport/session.go
index 7d33ea2..f6a320e 100644
--- a/src/gnunet/transport/session.go
+++ b/src/gnunet/transport/session.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package transport
 
 // Session states
diff --git a/src/gnunet/util/address.go b/src/gnunet/util/address.go
index 37fb102..2d3e3ac 100644
--- a/src/gnunet/util/address.go
+++ b/src/gnunet/util/address.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (
diff --git a/src/gnunet/util/array.go b/src/gnunet/util/array.go
index f6213bf..be25ef9 100644
--- a/src/gnunet/util/array.go
+++ b/src/gnunet/util/array.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (
diff --git a/src/gnunet/util/base32.go b/src/gnunet/util/base32.go
index ff5711e..e3e500e 100644
--- a/src/gnunet/util/base32.go
+++ b/src/gnunet/util/base32.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (
diff --git a/src/gnunet/util/base32_test.go b/src/gnunet/util/base32_test.go
index e89109d..23b4372 100644
--- a/src/gnunet/util/base32_test.go
+++ b/src/gnunet/util/base32_test.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (
diff --git a/src/gnunet/util/format.go b/src/gnunet/util/format.go
index 780c814..7b7891a 100644
--- a/src/gnunet/util/format.go
+++ b/src/gnunet/util/format.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (
diff --git a/src/gnunet/util/fs.go b/src/gnunet/util/fs.go
new file mode 100644
index 0000000..009ef62
--- /dev/null
+++ b/src/gnunet/util/fs.go
@@ -0,0 +1,43 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package util
+
+import (
+       "fmt"
+       "os"
+
+       "github.com/bfix/gospel/logger"
+)
+
+// EnforceDirExists make sure that the path
+func EnforceDirExists(path string) error {
+       logger.Printf(logger.DBG, "[util] Checking directory '%s'...\n", path)
+       fi, err := os.Lstat(path)
+       if err != nil {
+               if os.IsNotExist(err) {
+                       logger.Printf(logger.DBG, "[util] Creating directory 
'%s'...\n", path)
+                       return os.Mkdir(path, 0770)
+               }
+               return err
+       }
+       if !fi.IsDir() {
+               return fmt.Errorf("Not a directory (%s)", path)
+       }
+       return nil
+}
diff --git a/src/gnunet/util/id.go b/src/gnunet/util/id.go
index ab9b98c..14333bf 100644
--- a/src/gnunet/util/id.go
+++ b/src/gnunet/util/id.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 var (
diff --git a/src/gnunet/util/misc.go b/src/gnunet/util/misc.go
index 6a8a4a3..afad974 100644
--- a/src/gnunet/util/misc.go
+++ b/src/gnunet/util/misc.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (
diff --git a/src/gnunet/util/peer_id.go b/src/gnunet/util/peer_id.go
index 6549d75..f4c14bd 100644
--- a/src/gnunet/util/peer_id.go
+++ b/src/gnunet/util/peer_id.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 // PeerID is the 32-byte binary representation od a Ed25519 key
diff --git a/src/gnunet/util/rnd.go b/src/gnunet/util/rnd.go
index a9f247f..9c8ee10 100644
--- a/src/gnunet/util/rnd.go
+++ b/src/gnunet/util/rnd.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (
diff --git a/src/gnunet/util/time.go b/src/gnunet/util/time.go
index 0dd51a0..3e09791 100644
--- a/src/gnunet/util/time.go
+++ b/src/gnunet/util/time.go
@@ -1,3 +1,21 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
 package util
 
 import (

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]