diff options
author | TheJackiMonster <thejackimonster@gmail.com> | 2020-10-01 21:13:43 +0200 |
---|---|---|
committer | TheJackiMonster <thejackimonster@gmail.com> | 2020-11-12 16:57:45 +0100 |
commit | 8bf864c25bda97c1448b709a76a168834753ff86 (patch) | |
tree | 6ffccc18a3c112e035235c596006f8b13aca1be7 /src | |
parent | 8fd7531e5841c9d9f80f821a3490a05934fee933 (diff) |
adding the messenger service and its client-side library
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat (limited to 'src')
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, ¬ification_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, ¬ification_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, |