summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2020-10-01 21:13:43 +0200
committerTheJackiMonster <thejackimonster@gmail.com>2020-11-12 16:57:45 +0100
commit8bf864c25bda97c1448b709a76a168834753ff86 (patch)
tree6ffccc18a3c112e035235c596006f8b13aca1be7 /src
parent8fd7531e5841c9d9f80f821a3490a05934fee933 (diff)
adding the messenger service and its client-side library
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am7
-rw-r--r--src/ats-tests/ats-testing-log.c4
-rw-r--r--src/cadet/gnunet-service-cadet_channel.c10
-rw-r--r--src/cadet/gnunet-service-cadet_core.c4
-rw-r--r--src/cadet/gnunet-service-cadet_dht.c4
-rw-r--r--src/cadet/gnunet-service-cadet_tunnels.c2
-rw-r--r--src/consensus/consensus_api.c2
-rw-r--r--src/conversation/Makefile.am1
-rw-r--r--src/conversation/conversation.h10
-rw-r--r--src/conversation/conversation_api.c4
-rw-r--r--src/conversation/gnunet-conversation.c6
-rw-r--r--src/conversation/gnunet-service-conversation.c15
-rw-r--r--src/conversation/test_conversation_api.c8
-rw-r--r--src/conversation/test_conversation_api_reject.c8
-rw-r--r--src/conversation/test_conversation_api_twocalls.c8
-rw-r--r--src/datacache/plugin_datacache_postgres.c9
-rw-r--r--src/datastore/datastore_api.c8
-rw-r--r--src/datastore/plugin_datastore_postgres.c14
-rw-r--r--src/dht/gnunet-service-dht_clients.c6
-rw-r--r--src/dht/gnunet-service-dht_datacache.c4
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c4
-rw-r--r--src/dht/plugin_block_dht.c2
-rw-r--r--src/dns/gnunet-dns-monitor.c2
-rw-r--r--src/fragmentation/fragmentation.c2
-rw-r--r--src/fs/fs_download.c2
-rw-r--r--src/fs/gnunet-daemon-fsprofiler.c4
-rw-r--r--src/fs/gnunet-publish.c18
-rw-r--r--src/gns/Makefile.am5
-rw-r--r--src/gns/gns.h2
-rw-r--r--src/gns/gns_api.c4
-rw-r--r--src/gns/gns_tld_api.c21
-rw-r--r--src/gns/gnunet-gns-import.c9
-rw-r--r--src/gns/gnunet-service-gns.c6
-rw-r--r--src/gns/gnunet-service-gns.h3
-rw-r--r--src/gns/gnunet-service-gns_interceptor.c2
-rw-r--r--src/gns/gnunet-service-gns_resolver.c71
-rw-r--r--src/gns/gnunet-service-gns_resolver.h2
-rw-r--r--src/gns/plugin_block_gns.c15
-rw-r--r--src/gns/plugin_gnsrecord_gns.c33
-rw-r--r--src/gns/plugin_rest_gns.c3
-rwxr-xr-xsrc/gns/test_gns_dht_lookup.sh1
-rw-r--r--src/gnsrecord/Makefile.am21
-rw-r--r--src/gnsrecord/gnsrecord_crypto.c315
-rw-r--r--src/gnsrecord/gnsrecord_misc.c151
-rw-r--r--src/gnsrecord/gnunet-gnsrecord-tvg.c49
-rw-r--r--src/gnsrecord/json_gnsrecord.c (renamed from src/json/json_gnsrecord.c)114
-rw-r--r--src/gnsrecord/perf_gnsrecord_crypto.c5
-rw-r--r--src/gnsrecord/plugin_gnsrecord_dns.c2
-rw-r--r--src/gnsrecord/test_gnsrecord_crypto.c11
-rw-r--r--src/identity/gnunet-identity.c45
-rw-r--r--src/identity/gnunet-service-identity.c77
-rw-r--r--src/identity/identity.h81
-rw-r--r--src/identity/identity_api.c391
-rw-r--r--src/identity/identity_api_lookup.c4
-rw-r--r--src/identity/plugin_rest_identity.c23
-rw-r--r--src/identity/test_identity.c8
-rw-r--r--src/identity/test_identity_defaults.c8
-rw-r--r--src/include/Makefile.am1
-rw-r--r--src/include/gnunet_buffer_lib.h3
-rw-r--r--src/include/gnunet_common.h15
-rw-r--r--src/include/gnunet_conversation_service.h2
-rw-r--r--src/include/gnunet_crypto_lib.h6
-rw-r--r--src/include/gnunet_gns_service.h5
-rw-r--r--src/include/gnunet_gnsrecord_json_lib.h73
-rw-r--r--src/include/gnunet_gnsrecord_lib.h125
-rw-r--r--src/include/gnunet_identity_service.h422
-rw-r--r--src/include/gnunet_json_lib.h27
-rw-r--r--src/include/gnunet_messenger_service.h436
-rw-r--r--src/include/gnunet_namestore_plugin.h12
-rw-r--r--src/include/gnunet_namestore_service.h15
-rw-r--r--src/include/gnunet_pq_lib.h55
-rw-r--r--src/include/gnunet_protocols.h43
-rw-r--r--src/include/gnunet_reclaim_service.h33
-rw-r--r--src/include/gnunet_revocation_service.h34
-rw-r--r--src/include/gnunet_uri_lib.h8
-rw-r--r--src/json/Makefile.am7
-rw-r--r--src/json/json.c14
-rw-r--r--src/json/json_generator.c108
-rw-r--r--src/messenger/.gitignore4
-rw-r--r--src/messenger/Makefile.am131
-rw-r--r--src/messenger/gnunet-messenger.c306
-rw-r--r--src/messenger/gnunet-service-messenger.c306
-rw-r--r--src/messenger/gnunet-service-messenger.h121
-rw-r--r--src/messenger/gnunet-service-messenger_basement.c58
-rw-r--r--src/messenger/gnunet-service-messenger_basement.h66
-rw-r--r--src/messenger/gnunet-service-messenger_contact.c96
-rw-r--r--src/messenger/gnunet-service-messenger_contact.h112
-rw-r--r--src/messenger/gnunet-service-messenger_handle.c503
-rw-r--r--src/messenger/gnunet-service-messenger_handle.h216
-rw-r--r--src/messenger/gnunet-service-messenger_list_handles.c95
-rw-r--r--src/messenger/gnunet-service-messenger_list_handles.h96
-rw-r--r--src/messenger/gnunet-service-messenger_list_messages.c76
-rw-r--r--src/messenger/gnunet-service-messenger_list_messages.h81
-rw-r--r--src/messenger/gnunet-service-messenger_message_handle.c130
-rw-r--r--src/messenger/gnunet-service-messenger_message_handle.h128
-rw-r--r--src/messenger/gnunet-service-messenger_message_kind.c192
-rw-r--r--src/messenger/gnunet-service-messenger_message_kind.h160
-rw-r--r--src/messenger/gnunet-service-messenger_message_recv.c204
-rw-r--r--src/messenger/gnunet-service-messenger_message_recv.h159
-rw-r--r--src/messenger/gnunet-service-messenger_message_send.c118
-rw-r--r--src/messenger/gnunet-service-messenger_message_send.h155
-rw-r--r--src/messenger/gnunet-service-messenger_message_store.c282
-rw-r--r--src/messenger/gnunet-service-messenger_message_store.h120
-rw-r--r--src/messenger/gnunet-service-messenger_room.c1051
-rw-r--r--src/messenger/gnunet-service-messenger_room.h378
-rw-r--r--src/messenger/gnunet-service-messenger_service.c516
-rw-r--r--src/messenger/gnunet-service-messenger_service.h259
-rw-r--r--src/messenger/gnunet-service-messenger_tunnel.c300
-rw-r--r--src/messenger/gnunet-service-messenger_tunnel.h155
-rw-r--r--src/messenger/gnunet-service-messenger_util.c64
-rw-r--r--src/messenger/gnunet-service-messenger_util.h53
-rw-r--r--src/messenger/messenger.conf.in13
-rw-r--r--src/messenger/messenger_api.c568
-rw-r--r--src/messenger/messenger_api_contact.c78
-rw-r--r--src/messenger/messenger_api_contact.h93
-rw-r--r--src/messenger/messenger_api_ego.h38
-rw-r--r--src/messenger/messenger_api_handle.c213
-rw-r--r--src/messenger/messenger_api_handle.h174
-rw-r--r--src/messenger/messenger_api_list_tunnels.c112
-rw-r--r--src/messenger/messenger_api_list_tunnels.h112
-rw-r--r--src/messenger/messenger_api_message.c602
-rw-r--r--src/messenger/messenger_api_message.h190
-rw-r--r--src/messenger/messenger_api_room.c189
-rw-r--r--src/messenger/messenger_api_room.h95
-rw-r--r--src/messenger/test_messenger.c187
-rw-r--r--src/messenger/test_messenger_anonymous.c179
-rw-r--r--src/messenger/test_messenger_comm0.c252
-rw-r--r--src/my/my_query_helper.c8
-rw-r--r--src/namecache/Makefile.am9
-rw-r--r--src/namecache/gnunet-namecache.c4
-rw-r--r--src/namecache/gnunet-service-namecache.c47
-rw-r--r--src/namecache/namecache.h4
-rw-r--r--src/namecache/namecache_api.c23
-rw-r--r--src/namecache/plugin_namecache_flat.c16
-rw-r--r--src/namecache/plugin_namecache_postgres.c30
-rw-r--r--src/namecache/plugin_namecache_sqlite.c16
-rw-r--r--src/namecache/test_namecache_api_cache_block.c20
-rw-r--r--src/namestore/Makefile.am11
-rw-r--r--src/namestore/gnunet-namestore-fcfsd.c49
-rw-r--r--src/namestore/gnunet-namestore.c45
-rw-r--r--src/namestore/gnunet-service-namestore.c34
-rw-r--r--src/namestore/gnunet-zoneimport.c4
-rw-r--r--src/namestore/namestore.h18
-rw-r--r--src/namestore/namestore_api.c14
-rw-r--r--src/namestore/namestore_api_monitor.c4
-rw-r--r--src/namestore/perf_namestore_api_zone_iteration.c7
-rw-r--r--src/namestore/plugin_namestore_flat.c37
-rw-r--r--src/namestore/plugin_namestore_postgres.c35
-rw-r--r--src/namestore/plugin_namestore_sqlite.c28
-rw-r--r--src/namestore/plugin_rest_namestore.c30
-rw-r--r--src/namestore/test_namestore_api_lookup_nick.c11
-rw-r--r--src/namestore/test_namestore_api_lookup_private.c11
-rw-r--r--src/namestore/test_namestore_api_lookup_public.c17
-rw-r--r--src/namestore/test_namestore_api_lookup_shadow.c17
-rw-r--r--src/namestore/test_namestore_api_lookup_shadow_filter.c17
-rw-r--r--src/namestore/test_namestore_api_monitoring.c12
-rw-r--r--src/namestore/test_namestore_api_monitoring_existing.c12
-rw-r--r--src/namestore/test_namestore_api_remove.c11
-rw-r--r--src/namestore/test_namestore_api_remove_not_existing_record.c9
-rw-r--r--src/namestore/test_namestore_api_store.c9
-rw-r--r--src/namestore/test_namestore_api_store_update.c13
-rw-r--r--src/namestore/test_namestore_api_zone_iteration.c39
-rw-r--r--src/namestore/test_namestore_api_zone_iteration_nick.c14
-rw-r--r--src/namestore/test_namestore_api_zone_iteration_specific_zone.c14
-rw-r--r--src/namestore/test_namestore_api_zone_iteration_stop.c39
-rw-r--r--src/namestore/test_namestore_api_zone_to_name.c18
-rw-r--r--src/namestore/test_plugin_namestore.c6
-rwxr-xr-xsrc/namestore/test_plugin_rest_namestore.sh21
-rw-r--r--src/nse/gnunet-nse-profiler.c2
-rw-r--r--src/peerinfo-tool/gnunet-peerinfo.c4
-rw-r--r--src/peerinfo-tool/plugin_rest_peerinfo.c4
-rw-r--r--src/pq/pq.c45
-rw-r--r--src/pq/pq_eval.c6
-rw-r--r--src/pq/pq_query_helper.c126
-rw-r--r--src/pq/pq_result_helper.c101
-rw-r--r--src/pq/test_pq.c17
-rw-r--r--src/pt/test_gns_vpn.c2
-rw-r--r--src/reclaim/Makefile.am1
-rw-r--r--src/reclaim/gnunet-reclaim.c14
-rw-r--r--src/reclaim/gnunet-service-reclaim.c26
-rw-r--r--src/reclaim/gnunet-service-reclaim_tickets.c36
-rw-r--r--src/reclaim/gnunet-service-reclaim_tickets.h12
-rw-r--r--src/reclaim/oidc_helper.c73
-rw-r--r--src/reclaim/oidc_helper.h10
-rw-r--r--src/reclaim/plugin_rest_openid_connect.c57
-rw-r--r--src/reclaim/plugin_rest_reclaim.c44
-rw-r--r--src/reclaim/reclaim.h26
-rw-r--r--src/reclaim/reclaim_api.c30
-rw-r--r--src/reclaim/test_reclaim_attribute.c2
-rw-r--r--src/regex/regex_block_lib.c8
-rw-r--r--src/regex/regex_internal_dht.c9
-rw-r--r--src/regex/regex_test_graph.c9
-rw-r--r--src/revocation/Makefile.am3
-rw-r--r--src/revocation/gnunet-revocation-tvg.c43
-rw-r--r--src/revocation/gnunet-revocation.c71
-rw-r--r--src/revocation/gnunet-service-revocation.c75
-rw-r--r--src/revocation/plugin_block_revocation.c23
-rw-r--r--src/revocation/revocation.h11
-rw-r--r--src/revocation/revocation_api.c182
-rw-r--r--src/revocation/test_revocation.c20
-rw-r--r--src/set/gnunet-service-set_union.c18
-rw-r--r--src/set/set_api.c3
-rw-r--r--src/setu/gnunet-service-setu.c20
-rw-r--r--src/statistics/statistics_api.c2
-rw-r--r--src/testbed-logger/gnunet-service-testbed-logger.c2
-rw-r--r--src/testbed/gnunet-service-testbed_cpustatus.c2
-rw-r--r--src/testbed/test_testbed_api_template.conf2
-rw-r--r--src/testbed/testbed_api.c2
-rw-r--r--src/testbed/testbed_api_topology.c6
-rw-r--r--src/transport/gnunet-communicator-udp.c494
-rw-r--r--src/transport/gnunet-service-transport.c2
-rw-r--r--src/transport/plugin_transport_http_client.c15
-rw-r--r--src/transport/plugin_transport_http_common.c2
-rw-r--r--src/transport/plugin_transport_http_server.c24
-rw-r--r--src/transport/plugin_transport_tcp.c12
-rw-r--r--src/transport/plugin_transport_udp.c15
-rw-r--r--src/transport/plugin_transport_unix.c4
-rw-r--r--src/transport/tcp_connection_legacy.c16
-rw-r--r--src/transport/tcp_service_legacy.c2
-rw-r--r--src/transport/test_communicator_basic.c206
-rw-r--r--src/transport/transport-testing2.c7
-rw-r--r--src/util/bio.c4
-rw-r--r--src/util/client.c2
-rw-r--r--src/util/configuration_loader.c15
-rw-r--r--src/util/os_installation.c2
-rw-r--r--src/util/program.c25
-rw-r--r--src/util/service.c4
-rw-r--r--src/util/strings.c25
-rw-r--r--src/zonemaster/Makefile.am3
-rw-r--r--src/zonemaster/gnunet-service-zonemaster-monitor.c8
-rw-r--r--src/zonemaster/gnunet-service-zonemaster.c8
231 files changed, 13889 insertions, 1818 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 234a63389..c04d730be 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,7 +12,8 @@ endif
if HAVE_EXPERIMENTAL
EXP_DIR = \
rps \
- abd
+ #abd FTBFS
+ messenger
if HAVE_ABE
EXP_DIR += \
abe
@@ -51,7 +52,6 @@ SUBDIRS = \
include $(INTLEMU_SUBDIRS) \
util \
nt \
- gnsrecord \
hello \
block \
statistics \
@@ -74,7 +74,6 @@ SUBDIRS = \
fragmentation \
transport \
ats-tool \
- peerinfo-tool \
core \
$(TESTBED) \
$(ATS_TESTS) \
@@ -85,8 +84,10 @@ SUBDIRS = \
regex \
dns \
identity \
+ gnsrecord \
namecache \
namestore \
+ peerinfo-tool \
cadet \
set \
seti \
diff --git a/src/ats-tests/ats-testing-log.c b/src/ats-tests/ats-testing-log.c
index 38094a438..955401dd8 100644
--- a/src/ats-tests/ats-testing-log.c
+++ b/src/ats-tests/ats-testing-log.c
@@ -575,7 +575,7 @@ GNUNET_ATS_TEST_logging_write_to_file (struct LoggingHandle *l,
/* Assembling slave string */
GNUNET_asprintf (&data,
- "%llu;%llu;%u;%u;%u;%u;%u;%u;%.3f;%u;%u;%u;%u;%u;%u;%u;%.3f;%.3f\n",
+ "%llu;%llu;%u;%u;%u;%u;%u;%u;%.3f;%u;%u;%llu;%u;%u;%u;%u;%.3f;%.3f\n",
(long long unsigned
int) cur_lt->timestamp.abs_value_us,
(long long unsigned
@@ -593,7 +593,7 @@ GNUNET_ATS_TEST_logging_write_to_file (struct LoggingHandle *l,
(double) plt->app_rtt / 1000,
plt->bandwidth_in,
plt->bandwidth_out,
- plt->ats_delay,
+ plt->ats_delay.rel_value_us,
plt->ats_distance,
plt->ats_network_type,
plt->ats_utilization_out,
diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c
index dab53b8c4..ae6d21452 100644
--- a/src/cadet/gnunet-service-cadet_channel.c
+++ b/src/cadet/gnunet-service-cadet_channel.c
@@ -442,7 +442,7 @@ GCCH_2s (const struct CadetChannel *ch)
? "loopback"
: GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
GNUNET_h2s (&ch->port),
- ch->ctn,
+ ch->ctn.cn,
(NULL == ch->owner)
? 0
: ntohl (ch->owner->ccn.channel_of_client),
@@ -1899,10 +1899,10 @@ GCCH_handle_local_data (struct CadetChannel *ch,
GNUNET_memcpy (&crm->data_message[1], buf, buf_len);
GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent, ch->tail_sent, crm);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending message %u from local client to %s with %u bytes\n",
+ "Sending message %u from local client to %s with %lu bytes\n",
ntohl (crm->data_message->mid.mid),
GCCH_2s (ch),
- buf_len);
+ (unsigned long) buf_len);
if (NULL != ch->retry_data_task)
{
GNUNET_SCHEDULER_cancel (ch->retry_data_task);
@@ -2044,7 +2044,7 @@ GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level)
LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
return;
}
- LOG2 (level, "CHN %s:%X (%p)\n", GCT_2s (ch->t), ch->ctn, ch);
+ LOG2 (level, "CHN %s:%X (%p)\n", GCT_2s (ch->t), ch->ctn.cn, ch);
if (NULL != ch->owner)
{
LOG2 (level,
@@ -2062,7 +2062,7 @@ GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level)
ntohl (ch->dest->ccn.channel_of_client));
}
LOG2 (level,
- "CHN Message IDs recv: %d (%LLX), send: %d\n",
+ "CHN Message IDs recv: %d (%llX), send: %d\n",
ntohl (ch->mid_recv.mid),
(unsigned long long) ch->mid_futures,
ntohl (ch->mid_send.mid));
diff --git a/src/cadet/gnunet-service-cadet_core.c b/src/cadet/gnunet-service-cadet_core.c
index 9a83fa31d..95a5d3f63 100644
--- a/src/cadet/gnunet-service-cadet_core.c
+++ b/src/cadet/gnunet-service-cadet_core.c
@@ -296,7 +296,7 @@ discard_all_from_rung_tail ()
while (NULL != (dir = tail->rd_head))
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Queue full due new message %s on connection %s, dropping old message\n",
+ "Queue full due new message on connection %s, dropping old message\n",
GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
GNUNET_STATISTICS_update (stats,
"# messages dropped due to full buffer",
@@ -408,7 +408,7 @@ route_message (struct CadetPeer *prev,
{
/* We are in the highest rung, drop our own! */
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Queue full due new message %s on connection %s, dropping old message\n",
+ "Queue full due new message on connection %s, dropping old message\n",
GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
GNUNET_STATISTICS_update (stats,
"# messages dropped due to full buffer",
diff --git a/src/cadet/gnunet-service-cadet_dht.c b/src/cadet/gnunet-service-cadet_dht.c
index 4e8ccbb08..e1bbeb2c3 100644
--- a/src/cadet/gnunet-service-cadet_dht.c
+++ b/src/cadet/gnunet-service-cadet_dht.c
@@ -195,8 +195,8 @@ announce_id (void *cls)
&my_full_id,
sizeof(my_full_id));
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Announcing my HELLO (%u bytes) in the DHT\n",
- size);
+ "Announcing my HELLO (%lu bytes) in the DHT\n",
+ (unsigned long) size);
GNUNET_DHT_put (dht_handle, /* DHT handle */
&phash, /* Key to use */
dht_replication_level, /* Replication level */
diff --git a/src/cadet/gnunet-service-cadet_tunnels.c b/src/cadet/gnunet-service-cadet_tunnels.c
index 2ca46b5aa..78bc54a5c 100644
--- a/src/cadet/gnunet-service-cadet_tunnels.c
+++ b/src/cadet/gnunet-service-cadet_tunnels.c
@@ -2431,7 +2431,7 @@ connection_ready_cb (void *cls,
{
case CADET_TUNNEL_KEY_UNINITIALIZED:
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Do not begin KX for %s if WE have no channels waiting. Retrying after %d\n",
+ "Do not begin KX for %s if WE have no channels waiting. Retrying after %llu\n",
GCT_2s (t),
GNUNET_TIME_absolute_get_remaining (t->next_kx_attempt).rel_value_us);
/* Do not begin KX if WE have no channels waiting! */
diff --git a/src/consensus/consensus_api.c b/src/consensus/consensus_api.c
index 06b4c88ef..b4a9e5d39 100644
--- a/src/consensus/consensus_api.c
+++ b/src/consensus/consensus_api.c
@@ -280,7 +280,7 @@ GNUNET_CONSENSUS_insert (struct GNUNET_CONSENSUS_Handle *consensus,
struct GNUNET_MQ_Envelope *ev;
struct InsertDoneInfo *i;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "inserting, size=%llu\n", element->size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "inserting, size=%u\n", element->size);
ev = GNUNET_MQ_msg_extra (element_msg, element->size,
GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_INSERT);
diff --git a/src/conversation/Makefile.am b/src/conversation/Makefile.am
index 7645b7973..0f99a6526 100644
--- a/src/conversation/Makefile.am
+++ b/src/conversation/Makefile.am
@@ -185,6 +185,7 @@ gnunet_service_conversation_LDADD = \
libgnunetmicrophone.la \
$(top_builddir)/src/cadet/libgnunetcadet.la \
$(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(INTLLIBS)
#gnunet_service_conversation_LDFLAGS = \
#
diff --git a/src/conversation/conversation.h b/src/conversation/conversation.h
index ed614ab1b..d244f5163 100644
--- a/src/conversation/conversation.h
+++ b/src/conversation/conversation.h
@@ -27,6 +27,8 @@
#ifndef CONVERSATION_H
#define CONVERSATION_H
+#include "gnunet_identity_service.h"
+
#ifdef __cplusplus
extern "C"
{
@@ -105,7 +107,7 @@ struct ClientPhoneRingMessage
/**
* Who is calling us?
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
+ struct GNUNET_IDENTITY_PublicKey caller_id;
};
@@ -230,7 +232,7 @@ struct ClientCallMessage
/**
* Identity of the caller.
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey caller_id;
+ struct GNUNET_IDENTITY_PrivateKey caller_id;
};
@@ -301,7 +303,7 @@ struct CadetPhoneRingMessage
/**
* Who is calling us? (also who is signing).
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
+ struct GNUNET_IDENTITY_PublicKey caller_id;
/**
* When does the signature expire?
@@ -311,7 +313,7 @@ struct CadetPhoneRingMessage
/**
* Signature over a `struct CadetPhoneRingInfoPS`
*/
- struct GNUNET_CRYPTO_EcdsaSignature signature;
+ struct GNUNET_IDENTITY_Signature signature;
};
diff --git a/src/conversation/conversation_api.c b/src/conversation/conversation_api.c
index daf51042a..88fe8f11c 100644
--- a/src/conversation/conversation_api.c
+++ b/src/conversation/conversation_api.c
@@ -105,7 +105,7 @@ struct GNUNET_CONVERSATION_Caller
/**
* Identity of the person calling us.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
+ struct GNUNET_IDENTITY_PublicKey caller_id;
/**
* Internal handle to identify the caller with the service.
@@ -192,7 +192,7 @@ struct GNUNET_CONVERSATION_Phone
/**
* My GNS zone.
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone;
+ struct GNUNET_IDENTITY_PrivateKey my_zone;
/**
* State machine for the phone.
diff --git a/src/conversation/gnunet-conversation.c b/src/conversation/gnunet-conversation.c
index 7a2a727a5..9ff0002e7 100644
--- a/src/conversation/gnunet-conversation.c
+++ b/src/conversation/gnunet-conversation.c
@@ -116,7 +116,7 @@ struct CallList
/**
* Public key identifying the caller.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
+ struct GNUNET_IDENTITY_PublicKey caller_id;
/**
* Unique number of the call.
@@ -194,7 +194,7 @@ static char *ego_name;
/**
* Public key of active conversation partner (if any).
*/
-static struct GNUNET_CRYPTO_EcdsaPublicKey peer_key;
+static struct GNUNET_IDENTITY_PublicKey peer_key;
/**
* Name of active conversation partner (if any).
@@ -244,7 +244,7 @@ static void
phone_event_handler (void *cls,
enum GNUNET_CONVERSATION_PhoneEventCode code,
struct GNUNET_CONVERSATION_Caller *caller,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id)
+ const struct GNUNET_IDENTITY_PublicKey *caller_id)
{
struct CallList *cl;
diff --git a/src/conversation/gnunet-service-conversation.c b/src/conversation/gnunet-service-conversation.c
index 502146255..a69c95a80 100644
--- a/src/conversation/gnunet-service-conversation.c
+++ b/src/conversation/gnunet-service-conversation.c
@@ -752,10 +752,11 @@ handle_cadet_ring_message (void *cls, const struct CadetPhoneRingMessage *msg)
rs.expiration_time = msg->expiration_time;
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
- &rs,
- &msg->signature,
- &msg->caller_id))
+ GNUNET_IDENTITY_signature_verify (
+ GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
+ &rs,
+ &msg->signature,
+ &msg->caller_id))
{
GNUNET_break_op (0);
destroy_line_cadet_channels (ch);
@@ -1136,11 +1137,9 @@ handle_client_call_message (void *cls, const struct ClientCallMessage *msg)
cadet_handlers);
ch->mq = GNUNET_CADET_get_mq (ch->channel);
e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
- GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id, &ring->caller_id);
+ GNUNET_IDENTITY_key_get_public (&msg->caller_id, &ring->caller_id);
ring->expiration_time = rs.expiration_time;
- GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
- &rs,
- &ring->signature);
+ GNUNET_IDENTITY_sign (&msg->caller_id, &rs, &ring->signature);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending RING message via CADET\n");
GNUNET_MQ_send (ch->mq, e);
GNUNET_SERVICE_client_continue (line->client);
diff --git a/src/conversation/test_conversation_api.c b/src/conversation/test_conversation_api.c
index b51186dc8..c5efecd52 100644
--- a/src/conversation/test_conversation_api.c
+++ b/src/conversation/test_conversation_api.c
@@ -305,7 +305,7 @@ static void
phone_event_handler (void *cls,
enum GNUNET_CONVERSATION_PhoneEventCode code,
struct GNUNET_CONVERSATION_Caller *caller,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id)
+ const struct GNUNET_IDENTITY_PublicKey *caller_id)
{
static enum GNUNET_CONVERSATION_PhoneEventCode expect =
GNUNET_CONVERSATION_EC_PHONE_RING;
@@ -385,7 +385,7 @@ call_event_handler (void *cls, enum GNUNET_CONVERSATION_CallEventCode code)
static void
caller_ego_create_cont (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
(void) cls;
@@ -414,7 +414,7 @@ identity_cb (void *cls,
const char *name)
{
struct GNUNET_GNSRECORD_Data rd;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+ struct GNUNET_IDENTITY_PublicKey pub;
(void) cls;
(void) ctx;
@@ -465,7 +465,7 @@ identity_cb (void *cls,
static void
phone_ego_create_cont (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
(void) cls;
diff --git a/src/conversation/test_conversation_api_reject.c b/src/conversation/test_conversation_api_reject.c
index 69fa9f1dc..08c64df37 100644
--- a/src/conversation/test_conversation_api_reject.c
+++ b/src/conversation/test_conversation_api_reject.c
@@ -179,7 +179,7 @@ static void
phone_event_handler (void *cls,
enum GNUNET_CONVERSATION_PhoneEventCode code,
struct GNUNET_CONVERSATION_Caller *caller,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id)
+ const struct GNUNET_IDENTITY_PublicKey *caller_id)
{
static enum GNUNET_CONVERSATION_PhoneEventCode expect =
GNUNET_CONVERSATION_EC_PHONE_RING;
@@ -238,7 +238,7 @@ call_event_handler (void *cls, enum GNUNET_CONVERSATION_CallEventCode code)
static void
caller_ego_create_cont (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
(void) cls;
@@ -267,7 +267,7 @@ identity_cb (void *cls,
const char *name)
{
struct GNUNET_GNSRECORD_Data rd;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+ struct GNUNET_IDENTITY_PublicKey pub;
(void) cls;
(void) ctx;
@@ -318,7 +318,7 @@ identity_cb (void *cls,
static void
phone_ego_create_cont (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
(void) cls;
diff --git a/src/conversation/test_conversation_api_twocalls.c b/src/conversation/test_conversation_api_twocalls.c
index 83e8cb55a..ac7a3c9dd 100644
--- a/src/conversation/test_conversation_api_twocalls.c
+++ b/src/conversation/test_conversation_api_twocalls.c
@@ -403,7 +403,7 @@ static void
phone_event_handler (void *cls,
enum GNUNET_CONVERSATION_PhoneEventCode code,
struct GNUNET_CONVERSATION_Caller *caller,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id)
+ const struct GNUNET_IDENTITY_PublicKey *caller_id)
{
const char *cid;
@@ -507,7 +507,7 @@ call_event_handler (void *cls, enum GNUNET_CONVERSATION_CallEventCode code)
static void
caller_ego_create_cont (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
(void) cls;
@@ -536,7 +536,7 @@ identity_cb (void *cls,
const char *name)
{
struct GNUNET_GNSRECORD_Data rd;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+ struct GNUNET_IDENTITY_PublicKey pub;
(void) cls;
(void) ctx;
@@ -594,7 +594,7 @@ identity_cb (void *cls,
static void
phone_ego_create_cont (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
(void) cls;
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c
index c21be9219..724324ca4 100644
--- a/src/datacache/plugin_datacache_postgres.c
+++ b/src/datacache/plugin_datacache_postgres.c
@@ -67,14 +67,19 @@ static int
init_connection (struct Plugin *plugin)
{
struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_try_execute ("CREATE TEMPORARY SEQUENCE IF NOT EXISTS gn011dc_oid_seq"),
GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS gn011dc ("
+ " oid OID NOT NULL DEFAULT nextval('gn011dc_oid_seq'),"
" type INTEGER NOT NULL,"
" prox INTEGER NOT NULL,"
" discard_time BIGINT NOT NULL,"
" key BYTEA NOT NULL,"
" value BYTEA NOT NULL,"
- " path BYTEA DEFAULT NULL)"
- "WITH OIDS"),
+ " path BYTEA DEFAULT NULL)"),
+ GNUNET_PQ_make_try_execute (
+ "ALTER SEQUENCE gnu011dc_oid_seq OWNED BY gn011dc.oid"),
+ GNUNET_PQ_make_try_execute (
+ "CREATE INDEX IF NOT EXISTS idx_oid ON gn011dc (oid)"),
GNUNET_PQ_make_try_execute (
"CREATE INDEX IF NOT EXISTS idx_key ON gn011dc (key)"),
GNUNET_PQ_make_try_execute (
diff --git a/src/datastore/datastore_api.c b/src/datastore/datastore_api.c
index 4537f6efe..bd7a612ed 100644
--- a/src/datastore/datastore_api.c
+++ b/src/datastore/datastore_api.c
@@ -994,8 +994,8 @@ GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to put %u bytes of data under key `%s' for %s\n",
- size,
+ "Asked to put %lu bytes of data under key `%s' for %s\n",
+ (unsigned long) size,
GNUNET_h2s (key),
GNUNET_STRINGS_relative_time_to_string (
GNUNET_TIME_absolute_get_remaining (expiration),
@@ -1205,8 +1205,8 @@ GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
if (NULL == cont)
cont = &drop_status_cont;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to remove %u bytes under key `%s'\n",
- size,
+ "Asked to remove %lu bytes under key `%s'\n",
+ (unsigned long) size,
GNUNET_h2s (key));
env = GNUNET_MQ_msg_extra (dm,
size,
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c
index 88ceb1b0a..6a5d45832 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -72,8 +72,10 @@ init_connection (struct Plugin *plugin)
* we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel
* we do math or inequality tests, so we can't handle the entire range of uint32_t.
* This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
- * PostgreSQL also recommends against using WITH OIDS.
- */GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS gn090 ("
+ */
+ GNUNET_PQ_make_try_execute (
+ "CREATE SEQUENCE IF NOT EXISTS gn090_oid_seq"),
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS gn090 ("
" repl INTEGER NOT NULL DEFAULT 0,"
" type INTEGER NOT NULL DEFAULT 0,"
" prio INTEGER NOT NULL DEFAULT 0,"
@@ -82,8 +84,12 @@ init_connection (struct Plugin *plugin)
" rvalue BIGINT NOT NULL DEFAULT 0,"
" hash BYTEA NOT NULL DEFAULT '',"
" vhash BYTEA NOT NULL DEFAULT '',"
- " value BYTEA NOT NULL DEFAULT '')"
- "WITH OIDS"),
+ " value BYTEA NOT NULL DEFAULT '',"
+ " oid OID NOT NULL DEFAULT nextval('gn090_oid_seq'))"),
+ GNUNET_PQ_make_try_execute (
+ "ALTER SEQUENCE gn090_oid_seq OWNED BY gn090.oid"),
+ GNUNET_PQ_make_try_execute (
+ "CREATE INDEX IF NOT EXISTS oid_hash ON gn090 (oid)"),
GNUNET_PQ_make_try_execute (
"CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)"),
GNUNET_PQ_make_try_execute (
diff --git a/src/dht/gnunet-service-dht_clients.c b/src/dht/gnunet-service-dht_clients.c
index 1e44c1fad..5eb3115f4 100644
--- a/src/dht/gnunet-service-dht_clients.c
+++ b/src/dht/gnunet-service-dht_clients.c
@@ -488,8 +488,8 @@ handle_dht_local_put (void *cls,
GNUNET_h2s_full (&dht_msg->key));
/* give to local clients */
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Handling local PUT of %u-bytes for query %s\n",
- size - sizeof(struct GNUNET_DHT_ClientPutMessage),
+ "Handling local PUT of %lu-bytes for query %s\n",
+ (unsigned long) (size - sizeof(struct GNUNET_DHT_ClientPutMessage)),
GNUNET_h2s (&dht_msg->key));
GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (dht_msg->expiration),
&dht_msg->key,
@@ -619,7 +619,7 @@ handle_dht_local_get (void *cls,
"Received GET request for %s from local client %p, xq: %.*s\n",
GNUNET_h2s (&get->key),
ch->client,
- xquery_size,
+ (int) xquery_size,
xquery);
LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
"CLIENT-GET %s\n",
diff --git a/src/dht/gnunet-service-dht_datacache.c b/src/dht/gnunet-service-dht_datacache.c
index 41b7a3a2b..7eded2152 100644
--- a/src/dht/gnunet-service-dht_datacache.c
+++ b/src/dht/gnunet-service-dht_datacache.c
@@ -94,9 +94,9 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
put_path_length,
put_path);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
+ "DATACACHE PUT for key %s [%lu] completed (%d) after %u hops\n",
GNUNET_h2s (key),
- data_size,
+ (unsigned long) data_size,
r,
put_path_length);
}
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
index b211fca6b..88b0c5d92 100644
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ b/src/dht/gnunet-service-dht_neighbours.c
@@ -2212,8 +2212,8 @@ handle_dht_p2p_get (void *cls,
bg,
peer_bf);
GDS_CLIENTS_process_get (options
- | (GNUNET_OK == forwarded)
- ? GNUNET_DHT_RO_LAST_HOP : 0,
+ | ((GNUNET_OK == forwarded)
+ ? GNUNET_DHT_RO_LAST_HOP : 0),
type,
ntohl (get->hop_count),
ntohl (get->desired_replication_level),
diff --git a/src/dht/plugin_block_dht.c b/src/dht/plugin_block_dht.c
index f213433ed..a9f336240 100644
--- a/src/dht/plugin_block_dht.c
+++ b/src/dht/plugin_block_dht.c
@@ -195,7 +195,7 @@ block_plugin_dht_get_key (void *cls,
{
GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
"block-dht",
- _ ("Size mismatch for block\n"),
+ _ ("Size mismatch for block with type %u\n"),
GNUNET_BLOCK_TYPE_DHT_HELLO);
return GNUNET_NO;
}
diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c
index d9830baa4..836d65c79 100644
--- a/src/dns/gnunet-dns-monitor.c
+++ b/src/dns/gnunet-dns-monitor.c
@@ -203,7 +203,7 @@ display_record (const struct GNUNET_DNSPARSER_Record *record)
else
{
GNUNET_asprintf (&tmp,
- "priority %u, weight = %s, port = %u, target = %s",
+ "priority %u, weight = %u, port = %u, target = %s",
(unsigned int) record->data.srv->priority,
(unsigned int) record->data.srv->weight,
(unsigned int) record->data.srv->port,
diff --git a/src/fragmentation/fragmentation.c b/src/fragmentation/fragmentation.c
index 3a7da37e8..36e1c33f4 100644
--- a/src/fragmentation/fragmentation.c
+++ b/src/fragmentation/fragmentation.c
@@ -158,7 +158,7 @@ GNUNET_FRAGMENT_print_ack (const struct GNUNET_MessageHeader *ack)
sizeof(buf),
"%u-%llX",
ntohl (fa->fragment_id),
- GNUNET_ntohll (fa->bits));
+ (unsigned long long) GNUNET_ntohll (fa->bits));
return buf;
}
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c
index 6154e8be0..d4677b794 100644
--- a/src/fs/fs_download.c
+++ b/src/fs/fs_download.c
@@ -1050,7 +1050,7 @@ process_result_with_request (void *cls,
GNUNET_asprintf (
&dc->emsg,
_ (
- "Internal error or bogus download URI (expected %u bytes at depth %u and offset %llu/%llu, got %u bytes)"),
+ "Internal error or bogus download URI (expected %lu bytes at depth %u and offset %llu/%llu, got %lu bytes)"),
bs,
dr->depth,
(unsigned long long) dr->offset,
diff --git a/src/fs/gnunet-daemon-fsprofiler.c b/src/fs/gnunet-daemon-fsprofiler.c
index 829906461..fbb7c6028 100644
--- a/src/fs/gnunet-daemon-fsprofiler.c
+++ b/src/fs/gnunet-daemon-fsprofiler.c
@@ -592,14 +592,14 @@ run (void *cls, char *const *args GNUNET_UNUSED,
&replication_level))
replication_level = 1;
GNUNET_snprintf (myoptname, sizeof(myoptname),
- "DOWNLOAD-PATTERN-%u", my_peerid);
+ "DOWNLOAD-PATTERN-%llu", my_peerid);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"FSPROFILER", myoptname,
&download_pattern))
download_pattern = GNUNET_strdup ("");
GNUNET_snprintf (myoptname, sizeof(myoptname),
- "PUBLISH-PATTERN-%u", my_peerid);
+ "PUBLISH-PATTERN-%llu", my_peerid);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"FSPROFILER", myoptname,
diff --git a/src/fs/gnunet-publish.c b/src/fs/gnunet-publish.c
index 91fcd8f8a..dea467669 100644
--- a/src/fs/gnunet-publish.c
+++ b/src/fs/gnunet-publish.c
@@ -475,6 +475,7 @@ uri_ksk_continuation (void *cls,
const char *emsg)
{
const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
+ const struct GNUNET_IDENTITY_PrivateKey *pk;
if (NULL != emsg)
{
@@ -486,7 +487,10 @@ uri_ksk_continuation (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- priv = GNUNET_IDENTITY_ego_get_private_key (namespace);
+ pk = GNUNET_IDENTITY_ego_get_private_key (namespace);
+ if (GNUNET_IDENTITY_TYPE_ECDSA != ntohl (pk->type))
+ return;
+ priv = &pk->ecdsa_key;
GNUNET_FS_publish_sks (ctx,
priv,
this_id,
@@ -569,6 +573,7 @@ directory_trim_complete (struct GNUNET_FS_ShareTreeItem *directory_scan_result)
{
struct GNUNET_FS_FileInformation *fi;
const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
+ const struct GNUNET_IDENTITY_PrivateKey *pk;
fi = get_file_information (directory_scan_result);
GNUNET_FS_share_tree_free (directory_scan_result);
@@ -586,10 +591,13 @@ directory_trim_complete (struct GNUNET_FS_ShareTreeItem *directory_scan_result)
GNUNET_SCHEDULER_shutdown ();
return;
}
- if (NULL == namespace)
- priv = NULL;
- else
- priv = GNUNET_IDENTITY_ego_get_private_key (namespace);
+ priv = NULL;
+ if (NULL != namespace)
+ {
+ pk = GNUNET_IDENTITY_ego_get_private_key (namespace);
+ GNUNET_assert (GNUNET_IDENTITY_TYPE_ECDSA == ntohl (pk->type));
+ priv = &pk->ecdsa_key;
+ }
pc = GNUNET_FS_publish_start (ctx,
fi,
priv,
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
index 5a9c70997..744ba66ec 100644
--- a/src/gns/Makefile.am
+++ b/src/gns/Makefile.am
@@ -109,6 +109,7 @@ libgnunet_plugin_rest_gns_la_SOURCES = \
plugin_rest_gns.c
libgnunet_plugin_rest_gns_la_LIBADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecordjson.la \
libgnunetgns.la \
$(top_builddir)/src/rest/libgnunetrest.la \
$(top_builddir)/src/identity/libgnunetidentity.la \
@@ -124,6 +125,7 @@ libgnunet_plugin_gnsrecord_gns_la_SOURCES = \
plugin_gnsrecord_gns.c
libgnunet_plugin_gnsrecord_gns_la_LIBADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(LTLIBINTL)
libgnunet_plugin_gnsrecord_gns_la_LDFLAGS = \
@@ -135,6 +137,7 @@ gnunet_gns_SOURCES = \
gnunet_gns_LDADD = \
libgnunetgns.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(LIBIDN) $(LIBIDN2) \
$(GN_LIBINTL)
@@ -144,6 +147,7 @@ gnunet_gns_benchmark_SOURCES = \
gnunet_gns_benchmark_LDADD = \
libgnunetgns.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL)
@@ -247,6 +251,7 @@ libgnunet_plugin_block_gns_la_LIBADD = \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/block/libgnunetblock.la \
$(top_builddir)/src/block/libgnunetblockgroup.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la
libgnunet_plugin_block_gns_la_LDFLAGS = \
$(GN_LIBINTL) \
diff --git a/src/gns/gns.h b/src/gns/gns.h
index a193632b7..d824742ad 100644
--- a/src/gns/gns.h
+++ b/src/gns/gns.h
@@ -48,7 +48,7 @@ struct LookupMessage
/**
* Zone that is to be used for lookup
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey zone;
+ struct GNUNET_IDENTITY_PublicKey zone;
/**
* Local options for where to look for results
diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c
index bf95bf340..841a0d240 100644
--- a/src/gns/gns_api.c
+++ b/src/gns/gns_api.c
@@ -343,7 +343,7 @@ GNUNET_GNS_lookup_cancel (struct GNUNET_GNS_LookupRequest *lr)
struct GNUNET_GNS_LookupRequest *
GNUNET_GNS_lookup_limited (struct GNUNET_GNS_Handle *handle,
const char *name,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
+ const struct GNUNET_IDENTITY_PublicKey *zone,
uint32_t type,
enum GNUNET_GNS_LocalOptions options,
uint16_t recursion_depth_limit,
@@ -411,7 +411,7 @@ GNUNET_GNS_lookup_limited (struct GNUNET_GNS_Handle *handle,
struct GNUNET_GNS_LookupRequest*
GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
const char *name,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
+ const struct GNUNET_IDENTITY_PublicKey *zone,
uint32_t type,
enum GNUNET_GNS_LocalOptions options,
GNUNET_GNS_LookupResultProcessor proc,
diff --git a/src/gns/gns_tld_api.c b/src/gns/gns_tld_api.c
index 3ebf07db6..b883662ad 100644
--- a/src/gns/gns_tld_api.c
+++ b/src/gns/gns_tld_api.c
@@ -167,7 +167,7 @@ process_lookup_result (void *cls,
*/
static void
lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
+ const struct GNUNET_IDENTITY_PublicKey *pkey)
{
ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
ltr->name,
@@ -190,11 +190,11 @@ lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
*/
static void
identity_zone_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+ const struct GNUNET_IDENTITY_PrivateKey *priv,
const char *ego_name)
{
struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
- struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+ struct GNUNET_IDENTITY_PublicKey pkey;
ltr->id_co = NULL;
if (NULL == priv)
@@ -219,7 +219,7 @@ identity_zone_cb (void *cls,
ltr->options = GNUNET_GNS_LO_NO_DHT;
else
ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
- GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pkey);
+ GNUNET_IDENTITY_key_get_public (priv, &pkey);
lookup_with_public_key (ltr, &pkey);
}
@@ -249,7 +249,7 @@ GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
const char *tld;
char *dot_tld;
char *zonestr;
- struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+ struct GNUNET_IDENTITY_PublicKey pkey;
ltr = GNUNET_new (struct GNUNET_GNS_LookupWithTldRequest);
ltr->gns_handle = handle;
@@ -261,8 +261,10 @@ GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
/* start with trivial case: TLD is zkey */
tld = get_tld (ltr->name);
if (GNUNET_OK ==
- GNUNET_CRYPTO_ecdsa_public_key_from_string (tld, strlen (tld), &pkey))
+ GNUNET_IDENTITY_public_key_from_string (tld, &pkey))
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "`%s' seems to be a valid zone key\n", tld);
eat_tld (ltr->name, tld);
lookup_with_public_key (ltr, &pkey);
return ltr;
@@ -281,9 +283,8 @@ GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
&zonestr))
{
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (zonestr,
- strlen (zonestr),
- &pkey))
+ GNUNET_IDENTITY_public_key_from_string (zonestr,
+ &pkey))
{
GNUNET_log_config_invalid (
GNUNET_ERROR_TYPE_ERROR,
@@ -304,6 +305,8 @@ GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
}
GNUNET_free (dot_tld);
}
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "`%s' should be a valid ego\n", ltr->name);
ltr->id_co =
GNUNET_IDENTITY_ego_lookup_by_suffix (ltr->gns_handle->cfg,
ltr->name,
diff --git a/src/gns/gnunet-gns-import.c b/src/gns/gnunet-gns-import.c
index 78db28cab..972fb49cd 100644
--- a/src/gns/gnunet-gns-import.c
+++ b/src/gns/gnunet-gns-import.c
@@ -168,12 +168,17 @@ check_pkey (unsigned int rd_len, const struct GNUNET_GNSRECORD_Data *rd,
char *pk, int *found_rec)
{
int i;
+ struct GNUNET_IDENTITY_PublicKey pubkey;
for (i = 0; i < rd_len; i++)
{
char *s;
- if ((GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type) ||
- (rd[i].data_size != sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+ if (sizeof (uint32_t) > rd[i].data_size)
+ continue;
+ if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (rd[i].data,
+ rd[i].data_size,
+ rd[i].record_type,
+ &pubkey))
continue;
s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
rd[i].data,
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
index 8c5b2d6c4..52300ae3b 100644
--- a/src/gns/gnunet-service-gns.c
+++ b/src/gns/gnunet-service-gns.c
@@ -123,7 +123,7 @@ struct GNS_TopLevelDomain
/**
* Public key associated with the @a tld.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+ struct GNUNET_IDENTITY_PublicKey pkey;
/**
* Top-level domain as a string, including leading ".".
@@ -177,7 +177,7 @@ static struct GNS_TopLevelDomain *tld_tail;
*/
int
GNS_find_tld (const char *tld_str,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
+ struct GNUNET_IDENTITY_PublicKey *pkey)
{
if ('\0' == *tld_str)
return GNUNET_NO;
@@ -485,7 +485,7 @@ read_service_conf (void *cls,
const char *option,
const char *value)
{
- struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+ struct GNUNET_IDENTITY_PublicKey pk;
struct GNS_TopLevelDomain *tld;
(void) cls;
diff --git a/src/gns/gnunet-service-gns.h b/src/gns/gnunet-service-gns.h
index 2a432f8aa..d4fb9ec9f 100644
--- a/src/gns/gnunet-service-gns.h
+++ b/src/gns/gnunet-service-gns.h
@@ -26,6 +26,7 @@
#ifndef GNUNET_SERVICE_GNS_H
#define GNUNET_SERVICE_GNS_H
+#include "gnunet_identity_service.h"
/**
* Find GNS zone belonging to TLD @a tld.
@@ -36,7 +37,7 @@
*/
int
GNS_find_tld (const char *tld_str,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pkey);
+ struct GNUNET_IDENTITY_PublicKey *pkey);
/**
diff --git a/src/gns/gnunet-service-gns_interceptor.c b/src/gns/gnunet-service-gns_interceptor.c
index 19416a506..b53f4af6b 100644
--- a/src/gns/gnunet-service-gns_interceptor.c
+++ b/src/gns/gnunet-service-gns_interceptor.c
@@ -314,7 +314,7 @@ handle_dns_request (void *cls,
{
struct GNUNET_DNSPARSER_Packet *p;
struct InterceptLookupHandle *ilh;
- struct GNUNET_CRYPTO_EcdsaPublicKey zone;
+ struct GNUNET_IDENTITY_PublicKey zone;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Hijacked a DNS request. Processing.\n");
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
index cb75b23c7..d9d0d3099 100644
--- a/src/gns/gnunet-service-gns_resolver.c
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -173,7 +173,7 @@ struct AuthorityChain
/**
* The zone of the GNS authority
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey gns_authority;
+ struct GNUNET_IDENTITY_PublicKey gns_authority;
struct
{
@@ -305,7 +305,7 @@ struct GNS_ResolverHandle
/**
* The top-level GNS authoritative zone to query
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey authority_zone;
+ struct GNUNET_IDENTITY_PublicKey authority_zone;
/**
* called when resolution phase finishes
@@ -1251,7 +1251,7 @@ handle_gns_cname_result (struct GNS_ResolverHandle *rh,
const char *tld;
struct AuthorityChain *ac;
int af;
- struct GNUNET_CRYPTO_EcdsaPublicKey zone;
+ struct GNUNET_IDENTITY_PublicKey zone;
nlen = strlen (cname);
tld = GNS_get_tld (cname);
@@ -1296,7 +1296,7 @@ handle_gns_cname_result (struct GNS_ResolverHandle *rh,
{
GNUNET_asprintf (&res,
"%.*s",
- strlen (cname) - (strlen (tld) + 1),
+ (int) (strlen (cname) - (strlen (tld) + 1)),
cname);
}
else
@@ -1305,7 +1305,7 @@ handle_gns_cname_result (struct GNS_ResolverHandle *rh,
"%.*s.%.*s",
(int) rh->name_resolution_pos,
rh->name,
- (int) strlen (cname) - (strlen (tld) + 1),
+ (int) (strlen (cname) - (strlen (tld) + 1)),
cname);
}
rh->name_resolution_pos = strlen (res);
@@ -1696,10 +1696,13 @@ recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
const struct GNUNET_GNSRECORD_Data *rd)
{
struct AuthorityChain *ac;
+ struct GNUNET_IDENTITY_PublicKey auth;
/* delegation to another zone */
- if (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) !=
- rd->data_size)
+ if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (rd->data,
+ rd->data_size,
+ rd->record_type,
+ &auth))
{
GNUNET_break_op (0);
fail_resolution (rh);
@@ -1709,9 +1712,7 @@ recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
ac = GNUNET_new (struct AuthorityChain);
ac->rh = rh;
ac->gns_authority = GNUNET_YES;
- GNUNET_memcpy (&ac->authority_info.gns_authority,
- rd->data,
- sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
+ ac->authority_info.gns_authority = auth;
ac->label = resolver_lookup_get_next_label (rh);
/* add AC to tail */
GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
@@ -1754,7 +1755,7 @@ recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
char *n;
size_t off;
struct Gns2DnsPending *gp;
- struct GNUNET_CRYPTO_EcdsaPublicKey zone;
+ struct GNUNET_IDENTITY_PublicKey zone;
struct sockaddr_in v4;
struct sockaddr_in6 v6;
@@ -2257,19 +2258,25 @@ handle_gns_resolution_result (void *cls,
break;
case GNUNET_GNSRECORD_TYPE_PKEY:
+ case GNUNET_GNSRECORD_TYPE_EDKEY:
{
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
-
- if (rd[i].data_size != sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))
+ struct GNUNET_IDENTITY_PublicKey pubkey;
+ if (rd[i].data_size < sizeof(uint32_t))
+ {
+ GNUNET_break_op (0);
+ break;
+ }
+ if (GNUNET_OK !=
+ GNUNET_GNSRECORD_identity_from_data (rd[i].data,
+ rd[i].data_size,
+ rd[i].record_type,
+ &pubkey))
{
GNUNET_break_op (0);
break;
}
- GNUNET_memcpy (&pub,
- rd[i].data,
- rd[i].data_size);
rd_off++;
- if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
+ if (rd[i].record_type != rh->record_type)
{
/* try to resolve "@" */
struct AuthorityChain *ac;
@@ -2277,7 +2284,7 @@ handle_gns_resolution_result (void *cls,
ac = GNUNET_new (struct AuthorityChain);
ac->rh = rh;
ac->gns_authority = GNUNET_YES;
- ac->authority_info.gns_authority = pub;
+ ac->authority_info.gns_authority = pubkey;
ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
rh->ac_tail,
@@ -2367,6 +2374,7 @@ handle_gns_resolution_result (void *cls,
return;
case GNUNET_GNSRECORD_TYPE_PKEY:
+ case GNUNET_GNSRECORD_TYPE_EDKEY:
GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
recursive_pkey_resolution (rh,
&rd[0]);
@@ -2469,10 +2477,7 @@ handle_dht_response (void *cls,
return;
}
block = data;
- if (size !=
- ntohl (block->purpose.size)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
- + sizeof(struct GNUNET_CRYPTO_EcdsaSignature))
+ if (size != GNUNET_GNSRECORD_block_get_size (block))
{
/* how did this pass DHT block validation!? */
GNUNET_break (0);
@@ -2480,8 +2485,8 @@ handle_dht_response (void *cls,
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Decrypting DHT block of size %u for `%s', expires %s\n",
- ntohl (block->purpose.size),
+ "Decrypting DHT block of size %lu for `%s', expires %s\n",
+ GNUNET_GNSRECORD_block_get_size (block),
rh->name,
GNUNET_STRINGS_absolute_time_to_string (exp));
if (GNUNET_OK !=
@@ -2495,8 +2500,8 @@ handle_dht_response (void *cls,
fail_resolution (rh);
return;
}
- if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
- block->expiration_time)).
+ if (0 == GNUNET_TIME_absolute_get_remaining (
+ GNUNET_GNSRECORD_block_get_expiration (block)).
rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2594,7 +2599,7 @@ handle_namecache_block_response (void *cls,
struct GNS_ResolverHandle *rh = cls;
struct AuthorityChain *ac = rh->ac_tail;
const char *label = ac->label;
- const struct GNUNET_CRYPTO_EcdsaPublicKey *auth =
+ const struct GNUNET_IDENTITY_PublicKey *auth =
&ac->authority_info.gns_authority;
struct GNUNET_HashCode query;
@@ -2604,8 +2609,8 @@ handle_namecache_block_response (void *cls,
((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
(ac != rh->ac_head))) &&
((NULL == block) ||
- (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
- block->expiration_time)).
+ (0 == GNUNET_TIME_absolute_get_remaining (
+ GNUNET_GNSRECORD_block_get_expiration (block)).
rel_value_us)))
{
/* namecache knows nothing; try DHT lookup */
@@ -2622,8 +2627,8 @@ handle_namecache_block_response (void *cls,
}
if ((NULL == block) ||
- (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
- block->expiration_time)).
+ (0 == GNUNET_TIME_absolute_get_remaining (
+ GNUNET_GNSRECORD_block_get_expiration (block)).
rel_value_us))
{
/* DHT not permitted and no local result, fail */
@@ -2857,7 +2862,7 @@ start_resolver_lookup (void *cls)
* @return handle to cancel operation
*/
struct GNS_ResolverHandle *
-GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
+GNS_resolver_lookup (const struct GNUNET_IDENTITY_PublicKey *zone,
uint32_t record_type,
const char *name,
enum GNUNET_GNS_LocalOptions options,
diff --git a/src/gns/gnunet-service-gns_resolver.h b/src/gns/gnunet-service-gns_resolver.h
index 3dab3c91a..b099c5d65 100644
--- a/src/gns/gnunet-service-gns_resolver.h
+++ b/src/gns/gnunet-service-gns_resolver.h
@@ -86,7 +86,7 @@ typedef void
* @return handle to cancel operation
*/
struct GNS_ResolverHandle *
-GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
+GNS_resolver_lookup (const struct GNUNET_IDENTITY_PublicKey *zone,
uint32_t record_type,
const char *name,
enum GNUNET_GNS_LocalOptions options,
diff --git a/src/gns/plugin_block_gns.c b/src/gns/plugin_block_gns.c
index aabedcaac..9b58c9034 100644
--- a/src/gns/plugin_block_gns.c
+++ b/src/gns/plugin_block_gns.c
@@ -145,17 +145,13 @@ block_plugin_gns_evaluate (void *cls,
return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
}
block = reply_block;
- if (ntohl (block->purpose.size) + sizeof(struct
- GNUNET_CRYPTO_EcdsaSignature)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) !=
- reply_block_size)
+ if (GNUNET_GNSRECORD_block_get_size (block) > reply_block_size)
{
GNUNET_break_op (0);
return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
}
- GNUNET_CRYPTO_hash (&block->derived_key,
- sizeof(block->derived_key),
- &h);
+ GNUNET_GNSRECORD_query_from_block (block,
+ &h);
if (0 != GNUNET_memcmp (&h, query))
{
GNUNET_break_op (0);
@@ -206,9 +202,8 @@ block_plugin_gns_get_key (void *cls,
return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
}
block = reply_block;
- GNUNET_CRYPTO_hash (&block->derived_key,
- sizeof(block->derived_key),
- key);
+ GNUNET_GNSRECORD_query_from_block (block,
+ key);
return GNUNET_OK;
}
diff --git a/src/gns/plugin_gnsrecord_gns.c b/src/gns/plugin_gnsrecord_gns.c
index 81f2b9eff..a2ad0b905 100644
--- a/src/gns/plugin_gnsrecord_gns.c
+++ b/src/gns/plugin_gnsrecord_gns.c
@@ -50,13 +50,18 @@ gns_value_to_string (void *cls,
size_t data_size)
{
const char *cdata;
+ struct GNUNET_IDENTITY_PublicKey pk;
switch (type)
{
case GNUNET_GNSRECORD_TYPE_PKEY:
- if (data_size != sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))
+ case GNUNET_GNSRECORD_TYPE_EDKEY:
+ if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (data,
+ data_size,
+ type,
+ &pk))
return NULL;
- return GNUNET_CRYPTO_ecdsa_public_key_to_string (data);
+ return GNUNET_IDENTITY_public_key_to_string (&pk);
case GNUNET_GNSRECORD_TYPE_NICK:
return GNUNET_strndup (data, data_size);
@@ -153,24 +158,35 @@ gns_string_to_value (void *cls,
void **data,
size_t *data_size)
{
- struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+ struct GNUNET_IDENTITY_PublicKey pk;
+ uint32_t record_type;
if (NULL == s)
return GNUNET_SYSERR;
switch (type)
{
case GNUNET_GNSRECORD_TYPE_PKEY:
+ case GNUNET_GNSRECORD_TYPE_EDKEY:
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (s, strlen (s), &pkey))
+ GNUNET_IDENTITY_public_key_from_string (s, &pk))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _ ("Unable to parse PKEY record `%s'\n"),
+ _ ("Unable to parse zone key record `%s'\n"),
s);
return GNUNET_SYSERR;
}
- *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
- GNUNET_memcpy (*data, &pkey, sizeof(pkey));
- *data_size = sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey);
+ *data_size = GNUNET_IDENTITY_key_get_length (&pk);
+ if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&pk,
+ (char **) data,
+ data_size,
+ &record_type))
+ return GNUNET_SYSERR;
+ if (record_type != type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Record type does not match parsed record type\n"));
+ return GNUNET_SYSERR;
+ }
return GNUNET_OK;
case GNUNET_GNSRECORD_TYPE_NICK:
@@ -301,6 +317,7 @@ static struct
const char *name;
uint32_t number;
} gns_name_map[] = { { "PKEY", GNUNET_GNSRECORD_TYPE_PKEY },
+ { "EDKEY", GNUNET_GNSRECORD_TYPE_PKEY },
{ "NICK", GNUNET_GNSRECORD_TYPE_NICK },
{ "LEHO", GNUNET_GNSRECORD_TYPE_LEHO },
{ "VPN", GNUNET_GNSRECORD_TYPE_VPN },
diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c
index 6ec921f70..2ccb5be2b 100644
--- a/src/gns/plugin_rest_gns.c
+++ b/src/gns/plugin_rest_gns.c
@@ -28,6 +28,7 @@
#include "gnunet_rest_lib.h"
#include "gnunet_json_lib.h"
#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_gnsrecord_json_lib.h"
#include "gnunet_gns_service.h"
#include "microhttpd.h"
#include <jansson.h>
@@ -264,7 +265,7 @@ handle_gns_response (void *cls,
return;
}
- result_obj = GNUNET_JSON_from_gnsrecord (handle->name, rd, rd_count);
+ result_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (handle->name, rd, rd_count);
result = json_dumps (result_obj, 0);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result);
diff --git a/src/gns/test_gns_dht_lookup.sh b/src/gns/test_gns_dht_lookup.sh
index d5516fd03..8d446c507 100755
--- a/src/gns/test_gns_dht_lookup.sh
+++ b/src/gns/test_gns_dht_lookup.sh
@@ -26,6 +26,7 @@ gnunet-arm -i datastore -c test_gns_lookup.conf
gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
+echo "MYEGO: $MY_EGO OTHER_EGO: $DELEGATED_PKEY"
gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
#This works
gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
diff --git a/src/gnsrecord/Makefile.am b/src/gnsrecord/Makefile.am
index 2e6eca7ba..ab604eb92 100644
--- a/src/gnsrecord/Makefile.am
+++ b/src/gnsrecord/Makefile.am
@@ -1,5 +1,5 @@
# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/src/include ${MHD_CFLAGS}
plugindir = $(libdir)/gnunet
@@ -30,12 +30,14 @@ TESTS = \
endif
lib_LTLIBRARIES = \
- libgnunetgnsrecord.la
+ libgnunetgnsrecord.la \
+ libgnunetgnsrecordjson.la
gnunet_gnsrecord_tvg_SOURCES = \
gnunet-gnsrecord-tvg.c
gnunet_gnsrecord_tvg_LDADD = \
$(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
libgnunetgnsrecord.la \
$(GN_LIBINTL)
@@ -47,11 +49,26 @@ libgnunetgnsrecord_la_SOURCES = \
gnsrecord_misc.c
libgnunetgnsrecord_la_LIBADD = \
$(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ $(LIBGCRYPT_LIBS) \
$(GN_LIBINTL)
+libgnunetgnsrecord_la_DEPENDENCIES = \
+ $(top_builddir)/src/identity/libgnunetidentity.la
libgnunetgnsrecord_la_LDFLAGS = \
$(GN_LIB_LDFLAGS) \
-version-info 0:0:0
+libgnunetgnsrecordjson_la_SOURCES = \
+ json_gnsrecord.c
+libgnunetgnsrecordjson_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ libgnunetgnsrecord.la \
+ -ljansson \
+ $(GN_LIBINTL)
+libgnunetgnsrecordjson_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) \
+ -version-info 0:0:0
plugin_LTLIBRARIES = \
libgnunet_plugin_gnsrecord_dns.la
diff --git a/src/gnsrecord/gnsrecord_crypto.c b/src/gnsrecord/gnsrecord_crypto.c
index c8919760a..9c551a936 100644
--- a/src/gnsrecord/gnsrecord_crypto.c
+++ b/src/gnsrecord/gnsrecord_crypto.c
@@ -37,6 +37,61 @@
#define LOG(kind, ...) GNUNET_log_from (kind, "gnsrecord", __VA_ARGS__)
+ssize_t
+ecdsa_symmetric_decrypt (
+ const void *block,
+ size_t size,
+ const unsigned char *key,
+ const unsigned char *ctr,
+ void *result)
+{
+ gcry_cipher_hd_t handle;
+ int rc;
+
+ GNUNET_assert (0 == gcry_cipher_open (&handle, GCRY_CIPHER_AES256,
+ GCRY_CIPHER_MODE_CTR, 0));
+ rc = gcry_cipher_setkey (handle,
+ key,
+ GNUNET_CRYPTO_AES_KEY_LENGTH);
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+ rc = gcry_cipher_setctr (handle,
+ ctr,
+ GNUNET_CRYPTO_AES_KEY_LENGTH / 2);
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+ GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, block, size));
+ gcry_cipher_close (handle);
+ return size;
+}
+
+
+
+ssize_t
+ecdsa_symmetric_encrypt (
+ const void *block,
+ size_t size,
+ const unsigned char *key,
+ const unsigned char *ctr,
+ void *result)
+{
+ gcry_cipher_hd_t handle;
+ int rc;
+
+ GNUNET_assert (0 == gcry_cipher_open (&handle, GCRY_CIPHER_AES256,
+ GCRY_CIPHER_MODE_CTR, 0));
+ rc = gcry_cipher_setkey (handle,
+ key,
+ GNUNET_CRYPTO_AES_KEY_LENGTH);
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+ rc = gcry_cipher_setctr (handle,
+ ctr,
+ GNUNET_CRYPTO_AES_KEY_LENGTH / 2);
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+ GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, size, block, size));
+ gcry_cipher_close (handle);
+ return size;
+}
+
+
/**
* Derive session key and iv from label and public key.
@@ -47,25 +102,31 @@
* @param pub public key to use for KDF
*/
static void
-derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
- struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
+derive_block_aes_key (unsigned char *ctr,
+ unsigned char *key,
const char *label,
+ uint64_t exp,
const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
{
static const char ctx_key[] = "gns-aes-ctx-key";
static const char ctx_iv[] = "gns-aes-ctx-iv";
- GNUNET_CRYPTO_kdf (skey, sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
+ GNUNET_CRYPTO_kdf (key, GNUNET_CRYPTO_AES_KEY_LENGTH,
ctx_key, strlen (ctx_key),
pub, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
label, strlen (label),
NULL, 0);
- GNUNET_CRYPTO_kdf (iv, sizeof(struct
- GNUNET_CRYPTO_SymmetricInitializationVector),
+ memset (ctr, 0, GNUNET_CRYPTO_AES_KEY_LENGTH / 2);
+ /** 4 byte nonce **/
+ GNUNET_CRYPTO_kdf (ctr, 4,
ctx_iv, strlen (ctx_iv),
pub, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
label, strlen (label),
NULL, 0);
+ /** Expiration time 64 bit. **/
+ memcpy (ctr + 4, &exp, sizeof (exp));
+ /** Set counter part to 1 **/
+ ctr[15] |= 0x01;
}
@@ -81,19 +142,20 @@ derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
* @return NULL on error (block too large)
*/
static struct GNUNET_GNSRECORD_Block *
-block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
- struct GNUNET_TIME_Absolute expire,
- const char *label,
- const struct GNUNET_GNSRECORD_Data *rd,
- unsigned int rd_count)
+block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
+ struct GNUNET_TIME_Absolute expire,
+ const char *label,
+ const struct GNUNET_GNSRECORD_Data *rd,
+ unsigned int rd_count)
{
ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count,
rd);
struct GNUNET_GNSRECORD_Block *block;
+ struct GNUNET_GNSRECORD_EcdsaBlock *ecblock;
struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+ unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2];
+ unsigned char skey[GNUNET_CRYPTO_AES_KEY_LENGTH];
struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL (rd_count)];
uint32_t rd_count_nbo;
struct GNUNET_TIME_Absolute now;
@@ -140,35 +202,38 @@ block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
block = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Block)
+ sizeof(uint32_t)
+ payload_len);
- block->purpose.size = htonl (sizeof(uint32_t)
- + payload_len
- + sizeof(struct
- GNUNET_CRYPTO_EccSignaturePurpose)
- + sizeof(struct GNUNET_TIME_AbsoluteNBO));
- block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
- block->expiration_time = GNUNET_TIME_absolute_hton (expire);
+ ecblock = &block->ecdsa_block;
+ block->type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
+ ecblock->purpose.size = htonl (sizeof(uint32_t)
+ + payload_len
+ + sizeof(struct
+ GNUNET_CRYPTO_EccSignaturePurpose)
+ + sizeof(struct GNUNET_TIME_AbsoluteNBO));
+ ecblock->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
+ ecblock->expiration_time = GNUNET_TIME_absolute_hton (expire);
/* encrypt and sign */
dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
label,
"gns");
GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
- &block->derived_key);
- derive_block_aes_key (&iv,
- &skey,
+ &ecblock->derived_key);
+ derive_block_aes_key (ctr,
+ skey,
label,
+ ecblock->expiration_time.abs_value_us__,
pkey);
GNUNET_break (payload_len + sizeof(uint32_t) ==
- GNUNET_CRYPTO_symmetric_encrypt (payload,
- payload_len
- + sizeof(uint32_t),
- &skey,
- &iv,
- &block[1]));
+ ecdsa_symmetric_encrypt (payload,
+ payload_len
+ + sizeof(uint32_t),
+ skey,
+ ctr,
+ &ecblock[1]));
}
if (GNUNET_OK !=
GNUNET_CRYPTO_ecdsa_sign_ (dkey,
- &block->purpose,
- &block->signature))
+ &ecblock->purpose,
+ &ecblock->signature))
{
GNUNET_break (0);
GNUNET_free (dkey);
@@ -191,7 +256,7 @@ block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
* @return NULL on error (block too large)
*/
struct GNUNET_GNSRECORD_Block *
-GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key,
struct GNUNET_TIME_Absolute expire,
const char *label,
const struct GNUNET_GNSRECORD_Data *rd,
@@ -199,14 +264,21 @@ GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
{
struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
- GNUNET_CRYPTO_ecdsa_key_get_public (key,
- &pkey);
- return block_create (key,
- &pkey,
- expire,
- label,
- rd,
- rd_count);
+ switch (ntohl (key->type))
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+ GNUNET_CRYPTO_ecdsa_key_get_public (&key->ecdsa_key,
+ &pkey);
+ return block_create_ecdsa (&key->ecdsa_key,
+ &pkey,
+ expire,
+ label,
+ rd,
+ rd_count);
+ default:
+ GNUNET_assert (0);
+ }
+ return NULL;
}
@@ -240,12 +312,19 @@ struct KeyCacheLine
* @return NULL on error (block too large)
*/
struct GNUNET_GNSRECORD_Block *
-GNUNET_GNSRECORD_block_create2 (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey,
struct GNUNET_TIME_Absolute expire,
const char *label,
const struct GNUNET_GNSRECORD_Data *rd,
unsigned int rd_count)
{
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
+
+ if (GNUNET_IDENTITY_TYPE_ECDSA != ntohl (pkey->type))
+ {
+ return NULL; // FIXME
+ }
+ key = &pkey->ecdsa_key;
#define CSIZE 64
static struct KeyCacheLine cache[CSIZE];
struct KeyCacheLine *line;
@@ -261,12 +340,12 @@ GNUNET_GNSRECORD_block_create2 (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
&line->pkey);
}
#undef CSIZE
- return block_create (key,
- &line->pkey,
- expire,
- label,
- rd,
- rd_count);
+ return block_create_ecdsa (key,
+ &line->pkey,
+ expire,
+ label,
+ rd,
+ rd_count);
}
@@ -277,40 +356,40 @@ GNUNET_GNSRECORD_block_create2 (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
* @param block block to verify
* @return #GNUNET_OK if the signature is valid
*/
-int
+enum GNUNET_GenericReturnValue
GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block)
{
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *key;
+ const struct GNUNET_GNSRECORD_EcdsaBlock *ecblock;
+
+ if (GNUNET_GNSRECORD_TYPE_PKEY != ntohl (block->type))
+ {
+ GNUNET_break (0);
+ return GNUNET_NO;
+ }
+ ecblock = &block->ecdsa_block;
+ key = &ecblock->derived_key;
+
return GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
- &block->purpose,
- &block->signature,
- &block->derived_key);
+ &ecblock->purpose,
+ &ecblock->signature,
+ key);
}
-/**
- * Decrypt block.
- *
- * @param block block to decrypt
- * @param zone_key public key of the zone
- * @param label the name for the records
- * @param proc function to call with the result
- * @param proc_cls closure for proc
- * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
- * not well-formed
- */
-int
-GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
- const struct
- GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
- const char *label,
- GNUNET_GNSRECORD_RecordCallback proc,
- void *proc_cls)
+enum GNUNET_GenericReturnValue
+block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_EcdsaBlock *block,
+ const struct
+ GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
+ const char *label,
+ GNUNET_GNSRECORD_RecordCallback proc,
+ void *proc_cls)
{
size_t payload_len = ntohl (block->purpose.size)
- sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
- sizeof(struct GNUNET_TIME_AbsoluteNBO);
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+ unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2];
+ unsigned char key[GNUNET_CRYPTO_AES_KEY_LENGTH];
if (ntohl (block->purpose.size) <
sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
@@ -319,18 +398,19 @@ GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- derive_block_aes_key (&iv,
- &skey,
+ derive_block_aes_key (ctr,
+ key,
label,
+ block->expiration_time.abs_value_us__,
zone_key);
{
char payload[payload_len];
uint32_t rd_count;
GNUNET_break (payload_len ==
- GNUNET_CRYPTO_symmetric_decrypt (&block[1], payload_len,
- &skey, &iv,
- payload));
+ ecdsa_symmetric_decrypt (&block[1], payload_len,
+ key, ctr,
+ payload));
GNUNET_memcpy (&rd_count,
payload,
sizeof(uint32_t));
@@ -426,6 +506,39 @@ GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
/**
+ * Decrypt block.
+ *
+ * @param block block to decrypt
+ * @param zone_key public key of the zone
+ * @param label the name for the records
+ * @param proc function to call with the result
+ * @param proc_cls closure for proc
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
+ * not well-formed
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
+ const struct
+ GNUNET_IDENTITY_PublicKey *zone_key,
+ const char *label,
+ GNUNET_GNSRECORD_RecordCallback proc,
+ void *proc_cls)
+{
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *key;
+
+ if (GNUNET_IDENTITY_TYPE_ECDSA != ntohl (zone_key->type))
+ {
+ return GNUNET_NO;
+ }
+ key = &zone_key->ecdsa_key;
+
+ return block_decrypt_ecdsa (&block->ecdsa_block,
+ key, label, proc, proc_cls);
+
+}
+
+
+/**
* Calculate the DHT query for a given @a label in a given @a zone.
*
* @param zone private key of the zone
@@ -434,17 +547,24 @@ GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
*/
void
GNUNET_GNSRECORD_query_from_private_key (const struct
- GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ GNUNET_IDENTITY_PrivateKey *zone,
const char *label,
struct GNUNET_HashCode *query)
{
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
-
- GNUNET_CRYPTO_ecdsa_key_get_public (zone,
- &pub);
- GNUNET_GNSRECORD_query_from_public_key (&pub,
- label,
- query);
+ struct GNUNET_IDENTITY_PublicKey pub;
+ switch (ntohl (zone->type))
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+
+ GNUNET_IDENTITY_key_get_public (zone,
+ &pub);
+ GNUNET_GNSRECORD_query_from_public_key (&pub,
+ label,
+ query);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
}
@@ -457,18 +577,27 @@ GNUNET_GNSRECORD_query_from_private_key (const struct
*/
void
GNUNET_GNSRECORD_query_from_public_key (const struct
- GNUNET_CRYPTO_EcdsaPublicKey *pub,
+ GNUNET_IDENTITY_PublicKey *pub,
const char *label,
struct GNUNET_HashCode *query)
{
- struct GNUNET_CRYPTO_EcdsaPublicKey pd;
- GNUNET_CRYPTO_ecdsa_public_key_derive (pub,
- label,
- "gns",
- &pd);
- GNUNET_CRYPTO_hash (&pd,
- sizeof(pd),
- query);
+ struct GNUNET_IDENTITY_PublicKey pd;
+
+ switch (ntohl (pub->type))
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+ pd.type = pub->type;
+ GNUNET_CRYPTO_ecdsa_public_key_derive (&pub->ecdsa_key,
+ label,
+ "gns",
+ &pd.ecdsa_key);
+ GNUNET_CRYPTO_hash (&pd.ecdsa_key,
+ sizeof (pd.ecdsa_key),
+ query);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
}
diff --git a/src/gnsrecord/gnsrecord_misc.c b/src/gnsrecord/gnsrecord_misc.c
index 5061f8493..82c38f19a 100644
--- a/src/gnsrecord/gnsrecord_misc.c
+++ b/src/gnsrecord/gnsrecord_misc.c
@@ -62,14 +62,14 @@ GNUNET_GNSRECORD_string_to_lowercase (const char *src)
* @return string form; will be overwritten by next call to #GNUNET_GNSRECORD_z2s
*/
const char *
-GNUNET_GNSRECORD_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z)
+GNUNET_GNSRECORD_z2s (const struct GNUNET_IDENTITY_PublicKey *z)
{
- static char buf[sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) * 8];
+ static char buf[sizeof(struct GNUNET_IDENTITY_PublicKey) * 8];
char *end;
end = GNUNET_STRINGS_data_to_string ((const unsigned char *) z,
sizeof(struct
- GNUNET_CRYPTO_EcdsaPublicKey),
+ GNUNET_IDENTITY_PublicKey),
buf, sizeof(buf));
if (NULL == end)
{
@@ -99,7 +99,7 @@ GNUNET_GNSRECORD_records_cmp (const struct GNUNET_GNSRECORD_Data *a,
if (a->record_type != b->record_type)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Record type %lu != %lu\n", a->record_type, b->record_type);
+ "Record type %u != %u\n", a->record_type, b->record_type);
return GNUNET_NO;
}
if ((a->expiration_time != b->expiration_time) &&
@@ -107,15 +107,15 @@ GNUNET_GNSRECORD_records_cmp (const struct GNUNET_GNSRECORD_Data *a,
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Expiration time %llu != %llu\n",
- a->expiration_time,
- b->expiration_time);
+ (unsigned long long) a->expiration_time,
+ (unsigned long long) b->expiration_time);
return GNUNET_NO;
}
if ((a->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS)
!= (b->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS))
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Flags %lu (%lu) != %lu (%lu)\n", a->flags,
+ "Flags %u (%u) != %u (%u)\n", a->flags,
a->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS, b->flags,
b->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS);
return GNUNET_NO;
@@ -236,12 +236,12 @@ GNUNET_GNSRECORD_is_expired (const struct GNUNET_GNSRECORD_Data *rd)
* key in an encoding suitable for DNS labels.
*/
const char *
-GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
+GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_IDENTITY_PublicKey *pkey)
{
static char ret[128];
char *pkeys;
- pkeys = GNUNET_CRYPTO_ecdsa_public_key_to_string (pkey);
+ pkeys = GNUNET_IDENTITY_public_key_to_string (pkey);
GNUNET_snprintf (ret,
sizeof(ret),
"%s",
@@ -262,15 +262,140 @@ GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
*/
int
GNUNET_GNSRECORD_zkey_to_pkey (const char *zkey,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
+ struct GNUNET_IDENTITY_PublicKey *pkey)
{
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (zkey,
- strlen (zkey),
- pkey))
+ GNUNET_IDENTITY_public_key_from_string (zkey,
+ pkey))
return GNUNET_SYSERR;
return GNUNET_OK;
}
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_identity_from_data (const char *data,
+ size_t data_size,
+ uint32_t type,
+ struct GNUNET_IDENTITY_PublicKey *key)
+{
+ if (GNUNET_NO == GNUNET_GNSRECORD_is_zonekey_type (type))
+ return GNUNET_SYSERR;
+ if (data_size > sizeof (struct GNUNET_IDENTITY_PublicKey))
+ return GNUNET_SYSERR;
+ return (GNUNET_IDENTITY_read_key_from_buffer (key, data, data_size) ==
+ data_size?
+ GNUNET_OK :
+ GNUNET_SYSERR);
+}
+
+
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_data_from_identity (const struct
+ GNUNET_IDENTITY_PublicKey *key,
+ char **data,
+ size_t *data_size,
+ uint32_t *type)
+{
+ *type = ntohl (key->type);
+ *data_size = GNUNET_IDENTITY_key_get_length (key);
+ if (0 == *data_size)
+ return GNUNET_SYSERR;
+ *data = GNUNET_malloc (*data_size);
+ return (GNUNET_IDENTITY_write_key_to_buffer (key, *data, *data_size) ==
+ *data_size?
+ GNUNET_OK :
+ GNUNET_SYSERR);
+}
+
+
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_is_zonekey_type (uint32_t type)
+{
+ switch (type)
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+ case GNUNET_GNSRECORD_TYPE_EDKEY:
+ return GNUNET_YES;
+ default:
+ return GNUNET_NO;
+ }
+}
+
+
+size_t
+GNUNET_GNSRECORD_block_get_size (const struct GNUNET_GNSRECORD_Block *block)
+{
+ switch (ntohl (block->type))
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+ return sizeof (uint32_t) /* zone type */
+ + sizeof (block->ecdsa_block) /* EcdsaBlock */
+ + ntohl (block->ecdsa_block.purpose.size) /* Length of signed data */
+ - sizeof (block->ecdsa_block.purpose); /* Purpose already in EcdsaBlock */
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+
+struct GNUNET_TIME_Absolute
+GNUNET_GNSRECORD_block_get_expiration (const struct
+ GNUNET_GNSRECORD_Block *block)
+{
+
+ switch (ntohl (block->type))
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+ return GNUNET_TIME_absolute_ntoh (block->ecdsa_block.expiration_time);
+ default:
+ return GNUNET_TIME_absolute_get_zero_ ();
+ }
+ return GNUNET_TIME_absolute_get_zero_ ();
+
+}
+
+
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_query_from_block (const struct GNUNET_GNSRECORD_Block *block,
+ struct GNUNET_HashCode *query)
+{
+ switch (ntohl (block->type))
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+ GNUNET_CRYPTO_hash (&block->ecdsa_block.derived_key,
+ sizeof (block->ecdsa_block.derived_key),
+ query);
+ return GNUNET_OK;
+ default:
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_SYSERR;
+
+}
+
+
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_record_to_identity_key (const struct GNUNET_GNSRECORD_Data *rd,
+ struct GNUNET_IDENTITY_PublicKey *key)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got record of type %u\n",
+ rd->record_type);
+ switch (rd->record_type)
+ {
+ case GNUNET_GNSRECORD_TYPE_PKEY:
+ key->type = htonl (rd->record_type);
+ memcpy (&key->ecdsa_key, rd->data, sizeof (key->ecdsa_key));
+ return GNUNET_OK;
+ default:
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_SYSERR;
+
+
+}
+
+
/* end of gnsrecord_misc.c */
diff --git a/src/gnsrecord/gnunet-gnsrecord-tvg.c b/src/gnsrecord/gnunet-gnsrecord-tvg.c
index 789ff8aa3..47b13bdab 100644
--- a/src/gnsrecord/gnunet-gnsrecord-tvg.c
+++ b/src/gnsrecord/gnunet-gnsrecord-tvg.c
@@ -90,28 +90,38 @@ run (void *cls,
struct GNUNET_TIME_Absolute exp_abs = GNUNET_TIME_absolute_get ();
struct GNUNET_GNSRECORD_Block *rrblock;
char *bdata;
- struct GNUNET_CRYPTO_EcdsaPrivateKey id_priv;
- struct GNUNET_CRYPTO_EcdsaPublicKey id_pub;
- struct GNUNET_CRYPTO_EcdsaPrivateKey pkey_data_p;
- struct GNUNET_CRYPTO_EcdsaPublicKey pkey_data;
+ struct GNUNET_IDENTITY_PrivateKey id_priv;
+ struct GNUNET_IDENTITY_PublicKey id_pub;
+ struct GNUNET_IDENTITY_PrivateKey pkey_data_p;
+ struct GNUNET_IDENTITY_PublicKey pkey_data;
void *data;
size_t data_size;
char *rdata;
size_t rdata_size;
-
- GNUNET_CRYPTO_ecdsa_key_create (&id_priv);
- GNUNET_CRYPTO_ecdsa_key_get_public (&id_priv,
- &id_pub);
- fprintf (stdout, "Zone private key (d, little-endian scalar):\n");
- print_bytes (&id_priv, sizeof(id_priv), 0);
+ char ztld[128];
+
+ id_priv.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
+ GNUNET_CRYPTO_ecdsa_key_create (&id_priv.ecdsa_key);
+ GNUNET_IDENTITY_key_get_public (&id_priv,
+ &id_pub);
+ fprintf (stdout, "Zone private key (d, little-endian, with ztype prepended):\n");
+ print_bytes (&id_priv, GNUNET_IDENTITY_key_get_length (&id_pub), 8); //FIXME length for privkey?
+ fprintf (stdout, "\n");
+ fprintf (stdout, "Zone identifier (zid):\n");
+ print_bytes (&id_pub, GNUNET_IDENTITY_key_get_length (&id_pub), 8);
+ GNUNET_STRINGS_data_to_string (&id_pub,
+ GNUNET_IDENTITY_key_get_length (&id_pub),
+ ztld,
+ sizeof (ztld));
fprintf (stdout, "\n");
- fprintf (stdout, "Zone public key (zk):\n");
- print_bytes (&id_pub, sizeof(id_pub), 0);
+ fprintf (stdout, "Encoded zone identifier (zkl = zTLD):\n");
+ fprintf (stdout, "%s\n", ztld);
fprintf (stdout, "\n");
- GNUNET_CRYPTO_ecdsa_key_create (&pkey_data_p);
- GNUNET_CRYPTO_ecdsa_key_get_public (&pkey_data_p,
- &pkey_data);
+ pkey_data_p.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
+ GNUNET_CRYPTO_ecdsa_key_create (&pkey_data_p.ecdsa_key);
+ GNUNET_IDENTITY_key_get_public (&pkey_data_p,
+ &pkey_data);
fprintf (stdout,
"Label: %s\nRRCOUNT: %d\n\n", TEST_RECORD_LABEL, TEST_RRCOUNT);
memset (rd, 0, sizeof (struct GNUNET_GNSRECORD_Data) * 2);
@@ -147,19 +157,20 @@ run (void *cls,
TEST_RECORD_LABEL,
rd,
TEST_RRCOUNT);
- size_t bdata_size = ntohl (rrblock->purpose.size)
+ size_t bdata_size = ntohl (rrblock->ecdsa_block.purpose.size)
- sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
- sizeof(struct GNUNET_TIME_AbsoluteNBO);
- size_t rrblock_size = ntohl (rrblock->purpose.size)
+ size_t ecblock_size = ntohl (rrblock->ecdsa_block.purpose.size)
+ sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
+ sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
+ size_t block_size = ecblock_size + sizeof (uint32_t);
- bdata = (char*) &rrblock[1];
+ bdata = (char*) &(&rrblock->ecdsa_block)[1];
fprintf (stdout, "BDATA:\n");
print_bytes (bdata, bdata_size, 8);
fprintf (stdout, "\n");
fprintf (stdout, "RRBLOCK:\n");
- print_bytes (rrblock, rrblock_size, 8);
+ print_bytes (rrblock, block_size, 8);
fprintf (stdout, "\n");
}
diff --git a/src/json/json_gnsrecord.c b/src/gnsrecord/json_gnsrecord.c
index 7e11aba94..068ff48c1 100644
--- a/src/json/json_gnsrecord.c
+++ b/src/gnsrecord/json_gnsrecord.c
@@ -26,6 +26,7 @@
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_json_lib.h"
+#include "gnunet_gnsrecord_lib.h"
#define GNUNET_JSON_GNSRECORD_VALUE "value"
#define GNUNET_JSON_GNSRECORD_RECORD_DATA "data"
@@ -258,7 +259,7 @@ clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
* @return JSON Specification
*/
struct GNUNET_JSON_Specification
-GNUNET_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
+GNUNET_GNSRECORD_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
unsigned int *rd_count,
char **name)
{
@@ -277,3 +278,114 @@ GNUNET_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
.size_ptr = NULL };
return ret;
}
+
+
+/**
+ * Convert GNS record to JSON.
+ *
+ * @param rname name of record
+ * @param rd record data
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_GNSRECORD_JSON_from_gnsrecord (const char*rname,
+ const struct GNUNET_GNSRECORD_Data *rd,
+ unsigned int rd_count)
+{
+ struct GNUNET_TIME_Absolute abs_exp;
+ struct GNUNET_TIME_Relative rel_exp;
+ const char *expiration_time_str;
+ const char *record_type_str;
+ char *value_str;
+ json_t *data;
+ json_t *record;
+ json_t *records;
+
+ data = json_object ();
+ if (NULL == data)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (0 !=
+ json_object_set_new (data,
+ "record_name",
+ json_string (rname)))
+ {
+ GNUNET_break (0);
+ json_decref (data);
+ return NULL;
+ }
+ records = json_array ();
+ if (NULL == records)
+ {
+ GNUNET_break (0);
+ json_decref (data);
+ return NULL;
+ }
+ for (int i = 0; i < rd_count; i++)
+ {
+ value_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
+ rd[i].data,
+ rd[i].data_size);
+ if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd[i].flags)
+ {
+ rel_exp.rel_value_us = rd[i].expiration_time;
+ expiration_time_str = GNUNET_STRINGS_relative_time_to_string (rel_exp,
+ GNUNET_NO);
+ }
+ else
+ {
+ abs_exp.abs_value_us = rd[i].expiration_time;
+ expiration_time_str = GNUNET_STRINGS_absolute_time_to_string (abs_exp);
+ }
+ record_type_str = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Packing %s %s %s %d\n",
+ value_str, record_type_str, expiration_time_str, rd[i].flags);
+ record = json_pack ("{s:s,s:s,s:s,s:b,s:b,s:b,s:b}",
+ "value",
+ value_str,
+ "record_type",
+ record_type_str,
+ "expiration_time",
+ expiration_time_str,
+ "private",
+ rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE,
+ "relative_expiration",
+ rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION,
+ "supplemental",
+ rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL,
+ "shadow",
+ rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD);
+ GNUNET_free (value_str);
+ if (NULL == record)
+ {
+ GNUNET_break (0);
+ json_decref (records);
+ json_decref (data);
+ return NULL;
+ }
+ if (0 !=
+ json_array_append_new (records,
+ record))
+ {
+ GNUNET_break (0);
+ json_decref (records);
+ json_decref (data);
+ return NULL;
+ }
+ }
+ if (0 !=
+ json_object_set_new (data,
+ "data",
+ records))
+ {
+ GNUNET_break (0);
+ json_decref (data);
+ return NULL;
+ }
+ return data;
+}
+
+
diff --git a/src/gnsrecord/perf_gnsrecord_crypto.c b/src/gnsrecord/perf_gnsrecord_crypto.c
index eb4633f75..d9a3c20cf 100644
--- a/src/gnsrecord/perf_gnsrecord_crypto.c
+++ b/src/gnsrecord/perf_gnsrecord_crypto.c
@@ -73,7 +73,7 @@ run (void *cls,
struct GNUNET_GNSRECORD_Data *s_rd;
const char *s_name;
struct GNUNET_TIME_Absolute start_time;
- struct GNUNET_CRYPTO_EcdsaPrivateKey privkey;
+ struct GNUNET_IDENTITY_PrivateKey privkey;
struct GNUNET_TIME_Absolute expire;
(void) cls;
@@ -81,7 +81,8 @@ run (void *cls,
(void) cfgfile;
(void) cfg;
expire = GNUNET_TIME_absolute_get ();
- GNUNET_CRYPTO_ecdsa_key_create (&privkey);
+ privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
+ GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
/* test block creation */
s_name = "DUMMY.dummy.gnunet";
diff --git a/src/gnsrecord/plugin_gnsrecord_dns.c b/src/gnsrecord/plugin_gnsrecord_dns.c
index 9ac6fb9e6..bde9944e2 100644
--- a/src/gnsrecord/plugin_gnsrecord_dns.c
+++ b/src/gnsrecord/plugin_gnsrecord_dns.c
@@ -100,7 +100,7 @@ dns_value_to_string (void *cls,
return NULL;
}
GNUNET_asprintf (&result,
- "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
+ "rname=%s mname=%s %u,%u,%u,%u,%u",
soa->rname,
soa->mname,
soa->serial,
diff --git a/src/gnsrecord/test_gnsrecord_crypto.c b/src/gnsrecord/test_gnsrecord_crypto.c
index b67e9a123..d541f3076 100644
--- a/src/gnsrecord/test_gnsrecord_crypto.c
+++ b/src/gnsrecord/test_gnsrecord_crypto.c
@@ -100,17 +100,18 @@ run (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct GNUNET_GNSRECORD_Block *block;
- struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
+ struct GNUNET_IDENTITY_PublicKey pubkey;
struct GNUNET_HashCode query_pub;
struct GNUNET_HashCode query_priv;
struct GNUNET_TIME_Absolute expire = GNUNET_TIME_absolute_get ();
- struct GNUNET_CRYPTO_EcdsaPrivateKey privkey;
+ struct GNUNET_IDENTITY_PrivateKey privkey;
- GNUNET_CRYPTO_ecdsa_key_create (&privkey);
+ privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
+ GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
/* get public key */
- GNUNET_CRYPTO_ecdsa_key_get_public (&privkey,
- &pubkey);
+ GNUNET_IDENTITY_key_get_public (&privkey,
+ &pubkey);
/* test query derivation */
GNUNET_GNSRECORD_query_from_private_key (&privkey,
diff --git a/src/identity/gnunet-identity.c b/src/identity/gnunet-identity.c
index d0f5546f3..a01cd1ed7 100644
--- a/src/identity/gnunet-identity.c
+++ b/src/identity/gnunet-identity.c
@@ -66,6 +66,11 @@ static unsigned int verbose;
static int quiet;
/**
+ * Was "eddsa" specified?
+ */
+static int type_eddsa;
+
+/**
* -C option
*/
static char *create_ego;
@@ -108,7 +113,7 @@ static struct GNUNET_IDENTITY_Operation *delete_op;
/**
* Private key from command line option, or NULL.
*/
-struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
+struct GNUNET_IDENTITY_PrivateKey pk;
/**
* Value to return from #main().
@@ -197,7 +202,7 @@ delete_finished (void *cls,
*/
static void
create_finished (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
struct GNUNET_IDENTITY_Operation **op = cls;
@@ -212,16 +217,16 @@ create_finished (void *cls,
}
else if (verbose)
{
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+ struct GNUNET_IDENTITY_PublicKey pub;
char *pubs;
- GNUNET_CRYPTO_ecdsa_key_get_public (pk, &pub);
- pubs = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pub);
+ GNUNET_IDENTITY_key_get_public (pk, &pub);
+ pubs = GNUNET_IDENTITY_public_key_to_string (&pub);
if (private_keys)
{
char *privs;
- privs = GNUNET_CRYPTO_ecdsa_private_key_to_string (pk);
+ privs = GNUNET_IDENTITY_private_key_to_string (pk);
fprintf (stdout, "%s - %s\n", pubs, privs);
GNUNET_free (privs);
}
@@ -293,7 +298,7 @@ print_ego (void *cls,
void **ctx,
const char *identifier)
{
- struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+ struct GNUNET_IDENTITY_PublicKey pk;
char *s;
char *privs;
@@ -342,8 +347,8 @@ print_ego (void *cls,
set_ego)) )
return;
GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- s = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
- privs = GNUNET_CRYPTO_ecdsa_private_key_to_string (
+ s = GNUNET_IDENTITY_public_key_to_string (&pk);
+ privs = GNUNET_IDENTITY_private_key_to_string (
GNUNET_IDENTITY_ego_get_private_key (ego));
if ((monitor) || (NULL != identifier))
{
@@ -357,9 +362,16 @@ print_ego (void *cls,
else
{
if (private_keys)
- fprintf (stdout, "%s - %s - %s\n", identifier, s, privs);
+ fprintf (stdout, "%s - %s - %s - %s\n",
+ identifier, s, privs,
+ (ntohl (pk.type) == GNUNET_IDENTITY_TYPE_ECDSA) ?
+ "ECDSA" : "EdDSA");
else
- fprintf (stdout, "%s - %s\n", identifier, s);
+ fprintf (stdout, "%s - %s - %s\n",
+ identifier, s,
+ (ntohl (pk.type) == GNUNET_IDENTITY_TYPE_ECDSA) ?
+ "ECDSA" : "EdDSA");
+
}
}
GNUNET_free (privs);
@@ -407,11 +419,12 @@ run (void *cls,
strlen (privkey_ego),
&pk,
sizeof(struct
- GNUNET_CRYPTO_EcdsaPrivateKey));
+ GNUNET_IDENTITY_PrivateKey));
create_op =
GNUNET_IDENTITY_create (sh,
create_ego,
&pk,
+ 0, // Ignored
&create_finished,
&create_op);
}
@@ -420,6 +433,9 @@ run (void *cls,
GNUNET_IDENTITY_create (sh,
create_ego,
NULL,
+ (type_eddsa) ?
+ GNUNET_IDENTITY_TYPE_EDDSA :
+ GNUNET_IDENTITY_TYPE_ECDSA,
&create_finished,
&create_op);
}
@@ -456,6 +472,11 @@ main (int argc, char *const *argv)
gettext_noop (
"set the private key for the identity to PRIVATE_KEY (use together with -C)"),
&privkey_ego),
+ GNUNET_GETOPT_option_flag ('X',
+ "eddsa",
+ gettext_noop (
+ "generate an EdDSA identity. (use together with -C) EXPERIMENTAL"),
+ &type_eddsa),
GNUNET_GETOPT_option_flag ('d',
"display",
gettext_noop ("display all egos"),
diff --git a/src/identity/gnunet-service-identity.c b/src/identity/gnunet-service-identity.c
index bdacf3ba0..6cdb1c2f7 100644
--- a/src/identity/gnunet-service-identity.c
+++ b/src/identity/gnunet-service-identity.c
@@ -57,7 +57,7 @@ struct Ego
/**
* Private key of the ego.
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
+ struct GNUNET_IDENTITY_PrivateKey pk;
/**
* String identifier for the ego.
@@ -538,8 +538,8 @@ handle_get_default_message (void *cls,
* @return 0 if the keys are equal
*/
static int
-key_cmp (const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk1,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk2)
+key_cmp (const struct GNUNET_IDENTITY_PrivateKey *pk1,
+ const struct GNUNET_IDENTITY_PrivateKey *pk2)
{
return GNUNET_memcmp (pk1, pk2);
}
@@ -738,10 +738,10 @@ handle_create_message (void *cls,
send_result_code (client, 0, NULL);
fn = get_ego_filename (ego);
(void) GNUNET_DISK_directory_create_for_file (fn);
- if (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey) !=
+ if (sizeof(struct GNUNET_IDENTITY_PrivateKey) !=
GNUNET_DISK_fn_write (fn,
&crm->private_key,
- sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey),
+ sizeof(struct GNUNET_IDENTITY_PrivateKey),
GNUNET_DISK_PERM_USER_READ
| GNUNET_DISK_PERM_USER_WRITE))
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn);
@@ -1038,6 +1038,67 @@ handle_delete_message (void *cls, const struct DeleteMessage *dm)
}
+static int
+read_from_file (const char *filename,
+ void *buf,
+ size_t buf_size)
+{
+ int fd;
+ struct stat sb;
+
+ fd = open (filename,
+ O_RDONLY);
+ if (-1 == fd)
+ {
+ memset (buf,
+ 0,
+ buf_size);
+ return GNUNET_SYSERR;
+ }
+ if (0 != fstat (fd,
+ &sb))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+ "stat",
+ filename);
+ GNUNET_assert (0 == close (fd));
+ memset (buf,
+ 0,
+ buf_size);
+ return GNUNET_SYSERR;
+ }
+ if (sb.st_size != buf_size)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "File `%s' has wrong size (%llu), expected %llu bytes\n",
+ filename,
+ (unsigned long long) sb.st_size,
+ (unsigned long long) buf_size);
+ GNUNET_assert (0 == close (fd));
+ memset (buf,
+ 0,
+ buf_size);
+ return GNUNET_SYSERR;
+ }
+ if (buf_size !=
+ read (fd,
+ buf,
+ buf_size))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+ "read",
+ filename);
+ GNUNET_assert (0 == close (fd));
+ memset (buf,
+ 0,
+ buf_size);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (0 == close (fd));
+ return GNUNET_OK;
+}
+
+
/**
* Process the given file from the "EGODIR". Parses the file
* and creates the respective 'struct Ego' in memory.
@@ -1063,9 +1124,9 @@ process_ego_file (void *cls,
}
ego = GNUNET_new (struct Ego);
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_key_from_file (filename,
- GNUNET_NO,
- &ego->pk))
+ read_from_file (filename,
+ &ego->pk,
+ sizeof (ego->pk)))
{
GNUNET_free (ego);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
diff --git a/src/identity/identity.h b/src/identity/identity.h
index ef638fa36..11c5883bc 100644
--- a/src/identity/identity.h
+++ b/src/identity/identity.h
@@ -30,6 +30,44 @@
#include "gnunet_common.h"
+/**
+ * Handle for an ego.
+ */
+struct GNUNET_IDENTITY_Ego
+{
+ /**
+ * Hash of the private key of this ego.
+ */
+ struct GNUNET_HashCode id;
+
+ /**
+ * The identity key pair
+ */
+ struct GNUNET_IDENTITY_PublicKey pub;
+
+ /**
+ * The identity key pair
+ */
+ struct GNUNET_IDENTITY_PrivateKey pk;
+
+ /**
+ * Current name associated with this ego.
+ */
+ char *name;
+
+ /**
+ * Client context associated with this ego.
+ */
+ void *ctx;
+
+ /**
+ * Set to true once @e pub was initialized
+ */
+ bool pub_initialized;
+};
+
+
+
GNUNET_NETWORK_STRUCT_BEGIN
@@ -95,7 +133,7 @@ struct UpdateMessage
/**
* The private key
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey private_key;
+ struct GNUNET_IDENTITY_PrivateKey private_key;
/* followed by 0-terminated ego name */
};
@@ -151,7 +189,7 @@ struct SetDefaultMessage
/**
* The private key
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey private_key;
+ struct GNUNET_IDENTITY_PrivateKey private_key;
/* followed by 0-terminated service name */
};
@@ -181,7 +219,7 @@ struct CreateRequestMessage
/**
* The private key
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey private_key;
+ struct GNUNET_IDENTITY_PrivateKey private_key;
/* followed by 0-terminated identity name */
};
@@ -239,42 +277,5 @@ struct DeleteMessage
GNUNET_NETWORK_STRUCT_END
-/**
- * Handle for an ego.
- */
-struct GNUNET_IDENTITY_Ego
-{
- /**
- * Hash of the private key of this ego.
- */
- struct GNUNET_HashCode id;
-
- /**
- * Private key associated with this ego.
- */
- struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
-
- /**
- * Public key associated with this ego. Initialized on demand.
- * Always use #GNUNET_IDENTITY_ego_get_public_key() to obtain.
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
-
- /**
- * Current name associated with this ego.
- */
- char *name;
-
- /**
- * Client context associated with this ego.
- */
- void *ctx;
-
- /**
- * Set to true once @e pub was initialized
- */
- bool pub_initialized;
-};
-
#endif
diff --git a/src/identity/identity_api.c b/src/identity/identity_api.c
index f7aca1655..64c088923 100644
--- a/src/identity/identity_api.c
+++ b/src/identity/identity_api.c
@@ -74,7 +74,7 @@ struct GNUNET_IDENTITY_Operation
/**
* Private key to return to @e create_cont, or NULL.
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
+ struct GNUNET_IDENTITY_PrivateKey pk;
/**
* Continuation to invoke with the result of the transmission for
@@ -157,13 +157,12 @@ GNUNET_IDENTITY_ego_get_anonymous ()
{
static struct GNUNET_IDENTITY_Ego anon;
static int setup;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
if (setup)
return &anon;
- anon.pk = *GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
- GNUNET_CRYPTO_ecdsa_key_get_public (&anon.pk,
- &pub);
+ anon.pk.type = htonl (GNUNET_IDENTITY_TYPE_ECDSA);
+ anon.pub.type = htonl (GNUNET_IDENTITY_TYPE_ECDSA);
+ anon.pk.ecdsa_key = *GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
GNUNET_CRYPTO_hash (&anon.pk,
sizeof(anon.pk),
&anon.id);
@@ -172,6 +171,51 @@ GNUNET_IDENTITY_ego_get_anonymous ()
}
+enum GNUNET_GenericReturnValue
+GNUNET_IDENTITY_key_get_public (const struct
+ GNUNET_IDENTITY_PrivateKey *privkey,
+ struct GNUNET_IDENTITY_PublicKey *key)
+{
+ key->type = privkey->type;
+ switch (ntohl (privkey->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ GNUNET_CRYPTO_ecdsa_key_get_public (&privkey->ecdsa_key,
+ &key->ecdsa_key);
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ GNUNET_CRYPTO_eddsa_key_get_public (&privkey->eddsa_key,
+ &key->eddsa_key);
+ break;
+ default:
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+static int
+private_key_create (enum GNUNET_IDENTITY_KeyType ktype,
+ struct GNUNET_IDENTITY_PrivateKey *key)
+{
+ key->type = htonl (ktype);
+ switch (ktype)
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ GNUNET_CRYPTO_ecdsa_key_create (&key->ecdsa_key);
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ GNUNET_CRYPTO_eddsa_key_create (&key->eddsa_key);
+ break;
+ default:
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
/**
* Try again to connect to the identity service.
*
@@ -591,7 +635,7 @@ GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
* @param ego the ego
* @return associated ECC key, valid as long as the ego is valid
*/
-const struct GNUNET_CRYPTO_EcdsaPrivateKey *
+const struct GNUNET_IDENTITY_PrivateKey *
GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
{
return &ego->pk;
@@ -606,12 +650,11 @@ GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
*/
void
GNUNET_IDENTITY_ego_get_public_key (struct GNUNET_IDENTITY_Ego *ego,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
+ struct GNUNET_IDENTITY_PublicKey *pk)
{
if (GNUNET_NO == ego->pub_initialized)
{
- GNUNET_CRYPTO_ecdsa_key_get_public (&ego->pk,
- &ego->pub);
+ GNUNET_IDENTITY_key_get_public (&ego->pk, &ego->pub);
ego->pub_initialized = GNUNET_YES;
}
*pk = ego->pub;
@@ -710,20 +753,11 @@ GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
}
-/**
- * Create a new identity with the given name.
- *
- * @param h identity service to use
- * @param name desired name
- * @param privkey desired private key or NULL to create one
- * @param cont function to call with the result (will only be called once)
- * @param cont_cls closure for @a cont
- * @return handle to abort the operation
- */
struct GNUNET_IDENTITY_Operation *
GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
const char *name,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey,
+ const struct GNUNET_IDENTITY_PrivateKey *privkey,
+ enum GNUNET_IDENTITY_KeyType ktype,
GNUNET_IDENTITY_CreateContinuation cont,
void *cont_cls)
{
@@ -749,7 +783,10 @@ GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
crm->name_len = htons (slen);
crm->reserved = htons (0);
if (NULL == privkey)
- GNUNET_CRYPTO_ecdsa_key_create (&crm->private_key);
+ {
+ GNUNET_assert (GNUNET_OK ==
+ private_key_create (ktype, &crm->private_key));
+ }
else
crm->private_key = *privkey;
op->pk = crm->private_key;
@@ -917,4 +954,316 @@ GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
}
+ssize_t
+private_key_get_length (const struct GNUNET_IDENTITY_PrivateKey *key)
+{
+ switch (ntohl (key->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ return sizeof (key->type) + sizeof (key->ecdsa_key);
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ return sizeof (key->type) + sizeof (key->eddsa_key);
+ break;
+ default:
+ GNUNET_break (0);
+ }
+ return -1;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_key_get_length (const struct GNUNET_IDENTITY_PublicKey *key)
+{
+ switch (ntohl (key->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ return sizeof (key->type) + sizeof (key->ecdsa_key);
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ return sizeof (key->type) + sizeof (key->eddsa_key);
+ break;
+ default:
+ GNUNET_break (0);
+ }
+ return -1;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_read_key_from_buffer (struct GNUNET_IDENTITY_PublicKey *key,
+ const void*buffer,
+ size_t len)
+{
+ if (len < sizeof (key->type))
+ return -1;
+ GNUNET_memcpy (&(key->type), buffer, sizeof (key->type));
+ const ssize_t length = GNUNET_IDENTITY_key_get_length (key);
+ if (len < length)
+ return -1;
+ if (length < 0)
+ return -2;
+ GNUNET_memcpy (&(key->ecdsa_key), buffer + sizeof (key->type), length
+ - sizeof (key->type));
+ return length;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_write_key_to_buffer (const struct
+ GNUNET_IDENTITY_PublicKey *key,
+ void*buffer,
+ size_t len)
+{
+ const ssize_t length = GNUNET_IDENTITY_key_get_length (key);
+ if (len < length)
+ return -1;
+ if (length < 0)
+ return -2;
+ GNUNET_memcpy (buffer, key, length);
+ return length;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_signature_get_length (const struct
+ GNUNET_IDENTITY_Signature *sig)
+{
+ switch (ntohl (sig->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ return sizeof (sig->type) + sizeof (sig->ecdsa_signature);
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ return sizeof (sig->type) + sizeof (sig->eddsa_signature);
+ break;
+ default:
+ GNUNET_break (0);
+ }
+ return -1;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_read_signature_from_buffer (struct
+ GNUNET_IDENTITY_Signature *sig,
+ const void*buffer,
+ size_t len)
+{
+ if (len < sizeof (sig->type))
+ return -1;
+ GNUNET_memcpy (&(sig->type), buffer, sizeof (sig->type));
+ const ssize_t length = GNUNET_IDENTITY_signature_get_length (sig);
+ if (len < length)
+ return -1;
+ if (length < 0)
+ return -2;
+ GNUNET_memcpy (&(sig->ecdsa_signature), buffer + sizeof (sig->type), length
+ - sizeof (sig->type));
+ return length;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_write_signature_to_buffer (const struct
+ GNUNET_IDENTITY_Signature *sig,
+ void*buffer,
+ size_t len)
+{
+ const ssize_t length = GNUNET_IDENTITY_signature_get_length (sig);
+ if (len < length)
+ return -1;
+ if (length < 0)
+ return -2;
+ GNUNET_memcpy (buffer, &(sig->type), sizeof (sig->type));
+ GNUNET_memcpy (buffer + sizeof (sig->type), &(sig->ecdsa_signature), length
+ - sizeof (sig->type));
+ return length;
+}
+
+
+int
+GNUNET_IDENTITY_sign_ (const struct
+ GNUNET_IDENTITY_PrivateKey *priv,
+ const struct
+ GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct GNUNET_IDENTITY_Signature *sig)
+{
+ sig->type = priv->type;
+ switch (ntohl (priv->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ return GNUNET_CRYPTO_ecdsa_sign_ (&(priv->ecdsa_key), purpose,
+ &(sig->ecdsa_signature));
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ return GNUNET_CRYPTO_eddsa_sign_ (&(priv->eddsa_key), purpose,
+ &(sig->eddsa_signature));
+ break;
+ default:
+ GNUNET_break (0);
+ }
+
+ return GNUNET_SYSERR;
+}
+
+
+int
+GNUNET_IDENTITY_signature_verify_ (uint32_t purpose,
+ const struct
+ GNUNET_CRYPTO_EccSignaturePurpose *validate,
+ const struct GNUNET_IDENTITY_Signature *sig,
+ const struct GNUNET_IDENTITY_PublicKey *pub)
+{
+ /* check type matching of 'sig' and 'pub' */
+ GNUNET_assert (ntohl (pub->type) == ntohl (sig->type));
+ switch (ntohl (pub->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ return GNUNET_CRYPTO_ecdsa_verify_ (purpose, validate,
+ &(sig->ecdsa_signature),
+ &(pub->ecdsa_key));
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ return GNUNET_CRYPTO_eddsa_verify_ (purpose, validate,
+ &(sig->eddsa_signature),
+ &(pub->eddsa_key));
+ break;
+ default:
+ GNUNET_break (0);
+ }
+
+ return GNUNET_SYSERR;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_encrypt (const void *block,
+ size_t size,
+ const struct GNUNET_IDENTITY_PublicKey *pub,
+ struct GNUNET_CRYPTO_EcdhePublicKey *ecc,
+ void *result)
+{
+ struct GNUNET_CRYPTO_EcdhePrivateKey pk;
+ GNUNET_CRYPTO_ecdhe_key_create (&pk);
+ struct GNUNET_HashCode hash;
+ switch (ntohl (pub->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdh_ecdsa (&pk, &(pub->ecdsa_key),
+ &hash))
+ return -1;
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdh_eddsa (&pk, &(pub->eddsa_key),
+ &hash))
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ GNUNET_CRYPTO_ecdhe_key_get_public (&pk, ecc);
+ GNUNET_CRYPTO_ecdhe_key_clear (&pk);
+ struct GNUNET_CRYPTO_SymmetricSessionKey key;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ GNUNET_CRYPTO_hash_to_aes_key (&hash, &key, &iv);
+ GNUNET_CRYPTO_zero_keys (&hash, sizeof(hash));
+ const ssize_t encrypted = GNUNET_CRYPTO_symmetric_encrypt (block, size, &key,
+ &iv, result);
+ GNUNET_CRYPTO_zero_keys (&key, sizeof(key));
+ GNUNET_CRYPTO_zero_keys (&iv, sizeof(iv));
+ return encrypted;
+}
+
+
+ssize_t
+GNUNET_IDENTITY_decrypt (const void *block,
+ size_t size,
+ const struct GNUNET_IDENTITY_PrivateKey *priv,
+ const struct GNUNET_CRYPTO_EcdhePublicKey *ecc,
+ void *result)
+{
+ struct GNUNET_HashCode hash;
+ switch (ntohl (priv->type))
+ {
+ case GNUNET_IDENTITY_TYPE_ECDSA:
+ if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_ecdh (&(priv->ecdsa_key), ecc,
+ &hash))
+ return -1;
+ break;
+ case GNUNET_IDENTITY_TYPE_EDDSA:
+ if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_ecdh (&(priv->eddsa_key), ecc,
+ &hash))
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ struct GNUNET_CRYPTO_SymmetricSessionKey key;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ GNUNET_CRYPTO_hash_to_aes_key (&hash, &key, &iv);
+ GNUNET_CRYPTO_zero_keys (&hash, sizeof(hash));
+ const ssize_t decrypted = GNUNET_CRYPTO_symmetric_decrypt (block, size, &key,
+ &iv, result);
+ GNUNET_CRYPTO_zero_keys (&key, sizeof(key));
+ GNUNET_CRYPTO_zero_keys (&iv, sizeof(iv));
+ return decrypted;
+}
+
+
+char *
+GNUNET_IDENTITY_public_key_to_string (const struct
+ GNUNET_IDENTITY_PublicKey *key)
+{
+ size_t size = GNUNET_IDENTITY_key_get_length (key);
+ return GNUNET_STRINGS_data_to_string_alloc (key,
+ size);
+}
+
+
+char *
+GNUNET_IDENTITY_private_key_to_string (const struct
+ GNUNET_IDENTITY_PrivateKey *key)
+{
+ size_t size = private_key_get_length (key);
+ return GNUNET_STRINGS_data_to_string_alloc (key,
+ size);
+}
+
+
+enum GNUNET_GenericReturnValue
+GNUNET_IDENTITY_public_key_from_string (const char *str,
+ struct GNUNET_IDENTITY_PublicKey *key)
+{
+ enum GNUNET_GenericReturnValue ret;
+ enum GNUNET_IDENTITY_KeyType ktype;
+ ret = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ key,
+ sizeof (*key));
+ if (GNUNET_OK != ret)
+ return GNUNET_SYSERR;
+ ktype = ntohl (key->type);
+ return (GNUNET_IDENTITY_TYPE_ECDSA == ktype) ? GNUNET_OK : GNUNET_SYSERR; // FIXME other keys, cleaner way?
+
+}
+
+
+enum GNUNET_GenericReturnValue
+GNUNET_IDENTITY_private_key_from_string (const char *str,
+ struct GNUNET_IDENTITY_PrivateKey *key)
+{
+ enum GNUNET_GenericReturnValue ret;
+ enum GNUNET_IDENTITY_KeyType ktype;
+ ret = GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ key,
+ sizeof (*key));
+ if (GNUNET_OK != ret)
+ return GNUNET_SYSERR;
+ ktype = ntohl (key->type);
+ return (GNUNET_IDENTITY_TYPE_ECDSA == ktype) ? GNUNET_OK : GNUNET_SYSERR; // FIXME other keys, cleaner way?
+}
+
+
/* end of identity_api.c */
diff --git a/src/identity/identity_api_lookup.c b/src/identity/identity_api_lookup.c
index 26b1eacd7..51afb2515 100644
--- a/src/identity/identity_api_lookup.c
+++ b/src/identity/identity_api_lookup.c
@@ -127,14 +127,12 @@ handle_identity_update (void *cls, const struct UpdateMessage *um)
struct GNUNET_IDENTITY_EgoLookup *el = cls;
uint16_t name_len = ntohs (um->name_len);
const char *str = (0 == name_len) ? NULL : (const char *) &um[1];
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
struct GNUNET_HashCode id;
struct GNUNET_IDENTITY_Ego ego;
memset (&ego, 0, sizeof (ego));
GNUNET_break (GNUNET_YES != ntohs (um->end_of_list));
- GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key, &pub);
- GNUNET_CRYPTO_hash (&pub, sizeof(pub), &id);
+ GNUNET_CRYPTO_hash (&um->private_key, sizeof(um->private_key), &id);
ego.pk = um->private_key;
ego.name = (char *) str;
ego.id = id;
diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c
index d86d29e36..dba1d478d 100644
--- a/src/identity/plugin_rest_identity.c
+++ b/src/identity/plugin_rest_identity.c
@@ -384,7 +384,7 @@ ego_get_for_subsystem (void *cls,
{
struct RequestHandle *handle = cls;
struct MHD_Response *resp;
- struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
+ struct GNUNET_IDENTITY_PublicKey public_key;
json_t *json_root;
char *result_str;
char *public_key_string;
@@ -398,7 +398,7 @@ ego_get_for_subsystem (void *cls,
}
GNUNET_IDENTITY_ego_get_public_key (ego, &public_key);
- public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string (&public_key);
+ public_key_string = GNUNET_IDENTITY_public_key_to_string (&public_key);
// create json with subsystem identity
json_root = json_object ();
@@ -496,7 +496,7 @@ ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
GNUNET_CONTAINER_multihashmap_contains (
handle->rest_handle->url_param_map, &key))
{
- privkey_str = GNUNET_CRYPTO_ecdsa_private_key_to_string (
+ privkey_str = GNUNET_IDENTITY_private_key_to_string (
GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego));
json_object_set_new (json_ego,
GNUNET_REST_IDENTITY_PARAM_PRIVKEY,
@@ -549,7 +549,7 @@ ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
GNUNET_CONTAINER_multihashmap_contains (
handle->rest_handle->url_param_map, &key))
{
- privkey_str = GNUNET_CRYPTO_ecdsa_private_key_to_string (
+ privkey_str = GNUNET_IDENTITY_private_key_to_string (
GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego));
json_object_set_new (json_ego,
GNUNET_REST_IDENTITY_PARAM_PRIVKEY,
@@ -686,7 +686,7 @@ do_finished (void *cls, const char *emsg)
*/
static void
do_finished_create (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
struct RequestHandle *handle = cls;
@@ -999,8 +999,8 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle,
json_error_t err;
char *egoname;
char *privkey;
- struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
- struct GNUNET_CRYPTO_EcdsaPrivateKey *pk_ptr;
+ struct GNUNET_IDENTITY_PrivateKey pk;
+ struct GNUNET_IDENTITY_PrivateKey *pk_ptr;
int json_unpack_state;
char term_data[handle->data_size + 1];
@@ -1074,7 +1074,7 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle,
strlen (privkey),
&pk,
sizeof(struct
- GNUNET_CRYPTO_EcdsaPrivateKey));
+ GNUNET_IDENTITY_PrivateKey));
pk_ptr = &pk;
}
else
@@ -1084,6 +1084,7 @@ ego_create (struct GNUNET_REST_RequestHandle *con_handle,
handle->op = GNUNET_IDENTITY_create (identity_handle,
handle->name,
pk_ptr,
+ GNUNET_IDENTITY_TYPE_ECDSA,
&do_finished_create,
handle);
}
@@ -1208,7 +1209,7 @@ list_ego (void *cls,
const char *identifier)
{
struct EgoEntry *ego_entry;
- struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+ struct GNUNET_IDENTITY_PublicKey pk;
if ((NULL == ego) && (ID_REST_STATE_INIT == state))
{
@@ -1219,7 +1220,7 @@ list_ego (void *cls,
{
ego_entry = GNUNET_new (struct EgoEntry);
GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+ ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
ego_entry->ego = ego;
ego_entry->identifier = GNUNET_strdup (identifier);
GNUNET_CONTAINER_DLL_insert_tail (ego_head,
@@ -1245,7 +1246,7 @@ list_ego (void *cls,
/* Add */
ego_entry = GNUNET_new (struct EgoEntry);
GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+ ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
ego_entry->ego = ego;
ego_entry->identifier = GNUNET_strdup (identifier);
GNUNET_CONTAINER_DLL_insert_tail (ego_head,
diff --git a/src/identity/test_identity.c b/src/identity/test_identity.c
index 37eeab238..4954fe7be 100644
--- a/src/identity/test_identity.c
+++ b/src/identity/test_identity.c
@@ -253,7 +253,7 @@ success_rename_cont (void *cls, const char *emsg)
*/
static void
create_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
CHECK (NULL != pk);
@@ -279,7 +279,11 @@ run (void *cls,
GNUNET_SCHEDULER_add_shutdown (&cleanup, NULL);
h = GNUNET_IDENTITY_connect (cfg, &notification_cb, NULL);
CHECK (NULL != h);
- op = GNUNET_IDENTITY_create (h, "test-id", NULL, &create_cb, NULL);
+ op = GNUNET_IDENTITY_create (h,
+ "test-id",
+ NULL,
+ GNUNET_IDENTITY_TYPE_ECDSA,
+ &create_cb, NULL);
}
diff --git a/src/identity/test_identity_defaults.c b/src/identity/test_identity_defaults.c
index 53eec1252..2d5244d1b 100644
--- a/src/identity/test_identity_defaults.c
+++ b/src/identity/test_identity_defaults.c
@@ -241,7 +241,7 @@ notification_cb (void *cls,
*/
static void
create_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg)
{
CHECK (NULL == emsg);
@@ -266,7 +266,11 @@ run_set (void *cls,
GNUNET_SCHEDULER_add_shutdown (&cleanup, NULL);
h = GNUNET_IDENTITY_connect (cfg, &notification_cb, NULL);
CHECK (NULL != h);
- op = GNUNET_IDENTITY_create (h, "test-id", NULL, &create_cb, NULL);
+ op = GNUNET_IDENTITY_create (h,
+ "test-id",
+ NULL,
+ GNUNET_IDENTITY_TYPE_ECDSA,
+ &create_cb, NULL);
}
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 202abb7ac..fc3d745a6 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -62,6 +62,7 @@ gnunetinclude_HEADERS = \
gnunet_json_lib.h \
gnunet_load_lib.h \
gnunet_cadet_service.h \
+ gnunet_messenger_service.h \
gnunet_mhd_compat.h \
gnunet_microphone_lib.h \
gnunet_mst_lib.h \
diff --git a/src/include/gnunet_buffer_lib.h b/src/include/gnunet_buffer_lib.h
index 0c566df75..7239eccfb 100644
--- a/src/include/gnunet_buffer_lib.h
+++ b/src/include/gnunet_buffer_lib.h
@@ -147,7 +147,8 @@ GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str);
* @param ... format arguments
*/
void
-GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...);
+GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...)
+__attribute__ ((format (printf, 2, 3)));
/**
diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h
index fcaae1026..21b87b0f5 100644
--- a/src/include/gnunet_common.h
+++ b/src/include/gnunet_common.h
@@ -488,7 +488,8 @@ void
GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind,
const char *comp,
const char *message,
- ...);
+ ...)
+__attribute__ ((format (printf, 3, 4)));
#if ! defined(GNUNET_CULL_LOGGING)
#define GNUNET_log_from(kind, comp, ...) \
@@ -1445,6 +1446,7 @@ GNUNET_is_zero_ (const void *a,
memcpy (&(arr1) [(len1) - (len2)], _a2, (len2) * sizeof (*arr1)); \
} while (0)
+
/**
* @ingroup memory
* Like snprintf, just aborts if the buffer is of insufficient size.
@@ -1456,7 +1458,11 @@ GNUNET_is_zero_ (const void *a,
* @return number of bytes written to buf or negative value on error
*/
int
-GNUNET_snprintf (char *buf, size_t size, const char *format, ...);
+GNUNET_snprintf (char *buf,
+ size_t size,
+ const char *format,
+ ...)
+__attribute__ ((format (printf, 3, 4)));
/**
@@ -1469,7 +1475,10 @@ GNUNET_snprintf (char *buf, size_t size, const char *format, ...);
* @return number of bytes in "*buf" excluding 0-termination
*/
int
-GNUNET_asprintf (char **buf, const char *format, ...);
+GNUNET_asprintf (char **buf,
+ const char *format,
+ ...)
+__attribute__ ((format (printf, 2, 3)));
/* ************** internal implementations, use macros above! ************** */
diff --git a/src/include/gnunet_conversation_service.h b/src/include/gnunet_conversation_service.h
index 4566caad0..be5a81cfb 100644
--- a/src/include/gnunet_conversation_service.h
+++ b/src/include/gnunet_conversation_service.h
@@ -147,7 +147,7 @@ typedef void
struct GNUNET_CONVERSATION_Caller *
caller,
const struct
- GNUNET_CRYPTO_EcdsaPublicKey *caller_id);
+ GNUNET_IDENTITY_PublicKey *caller_id);
/**
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h
index 03fb16a43..2bbf2b1e7 100644
--- a/src/include/gnunet_crypto_lib.h
+++ b/src/include/gnunet_crypto_lib.h
@@ -1700,7 +1700,7 @@ GNUNET_CRYPTO_eddsa_sign_ (
*/
#define GNUNET_CRYPTO_eddsa_sign(priv,ps,sig) do { \
/* check size is set correctly */ \
- GNUNET_assert (htonl ((ps)->purpose.size) == sizeof (*ps)); \
+ GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*ps)); \
/* check 'ps' begins with the purpose */ \
GNUNET_static_assert (((void*) (ps)) == \
((void*) &(ps)->purpose)); \
@@ -1747,7 +1747,7 @@ GNUNET_CRYPTO_ecdsa_sign_ (
*/
#define GNUNET_CRYPTO_ecdsa_sign(priv,ps,sig) do { \
/* check size is set correctly */ \
- GNUNET_assert (htonl ((ps)->purpose.size) == sizeof (*(ps))); \
+ GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \
/* check 'ps' begins with the purpose */ \
GNUNET_static_assert (((void*) (ps)) == \
((void*) &(ps)->purpose)); \
@@ -1853,7 +1853,7 @@ GNUNET_CRYPTO_ecdsa_verify_ (
*/
#define GNUNET_CRYPTO_ecdsa_verify(purp,ps,sig,pub) ({ \
/* check size is set correctly */ \
- GNUNET_assert (htonl ((ps)->purpose.size) == sizeof (*(ps))); \
+ GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \
/* check 'ps' begins with the purpose */ \
GNUNET_static_assert (((void*) (ps)) == \
((void*) &(ps)->purpose)); \
diff --git a/src/include/gnunet_gns_service.h b/src/include/gnunet_gns_service.h
index ef81e9a88..3f6c9b9aa 100644
--- a/src/include/gnunet_gns_service.h
+++ b/src/include/gnunet_gns_service.h
@@ -36,6 +36,7 @@
#include "gnunet_util_lib.h"
#include "gnunet_dnsparser_lib.h"
+#include "gnunet_identity_service.h"
#include "gnunet_namestore_service.h"
#ifdef __cplusplus
@@ -139,7 +140,7 @@ enum GNUNET_GNS_LocalOptions
struct GNUNET_GNS_LookupRequest *
GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
const char *name,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
+ const struct GNUNET_IDENTITY_PublicKey *zone,
uint32_t type,
enum GNUNET_GNS_LocalOptions options,
GNUNET_GNS_LookupResultProcessor proc,
@@ -163,7 +164,7 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
struct GNUNET_GNS_LookupRequest *
GNUNET_GNS_lookup_limited (struct GNUNET_GNS_Handle *handle,
const char *name,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
+ const struct GNUNET_IDENTITY_PublicKey *zone,
uint32_t type,
enum GNUNET_GNS_LocalOptions options,
uint16_t recursion_depth_limit,
diff --git a/src/include/gnunet_gnsrecord_json_lib.h b/src/include/gnunet_gnsrecord_json_lib.h
new file mode 100644
index 000000000..966461705
--- /dev/null
+++ b/src/include/gnunet_gnsrecord_json_lib.h
@@ -0,0 +1,73 @@
+/*
+ This file is part of GNUnet
+ Copyright (C) 2012, 2013 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+
+/**
+ * @author Martin Schanzenbach
+ *
+ * @file
+ * API that can be used to manipulate JSON GNS record data
+ *
+ * @defgroup gnsrecord GNS Record library
+ * Manipulate GNS record data
+ *
+ * @see [Documentation](https://gnunet.org/gns-plugins)
+ *
+ * @{
+ */
+#ifndef GNUNET_GNSRECORD_JSON_LIB_H
+#define GNUNET_GNSRECORD_JSON_LIB_H
+
+#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_json_lib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+
+/**
+ * JSON Specification for GNS Records.
+ *
+ * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
+ * @return JSON Specification
+ */
+struct GNUNET_JSON_Specification
+GNUNET_GNSRECORD_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
+ unsigned int *rd_count,
+ char **name);
+
+
+/**
+ * Convert GNS record to JSON.
+ *
+ * @param rname name of record
+ * @param rd record data
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_GNSRECORD_JSON_from_gnsrecord (const char*rname,
+ const struct GNUNET_GNSRECORD_Data *rd,
+ unsigned int rd_count);
+
+
+#endif
diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h
index 960203fb1..0bf2ceed7 100644
--- a/src/include/gnunet_gnsrecord_lib.h
+++ b/src/include/gnunet_gnsrecord_lib.h
@@ -34,6 +34,8 @@
#ifndef GNUNET_GNSRECORD_LIB_H
#define GNUNET_GNSRECORD_LIB_H
+#include "gnunet_identity_service.h"
+
#ifdef __cplusplus
extern "C" {
#if 0 /* keep Emacsens' auto-indent happy */
@@ -55,7 +57,7 @@ extern "C" {
/**
* Record type for GNS zone transfer ("PKEY").
*/
-#define GNUNET_GNSRECORD_TYPE_PKEY 65536
+#define GNUNET_GNSRECORD_TYPE_PKEY GNUNET_IDENTITY_TYPE_ECDSA
/**
* Record type for GNS nick names ("NICK").
@@ -151,6 +153,11 @@ extern "C" {
*/
#define GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION 65555
+/**
+ * Record type for EDKEY delegations.
+ */
+#define GNUNET_GNSRECORD_TYPE_EDKEY GNUNET_IDENTITY_TYPE_EDDSA
+
/**
* Flags that can be set for a record.
@@ -261,21 +268,20 @@ struct GNUNET_GNSRECORD_PlaceData
/* Followed by struct GNUNET_PeerIdentity relays[relay_count] */
};
-
/**
* Information we have in an encrypted block with record data (i.e. in the DHT).
*/
-struct GNUNET_GNSRECORD_Block
+struct GNUNET_GNSRECORD_EcdsaBlock
{
/**
- * Signature of the block.
+ * Derived key used for signing; hash of this is the query.
*/
- struct GNUNET_CRYPTO_EcdsaSignature signature;
+ struct GNUNET_CRYPTO_EcdsaPublicKey derived_key;
/**
- * Derived key used for signing; hash of this is the query.
+ * Signature of the block.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey derived_key;
+ struct GNUNET_CRYPTO_EcdsaSignature signature;
/**
* Number of bytes signed; also specifies the number of bytes
@@ -291,6 +297,17 @@ struct GNUNET_GNSRECORD_Block
/* followed by encrypted data */
};
+struct GNUNET_GNSRECORD_Block
+{
+ uint32_t type;
+
+ union
+ {
+ struct GNUNET_GNSRECORD_EcdsaBlock ecdsa_block;
+ //struct GNUNET_GNSRECORD_EddsaBlock eddsa_block;
+ };
+};
+
/**
* Record type used to box up SRV and TLSA records. For example, a
@@ -335,7 +352,7 @@ struct GNUNET_GNSRECORD_ReverseRecord
/**
* The public key of the namespace the is delegating to our namespace
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+ struct GNUNET_IDENTITY_PublicKey pkey;
/**
* The expiration time of the delegation
@@ -488,7 +505,7 @@ GNUNET_GNSRECORD_string_to_lowercase (const char *src);
* #GNUNET_GNSRECORD_z2s.
*/
const char *
-GNUNET_GNSRECORD_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z);
+GNUNET_GNSRECORD_z2s (const struct GNUNET_IDENTITY_PublicKey *z);
/**
@@ -502,7 +519,7 @@ GNUNET_GNSRECORD_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z);
* key in an encoding suitable for DNS labels.
*/
const char *
-GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey);
+GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_IDENTITY_PublicKey *pkey);
/**
@@ -516,7 +533,7 @@ GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey);
*/
int
GNUNET_GNSRECORD_zkey_to_pkey (const char *zkey,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pkey);
+ struct GNUNET_IDENTITY_PublicKey *pkey);
/**
@@ -528,7 +545,7 @@ GNUNET_GNSRECORD_zkey_to_pkey (const char *zkey,
*/
void
GNUNET_GNSRECORD_query_from_private_key (
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const char *label,
+ const struct GNUNET_IDENTITY_PrivateKey *zone, const char *label,
struct GNUNET_HashCode *query);
@@ -541,7 +558,7 @@ GNUNET_GNSRECORD_query_from_private_key (
*/
void
GNUNET_GNSRECORD_query_from_public_key (
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pub, const char *label,
+ const struct GNUNET_IDENTITY_PublicKey *pub, const char *label,
struct GNUNET_HashCode *query);
@@ -555,7 +572,7 @@ GNUNET_GNSRECORD_query_from_public_key (
* @param rd_count number of records in @a rd
*/
struct GNUNET_GNSRECORD_Block *
-GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key,
struct GNUNET_TIME_Absolute expire,
const char *label,
const struct GNUNET_GNSRECORD_Data *rd,
@@ -574,7 +591,7 @@ GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
* @param rd_count number of records in @a rd
*/
struct GNUNET_GNSRECORD_Block *
-GNUNET_GNSRECORD_block_create2 (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *key,
struct GNUNET_TIME_Absolute expire,
const char *label,
const struct GNUNET_GNSRECORD_Data *rd,
@@ -606,7 +623,7 @@ GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block);
int
GNUNET_GNSRECORD_block_decrypt (
const struct GNUNET_GNSRECORD_Block *block,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key, const char *label,
+ const struct GNUNET_IDENTITY_PublicKey *zone_key, const char *label,
GNUNET_GNSRECORD_RecordCallback proc, void *proc_cls);
@@ -636,6 +653,82 @@ GNUNET_GNSRECORD_record_get_expiration_time (
unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd);
+/**
+ * Returns the length of this block in bytes.
+ * Block length strongly depends on the zone type.
+ *
+ * @param block the block.
+ * @return the length of this block in bytes
+ */
+size_t
+GNUNET_GNSRECORD_block_get_size (const struct GNUNET_GNSRECORD_Block *block);
+
+/**
+ * Returns the expiration of a block.
+ *
+ * @param block the block.
+ * @return the block expiration.
+ */
+struct GNUNET_TIME_Absolute
+GNUNET_GNSRECORD_block_get_expiration (const struct GNUNET_GNSRECORD_Block *block);
+
+
+/**
+ * Builds the query hash from a block.
+ *
+ * @param block the block.
+ * @param query where to write the query hash.
+ * @return GNUNET_SYSERR on error.
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_query_from_block (const struct GNUNET_GNSRECORD_Block *block,
+ struct GNUNET_HashCode *query);
+
+
+/**
+ * Build a #GNUNET_GNSRECORD_PublicKey from
+ * zone delegation resource record data.
+ *
+ * @param data the record data-
+ * @param data_size the data size.
+ * @param type the record type
+ * @param key the identity key to store the data in (must be allocated).
+ * @return GNUNET_OK if successful.
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_identity_from_data (const char *data,
+ size_t data_size,
+ uint32_t type,
+ struct GNUNET_IDENTITY_PublicKey *key);
+
+
+/**
+ * Create record data and size from an identity key.
+ *
+ * @param key the identity key to use.
+ * @param data the record data (will be allocated)
+ * @param data_size the allocated data size.
+ * @param type the resulting record type
+ * @return GNUNET_OK if successful.
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_data_from_identity (const struct GNUNET_IDENTITY_PublicKey *key,
+ char **data,
+ size_t *data_size,
+ uint32_t *type);
+
+
+/**
+ * Check if this type is one of the supported GNS zone
+ * types.
+ *
+ * @param type the type to check
+ * @return GNUNET_YES if it is one of the supported types.
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_GNSRECORD_is_zonekey_type (uint32_t type);
+
+
#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
diff --git a/src/include/gnunet_identity_service.h b/src/include/gnunet_identity_service.h
index 94127248e..2974568db 100644
--- a/src/include/gnunet_identity_service.h
+++ b/src/include/gnunet_identity_service.h
@@ -57,6 +57,21 @@ extern "C" {
*/
#define GNUNET_IDENTITY_VERSION 0x00000100
+enum GNUNET_IDENTITY_KeyType
+{
+ /**
+ * The identity type. The value is the same as the
+ * PKEY record type.
+ */
+ GNUNET_IDENTITY_TYPE_ECDSA = 65536,
+
+ /**
+ * EDDSA identity. The value is the same as the EDKEY
+ * record type.
+ */
+ GNUNET_IDENTITY_TYPE_EDDSA = 65556
+};
+
/**
* Handle to access the identity service.
*/
@@ -67,6 +82,88 @@ struct GNUNET_IDENTITY_Handle;
*/
struct GNUNET_IDENTITY_Ego;
+
+/**
+ * A private key for an identity as per LSD0001.
+ */
+struct GNUNET_IDENTITY_PrivateKey
+{
+ /**
+ * Type of public key.
+ * Defined by the GNS zone type value.
+ * In NBO.
+ */
+ uint32_t type;
+
+ union
+ {
+ /**
+ * An ECDSA identity key.
+ */
+ struct GNUNET_CRYPTO_EcdsaPrivateKey ecdsa_key;
+
+ /**
+ * AN EdDSA identtiy key
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_key;
+ };
+};
+
+
+/**
+ * An identity key as per LSD0001.
+ */
+struct GNUNET_IDENTITY_PublicKey
+{
+ /**
+ * Type of public key.
+ * Defined by the GNS zone type value.
+ * In NBO.
+ */
+ uint32_t type;
+
+ union
+ {
+ /**
+ * An ECDSA identity key.
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey ecdsa_key;
+
+ /**
+ * AN EdDSA identtiy key
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey eddsa_key;
+ };
+};
+
+
+/**
+ * An identity signature as per LSD0001.
+ */
+struct GNUNET_IDENTITY_Signature
+{
+ /**
+ * Type of signature.
+ * Defined by the GNS zone type value.
+ * In NBO.
+ */
+ uint32_t type;
+
+ union
+ {
+ /**
+ * An ECDSA signature
+ */
+ struct GNUNET_CRYPTO_EcdsaSignature ecdsa_signature;
+
+ /**
+ * AN EdDSA signature
+ */
+ struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
+ };
+};
+
+
/**
* Handle for an operation with the identity service.
*/
@@ -79,7 +176,7 @@ struct GNUNET_IDENTITY_Operation;
* @param ego the ego
* @return associated ECC key, valid as long as the ego is valid
*/
-const struct GNUNET_CRYPTO_EcdsaPrivateKey *
+const struct GNUNET_IDENTITY_PrivateKey *
GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego);
@@ -100,7 +197,7 @@ GNUNET_IDENTITY_ego_get_anonymous (void);
*/
void
GNUNET_IDENTITY_ego_get_public_key (struct GNUNET_IDENTITY_Ego *ego,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pk);
+ struct GNUNET_IDENTITY_PublicKey *pk);
/**
@@ -224,7 +321,7 @@ GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h);
typedef void
(*GNUNET_IDENTITY_CreateContinuation) (
void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
+ const struct GNUNET_IDENTITY_PrivateKey *pk,
const char *emsg);
@@ -234,6 +331,7 @@ typedef void
* @param id identity service to use
* @param name desired name
* @param privkey desired private key or NULL to create one
+ * @param ktype the type of key to create. Ignored if privkey != NULL.
* @param cont function to call with the result (will only be called once)
* @param cont_cls closure for @a cont
* @return handle to abort the operation
@@ -241,7 +339,8 @@ typedef void
struct GNUNET_IDENTITY_Operation *
GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *id,
const char *name,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey,
+ const struct GNUNET_IDENTITY_PrivateKey *privkey,
+ enum GNUNET_IDENTITY_KeyType ktype,
GNUNET_IDENTITY_CreateContinuation cont,
void *cont_cls);
@@ -292,6 +391,319 @@ void
GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op);
+/**
+ * Get the compacted length of a #GNUNET_IDENTITY_PublicKey.
+ * Compacted means that it returns the minimum number of bytes this
+ * key is long, as opposed to the union structure inside
+ * #GNUNET_IDENTITY_PublicKey.
+ * Useful for compact serializations.
+ *
+ * @param key the key.
+ * @return -1 on error, else the compacted length of the key.
+ */
+ssize_t
+GNUNET_IDENTITY_key_get_length (const struct GNUNET_IDENTITY_PublicKey *key);
+
+
+/**
+ * Reads a #GNUNET_IDENTITY_PublicKey from a compact buffer.
+ * The buffer has to contain at least the compacted length of
+ * a #GNUNET_IDENTITY_PublicKey in bytes.
+ * If the buffer is too small, the function returns -1 as error.
+ * If the buffer does not contain a valid key, it returns -2 as error.
+ *
+ * @param key the key
+ * @param buffer the buffer
+ * @param len the length of buffer
+ * @return -1 or -2 on error, else the amount of bytes read from the buffer
+ */
+ssize_t
+GNUNET_IDENTITY_read_key_from_buffer (struct GNUNET_IDENTITY_PublicKey *key,
+ const void*buffer,
+ size_t len);
+
+
+/**
+ * Writes a #GNUNET_IDENTITY_PublicKey to a compact buffer.
+ * The buffer requires space for at least the compacted length of
+ * a #GNUNET_IDENTITY_PublicKey in bytes.
+ * If the buffer is too small, the function returns -1 as error.
+ * If the key is not valid, it returns -2 as error.
+ *
+ * @param key the key
+ * @param buffer the buffer
+ * @param len the length of buffer
+ * @return -1 or -2 on error, else the amount of bytes written to the buffer
+ */
+ssize_t
+GNUNET_IDENTITY_write_key_to_buffer (const struct
+ GNUNET_IDENTITY_PublicKey *key,
+ void*buffer,
+ size_t len);
+
+
+/**
+ * Get the compacted length of a #GNUNET_IDENTITY_Signature.
+ * Compacted means that it returns the minimum number of bytes this
+ * signature is long, as opposed to the union structure inside
+ * #GNUNET_IDENTITY_Signature.
+ * Useful for compact serializations.
+ *
+ * @param sig the signature.
+ * @return -1 on error, else the compacted length of the signature.
+ */
+ssize_t
+GNUNET_IDENTITY_signature_get_length (const struct
+ GNUNET_IDENTITY_Signature *sig);
+
+
+/**
+ * Reads a #GNUNET_IDENTITY_Signature from a compact buffer.
+ * The buffer has to contain at least the compacted length of
+ * a #GNUNET_IDENTITY_Signature in bytes.
+ * If the buffer is too small, the function returns -1 as error.
+ * If the buffer does not contain a valid key, it returns -2 as error.
+ *
+ * @param sig the signature
+ * @param buffer the buffer
+ * @param len the length of buffer
+ * @return -1 or -2 on error, else the amount of bytes read from the buffer
+ */
+ssize_t
+GNUNET_IDENTITY_read_signature_from_buffer (struct
+ GNUNET_IDENTITY_Signature *sig,
+ const void*buffer,
+ size_t len);
+
+
+/**
+ * Writes a #GNUNET_IDENTITY_Signature to a compact buffer.
+ * The buffer requires space for at least the compacted length of
+ * a #GNUNET_IDENTITY_Signature in bytes.
+ * If the buffer is too small, the function returns -1 as error.
+ * If the key is not valid, it returns -2 as error.
+ *
+ * @param sig the signature
+ * @param buffer the buffer
+ * @param len the length of buffer
+ * @return -1 or -2 on error, else the amount of bytes written to the buffer
+ */
+ssize_t
+GNUNET_IDENTITY_write_signature_to_buffer (const struct
+ GNUNET_IDENTITY_Signature *sig,
+ void*buffer,
+ size_t len);
+
+
+/**
+ * @brief Sign a given block.
+ *
+ * The @a purpose data is the beginning of the data of which the signature is
+ * to be created. The `size` field in @a purpose must correctly indicate the
+ * number of bytes of the data structure, including its header. If possible,
+ * use #GNUNET_IDENTITY_sign() instead of this function.
+ *
+ * @param priv private key to use for the signing
+ * @param purpose what to sign (size, purpose)
+ * @param[out] sig where to write the signature
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_IDENTITY_sign_ (const struct
+ GNUNET_IDENTITY_PrivateKey *priv,
+ const struct
+ GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct GNUNET_IDENTITY_Signature *sig);
+
+
+/**
+ * @brief Sign a given block with #GNUNET_IDENTITY_PrivateKey.
+ *
+ * The @a ps data must be a fixed-size struct for which the signature is to be
+ * created. The `size` field in @a ps->purpose must correctly indicate the
+ * number of bytes of the data structure, including its header.
+ *
+ * @param priv private key to use for the signing
+ * @param ps packed struct with what to sign, MUST begin with a purpose
+ * @param[out] sig where to write the signature
+ */
+#define GNUNET_IDENTITY_sign(priv,ps,sig) do { \
+ /* check size is set correctly */ \
+ GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \
+ /* check 'ps' begins with the purpose */ \
+ GNUNET_static_assert (((void*) (ps)) == \
+ ((void*) &(ps)->purpose)); \
+ GNUNET_assert (GNUNET_OK == \
+ GNUNET_IDENTITY_sign_ (priv, \
+ &(ps)->purpose, \
+ sig)); \
+} while (0)
+
+
+/**
+ * @brief Verify a given signature.
+ *
+ * The @a validate data is the beginning of the data of which the signature
+ * is to be verified. The `size` field in @a validate must correctly indicate
+ * the number of bytes of the data structure, including its header. If @a
+ * purpose does not match the purpose given in @a validate (the latter must be
+ * in big endian), signature verification fails. If possible,
+ * use #GNUNET_IDENTITY_signature_verify() instead of this function (only if @a validate
+ * is not fixed-size, you must use this function directly).
+ *
+ * @param purpose what is the purpose that the signature should have?
+ * @param validate block to validate (size, purpose, data)
+ * @param sig signature that is being validated
+ * @param pub public key of the signer
+ * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
+ */
+int
+GNUNET_IDENTITY_signature_verify_ (uint32_t purpose,
+ const struct
+ GNUNET_CRYPTO_EccSignaturePurpose *validate,
+ const struct GNUNET_IDENTITY_Signature *sig,
+ const struct
+ GNUNET_IDENTITY_PublicKey *pub);
+
+
+/**
+ * @brief Verify a given signature with #GNUNET_IDENTITY_PublicKey.
+ *
+ * The @a ps data must be a fixed-size struct for which the signature is to be
+ * created. The `size` field in @a ps->purpose must correctly indicate the
+ * number of bytes of the data structure, including its header.
+ *
+ * @param purp purpose of the signature, must match 'ps->purpose.purpose'
+ * (except in host byte order)
+ * @param ps packed struct with what to sign, MUST begin with a purpose
+ * @param sig where to read the signature from
+ * @param pub public key to use for the verifying
+ */
+#define GNUNET_IDENTITY_signature_verify(purp,ps,sig,pub) ({ \
+ /* check size is set correctly */ \
+ GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \
+ /* check 'ps' begins with the purpose */ \
+ GNUNET_static_assert (((void*) (ps)) == \
+ ((void*) &(ps)->purpose)); \
+ GNUNET_IDENTITY_signature_verify_ (purp, \
+ &(ps)->purpose, \
+ sig, \
+ pub); \
+ })
+
+
+/**
+ * Encrypt a block with #GNUNET_IDENTITY_PublicKey and derives a
+ * #GNUNET_CRYPTO_EcdhePublicKey which is required for decryption
+ * using ecdh to derive a symmetric key.
+ *
+ * @param block the block to encrypt
+ * @param size the size of the @a block
+ * @param pub public key to use for ecdh
+ * @param ecc where to write the ecc public key
+ * @param result the output parameter in which to store the encrypted result
+ * can be the same or overlap with @c block
+ * @returns the size of the encrypted block, -1 for errors.
+ * Due to the use of CFB and therefore an effective stream cipher,
+ * this size should be the same as @c len.
+ */
+ssize_t
+GNUNET_IDENTITY_encrypt (const void *block,
+ size_t size,
+ const struct GNUNET_IDENTITY_PublicKey *pub,
+ struct GNUNET_CRYPTO_EcdhePublicKey *ecc,
+ void *result);
+
+
+/**
+ * Decrypt a given block with #GNUNET_IDENTITY_PrivateKey and a given
+ * #GNUNET_CRYPTO_EcdhePublicKey using ecdh to derive a symmetric key.
+ *
+ * @param block the data to decrypt, encoded as returned by encrypt
+ * @param size the size of the @a block to decrypt
+ * @param priv private key to use for ecdh
+ * @param ecc the ecc public key
+ * @param result address to store the result at
+ * can be the same or overlap with @c block
+ * @return -1 on failure, size of decrypted block on success.
+ * Due to the use of CFB and therefore an effective stream cipher,
+ * this size should be the same as @c size.
+ */
+ssize_t
+GNUNET_IDENTITY_decrypt (const void *block,
+ size_t size,
+ const struct
+ GNUNET_IDENTITY_PrivateKey *priv,
+ const struct
+ GNUNET_CRYPTO_EcdhePublicKey *ecc,
+ void *result);
+
+
+/**
+ * Creates a (Base32) string representation of the public key.
+ * The resulting string encodes a compacted representation of the key.
+ * See also #GNUNET_IDENTITY_key_get_length.
+ *
+ * @param key the key.
+ * @return the string representation of the key, or NULL on error.
+ */
+char *
+GNUNET_IDENTITY_public_key_to_string (const struct
+ GNUNET_IDENTITY_PublicKey *key);
+
+
+/**
+ * Creates a (Base32) string representation of the private key.
+ * The resulting string encodes a compacted representation of the key.
+ * See also #GNUNET_IDENTITY_key_get_length.
+ *
+ * @param key the key.
+ * @return the string representation of the key, or NULL on error.
+ */
+char *
+GNUNET_IDENTITY_private_key_to_string (const struct
+ GNUNET_IDENTITY_PrivateKey *key);
+
+
+/**
+ * Parses a (Base32) string representation of the public key.
+ * See also #GNUNET_IDENTITY_public_key_to_string.
+ *
+ * @param str the encoded key.
+ * @param key where to write the key.
+ * @return GNUNET_SYSERR on error.
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_IDENTITY_public_key_from_string (const char*str,
+ struct GNUNET_IDENTITY_PublicKey *key);
+
+
+/**
+ * Parses a (Base32) string representation of the private key.
+ * See also #GNUNET_IDENTITY_private_key_to_string.
+ *
+ * @param str the encoded key.
+ * @param key where to write the key.
+ * @return GNUNET_SYSERR on error.
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_IDENTITY_private_key_from_string (const char*str,
+ struct GNUNET_IDENTITY_PrivateKey *key);
+
+
+/**
+ * Retrieves the public key representation of a private key.
+ *
+ * @param privkey the private key.
+ * @param key the public key result.
+ * @return GNUNET_SYSERR on error.
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_IDENTITY_key_get_public (const struct
+ GNUNET_IDENTITY_PrivateKey *privkey,
+ struct GNUNET_IDENTITY_PublicKey *key);
+
+
/* ************* convenience API to lookup an ego ***************** */
/**
@@ -344,7 +756,7 @@ GNUNET_IDENTITY_ego_lookup_cancel (struct GNUNET_IDENTITY_EgoLookup *el);
typedef void
(*GNUNET_IDENTITY_EgoSuffixCallback) (
void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+ const struct GNUNET_IDENTITY_PrivateKey *priv,
const char *ego_name);
diff --git a/src/include/gnunet_json_lib.h b/src/include/gnunet_json_lib.h
index 07a14d329..3dc79105e 100644
--- a/src/include/gnunet_json_lib.h
+++ b/src/include/gnunet_json_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet
- Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+ Copyright (C) 2014, 2015, 2016, 2020 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
@@ -28,7 +28,6 @@
#define GNUNET_JSON_LIB_H
#include "gnunet_util_lib.h"
-#include "gnunet_gnsrecord_lib.h"
#include <jansson.h>
#include <microhttpd.h>
@@ -359,18 +358,6 @@ GNUNET_JSON_spec_rsa_signature (const char *name,
struct GNUNET_CRYPTO_RsaSignature **sig);
-/**
- * JSON Specification for GNS Records.
- *
- * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
- * @return JSON Specification
- */
-struct GNUNET_JSON_Specification
-GNUNET_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
- unsigned int *rd_count,
- char **name);
-
-
/* ****************** Generic generator interface ******************* */
@@ -446,18 +433,6 @@ GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *pk);
json_t *
GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig);
-/**
- * Convert Gns record to JSON.
- *
- * @param rname name of record
- * @param rd record data
- * @return corresponding JSON encoding
- */
-json_t *
-GNUNET_JSON_from_gnsrecord (const char *rname,
- const struct GNUNET_GNSRECORD_Data *rd,
- unsigned int rd_count);
-
/* ******************* Helpers for MHD upload handling ******************* */
/**
diff --git a/src/include/gnunet_messenger_service.h b/src/include/gnunet_messenger_service.h
new file mode 100644
index 000000000..8f5315c30
--- /dev/null
+++ b/src/include/gnunet_messenger_service.h
@@ -0,0 +1,436 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ *
+ * @file
+ * MESSENGER service; manages decentralized chat groups
+ *
+ * @defgroup messenger MESSENGER service
+ * Instant messaging based on the CADET subsystem
+ *
+ * @{
+ */
+
+#ifndef GNUNET_MESSENGER_SERVICE_H
+#define GNUNET_MESSENGER_SERVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_configuration_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_mq_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_time_lib.h"
+
+#define GNUNET_MESSENGER_SERVICE_NAME "messenger"
+
+/**
+ * Opaque handle to the messenger
+ */
+struct GNUNET_MESSENGER_Handle;
+
+/**
+ * Opaque handle to a room
+ */
+struct GNUNET_MESSENGER_Room;
+
+/**
+ * Opaque handle to a contact
+ */
+struct GNUNET_MESSENGER_Contact;
+
+/**
+ * Enum for the different supported kinds of messages
+ */
+enum GNUNET_MESSENGER_MessageKind
+{
+ GNUNET_MESSENGER_KIND_INFO = 1,
+
+ GNUNET_MESSENGER_KIND_JOIN = 2,
+ GNUNET_MESSENGER_KIND_LEAVE = 3,
+
+ GNUNET_MESSENGER_KIND_NAME = 4,
+ GNUNET_MESSENGER_KIND_KEY = 5,
+ GNUNET_MESSENGER_KIND_PEER = 6,
+ GNUNET_MESSENGER_KIND_ID = 7,
+
+ GNUNET_MESSENGER_KIND_MISS = 8,
+ GNUNET_MESSENGER_KIND_MERGE = 9,
+ GNUNET_MESSENGER_KIND_REQUEST = 10,
+
+ GNUNET_MESSENGER_KIND_INVITE = 11,
+ GNUNET_MESSENGER_KIND_TEXT = 12,
+ GNUNET_MESSENGER_KIND_FILE = 13,
+
+ GNUNET_MESSENGER_KIND_PRIVATE = 14,
+
+ GNUNET_MESSENGER_KIND_UNKNOWN = 0
+}__attribute__((__packed__));
+
+/**
+ * Get the name of a message <i>kind</i>.
+ *
+ * @param kind Kind of a message
+ * @return Name of that kind
+ */
+const char*
+GNUNET_MESSENGER_name_of_kind (enum GNUNET_MESSENGER_MessageKind kind);
+
+struct GNUNET_MESSENGER_MessageHeader
+{
+ struct GNUNET_IDENTITY_Signature signature;
+
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+
+ struct GNUNET_ShortHashCode sender_id;
+ struct GNUNET_HashCode previous;
+
+ enum GNUNET_MESSENGER_MessageKind kind;
+};
+
+struct GNUNET_MESSENGER_MessageInfo
+{
+ struct GNUNET_IDENTITY_PublicKey host_key;
+ struct GNUNET_ShortHashCode unique_id;
+};
+
+struct GNUNET_MESSENGER_MessageJoin
+{
+ struct GNUNET_IDENTITY_PublicKey key;
+};
+
+struct GNUNET_MESSENGER_MessageLeave
+{
+};
+
+struct GNUNET_MESSENGER_MessageName
+{
+ char *name;
+};
+
+struct GNUNET_MESSENGER_MessageKey
+{
+ struct GNUNET_IDENTITY_PublicKey key;
+};
+
+struct GNUNET_MESSENGER_MessagePeer
+{
+ struct GNUNET_PeerIdentity peer;
+};
+
+struct GNUNET_MESSENGER_MessageId
+{
+ struct GNUNET_ShortHashCode id;
+};
+
+struct GNUNET_MESSENGER_MessageMiss
+{
+ struct GNUNET_PeerIdentity peer;
+};
+
+struct GNUNET_MESSENGER_MessageMerge
+{
+ struct GNUNET_HashCode previous;
+};
+
+struct GNUNET_MESSENGER_MessageRequest
+{
+ struct GNUNET_HashCode hash;
+};
+
+struct GNUNET_MESSENGER_MessageInvite
+{
+ struct GNUNET_PeerIdentity door;
+ struct GNUNET_HashCode key;
+};
+
+struct GNUNET_MESSENGER_MessageText
+{
+ char *text;
+};
+
+struct GNUNET_MESSENGER_MessageFile
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey key;
+ struct GNUNET_HashCode hash;
+ char name[NAME_MAX];
+ char *uri;
+};
+
+struct GNUNET_MESSENGER_MessagePrivate
+{
+ struct GNUNET_CRYPTO_EcdhePublicKey key;
+
+ uint16_t length;
+ char *data;
+};
+
+struct GNUNET_MESSENGER_MessageBody
+{
+ union
+ {
+ struct GNUNET_MESSENGER_MessageInfo info;
+
+ struct GNUNET_MESSENGER_MessageJoin join;
+ struct GNUNET_MESSENGER_MessageLeave leave;
+
+ struct GNUNET_MESSENGER_MessageName name;
+ struct GNUNET_MESSENGER_MessageKey key;
+ struct GNUNET_MESSENGER_MessagePeer peer;
+ struct GNUNET_MESSENGER_MessageId id;
+
+ struct GNUNET_MESSENGER_MessageMiss miss;
+ struct GNUNET_MESSENGER_MessageMerge merge;
+ struct GNUNET_MESSENGER_MessageRequest request;
+
+ struct GNUNET_MESSENGER_MessageInvite invite;
+ struct GNUNET_MESSENGER_MessageText text;
+ struct GNUNET_MESSENGER_MessageFile file;
+
+ struct GNUNET_MESSENGER_MessagePrivate private;
+ };
+};
+
+/**
+ * Struct to a message
+ */
+struct GNUNET_MESSENGER_Message
+{
+ struct GNUNET_MESSENGER_MessageHeader header;
+ struct GNUNET_MESSENGER_MessageBody body;
+};
+
+/**
+ * Method called whenever the EGO of a <i>handle</i> changes or if the first connection fails
+ * to load a valid EGO and the anonymous keypair will be used instead.
+ *
+ * @param cls Closure from <i>GNUNET_MESSENGER_connect</i>
+ * @param handle Messenger handle
+ */
+typedef void
+(*GNUNET_MESSENGER_IdentityCallback) (void *cls, struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Method called whenever a message is sent or received from a <i>room</i>.
+ *
+ * @param cls Closure from <i>GNUNET_MESSENGER_connect</i>
+ * @param room Room handle
+ * @param message Newly received or sent message
+ * @param hash Hash identifying the message
+ */
+typedef void
+(*GNUNET_MESSENGER_MessageCallback) (void *cls, const struct GNUNET_MESSENGER_Room *room,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Set up a handle for the messenger related functions and connects to all necessary services. It will look up the ego
+ * key identified by its <i>name</i> and use it for signing all messages from the handle.
+ *
+ * @param cfg Configuration to use
+ * @param name Name to look up an ego or NULL to stay anonymous
+ * @param identity_callback Function called when the EGO of the handle changes
+ * @param identity_cls Closure for the <i>identity_callback</i> handler
+ * @param msg_callback Function called when a new message is sent or received
+ * @param msg_cls Closure for the <i>msg_callback</i> handler
+ * @return Messenger handle to use, NULL on error
+ */
+struct GNUNET_MESSENGER_Handle*
+GNUNET_MESSENGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name,
+ GNUNET_MESSENGER_IdentityCallback identity_callback, void *identity_cls,
+ GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls);
+
+/**
+ * Update a handle of the messenger to use a different ego key and replace the old one with a newly generated one. All
+ * participated rooms get informed about the key renewal. The handle requires a set name for this function to work and
+ * it needs to be unused by other egos.
+ *
+ * Keep in mind that this will fully delete the old ego key (if any is used) even if any other service wants to use it
+ * as default.
+ *
+ * @param handle Messenger handle to use
+ * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ */
+int
+GNUNET_MESSENGER_update (struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Disconnect all of the messengers used services and clears up its used memory.
+ *
+ * @param handle Messenger handle to use
+ */
+void
+GNUNET_MESSENGER_disconnect (struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Get the name (if specified, otherwise NULL) used by the messenger.
+ *
+ * @param handle Messenger handle to use
+ * @return Name used by the messenger or NULL
+ */
+const char*
+GNUNET_MESSENGER_get_name (const struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Set the name for the messenger. This will rename the currently used ego and move all stored files related to the current
+ * name to its new directory. If anything fails during this process the function returns GNUNET_NO and the name for
+ * the messenger won't change as specified.
+ *
+ * @param handle Messenger handle to use
+ * @param name Name for the messenger to change to
+ * @return GNUNET_YES on success, GNUNET_NO on failure and GNUNET_SYSERR if <i>handle</i> is NULL
+ */
+int
+GNUNET_MESSENGER_set_name (struct GNUNET_MESSENGER_Handle *handle, const char *name);
+
+/**
+ * Get the public key used by the messenger.
+ *
+ * @param handle Messenger handle to use
+ * @return Used ego's public key
+ */
+const struct GNUNET_IDENTITY_PublicKey*
+GNUNET_MESSENGER_get_key (const struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Open a room to send and receive messages. The room will use the specified <i>key</i> as port for the underlying cadet
+ * service. Opening a room results in opening the port for incoming connections as possible <b>door</b>.
+ *
+ * Notice that there can only be one room related to a specific <i>key</i>. So trying to open two rooms with the same
+ * <i>key</i> will result in opening the room once but returning the handle both times because the room stays open.
+ *
+ * You can also open a room after entering it through a <b>door</b> using <i>GNUNET_MESSENGER_entry_room(...)</i>. This
+ * will notify all entered <b>doors</b> to list you as new <b>door</b>.
+ *
+ * ( All <b>doors</b> form a ring structured network to shorten the latency sending and receiving messages. )
+ *
+ * @param handle Messenger handle to use
+ * @param key Hash identifying the port
+ * @return Room handle, NULL on error
+ */
+struct GNUNET_MESSENGER_Room*
+GNUNET_MESSENGER_open_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
+
+/**
+ * Enter a room to send and receive messages through a <b>door</b> opened using <i>GNUNET_MESSENGER_open_room(...)</i>.
+ *
+ * Notice that there can only be one room related to a specific <i>key</i>. So trying to enter two rooms with the same
+ * <i>key</i> will result in entering the room once but returning the handle both times because the room stays entered.
+ * You can however enter a room through multiple <b>doors</b> in parallel which results in connecting both ends. But
+ * entering the room through the same <b>door</b> won't have any effect after the first time.
+ *
+ * You can also enter a room through a <b>door</b> after opening it using <i>GNUNET_MESSENGER_open_room(...)</i>. But the
+ * <b>door</b> may not be your own peer identity.
+ *
+ * ( All <b>doors</b> form a ring structured network to shorten the latency sending and receiving messages. )
+ *
+ * @param handle Messenger handle to use
+ * @param door Peer identity of an open <b>door</b>
+ * @param key Hash identifying the port
+ * @return Room handle, NULL on error
+ */
+struct GNUNET_MESSENGER_Room*
+GNUNET_MESSENGER_entry_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
+ const struct GNUNET_HashCode *key);
+
+/**
+ * Close a room which was entered, opened or both in various order and variety. Closing a room will destroy all connections
+ * from your peer to another and the other way around.
+ *
+ * ( After a member closes a <b>door</b>, all members entered through that specific <b>door</b> have to use another one
+ * or open the room on their own. )
+ *
+ * @param room Room handle
+ */
+void
+GNUNET_MESSENGER_close_room (struct GNUNET_MESSENGER_Room *room);
+
+/**
+ * Get the contact of a member in a <i>room</i> identified by their <i>id</i>.
+ *
+ * Notice that contacts are independent of rooms but will be removed if all rooms containing these contacts get closed.
+ *
+ * @param room Room handle
+ * @param id Hash identifying a member
+ * @return Contact handle, NULL if <i>id</i> is not in use
+ */
+struct GNUNET_MESSENGER_Contact*
+GNUNET_MESSENGER_get_member (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_ShortHashCode *id);
+
+/**
+ * Get the name used by the <i>contact</i>.
+ *
+ * @param contact Contact handle
+ * @return Name of <i>contact</i> or NULL
+ */
+const char*
+GNUNET_MESSENGER_contact_get_name (const struct GNUNET_MESSENGER_Contact *contact);
+
+/**
+ * Get the public key used by the <i>contact</i>.
+ *
+ * @param contact Contact handle
+ * @return Public key of the ego used by <i>contact</i>
+ */
+const struct GNUNET_IDENTITY_PublicKey*
+GNUNET_MESSENGER_contact_get_key (const struct GNUNET_MESSENGER_Contact *contact);
+
+/**
+ * Send a <i>message</i> into a </i>room</i>. If you opened the <i>room</i> all entered members will receive the
+ * <i>message</i>. If you entered the <i>room</i> through a <b>door</b> all so entered <b>doors</b> will receive the
+ * <i>message</i> as well. All members receiving the <i>message</i> will also propagate this <i>message</i> recursively
+ * as long as the <i>message</i> is unknown to them.
+ *
+ * Notice that all messages sent and received are also stored and can be propagated to new members entering the room.
+ *
+ * @param room Room handle
+ * @param message New message to send
+ */
+void
+GNUNET_MESSENGER_send_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message);
+
+/**
+ * Get the message in a <i>room</i> identified by its <i>hash</i>.
+ *
+ * @param room Room handle
+ * @param hash Hash identifying a message
+ * @return Message struct or NULL if no message with that hash is known
+ */
+const struct GNUNET_MESSENGER_Message*
+GNUNET_MESSENGER_get_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash);
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif //GNUNET_MESSENGER_SERVICE_H
+
+/** @} *//* end of group */
diff --git a/src/include/gnunet_namestore_plugin.h b/src/include/gnunet_namestore_plugin.h
index 443c9e451..9cc8abc6e 100644
--- a/src/include/gnunet_namestore_plugin.h
+++ b/src/include/gnunet_namestore_plugin.h
@@ -58,7 +58,7 @@ typedef void
(*GNUNET_NAMESTORE_RecordIterator) (void *cls,
uint64_t serial,
const struct
- GNUNET_CRYPTO_EcdsaPrivateKey *private_key,
+ GNUNET_IDENTITY_PrivateKey *private_key,
const char *label,
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd);
@@ -87,7 +87,7 @@ struct GNUNET_NAMESTORE_PluginFunctions
*/
int
(*store_records) (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const struct GNUNET_IDENTITY_PrivateKey *zone,
const char *label,
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd);
@@ -104,7 +104,7 @@ struct GNUNET_NAMESTORE_PluginFunctions
*/
int
(*lookup_records) (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const struct GNUNET_IDENTITY_PrivateKey *zone,
const char *label,
GNUNET_NAMESTORE_RecordIterator iter,
void *iter_cls);
@@ -126,7 +126,7 @@ struct GNUNET_NAMESTORE_PluginFunctions
*/
int
(*iterate_records) (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const struct GNUNET_IDENTITY_PrivateKey *zone,
uint64_t serial,
uint64_t limit,
GNUNET_NAMESTORE_RecordIterator iter,
@@ -146,8 +146,8 @@ struct GNUNET_NAMESTORE_PluginFunctions
*/
int
(*zone_to_name) (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
+ const struct GNUNET_IDENTITY_PrivateKey *zone,
+ const struct GNUNET_IDENTITY_PublicKey *value_zone,
GNUNET_NAMESTORE_RecordIterator iter,
void *iter_cls);
};
diff --git a/src/include/gnunet_namestore_service.h b/src/include/gnunet_namestore_service.h
index bf42c8d34..ca4d2cb52 100644
--- a/src/include/gnunet_namestore_service.h
+++ b/src/include/gnunet_namestore_service.h
@@ -41,6 +41,7 @@
#include "gnunet_util_lib.h"
#include "gnunet_block_lib.h"
#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_identity_service.h"
#ifdef __cplusplus
extern "C"
@@ -127,7 +128,7 @@ typedef void
struct GNUNET_NAMESTORE_QueueEntry *
GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
const struct
- GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ GNUNET_IDENTITY_PrivateKey *pkey,
const char *label,
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd,
@@ -147,7 +148,7 @@ GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
typedef void
(*GNUNET_NAMESTORE_RecordMonitor) (void *cls,
const struct
- GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ GNUNET_IDENTITY_PrivateKey *zone,
const char *label,
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd);
@@ -170,7 +171,7 @@ typedef void
struct GNUNET_NAMESTORE_QueueEntry *
GNUNET_NAMESTORE_records_lookup (struct GNUNET_NAMESTORE_Handle *h,
const struct
- GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ GNUNET_IDENTITY_PrivateKey *pkey,
const char *label,
GNUNET_SCHEDULER_TaskCallback error_cb,
void *error_cb_cls,
@@ -197,9 +198,9 @@ GNUNET_NAMESTORE_records_lookup (struct GNUNET_NAMESTORE_Handle *h,
*/
struct GNUNET_NAMESTORE_QueueEntry *
GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const struct GNUNET_IDENTITY_PrivateKey *zone,
const struct
- GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
+ GNUNET_IDENTITY_PublicKey *value_zone,
GNUNET_SCHEDULER_TaskCallback error_cb,
void *error_cb_cls,
GNUNET_NAMESTORE_RecordMonitor proc,
@@ -246,7 +247,7 @@ GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe);
struct GNUNET_NAMESTORE_ZoneIterator *
GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h,
const struct
- GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ GNUNET_IDENTITY_PrivateKey *zone,
GNUNET_SCHEDULER_TaskCallback error_cb,
void *error_cb_cls,
GNUNET_NAMESTORE_RecordMonitor proc,
@@ -316,7 +317,7 @@ struct GNUNET_NAMESTORE_ZoneMonitor *
GNUNET_NAMESTORE_zone_monitor_start (const struct
GNUNET_CONFIGURATION_Handle *cfg,
const struct
- GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ GNUNET_IDENTITY_PrivateKey *zone,
int iterate_first,
GNUNET_SCHEDULER_TaskCallback error_cb,
void *error_cb_cls,
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
index ca549f77c..de717526c 100644
--- a/src/include/gnunet_pq_lib.h
+++ b/src/include/gnunet_pq_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet
- Copyright (C) 2016, 2017 GNUnet e.V.
+ Copyright (C) 2016, 2017, 2020 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
@@ -87,6 +87,7 @@ struct GNUNET_PQ_QueryParam
* Number of parameters eaten by this operation.
*/
unsigned int num_params;
+
};
@@ -100,20 +101,32 @@ struct GNUNET_PQ_QueryParam
/**
+ * Generate query parameter to create a NULL value.
+ *
+ * @return query parameter to use to insert NULL into DB
+ */
+struct GNUNET_PQ_QueryParam
+GNUNET_PQ_query_param_null (void);
+
+
+/**
* Generate query parameter for a buffer @a ptr of
* @a ptr_size bytes.
*
* @param ptr pointer to the query parameter to pass
* @oaran ptr_size number of bytes in @a ptr
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
-GNUNET_PQ_query_param_fixed_size (const void *ptr, size_t ptr_size);
+GNUNET_PQ_query_param_fixed_size (const void *ptr,
+ size_t ptr_size);
/**
* Generate query parameter for a string.
*
* @param ptr pointer to the string query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_string (const char *ptr);
@@ -124,6 +137,7 @@ GNUNET_PQ_query_param_string (const char *ptr);
* by variable type.
*
* @param x pointer to the query parameter to pass.
+ * @return query parameter to use
*/
#define GNUNET_PQ_query_param_auto_from_type(x) \
GNUNET_PQ_query_param_fixed_size ((x), sizeof(*(x)))
@@ -134,6 +148,7 @@ GNUNET_PQ_query_param_string (const char *ptr);
* database must contain a BLOB type in the respective position.
*
* @param x the query parameter to pass.
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_rsa_public_key (
@@ -145,6 +160,7 @@ GNUNET_PQ_query_param_rsa_public_key (
* database must contain a BLOB type in the respective position.
*
* @param x the query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_rsa_signature (
@@ -156,6 +172,7 @@ GNUNET_PQ_query_param_rsa_signature (
* The database must store a 64-bit integer.
*
* @param x pointer to the query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_relative_time (const struct GNUNET_TIME_Relative *x);
@@ -166,6 +183,7 @@ GNUNET_PQ_query_param_relative_time (const struct GNUNET_TIME_Relative *x);
* The database must store a 64-bit integer.
*
* @param x pointer to the query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x);
@@ -176,6 +194,7 @@ GNUNET_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x);
* The database must store a 64-bit integer.
*
* @param x pointer to the query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_absolute_time_nbo (
@@ -186,6 +205,7 @@ GNUNET_PQ_query_param_absolute_time_nbo (
* Generate query parameter for an uint16_t in host byte order.
*
* @param x pointer to the query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_uint16 (const uint16_t *x);
@@ -195,6 +215,7 @@ GNUNET_PQ_query_param_uint16 (const uint16_t *x);
* Generate query parameter for an uint32_t in host byte order.
*
* @param x pointer to the query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_uint32 (const uint32_t *x);
@@ -204,6 +225,7 @@ GNUNET_PQ_query_param_uint32 (const uint32_t *x);
* Generate query parameter for an uint16_t in host byte order.
*
* @param x pointer to the query parameter to pass
+ * @return query parameter to use
*/
struct GNUNET_PQ_QueryParam
GNUNET_PQ_query_param_uint64 (const uint64_t *x);
@@ -288,6 +310,20 @@ struct GNUNET_PQ_ResultSpec
* Where to store actual size of the result.
*/
size_t *result_size;
+
+ /**
+ * True if NULL is allowed for a value in the database.
+ */
+ bool is_nullable;
+
+ /**
+ * Points to a location where we should store
+ * "true" if the result found is NULL, and
+ * otherwise "false". Only used if @e is_nullable
+ * is true.
+ */
+ bool *is_null;
+
};
@@ -303,6 +339,21 @@ struct GNUNET_PQ_ResultSpec
/**
+ * Allow NULL value to be found in the database
+ * for the given value.
+ *
+ * @param rs result spec entry to modify
+ * @param[out] is_null location set to 'true' if the
+ * value was indeed NULL, set to 'false' if the
+ * value was non-NULL
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_allow_null (struct GNUNET_PQ_ResultSpec rs,
+ bool *is_null);
+
+
+/**
* Variable-size result expected.
*
* @param name name of the field in the table
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index d9821ffe8..3bdebeb50 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2001--2018 GNUnet e.V.
+ Copyright (C) 2001--2020 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
@@ -20,6 +20,7 @@
/**
* @author Christian Grothoff
+ * @author Tobias Frisch
*
* @file
* Constants for network protocols
@@ -3518,6 +3519,46 @@ extern "C" {
#define GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT 1501
+/*********************************************************************************/
+/********************************** MESSENGER **********************************/
+/*********************************************************************************/
+/* MESSENGER: message types 1600-1629
+ * 1600-1609 Connection-level Messages
+ * 1610-1619 Room-level Messages
+ */
+
+/********************************* Connection **********************************/
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE 1600
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_UPDATE 1601
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY 1602
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_NAME 1603
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_SET_NAME 1604
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_KEY 1605
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID 1606
+
+/************************************ Room *************************************/
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN 1610
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY 1611
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE 1612
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE 1614
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE 1615
+
+#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE 1616
+
+/*********************************************************************************/
+
/**
* Type used to match 'all' message types.
*/
diff --git a/src/include/gnunet_reclaim_service.h b/src/include/gnunet_reclaim_service.h
index 368058f56..8549081a1 100644
--- a/src/include/gnunet_reclaim_service.h
+++ b/src/include/gnunet_reclaim_service.h
@@ -38,6 +38,7 @@ extern "C" {
#endif
#endif
+#include "gnunet_identity_service.h"
#include "gnunet_reclaim_lib.h"
#include "gnunet_util_lib.h"
@@ -69,12 +70,12 @@ struct GNUNET_RECLAIM_Ticket
/**
* The ticket issuer (= the user)
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey identity;
+ struct GNUNET_IDENTITY_PublicKey identity;
/**
* The ticket audience (= relying party)
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey audience;
+ struct GNUNET_IDENTITY_PublicKey audience;
/**
* The ticket random identifier
@@ -129,7 +130,7 @@ typedef void (*GNUNET_RECLAIM_ContinuationWithStatus) (void *cls,
* @param attr The attribute
*/
typedef void (*GNUNET_RECLAIM_AttributeResult) (
- void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+ void *cls, const struct GNUNET_IDENTITY_PublicKey *identity,
const struct GNUNET_RECLAIM_Attribute *attr);
/**
@@ -141,7 +142,7 @@ typedef void (*GNUNET_RECLAIM_AttributeResult) (
* @param presentation The presentation for the credential (may be NULL)
*/
typedef void (*GNUNET_RECLAIM_AttributeTicketResult) (
- void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+ void *cls, const struct GNUNET_IDENTITY_PublicKey *identity,
const struct GNUNET_RECLAIM_Attribute *attr,
const struct GNUNET_RECLAIM_Presentation *presentation);
@@ -155,7 +156,7 @@ typedef void (*GNUNET_RECLAIM_AttributeTicketResult) (
* @param attributes the parsed attributes
*/
typedef void (*GNUNET_RECLAIM_CredentialResult) (
- void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+ void *cls, const struct GNUNET_IDENTITY_PublicKey *identity,
const struct GNUNET_RECLAIM_Credential *credential);
@@ -184,7 +185,7 @@ GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
struct GNUNET_RECLAIM_Operation *
GNUNET_RECLAIM_attribute_store (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ const struct GNUNET_IDENTITY_PrivateKey *pkey,
const struct GNUNET_RECLAIM_Attribute *attr,
const struct GNUNET_TIME_Relative *exp_interval,
GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls);
@@ -205,7 +206,7 @@ GNUNET_RECLAIM_attribute_store (
struct GNUNET_RECLAIM_Operation *
GNUNET_RECLAIM_credential_store (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ const struct GNUNET_IDENTITY_PrivateKey *pkey,
const struct GNUNET_RECLAIM_Credential *credential,
const struct GNUNET_TIME_Relative *exp_interval,
GNUNET_RECLAIM_ContinuationWithStatus cont,
@@ -226,7 +227,7 @@ GNUNET_RECLAIM_credential_store (
struct GNUNET_RECLAIM_Operation *
GNUNET_RECLAIM_attribute_delete (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ const struct GNUNET_IDENTITY_PrivateKey *pkey,
const struct GNUNET_RECLAIM_Attribute *attr,
GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls);
@@ -244,7 +245,7 @@ GNUNET_RECLAIM_attribute_delete (
struct GNUNET_RECLAIM_Operation *
GNUNET_RECLAIM_credential_delete (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ const struct GNUNET_IDENTITY_PrivateKey *pkey,
const struct GNUNET_RECLAIM_Credential *cred,
GNUNET_RECLAIM_ContinuationWithStatus cont,
void *cont_cls);
@@ -276,7 +277,7 @@ GNUNET_RECLAIM_credential_delete (
struct GNUNET_RECLAIM_AttributeIterator *
GNUNET_RECLAIM_get_attributes_start (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
+ const struct GNUNET_IDENTITY_PrivateKey *identity,
GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls,
GNUNET_RECLAIM_AttributeResult proc, void *proc_cls,
GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls);
@@ -332,7 +333,7 @@ GNUNET_RECLAIM_get_attributes_stop (
struct GNUNET_RECLAIM_CredentialIterator *
GNUNET_RECLAIM_get_credentials_start (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
+ const struct GNUNET_IDENTITY_PrivateKey *identity,
GNUNET_SCHEDULER_TaskCallback error_cb,
void *error_cb_cls,
GNUNET_RECLAIM_CredentialResult proc,
@@ -380,8 +381,8 @@ GNUNET_RECLAIM_get_credentials_stop (
struct GNUNET_RECLAIM_Operation *
GNUNET_RECLAIM_ticket_issue (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
+ const struct GNUNET_IDENTITY_PrivateKey *iss,
+ const struct GNUNET_IDENTITY_PublicKey *rp,
const struct GNUNET_RECLAIM_AttributeList *attrs,
GNUNET_RECLAIM_IssueTicketCallback cb, void *cb_cls);
@@ -402,7 +403,7 @@ GNUNET_RECLAIM_ticket_issue (
struct GNUNET_RECLAIM_Operation *
GNUNET_RECLAIM_ticket_revoke (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
+ const struct GNUNET_IDENTITY_PrivateKey *identity,
const struct GNUNET_RECLAIM_Ticket *ticket,
GNUNET_RECLAIM_ContinuationWithStatus cb, void *cb_cls);
@@ -422,7 +423,7 @@ GNUNET_RECLAIM_ticket_revoke (
struct GNUNET_RECLAIM_Operation *
GNUNET_RECLAIM_ticket_consume (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
+ const struct GNUNET_IDENTITY_PrivateKey *identity,
const struct GNUNET_RECLAIM_Ticket *ticket,
GNUNET_RECLAIM_AttributeTicketResult cb, void *cb_cls);
@@ -447,7 +448,7 @@ GNUNET_RECLAIM_ticket_consume (
struct GNUNET_RECLAIM_TicketIterator *
GNUNET_RECLAIM_ticket_iteration_start (
struct GNUNET_RECLAIM_Handle *h,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
+ const struct GNUNET_IDENTITY_PrivateKey *identity,
GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls,
GNUNET_RECLAIM_TicketCallback proc, void *proc_cls,
GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls);
diff --git a/src/include/gnunet_revocation_service.h b/src/include/gnunet_revocation_service.h
index 105bb1149..d56116914 100644
--- a/src/include/gnunet_revocation_service.h
+++ b/src/include/gnunet_revocation_service.h
@@ -21,6 +21,8 @@
#ifndef GNUNET_REVOCATION_SERVICE_H_
#define GNUNET_REVOCATION_SERVICE_H_
+#include "gnunet_identity_service.h"
+
/**
* @author Christian Grothoff
*
@@ -51,6 +53,13 @@ extern "C"
#define GNUNET_REVOCATION_VERSION 0x00000001
/**
+ * Maximum length of a revocation
+ */
+#define GNUNET_REVOCATION_MAX_PROOF_SIZE sizeof(struct GNUNET_REVOCATION_PowP) +\
+ sizeof(struct GNUNET_IDENTITY_PublicKey) +\
+ 1024 //FIXME max sig_len
+
+/**
* The proof-of-work narrowing factor.
* The number of PoWs that are calculates as part of revocation.
*/
@@ -79,15 +88,7 @@ struct GNUNET_REVOCATION_PowP
*/
uint64_t pow[POW_COUNT] GNUNET_PACKED;
- /**
- * The signature
- */
- struct GNUNET_CRYPTO_EcdsaSignature signature;
-
- /**
- * The revoked public key
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey key;
+ /** followed by the public key type, the key and a signature **/
};
@@ -102,14 +103,11 @@ struct GNUNET_REVOCATION_SignaturePurposePS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * The revoked public key
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey key;
-
- /**
* The timestamp of the revocation
*/
struct GNUNET_TIME_AbsoluteNBO timestamp;
+
+ /** Followed by the zone public key type and key **/
};
GNUNET_NETWORK_STRUCT_END
@@ -150,7 +148,7 @@ typedef void (*GNUNET_REVOCATION_Callback) (void *cls,
*/
struct GNUNET_REVOCATION_Query *
GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
+ const struct GNUNET_IDENTITY_PublicKey *key,
GNUNET_REVOCATION_Callback func, void *func_cls);
@@ -217,7 +215,7 @@ GNUNET_REVOCATION_check_pow (const struct GNUNET_REVOCATION_PowP *pow,
* @param pow the pow object to work with in the calculation.
*/
void
-GNUNET_REVOCATION_pow_init (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+GNUNET_REVOCATION_pow_init (const struct GNUNET_IDENTITY_PrivateKey *key,
struct GNUNET_REVOCATION_PowP *pow);
@@ -256,6 +254,10 @@ GNUNET_REVOCATION_pow_round (struct GNUNET_REVOCATION_PowCalculationHandle *pc);
void
GNUNET_REVOCATION_pow_stop (struct GNUNET_REVOCATION_PowCalculationHandle *pc);
+size_t
+GNUNET_REVOCATION_proof_get_size (const struct GNUNET_REVOCATION_PowP *pow);
+
+
#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
diff --git a/src/include/gnunet_uri_lib.h b/src/include/gnunet_uri_lib.h
index d428bdd9a..57c9e9316 100644
--- a/src/include/gnunet_uri_lib.h
+++ b/src/include/gnunet_uri_lib.h
@@ -26,12 +26,13 @@
/**
* The struct where the parsed values will be stored:
*
- * scheme ":" [ "//" ] [ username ":" password "@" ] host [ ":" port ] [ "/" ] [ path ] [ "?" query ]
+ * scheme ":" [ "//" ] [ username ":" password "@" ] host [ ":" port ] [ "/" ] [ path ] [ "?" query ] [ "#" fragment ]
*
* Note: to make sure that no strings are copied, the first slash "/" in the
* path will be used to null terminate the hostname if no port is supplied.
*/
-struct GNUNET_Uri {
+struct GNUNET_Uri
+{
char *scheme; /* scheme, without ":" and "//" */
char *username; /* username, default: NULL */
char *password; /* password, default: NULL */
@@ -44,7 +45,8 @@ struct GNUNET_Uri {
/* A struct to hold the query string parameter values. */
-struct GNUNET_UriParam {
+struct GNUNET_UriParam
+{
char *key;
char *val;
};
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index 2ed05c35a..d4ea38adf 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -18,18 +18,15 @@ libgnunetjson_la_SOURCES = \
json.c \
json_mhd.c \
json_generator.c \
- json_helper.c \
- json_gnsrecord.c
+ json_helper.c
libgnunetjson_la_LIBADD = \
$(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
-ljansson \
$(MHD_LIBS) \
$(XLIB) \
$(Z_LIBS)
libgnunetjson_la_DEPENDENCIES = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la
+ $(top_builddir)/src/util/libgnunetutil.la
check_PROGRAMS = \
diff --git a/src/json/json.c b/src/json/json.c
index 0631c51bb..503702962 100644
--- a/src/json/json.c
+++ b/src/json/json.c
@@ -56,11 +56,17 @@ GNUNET_JSON_parse (const json_t *root,
if (NULL == spec[i].field)
pos = (json_t *) root;
else
- pos = json_object_get (root, spec[i].field);
- if ((NULL == pos) && (spec[i].is_optional))
+ pos = json_object_get (root,
+ spec[i].field);
+ if ( ( (NULL == pos) ||
+ (json_is_null (pos) ) ) &&
+ (spec[i].is_optional) )
continue;
- if ((NULL == pos) ||
- (GNUNET_OK != spec[i].parser (spec[i].cls, pos, &spec[i])))
+ if ( (NULL == pos) ||
+ (GNUNET_OK !=
+ spec[i].parser (spec[i].cls,
+ pos,
+ &spec[i])) )
{
if (NULL != error_json_name)
*error_json_name = spec[i].field;
diff --git a/src/json/json_generator.c b/src/json/json_generator.c
index 3f82a5f17..5806eb174 100644
--- a/src/json/json_generator.c
+++ b/src/json/json_generator.c
@@ -201,113 +201,5 @@ GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig)
}
-/**
- * Convert GNS record to JSON.
- *
- * @param rname name of record
- * @param rd record data
- * @return corresponding JSON encoding
- */
-json_t *
-GNUNET_JSON_from_gnsrecord (const char*rname,
- const struct GNUNET_GNSRECORD_Data *rd,
- unsigned int rd_count)
-{
- struct GNUNET_TIME_Absolute abs_exp;
- struct GNUNET_TIME_Relative rel_exp;
- const char *expiration_time_str;
- const char *record_type_str;
- char *value_str;
- json_t *data;
- json_t *record;
- json_t *records;
-
- data = json_object ();
- if (NULL == data)
- {
- GNUNET_break (0);
- return NULL;
- }
- if (0 !=
- json_object_set_new (data,
- "record_name",
- json_string (rname)))
- {
- GNUNET_break (0);
- json_decref (data);
- return NULL;
- }
- records = json_array ();
- if (NULL == records)
- {
- GNUNET_break (0);
- json_decref (data);
- return NULL;
- }
- for (int i = 0; i < rd_count; i++)
- {
- value_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
- rd[i].data,
- rd[i].data_size);
- if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd[i].flags)
- {
- rel_exp.rel_value_us = rd[i].expiration_time;
- expiration_time_str = GNUNET_STRINGS_relative_time_to_string (rel_exp,
- GNUNET_NO);
- }
- else
- {
- abs_exp.abs_value_us = rd[i].expiration_time;
- expiration_time_str = GNUNET_STRINGS_absolute_time_to_string (abs_exp);
- }
- record_type_str = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Packing %s %s %s %d\n",
- value_str, record_type_str, expiration_time_str, rd[i].flags);
- record = json_pack ("{s:s,s:s,s:s,s:b,s:b,s:b,s:b}",
- "value",
- value_str,
- "record_type",
- record_type_str,
- "expiration_time",
- expiration_time_str,
- "private",
- rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE,
- "relative_expiration",
- rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION,
- "supplemental",
- rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL,
- "shadow",
- rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD);
- GNUNET_free (value_str);
- if (NULL == record)
- {
- GNUNET_break (0);
- json_decref (records);
- json_decref (data);
- return NULL;
- }
- if (0 !=
- json_array_append_new (records,
- record))
- {
- GNUNET_break (0);
- json_decref (records);
- json_decref (data);
- return NULL;
- }
- }
- if (0 !=
- json_object_set_new (data,
- "data",
- records))
- {
- GNUNET_break (0);
- json_decref (data);
- return NULL;
- }
- return data;
-}
-
/* End of json/json_generator.c */
diff --git a/src/messenger/.gitignore b/src/messenger/.gitignore
new file mode 100644
index 000000000..9de3fb304
--- /dev/null
+++ b/src/messenger/.gitignore
@@ -0,0 +1,4 @@
+gnunet-service-messenger
+gnunet-messenger
+test_messenger_api
+test_messenger_anonymous
diff --git a/src/messenger/Makefile.am b/src/messenger/Makefile.am
new file mode 100644
index 000000000..ebe08290e
--- /dev/null
+++ b/src/messenger/Makefile.am
@@ -0,0 +1,131 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfg_DATA = \
+ messenger.conf
+
+plugindir = $(libdir)/gnunet
+
+AM_CLFAGS = -g
+
+libexec_PROGRAMS = \
+ gnunet-service-messenger \
+ $(EXP_LIBEXEC)
+
+bin_PROGRAMS = \
+ gnunet-messenger
+
+lib_LTLIBRARIES = \
+ libgnunetmessenger_common.la \
+ libgnunetmessenger.la \
+ $(EXP_LIB)
+
+libgnunetmessenger_common_la_SOURCES = \
+ messenger_api_ego.h \
+ messenger_api_message.c messenger_api_message.h \
+ messenger_api_list_tunnels.c messenger_api_list_tunnels.h
+libgnunetmessenger_common_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ $(XLIB) \
+ $(LTLIBINTL)
+libgnunetmessenger_common_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) \
+ -version-info 0:0:0
+
+libgnunetmessenger_la_SOURCES = \
+ messenger_api.c \
+ messenger_api_contact.c messenger_api_contact.h \
+ messenger_api_handle.c messenger_api_handle.h \
+ messenger_api_room.c messenger_api_room.h
+libgnunetmessenger_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ libgnunetmessenger_common.la \
+ $(XLIB) \
+ $(LTLIBINTL)
+libgnunetmessenger_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) \
+ -version-info 0:0:0
+
+gnunet_messenger_SOURCES = \
+ gnunet-messenger.c
+gnunet_messenger_LDADD = \
+ libgnunetmessenger_common.la \
+ libgnunetmessenger.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+gnunet_messenger_LDFLAGS = \
+ $(GN_LIBINTL)
+
+gnunet_service_messenger_SOURCES = \
+ gnunet-service-messenger.c gnunet-service-messenger.h \
+ gnunet-service-messenger_service.c gnunet-service-messenger_service.h \
+ gnunet-service-messenger_list_handles.c gnunet-service-messenger_list_handles.h \
+ gnunet-service-messenger_list_messages.c gnunet-service-messenger_list_messages.h \
+ gnunet-service-messenger_message_handle.c gnunet-service-messenger_message_handle.h \
+ gnunet-service-messenger_message_kind.c gnunet-service-messenger_message_kind.h \
+ gnunet-service-messenger_message_recv.c gnunet-service-messenger_message_recv.h \
+ gnunet-service-messenger_message_send.c gnunet-service-messenger_message_send.h \
+ gnunet-service-messenger_message_store.c gnunet-service-messenger_message_store.h \
+ gnunet-service-messenger_basement.c gnunet-service-messenger_basement.h \
+ gnunet-service-messenger_contact.c gnunet-service-messenger_contact.h \
+ gnunet-service-messenger_handle.c gnunet-service-messenger_handle.h \
+ gnunet-service-messenger_room.c gnunet-service-messenger_room.h \
+ gnunet-service-messenger_tunnel.c gnunet-service-messenger_tunnel.h \
+ gnunet-service-messenger_util.c gnunet-service-messenger_util.h
+gnunet_service_messenger_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/cadet/libgnunetcadet.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ libgnunetmessenger_common.la \
+ libgnunetmessenger.la \
+ $(GN_LIBINTL)
+
+check_PROGRAMS = \
+ test_messenger_api \
+ test_messenger_anonymous \
+ test_messenger_comm0
+
+if ENABLE_TEST_RUN
+AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
+TESTS = \
+ $(check_PROGRAMS)
+endif
+
+test_messenger_api_SOURCES = \
+ test_messenger.c
+test_messenger_api_LDADD = \
+ libgnunetmessenger_common.la \
+ libgnunetmessenger.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_messenger_anonymous_SOURCES = \
+ test_messenger_anonymous.c
+test_messenger_anonymous_LDADD = \
+ libgnunetmessenger_common.la \
+ libgnunetmessenger.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_messenger_comm0_SOURCES = \
+ test_messenger_comm0.c
+test_messenger_comm0_LDADD = \
+ libgnunetmessenger_common.la \
+ libgnunetmessenger.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ $(top_builddir)/src/testbed-logger/libgnunettestbedlogger.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+EXTRA_DIST = \
+ test_messenger_api.conf
diff --git a/src/messenger/gnunet-messenger.c b/src/messenger/gnunet-messenger.c
new file mode 100644
index 000000000..579e5c3ad
--- /dev/null
+++ b/src/messenger/gnunet-messenger.c
@@ -0,0 +1,306 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-messenger.c
+ * @brief Print information about messenger groups.
+ */
+
+#include <stdio.h>
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_messenger_service.h"
+
+struct GNUNET_MESSENGER_Handle *messenger;
+
+/**
+ * Function called whenever a message is received or sent.
+ *
+ * @param cls Closure
+ * @param room Room
+ * @param message Message
+ * @param hash Hash of message
+ */
+void
+on_message (void *cls, const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_member (room, &(message->header.sender_id));
+
+ const char *sender_name = GNUNET_MESSENGER_contact_get_name (sender);
+
+ if (!sender_name)
+ sender_name = "anonymous";
+
+ switch (message->header.kind)
+ {
+ case GNUNET_MESSENGER_KIND_JOIN:
+ {
+ printf ("* '%s' joined the room! [ %u %u %u %u ]\n", sender_name, message->body.join.key.ecdsa_key.q_y[0],
+ message->body.join.key.ecdsa_key.q_y[1], message->body.join.key.ecdsa_key.q_y[2],
+ message->body.join.key.ecdsa_key.q_y[3]);
+ break;
+ }
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ {
+ printf ("* '%s' leaves the room!\n", sender_name);
+ break;
+ }
+ case GNUNET_MESSENGER_KIND_PEER:
+ {
+ printf ("* '%s' opened the room on: %s\n", sender_name, GNUNET_i2s_full (&(message->body.peer.peer)));
+ break;
+ }
+ case GNUNET_MESSENGER_KIND_TEXT:
+ {
+ printf ("* '%s' says: \"%s\"\n", sender_name, message->body.text.text);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+struct GNUNET_SCHEDULER_Task *read_task;
+
+/**
+ * Task to shut down this application.
+ *
+ * @param cls Closure
+ */
+static void
+shutdown_hook (void *cls)
+{
+ struct GNUNET_MESSENGER_Room *room = cls;
+
+ if (read_task)
+ GNUNET_SCHEDULER_cancel (read_task);
+
+ if (room)
+ GNUNET_MESSENGER_close_room (room);
+
+ if (messenger)
+ GNUNET_MESSENGER_disconnect (messenger);
+}
+
+static void
+listen_stdio (void *cls);
+
+#define MAX_BUFFER_SIZE 60000
+
+/**
+ * Task run in stdio mode, after some data is available at stdin.
+ *
+ * @param cls Closure
+ */
+static void
+read_stdio (void *cls)
+{
+ read_task = NULL;
+
+ char buffer[MAX_BUFFER_SIZE];
+ ssize_t length;
+
+ length = read (0, buffer, MAX_BUFFER_SIZE);
+
+ if ((length <= 0) || (length >= MAX_BUFFER_SIZE))
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (buffer[length - 1] == '\n')
+ buffer[length - 1] = '\0';
+ else
+ buffer[length] = '\0';
+
+ struct GNUNET_MESSENGER_Room *room = cls;
+
+ struct GNUNET_MESSENGER_Message message;
+ message.header.kind = GNUNET_MESSENGER_KIND_TEXT;
+ message.body.text.text = buffer;
+
+ GNUNET_MESSENGER_send_message (room, &message);
+
+ read_task = GNUNET_SCHEDULER_add_now (listen_stdio, cls);
+}
+
+/**
+ * Wait for input on STDIO and send it out over the #ch.
+ *
+ * @param cls Closure
+ */
+static void
+listen_stdio (void *cls)
+{
+ read_task = NULL;
+
+ struct GNUNET_NETWORK_FDSet *rs = GNUNET_NETWORK_fdset_create ();
+
+ GNUNET_NETWORK_fdset_set_native (rs, 0);
+
+ read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ rs,
+ NULL,
+ &read_stdio, cls);
+
+ GNUNET_NETWORK_fdset_destroy (rs);
+}
+
+/**
+ * Initial task to startup application.
+ *
+ * @param cls Closure
+ */
+static void
+idle (void *cls)
+{
+ struct GNUNET_MESSENGER_Room *room = cls;
+
+ printf ("* You joined the room.\n");
+
+ read_task = GNUNET_SCHEDULER_add_now (listen_stdio, room);
+}
+
+char *door_id;
+char *ego_name;
+char *room_key;
+
+struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+/**
+ * Function called when an identity is retrieved.
+ *
+ * @param cls Closure
+ * @param handle Handle of messenger service
+ */
+static void
+on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
+{
+ struct GNUNET_HashCode key;
+ memset (&key, 0, sizeof(key));
+
+ if (room_key)
+ GNUNET_CRYPTO_hash (room_key, strlen (room_key), &key);
+
+ struct GNUNET_PeerIdentity *door = NULL;
+
+ if (door_id)
+ {
+ door = GNUNET_new(struct GNUNET_PeerIdentity);
+
+ if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (door_id, strlen (door_id), &(door->public_key)))
+ {
+ GNUNET_free(door);
+ door = NULL;
+ }
+ }
+
+ const char *name = GNUNET_MESSENGER_get_name (handle);
+
+ if (!name)
+ name = "anonymous";
+
+ printf ("* Welcome to the messenger, '%s'!\n", name);
+
+ struct GNUNET_MESSENGER_Room *room;
+
+ if (door)
+ {
+ printf ("* You try to entry a room...\n");
+
+ room = GNUNET_MESSENGER_entry_room (messenger, door, &key);
+ }
+ else
+ {
+ printf ("* You try to open a room...\n");
+
+ room = GNUNET_MESSENGER_open_room (messenger, &key);
+ }
+
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+
+ shutdown_task = GNUNET_SCHEDULER_add_shutdown (shutdown_hook, room);
+
+ if (!room)
+ GNUNET_SCHEDULER_shutdown ();
+ else
+ GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_get_zero_ (), GNUNET_SCHEDULER_PRIORITY_IDLE, idle,
+ room);
+}
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const*args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ messenger = GNUNET_MESSENGER_connect (cfg, ego_name, &on_identity, NULL, &on_message, NULL);
+
+ shutdown_task = GNUNET_SCHEDULER_add_shutdown (shutdown_hook, NULL);
+}
+
+/**
+ * The main function to obtain messenger information.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char **argv)
+{
+ const char *description = "Open and connect to rooms using the MESSENGER to chat.";
+
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_option_string ('d',
+ "door",
+ "PEERIDENTITY",
+ "peer identity to entry into the room",
+ &door_id),
+ GNUNET_GETOPT_option_string ('e',
+ "ego",
+ "IDENTITY",
+ "identity to use for messaging",
+ &ego_name),
+ GNUNET_GETOPT_option_string ('r',
+ "room",
+ "ROOMKEY",
+ "key of the room to connect to",
+ &room_key),
+ GNUNET_GETOPT_OPTION_END };
+
+ return (GNUNET_OK == GNUNET_PROGRAM_run (argc,
+ argv,
+ "gnunet-messenger\0",
+ gettext_noop(description),
+ options,
+ &run,
+ NULL) ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/src/messenger/gnunet-service-messenger.c b/src/messenger/gnunet-service-messenger.c
new file mode 100644
index 000000000..2c92305c4
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger.c
@@ -0,0 +1,306 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger.h"
+
+#include "gnunet-service-messenger_service.h"
+#include "messenger_api_message.h"
+
+struct GNUNET_MESSENGER_Client
+{
+ struct GNUNET_SERVICE_Client *client;
+ struct GNUNET_MESSENGER_SrvHandle *handle;
+};
+
+struct GNUNET_MESSENGER_Service *messenger;
+
+static int
+check_create (void *cls, const struct GNUNET_MESSENGER_CreateMessage *msg)
+{
+ GNUNET_MQ_check_zero_termination(msg);
+ return GNUNET_OK;
+}
+
+static void
+handle_create (void *cls, const struct GNUNET_MESSENGER_CreateMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ const char *name = ((const char*) msg) + sizeof(*msg);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Handle created with name: %s\n", name);
+
+ setup_handle_name (msg_client->handle, strlen (name) > 0? name : NULL);
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static void
+handle_update (void *cls, const struct GNUNET_MESSENGER_UpdateMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ if (GNUNET_OK != update_handle (msg_client->handle))
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Name is required to update key!\n");
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static void
+handle_destroy (void *cls, const struct GNUNET_MESSENGER_DestroyMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ GNUNET_SERVICE_client_drop (msg_client->client);
+}
+
+static int
+check_set_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
+{
+ GNUNET_MQ_check_zero_termination(msg);
+ return GNUNET_OK;
+}
+
+static void
+handle_set_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ const char *name = ((const char*) msg) + sizeof(*msg);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Handles name is now: %s\n", name);
+
+ if (GNUNET_YES != set_handle_name (msg_client->handle, name))
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No valid name: %s\n", name);
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static void
+handle_room_open (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Opening room: %s\n",
+ GNUNET_h2s (&(msg->key)));
+
+ if (GNUNET_YES == open_handle_room (msg_client->handle, &(msg->key)))
+ {
+ const struct GNUNET_ShortHashCode* member_id = get_handle_member_id(msg_client->handle, &(msg->key));
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Opening room with member id: %s\n",
+ GNUNET_sh2s (member_id));
+
+ struct GNUNET_MESSENGER_RoomMessage *response;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN);
+ GNUNET_memcpy(&(response->key), &(msg->key), sizeof(msg->key));
+ GNUNET_MQ_send (msg_client->handle->mq, env);
+ }
+ else
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Opening room failed: %s\n",
+ GNUNET_h2s (&(msg->key)));
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static void
+handle_room_entry (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Entering room: %s, %s\n",
+ GNUNET_h2s (&(msg->key)), GNUNET_i2s (&(msg->door)));
+
+ if (GNUNET_YES == entry_handle_room (msg_client->handle, &(msg->door), &(msg->key)))
+ {
+ const struct GNUNET_ShortHashCode* member_id = get_handle_member_id(msg_client->handle, &(msg->key));
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Entering room with member id: %s\n",
+ GNUNET_sh2s (member_id));
+
+ struct GNUNET_MESSENGER_RoomMessage *response;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY);
+ GNUNET_memcpy(&(response->door), &(msg->door), sizeof(msg->door));
+ GNUNET_memcpy(&(response->key), &(msg->key), sizeof(msg->key));
+ GNUNET_MQ_send (msg_client->handle->mq, env);
+ }
+ else
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Entrance into room failed: %s, %s\n",
+ GNUNET_h2s (&(msg->key)), GNUNET_i2s (&(msg->door)));
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static void
+handle_room_close (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Closing room: %s\n", GNUNET_h2s (&(msg->key)));
+
+ if (GNUNET_YES == close_handle_room (msg_client->handle, &(msg->key)))
+ {
+ const struct GNUNET_ShortHashCode* member_id = get_handle_member_id(msg_client->handle, &(msg->key));
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Closing room with member id: %s\n",
+ GNUNET_sh2s (member_id));
+
+ struct GNUNET_MESSENGER_RoomMessage *response;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE);
+ GNUNET_memcpy(&(response->key), &(msg->key), sizeof(msg->key));
+ GNUNET_MQ_send (msg_client->handle->mq, env);
+ }
+ else
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Closing room failed: %s\n", GNUNET_h2s (&(msg->key)));
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static int
+check_send_message (void *cls, const struct GNUNET_MESSENGER_SendMessage *msg)
+{
+ const uint16_t full_length = ntohs (msg->header.size) - sizeof(msg->header);
+
+ if (full_length < sizeof(msg->key))
+ return GNUNET_NO;
+
+ const uint16_t length = full_length - sizeof(msg->key);
+ const char *buffer = ((const char*) msg) + sizeof(*msg);
+
+ struct GNUNET_MESSENGER_Message message;
+
+ if (GNUNET_YES != decode_message (&message, length, buffer))
+ return GNUNET_NO;
+
+ return GNUNET_OK;
+}
+
+static void
+handle_send_message (void *cls, const struct GNUNET_MESSENGER_SendMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ const struct GNUNET_HashCode *key = &(msg->key);
+ const char *buffer = ((const char*) msg) + sizeof(*msg);
+
+ const uint16_t length = ntohs (msg->header.size) - sizeof(*msg);
+
+ struct GNUNET_MESSENGER_Message message;
+ decode_message (&message, length, buffer);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending message: %s to %s\n",
+ GNUNET_MESSENGER_name_of_kind (message.header.kind),
+ GNUNET_h2s (key));
+
+ if (GNUNET_YES != send_handle_message (msg_client->handle, key, &message))
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sending message failed: %s to %s\n",
+ GNUNET_MESSENGER_name_of_kind (message.header.kind),
+ GNUNET_h2s (key));
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static void
+handle_get_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Requesting message from room: %s\n",
+ GNUNET_h2s (&(msg->key)));
+
+ struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (messenger, &(msg->key));
+
+ if (room)
+ get_room_message (room, msg_client->handle, &(msg->hash), GNUNET_YES);
+ else
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Room not found: %s\n",
+ GNUNET_h2s (&(msg->key)));
+
+ GNUNET_SERVICE_client_continue (msg_client->client);
+}
+
+static void*
+callback_client_connect (void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = GNUNET_new(struct GNUNET_MESSENGER_Client);
+
+ msg_client->client = client;
+ msg_client->handle = add_service_handle (messenger, mq);
+
+ return msg_client;
+}
+
+static void
+callback_client_disconnect (void *cls, struct GNUNET_SERVICE_Client *client, void *internal_cls)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = internal_cls;
+
+ remove_service_handle (messenger, msg_client->handle);
+
+ GNUNET_free(msg_client);
+}
+
+/**
+ * Setup MESSENGER internals.
+ *
+ * @param cls closure
+ * @param config configuration to use
+ * @param service the initialized service
+ */
+static void
+run (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service)
+{
+ messenger = create_service (config, service);
+
+ if ((!messenger) || (!messenger->cadet) || (!messenger->identity))
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN(
+ GNUNET_MESSENGER_SERVICE_NAME,
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &callback_client_connect,
+ &callback_client_disconnect,
+ NULL,
+ GNUNET_MQ_hd_var_size( create, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE, struct GNUNET_MESSENGER_CreateMessage, NULL ),
+ GNUNET_MQ_hd_fixed_size( update, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_UPDATE, struct GNUNET_MESSENGER_UpdateMessage, NULL ),
+ GNUNET_MQ_hd_fixed_size( destroy, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY, struct GNUNET_MESSENGER_DestroyMessage, NULL ),
+ GNUNET_MQ_hd_var_size( set_name, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_SET_NAME, struct GNUNET_MESSENGER_NameMessage, NULL ),
+ GNUNET_MQ_hd_fixed_size( room_open, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN, struct GNUNET_MESSENGER_RoomMessage, NULL ),
+ GNUNET_MQ_hd_fixed_size( room_entry, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY, struct GNUNET_MESSENGER_RoomMessage, NULL ),
+ GNUNET_MQ_hd_fixed_size( room_close, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE, struct GNUNET_MESSENGER_RoomMessage, NULL ),
+ GNUNET_MQ_hd_var_size( send_message, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE, struct GNUNET_MESSENGER_SendMessage, NULL ),
+ GNUNET_MQ_hd_fixed_size( get_message, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE, struct GNUNET_MESSENGER_RecvMessage, NULL ),
+ GNUNET_MQ_handler_end());
diff --git a/src/messenger/gnunet-service-messenger.h b/src/messenger/gnunet-service-messenger.h
new file mode 100644
index 000000000..85a1d2549
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger.h
@@ -0,0 +1,121 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_H
+#define GNUNET_SERVICE_MESSENGER_H
+
+#include "platform.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_mq_lib.h"
+#include "gnunet_peer_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * Message to create a handle for a client
+ */
+struct GNUNET_MESSENGER_CreateMessage
+{
+ struct GNUNET_MessageHeader header;
+};
+
+/**
+ * Message to update the handle (its EGO key) for a client
+ */
+struct GNUNET_MESSENGER_UpdateMessage
+{
+ struct GNUNET_MessageHeader header;
+};
+
+/**
+ * Message to destroy the handle for a client
+ */
+struct GNUNET_MESSENGER_DestroyMessage
+{
+ struct GNUNET_MessageHeader header;
+};
+
+/**
+ * Message to receive the current name of a handle
+ */
+struct GNUNET_MESSENGER_NameMessage
+{
+ struct GNUNET_MessageHeader header;
+};
+
+/**
+ * Message to receive the current public key of a handle
+ */
+struct GNUNET_MESSENGER_KeyMessage
+{
+ struct GNUNET_MessageHeader header;
+ struct GNUNET_IDENTITY_PublicKey pubkey;
+};
+
+/**
+ * General message to confirm interaction with a room
+ */
+struct GNUNET_MESSENGER_RoomMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ struct GNUNET_PeerIdentity door;
+ struct GNUNET_HashCode key;
+};
+
+/**
+ * Message to receive the current member id of a handle in room
+ */
+struct GNUNET_MESSENGER_MemberMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ struct GNUNET_HashCode key;
+ struct GNUNET_ShortHashCode id;
+};
+
+/**
+ * Message to send something into a room
+ */
+struct GNUNET_MESSENGER_SendMessage
+{
+ struct GNUNET_MessageHeader header;
+ struct GNUNET_HashCode key;
+};
+
+/**
+ * Message to receive something from a room
+ */
+struct GNUNET_MESSENGER_RecvMessage
+{
+ struct GNUNET_MessageHeader header;
+ struct GNUNET_HashCode key;
+ struct GNUNET_HashCode hash;
+};
+
+#endif //GNUNET_SERVICE_MESSENGER_H
diff --git a/src/messenger/gnunet-service-messenger_basement.c b/src/messenger/gnunet-service-messenger_basement.c
new file mode 100644
index 000000000..190cf2de5
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_basement.c
@@ -0,0 +1,58 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_basement.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_basement.h"
+
+size_t
+count_of_tunnels (const struct GNUNET_MESSENGER_ListTunnels *tunnels)
+{
+ const struct GNUNET_MESSENGER_ListTunnel *element;
+ size_t count = 0;
+
+ for (element = tunnels->head; element; element = element->next)
+ count++;
+
+ return count;
+}
+
+int
+should_connect_tunnel_to (size_t count, size_t src, size_t dst)
+{
+ if ((src + 1) % count == dst % count)
+ return GNUNET_YES;
+
+ return GNUNET_NO;
+}
+
+int
+required_connection_between (size_t count, size_t src, size_t dst)
+{
+ if (GNUNET_YES == should_connect_tunnel_to (count, src, dst))
+ return GNUNET_YES;
+ if (GNUNET_YES == should_connect_tunnel_to (count, dst, src))
+ return GNUNET_YES;
+
+ return GNUNET_NO;
+}
diff --git a/src/messenger/gnunet-service-messenger_basement.h b/src/messenger/gnunet-service-messenger_basement.h
new file mode 100644
index 000000000..0a1a9b126
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_basement.h
@@ -0,0 +1,66 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_basement.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_BASEMENT_H
+#define GNUNET_SERVICE_MESSENGER_BASEMENT_H
+
+#include "messenger_api_list_tunnels.h"
+
+/**
+ * Returns the count of peers in a list (typically from the basement of a room).
+ *
+ * @param tunnels List of peer identities
+ * @return Count of the entries in the list
+ */
+size_t
+count_of_tunnels (const struct GNUNET_MESSENGER_ListTunnels *tunnels);
+
+/**
+ * Returns GNUNET_YES or GNUNET_NO to determine if the peer at index <i>src</i> should
+ * or should not connect outgoing to the peer at index <i>dst</i> to construct a complete
+ * basement with a given <i>count</i> of peers.
+ *
+ * @param count Count of peers
+ * @param src Source index
+ * @param dst Destination index
+ * @return GNUNET_YES or GNUNET_NO based on topologic requirement
+ */
+int
+should_connect_tunnel_to (size_t count, size_t src, size_t dst);
+
+/**
+ * Returns GNUNET_YES or GNUNET_NO to determine if the peers of index <i>src</i> and
+ * index <i>dst</i> should be connected in any direction to construct a complete
+ * basement with a given <i>count</i> of peers.
+ *
+ * @param count Count of peers
+ * @param src Source index
+ * @param dst Destination index
+ * @return GNUNET_YES or GNUNET_NO based on topologic requirement
+ */
+int
+required_connection_between (size_t count, size_t src, size_t dst);
+
+#endif //GNUNET_SERVICE_MESSENGER_BASEMENT_H
diff --git a/src/messenger/gnunet-service-messenger_contact.c b/src/messenger/gnunet-service-messenger_contact.c
new file mode 100644
index 000000000..1ec125402
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_contact.c
@@ -0,0 +1,96 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_contact.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_contact.h"
+
+struct GNUNET_MESSENGER_SrvContact*
+create_contact (const struct GNUNET_IDENTITY_PublicKey *key)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_new(struct GNUNET_MESSENGER_SrvContact);
+
+ contact->name = NULL;
+ contact->rc = 0;
+
+ GNUNET_memcpy(&(contact->public_key), key, sizeof(contact->public_key));
+
+ return contact;
+}
+
+void
+destroy_contact (struct GNUNET_MESSENGER_SrvContact *contact)
+{
+ if (contact->name)
+ GNUNET_free(contact->name);
+
+ GNUNET_free(contact);
+}
+
+const char*
+get_contact_name (const struct GNUNET_MESSENGER_SrvContact *contact)
+{
+ return contact->name;
+}
+
+void
+set_contact_name (struct GNUNET_MESSENGER_SrvContact *contact, const char *name)
+{
+ GNUNET_assert(name);
+
+ if (contact->name)
+ GNUNET_free(contact->name);
+
+ contact->name = GNUNET_strdup(name);
+}
+
+const struct GNUNET_IDENTITY_PublicKey*
+get_contact_key (const struct GNUNET_MESSENGER_SrvContact *contact)
+{
+ return &(contact->public_key);
+}
+
+void
+increase_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact)
+{
+ contact->rc++;
+}
+
+int
+decrease_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact)
+{
+ if (contact->rc > 0)
+ contact->rc--;
+
+ return contact->rc ? GNUNET_NO : GNUNET_YES;
+}
+
+const struct GNUNET_HashCode*
+get_contact_id_from_key (const struct GNUNET_MESSENGER_SrvContact *contact)
+{
+ static struct GNUNET_HashCode id;
+
+ GNUNET_CRYPTO_hash (&(contact->public_key), sizeof(contact->public_key), &id);
+
+ return &id;
+}
diff --git a/src/messenger/gnunet-service-messenger_contact.h b/src/messenger/gnunet-service-messenger_contact.h
new file mode 100644
index 000000000..4a4f8bf0f
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_contact.h
@@ -0,0 +1,112 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_contact.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_CONTACT_H
+#define GNUNET_SERVICE_MESSENGER_CONTACT_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+
+struct GNUNET_MESSENGER_SrvContact
+{
+ char *name;
+ size_t rc;
+
+ struct GNUNET_IDENTITY_PublicKey public_key;
+};
+
+/**
+ * Creates and allocates a new contact with a given public <i>key</i> from an EGO.
+ *
+ * @param key Public key
+ * @return New contact
+ */
+struct GNUNET_MESSENGER_SrvContact*
+create_contact (const struct GNUNET_IDENTITY_PublicKey *key);
+
+/**
+ * Destroys a contact and frees its memory fully.
+ *
+ * @param contact Contact
+ */
+void
+destroy_contact (struct GNUNET_MESSENGER_SrvContact *contact);
+
+/**
+ * Returns the current name of a given <i>contact</i> or NULL if no valid name was assigned yet.
+ *
+ * @param contact Contact
+ * @return Name of the contact or NULL
+ */
+const char*
+get_contact_name (const struct GNUNET_MESSENGER_SrvContact *contact);
+
+/**
+ * Changes the current name of a given <i>contact</i> by copying it from the parameter <i>name</i>.
+ *
+ * @param contact Contact
+ * @param name Valid name (may not be NULL!)
+ */
+void
+set_contact_name (struct GNUNET_MESSENGER_SrvContact *contact, const char *name);
+
+/**
+ * Returns the public key of a given <i>contact</i>.
+ *
+ * @param contact Contact
+ * @return Public key of the contact
+ */
+const struct GNUNET_IDENTITY_PublicKey*
+get_contact_key (const struct GNUNET_MESSENGER_SrvContact *contact);
+
+/**
+ * Increases the reference counter of a given <i>contact</i> which is zero as default.
+ *
+ * @param contact Contact
+ */
+void
+increase_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact);
+
+/**
+ * Decreases the reference counter if possible (can not underflow!) of a given <i>contact</i>
+ * and returns GNUNET_YES if the counter is equal to zero, otherwise GNUNET_NO.
+ *
+ * @param contact Contact
+ * @return GNUNET_YES or GNUNET_NO depending on the reference counter
+ */
+int
+decrease_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact);
+
+/**
+ * Returns the resulting hashcode of the public key from a given <i>contact</i>.
+ *
+ * @param contact Contact
+ * @return Hash of the contacts public key
+ */
+const struct GNUNET_HashCode*
+get_contact_id_from_key (const struct GNUNET_MESSENGER_SrvContact *contact);
+
+#endif //GNUNET_SERVICE_MESSENGER_CONTACT_H
diff --git a/src/messenger/gnunet-service-messenger_handle.c b/src/messenger/gnunet-service-messenger_handle.c
new file mode 100644
index 000000000..38ad6fbb4
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_handle.c
@@ -0,0 +1,503 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_handle.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_handle.h"
+
+#include "gnunet-service-messenger.h"
+#include "gnunet-service-messenger_message_kind.h"
+
+struct GNUNET_MESSENGER_SrvHandle*
+create_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq)
+{
+ struct GNUNET_MESSENGER_SrvHandle *handle = GNUNET_new(struct GNUNET_MESSENGER_SrvHandle);
+
+ handle->service = service;
+ handle->mq = mq;
+
+ handle->name = NULL;
+
+ handle->operation = NULL;
+
+ handle->ego = NULL;
+
+ handle->member_ids = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+
+ return handle;
+}
+
+int
+iterate_free_member_ids (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ GNUNET_free(value);
+
+ return GNUNET_YES;
+}
+
+void
+destroy_handle (struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ if (handle->service->dir)
+ save_handle_configuration(handle);
+
+ if (handle->operation)
+ GNUNET_IDENTITY_cancel (handle->operation);
+
+ if (handle->name)
+ GNUNET_free(handle->name);
+
+ GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_free_member_ids, NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (handle->member_ids);
+
+ GNUNET_free(handle);
+}
+
+void
+get_handle_data_subdir (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name, char **dir)
+{
+ if (name)
+ GNUNET_asprintf (dir, "%s%s%c%s%c", handle->service->dir, "identities",
+ DIR_SEPARATOR, name, DIR_SEPARATOR);
+ else
+ GNUNET_asprintf (dir, "%s%s%c", handle->service->dir, "anonymous",
+ DIR_SEPARATOR);
+}
+
+static int
+create_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_ShortHashCode *random_id = generate_service_new_member_id (handle->service, key);
+
+ if (!random_id)
+ return GNUNET_NO;
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key, random_id,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ GNUNET_free(random_id);
+ return GNUNET_NO;
+ }
+
+ GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Created a new member id (%s) for room: %s\n",
+ GNUNET_sh2s(random_id), GNUNET_h2s(key));
+
+ return GNUNET_YES;
+}
+
+const struct GNUNET_ShortHashCode*
+get_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
+{
+ return GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key);
+}
+
+void
+change_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
+ const struct GNUNET_ShortHashCode *unique_id)
+{
+ struct GNUNET_ShortHashCode *member_id = GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key);
+
+ if (member_id)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Changed a member id (%s) for room (%s) ",
+ GNUNET_sh2s(member_id), GNUNET_h2s(key));
+ GNUNET_log(GNUNET_ERROR_TYPE_INFO, "into (%s).\n",
+ GNUNET_sh2s(unique_id));
+
+ GNUNET_memcpy(member_id, unique_id, sizeof(*unique_id));
+
+ struct GNUNET_MESSENGER_MemberMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID);
+
+ GNUNET_memcpy(&(msg->key), key, sizeof(*key));
+ GNUNET_memcpy(&(msg->id), member_id, sizeof(*member_id));
+
+ GNUNET_MQ_send (handle->mq, env);
+ }
+ else
+ {
+ member_id = GNUNET_new(struct GNUNET_ShortHashCode);
+ GNUNET_memcpy(member_id, unique_id, sizeof(*member_id));
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key, member_id,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ GNUNET_free(member_id);
+ }
+}
+
+static void
+change_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name)
+{
+ if (handle->name)
+ GNUNET_free(handle->name);
+
+ handle->name = name ? GNUNET_strdup(name) : NULL;
+
+ const uint16_t name_len = handle->name ? strlen (handle->name) : 0;
+
+ struct GNUNET_MESSENGER_NameMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg_extra(msg, name_len + 1, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_NAME);
+
+ char *extra = ((char*) msg) + sizeof(*msg);
+
+ if (name_len)
+ GNUNET_memcpy(extra, handle->name, name_len);
+
+ extra[name_len] = '\0';
+
+ GNUNET_MQ_send (handle->mq, env);
+}
+
+static void
+change_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle, struct GNUNET_MESSENGER_Ego *ego)
+{
+ handle->ego = ego;
+
+ ego = get_handle_ego(handle);
+
+ struct GNUNET_MESSENGER_KeyMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_KEY);
+
+ GNUNET_memcpy(&(msg->pubkey), &(ego->pub), sizeof(ego->pub));
+
+ GNUNET_MQ_send (handle->mq, env);
+}
+
+struct GNUNET_MESSENGER_Ego*
+get_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ static struct GNUNET_MESSENGER_Ego anonymous;
+ static int read_keys = 0;
+
+ if (handle->ego)
+ return handle->ego;
+
+ if (!read_keys)
+ {
+ struct GNUNET_IDENTITY_Ego* ego = GNUNET_IDENTITY_ego_get_anonymous ();
+ GNUNET_memcpy(&(anonymous.priv), GNUNET_IDENTITY_ego_get_private_key(ego), sizeof(anonymous.priv));
+ GNUNET_IDENTITY_ego_get_public_key(ego, &(anonymous.pub));
+ read_keys = 1;
+ }
+
+ return &anonymous;
+}
+
+void
+setup_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name)
+{
+ change_handle_name (handle, name);
+ change_handle_ego (handle, handle->name? lookup_service_ego(handle->service, handle->name) : NULL);
+
+ if (handle->service->dir)
+ load_handle_configuration(handle);
+}
+
+struct GNUNET_MESSENGER_MessageHandle
+{
+ struct GNUNET_MESSENGER_SrvHandle *handle;
+ struct GNUNET_MESSENGER_Message *message;
+};
+
+static int
+iterate_send_message (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_MessageHandle *msg_handle = cls;
+
+ send_handle_message (msg_handle->handle, key, msg_handle->message);
+
+ return GNUNET_YES;
+}
+
+static void
+callback_ego_create (void *cls, const struct GNUNET_IDENTITY_PrivateKey *key, const char *emsg)
+{
+ struct GNUNET_MESSENGER_SrvHandle *handle = cls;
+
+ handle->operation = NULL;
+
+ if (emsg)
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s\n", emsg);
+
+ if (key)
+ {
+ struct GNUNET_MESSENGER_MessageHandle msg_handle;
+
+ msg_handle.handle = handle;
+ msg_handle.message = create_message_key (key);
+
+ GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_send_message, &msg_handle);
+
+ destroy_message (msg_handle.message);
+
+ update_service_ego(handle->service, handle->name, key);
+
+ change_handle_ego (handle, lookup_service_ego(handle->service, handle->name));
+ }
+}
+
+int
+update_handle (struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ GNUNET_assert(handle);
+
+ if (!handle->name)
+ return GNUNET_SYSERR;
+
+ struct GNUNET_MESSENGER_Ego *ego = lookup_service_ego(handle->service, handle->name);
+
+ if (!ego)
+ handle->operation = GNUNET_IDENTITY_create (handle->service->identity, handle->name, NULL,
+ GNUNET_IDENTITY_TYPE_ECDSA, callback_ego_create, handle);
+ else
+ change_handle_ego (handle, ego);
+
+ return GNUNET_OK;
+}
+
+int
+set_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name)
+{
+ GNUNET_assert(handle);
+
+ if ((name) && (lookup_service_ego(handle->service, name)))
+ return GNUNET_NO;
+
+ struct GNUNET_IDENTITY_Operation *operation = handle->operation;
+
+ if (handle->name)
+ handle->operation = GNUNET_IDENTITY_rename (handle->service->identity, handle->name, name, NULL, NULL);
+
+ char *old_dir;
+ get_handle_data_subdir (handle, handle->name, &old_dir);
+
+ char *new_dir;
+ get_handle_data_subdir (handle, name, &new_dir);
+
+ int result = 0;
+
+ if (GNUNET_YES == GNUNET_DISK_directory_test (old_dir, GNUNET_YES))
+ {
+ GNUNET_DISK_directory_create_for_file (new_dir);
+
+ result = rename (old_dir, new_dir);
+ }
+ else if (GNUNET_YES == GNUNET_DISK_directory_test (new_dir, GNUNET_NO))
+ result = -1;
+
+ if (0 == result)
+ {
+ struct GNUNET_MESSENGER_MessageHandle msg_handle;
+
+ msg_handle.handle = handle;
+ msg_handle.message = create_message_name (name);
+
+ GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_send_message, &msg_handle);
+
+ destroy_message (msg_handle.message);
+
+ change_handle_name (handle, name);
+
+ if (operation)
+ GNUNET_IDENTITY_cancel (operation);
+ }
+ else
+ {
+ if (handle->operation)
+ {
+ GNUNET_IDENTITY_cancel (handle->operation);
+
+ handle->operation = operation;
+ }
+ }
+
+ GNUNET_free(old_dir);
+ GNUNET_free(new_dir);
+
+ return (result == 0 ? GNUNET_OK : GNUNET_NO);
+}
+
+int
+open_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
+{
+ if ((!get_handle_member_id (handle, key)) && (GNUNET_YES != create_handle_member_id (handle, key)))
+ return GNUNET_NO;
+
+ return open_service_room (handle->service, handle, key);
+}
+
+int
+entry_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_PeerIdentity *door,
+ const struct GNUNET_HashCode *key)
+{
+ if ((!get_handle_member_id (handle, key)) && (GNUNET_YES != create_handle_member_id (handle, key)))
+ return GNUNET_NO;
+
+ return entry_service_room (handle->service, handle, door, key);
+}
+
+int
+close_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
+{
+ if (!get_handle_member_id (handle, key))
+ return GNUNET_NO;
+
+ return close_service_room (handle->service, handle, key);
+}
+
+int
+send_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
+ struct GNUNET_MESSENGER_Message *message)
+{
+ const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, key);
+
+ if (!id)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "It is required to be a member of a room to send messages!\n");
+ return GNUNET_NO;
+ }
+
+ struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (handle->service, key);
+
+ if (!room)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "The room (%s) is unknown!\n", GNUNET_h2s (key));
+ return GNUNET_NO;
+ }
+
+ struct GNUNET_HashCode hash;
+
+ GNUNET_memcpy(&(message->header.sender_id), id, sizeof(*id));
+
+ send_room_message (room, handle, message, &hash);
+ return GNUNET_YES;
+}
+
+static int callback_scan_for_rooms(void* cls, const char *filename) {
+ struct GNUNET_MESSENGER_SrvHandle* handle = cls;
+
+ struct GNUNET_CONFIGURATION_Handle* cfg = GNUNET_CONFIGURATION_create();
+
+ if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) &&
+ (GNUNET_OK == GNUNET_CONFIGURATION_parse(cfg, filename)))
+ {
+ struct GNUNET_HashCode key;
+ struct GNUNET_ShortHashCode member_id;
+
+ if ((GNUNET_OK == GNUNET_CONFIGURATION_get_data(cfg, "room", "key", &key, sizeof(key))) &&
+ (GNUNET_OK == GNUNET_CONFIGURATION_get_data(cfg, "room", "member_id", &member_id, sizeof(member_id))))
+ change_handle_member_id(handle, &key, &member_id);
+ }
+
+ GNUNET_CONFIGURATION_destroy(cfg);
+ return GNUNET_OK;
+}
+
+void load_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle) {
+ char* id_dir;
+ get_handle_data_subdir(handle, handle->name, &id_dir);
+
+ if (GNUNET_YES == GNUNET_DISK_directory_test(id_dir, GNUNET_YES))
+ {
+ char* scan_dir;
+ GNUNET_asprintf(&scan_dir, "%s%s%c", id_dir, "rooms", DIR_SEPARATOR);
+
+ if (GNUNET_OK == GNUNET_DISK_directory_test(scan_dir, GNUNET_YES))
+ GNUNET_DISK_directory_scan(scan_dir, callback_scan_for_rooms, handle);
+
+ GNUNET_free(scan_dir);
+ }
+
+ GNUNET_free(id_dir);
+}
+
+static int
+iterate_save_rooms(void* cls, const struct GNUNET_HashCode* key, void* value)
+{
+ struct GNUNET_MESSENGER_SrvHandle* handle = cls;
+ struct GNUNET_ShortHashCode* member_id = value;
+
+ char* id_dir;
+ get_handle_data_subdir(handle, handle->name, &id_dir);
+
+ char* filename;
+ GNUNET_asprintf(&filename, "%s%s%c%s.cfg",
+ id_dir, "rooms", DIR_SEPARATOR,
+ GNUNET_h2s(key));
+
+ GNUNET_free(id_dir);
+
+ struct GNUNET_CONFIGURATION_Handle* cfg = GNUNET_CONFIGURATION_create();
+
+ char* key_data = GNUNET_STRINGS_data_to_string_alloc(key, sizeof(*key));
+
+ if (key_data)
+ {
+ GNUNET_CONFIGURATION_set_value_string(cfg, "room", "key", key_data);
+
+ GNUNET_free(key_data);
+ }
+
+ char* member_id_data = GNUNET_STRINGS_data_to_string_alloc(member_id, sizeof(*member_id));
+
+ if (member_id_data)
+ {
+ GNUNET_CONFIGURATION_set_value_string(cfg, "room", "member_id", member_id_data);
+
+ GNUNET_free(member_id_data);
+ }
+
+ GNUNET_CONFIGURATION_write(cfg, filename);
+ GNUNET_CONFIGURATION_destroy(cfg);
+
+ GNUNET_free(filename);
+
+ return GNUNET_YES;
+}
+
+void save_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ char* id_dir;
+ get_handle_data_subdir(handle, handle->name, &id_dir);
+
+ if ((GNUNET_YES == GNUNET_DISK_directory_test(id_dir, GNUNET_NO)) ||
+ (GNUNET_OK == GNUNET_DISK_directory_create(id_dir)))
+ {
+ char* save_dir;
+ GNUNET_asprintf(&save_dir, "%s%s%c", id_dir, "rooms", DIR_SEPARATOR);
+
+ if ((GNUNET_YES == GNUNET_DISK_directory_test(save_dir, GNUNET_NO)) ||
+ (GNUNET_OK == GNUNET_DISK_directory_create(save_dir)))
+ GNUNET_CONTAINER_multihashmap_iterate(handle->member_ids, iterate_save_rooms, handle);
+
+ GNUNET_free(save_dir);
+ }
+
+ GNUNET_free(id_dir);
+}
diff --git a/src/messenger/gnunet-service-messenger_handle.h b/src/messenger/gnunet-service-messenger_handle.h
new file mode 100644
index 000000000..81cf377a8
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_handle.h
@@ -0,0 +1,216 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_handle.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_HANDLE_H
+#define GNUNET_SERVICE_MESSENGER_HANDLE_H
+
+#include "platform.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_peer_lib.h"
+#include "gnunet_mq_lib.h"
+
+#include "gnunet-service-messenger_service.h"
+
+#include "messenger_api_ego.h"
+#include "messenger_api_message.h"
+
+struct GNUNET_MESSENGER_SrvHandle
+{
+ struct GNUNET_MESSENGER_Service *service;
+ struct GNUNET_MQ_Handle *mq;
+
+ char *name;
+
+ struct GNUNET_IDENTITY_Operation *operation;
+
+ struct GNUNET_MESSENGER_Ego *ego;
+
+ struct GNUNET_CONTAINER_MultiHashMap *member_ids;
+};
+
+/**
+ * Creates and allocates a new handle related to a <i>service</i> and using a given <i>mq</i> (message queue).
+ *
+ * @param service MESSENGER Service
+ * @param mq Message queue
+ * @return New handle
+ */
+struct GNUNET_MESSENGER_SrvHandle*
+create_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq);
+
+/**
+ * Destroys a handle and frees its memory fully.
+ *
+ * @param handle Handle
+ */
+void
+destroy_handle (struct GNUNET_MESSENGER_SrvHandle *handle);
+
+/**
+ * Writes the path of the directory for a given <i>handle</i> using a specific <i>name</i> to the parameter
+ * <i>dir</i>. This directory will be used to store data regarding the handle and its messages.
+ *
+ * @param handle Handle
+ * @param name Potential name of the handle
+ * @param dir[out] Path to store data
+ */
+void
+get_handle_data_subdir (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name, char **dir);
+
+/**
+ * Returns the member id of a given <i>handle</i> in a specific <i>room</i>.
+ *
+ * If the handle is not a member of the specific <i>room</i>, NULL gets returned.
+ *
+ * @param handle Handle
+ * @param key Key of a room
+ * @return Member id or NULL
+ */
+const struct GNUNET_ShortHashCode*
+get_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
+
+/**
+ * Changes the member id of a given <i>handle</i> in a specific <i>room</i> to match a <i>unique_id</i>.
+ *
+ * The client connected to the <i>handle</i> will be informed afterwards automatically.
+ *
+ * @param handle Handle
+ * @param key Key of a room
+ * @param unique_id Unique member id
+ */
+void
+change_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
+ const struct GNUNET_ShortHashCode *unique_id);
+
+/**
+ * Returns the EGO used by a given <i>handle</i>.
+ *
+ * @param handle Handle
+ * @return EGO keypair
+ */
+struct GNUNET_MESSENGER_Ego*
+get_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle);
+
+/**
+ * Tries to set the name and EGO key of a <i>handle</i> initially by looking up a specific <i>name</i>.
+ *
+ * @param handle Handle
+ * @param name Name (optionally: valid EGO name)
+ */
+void
+setup_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name);
+
+/**
+ * Tries to change the keypair of an EGO of a <i>handle</i> under the same name and informs all rooms
+ * about the change automatically.
+ *
+ * @param handle Handle
+ * @return GNUNET_OK on success, otherwise GNUNET_SYSERR
+ */
+int
+update_handle (struct GNUNET_MESSENGER_SrvHandle *handle);
+
+/**
+ * Tries to rename the handle which implies renaming the EGO its using and moving all related data into
+ * the directory fitting to the changed <i>name</i>.
+ *
+ * The client connected to the <i>handle</i> will be informed afterwards automatically.
+ *
+ * @param handle Handle
+ * @param name New name
+ * @return GNUNET_OK on success, otherwise GNUNET_NO
+ */
+int
+set_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name);
+
+/**
+ * Makes a given <i>handle</i> a member of the room using a specific <i>key</i> and opens the
+ * room from the handles service.
+ *
+ * @param handle Handle
+ * @param key Key of a room
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+open_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
+
+/**
+ * Makes a given <i>handle</i> a member of the room using a specific <i>key</i> and enters the room
+ * through a tunnel to a peer identified by a given <i>door</i> (peer identity).
+ *
+ * @param handle Handle
+ * @param door Peer identity
+ * @param key Key of a room
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+entry_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_PeerIdentity *door,
+ const struct GNUNET_HashCode *key);
+
+/**
+ * Removes the membership of the room using a specific <i>key</i> and closes it if no other handle
+ * from this service is still a member of it.
+ *
+ * @param handle Handle
+ * @param key Key of a room
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+close_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
+
+/**
+ * Sends a <i>message</i> from a given <i>handle</i> to the room using a specific <i>key</i>.
+ *
+ * @param handle Handle
+ * @param key Key of a room
+ * @param message Message
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+send_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
+ struct GNUNET_MESSENGER_Message *message);
+
+/**
+ * Loads member ids and other potential configuration from a given <i>handle</i> which
+ * depends on the given name the <i>handle</i> uses.
+ *
+ * @param handle Handle
+ */
+void
+load_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle);
+
+/**
+ * Saves member ids and other potential configuration from a given <i>handle</i> which
+ * depends on the given name the <i>handle</i> uses.
+ *
+ * @param handle Handle
+ */
+void
+save_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle);
+
+#endif //GNUNET_SERVICE_MESSENGER_HANDLE_H
diff --git a/src/messenger/gnunet-service-messenger_list_handles.c b/src/messenger/gnunet-service-messenger_list_handles.c
new file mode 100644
index 000000000..16a160dea
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_list_handles.c
@@ -0,0 +1,95 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_list_handles.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_list_handles.h"
+
+#include "gnunet-service-messenger_handle.h"
+
+void
+init_list_handles (struct GNUNET_MESSENGER_ListHandles *handles)
+{
+ GNUNET_assert(handles);
+
+ handles->head = NULL;
+ handles->tail = NULL;
+}
+
+void
+clear_list_handles (struct GNUNET_MESSENGER_ListHandles *handles)
+{
+ GNUNET_assert(handles);
+
+ while (handles->head)
+ {
+ struct GNUNET_MESSENGER_ListHandle *element = handles->head;
+
+ GNUNET_CONTAINER_DLL_remove(handles->head, handles->tail, element);
+ destroy_handle (element->handle);
+ GNUNET_free(element);
+ }
+
+ handles->head = NULL;
+ handles->tail = NULL;
+}
+
+void
+add_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle)
+{
+ struct GNUNET_MESSENGER_ListHandle *element = GNUNET_new(struct GNUNET_MESSENGER_ListHandle);
+
+ element->handle = handle;
+
+ GNUNET_CONTAINER_DLL_insert_tail(handles->head, handles->tail, element);
+}
+
+int
+remove_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle)
+{
+ struct GNUNET_MESSENGER_ListHandle *element;
+
+ for (element = handles->head; element; element = element->next)
+ if (element->handle == handle)
+ break;
+
+ if (!element)
+ return GNUNET_NO;
+
+ GNUNET_CONTAINER_DLL_remove(handles->head, handles->tail, element);
+ GNUNET_free(element);
+
+ return GNUNET_YES;
+}
+
+void*
+find_list_handle_by_member (struct GNUNET_MESSENGER_ListHandles *handles, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_ListHandle *element;
+
+ for (element = handles->head; element; element = element->next)
+ if (get_handle_member_id ((struct GNUNET_MESSENGER_SrvHandle*) element->handle, key))
+ return element->handle;
+
+ return NULL;
+}
diff --git a/src/messenger/gnunet-service-messenger_list_handles.h b/src/messenger/gnunet-service-messenger_list_handles.h
new file mode 100644
index 000000000..fe92cc58a
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_list_handles.h
@@ -0,0 +1,96 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_list_handles.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
+#define GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_container_lib.h"
+
+struct GNUNET_MESSENGER_ListHandle
+{
+ struct GNUNET_MESSENGER_ListHandle *prev;
+ struct GNUNET_MESSENGER_ListHandle *next;
+
+ void *handle;
+};
+
+struct GNUNET_MESSENGER_ListHandles
+{
+ struct GNUNET_MESSENGER_ListHandle *head;
+ struct GNUNET_MESSENGER_ListHandle *tail;
+};
+
+/**
+ * Initializes list of handles as empty list.
+ *
+ * @param handles List of handles
+ */
+void
+init_list_handles (struct GNUNET_MESSENGER_ListHandles *handles);
+
+/**
+ * Destroys remaining handles and clears the list.
+ *
+ * @param handles List of handles
+ */
+void
+clear_list_handles (struct GNUNET_MESSENGER_ListHandles *handles);
+
+/**
+ * Adds a specific <i>handle</i> to the end of the list.
+ *
+ * @param handles List of handles
+ * @param handle Handle
+ */
+void
+add_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle);
+
+/**
+ * Removes the first entry matching with a specific <i>handle</i> from the list and
+ * returns GNUNET_YES on success or GNUNET_NO on failure.
+ *
+ * @param handles List of handles
+ * @param handle Handle
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+remove_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle);
+
+/**
+ * Searches linearly through the list of handles for members of a specific room
+ * which is identified by a given <i>key</i>.
+ *
+ * If no handle is found which is a current member, NULL gets returned.
+ *
+ * @param handles List of handles
+ * @param key Common key of a room
+ * @return First handle which is a current member
+ */
+void*
+find_list_handle_by_member (struct GNUNET_MESSENGER_ListHandles *handles, const struct GNUNET_HashCode *key);
+
+#endif //GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
diff --git a/src/messenger/gnunet-service-messenger_list_messages.c b/src/messenger/gnunet-service-messenger_list_messages.c
new file mode 100644
index 000000000..c4f1f7043
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_list_messages.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_list_messages.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_list_messages.h"
+
+void
+init_list_messages (struct GNUNET_MESSENGER_ListMessages *messages)
+{
+ GNUNET_assert(messages);
+
+ messages->head = NULL;
+ messages->tail = NULL;
+}
+
+void
+clear_list_messages (struct GNUNET_MESSENGER_ListMessages *messages)
+{
+ GNUNET_assert(messages);
+
+ while (messages->head)
+ {
+ struct GNUNET_MESSENGER_ListMessage *element = messages->head;
+
+ GNUNET_CONTAINER_DLL_remove(messages->head, messages->tail, element);
+ GNUNET_free(element);
+ }
+
+ messages->head = NULL;
+ messages->tail = NULL;
+}
+
+void
+add_to_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_ListMessage *element = GNUNET_new(struct GNUNET_MESSENGER_ListMessage);
+
+ GNUNET_memcpy(&(element->hash), hash, sizeof(struct GNUNET_HashCode));
+
+ GNUNET_CONTAINER_DLL_insert_tail(messages->head, messages->tail, element);
+}
+
+void
+remove_from_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_ListMessage *element;
+
+ for (element = messages->head; element; element = element->next)
+ if (0 == GNUNET_CRYPTO_hash_cmp (&(element->hash), hash))
+ {
+ GNUNET_CONTAINER_DLL_remove(messages->head, messages->tail, element);
+ GNUNET_free(element);
+ break;
+ }
+}
diff --git a/src/messenger/gnunet-service-messenger_list_messages.h b/src/messenger/gnunet-service-messenger_list_messages.h
new file mode 100644
index 000000000..266c30ec6
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_list_messages.h
@@ -0,0 +1,81 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_list_messages.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
+#define GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_container_lib.h"
+
+struct GNUNET_MESSENGER_ListMessage
+{
+ struct GNUNET_MESSENGER_ListMessage *prev;
+ struct GNUNET_MESSENGER_ListMessage *next;
+
+ struct GNUNET_HashCode hash;
+};
+
+struct GNUNET_MESSENGER_ListMessages
+{
+ struct GNUNET_MESSENGER_ListMessage *head;
+ struct GNUNET_MESSENGER_ListMessage *tail;
+};
+
+/**
+ * Initializes list of message hashes as empty list.
+ *
+ * @param messages List of hashes
+ */
+void
+init_list_messages (struct GNUNET_MESSENGER_ListMessages *messages);
+
+/**
+ * Clears the list of message hashes.
+ *
+ * @param messages List of hashes
+ */
+void
+clear_list_messages (struct GNUNET_MESSENGER_ListMessages *messages);
+
+/**
+ * Adds a specific <i>hash</i> from a message to the end of the list.
+ *
+ * @param messages List of hashes
+ * @param hash Hash of message
+ */
+void
+add_to_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash);
+
+/**
+ * Removes the first entry with a matching <i>hash</i> from the list.
+ *
+ * @param messages List of hashes
+ * @param hash Hash of message
+ */
+void
+remove_from_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash);
+
+#endif //GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
diff --git a/src/messenger/gnunet-service-messenger_message_handle.c b/src/messenger/gnunet-service-messenger_message_handle.c
new file mode 100644
index 000000000..1652435c8
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_handle.c
@@ -0,0 +1,130 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_handle.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_message_handle.h"
+
+void
+handle_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = get_room_contact (room, &(message->header.sender_id));
+
+ if (!contact)
+ add_room_contact (room, &(message->header.sender_id), &(message->body.join.key));
+
+ struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
+
+ if (!info)
+ {
+ info = GNUNET_new(struct GNUNET_MESSENGER_MemberInfo);
+
+ info->access = GNUNET_MESSENGER_MEMBER_UNKNOWN;
+ init_list_messages (&(info->session_messages));
+ }
+ else
+ clear_list_messages (&(info->session_messages));
+
+ if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_put (room->member_infos, &(message->header.sender_id), info,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ add_to_list_messages (&(info->session_messages), hash);
+}
+
+void
+handle_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
+
+ if (info)
+ clear_list_messages (&(info->session_messages));
+}
+
+void
+handle_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = get_room_contact (room, &(message->header.sender_id));
+
+ if (contact)
+ set_contact_name (contact, message->body.name.name);
+
+ struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
+
+ if (info)
+ add_to_list_messages (&(info->session_messages), hash);
+}
+
+void
+handle_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = get_room_contact (room, &(message->header.sender_id));
+
+ if (contact)
+ swap_service_contact_by_pubkey (room->service, contact, &(message->body.key.key));
+
+ struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
+
+ if (info)
+ add_to_list_messages (&(info->session_messages), hash);
+}
+
+void
+handle_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ if (GNUNET_NO == contains_list_tunnels (&(room->basement), &(message->body.peer.peer)))
+ add_to_list_tunnels (&(room->basement), &(message->body.peer.peer));
+
+ if (room->peer_message)
+ rebuild_room_basement_structure (room);
+}
+
+void
+handle_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
+
+ if (info)
+ add_to_list_messages (&(info->session_messages), hash);
+
+ switch_room_member_id (room, &(message->header.sender_id), &(message->body.id.id), hash);
+}
+
+void
+handle_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_ListTunnel *element = find_list_tunnels (&(room->basement), &(message->body.peer.peer), NULL);
+
+ if (!element)
+ return;
+
+ remove_from_list_tunnels (&(room->basement), element);
+
+ if (room->peer_message)
+ rebuild_room_basement_structure (room);
+}
diff --git a/src/messenger/gnunet-service-messenger_message_handle.h b/src/messenger/gnunet-service-messenger_message_handle.h
new file mode 100644
index 000000000..d091e1d11
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_handle.h
@@ -0,0 +1,128 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_handle.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
+#define GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+
+#include "gnunet-service-messenger_message_kind.h"
+
+#include "gnunet-service-messenger_tunnel.h"
+#include "messenger_api_message.h"
+
+/**
+ * Handles a received or sent join message to make changes of current member information.
+ * (add matching member and clear member info)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving/sending connection (may be NULL)
+ * @param message JOIN-Message
+ * @param hash Hash of the message
+ */
+void
+handle_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received or sent leave message to make changes of current member information.
+ * (remove matching member and clear member info)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving/sending connection (may be NULL)
+ * @param message LEAVE-Message
+ * @param hash Hash of the message
+ */
+void
+handle_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received or sent name message to rename a current member.
+ * (change name of matching member)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving/sending connection (may be NULL)
+ * @param message NAME-Message
+ * @param hash Hash of the message
+ */
+void
+handle_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received or sent key message to change the key of a member and rearrange the contacts accordingly.
+ * (move the member in the contacts and change its key)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving/sending connection (may be NULL)
+ * @param message KEY-Message
+ * @param hash Hash of the message
+ */
+void
+handle_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received or sent peer message to make changes of the basement in the room.
+ * (add a new peer to the basement and restructure connections based on updated list of peers)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving/sending connection (may be NULL)
+ * @param message PEER-Message
+ * @param hash Hash of the message
+ */
+void
+handle_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received or sent id message to change a members id.
+ * (change id of matching member)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving/sending connection (may be NULL)
+ * @param message ID-Message
+ * @param hash Hash of the message
+ */
+void
+handle_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received or sent miss message to drop a peer from the basement in the room.
+ * (remove a peer from the basement and restructure connections based on updated list of peers)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving/sending connection (may be NULL)
+ * @param message MISS-Message
+ * @param hash Hash of the message
+ */
+void
+handle_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
diff --git a/src/messenger/gnunet-service-messenger_message_kind.c b/src/messenger/gnunet-service-messenger_message_kind.c
new file mode 100644
index 000000000..9c829fe09
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_kind.c
@@ -0,0 +1,192 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_kind.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_message_kind.h"
+#include "gnunet-service-messenger_util.h"
+
+struct GNUNET_MESSENGER_Message*
+create_message_info (struct GNUNET_MESSENGER_Ego *ego, struct GNUNET_CONTAINER_MultiShortmap *members)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_INFO);
+
+ if (!message)
+ return NULL;
+
+ GNUNET_memcpy(&(message->body.info.host_key), &(ego->pub), sizeof(ego->pub));
+
+ if (GNUNET_YES == generate_free_member_id (&(message->body.info.unique_id), members))
+ return message;
+ else
+ {
+ destroy_message (message);
+ return NULL;
+ }
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_join (struct GNUNET_MESSENGER_Ego *ego)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_JOIN);
+
+ if (!message)
+ return NULL;
+
+ GNUNET_memcpy(&(message->body.join.key), &(ego->pub), sizeof(ego->pub));
+
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_leave ()
+{
+ return create_message (GNUNET_MESSENGER_KIND_LEAVE);
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_name (const char *name)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_NAME);
+
+ if (!message)
+ return NULL;
+
+ message->body.name.name = GNUNET_strdup(name);
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_key (const struct GNUNET_IDENTITY_PrivateKey *key)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_KEY);
+
+ if (!message)
+ return NULL;
+
+ GNUNET_IDENTITY_key_get_public (key, &(message->body.key.key));
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_peer (const struct GNUNET_MESSENGER_Service *service)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_PEER);
+
+ if (!message)
+ return NULL;
+
+ if (GNUNET_OK == get_service_peer_identity (service, &(message->body.peer.peer)))
+ return message;
+ else
+ {
+ destroy_message (message);
+ return NULL;
+ }
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_id (const struct GNUNET_ShortHashCode *unique_id)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_ID);
+
+ if (!message)
+ return NULL;
+
+ GNUNET_memcpy(&(message->body.id.id), unique_id, sizeof(struct GNUNET_ShortHashCode));
+
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_miss (const struct GNUNET_PeerIdentity *peer)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_MISS);
+
+ if (!message)
+ {
+ return NULL;
+ }
+
+ GNUNET_memcpy(&(message->body.miss.peer), peer, sizeof(struct GNUNET_PeerIdentity));
+
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_merge (const struct GNUNET_HashCode *previous)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_MERGE);
+
+ if (!message)
+ return NULL;
+
+ GNUNET_memcpy(&(message->body.merge.previous), previous, sizeof(struct GNUNET_HashCode));
+
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_request (const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_HashCode zero;
+ memset (&zero, 0, sizeof(zero));
+
+ if (0 == GNUNET_CRYPTO_hash_cmp (hash, &zero))
+ return NULL;
+
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_REQUEST);
+
+ if (!message)
+ return NULL;
+
+ GNUNET_memcpy(&(message->body.request.hash), hash, sizeof(struct GNUNET_HashCode));
+
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_invite (const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_INVITE);
+
+ if (!message)
+ return NULL;
+
+ GNUNET_memcpy(&(message->body.invite.door), door, sizeof(struct GNUNET_PeerIdentity));
+ GNUNET_memcpy(&(message->body.invite.key), key, sizeof(struct GNUNET_HashCode));
+
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+create_message_text (const char *text)
+{
+ struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_TEXT);
+
+ if (!message)
+ return NULL;
+
+ message->body.text.text = GNUNET_strdup(text);
+ return message;
+}
diff --git a/src/messenger/gnunet-service-messenger_message_kind.h b/src/messenger/gnunet-service-messenger_message_kind.h
new file mode 100644
index 000000000..dd89d0b2f
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_kind.h
@@ -0,0 +1,160 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_kind.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
+#define GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
+
+#include "platform.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+
+#include "messenger_api_message.h"
+#include "gnunet-service-messenger_service.h"
+#include "messenger_api_ego.h"
+
+/**
+ * Creates and allocates a new info message containing the hosts public key and a newly generated unique member id.
+ * (all values are stored as copy)
+ *
+ * @param ego EGO of the host
+ * @param members Map of all assigned member ids
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_info (struct GNUNET_MESSENGER_Ego *ego, struct GNUNET_CONTAINER_MultiShortmap *members);
+
+/**
+ * Creates and allocates a new join message containing the clients public key.
+ * (all values are stored as copy)
+ *
+ * @param ego EGO of the client
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_join (struct GNUNET_MESSENGER_Ego *ego);
+
+/**
+ * Creates and allocates a new leave message.
+ *
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_leave ();
+
+/**
+ * Creates and allocates a new name message containing the <i>name</i> to change to.
+ * (all values are stored as copy)
+ *
+ * @param name New name
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_name (const char *name);
+
+/**
+ * Creates and allocates a new key message containing the public key to change to derived
+ * from its private counterpart. (all values are stored as copy)
+ *
+ * @param key Private key of EGO
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_key (const struct GNUNET_IDENTITY_PrivateKey *key);
+
+/**
+ * Creates and allocates a new peer message containing a services peer identity.
+ * (all values are stored as copy)
+ *
+ * @param service Service
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_peer (const struct GNUNET_MESSENGER_Service *service);
+
+/**
+ * Creates and allocates a new id message containing the unique member id to change to.
+ * (all values are stored as copy)
+ *
+ * @param unique_id Unique member id
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_id (const struct GNUNET_ShortHashCode *unique_id);
+
+/**
+ * Creates and allocates a new miss message containing the missing peer identity.
+ * (all values are stored as copy)
+ *
+ * @param peer Missing peer identity
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_miss (const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Creates and allocates a new merge message containing the hash of a second previous message
+ * besides the regular previous message mentioned in a messages header.
+ * (all values are stored as copy)
+ *
+ * @param previous Hash of message
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_merge (const struct GNUNET_HashCode *previous);
+
+/**
+ * Creates and allocates a new request message containing the hash of a missing message.
+ * (all values are stored as copy)
+ *
+ * @param hash Hash of message
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_request (const struct GNUNET_HashCode *hash);
+
+/**
+ * Creates and allocates a new invite message containing the peer identity of an entrance peer
+ * to a room using a given <i>key</i> as shared secret for communication.
+ * (all values are stored as copy)
+ *
+ * @param door Peer identity
+ * @param key Shared secret of a room
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_invite (const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key);
+
+/**
+ * Creates and allocates a new text message containing a string representing text.
+ * (all values are stored as copy)
+ *
+ * @param text Text
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message_text (const char *text);
+
+#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
diff --git a/src/messenger/gnunet-service-messenger_message_recv.c b/src/messenger/gnunet-service-messenger_message_recv.c
new file mode 100644
index 000000000..aa28a36ea
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_recv.c
@@ -0,0 +1,204 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_recv.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_message_recv.h"
+#include "gnunet-service-messenger_message_handle.h"
+
+void
+recv_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ int conflict = GNUNET_CONTAINER_multishortmap_contains (room->members, &(message->body.info.unique_id));
+
+ if (GNUNET_NO == conflict)
+ {
+ struct GNUNET_MESSENGER_Message *sync_message = create_message_id (&(message->body.info.unique_id));
+ struct GNUNET_HashCode sync_hash;
+
+ send_room_message_ext (room, room->host, sync_message, &sync_hash, tunnel);
+ destroy_message (sync_message);
+
+ switch_room_member_id (room, get_room_host_id (room), &(message->body.info.unique_id), NULL);
+
+ change_room_host_id (room, &(message->body.info.unique_id));
+ }
+
+ if (!tunnel->contact_id)
+ tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
+
+ GNUNET_memcpy(tunnel->contact_id, &(message->header.sender_id), sizeof(struct GNUNET_ShortHashCode));
+
+ struct GNUNET_ShortHashCode original_id;
+
+ if (GNUNET_YES == conflict)
+ {
+ GNUNET_memcpy(&original_id, get_room_host_id (room), sizeof(struct GNUNET_ShortHashCode));
+
+ change_room_host_id (room, &(message->body.info.unique_id));
+ }
+
+ {
+ struct GNUNET_MESSENGER_Message *join_message = create_message_join (room->host->ego);
+ struct GNUNET_HashCode join_hash;
+
+ send_tunnel_message (tunnel, room->host, join_message, &join_hash);
+ destroy_message (join_message);
+ }
+
+ if ((GNUNET_YES == conflict) && (0 != GNUNET_memcmp(&original_id, get_room_host_id (room))))
+ {
+ struct GNUNET_MESSENGER_Message *sync_message = create_message_id (&original_id);
+ struct GNUNET_HashCode sync_hash;
+
+ send_tunnel_message (tunnel, room->host, sync_message, &sync_hash);
+ destroy_message (sync_message);
+ }
+}
+
+struct GNUNET_MESSENGER_MemberInfoSpread
+{
+ struct GNUNET_MESSENGER_SrvRoom *room;
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel;
+};
+
+static int
+iterate_send_member_infos (void *cls, const struct GNUNET_ShortHashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_MemberInfo *info = value;
+ struct GNUNET_MESSENGER_MemberInfoSpread *spread = cls;
+
+ struct GNUNET_MESSENGER_ListMessage *element = info->session_messages.head;
+
+ while (element)
+ {
+ const struct GNUNET_MESSENGER_Message *message = get_room_message (spread->room, spread->room->host,
+ &(element->hash), GNUNET_NO);
+
+ if (message)
+ forward_tunnel_message (spread->tunnel, message, &(element->hash));
+
+ element = element->next;
+ }
+
+ return GNUNET_YES;
+}
+
+void
+recv_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ const struct GNUNET_MESSENGER_Message *info_msg = get_room_message (room, room->host, &(message->header.previous),
+ GNUNET_NO);
+
+ if ((info_msg) && (0 == GNUNET_memcmp(&(info_msg->header.sender_id), get_room_host_id (room)))
+ && (GNUNET_MESSENGER_KIND_INFO == info_msg->header.kind))
+ {
+ struct GNUNET_MESSENGER_MemberInfoSpread spread;
+
+ spread.room = room;
+
+ if ((tunnel) && (tunnel->contact_id) && (0 == GNUNET_memcmp(tunnel->contact_id, &(message->header.sender_id))))
+ spread.tunnel = tunnel;
+ else
+ spread.tunnel = find_room_tunnel_to (room, &(message->header.sender_id));
+
+ if (spread.tunnel)
+ GNUNET_CONTAINER_multishortmap_iterate (room->member_infos, iterate_send_member_infos, &spread);
+ }
+
+ handle_message_join (room, tunnel, message, hash);
+}
+
+void
+recv_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ handle_message_leave (room, tunnel, message, hash);
+}
+
+void
+recv_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ handle_message_name (room, tunnel, message, hash);
+}
+
+void
+recv_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ handle_message_key (room, tunnel, message, hash);
+}
+
+void
+recv_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_PeerIdentity peer;
+ GNUNET_PEER_resolve (tunnel->peer, &peer);
+
+ if (0 == GNUNET_memcmp(&peer, &(message->body.peer.peer)))
+ {
+ if (!tunnel->peer_message)
+ tunnel->peer_message = GNUNET_new(struct GNUNET_HashCode);
+
+ GNUNET_memcpy(tunnel->peer_message, hash, sizeof(struct GNUNET_HashCode));
+
+ if (!tunnel->contact_id)
+ tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
+
+ GNUNET_memcpy(tunnel->contact_id, &(message->header.sender_id), sizeof(struct GNUNET_ShortHashCode));
+ }
+
+ handle_message_peer (room, tunnel, message, hash);
+}
+
+void
+recv_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ if ((tunnel->contact_id) && (0 == GNUNET_memcmp(tunnel->contact_id, &(message->header.sender_id))))
+ GNUNET_memcpy(tunnel->contact_id, &(message->body.id.id), sizeof(struct GNUNET_ShortHashCode));
+
+ handle_message_id (room, tunnel, message, hash);
+}
+
+void
+recv_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ handle_message_miss (room, tunnel, message, hash);
+}
+
+void
+recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ const struct GNUNET_MESSENGER_Message *msg = get_room_message (room, room->host, &(message->body.request.hash),
+ GNUNET_NO);
+
+ if (msg)
+ forward_tunnel_message (tunnel, msg, &(message->body.request.hash));
+}
diff --git a/src/messenger/gnunet-service-messenger_message_recv.h b/src/messenger/gnunet-service-messenger_message_recv.h
new file mode 100644
index 000000000..245612cb0
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_recv.h
@@ -0,0 +1,159 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_recv.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
+#define GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+
+#include "gnunet-service-messenger_tunnel.h"
+#include "messenger_api_message.h"
+
+/**
+ * Handles a received info message to change the current member id to the one generated by
+ * the host connected to. (all current tunnels will be informed about the id change)
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message INFO-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received join message to forward all member information to the new member if the message was
+ * the direct reaction to a previous info message from this peer.
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message JOIN-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received leave message.
+ * @see handle_message_leave()
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message LEAVE-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received name message.
+ * @see handle_message_name()
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message NAME-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received key message.
+ * @see handle_message_key()
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message KEY-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received peer message to link it to its origin tunnel if the peer identity matches.
+ * (the peer message and the member id can potentially be linked to the tunnel)
+ *
+ * TODO: This handling will only check the one given tunnel!
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message PEER-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received id message to change the tunnels linked member id if necessary.
+ * (the tunnels linked member id will be changed if the sender id is matching)
+ *
+ * TODO: This handling will only check the one given tunnel!
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message ID-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received miss message.
+ * @see handle_message_miss()
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message MISS-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a received request message by checking for the requested message and forwarding it back
+ * if the message was found.
+ * (this can also cause this peer to send a new request instead of only forwarding the received one)
+ *
+ * TODO: Requests can cause exponentially more requests!
+ *
+ * @param room Room of the message
+ * @param tunnel Receiving connection
+ * @param message REQUEST-Message
+ * @param hash Hash of the message
+ */
+void
+recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
diff --git a/src/messenger/gnunet-service-messenger_message_send.c b/src/messenger/gnunet-service-messenger_message_send.c
new file mode 100644
index 000000000..86cf9b888
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_send.c
@@ -0,0 +1,118 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_send.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_message_send.h"
+#include "gnunet-service-messenger_message_handle.h"
+
+void
+send_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ if (!tunnel->contact_id)
+ {
+ tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
+
+ GNUNET_memcpy(tunnel->contact_id, &(message->body.info.unique_id), sizeof(struct GNUNET_ShortHashCode));
+ }
+ else
+ {
+ disconnect_tunnel (tunnel);
+ }
+}
+
+void
+send_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ handle_message_join (room, tunnel, message, hash);
+
+ if (room->peer_message)
+ {
+ const struct GNUNET_MESSENGER_Message *peer_message = get_room_message (room, handle, room->peer_message,
+ GNUNET_NO);
+
+ if ((peer_message) && (tunnel))
+ {
+ forward_tunnel_message (tunnel, peer_message, room->peer_message);
+ }
+ }
+}
+
+void
+send_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ handle_message_leave (room, tunnel, message, hash);
+}
+
+void
+send_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ handle_message_name (room, tunnel, message, hash);
+}
+
+void
+send_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ handle_message_key (room, tunnel, message, hash);
+}
+
+void
+send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ if (!room->peer_message)
+ {
+ room->peer_message = GNUNET_new(struct GNUNET_HashCode);
+ }
+
+ GNUNET_memcpy(room->peer_message, hash, sizeof(struct GNUNET_HashCode));
+
+ handle_message_peer (room, tunnel, message, hash);
+}
+
+void
+send_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ handle_message_id (room, tunnel, message, hash);
+}
+
+void
+send_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ handle_message_miss (room, tunnel, message, hash);
+}
diff --git a/src/messenger/gnunet-service-messenger_message_send.h b/src/messenger/gnunet-service-messenger_message_send.h
new file mode 100644
index 000000000..c1096205a
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_send.h
@@ -0,0 +1,155 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_send.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
+#define GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+
+#include "gnunet-service-messenger_tunnel.h"
+#include "messenger_api_message.h"
+
+/**
+ * Handles a sent info message to setup a tunnels linked member id.
+ * (if a tunnel has already got a member id linked to it, the connection will be closed)
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message INFO-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a sent join message to ensure growth of the decentralized room structure.
+ * (if the service provides a peer message for this room currently, it will be forwarded)
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message JOIN-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a sent leave message.
+ * @see handle_message_leave()
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message LEAVE-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a sent name message.
+ * @see handle_message_name()
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message NAME-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a sent key message.
+ * @see handle_message_key()
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message KEY-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a sent peer message to update the rooms peer message of this service.
+ * (a set peer message indicates this service being a part of the decentralized room structure)
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message PEER-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a sent id message.
+ * @see handle_message_id()
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message ID-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a sent miss message.
+ * @see handle_message_miss()
+ *
+ * @param room Room of the message
+ * @param handle Sending handle
+ * @param tunnel Sending connection (may be NULL)
+ * @param message MISS-Message
+ * @param hash Hash of the message
+ */
+void
+send_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
diff --git a/src/messenger/gnunet-service-messenger_message_store.c b/src/messenger/gnunet-service-messenger_message_store.c
new file mode 100644
index 000000000..5933d6390
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_store.c
@@ -0,0 +1,282 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_store.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_message_store.h"
+#include "messenger_api_message.h"
+
+void
+init_message_store (struct GNUNET_MESSENGER_MessageStore *store)
+{
+ store->storage_messages = NULL;
+
+ store->entries = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+ store->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+}
+
+static int
+iterate_destroy_entries (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_MessageEntry *entry = value;
+
+ GNUNET_free(entry);
+
+ return GNUNET_YES;
+}
+
+static int
+iterate_destroy_messages (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_Message *message = value;
+
+ destroy_message (message);
+
+ return GNUNET_YES;
+}
+
+void
+clear_message_store (struct GNUNET_MESSENGER_MessageStore *store)
+{
+ if (store->storage_messages)
+ {
+ GNUNET_DISK_file_close (store->storage_messages);
+
+ store->storage_messages = NULL;
+ }
+
+ GNUNET_CONTAINER_multihashmap_iterate (store->entries, iterate_destroy_entries, NULL);
+ GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_destroy_messages, NULL);
+
+ GNUNET_CONTAINER_multihashmap_destroy (store->entries);
+ GNUNET_CONTAINER_multihashmap_destroy (store->messages);
+}
+
+struct GNUNET_MESSENGER_MessageEntryStorage
+{
+ struct GNUNET_HashCode hash;
+ struct GNUNET_MESSENGER_MessageEntry entry;
+};
+
+void
+load_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
+{
+ enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
+
+ if (store->storage_messages)
+ GNUNET_DISK_file_close (store->storage_messages);
+
+ char *filename;
+ GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
+
+ if (GNUNET_YES == GNUNET_DISK_file_test (filename))
+ store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
+ else
+ store->storage_messages = NULL;
+
+ GNUNET_free(filename);
+
+ if (!store->storage_messages)
+ return;
+
+ GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
+
+ if (GNUNET_YES != GNUNET_DISK_file_test (filename))
+ goto free_filename;
+
+ struct GNUNET_DISK_FileHandle *entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
+
+ if (!entries)
+ goto free_filename;
+
+ struct GNUNET_MESSENGER_MessageEntryStorage storage;
+ struct GNUNET_MESSENGER_MessageEntry *entry;
+
+ do
+ {
+ entry = GNUNET_new(struct GNUNET_MESSENGER_MessageEntry);
+
+ if (GNUNET_DISK_file_read (entries, &storage, sizeof(storage)) == sizeof(storage))
+ {
+ GNUNET_memcpy(entry, &(storage.entry), sizeof(*entry));
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->entries, &(storage.hash), entry,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ GNUNET_free(entry);
+ }
+ else
+ {
+ GNUNET_free(entry);
+
+ entry = NULL;
+ }
+ }
+ while (entry);
+
+ GNUNET_DISK_file_close (entries);
+
+free_filename:
+ GNUNET_free(filename);
+}
+
+struct GNUNET_MESSENGER_MessageSave
+{
+ struct GNUNET_MESSENGER_MessageStore *store;
+
+ struct GNUNET_DISK_FileHandle *storage_entries;
+};
+
+static int
+iterate_save_messages (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_MessageSave *save = cls;
+
+ if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (save->store->entries, key))
+ return GNUNET_YES;
+
+ struct GNUNET_MESSENGER_Message *message = value;
+ struct GNUNET_MESSENGER_MessageEntryStorage storage;
+
+ GNUNET_memcpy(&(storage.hash), key, sizeof(storage.hash));
+
+ storage.entry.length = get_message_size (message);
+ storage.entry.offset = GNUNET_DISK_file_seek (save->store->storage_messages, 0, GNUNET_DISK_SEEK_END);
+
+ if ((GNUNET_SYSERR == storage.entry.offset) ||
+ (sizeof(storage) != GNUNET_DISK_file_write (save->storage_entries, &storage, sizeof(storage))))
+ return GNUNET_YES;
+
+ char *buffer = GNUNET_malloc(storage.entry.length);
+
+ encode_message (message, storage.entry.length, buffer);
+
+ GNUNET_DISK_file_write (save->store->storage_messages, buffer, storage.entry.length);
+
+ GNUNET_free(buffer);
+
+ return GNUNET_YES;
+}
+
+void
+save_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
+{
+ struct GNUNET_MESSENGER_MessageSave save;
+
+ enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
+
+ char *filename;
+ GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
+
+ save.store = store;
+ save.storage_entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE, permission);
+
+ GNUNET_free(filename);
+
+ if (!save.storage_entries)
+ return;
+
+ if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage_entries, 0, GNUNET_DISK_SEEK_END))
+ goto close_entries;
+
+ if (store->storage_messages)
+ GNUNET_DISK_file_close (store->storage_messages);
+
+ GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
+
+ store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE,
+ permission);
+
+ GNUNET_free(filename);
+
+ if (store->storage_messages)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_save_messages, &save);
+
+ GNUNET_DISK_file_sync (store->storage_messages);
+ GNUNET_DISK_file_sync (save.storage_entries);
+ }
+
+close_entries:
+ GNUNET_DISK_file_close (save.storage_entries);
+}
+
+int
+contains_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
+{
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->messages, hash))
+ return GNUNET_YES;
+
+ return GNUNET_CONTAINER_multihashmap_contains (store->entries, hash);
+}
+
+const struct GNUNET_MESSENGER_Message*
+get_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Message *message = GNUNET_CONTAINER_multihashmap_get (store->messages, hash);
+
+ if (message)
+ return message;
+
+ if (!store->storage_messages)
+ return NULL;
+
+ const struct GNUNET_MESSENGER_MessageEntry *entry = GNUNET_CONTAINER_multihashmap_get (store->entries, hash);
+
+ if (!entry)
+ return NULL;
+
+ if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages, entry->offset, GNUNET_DISK_SEEK_SET))
+ return message;
+
+ char *buffer = GNUNET_malloc(entry->length);
+
+ if (GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) != entry->length)
+ goto free_buffer;
+
+
+ message = create_message (GNUNET_MESSENGER_KIND_UNKNOWN);
+
+ if ((GNUNET_YES != decode_message (message, entry->length, buffer)) || (GNUNET_OK
+ != GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
+ {
+ destroy_message (message);
+
+ message = NULL;
+
+ GNUNET_CONTAINER_multihashmap_remove (store->entries, hash, entry);
+ }
+
+free_buffer:
+ GNUNET_free(buffer);
+
+ return message;
+}
+
+int
+put_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash,
+ struct GNUNET_MESSENGER_Message *message)
+{
+ return GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+}
diff --git a/src/messenger/gnunet-service-messenger_message_store.h b/src/messenger/gnunet-service-messenger_message_store.h
new file mode 100644
index 000000000..e58459b21
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_store.h
@@ -0,0 +1,120 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_message_store.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
+#define GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
+
+#include "platform.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_disk_lib.h"
+
+struct GNUNET_MESSENGER_MessageEntry
+{
+ off_t offset;
+ uint16_t length;
+};
+
+struct GNUNET_MESSENGER_MessageStore
+{
+ struct GNUNET_DISK_FileHandle *storage_messages;
+
+ struct GNUNET_CONTAINER_MultiHashMap *entries;
+ struct GNUNET_CONTAINER_MultiHashMap *messages;
+};
+
+/**
+ * Initializes a message store as fully empty.
+ *
+ * @param store Message store
+ */
+void
+init_message_store (struct GNUNET_MESSENGER_MessageStore *store);
+
+/**
+ * Clears a message store, wipes its content and deallocates its memory.
+ *
+ * @param store Message store
+ */
+void
+clear_message_store (struct GNUNET_MESSENGER_MessageStore *store);
+
+/**
+ * Loads messages from a directory into a message store.
+ *
+ * @param store Message store
+ * @param directory Path to a directory
+ */
+void
+load_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory);
+
+/**
+ * Saves messages from a message store into a directory.
+ *
+ * @param store Message store
+ * @param directory Path to a directory
+ */
+void
+save_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory);
+
+/**
+ * Checks if a message matching a given <i>hash</i> is stored in a message store. The function returns
+ * GNUNET_YES if a match is found, GNUNET_NO otherwise.
+ *
+ * The message has not to be loaded from disk into memory for this check!
+ *
+ * @param store Message store
+ * @param hash Hash of message
+ * @return GNUNET_YES on match, otherwise GNUNET_NO
+ */
+int
+contains_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash);
+
+/**
+ * Returns the message from a message store matching a given <i>hash</i>. If no matching message is found,
+ * NULL gets returned.
+ *
+ * This function requires the message to be loaded into memory!
+ * @see contains_store_message()
+ *
+ * @param store Message store
+ * @param hash Hash of message
+ * @return Message or NULL
+ */
+const struct GNUNET_MESSENGER_Message*
+get_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash);
+
+/**
+ * Stores a message into the message store. The result indicates if the operation was successful.
+ *
+ * @param store Message store
+ * @param hash Hash of message
+ * @param message Message
+ * @return GNUNET_OK on success, otherwise GNUNET_NO
+ */
+int
+put_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash,
+ struct GNUNET_MESSENGER_Message *message);
+
+#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
diff --git a/src/messenger/gnunet-service-messenger_room.c b/src/messenger/gnunet-service-messenger_room.c
new file mode 100644
index 000000000..7383e1d20
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_room.c
@@ -0,0 +1,1051 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_room.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_room.h"
+
+#include "gnunet-service-messenger_message_kind.h"
+
+#include "gnunet-service-messenger_service.h"
+#include "gnunet-service-messenger_util.h"
+
+static void
+idle_request_room_messages (void *cls);
+
+struct GNUNET_MESSENGER_SrvRoom*
+create_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
+{
+ GNUNET_assert((handle) && (key));
+
+ struct GNUNET_MESSENGER_SrvRoom *room = GNUNET_new(struct GNUNET_MESSENGER_SrvRoom);
+
+ room->service = handle->service;
+ room->host = handle;
+ room->port = NULL;
+
+ GNUNET_memcpy(&(room->key), key, sizeof(struct GNUNET_HashCode));
+
+ room->tunnels = GNUNET_CONTAINER_multipeermap_create (8, GNUNET_NO);
+ room->members = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
+ room->member_infos = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
+
+ init_message_store (&(room->store));
+ room->requested = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+
+ init_list_tunnels (&(room->basement));
+ init_list_messages (&(room->last_messages));
+
+ room->peer_message = NULL;
+
+ init_list_messages (&(room->handling));
+ room->idle = NULL;
+
+ room->strict_access = GNUNET_NO;
+
+ if (room->service->dir)
+ load_service_room_and_messages (room->service, room);
+
+ room->idle = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, idle_request_room_messages, room);
+
+ return room;
+}
+
+static int
+iterate_destroy_tunnels (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
+ destroy_tunnel (tunnel);
+ return GNUNET_YES;
+}
+
+static int
+iterate_clear_members (void *cls, const struct GNUNET_ShortHashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = value;
+
+ if (GNUNET_YES == decrease_contact_rc (contact))
+ {
+ struct GNUNET_MESSENGER_SrvRoom *room = cls;
+
+ const struct GNUNET_HashCode *id = get_contact_id_from_key (contact);
+
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (room->service->contacts, id, contact))
+ destroy_contact (contact);
+ }
+
+ return GNUNET_YES;
+}
+
+static int
+iterate_destroy_member_infos (void *cls, const struct GNUNET_ShortHashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_MemberInfo *info = value;
+
+ clear_list_messages (&(info->session_messages));
+
+ GNUNET_free(info);
+ return GNUNET_YES;
+}
+
+void
+destroy_room (struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ GNUNET_assert(room);
+
+ if (room->idle)
+ {
+ GNUNET_SCHEDULER_cancel (room->idle);
+
+ room->idle = NULL;
+ }
+
+ if (room->port)
+ GNUNET_CADET_close_port (room->port);
+
+ merge_room_last_messages (room, room->host);
+
+ GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_destroy_tunnels,
+ NULL);
+
+ handle_room_messages (room);
+
+ if (room->service->dir)
+ save_service_room_and_messages (room->service, room);
+
+ GNUNET_CONTAINER_multishortmap_iterate (room->members, iterate_clear_members, room);
+ GNUNET_CONTAINER_multishortmap_iterate (room->member_infos, iterate_destroy_member_infos, NULL);
+
+ clear_message_store (&(room->store));
+
+ GNUNET_CONTAINER_multihashmap_destroy (room->requested);
+
+ GNUNET_CONTAINER_multipeermap_destroy (room->tunnels);
+ GNUNET_CONTAINER_multishortmap_destroy (room->members);
+ GNUNET_CONTAINER_multishortmap_destroy (room->member_infos);
+
+ clear_list_tunnels (&(room->basement));
+ clear_list_messages (&(room->last_messages));
+
+ if (room->peer_message)
+ GNUNET_free(room->peer_message);
+
+ GNUNET_free(room);
+}
+
+struct GNUNET_MESSENGER_SrvContact*
+get_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id)
+{
+ GNUNET_assert((room) && (room->members));
+
+ return GNUNET_CONTAINER_multishortmap_get (room->members, id);
+}
+
+void
+add_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = get_service_contact_by_pubkey (room->service, pubkey);
+
+ if (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put (room->members, id, contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ increase_contact_rc (contact);
+}
+
+struct GNUNET_MESSENGER_MemberInfo*
+get_room_member_info (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id)
+{
+ GNUNET_assert((room) && (room->member_infos));
+
+ return GNUNET_CONTAINER_multishortmap_get (room->member_infos, id);
+}
+
+struct GNUNET_ShortHashCode*
+generate_room_member_id (const struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ struct GNUNET_ShortHashCode *unique_id = GNUNET_new(struct GNUNET_ShortHashCode);
+
+ GNUNET_assert(room);
+
+ if (GNUNET_YES == generate_free_member_id (unique_id, room->members))
+ return unique_id;
+ else
+ {
+ GNUNET_free(unique_id);
+ return NULL;
+ }
+}
+
+const struct GNUNET_ShortHashCode*
+get_room_host_id (const struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ GNUNET_assert(room);
+
+ return get_handle_member_id (room->host, &(room->key));
+}
+
+void
+change_room_host_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *unique_id)
+{
+ GNUNET_assert(room);
+
+ change_handle_member_id (room->host, &(room->key), unique_id);
+}
+
+static int
+send_room_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel)
+{
+ if (!handle)
+ return GNUNET_NO;
+
+ merge_room_last_messages (room, handle);
+
+ if (!is_tunnel_connected (tunnel))
+ return GNUNET_NO;
+
+ struct GNUNET_MESSENGER_Message *message = create_message_info (get_handle_ego(handle), room->members);
+
+ if (!message)
+ return GNUNET_NO;
+
+ if ((tunnel->peer_message) && (tunnel->contact_id))
+ {
+ GNUNET_memcpy(&(message->body.info.unique_id), &(tunnel->contact_id), sizeof(struct GNUNET_ShortHashCode));
+ GNUNET_free(tunnel->contact_id);
+
+ tunnel->contact_id = NULL;
+ }
+
+ struct GNUNET_HashCode hash;
+
+ send_tunnel_message (tunnel, handle, message, &hash);
+ destroy_message (message);
+
+ if (tunnel->contact_id)
+ {
+ GNUNET_free(tunnel->contact_id);
+
+ tunnel->contact_id = NULL;
+ }
+
+ return GNUNET_YES;
+}
+
+static void*
+callback_room_connect (void *cls, struct GNUNET_CADET_Channel *channel, const struct GNUNET_PeerIdentity *source)
+{
+ struct GNUNET_MESSENGER_SrvRoom *room = cls;
+
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, source);
+
+ if (tunnel)
+ {
+ if (GNUNET_YES == bind_tunnel (tunnel, channel))
+ {
+ if (GNUNET_YES == send_room_info (room, room->host, tunnel))
+ return tunnel;
+ else
+ {
+ disconnect_tunnel (tunnel);
+ return NULL;
+ }
+ }
+ else
+ {
+ delayed_disconnect_channel (channel);
+ return NULL;
+ }
+ }
+ else
+ {
+ tunnel = create_tunnel (room, source);
+
+ if ((GNUNET_YES == bind_tunnel (tunnel, channel)) && (GNUNET_OK
+ == GNUNET_CONTAINER_multipeermap_put (room->tunnels, source, tunnel,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
+ {
+ if (GNUNET_YES == send_room_info (room, room->host, tunnel))
+ return tunnel;
+ else
+ {
+ GNUNET_CONTAINER_multipeermap_remove (room->tunnels, source, tunnel);
+
+ disconnect_tunnel (tunnel);
+ destroy_tunnel (tunnel);
+ return NULL;
+ }
+ }
+ else
+ {
+ tunnel->channel = NULL;
+ destroy_tunnel (tunnel);
+
+ delayed_disconnect_channel (channel);
+ return NULL;
+ }
+ }
+}
+
+static int
+join_room (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_ShortHashCode *member_id)
+{
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Joining room: %s (%s)\n", GNUNET_h2s(get_room_key(room)), GNUNET_sh2s(member_id));
+
+ struct GNUNET_MESSENGER_Message *message = create_message_join (get_handle_ego(handle));
+
+ if (!message)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Your join message could not be created!\n");
+
+ return GNUNET_NO;
+ }
+
+ struct GNUNET_HashCode hash;
+
+ send_room_message (room, handle, message, &hash);
+ destroy_message (message);
+
+ struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_new(struct GNUNET_MESSENGER_MemberInfo);
+
+ info->access = GNUNET_MESSENGER_MEMBER_ALLOWED;
+ init_list_messages (&(info->session_messages));
+
+ if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_put (room->member_infos, member_id, info,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ change_handle_member_id (handle, &(room->key), member_id);
+
+ add_to_list_messages (&(info->session_messages), &hash);
+ return GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Your member information could not be registered!\n");
+
+ GNUNET_free(info);
+ return GNUNET_NO;
+ }
+}
+
+static int
+join_room_locally (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ const struct GNUNET_ShortHashCode *member_id = get_handle_member_id (handle, &(room->key));
+
+ struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos, member_id);
+
+ if ((!info) && (GNUNET_NO == join_room (room, handle, member_id)))
+ return GNUNET_NO;
+
+ return GNUNET_YES;
+}
+
+extern int
+check_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header);
+extern void
+handle_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header);
+
+extern void
+callback_tunnel_disconnect (void *cls, const struct GNUNET_CADET_Channel *channel);
+
+int
+open_room (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ if (room->port)
+ return join_room_locally (room, handle);
+
+ struct GNUNET_CADET_Handle *cadet = get_room_cadet (room);
+ struct GNUNET_HashCode *key = get_room_key (room);
+
+ struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size(tunnel_message, GNUNET_MESSAGE_TYPE_CADET_CLI,
+ struct GNUNET_MessageHeader, NULL),
+ GNUNET_MQ_handler_end() };
+
+ room->port = GNUNET_CADET_open_port (cadet, key, callback_room_connect, room, NULL,
+ callback_tunnel_disconnect, handlers);
+
+ const struct GNUNET_ShortHashCode *member_id = get_handle_member_id (handle, &(room->key));
+
+ struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos, member_id);
+
+ if ((!info) && (GNUNET_NO == join_room (room, handle, member_id)) && (room->port))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not join the room, therefore it keeps closed!\n");
+
+ GNUNET_CADET_close_port (room->port);
+ room->port = NULL;
+
+ return GNUNET_NO;
+ }
+
+ struct GNUNET_MESSENGER_Message *message = create_message_peer (room->service);
+
+ if (message)
+ {
+ struct GNUNET_HashCode hash;
+
+ send_room_message (room, handle, message, &hash);
+ destroy_message (message);
+ }
+
+ return (room->port ? GNUNET_YES : GNUNET_NO);
+}
+
+int
+entry_room_at (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_PeerIdentity *door)
+{
+ if (room->peer_message)
+ {
+ const struct GNUNET_MESSENGER_Message *msg = get_room_message (room, handle, room->peer_message, GNUNET_NO);
+
+ if (0 == GNUNET_memcmp(&(msg->body.peer.peer), door))
+ return join_room_locally (room, handle);
+ }
+
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, door);
+
+ if (tunnel)
+ {
+ switch (connect_tunnel (tunnel))
+ {
+ case GNUNET_YES:
+ return GNUNET_YES;
+ case GNUNET_NO:
+ return join_room_locally (room, handle);
+ default:
+ return GNUNET_NO;
+ }
+ }
+
+ tunnel = create_tunnel (room, door);
+
+ if ((GNUNET_YES == connect_tunnel (tunnel)) &&
+ (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (room->tunnels, door, tunnel,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
+ return GNUNET_YES;
+ else
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not connect to that door!\n");
+
+ destroy_tunnel (tunnel);
+ return GNUNET_NO;
+ }
+}
+
+struct GNUNET_MESSENGER_SrvTunnelFinder
+{
+ const struct GNUNET_ShortHashCode *needle;
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel;
+};
+
+static int
+iterate_find_tunnel (void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
+ struct GNUNET_MESSENGER_SrvTunnelFinder *finder = cls;
+
+ if ((tunnel->contact_id) && (0 == GNUNET_memcmp(tunnel->contact_id, finder->needle)))
+ {
+ finder->tunnel = tunnel;
+ return GNUNET_NO;
+ }
+
+ return GNUNET_YES;
+}
+
+struct GNUNET_MESSENGER_SrvTunnel*
+find_room_tunnel_to (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *contact_id)
+{
+ struct GNUNET_MESSENGER_SrvTunnelFinder finder;
+
+ finder.needle = contact_id;
+ finder.tunnel = NULL;
+
+ GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_find_tunnel, &finder);
+
+ return finder.tunnel;
+}
+
+struct GNUNET_MQ_Envelope*
+pack_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash, int mode)
+{
+ message->header.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+
+ const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, &(room->key));
+
+ GNUNET_assert(id);
+
+ GNUNET_memcpy(&(message->header.sender_id), id, sizeof(struct GNUNET_ShortHashCode));
+
+ if (room->last_messages.head)
+ GNUNET_memcpy(&(message->header.previous), &(room->last_messages.head->hash), sizeof(struct GNUNET_HashCode));
+ else
+ memset (&(message->header.previous), 0, sizeof(struct GNUNET_HashCode));
+
+ return pack_message (message, hash, get_handle_ego (handle), mode);
+}
+
+struct GNUNET_MESSENGER_ClosureSendRoom
+{
+ struct GNUNET_MESSENGER_SrvRoom *room;
+ struct GNUNET_MESSENGER_SrvHandle *handle;
+ struct GNUNET_MESSENGER_SrvTunnel *exclude;
+ struct GNUNET_MESSENGER_Message *message;
+ struct GNUNET_HashCode *hash;
+ int packed;
+};
+
+static int
+iterate_send_room_message (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
+
+ if ((!is_tunnel_connected (tunnel)) || (!tunnel->contact_id))
+ return GNUNET_YES;
+
+ struct GNUNET_MESSENGER_ClosureSendRoom *closure = cls;
+
+ if (tunnel == closure->exclude)
+ return GNUNET_YES;
+
+ struct GNUNET_MQ_Envelope *env = NULL;
+
+ if (closure->packed == GNUNET_NO)
+ {
+ env = pack_room_message (closure->room, closure->handle, closure->message, closure->hash,
+ GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
+
+ if (env)
+ {
+ closure->message = copy_message (closure->message);
+ closure->packed = GNUNET_YES;
+ }
+ }
+ else
+ {
+ env = pack_message (closure->message, NULL, NULL,
+ GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
+ }
+
+ if (env)
+ send_tunnel_envelope (tunnel, closure->handle, env, closure->message, closure->hash);
+
+ return GNUNET_YES;
+}
+
+void
+callback_room_sent (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle, void *cls,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+void
+send_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_ClosureSendRoom closure;
+
+ closure.room = room;
+ closure.handle = handle;
+ closure.exclude = NULL;
+ closure.message = message;
+ closure.hash = hash;
+ closure.packed = GNUNET_NO;
+
+ GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
+
+ if ((GNUNET_NO == closure.packed) && (closure.message == message))
+ {
+ pack_room_message (room, handle, message, hash,
+ GNUNET_MESSENGER_PACK_MODE_UNKNOWN);
+
+ callback_room_sent (room, handle, NULL, copy_message (message), hash);
+ }
+}
+
+void
+send_room_message_ext (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel)
+{
+ struct GNUNET_MESSENGER_ClosureSendRoom closure;
+
+ closure.room = room;
+ closure.handle = handle;
+ closure.exclude = tunnel;
+ closure.message = message;
+ closure.hash = hash;
+ closure.packed = GNUNET_NO;
+
+ GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
+
+ if ((GNUNET_NO == closure.packed) && (closure.message == message))
+ {
+ pack_room_message (room, handle, message, hash,
+ GNUNET_MESSENGER_PACK_MODE_UNKNOWN);
+
+ callback_room_sent (room, handle, NULL, copy_message (message), hash);
+ }
+}
+
+void
+forward_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_ClosureSendRoom closure;
+ struct GNUNET_HashCode message_hash;
+
+ GNUNET_memcpy(&message_hash, hash, sizeof(struct GNUNET_HashCode));
+
+ closure.room = room;
+ closure.handle = NULL;
+ closure.exclude = tunnel;
+ closure.message = copy_message (message);
+ closure.hash = &message_hash;
+ closure.packed = GNUNET_YES;
+
+ GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
+}
+
+void
+merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ if (!handle)
+ return;
+
+ if (!room->last_messages.head)
+ return;
+
+ while (room->last_messages.head != room->last_messages.tail)
+ {
+ struct GNUNET_MESSENGER_ListMessage *element = room->last_messages.tail;
+
+ struct GNUNET_MESSENGER_Message *message = create_message_merge (&(element->hash));
+
+ if (message)
+ {
+ struct GNUNET_HashCode hash;
+
+ send_room_message (room, handle, message, &hash);
+ destroy_message (message);
+ }
+
+ if (element->prev)
+ GNUNET_CONTAINER_DLL_remove(room->last_messages.head, room->last_messages.tail, element);
+ }
+}
+
+struct GNUNET_CADET_Handle*
+get_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ return room->service->cadet;
+}
+
+struct GNUNET_HashCode*
+get_room_key (struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ return &(room->key);
+}
+
+const struct GNUNET_MESSENGER_SrvTunnel*
+get_room_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *peer)
+{
+ return GNUNET_CONTAINER_multipeermap_get (room->tunnels, peer);
+}
+
+const struct GNUNET_MESSENGER_Message*
+get_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_HashCode *hash, int request)
+{
+ const struct GNUNET_MESSENGER_Message *message = get_store_message (&(room->store), hash);
+
+ if ((message) || (!handle) || (GNUNET_YES != request)
+ || (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (room->requested, hash)))
+ return message;
+
+ struct GNUNET_MESSENGER_Message *request_msg = create_message_request (hash);
+
+ if (request_msg)
+ {
+ if (GNUNET_CONTAINER_multihashmap_put (room->requested, hash, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST) == GNUNET_OK)
+ {
+ struct GNUNET_HashCode request_hash;
+
+ send_room_message (room, handle, request_msg, &request_hash);
+ }
+
+ destroy_message (request_msg);
+ }
+
+ return message;
+}
+
+void
+callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room, void *cls)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
+
+ if (!room->host)
+ return;
+
+ struct GNUNET_PeerIdentity identity;
+
+ GNUNET_PEER_resolve (tunnel->peer, &identity);
+
+ if (GNUNET_YES == contains_list_tunnels (&(room->basement), &identity))
+ {
+ struct GNUNET_MESSENGER_Message *message = create_message_miss (&identity);
+
+ if (message)
+ {
+ struct GNUNET_HashCode hash;
+
+ send_room_message (room, room->host, message, &hash);
+ destroy_message (message);
+ }
+ }
+}
+
+int
+callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room, void *cls,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash)
+{
+ if (GNUNET_MESSENGER_KIND_UNKNOWN == message->header.kind)
+ return GNUNET_SYSERR;
+
+ struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
+ &(message->header.sender_id));
+
+ if (!contact)
+ {
+ if (GNUNET_MESSENGER_KIND_INFO == message->header.kind)
+ contact = get_service_contact_by_pubkey (room->service, &(message->body.info.host_key));
+ else if (GNUNET_MESSENGER_KIND_JOIN == message->header.kind)
+ contact = get_service_contact_by_pubkey (room->service, &(message->body.join.key));
+ }
+
+ if ((!contact) || (GNUNET_SYSERR == verify_message (message, hash, get_contact_key (contact))))
+ return GNUNET_SYSERR;
+
+ if (GNUNET_YES == room->strict_access)
+ {
+ struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos,
+ &(message->header.sender_id));
+
+ if ((info) && (GNUNET_MESSENGER_MEMBER_BLOCKED == info->access))
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_YES == contains_store_message (&(room->store), hash))
+ return GNUNET_NO;
+
+ return GNUNET_YES;
+}
+
+static void
+search_room_for_message (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash)
+{
+ const struct GNUNET_MESSENGER_Message *message = get_room_message (room, room->host, hash, GNUNET_YES);
+
+ if (!message)
+ return;
+
+ if (GNUNET_MESSENGER_KIND_MERGE == message->header.kind)
+ search_room_for_message (room, &(message->body.merge.previous));
+
+ search_room_for_message (room, &(message->header.previous));
+}
+
+static void
+idle_request_room_messages (void *cls)
+{
+ struct GNUNET_MESSENGER_SrvRoom *room = cls;
+
+ room->idle = NULL;
+
+ struct GNUNET_MESSENGER_ListMessage *element = room->last_messages.head;
+
+ while (element)
+ {
+ search_room_for_message (room, &(element->hash));
+
+ element = element->next;
+ }
+
+ merge_room_last_messages (room, room->host);
+
+ room->idle = GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_get_second_ (),
+ GNUNET_SCHEDULER_PRIORITY_IDLE, idle_request_room_messages,
+ cls);
+}
+
+void
+update_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_ListMessage *element = room->last_messages.head;
+ struct GNUNET_MESSENGER_ListMessage *merging = NULL;
+
+ if (GNUNET_MESSENGER_KIND_MERGE == message->header.kind)
+ {
+ merging = room->last_messages.head;
+
+ while (merging)
+ {
+ if (0 == GNUNET_CRYPTO_hash_cmp (&(merging->hash), &(message->body.merge.previous)))
+ break;
+
+ merging = merging->next;
+ }
+
+ if (merging)
+ element = merging->next;
+ }
+
+ while (element)
+ {
+ if (0 == GNUNET_CRYPTO_hash_cmp (&(element->hash), &(message->header.previous)))
+ break;
+
+ element = element->next;
+ }
+
+ if ((merging) && (!element))
+ {
+ element = merging;
+ merging = NULL;
+ }
+
+ if (element)
+ {
+ GNUNET_memcpy(&(element->hash), hash, sizeof(struct GNUNET_HashCode));
+
+ if (merging)
+ GNUNET_CONTAINER_DLL_remove(room->last_messages.head, room->last_messages.tail, merging);
+ }
+ else
+ add_to_list_messages (&(room->last_messages), hash);
+
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (room->requested, hash))
+ GNUNET_CONTAINER_multihashmap_remove_all (room->requested, hash);
+}
+
+void
+switch_room_member_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *old_id,
+ const struct GNUNET_ShortHashCode *new_id, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multishortmap_get (room->members, old_id);
+
+ if ((contact) && (GNUNET_YES == GNUNET_CONTAINER_multishortmap_remove (room->members, old_id, contact)))
+ GNUNET_CONTAINER_multishortmap_put (room->members, new_id, contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+
+ struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos, old_id);
+
+ if ((!info) || (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->member_infos, old_id, contact))
+ || (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (room->member_infos, new_id, contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
+ return;
+
+ if (hash)
+ add_to_list_messages (&(info->session_messages), hash);
+}
+
+void
+rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ struct GNUNET_PeerIdentity peer;
+ size_t src;
+
+ if ((GNUNET_OK != get_service_peer_identity (room->service, &peer)) || (!find_list_tunnels (&(room->basement), &peer,
+ &src)))
+ return;
+
+ size_t count = count_of_tunnels (&(room->basement));
+
+ struct GNUNET_MESSENGER_ListTunnel *element = room->basement.head;
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel;
+
+ size_t dst = 0;
+
+ while (element)
+ {
+ GNUNET_PEER_resolve (element->peer, &peer);
+
+ tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, &peer);
+
+ if (!tunnel)
+ {
+ element = remove_from_list_tunnels (&(room->basement), element);
+ continue;
+ }
+
+ if (GNUNET_YES == required_connection_between (count, src, dst))
+ {
+ if (GNUNET_SYSERR == connect_tunnel (tunnel))
+ {
+ element = remove_from_list_tunnels (&(room->basement), element);
+ continue;
+ }
+ }
+ else
+ disconnect_tunnel (tunnel);
+
+ element = element->next;
+ dst++;
+ }
+}
+
+void
+handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ while (room->handling.head)
+ {
+ struct GNUNET_MESSENGER_ListMessage *element = room->handling.head;
+
+ const struct GNUNET_MESSENGER_Message *msg = get_room_message (room, room->host, &(element->hash), GNUNET_NO);
+
+ if (msg)
+ handle_service_message (room->service, room, msg, &(element->hash));
+
+ GNUNET_CONTAINER_DLL_remove(room->handling.head, room->handling.tail, element);
+ GNUNET_free(element);
+ }
+}
+
+#include "gnunet-service-messenger_message_recv.h"
+
+void
+callback_room_recv (struct GNUNET_MESSENGER_SrvRoom *room, void *cls, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
+
+ if (GNUNET_OK != put_store_message (&(room->store), hash, message))
+ return;
+
+ update_room_last_messages (room, message, hash);
+
+ if (GNUNET_MESSENGER_KIND_INFO != message->header.kind)
+ forward_room_message (room, tunnel, message, hash);
+
+ const int start_handle = room->handling.head ? GNUNET_NO : GNUNET_YES;
+
+ add_to_list_messages (&(room->handling), hash);
+
+ switch (message->header.kind)
+ {
+ case GNUNET_MESSENGER_KIND_INFO:
+ recv_message_info (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_JOIN:
+ recv_message_join (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ recv_message_leave (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_NAME:
+ recv_message_name (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_KEY:
+ recv_message_key (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_PEER:
+ recv_message_peer (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_ID:
+ recv_message_id (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_MISS:
+ recv_message_miss (room, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_REQUEST:
+ recv_message_request (room, tunnel, message, hash);
+ break;
+ default:
+ break;
+ }
+
+ if (GNUNET_YES == start_handle)
+ handle_room_messages (room);
+}
+
+#include "gnunet-service-messenger_message_send.h"
+
+void
+callback_room_sent (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle, void *cls,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ const struct GNUNET_MESSENGER_Message *old_message = get_room_message (room, handle, hash, GNUNET_NO);
+
+ if ((old_message) || (GNUNET_OK != put_store_message (&(room->store), hash, message)))
+ {
+ if (old_message != message)
+ GNUNET_free(message);
+ }
+ else
+ {
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls; // may be NULL
+
+ update_room_last_messages (room, message, hash);
+
+ const int start_handle = room->handling.head ? GNUNET_NO : GNUNET_YES;
+
+ add_to_list_messages (&(room->handling), hash);
+
+ switch (message->header.kind)
+ {
+ case GNUNET_MESSENGER_KIND_INFO:
+ send_message_info (room, handle, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_JOIN:
+ send_message_join (room, handle, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ send_message_leave (room, handle, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_NAME:
+ send_message_name (room, handle, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_KEY:
+ send_message_key (room, handle, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_PEER:
+ send_message_peer (room, handle, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_ID:
+ send_message_id (room, handle, tunnel, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_MISS:
+ send_message_miss (room, handle, tunnel, message, hash);
+ break;
+ default:
+ break;
+ }
+
+ if (GNUNET_YES == start_handle)
+ handle_room_messages (room);
+ }
+}
diff --git a/src/messenger/gnunet-service-messenger_room.h b/src/messenger/gnunet-service-messenger_room.h
new file mode 100644
index 000000000..36c9e8cf5
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_room.h
@@ -0,0 +1,378 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_room.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_ROOM_H
+#define GNUNET_SERVICE_MESSENGER_ROOM_H
+
+#include "platform.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_mq_lib.h"
+
+#include "gnunet-service-messenger_contact.h"
+
+#include "gnunet_messenger_service.h"
+#include "gnunet-service-messenger_basement.h"
+#include "gnunet-service-messenger_handle.h"
+#include "gnunet-service-messenger_tunnel.h"
+
+#include "gnunet-service-messenger_list_messages.h"
+#include "messenger_api_list_tunnels.h"
+
+#include "gnunet-service-messenger_message_store.h"
+#include "messenger_api_ego.h"
+
+enum GNUNET_MESSENGER_MemberAccess
+{
+ GNUNET_MESSENGER_MEMBER_ALLOWED = 1,
+ GNUNET_MESSENGER_MEMBER_BLOCKED = 1,
+
+ GNUNET_MESSENGER_MEMBER_UNKNOWN = 0
+};
+
+struct GNUNET_MESSENGER_MemberInfo
+{
+ enum GNUNET_MESSENGER_MemberAccess access;
+
+ struct GNUNET_MESSENGER_ListMessages session_messages;
+};
+
+struct GNUNET_MESSENGER_SrvRoom
+{
+ struct GNUNET_MESSENGER_Service *service;
+ struct GNUNET_MESSENGER_SrvHandle *host;
+ struct GNUNET_CADET_Port *port;
+
+ struct GNUNET_HashCode key;
+
+ struct GNUNET_CONTAINER_MultiPeerMap *tunnels;
+ struct GNUNET_CONTAINER_MultiShortmap *members;
+ struct GNUNET_CONTAINER_MultiShortmap *member_infos;
+
+ struct GNUNET_MESSENGER_MessageStore store;
+ struct GNUNET_CONTAINER_MultiHashMap *requested;
+
+ struct GNUNET_MESSENGER_ListTunnels basement;
+ struct GNUNET_MESSENGER_ListMessages last_messages;
+
+ struct GNUNET_HashCode *peer_message;
+
+ struct GNUNET_MESSENGER_ListMessages handling;
+ struct GNUNET_SCHEDULER_Task *idle;
+
+ int strict_access;
+};
+
+/**
+ * Creates and allocates a new room for a <i>handle</i> with a given <i>key</i>.
+ *
+ * @param handle Handle
+ * @param key Key of room
+ * @return New room
+ */
+struct GNUNET_MESSENGER_SrvRoom*
+create_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
+
+/**
+ * Destroys a room and frees its memory fully.
+ *
+ * @param room Room
+ */
+void
+destroy_room (struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Returns the contact of a member in a <i>room</i> identified by a given <i>id</i>. If the <i>room</i>
+ * does not contain a member with the given <i>id</i>, NULL gets returned.
+ *
+ * @param room Room
+ * @param id Member id
+ * @return Contact or NULL
+ */
+struct GNUNET_MESSENGER_SrvContact*
+get_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id);
+
+/**
+ * Adds a contact from the service to a <i>room</i> under a specific <i>id</i> with a given public key.
+ *
+ * @param room Room
+ * @param id Member id
+ * @param pubkey Public key of EGO
+ */
+void
+add_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey);
+
+/**
+ * Returns the member information of a member in a <i>room</i> identified by a given <i>id</i>. If the <i>room</i>
+ * does not contain a member with the given <i>id</i>, NULL gets returned.
+ *
+ * @param room Room
+ * @param id Member id
+ * @return Member information or NULL
+ */
+struct GNUNET_MESSENGER_MemberInfo*
+get_room_member_info (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id);
+
+/**
+ * Tries to generate and allocate a new unique member id checking all current members for possible
+ * duplicates. If the function fails, NULL gets returned.
+ *
+ * @param room Room
+ * @return New member id or NULL
+ */
+struct GNUNET_ShortHashCode*
+generate_room_member_id (const struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Returns the member id of the member representing the handle currently hosting this <i>room</i>.
+ *
+ * @param room Room
+ * @return Host member id or NULL
+ */
+const struct GNUNET_ShortHashCode*
+get_room_host_id (const struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Changes the member id of the member representing the handle currently hosting this <i>room</i>.
+ *
+ * @param room Room
+ * @param unique_id Unique member id
+ */
+void
+change_room_host_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *unique_id);
+
+/**
+ * Tries to open a <i>room</i> for a given <i>handle</i>. If the room has already been opened, the handle
+ * will locally join the room.
+ *
+ * Calling this method should result in joining a room and sending a peer message as well for this peer.
+ *
+ * If the function returns GNUNET_YES the port for this room is guranteed to be open for incoming connections.
+ *
+ * @param room Room
+ * @param handle Handle
+ * @return GNUNET_YES on success, GNUNET_NO on failure.
+ */
+int
+open_room (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle);
+
+/**
+ * Connects a tunnel to a hosting peer of a <i>room</i> through a so called <i>door</i> which is represented by
+ * a peer identity of a hosting peer. During the connection the handle will join the room as a member, waiting for
+ * an info message from the selected host.
+ *
+ * @param room Room
+ * @param handle Handle
+ * @param door Peer identity
+ * @return GNUNET_YES on success, GNUNET_NO on failure.
+ */
+int
+entry_room_at (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_PeerIdentity *door);
+
+/**
+ * Returns a tunnel granting a direct connection to a specific member in a <i>room</i>. The member gets identified
+ * by an <i>id</i>. If no tunnel has been linked to the selected id, NULL gets returned.
+ *
+ * @param room Room
+ * @param contact_id Member id
+ * @return Tunnel to the member or NULL
+ */
+struct GNUNET_MESSENGER_SrvTunnel*
+find_room_tunnel_to (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *contact_id);
+
+/**
+ * Packs a <i>message</i> depending on the selected <i>mode</i> into a newly allocated envelope. It will set the
+ * timestamp of the message, the sender id and the previous messages hash automatically before packing. The message
+ * will be signed by the handles EGO.
+ *
+ * If the optional <i>hash</i> parameter is a valid pointer, its value will be overriden by the signed messages hash.
+ *
+ * If <i>mode</i> is set to GNUNET_MESSENGER_PACK_MODE_ENVELOPE, the function returns a valid envelope to send
+ * through a message queue, otherwise NULL.
+ *
+ * @param room Room
+ * @param handle Handle
+ * @param message Message
+ * @param[out] hash Hash of message
+ * @param mode Packing mode
+ * @return New envelope or NULL
+ */
+struct GNUNET_MQ_Envelope*
+pack_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash, int mode);
+
+/**
+ * Sends a <i>message</i> from a given <i>handle</i> into a <i>room</i>. The <i>hash</i> parameter will be
+ * updated with the hash-value resulting from the sent message.
+ *
+ * The function handles packing the message automatically and will call linked message-events locally even if
+ * the message won't be sent to another peer.
+ *
+ * @param room Room
+ * @param handle Handle
+ * @param message Message
+ * @param[out] hash Hash of message
+ */
+void
+send_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash);
+
+/**
+ * Sends a <i>message</i> from a given <i>handle</i> into a <i>room</i> excluding one specific <i>tunnel</i>.
+ * The <i>hash</i> parameter will be updated with the hash-value resulting from the sent message.
+ *
+ * The function handles packing the message automatically and will call linked message-events locally even if
+ * the message won't be sent to another peer.
+ *
+ * @param room Room
+ * @param handle Handle
+ * @param message Message
+ * @param[out] hash Hash of message
+ * @param tunnel Tunnel
+ */
+void
+send_room_message_ext (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel);
+
+/**
+ * Forwards a <i>message</i> with a given <i>hash</i> to a specific <i>tunnel</i> inside of a <i>room</i>.
+ *
+ * @param room Room
+ * @param tunnel Tunnel
+ * @param message Message
+ * @param hash Hash of message
+ */
+void
+forward_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Reduces all current forks inside of the message history of a <i>room</i> to one remaining last message
+ * by merging them down. All merge messages will be sent from a given <i>handle</i>.
+ *
+ * @param room Room
+ * @param handle Handle
+ */
+void
+merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle);
+
+/**
+ * Returns the CADET handle from a rooms service.
+ *
+ * @param room Room
+ * @return CADET handle
+ */
+struct GNUNET_CADET_Handle*
+get_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Returns the shared secret you need to access a <i>room</i>.
+ *
+ * @param room Room
+ * @return Shared secret
+ */
+struct GNUNET_HashCode*
+get_room_key (struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Returns a tunnel inside of a <i>room</i> leading towards a given <i>peer</i> if such a tunnel exists,
+ * otherwise NULL.
+ *
+ * @param room Room
+ * @param peer Peer identity
+ * @return Tunnel or NULL
+ */
+const struct GNUNET_MESSENGER_SrvTunnel*
+get_room_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Returns a message from a <i>room</i> identified by a given <i>hash</i>. If no matching message is
+ * found and <i>request</i> is set to GNUNET_YES, the <i>handle</i> will request the missing message
+ * automatically.
+ *
+ * The function uses the optimized check for a message via its hash from the message store.
+ * @see contains_store_message()
+ *
+ * If a message is missing independent of the following request, NULL gets returned instead of the
+ * matching message.
+ *
+ * @param room Room
+ * @param handle Handle
+ * @param hash Hash of message
+ * @param request Flag to request a message
+ * @return Message or NULL
+ */
+const struct GNUNET_MESSENGER_Message*
+get_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_HashCode *hash, int request);
+
+/**
+ * Updates the last messages of a <i>room</i> by replacing them if the previous hash of a given <i>message</i>
+ * matches with one of the latest messages.
+ *
+ * @param room Room
+ * @param message Message
+ * @param hash Hash of message
+ */
+void
+update_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Changes an id of a current member from an old id to a new one and adds optionally the <i>hash</i> of an
+ * id message to the members information.
+ *
+ * @param room Room
+ * @param old_id Old member id
+ * @param new_id New member id
+ * @param hash Hash of id message
+ */
+void
+switch_room_member_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *old_id,
+ const struct GNUNET_ShortHashCode *new_id, const struct GNUNET_HashCode *hash);
+
+/**
+ * Rebuilds the decentralized structure for a <i>room</i> by ensuring all required connections are made
+ * depending on the amount of peers and this peers index in the list of them.
+ *
+ * @param room Room
+ */
+void
+rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Handles all queued up messages of a room to handle in correct order.
+ *
+ * @param room Room
+ */
+void
+handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room);
+
+#endif //GNUNET_SERVICE_MESSENGER_ROOM_H
diff --git a/src/messenger/gnunet-service-messenger_service.c b/src/messenger/gnunet-service-messenger_service.c
new file mode 100644
index 000000000..963314fd8
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_service.c
@@ -0,0 +1,516 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_service.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_service.h"
+
+#include "gnunet-service-messenger_message_kind.h"
+
+#include "gnunet-service-messenger.h"
+#include "gnunet-service-messenger_util.h"
+
+static void
+callback_shutdown_service (void *cls)
+{
+ struct GNUNET_MESSENGER_Service *service = cls;
+
+ if (service)
+ {
+ service->shutdown = NULL;
+
+ destroy_service (service);
+ }
+}
+
+static void
+callback_update_ego (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ void **ctx,
+ const char *identifier)
+{
+ if ((!ego) || (!identifier))
+ return;
+
+ struct GNUNET_MESSENGER_Service *service = cls;
+
+ update_service_ego(service, identifier, GNUNET_IDENTITY_ego_get_private_key(ego));
+}
+
+struct GNUNET_MESSENGER_Service*
+create_service (const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service_handle)
+{
+ struct GNUNET_MESSENGER_Service *service = GNUNET_new(struct GNUNET_MESSENGER_Service);
+
+ service->config = config;
+ service->service = service_handle;
+
+ service->shutdown = GNUNET_SCHEDULER_add_shutdown (&callback_shutdown_service, service);
+
+ service->dir = NULL;
+
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (service->config,
+ GNUNET_MESSENGER_SERVICE_NAME,
+ "MESSENGER_DIR", &(service->dir)))
+ {
+ if (service->dir)
+ GNUNET_free(service->dir);
+
+ service->dir = NULL;
+ }
+ else
+ {
+ if ((GNUNET_YES != GNUNET_DISK_directory_test (service->dir, GNUNET_YES)) && (GNUNET_OK
+ != GNUNET_DISK_directory_create (service->dir)))
+ {
+ GNUNET_free(service->dir);
+
+ service->dir = NULL;
+ }
+ }
+
+ service->cadet = GNUNET_CADET_connect (service->config);
+ service->identity = GNUNET_IDENTITY_connect (service->config, &callback_update_ego, service);
+
+ service->egos = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+
+ init_list_handles (&(service->handles));
+
+ service->contacts = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+ service->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+
+ return service;
+}
+
+static int
+iterate_destroy_egos (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_Ego *ego = value;
+ GNUNET_free(ego);
+ return GNUNET_YES;
+}
+
+static int
+iterate_destroy_rooms (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_SrvRoom *room = value;
+ destroy_room (room);
+ return GNUNET_YES;
+}
+
+static int
+iterate_destroy_contacts (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_SrvContact *contact = value;
+ destroy_contact (contact);
+ return GNUNET_YES;
+}
+
+void
+destroy_service (struct GNUNET_MESSENGER_Service *service)
+{
+ if (service->shutdown)
+ {
+ GNUNET_SCHEDULER_cancel (service->shutdown);
+
+ service->shutdown = NULL;
+ }
+
+ GNUNET_CONTAINER_multihashmap_iterate (service->egos, iterate_destroy_egos, NULL);
+
+ clear_list_handles (&(service->handles));
+
+ GNUNET_CONTAINER_multihashmap_iterate (service->rooms, iterate_destroy_rooms, NULL);
+ GNUNET_CONTAINER_multihashmap_iterate (service->contacts, iterate_destroy_contacts, NULL);
+
+ GNUNET_CONTAINER_multihashmap_destroy (service->egos);
+ GNUNET_CONTAINER_multihashmap_destroy (service->rooms);
+ GNUNET_CONTAINER_multihashmap_destroy (service->contacts);
+
+ if (service->cadet)
+ {
+ GNUNET_CADET_disconnect (service->cadet);
+
+ service->cadet = NULL;
+ }
+
+ if (service->identity)
+ {
+ GNUNET_IDENTITY_disconnect (service->identity);
+
+ service->identity = NULL;
+ }
+
+ if (service->dir)
+ {
+ GNUNET_free(service->dir);
+
+ service->dir = NULL;
+ }
+
+ GNUNET_SERVICE_shutdown (service->service);
+
+ GNUNET_free(service);
+}
+
+struct GNUNET_MESSENGER_Ego*
+lookup_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier)
+{
+ GNUNET_assert(identifier);
+
+ struct GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
+ return GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
+}
+
+void
+update_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier,
+ const struct GNUNET_IDENTITY_PrivateKey* key)
+{
+ GNUNET_assert((identifier) && (key));
+
+ struct GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
+
+ struct GNUNET_MESSENGER_Ego* ego = GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
+
+ if (!ego)
+ {
+ ego = GNUNET_new(struct GNUNET_MESSENGER_Ego);
+ GNUNET_CONTAINER_multihashmap_put(service->egos, &hash, ego, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ }
+
+ GNUNET_memcpy(&(ego->priv), key, sizeof(*key));
+
+ if (GNUNET_OK != GNUNET_IDENTITY_key_get_public(key, &(ego->pub)))
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Updating invalid ego key failed!\n");
+}
+
+struct GNUNET_MESSENGER_SrvHandle*
+add_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq)
+{
+ struct GNUNET_MESSENGER_SrvHandle *handle = create_handle (service, mq);
+
+ if (handle)
+ {
+ add_list_handle (&(service->handles), handle);
+ }
+
+ return handle;
+}
+
+void
+remove_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle)
+{
+ if (!handle)
+ return;
+
+ if (GNUNET_YES == remove_list_handle (&(service->handles), handle))
+ destroy_handle (handle);
+}
+
+int
+get_service_peer_identity (const struct GNUNET_MESSENGER_Service *service, struct GNUNET_PeerIdentity *peer)
+{
+ return GNUNET_CRYPTO_get_peer_identity (service->config, peer);
+}
+
+struct GNUNET_MESSENGER_SrvContact*
+get_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_IDENTITY_PublicKey *pubkey)
+{
+ struct GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
+
+ struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multihashmap_get (service->contacts, &hash);
+
+ if (contact)
+ return contact;
+
+ contact = create_contact (pubkey);
+
+ if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->contacts, &hash, contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ return contact;
+
+ destroy_contact (contact);
+ return NULL;
+}
+
+void
+swap_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvContact *contact,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey)
+{
+ const struct GNUNET_HashCode *hash = get_contact_id_from_key (contact);
+
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (service->contacts, hash, contact))
+ {
+ GNUNET_memcpy(&(contact->public_key), pubkey, sizeof(*pubkey));
+
+ hash = get_contact_id_from_key (contact);
+
+ GNUNET_CONTAINER_multihashmap_put (service->contacts, hash, contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ }
+}
+
+struct GNUNET_ShortHashCode*
+generate_service_new_member_id (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
+
+ if (room)
+ {
+ return generate_room_member_id (room);
+ }
+ else
+ {
+ struct GNUNET_ShortHashCode *random_id = GNUNET_new(struct GNUNET_ShortHashCode);
+ generate_free_member_id (random_id, NULL);
+ return random_id;
+ }
+}
+
+struct GNUNET_MESSENGER_SrvRoom*
+get_service_room (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
+{
+ return GNUNET_CONTAINER_multihashmap_get (service->rooms, key);
+}
+
+int
+open_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
+
+ if (room)
+ return open_room (room, handle);
+
+ room = create_room (handle, key);
+
+ if ((GNUNET_YES == open_room (room, handle)) && (GNUNET_OK
+ == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
+ return GNUNET_YES;
+
+ destroy_room (room);
+ return GNUNET_NO;
+}
+
+int
+entry_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
+
+ if (room)
+ {
+ if (GNUNET_YES == entry_room_at (room, handle, door))
+ return GNUNET_YES;
+ else
+ return GNUNET_NO;
+ }
+
+ room = create_room (handle, key);
+
+ if ((GNUNET_YES == entry_room_at (room, handle, door)) && (GNUNET_OK
+ == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
+ {
+ return GNUNET_YES;
+ }
+ else
+ {
+ destroy_room (room);
+ return GNUNET_NO;
+ }
+
+}
+
+int
+close_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
+
+ if (!room)
+ return GNUNET_NO;
+
+ struct GNUNET_MESSENGER_Message *message = create_message_leave ();
+
+ if (message)
+ {
+ struct GNUNET_HashCode hash;
+
+ send_room_message (room, handle, message, &hash);
+ destroy_message (message);
+ }
+
+ const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, key);
+
+ GNUNET_assert(id);
+
+ if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (handle->member_ids, key, id))
+ return GNUNET_NO;
+
+ struct GNUNET_MESSENGER_SrvHandle *member_handle = (struct GNUNET_MESSENGER_SrvHandle*) find_list_handle_by_member (
+ &(service->handles), key);
+
+ if (!member_handle)
+ {
+ if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (service->rooms, key, room))
+ {
+ destroy_room (room);
+ return GNUNET_YES;
+ }
+ else
+ return GNUNET_NO;
+ }
+
+ if (room->host == handle)
+ room->host = member_handle;
+
+ return GNUNET_YES;
+}
+
+static void
+get_room_data_subdir (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room, char **dir)
+{
+ GNUNET_asprintf (dir, "%s%s%c%s%c", service->dir, "rooms", DIR_SEPARATOR, GNUNET_h2s (&(room->key)), DIR_SEPARATOR);
+}
+
+void
+load_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ char *room_dir;
+ get_room_data_subdir (service, room, &room_dir);
+
+ if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
+ {
+ load_message_store (&room->store, room_dir);
+
+ char *config_file;
+ GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
+
+ struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
+
+ if ((GNUNET_YES == GNUNET_DISK_file_test (config_file)) && (GNUNET_OK
+ == GNUNET_CONFIGURATION_parse (cfg, config_file)))
+ {
+ unsigned long long access;
+
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "room", "access-rule", &access))
+ room->strict_access = (int) (access);
+
+ char *message_string;
+
+ if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "room", "last-message", &message_string)) && (message_string))
+ {
+ struct GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash_from_string(message_string, &hash);
+
+ const struct GNUNET_MESSENGER_Message *message = get_room_message (room, room->host, &hash, GNUNET_NO);
+
+ if (message)
+ update_room_last_messages (room, message, &hash);
+
+ GNUNET_free(message_string);
+ }
+ }
+
+ GNUNET_CONFIGURATION_destroy (cfg);
+
+ GNUNET_free(config_file);
+ }
+
+ GNUNET_free(room_dir);
+}
+
+void
+save_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
+{
+ if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (service->rooms, &(room->key)))
+ {
+ return;
+ }
+
+ char *room_dir;
+ get_room_data_subdir (service, room, &room_dir);
+
+ if ((GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_NO)) || (GNUNET_OK
+ == GNUNET_DISK_directory_create (room_dir)))
+ {
+ save_message_store (&room->store, room_dir);
+
+ char *config_file;
+ GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
+
+ struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
+
+ GNUNET_CONFIGURATION_set_value_number (cfg, "room", "access-rule", room->strict_access);
+
+ if (room->last_messages.head)
+ GNUNET_CONFIGURATION_set_value_string (cfg, "room", "last-message",
+ GNUNET_h2s_full (&(room->last_messages.head->hash)));
+
+ GNUNET_CONFIGURATION_write (cfg, config_file);
+ GNUNET_CONFIGURATION_destroy (cfg);
+
+ GNUNET_free(config_file);
+ }
+
+ GNUNET_free(room_dir);
+}
+
+void
+handle_service_message (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_ListHandle *element = service->handles.head;
+
+ const uint16_t length = get_message_size (message);
+
+ while (element)
+ {
+ struct GNUNET_MESSENGER_SrvHandle *handle = (struct GNUNET_MESSENGER_SrvHandle*) element->handle;
+
+ if ((handle->mq) && (get_handle_member_id (handle, &(room->key))))
+ {
+ struct GNUNET_MESSENGER_RecvMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE);
+
+ GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
+ GNUNET_memcpy(&(msg->hash), hash, sizeof(*hash));
+
+ char *buffer = ((char*) msg) + sizeof(*msg);
+ encode_message (message, length, buffer);
+
+ GNUNET_MQ_send (handle->mq, env);
+ }
+
+ element = element->next;
+ }
+}
diff --git a/src/messenger/gnunet-service-messenger_service.h b/src/messenger/gnunet-service-messenger_service.h
new file mode 100644
index 000000000..246c74771
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_service.h
@@ -0,0 +1,259 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_service.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_SERVICE_H
+#define GNUNET_SERVICE_MESSENGER_SERVICE_H
+
+#include "platform.h"
+#include "gnunet_configuration_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_disk_lib.h"
+#include "gnunet_identity_service.h"
+
+#include "messenger_api_ego.h"
+
+#include "gnunet-service-messenger_list_handles.h"
+
+#include "gnunet-service-messenger_contact.h"
+#include "gnunet-service-messenger_room.h"
+
+struct GNUNET_MESSENGER_Service
+{
+ const struct GNUNET_CONFIGURATION_Handle *config;
+ struct GNUNET_SERVICE_Handle *service;
+
+ struct GNUNET_SCHEDULER_Task *shutdown;
+
+ char *dir;
+
+ struct GNUNET_CADET_Handle *cadet;
+ struct GNUNET_IDENTITY_Handle *identity;
+
+ struct GNUNET_CONTAINER_MultiHashMap *egos;
+
+ struct GNUNET_MESSENGER_ListHandles handles;
+
+ struct GNUNET_CONTAINER_MultiHashMap *contacts;
+ struct GNUNET_CONTAINER_MultiHashMap *rooms;
+};
+
+/**
+ * Creates and allocates a new service using a given <i>config</i> and a GNUnet service handle.
+ *
+ * @param config Configuration
+ * @param service_handle GNUnet service handle
+ * @return New service
+ */
+struct GNUNET_MESSENGER_Service*
+create_service (const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service_handle);
+
+/**
+ * Destroys a <i>service</i> and frees its memory fully.
+ *
+ * @param service Service
+ */
+void
+destroy_service (struct GNUNET_MESSENGER_Service *service);
+
+/**
+ * Lookups an EGO which was registered to a <i>service</i> under
+ * a specific <i>identifier</i>.
+ *
+ * @param service Service
+ * @param identifier Identifier string
+ * @return EGO or NULL
+ */
+struct GNUNET_MESSENGER_Ego*
+lookup_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier);
+
+/**
+ * Updates the registration of an EGO to a <i>service</i> under
+ * a specific <i>identifier</i> with a new <i>key</i>.
+ *
+ * @param service Service
+ * @param identifier Identifier string
+ * @param key Private EGO key
+ */
+void
+update_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier,
+ const struct GNUNET_IDENTITY_PrivateKey* key);
+
+/**
+ * Creates and adds a new handle to a <i>service</i> using a given message queue.
+ *
+ * @param service Service
+ * @param mq Message queue
+ * @return New handle
+ */
+struct GNUNET_MESSENGER_SrvHandle*
+add_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq);
+
+/**
+ * Removes a <i>handle</i> from a <i>service</i> and destroys it.
+ *
+ * @param service Service
+ * @param handle Handle
+ */
+void
+remove_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle);
+
+/**
+ * Tries to write the peer identity of the peer running a <i>service</i> on to the <i>peer</i>
+ * parameter. The functions returns GNUNET_OK on success, otherwise GNUNET_SYSERR.
+ *
+ * @param service Service
+ * @param[out] peer Peer identity
+ * @return GNUNET_OK on success, otherwise GNUNET_SYSERR
+ */
+int
+get_service_peer_identity (const struct GNUNET_MESSENGER_Service *service, struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Returns a contact of a <i>service</i> identified by a given public key. If no matching contact exists,
+ * it will tried to create one with the specific public key. If the function still fails to do so,
+ * NULL gets returned.
+ *
+ * @param service Service
+ * @param pubkey Public key of EGO
+ * @return Contact
+ */
+struct GNUNET_MESSENGER_SrvContact*
+get_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_IDENTITY_PublicKey *pubkey);
+
+/**
+ * Changes the public key for a <i>contact</i> known to a <i>service</i> to a specific public key and
+ * updates local map entries to access the contact by its updated key.
+ *
+ * @param service Service
+ * @param contact Contact
+ * @param pubkey Public key of EGO
+ */
+void
+swap_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvContact *contact,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey);
+
+/**
+ * Tries to generate and allocate a new unique member id for a given room of a service identified by its <i>key</i>.
+ * If the generation fails caused by too many tries of duplicates, it returns NULL.
+ *
+ * @param service Service
+ * @param key Key of room
+ * @return Newly generated member id or NULL
+ */
+struct GNUNET_ShortHashCode*
+generate_service_new_member_id (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key);
+
+/**
+ * Returns the room identified by a given <i>key</i> for a <i>service</i>. If the service doesn't know any room
+ * using the given key, NULL gets returned.
+ *
+ * @param service Service
+ * @param key Key of room
+ * @return Room or NULL
+ */
+struct GNUNET_MESSENGER_SrvRoom*
+get_service_room (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key);
+
+/**
+ * Tries to open a room using a given <i>key</i> for a <i>service</i> by a specific <i>handle</i>. The room will be
+ * created if necessary. If the function is successful, it returns GNUNET_YES, otherwise GNUNET_NO.
+ *
+ * @param service Service
+ * @param handle Handle
+ * @param key Key of room
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+open_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_HashCode *key);
+
+/**
+ * Tries to enter a room using a given <i>key</i> for a <i>service</i> by a specific <i>handle</i>. The room will
+ * be created if necessary. If the function is successful, it returns GNUNET_YES, otherwise GNUNET_NO.
+ *
+ * The room will be entered through the peer identitied by the peer identity provided as <i>door</i> parameter and
+ * a new connection will be made.
+ *
+ * @param service Service
+ * @param handle Handle
+ * @param door Peer identity
+ * @param key Key of room
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+entry_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key);
+
+/**
+ * Tries to close a room using a given <i>key</i> for a <i>service</i> by a specific <i>handle</i>. The room will
+ * be created if necessary. If the function is successful, it returns GNUNET_YES, otherwise GNUNET_NO.
+ *
+ * If the specific handle is currently the host of the room for this service, a new handle which is a member will
+ * take its place. Otherwise the room will be destroyed for this service.
+ *
+ * @param service Service
+ * @param handle Handle
+ * @param key Key of room
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+close_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_HashCode *key);
+
+/**
+ * Loads the local configuration for a given <i>room</i> of a <i>service</i> which contains the last messages hash
+ * and the ruleset for general access of new members.
+ *
+ * @param service Service
+ * @param room Room
+ */
+void
+load_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Saves the configuration for a given <i>room</i> of a <i>service</i> which contains the last messages hash
+ * and the ruleset for general access of new members locally.
+ *
+ * @param service Service
+ * @param room Room
+ */
+void
+save_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room);
+
+/**
+ * Sends a received or sent <i>message</i> with a given <i>hash</i> to each handle of a <i>service</i> which
+ * is currently member of a specific <i>room</i> for handling it in the client API.
+ *
+ * @param service Service
+ * @param room Room
+ * @param message Message
+ * @param hash Hash of message
+ */
+void
+handle_service_message (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+#endif //GNUNET_SERVICE_MESSENGER_SERVICE_H
diff --git a/src/messenger/gnunet-service-messenger_tunnel.c b/src/messenger/gnunet-service-messenger_tunnel.c
new file mode 100644
index 000000000..df9e5c4c7
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_tunnel.c
@@ -0,0 +1,300 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_tunnel.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_tunnel.h"
+
+#include "gnunet-service-messenger_handle.h"
+#include "gnunet-service-messenger_util.h"
+
+struct GNUNET_MESSENGER_SrvTunnel*
+create_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *door)
+{
+ GNUNET_assert((room) && (door));
+
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_new(struct GNUNET_MESSENGER_SrvTunnel);
+
+ tunnel->room = room;
+ tunnel->channel = NULL;
+
+ tunnel->peer = GNUNET_PEER_intern (door);
+ tunnel->contact_id = NULL;
+
+ tunnel->peer_message = NULL;
+ tunnel->last_message = NULL;
+
+ return tunnel;
+}
+
+void
+destroy_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
+{
+ GNUNET_assert(tunnel);
+
+ if (tunnel->channel)
+ GNUNET_CADET_channel_destroy (tunnel->channel);
+
+ GNUNET_PEER_change_rc (tunnel->peer, -1);
+
+ if (tunnel->contact_id)
+ GNUNET_free(tunnel->contact_id);
+
+ if (tunnel->peer_message)
+ GNUNET_free(tunnel->peer_message);
+
+ if (tunnel->last_message)
+ GNUNET_free(tunnel->last_message);
+
+ GNUNET_free(tunnel);
+}
+
+int
+bind_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_CADET_Channel *channel)
+{
+ GNUNET_assert(tunnel);
+
+ if (tunnel->channel)
+ {
+ if (tunnel->contact_id)
+ return GNUNET_NO;
+
+ delayed_disconnect_channel (tunnel->channel);
+ }
+
+ tunnel->channel = channel;
+
+ return GNUNET_YES;
+}
+
+extern void
+callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room, void *cls);
+
+void
+callback_tunnel_disconnect (void *cls, const struct GNUNET_CADET_Channel *channel)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
+
+ if (tunnel)
+ {
+ tunnel->channel = NULL;
+
+ callback_room_disconnect (tunnel->room, cls);
+ }
+}
+
+extern int
+callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room, void *cls,
+ struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash);
+
+int
+check_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
+
+ if (!tunnel)
+ return GNUNET_NO;
+
+ const uint16_t length = ntohs (header->size) - sizeof(*header);
+ const char *buffer = (const char*) &header[1];
+
+ struct GNUNET_MESSENGER_Message message;
+
+ if (length < sizeof(message.header))
+ return GNUNET_NO;
+
+ if (GNUNET_YES != decode_message (&message, length, buffer))
+ return GNUNET_NO;
+
+ struct GNUNET_HashCode hash;
+ hash_message (length, buffer, &hash);
+
+ int result = callback_verify_room_message (tunnel->room, cls, &message, &hash);
+
+ if (GNUNET_MESSENGER_KIND_PEER == message.header.kind)
+ {
+ struct GNUNET_PeerIdentity identity;
+
+ GNUNET_PEER_resolve (tunnel->peer, &identity);
+
+ if (0 == GNUNET_memcmp(&(message.body.peer.peer), &(identity)))
+ {
+ if (tunnel->contact_id)
+ {
+ if (0 != GNUNET_memcmp(tunnel->contact_id, &(message.header.sender_id)))
+ result = GNUNET_SYSERR;
+ }
+ else
+ {
+ tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
+
+ GNUNET_memcpy(tunnel->contact_id, &(message.header.sender_id), sizeof(struct GNUNET_ShortHashCode));
+ }
+ }
+ }
+
+ return (result == GNUNET_YES ? GNUNET_OK : GNUNET_NO);
+}
+
+extern void
+callback_room_recv (struct GNUNET_MESSENGER_SrvRoom *room, void *cls, struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+void
+handle_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header)
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
+
+ const uint16_t length = ntohs (header->size) - sizeof(*header);
+ const char *buffer = (const char*) &header[1];
+
+ struct GNUNET_MESSENGER_Message message;
+ struct GNUNET_HashCode hash;
+
+ decode_message (&message, length, buffer);
+ hash_message (length, buffer, &hash);
+
+ if (tunnel)
+ {
+ if (!tunnel->last_message)
+ tunnel->last_message = GNUNET_new(struct GNUNET_HashCode);
+
+ GNUNET_memcpy(tunnel->last_message, &hash, sizeof(struct GNUNET_HashCode));
+
+ callback_room_recv (tunnel->room, cls, copy_message (&message), &hash);
+ }
+
+ GNUNET_CADET_receive_done (tunnel->channel);
+}
+
+int
+connect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
+{
+ GNUNET_assert(tunnel);
+
+ if (tunnel->channel)
+ return GNUNET_NO;
+
+ const struct GNUNET_PeerIdentity *door = GNUNET_PEER_resolve2 (tunnel->peer);
+
+ struct GNUNET_CADET_Handle *cadet = get_room_cadet (tunnel->room);
+ struct GNUNET_HashCode *key = get_room_key (tunnel->room);
+
+ struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size(tunnel_message, GNUNET_MESSAGE_TYPE_CADET_CLI,
+ struct GNUNET_MessageHeader, NULL),
+ GNUNET_MQ_handler_end() };
+
+ tunnel->channel = GNUNET_CADET_channel_create (cadet, tunnel, door, key, NULL, callback_tunnel_disconnect, handlers);
+
+ return GNUNET_YES;
+}
+
+void
+disconnect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
+{
+ if (tunnel->channel)
+ {
+ delayed_disconnect_channel (tunnel->channel);
+
+ tunnel->channel = NULL;
+ }
+}
+
+int
+is_tunnel_connected (const struct GNUNET_MESSENGER_SrvTunnel *tunnel)
+{
+ return (tunnel->channel ? GNUNET_YES : GNUNET_NO);
+}
+
+struct GNUNET_MESSENGER_MessageSent
+{
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel;
+ struct GNUNET_HashCode hash;
+};
+
+extern void
+callback_room_sent (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle, void *cls,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+static void
+callback_tunnel_sent (void *cls)
+{
+ struct GNUNET_MESSENGER_MessageSent *sent = cls;
+
+ if (sent->tunnel)
+ {
+ if (!sent->tunnel->last_message)
+ sent->tunnel->last_message = GNUNET_new(struct GNUNET_HashCode);
+
+ GNUNET_memcpy(sent->tunnel->last_message, &(sent->hash), sizeof(struct GNUNET_HashCode));
+ }
+
+ GNUNET_free(sent);
+}
+
+void
+send_tunnel_envelope (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MQ_Envelope *env,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MQ_Handle *mq = GNUNET_CADET_get_mq (tunnel->channel);
+
+ struct GNUNET_MESSENGER_MessageSent *sent = GNUNET_new(struct GNUNET_MESSENGER_MessageSent);
+
+ GNUNET_memcpy(&(sent->hash), hash, sizeof(struct GNUNET_HashCode));
+
+ sent->tunnel = tunnel;
+
+ GNUNET_MQ_notify_sent (env, callback_tunnel_sent, sent);
+ GNUNET_MQ_send (mq, env);
+
+ callback_room_sent (tunnel->room, (struct GNUNET_MESSENGER_SrvHandle*) handle, tunnel, message, hash);
+}
+
+void
+send_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MESSENGER_Message *message,
+ struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MQ_Envelope *env = pack_room_message (tunnel->room, (struct GNUNET_MESSENGER_SrvHandle*) handle,
+ message, hash,
+ GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
+
+ if (env)
+ send_tunnel_envelope (tunnel, handle, env, copy_message (message), hash);
+}
+
+void
+forward_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Message *clone = copy_message (message);
+ struct GNUNET_MQ_Envelope *env = pack_message (clone, NULL, NULL, GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
+
+ if (env)
+ send_tunnel_envelope (tunnel, NULL, env, clone, hash);
+}
+
+const struct GNUNET_HashCode*
+get_tunnel_peer_message (const struct GNUNET_MESSENGER_SrvTunnel *tunnel)
+{
+ return tunnel->peer_message;
+}
diff --git a/src/messenger/gnunet-service-messenger_tunnel.h b/src/messenger/gnunet-service-messenger_tunnel.h
new file mode 100644
index 000000000..e6efb226d
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_tunnel.h
@@ -0,0 +1,155 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_tunnel.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_TUNNEL_H
+#define GNUNET_SERVICE_MESSENGER_TUNNEL_H
+
+#include "platform.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_peer_lib.h"
+#include "gnunet_crypto_lib.h"
+
+#include "gnunet-service-messenger_room.h"
+
+struct GNUNET_MESSENGER_SrvTunnel
+{
+ struct GNUNET_MESSENGER_SrvRoom *room;
+ struct GNUNET_CADET_Channel *channel;
+
+ GNUNET_PEER_Id peer;
+ struct GNUNET_ShortHashCode *contact_id;
+
+ struct GNUNET_HashCode *peer_message;
+ struct GNUNET_HashCode *last_message;
+};
+
+/**
+ * Creates and allocates a tunnel of a <i>room</i> to a specific peer identity.
+ *
+ * @param room Room
+ * @param door Peer identity
+ * @return New tunnel
+ */
+struct GNUNET_MESSENGER_SrvTunnel*
+create_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *door);
+
+/**
+ * Destroys a <i>tunnel</i> and frees its memory fully.
+ *
+ * @param tunnel
+ */
+void
+destroy_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
+
+/**
+ * Binds a CADET <i>channel</i> to a <i>tunnel</i> on returns GNUNET_YES only if
+ * the bounds channel was replaced successfully, otherwise GNUNET_NO gets returned.
+ *
+ * @param tunnel Tunnel
+ * @param channel CADET channel
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+bind_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_CADET_Channel *channel);
+
+/**
+ * Tries to connect a <i>tunnel</i> by creating a new CADET channel and binding it.
+ * The function returns GNUNET_YES on success, otherwise GNUNET_NO.
+ *
+ * @param tunnel Tunnel
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+connect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
+
+/**
+ * Disconnects and unbinds a channel from a <i>tunnel</i>. The actual disconnection
+ * will be asynchronous.
+ *
+ * @param tunnel Tunnel
+ */
+void
+disconnect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
+
+/**
+ * Returns the status of a currently bound channel of a <i>tunnel</i>.
+ *
+ * @param tunnel Tunnel
+ * @return GNUNET_YES or GNUNET_NO
+ */
+int
+is_tunnel_connected (const struct GNUNET_MESSENGER_SrvTunnel *tunnel);
+
+/**
+ * Sends an envelope containing a <i>message</i> with a given <i>hash</i> through
+ * a <i>tunnel</i> by a given <i>handle</i>.
+ *
+ * @param tunnel Tunnel
+ * @param handle Handle
+ * @param env Envelope
+ * @param message Message
+ * @param hash Hash of message
+ */
+void
+send_tunnel_envelope (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MQ_Envelope *env,
+ struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
+ * Sends a <i>message</i> by packing it automatically into an envelope and passing it
+ * through the <i>tunnel</i>. The used <i>handle</i> will sign the message and
+ * the <i>hash</i> will be calculated and stored.
+ *
+ * @param tunnel Tunnel
+ * @param handle Handle
+ * @param[out] message Message
+ * @param[out] hash Hash of message
+ */
+void
+send_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MESSENGER_Message *message,
+ struct GNUNET_HashCode *hash);
+
+/**
+ * Forwards a given <i>message</i> with a known <i>hash</i> through a <i>tunnel</i>.
+ *
+ * @param tunnel Tunnel
+ * @param message Message
+ * @param hash Hash of message
+ */
+void
+forward_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+/**
+ * Returns the hash of the latest peer message published through a given <i>tunnel</i>
+ * and matching the tunnels peer identity. If no peer message has been linked to the tunnel
+ * yet, NULL gets returned.
+ *
+ * @param tunnel Tunnel
+ * @return Hash of peer message or NULL
+ */
+const struct GNUNET_HashCode*
+get_tunnel_peer_message (const struct GNUNET_MESSENGER_SrvTunnel *tunnel);
+
+#endif //GNUNET_SERVICE_MESSENGER_TUNNEL_H
diff --git a/src/messenger/gnunet-service-messenger_util.c b/src/messenger/gnunet-service-messenger_util.c
new file mode 100644
index 000000000..94fc9469d
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_util.c
@@ -0,0 +1,64 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_util.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_util.h"
+
+static void
+callback_close_channel (void *cls)
+{
+ struct GNUNET_CADET_Channel *channel = cls;
+
+ if (channel)
+ GNUNET_CADET_channel_destroy (channel);
+}
+
+void
+delayed_disconnect_channel (struct GNUNET_CADET_Channel *channel)
+{
+ GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_get_zero_ (), GNUNET_SCHEDULER_PRIORITY_URGENT,
+ callback_close_channel, channel);
+}
+
+int
+generate_free_member_id (struct GNUNET_ShortHashCode *id, const struct GNUNET_CONTAINER_MultiShortmap *members)
+{
+ size_t counter = 1 + (members ? GNUNET_CONTAINER_multishortmap_size (members) : 0);
+
+ do
+ {
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, id, sizeof(struct GNUNET_ShortHashCode));
+
+ if ((members) && (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains (members, id)))
+ counter--;
+ else
+ break;
+ }
+ while (counter > 0);
+
+ if (counter)
+ return GNUNET_YES;
+
+ return GNUNET_NO;
+}
diff --git a/src/messenger/gnunet-service-messenger_util.h b/src/messenger/gnunet-service-messenger_util.h
new file mode 100644
index 000000000..20f8f0afe
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_util.h
@@ -0,0 +1,53 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/gnunet-service-messenger_util.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_UTIL_H
+#define GNUNET_SERVICE_MESSENGER_UTIL_H
+
+#include "platform.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_crypto_lib.h"
+
+/**
+ * Starts an urgent task to close a CADET channel asynchronously.
+ *
+ * @param channel Channel
+ */
+void
+delayed_disconnect_channel (struct GNUNET_CADET_Channel *channel);
+
+/**
+ * Tries to generate an unused member id and store it into the <i>id</i> parameter. A map containing all currently
+ * used member ids is used to check against.
+ *
+ * @param[out] id New member id
+ * @param members Map of member ids
+ * @return GNUNET_YES on success, GNUNET_NO on failure
+ */
+int
+generate_free_member_id (struct GNUNET_ShortHashCode *id, const struct GNUNET_CONTAINER_MultiShortmap *members);
+
+#endif //GNUNET_SERVICE_MESSENGER_UTIL_H
diff --git a/src/messenger/messenger.conf.in b/src/messenger/messenger.conf.in
new file mode 100644
index 000000000..59e11b166
--- /dev/null
+++ b/src/messenger/messenger.conf.in
@@ -0,0 +1,13 @@
+[messenger]
+START_ON_DEMAND = YES
+PORT = 2097
+HOSTNAME = localhost
+BINARY = gnunet-service-messenger
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-messenger.sock
+UNIX_MATCH_UID = NO
+UNIX_MATCH_GID = YES
+
+# Directory to store messages and contacts
+MESSENGER_DIR = $GNUNET_DATA_HOME/messenger/ \ No newline at end of file
diff --git a/src/messenger/messenger_api.c b/src/messenger/messenger_api.c
new file mode 100644
index 000000000..6401b18d7
--- /dev/null
+++ b/src/messenger/messenger_api.c
@@ -0,0 +1,568 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api.c
+ * @brief messenger api: client implementation of GNUnet MESSENGER service
+ */
+
+#include "gnunet_messenger_service.h"
+
+#include "gnunet-service-messenger.h"
+
+#include "messenger_api_handle.h"
+#include "messenger_api_message.h"
+
+const char*
+GNUNET_MESSENGER_name_of_kind (enum GNUNET_MESSENGER_MessageKind kind)
+{
+ switch (kind)
+ {
+ case GNUNET_MESSENGER_KIND_INFO:
+ return "INFO";
+ case GNUNET_MESSENGER_KIND_JOIN:
+ return "JOIN";
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ return "LEAVE";
+ case GNUNET_MESSENGER_KIND_NAME:
+ return "NAME";
+ case GNUNET_MESSENGER_KIND_KEY:
+ return "KEY";
+ case GNUNET_MESSENGER_KIND_PEER:
+ return "PEER";
+ case GNUNET_MESSENGER_KIND_ID:
+ return "ID";
+ case GNUNET_MESSENGER_KIND_MISS:
+ return "MISS";
+ case GNUNET_MESSENGER_KIND_MERGE:
+ return "MERGE";
+ case GNUNET_MESSENGER_KIND_REQUEST:
+ return "REQUEST";
+ case GNUNET_MESSENGER_KIND_INVITE:
+ return "INVITE";
+ case GNUNET_MESSENGER_KIND_TEXT:
+ return "TEXT";
+ case GNUNET_MESSENGER_KIND_FILE:
+ return "FILE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int
+check_get_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
+{
+ GNUNET_MQ_check_zero_termination(msg);
+ return GNUNET_OK;
+}
+
+static void
+handle_get_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ const char *name = ((const char*) msg) + sizeof(*msg);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Set name of handle: %s\n", name);
+
+ set_handle_name (handle, strlen(name) > 0? name : NULL);
+}
+
+static void
+handle_get_key (void *cls, const struct GNUNET_MESSENGER_KeyMessage *msg)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ const struct GNUNET_IDENTITY_PublicKey *pubkey = &(msg->pubkey);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Set key of handle: %s\n", GNUNET_IDENTITY_public_key_to_string (pubkey));
+
+ set_handle_key (handle, pubkey);
+
+ if (handle->identity_callback)
+ handle->identity_callback (handle->identity_cls, handle);
+}
+
+static void
+handle_member_id (void *cls, const struct GNUNET_MESSENGER_MemberMessage *msg)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ const struct GNUNET_HashCode *key = &(msg->key);
+ const struct GNUNET_ShortHashCode *id = &(msg->id);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Set id of handle in room: %s\n", GNUNET_h2s (key));
+
+ struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
+
+ if (room)
+ {
+ if (!room->contact_id)
+ room->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
+
+ GNUNET_memcpy(room->contact_id, id, sizeof(*id));
+ }
+}
+
+static void
+handle_room_open (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ const struct GNUNET_HashCode *key = &(msg->key);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Opened room: %s\n", GNUNET_h2s (key));
+
+ open_handle_room (handle, key);
+}
+
+static void
+handle_room_entry (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ const struct GNUNET_PeerIdentity *door = &(msg->door);
+ const struct GNUNET_HashCode *key = &(msg->key);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Entered room: %s\n", GNUNET_h2s (key));
+
+ entry_handle_room_at (handle, door, key);
+}
+
+static void
+handle_room_close (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ const struct GNUNET_HashCode *key = &(msg->key);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Closed room: %s\n", GNUNET_h2s (key));
+
+ close_handle_room (handle, key);
+}
+
+static int
+check_recv_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg)
+{
+ const uint16_t full_length = ntohs (msg->header.size) - sizeof(msg->header);
+
+ if (full_length < sizeof(msg->hash))
+ return GNUNET_NO;
+
+ const uint16_t length = full_length - sizeof(msg->hash);
+ const char *buffer = ((const char*) msg) + sizeof(*msg);
+
+ struct GNUNET_MESSENGER_Message message;
+
+ if (length < sizeof(message.header))
+ return GNUNET_NO;
+
+ if (GNUNET_YES != decode_message (&message, length, buffer))
+ return GNUNET_NO;
+
+ return GNUNET_OK;
+}
+
+static void
+handle_recv_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ const struct GNUNET_HashCode *key = &(msg->key);
+ const struct GNUNET_HashCode *hash = &(msg->hash);
+
+ const char *buffer = ((const char*) msg) + sizeof(*msg);
+
+ const uint16_t length = ntohs (msg->header.size) - sizeof(*msg);
+
+ struct GNUNET_MESSENGER_Message message;
+ decode_message (&message, length, buffer);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Receiving message: %s\n", GNUNET_MESSENGER_name_of_kind (message.header.kind));
+
+ struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
+
+ if (room)
+ {
+ handle_room_message (room, &message, hash);
+
+ if (handle->msg_callback)
+ handle->msg_callback (handle->msg_cls, room, &message, hash);
+ }
+ else
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "MESSENGER ERROR: Room not found\n");
+}
+
+static void
+reconnect (struct GNUNET_MESSENGER_Handle *handle);
+
+static void
+send_open_room (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Room *room)
+{
+ struct GNUNET_MESSENGER_RoomMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN);
+ GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
+ GNUNET_MQ_send (handle->mq, env);
+}
+
+static void
+send_entry_room (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Room *room,
+ const struct GNUNET_PeerIdentity *door)
+{
+ struct GNUNET_MESSENGER_RoomMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY);
+ GNUNET_memcpy(&(msg->door), door, sizeof(*door));
+ GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
+ GNUNET_MQ_send (handle->mq, env);
+}
+
+static void
+send_close_room (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Room *room)
+{
+ struct GNUNET_MESSENGER_RoomMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE);
+ GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
+ GNUNET_MQ_send (handle->mq, env);
+}
+
+static int
+iterate_reset_room (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+ struct GNUNET_MESSENGER_Room *room = value;
+
+ if (GNUNET_YES == room->opened)
+ send_open_room (handle, room);
+
+ struct GNUNET_MESSENGER_ListTunnel *entry = room->entries.head;
+
+ struct GNUNET_PeerIdentity door;
+
+ while (entry)
+ {
+ GNUNET_PEER_resolve (entry->peer, &door);
+
+ send_entry_room (handle, room, &door);
+
+ entry = entry->next;
+ }
+
+ return GNUNET_YES;
+}
+
+static void
+callback_reconnect (void *cls)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ handle->reconnect_task = NULL;
+ handle->reconnect_time = GNUNET_TIME_STD_BACKOFF(handle->reconnect_time)
+ ;
+
+ reconnect (handle);
+
+ GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_reset_room, handle);
+}
+
+static int
+iterate_close_room (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+ struct GNUNET_MESSENGER_Room *room = value;
+
+ send_close_room (handle, room);
+
+ return GNUNET_YES;
+}
+
+static void
+callback_mq_error (void *cls, enum GNUNET_MQ_Error error)
+{
+ struct GNUNET_MESSENGER_Handle *handle = cls;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %u\n", error);
+
+ GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_close_room, handle);
+
+ if (handle->mq)
+ {
+ GNUNET_MQ_destroy (handle->mq);
+ handle->mq = NULL;
+ }
+
+ handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->reconnect_time, &callback_reconnect, handle);
+}
+
+static void
+reconnect (struct GNUNET_MESSENGER_Handle *handle)
+{
+ const struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size(
+ get_name, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_NAME, struct GNUNET_MESSENGER_NameMessage, handle),
+ GNUNET_MQ_hd_fixed_size(
+ get_key, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_KEY,
+ struct GNUNET_MESSENGER_KeyMessage, handle),
+ GNUNET_MQ_hd_fixed_size(
+ member_id,
+ GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID,
+ struct GNUNET_MESSENGER_MemberMessage, handle),
+ GNUNET_MQ_hd_fixed_size(room_open,
+ GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN,
+ struct GNUNET_MESSENGER_RoomMessage,
+ handle),
+ GNUNET_MQ_hd_fixed_size(room_entry,
+ GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY,
+ struct GNUNET_MESSENGER_RoomMessage,
+ handle),
+ GNUNET_MQ_hd_fixed_size(room_close,
+ GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE,
+ struct GNUNET_MESSENGER_RoomMessage,
+ handle),
+ GNUNET_MQ_hd_var_size(
+ recv_message,
+ GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE,
+ struct GNUNET_MESSENGER_RecvMessage, handle),
+ GNUNET_MQ_handler_end() };
+
+ handle->mq = GNUNET_CLIENT_connect (handle->cfg,
+ GNUNET_MESSENGER_SERVICE_NAME,
+ handlers, &callback_mq_error, handle);
+}
+
+struct GNUNET_MESSENGER_Handle*
+GNUNET_MESSENGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name,
+ GNUNET_MESSENGER_IdentityCallback identity_callback, void *identity_cls,
+ GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls)
+{
+ struct GNUNET_MESSENGER_Handle *handle = create_handle (cfg, identity_callback, identity_cls, msg_callback, msg_cls);
+
+ reconnect (handle);
+
+ if (handle->mq)
+ {
+ const uint16_t name_len = name ? strlen (name) : 0;
+
+ struct GNUNET_MESSENGER_CreateMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg_extra(msg, name_len + 1, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE);
+
+ char *extra = ((char*) msg) + sizeof(*msg);
+
+ if (name_len)
+ GNUNET_memcpy(extra, name, name_len);
+
+ extra[name_len] = '\0';
+
+ GNUNET_MQ_send (handle->mq, env);
+ return handle;
+ }
+ else
+ {
+ destroy_handle (handle);
+ return NULL;
+ }
+}
+
+int
+GNUNET_MESSENGER_update (struct GNUNET_MESSENGER_Handle *handle)
+{
+ if ((!handle) || (!get_handle_name(handle)))
+ return GNUNET_SYSERR;
+
+ struct GNUNET_MESSENGER_UpdateMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_UPDATE);
+ GNUNET_MQ_send (handle->mq, env);
+ return GNUNET_OK;
+}
+
+void
+GNUNET_MESSENGER_disconnect (struct GNUNET_MESSENGER_Handle *handle)
+{
+ if (!handle)
+ return;
+
+ struct GNUNET_MESSENGER_DestroyMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY);
+ GNUNET_MQ_send (handle->mq, env);
+
+ destroy_handle (handle);
+}
+
+const char*
+GNUNET_MESSENGER_get_name (const struct GNUNET_MESSENGER_Handle *handle)
+{
+ if (!handle)
+ return NULL;
+
+ return get_handle_name (handle);
+}
+
+int
+GNUNET_MESSENGER_set_name (struct GNUNET_MESSENGER_Handle *handle, const char *name)
+{
+ if (!handle)
+ return GNUNET_SYSERR;
+
+ const uint16_t name_len = name ? strlen (name) : 0;
+
+ struct GNUNET_MESSENGER_NameMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg_extra(msg, name_len + 1, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_SET_NAME);
+
+ char *extra = ((char*) msg) + sizeof(*msg);
+
+ if (name_len)
+ GNUNET_memcpy(extra, name, name_len);
+
+ extra[name_len] = '\0';
+
+ GNUNET_MQ_send (handle->mq, env);
+ return GNUNET_YES;
+}
+
+const struct GNUNET_IDENTITY_PublicKey*
+GNUNET_MESSENGER_get_key (const struct GNUNET_MESSENGER_Handle *handle)
+{
+ if (!handle)
+ return NULL;
+
+ return get_handle_key (handle);
+}
+
+struct GNUNET_MESSENGER_Room*
+GNUNET_MESSENGER_open_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
+
+ if (!room)
+ {
+ room = create_room (handle, key);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->rooms, key, room,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ destroy_room (room);
+ return NULL;
+ }
+ }
+
+ send_open_room (handle, room);
+ return room;
+}
+
+struct GNUNET_MESSENGER_Room*
+GNUNET_MESSENGER_entry_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
+ const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
+
+ if (!room)
+ {
+ room = create_room (handle, key);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->rooms, key, room,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ destroy_room (room);
+ return NULL;
+ }
+ }
+
+ send_entry_room (handle, room, door);
+ return room;
+}
+
+void
+GNUNET_MESSENGER_close_room (struct GNUNET_MESSENGER_Room *room)
+{
+ send_close_room (room->handle, room);
+}
+
+struct GNUNET_MESSENGER_Contact*
+GNUNET_MESSENGER_get_member (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_ShortHashCode *id)
+{
+ return GNUNET_CONTAINER_multishortmap_get (room->members, id);
+}
+
+const char*
+GNUNET_MESSENGER_contact_get_name (const struct GNUNET_MESSENGER_Contact *contact)
+{
+ if (!contact)
+ return NULL;
+
+ return get_contact_name (contact);
+}
+
+const struct GNUNET_IDENTITY_PublicKey*
+GNUNET_MESSENGER_contact_get_key (const struct GNUNET_MESSENGER_Contact *contact)
+{
+ if (!contact)
+ return NULL;
+
+ return get_contact_key (contact);
+}
+
+void
+GNUNET_MESSENGER_send_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message)
+{
+ const uint16_t length = get_message_size (message);
+
+ struct GNUNET_MESSENGER_SendMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE);
+
+ GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
+
+ char *buffer = ((char*) msg) + sizeof(*msg);
+ encode_message (message, length, buffer);
+
+ GNUNET_MQ_send (room->handle->mq, env);
+}
+
+const struct GNUNET_MESSENGER_Message*
+GNUNET_MESSENGER_get_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash)
+{
+ const struct GNUNET_MESSENGER_Message *message = get_room_message (room, hash);
+
+ if (!message)
+ {
+ struct GNUNET_MESSENGER_RecvMessage *msg;
+ struct GNUNET_MQ_Envelope *env;
+
+ env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE);
+ GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
+ GNUNET_memcpy(&(msg->hash), hash, sizeof(*hash));
+ GNUNET_MQ_send (room->handle->mq, env);
+ }
+
+ return message;
+}
diff --git a/src/messenger/messenger_api_contact.c b/src/messenger/messenger_api_contact.c
new file mode 100644
index 000000000..9a242aa00
--- /dev/null
+++ b/src/messenger/messenger_api_contact.c
@@ -0,0 +1,78 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_contact.c
+ * @brief messenger api: client implementation of GNUnet MESSENGER service
+ */
+
+#include "messenger_api_contact.h"
+
+struct GNUNET_MESSENGER_Contact*
+create_contact (const struct GNUNET_IDENTITY_PublicKey *key)
+{
+ struct GNUNET_MESSENGER_Contact *contact = GNUNET_new(struct GNUNET_MESSENGER_Contact);
+
+ contact->name = NULL;
+
+ GNUNET_memcpy(&(contact->public_key), key, sizeof(contact->public_key));
+
+ return contact;
+}
+
+void
+destroy_contact (struct GNUNET_MESSENGER_Contact *contact)
+{
+ if (contact->name)
+ GNUNET_free(contact->name);
+
+ GNUNET_free(contact);
+}
+
+const char*
+get_contact_name (const struct GNUNET_MESSENGER_Contact *contact)
+{
+ return contact->name;
+}
+
+void
+set_contact_name (struct GNUNET_MESSENGER_Contact *contact, const char *name)
+{
+ if (contact->name)
+ GNUNET_free(contact->name);
+
+ contact->name = name? GNUNET_strdup(name) : NULL;
+}
+
+const struct GNUNET_IDENTITY_PublicKey*
+get_contact_key (const struct GNUNET_MESSENGER_Contact *contact)
+{
+ return &(contact->public_key);
+}
+
+const struct GNUNET_HashCode*
+get_contact_id_from_key (const struct GNUNET_MESSENGER_Contact *contact)
+{
+ static struct GNUNET_HashCode id;
+
+ GNUNET_CRYPTO_hash (&(contact->public_key), sizeof(contact->public_key), &id);
+
+ return &id;
+}
diff --git a/src/messenger/messenger_api_contact.h b/src/messenger/messenger_api_contact.h
new file mode 100644
index 000000000..0673b9b85
--- /dev/null
+++ b/src/messenger/messenger_api_contact.h
@@ -0,0 +1,93 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_contact.h
+ * @brief messenger api: client implementation of GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_MESSENGER_API_CONTACT_H
+#define GNUNET_MESSENGER_API_CONTACT_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+
+struct GNUNET_MESSENGER_Contact
+{
+ char *name;
+
+ struct GNUNET_IDENTITY_PublicKey public_key;
+};
+
+/**
+ * Creates and allocates a new contact with a given public <i>key</i> from an EGO.
+ *
+ * @param key Public key
+ * @return New contact
+ */
+struct GNUNET_MESSENGER_Contact*
+create_contact (const struct GNUNET_IDENTITY_PublicKey *key);
+
+/**
+ * Destroys a contact and frees its memory fully.
+ *
+ * @param contact Contact
+ */
+void
+destroy_contact (struct GNUNET_MESSENGER_Contact *contact);
+
+/**
+ * Returns the current name of a given <i>contact</i> or NULL if no valid name was assigned yet.
+ *
+ * @param contact Contact
+ * @return Name of the contact or NULL
+ */
+const char*
+get_contact_name (const struct GNUNET_MESSENGER_Contact *contact);
+
+/**
+ * Changes the current name of a given <i>contact</i> by copying it from the parameter <i>name</i>.
+ *
+ * @param contact Contact
+ * @param name Valid name (may not be NULL!)
+ */
+void
+set_contact_name (struct GNUNET_MESSENGER_Contact *contact, const char *name);
+
+/**
+ * Returns the public key of a given <i>contact</i>.
+ *
+ * @param contact Contact
+ * @return Public key of the contact
+ */
+const struct GNUNET_IDENTITY_PublicKey*
+get_contact_key (const struct GNUNET_MESSENGER_Contact *contact);
+
+/**
+ * Returns the resulting hashcode of the public key from a given <i>contact</i>.
+ *
+ * @param contact Contact
+ * @return Hash of the contacts public key
+ */
+const struct GNUNET_HashCode*
+get_contact_id_from_key (const struct GNUNET_MESSENGER_Contact *contact);
+
+#endif //GNUNET_MESSENGER_API_CONTACT_H
diff --git a/src/messenger/messenger_api_ego.h b/src/messenger/messenger_api_ego.h
new file mode 100644
index 000000000..c60eeac50
--- /dev/null
+++ b/src/messenger/messenger_api_ego.h
@@ -0,0 +1,38 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_ego.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_MESSENGER_API_EGO_H
+#define GNUNET_MESSENGER_API_EGO_H
+
+#include "platform.h"
+#include "gnunet_identity_service.h"
+
+struct GNUNET_MESSENGER_Ego
+{
+ struct GNUNET_IDENTITY_PrivateKey priv;
+ struct GNUNET_IDENTITY_PublicKey pub;
+};
+
+#endif //GNUNET_MESSENGER_API_EGO_H
diff --git a/src/messenger/messenger_api_handle.c b/src/messenger/messenger_api_handle.c
new file mode 100644
index 000000000..20ef77254
--- /dev/null
+++ b/src/messenger/messenger_api_handle.c
@@ -0,0 +1,213 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_handle.c
+ * @brief messenger api: client implementation of GNUnet MESSENGER service
+ */
+
+#include "messenger_api_handle.h"
+
+struct GNUNET_MESSENGER_Handle*
+create_handle (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_MESSENGER_IdentityCallback identity_callback,
+ void *identity_cls, GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls)
+{
+ struct GNUNET_MESSENGER_Handle *handle = GNUNET_new(struct GNUNET_MESSENGER_Handle);
+
+ handle->cfg = cfg;
+ handle->mq = NULL;
+
+ handle->identity_callback = identity_callback;
+ handle->identity_cls = identity_cls;
+
+ handle->msg_callback = msg_callback;
+ handle->msg_cls = msg_cls;
+
+ handle->name = NULL;
+ handle->pubkey = NULL;
+
+ handle->reconnect_time = GNUNET_TIME_relative_get_zero_ ();
+ handle->reconnect_task = NULL;
+
+ handle->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+ handle->contacts = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+
+ return handle;
+}
+
+static int
+iterate_destroy_room (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_Room *room = value;
+
+ destroy_room (room);
+
+ return GNUNET_YES;
+}
+
+static int
+iterate_destroy_contact (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_Contact *contact = value;
+
+ destroy_contact (contact);
+
+ return GNUNET_YES;
+}
+
+void
+destroy_handle (struct GNUNET_MESSENGER_Handle *handle)
+{
+ if (handle->reconnect_task)
+ GNUNET_SCHEDULER_cancel (handle->reconnect_task);
+
+ if (handle->mq)
+ GNUNET_MQ_destroy (handle->mq);
+
+ if (handle->name)
+ GNUNET_free(handle->name);
+
+ if (handle->pubkey)
+ GNUNET_free(handle->pubkey);
+
+ if (handle->rooms)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_destroy_room, NULL);
+
+ GNUNET_CONTAINER_multihashmap_destroy (handle->rooms);
+ }
+
+ if (handle->contacts)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (handle->contacts, iterate_destroy_contact, NULL);
+
+ GNUNET_CONTAINER_multihashmap_destroy (handle->contacts);
+ }
+
+ GNUNET_free(handle->name);
+}
+
+void
+set_handle_name (struct GNUNET_MESSENGER_Handle *handle, const char *name)
+{
+ if (handle->name)
+ GNUNET_free(handle->name);
+
+ handle->name = name? GNUNET_strdup(name) : NULL;
+}
+
+const char*
+get_handle_name (const struct GNUNET_MESSENGER_Handle *handle)
+{
+ return handle->name;
+}
+
+void
+set_handle_key (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_IDENTITY_PublicKey *pubkey)
+{
+ if (!handle->pubkey)
+ handle->pubkey = GNUNET_new(struct GNUNET_IDENTITY_PublicKey);
+
+ GNUNET_memcpy(handle->pubkey, pubkey, sizeof(*pubkey));
+}
+
+const struct GNUNET_IDENTITY_PublicKey*
+get_handle_key (const struct GNUNET_MESSENGER_Handle *handle)
+{
+ if (!handle->pubkey)
+ {
+ struct GNUNET_IDENTITY_Ego *anonymous = GNUNET_IDENTITY_ego_get_anonymous ();
+ static struct GNUNET_IDENTITY_PublicKey pubkey;
+
+ GNUNET_IDENTITY_ego_get_public_key (anonymous, &pubkey);
+
+ return &pubkey;
+ }
+
+ return handle->pubkey;
+}
+
+struct GNUNET_MESSENGER_Contact*
+get_handle_contact_by_pubkey (const struct GNUNET_MESSENGER_Handle *handle,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey)
+{
+ struct GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
+
+ struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multihashmap_get (handle->contacts, &hash);
+
+ if (contact)
+ return contact;
+
+ contact = create_contact (pubkey);
+
+ if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (handle->contacts, &hash, contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ return contact;
+
+ destroy_contact (contact);
+ return NULL;
+}
+
+void
+swap_handle_contact_by_pubkey (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Contact *contact,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey)
+{
+ const struct GNUNET_HashCode *hash = get_contact_id_from_key (contact);
+
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->contacts, hash, contact))
+ {
+ GNUNET_memcpy(&(contact->public_key), pubkey, sizeof(*pubkey));
+
+ hash = get_contact_id_from_key (contact);
+
+ GNUNET_CONTAINER_multihashmap_put (handle->contacts, hash, contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ }
+}
+
+void
+open_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
+
+ if (room)
+ room->opened = GNUNET_YES;
+}
+
+void
+entry_handle_room_at (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
+ const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
+
+ if (room)
+ add_to_list_tunnels (&(room->entries), door);
+}
+
+void
+close_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
+
+ if ((room) && (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->rooms, key, room)))
+ destroy_room (room);
+}
diff --git a/src/messenger/messenger_api_handle.h b/src/messenger/messenger_api_handle.h
new file mode 100644
index 000000000..d6cde0106
--- /dev/null
+++ b/src/messenger/messenger_api_handle.h
@@ -0,0 +1,174 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_handle.h
+ * @brief messenger api: client implementation of GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_MESSENGER_API_HANDLE_H
+#define GNUNET_MESSENGER_API_HANDLE_H
+
+#include "platform.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_peer_lib.h"
+
+#include "gnunet_messenger_service.h"
+
+#include "messenger_api_contact.h"
+#include "messenger_api_room.h"
+
+struct GNUNET_MESSENGER_Handle
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ struct GNUNET_MQ_Handle *mq;
+
+ GNUNET_MESSENGER_IdentityCallback identity_callback;
+ void *identity_cls;
+
+ GNUNET_MESSENGER_MessageCallback msg_callback;
+ void *msg_cls;
+
+ char *name;
+ struct GNUNET_IDENTITY_PublicKey *pubkey;
+
+ struct GNUNET_TIME_Relative reconnect_time;
+ struct GNUNET_SCHEDULER_Task *reconnect_task;
+
+ struct GNUNET_CONTAINER_MultiHashMap *rooms;
+ struct GNUNET_CONTAINER_MultiHashMap *contacts;
+};
+
+/**
+ * Creates and allocates a new handle using a given configuration and a custom message callback
+ * with a given closure for the client API.
+ *
+ * @param cfg Configuration
+ * @param msg_callback Message callback
+ * @param msg_cls Closure
+ * @return New handle
+ */
+struct GNUNET_MESSENGER_Handle*
+create_handle (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_MESSENGER_IdentityCallback identity_callback,
+ void *identity_cls, GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls);
+
+/**
+ * Destroys a <i>handle</i> and frees its memory fully from the client API.
+ *
+ * @param handle Handle
+ */
+void
+destroy_handle (struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Sets the name of a <i>handle</i> to a specific <i>name</i>.
+ *
+ * @param handle Handle
+ * @param name New name
+ */
+void
+set_handle_name (struct GNUNET_MESSENGER_Handle *handle, const char *name);
+
+/**
+ * Returns the current name of a given <i>handle</i> or NULL if no valid name was assigned yet.
+ *
+ * @param handle Handle
+ * @return Name of the handle or NULL
+ */
+const char*
+get_handle_name (const struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Sets the public key of a given <i>handle</i> to a specific public key.
+ *
+ * @param handle Handle
+ * @param pubkey Public key
+ */
+void
+set_handle_key (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_IDENTITY_PublicKey *pubkey);
+
+/**
+ * Returns the public key of a given <i>handle</i>.
+ *
+ * @param handle Handle
+ * @return Public key of the handle
+ */
+const struct GNUNET_IDENTITY_PublicKey*
+get_handle_key (const struct GNUNET_MESSENGER_Handle *handle);
+
+/**
+ * Returns a contact known to a <i>handle</i> identified by a given public key. If not matching
+ * contact is found, NULL gets returned.
+ *
+ * @param handle Handle
+ * @param pubkey Public key of EGO
+ * @return Contact or NULL
+ */
+struct GNUNET_MESSENGER_Contact*
+get_handle_contact_by_pubkey (const struct GNUNET_MESSENGER_Handle *handle,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey);
+
+/**
+ * Changes the public key for a <i>contact</i> known to a <i>handle</i> to a specific public key and
+ * updates local map entries to access the contact by its updated key.
+ *
+ * @param handle Handle
+ * @param contact Contact
+ * @param pubkey Public key of EGO
+ */
+void
+swap_handle_contact_by_pubkey (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Contact *contact,
+ const struct GNUNET_IDENTITY_PublicKey *pubkey);
+
+/**
+ * Marks a room known to a <i>handle</i> identified by a given <i>key</i> as open.
+ *
+ * @param handle Handle
+ * @param key Key of room
+ */
+void
+open_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
+
+/**
+ * Adds a tunnel for a room known to a <i>handle</i> identified by a given <i>key</i> to a
+ * list of opened connections.
+ *
+ * @param handle Handle
+ * @param door Peer identity
+ * @param key Key of room
+ */
+void
+entry_handle_room_at (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
+ const struct GNUNET_HashCode *key);
+
+/**
+ * Destroys and so implicitly closes a room known to a <i>handle</i> identified by a given <i>key</i>.
+ *
+ * @param handle Handle
+ * @param key Key of room
+ */
+void
+close_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
+
+#endif //GNUNET_MESSENGER_API_HANDLE_H
diff --git a/src/messenger/messenger_api_list_tunnels.c b/src/messenger/messenger_api_list_tunnels.c
new file mode 100644
index 000000000..13d8c1906
--- /dev/null
+++ b/src/messenger/messenger_api_list_tunnels.c
@@ -0,0 +1,112 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_list_tunnels.c
+ * @brief messenger api: client and service implementation of GNUnet MESSENGER service
+ */
+
+#include "messenger_api_list_tunnels.h"
+
+void
+init_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels)
+{
+ GNUNET_assert(tunnels);
+
+ tunnels->head = NULL;
+ tunnels->tail = NULL;
+}
+
+void
+clear_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels)
+{
+ GNUNET_assert(tunnels);
+
+ struct GNUNET_MESSENGER_ListTunnel *element;
+
+ for (element = tunnels->head; element; element = tunnels->head)
+ {
+ GNUNET_CONTAINER_DLL_remove(tunnels->head, tunnels->tail, element);
+ GNUNET_PEER_change_rc (element->peer, -1);
+ GNUNET_free(element);
+ }
+
+ tunnels->head = NULL;
+ tunnels->tail = NULL;
+}
+
+static int
+compare_list_tunnels (void *cls, struct GNUNET_MESSENGER_ListTunnel *element0,
+ struct GNUNET_MESSENGER_ListTunnel *element1)
+{
+ return ((int) element0->peer) - ((int) element1->peer);
+}
+
+void
+add_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer)
+{
+ struct GNUNET_MESSENGER_ListTunnel *element = GNUNET_new(struct GNUNET_MESSENGER_ListTunnel);
+
+ element->peer = GNUNET_PEER_intern (peer);
+
+ GNUNET_CONTAINER_DLL_insert_sorted(struct GNUNET_MESSENGER_ListTunnel, compare_list_tunnels, NULL, tunnels->head,
+ tunnels->tail, element);
+}
+
+struct GNUNET_MESSENGER_ListTunnel*
+find_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer, size_t *index)
+{
+ struct GNUNET_MESSENGER_ListTunnel *element;
+ struct GNUNET_PeerIdentity pid;
+
+ if (index)
+ *index = 0;
+
+ for (element = tunnels->head; element; element = element->next)
+ {
+ GNUNET_PEER_resolve (element->peer, &pid);
+
+ if (0 == GNUNET_memcmp(&pid, peer))
+ return element;
+
+ if (index)
+ (*index) = (*index) + 1;
+ }
+
+ return NULL;
+}
+
+int
+contains_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer)
+{
+ return find_list_tunnels (tunnels, peer, NULL) != NULL ? GNUNET_YES : GNUNET_NO;
+}
+
+struct GNUNET_MESSENGER_ListTunnel*
+remove_from_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, struct GNUNET_MESSENGER_ListTunnel *element)
+{
+ struct GNUNET_MESSENGER_ListTunnel *next = element->next;
+
+ GNUNET_CONTAINER_DLL_remove(tunnels->head, tunnels->tail, element);
+ GNUNET_PEER_change_rc (element->peer, -1);
+ GNUNET_free(element);
+
+ return next;
+}
diff --git a/src/messenger/messenger_api_list_tunnels.h b/src/messenger/messenger_api_list_tunnels.h
new file mode 100644
index 000000000..0240fceb8
--- /dev/null
+++ b/src/messenger/messenger_api_list_tunnels.h
@@ -0,0 +1,112 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_list_tunnels.h
+ * @brief messenger api: client and service implementation of GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_MESSENGER_API_LIST_TUNNELS_H
+#define GNUNET_MESSENGER_API_LIST_TUNNELS_H
+
+#include "platform.h"
+#include "gnunet_peer_lib.h"
+#include "gnunet_container_lib.h"
+
+struct GNUNET_MESSENGER_ListTunnel
+{
+ struct GNUNET_MESSENGER_ListTunnel *prev;
+ struct GNUNET_MESSENGER_ListTunnel *next;
+
+ GNUNET_PEER_Id peer;
+};
+
+struct GNUNET_MESSENGER_ListTunnels
+{
+ struct GNUNET_MESSENGER_ListTunnel *head;
+ struct GNUNET_MESSENGER_ListTunnel *tail;
+};
+
+/**
+ * Initializes list of tunnels peer identities as empty list.
+ *
+ * @param tunnels List of peer identities
+ */
+void
+init_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels);
+
+/**
+ * Clears the list of tunnels peer identities.
+ *
+ * @param tunnels List of peer identities
+ */
+void
+clear_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels);
+
+/**
+ * Adds a specific <i>peer</i> from a tunnel to the end of the list.
+ *
+ * @param tunnels List of peer identities
+ * @param peer Peer identity of tunnel
+ */
+void
+add_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Searches linearly through the list of tunnels peer identities for matching a
+ * specific <i>peer</i> identity and returns the matching element of the list.
+ *
+ * If no matching element is found, NULL gets returned.
+ *
+ * If <i>index</i> is not NULL, <i>index</i> will be overriden with the numeric index of
+ * the found element in the list. If no matching element is found, <i>index</i> will
+ * contain the total amount of elements in the list.
+ *
+ * @param tunnels List of peer identities
+ * @param peer Peer identity of tunnel
+ * @param[out] index Index of found element (optional)
+ * @return Element in the list with matching peer identity
+ */
+struct GNUNET_MESSENGER_ListTunnel*
+find_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer, size_t *index);
+
+/**
+ * Tests linearly if the list of tunnels peer identities contains a specific
+ * <i>peer</i> identity and returns GNUNET_YES on success, otherwise GNUNET_NO.
+ *
+ * @param tunnels List of peer identities
+ * @param peer Peer identity of tunnel
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+contains_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Removes a specific <i>element</i> from the list of tunnels peer identities and returns
+ * the next element in the list.
+ *
+ * @param tunnels List of peer identities
+ * @param element Element of the list
+ * @return Next element in the list
+ */
+struct GNUNET_MESSENGER_ListTunnel*
+remove_from_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, struct GNUNET_MESSENGER_ListTunnel *element);
+
+#endif //GNUNET_MESSENGER_API_LIST_TUNNELS_H
diff --git a/src/messenger/messenger_api_message.c b/src/messenger/messenger_api_message.c
new file mode 100644
index 000000000..fdab60eef
--- /dev/null
+++ b/src/messenger/messenger_api_message.c
@@ -0,0 +1,602 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_message.c
+ * @brief messenger api: client and service implementation of GNUnet MESSENGER service
+ */
+
+#include "messenger_api_message.h"
+
+struct GNUNET_MESSENGER_MessageSignature
+{
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode hash;
+};
+
+struct GNUNET_MESSENGER_ShortMessage
+{
+ enum GNUNET_MESSENGER_MessageKind kind;
+ struct GNUNET_MESSENGER_MessageBody body;
+};
+
+struct GNUNET_MESSENGER_Message*
+create_message (enum GNUNET_MESSENGER_MessageKind kind)
+{
+ struct GNUNET_MESSENGER_Message *message = GNUNET_new(struct GNUNET_MESSENGER_Message);
+
+ message->header.kind = kind;
+
+ switch (message->header.kind)
+ {
+ case GNUNET_MESSENGER_KIND_NAME:
+ message->body.name.name = NULL;
+ break;
+ case GNUNET_MESSENGER_KIND_TEXT:
+ message->body.text.text = NULL;
+ break;
+ case GNUNET_MESSENGER_KIND_FILE:
+ message->body.file.uri = NULL;
+ break;
+ case GNUNET_MESSENGER_KIND_PRIVATE:
+ message->body.private.length = 0;
+ message->body.private.data = NULL;
+ break;
+ default:
+ break;
+ }
+
+ return message;
+}
+
+struct GNUNET_MESSENGER_Message*
+copy_message (const struct GNUNET_MESSENGER_Message *message)
+{
+ struct GNUNET_MESSENGER_Message *copy = GNUNET_new(struct GNUNET_MESSENGER_Message);
+
+ GNUNET_memcpy(copy, message, sizeof(struct GNUNET_MESSENGER_Message));
+
+ switch (message->header.kind)
+ {
+ case GNUNET_MESSENGER_KIND_NAME:
+ copy->body.name.name = GNUNET_strdup(message->body.name.name);
+ break;
+ case GNUNET_MESSENGER_KIND_TEXT:
+ copy->body.text.text = GNUNET_strdup(message->body.text.text);
+ break;
+ case GNUNET_MESSENGER_KIND_FILE:
+ copy->body.file.uri = GNUNET_strdup(message->body.file.uri);
+ break;
+ case GNUNET_MESSENGER_KIND_PRIVATE:
+ copy->body.private.data = copy->body.private.length ? GNUNET_malloc(copy->body.private.length) : NULL;
+
+ if (copy->body.private.data)
+ {
+ GNUNET_memcpy(copy->body.private.data, message->body.private.data, copy->body.private.length);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return copy;
+}
+
+static void
+destroy_message_body (enum GNUNET_MESSENGER_MessageKind kind, struct GNUNET_MESSENGER_MessageBody *body)
+{
+ switch (kind)
+ {
+ case GNUNET_MESSENGER_KIND_NAME:
+ GNUNET_free(body->name.name);
+ break;
+ case GNUNET_MESSENGER_KIND_TEXT:
+ GNUNET_free(body->text.text);
+ break;
+ case GNUNET_MESSENGER_KIND_FILE:
+ GNUNET_free(body->file.uri);
+ break;
+ case GNUNET_MESSENGER_KIND_PRIVATE:
+ GNUNET_free(body->private.data);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+destroy_message (struct GNUNET_MESSENGER_Message *message)
+{
+ destroy_message_body (message->header.kind, &(message->body));
+
+ GNUNET_free(message);
+}
+
+static void
+fold_short_message (const struct GNUNET_MESSENGER_Message *message, struct GNUNET_MESSENGER_ShortMessage *shortened)
+{
+ shortened->kind = message->header.kind;
+
+ GNUNET_memcpy(&(shortened->body), &(message->body), sizeof(struct GNUNET_MESSENGER_MessageBody));
+}
+
+static void
+unfold_short_message (struct GNUNET_MESSENGER_ShortMessage *shortened, struct GNUNET_MESSENGER_Message *message)
+{
+ destroy_message_body (message->header.kind, &(message->body));
+
+ message->header.kind = shortened->kind;
+
+ GNUNET_memcpy(&(message->body), &(shortened->body), sizeof(struct GNUNET_MESSENGER_MessageBody));
+}
+
+#define member_size(type, member) sizeof(((type*) NULL)->member)
+
+static uint16_t
+get_message_body_kind_size (enum GNUNET_MESSENGER_MessageKind kind)
+{
+ uint16_t length = 0;
+
+ switch (kind)
+ {
+ case GNUNET_MESSENGER_KIND_INFO:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.info.host_key);
+ length += member_size(struct GNUNET_MESSENGER_Message, body.info.unique_id);
+ break;
+ case GNUNET_MESSENGER_KIND_JOIN:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.join.key);
+ break;
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ break;
+ case GNUNET_MESSENGER_KIND_NAME:
+ break;
+ case GNUNET_MESSENGER_KIND_KEY:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.key.key);
+ break;
+ case GNUNET_MESSENGER_KIND_PEER:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.peer.peer);
+ break;
+ case GNUNET_MESSENGER_KIND_ID:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.id.id);
+ break;
+ case GNUNET_MESSENGER_KIND_MISS:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.miss.peer);
+ break;
+ case GNUNET_MESSENGER_KIND_MERGE:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.merge.previous);
+ break;
+ case GNUNET_MESSENGER_KIND_REQUEST:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.request.hash);
+ break;
+ case GNUNET_MESSENGER_KIND_INVITE:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.invite.door);
+ length += member_size(struct GNUNET_MESSENGER_Message, body.invite.key);
+ break;
+ case GNUNET_MESSENGER_KIND_TEXT:
+ break;
+ case GNUNET_MESSENGER_KIND_FILE:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.file.key);
+ length += member_size(struct GNUNET_MESSENGER_Message, body.file.hash);
+ length += NAME_MAX;
+ break;
+ case GNUNET_MESSENGER_KIND_PRIVATE:
+ length += member_size(struct GNUNET_MESSENGER_Message, body.private.key);
+ break;
+ default:
+ break;
+ }
+
+ return length;
+}
+
+uint16_t
+get_message_kind_size (enum GNUNET_MESSENGER_MessageKind kind)
+{
+ uint16_t length = 0;
+
+ length += member_size(struct GNUNET_MESSENGER_Message, header.signature);
+ length += member_size(struct GNUNET_MESSENGER_Message, header.timestamp);
+ length += member_size(struct GNUNET_MESSENGER_Message, header.sender_id);
+ length += member_size(struct GNUNET_MESSENGER_Message, header.previous);
+ length += member_size(struct GNUNET_MESSENGER_Message, header.kind);
+
+ return length + get_message_body_kind_size (kind);
+}
+
+static uint16_t
+get_message_body_size (enum GNUNET_MESSENGER_MessageKind kind, const struct GNUNET_MESSENGER_MessageBody *body)
+{
+ uint16_t length = 0;
+
+ switch (kind)
+ {
+ case GNUNET_MESSENGER_KIND_NAME:
+ length += (body->name.name? strlen (body->name.name) : 0);
+ break;
+ case GNUNET_MESSENGER_KIND_TEXT:
+ length += strlen (body->text.text);
+ break;
+ case GNUNET_MESSENGER_KIND_FILE:
+ length += strlen (body->file.uri);
+ break;
+ case GNUNET_MESSENGER_KIND_PRIVATE:
+ length += body->private.length;
+ break;
+ default:
+ break;
+ }
+
+ return length;
+}
+
+uint16_t
+get_message_size (const struct GNUNET_MESSENGER_Message *message)
+{
+ return get_message_kind_size (message->header.kind) + get_message_body_size (message->header.kind, &(message->body));
+}
+
+static uint16_t
+get_short_message_size (const struct GNUNET_MESSENGER_ShortMessage *message)
+{
+ if (message)
+ return sizeof(message->kind) + get_message_body_kind_size (message->kind)
+ + get_message_body_size (message->kind, &(message->body));
+ else
+ return sizeof(message->kind);
+}
+
+#define min(x, y) (x < y? x : y)
+
+#define encode_step_ext(dst, offset, src, size) do { \
+ GNUNET_memcpy(dst + offset, src, size); \
+ offset += size; \
+} while (0)
+
+#define encode_step(dst, offset, src) do { \
+ encode_step_ext(dst, offset, src, sizeof(*src)); \
+} while(0)
+
+static void
+encode_message_body (enum GNUNET_MESSENGER_MessageKind kind, const struct GNUNET_MESSENGER_MessageBody *body,
+ uint16_t length, char *buffer, uint16_t offset)
+{
+ switch (kind)
+ {
+ case GNUNET_MESSENGER_KIND_INFO:
+ encode_step(buffer, offset, &(body->info.host_key));
+ encode_step(buffer, offset, &(body->info.unique_id));
+ break;
+ case GNUNET_MESSENGER_KIND_JOIN:
+ encode_step(buffer, offset, &(body->join.key));
+ break;
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ break;
+ case GNUNET_MESSENGER_KIND_NAME:
+ if (body->name.name)
+ encode_step_ext(buffer, offset, body->name.name, min(length - offset, strlen(body->name.name)));
+ break;
+ case GNUNET_MESSENGER_KIND_KEY:
+ encode_step(buffer, offset, &(body->key.key));
+ break;
+ case GNUNET_MESSENGER_KIND_PEER:
+ encode_step(buffer, offset, &(body->peer.peer));
+ break;
+ case GNUNET_MESSENGER_KIND_ID:
+ encode_step(buffer, offset, &(body->id.id));
+ break;
+ case GNUNET_MESSENGER_KIND_MISS:
+ encode_step(buffer, offset, &(body->miss.peer));
+ break;
+ case GNUNET_MESSENGER_KIND_MERGE:
+ encode_step(buffer, offset, &(body->merge.previous));
+ break;
+ case GNUNET_MESSENGER_KIND_REQUEST:
+ encode_step(buffer, offset, &(body->request.hash));
+ break;
+ case GNUNET_MESSENGER_KIND_INVITE:
+ encode_step(buffer, offset, &(body->invite.door));
+ encode_step(buffer, offset, &(body->invite.key));
+ break;
+ case GNUNET_MESSENGER_KIND_TEXT:
+ encode_step_ext(buffer, offset, body->text.text, min(length - offset, strlen(body->text.text)));
+ break;
+ case GNUNET_MESSENGER_KIND_FILE:
+ encode_step(buffer, offset, &(body->file.key));
+ encode_step(buffer, offset, &(body->file.hash));
+ encode_step_ext(buffer, offset, body->file.name, NAME_MAX);
+ encode_step_ext(buffer, offset, body->file.uri, min(length - offset, strlen(body->file.uri)));
+ break;
+ case GNUNET_MESSENGER_KIND_PRIVATE:
+ encode_step(buffer, offset, &(body->private.key));
+ encode_step_ext(buffer, offset, body->private.data, min(length - offset, body->private.length));
+ break;
+ default:
+ break;
+ }
+}
+
+void
+encode_message (const struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer)
+{
+ uint16_t offset = 0;
+
+ encode_step(buffer, offset, &(message->header.signature));
+ encode_step(buffer, offset, &(message->header.timestamp));
+ encode_step(buffer, offset, &(message->header.sender_id));
+ encode_step(buffer, offset, &(message->header.previous));
+ encode_step(buffer, offset, &(message->header.kind));
+
+ encode_message_body (message->header.kind, &(message->body), length, buffer, offset);
+}
+
+static void
+encode_short_message (const struct GNUNET_MESSENGER_ShortMessage *message, uint16_t length, char *buffer)
+{
+ uint16_t offset = 0;
+
+ encode_step(buffer, offset, &(message->kind));
+
+ encode_message_body (message->kind, &(message->body), length, buffer, offset);
+}
+
+#define decode_step_ext(src, offset, dst, size) do { \
+ GNUNET_memcpy(dst, src + offset, size); \
+ offset += size; \
+} while (0)
+
+#define decode_step(src, offset, dst) do { \
+ decode_step_ext(src, offset, dst, sizeof(*dst)); \
+} while (0)
+
+#define decode_step_malloc(src, offset, dst, size, zero) do { \
+ dst = GNUNET_malloc(size + zero); \
+ if (zero) dst[size] = 0; \
+ decode_step_ext(src, offset, dst, size); \
+} while (0)
+
+static void
+decode_message_body (enum GNUNET_MESSENGER_MessageKind *kind, struct GNUNET_MESSENGER_MessageBody *body,
+ uint16_t length, const char *buffer, uint16_t offset)
+{
+ switch (*kind)
+ {
+ case GNUNET_MESSENGER_KIND_INFO:
+ decode_step(buffer, offset, &(body->info.host_key));
+ decode_step(buffer, offset, &(body->info.unique_id));
+ break;
+ case GNUNET_MESSENGER_KIND_JOIN:
+ decode_step(buffer, offset, &(body->join.key));
+ break;
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ break;
+ case GNUNET_MESSENGER_KIND_NAME:
+ if (length - offset > 0)
+ decode_step_malloc(buffer, offset, body->name.name, length - offset, 1);
+ else
+ body->name.name = NULL;
+ break;
+ case GNUNET_MESSENGER_KIND_KEY:
+ decode_step(buffer, offset, &(body->key.key));
+ break;
+ case GNUNET_MESSENGER_KIND_PEER:
+ decode_step(buffer, offset, &(body->peer.peer));
+ break;
+ case GNUNET_MESSENGER_KIND_ID:
+ decode_step(buffer, offset, &(body->id.id));
+ break;
+ case GNUNET_MESSENGER_KIND_MISS:
+ decode_step(buffer, offset, &(body->miss.peer));
+ break;
+ case GNUNET_MESSENGER_KIND_MERGE:
+ decode_step(buffer, offset, &(body->merge.previous));
+ break;
+ case GNUNET_MESSENGER_KIND_REQUEST:
+ decode_step(buffer, offset, &(body->request.hash));
+ break;
+ case GNUNET_MESSENGER_KIND_INVITE:
+ decode_step(buffer, offset, &(body->invite.door));
+ decode_step(buffer, offset, &(body->invite.key));
+ break;
+ case GNUNET_MESSENGER_KIND_TEXT:
+ decode_step_malloc(buffer, offset, body->text.text, length - offset, 1);
+ break;
+ case GNUNET_MESSENGER_KIND_FILE:
+ decode_step(buffer, offset, &(body->file.key));
+ decode_step(buffer, offset, &(body->file.hash));
+ decode_step_ext(buffer, offset, body->file.name, NAME_MAX);
+ decode_step_malloc(buffer, offset, body->file.uri, length - offset, 1);
+ break;
+ case GNUNET_MESSENGER_KIND_PRIVATE:
+ decode_step(buffer, offset, &(body->private.key));
+
+ body->private.length = (length - offset);
+ decode_step_malloc(buffer, offset, body->private.data, length - offset, 0);
+ break;
+ default:
+ *kind = GNUNET_MESSENGER_KIND_UNKNOWN;
+ break;
+ }
+}
+
+int
+decode_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, const char *buffer)
+{
+ uint16_t offset = 0;
+
+ if (length < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN))
+ return GNUNET_NO;
+
+ decode_step(buffer, offset, &(message->header.signature));
+ decode_step(buffer, offset, &(message->header.timestamp));
+ decode_step(buffer, offset, &(message->header.sender_id));
+ decode_step(buffer, offset, &(message->header.previous));
+ decode_step(buffer, offset, &(message->header.kind));
+
+ if (length < get_message_kind_size (message->header.kind))
+ return GNUNET_NO;
+
+ decode_message_body (&(message->header.kind), &(message->body), length, buffer, offset);
+
+ return GNUNET_YES;
+}
+
+static int
+decode_short_message (struct GNUNET_MESSENGER_ShortMessage *message, uint16_t length, const char *buffer)
+{
+ uint16_t offset = 0;
+
+ if (length < get_short_message_size (NULL))
+ return GNUNET_NO;
+
+ decode_step(buffer, offset, &(message->kind));
+
+ if (length < get_short_message_size (message))
+ return GNUNET_NO;
+
+ decode_message_body (&(message->kind), &(message->body), length, buffer, offset);
+
+ return GNUNET_YES;
+}
+
+void
+hash_message (uint16_t length, const char *buffer, struct GNUNET_HashCode *hash)
+{
+ GNUNET_CRYPTO_hash (buffer + sizeof(struct GNUNET_CRYPTO_EcdsaSignature),
+ length - sizeof(struct GNUNET_CRYPTO_EcdsaSignature), hash);
+}
+
+void
+sign_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer,
+ const struct GNUNET_HashCode *hash, const struct GNUNET_MESSENGER_Ego *ego)
+{
+ struct GNUNET_MESSENGER_MessageSignature signature;
+
+ signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
+ signature.purpose.size = htonl (sizeof(signature));
+
+ GNUNET_memcpy(&(signature.hash), hash, sizeof(struct GNUNET_HashCode));
+
+ GNUNET_IDENTITY_sign(&(ego->priv), &signature, &(message->header.signature));
+ GNUNET_memcpy(buffer, &(message->header.signature), sizeof(struct GNUNET_CRYPTO_EcdsaSignature));
+}
+
+int
+verify_message (const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash,
+ const struct GNUNET_IDENTITY_PublicKey *key)
+{
+ struct GNUNET_MESSENGER_MessageSignature signature;
+
+ signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
+ signature.purpose.size = htonl (sizeof(signature));
+
+ GNUNET_memcpy(&(signature.hash), hash, sizeof(struct GNUNET_HashCode));
+
+ return GNUNET_IDENTITY_signature_verify(GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE, &signature,
+ &(message->header.signature), key);
+}
+
+int
+encrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PublicKey *key)
+{
+ struct GNUNET_MESSENGER_ShortMessage shortened;
+
+ fold_short_message (message, &shortened);
+
+ const uint16_t length = get_short_message_size (&shortened);
+
+ message->header.kind = GNUNET_MESSENGER_KIND_PRIVATE;
+ message->body.private.data = GNUNET_malloc(length);
+
+ encode_short_message (&shortened, length, message->body.private.data);
+
+ if (GNUNET_IDENTITY_encrypt (message->body.private.data, length, key, &(message->body.private.key),
+ message->body.private.data)
+ == length)
+ {
+ destroy_message_body (shortened.kind, &(shortened.body));
+ return GNUNET_YES;
+ }
+ else
+ {
+ unfold_short_message (&shortened, message);
+ return GNUNET_NO;
+ }
+}
+
+int
+decrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PrivateKey *key)
+{
+ if (message->body.private.length != GNUNET_IDENTITY_decrypt (message->body.private.data,
+ message->body.private.length, key,
+ &(message->body.private.key),
+ message->body.private.data))
+ return GNUNET_NO;
+
+ struct GNUNET_MESSENGER_ShortMessage shortened;
+
+ if (GNUNET_YES != decode_short_message (&shortened, message->body.private.length, message->body.private.data))
+ return GNUNET_NO;
+
+ unfold_short_message (&shortened, message);
+ return GNUNET_YES;
+}
+
+struct GNUNET_MQ_Envelope*
+pack_message (struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
+ const struct GNUNET_MESSENGER_Ego *ego, int mode)
+{
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Packing message: %u\n", message->header.kind);
+
+ struct GNUNET_MessageHeader *header;
+
+ uint16_t length = get_message_size (message);
+
+ struct GNUNET_MQ_Envelope *env;
+ char *buffer;
+
+ if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE == mode)
+ {
+ env = GNUNET_MQ_msg_extra(header, length, GNUNET_MESSAGE_TYPE_CADET_CLI);
+
+ buffer = (char*) &(header[1]);
+ }
+ else
+ {
+ env = NULL;
+
+ buffer = GNUNET_malloc(length);
+ }
+
+ encode_message (message, length, buffer);
+
+ if (hash)
+ {
+ hash_message (length, buffer, hash);
+
+ if (ego)
+ sign_message (message, length, buffer, hash, ego);
+ }
+
+ if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE != mode)
+ GNUNET_free(buffer);
+
+ return env;
+}
diff --git a/src/messenger/messenger_api_message.h b/src/messenger/messenger_api_message.h
new file mode 100644
index 000000000..0f0a97e9c
--- /dev/null
+++ b/src/messenger/messenger_api_message.h
@@ -0,0 +1,190 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_message.h
+ * @brief messenger api: client and service implementation of GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_MESSENGER_API_MESSAGE_H
+#define GNUNET_MESSENGER_API_MESSAGE_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_mq_lib.h"
+#include "gnunet_signatures.h"
+
+#include "gnunet_messenger_service.h"
+
+#include "messenger_api_ego.h"
+
+/**
+ * Creates and allocates a new message with a specific <i>kind</i>.
+ *
+ * @param kind Kind of message
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+create_message (enum GNUNET_MESSENGER_MessageKind kind);
+
+/**
+ * Creates and allocates a copy of a given <i>message</i>.
+ *
+ * @param message Message
+ * @return New message
+ */
+struct GNUNET_MESSENGER_Message*
+copy_message (const struct GNUNET_MESSENGER_Message *message);
+
+/**
+ * Destroys a message and frees its memory fully.
+ *
+ * @param message Message
+ */
+void
+destroy_message (struct GNUNET_MESSENGER_Message *message);
+
+/**
+ * Returns the minimal size in bytes to encode a message of a specific <i>kind</i>.
+ *
+ * @param kind Kind of message
+ * @return Minimal size to encode
+ */
+uint16_t
+get_message_kind_size (enum GNUNET_MESSENGER_MessageKind kind);
+
+/**
+ * Returns the exact size in bytes to encode a given <i>message</i>.
+ *
+ * @param message Message
+ * @return Size to encode
+ */
+uint16_t
+get_message_size (const struct GNUNET_MESSENGER_Message *message);
+
+/**
+ * Encodes a given <i>message</i> into a <i>buffer</i> of a maximal <i>length</i> in bytes.
+ *
+ * @param message Message
+ * @param length Maximal length to encode
+ * @param[out] buffer Buffer
+ */
+void
+encode_message (const struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer);
+
+/**
+ * Decodes a <i>message</i> from a given <i>buffer</i> of a maximal <i>length</i> in bytes.
+ *
+ * If the buffer is too small for a message of its decoded kind the function fails with
+ * resulting GNUNET_NO after decoding only the messages header.
+ *
+ * On success the function returns GNUNET_YES.
+ *
+ * @param[out] message Message
+ * @param length Maximal length to decode
+ * @param buffer Buffer
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+decode_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, const char *buffer);
+
+/**
+ * Calculates a <i>hash</i> of a given <i>buffer</i> of a <i>length</i> in bytes.
+ *
+ * @param length Length of buffer
+ * @param buffer Buffer
+ * @param[out] hash Hash
+ */
+void
+hash_message (uint16_t length, const char *buffer, struct GNUNET_HashCode *hash);
+
+/**
+ * Signs the <i>hash</i> of a <i>message</i> with a given <i>ego</i> and writes the signature
+ * into the <i>buffer</i> as well.
+ *
+ * @param[out] message Message
+ * @param length Length of buffer
+ * @param[out] buffer Buffer
+ * @param hash Hash of message
+ * @param ego EGO
+ */
+void
+sign_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer,
+ const struct GNUNET_HashCode *hash, const struct GNUNET_MESSENGER_Ego *ego);
+
+/**
+ * Verifies the signature of a given <i>message</i> and its <i>hash</i> with a specific
+ * public key. The function returns GNUNET_OK if the signature was valid, otherwise
+ * GNUNET_SYSERR.
+ *
+ * @param message Message
+ * @param hash Hash of message
+ * @param key Public key of EGO
+ * @return GNUNET_OK on success, otherwise GNUNET_SYSERR
+ */
+int
+verify_message (const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash,
+ const struct GNUNET_IDENTITY_PublicKey *key);
+
+/**
+ * Encrypts a <i>message</i> using a given public <i>key</i> and replaces its body
+ * and kind with the now private encrypted <i>message</i>. The function returns
+ * GNUNET_YES if the operation succeeded, otherwise GNUNET_NO.
+ *
+ * @param message Message
+ * @param key Public key of EGO
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+encrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PublicKey *key);
+
+/**
+ * Decrypts a private <i>message</i> using a given private <i>key</i> and replaces its body
+ * and kind with the inner encrypted message. The function returns GNUNET_YES if the
+ * operation succeeded, otherwise GNUNET_NO.
+ *
+ * @param message Message
+ * @param key Private key of EGO
+ * @return GNUNET_YES on success, otherwise GNUNET_NO
+ */
+int
+decrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PrivateKey *key);
+
+#define GNUNET_MESSENGER_PACK_MODE_ENVELOPE 0x1
+#define GNUNET_MESSENGER_PACK_MODE_UNKNOWN 0x0
+
+/**
+ * Encodes the <i>message</i> to pack it into a newly allocated envelope if <i>mode</i>
+ * is equal to GNUNET_MESSENGER_PACK_MODE_ENVELOPE. Independent of the mode the message
+ * will be hashed if <i>hash</i> is not NULL and it will be signed if the <i>ego</i> is
+ * not NULL.
+ *
+ * @param[out] message Message
+ * @param[out] hash Hash of message
+ * @param ego EGO to sign
+ * @param mode Mode of packing
+ * @return Envelope or NULL
+ */
+struct GNUNET_MQ_Envelope*
+pack_message (struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
+ const struct GNUNET_MESSENGER_Ego *ego, int mode);
+
+#endif //GNUNET_MESSENGER_API_MESSAGE_H
diff --git a/src/messenger/messenger_api_room.c b/src/messenger/messenger_api_room.c
new file mode 100644
index 000000000..5fedf1a78
--- /dev/null
+++ b/src/messenger/messenger_api_room.c
@@ -0,0 +1,189 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_room.c
+ * @brief messenger api: client implementation of GNUnet MESSENGER service
+ */
+
+#include "messenger_api_room.h"
+
+#include "messenger_api_handle.h"
+
+struct GNUNET_MESSENGER_Room*
+create_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
+{
+ struct GNUNET_MESSENGER_Room *room = GNUNET_new(struct GNUNET_MESSENGER_Room);
+
+ room->handle = handle;
+ GNUNET_memcpy(&(room->key), key, sizeof(*key));
+
+ room->opened = GNUNET_NO;
+ room->contact_id = NULL;
+
+ room->members = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
+
+ init_list_tunnels (&(room->entries));
+
+ room->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
+
+ return room;
+}
+
+static int
+iterate_destroy_message (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct GNUNET_MESSENGER_Message *message = value;
+
+ destroy_message (message);
+
+ return GNUNET_YES;
+}
+
+void
+destroy_room (struct GNUNET_MESSENGER_Room *room)
+{
+ if (room->members)
+ GNUNET_CONTAINER_multishortmap_destroy (room->members);
+
+ clear_list_tunnels (&(room->entries));
+
+ if (room->messages)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (room->messages, iterate_destroy_message, NULL);
+
+ GNUNET_CONTAINER_multihashmap_destroy (room->messages);
+ }
+
+ if (room->contact_id)
+ GNUNET_free(room->contact_id);
+
+ GNUNET_free(room);
+}
+
+const struct GNUNET_MESSENGER_Message*
+get_room_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash)
+{
+ return GNUNET_CONTAINER_multihashmap_get (room->messages, hash);
+}
+
+static void
+handle_join_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Contact *contact = get_handle_contact_by_pubkey (room->handle, &(message->body.join.key));
+
+ if (contact)
+ GNUNET_CONTAINER_multishortmap_put (room->members, &(message->header.sender_id), contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+}
+
+static void
+handle_leave_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ GNUNET_CONTAINER_multishortmap_remove_all (room->members, &(message->header.sender_id));
+}
+
+static void
+handle_name_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
+ &(message->header.sender_id));
+
+ if (contact)
+ set_contact_name (contact, message->body.name.name);
+}
+
+static void
+handle_key_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
+ &(message->header.sender_id));
+
+ if (contact)
+ swap_handle_contact_by_pubkey (room->handle, contact, &(message->body.key.key));
+}
+
+static void
+handle_id_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
+ &(message->header.sender_id));
+
+ if ((contact) && (GNUNET_OK
+ == GNUNET_CONTAINER_multishortmap_put (room->members, &(message->body.id.id), contact,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
+ GNUNET_CONTAINER_multishortmap_remove (room->members, &(message->header.sender_id), contact);
+}
+
+static void
+handle_miss_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ if ((room->contact_id) && (0 == GNUNET_memcmp(&(message->header.sender_id), room->contact_id)))
+ {
+ struct GNUNET_MESSENGER_ListTunnel *match = find_list_tunnels (&(room->entries), &(message->body.miss.peer), NULL);
+
+ if (match)
+ remove_from_list_tunnels (&(room->entries), match);
+ }
+}
+
+void
+handle_room_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (room->messages, hash))
+ return;
+
+ switch (message->header.kind)
+ {
+ case GNUNET_MESSENGER_KIND_JOIN:
+ handle_join_message (room, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_LEAVE:
+ handle_leave_message (room, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_NAME:
+ handle_name_message (room, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_KEY:
+ handle_key_message (room, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_ID:
+ handle_id_message (room, message, hash);
+ break;
+ case GNUNET_MESSENGER_KIND_MISS:
+ handle_miss_message (room, message, hash);
+ break;
+ default:
+ break;
+ }
+
+ struct GNUNET_MESSENGER_Message *clone = copy_message (message);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages, hash, clone,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ destroy_message (clone);
+}
diff --git a/src/messenger/messenger_api_room.h b/src/messenger/messenger_api_room.h
new file mode 100644
index 000000000..0038128d8
--- /dev/null
+++ b/src/messenger/messenger_api_room.h
@@ -0,0 +1,95 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @author Tobias Frisch
+ * @file src/messenger/messenger_api_room.h
+ * @brief messenger api: client implementation of GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_MESSENGER_API_ROOM_H
+#define GNUNET_MESSENGER_API_ROOM_H
+
+#include "platform.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_crypto_lib.h"
+
+#include "gnunet_messenger_service.h"
+
+#include "messenger_api_list_tunnels.h"
+#include "messenger_api_contact.h"
+#include "messenger_api_message.h"
+
+struct GNUNET_MESSENGER_Room
+{
+ struct GNUNET_MESSENGER_Handle *handle;
+ struct GNUNET_HashCode key;
+
+ int opened;
+
+ struct GNUNET_ShortHashCode *contact_id;
+
+ struct GNUNET_CONTAINER_MultiShortmap *members;
+ struct GNUNET_MESSENGER_ListTunnels entries;
+
+ struct GNUNET_CONTAINER_MultiHashMap *messages;
+};
+
+/**
+ * Creates and allocates a new room for a <i>handle</i> with a given <i>key</i> for the client API.
+ *
+ * @param handle Handle
+ * @param key Key of room
+ * @return New room
+ */
+struct GNUNET_MESSENGER_Room*
+create_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
+
+/**
+ * Destroys a room and frees its memory fully from the client API.
+ *
+ * @param room Room
+ */
+void
+destroy_room (struct GNUNET_MESSENGER_Room *room);
+
+/**
+ * Returns a message locally stored from a map for a given <i>hash</i> in a <i>room</i>. If no matching
+ * message is found, NULL gets returned.
+ *
+ * @param room Room
+ * @param hash Hash of message
+ * @return Message or NULL
+ */
+const struct GNUNET_MESSENGER_Message*
+get_room_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash);
+
+/**
+ * Handles a <i>message</i> with a given <i>hash</i> in a <i>room</i> for the client API to update
+ * members and its information. The function also stores the message in map locally for access afterwards.
+ *
+ * @param room Room
+ * @param message Message
+ * @param hash Hash of message
+ */
+void
+handle_room_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash);
+
+#endif //GNUNET_MESSENGER_API_ROOM_H
diff --git a/src/messenger/test_messenger.c b/src/messenger/test_messenger.c
new file mode 100644
index 000000000..b42dfe6d9
--- /dev/null
+++ b/src/messenger/test_messenger.c
@@ -0,0 +1,187 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @file messenger/test_messenger.c
+ * @author Tobias Frisch
+ * @brief Test for the messenger service using cadet API.
+ */
+#include <stdio.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_messenger_service.h"
+
+/**
+ * How long until we really give up on a particular testcase portion?
+ */
+#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+ 60)
+
+/**
+ * How long until we give up on any particular operation (and retry)?
+ */
+#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+#define TESTER_NAME "tester"
+
+static int status = 1;
+
+static struct GNUNET_SCHEDULER_Task *die_task = NULL;
+static struct GNUNET_SCHEDULER_Task *op_task = NULL;
+
+struct GNUNET_MESSENGER_Handle *messenger = NULL;
+
+static void
+end (void *cls)
+{
+ die_task = NULL;
+
+ if (op_task)
+ {
+ GNUNET_SCHEDULER_cancel (op_task);
+ op_task = NULL;
+ }
+
+ if (messenger)
+ {
+ GNUNET_MESSENGER_disconnect(messenger);
+ messenger = NULL;
+ }
+
+ status = 0;
+}
+
+
+static void
+end_badly (void *cls)
+{
+ fprintf (stderr, "Testcase failed (timeout).\n");
+
+ end (NULL);
+ status = 1;
+}
+
+static void
+end_operation (void *cls)
+{
+ op_task = NULL;
+
+ fprintf (stderr, "Testcase failed (operation: '%s').\n", cls? (const char*) cls : "unknown");
+
+ if (die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ end (NULL);
+ status = 1;
+}
+
+static int identity_counter = 0;
+
+/**
+ * Function called when an identity is retrieved.
+ *
+ * @param cls Closure
+ * @param handle Handle of messenger service
+ */
+static void
+on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
+{
+ if (op_task)
+ {
+ GNUNET_SCHEDULER_cancel (op_task);
+ op_task = NULL;
+ }
+
+ const char* name = GNUNET_MESSENGER_get_name(handle);
+
+ if (0 != strcmp(name, TESTER_NAME))
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "name");
+ return;
+ }
+
+ struct GNUNET_IDENTITY_Ego* ego = GNUNET_IDENTITY_ego_get_anonymous();
+ struct GNUNET_IDENTITY_PublicKey anonymous_key;
+
+ GNUNET_IDENTITY_ego_get_public_key(ego, &anonymous_key);
+
+ const struct GNUNET_IDENTITY_PublicKey* key = GNUNET_MESSENGER_get_key(handle);
+
+ if (((!identity_counter) && (0 != GNUNET_memcmp(key, (&anonymous_key)))) ||
+ ((identity_counter) && (0 == GNUNET_memcmp(key, (&anonymous_key)))))
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "key");
+ return;
+ }
+
+ if (identity_counter) {
+ GNUNET_MESSENGER_disconnect(handle);
+
+ op_task = NULL;
+ messenger = NULL;
+
+ if (die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ die_task = GNUNET_SCHEDULER_add_now (&end, NULL);
+ return;
+ }
+
+ GNUNET_MESSENGER_update(messenger);
+ identity_counter++;
+}
+
+/**
+ * Main function for testcase.
+ *
+ * @param cls Closure
+ * @param cfg Configuration
+ * @param peer Peer for testing
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_TESTING_Peer *peer)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
+
+ identity_counter = 0;
+
+ op_task = GNUNET_SCHEDULER_add_delayed (BASE_TIMEOUT, &end_operation, "connect");
+ messenger = GNUNET_MESSENGER_connect(cfg, TESTER_NAME, &on_identity, NULL, NULL, NULL);
+}
+
+/**
+ * The main function.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main(int argc, char **argv)
+{
+ if (0 != GNUNET_TESTING_peer_run("test-messenger",
+ "test_messenger_api.conf",
+ &run, NULL))
+ return 1;
+
+ return status;
+}
diff --git a/src/messenger/test_messenger_anonymous.c b/src/messenger/test_messenger_anonymous.c
new file mode 100644
index 000000000..e2057acc4
--- /dev/null
+++ b/src/messenger/test_messenger_anonymous.c
@@ -0,0 +1,179 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @file messenger/test_messenger_anonymous.c
+ * @author Tobias Frisch
+ * @brief Test for the messenger service using cadet API.
+ */
+#include <stdio.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_messenger_service.h"
+
+/**
+ * How long until we really give up on a particular testcase portion?
+ */
+#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+ 60)
+
+/**
+ * How long until we give up on any particular operation (and retry)?
+ */
+#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+static int status = 1;
+
+static struct GNUNET_SCHEDULER_Task *die_task = NULL;
+static struct GNUNET_SCHEDULER_Task *op_task = NULL;
+
+struct GNUNET_MESSENGER_Handle *messenger = NULL;
+
+static void
+end (void *cls)
+{
+ die_task = NULL;
+
+ if (op_task)
+ {
+ GNUNET_SCHEDULER_cancel (op_task);
+ op_task = NULL;
+ }
+
+ if (messenger)
+ {
+ GNUNET_MESSENGER_disconnect(messenger);
+ messenger = NULL;
+ }
+
+ status = 0;
+}
+
+
+static void
+end_badly (void *cls)
+{
+ fprintf (stderr, "Testcase failed (timeout).\n");
+
+ end (NULL);
+ status = 1;
+}
+
+static void
+end_operation (void *cls)
+{
+ op_task = NULL;
+
+ fprintf (stderr, "Testcase failed (operation: '%s').\n", cls? (const char*) cls : "unknown");
+
+ if (die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ end (NULL);
+ status = 1;
+}
+
+/**
+ * Function called when an identity is retrieved.
+ *
+ * @param cls Closure
+ * @param handle Handle of messenger service
+ */
+static void
+on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
+{
+ if (op_task)
+ {
+ GNUNET_SCHEDULER_cancel (op_task);
+ op_task = NULL;
+ }
+
+ const char* name = GNUNET_MESSENGER_get_name(handle);
+
+ if (NULL != name)
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "name-anonymous");
+ return;
+ }
+
+ if (GNUNET_SYSERR != GNUNET_MESSENGER_update(handle))
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "update-fail");
+ return;
+ }
+
+ struct GNUNET_IDENTITY_Ego* ego = GNUNET_IDENTITY_ego_get_anonymous();
+ struct GNUNET_IDENTITY_PublicKey anonymous_key;
+
+ GNUNET_IDENTITY_ego_get_public_key(ego, &anonymous_key);
+
+ const struct GNUNET_IDENTITY_PublicKey* key = GNUNET_MESSENGER_get_key(handle);
+
+ if (0 != GNUNET_memcmp(key, (&anonymous_key)))
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "key-anonymous");
+ return;
+ }
+
+ GNUNET_MESSENGER_disconnect(handle);
+
+ messenger = NULL;
+
+ if (die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ die_task = GNUNET_SCHEDULER_add_now (&end, NULL);
+}
+
+/**
+ * Main function for testcase.
+ *
+ * @param cls Closure
+ * @param cfg Configuration
+ * @param peer Peer for testing
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_TESTING_Peer *peer)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
+
+ op_task = GNUNET_SCHEDULER_add_delayed (BASE_TIMEOUT, &end_operation, "connect");
+ messenger = GNUNET_MESSENGER_connect(cfg, NULL, &on_identity, NULL, NULL, NULL);
+}
+
+/**
+ * The main function.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main(int argc, char **argv)
+{
+ if (0 != GNUNET_TESTING_peer_run("test-messenger",
+ "test_messenger_api.conf",
+ &run, NULL))
+ return 1;
+
+ return status;
+}
diff --git a/src/messenger/test_messenger_comm0.c b/src/messenger/test_messenger_comm0.c
new file mode 100644
index 000000000..631b5b2c9
--- /dev/null
+++ b/src/messenger/test_messenger_comm0.c
@@ -0,0 +1,252 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020 GNUnet e.V.
+
+ GNUnet 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 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
+ */
+/**
+ * @file messenger/test_messenger_comm0.c
+ * @author Tobias Frisch
+ * @brief Test for the messenger service using cadet API.
+ */
+#include <stdio.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_logger_service.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_messenger_service.h"
+
+/**
+ * How long until we really give up on a particular testcase portion?
+ */
+#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+ 60)
+
+/**
+ * How long until we give up on any particular operation (and retry)?
+ */
+#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+static int status = 1;
+
+static struct GNUNET_SCHEDULER_Task *die_task = NULL;
+static struct GNUNET_SCHEDULER_Task *op_task = NULL;
+
+static void
+end (void *cls)
+{
+ die_task = NULL;
+
+ if (op_task)
+ {
+ GNUNET_SCHEDULER_cancel (op_task);
+ op_task = NULL;
+ }
+
+ GNUNET_SCHEDULER_shutdown ();
+ status = 0;
+}
+
+
+static void
+end_badly (void *cls)
+{
+ fprintf (stderr, "Testcase failed (timeout).\n");
+
+ end (NULL);
+ status = 1;
+}
+
+static void
+end_operation (void *cls)
+{
+ op_task = NULL;
+
+ fprintf (stderr, "Testcase failed (operation: '%s').\n", cls? (const char*) cls : "unknown");
+
+ if (die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ end (NULL);
+ status = 1;
+}
+
+static void
+end_error (void *cls)
+{
+ op_task = NULL;
+
+ fprintf (stderr, "Testcase failed (error: '%s').\n", cls? (const char*) cls : "unknown");
+ GNUNET_free(cls);
+
+ if (die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ end (NULL);
+ status = 1;
+}
+
+/**
+ * Function called whenever a message is received or sent.
+ *
+ * @param cls Closure
+ * @param room Room
+ * @param message Message
+ * @param hash Hash of message
+ */
+static void
+on_message (void *cls, const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ // TODO
+}
+
+/**
+ * Function called when an identity is retrieved.
+ *
+ * @param cls Closure
+ * @param handle Handle of messenger service
+ */
+static void
+on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
+{
+ // TODO
+}
+
+static void
+on_peer (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
+ const struct GNUNET_TESTBED_PeerInformation *pinfo,
+ const char *emsg)
+{
+ if (emsg)
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_error, GNUNET_strdup(emsg));
+ return;
+ }
+
+ if (pinfo->pit != GNUNET_TESTBED_PIT_CONFIGURATION)
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "config");
+ return;
+ }
+
+ struct GNUNET_MESSENGER_Handle *handle;
+ struct GNUNET_MESSENGER_Room *room;
+
+ fprintf (stderr, "MSG: connect\n");
+
+ handle = GNUNET_MESSENGER_connect(pinfo->result.cfg, "tester", &on_identity, NULL, &on_message, NULL);
+
+ struct GNUNET_HashCode hash;
+ GNUNET_CRYPTO_hash("test", 4, &hash);
+
+ fprintf (stderr, "MSG: open\n");
+
+ room = GNUNET_MESSENGER_open_room(handle, &hash);
+
+ fprintf (stderr, "MSG: close\n");
+
+ GNUNET_MESSENGER_close_room(room);
+
+ fprintf (stderr, "MSG: disconnect\n");
+
+ GNUNET_MESSENGER_disconnect(handle);
+
+ GNUNET_TESTBED_operation_done(op);
+
+}
+
+/**
+ * Main function for a peer of the testcase.
+ *
+ * @param cls Closure
+ * @param event Information about the event
+ */
+static void
+run (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
+{
+ if (GNUNET_TESTBED_ET_PEER_START != event->type)
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "start");
+ return;
+ }
+
+ GNUNET_TESTBED_peer_get_information(event->details.peer_start.peer,
+ GNUNET_TESTBED_PIT_CONFIGURATION,
+ on_peer, event->details.peer_start.peer);
+
+ fprintf (stderr, "MSG: barrier\n");
+
+ GNUNET_TESTBED_barrier_wait("exit", NULL, NULL);
+
+ fprintf (stderr, "MSG: exit\n");
+}
+
+static void
+exit_status (void *cls, const char *name,
+ struct GNUNET_TESTBED_Barrier *barrier,
+ enum GNUNET_TESTBED_BarrierStatus status,
+ const char *emsg)
+{
+ if (emsg)
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_error, GNUNET_strdup(emsg));
+ return;
+ }
+
+ if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
+ {
+ op_task = GNUNET_SCHEDULER_add_now (&end_operation, "exit");
+ return;
+ }
+ else if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED == status)
+ GNUNET_SCHEDULER_add_now(&end, NULL);
+}
+
+static void
+init (void *cls, struct GNUNET_TESTBED_RunHandle *h, unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers, unsigned int links_succeeded,
+ unsigned int links_failed)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
+
+ struct GNUNET_TESTBED_Controller *controller;
+
+ controller = GNUNET_TESTBED_run_get_controller_handle(h);
+
+ GNUNET_TESTBED_barrier_init(controller, "exit", num_peers, exit_status, NULL);
+}
+
+/**
+ * The main function.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main(int argc, char **argv)
+{
+ if (GNUNET_OK != GNUNET_TESTBED_test_run("test-messenger-comm0",
+ "test_messenger_api.conf",
+ 2, 0,
+ &run, NULL,
+ &init, NULL))
+ return 1;
+
+ return status;
+}
diff --git a/src/my/my_query_helper.c b/src/my/my_query_helper.c
index 526e57b8b..97ea04fd1 100644
--- a/src/my/my_query_helper.c
+++ b/src/my/my_query_helper.c
@@ -280,14 +280,14 @@ my_conv_rsa_public_key (void *cls,
MYSQL_BIND *qbind)
{
const struct GNUNET_CRYPTO_RsaPublicKey *rsa = qp->data;
- char *buf;
+ void *buf;
size_t buf_size;
(void) cls;
GNUNET_assert (1 == qp->num_params);
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rsa,
&buf);
- qbind->buffer = (void *) buf;
+ qbind->buffer = buf;
qbind->buffer_length = buf_size;
qbind->buffer_type = MYSQL_TYPE_BLOB;
return 1;
@@ -332,14 +332,14 @@ my_conv_rsa_signature (void *cls,
MYSQL_BIND *qbind)
{
const struct GNUNET_CRYPTO_RsaSignature *sig = qp->data;
- char *buf;
+ void *buf;
size_t buf_size;
(void) cls;
GNUNET_assert (1 == qp->num_params);
buf_size = GNUNET_CRYPTO_rsa_signature_encode (sig,
&buf);
- qbind->buffer = (void *) buf;
+ qbind->buffer = buf;
qbind->buffer_length = buf_size;
qbind->buffer_type = MYSQL_TYPE_BLOB;
return 1;
diff --git a/src/namecache/Makefile.am b/src/namecache/Makefile.am
index 5e80ea4c5..836a6b5d9 100644
--- a/src/namecache/Makefile.am
+++ b/src/namecache/Makefile.am
@@ -65,6 +65,7 @@ libgnunetnamecache_la_SOURCES = \
namecache.h
libgnunetnamecache_la_LIBADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL)
libgnunetnamecache_la_LDFLAGS = \
@@ -82,6 +83,7 @@ gnunet_namecache_SOURCES = \
gnunet-namecache.c
gnunet_namecache_LDADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la \
libgnunetnamecache.la \
$(GN_LIBINTL)
@@ -91,6 +93,7 @@ gnunet_service_namecache_SOURCES = \
gnunet_service_namecache_LDADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la \
libgnunetnamecache.la \
@@ -107,6 +110,8 @@ libgnunet_plugin_namecache_flat_la_SOURCES = \
libgnunet_plugin_namecache_flat_la_LIBADD = \
libgnunetnamecache.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
$(LTLIBINTL)
libgnunet_plugin_namecache_flat_la_LDFLAGS = \
@@ -118,6 +123,8 @@ libgnunet_plugin_namecache_sqlite_la_LIBADD = \
libgnunetnamecache.la \
$(top_builddir)/src/sq/libgnunetsq.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
$(LTLIBINTL)
libgnunet_plugin_namecache_sqlite_la_LDFLAGS = \
@@ -130,6 +137,8 @@ libgnunet_plugin_namecache_postgres_la_LIBADD = \
libgnunetnamecache.la \
$(top_builddir)/src/pq/libgnunetpq.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
$(LTLIBINTL)
libgnunet_plugin_namecache_postgres_la_LDFLAGS = \
diff --git a/src/namecache/gnunet-namecache.c b/src/namecache/gnunet-namecache.c
index 2e3c733e6..19f2a5766 100644
--- a/src/namecache/gnunet-namecache.c
+++ b/src/namecache/gnunet-namecache.c
@@ -51,7 +51,7 @@ static char *name;
/**
* Public key of the zone to look in.
*/
-static struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
+static struct GNUNET_IDENTITY_PublicKey pubkey;
/**
* Public key of the zone to look in, in ASCII.
@@ -177,7 +177,7 @@ run (void *cls,
}
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey, strlen (pkey), &pubkey))
+ GNUNET_IDENTITY_public_key_from_string (pkey, &pubkey))
{
fprintf (stderr, _ ("Invalid public key for zone `%s'\n"), pkey);
GNUNET_SCHEDULER_shutdown ();
diff --git a/src/namecache/gnunet-service-namecache.c b/src/namecache/gnunet-service-namecache.c
index 7cf216ce3..07bf30de9 100644
--- a/src/namecache/gnunet-service-namecache.c
+++ b/src/namecache/gnunet-service-namecache.c
@@ -184,40 +184,24 @@ handle_lookup_block_it (void *cls,
struct LookupBlockContext *lnc = cls;
struct GNUNET_MQ_Envelope *env;
struct LookupBlockResponseMessage *r;
- size_t esize;
size_t bsize;
- bsize = ntohl (block->purpose.size);
- if (bsize <
- (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof(struct
- GNUNET_TIME_AbsoluteNBO)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Malformed block.");
- lnc->status = GNUNET_SYSERR;
- return;
- }
- esize = ntohl (block->purpose.size)
- - sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
- - sizeof(struct GNUNET_TIME_AbsoluteNBO);
+ bsize = GNUNET_GNSRECORD_block_get_size (block);
env = GNUNET_MQ_msg_extra (r,
- esize,
+ bsize,
GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
r->gns_header.r_id = htonl (lnc->request_id);
- r->expire = block->expiration_time;
- r->signature = block->signature;
- r->derived_key = block->derived_key;
GNUNET_memcpy (&r[1],
- &block[1],
- esize);
+ block,
+ bsize);
GNUNET_STATISTICS_update (statistics,
"blocks found in cache",
1,
GNUNET_NO);
+ r->expire = GNUNET_TIME_absolute_hton (
+ GNUNET_GNSRECORD_block_get_expiration (block));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message with expiration time %s\n",
- GNUNET_STRINGS_absolute_time_to_string (
- GNUNET_TIME_absolute_ntoh (r->expire)));
+ "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message\n");
GNUNET_MQ_send (lnc->nc->mq,
env);
}
@@ -314,20 +298,11 @@ handle_block_cache (void *cls,
GNUNET_NO);
esize = ntohs (rp_msg->gns_header.header.size) - sizeof(struct
BlockCacheMessage);
- block = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Block) + esize);
- block->signature = rp_msg->signature;
- block->derived_key = rp_msg->derived_key;
- block->purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
- + sizeof(struct GNUNET_TIME_AbsoluteNBO)
- + esize);
- block->expiration_time = rp_msg->expire;
+ block = GNUNET_malloc (esize);
+ memcpy (block, &rp_msg[1], esize);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received NAMECACHE_BLOCK_CACHE message with expiration time %s\n",
- GNUNET_STRINGS_absolute_time_to_string (
- GNUNET_TIME_absolute_ntoh (block->expiration_time)));
- GNUNET_memcpy (&block[1],
- &rp_msg[1],
- esize);
+ "Received NAMECACHE_BLOCK_CACHE message with type %u\n",
+ htonl (block->type));
res = GSN_database->cache_block (GSN_database->cls,
block);
GNUNET_free (block);
diff --git a/src/namecache/namecache.h b/src/namecache/namecache.h
index 1657662c2..43c8cf85f 100644
--- a/src/namecache/namecache.h
+++ b/src/namecache/namecache.h
@@ -92,7 +92,7 @@ struct LookupBlockResponseMessage
/**
* Derived public key.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey derived_key;
+ struct GNUNET_IDENTITY_PublicKey derived_key;
/* follwed by encrypted block data */
};
@@ -121,7 +121,7 @@ struct BlockCacheMessage
/**
* Derived public key.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey derived_key;
+ struct GNUNET_IDENTITY_PublicKey derived_key;
/* follwed by encrypted block data */
};
diff --git a/src/namecache/namecache_api.c b/src/namecache/namecache_api.c
index 0c904c9ed..fdbf142a7 100644
--- a/src/namecache/namecache_api.c
+++ b/src/namecache/namecache_api.c
@@ -225,19 +225,11 @@ handle_lookup_block_response (void *cls,
size = ntohs (msg->gns_header.header.size)
- sizeof(struct LookupBlockResponseMessage);
{
- char buf[size + sizeof(struct GNUNET_GNSRECORD_Block)] GNUNET_ALIGN;
+ char buf[size] GNUNET_ALIGN;
struct GNUNET_GNSRECORD_Block *block;
block = (struct GNUNET_GNSRECORD_Block *) buf;
- block->signature = msg->signature;
- block->derived_key = msg->derived_key;
- block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
- block->purpose.size = htonl (size
- + sizeof(struct GNUNET_TIME_AbsoluteNBO)
- + sizeof(struct
- GNUNET_CRYPTO_EccSignaturePurpose));
- block->expiration_time = msg->expire;
- GNUNET_memcpy (&block[1],
+ GNUNET_memcpy (block,
&msg[1],
size);
if (GNUNET_OK !=
@@ -483,11 +475,7 @@ GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
if (NULL == h->mq)
return NULL;
- blen = ntohl (block->purpose.size);
- GNUNET_assert (blen > (sizeof(struct GNUNET_TIME_AbsoluteNBO)
- + sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)));
- blen -= (sizeof(struct GNUNET_TIME_AbsoluteNBO)
- + sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
+ blen = GNUNET_GNSRECORD_block_get_size (block);
rid = get_op_id (h);
qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
qe->nsh = h;
@@ -502,11 +490,8 @@ GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
blen,
GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE);
msg->gns_header.r_id = htonl (rid);
- msg->expire = block->expiration_time;
- msg->signature = block->signature;
- msg->derived_key = block->derived_key;
GNUNET_memcpy (&msg[1],
- &block[1],
+ block,
blen);
GNUNET_MQ_send (h->mq,
env);
diff --git a/src/namecache/plugin_namecache_flat.c b/src/namecache/plugin_namecache_flat.c
index 24f4f2570..eb7800051 100644
--- a/src/namecache/plugin_namecache_flat.c
+++ b/src/namecache/plugin_namecache_flat.c
@@ -207,10 +207,7 @@ store_and_free_entries (void *cls,
struct GNUNET_CRYPTO_HashAsciiEncoded query;
size_t block_size;
- block_size = ntohl (entry->block->purpose.size)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
- + sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
-
+ block_size = GNUNET_GNSRECORD_block_get_size (entry->block);
GNUNET_STRINGS_base64_encode ((char *) entry->block,
block_size,
&block_b64);
@@ -277,7 +274,7 @@ expire_blocks (void *cls,
struct GNUNET_TIME_Absolute expiration;
now = GNUNET_TIME_absolute_get ();
- expiration = GNUNET_TIME_absolute_ntoh (entry->block->expiration_time);
+ expiration = GNUNET_GNSRECORD_block_get_expiration (entry->block);
if (0 == GNUNET_TIME_absolute_get_difference (now,
expiration).rel_value_us)
@@ -319,12 +316,9 @@ namecache_cache_block (void *cls,
size_t block_size;
namecache_expire_blocks (plugin);
- GNUNET_CRYPTO_hash (&block->derived_key,
- sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
- &query);
- block_size = ntohl (block->purpose.size)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
- + sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
+ GNUNET_GNSRECORD_query_from_block (block,
+ &query);
+ block_size = GNUNET_GNSRECORD_block_get_size (block);
if (block_size > 64 * 65536)
{
GNUNET_break (0);
diff --git a/src/namecache/plugin_namecache_postgres.c b/src/namecache/plugin_namecache_postgres.c
index 0e947e9c5..ae0f71a1f 100644
--- a/src/namecache/plugin_namecache_postgres.c
+++ b/src/namecache/plugin_namecache_postgres.c
@@ -64,15 +64,13 @@ database_setup (struct Plugin *plugin)
" query BYTEA NOT NULL DEFAULT '',"
" block BYTEA NOT NULL DEFAULT '',"
" expiration_time BIGINT NOT NULL DEFAULT 0"
- ")"
- "WITH OIDS");
+ ")");
struct GNUNET_PQ_ExecuteStatement es_default =
GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns096blocks ("
" query BYTEA NOT NULL DEFAULT '',"
" block BYTEA NOT NULL DEFAULT '',"
" expiration_time BIGINT NOT NULL DEFAULT 0"
- ")"
- "WITH OIDS");
+ ")");
const struct GNUNET_PQ_ExecuteStatement *cr;
if (GNUNET_YES ==
@@ -155,11 +153,11 @@ namecache_postgres_expire_blocks (struct Plugin *plugin)
static void
delete_old_block (struct Plugin *plugin,
const struct GNUNET_HashCode *query,
- struct GNUNET_TIME_AbsoluteNBO expiration_time)
+ struct GNUNET_TIME_Absolute expiration_time)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (query),
- GNUNET_PQ_query_param_absolute_time_nbo (&expiration_time),
+ GNUNET_PQ_query_param_absolute_time (&expiration_time),
GNUNET_PQ_query_param_end
};
enum GNUNET_DB_QueryStatus res;
@@ -184,21 +182,20 @@ namecache_postgres_cache_block (void *cls,
{
struct Plugin *plugin = cls;
struct GNUNET_HashCode query;
- size_t block_size = ntohl (block->purpose.size)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
- + sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
+ size_t block_size = GNUNET_GNSRECORD_block_get_size (block);
+ struct GNUNET_TIME_Absolute exp;
+ exp = GNUNET_GNSRECORD_block_get_expiration (block);
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&query),
GNUNET_PQ_query_param_fixed_size (block, block_size),
- GNUNET_PQ_query_param_absolute_time_nbo (&block->expiration_time),
+ GNUNET_PQ_query_param_absolute_time (&exp),
GNUNET_PQ_query_param_end
};
enum GNUNET_DB_QueryStatus res;
namecache_postgres_expire_blocks (plugin);
- GNUNET_CRYPTO_hash (&block->derived_key,
- sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
- &query);
+ GNUNET_GNSRECORD_query_from_block (block,
+ &query);
if (block_size > 64 * 65536)
{
GNUNET_break (0);
@@ -206,7 +203,7 @@ namecache_postgres_cache_block (void *cls,
}
delete_old_block (plugin,
&query,
- block->expiration_time);
+ exp);
res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
"cache_block",
@@ -265,10 +262,7 @@ namecache_postgres_lookup_block (void *cls,
"Ending iteration (no more results)\n");
return GNUNET_NO;
}
- if ((bsize < sizeof(*block)) ||
- (bsize != ntohl (block->purpose.size)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
- + sizeof(struct GNUNET_CRYPTO_EcdsaSignature)))
+ if ((bsize < sizeof(*block)))
{
GNUNET_break (0);
LOG (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/namecache/plugin_namecache_sqlite.c b/src/namecache/plugin_namecache_sqlite.c
index c9d79ba2d..82008c837 100644
--- a/src/namecache/plugin_namecache_sqlite.c
+++ b/src/namecache/plugin_namecache_sqlite.c
@@ -332,9 +332,7 @@ namecache_sqlite_cache_block (void *cls,
struct Plugin *plugin = cls;
struct GNUNET_HashCode query;
struct GNUNET_TIME_Absolute expiration;
- size_t block_size = ntohl (block->purpose.size)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
- + sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
+ size_t block_size = GNUNET_GNSRECORD_block_get_size (block);
struct GNUNET_SQ_QueryParam del_params[] = {
GNUNET_SQ_query_param_auto_from_type (&query),
GNUNET_SQ_query_param_absolute_time (&expiration),
@@ -356,10 +354,9 @@ namecache_sqlite_cache_block (void *cls,
last_expire = GNUNET_TIME_absolute_get ();
namecache_sqlite_expire_blocks (plugin);
}
- GNUNET_CRYPTO_hash (&block->derived_key,
- sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
- &query);
- expiration = GNUNET_TIME_absolute_ntoh (block->expiration_time);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_GNSRECORD_query_from_block (block, &query));
+ expiration = GNUNET_GNSRECORD_block_get_expiration (block);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Caching new version of block %s (expires %s)\n",
GNUNET_h2s (&query),
@@ -498,10 +495,7 @@ namecache_sqlite_lookup_block (void *cls,
GNUNET_break (0);
ret = GNUNET_SYSERR;
}
- else if ((block_size < sizeof(struct GNUNET_GNSRECORD_Block)) ||
- (ntohl (block->purpose.size)
- + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
- + sizeof(struct GNUNET_CRYPTO_EcdsaSignature) != block_size))
+ else if ((block_size < sizeof(struct GNUNET_GNSRECORD_Block)))
{
GNUNET_break (0);
GNUNET_SQ_cleanup_result (rs);
diff --git a/src/namecache/test_namecache_api_cache_block.c b/src/namecache/test_namecache_api_cache_block.c
index 12b72d93b..310c4de42 100644
--- a/src/namecache/test_namecache_api_cache_block.c
+++ b/src/namecache/test_namecache_api_cache_block.c
@@ -39,9 +39,9 @@ static struct GNUNET_NAMECACHE_Handle *nsh;
static struct GNUNET_SCHEDULER_Task *endbadly_task;
-static struct GNUNET_CRYPTO_EcdsaPrivateKey privkey;
+static struct GNUNET_IDENTITY_PrivateKey privkey;
-static struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
+static struct GNUNET_IDENTITY_PublicKey pubkey;
static int res;
@@ -172,23 +172,13 @@ run (void *cls,
{
struct GNUNET_GNSRECORD_Data rd;
struct GNUNET_GNSRECORD_Block *block;
- char *hostkey_file;
const char *name = "dummy.dummy.gnunet";
endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
&endbadly, NULL);
- GNUNET_asprintf (&hostkey_file,
- "zonefiles%s%s",
- DIR_SEPARATOR_STR,
- "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n",
- hostkey_file);
- GNUNET_assert (GNUNET_SYSERR !=
- GNUNET_CRYPTO_ecdsa_key_from_file (hostkey_file,
- GNUNET_YES,
- &privkey));
- GNUNET_free (hostkey_file);
- GNUNET_CRYPTO_ecdsa_key_get_public (&privkey, &pubkey);
+ privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
+ GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
+ GNUNET_IDENTITY_key_get_public (&privkey, &pubkey);
rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us + 10000000000;
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 40ac64197..3a92f98c9 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -131,6 +131,7 @@ libgnunet_plugin_rest_namestore_la_LIBADD = \
$(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/json/libgnunetjson.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecordjson.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
$(LTLIBINTL) -ljansson $(MHD_LIBS)
libgnunet_plugin_rest_namestore_la_LDFLAGS = \
@@ -144,6 +145,7 @@ libgnunetnamestore_la_SOURCES = \
namestore.h
libgnunetnamestore_la_LIBADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL)
@@ -190,6 +192,7 @@ gnunet_service_namestore_SOURCES = \
gnunet_service_namestore_LDADD = \
$(top_builddir)/src/namecache/libgnunetnamecache.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la \
libgnunetnamestore.la \
@@ -200,7 +203,8 @@ gnunet_service_namestore_LDADD = \
libgnunet_plugin_namestore_flat_la_SOURCES = \
plugin_namestore_flat.c
libgnunet_plugin_namestore_flat_la_LIBADD = \
- $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
$(LTLIBINTL)
@@ -212,6 +216,7 @@ libgnunet_plugin_namestore_sqlite_la_SOURCES = \
plugin_namestore_sqlite.c
libgnunet_plugin_namestore_sqlite_la_LIBADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/sq/libgnunetsq.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
@@ -223,6 +228,7 @@ libgnunet_plugin_namestore_postgres_la_SOURCES = \
plugin_namestore_postgres.c
libgnunet_plugin_namestore_postgres_la_LIBADD = \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
$(top_builddir)/src/pq/libgnunetpq.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
@@ -236,6 +242,7 @@ test_namestore_api_store_flat_LDADD = \
$(top_builddir)/src/testing/libgnunettesting.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
libgnunetnamestore.la
test_namestore_api_store_sqlite_SOURCES = \
@@ -244,6 +251,7 @@ test_namestore_api_store_sqlite_LDADD = \
$(top_builddir)/src/testing/libgnunettesting.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
libgnunetnamestore.la
test_namestore_api_store_postgres_SOURCES = \
@@ -252,6 +260,7 @@ test_namestore_api_store_postgres_LDADD = \
$(top_builddir)/src/testing/libgnunettesting.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
libgnunetnamestore.la
test_namestore_api_store_update_flat_SOURCES = \
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c
index 34641d22e..22d108067 100644
--- a/src/namestore/gnunet-namestore-fcfsd.c
+++ b/src/namestore/gnunet-namestore-fcfsd.c
@@ -164,7 +164,7 @@ struct Request
*/
char public_key[128];
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+ struct GNUNET_IDENTITY_PublicKey pub;
};
/**
@@ -211,7 +211,7 @@ static struct GNUNET_NAMESTORE_Handle *ns;
/**
* Private key for the fcfsd zone.
*/
-static struct GNUNET_CRYPTO_EcdsaPrivateKey fcfs_zone_pkey;
+static struct GNUNET_IDENTITY_PrivateKey fcfs_zone_pkey;
/**
* Connection to identity service.
@@ -306,7 +306,6 @@ zone_iteration_end (void *cls)
/* return static form */
GNUNET_asprintf (&full_page,
ZONEINFO_PAGE,
- zr->zoneinfo,
zr->zoneinfo);
response = MHD_create_response_from_buffer (strlen (full_page),
(void *) full_page,
@@ -332,7 +331,7 @@ zone_iteration_end (void *cls)
*/
static void
iterate_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const struct GNUNET_IDENTITY_PrivateKey *zone_key,
const char *name,
unsigned int rd_len,
const struct GNUNET_GNSRECORD_Data *rd)
@@ -350,7 +349,8 @@ iterate_cb (void *cls,
return;
}
- if (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type)
+ if ((GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type) &&
+ (GNUNET_GNSRECORD_TYPE_EDKEY != rd->record_type))
{
GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
1);
@@ -615,13 +615,14 @@ zone_to_name_error (void *cls)
*/
static void
zone_to_name_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const struct GNUNET_IDENTITY_PrivateKey *zone_key,
const char *name,
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd)
{
struct Request *request = cls;
struct GNUNET_GNSRECORD_Data r;
+ char *rdata;
(void) rd;
(void) zone_key;
@@ -636,10 +637,21 @@ zone_to_name_cb (void *cls,
run_httpd_now ();
return;
}
- r.data = &request->pub;
- r.data_size = sizeof(request->pub);
+ if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&request->pub,
+ &rdata,
+ &r.data_size,
+ &r.record_type))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _ ("Error creating record data.\n"));
+ request->phase = RP_FAIL;
+ MHD_resume_connection (request->con);
+ run_httpd_now ();
+ return;
+ }
+
+ r.data = rdata;
r.expiration_time = UINT64_MAX;
- r.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
r.flags = GNUNET_GNSRECORD_RF_NONE;
request->qe = GNUNET_NAMESTORE_records_store (ns,
&fcfs_zone_pkey,
@@ -647,6 +659,7 @@ zone_to_name_cb (void *cls,
1, &r,
&put_continuation,
request);
+ GNUNET_free (rdata);
}
@@ -677,7 +690,7 @@ lookup_it_error (void *cls)
*/
static void
lookup_it_processor (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zonekey,
+ const struct GNUNET_IDENTITY_PrivateKey *zonekey,
const char *label,
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd)
@@ -712,9 +725,8 @@ lookup_it_finished (void *cls)
return;
}
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
- strlen (request->public_key),
- &request->pub))
+ GNUNET_IDENTITY_public_key_from_string (request->public_key,
+ &request->pub))
{
GNUNET_break (0);
request->phase = RP_FAIL;
@@ -767,7 +779,7 @@ create_response (void *cls,
{
struct MHD_Response *response;
struct Request *request;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+ struct GNUNET_IDENTITY_PublicKey pub;
MHD_RESULT ret;
(void) cls;
@@ -822,10 +834,8 @@ create_response (void *cls,
request->pp = NULL;
}
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
- strlen (
- request->public_key),
- &pub))
+ GNUNET_IDENTITY_public_key_from_string (request->public_key,
+ &pub))
{
/* parse error */
return fill_s_reply ("Failed to parse given public key",
@@ -1211,7 +1221,8 @@ main (int argc,
options,
&run, NULL)) ? 0 : 1;
GNUNET_free_nz ((void *) argv);
- GNUNET_CRYPTO_ecdsa_key_clear (&fcfs_zone_pkey);
+ // FIXME
+ // GNUNET_CRYPTO_ecdsa_key_clear (&fcfs_zone_pkey);
return ret;
}
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
index 07d045b90..92d2cf627 100644
--- a/src/namestore/gnunet-namestore.c
+++ b/src/namestore/gnunet-namestore.c
@@ -59,7 +59,7 @@ static struct GNUNET_NAMESTORE_Handle *ns;
/**
* Private key for the our zone.
*/
-static struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
+static struct GNUNET_IDENTITY_PrivateKey zone_pkey;
/**
* Handle to identity lookup.
@@ -496,7 +496,7 @@ display_record (const char *rname,
*/
static void
display_record_iterator (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const struct GNUNET_IDENTITY_PrivateKey *zone_key,
const char *rname,
unsigned int rd_len,
const struct GNUNET_GNSRECORD_Data *rd)
@@ -519,7 +519,7 @@ display_record_iterator (void *cls,
*/
static void
display_record_monitor (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const struct GNUNET_IDENTITY_PrivateKey *zone_key,
const char *rname,
unsigned int rd_len,
const struct GNUNET_GNSRECORD_Data *rd)
@@ -542,7 +542,7 @@ display_record_monitor (void *cls,
*/
static void
display_record_lookup (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const struct GNUNET_IDENTITY_PrivateKey *zone_key,
const char *rname,
unsigned int rd_len,
const struct GNUNET_GNSRECORD_Data *rd)
@@ -622,7 +622,7 @@ add_error_cb (void *cls)
*/
static void
get_existing_record (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const struct GNUNET_IDENTITY_PrivateKey *zone_key,