aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/identity/identity_api.c22
-rw-r--r--src/include/Makefile.am1
-rw-r--r--src/include/gnunet_messenger_service.h436
-rw-r--r--src/include/gnunet_protocols.h43
-rw-r--r--src/messenger/.gitignore4
-rw-r--r--src/messenger/Makefile.am131
-rw-r--r--src/messenger/gnunet-messenger.c306
-rw-r--r--src/messenger/gnunet-service-messenger.c306
-rw-r--r--src/messenger/gnunet-service-messenger.h121
-rw-r--r--src/messenger/gnunet-service-messenger_basement.c58
-rw-r--r--src/messenger/gnunet-service-messenger_basement.h66
-rw-r--r--src/messenger/gnunet-service-messenger_contact.c96
-rw-r--r--src/messenger/gnunet-service-messenger_contact.h112
-rw-r--r--src/messenger/gnunet-service-messenger_handle.c503
-rw-r--r--src/messenger/gnunet-service-messenger_handle.h216
-rw-r--r--src/messenger/gnunet-service-messenger_list_handles.c95
-rw-r--r--src/messenger/gnunet-service-messenger_list_handles.h96
-rw-r--r--src/messenger/gnunet-service-messenger_list_messages.c76
-rw-r--r--src/messenger/gnunet-service-messenger_list_messages.h81
-rw-r--r--src/messenger/gnunet-service-messenger_message_handle.c130
-rw-r--r--src/messenger/gnunet-service-messenger_message_handle.h128
-rw-r--r--src/messenger/gnunet-service-messenger_message_kind.c192
-rw-r--r--src/messenger/gnunet-service-messenger_message_kind.h160
-rw-r--r--src/messenger/gnunet-service-messenger_message_recv.c204
-rw-r--r--src/messenger/gnunet-service-messenger_message_recv.h159
-rw-r--r--src/messenger/gnunet-service-messenger_message_send.c118
-rw-r--r--src/messenger/gnunet-service-messenger_message_send.h155
-rw-r--r--src/messenger/gnunet-service-messenger_message_store.c282
-rw-r--r--src/messenger/gnunet-service-messenger_message_store.h120
-rw-r--r--src/messenger/gnunet-service-messenger_room.c1051
-rw-r--r--src/messenger/gnunet-service-messenger_room.h378
-rw-r--r--src/messenger/gnunet-service-messenger_service.c516
-rw-r--r--src/messenger/gnunet-service-messenger_service.h259
-rw-r--r--src/messenger/gnunet-service-messenger_tunnel.c300
-rw-r--r--src/messenger/gnunet-service-messenger_tunnel.h155
-rw-r--r--src/messenger/gnunet-service-messenger_util.c64
-rw-r--r--src/messenger/gnunet-service-messenger_util.h53
-rw-r--r--src/messenger/messenger.conf.in13
-rw-r--r--src/messenger/messenger_api.c568
-rw-r--r--src/messenger/messenger_api_contact.c78
-rw-r--r--src/messenger/messenger_api_contact.h93
-rw-r--r--src/messenger/messenger_api_ego.h38
-rw-r--r--src/messenger/messenger_api_handle.c213
-rw-r--r--src/messenger/messenger_api_handle.h174
-rw-r--r--src/messenger/messenger_api_list_tunnels.c112
-rw-r--r--src/messenger/messenger_api_list_tunnels.h112
-rw-r--r--src/messenger/messenger_api_message.c602
-rw-r--r--src/messenger/messenger_api_message.h190
-rw-r--r--src/messenger/messenger_api_room.c189
-rw-r--r--src/messenger/messenger_api_room.h95
-rw-r--r--src/messenger/test_messenger.c187
-rw-r--r--src/messenger/test_messenger_anonymous.c179
-rw-r--r--src/messenger/test_messenger_comm0.c252
54 files changed, 10277 insertions, 14 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index f98cb96df..d8a869acb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,8 @@ endif
11 11
12if HAVE_EXPERIMENTAL 12if HAVE_EXPERIMENTAL
13 EXP_DIR = \ 13 EXP_DIR = \
14 rps 14 rps \
15 messenger
15 #abd FTBFS 16 #abd FTBFS
16if HAVE_ABE 17if HAVE_ABE
17 EXP_DIR += \ 18 EXP_DIR += \
diff --git a/src/identity/identity_api.c b/src/identity/identity_api.c
index d44e8da96..64c088923 100644
--- a/src/identity/identity_api.c
+++ b/src/identity/identity_api.c
@@ -1138,11 +1138,11 @@ GNUNET_IDENTITY_signature_verify_ (uint32_t purpose,
1138 1138
1139 1139
1140ssize_t 1140ssize_t
1141GNUNET_IDENTITY_public_key_encrypt (const void *block, 1141GNUNET_IDENTITY_encrypt (const void *block,
1142 size_t size, 1142 size_t size,
1143 const struct GNUNET_IDENTITY_PublicKey *pub, 1143 const struct GNUNET_IDENTITY_PublicKey *pub,
1144 struct GNUNET_CRYPTO_EcdhePublicKey *ecc, 1144 struct GNUNET_CRYPTO_EcdhePublicKey *ecc,
1145 void *result) 1145 void *result)
1146{ 1146{
1147 struct GNUNET_CRYPTO_EcdhePrivateKey pk; 1147 struct GNUNET_CRYPTO_EcdhePrivateKey pk;
1148 GNUNET_CRYPTO_ecdhe_key_create (&pk); 1148 GNUNET_CRYPTO_ecdhe_key_create (&pk);
@@ -1177,13 +1177,11 @@ GNUNET_IDENTITY_public_key_encrypt (const void *block,
1177 1177
1178 1178
1179ssize_t 1179ssize_t
1180GNUNET_IDENTITY_private_key_decrypt (const void *block, 1180GNUNET_IDENTITY_decrypt (const void *block,
1181 size_t size, 1181 size_t size,
1182 const struct 1182 const struct GNUNET_IDENTITY_PrivateKey *priv,
1183 GNUNET_IDENTITY_PrivateKey *priv, 1183 const struct GNUNET_CRYPTO_EcdhePublicKey *ecc,
1184 const struct 1184 void *result)
1185 GNUNET_CRYPTO_EcdhePublicKey *ecc,
1186 void *result)
1187{ 1185{
1188 struct GNUNET_HashCode hash; 1186 struct GNUNET_HashCode hash;
1189 switch (ntohl (priv->type)) 1187 switch (ntohl (priv->type))
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 = \
62 gnunet_json_lib.h \ 62 gnunet_json_lib.h \
63 gnunet_load_lib.h \ 63 gnunet_load_lib.h \
64 gnunet_cadet_service.h \ 64 gnunet_cadet_service.h \
65 gnunet_messenger_service.h \
65 gnunet_mhd_compat.h \ 66 gnunet_mhd_compat.h \
66 gnunet_microphone_lib.h \ 67 gnunet_microphone_lib.h \
67 gnunet_mst_lib.h \ 68 gnunet_mst_lib.h \
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 *
23 * @file
24 * MESSENGER service; manages decentralized chat groups
25 *
26 * @defgroup messenger MESSENGER service
27 * Instant messaging based on the CADET subsystem
28 *
29 * @{
30 */
31
32#ifndef GNUNET_MESSENGER_SERVICE_H
33#define GNUNET_MESSENGER_SERVICE_H
34
35#ifdef __cplusplus
36extern "C" {
37#if 0 /* keep Emacsens' auto-indent happy */
38}
39#endif
40#endif
41
42#include "platform.h"
43#include "gnunet_configuration_lib.h"
44#include "gnunet_crypto_lib.h"
45#include "gnunet_identity_service.h"
46#include "gnunet_mq_lib.h"
47#include "gnunet_protocols.h"
48#include "gnunet_scheduler_lib.h"
49#include "gnunet_time_lib.h"
50
51#define GNUNET_MESSENGER_SERVICE_NAME "messenger"
52
53/**
54 * Opaque handle to the messenger
55 */
56struct GNUNET_MESSENGER_Handle;
57
58/**
59 * Opaque handle to a room
60 */
61struct GNUNET_MESSENGER_Room;
62
63/**
64 * Opaque handle to a contact
65 */
66struct GNUNET_MESSENGER_Contact;
67
68/**
69 * Enum for the different supported kinds of messages
70 */
71enum GNUNET_MESSENGER_MessageKind
72{
73 GNUNET_MESSENGER_KIND_INFO = 1,
74
75 GNUNET_MESSENGER_KIND_JOIN = 2,
76 GNUNET_MESSENGER_KIND_LEAVE = 3,
77
78 GNUNET_MESSENGER_KIND_NAME = 4,
79 GNUNET_MESSENGER_KIND_KEY = 5,
80 GNUNET_MESSENGER_KIND_PEER = 6,
81 GNUNET_MESSENGER_KIND_ID = 7,
82
83 GNUNET_MESSENGER_KIND_MISS = 8,
84 GNUNET_MESSENGER_KIND_MERGE = 9,
85 GNUNET_MESSENGER_KIND_REQUEST = 10,
86
87 GNUNET_MESSENGER_KIND_INVITE = 11,
88 GNUNET_MESSENGER_KIND_TEXT = 12,
89 GNUNET_MESSENGER_KIND_FILE = 13,
90
91 GNUNET_MESSENGER_KIND_PRIVATE = 14,
92
93 GNUNET_MESSENGER_KIND_UNKNOWN = 0
94}__attribute__((__packed__));
95
96/**
97 * Get the name of a message <i>kind</i>.
98 *
99 * @param kind Kind of a message
100 * @return Name of that kind
101 */
102const char*
103GNUNET_MESSENGER_name_of_kind (enum GNUNET_MESSENGER_MessageKind kind);
104
105struct GNUNET_MESSENGER_MessageHeader
106{
107 struct GNUNET_IDENTITY_Signature signature;
108
109 struct GNUNET_TIME_AbsoluteNBO timestamp;
110
111 struct GNUNET_ShortHashCode sender_id;
112 struct GNUNET_HashCode previous;
113
114 enum GNUNET_MESSENGER_MessageKind kind;
115};
116
117struct GNUNET_MESSENGER_MessageInfo
118{
119 struct GNUNET_IDENTITY_PublicKey host_key;
120 struct GNUNET_ShortHashCode unique_id;
121};
122
123struct GNUNET_MESSENGER_MessageJoin
124{
125 struct GNUNET_IDENTITY_PublicKey key;
126};
127
128struct GNUNET_MESSENGER_MessageLeave
129{
130};
131
132struct GNUNET_MESSENGER_MessageName
133{
134 char *name;
135};
136
137struct GNUNET_MESSENGER_MessageKey
138{
139 struct GNUNET_IDENTITY_PublicKey key;
140};
141
142struct GNUNET_MESSENGER_MessagePeer
143{
144 struct GNUNET_PeerIdentity peer;
145};
146
147struct GNUNET_MESSENGER_MessageId
148{
149 struct GNUNET_ShortHashCode id;
150};
151
152struct GNUNET_MESSENGER_MessageMiss
153{
154 struct GNUNET_PeerIdentity peer;
155};
156
157struct GNUNET_MESSENGER_MessageMerge
158{
159 struct GNUNET_HashCode previous;
160};
161
162struct GNUNET_MESSENGER_MessageRequest
163{
164 struct GNUNET_HashCode hash;
165};
166
167struct GNUNET_MESSENGER_MessageInvite
168{
169 struct GNUNET_PeerIdentity door;
170 struct GNUNET_HashCode key;
171};
172
173struct GNUNET_MESSENGER_MessageText
174{
175 char *text;
176};
177
178struct GNUNET_MESSENGER_MessageFile
179{
180 struct GNUNET_CRYPTO_SymmetricSessionKey key;
181 struct GNUNET_HashCode hash;
182 char name[NAME_MAX];
183 char *uri;
184};
185
186struct GNUNET_MESSENGER_MessagePrivate
187{
188 struct GNUNET_CRYPTO_EcdhePublicKey key;
189
190 uint16_t length;
191 char *data;
192};
193
194struct GNUNET_MESSENGER_MessageBody
195{
196 union
197 {
198 struct GNUNET_MESSENGER_MessageInfo info;
199
200 struct GNUNET_MESSENGER_MessageJoin join;
201 struct GNUNET_MESSENGER_MessageLeave leave;
202
203 struct GNUNET_MESSENGER_MessageName name;
204 struct GNUNET_MESSENGER_MessageKey key;
205 struct GNUNET_MESSENGER_MessagePeer peer;
206 struct GNUNET_MESSENGER_MessageId id;
207
208 struct GNUNET_MESSENGER_MessageMiss miss;
209 struct GNUNET_MESSENGER_MessageMerge merge;
210 struct GNUNET_MESSENGER_MessageRequest request;
211
212 struct GNUNET_MESSENGER_MessageInvite invite;
213 struct GNUNET_MESSENGER_MessageText text;
214 struct GNUNET_MESSENGER_MessageFile file;
215
216 struct GNUNET_MESSENGER_MessagePrivate private;
217 };
218};
219
220/**
221 * Struct to a message
222 */
223struct GNUNET_MESSENGER_Message
224{
225 struct GNUNET_MESSENGER_MessageHeader header;
226 struct GNUNET_MESSENGER_MessageBody body;
227};
228
229/**
230 * Method called whenever the EGO of a <i>handle</i> changes or if the first connection fails
231 * to load a valid EGO and the anonymous keypair will be used instead.
232 *
233 * @param cls Closure from <i>GNUNET_MESSENGER_connect</i>
234 * @param handle Messenger handle
235 */
236typedef void
237(*GNUNET_MESSENGER_IdentityCallback) (void *cls, struct GNUNET_MESSENGER_Handle *handle);
238
239/**
240 * Method called whenever a message is sent or received from a <i>room</i>.
241 *
242 * @param cls Closure from <i>GNUNET_MESSENGER_connect</i>
243 * @param room Room handle
244 * @param message Newly received or sent message
245 * @param hash Hash identifying the message
246 */
247typedef void
248(*GNUNET_MESSENGER_MessageCallback) (void *cls, const struct GNUNET_MESSENGER_Room *room,
249 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
250
251/**
252 * Set up a handle for the messenger related functions and connects to all necessary services. It will look up the ego
253 * key identified by its <i>name</i> and use it for signing all messages from the handle.
254 *
255 * @param cfg Configuration to use
256 * @param name Name to look up an ego or NULL to stay anonymous
257 * @param identity_callback Function called when the EGO of the handle changes
258 * @param identity_cls Closure for the <i>identity_callback</i> handler
259 * @param msg_callback Function called when a new message is sent or received
260 * @param msg_cls Closure for the <i>msg_callback</i> handler
261 * @return Messenger handle to use, NULL on error
262 */
263struct GNUNET_MESSENGER_Handle*
264GNUNET_MESSENGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name,
265 GNUNET_MESSENGER_IdentityCallback identity_callback, void *identity_cls,
266 GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls);
267
268/**
269 * Update a handle of the messenger to use a different ego key and replace the old one with a newly generated one. All
270 * participated rooms get informed about the key renewal. The handle requires a set name for this function to work and
271 * it needs to be unused by other egos.
272 *
273 * 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
274 * as default.
275 *
276 * @param handle Messenger handle to use
277 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
278 */
279int
280GNUNET_MESSENGER_update (struct GNUNET_MESSENGER_Handle *handle);
281
282/**
283 * Disconnect all of the messengers used services and clears up its used memory.
284 *
285 * @param handle Messenger handle to use
286 */
287void
288GNUNET_MESSENGER_disconnect (struct GNUNET_MESSENGER_Handle *handle);
289
290/**
291 * Get the name (if specified, otherwise NULL) used by the messenger.
292 *
293 * @param handle Messenger handle to use
294 * @return Name used by the messenger or NULL
295 */
296const char*
297GNUNET_MESSENGER_get_name (const struct GNUNET_MESSENGER_Handle *handle);
298
299/**
300 * Set the name for the messenger. This will rename the currently used ego and move all stored files related to the current
301 * name to its new directory. If anything fails during this process the function returns GNUNET_NO and the name for
302 * the messenger won't change as specified.
303 *
304 * @param handle Messenger handle to use
305 * @param name Name for the messenger to change to
306 * @return GNUNET_YES on success, GNUNET_NO on failure and GNUNET_SYSERR if <i>handle</i> is NULL
307 */
308int
309GNUNET_MESSENGER_set_name (struct GNUNET_MESSENGER_Handle *handle, const char *name);
310
311/**
312 * Get the public key used by the messenger.
313 *
314 * @param handle Messenger handle to use
315 * @return Used ego's public key
316 */
317const struct GNUNET_IDENTITY_PublicKey*
318GNUNET_MESSENGER_get_key (const struct GNUNET_MESSENGER_Handle *handle);
319
320/**
321 * Open a room to send and receive messages. The room will use the specified <i>key</i> as port for the underlying cadet
322 * service. Opening a room results in opening the port for incoming connections as possible <b>door</b>.
323 *
324 * Notice that there can only be one room related to a specific <i>key</i>. So trying to open two rooms with the same
325 * <i>key</i> will result in opening the room once but returning the handle both times because the room stays open.
326 *
327 * You can also open a room after entering it through a <b>door</b> using <i>GNUNET_MESSENGER_entry_room(...)</i>. This
328 * will notify all entered <b>doors</b> to list you as new <b>door</b>.
329 *
330 * ( All <b>doors</b> form a ring structured network to shorten the latency sending and receiving messages. )
331 *
332 * @param handle Messenger handle to use
333 * @param key Hash identifying the port
334 * @return Room handle, NULL on error
335 */
336struct GNUNET_MESSENGER_Room*
337GNUNET_MESSENGER_open_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
338
339/**
340 * Enter a room to send and receive messages through a <b>door</b> opened using <i>GNUNET_MESSENGER_open_room(...)</i>.
341 *
342 * Notice that there can only be one room related to a specific <i>key</i>. So trying to enter two rooms with the same
343 * <i>key</i> will result in entering the room once but returning the handle both times because the room stays entered.
344 * You can however enter a room through multiple <b>doors</b> in parallel which results in connecting both ends. But
345 * entering the room through the same <b>door</b> won't have any effect after the first time.
346 *
347 * You can also enter a room through a <b>door</b> after opening it using <i>GNUNET_MESSENGER_open_room(...)</i>. But the
348 * <b>door</b> may not be your own peer identity.
349 *
350 * ( All <b>doors</b> form a ring structured network to shorten the latency sending and receiving messages. )
351 *
352 * @param handle Messenger handle to use
353 * @param door Peer identity of an open <b>door</b>
354 * @param key Hash identifying the port
355 * @return Room handle, NULL on error
356 */
357struct GNUNET_MESSENGER_Room*
358GNUNET_MESSENGER_entry_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
359 const struct GNUNET_HashCode *key);
360
361/**
362 * Close a room which was entered, opened or both in various order and variety. Closing a room will destroy all connections
363 * from your peer to another and the other way around.
364 *
365 * ( After a member closes a <b>door</b>, all members entered through that specific <b>door</b> have to use another one
366 * or open the room on their own. )
367 *
368 * @param room Room handle
369 */
370void
371GNUNET_MESSENGER_close_room (struct GNUNET_MESSENGER_Room *room);
372
373/**
374 * Get the contact of a member in a <i>room</i> identified by their <i>id</i>.
375 *
376 * Notice that contacts are independent of rooms but will be removed if all rooms containing these contacts get closed.
377 *
378 * @param room Room handle
379 * @param id Hash identifying a member
380 * @return Contact handle, NULL if <i>id</i> is not in use
381 */
382struct GNUNET_MESSENGER_Contact*
383GNUNET_MESSENGER_get_member (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_ShortHashCode *id);
384
385/**
386 * Get the name used by the <i>contact</i>.
387 *
388 * @param contact Contact handle
389 * @return Name of <i>contact</i> or NULL
390 */
391const char*
392GNUNET_MESSENGER_contact_get_name (const struct GNUNET_MESSENGER_Contact *contact);
393
394/**
395 * Get the public key used by the <i>contact</i>.
396 *
397 * @param contact Contact handle
398 * @return Public key of the ego used by <i>contact</i>
399 */
400const struct GNUNET_IDENTITY_PublicKey*
401GNUNET_MESSENGER_contact_get_key (const struct GNUNET_MESSENGER_Contact *contact);
402
403/**
404 * Send a <i>message</i> into a </i>room</i>. If you opened the <i>room</i> all entered members will receive the
405 * <i>message</i>. If you entered the <i>room</i> through a <b>door</b> all so entered <b>doors</b> will receive the
406 * <i>message</i> as well. All members receiving the <i>message</i> will also propagate this <i>message</i> recursively
407 * as long as the <i>message</i> is unknown to them.
408 *
409 * Notice that all messages sent and received are also stored and can be propagated to new members entering the room.
410 *
411 * @param room Room handle
412 * @param message New message to send
413 */
414void
415GNUNET_MESSENGER_send_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message);
416
417/**
418 * Get the message in a <i>room</i> identified by its <i>hash</i>.
419 *
420 * @param room Room handle
421 * @param hash Hash identifying a message
422 * @return Message struct or NULL if no message with that hash is known
423 */
424const struct GNUNET_MESSENGER_Message*
425GNUNET_MESSENGER_get_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash);
426
427#if 0 /* keep Emacsens' auto-indent happy */
428{
429#endif
430#ifdef __cplusplus
431}
432#endif
433
434#endif //GNUNET_MESSENGER_SERVICE_H
435
436/** @} *//* end of group */
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 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2001--2018 GNUnet e.V. 3 Copyright (C) 2001--2020 GNUnet e.V.
4 4
5 GNUnet is free software: you can redistribute it and/or modify it 5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published 6 under the terms of the GNU Affero General Public License as published
@@ -20,6 +20,7 @@
20 20
21/** 21/**
22 * @author Christian Grothoff 22 * @author Christian Grothoff
23 * @author Tobias Frisch
23 * 24 *
24 * @file 25 * @file
25 * Constants for network protocols 26 * Constants for network protocols
@@ -3518,6 +3519,46 @@ extern "C" {
3518#define GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT 1501 3519#define GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT 1501
3519 3520
3520 3521
3522/*********************************************************************************/
3523/********************************** MESSENGER **********************************/
3524/*********************************************************************************/
3525/* MESSENGER: message types 1600-1629
3526 * 1600-1609 Connection-level Messages
3527 * 1610-1619 Room-level Messages
3528 */
3529
3530/********************************* Connection **********************************/
3531
3532#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE 1600
3533
3534#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_UPDATE 1601
3535
3536#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY 1602
3537
3538#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_NAME 1603
3539
3540#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_SET_NAME 1604
3541
3542#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_KEY 1605
3543
3544#define GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID 1606
3545
3546/************************************ Room *************************************/
3547
3548#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN 1610
3549
3550#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY 1611
3551
3552#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE 1612
3553
3554#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE 1614
3555
3556#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE 1615
3557
3558#define GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE 1616
3559
3560/*********************************************************************************/
3561
3521/** 3562/**
3522 * Type used to match 'all' message types. 3563 * Type used to match 'all' message types.
3523 */ 3564 */
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 @@
1gnunet-service-messenger
2gnunet-messenger
3test_messenger_api
4test_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 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6 XLIB = -lgcov
7endif
8
9pkgcfgdir= $(pkgdatadir)/config.d/
10
11libexecdir= $(pkglibdir)/libexec/
12
13pkgcfg_DATA = \
14 messenger.conf
15
16plugindir = $(libdir)/gnunet
17
18AM_CLFAGS = -g
19
20libexec_PROGRAMS = \
21 gnunet-service-messenger \
22 $(EXP_LIBEXEC)
23
24bin_PROGRAMS = \
25 gnunet-messenger
26
27lib_LTLIBRARIES = \
28 libgnunetmessenger_common.la \
29 libgnunetmessenger.la \
30 $(EXP_LIB)
31
32libgnunetmessenger_common_la_SOURCES = \
33 messenger_api_ego.h \
34 messenger_api_message.c messenger_api_message.h \
35 messenger_api_list_tunnels.c messenger_api_list_tunnels.h
36libgnunetmessenger_common_la_LIBADD = \
37 $(top_builddir)/src/util/libgnunetutil.la \
38 $(top_builddir)/src/identity/libgnunetidentity.la \
39 $(XLIB) \
40 $(LTLIBINTL)
41libgnunetmessenger_common_la_LDFLAGS = \
42 $(GN_LIB_LDFLAGS) \
43 -version-info 0:0:0
44
45libgnunetmessenger_la_SOURCES = \
46 messenger_api.c \
47 messenger_api_contact.c messenger_api_contact.h \
48 messenger_api_handle.c messenger_api_handle.h \
49 messenger_api_room.c messenger_api_room.h
50libgnunetmessenger_la_LIBADD = \
51 $(top_builddir)/src/util/libgnunetutil.la \
52 $(top_builddir)/src/identity/libgnunetidentity.la \
53 libgnunetmessenger_common.la \
54 $(XLIB) \
55 $(LTLIBINTL)
56libgnunetmessenger_la_LDFLAGS = \
57 $(GN_LIB_LDFLAGS) \
58 -version-info 0:0:0
59
60gnunet_messenger_SOURCES = \
61 gnunet-messenger.c
62gnunet_messenger_LDADD = \
63 libgnunetmessenger_common.la \
64 libgnunetmessenger.la \
65 $(top_builddir)/src/util/libgnunetutil.la
66gnunet_messenger_LDFLAGS = \
67 $(GN_LIBINTL)
68
69gnunet_service_messenger_SOURCES = \
70 gnunet-service-messenger.c gnunet-service-messenger.h \
71 gnunet-service-messenger_service.c gnunet-service-messenger_service.h \
72 gnunet-service-messenger_list_handles.c gnunet-service-messenger_list_handles.h \
73 gnunet-service-messenger_list_messages.c gnunet-service-messenger_list_messages.h \
74 gnunet-service-messenger_message_handle.c gnunet-service-messenger_message_handle.h \
75 gnunet-service-messenger_message_kind.c gnunet-service-messenger_message_kind.h \
76 gnunet-service-messenger_message_recv.c gnunet-service-messenger_message_recv.h \
77 gnunet-service-messenger_message_send.c gnunet-service-messenger_message_send.h \
78 gnunet-service-messenger_message_store.c gnunet-service-messenger_message_store.h \
79 gnunet-service-messenger_basement.c gnunet-service-messenger_basement.h \
80 gnunet-service-messenger_contact.c gnunet-service-messenger_contact.h \
81 gnunet-service-messenger_handle.c gnunet-service-messenger_handle.h \
82 gnunet-service-messenger_room.c gnunet-service-messenger_room.h \
83 gnunet-service-messenger_tunnel.c gnunet-service-messenger_tunnel.h \
84 gnunet-service-messenger_util.c gnunet-service-messenger_util.h
85gnunet_service_messenger_LDADD = \
86 $(top_builddir)/src/util/libgnunetutil.la \
87 $(top_builddir)/src/cadet/libgnunetcadet.la \
88 $(top_builddir)/src/identity/libgnunetidentity.la \
89 libgnunetmessenger_common.la \
90 libgnunetmessenger.la \
91 $(GN_LIBINTL)
92
93check_PROGRAMS = \
94 test_messenger_api \
95 test_messenger_anonymous \
96 test_messenger_comm0
97
98if ENABLE_TEST_RUN
99AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
100TESTS = \
101 $(check_PROGRAMS)
102endif
103
104test_messenger_api_SOURCES = \
105 test_messenger.c
106test_messenger_api_LDADD = \
107 libgnunetmessenger_common.la \
108 libgnunetmessenger.la \
109 $(top_builddir)/src/testing/libgnunettesting.la \
110 $(top_builddir)/src/util/libgnunetutil.la
111
112test_messenger_anonymous_SOURCES = \
113 test_messenger_anonymous.c
114test_messenger_anonymous_LDADD = \
115 libgnunetmessenger_common.la \
116 libgnunetmessenger.la \
117 $(top_builddir)/src/testing/libgnunettesting.la \
118 $(top_builddir)/src/util/libgnunetutil.la
119
120test_messenger_comm0_SOURCES = \
121 test_messenger_comm0.c
122test_messenger_comm0_LDADD = \
123 libgnunetmessenger_common.la \
124 libgnunetmessenger.la \
125 $(top_builddir)/src/testbed/libgnunettestbed.la \
126 $(top_builddir)/src/testbed-logger/libgnunettestbedlogger.la \
127 $(top_builddir)/src/testing/libgnunettesting.la \
128 $(top_builddir)/src/util/libgnunetutil.la
129
130EXTRA_DIST = \
131 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-messenger.c
23 * @brief Print information about messenger groups.
24 */
25
26#include <stdio.h>
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_messenger_service.h"
31
32struct GNUNET_MESSENGER_Handle *messenger;
33
34/**
35 * Function called whenever a message is received or sent.
36 *
37 * @param cls Closure
38 * @param room Room
39 * @param message Message
40 * @param hash Hash of message
41 */
42void
43on_message (void *cls, const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
44 const struct GNUNET_HashCode *hash)
45{
46 struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_member (room, &(message->header.sender_id));
47
48 const char *sender_name = GNUNET_MESSENGER_contact_get_name (sender);
49
50 if (!sender_name)
51 sender_name = "anonymous";
52
53 switch (message->header.kind)
54 {
55 case GNUNET_MESSENGER_KIND_JOIN:
56 {
57 printf ("* '%s' joined the room! [ %u %u %u %u ]\n", sender_name, message->body.join.key.ecdsa_key.q_y[0],
58 message->body.join.key.ecdsa_key.q_y[1], message->body.join.key.ecdsa_key.q_y[2],
59 message->body.join.key.ecdsa_key.q_y[3]);
60 break;
61 }
62 case GNUNET_MESSENGER_KIND_LEAVE:
63 {
64 printf ("* '%s' leaves the room!\n", sender_name);
65 break;
66 }
67 case GNUNET_MESSENGER_KIND_PEER:
68 {
69 printf ("* '%s' opened the room on: %s\n", sender_name, GNUNET_i2s_full (&(message->body.peer.peer)));
70 break;
71 }
72 case GNUNET_MESSENGER_KIND_TEXT:
73 {
74 printf ("* '%s' says: \"%s\"\n", sender_name, message->body.text.text);
75 break;
76 }
77 default:
78 {
79 break;
80 }
81 }
82}
83
84struct GNUNET_SCHEDULER_Task *read_task;
85
86/**
87 * Task to shut down this application.
88 *
89 * @param cls Closure
90 */
91static void
92shutdown_hook (void *cls)
93{
94 struct GNUNET_MESSENGER_Room *room = cls;
95
96 if (read_task)
97 GNUNET_SCHEDULER_cancel (read_task);
98
99 if (room)
100 GNUNET_MESSENGER_close_room (room);
101
102 if (messenger)
103 GNUNET_MESSENGER_disconnect (messenger);
104}
105
106static void
107listen_stdio (void *cls);
108
109#define MAX_BUFFER_SIZE 60000
110
111/**
112 * Task run in stdio mode, after some data is available at stdin.
113 *
114 * @param cls Closure
115 */
116static void
117read_stdio (void *cls)
118{
119 read_task = NULL;
120
121 char buffer[MAX_BUFFER_SIZE];
122 ssize_t length;
123
124 length = read (0, buffer, MAX_BUFFER_SIZE);
125
126 if ((length <= 0) || (length >= MAX_BUFFER_SIZE))
127 {
128 GNUNET_SCHEDULER_shutdown ();
129 return;
130 }
131
132 if (buffer[length - 1] == '\n')
133 buffer[length - 1] = '\0';
134 else
135 buffer[length] = '\0';
136
137 struct GNUNET_MESSENGER_Room *room = cls;
138
139 struct GNUNET_MESSENGER_Message message;
140 message.header.kind = GNUNET_MESSENGER_KIND_TEXT;
141 message.body.text.text = buffer;
142
143 GNUNET_MESSENGER_send_message (room, &message);
144
145 read_task = GNUNET_SCHEDULER_add_now (listen_stdio, cls);
146}
147
148/**
149 * Wait for input on STDIO and send it out over the #ch.
150 *
151 * @param cls Closure
152 */
153static void
154listen_stdio (void *cls)
155{
156 read_task = NULL;
157
158 struct GNUNET_NETWORK_FDSet *rs = GNUNET_NETWORK_fdset_create ();
159
160 GNUNET_NETWORK_fdset_set_native (rs, 0);
161
162 read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
163 GNUNET_TIME_UNIT_FOREVER_REL,
164 rs,
165 NULL,
166 &read_stdio, cls);
167
168 GNUNET_NETWORK_fdset_destroy (rs);
169}
170
171/**
172 * Initial task to startup application.
173 *
174 * @param cls Closure
175 */
176static void
177idle (void *cls)
178{
179 struct GNUNET_MESSENGER_Room *room = cls;
180
181 printf ("* You joined the room.\n");
182
183 read_task = GNUNET_SCHEDULER_add_now (listen_stdio, room);
184}
185
186char *door_id;
187char *ego_name;
188char *room_key;
189
190struct GNUNET_SCHEDULER_Task *shutdown_task;
191
192/**
193 * Function called when an identity is retrieved.
194 *
195 * @param cls Closure
196 * @param handle Handle of messenger service
197 */
198static void
199on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
200{
201 struct GNUNET_HashCode key;
202 memset (&key, 0, sizeof(key));
203
204 if (room_key)
205 GNUNET_CRYPTO_hash (room_key, strlen (room_key), &key);
206
207 struct GNUNET_PeerIdentity *door = NULL;
208
209 if (door_id)
210 {
211 door = GNUNET_new(struct GNUNET_PeerIdentity);
212
213 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (door_id, strlen (door_id), &(door->public_key)))
214 {
215 GNUNET_free(door);
216 door = NULL;
217 }
218 }
219
220 const char *name = GNUNET_MESSENGER_get_name (handle);
221
222 if (!name)
223 name = "anonymous";
224
225 printf ("* Welcome to the messenger, '%s'!\n", name);
226
227 struct GNUNET_MESSENGER_Room *room;
228
229 if (door)
230 {
231 printf ("* You try to entry a room...\n");
232
233 room = GNUNET_MESSENGER_entry_room (messenger, door, &key);
234 }
235 else
236 {
237 printf ("* You try to open a room...\n");
238
239 room = GNUNET_MESSENGER_open_room (messenger, &key);
240 }
241
242 GNUNET_SCHEDULER_cancel (shutdown_task);
243
244 shutdown_task = GNUNET_SCHEDULER_add_shutdown (shutdown_hook, room);
245
246 if (!room)
247 GNUNET_SCHEDULER_shutdown ();
248 else
249 GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_get_zero_ (), GNUNET_SCHEDULER_PRIORITY_IDLE, idle,
250 room);
251}
252
253/**
254 * Main function that will be run by the scheduler.
255 *
256 * @param cls closure
257 * @param args remaining command-line arguments
258 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
259 * @param cfg configuration
260 */
261static void
262run (void *cls, char *const*args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
263{
264 messenger = GNUNET_MESSENGER_connect (cfg, ego_name, &on_identity, NULL, &on_message, NULL);
265
266 shutdown_task = GNUNET_SCHEDULER_add_shutdown (shutdown_hook, NULL);
267}
268
269/**
270 * The main function to obtain messenger information.
271 *
272 * @param argc number of arguments from the command line
273 * @param argv command line arguments
274 * @return 0 ok, 1 on error
275 */
276int
277main (int argc, char **argv)
278{
279 const char *description = "Open and connect to rooms using the MESSENGER to chat.";
280
281 struct GNUNET_GETOPT_CommandLineOption options[] = {
282 GNUNET_GETOPT_option_string ('d',
283 "door",
284 "PEERIDENTITY",
285 "peer identity to entry into the room",
286 &door_id),
287 GNUNET_GETOPT_option_string ('e',
288 "ego",
289 "IDENTITY",
290 "identity to use for messaging",
291 &ego_name),
292 GNUNET_GETOPT_option_string ('r',
293 "room",
294 "ROOMKEY",
295 "key of the room to connect to",
296 &room_key),
297 GNUNET_GETOPT_OPTION_END };
298
299 return (GNUNET_OK == GNUNET_PROGRAM_run (argc,
300 argv,
301 "gnunet-messenger\0",
302 gettext_noop(description),
303 options,
304 &run,
305 NULL) ? EXIT_SUCCESS : EXIT_FAILURE);
306}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger.h"
27
28#include "gnunet-service-messenger_service.h"
29#include "messenger_api_message.h"
30
31struct GNUNET_MESSENGER_Client
32{
33 struct GNUNET_SERVICE_Client *client;
34 struct GNUNET_MESSENGER_SrvHandle *handle;
35};
36
37struct GNUNET_MESSENGER_Service *messenger;
38
39static int
40check_create (void *cls, const struct GNUNET_MESSENGER_CreateMessage *msg)
41{
42 GNUNET_MQ_check_zero_termination(msg);
43 return GNUNET_OK;
44}
45
46static void
47handle_create (void *cls, const struct GNUNET_MESSENGER_CreateMessage *msg)
48{
49 struct GNUNET_MESSENGER_Client *msg_client = cls;
50
51 const char *name = ((const char*) msg) + sizeof(*msg);
52
53 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Handle created with name: %s\n", name);
54
55 setup_handle_name (msg_client->handle, strlen (name) > 0? name : NULL);
56
57 GNUNET_SERVICE_client_continue (msg_client->client);
58}
59
60static void
61handle_update (void *cls, const struct GNUNET_MESSENGER_UpdateMessage *msg)
62{
63 struct GNUNET_MESSENGER_Client *msg_client = cls;
64
65 if (GNUNET_OK != update_handle (msg_client->handle))
66 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Name is required to update key!\n");
67
68 GNUNET_SERVICE_client_continue (msg_client->client);
69}
70
71static void
72handle_destroy (void *cls, const struct GNUNET_MESSENGER_DestroyMessage *msg)
73{
74 struct GNUNET_MESSENGER_Client *msg_client = cls;
75
76 GNUNET_SERVICE_client_drop (msg_client->client);
77}
78
79static int
80check_set_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
81{
82 GNUNET_MQ_check_zero_termination(msg);
83 return GNUNET_OK;
84}
85
86static void
87handle_set_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
88{
89 struct GNUNET_MESSENGER_Client *msg_client = cls;
90
91 const char *name = ((const char*) msg) + sizeof(*msg);
92
93 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Handles name is now: %s\n", name);
94
95 if (GNUNET_YES != set_handle_name (msg_client->handle, name))
96 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No valid name: %s\n", name);
97
98 GNUNET_SERVICE_client_continue (msg_client->client);
99}
100
101static void
102handle_room_open (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
103{
104 struct GNUNET_MESSENGER_Client *msg_client = cls;
105
106 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Opening room: %s\n",
107 GNUNET_h2s (&(msg->key)));
108
109 if (GNUNET_YES == open_handle_room (msg_client->handle, &(msg->key)))
110 {
111 const struct GNUNET_ShortHashCode* member_id = get_handle_member_id(msg_client->handle, &(msg->key));
112
113 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Opening room with member id: %s\n",
114 GNUNET_sh2s (member_id));
115
116 struct GNUNET_MESSENGER_RoomMessage *response;
117 struct GNUNET_MQ_Envelope *env;
118
119 env = GNUNET_MQ_msg(response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN);
120 GNUNET_memcpy(&(response->key), &(msg->key), sizeof(msg->key));
121 GNUNET_MQ_send (msg_client->handle->mq, env);
122 }
123 else
124 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Opening room failed: %s\n",
125 GNUNET_h2s (&(msg->key)));
126
127 GNUNET_SERVICE_client_continue (msg_client->client);
128}
129
130static void
131handle_room_entry (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
132{
133 struct GNUNET_MESSENGER_Client *msg_client = cls;
134
135 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Entering room: %s, %s\n",
136 GNUNET_h2s (&(msg->key)), GNUNET_i2s (&(msg->door)));
137
138 if (GNUNET_YES == entry_handle_room (msg_client->handle, &(msg->door), &(msg->key)))
139 {
140 const struct GNUNET_ShortHashCode* member_id = get_handle_member_id(msg_client->handle, &(msg->key));
141
142 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Entering room with member id: %s\n",
143 GNUNET_sh2s (member_id));
144
145 struct GNUNET_MESSENGER_RoomMessage *response;
146 struct GNUNET_MQ_Envelope *env;
147
148 env = GNUNET_MQ_msg(response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY);
149 GNUNET_memcpy(&(response->door), &(msg->door), sizeof(msg->door));
150 GNUNET_memcpy(&(response->key), &(msg->key), sizeof(msg->key));
151 GNUNET_MQ_send (msg_client->handle->mq, env);
152 }
153 else
154 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Entrance into room failed: %s, %s\n",
155 GNUNET_h2s (&(msg->key)), GNUNET_i2s (&(msg->door)));
156
157 GNUNET_SERVICE_client_continue (msg_client->client);
158}
159
160static void
161handle_room_close (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
162{
163 struct GNUNET_MESSENGER_Client *msg_client = cls;
164
165 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Closing room: %s\n", GNUNET_h2s (&(msg->key)));
166
167 if (GNUNET_YES == close_handle_room (msg_client->handle, &(msg->key)))
168 {
169 const struct GNUNET_ShortHashCode* member_id = get_handle_member_id(msg_client->handle, &(msg->key));
170
171 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Closing room with member id: %s\n",
172 GNUNET_sh2s (member_id));
173
174 struct GNUNET_MESSENGER_RoomMessage *response;
175 struct GNUNET_MQ_Envelope *env;
176
177 env = GNUNET_MQ_msg(response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE);
178 GNUNET_memcpy(&(response->key), &(msg->key), sizeof(msg->key));
179 GNUNET_MQ_send (msg_client->handle->mq, env);
180 }
181 else
182 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Closing room failed: %s\n", GNUNET_h2s (&(msg->key)));
183
184 GNUNET_SERVICE_client_continue (msg_client->client);
185}
186
187static int
188check_send_message (void *cls, const struct GNUNET_MESSENGER_SendMessage *msg)
189{
190 const uint16_t full_length = ntohs (msg->header.size) - sizeof(msg->header);
191
192 if (full_length < sizeof(msg->key))
193 return GNUNET_NO;
194
195 const uint16_t length = full_length - sizeof(msg->key);
196 const char *buffer = ((const char*) msg) + sizeof(*msg);
197
198 struct GNUNET_MESSENGER_Message message;
199
200 if (GNUNET_YES != decode_message (&message, length, buffer))
201 return GNUNET_NO;
202
203 return GNUNET_OK;
204}
205
206static void
207handle_send_message (void *cls, const struct GNUNET_MESSENGER_SendMessage *msg)
208{
209 struct GNUNET_MESSENGER_Client *msg_client = cls;
210
211 const struct GNUNET_HashCode *key = &(msg->key);
212 const char *buffer = ((const char*) msg) + sizeof(*msg);
213
214 const uint16_t length = ntohs (msg->header.size) - sizeof(*msg);
215
216 struct GNUNET_MESSENGER_Message message;
217 decode_message (&message, length, buffer);
218
219 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending message: %s to %s\n",
220 GNUNET_MESSENGER_name_of_kind (message.header.kind),
221 GNUNET_h2s (key));
222
223 if (GNUNET_YES != send_handle_message (msg_client->handle, key, &message))
224 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sending message failed: %s to %s\n",
225 GNUNET_MESSENGER_name_of_kind (message.header.kind),
226 GNUNET_h2s (key));
227
228 GNUNET_SERVICE_client_continue (msg_client->client);
229}
230
231static void
232handle_get_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg)
233{
234 struct GNUNET_MESSENGER_Client *msg_client = cls;
235
236 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Requesting message from room: %s\n",
237 GNUNET_h2s (&(msg->key)));
238
239 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (messenger, &(msg->key));
240
241 if (room)
242 get_room_message (room, msg_client->handle, &(msg->hash), GNUNET_YES);
243 else
244 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Room not found: %s\n",
245 GNUNET_h2s (&(msg->key)));
246
247 GNUNET_SERVICE_client_continue (msg_client->client);
248}
249
250static void*
251callback_client_connect (void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
252{
253 struct GNUNET_MESSENGER_Client *msg_client = GNUNET_new(struct GNUNET_MESSENGER_Client);
254
255 msg_client->client = client;
256 msg_client->handle = add_service_handle (messenger, mq);
257
258 return msg_client;
259}
260
261static void
262callback_client_disconnect (void *cls, struct GNUNET_SERVICE_Client *client, void *internal_cls)
263{
264 struct GNUNET_MESSENGER_Client *msg_client = internal_cls;
265
266 remove_service_handle (messenger, msg_client->handle);
267
268 GNUNET_free(msg_client);
269}
270
271/**
272 * Setup MESSENGER internals.
273 *
274 * @param cls closure
275 * @param config configuration to use
276 * @param service the initialized service
277 */
278static void
279run (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service)
280{
281 messenger = create_service (config, service);
282
283 if ((!messenger) || (!messenger->cadet) || (!messenger->identity))
284 GNUNET_SCHEDULER_shutdown ();
285}
286
287/**
288 * Define "main" method using service macro.
289 */
290GNUNET_SERVICE_MAIN(
291 GNUNET_MESSENGER_SERVICE_NAME,
292 GNUNET_SERVICE_OPTION_NONE,
293 &run,
294 &callback_client_connect,
295 &callback_client_disconnect,
296 NULL,
297 GNUNET_MQ_hd_var_size( create, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE, struct GNUNET_MESSENGER_CreateMessage, NULL ),
298 GNUNET_MQ_hd_fixed_size( update, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_UPDATE, struct GNUNET_MESSENGER_UpdateMessage, NULL ),
299 GNUNET_MQ_hd_fixed_size( destroy, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY, struct GNUNET_MESSENGER_DestroyMessage, NULL ),
300 GNUNET_MQ_hd_var_size( set_name, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_SET_NAME, struct GNUNET_MESSENGER_NameMessage, NULL ),
301 GNUNET_MQ_hd_fixed_size( room_open, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN, struct GNUNET_MESSENGER_RoomMessage, NULL ),
302 GNUNET_MQ_hd_fixed_size( room_entry, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY, struct GNUNET_MESSENGER_RoomMessage, NULL ),
303 GNUNET_MQ_hd_fixed_size( room_close, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE, struct GNUNET_MESSENGER_RoomMessage, NULL ),
304 GNUNET_MQ_hd_var_size( send_message, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE, struct GNUNET_MESSENGER_SendMessage, NULL ),
305 GNUNET_MQ_hd_fixed_size( get_message, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE, struct GNUNET_MESSENGER_RecvMessage, NULL ),
306 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_H
27#define GNUNET_SERVICE_MESSENGER_H
28
29#include "platform.h"
30#include "gnunet_cadet_service.h"
31#include "gnunet_container_lib.h"
32#include "gnunet_crypto_lib.h"
33#include "gnunet_identity_service.h"
34#include "gnunet_mq_lib.h"
35#include "gnunet_peer_lib.h"
36#include "gnunet_protocols.h"
37#include "gnunet_util_lib.h"
38
39/**
40 * Message to create a handle for a client
41 */
42struct GNUNET_MESSENGER_CreateMessage
43{
44 struct GNUNET_MessageHeader header;
45};
46
47/**
48 * Message to update the handle (its EGO key) for a client
49 */
50struct GNUNET_MESSENGER_UpdateMessage
51{
52 struct GNUNET_MessageHeader header;
53};
54
55/**
56 * Message to destroy the handle for a client
57 */
58struct GNUNET_MESSENGER_DestroyMessage
59{
60 struct GNUNET_MessageHeader header;
61};
62
63/**
64 * Message to receive the current name of a handle
65 */
66struct GNUNET_MESSENGER_NameMessage
67{
68 struct GNUNET_MessageHeader header;
69};
70
71/**
72 * Message to receive the current public key of a handle
73 */
74struct GNUNET_MESSENGER_KeyMessage
75{
76 struct GNUNET_MessageHeader header;
77 struct GNUNET_IDENTITY_PublicKey pubkey;
78};
79
80/**
81 * General message to confirm interaction with a room
82 */
83struct GNUNET_MESSENGER_RoomMessage
84{
85 struct GNUNET_MessageHeader header;
86
87 struct GNUNET_PeerIdentity door;
88 struct GNUNET_HashCode key;
89};
90
91/**
92 * Message to receive the current member id of a handle in room
93 */
94struct GNUNET_MESSENGER_MemberMessage
95{
96 struct GNUNET_MessageHeader header;
97
98 struct GNUNET_HashCode key;
99 struct GNUNET_ShortHashCode id;
100};
101
102/**
103 * Message to send something into a room
104 */
105struct GNUNET_MESSENGER_SendMessage
106{
107 struct GNUNET_MessageHeader header;
108 struct GNUNET_HashCode key;
109};
110
111/**
112 * Message to receive something from a room
113 */
114struct GNUNET_MESSENGER_RecvMessage
115{
116 struct GNUNET_MessageHeader header;
117 struct GNUNET_HashCode key;
118 struct GNUNET_HashCode hash;
119};
120
121#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_basement.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_basement.h"
27
28size_t
29count_of_tunnels (const struct GNUNET_MESSENGER_ListTunnels *tunnels)
30{
31 const struct GNUNET_MESSENGER_ListTunnel *element;
32 size_t count = 0;
33
34 for (element = tunnels->head; element; element = element->next)
35 count++;
36
37 return count;
38}
39
40int
41should_connect_tunnel_to (size_t count, size_t src, size_t dst)
42{
43 if ((src + 1) % count == dst % count)
44 return GNUNET_YES;
45
46 return GNUNET_NO;
47}
48
49int
50required_connection_between (size_t count, size_t src, size_t dst)
51{
52 if (GNUNET_YES == should_connect_tunnel_to (count, src, dst))
53 return GNUNET_YES;
54 if (GNUNET_YES == should_connect_tunnel_to (count, dst, src))
55 return GNUNET_YES;
56
57 return GNUNET_NO;
58}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_basement.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_BASEMENT_H
27#define GNUNET_SERVICE_MESSENGER_BASEMENT_H
28
29#include "messenger_api_list_tunnels.h"
30
31/**
32 * Returns the count of peers in a list (typically from the basement of a room).
33 *
34 * @param tunnels List of peer identities
35 * @return Count of the entries in the list
36 */
37size_t
38count_of_tunnels (const struct GNUNET_MESSENGER_ListTunnels *tunnels);
39
40/**
41 * Returns GNUNET_YES or GNUNET_NO to determine if the peer at index <i>src</i> should
42 * or should not connect outgoing to the peer at index <i>dst</i> to construct a complete
43 * basement with a given <i>count</i> of peers.
44 *
45 * @param count Count of peers
46 * @param src Source index
47 * @param dst Destination index
48 * @return GNUNET_YES or GNUNET_NO based on topologic requirement
49 */
50int
51should_connect_tunnel_to (size_t count, size_t src, size_t dst);
52
53/**
54 * Returns GNUNET_YES or GNUNET_NO to determine if the peers of index <i>src</i> and
55 * index <i>dst</i> should be connected in any direction to construct a complete
56 * basement with a given <i>count</i> of peers.
57 *
58 * @param count Count of peers
59 * @param src Source index
60 * @param dst Destination index
61 * @return GNUNET_YES or GNUNET_NO based on topologic requirement
62 */
63int
64required_connection_between (size_t count, size_t src, size_t dst);
65
66#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_contact.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_contact.h"
27
28struct GNUNET_MESSENGER_SrvContact*
29create_contact (const struct GNUNET_IDENTITY_PublicKey *key)
30{
31 struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_new(struct GNUNET_MESSENGER_SrvContact);
32
33 contact->name = NULL;
34 contact->rc = 0;
35
36 GNUNET_memcpy(&(contact->public_key), key, sizeof(contact->public_key));
37
38 return contact;
39}
40
41void
42destroy_contact (struct GNUNET_MESSENGER_SrvContact *contact)
43{
44 if (contact->name)
45 GNUNET_free(contact->name);
46
47 GNUNET_free(contact);
48}
49
50const char*
51get_contact_name (const struct GNUNET_MESSENGER_SrvContact *contact)
52{
53 return contact->name;
54}
55
56void
57set_contact_name (struct GNUNET_MESSENGER_SrvContact *contact, const char *name)
58{
59 GNUNET_assert(name);
60
61 if (contact->name)
62 GNUNET_free(contact->name);
63
64 contact->name = GNUNET_strdup(name);
65}
66
67const struct GNUNET_IDENTITY_PublicKey*
68get_contact_key (const struct GNUNET_MESSENGER_SrvContact *contact)
69{
70 return &(contact->public_key);
71}
72
73void
74increase_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact)
75{
76 contact->rc++;
77}
78
79int
80decrease_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact)
81{
82 if (contact->rc > 0)
83 contact->rc--;
84
85 return contact->rc ? GNUNET_NO : GNUNET_YES;
86}
87
88const struct GNUNET_HashCode*
89get_contact_id_from_key (const struct GNUNET_MESSENGER_SrvContact *contact)
90{
91 static struct GNUNET_HashCode id;
92
93 GNUNET_CRYPTO_hash (&(contact->public_key), sizeof(contact->public_key), &id);
94
95 return &id;
96}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_contact.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_CONTACT_H
27#define GNUNET_SERVICE_MESSENGER_CONTACT_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_identity_service.h"
32
33struct GNUNET_MESSENGER_SrvContact
34{
35 char *name;
36 size_t rc;
37
38 struct GNUNET_IDENTITY_PublicKey public_key;
39};
40
41/**
42 * Creates and allocates a new contact with a given public <i>key</i> from an EGO.
43 *
44 * @param key Public key
45 * @return New contact
46 */
47struct GNUNET_MESSENGER_SrvContact*
48create_contact (const struct GNUNET_IDENTITY_PublicKey *key);
49
50/**
51 * Destroys a contact and frees its memory fully.
52 *
53 * @param contact Contact
54 */
55void
56destroy_contact (struct GNUNET_MESSENGER_SrvContact *contact);
57
58/**
59 * Returns the current name of a given <i>contact</i> or NULL if no valid name was assigned yet.
60 *
61 * @param contact Contact
62 * @return Name of the contact or NULL
63 */
64const char*
65get_contact_name (const struct GNUNET_MESSENGER_SrvContact *contact);
66
67/**
68 * Changes the current name of a given <i>contact</i> by copying it from the parameter <i>name</i>.
69 *
70 * @param contact Contact
71 * @param name Valid name (may not be NULL!)
72 */
73void
74set_contact_name (struct GNUNET_MESSENGER_SrvContact *contact, const char *name);
75
76/**
77 * Returns the public key of a given <i>contact</i>.
78 *
79 * @param contact Contact
80 * @return Public key of the contact
81 */
82const struct GNUNET_IDENTITY_PublicKey*
83get_contact_key (const struct GNUNET_MESSENGER_SrvContact *contact);
84
85/**
86 * Increases the reference counter of a given <i>contact</i> which is zero as default.
87 *
88 * @param contact Contact
89 */
90void
91increase_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact);
92
93/**
94 * Decreases the reference counter if possible (can not underflow!) of a given <i>contact</i>
95 * and returns GNUNET_YES if the counter is equal to zero, otherwise GNUNET_NO.
96 *
97 * @param contact Contact
98 * @return GNUNET_YES or GNUNET_NO depending on the reference counter
99 */
100int
101decrease_contact_rc (struct GNUNET_MESSENGER_SrvContact *contact);
102
103/**
104 * Returns the resulting hashcode of the public key from a given <i>contact</i>.
105 *
106 * @param contact Contact
107 * @return Hash of the contacts public key
108 */
109const struct GNUNET_HashCode*
110get_contact_id_from_key (const struct GNUNET_MESSENGER_SrvContact *contact);
111
112#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_handle.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_handle.h"
27
28#include "gnunet-service-messenger.h"
29#include "gnunet-service-messenger_message_kind.h"
30
31struct GNUNET_MESSENGER_SrvHandle*
32create_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq)
33{
34 struct GNUNET_MESSENGER_SrvHandle *handle = GNUNET_new(struct GNUNET_MESSENGER_SrvHandle);
35
36 handle->service = service;
37 handle->mq = mq;
38
39 handle->name = NULL;
40
41 handle->operation = NULL;
42
43 handle->ego = NULL;
44
45 handle->member_ids = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
46
47 return handle;
48}
49
50int
51iterate_free_member_ids (void *cls, const struct GNUNET_HashCode *key, void *value)
52{
53 GNUNET_free(value);
54
55 return GNUNET_YES;
56}
57
58void
59destroy_handle (struct GNUNET_MESSENGER_SrvHandle *handle)
60{
61 if (handle->service->dir)
62 save_handle_configuration(handle);
63
64 if (handle->operation)
65 GNUNET_IDENTITY_cancel (handle->operation);
66
67 if (handle->name)
68 GNUNET_free(handle->name);
69
70 GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_free_member_ids, NULL);
71 GNUNET_CONTAINER_multihashmap_destroy (handle->member_ids);
72
73 GNUNET_free(handle);
74}
75
76void
77get_handle_data_subdir (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name, char **dir)
78{
79 if (name)
80 GNUNET_asprintf (dir, "%s%s%c%s%c", handle->service->dir, "identities",
81 DIR_SEPARATOR, name, DIR_SEPARATOR);
82 else
83 GNUNET_asprintf (dir, "%s%s%c", handle->service->dir, "anonymous",
84 DIR_SEPARATOR);
85}
86
87static int
88create_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
89{
90 struct GNUNET_ShortHashCode *random_id = generate_service_new_member_id (handle->service, key);
91
92 if (!random_id)
93 return GNUNET_NO;
94
95 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key, random_id,
96 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
97 {
98 GNUNET_free(random_id);
99 return GNUNET_NO;
100 }
101
102 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Created a new member id (%s) for room: %s\n",
103 GNUNET_sh2s(random_id), GNUNET_h2s(key));
104
105 return GNUNET_YES;
106}
107
108const struct GNUNET_ShortHashCode*
109get_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
110{
111 return GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key);
112}
113
114void
115change_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
116 const struct GNUNET_ShortHashCode *unique_id)
117{
118 struct GNUNET_ShortHashCode *member_id = GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key);
119
120 if (member_id)
121 {
122 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Changed a member id (%s) for room (%s) ",
123 GNUNET_sh2s(member_id), GNUNET_h2s(key));
124 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "into (%s).\n",
125 GNUNET_sh2s(unique_id));
126
127 GNUNET_memcpy(member_id, unique_id, sizeof(*unique_id));
128
129 struct GNUNET_MESSENGER_MemberMessage *msg;
130 struct GNUNET_MQ_Envelope *env;
131
132 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID);
133
134 GNUNET_memcpy(&(msg->key), key, sizeof(*key));
135 GNUNET_memcpy(&(msg->id), member_id, sizeof(*member_id));
136
137 GNUNET_MQ_send (handle->mq, env);
138 }
139 else
140 {
141 member_id = GNUNET_new(struct GNUNET_ShortHashCode);
142 GNUNET_memcpy(member_id, unique_id, sizeof(*member_id));
143
144 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key, member_id,
145 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
146 GNUNET_free(member_id);
147 }
148}
149
150static void
151change_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name)
152{
153 if (handle->name)
154 GNUNET_free(handle->name);
155
156 handle->name = name ? GNUNET_strdup(name) : NULL;
157
158 const uint16_t name_len = handle->name ? strlen (handle->name) : 0;
159
160 struct GNUNET_MESSENGER_NameMessage *msg;
161 struct GNUNET_MQ_Envelope *env;
162
163 env = GNUNET_MQ_msg_extra(msg, name_len + 1, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_NAME);
164
165 char *extra = ((char*) msg) + sizeof(*msg);
166
167 if (name_len)
168 GNUNET_memcpy(extra, handle->name, name_len);
169
170 extra[name_len] = '\0';
171
172 GNUNET_MQ_send (handle->mq, env);
173}
174
175static void
176change_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle, struct GNUNET_MESSENGER_Ego *ego)
177{
178 handle->ego = ego;
179
180 ego = get_handle_ego(handle);
181
182 struct GNUNET_MESSENGER_KeyMessage *msg;
183 struct GNUNET_MQ_Envelope *env;
184
185 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_KEY);
186
187 GNUNET_memcpy(&(msg->pubkey), &(ego->pub), sizeof(ego->pub));
188
189 GNUNET_MQ_send (handle->mq, env);
190}
191
192struct GNUNET_MESSENGER_Ego*
193get_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle)
194{
195 static struct GNUNET_MESSENGER_Ego anonymous;
196 static int read_keys = 0;
197
198 if (handle->ego)
199 return handle->ego;
200
201 if (!read_keys)
202 {
203 struct GNUNET_IDENTITY_Ego* ego = GNUNET_IDENTITY_ego_get_anonymous ();
204 GNUNET_memcpy(&(anonymous.priv), GNUNET_IDENTITY_ego_get_private_key(ego), sizeof(anonymous.priv));
205 GNUNET_IDENTITY_ego_get_public_key(ego, &(anonymous.pub));
206 read_keys = 1;
207 }
208
209 return &anonymous;
210}
211
212void
213setup_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name)
214{
215 change_handle_name (handle, name);
216 change_handle_ego (handle, handle->name? lookup_service_ego(handle->service, handle->name) : NULL);
217
218 if (handle->service->dir)
219 load_handle_configuration(handle);
220}
221
222struct GNUNET_MESSENGER_MessageHandle
223{
224 struct GNUNET_MESSENGER_SrvHandle *handle;
225 struct GNUNET_MESSENGER_Message *message;
226};
227
228static int
229iterate_send_message (void *cls, const struct GNUNET_HashCode *key, void *value)
230{
231 struct GNUNET_MESSENGER_MessageHandle *msg_handle = cls;
232
233 send_handle_message (msg_handle->handle, key, msg_handle->message);
234
235 return GNUNET_YES;
236}
237
238static void
239callback_ego_create (void *cls, const struct GNUNET_IDENTITY_PrivateKey *key, const char *emsg)
240{
241 struct GNUNET_MESSENGER_SrvHandle *handle = cls;
242
243 handle->operation = NULL;
244
245 if (emsg)
246 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s\n", emsg);
247
248 if (key)
249 {
250 struct GNUNET_MESSENGER_MessageHandle msg_handle;
251
252 msg_handle.handle = handle;
253 msg_handle.message = create_message_key (key);
254
255 GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_send_message, &msg_handle);
256
257 destroy_message (msg_handle.message);
258
259 update_service_ego(handle->service, handle->name, key);
260
261 change_handle_ego (handle, lookup_service_ego(handle->service, handle->name));
262 }
263}
264
265int
266update_handle (struct GNUNET_MESSENGER_SrvHandle *handle)
267{
268 GNUNET_assert(handle);
269
270 if (!handle->name)
271 return GNUNET_SYSERR;
272
273 struct GNUNET_MESSENGER_Ego *ego = lookup_service_ego(handle->service, handle->name);
274
275 if (!ego)
276 handle->operation = GNUNET_IDENTITY_create (handle->service->identity, handle->name, NULL,
277 GNUNET_IDENTITY_TYPE_ECDSA, callback_ego_create, handle);
278 else
279 change_handle_ego (handle, ego);
280
281 return GNUNET_OK;
282}
283
284int
285set_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name)
286{
287 GNUNET_assert(handle);
288
289 if ((name) && (lookup_service_ego(handle->service, name)))
290 return GNUNET_NO;
291
292 struct GNUNET_IDENTITY_Operation *operation = handle->operation;
293
294 if (handle->name)
295 handle->operation = GNUNET_IDENTITY_rename (handle->service->identity, handle->name, name, NULL, NULL);
296
297 char *old_dir;
298 get_handle_data_subdir (handle, handle->name, &old_dir);
299
300 char *new_dir;
301 get_handle_data_subdir (handle, name, &new_dir);
302
303 int result = 0;
304
305 if (GNUNET_YES == GNUNET_DISK_directory_test (old_dir, GNUNET_YES))
306 {
307 GNUNET_DISK_directory_create_for_file (new_dir);
308
309 result = rename (old_dir, new_dir);
310 }
311 else if (GNUNET_YES == GNUNET_DISK_directory_test (new_dir, GNUNET_NO))
312 result = -1;
313
314 if (0 == result)
315 {
316 struct GNUNET_MESSENGER_MessageHandle msg_handle;
317
318 msg_handle.handle = handle;
319 msg_handle.message = create_message_name (name);
320
321 GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_send_message, &msg_handle);
322
323 destroy_message (msg_handle.message);
324
325 change_handle_name (handle, name);
326
327 if (operation)
328 GNUNET_IDENTITY_cancel (operation);
329 }
330 else
331 {
332 if (handle->operation)
333 {
334 GNUNET_IDENTITY_cancel (handle->operation);
335
336 handle->operation = operation;
337 }
338 }
339
340 GNUNET_free(old_dir);
341 GNUNET_free(new_dir);
342
343 return (result == 0 ? GNUNET_OK : GNUNET_NO);
344}
345
346int
347open_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
348{
349 if ((!get_handle_member_id (handle, key)) && (GNUNET_YES != create_handle_member_id (handle, key)))
350 return GNUNET_NO;
351
352 return open_service_room (handle->service, handle, key);
353}
354
355int
356entry_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_PeerIdentity *door,
357 const struct GNUNET_HashCode *key)
358{
359 if ((!get_handle_member_id (handle, key)) && (GNUNET_YES != create_handle_member_id (handle, key)))
360 return GNUNET_NO;
361
362 return entry_service_room (handle->service, handle, door, key);
363}
364
365int
366close_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
367{
368 if (!get_handle_member_id (handle, key))
369 return GNUNET_NO;
370
371 return close_service_room (handle->service, handle, key);
372}
373
374int
375send_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
376 struct GNUNET_MESSENGER_Message *message)
377{
378 const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, key);
379
380 if (!id)
381 {
382 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "It is required to be a member of a room to send messages!\n");
383 return GNUNET_NO;
384 }
385
386 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (handle->service, key);
387
388 if (!room)
389 {
390 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "The room (%s) is unknown!\n", GNUNET_h2s (key));
391 return GNUNET_NO;
392 }
393
394 struct GNUNET_HashCode hash;
395
396 GNUNET_memcpy(&(message->header.sender_id), id, sizeof(*id));
397
398 send_room_message (room, handle, message, &hash);
399 return GNUNET_YES;
400}
401
402static int callback_scan_for_rooms(void* cls, const char *filename) {
403 struct GNUNET_MESSENGER_SrvHandle* handle = cls;
404
405 struct GNUNET_CONFIGURATION_Handle* cfg = GNUNET_CONFIGURATION_create();
406
407 if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) &&
408 (GNUNET_OK == GNUNET_CONFIGURATION_parse(cfg, filename)))
409 {
410 struct GNUNET_HashCode key;
411 struct GNUNET_ShortHashCode member_id;
412
413 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_data(cfg, "room", "key", &key, sizeof(key))) &&
414 (GNUNET_OK == GNUNET_CONFIGURATION_get_data(cfg, "room", "member_id", &member_id, sizeof(member_id))))
415 change_handle_member_id(handle, &key, &member_id);
416 }
417
418 GNUNET_CONFIGURATION_destroy(cfg);
419 return GNUNET_OK;
420}
421
422void load_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle) {
423 char* id_dir;
424 get_handle_data_subdir(handle, handle->name, &id_dir);
425
426 if (GNUNET_YES == GNUNET_DISK_directory_test(id_dir, GNUNET_YES))
427 {
428 char* scan_dir;
429 GNUNET_asprintf(&scan_dir, "%s%s%c", id_dir, "rooms", DIR_SEPARATOR);
430
431 if (GNUNET_OK == GNUNET_DISK_directory_test(scan_dir, GNUNET_YES))
432 GNUNET_DISK_directory_scan(scan_dir, callback_scan_for_rooms, handle);
433
434 GNUNET_free(scan_dir);
435 }
436
437 GNUNET_free(id_dir);
438}
439
440static int
441iterate_save_rooms(void* cls, const struct GNUNET_HashCode* key, void* value)
442{
443 struct GNUNET_MESSENGER_SrvHandle* handle = cls;
444 struct GNUNET_ShortHashCode* member_id = value;
445
446 char* id_dir;
447 get_handle_data_subdir(handle, handle->name, &id_dir);
448
449 char* filename;
450 GNUNET_asprintf(&filename, "%s%s%c%s.cfg",
451 id_dir, "rooms", DIR_SEPARATOR,
452 GNUNET_h2s(key));
453
454 GNUNET_free(id_dir);
455
456 struct GNUNET_CONFIGURATION_Handle* cfg = GNUNET_CONFIGURATION_create();
457
458 char* key_data = GNUNET_STRINGS_data_to_string_alloc(key, sizeof(*key));
459
460 if (key_data)
461 {
462 GNUNET_CONFIGURATION_set_value_string(cfg, "room", "key", key_data);
463
464 GNUNET_free(key_data);
465 }
466
467 char* member_id_data = GNUNET_STRINGS_data_to_string_alloc(member_id, sizeof(*member_id));
468
469 if (member_id_data)
470 {
471 GNUNET_CONFIGURATION_set_value_string(cfg, "room", "member_id", member_id_data);
472
473 GNUNET_free(member_id_data);
474 }
475
476 GNUNET_CONFIGURATION_write(cfg, filename);
477 GNUNET_CONFIGURATION_destroy(cfg);
478
479 GNUNET_free(filename);
480
481 return GNUNET_YES;
482}
483
484void save_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle)
485{
486 char* id_dir;
487 get_handle_data_subdir(handle, handle->name, &id_dir);
488
489 if ((GNUNET_YES == GNUNET_DISK_directory_test(id_dir, GNUNET_NO)) ||
490 (GNUNET_OK == GNUNET_DISK_directory_create(id_dir)))
491 {
492 char* save_dir;
493 GNUNET_asprintf(&save_dir, "%s%s%c", id_dir, "rooms", DIR_SEPARATOR);
494
495 if ((GNUNET_YES == GNUNET_DISK_directory_test(save_dir, GNUNET_NO)) ||
496 (GNUNET_OK == GNUNET_DISK_directory_create(save_dir)))
497 GNUNET_CONTAINER_multihashmap_iterate(handle->member_ids, iterate_save_rooms, handle);
498
499 GNUNET_free(save_dir);
500 }
501
502 GNUNET_free(id_dir);
503}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_handle.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_HANDLE_H
27#define GNUNET_SERVICE_MESSENGER_HANDLE_H
28
29#include "platform.h"
30#include "gnunet_cadet_service.h"
31#include "gnunet_container_lib.h"
32#include "gnunet_crypto_lib.h"
33#include "gnunet_identity_service.h"
34#include "gnunet_peer_lib.h"
35#include "gnunet_mq_lib.h"
36
37#include "gnunet-service-messenger_service.h"
38
39#include "messenger_api_ego.h"
40#include "messenger_api_message.h"
41
42struct GNUNET_MESSENGER_SrvHandle
43{
44 struct GNUNET_MESSENGER_Service *service;
45 struct GNUNET_MQ_Handle *mq;
46
47 char *name;
48
49 struct GNUNET_IDENTITY_Operation *operation;
50
51 struct GNUNET_MESSENGER_Ego *ego;
52
53 struct GNUNET_CONTAINER_MultiHashMap *member_ids;
54};
55
56/**
57 * Creates and allocates a new handle related to a <i>service</i> and using a given <i>mq</i> (message queue).
58 *
59 * @param service MESSENGER Service
60 * @param mq Message queue
61 * @return New handle
62 */
63struct GNUNET_MESSENGER_SrvHandle*
64create_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq);
65
66/**
67 * Destroys a handle and frees its memory fully.
68 *
69 * @param handle Handle
70 */
71void
72destroy_handle (struct GNUNET_MESSENGER_SrvHandle *handle);
73
74/**
75 * Writes the path of the directory for a given <i>handle</i> using a specific <i>name</i> to the parameter
76 * <i>dir</i>. This directory will be used to store data regarding the handle and its messages.
77 *
78 * @param handle Handle
79 * @param name Potential name of the handle
80 * @param dir[out] Path to store data
81 */
82void
83get_handle_data_subdir (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name, char **dir);
84
85/**
86 * Returns the member id of a given <i>handle</i> in a specific <i>room</i>.
87 *
88 * If the handle is not a member of the specific <i>room</i>, NULL gets returned.
89 *
90 * @param handle Handle
91 * @param key Key of a room
92 * @return Member id or NULL
93 */
94const struct GNUNET_ShortHashCode*
95get_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
96
97/**
98 * Changes the member id of a given <i>handle</i> in a specific <i>room</i> to match a <i>unique_id</i>.
99 *
100 * The client connected to the <i>handle</i> will be informed afterwards automatically.
101 *
102 * @param handle Handle
103 * @param key Key of a room
104 * @param unique_id Unique member id
105 */
106void
107change_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
108 const struct GNUNET_ShortHashCode *unique_id);
109
110/**
111 * Returns the EGO used by a given <i>handle</i>.
112 *
113 * @param handle Handle
114 * @return EGO keypair
115 */
116struct GNUNET_MESSENGER_Ego*
117get_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle);
118
119/**
120 * Tries to set the name and EGO key of a <i>handle</i> initially by looking up a specific <i>name</i>.
121 *
122 * @param handle Handle
123 * @param name Name (optionally: valid EGO name)
124 */
125void
126setup_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name);
127
128/**
129 * Tries to change the keypair of an EGO of a <i>handle</i> under the same name and informs all rooms
130 * about the change automatically.
131 *
132 * @param handle Handle
133 * @return GNUNET_OK on success, otherwise GNUNET_SYSERR
134 */
135int
136update_handle (struct GNUNET_MESSENGER_SrvHandle *handle);
137
138/**
139 * Tries to rename the handle which implies renaming the EGO its using and moving all related data into
140 * the directory fitting to the changed <i>name</i>.
141 *
142 * The client connected to the <i>handle</i> will be informed afterwards automatically.
143 *
144 * @param handle Handle
145 * @param name New name
146 * @return GNUNET_OK on success, otherwise GNUNET_NO
147 */
148int
149set_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle, const char *name);
150
151/**
152 * Makes a given <i>handle</i> a member of the room using a specific <i>key</i> and opens the
153 * room from the handles service.
154 *
155 * @param handle Handle
156 * @param key Key of a room
157 * @return GNUNET_YES on success, otherwise GNUNET_NO
158 */
159int
160open_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
161
162/**
163 * Makes a given <i>handle</i> a member of the room using a specific <i>key</i> and enters the room
164 * through a tunnel to a peer identified by a given <i>door</i> (peer identity).
165 *
166 * @param handle Handle
167 * @param door Peer identity
168 * @param key Key of a room
169 * @return GNUNET_YES on success, otherwise GNUNET_NO
170 */
171int
172entry_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_PeerIdentity *door,
173 const struct GNUNET_HashCode *key);
174
175/**
176 * Removes the membership of the room using a specific <i>key</i> and closes it if no other handle
177 * from this service is still a member of it.
178 *
179 * @param handle Handle
180 * @param key Key of a room
181 * @return GNUNET_YES on success, otherwise GNUNET_NO
182 */
183int
184close_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
185
186/**
187 * Sends a <i>message</i> from a given <i>handle</i> to the room using a specific <i>key</i>.
188 *
189 * @param handle Handle
190 * @param key Key of a room
191 * @param message Message
192 * @return GNUNET_YES on success, otherwise GNUNET_NO
193 */
194int
195send_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key,
196 struct GNUNET_MESSENGER_Message *message);
197
198/**
199 * Loads member ids and other potential configuration from a given <i>handle</i> which
200 * depends on the given name the <i>handle</i> uses.
201 *
202 * @param handle Handle
203 */
204void
205load_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle);
206
207/**
208 * Saves member ids and other potential configuration from a given <i>handle</i> which
209 * depends on the given name the <i>handle</i> uses.
210 *
211 * @param handle Handle
212 */
213void
214save_handle_configuration(struct GNUNET_MESSENGER_SrvHandle *handle);
215
216#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_handles.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_list_handles.h"
27
28#include "gnunet-service-messenger_handle.h"
29
30void
31init_list_handles (struct GNUNET_MESSENGER_ListHandles *handles)
32{
33 GNUNET_assert(handles);
34
35 handles->head = NULL;
36 handles->tail = NULL;
37}
38
39void
40clear_list_handles (struct GNUNET_MESSENGER_ListHandles *handles)
41{
42 GNUNET_assert(handles);
43
44 while (handles->head)
45 {
46 struct GNUNET_MESSENGER_ListHandle *element = handles->head;
47
48 GNUNET_CONTAINER_DLL_remove(handles->head, handles->tail, element);
49 destroy_handle (element->handle);
50 GNUNET_free(element);
51 }
52
53 handles->head = NULL;
54 handles->tail = NULL;
55}
56
57void
58add_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle)
59{
60 struct GNUNET_MESSENGER_ListHandle *element = GNUNET_new(struct GNUNET_MESSENGER_ListHandle);
61
62 element->handle = handle;
63
64 GNUNET_CONTAINER_DLL_insert_tail(handles->head, handles->tail, element);
65}
66
67int
68remove_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle)
69{
70 struct GNUNET_MESSENGER_ListHandle *element;
71
72 for (element = handles->head; element; element = element->next)
73 if (element->handle == handle)
74 break;
75
76 if (!element)
77 return GNUNET_NO;
78
79 GNUNET_CONTAINER_DLL_remove(handles->head, handles->tail, element);
80 GNUNET_free(element);
81
82 return GNUNET_YES;
83}
84
85void*
86find_list_handle_by_member (struct GNUNET_MESSENGER_ListHandles *handles, const struct GNUNET_HashCode *key)
87{
88 struct GNUNET_MESSENGER_ListHandle *element;
89
90 for (element = handles->head; element; element = element->next)
91 if (get_handle_member_id ((struct GNUNET_MESSENGER_SrvHandle*) element->handle, key))
92 return element->handle;
93
94 return NULL;
95}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_handles.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
27#define GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_container_lib.h"
32
33struct GNUNET_MESSENGER_ListHandle
34{
35 struct GNUNET_MESSENGER_ListHandle *prev;
36 struct GNUNET_MESSENGER_ListHandle *next;
37
38 void *handle;
39};
40
41struct GNUNET_MESSENGER_ListHandles
42{
43 struct GNUNET_MESSENGER_ListHandle *head;
44 struct GNUNET_MESSENGER_ListHandle *tail;
45};
46
47/**
48 * Initializes list of handles as empty list.
49 *
50 * @param handles List of handles
51 */
52void
53init_list_handles (struct GNUNET_MESSENGER_ListHandles *handles);
54
55/**
56 * Destroys remaining handles and clears the list.
57 *
58 * @param handles List of handles
59 */
60void
61clear_list_handles (struct GNUNET_MESSENGER_ListHandles *handles);
62
63/**
64 * Adds a specific <i>handle</i> to the end of the list.
65 *
66 * @param handles List of handles
67 * @param handle Handle
68 */
69void
70add_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle);
71
72/**
73 * Removes the first entry matching with a specific <i>handle</i> from the list and
74 * returns GNUNET_YES on success or GNUNET_NO on failure.
75 *
76 * @param handles List of handles
77 * @param handle Handle
78 * @return GNUNET_YES on success, otherwise GNUNET_NO
79 */
80int
81remove_list_handle (struct GNUNET_MESSENGER_ListHandles *handles, void *handle);
82
83/**
84 * Searches linearly through the list of handles for members of a specific room
85 * which is identified by a given <i>key</i>.
86 *
87 * If no handle is found which is a current member, NULL gets returned.
88 *
89 * @param handles List of handles
90 * @param key Common key of a room
91 * @return First handle which is a current member
92 */
93void*
94find_list_handle_by_member (struct GNUNET_MESSENGER_ListHandles *handles, const struct GNUNET_HashCode *key);
95
96#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_messages.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_list_messages.h"
27
28void
29init_list_messages (struct GNUNET_MESSENGER_ListMessages *messages)
30{
31 GNUNET_assert(messages);
32
33 messages->head = NULL;
34 messages->tail = NULL;
35}
36
37void
38clear_list_messages (struct GNUNET_MESSENGER_ListMessages *messages)
39{
40 GNUNET_assert(messages);
41
42 while (messages->head)
43 {
44 struct GNUNET_MESSENGER_ListMessage *element = messages->head;
45
46 GNUNET_CONTAINER_DLL_remove(messages->head, messages->tail, element);
47 GNUNET_free(element);
48 }
49
50 messages->head = NULL;
51 messages->tail = NULL;
52}
53
54void
55add_to_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash)
56{
57 struct GNUNET_MESSENGER_ListMessage *element = GNUNET_new(struct GNUNET_MESSENGER_ListMessage);
58
59 GNUNET_memcpy(&(element->hash), hash, sizeof(struct GNUNET_HashCode));
60
61 GNUNET_CONTAINER_DLL_insert_tail(messages->head, messages->tail, element);
62}
63
64void
65remove_from_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash)
66{
67 struct GNUNET_MESSENGER_ListMessage *element;
68
69 for (element = messages->head; element; element = element->next)
70 if (0 == GNUNET_CRYPTO_hash_cmp (&(element->hash), hash))
71 {
72 GNUNET_CONTAINER_DLL_remove(messages->head, messages->tail, element);
73 GNUNET_free(element);
74 break;
75 }
76}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_messages.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
27#define GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_container_lib.h"
32
33struct GNUNET_MESSENGER_ListMessage
34{
35 struct GNUNET_MESSENGER_ListMessage *prev;
36 struct GNUNET_MESSENGER_ListMessage *next;
37
38 struct GNUNET_HashCode hash;
39};
40
41struct GNUNET_MESSENGER_ListMessages
42{
43 struct GNUNET_MESSENGER_ListMessage *head;
44 struct GNUNET_MESSENGER_ListMessage *tail;
45};
46
47/**
48 * Initializes list of message hashes as empty list.
49 *
50 * @param messages List of hashes
51 */
52void
53init_list_messages (struct GNUNET_MESSENGER_ListMessages *messages);
54
55/**
56 * Clears the list of message hashes.
57 *
58 * @param messages List of hashes
59 */
60void
61clear_list_messages (struct GNUNET_MESSENGER_ListMessages *messages);
62
63/**
64 * Adds a specific <i>hash</i> from a message to the end of the list.
65 *
66 * @param messages List of hashes
67 * @param hash Hash of message
68 */
69void
70add_to_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash);
71
72/**
73 * Removes the first entry with a matching <i>hash</i> from the list.
74 *
75 * @param messages List of hashes
76 * @param hash Hash of message
77 */
78void
79remove_from_list_messages (struct GNUNET_MESSENGER_ListMessages *messages, const struct GNUNET_HashCode *hash);
80
81#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_handle.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_handle.h"
27
28void
29handle_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
30 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
31{
32 struct GNUNET_MESSENGER_SrvContact *contact = get_room_contact (room, &(message->header.sender_id));
33
34 if (!contact)
35 add_room_contact (room, &(message->header.sender_id), &(message->body.join.key));
36
37 struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
38
39 if (!info)
40 {
41 info = GNUNET_new(struct GNUNET_MESSENGER_MemberInfo);
42
43 info->access = GNUNET_MESSENGER_MEMBER_UNKNOWN;
44 init_list_messages (&(info->session_messages));
45 }
46 else
47 clear_list_messages (&(info->session_messages));
48
49 if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_put (room->member_infos, &(message->header.sender_id), info,
50 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
51 add_to_list_messages (&(info->session_messages), hash);
52}
53
54void
55handle_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
56 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
57{
58 struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
59
60 if (info)
61 clear_list_messages (&(info->session_messages));
62}
63
64void
65handle_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
66 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
67{
68 struct GNUNET_MESSENGER_SrvContact *contact = get_room_contact (room, &(message->header.sender_id));
69
70 if (contact)
71 set_contact_name (contact, message->body.name.name);
72
73 struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
74
75 if (info)
76 add_to_list_messages (&(info->session_messages), hash);
77}
78
79void
80handle_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
81 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
82{
83 struct GNUNET_MESSENGER_SrvContact *contact = get_room_contact (room, &(message->header.sender_id));
84
85 if (contact)
86 swap_service_contact_by_pubkey (room->service, contact, &(message->body.key.key));
87
88 struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
89
90 if (info)
91 add_to_list_messages (&(info->session_messages), hash);
92}
93
94void
95handle_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
96 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
97{
98 if (GNUNET_NO == contains_list_tunnels (&(room->basement), &(message->body.peer.peer)))
99 add_to_list_tunnels (&(room->basement), &(message->body.peer.peer));
100
101 if (room->peer_message)
102 rebuild_room_basement_structure (room);
103}
104
105void
106handle_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
107 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
108{
109 struct GNUNET_MESSENGER_MemberInfo *info = get_room_member_info (room, &(message->header.sender_id));
110
111 if (info)
112 add_to_list_messages (&(info->session_messages), hash);
113
114 switch_room_member_id (room, &(message->header.sender_id), &(message->body.id.id), hash);
115}
116
117void
118handle_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
119 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
120{
121 struct GNUNET_MESSENGER_ListTunnel *element = find_list_tunnels (&(room->basement), &(message->body.peer.peer), NULL);
122
123 if (!element)
124 return;
125
126 remove_from_list_tunnels (&(room->basement), element);
127
128 if (room->peer_message)
129 rebuild_room_basement_structure (room);
130}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_handle.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31
32#include "gnunet-service-messenger_message_kind.h"
33
34#include "gnunet-service-messenger_tunnel.h"
35#include "messenger_api_message.h"
36
37/**
38 * Handles a received or sent join message to make changes of current member information.
39 * (add matching member and clear member info)
40 *
41 * @param room Room of the message
42 * @param tunnel Receiving/sending connection (may be NULL)
43 * @param message JOIN-Message
44 * @param hash Hash of the message
45 */
46void
47handle_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
48 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
49
50/**
51 * Handles a received or sent leave message to make changes of current member information.
52 * (remove matching member and clear member info)
53 *
54 * @param room Room of the message
55 * @param tunnel Receiving/sending connection (may be NULL)
56 * @param message LEAVE-Message
57 * @param hash Hash of the message
58 */
59void
60handle_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
61 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
62
63/**
64 * Handles a received or sent name message to rename a current member.
65 * (change name of matching member)
66 *
67 * @param room Room of the message
68 * @param tunnel Receiving/sending connection (may be NULL)
69 * @param message NAME-Message
70 * @param hash Hash of the message
71 */
72void
73handle_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
74 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
75
76/**
77 * Handles a received or sent key message to change the key of a member and rearrange the contacts accordingly.
78 * (move the member in the contacts and change its key)
79 *
80 * @param room Room of the message
81 * @param tunnel Receiving/sending connection (may be NULL)
82 * @param message KEY-Message
83 * @param hash Hash of the message
84 */
85void
86handle_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
87 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
88
89/**
90 * Handles a received or sent peer message to make changes of the basement in the room.
91 * (add a new peer to the basement and restructure connections based on updated list of peers)
92 *
93 * @param room Room of the message
94 * @param tunnel Receiving/sending connection (may be NULL)
95 * @param message PEER-Message
96 * @param hash Hash of the message
97 */
98void
99handle_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
100 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
101
102/**
103 * Handles a received or sent id message to change a members id.
104 * (change id of matching member)
105 *
106 * @param room Room of the message
107 * @param tunnel Receiving/sending connection (may be NULL)
108 * @param message ID-Message
109 * @param hash Hash of the message
110 */
111void
112handle_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
113 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
114
115/**
116 * Handles a received or sent miss message to drop a peer from the basement in the room.
117 * (remove a peer from the basement and restructure connections based on updated list of peers)
118 *
119 * @param room Room of the message
120 * @param tunnel Receiving/sending connection (may be NULL)
121 * @param message MISS-Message
122 * @param hash Hash of the message
123 */
124void
125handle_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
126 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
127
128#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_kind.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_kind.h"
27#include "gnunet-service-messenger_util.h"
28
29struct GNUNET_MESSENGER_Message*
30create_message_info (struct GNUNET_MESSENGER_Ego *ego, struct GNUNET_CONTAINER_MultiShortmap *members)
31{
32 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_INFO);
33
34 if (!message)
35 return NULL;
36
37 GNUNET_memcpy(&(message->body.info.host_key), &(ego->pub), sizeof(ego->pub));
38
39 if (GNUNET_YES == generate_free_member_id (&(message->body.info.unique_id), members))
40 return message;
41 else
42 {
43 destroy_message (message);
44 return NULL;
45 }
46}
47
48struct GNUNET_MESSENGER_Message*
49create_message_join (struct GNUNET_MESSENGER_Ego *ego)
50{
51 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_JOIN);
52
53 if (!message)
54 return NULL;
55
56 GNUNET_memcpy(&(message->body.join.key), &(ego->pub), sizeof(ego->pub));
57
58 return message;
59}
60
61struct GNUNET_MESSENGER_Message*
62create_message_leave ()
63{
64 return create_message (GNUNET_MESSENGER_KIND_LEAVE);
65}
66
67struct GNUNET_MESSENGER_Message*
68create_message_name (const char *name)
69{
70 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_NAME);
71
72 if (!message)
73 return NULL;
74
75 message->body.name.name = GNUNET_strdup(name);
76 return message;
77}
78
79struct GNUNET_MESSENGER_Message*
80create_message_key (const struct GNUNET_IDENTITY_PrivateKey *key)
81{
82 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_KEY);
83
84 if (!message)
85 return NULL;
86
87 GNUNET_IDENTITY_key_get_public (key, &(message->body.key.key));
88 return message;
89}
90
91struct GNUNET_MESSENGER_Message*
92create_message_peer (const struct GNUNET_MESSENGER_Service *service)
93{
94 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_PEER);
95
96 if (!message)
97 return NULL;
98
99 if (GNUNET_OK == get_service_peer_identity (service, &(message->body.peer.peer)))
100 return message;
101 else
102 {
103 destroy_message (message);
104 return NULL;
105 }
106}
107
108struct GNUNET_MESSENGER_Message*
109create_message_id (const struct GNUNET_ShortHashCode *unique_id)
110{
111 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_ID);
112
113 if (!message)
114 return NULL;
115
116 GNUNET_memcpy(&(message->body.id.id), unique_id, sizeof(struct GNUNET_ShortHashCode));
117
118 return message;
119}
120
121struct GNUNET_MESSENGER_Message*
122create_message_miss (const struct GNUNET_PeerIdentity *peer)
123{
124 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_MISS);
125
126 if (!message)
127 {
128 return NULL;
129 }
130
131 GNUNET_memcpy(&(message->body.miss.peer), peer, sizeof(struct GNUNET_PeerIdentity));
132
133 return message;
134}
135
136struct GNUNET_MESSENGER_Message*
137create_message_merge (const struct GNUNET_HashCode *previous)
138{
139 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_MERGE);
140
141 if (!message)
142 return NULL;
143
144 GNUNET_memcpy(&(message->body.merge.previous), previous, sizeof(struct GNUNET_HashCode));
145
146 return message;
147}
148
149struct GNUNET_MESSENGER_Message*
150create_message_request (const struct GNUNET_HashCode *hash)
151{
152 struct GNUNET_HashCode zero;
153 memset (&zero, 0, sizeof(zero));
154
155 if (0 == GNUNET_CRYPTO_hash_cmp (hash, &zero))
156 return NULL;
157
158 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_REQUEST);
159
160 if (!message)
161 return NULL;
162
163 GNUNET_memcpy(&(message->body.request.hash), hash, sizeof(struct GNUNET_HashCode));
164
165 return message;
166}
167
168struct GNUNET_MESSENGER_Message*
169create_message_invite (const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key)
170{
171 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_INVITE);
172
173 if (!message)
174 return NULL;
175
176 GNUNET_memcpy(&(message->body.invite.door), door, sizeof(struct GNUNET_PeerIdentity));
177 GNUNET_memcpy(&(message->body.invite.key), key, sizeof(struct GNUNET_HashCode));
178
179 return message;
180}
181
182struct GNUNET_MESSENGER_Message*
183create_message_text (const char *text)
184{
185 struct GNUNET_MESSENGER_Message *message = create_message (GNUNET_MESSENGER_KIND_TEXT);
186
187 if (!message)
188 return NULL;
189
190 message->body.text.text = GNUNET_strdup(text);
191 return message;
192}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_kind.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
28
29#include "platform.h"
30#include "gnunet_container_lib.h"
31#include "gnunet_crypto_lib.h"
32#include "gnunet_identity_service.h"
33
34#include "messenger_api_message.h"
35#include "gnunet-service-messenger_service.h"
36#include "messenger_api_ego.h"
37
38/**
39 * Creates and allocates a new info message containing the hosts public key and a newly generated unique member id.
40 * (all values are stored as copy)
41 *
42 * @param ego EGO of the host
43 * @param members Map of all assigned member ids
44 * @return New message
45 */
46struct GNUNET_MESSENGER_Message*
47create_message_info (struct GNUNET_MESSENGER_Ego *ego, struct GNUNET_CONTAINER_MultiShortmap *members);
48
49/**
50 * Creates and allocates a new join message containing the clients public key.
51 * (all values are stored as copy)
52 *
53 * @param ego EGO of the client
54 * @return New message
55 */
56struct GNUNET_MESSENGER_Message*
57create_message_join (struct GNUNET_MESSENGER_Ego *ego);
58
59/**
60 * Creates and allocates a new leave message.
61 *
62 * @return New message
63 */
64struct GNUNET_MESSENGER_Message*
65create_message_leave ();
66
67/**
68 * Creates and allocates a new name message containing the <i>name</i> to change to.
69 * (all values are stored as copy)
70 *
71 * @param name New name
72 * @return New message
73 */
74struct GNUNET_MESSENGER_Message*
75create_message_name (const char *name);
76
77/**
78 * Creates and allocates a new key message containing the public key to change to derived
79 * from its private counterpart. (all values are stored as copy)
80 *
81 * @param key Private key of EGO
82 * @return New message
83 */
84struct GNUNET_MESSENGER_Message*
85create_message_key (const struct GNUNET_IDENTITY_PrivateKey *key);
86
87/**
88 * Creates and allocates a new peer message containing a services peer identity.
89 * (all values are stored as copy)
90 *
91 * @param service Service
92 * @return New message
93 */
94struct GNUNET_MESSENGER_Message*
95create_message_peer (const struct GNUNET_MESSENGER_Service *service);
96
97/**
98 * Creates and allocates a new id message containing the unique member id to change to.
99 * (all values are stored as copy)
100 *
101 * @param unique_id Unique member id
102 * @return New message
103 */
104struct GNUNET_MESSENGER_Message*
105create_message_id (const struct GNUNET_ShortHashCode *unique_id);
106
107/**
108 * Creates and allocates a new miss message containing the missing peer identity.
109 * (all values are stored as copy)
110 *
111 * @param peer Missing peer identity
112 * @return New message
113 */
114struct GNUNET_MESSENGER_Message*
115create_message_miss (const struct GNUNET_PeerIdentity *peer);
116
117/**
118 * Creates and allocates a new merge message containing the hash of a second previous message
119 * besides the regular previous message mentioned in a messages header.
120 * (all values are stored as copy)
121 *
122 * @param previous Hash of message
123 * @return New message
124 */
125struct GNUNET_MESSENGER_Message*
126create_message_merge (const struct GNUNET_HashCode *previous);
127
128/**
129 * Creates and allocates a new request message containing the hash of a missing message.
130 * (all values are stored as copy)
131 *
132 * @param hash Hash of message
133 * @return New message
134 */
135struct GNUNET_MESSENGER_Message*
136create_message_request (const struct GNUNET_HashCode *hash);
137
138/**
139 * Creates and allocates a new invite message containing the peer identity of an entrance peer
140 * to a room using a given <i>key</i> as shared secret for communication.
141 * (all values are stored as copy)
142 *
143 * @param door Peer identity
144 * @param key Shared secret of a room
145 * @return New message
146 */
147struct GNUNET_MESSENGER_Message*
148create_message_invite (const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key);
149
150/**
151 * Creates and allocates a new text message containing a string representing text.
152 * (all values are stored as copy)
153 *
154 * @param text Text
155 * @return New message
156 */
157struct GNUNET_MESSENGER_Message*
158create_message_text (const char *text);
159
160#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_recv.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_recv.h"
27#include "gnunet-service-messenger_message_handle.h"
28
29void
30recv_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
31 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
32{
33 int conflict = GNUNET_CONTAINER_multishortmap_contains (room->members, &(message->body.info.unique_id));
34
35 if (GNUNET_NO == conflict)
36 {
37 struct GNUNET_MESSENGER_Message *sync_message = create_message_id (&(message->body.info.unique_id));
38 struct GNUNET_HashCode sync_hash;
39
40 send_room_message_ext (room, room->host, sync_message, &sync_hash, tunnel);
41 destroy_message (sync_message);
42
43 switch_room_member_id (room, get_room_host_id (room), &(message->body.info.unique_id), NULL);
44
45 change_room_host_id (room, &(message->body.info.unique_id));
46 }
47
48 if (!tunnel->contact_id)
49 tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
50
51 GNUNET_memcpy(tunnel->contact_id, &(message->header.sender_id), sizeof(struct GNUNET_ShortHashCode));
52
53 struct GNUNET_ShortHashCode original_id;
54
55 if (GNUNET_YES == conflict)
56 {
57 GNUNET_memcpy(&original_id, get_room_host_id (room), sizeof(struct GNUNET_ShortHashCode));
58
59 change_room_host_id (room, &(message->body.info.unique_id));
60 }
61
62 {
63 struct GNUNET_MESSENGER_Message *join_message = create_message_join (room->host->ego);
64 struct GNUNET_HashCode join_hash;
65
66 send_tunnel_message (tunnel, room->host, join_message, &join_hash);
67 destroy_message (join_message);
68 }
69
70 if ((GNUNET_YES == conflict) && (0 != GNUNET_memcmp(&original_id, get_room_host_id (room))))
71 {
72 struct GNUNET_MESSENGER_Message *sync_message = create_message_id (&original_id);
73 struct GNUNET_HashCode sync_hash;
74
75 send_tunnel_message (tunnel, room->host, sync_message, &sync_hash);
76 destroy_message (sync_message);
77 }
78}
79
80struct GNUNET_MESSENGER_MemberInfoSpread
81{
82 struct GNUNET_MESSENGER_SrvRoom *room;
83 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
84};
85
86static int
87iterate_send_member_infos (void *cls, const struct GNUNET_ShortHashCode *key, void *value)
88{
89 struct GNUNET_MESSENGER_MemberInfo *info = value;
90 struct GNUNET_MESSENGER_MemberInfoSpread *spread = cls;
91
92 struct GNUNET_MESSENGER_ListMessage *element = info->session_messages.head;
93
94 while (element)
95 {
96 const struct GNUNET_MESSENGER_Message *message = get_room_message (spread->room, spread->room->host,
97 &(element->hash), GNUNET_NO);
98
99 if (message)
100 forward_tunnel_message (spread->tunnel, message, &(element->hash));
101
102 element = element->next;
103 }
104
105 return GNUNET_YES;
106}
107
108void
109recv_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
110 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
111{
112 const struct GNUNET_MESSENGER_Message *info_msg = get_room_message (room, room->host, &(message->header.previous),
113 GNUNET_NO);
114
115 if ((info_msg) && (0 == GNUNET_memcmp(&(info_msg->header.sender_id), get_room_host_id (room)))
116 && (GNUNET_MESSENGER_KIND_INFO == info_msg->header.kind))
117 {
118 struct GNUNET_MESSENGER_MemberInfoSpread spread;
119
120 spread.room = room;
121
122 if ((tunnel) && (tunnel->contact_id) && (0 == GNUNET_memcmp(tunnel->contact_id, &(message->header.sender_id))))
123 spread.tunnel = tunnel;
124 else
125 spread.tunnel = find_room_tunnel_to (room, &(message->header.sender_id));
126
127 if (spread.tunnel)
128 GNUNET_CONTAINER_multishortmap_iterate (room->member_infos, iterate_send_member_infos, &spread);
129 }
130
131 handle_message_join (room, tunnel, message, hash);
132}
133
134void
135recv_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
136 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
137{
138 handle_message_leave (room, tunnel, message, hash);
139}
140
141void
142recv_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
143 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
144{
145 handle_message_name (room, tunnel, message, hash);
146}
147
148void
149recv_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
150 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
151{
152 handle_message_key (room, tunnel, message, hash);
153}
154
155void
156recv_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
157 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
158{
159 struct GNUNET_PeerIdentity peer;
160 GNUNET_PEER_resolve (tunnel->peer, &peer);
161
162 if (0 == GNUNET_memcmp(&peer, &(message->body.peer.peer)))
163 {
164 if (!tunnel->peer_message)
165 tunnel->peer_message = GNUNET_new(struct GNUNET_HashCode);
166
167 GNUNET_memcpy(tunnel->peer_message, hash, sizeof(struct GNUNET_HashCode));
168
169 if (!tunnel->contact_id)
170 tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
171
172 GNUNET_memcpy(tunnel->contact_id, &(message->header.sender_id), sizeof(struct GNUNET_ShortHashCode));
173 }
174
175 handle_message_peer (room, tunnel, message, hash);
176}
177
178void
179recv_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
180 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
181{
182 if ((tunnel->contact_id) && (0 == GNUNET_memcmp(tunnel->contact_id, &(message->header.sender_id))))
183 GNUNET_memcpy(tunnel->contact_id, &(message->body.id.id), sizeof(struct GNUNET_ShortHashCode));
184
185 handle_message_id (room, tunnel, message, hash);
186}
187
188void
189recv_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
190 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
191{
192 handle_message_miss (room, tunnel, message, hash);
193}
194
195void
196recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
197 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
198{
199 const struct GNUNET_MESSENGER_Message *msg = get_room_message (room, room->host, &(message->body.request.hash),
200 GNUNET_NO);
201
202 if (msg)
203 forward_tunnel_message (tunnel, msg, &(message->body.request.hash));
204}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_recv.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31
32#include "gnunet-service-messenger_tunnel.h"
33#include "messenger_api_message.h"
34
35/**
36 * Handles a received info message to change the current member id to the one generated by
37 * the host connected to. (all current tunnels will be informed about the id change)
38 *
39 * @param room Room of the message
40 * @param tunnel Receiving connection
41 * @param message INFO-Message
42 * @param hash Hash of the message
43 */
44void
45recv_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
46 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
47
48/**
49 * Handles a received join message to forward all member information to the new member if the message was
50 * the direct reaction to a previous info message from this peer.
51 *
52 * @param room Room of the message
53 * @param tunnel Receiving connection
54 * @param message JOIN-Message
55 * @param hash Hash of the message
56 */
57void
58recv_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
59 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
60
61/**
62 * Handles a received leave message.
63 * @see handle_message_leave()
64 *
65 * @param room Room of the message
66 * @param tunnel Receiving connection
67 * @param message LEAVE-Message
68 * @param hash Hash of the message
69 */
70void
71recv_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
72 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
73
74/**
75 * Handles a received name message.
76 * @see handle_message_name()
77 *
78 * @param room Room of the message
79 * @param tunnel Receiving connection
80 * @param message NAME-Message
81 * @param hash Hash of the message
82 */
83void
84recv_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
85 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
86
87/**
88 * Handles a received key message.
89 * @see handle_message_key()
90 *
91 * @param room Room of the message
92 * @param tunnel Receiving connection
93 * @param message KEY-Message
94 * @param hash Hash of the message
95 */
96void
97recv_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
98 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
99
100/**
101 * Handles a received peer message to link it to its origin tunnel if the peer identity matches.
102 * (the peer message and the member id can potentially be linked to the tunnel)
103 *
104 * TODO: This handling will only check the one given tunnel!
105 *
106 * @param room Room of the message
107 * @param tunnel Receiving connection
108 * @param message PEER-Message
109 * @param hash Hash of the message
110 */
111void
112recv_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
113 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
114
115/**
116 * Handles a received id message to change the tunnels linked member id if necessary.
117 * (the tunnels linked member id will be changed if the sender id is matching)
118 *
119 * TODO: This handling will only check the one given tunnel!
120 *
121 * @param room Room of the message
122 * @param tunnel Receiving connection
123 * @param message ID-Message
124 * @param hash Hash of the message
125 */
126void
127recv_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
128 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
129
130/**
131 * Handles a received miss message.
132 * @see handle_message_miss()
133 *
134 * @param room Room of the message
135 * @param tunnel Receiving connection
136 * @param message MISS-Message
137 * @param hash Hash of the message
138 */
139void
140recv_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
141 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
142
143/**
144 * Handles a received request message by checking for the requested message and forwarding it back
145 * if the message was found.
146 * (this can also cause this peer to send a new request instead of only forwarding the received one)
147 *
148 * TODO: Requests can cause exponentially more requests!
149 *
150 * @param room Room of the message
151 * @param tunnel Receiving connection
152 * @param message REQUEST-Message
153 * @param hash Hash of the message
154 */
155void
156recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
157 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
158
159#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_send.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_send.h"
27#include "gnunet-service-messenger_message_handle.h"
28
29void
30send_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
31 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
32 const struct GNUNET_HashCode *hash)
33{
34 if (!tunnel->contact_id)
35 {
36 tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
37
38 GNUNET_memcpy(tunnel->contact_id, &(message->body.info.unique_id), sizeof(struct GNUNET_ShortHashCode));
39 }
40 else
41 {
42 disconnect_tunnel (tunnel);
43 }
44}
45
46void
47send_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
48 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
49 const struct GNUNET_HashCode *hash)
50{
51 handle_message_join (room, tunnel, message, hash);
52
53 if (room->peer_message)
54 {
55 const struct GNUNET_MESSENGER_Message *peer_message = get_room_message (room, handle, room->peer_message,
56 GNUNET_NO);
57
58 if ((peer_message) && (tunnel))
59 {
60 forward_tunnel_message (tunnel, peer_message, room->peer_message);
61 }
62 }
63}
64
65void
66send_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
67 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
68 const struct GNUNET_HashCode *hash)
69{
70 handle_message_leave (room, tunnel, message, hash);
71}
72
73void
74send_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
75 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
76 const struct GNUNET_HashCode *hash)
77{
78 handle_message_name (room, tunnel, message, hash);
79}
80
81void
82send_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
83 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
84 const struct GNUNET_HashCode *hash)
85{
86 handle_message_key (room, tunnel, message, hash);
87}
88
89void
90send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
91 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
92 const struct GNUNET_HashCode *hash)
93{
94 if (!room->peer_message)
95 {
96 room->peer_message = GNUNET_new(struct GNUNET_HashCode);
97 }
98
99 GNUNET_memcpy(room->peer_message, hash, sizeof(struct GNUNET_HashCode));
100
101 handle_message_peer (room, tunnel, message, hash);
102}
103
104void
105send_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
106 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
107 const struct GNUNET_HashCode *hash)
108{
109 handle_message_id (room, tunnel, message, hash);
110}
111
112void
113send_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
114 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
115 const struct GNUNET_HashCode *hash)
116{
117 handle_message_miss (room, tunnel, message, hash);
118}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_send.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31
32#include "gnunet-service-messenger_tunnel.h"
33#include "messenger_api_message.h"
34
35/**
36 * Handles a sent info message to setup a tunnels linked member id.
37 * (if a tunnel has already got a member id linked to it, the connection will be closed)
38 *
39 * @param room Room of the message
40 * @param handle Sending handle
41 * @param tunnel Sending connection (may be NULL)
42 * @param message INFO-Message
43 * @param hash Hash of the message
44 */
45void
46send_message_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
47 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
48 const struct GNUNET_HashCode *hash);
49
50/**
51 * Handles a sent join message to ensure growth of the decentralized room structure.
52 * (if the service provides a peer message for this room currently, it will be forwarded)
53 *
54 * @param room Room of the message
55 * @param handle Sending handle
56 * @param tunnel Sending connection (may be NULL)
57 * @param message JOIN-Message
58 * @param hash Hash of the message
59 */
60void
61send_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
62 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
63 const struct GNUNET_HashCode *hash);
64
65/**
66 * Handles a sent leave message.
67 * @see handle_message_leave()
68 *
69 * @param room Room of the message
70 * @param handle Sending handle
71 * @param tunnel Sending connection (may be NULL)
72 * @param message LEAVE-Message
73 * @param hash Hash of the message
74 */
75void
76send_message_leave (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
77 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
78 const struct GNUNET_HashCode *hash);
79
80/**
81 * Handles a sent name message.
82 * @see handle_message_name()
83 *
84 * @param room Room of the message
85 * @param handle Sending handle
86 * @param tunnel Sending connection (may be NULL)
87 * @param message NAME-Message
88 * @param hash Hash of the message
89 */
90void
91send_message_name (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
92 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
93 const struct GNUNET_HashCode *hash);
94
95/**
96 * Handles a sent key message.
97 * @see handle_message_key()
98 *
99 * @param room Room of the message
100 * @param handle Sending handle
101 * @param tunnel Sending connection (may be NULL)
102 * @param message KEY-Message
103 * @param hash Hash of the message
104 */
105void
106send_message_key (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
107 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
108 const struct GNUNET_HashCode *hash);
109
110/**
111 * Handles a sent peer message to update the rooms peer message of this service.
112 * (a set peer message indicates this service being a part of the decentralized room structure)
113 *
114 * @param room Room of the message
115 * @param handle Sending handle
116 * @param tunnel Sending connection (may be NULL)
117 * @param message PEER-Message
118 * @param hash Hash of the message
119 */
120void
121send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
122 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
123 const struct GNUNET_HashCode *hash);
124
125/**
126 * Handles a sent id message.
127 * @see handle_message_id()
128 *
129 * @param room Room of the message
130 * @param handle Sending handle
131 * @param tunnel Sending connection (may be NULL)
132 * @param message ID-Message
133 * @param hash Hash of the message
134 */
135void
136send_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
137 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
138 const struct GNUNET_HashCode *hash);
139
140/**
141 * Handles a sent miss message.
142 * @see handle_message_miss()
143 *
144 * @param room Room of the message
145 * @param handle Sending handle
146 * @param tunnel Sending connection (may be NULL)
147 * @param message MISS-Message
148 * @param hash Hash of the message
149 */
150void
151send_message_miss (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
152 struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_MESSENGER_Message *message,
153 const struct GNUNET_HashCode *hash);
154
155#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_store.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_store.h"
27#include "messenger_api_message.h"
28
29void
30init_message_store (struct GNUNET_MESSENGER_MessageStore *store)
31{
32 store->storage_messages = NULL;
33
34 store->entries = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
35 store->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
36}
37
38static int
39iterate_destroy_entries (void *cls, const struct GNUNET_HashCode *key, void *value)
40{
41 struct GNUNET_MESSENGER_MessageEntry *entry = value;
42
43 GNUNET_free(entry);
44
45 return GNUNET_YES;
46}
47
48static int
49iterate_destroy_messages (void *cls, const struct GNUNET_HashCode *key, void *value)
50{
51 struct GNUNET_MESSENGER_Message *message = value;
52
53 destroy_message (message);
54
55 return GNUNET_YES;
56}
57
58void
59clear_message_store (struct GNUNET_MESSENGER_MessageStore *store)
60{
61 if (store->storage_messages)
62 {
63 GNUNET_DISK_file_close (store->storage_messages);
64
65 store->storage_messages = NULL;
66 }
67
68 GNUNET_CONTAINER_multihashmap_iterate (store->entries, iterate_destroy_entries, NULL);
69 GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_destroy_messages, NULL);
70
71 GNUNET_CONTAINER_multihashmap_destroy (store->entries);
72 GNUNET_CONTAINER_multihashmap_destroy (store->messages);
73}
74
75struct GNUNET_MESSENGER_MessageEntryStorage
76{
77 struct GNUNET_HashCode hash;
78 struct GNUNET_MESSENGER_MessageEntry entry;
79};
80
81void
82load_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
83{
84 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
85
86 if (store->storage_messages)
87 GNUNET_DISK_file_close (store->storage_messages);
88
89 char *filename;
90 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
91
92 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
93 store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
94 else
95 store->storage_messages = NULL;
96
97 GNUNET_free(filename);
98
99 if (!store->storage_messages)
100 return;
101
102 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
103
104 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
105 goto free_filename;
106
107 struct GNUNET_DISK_FileHandle *entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
108
109 if (!entries)
110 goto free_filename;
111
112 struct GNUNET_MESSENGER_MessageEntryStorage storage;
113 struct GNUNET_MESSENGER_MessageEntry *entry;
114
115 do
116 {
117 entry = GNUNET_new(struct GNUNET_MESSENGER_MessageEntry);
118
119 if (GNUNET_DISK_file_read (entries, &storage, sizeof(storage)) == sizeof(storage))
120 {
121 GNUNET_memcpy(entry, &(storage.entry), sizeof(*entry));
122
123 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->entries, &(storage.hash), entry,
124 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
125 GNUNET_free(entry);
126 }
127 else
128 {
129 GNUNET_free(entry);
130
131 entry = NULL;
132 }
133 }
134 while (entry);
135
136 GNUNET_DISK_file_close (entries);
137
138free_filename:
139 GNUNET_free(filename);
140}
141
142struct GNUNET_MESSENGER_MessageSave
143{
144 struct GNUNET_MESSENGER_MessageStore *store;
145
146 struct GNUNET_DISK_FileHandle *storage_entries;
147};
148
149static int
150iterate_save_messages (void *cls, const struct GNUNET_HashCode *key, void *value)
151{
152 struct GNUNET_MESSENGER_MessageSave *save = cls;
153
154 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (save->store->entries, key))
155 return GNUNET_YES;
156
157 struct GNUNET_MESSENGER_Message *message = value;
158 struct GNUNET_MESSENGER_MessageEntryStorage storage;
159
160 GNUNET_memcpy(&(storage.hash), key, sizeof(storage.hash));
161
162 storage.entry.length = get_message_size (message);
163 storage.entry.offset = GNUNET_DISK_file_seek (save->store->storage_messages, 0, GNUNET_DISK_SEEK_END);
164
165 if ((GNUNET_SYSERR == storage.entry.offset) ||
166 (sizeof(storage) != GNUNET_DISK_file_write (save->storage_entries, &storage, sizeof(storage))))
167 return GNUNET_YES;
168
169 char *buffer = GNUNET_malloc(storage.entry.length);
170
171 encode_message (message, storage.entry.length, buffer);
172
173 GNUNET_DISK_file_write (save->store->storage_messages, buffer, storage.entry.length);
174
175 GNUNET_free(buffer);
176
177 return GNUNET_YES;
178}
179
180void
181save_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
182{
183 struct GNUNET_MESSENGER_MessageSave save;
184
185 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
186
187 char *filename;
188 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
189
190 save.store = store;
191 save.storage_entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE, permission);
192
193 GNUNET_free(filename);
194
195 if (!save.storage_entries)
196 return;
197
198 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage_entries, 0, GNUNET_DISK_SEEK_END))
199 goto close_entries;
200
201 if (store->storage_messages)
202 GNUNET_DISK_file_close (store->storage_messages);
203
204 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
205
206 store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE,
207 permission);
208
209 GNUNET_free(filename);
210
211 if (store->storage_messages)
212 {
213 GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_save_messages, &save);
214
215 GNUNET_DISK_file_sync (store->storage_messages);
216 GNUNET_DISK_file_sync (save.storage_entries);
217 }
218
219close_entries:
220 GNUNET_DISK_file_close (save.storage_entries);
221}
222
223int
224contains_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
225{
226 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->messages, hash))
227 return GNUNET_YES;
228
229 return GNUNET_CONTAINER_multihashmap_contains (store->entries, hash);
230}
231
232const struct GNUNET_MESSENGER_Message*
233get_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
234{
235 struct GNUNET_MESSENGER_Message *message = GNUNET_CONTAINER_multihashmap_get (store->messages, hash);
236
237 if (message)
238 return message;
239
240 if (!store->storage_messages)
241 return NULL;
242
243 const struct GNUNET_MESSENGER_MessageEntry *entry = GNUNET_CONTAINER_multihashmap_get (store->entries, hash);
244
245 if (!entry)
246 return NULL;
247
248 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages, entry->offset, GNUNET_DISK_SEEK_SET))
249 return message;
250
251 char *buffer = GNUNET_malloc(entry->length);
252
253 if (GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) != entry->length)
254 goto free_buffer;
255
256
257 message = create_message (GNUNET_MESSENGER_KIND_UNKNOWN);
258
259 if ((GNUNET_YES != decode_message (message, entry->length, buffer)) || (GNUNET_OK
260 != GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
261 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
262 {
263 destroy_message (message);
264
265 message = NULL;
266
267 GNUNET_CONTAINER_multihashmap_remove (store->entries, hash, entry);
268 }
269
270free_buffer:
271 GNUNET_free(buffer);
272
273 return message;
274}
275
276int
277put_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash,
278 struct GNUNET_MESSENGER_Message *message)
279{
280 return GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
281 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
282}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_store.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
28
29#include "platform.h"
30#include "gnunet_container_lib.h"
31#include "gnunet_disk_lib.h"
32
33struct GNUNET_MESSENGER_MessageEntry
34{
35 off_t offset;
36 uint16_t length;
37};
38
39struct GNUNET_MESSENGER_MessageStore
40{
41 struct GNUNET_DISK_FileHandle *storage_messages;
42
43 struct GNUNET_CONTAINER_MultiHashMap *entries;
44 struct GNUNET_CONTAINER_MultiHashMap *messages;
45};
46
47/**
48 * Initializes a message store as fully empty.
49 *
50 * @param store Message store
51 */
52void
53init_message_store (struct GNUNET_MESSENGER_MessageStore *store);
54
55/**
56 * Clears a message store, wipes its content and deallocates its memory.
57 *
58 * @param store Message store
59 */
60void
61clear_message_store (struct GNUNET_MESSENGER_MessageStore *store);
62
63/**
64 * Loads messages from a directory into a message store.
65 *
66 * @param store Message store
67 * @param directory Path to a directory
68 */
69void
70load_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory);
71
72/**
73 * Saves messages from a message store into a directory.
74 *
75 * @param store Message store
76 * @param directory Path to a directory
77 */
78void
79save_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory);
80
81/**
82 * Checks if a message matching a given <i>hash</i> is stored in a message store. The function returns
83 * GNUNET_YES if a match is found, GNUNET_NO otherwise.
84 *
85 * The message has not to be loaded from disk into memory for this check!
86 *
87 * @param store Message store
88 * @param hash Hash of message
89 * @return GNUNET_YES on match, otherwise GNUNET_NO
90 */
91int
92contains_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash);
93
94/**
95 * Returns the message from a message store matching a given <i>hash</i>. If no matching message is found,
96 * NULL gets returned.
97 *
98 * This function requires the message to be loaded into memory!
99 * @see contains_store_message()
100 *
101 * @param store Message store
102 * @param hash Hash of message
103 * @return Message or NULL
104 */
105const struct GNUNET_MESSENGER_Message*
106get_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash);
107
108/**
109 * Stores a message into the message store. The result indicates if the operation was successful.
110 *
111 * @param store Message store
112 * @param hash Hash of message
113 * @param message Message
114 * @return GNUNET_OK on success, otherwise GNUNET_NO
115 */
116int
117put_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash,
118 struct GNUNET_MESSENGER_Message *message);
119
120#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_room.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_room.h"
27
28#include "gnunet-service-messenger_message_kind.h"
29
30#include "gnunet-service-messenger_service.h"
31#include "gnunet-service-messenger_util.h"
32
33static void
34idle_request_room_messages (void *cls);
35
36struct GNUNET_MESSENGER_SrvRoom*
37create_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key)
38{
39 GNUNET_assert((handle) && (key));
40
41 struct GNUNET_MESSENGER_SrvRoom *room = GNUNET_new(struct GNUNET_MESSENGER_SrvRoom);
42
43 room->service = handle->service;
44 room->host = handle;
45 room->port = NULL;
46
47 GNUNET_memcpy(&(room->key), key, sizeof(struct GNUNET_HashCode));
48
49 room->tunnels = GNUNET_CONTAINER_multipeermap_create (8, GNUNET_NO);
50 room->members = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
51 room->member_infos = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
52
53 init_message_store (&(room->store));
54 room->requested = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
55
56 init_list_tunnels (&(room->basement));
57 init_list_messages (&(room->last_messages));
58
59 room->peer_message = NULL;
60
61 init_list_messages (&(room->handling));
62 room->idle = NULL;
63
64 room->strict_access = GNUNET_NO;
65
66 if (room->service->dir)
67 load_service_room_and_messages (room->service, room);
68
69 room->idle = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, idle_request_room_messages, room);
70
71 return room;
72}
73
74static int
75iterate_destroy_tunnels (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
76{
77 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
78 destroy_tunnel (tunnel);
79 return GNUNET_YES;
80}
81
82static int
83iterate_clear_members (void *cls, const struct GNUNET_ShortHashCode *key, void *value)
84{
85 struct GNUNET_MESSENGER_SrvContact *contact = value;
86
87 if (GNUNET_YES == decrease_contact_rc (contact))
88 {
89 struct GNUNET_MESSENGER_SrvRoom *room = cls;
90
91 const struct GNUNET_HashCode *id = get_contact_id_from_key (contact);
92
93 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (room->service->contacts, id, contact))
94 destroy_contact (contact);
95 }
96
97 return GNUNET_YES;
98}
99
100static int
101iterate_destroy_member_infos (void *cls, const struct GNUNET_ShortHashCode *key, void *value)
102{
103 struct GNUNET_MESSENGER_MemberInfo *info = value;
104
105 clear_list_messages (&(info->session_messages));
106
107 GNUNET_free(info);
108 return GNUNET_YES;
109}
110
111void
112destroy_room (struct GNUNET_MESSENGER_SrvRoom *room)
113{
114 GNUNET_assert(room);
115
116 if (room->idle)
117 {
118 GNUNET_SCHEDULER_cancel (room->idle);
119
120 room->idle = NULL;
121 }
122
123 if (room->port)
124 GNUNET_CADET_close_port (room->port);
125
126 merge_room_last_messages (room, room->host);
127
128 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_destroy_tunnels,
129 NULL);
130
131 handle_room_messages (room);
132
133 if (room->service->dir)
134 save_service_room_and_messages (room->service, room);
135
136 GNUNET_CONTAINER_multishortmap_iterate (room->members, iterate_clear_members, room);
137 GNUNET_CONTAINER_multishortmap_iterate (room->member_infos, iterate_destroy_member_infos, NULL);
138
139 clear_message_store (&(room->store));
140
141 GNUNET_CONTAINER_multihashmap_destroy (room->requested);
142
143 GNUNET_CONTAINER_multipeermap_destroy (room->tunnels);
144 GNUNET_CONTAINER_multishortmap_destroy (room->members);
145 GNUNET_CONTAINER_multishortmap_destroy (room->member_infos);
146
147 clear_list_tunnels (&(room->basement));
148 clear_list_messages (&(room->last_messages));
149
150 if (room->peer_message)
151 GNUNET_free(room->peer_message);
152
153 GNUNET_free(room);
154}
155
156struct GNUNET_MESSENGER_SrvContact*
157get_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id)
158{
159 GNUNET_assert((room) && (room->members));
160
161 return GNUNET_CONTAINER_multishortmap_get (room->members, id);
162}
163
164void
165add_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id,
166 const struct GNUNET_IDENTITY_PublicKey *pubkey)
167{
168 struct GNUNET_MESSENGER_SrvContact *contact = get_service_contact_by_pubkey (room->service, pubkey);
169
170 if (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put (room->members, id, contact,
171 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
172 increase_contact_rc (contact);
173}
174
175struct GNUNET_MESSENGER_MemberInfo*
176get_room_member_info (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id)
177{
178 GNUNET_assert((room) && (room->member_infos));
179
180 return GNUNET_CONTAINER_multishortmap_get (room->member_infos, id);
181}
182
183struct GNUNET_ShortHashCode*
184generate_room_member_id (const struct GNUNET_MESSENGER_SrvRoom *room)
185{
186 struct GNUNET_ShortHashCode *unique_id = GNUNET_new(struct GNUNET_ShortHashCode);
187
188 GNUNET_assert(room);
189
190 if (GNUNET_YES == generate_free_member_id (unique_id, room->members))
191 return unique_id;
192 else
193 {
194 GNUNET_free(unique_id);
195 return NULL;
196 }
197}
198
199const struct GNUNET_ShortHashCode*
200get_room_host_id (const struct GNUNET_MESSENGER_SrvRoom *room)
201{
202 GNUNET_assert(room);
203
204 return get_handle_member_id (room->host, &(room->key));
205}
206
207void
208change_room_host_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *unique_id)
209{
210 GNUNET_assert(room);
211
212 change_handle_member_id (room->host, &(room->key), unique_id);
213}
214
215static int
216send_room_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
217 struct GNUNET_MESSENGER_SrvTunnel *tunnel)
218{
219 if (!handle)
220 return GNUNET_NO;
221
222 merge_room_last_messages (room, handle);
223
224 if (!is_tunnel_connected (tunnel))
225 return GNUNET_NO;
226
227 struct GNUNET_MESSENGER_Message *message = create_message_info (get_handle_ego(handle), room->members);
228
229 if (!message)
230 return GNUNET_NO;
231
232 if ((tunnel->peer_message) && (tunnel->contact_id))
233 {
234 GNUNET_memcpy(&(message->body.info.unique_id), &(tunnel->contact_id), sizeof(struct GNUNET_ShortHashCode));
235 GNUNET_free(tunnel->contact_id);
236
237 tunnel->contact_id = NULL;
238 }
239
240 struct GNUNET_HashCode hash;
241
242 send_tunnel_message (tunnel, handle, message, &hash);
243 destroy_message (message);
244
245 if (tunnel->contact_id)
246 {
247 GNUNET_free(tunnel->contact_id);
248
249 tunnel->contact_id = NULL;
250 }
251
252 return GNUNET_YES;
253}
254
255static void*
256callback_room_connect (void *cls, struct GNUNET_CADET_Channel *channel, const struct GNUNET_PeerIdentity *source)
257{
258 struct GNUNET_MESSENGER_SrvRoom *room = cls;
259
260 struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, source);
261
262 if (tunnel)
263 {
264 if (GNUNET_YES == bind_tunnel (tunnel, channel))
265 {
266 if (GNUNET_YES == send_room_info (room, room->host, tunnel))
267 return tunnel;
268 else
269 {
270 disconnect_tunnel (tunnel);
271 return NULL;
272 }
273 }
274 else
275 {
276 delayed_disconnect_channel (channel);
277 return NULL;
278 }
279 }
280 else
281 {
282 tunnel = create_tunnel (room, source);
283
284 if ((GNUNET_YES == bind_tunnel (tunnel, channel)) && (GNUNET_OK
285 == GNUNET_CONTAINER_multipeermap_put (room->tunnels, source, tunnel,
286 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
287 {
288 if (GNUNET_YES == send_room_info (room, room->host, tunnel))
289 return tunnel;
290 else
291 {
292 GNUNET_CONTAINER_multipeermap_remove (room->tunnels, source, tunnel);
293
294 disconnect_tunnel (tunnel);
295 destroy_tunnel (tunnel);
296 return NULL;
297 }
298 }
299 else
300 {
301 tunnel->channel = NULL;
302 destroy_tunnel (tunnel);
303
304 delayed_disconnect_channel (channel);
305 return NULL;
306 }
307 }
308}
309
310static int
311join_room (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
312 const struct GNUNET_ShortHashCode *member_id)
313{
314 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Joining room: %s (%s)\n", GNUNET_h2s(get_room_key(room)), GNUNET_sh2s(member_id));
315
316 struct GNUNET_MESSENGER_Message *message = create_message_join (get_handle_ego(handle));
317
318 if (!message)
319 {
320 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Your join message could not be created!\n");
321
322 return GNUNET_NO;
323 }
324
325 struct GNUNET_HashCode hash;
326
327 send_room_message (room, handle, message, &hash);
328 destroy_message (message);
329
330 struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_new(struct GNUNET_MESSENGER_MemberInfo);
331
332 info->access = GNUNET_MESSENGER_MEMBER_ALLOWED;
333 init_list_messages (&(info->session_messages));
334
335 if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_put (room->member_infos, member_id, info,
336 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
337 {
338 change_handle_member_id (handle, &(room->key), member_id);
339
340 add_to_list_messages (&(info->session_messages), &hash);
341 return GNUNET_YES;
342 }
343 else
344 {
345 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Your member information could not be registered!\n");
346
347 GNUNET_free(info);
348 return GNUNET_NO;
349 }
350}
351
352static int
353join_room_locally (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
354{
355 const struct GNUNET_ShortHashCode *member_id = get_handle_member_id (handle, &(room->key));
356
357 struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos, member_id);
358
359 if ((!info) && (GNUNET_NO == join_room (room, handle, member_id)))
360 return GNUNET_NO;
361
362 return GNUNET_YES;
363}
364
365extern int
366check_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header);
367extern void
368handle_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header);
369
370extern void
371callback_tunnel_disconnect (void *cls, const struct GNUNET_CADET_Channel *channel);
372
373int
374open_room (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
375{
376 if (room->port)
377 return join_room_locally (room, handle);
378
379 struct GNUNET_CADET_Handle *cadet = get_room_cadet (room);
380 struct GNUNET_HashCode *key = get_room_key (room);
381
382 struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size(tunnel_message, GNUNET_MESSAGE_TYPE_CADET_CLI,
383 struct GNUNET_MessageHeader, NULL),
384 GNUNET_MQ_handler_end() };
385
386 room->port = GNUNET_CADET_open_port (cadet, key, callback_room_connect, room, NULL,
387 callback_tunnel_disconnect, handlers);
388
389 const struct GNUNET_ShortHashCode *member_id = get_handle_member_id (handle, &(room->key));
390
391 struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos, member_id);
392
393 if ((!info) && (GNUNET_NO == join_room (room, handle, member_id)) && (room->port))
394 {
395 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not join the room, therefore it keeps closed!\n");
396
397 GNUNET_CADET_close_port (room->port);
398 room->port = NULL;
399
400 return GNUNET_NO;
401 }
402
403 struct GNUNET_MESSENGER_Message *message = create_message_peer (room->service);
404
405 if (message)
406 {
407 struct GNUNET_HashCode hash;
408
409 send_room_message (room, handle, message, &hash);
410 destroy_message (message);
411 }
412
413 return (room->port ? GNUNET_YES : GNUNET_NO);
414}
415
416int
417entry_room_at (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
418 const struct GNUNET_PeerIdentity *door)
419{
420 if (room->peer_message)
421 {
422 const struct GNUNET_MESSENGER_Message *msg = get_room_message (room, handle, room->peer_message, GNUNET_NO);
423
424 if (0 == GNUNET_memcmp(&(msg->body.peer.peer), door))
425 return join_room_locally (room, handle);
426 }
427
428 struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, door);
429
430 if (tunnel)
431 {
432 switch (connect_tunnel (tunnel))
433 {
434 case GNUNET_YES:
435 return GNUNET_YES;
436 case GNUNET_NO:
437 return join_room_locally (room, handle);
438 default:
439 return GNUNET_NO;
440 }
441 }
442
443 tunnel = create_tunnel (room, door);
444
445 if ((GNUNET_YES == connect_tunnel (tunnel)) &&
446 (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (room->tunnels, door, tunnel,
447 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
448 return GNUNET_YES;
449 else
450 {
451 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not connect to that door!\n");
452
453 destroy_tunnel (tunnel);
454 return GNUNET_NO;
455 }
456}
457
458struct GNUNET_MESSENGER_SrvTunnelFinder
459{
460 const struct GNUNET_ShortHashCode *needle;
461 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
462};
463
464static int
465iterate_find_tunnel (void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
466{
467 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
468 struct GNUNET_MESSENGER_SrvTunnelFinder *finder = cls;
469
470 if ((tunnel->contact_id) && (0 == GNUNET_memcmp(tunnel->contact_id, finder->needle)))
471 {
472 finder->tunnel = tunnel;
473 return GNUNET_NO;
474 }
475
476 return GNUNET_YES;
477}
478
479struct GNUNET_MESSENGER_SrvTunnel*
480find_room_tunnel_to (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *contact_id)
481{
482 struct GNUNET_MESSENGER_SrvTunnelFinder finder;
483
484 finder.needle = contact_id;
485 finder.tunnel = NULL;
486
487 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_find_tunnel, &finder);
488
489 return finder.tunnel;
490}
491
492struct GNUNET_MQ_Envelope*
493pack_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
494 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash, int mode)
495{
496 message->header.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
497
498 const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, &(room->key));
499
500 GNUNET_assert(id);
501
502 GNUNET_memcpy(&(message->header.sender_id), id, sizeof(struct GNUNET_ShortHashCode));
503
504 if (room->last_messages.head)
505 GNUNET_memcpy(&(message->header.previous), &(room->last_messages.head->hash), sizeof(struct GNUNET_HashCode));
506 else
507 memset (&(message->header.previous), 0, sizeof(struct GNUNET_HashCode));
508
509 return pack_message (message, hash, get_handle_ego (handle), mode);
510}
511
512struct GNUNET_MESSENGER_ClosureSendRoom
513{
514 struct GNUNET_MESSENGER_SrvRoom *room;
515 struct GNUNET_MESSENGER_SrvHandle *handle;
516 struct GNUNET_MESSENGER_SrvTunnel *exclude;
517 struct GNUNET_MESSENGER_Message *message;
518 struct GNUNET_HashCode *hash;
519 int packed;
520};
521
522static int
523iterate_send_room_message (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
524{
525 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
526
527 if ((!is_tunnel_connected (tunnel)) || (!tunnel->contact_id))
528 return GNUNET_YES;
529
530 struct GNUNET_MESSENGER_ClosureSendRoom *closure = cls;
531
532 if (tunnel == closure->exclude)
533 return GNUNET_YES;
534
535 struct GNUNET_MQ_Envelope *env = NULL;
536
537 if (closure->packed == GNUNET_NO)
538 {
539 env = pack_room_message (closure->room, closure->handle, closure->message, closure->hash,
540 GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
541
542 if (env)
543 {
544 closure->message = copy_message (closure->message);
545 closure->packed = GNUNET_YES;
546 }
547 }
548 else
549 {
550 env = pack_message (closure->message, NULL, NULL,
551 GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
552 }
553
554 if (env)
555 send_tunnel_envelope (tunnel, closure->handle, env, closure->message, closure->hash);
556
557 return GNUNET_YES;
558}
559
560void
561callback_room_sent (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle, void *cls,
562 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
563
564void
565send_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
566 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash)
567{
568 struct GNUNET_MESSENGER_ClosureSendRoom closure;
569
570 closure.room = room;
571 closure.handle = handle;
572 closure.exclude = NULL;
573 closure.message = message;
574 closure.hash = hash;
575 closure.packed = GNUNET_NO;
576
577 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
578
579 if ((GNUNET_NO == closure.packed) && (closure.message == message))
580 {
581 pack_room_message (room, handle, message, hash,
582 GNUNET_MESSENGER_PACK_MODE_UNKNOWN);
583
584 callback_room_sent (room, handle, NULL, copy_message (message), hash);
585 }
586}
587
588void
589send_room_message_ext (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
590 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
591 struct GNUNET_MESSENGER_SrvTunnel *tunnel)
592{
593 struct GNUNET_MESSENGER_ClosureSendRoom closure;
594
595 closure.room = room;
596 closure.handle = handle;
597 closure.exclude = tunnel;
598 closure.message = message;
599 closure.hash = hash;
600 closure.packed = GNUNET_NO;
601
602 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
603
604 if ((GNUNET_NO == closure.packed) && (closure.message == message))
605 {
606 pack_room_message (room, handle, message, hash,
607 GNUNET_MESSENGER_PACK_MODE_UNKNOWN);
608
609 callback_room_sent (room, handle, NULL, copy_message (message), hash);
610 }
611}
612
613void
614forward_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
615 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
616{
617 struct GNUNET_MESSENGER_ClosureSendRoom closure;
618 struct GNUNET_HashCode message_hash;
619
620 GNUNET_memcpy(&message_hash, hash, sizeof(struct GNUNET_HashCode));
621
622 closure.room = room;
623 closure.handle = NULL;
624 closure.exclude = tunnel;
625 closure.message = copy_message (message);
626 closure.hash = &message_hash;
627 closure.packed = GNUNET_YES;
628
629 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
630}
631
632void
633merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
634{
635 if (!handle)
636 return;
637
638 if (!room->last_messages.head)
639 return;
640
641 while (room->last_messages.head != room->last_messages.tail)
642 {
643 struct GNUNET_MESSENGER_ListMessage *element = room->last_messages.tail;
644
645 struct GNUNET_MESSENGER_Message *message = create_message_merge (&(element->hash));
646
647 if (message)
648 {
649 struct GNUNET_HashCode hash;
650
651 send_room_message (room, handle, message, &hash);
652 destroy_message (message);
653 }
654
655 if (element->prev)
656 GNUNET_CONTAINER_DLL_remove(room->last_messages.head, room->last_messages.tail, element);
657 }
658}
659
660struct GNUNET_CADET_Handle*
661get_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room)
662{
663 return room->service->cadet;
664}
665
666struct GNUNET_HashCode*
667get_room_key (struct GNUNET_MESSENGER_SrvRoom *room)
668{
669 return &(room->key);
670}
671
672const struct GNUNET_MESSENGER_SrvTunnel*
673get_room_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *peer)
674{
675 return GNUNET_CONTAINER_multipeermap_get (room->tunnels, peer);
676}
677
678const struct GNUNET_MESSENGER_Message*
679get_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
680 const struct GNUNET_HashCode *hash, int request)
681{
682 const struct GNUNET_MESSENGER_Message *message = get_store_message (&(room->store), hash);
683
684 if ((message) || (!handle) || (GNUNET_YES != request)
685 || (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (room->requested, hash)))
686 return message;
687
688 struct GNUNET_MESSENGER_Message *request_msg = create_message_request (hash);
689
690 if (request_msg)
691 {
692 if (GNUNET_CONTAINER_multihashmap_put (room->requested, hash, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST) == GNUNET_OK)
693 {
694 struct GNUNET_HashCode request_hash;
695
696 send_room_message (room, handle, request_msg, &request_hash);
697 }
698
699 destroy_message (request_msg);
700 }
701
702 return message;
703}
704
705void
706callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room, void *cls)
707{
708 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
709
710 if (!room->host)
711 return;
712
713 struct GNUNET_PeerIdentity identity;
714
715 GNUNET_PEER_resolve (tunnel->peer, &identity);
716
717 if (GNUNET_YES == contains_list_tunnels (&(room->basement), &identity))
718 {
719 struct GNUNET_MESSENGER_Message *message = create_message_miss (&identity);
720
721 if (message)
722 {
723 struct GNUNET_HashCode hash;
724
725 send_room_message (room, room->host, message, &hash);
726 destroy_message (message);
727 }
728 }
729}
730
731int
732callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room, void *cls,
733 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash)
734{
735 if (GNUNET_MESSENGER_KIND_UNKNOWN == message->header.kind)
736 return GNUNET_SYSERR;
737
738 struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
739 &(message->header.sender_id));
740
741 if (!contact)
742 {
743 if (GNUNET_MESSENGER_KIND_INFO == message->header.kind)
744 contact = get_service_contact_by_pubkey (room->service, &(message->body.info.host_key));
745 else if (GNUNET_MESSENGER_KIND_JOIN == message->header.kind)
746 contact = get_service_contact_by_pubkey (room->service, &(message->body.join.key));
747 }
748
749 if ((!contact) || (GNUNET_SYSERR == verify_message (message, hash, get_contact_key (contact))))
750 return GNUNET_SYSERR;
751
752 if (GNUNET_YES == room->strict_access)
753 {
754 struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos,
755 &(message->header.sender_id));
756
757 if ((info) && (GNUNET_MESSENGER_MEMBER_BLOCKED == info->access))
758 return GNUNET_SYSERR;
759 }
760
761 if (GNUNET_YES == contains_store_message (&(room->store), hash))
762 return GNUNET_NO;
763
764 return GNUNET_YES;
765}
766
767static void
768search_room_for_message (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash)
769{
770 const struct GNUNET_MESSENGER_Message *message = get_room_message (room, room->host, hash, GNUNET_YES);
771
772 if (!message)
773 return;
774
775 if (GNUNET_MESSENGER_KIND_MERGE == message->header.kind)
776 search_room_for_message (room, &(message->body.merge.previous));
777
778 search_room_for_message (room, &(message->header.previous));
779}
780
781static void
782idle_request_room_messages (void *cls)
783{
784 struct GNUNET_MESSENGER_SrvRoom *room = cls;
785
786 room->idle = NULL;
787
788 struct GNUNET_MESSENGER_ListMessage *element = room->last_messages.head;
789
790 while (element)
791 {
792 search_room_for_message (room, &(element->hash));
793
794 element = element->next;
795 }
796
797 merge_room_last_messages (room, room->host);
798
799 room->idle = GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_get_second_ (),
800 GNUNET_SCHEDULER_PRIORITY_IDLE, idle_request_room_messages,
801 cls);
802}
803
804void
805update_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_MESSENGER_Message *message,
806 const struct GNUNET_HashCode *hash)
807{
808 struct GNUNET_MESSENGER_ListMessage *element = room->last_messages.head;
809 struct GNUNET_MESSENGER_ListMessage *merging = NULL;
810
811 if (GNUNET_MESSENGER_KIND_MERGE == message->header.kind)
812 {
813 merging = room->last_messages.head;
814
815 while (merging)
816 {
817 if (0 == GNUNET_CRYPTO_hash_cmp (&(merging->hash), &(message->body.merge.previous)))
818 break;
819
820 merging = merging->next;
821 }
822
823 if (merging)
824 element = merging->next;
825 }
826
827 while (element)
828 {
829 if (0 == GNUNET_CRYPTO_hash_cmp (&(element->hash), &(message->header.previous)))
830 break;
831
832 element = element->next;
833 }
834
835 if ((merging) && (!element))
836 {
837 element = merging;
838 merging = NULL;
839 }
840
841 if (element)
842 {
843 GNUNET_memcpy(&(element->hash), hash, sizeof(struct GNUNET_HashCode));
844
845 if (merging)
846 GNUNET_CONTAINER_DLL_remove(room->last_messages.head, room->last_messages.tail, merging);
847 }
848 else
849 add_to_list_messages (&(room->last_messages), hash);
850
851 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (room->requested, hash))
852 GNUNET_CONTAINER_multihashmap_remove_all (room->requested, hash);
853}
854
855void
856switch_room_member_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *old_id,
857 const struct GNUNET_ShortHashCode *new_id, const struct GNUNET_HashCode *hash)
858{
859 struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multishortmap_get (room->members, old_id);
860
861 if ((contact) && (GNUNET_YES == GNUNET_CONTAINER_multishortmap_remove (room->members, old_id, contact)))
862 GNUNET_CONTAINER_multishortmap_put (room->members, new_id, contact,
863 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
864
865 struct GNUNET_MESSENGER_MemberInfo *info = GNUNET_CONTAINER_multishortmap_get (room->member_infos, old_id);
866
867 if ((!info) || (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->member_infos, old_id, contact))
868 || (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (room->member_infos, new_id, contact,
869 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
870 return;
871
872 if (hash)
873 add_to_list_messages (&(info->session_messages), hash);
874}
875
876void
877rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room)
878{
879 struct GNUNET_PeerIdentity peer;
880 size_t src;
881
882 if ((GNUNET_OK != get_service_peer_identity (room->service, &peer)) || (!find_list_tunnels (&(room->basement), &peer,
883 &src)))
884 return;
885
886 size_t count = count_of_tunnels (&(room->basement));
887
888 struct GNUNET_MESSENGER_ListTunnel *element = room->basement.head;
889 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
890
891 size_t dst = 0;
892
893 while (element)
894 {
895 GNUNET_PEER_resolve (element->peer, &peer);
896
897 tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, &peer);
898
899 if (!tunnel)
900 {
901 element = remove_from_list_tunnels (&(room->basement), element);
902 continue;
903 }
904
905 if (GNUNET_YES == required_connection_between (count, src, dst))
906 {
907 if (GNUNET_SYSERR == connect_tunnel (tunnel))
908 {
909 element = remove_from_list_tunnels (&(room->basement), element);
910 continue;
911 }
912 }
913 else
914 disconnect_tunnel (tunnel);
915
916 element = element->next;
917 dst++;
918 }
919}
920
921void
922handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room)
923{
924 while (room->handling.head)
925 {
926 struct GNUNET_MESSENGER_ListMessage *element = room->handling.head;
927
928 const struct GNUNET_MESSENGER_Message *msg = get_room_message (room, room->host, &(element->hash), GNUNET_NO);
929
930 if (msg)
931 handle_service_message (room->service, room, msg, &(element->hash));
932
933 GNUNET_CONTAINER_DLL_remove(room->handling.head, room->handling.tail, element);
934 GNUNET_free(element);
935 }
936}
937
938#include "gnunet-service-messenger_message_recv.h"
939
940void
941callback_room_recv (struct GNUNET_MESSENGER_SrvRoom *room, void *cls, struct GNUNET_MESSENGER_Message *message,
942 const struct GNUNET_HashCode *hash)
943{
944 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
945
946 if (GNUNET_OK != put_store_message (&(room->store), hash, message))
947 return;
948
949 update_room_last_messages (room, message, hash);
950
951 if (GNUNET_MESSENGER_KIND_INFO != message->header.kind)
952 forward_room_message (room, tunnel, message, hash);
953
954 const int start_handle = room->handling.head ? GNUNET_NO : GNUNET_YES;
955
956 add_to_list_messages (&(room->handling), hash);
957
958 switch (message->header.kind)
959 {
960 case GNUNET_MESSENGER_KIND_INFO:
961 recv_message_info (room, tunnel, message, hash);
962 break;
963 case GNUNET_MESSENGER_KIND_JOIN:
964 recv_message_join (room, tunnel, message, hash);
965 break;
966 case GNUNET_MESSENGER_KIND_LEAVE:
967 recv_message_leave (room, tunnel, message, hash);
968 break;
969 case GNUNET_MESSENGER_KIND_NAME:
970 recv_message_name (room, tunnel, message, hash);
971 break;
972 case GNUNET_MESSENGER_KIND_KEY:
973 recv_message_key (room, tunnel, message, hash);
974 break;
975 case GNUNET_MESSENGER_KIND_PEER:
976 recv_message_peer (room, tunnel, message, hash);
977 break;
978 case GNUNET_MESSENGER_KIND_ID:
979 recv_message_id (room, tunnel, message, hash);
980 break;
981 case GNUNET_MESSENGER_KIND_MISS:
982 recv_message_miss (room, tunnel, message, hash);
983 break;
984 case GNUNET_MESSENGER_KIND_REQUEST:
985 recv_message_request (room, tunnel, message, hash);
986 break;
987 default:
988 break;
989 }
990
991 if (GNUNET_YES == start_handle)
992 handle_room_messages (room);
993}
994
995#include "gnunet-service-messenger_message_send.h"
996
997void
998callback_room_sent (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle, void *cls,
999 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
1000{
1001 const struct GNUNET_MESSENGER_Message *old_message = get_room_message (room, handle, hash, GNUNET_NO);
1002
1003 if ((old_message) || (GNUNET_OK != put_store_message (&(room->store), hash, message)))
1004 {
1005 if (old_message != message)
1006 GNUNET_free(message);
1007 }
1008 else
1009 {
1010 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls; // may be NULL
1011
1012 update_room_last_messages (room, message, hash);
1013
1014 const int start_handle = room->handling.head ? GNUNET_NO : GNUNET_YES;
1015
1016 add_to_list_messages (&(room->handling), hash);
1017
1018 switch (message->header.kind)
1019 {
1020 case GNUNET_MESSENGER_KIND_INFO:
1021 send_message_info (room, handle, tunnel, message, hash);
1022 break;
1023 case GNUNET_MESSENGER_KIND_JOIN:
1024 send_message_join (room, handle, tunnel, message, hash);
1025 break;
1026 case GNUNET_MESSENGER_KIND_LEAVE:
1027 send_message_leave (room, handle, tunnel, message, hash);
1028 break;
1029 case GNUNET_MESSENGER_KIND_NAME:
1030 send_message_name (room, handle, tunnel, message, hash);
1031 break;
1032 case GNUNET_MESSENGER_KIND_KEY:
1033 send_message_key (room, handle, tunnel, message, hash);
1034 break;
1035 case GNUNET_MESSENGER_KIND_PEER:
1036 send_message_peer (room, handle, tunnel, message, hash);
1037 break;
1038 case GNUNET_MESSENGER_KIND_ID:
1039 send_message_id (room, handle, tunnel, message, hash);
1040 break;
1041 case GNUNET_MESSENGER_KIND_MISS:
1042 send_message_miss (room, handle, tunnel, message, hash);
1043 break;
1044 default:
1045 break;
1046 }
1047
1048 if (GNUNET_YES == start_handle)
1049 handle_room_messages (room);
1050 }
1051}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_room.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_ROOM_H
27#define GNUNET_SERVICE_MESSENGER_ROOM_H
28
29#include "platform.h"
30#include "gnunet_cadet_service.h"
31#include "gnunet_container_lib.h"
32#include "gnunet_crypto_lib.h"
33#include "gnunet_identity_service.h"
34#include "gnunet_mq_lib.h"
35
36#include "gnunet-service-messenger_contact.h"
37
38#include "gnunet_messenger_service.h"
39#include "gnunet-service-messenger_basement.h"
40#include "gnunet-service-messenger_handle.h"
41#include "gnunet-service-messenger_tunnel.h"
42
43#include "gnunet-service-messenger_list_messages.h"
44#include "messenger_api_list_tunnels.h"
45
46#include "gnunet-service-messenger_message_store.h"
47#include "messenger_api_ego.h"
48
49enum GNUNET_MESSENGER_MemberAccess
50{
51 GNUNET_MESSENGER_MEMBER_ALLOWED = 1,
52 GNUNET_MESSENGER_MEMBER_BLOCKED = 1,
53
54 GNUNET_MESSENGER_MEMBER_UNKNOWN = 0
55};
56
57struct GNUNET_MESSENGER_MemberInfo
58{
59 enum GNUNET_MESSENGER_MemberAccess access;
60
61 struct GNUNET_MESSENGER_ListMessages session_messages;
62};
63
64struct GNUNET_MESSENGER_SrvRoom
65{
66 struct GNUNET_MESSENGER_Service *service;
67 struct GNUNET_MESSENGER_SrvHandle *host;
68 struct GNUNET_CADET_Port *port;
69
70 struct GNUNET_HashCode key;
71
72 struct GNUNET_CONTAINER_MultiPeerMap *tunnels;
73 struct GNUNET_CONTAINER_MultiShortmap *members;
74 struct GNUNET_CONTAINER_MultiShortmap *member_infos;
75
76 struct GNUNET_MESSENGER_MessageStore store;
77 struct GNUNET_CONTAINER_MultiHashMap *requested;
78
79 struct GNUNET_MESSENGER_ListTunnels basement;
80 struct GNUNET_MESSENGER_ListMessages last_messages;
81
82 struct GNUNET_HashCode *peer_message;
83
84 struct GNUNET_MESSENGER_ListMessages handling;
85 struct GNUNET_SCHEDULER_Task *idle;
86
87 int strict_access;
88};
89
90/**
91 * Creates and allocates a new room for a <i>handle</i> with a given <i>key</i>.
92 *
93 * @param handle Handle
94 * @param key Key of room
95 * @return New room
96 */
97struct GNUNET_MESSENGER_SrvRoom*
98create_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_HashCode *key);
99
100/**
101 * Destroys a room and frees its memory fully.
102 *
103 * @param room Room
104 */
105void
106destroy_room (struct GNUNET_MESSENGER_SrvRoom *room);
107
108/**
109 * Returns the contact of a member in a <i>room</i> identified by a given <i>id</i>. If the <i>room</i>
110 * does not contain a member with the given <i>id</i>, NULL gets returned.
111 *
112 * @param room Room
113 * @param id Member id
114 * @return Contact or NULL
115 */
116struct GNUNET_MESSENGER_SrvContact*
117get_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id);
118
119/**
120 * Adds a contact from the service to a <i>room</i> under a specific <i>id</i> with a given public key.
121 *
122 * @param room Room
123 * @param id Member id
124 * @param pubkey Public key of EGO
125 */
126void
127add_room_contact (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id,
128 const struct GNUNET_IDENTITY_PublicKey *pubkey);
129
130/**
131 * Returns the member information of a member in a <i>room</i> identified by a given <i>id</i>. If the <i>room</i>
132 * does not contain a member with the given <i>id</i>, NULL gets returned.
133 *
134 * @param room Room
135 * @param id Member id
136 * @return Member information or NULL
137 */
138struct GNUNET_MESSENGER_MemberInfo*
139get_room_member_info (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *id);
140
141/**
142 * Tries to generate and allocate a new unique member id checking all current members for possible
143 * duplicates. If the function fails, NULL gets returned.
144 *
145 * @param room Room
146 * @return New member id or NULL
147 */
148struct GNUNET_ShortHashCode*
149generate_room_member_id (const struct GNUNET_MESSENGER_SrvRoom *room);
150
151/**
152 * Returns the member id of the member representing the handle currently hosting this <i>room</i>.
153 *
154 * @param room Room
155 * @return Host member id or NULL
156 */
157const struct GNUNET_ShortHashCode*
158get_room_host_id (const struct GNUNET_MESSENGER_SrvRoom *room);
159
160/**
161 * Changes the member id of the member representing the handle currently hosting this <i>room</i>.
162 *
163 * @param room Room
164 * @param unique_id Unique member id
165 */
166void
167change_room_host_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *unique_id);
168
169/**
170 * Tries to open a <i>room</i> for a given <i>handle</i>. If the room has already been opened, the handle
171 * will locally join the room.
172 *
173 * Calling this method should result in joining a room and sending a peer message as well for this peer.
174 *
175 * If the function returns GNUNET_YES the port for this room is guranteed to be open for incoming connections.
176 *
177 * @param room Room
178 * @param handle Handle
179 * @return GNUNET_YES on success, GNUNET_NO on failure.
180 */
181int
182open_room (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle);
183
184/**
185 * Connects a tunnel to a hosting peer of a <i>room</i> through a so called <i>door</i> which is represented by
186 * a peer identity of a hosting peer. During the connection the handle will join the room as a member, waiting for
187 * an info message from the selected host.
188 *
189 * @param room Room
190 * @param handle Handle
191 * @param door Peer identity
192 * @return GNUNET_YES on success, GNUNET_NO on failure.
193 */
194int
195entry_room_at (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
196 const struct GNUNET_PeerIdentity *door);
197
198/**
199 * Returns a tunnel granting a direct connection to a specific member in a <i>room</i>. The member gets identified
200 * by an <i>id</i>. If no tunnel has been linked to the selected id, NULL gets returned.
201 *
202 * @param room Room
203 * @param contact_id Member id
204 * @return Tunnel to the member or NULL
205 */
206struct GNUNET_MESSENGER_SrvTunnel*
207find_room_tunnel_to (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *contact_id);
208
209/**
210 * Packs a <i>message</i> depending on the selected <i>mode</i> into a newly allocated envelope. It will set the
211 * timestamp of the message, the sender id and the previous messages hash automatically before packing. The message
212 * will be signed by the handles EGO.
213 *
214 * If the optional <i>hash</i> parameter is a valid pointer, its value will be overriden by the signed messages hash.
215 *
216 * If <i>mode</i> is set to GNUNET_MESSENGER_PACK_MODE_ENVELOPE, the function returns a valid envelope to send
217 * through a message queue, otherwise NULL.
218 *
219 * @param room Room
220 * @param handle Handle
221 * @param message Message
222 * @param[out] hash Hash of message
223 * @param mode Packing mode
224 * @return New envelope or NULL
225 */
226struct GNUNET_MQ_Envelope*
227pack_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
228 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash, int mode);
229
230/**
231 * Sends a <i>message</i> from a given <i>handle</i> into a <i>room</i>. The <i>hash</i> parameter will be
232 * updated with the hash-value resulting from the sent message.
233 *
234 * The function handles packing the message automatically and will call linked message-events locally even if
235 * the message won't be sent to another peer.
236 *
237 * @param room Room
238 * @param handle Handle
239 * @param message Message
240 * @param[out] hash Hash of message
241 */
242void
243send_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
244 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash);
245
246/**
247 * Sends a <i>message</i> from a given <i>handle</i> into a <i>room</i> excluding one specific <i>tunnel</i>.
248 * The <i>hash</i> parameter will be updated with the hash-value resulting from the sent message.
249 *
250 * The function handles packing the message automatically and will call linked message-events locally even if
251 * the message won't be sent to another peer.
252 *
253 * @param room Room
254 * @param handle Handle
255 * @param message Message
256 * @param[out] hash Hash of message
257 * @param tunnel Tunnel
258 */
259void
260send_room_message_ext (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
261 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
262 struct GNUNET_MESSENGER_SrvTunnel *tunnel);
263
264/**
265 * Forwards a <i>message</i> with a given <i>hash</i> to a specific <i>tunnel</i> inside of a <i>room</i>.
266 *
267 * @param room Room
268 * @param tunnel Tunnel
269 * @param message Message
270 * @param hash Hash of message
271 */
272void
273forward_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
274 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
275
276/**
277 * Reduces all current forks inside of the message history of a <i>room</i> to one remaining last message
278 * by merging them down. All merge messages will be sent from a given <i>handle</i>.
279 *
280 * @param room Room
281 * @param handle Handle
282 */
283void
284merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle);
285
286/**
287 * Returns the CADET handle from a rooms service.
288 *
289 * @param room Room
290 * @return CADET handle
291 */
292struct GNUNET_CADET_Handle*
293get_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room);
294
295/**
296 * Returns the shared secret you need to access a <i>room</i>.
297 *
298 * @param room Room
299 * @return Shared secret
300 */
301struct GNUNET_HashCode*
302get_room_key (struct GNUNET_MESSENGER_SrvRoom *room);
303
304/**
305 * Returns a tunnel inside of a <i>room</i> leading towards a given <i>peer</i> if such a tunnel exists,
306 * otherwise NULL.
307 *
308 * @param room Room
309 * @param peer Peer identity
310 * @return Tunnel or NULL
311 */
312const struct GNUNET_MESSENGER_SrvTunnel*
313get_room_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *peer);
314
315/**
316 * Returns a message from a <i>room</i> identified by a given <i>hash</i>. If no matching message is
317 * found and <i>request</i> is set to GNUNET_YES, the <i>handle</i> will request the missing message
318 * automatically.
319 *
320 * The function uses the optimized check for a message via its hash from the message store.
321 * @see contains_store_message()
322 *
323 * If a message is missing independent of the following request, NULL gets returned instead of the
324 * matching message.
325 *
326 * @param room Room
327 * @param handle Handle
328 * @param hash Hash of message
329 * @param request Flag to request a message
330 * @return Message or NULL
331 */
332const struct GNUNET_MESSENGER_Message*
333get_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
334 const struct GNUNET_HashCode *hash, int request);
335
336/**
337 * Updates the last messages of a <i>room</i> by replacing them if the previous hash of a given <i>message</i>
338 * matches with one of the latest messages.
339 *
340 * @param room Room
341 * @param message Message
342 * @param hash Hash of message
343 */
344void
345update_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_MESSENGER_Message *message,
346 const struct GNUNET_HashCode *hash);
347
348/**
349 * Changes an id of a current member from an old id to a new one and adds optionally the <i>hash</i> of an
350 * id message to the members information.
351 *
352 * @param room Room
353 * @param old_id Old member id
354 * @param new_id New member id
355 * @param hash Hash of id message
356 */
357void
358switch_room_member_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *old_id,
359 const struct GNUNET_ShortHashCode *new_id, const struct GNUNET_HashCode *hash);
360
361/**
362 * Rebuilds the decentralized structure for a <i>room</i> by ensuring all required connections are made
363 * depending on the amount of peers and this peers index in the list of them.
364 *
365 * @param room Room
366 */
367void
368rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room);
369
370/**
371 * Handles all queued up messages of a room to handle in correct order.
372 *
373 * @param room Room
374 */
375void
376handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room);
377
378#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_service.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_service.h"
27
28#include "gnunet-service-messenger_message_kind.h"
29
30#include "gnunet-service-messenger.h"
31#include "gnunet-service-messenger_util.h"
32
33static void
34callback_shutdown_service (void *cls)
35{
36 struct GNUNET_MESSENGER_Service *service = cls;
37
38 if (service)
39 {
40 service->shutdown = NULL;
41
42 destroy_service (service);
43 }
44}
45
46static void
47callback_update_ego (void *cls,
48 struct GNUNET_IDENTITY_Ego *ego,
49 void **ctx,
50 const char *identifier)
51{
52 if ((!ego) || (!identifier))
53 return;
54
55 struct GNUNET_MESSENGER_Service *service = cls;
56
57 update_service_ego(service, identifier, GNUNET_IDENTITY_ego_get_private_key(ego));
58}
59
60struct GNUNET_MESSENGER_Service*
61create_service (const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service_handle)
62{
63 struct GNUNET_MESSENGER_Service *service = GNUNET_new(struct GNUNET_MESSENGER_Service);
64
65 service->config = config;
66 service->service = service_handle;
67
68 service->shutdown = GNUNET_SCHEDULER_add_shutdown (&callback_shutdown_service, service);
69
70 service->dir = NULL;
71
72 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (service->config,
73 GNUNET_MESSENGER_SERVICE_NAME,
74 "MESSENGER_DIR", &(service->dir)))
75 {
76 if (service->dir)
77 GNUNET_free(service->dir);
78
79 service->dir = NULL;
80 }
81 else
82 {
83 if ((GNUNET_YES != GNUNET_DISK_directory_test (service->dir, GNUNET_YES)) && (GNUNET_OK
84 != GNUNET_DISK_directory_create (service->dir)))
85 {
86 GNUNET_free(service->dir);
87
88 service->dir = NULL;
89 }
90 }
91
92 service->cadet = GNUNET_CADET_connect (service->config);
93 service->identity = GNUNET_IDENTITY_connect (service->config, &callback_update_ego, service);
94
95 service->egos = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
96
97 init_list_handles (&(service->handles));
98
99 service->contacts = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
100 service->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
101
102 return service;
103}
104
105static int
106iterate_destroy_egos (void *cls, const struct GNUNET_HashCode *key, void *value)
107{
108 struct GNUNET_MESSENGER_Ego *ego = value;
109 GNUNET_free(ego);
110 return GNUNET_YES;
111}
112
113static int
114iterate_destroy_rooms (void *cls, const struct GNUNET_HashCode *key, void *value)
115{
116 struct GNUNET_MESSENGER_SrvRoom *room = value;
117 destroy_room (room);
118 return GNUNET_YES;
119}
120
121static int
122iterate_destroy_contacts (void *cls, const struct GNUNET_HashCode *key, void *value)
123{
124 struct GNUNET_MESSENGER_SrvContact *contact = value;
125 destroy_contact (contact);
126 return GNUNET_YES;
127}
128
129void
130destroy_service (struct GNUNET_MESSENGER_Service *service)
131{
132 if (service->shutdown)
133 {
134 GNUNET_SCHEDULER_cancel (service->shutdown);
135
136 service->shutdown = NULL;
137 }
138
139 GNUNET_CONTAINER_multihashmap_iterate (service->egos, iterate_destroy_egos, NULL);
140
141 clear_list_handles (&(service->handles));
142
143 GNUNET_CONTAINER_multihashmap_iterate (service->rooms, iterate_destroy_rooms, NULL);
144 GNUNET_CONTAINER_multihashmap_iterate (service->contacts, iterate_destroy_contacts, NULL);
145
146 GNUNET_CONTAINER_multihashmap_destroy (service->egos);
147 GNUNET_CONTAINER_multihashmap_destroy (service->rooms);
148 GNUNET_CONTAINER_multihashmap_destroy (service->contacts);
149
150 if (service->cadet)
151 {
152 GNUNET_CADET_disconnect (service->cadet);
153
154 service->cadet = NULL;
155 }
156
157 if (service->identity)
158 {
159 GNUNET_IDENTITY_disconnect (service->identity);
160
161 service->identity = NULL;
162 }
163
164 if (service->dir)
165 {
166 GNUNET_free(service->dir);
167
168 service->dir = NULL;
169 }
170
171 GNUNET_SERVICE_shutdown (service->service);
172
173 GNUNET_free(service);
174}
175
176struct GNUNET_MESSENGER_Ego*
177lookup_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier)
178{
179 GNUNET_assert(identifier);
180
181 struct GNUNET_HashCode hash;
182
183 GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
184 return GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
185}
186
187void
188update_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier,
189 const struct GNUNET_IDENTITY_PrivateKey* key)
190{
191 GNUNET_assert((identifier) && (key));
192
193 struct GNUNET_HashCode hash;
194
195 GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
196
197 struct GNUNET_MESSENGER_Ego* ego = GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
198
199 if (!ego)
200 {
201 ego = GNUNET_new(struct GNUNET_MESSENGER_Ego);
202 GNUNET_CONTAINER_multihashmap_put(service->egos, &hash, ego, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
203 }
204
205 GNUNET_memcpy(&(ego->priv), key, sizeof(*key));
206
207 if (GNUNET_OK != GNUNET_IDENTITY_key_get_public(key, &(ego->pub)))
208 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Updating invalid ego key failed!\n");
209}
210
211struct GNUNET_MESSENGER_SrvHandle*
212add_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq)
213{
214 struct GNUNET_MESSENGER_SrvHandle *handle = create_handle (service, mq);
215
216 if (handle)
217 {
218 add_list_handle (&(service->handles), handle);
219 }
220
221 return handle;
222}
223
224void
225remove_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle)
226{
227 if (!handle)
228 return;
229
230 if (GNUNET_YES == remove_list_handle (&(service->handles), handle))
231 destroy_handle (handle);
232}
233
234int
235get_service_peer_identity (const struct GNUNET_MESSENGER_Service *service, struct GNUNET_PeerIdentity *peer)
236{
237 return GNUNET_CRYPTO_get_peer_identity (service->config, peer);
238}
239
240struct GNUNET_MESSENGER_SrvContact*
241get_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_IDENTITY_PublicKey *pubkey)
242{
243 struct GNUNET_HashCode hash;
244
245 GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
246
247 struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multihashmap_get (service->contacts, &hash);
248
249 if (contact)
250 return contact;
251
252 contact = create_contact (pubkey);
253
254 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->contacts, &hash, contact,
255 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
256 return contact;
257
258 destroy_contact (contact);
259 return NULL;
260}
261
262void
263swap_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvContact *contact,
264 const struct GNUNET_IDENTITY_PublicKey *pubkey)
265{
266 const struct GNUNET_HashCode *hash = get_contact_id_from_key (contact);
267
268 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (service->contacts, hash, contact))
269 {
270 GNUNET_memcpy(&(contact->public_key), pubkey, sizeof(*pubkey));
271
272 hash = get_contact_id_from_key (contact);
273
274 GNUNET_CONTAINER_multihashmap_put (service->contacts, hash, contact,
275 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
276 }
277}
278
279struct GNUNET_ShortHashCode*
280generate_service_new_member_id (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
281{
282 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
283
284 if (room)
285 {
286 return generate_room_member_id (room);
287 }
288 else
289 {
290 struct GNUNET_ShortHashCode *random_id = GNUNET_new(struct GNUNET_ShortHashCode);
291 generate_free_member_id (random_id, NULL);
292 return random_id;
293 }
294}
295
296struct GNUNET_MESSENGER_SrvRoom*
297get_service_room (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
298{
299 return GNUNET_CONTAINER_multihashmap_get (service->rooms, key);
300}
301
302int
303open_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
304 const struct GNUNET_HashCode *key)
305{
306 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
307
308 if (room)
309 return open_room (room, handle);
310
311 room = create_room (handle, key);
312
313 if ((GNUNET_YES == open_room (room, handle)) && (GNUNET_OK
314 == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
315 return GNUNET_YES;
316
317 destroy_room (room);
318 return GNUNET_NO;
319}
320
321int
322entry_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
323 const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key)
324{
325 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
326
327 if (room)
328 {
329 if (GNUNET_YES == entry_room_at (room, handle, door))
330 return GNUNET_YES;
331 else
332 return GNUNET_NO;
333 }
334
335 room = create_room (handle, key);
336
337 if ((GNUNET_YES == entry_room_at (room, handle, door)) && (GNUNET_OK
338 == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
339 {
340 return GNUNET_YES;
341 }
342 else
343 {
344 destroy_room (room);
345 return GNUNET_NO;
346 }
347
348}
349
350int
351close_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
352 const struct GNUNET_HashCode *key)
353{
354 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
355
356 if (!room)
357 return GNUNET_NO;
358
359 struct GNUNET_MESSENGER_Message *message = create_message_leave ();
360
361 if (message)
362 {
363 struct GNUNET_HashCode hash;
364
365 send_room_message (room, handle, message, &hash);
366 destroy_message (message);
367 }
368
369 const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, key);
370
371 GNUNET_assert(id);
372
373 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (handle->member_ids, key, id))
374 return GNUNET_NO;
375
376 struct GNUNET_MESSENGER_SrvHandle *member_handle = (struct GNUNET_MESSENGER_SrvHandle*) find_list_handle_by_member (
377 &(service->handles), key);
378
379 if (!member_handle)
380 {
381 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (service->rooms, key, room))
382 {
383 destroy_room (room);
384 return GNUNET_YES;
385 }
386 else
387 return GNUNET_NO;
388 }
389
390 if (room->host == handle)
391 room->host = member_handle;
392
393 return GNUNET_YES;
394}
395
396static void
397get_room_data_subdir (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room, char **dir)
398{
399 GNUNET_asprintf (dir, "%s%s%c%s%c", service->dir, "rooms", DIR_SEPARATOR, GNUNET_h2s (&(room->key)), DIR_SEPARATOR);
400}
401
402void
403load_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
404{
405 char *room_dir;
406 get_room_data_subdir (service, room, &room_dir);
407
408 if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
409 {
410 load_message_store (&room->store, room_dir);
411
412 char *config_file;
413 GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
414
415 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
416
417 if ((GNUNET_YES == GNUNET_DISK_file_test (config_file)) && (GNUNET_OK
418 == GNUNET_CONFIGURATION_parse (cfg, config_file)))
419 {
420 unsigned long long access;
421
422 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "room", "access-rule", &access))
423 room->strict_access = (int) (access);
424
425 char *message_string;
426
427 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "room", "last-message", &message_string)) && (message_string))
428 {
429 struct GNUNET_HashCode hash;
430
431 GNUNET_CRYPTO_hash_from_string(message_string, &hash);
432
433 const struct GNUNET_MESSENGER_Message *message = get_room_message (room, room->host, &hash, GNUNET_NO);
434
435 if (message)
436 update_room_last_messages (room, message, &hash);
437
438 GNUNET_free(message_string);
439 }
440 }
441
442 GNUNET_CONFIGURATION_destroy (cfg);
443
444 GNUNET_free(config_file);
445 }
446
447 GNUNET_free(room_dir);
448}
449
450void
451save_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
452{
453 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (service->rooms, &(room->key)))
454 {
455 return;
456 }
457
458 char *room_dir;
459 get_room_data_subdir (service, room, &room_dir);
460
461 if ((GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_NO)) || (GNUNET_OK
462 == GNUNET_DISK_directory_create (room_dir)))
463 {
464 save_message_store (&room->store, room_dir);
465
466 char *config_file;
467 GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
468
469 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
470
471 GNUNET_CONFIGURATION_set_value_number (cfg, "room", "access-rule", room->strict_access);
472
473 if (room->last_messages.head)
474 GNUNET_CONFIGURATION_set_value_string (cfg, "room", "last-message",
475 GNUNET_h2s_full (&(room->last_messages.head->hash)));
476
477 GNUNET_CONFIGURATION_write (cfg, config_file);
478 GNUNET_CONFIGURATION_destroy (cfg);
479
480 GNUNET_free(config_file);
481 }
482
483 GNUNET_free(room_dir);
484}
485
486void
487handle_service_message (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room,
488 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
489{
490 struct GNUNET_MESSENGER_ListHandle *element = service->handles.head;
491
492 const uint16_t length = get_message_size (message);
493
494 while (element)
495 {
496 struct GNUNET_MESSENGER_SrvHandle *handle = (struct GNUNET_MESSENGER_SrvHandle*) element->handle;
497
498 if ((handle->mq) && (get_handle_member_id (handle, &(room->key))))
499 {
500 struct GNUNET_MESSENGER_RecvMessage *msg;
501 struct GNUNET_MQ_Envelope *env;
502
503 env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE);
504
505 GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
506 GNUNET_memcpy(&(msg->hash), hash, sizeof(*hash));
507
508 char *buffer = ((char*) msg) + sizeof(*msg);
509 encode_message (message, length, buffer);
510
511 GNUNET_MQ_send (handle->mq, env);
512 }
513
514 element = element->next;
515 }
516}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_service.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_SERVICE_H
27#define GNUNET_SERVICE_MESSENGER_SERVICE_H
28
29#include "platform.h"
30#include "gnunet_configuration_lib.h"
31#include "gnunet_crypto_lib.h"
32#include "gnunet_container_lib.h"
33#include "gnunet_disk_lib.h"
34#include "gnunet_identity_service.h"
35
36#include "messenger_api_ego.h"
37
38#include "gnunet-service-messenger_list_handles.h"
39
40#include "gnunet-service-messenger_contact.h"
41#include "gnunet-service-messenger_room.h"
42
43struct GNUNET_MESSENGER_Service
44{
45 const struct GNUNET_CONFIGURATION_Handle *config;
46 struct GNUNET_SERVICE_Handle *service;
47
48 struct GNUNET_SCHEDULER_Task *shutdown;
49
50 char *dir;
51
52 struct GNUNET_CADET_Handle *cadet;
53 struct GNUNET_IDENTITY_Handle *identity;
54
55 struct GNUNET_CONTAINER_MultiHashMap *egos;
56
57 struct GNUNET_MESSENGER_ListHandles handles;
58
59 struct GNUNET_CONTAINER_MultiHashMap *contacts;
60 struct GNUNET_CONTAINER_MultiHashMap *rooms;
61};
62
63/**
64 * Creates and allocates a new service using a given <i>config</i> and a GNUnet service handle.
65 *
66 * @param config Configuration
67 * @param service_handle GNUnet service handle
68 * @return New service
69 */
70struct GNUNET_MESSENGER_Service*
71create_service (const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service_handle);
72
73/**
74 * Destroys a <i>service</i> and frees its memory fully.
75 *
76 * @param service Service
77 */
78void
79destroy_service (struct GNUNET_MESSENGER_Service *service);
80
81/**
82 * Lookups an EGO which was registered to a <i>service</i> under
83 * a specific <i>identifier</i>.
84 *
85 * @param service Service
86 * @param identifier Identifier string
87 * @return EGO or NULL
88 */
89struct GNUNET_MESSENGER_Ego*
90lookup_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier);
91
92/**
93 * Updates the registration of an EGO to a <i>service</i> under
94 * a specific <i>identifier</i> with a new <i>key</i>.
95 *
96 * @param service Service
97 * @param identifier Identifier string
98 * @param key Private EGO key
99 */
100void
101update_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier,
102 const struct GNUNET_IDENTITY_PrivateKey* key);
103
104/**
105 * Creates and adds a new handle to a <i>service</i> using a given message queue.
106 *
107 * @param service Service
108 * @param mq Message queue
109 * @return New handle
110 */
111struct GNUNET_MESSENGER_SrvHandle*
112add_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq);
113
114/**
115 * Removes a <i>handle</i> from a <i>service</i> and destroys it.
116 *
117 * @param service Service
118 * @param handle Handle
119 */
120void
121remove_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle);
122
123/**
124 * Tries to write the peer identity of the peer running a <i>service</i> on to the <i>peer</i>
125 * parameter. The functions returns GNUNET_OK on success, otherwise GNUNET_SYSERR.
126 *
127 * @param service Service
128 * @param[out] peer Peer identity
129 * @return GNUNET_OK on success, otherwise GNUNET_SYSERR
130 */
131int
132get_service_peer_identity (const struct GNUNET_MESSENGER_Service *service, struct GNUNET_PeerIdentity *peer);
133
134/**
135 * Returns a contact of a <i>service</i> identified by a given public key. If no matching contact exists,
136 * it will tried to create one with the specific public key. If the function still fails to do so,
137 * NULL gets returned.
138 *
139 * @param service Service
140 * @param pubkey Public key of EGO
141 * @return Contact
142 */
143struct GNUNET_MESSENGER_SrvContact*
144get_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_IDENTITY_PublicKey *pubkey);
145
146/**
147 * Changes the public key for a <i>contact</i> known to a <i>service</i> to a specific public key and
148 * updates local map entries to access the contact by its updated key.
149 *
150 * @param service Service
151 * @param contact Contact
152 * @param pubkey Public key of EGO
153 */
154void
155swap_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvContact *contact,
156 const struct GNUNET_IDENTITY_PublicKey *pubkey);
157
158/**
159 * Tries to generate and allocate a new unique member id for a given room of a service identified by its <i>key</i>.
160 * If the generation fails caused by too many tries of duplicates, it returns NULL.
161 *
162 * @param service Service
163 * @param key Key of room
164 * @return Newly generated member id or NULL
165 */
166struct GNUNET_ShortHashCode*
167generate_service_new_member_id (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key);
168
169/**
170 * Returns the room identified by a given <i>key</i> for a <i>service</i>. If the service doesn't know any room
171 * using the given key, NULL gets returned.
172 *
173 * @param service Service
174 * @param key Key of room
175 * @return Room or NULL
176 */
177struct GNUNET_MESSENGER_SrvRoom*
178get_service_room (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key);
179
180/**
181 * 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
182 * created if necessary. If the function is successful, it returns GNUNET_YES, otherwise GNUNET_NO.
183 *
184 * @param service Service
185 * @param handle Handle
186 * @param key Key of room
187 * @return GNUNET_YES on success, otherwise GNUNET_NO
188 */
189int
190open_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
191 const struct GNUNET_HashCode *key);
192
193/**
194 * 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
195 * be created if necessary. If the function is successful, it returns GNUNET_YES, otherwise GNUNET_NO.
196 *
197 * The room will be entered through the peer identitied by the peer identity provided as <i>door</i> parameter and
198 * a new connection will be made.
199 *
200 * @param service Service
201 * @param handle Handle
202 * @param door Peer identity
203 * @param key Key of room
204 * @return GNUNET_YES on success, otherwise GNUNET_NO
205 */
206int
207entry_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
208 const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key);
209
210/**
211 * 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
212 * be created if necessary. If the function is successful, it returns GNUNET_YES, otherwise GNUNET_NO.
213 *
214 * If the specific handle is currently the host of the room for this service, a new handle which is a member will
215 * take its place. Otherwise the room will be destroyed for this service.
216 *
217 * @param service Service
218 * @param handle Handle
219 * @param key Key of room
220 * @return GNUNET_YES on success, otherwise GNUNET_NO
221 */
222int
223close_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
224 const struct GNUNET_HashCode *key);
225
226/**
227 * Loads the local configuration for a given <i>room</i> of a <i>service</i> which contains the last messages hash
228 * and the ruleset for general access of new members.
229 *
230 * @param service Service
231 * @param room Room
232 */
233void
234load_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room);
235
236/**
237 * Saves the configuration for a given <i>room</i> of a <i>service</i> which contains the last messages hash
238 * and the ruleset for general access of new members locally.
239 *
240 * @param service Service
241 * @param room Room
242 */
243void
244save_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room);
245
246/**
247 * Sends a received or sent <i>message</i> with a given <i>hash</i> to each handle of a <i>service</i> which
248 * is currently member of a specific <i>room</i> for handling it in the client API.
249 *
250 * @param service Service
251 * @param room Room
252 * @param message Message
253 * @param hash Hash of message
254 */
255void
256handle_service_message (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room,
257 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
258
259#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_tunnel.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_tunnel.h"
27
28#include "gnunet-service-messenger_handle.h"
29#include "gnunet-service-messenger_util.h"
30
31struct GNUNET_MESSENGER_SrvTunnel*
32create_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *door)
33{
34 GNUNET_assert((room) && (door));
35
36 struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_new(struct GNUNET_MESSENGER_SrvTunnel);
37
38 tunnel->room = room;
39 tunnel->channel = NULL;
40
41 tunnel->peer = GNUNET_PEER_intern (door);
42 tunnel->contact_id = NULL;
43
44 tunnel->peer_message = NULL;
45 tunnel->last_message = NULL;
46
47 return tunnel;
48}
49
50void
51destroy_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
52{
53 GNUNET_assert(tunnel);
54
55 if (tunnel->channel)
56 GNUNET_CADET_channel_destroy (tunnel->channel);
57
58 GNUNET_PEER_change_rc (tunnel->peer, -1);
59
60 if (tunnel->contact_id)
61 GNUNET_free(tunnel->contact_id);
62
63 if (tunnel->peer_message)
64 GNUNET_free(tunnel->peer_message);
65
66 if (tunnel->last_message)
67 GNUNET_free(tunnel->last_message);
68
69 GNUNET_free(tunnel);
70}
71
72int
73bind_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_CADET_Channel *channel)
74{
75 GNUNET_assert(tunnel);
76
77 if (tunnel->channel)
78 {
79 if (tunnel->contact_id)
80 return GNUNET_NO;
81
82 delayed_disconnect_channel (tunnel->channel);
83 }
84
85 tunnel->channel = channel;
86
87 return GNUNET_YES;
88}
89
90extern void
91callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room, void *cls);
92
93void
94callback_tunnel_disconnect (void *cls, const struct GNUNET_CADET_Channel *channel)
95{
96 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
97
98 if (tunnel)
99 {
100 tunnel->channel = NULL;
101
102 callback_room_disconnect (tunnel->room, cls);
103 }
104}
105
106extern int
107callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room, void *cls,
108 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash);
109
110int
111check_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header)
112{
113 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
114
115 if (!tunnel)
116 return GNUNET_NO;
117
118 const uint16_t length = ntohs (header->size) - sizeof(*header);
119 const char *buffer = (const char*) &header[1];
120
121 struct GNUNET_MESSENGER_Message message;
122
123 if (length < sizeof(message.header))
124 return GNUNET_NO;
125
126 if (GNUNET_YES != decode_message (&message, length, buffer))
127 return GNUNET_NO;
128
129 struct GNUNET_HashCode hash;
130 hash_message (length, buffer, &hash);
131
132 int result = callback_verify_room_message (tunnel->room, cls, &message, &hash);
133
134 if (GNUNET_MESSENGER_KIND_PEER == message.header.kind)
135 {
136 struct GNUNET_PeerIdentity identity;
137
138 GNUNET_PEER_resolve (tunnel->peer, &identity);
139
140 if (0 == GNUNET_memcmp(&(message.body.peer.peer), &(identity)))
141 {
142 if (tunnel->contact_id)
143 {
144 if (0 != GNUNET_memcmp(tunnel->contact_id, &(message.header.sender_id)))
145 result = GNUNET_SYSERR;
146 }
147 else
148 {
149 tunnel->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
150
151 GNUNET_memcpy(tunnel->contact_id, &(message.header.sender_id), sizeof(struct GNUNET_ShortHashCode));
152 }
153 }
154 }
155
156 return (result == GNUNET_YES ? GNUNET_OK : GNUNET_NO);
157}
158
159extern void
160callback_room_recv (struct GNUNET_MESSENGER_SrvRoom *room, void *cls, struct GNUNET_MESSENGER_Message *message,
161 const struct GNUNET_HashCode *hash);
162
163void
164handle_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header)
165{
166 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
167
168 const uint16_t length = ntohs (header->size) - sizeof(*header);
169 const char *buffer = (const char*) &header[1];
170
171 struct GNUNET_MESSENGER_Message message;
172 struct GNUNET_HashCode hash;
173
174 decode_message (&message, length, buffer);
175 hash_message (length, buffer, &hash);
176
177 if (tunnel)
178 {
179 if (!tunnel->last_message)
180 tunnel->last_message = GNUNET_new(struct GNUNET_HashCode);
181
182 GNUNET_memcpy(tunnel->last_message, &hash, sizeof(struct GNUNET_HashCode));
183
184 callback_room_recv (tunnel->room, cls, copy_message (&message), &hash);
185 }
186
187 GNUNET_CADET_receive_done (tunnel->channel);
188}
189
190int
191connect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
192{
193 GNUNET_assert(tunnel);
194
195 if (tunnel->channel)
196 return GNUNET_NO;
197
198 const struct GNUNET_PeerIdentity *door = GNUNET_PEER_resolve2 (tunnel->peer);
199
200 struct GNUNET_CADET_Handle *cadet = get_room_cadet (tunnel->room);
201 struct GNUNET_HashCode *key = get_room_key (tunnel->room);
202
203 struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size(tunnel_message, GNUNET_MESSAGE_TYPE_CADET_CLI,
204 struct GNUNET_MessageHeader, NULL),
205 GNUNET_MQ_handler_end() };
206
207 tunnel->channel = GNUNET_CADET_channel_create (cadet, tunnel, door, key, NULL, callback_tunnel_disconnect, handlers);
208
209 return GNUNET_YES;
210}
211
212void
213disconnect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
214{
215 if (tunnel->channel)
216 {
217 delayed_disconnect_channel (tunnel->channel);
218
219 tunnel->channel = NULL;
220 }
221}
222
223int
224is_tunnel_connected (const struct GNUNET_MESSENGER_SrvTunnel *tunnel)
225{
226 return (tunnel->channel ? GNUNET_YES : GNUNET_NO);
227}
228
229struct GNUNET_MESSENGER_MessageSent
230{
231 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
232 struct GNUNET_HashCode hash;
233};
234
235extern void
236callback_room_sent (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle, void *cls,
237 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
238
239static void
240callback_tunnel_sent (void *cls)
241{
242 struct GNUNET_MESSENGER_MessageSent *sent = cls;
243
244 if (sent->tunnel)
245 {
246 if (!sent->tunnel->last_message)
247 sent->tunnel->last_message = GNUNET_new(struct GNUNET_HashCode);
248
249 GNUNET_memcpy(sent->tunnel->last_message, &(sent->hash), sizeof(struct GNUNET_HashCode));
250 }
251
252 GNUNET_free(sent);
253}
254
255void
256send_tunnel_envelope (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MQ_Envelope *env,
257 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
258{
259 struct GNUNET_MQ_Handle *mq = GNUNET_CADET_get_mq (tunnel->channel);
260
261 struct GNUNET_MESSENGER_MessageSent *sent = GNUNET_new(struct GNUNET_MESSENGER_MessageSent);
262
263 GNUNET_memcpy(&(sent->hash), hash, sizeof(struct GNUNET_HashCode));
264
265 sent->tunnel = tunnel;
266
267 GNUNET_MQ_notify_sent (env, callback_tunnel_sent, sent);
268 GNUNET_MQ_send (mq, env);
269
270 callback_room_sent (tunnel->room, (struct GNUNET_MESSENGER_SrvHandle*) handle, tunnel, message, hash);
271}
272
273void
274send_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MESSENGER_Message *message,
275 struct GNUNET_HashCode *hash)
276{
277 struct GNUNET_MQ_Envelope *env = pack_room_message (tunnel->room, (struct GNUNET_MESSENGER_SrvHandle*) handle,
278 message, hash,
279 GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
280
281 if (env)
282 send_tunnel_envelope (tunnel, handle, env, copy_message (message), hash);
283}
284
285void
286forward_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, const struct GNUNET_MESSENGER_Message *message,
287 const struct GNUNET_HashCode *hash)
288{
289 struct GNUNET_MESSENGER_Message *clone = copy_message (message);
290 struct GNUNET_MQ_Envelope *env = pack_message (clone, NULL, NULL, GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
291
292 if (env)
293 send_tunnel_envelope (tunnel, NULL, env, clone, hash);
294}
295
296const struct GNUNET_HashCode*
297get_tunnel_peer_message (const struct GNUNET_MESSENGER_SrvTunnel *tunnel)
298{
299 return tunnel->peer_message;
300}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_tunnel.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_TUNNEL_H
27#define GNUNET_SERVICE_MESSENGER_TUNNEL_H
28
29#include "platform.h"
30#include "gnunet_cadet_service.h"
31#include "gnunet_peer_lib.h"
32#include "gnunet_crypto_lib.h"
33
34#include "gnunet-service-messenger_room.h"
35
36struct GNUNET_MESSENGER_SrvTunnel
37{
38 struct GNUNET_MESSENGER_SrvRoom *room;
39 struct GNUNET_CADET_Channel *channel;
40
41 GNUNET_PEER_Id peer;
42 struct GNUNET_ShortHashCode *contact_id;
43
44 struct GNUNET_HashCode *peer_message;
45 struct GNUNET_HashCode *last_message;
46};
47
48/**
49 * Creates and allocates a tunnel of a <i>room</i> to a specific peer identity.
50 *
51 * @param room Room
52 * @param door Peer identity
53 * @return New tunnel
54 */
55struct GNUNET_MESSENGER_SrvTunnel*
56create_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *door);
57
58/**
59 * Destroys a <i>tunnel</i> and frees its memory fully.
60 *
61 * @param tunnel
62 */
63void
64destroy_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
65
66/**
67 * Binds a CADET <i>channel</i> to a <i>tunnel</i> on returns GNUNET_YES only if
68 * the bounds channel was replaced successfully, otherwise GNUNET_NO gets returned.
69 *
70 * @param tunnel Tunnel
71 * @param channel CADET channel
72 * @return GNUNET_YES on success, otherwise GNUNET_NO
73 */
74int
75bind_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel, struct GNUNET_CADET_Channel *channel);
76
77/**
78 * Tries to connect a <i>tunnel</i> by creating a new CADET channel and binding it.
79 * The function returns GNUNET_YES on success, otherwise GNUNET_NO.
80 *
81 * @param tunnel Tunnel
82 * @return GNUNET_YES on success, otherwise GNUNET_NO
83 */
84int
85connect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
86
87/**
88 * Disconnects and unbinds a channel from a <i>tunnel</i>. The actual disconnection
89 * will be asynchronous.
90 *
91 * @param tunnel Tunnel
92 */
93void
94disconnect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
95
96/**
97 * Returns the status of a currently bound channel of a <i>tunnel</i>.
98 *
99 * @param tunnel Tunnel
100 * @return GNUNET_YES or GNUNET_NO
101 */
102int
103is_tunnel_connected (const struct GNUNET_MESSENGER_SrvTunnel *tunnel);
104
105/**
106 * Sends an envelope containing a <i>message</i> with a given <i>hash</i> through
107 * a <i>tunnel</i> by a given <i>handle</i>.
108 *
109 * @param tunnel Tunnel
110 * @param handle Handle
111 * @param env Envelope
112 * @param message Message
113 * @param hash Hash of message
114 */
115void
116send_tunnel_envelope (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MQ_Envelope *env,
117 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
118
119/**
120 * Sends a <i>message</i> by packing it automatically into an envelope and passing it
121 * through the <i>tunnel</i>. The used <i>handle</i> will sign the message and
122 * the <i>hash</i> will be calculated and stored.
123 *
124 * @param tunnel Tunnel
125 * @param handle Handle
126 * @param[out] message Message
127 * @param[out] hash Hash of message
128 */
129void
130send_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, void *handle, struct GNUNET_MESSENGER_Message *message,
131 struct GNUNET_HashCode *hash);
132
133/**
134 * Forwards a given <i>message</i> with a known <i>hash</i> through a <i>tunnel</i>.
135 *
136 * @param tunnel Tunnel
137 * @param message Message
138 * @param hash Hash of message
139 */
140void
141forward_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, const struct GNUNET_MESSENGER_Message *message,
142 const struct GNUNET_HashCode *hash);
143
144/**
145 * Returns the hash of the latest peer message published through a given <i>tunnel</i>
146 * and matching the tunnels peer identity. If no peer message has been linked to the tunnel
147 * yet, NULL gets returned.
148 *
149 * @param tunnel Tunnel
150 * @return Hash of peer message or NULL
151 */
152const struct GNUNET_HashCode*
153get_tunnel_peer_message (const struct GNUNET_MESSENGER_SrvTunnel *tunnel);
154
155#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_util.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_util.h"
27
28static void
29callback_close_channel (void *cls)
30{
31 struct GNUNET_CADET_Channel *channel = cls;
32
33 if (channel)
34 GNUNET_CADET_channel_destroy (channel);
35}
36
37void
38delayed_disconnect_channel (struct GNUNET_CADET_Channel *channel)
39{
40 GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_get_zero_ (), GNUNET_SCHEDULER_PRIORITY_URGENT,
41 callback_close_channel, channel);
42}
43
44int
45generate_free_member_id (struct GNUNET_ShortHashCode *id, const struct GNUNET_CONTAINER_MultiShortmap *members)
46{
47 size_t counter = 1 + (members ? GNUNET_CONTAINER_multishortmap_size (members) : 0);
48
49 do
50 {
51 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, id, sizeof(struct GNUNET_ShortHashCode));
52
53 if ((members) && (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains (members, id)))
54 counter--;
55 else
56 break;
57 }
58 while (counter > 0);
59
60 if (counter)
61 return GNUNET_YES;
62
63 return GNUNET_NO;
64}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_util.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_UTIL_H
27#define GNUNET_SERVICE_MESSENGER_UTIL_H
28
29#include "platform.h"
30#include "gnunet_cadet_service.h"
31#include "gnunet_container_lib.h"
32#include "gnunet_crypto_lib.h"
33
34/**
35 * Starts an urgent task to close a CADET channel asynchronously.
36 *
37 * @param channel Channel
38 */
39void
40delayed_disconnect_channel (struct GNUNET_CADET_Channel *channel);
41
42/**
43 * Tries to generate an unused member id and store it into the <i>id</i> parameter. A map containing all currently
44 * used member ids is used to check against.
45 *
46 * @param[out] id New member id
47 * @param members Map of member ids
48 * @return GNUNET_YES on success, GNUNET_NO on failure
49 */
50int
51generate_free_member_id (struct GNUNET_ShortHashCode *id, const struct GNUNET_CONTAINER_MultiShortmap *members);
52
53#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 @@
1[messenger]
2START_ON_DEMAND = YES
3PORT = 2097
4HOSTNAME = localhost
5BINARY = gnunet-service-messenger
6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-messenger.sock
9UNIX_MATCH_UID = NO
10UNIX_MATCH_GID = YES
11
12# Directory to store messages and contacts
13MESSENGER_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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "gnunet_messenger_service.h"
27
28#include "gnunet-service-messenger.h"
29
30#include "messenger_api_handle.h"
31#include "messenger_api_message.h"
32
33const char*
34GNUNET_MESSENGER_name_of_kind (enum GNUNET_MESSENGER_MessageKind kind)
35{
36 switch (kind)
37 {
38 case GNUNET_MESSENGER_KIND_INFO:
39 return "INFO";
40 case GNUNET_MESSENGER_KIND_JOIN:
41 return "JOIN";
42 case GNUNET_MESSENGER_KIND_LEAVE:
43 return "LEAVE";
44 case GNUNET_MESSENGER_KIND_NAME:
45 return "NAME";
46 case GNUNET_MESSENGER_KIND_KEY:
47 return "KEY";
48 case GNUNET_MESSENGER_KIND_PEER:
49 return "PEER";
50 case GNUNET_MESSENGER_KIND_ID:
51 return "ID";
52 case GNUNET_MESSENGER_KIND_MISS:
53 return "MISS";
54 case GNUNET_MESSENGER_KIND_MERGE:
55 return "MERGE";
56 case GNUNET_MESSENGER_KIND_REQUEST:
57 return "REQUEST";
58 case GNUNET_MESSENGER_KIND_INVITE:
59 return "INVITE";
60 case GNUNET_MESSENGER_KIND_TEXT:
61 return "TEXT";
62 case GNUNET_MESSENGER_KIND_FILE:
63 return "FILE";
64 default:
65 return "UNKNOWN";
66 }
67}
68
69static int
70check_get_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
71{
72 GNUNET_MQ_check_zero_termination(msg);
73 return GNUNET_OK;
74}
75
76static void
77handle_get_name (void *cls, const struct GNUNET_MESSENGER_NameMessage *msg)
78{
79 struct GNUNET_MESSENGER_Handle *handle = cls;
80
81 const char *name = ((const char*) msg) + sizeof(*msg);
82
83 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Set name of handle: %s\n", name);
84
85 set_handle_name (handle, strlen(name) > 0? name : NULL);
86}
87
88static void
89handle_get_key (void *cls, const struct GNUNET_MESSENGER_KeyMessage *msg)
90{
91 struct GNUNET_MESSENGER_Handle *handle = cls;
92
93 const struct GNUNET_IDENTITY_PublicKey *pubkey = &(msg->pubkey);
94
95 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Set key of handle: %s\n", GNUNET_IDENTITY_public_key_to_string (pubkey));
96
97 set_handle_key (handle, pubkey);
98
99 if (handle->identity_callback)
100 handle->identity_callback (handle->identity_cls, handle);
101}
102
103static void
104handle_member_id (void *cls, const struct GNUNET_MESSENGER_MemberMessage *msg)
105{
106 struct GNUNET_MESSENGER_Handle *handle = cls;
107
108 const struct GNUNET_HashCode *key = &(msg->key);
109 const struct GNUNET_ShortHashCode *id = &(msg->id);
110
111 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Set id of handle in room: %s\n", GNUNET_h2s (key));
112
113 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
114
115 if (room)
116 {
117 if (!room->contact_id)
118 room->contact_id = GNUNET_new(struct GNUNET_ShortHashCode);
119
120 GNUNET_memcpy(room->contact_id, id, sizeof(*id));
121 }
122}
123
124static void
125handle_room_open (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
126{
127 struct GNUNET_MESSENGER_Handle *handle = cls;
128
129 const struct GNUNET_HashCode *key = &(msg->key);
130
131 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Opened room: %s\n", GNUNET_h2s (key));
132
133 open_handle_room (handle, key);
134}
135
136static void
137handle_room_entry (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
138{
139 struct GNUNET_MESSENGER_Handle *handle = cls;
140
141 const struct GNUNET_PeerIdentity *door = &(msg->door);
142 const struct GNUNET_HashCode *key = &(msg->key);
143
144 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Entered room: %s\n", GNUNET_h2s (key));
145
146 entry_handle_room_at (handle, door, key);
147}
148
149static void
150handle_room_close (void *cls, const struct GNUNET_MESSENGER_RoomMessage *msg)
151{
152 struct GNUNET_MESSENGER_Handle *handle = cls;
153
154 const struct GNUNET_HashCode *key = &(msg->key);
155
156 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Closed room: %s\n", GNUNET_h2s (key));
157
158 close_handle_room (handle, key);
159}
160
161static int
162check_recv_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg)
163{
164 const uint16_t full_length = ntohs (msg->header.size) - sizeof(msg->header);
165
166 if (full_length < sizeof(msg->hash))
167 return GNUNET_NO;
168
169 const uint16_t length = full_length - sizeof(msg->hash);
170 const char *buffer = ((const char*) msg) + sizeof(*msg);
171
172 struct GNUNET_MESSENGER_Message message;
173
174 if (length < sizeof(message.header))
175 return GNUNET_NO;
176
177 if (GNUNET_YES != decode_message (&message, length, buffer))
178 return GNUNET_NO;
179
180 return GNUNET_OK;
181}
182
183static void
184handle_recv_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg)
185{
186 struct GNUNET_MESSENGER_Handle *handle = cls;
187
188 const struct GNUNET_HashCode *key = &(msg->key);
189 const struct GNUNET_HashCode *hash = &(msg->hash);
190
191 const char *buffer = ((const char*) msg) + sizeof(*msg);
192
193 const uint16_t length = ntohs (msg->header.size) - sizeof(*msg);
194
195 struct GNUNET_MESSENGER_Message message;
196 decode_message (&message, length, buffer);
197
198 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Receiving message: %s\n", GNUNET_MESSENGER_name_of_kind (message.header.kind));
199
200 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
201
202 if (room)
203 {
204 handle_room_message (room, &message, hash);
205
206 if (handle->msg_callback)
207 handle->msg_callback (handle->msg_cls, room, &message, hash);
208 }
209 else
210 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "MESSENGER ERROR: Room not found\n");
211}
212
213static void
214reconnect (struct GNUNET_MESSENGER_Handle *handle);
215
216static void
217send_open_room (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Room *room)
218{
219 struct GNUNET_MESSENGER_RoomMessage *msg;
220 struct GNUNET_MQ_Envelope *env;
221
222 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN);
223 GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
224 GNUNET_MQ_send (handle->mq, env);
225}
226
227static void
228send_entry_room (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Room *room,
229 const struct GNUNET_PeerIdentity *door)
230{
231 struct GNUNET_MESSENGER_RoomMessage *msg;
232 struct GNUNET_MQ_Envelope *env;
233
234 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY);
235 GNUNET_memcpy(&(msg->door), door, sizeof(*door));
236 GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
237 GNUNET_MQ_send (handle->mq, env);
238}
239
240static void
241send_close_room (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Room *room)
242{
243 struct GNUNET_MESSENGER_RoomMessage *msg;
244 struct GNUNET_MQ_Envelope *env;
245
246 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE);
247 GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
248 GNUNET_MQ_send (handle->mq, env);
249}
250
251static int
252iterate_reset_room (void *cls, const struct GNUNET_HashCode *key, void *value)
253{
254 struct GNUNET_MESSENGER_Handle *handle = cls;
255 struct GNUNET_MESSENGER_Room *room = value;
256
257 if (GNUNET_YES == room->opened)
258 send_open_room (handle, room);
259
260 struct GNUNET_MESSENGER_ListTunnel *entry = room->entries.head;
261
262 struct GNUNET_PeerIdentity door;
263
264 while (entry)
265 {
266 GNUNET_PEER_resolve (entry->peer, &door);
267
268 send_entry_room (handle, room, &door);
269
270 entry = entry->next;
271 }
272
273 return GNUNET_YES;
274}
275
276static void
277callback_reconnect (void *cls)
278{
279 struct GNUNET_MESSENGER_Handle *handle = cls;
280
281 handle->reconnect_task = NULL;
282 handle->reconnect_time = GNUNET_TIME_STD_BACKOFF(handle->reconnect_time)
283 ;
284
285 reconnect (handle);
286
287 GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_reset_room, handle);
288}
289
290static int
291iterate_close_room (void *cls, const struct GNUNET_HashCode *key, void *value)
292{
293 struct GNUNET_MESSENGER_Handle *handle = cls;
294 struct GNUNET_MESSENGER_Room *room = value;
295
296 send_close_room (handle, room);
297
298 return GNUNET_YES;
299}
300
301static void
302callback_mq_error (void *cls, enum GNUNET_MQ_Error error)
303{
304 struct GNUNET_MESSENGER_Handle *handle = cls;
305
306 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %u\n", error);
307
308 GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_close_room, handle);
309
310 if (handle->mq)
311 {
312 GNUNET_MQ_destroy (handle->mq);
313 handle->mq = NULL;
314 }
315
316 handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->reconnect_time, &callback_reconnect, handle);
317}
318
319static void
320reconnect (struct GNUNET_MESSENGER_Handle *handle)
321{
322 const struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size(
323 get_name, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_NAME, struct GNUNET_MESSENGER_NameMessage, handle),
324 GNUNET_MQ_hd_fixed_size(
325 get_key, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_KEY,
326 struct GNUNET_MESSENGER_KeyMessage, handle),
327 GNUNET_MQ_hd_fixed_size(
328 member_id,
329 GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID,
330 struct GNUNET_MESSENGER_MemberMessage, handle),
331 GNUNET_MQ_hd_fixed_size(room_open,
332 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN,
333 struct GNUNET_MESSENGER_RoomMessage,
334 handle),
335 GNUNET_MQ_hd_fixed_size(room_entry,
336 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY,
337 struct GNUNET_MESSENGER_RoomMessage,
338 handle),
339 GNUNET_MQ_hd_fixed_size(room_close,
340 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE,
341 struct GNUNET_MESSENGER_RoomMessage,
342 handle),
343 GNUNET_MQ_hd_var_size(
344 recv_message,
345 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE,
346 struct GNUNET_MESSENGER_RecvMessage, handle),
347 GNUNET_MQ_handler_end() };
348
349 handle->mq = GNUNET_CLIENT_connect (handle->cfg,
350 GNUNET_MESSENGER_SERVICE_NAME,
351 handlers, &callback_mq_error, handle);
352}
353
354struct GNUNET_MESSENGER_Handle*
355GNUNET_MESSENGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name,
356 GNUNET_MESSENGER_IdentityCallback identity_callback, void *identity_cls,
357 GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls)
358{
359 struct GNUNET_MESSENGER_Handle *handle = create_handle (cfg, identity_callback, identity_cls, msg_callback, msg_cls);
360
361 reconnect (handle);
362
363 if (handle->mq)
364 {
365 const uint16_t name_len = name ? strlen (name) : 0;
366
367 struct GNUNET_MESSENGER_CreateMessage *msg;
368 struct GNUNET_MQ_Envelope *env;
369
370 env = GNUNET_MQ_msg_extra(msg, name_len + 1, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE);
371
372 char *extra = ((char*) msg) + sizeof(*msg);
373
374 if (name_len)
375 GNUNET_memcpy(extra, name, name_len);
376
377 extra[name_len] = '\0';
378
379 GNUNET_MQ_send (handle->mq, env);
380 return handle;
381 }
382 else
383 {
384 destroy_handle (handle);
385 return NULL;
386 }
387}
388
389int
390GNUNET_MESSENGER_update (struct GNUNET_MESSENGER_Handle *handle)
391{
392 if ((!handle) || (!get_handle_name(handle)))
393 return GNUNET_SYSERR;
394
395 struct GNUNET_MESSENGER_UpdateMessage *msg;
396 struct GNUNET_MQ_Envelope *env;
397
398 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_UPDATE);
399 GNUNET_MQ_send (handle->mq, env);
400 return GNUNET_OK;
401}
402
403void
404GNUNET_MESSENGER_disconnect (struct GNUNET_MESSENGER_Handle *handle)
405{
406 if (!handle)
407 return;
408
409 struct GNUNET_MESSENGER_DestroyMessage *msg;
410 struct GNUNET_MQ_Envelope *env;
411
412 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY);
413 GNUNET_MQ_send (handle->mq, env);
414
415 destroy_handle (handle);
416}
417
418const char*
419GNUNET_MESSENGER_get_name (const struct GNUNET_MESSENGER_Handle *handle)
420{
421 if (!handle)
422 return NULL;
423
424 return get_handle_name (handle);
425}
426
427int
428GNUNET_MESSENGER_set_name (struct GNUNET_MESSENGER_Handle *handle, const char *name)
429{
430 if (!handle)
431 return GNUNET_SYSERR;
432
433 const uint16_t name_len = name ? strlen (name) : 0;
434
435 struct GNUNET_MESSENGER_NameMessage *msg;
436 struct GNUNET_MQ_Envelope *env;
437
438 env = GNUNET_MQ_msg_extra(msg, name_len + 1, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_SET_NAME);
439
440 char *extra = ((char*) msg) + sizeof(*msg);
441
442 if (name_len)
443 GNUNET_memcpy(extra, name, name_len);
444
445 extra[name_len] = '\0';
446
447 GNUNET_MQ_send (handle->mq, env);
448 return GNUNET_YES;
449}
450
451const struct GNUNET_IDENTITY_PublicKey*
452GNUNET_MESSENGER_get_key (const struct GNUNET_MESSENGER_Handle *handle)
453{
454 if (!handle)
455 return NULL;
456
457 return get_handle_key (handle);
458}
459
460struct GNUNET_MESSENGER_Room*
461GNUNET_MESSENGER_open_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
462{
463 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
464
465 if (!room)
466 {
467 room = create_room (handle, key);
468
469 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->rooms, key, room,
470 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
471 {
472 destroy_room (room);
473 return NULL;
474 }
475 }
476
477 send_open_room (handle, room);
478 return room;
479}
480
481struct GNUNET_MESSENGER_Room*
482GNUNET_MESSENGER_entry_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
483 const struct GNUNET_HashCode *key)
484{
485 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
486
487 if (!room)
488 {
489 room = create_room (handle, key);
490
491 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->rooms, key, room,
492 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
493 {
494 destroy_room (room);
495 return NULL;
496 }
497 }
498
499 send_entry_room (handle, room, door);
500 return room;
501}
502
503void
504GNUNET_MESSENGER_close_room (struct GNUNET_MESSENGER_Room *room)
505{
506 send_close_room (room->handle, room);
507}
508
509struct GNUNET_MESSENGER_Contact*
510GNUNET_MESSENGER_get_member (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_ShortHashCode *id)
511{
512 return GNUNET_CONTAINER_multishortmap_get (room->members, id);
513}
514
515const char*
516GNUNET_MESSENGER_contact_get_name (const struct GNUNET_MESSENGER_Contact *contact)
517{
518 if (!contact)
519 return NULL;
520
521 return get_contact_name (contact);
522}
523
524const struct GNUNET_IDENTITY_PublicKey*
525GNUNET_MESSENGER_contact_get_key (const struct GNUNET_MESSENGER_Contact *contact)
526{
527 if (!contact)
528 return NULL;
529
530 return get_contact_key (contact);
531}
532
533void
534GNUNET_MESSENGER_send_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message)
535{
536 const uint16_t length = get_message_size (message);
537
538 struct GNUNET_MESSENGER_SendMessage *msg;
539 struct GNUNET_MQ_Envelope *env;
540
541 env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE);
542
543 GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
544
545 char *buffer = ((char*) msg) + sizeof(*msg);
546 encode_message (message, length, buffer);
547
548 GNUNET_MQ_send (room->handle->mq, env);
549}
550
551const struct GNUNET_MESSENGER_Message*
552GNUNET_MESSENGER_get_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash)
553{
554 const struct GNUNET_MESSENGER_Message *message = get_room_message (room, hash);
555
556 if (!message)
557 {
558 struct GNUNET_MESSENGER_RecvMessage *msg;
559 struct GNUNET_MQ_Envelope *env;
560
561 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE);
562 GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
563 GNUNET_memcpy(&(msg->hash), hash, sizeof(*hash));
564 GNUNET_MQ_send (room->handle->mq, env);
565 }
566
567 return message;
568}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_contact.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_contact.h"
27
28struct GNUNET_MESSENGER_Contact*
29create_contact (const struct GNUNET_IDENTITY_PublicKey *key)
30{
31 struct GNUNET_MESSENGER_Contact *contact = GNUNET_new(struct GNUNET_MESSENGER_Contact);
32
33 contact->name = NULL;
34
35 GNUNET_memcpy(&(contact->public_key), key, sizeof(contact->public_key));
36
37 return contact;
38}
39
40void
41destroy_contact (struct GNUNET_MESSENGER_Contact *contact)
42{
43 if (contact->name)
44 GNUNET_free(contact->name);
45
46 GNUNET_free(contact);
47}
48
49const char*
50get_contact_name (const struct GNUNET_MESSENGER_Contact *contact)
51{
52 return contact->name;
53}
54
55void
56set_contact_name (struct GNUNET_MESSENGER_Contact *contact, const char *name)
57{
58 if (contact->name)
59 GNUNET_free(contact->name);
60
61 contact->name = name? GNUNET_strdup(name) : NULL;
62}
63
64const struct GNUNET_IDENTITY_PublicKey*
65get_contact_key (const struct GNUNET_MESSENGER_Contact *contact)
66{
67 return &(contact->public_key);
68}
69
70const struct GNUNET_HashCode*
71get_contact_id_from_key (const struct GNUNET_MESSENGER_Contact *contact)
72{
73 static struct GNUNET_HashCode id;
74
75 GNUNET_CRYPTO_hash (&(contact->public_key), sizeof(contact->public_key), &id);
76
77 return &id;
78}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_contact.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_CONTACT_H
27#define GNUNET_MESSENGER_API_CONTACT_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_identity_service.h"
32
33struct GNUNET_MESSENGER_Contact
34{
35 char *name;
36
37 struct GNUNET_IDENTITY_PublicKey public_key;
38};
39
40/**
41 * Creates and allocates a new contact with a given public <i>key</i> from an EGO.
42 *
43 * @param key Public key
44 * @return New contact
45 */
46struct GNUNET_MESSENGER_Contact*
47create_contact (const struct GNUNET_IDENTITY_PublicKey *key);
48
49/**
50 * Destroys a contact and frees its memory fully.
51 *
52 * @param contact Contact
53 */
54void
55destroy_contact (struct GNUNET_MESSENGER_Contact *contact);
56
57/**
58 * Returns the current name of a given <i>contact</i> or NULL if no valid name was assigned yet.
59 *
60 * @param contact Contact
61 * @return Name of the contact or NULL
62 */
63const char*
64get_contact_name (const struct GNUNET_MESSENGER_Contact *contact);
65
66/**
67 * Changes the current name of a given <i>contact</i> by copying it from the parameter <i>name</i>.
68 *
69 * @param contact Contact
70 * @param name Valid name (may not be NULL!)
71 */
72void
73set_contact_name (struct GNUNET_MESSENGER_Contact *contact, const char *name);
74
75/**
76 * Returns the public key of a given <i>contact</i>.
77 *
78 * @param contact Contact
79 * @return Public key of the contact
80 */
81const struct GNUNET_IDENTITY_PublicKey*
82get_contact_key (const struct GNUNET_MESSENGER_Contact *contact);
83
84/**
85 * Returns the resulting hashcode of the public key from a given <i>contact</i>.
86 *
87 * @param contact Contact
88 * @return Hash of the contacts public key
89 */
90const struct GNUNET_HashCode*
91get_contact_id_from_key (const struct GNUNET_MESSENGER_Contact *contact);
92
93#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_ego.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_EGO_H
27#define GNUNET_MESSENGER_API_EGO_H
28
29#include "platform.h"
30#include "gnunet_identity_service.h"
31
32struct GNUNET_MESSENGER_Ego
33{
34 struct GNUNET_IDENTITY_PrivateKey priv;
35 struct GNUNET_IDENTITY_PublicKey pub;
36};
37
38#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_handle.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_handle.h"
27
28struct GNUNET_MESSENGER_Handle*
29create_handle (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_MESSENGER_IdentityCallback identity_callback,
30 void *identity_cls, GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls)
31{
32 struct GNUNET_MESSENGER_Handle *handle = GNUNET_new(struct GNUNET_MESSENGER_Handle);
33
34 handle->cfg = cfg;
35 handle->mq = NULL;
36
37 handle->identity_callback = identity_callback;
38 handle->identity_cls = identity_cls;
39
40 handle->msg_callback = msg_callback;
41 handle->msg_cls = msg_cls;
42
43 handle->name = NULL;
44 handle->pubkey = NULL;
45
46 handle->reconnect_time = GNUNET_TIME_relative_get_zero_ ();
47 handle->reconnect_task = NULL;
48
49 handle->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
50 handle->contacts = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
51
52 return handle;
53}
54
55static int
56iterate_destroy_room (void *cls, const struct GNUNET_HashCode *key, void *value)
57{
58 struct GNUNET_MESSENGER_Room *room = value;
59
60 destroy_room (room);
61
62 return GNUNET_YES;
63}
64
65static int
66iterate_destroy_contact (void *cls, const struct GNUNET_HashCode *key, void *value)
67{
68 struct GNUNET_MESSENGER_Contact *contact = value;
69
70 destroy_contact (contact);
71
72 return GNUNET_YES;
73}
74
75void
76destroy_handle (struct GNUNET_MESSENGER_Handle *handle)
77{
78 if (handle->reconnect_task)
79 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
80
81 if (handle->mq)
82 GNUNET_MQ_destroy (handle->mq);
83
84 if (handle->name)
85 GNUNET_free(handle->name);
86
87 if (handle->pubkey)
88 GNUNET_free(handle->pubkey);
89
90 if (handle->rooms)
91 {
92 GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_destroy_room, NULL);
93
94 GNUNET_CONTAINER_multihashmap_destroy (handle->rooms);
95 }
96
97 if (handle->contacts)
98 {
99 GNUNET_CONTAINER_multihashmap_iterate (handle->contacts, iterate_destroy_contact, NULL);
100
101 GNUNET_CONTAINER_multihashmap_destroy (handle->contacts);
102 }
103
104 GNUNET_free(handle->name);
105}
106
107void
108set_handle_name (struct GNUNET_MESSENGER_Handle *handle, const char *name)
109{
110 if (handle->name)
111 GNUNET_free(handle->name);
112
113 handle->name = name? GNUNET_strdup(name) : NULL;
114}
115
116const char*
117get_handle_name (const struct GNUNET_MESSENGER_Handle *handle)
118{
119 return handle->name;
120}
121
122void
123set_handle_key (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_IDENTITY_PublicKey *pubkey)
124{
125 if (!handle->pubkey)
126 handle->pubkey = GNUNET_new(struct GNUNET_IDENTITY_PublicKey);
127
128 GNUNET_memcpy(handle->pubkey, pubkey, sizeof(*pubkey));
129}
130
131const struct GNUNET_IDENTITY_PublicKey*
132get_handle_key (const struct GNUNET_MESSENGER_Handle *handle)
133{
134 if (!handle->pubkey)
135 {
136 struct GNUNET_IDENTITY_Ego *anonymous = GNUNET_IDENTITY_ego_get_anonymous ();
137 static struct GNUNET_IDENTITY_PublicKey pubkey;
138
139 GNUNET_IDENTITY_ego_get_public_key (anonymous, &pubkey);
140
141 return &pubkey;
142 }
143
144 return handle->pubkey;
145}
146
147struct GNUNET_MESSENGER_Contact*
148get_handle_contact_by_pubkey (const struct GNUNET_MESSENGER_Handle *handle,
149 const struct GNUNET_IDENTITY_PublicKey *pubkey)
150{
151 struct GNUNET_HashCode hash;
152
153 GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
154
155 struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multihashmap_get (handle->contacts, &hash);
156
157 if (contact)
158 return contact;
159
160 contact = create_contact (pubkey);
161
162 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (handle->contacts, &hash, contact,
163 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
164 return contact;
165
166 destroy_contact (contact);
167 return NULL;
168}
169
170void
171swap_handle_contact_by_pubkey (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Contact *contact,
172 const struct GNUNET_IDENTITY_PublicKey *pubkey)
173{
174 const struct GNUNET_HashCode *hash = get_contact_id_from_key (contact);
175
176 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->contacts, hash, contact))
177 {
178 GNUNET_memcpy(&(contact->public_key), pubkey, sizeof(*pubkey));
179
180 hash = get_contact_id_from_key (contact);
181
182 GNUNET_CONTAINER_multihashmap_put (handle->contacts, hash, contact,
183 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
184 }
185}
186
187void
188open_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
189{
190 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
191
192 if (room)
193 room->opened = GNUNET_YES;
194}
195
196void
197entry_handle_room_at (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
198 const struct GNUNET_HashCode *key)
199{
200 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
201
202 if (room)
203 add_to_list_tunnels (&(room->entries), door);
204}
205
206void
207close_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
208{
209 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
210
211 if ((room) && (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->rooms, key, room)))
212 destroy_room (room);
213}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_handle.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_HANDLE_H
27#define GNUNET_MESSENGER_API_HANDLE_H
28
29#include "platform.h"
30#include "gnunet_cadet_service.h"
31#include "gnunet_container_lib.h"
32#include "gnunet_crypto_lib.h"
33#include "gnunet_identity_service.h"
34#include "gnunet_peer_lib.h"
35
36#include "gnunet_messenger_service.h"
37
38#include "messenger_api_contact.h"
39#include "messenger_api_room.h"
40
41struct GNUNET_MESSENGER_Handle
42{
43 const struct GNUNET_CONFIGURATION_Handle *cfg;
44
45 struct GNUNET_MQ_Handle *mq;
46
47 GNUNET_MESSENGER_IdentityCallback identity_callback;
48 void *identity_cls;
49
50 GNUNET_MESSENGER_MessageCallback msg_callback;
51 void *msg_cls;
52
53 char *name;
54 struct GNUNET_IDENTITY_PublicKey *pubkey;
55
56 struct GNUNET_TIME_Relative reconnect_time;
57 struct GNUNET_SCHEDULER_Task *reconnect_task;
58
59 struct GNUNET_CONTAINER_MultiHashMap *rooms;
60 struct GNUNET_CONTAINER_MultiHashMap *contacts;
61};
62
63/**
64 * Creates and allocates a new handle using a given configuration and a custom message callback
65 * with a given closure for the client API.
66 *
67 * @param cfg Configuration
68 * @param msg_callback Message callback
69 * @param msg_cls Closure
70 * @return New handle
71 */
72struct GNUNET_MESSENGER_Handle*
73create_handle (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_MESSENGER_IdentityCallback identity_callback,
74 void *identity_cls, GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls);
75
76/**
77 * Destroys a <i>handle</i> and frees its memory fully from the client API.
78 *
79 * @param handle Handle
80 */
81void
82destroy_handle (struct GNUNET_MESSENGER_Handle *handle);
83
84/**
85 * Sets the name of a <i>handle</i> to a specific <i>name</i>.
86 *
87 * @param handle Handle
88 * @param name New name
89 */
90void
91set_handle_name (struct GNUNET_MESSENGER_Handle *handle, const char *name);
92
93/**
94 * Returns the current name of a given <i>handle</i> or NULL if no valid name was assigned yet.
95 *
96 * @param handle Handle
97 * @return Name of the handle or NULL
98 */
99const char*
100get_handle_name (const struct GNUNET_MESSENGER_Handle *handle);
101
102/**
103 * Sets the public key of a given <i>handle</i> to a specific public key.
104 *
105 * @param handle Handle
106 * @param pubkey Public key
107 */
108void
109set_handle_key (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_IDENTITY_PublicKey *pubkey);
110
111/**
112 * Returns the public key of a given <i>handle</i>.
113 *
114 * @param handle Handle
115 * @return Public key of the handle
116 */
117const struct GNUNET_IDENTITY_PublicKey*
118get_handle_key (const struct GNUNET_MESSENGER_Handle *handle);
119
120/**
121 * Returns a contact known to a <i>handle</i> identified by a given public key. If not matching
122 * contact is found, NULL gets returned.
123 *
124 * @param handle Handle
125 * @param pubkey Public key of EGO
126 * @return Contact or NULL
127 */
128struct GNUNET_MESSENGER_Contact*
129get_handle_contact_by_pubkey (const struct GNUNET_MESSENGER_Handle *handle,
130 const struct GNUNET_IDENTITY_PublicKey *pubkey);
131
132/**
133 * Changes the public key for a <i>contact</i> known to a <i>handle</i> to a specific public key and
134 * updates local map entries to access the contact by its updated key.
135 *
136 * @param handle Handle
137 * @param contact Contact
138 * @param pubkey Public key of EGO
139 */
140void
141swap_handle_contact_by_pubkey (struct GNUNET_MESSENGER_Handle *handle, struct GNUNET_MESSENGER_Contact *contact,
142 const struct GNUNET_IDENTITY_PublicKey *pubkey);
143
144/**
145 * Marks a room known to a <i>handle</i> identified by a given <i>key</i> as open.
146 *
147 * @param handle Handle
148 * @param key Key of room
149 */
150void
151open_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
152
153/**
154 * Adds a tunnel for a room known to a <i>handle</i> identified by a given <i>key</i> to a
155 * list of opened connections.
156 *
157 * @param handle Handle
158 * @param door Peer identity
159 * @param key Key of room
160 */
161void
162entry_handle_room_at (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door,
163 const struct GNUNET_HashCode *key);
164
165/**
166 * Destroys and so implicitly closes a room known to a <i>handle</i> identified by a given <i>key</i>.
167 *
168 * @param handle Handle
169 * @param key Key of room
170 */
171void
172close_handle_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
173
174#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_list_tunnels.c
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_list_tunnels.h"
27
28void
29init_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels)
30{
31 GNUNET_assert(tunnels);
32
33 tunnels->head = NULL;
34 tunnels->tail = NULL;
35}
36
37void
38clear_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels)
39{
40 GNUNET_assert(tunnels);
41
42 struct GNUNET_MESSENGER_ListTunnel *element;
43
44 for (element = tunnels->head; element; element = tunnels->head)
45 {
46 GNUNET_CONTAINER_DLL_remove(tunnels->head, tunnels->tail, element);
47 GNUNET_PEER_change_rc (element->peer, -1);
48 GNUNET_free(element);
49 }
50
51 tunnels->head = NULL;
52 tunnels->tail = NULL;
53}
54
55static int
56compare_list_tunnels (void *cls, struct GNUNET_MESSENGER_ListTunnel *element0,
57 struct GNUNET_MESSENGER_ListTunnel *element1)
58{
59 return ((int) element0->peer) - ((int) element1->peer);
60}
61
62void
63add_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer)
64{
65 struct GNUNET_MESSENGER_ListTunnel *element = GNUNET_new(struct GNUNET_MESSENGER_ListTunnel);
66
67 element->peer = GNUNET_PEER_intern (peer);
68
69 GNUNET_CONTAINER_DLL_insert_sorted(struct GNUNET_MESSENGER_ListTunnel, compare_list_tunnels, NULL, tunnels->head,
70 tunnels->tail, element);
71}
72
73struct GNUNET_MESSENGER_ListTunnel*
74find_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer, size_t *index)
75{
76 struct GNUNET_MESSENGER_ListTunnel *element;
77 struct GNUNET_PeerIdentity pid;
78
79 if (index)
80 *index = 0;
81
82 for (element = tunnels->head; element; element = element->next)
83 {
84 GNUNET_PEER_resolve (element->peer, &pid);
85
86 if (0 == GNUNET_memcmp(&pid, peer))
87 return element;
88
89 if (index)
90 (*index) = (*index) + 1;
91 }
92
93 return NULL;
94}
95
96int
97contains_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer)
98{
99 return find_list_tunnels (tunnels, peer, NULL) != NULL ? GNUNET_YES : GNUNET_NO;
100}
101
102struct GNUNET_MESSENGER_ListTunnel*
103remove_from_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, struct GNUNET_MESSENGER_ListTunnel *element)
104{
105 struct GNUNET_MESSENGER_ListTunnel *next = element->next;
106
107 GNUNET_CONTAINER_DLL_remove(tunnels->head, tunnels->tail, element);
108 GNUNET_PEER_change_rc (element->peer, -1);
109 GNUNET_free(element);
110
111 return next;
112}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_list_tunnels.h
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_LIST_TUNNELS_H
27#define GNUNET_MESSENGER_API_LIST_TUNNELS_H
28
29#include "platform.h"
30#include "gnunet_peer_lib.h"
31#include "gnunet_container_lib.h"
32
33struct GNUNET_MESSENGER_ListTunnel
34{
35 struct GNUNET_MESSENGER_ListTunnel *prev;
36 struct GNUNET_MESSENGER_ListTunnel *next;
37
38 GNUNET_PEER_Id peer;
39};
40
41struct GNUNET_MESSENGER_ListTunnels
42{
43 struct GNUNET_MESSENGER_ListTunnel *head;
44 struct GNUNET_MESSENGER_ListTunnel *tail;
45};
46
47/**
48 * Initializes list of tunnels peer identities as empty list.
49 *
50 * @param tunnels List of peer identities
51 */
52void
53init_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels);
54
55/**
56 * Clears the list of tunnels peer identities.
57 *
58 * @param tunnels List of peer identities
59 */
60void
61clear_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels);
62
63/**
64 * Adds a specific <i>peer</i> from a tunnel to the end of the list.
65 *
66 * @param tunnels List of peer identities
67 * @param peer Peer identity of tunnel
68 */
69void
70add_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer);
71
72/**
73 * Searches linearly through the list of tunnels peer identities for matching a
74 * specific <i>peer</i> identity and returns the matching element of the list.
75 *
76 * If no matching element is found, NULL gets returned.
77 *
78 * If <i>index</i> is not NULL, <i>index</i> will be overriden with the numeric index of
79 * the found element in the list. If no matching element is found, <i>index</i> will
80 * contain the total amount of elements in the list.
81 *
82 * @param tunnels List of peer identities
83 * @param peer Peer identity of tunnel
84 * @param[out] index Index of found element (optional)
85 * @return Element in the list with matching peer identity
86 */
87struct GNUNET_MESSENGER_ListTunnel*
88find_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer, size_t *index);
89
90/**
91 * Tests linearly if the list of tunnels peer identities contains a specific
92 * <i>peer</i> identity and returns GNUNET_YES on success, otherwise GNUNET_NO.
93 *
94 * @param tunnels List of peer identities
95 * @param peer Peer identity of tunnel
96 * @return GNUNET_YES on success, otherwise GNUNET_NO
97 */
98int
99contains_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, const struct GNUNET_PeerIdentity *peer);
100
101/**
102 * Removes a specific <i>element</i> from the list of tunnels peer identities and returns
103 * the next element in the list.
104 *
105 * @param tunnels List of peer identities
106 * @param element Element of the list
107 * @return Next element in the list
108 */
109struct GNUNET_MESSENGER_ListTunnel*
110remove_from_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels, struct GNUNET_MESSENGER_ListTunnel *element);
111
112#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message.c
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_message.h"
27
28struct GNUNET_MESSENGER_MessageSignature
29{
30 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
31 struct GNUNET_HashCode hash;
32};
33
34struct GNUNET_MESSENGER_ShortMessage
35{
36 enum GNUNET_MESSENGER_MessageKind kind;
37 struct GNUNET_MESSENGER_MessageBody body;
38};
39
40struct GNUNET_MESSENGER_Message*
41create_message (enum GNUNET_MESSENGER_MessageKind kind)
42{
43 struct GNUNET_MESSENGER_Message *message = GNUNET_new(struct GNUNET_MESSENGER_Message);
44
45 message->header.kind = kind;
46
47 switch (message->header.kind)
48 {
49 case GNUNET_MESSENGER_KIND_NAME:
50 message->body.name.name = NULL;
51 break;
52 case GNUNET_MESSENGER_KIND_TEXT:
53 message->body.text.text = NULL;
54 break;
55 case GNUNET_MESSENGER_KIND_FILE:
56 message->body.file.uri = NULL;
57 break;
58 case GNUNET_MESSENGER_KIND_PRIVATE:
59 message->body.private.length = 0;
60 message->body.private.data = NULL;
61 break;
62 default:
63 break;
64 }
65
66 return message;
67}
68
69struct GNUNET_MESSENGER_Message*
70copy_message (const struct GNUNET_MESSENGER_Message *message)
71{
72 struct GNUNET_MESSENGER_Message *copy = GNUNET_new(struct GNUNET_MESSENGER_Message);
73
74 GNUNET_memcpy(copy, message, sizeof(struct GNUNET_MESSENGER_Message));
75
76 switch (message->header.kind)
77 {
78 case GNUNET_MESSENGER_KIND_NAME:
79 copy->body.name.name = GNUNET_strdup(message->body.name.name);
80 break;
81 case GNUNET_MESSENGER_KIND_TEXT:
82 copy->body.text.text = GNUNET_strdup(message->body.text.text);
83 break;
84 case GNUNET_MESSENGER_KIND_FILE:
85 copy->body.file.uri = GNUNET_strdup(message->body.file.uri);
86 break;
87 case GNUNET_MESSENGER_KIND_PRIVATE:
88 copy->body.private.data = copy->body.private.length ? GNUNET_malloc(copy->body.private.length) : NULL;
89
90 if (copy->body.private.data)
91 {
92 GNUNET_memcpy(copy->body.private.data, message->body.private.data, copy->body.private.length);
93 }
94
95 break;
96 default:
97 break;
98 }
99
100 return copy;
101}
102
103static void
104destroy_message_body (enum GNUNET_MESSENGER_MessageKind kind, struct GNUNET_MESSENGER_MessageBody *body)
105{
106 switch (kind)
107 {
108 case GNUNET_MESSENGER_KIND_NAME:
109 GNUNET_free(body->name.name);
110 break;
111 case GNUNET_MESSENGER_KIND_TEXT:
112 GNUNET_free(body->text.text);
113 break;
114 case GNUNET_MESSENGER_KIND_FILE:
115 GNUNET_free(body->file.uri);
116 break;
117 case GNUNET_MESSENGER_KIND_PRIVATE:
118 GNUNET_free(body->private.data);
119 break;
120 default:
121 break;
122 }
123}
124
125void
126destroy_message (struct GNUNET_MESSENGER_Message *message)
127{
128 destroy_message_body (message->header.kind, &(message->body));
129
130 GNUNET_free(message);
131}
132
133static void
134fold_short_message (const struct GNUNET_MESSENGER_Message *message, struct GNUNET_MESSENGER_ShortMessage *shortened)
135{
136 shortened->kind = message->header.kind;
137
138 GNUNET_memcpy(&(shortened->body), &(message->body), sizeof(struct GNUNET_MESSENGER_MessageBody));
139}
140
141static void
142unfold_short_message (struct GNUNET_MESSENGER_ShortMessage *shortened, struct GNUNET_MESSENGER_Message *message)
143{
144 destroy_message_body (message->header.kind, &(message->body));
145
146 message->header.kind = shortened->kind;
147
148 GNUNET_memcpy(&(message->body), &(shortened->body), sizeof(struct GNUNET_MESSENGER_MessageBody));
149}
150
151#define member_size(type, member) sizeof(((type*) NULL)->member)
152
153static uint16_t
154get_message_body_kind_size (enum GNUNET_MESSENGER_MessageKind kind)
155{
156 uint16_t length = 0;
157
158 switch (kind)
159 {
160 case GNUNET_MESSENGER_KIND_INFO:
161 length += member_size(struct GNUNET_MESSENGER_Message, body.info.host_key);
162 length += member_size(struct GNUNET_MESSENGER_Message, body.info.unique_id);
163 break;
164 case GNUNET_MESSENGER_KIND_JOIN:
165 length += member_size(struct GNUNET_MESSENGER_Message, body.join.key);
166 break;
167 case GNUNET_MESSENGER_KIND_LEAVE:
168 break;
169 case GNUNET_MESSENGER_KIND_NAME:
170 break;
171 case GNUNET_MESSENGER_KIND_KEY:
172 length += member_size(struct GNUNET_MESSENGER_Message, body.key.key);
173 break;
174 case GNUNET_MESSENGER_KIND_PEER:
175 length += member_size(struct GNUNET_MESSENGER_Message, body.peer.peer);
176 break;
177 case GNUNET_MESSENGER_KIND_ID:
178 length += member_size(struct GNUNET_MESSENGER_Message, body.id.id);
179 break;
180 case GNUNET_MESSENGER_KIND_MISS:
181 length += member_size(struct GNUNET_MESSENGER_Message, body.miss.peer);
182 break;
183 case GNUNET_MESSENGER_KIND_MERGE:
184 length += member_size(struct GNUNET_MESSENGER_Message, body.merge.previous);
185 break;
186 case GNUNET_MESSENGER_KIND_REQUEST:
187 length += member_size(struct GNUNET_MESSENGER_Message, body.request.hash);
188 break;
189 case GNUNET_MESSENGER_KIND_INVITE:
190 length += member_size(struct GNUNET_MESSENGER_Message, body.invite.door);
191 length += member_size(struct GNUNET_MESSENGER_Message, body.invite.key);
192 break;
193 case GNUNET_MESSENGER_KIND_TEXT:
194 break;
195 case GNUNET_MESSENGER_KIND_FILE:
196 length += member_size(struct GNUNET_MESSENGER_Message, body.file.key);
197 length += member_size(struct GNUNET_MESSENGER_Message, body.file.hash);
198 length += NAME_MAX;
199 break;
200 case GNUNET_MESSENGER_KIND_PRIVATE:
201 length += member_size(struct GNUNET_MESSENGER_Message, body.private.key);
202 break;
203 default:
204 break;
205 }
206
207 return length;
208}
209
210uint16_t
211get_message_kind_size (enum GNUNET_MESSENGER_MessageKind kind)
212{
213 uint16_t length = 0;
214
215 length += member_size(struct GNUNET_MESSENGER_Message, header.signature);
216 length += member_size(struct GNUNET_MESSENGER_Message, header.timestamp);
217 length += member_size(struct GNUNET_MESSENGER_Message, header.sender_id);
218 length += member_size(struct GNUNET_MESSENGER_Message, header.previous);
219 length += member_size(struct GNUNET_MESSENGER_Message, header.kind);
220
221 return length + get_message_body_kind_size (kind);
222}
223
224static uint16_t
225get_message_body_size (enum GNUNET_MESSENGER_MessageKind kind, const struct GNUNET_MESSENGER_MessageBody *body)
226{
227 uint16_t length = 0;
228
229 switch (kind)
230 {
231 case GNUNET_MESSENGER_KIND_NAME:
232 length += (body->name.name? strlen (body->name.name) : 0);
233 break;
234 case GNUNET_MESSENGER_KIND_TEXT:
235 length += strlen (body->text.text);
236 break;
237 case GNUNET_MESSENGER_KIND_FILE:
238 length += strlen (body->file.uri);
239 break;
240 case GNUNET_MESSENGER_KIND_PRIVATE:
241 length += body->private.length;
242 break;
243 default:
244 break;
245 }
246
247 return length;
248}
249
250uint16_t
251get_message_size (const struct GNUNET_MESSENGER_Message *message)
252{
253 return get_message_kind_size (message->header.kind) + get_message_body_size (message->header.kind, &(message->body));
254}
255
256static uint16_t
257get_short_message_size (const struct GNUNET_MESSENGER_ShortMessage *message)
258{
259 if (message)
260 return sizeof(message->kind) + get_message_body_kind_size (message->kind)
261 + get_message_body_size (message->kind, &(message->body));
262 else
263 return sizeof(message->kind);
264}
265
266#define min(x, y) (x < y? x : y)
267
268#define encode_step_ext(dst, offset, src, size) do { \
269 GNUNET_memcpy(dst + offset, src, size); \
270 offset += size; \
271} while (0)
272
273#define encode_step(dst, offset, src) do { \
274 encode_step_ext(dst, offset, src, sizeof(*src)); \
275} while(0)
276
277static void
278encode_message_body (enum GNUNET_MESSENGER_MessageKind kind, const struct GNUNET_MESSENGER_MessageBody *body,
279 uint16_t length, char *buffer, uint16_t offset)
280{
281 switch (kind)
282 {
283 case GNUNET_MESSENGER_KIND_INFO:
284 encode_step(buffer, offset, &(body->info.host_key));
285 encode_step(buffer, offset, &(body->info.unique_id));
286 break;
287 case GNUNET_MESSENGER_KIND_JOIN:
288 encode_step(buffer, offset, &(body->join.key));
289 break;
290 case GNUNET_MESSENGER_KIND_LEAVE:
291 break;
292 case GNUNET_MESSENGER_KIND_NAME:
293 if (body->name.name)
294 encode_step_ext(buffer, offset, body->name.name, min(length - offset, strlen(body->name.name)));
295 break;
296 case GNUNET_MESSENGER_KIND_KEY:
297 encode_step(buffer, offset, &(body->key.key));
298 break;
299 case GNUNET_MESSENGER_KIND_PEER:
300 encode_step(buffer, offset, &(body->peer.peer));
301 break;
302 case GNUNET_MESSENGER_KIND_ID:
303 encode_step(buffer, offset, &(body->id.id));
304 break;
305 case GNUNET_MESSENGER_KIND_MISS:
306 encode_step(buffer, offset, &(body->miss.peer));
307 break;
308 case GNUNET_MESSENGER_KIND_MERGE:
309 encode_step(buffer, offset, &(body->merge.previous));
310 break;
311 case GNUNET_MESSENGER_KIND_REQUEST:
312 encode_step(buffer, offset, &(body->request.hash));
313 break;
314 case GNUNET_MESSENGER_KIND_INVITE:
315 encode_step(buffer, offset, &(body->invite.door));
316 encode_step(buffer, offset, &(body->invite.key));
317 break;
318 case GNUNET_MESSENGER_KIND_TEXT:
319 encode_step_ext(buffer, offset, body->text.text, min(length - offset, strlen(body->text.text)));
320 break;
321 case GNUNET_MESSENGER_KIND_FILE:
322 encode_step(buffer, offset, &(body->file.key));
323 encode_step(buffer, offset, &(body->file.hash));
324 encode_step_ext(buffer, offset, body->file.name, NAME_MAX);
325 encode_step_ext(buffer, offset, body->file.uri, min(length - offset, strlen(body->file.uri)));
326 break;
327 case GNUNET_MESSENGER_KIND_PRIVATE:
328 encode_step(buffer, offset, &(body->private.key));
329 encode_step_ext(buffer, offset, body->private.data, min(length - offset, body->private.length));
330 break;
331 default:
332 break;
333 }
334}
335
336void
337encode_message (const struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer)
338{
339 uint16_t offset = 0;
340
341 encode_step(buffer, offset, &(message->header.signature));
342 encode_step(buffer, offset, &(message->header.timestamp));
343 encode_step(buffer, offset, &(message->header.sender_id));
344 encode_step(buffer, offset, &(message->header.previous));
345 encode_step(buffer, offset, &(message->header.kind));
346
347 encode_message_body (message->header.kind, &(message->body), length, buffer, offset);
348}
349
350static void
351encode_short_message (const struct GNUNET_MESSENGER_ShortMessage *message, uint16_t length, char *buffer)
352{
353 uint16_t offset = 0;
354
355 encode_step(buffer, offset, &(message->kind));
356
357 encode_message_body (message->kind, &(message->body), length, buffer, offset);
358}
359
360#define decode_step_ext(src, offset, dst, size) do { \
361 GNUNET_memcpy(dst, src + offset, size); \
362 offset += size; \
363} while (0)
364
365#define decode_step(src, offset, dst) do { \
366 decode_step_ext(src, offset, dst, sizeof(*dst)); \
367} while (0)
368
369#define decode_step_malloc(src, offset, dst, size, zero) do { \
370 dst = GNUNET_malloc(size + zero); \
371 if (zero) dst[size] = 0; \
372 decode_step_ext(src, offset, dst, size); \
373} while (0)
374
375static void
376decode_message_body (enum GNUNET_MESSENGER_MessageKind *kind, struct GNUNET_MESSENGER_MessageBody *body,
377 uint16_t length, const char *buffer, uint16_t offset)
378{
379 switch (*kind)
380 {
381 case GNUNET_MESSENGER_KIND_INFO:
382 decode_step(buffer, offset, &(body->info.host_key));
383 decode_step(buffer, offset, &(body->info.unique_id));
384 break;
385 case GNUNET_MESSENGER_KIND_JOIN:
386 decode_step(buffer, offset, &(body->join.key));
387 break;
388 case GNUNET_MESSENGER_KIND_LEAVE:
389 break;
390 case GNUNET_MESSENGER_KIND_NAME:
391 if (length - offset > 0)
392 decode_step_malloc(buffer, offset, body->name.name, length - offset, 1);
393 else
394 body->name.name = NULL;
395 break;
396 case GNUNET_MESSENGER_KIND_KEY:
397 decode_step(buffer, offset, &(body->key.key));
398 break;
399 case GNUNET_MESSENGER_KIND_PEER:
400 decode_step(buffer, offset, &(body->peer.peer));
401 break;
402 case GNUNET_MESSENGER_KIND_ID:
403 decode_step(buffer, offset, &(body->id.id));
404 break;
405 case GNUNET_MESSENGER_KIND_MISS:
406 decode_step(buffer, offset, &(body->miss.peer));
407 break;
408 case GNUNET_MESSENGER_KIND_MERGE:
409 decode_step(buffer, offset, &(body->merge.previous));
410 break;
411 case GNUNET_MESSENGER_KIND_REQUEST:
412 decode_step(buffer, offset, &(body->request.hash));
413 break;
414 case GNUNET_MESSENGER_KIND_INVITE:
415 decode_step(buffer, offset, &(body->invite.door));
416 decode_step(buffer, offset, &(body->invite.key));
417 break;
418 case GNUNET_MESSENGER_KIND_TEXT:
419 decode_step_malloc(buffer, offset, body->text.text, length - offset, 1);
420 break;
421 case GNUNET_MESSENGER_KIND_FILE:
422 decode_step(buffer, offset, &(body->file.key));
423 decode_step(buffer, offset, &(body->file.hash));
424 decode_step_ext(buffer, offset, body->file.name, NAME_MAX);
425 decode_step_malloc(buffer, offset, body->file.uri, length - offset, 1);
426 break;
427 case GNUNET_MESSENGER_KIND_PRIVATE:
428 decode_step(buffer, offset, &(body->private.key));
429
430 body->private.length = (length - offset);
431 decode_step_malloc(buffer, offset, body->private.data, length - offset, 0);
432 break;
433 default:
434 *kind = GNUNET_MESSENGER_KIND_UNKNOWN;
435 break;
436 }
437}
438
439int
440decode_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, const char *buffer)
441{
442 uint16_t offset = 0;
443
444 if (length < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN))
445 return GNUNET_NO;
446
447 decode_step(buffer, offset, &(message->header.signature));
448 decode_step(buffer, offset, &(message->header.timestamp));
449 decode_step(buffer, offset, &(message->header.sender_id));
450 decode_step(buffer, offset, &(message->header.previous));
451 decode_step(buffer, offset, &(message->header.kind));
452
453 if (length < get_message_kind_size (message->header.kind))
454 return GNUNET_NO;
455
456 decode_message_body (&(message->header.kind), &(message->body), length, buffer, offset);
457
458 return GNUNET_YES;
459}
460
461static int
462decode_short_message (struct GNUNET_MESSENGER_ShortMessage *message, uint16_t length, const char *buffer)
463{
464 uint16_t offset = 0;
465
466 if (length < get_short_message_size (NULL))
467 return GNUNET_NO;
468
469 decode_step(buffer, offset, &(message->kind));
470
471 if (length < get_short_message_size (message))
472 return GNUNET_NO;
473
474 decode_message_body (&(message->kind), &(message->body), length, buffer, offset);
475
476 return GNUNET_YES;
477}
478
479void
480hash_message (uint16_t length, const char *buffer, struct GNUNET_HashCode *hash)
481{
482 GNUNET_CRYPTO_hash (buffer + sizeof(struct GNUNET_CRYPTO_EcdsaSignature),
483 length - sizeof(struct GNUNET_CRYPTO_EcdsaSignature), hash);
484}
485
486void
487sign_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer,
488 const struct GNUNET_HashCode *hash, const struct GNUNET_MESSENGER_Ego *ego)
489{
490 struct GNUNET_MESSENGER_MessageSignature signature;
491
492 signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
493 signature.purpose.size = htonl (sizeof(signature));
494
495 GNUNET_memcpy(&(signature.hash), hash, sizeof(struct GNUNET_HashCode));
496
497 GNUNET_IDENTITY_sign(&(ego->priv), &signature, &(message->header.signature));
498 GNUNET_memcpy(buffer, &(message->header.signature), sizeof(struct GNUNET_CRYPTO_EcdsaSignature));
499}
500
501int
502verify_message (const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash,
503 const struct GNUNET_IDENTITY_PublicKey *key)
504{
505 struct GNUNET_MESSENGER_MessageSignature signature;
506
507 signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
508 signature.purpose.size = htonl (sizeof(signature));
509
510 GNUNET_memcpy(&(signature.hash), hash, sizeof(struct GNUNET_HashCode));
511
512 return GNUNET_IDENTITY_signature_verify(GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE, &signature,
513 &(message->header.signature), key);
514}
515
516int
517encrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PublicKey *key)
518{
519 struct GNUNET_MESSENGER_ShortMessage shortened;
520
521 fold_short_message (message, &shortened);
522
523 const uint16_t length = get_short_message_size (&shortened);
524
525 message->header.kind = GNUNET_MESSENGER_KIND_PRIVATE;
526 message->body.private.data = GNUNET_malloc(length);
527
528 encode_short_message (&shortened, length, message->body.private.data);
529
530 if (GNUNET_IDENTITY_encrypt (message->body.private.data, length, key, &(message->body.private.key),
531 message->body.private.data)
532 == length)
533 {
534 destroy_message_body (shortened.kind, &(shortened.body));
535 return GNUNET_YES;
536 }
537 else
538 {
539 unfold_short_message (&shortened, message);
540 return GNUNET_NO;
541 }
542}
543
544int
545decrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PrivateKey *key)
546{
547 if (message->body.private.length != GNUNET_IDENTITY_decrypt (message->body.private.data,
548 message->body.private.length, key,
549 &(message->body.private.key),
550 message->body.private.data))
551 return GNUNET_NO;
552
553 struct GNUNET_MESSENGER_ShortMessage shortened;
554
555 if (GNUNET_YES != decode_short_message (&shortened, message->body.private.length, message->body.private.data))
556 return GNUNET_NO;
557
558 unfold_short_message (&shortened, message);
559 return GNUNET_YES;
560}
561
562struct GNUNET_MQ_Envelope*
563pack_message (struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
564 const struct GNUNET_MESSENGER_Ego *ego, int mode)
565{
566 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Packing message: %u\n", message->header.kind);
567
568 struct GNUNET_MessageHeader *header;
569
570 uint16_t length = get_message_size (message);
571
572 struct GNUNET_MQ_Envelope *env;
573 char *buffer;
574
575 if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE == mode)
576 {
577 env = GNUNET_MQ_msg_extra(header, length, GNUNET_MESSAGE_TYPE_CADET_CLI);
578
579 buffer = (char*) &(header[1]);
580 }
581 else
582 {
583 env = NULL;
584
585 buffer = GNUNET_malloc(length);
586 }
587
588 encode_message (message, length, buffer);
589
590 if (hash)
591 {
592 hash_message (length, buffer, hash);
593
594 if (ego)
595 sign_message (message, length, buffer, hash, ego);
596 }
597
598 if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE != mode)
599 GNUNET_free(buffer);
600
601 return env;
602}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message.h
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_MESSAGE_H
27#define GNUNET_MESSENGER_API_MESSAGE_H
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_identity_service.h"
32#include "gnunet_mq_lib.h"
33#include "gnunet_signatures.h"
34
35#include "gnunet_messenger_service.h"
36
37#include "messenger_api_ego.h"
38
39/**
40 * Creates and allocates a new message with a specific <i>kind</i>.
41 *
42 * @param kind Kind of message
43 * @return New message
44 */
45struct GNUNET_MESSENGER_Message*
46create_message (enum GNUNET_MESSENGER_MessageKind kind);
47
48/**
49 * Creates and allocates a copy of a given <i>message</i>.
50 *
51 * @param message Message
52 * @return New message
53 */
54struct GNUNET_MESSENGER_Message*
55copy_message (const struct GNUNET_MESSENGER_Message *message);
56
57/**
58 * Destroys a message and frees its memory fully.
59 *
60 * @param message Message
61 */
62void
63destroy_message (struct GNUNET_MESSENGER_Message *message);
64
65/**
66 * Returns the minimal size in bytes to encode a message of a specific <i>kind</i>.
67 *
68 * @param kind Kind of message
69 * @return Minimal size to encode
70 */
71uint16_t
72get_message_kind_size (enum GNUNET_MESSENGER_MessageKind kind);
73
74/**
75 * Returns the exact size in bytes to encode a given <i>message</i>.
76 *
77 * @param message Message
78 * @return Size to encode
79 */
80uint16_t
81get_message_size (const struct GNUNET_MESSENGER_Message *message);
82
83/**
84 * Encodes a given <i>message</i> into a <i>buffer</i> of a maximal <i>length</i> in bytes.
85 *
86 * @param message Message
87 * @param length Maximal length to encode
88 * @param[out] buffer Buffer
89 */
90void
91encode_message (const struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer);
92
93/**
94 * Decodes a <i>message</i> from a given <i>buffer</i> of a maximal <i>length</i> in bytes.
95 *
96 * If the buffer is too small for a message of its decoded kind the function fails with
97 * resulting GNUNET_NO after decoding only the messages header.
98 *
99 * On success the function returns GNUNET_YES.
100 *
101 * @param[out] message Message
102 * @param length Maximal length to decode
103 * @param buffer Buffer
104 * @return GNUNET_YES on success, otherwise GNUNET_NO
105 */
106int
107decode_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, const char *buffer);
108
109/**
110 * Calculates a <i>hash</i> of a given <i>buffer</i> of a <i>length</i> in bytes.
111 *
112 * @param length Length of buffer
113 * @param buffer Buffer
114 * @param[out] hash Hash
115 */
116void
117hash_message (uint16_t length, const char *buffer, struct GNUNET_HashCode *hash);
118
119/**
120 * Signs the <i>hash</i> of a <i>message</i> with a given <i>ego</i> and writes the signature
121 * into the <i>buffer</i> as well.
122 *
123 * @param[out] message Message
124 * @param length Length of buffer
125 * @param[out] buffer Buffer
126 * @param hash Hash of message
127 * @param ego EGO
128 */
129void
130sign_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer,
131 const struct GNUNET_HashCode *hash, const struct GNUNET_MESSENGER_Ego *ego);
132
133/**
134 * Verifies the signature of a given <i>message</i> and its <i>hash</i> with a specific
135 * public key. The function returns GNUNET_OK if the signature was valid, otherwise
136 * GNUNET_SYSERR.
137 *
138 * @param message Message
139 * @param hash Hash of message
140 * @param key Public key of EGO
141 * @return GNUNET_OK on success, otherwise GNUNET_SYSERR
142 */
143int
144verify_message (const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash,
145 const struct GNUNET_IDENTITY_PublicKey *key);
146
147/**
148 * Encrypts a <i>message</i> using a given public <i>key</i> and replaces its body
149 * and kind with the now private encrypted <i>message</i>. The function returns
150 * GNUNET_YES if the operation succeeded, otherwise GNUNET_NO.
151 *
152 * @param message Message
153 * @param key Public key of EGO
154 * @return GNUNET_YES on success, otherwise GNUNET_NO
155 */
156int
157encrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PublicKey *key);
158
159/**
160 * Decrypts a private <i>message</i> using a given private <i>key</i> and replaces its body
161 * and kind with the inner encrypted message. The function returns GNUNET_YES if the
162 * operation succeeded, otherwise GNUNET_NO.
163 *
164 * @param message Message
165 * @param key Private key of EGO
166 * @return GNUNET_YES on success, otherwise GNUNET_NO
167 */
168int
169decrypt_message (struct GNUNET_MESSENGER_Message *message, const struct GNUNET_IDENTITY_PrivateKey *key);
170
171#define GNUNET_MESSENGER_PACK_MODE_ENVELOPE 0x1
172#define GNUNET_MESSENGER_PACK_MODE_UNKNOWN 0x0
173
174/**
175 * Encodes the <i>message</i> to pack it into a newly allocated envelope if <i>mode</i>
176 * is equal to GNUNET_MESSENGER_PACK_MODE_ENVELOPE. Independent of the mode the message
177 * will be hashed if <i>hash</i> is not NULL and it will be signed if the <i>ego</i> is
178 * not NULL.
179 *
180 * @param[out] message Message
181 * @param[out] hash Hash of message
182 * @param ego EGO to sign
183 * @param mode Mode of packing
184 * @return Envelope or NULL
185 */
186struct GNUNET_MQ_Envelope*
187pack_message (struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash,
188 const struct GNUNET_MESSENGER_Ego *ego, int mode);
189
190#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_room.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_room.h"
27
28#include "messenger_api_handle.h"
29
30struct GNUNET_MESSENGER_Room*
31create_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
32{
33 struct GNUNET_MESSENGER_Room *room = GNUNET_new(struct GNUNET_MESSENGER_Room);
34
35 room->handle = handle;
36 GNUNET_memcpy(&(room->key), key, sizeof(*key));
37
38 room->opened = GNUNET_NO;
39 room->contact_id = NULL;
40
41 room->members = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
42
43 init_list_tunnels (&(room->entries));
44
45 room->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
46
47 return room;
48}
49
50static int
51iterate_destroy_message (void *cls, const struct GNUNET_HashCode *key, void *value)
52{
53 struct GNUNET_MESSENGER_Message *message = value;
54
55 destroy_message (message);
56
57 return GNUNET_YES;
58}
59
60void
61destroy_room (struct GNUNET_MESSENGER_Room *room)
62{
63 if (room->members)
64 GNUNET_CONTAINER_multishortmap_destroy (room->members);
65
66 clear_list_tunnels (&(room->entries));
67
68 if (room->messages)
69 {
70 GNUNET_CONTAINER_multihashmap_iterate (room->messages, iterate_destroy_message, NULL);
71
72 GNUNET_CONTAINER_multihashmap_destroy (room->messages);
73 }
74
75 if (room->contact_id)
76 GNUNET_free(room->contact_id);
77
78 GNUNET_free(room);
79}
80
81const struct GNUNET_MESSENGER_Message*
82get_room_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash)
83{
84 return GNUNET_CONTAINER_multihashmap_get (room->messages, hash);
85}
86
87static void
88handle_join_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
89 const struct GNUNET_HashCode *hash)
90{
91 struct GNUNET_MESSENGER_Contact *contact = get_handle_contact_by_pubkey (room->handle, &(message->body.join.key));
92
93 if (contact)
94 GNUNET_CONTAINER_multishortmap_put (room->members, &(message->header.sender_id), contact,
95 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
96}
97
98static void
99handle_leave_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
100 const struct GNUNET_HashCode *hash)
101{
102 GNUNET_CONTAINER_multishortmap_remove_all (room->members, &(message->header.sender_id));
103}
104
105static void
106handle_name_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
107 const struct GNUNET_HashCode *hash)
108{
109 struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
110 &(message->header.sender_id));
111
112 if (contact)
113 set_contact_name (contact, message->body.name.name);
114}
115
116static void
117handle_key_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
118 const struct GNUNET_HashCode *hash)
119{
120 struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
121 &(message->header.sender_id));
122
123 if (contact)
124 swap_handle_contact_by_pubkey (room->handle, contact, &(message->body.key.key));
125}
126
127static void
128handle_id_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
129 const struct GNUNET_HashCode *hash)
130{
131 struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multishortmap_get (room->members,
132 &(message->header.sender_id));
133
134 if ((contact) && (GNUNET_OK
135 == GNUNET_CONTAINER_multishortmap_put (room->members, &(message->body.id.id), contact,
136 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
137 GNUNET_CONTAINER_multishortmap_remove (room->members, &(message->header.sender_id), contact);
138}
139
140static void
141handle_miss_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
142 const struct GNUNET_HashCode *hash)
143{
144 if ((room->contact_id) && (0 == GNUNET_memcmp(&(message->header.sender_id), room->contact_id)))
145 {
146 struct GNUNET_MESSENGER_ListTunnel *match = find_list_tunnels (&(room->entries), &(message->body.miss.peer), NULL);
147
148 if (match)
149 remove_from_list_tunnels (&(room->entries), match);
150 }
151}
152
153void
154handle_room_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
155 const struct GNUNET_HashCode *hash)
156{
157 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (room->messages, hash))
158 return;
159
160 switch (message->header.kind)
161 {
162 case GNUNET_MESSENGER_KIND_JOIN:
163 handle_join_message (room, message, hash);
164 break;
165 case GNUNET_MESSENGER_KIND_LEAVE:
166 handle_leave_message (room, message, hash);
167 break;
168 case GNUNET_MESSENGER_KIND_NAME:
169 handle_name_message (room, message, hash);
170 break;
171 case GNUNET_MESSENGER_KIND_KEY:
172 handle_key_message (room, message, hash);
173 break;
174 case GNUNET_MESSENGER_KIND_ID:
175 handle_id_message (room, message, hash);
176 break;
177 case GNUNET_MESSENGER_KIND_MISS:
178 handle_miss_message (room, message, hash);
179 break;
180 default:
181 break;
182 }
183
184 struct GNUNET_MESSENGER_Message *clone = copy_message (message);
185
186 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages, hash, clone,
187 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
188 destroy_message (clone);
189}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_room.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_ROOM_H
27#define GNUNET_MESSENGER_API_ROOM_H
28
29#include "platform.h"
30#include "gnunet_container_lib.h"
31#include "gnunet_crypto_lib.h"
32
33#include "gnunet_messenger_service.h"
34
35#include "messenger_api_list_tunnels.h"
36#include "messenger_api_contact.h"
37#include "messenger_api_message.h"
38
39struct GNUNET_MESSENGER_Room
40{
41 struct GNUNET_MESSENGER_Handle *handle;
42 struct GNUNET_HashCode key;
43
44 int opened;
45
46 struct GNUNET_ShortHashCode *contact_id;
47
48 struct GNUNET_CONTAINER_MultiShortmap *members;
49 struct GNUNET_MESSENGER_ListTunnels entries;
50
51 struct GNUNET_CONTAINER_MultiHashMap *messages;
52};
53
54/**
55 * Creates and allocates a new room for a <i>handle</i> with a given <i>key</i> for the client API.
56 *
57 * @param handle Handle
58 * @param key Key of room
59 * @return New room
60 */
61struct GNUNET_MESSENGER_Room*
62create_room (struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key);
63
64/**
65 * Destroys a room and frees its memory fully from the client API.
66 *
67 * @param room Room
68 */
69void
70destroy_room (struct GNUNET_MESSENGER_Room *room);
71
72/**
73 * Returns a message locally stored from a map for a given <i>hash</i> in a <i>room</i>. If no matching
74 * message is found, NULL gets returned.
75 *
76 * @param room Room
77 * @param hash Hash of message
78 * @return Message or NULL
79 */
80const struct GNUNET_MESSENGER_Message*
81get_room_message (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash);
82
83/**
84 * Handles a <i>message</i> with a given <i>hash</i> in a <i>room</i> for the client API to update
85 * members and its information. The function also stores the message in map locally for access afterwards.
86 *
87 * @param room Room
88 * @param message Message
89 * @param hash Hash of message
90 */
91void
92handle_room_message (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
93 const struct GNUNET_HashCode *hash);
94
95#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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file messenger/test_messenger.c
22 * @author Tobias Frisch
23 * @brief Test for the messenger service using cadet API.
24 */
25#include <stdio.h>
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_lib.h"
29#include "gnunet_messenger_service.h"
30
31/**
32 * How long until we really give up on a particular testcase portion?
33 */
34#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
35 60)
36
37/**
38 * How long until we give up on any particular operation (and retry)?
39 */
40#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
41
42#define TESTER_NAME "tester"
43
44static int status = 1;
45
46static struct GNUNET_SCHEDULER_Task *die_task = NULL;
47static struct GNUNET_SCHEDULER_Task *op_task = NULL;
48
49struct GNUNET_MESSENGER_Handle *messenger = NULL;
50
51static void
52end (void *cls)
53{
54 die_task = NULL;
55
56 if (op_task)
57 {
58 GNUNET_SCHEDULER_cancel (op_task);
59 op_task = NULL;
60 }
61
62 if (messenger)
63 {
64 GNUNET_MESSENGER_disconnect(messenger);
65 messenger = NULL;
66 }
67
68 status = 0;
69}
70
71
72static void
73end_badly (void *cls)
74{
75 fprintf (stderr, "Testcase failed (timeout).\n");
76
77 end (NULL);
78 status = 1;
79}
80
81static void
82end_operation (void *cls)
83{
84 op_task = NULL;
85
86 fprintf (stderr, "Testcase failed (operation: '%s').\n", cls? (const char*) cls : "unknown");
87
88 if (die_task)
89 GNUNET_SCHEDULER_cancel (die_task);
90
91 end (NULL);
92 status = 1;
93}
94
95static int identity_counter = 0;
96
97/**
98 * Function called when an identity is retrieved.
99 *
100 * @param cls Closure
101 * @param handle Handle of messenger service
102 */
103static void
104on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
105{
106 if (op_task)
107 {
108 GNUNET_SCHEDULER_cancel (op_task);
109 op_task = NULL;
110 }
111
112 const char* name = GNUNET_MESSENGER_get_name(handle);
113
114 if (0 != strcmp(name, TESTER_NAME))
115 {
116 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "name");
117 return;
118 }
119
120 struct GNUNET_IDENTITY_Ego* ego = GNUNET_IDENTITY_ego_get_anonymous();
121 struct GNUNET_IDENTITY_PublicKey anonymous_key;
122
123 GNUNET_IDENTITY_ego_get_public_key(ego, &anonymous_key);
124
125 const struct GNUNET_IDENTITY_PublicKey* key = GNUNET_MESSENGER_get_key(handle);
126
127 if (((!identity_counter) && (0 != GNUNET_memcmp(key, (&anonymous_key)))) ||
128 ((identity_counter) && (0 == GNUNET_memcmp(key, (&anonymous_key)))))
129 {
130 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "key");
131 return;
132 }
133
134 if (identity_counter) {
135 GNUNET_MESSENGER_disconnect(handle);
136
137 op_task = NULL;
138 messenger = NULL;
139
140 if (die_task)
141 GNUNET_SCHEDULER_cancel (die_task);
142
143 die_task = GNUNET_SCHEDULER_add_now (&end, NULL);
144 return;
145 }
146
147 GNUNET_MESSENGER_update(messenger);
148 identity_counter++;
149}
150
151/**
152 * Main function for testcase.
153 *
154 * @param cls Closure
155 * @param cfg Configuration
156 * @param peer Peer for testing
157 */
158static void
159run (void *cls,
160 const struct GNUNET_CONFIGURATION_Handle *cfg,
161 struct GNUNET_TESTING_Peer *peer)
162{
163 die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
164
165 identity_counter = 0;
166
167 op_task = GNUNET_SCHEDULER_add_delayed (BASE_TIMEOUT, &end_operation, "connect");
168 messenger = GNUNET_MESSENGER_connect(cfg, TESTER_NAME, &on_identity, NULL, NULL, NULL);
169}
170
171/**
172 * The main function.
173 *
174 * @param argc number of arguments from the command line
175 * @param argv command line arguments
176 * @return 0 ok, 1 on error
177 */
178int
179main(int argc, char **argv)
180{
181 if (0 != GNUNET_TESTING_peer_run("test-messenger",
182 "test_messenger_api.conf",
183 &run, NULL))
184 return 1;
185
186 return status;
187}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file messenger/test_messenger_anonymous.c
22 * @author Tobias Frisch
23 * @brief Test for the messenger service using cadet API.
24 */
25#include <stdio.h>
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_lib.h"
29#include "gnunet_messenger_service.h"
30
31/**
32 * How long until we really give up on a particular testcase portion?
33 */
34#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
35 60)
36
37/**
38 * How long until we give up on any particular operation (and retry)?
39 */
40#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
41
42static int status = 1;
43
44static struct GNUNET_SCHEDULER_Task *die_task = NULL;
45static struct GNUNET_SCHEDULER_Task *op_task = NULL;
46
47struct GNUNET_MESSENGER_Handle *messenger = NULL;
48
49static void
50end (void *cls)
51{
52 die_task = NULL;
53
54 if (op_task)
55 {
56 GNUNET_SCHEDULER_cancel (op_task);
57 op_task = NULL;
58 }
59
60 if (messenger)
61 {
62 GNUNET_MESSENGER_disconnect(messenger);
63 messenger = NULL;
64 }
65
66 status = 0;
67}
68
69
70static void
71end_badly (void *cls)
72{
73 fprintf (stderr, "Testcase failed (timeout).\n");
74
75 end (NULL);
76 status = 1;
77}
78
79static void
80end_operation (void *cls)
81{
82 op_task = NULL;
83
84 fprintf (stderr, "Testcase failed (operation: '%s').\n", cls? (const char*) cls : "unknown");
85
86 if (die_task)
87 GNUNET_SCHEDULER_cancel (die_task);
88
89 end (NULL);
90 status = 1;
91}
92
93/**
94 * Function called when an identity is retrieved.
95 *
96 * @param cls Closure
97 * @param handle Handle of messenger service
98 */
99static void
100on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
101{
102 if (op_task)
103 {
104 GNUNET_SCHEDULER_cancel (op_task);
105 op_task = NULL;
106 }
107
108 const char* name = GNUNET_MESSENGER_get_name(handle);
109
110 if (NULL != name)
111 {
112 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "name-anonymous");
113 return;
114 }
115
116 if (GNUNET_SYSERR != GNUNET_MESSENGER_update(handle))
117 {
118 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "update-fail");
119 return;
120 }
121
122 struct GNUNET_IDENTITY_Ego* ego = GNUNET_IDENTITY_ego_get_anonymous();
123 struct GNUNET_IDENTITY_PublicKey anonymous_key;
124
125 GNUNET_IDENTITY_ego_get_public_key(ego, &anonymous_key);
126
127 const struct GNUNET_IDENTITY_PublicKey* key = GNUNET_MESSENGER_get_key(handle);
128
129 if (0 != GNUNET_memcmp(key, (&anonymous_key)))
130 {
131 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "key-anonymous");
132 return;
133 }
134
135 GNUNET_MESSENGER_disconnect(handle);
136
137 messenger = NULL;
138
139 if (die_task)
140 GNUNET_SCHEDULER_cancel (die_task);
141
142 die_task = GNUNET_SCHEDULER_add_now (&end, NULL);
143}
144
145/**
146 * Main function for testcase.
147 *
148 * @param cls Closure
149 * @param cfg Configuration
150 * @param peer Peer for testing
151 */
152static void
153run (void *cls,
154 const struct GNUNET_CONFIGURATION_Handle *cfg,
155 struct GNUNET_TESTING_Peer *peer)
156{
157 die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
158
159 op_task = GNUNET_SCHEDULER_add_delayed (BASE_TIMEOUT, &end_operation, "connect");
160 messenger = GNUNET_MESSENGER_connect(cfg, NULL, &on_identity, NULL, NULL, NULL);
161}
162
163/**
164 * The main function.
165 *
166 * @param argc number of arguments from the command line
167 * @param argv command line arguments
168 * @return 0 ok, 1 on error
169 */
170int
171main(int argc, char **argv)
172{
173 if (0 != GNUNET_TESTING_peer_run("test-messenger",
174 "test_messenger_api.conf",
175 &run, NULL))
176 return 1;
177
178 return status;
179}
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file messenger/test_messenger_comm0.c
22 * @author Tobias Frisch
23 * @brief Test for the messenger service using cadet API.
24 */
25#include <stdio.h>
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testbed_logger_service.h"
29#include "gnunet_testbed_service.h"
30#include "gnunet_testing_lib.h"
31#include "gnunet_messenger_service.h"
32
33/**
34 * How long until we really give up on a particular testcase portion?
35 */
36#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
37 60)
38
39/**
40 * How long until we give up on any particular operation (and retry)?
41 */
42#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
43
44static int status = 1;
45
46static struct GNUNET_SCHEDULER_Task *die_task = NULL;
47static struct GNUNET_SCHEDULER_Task *op_task = NULL;
48
49static void
50end (void *cls)
51{
52 die_task = NULL;
53
54 if (op_task)
55 {
56 GNUNET_SCHEDULER_cancel (op_task);
57 op_task = NULL;
58 }
59
60 GNUNET_SCHEDULER_shutdown ();
61 status = 0;
62}
63
64
65static void
66end_badly (void *cls)
67{
68 fprintf (stderr, "Testcase failed (timeout).\n");
69
70 end (NULL);
71 status = 1;
72}
73
74static void
75end_operation (void *cls)
76{
77 op_task = NULL;
78
79 fprintf (stderr, "Testcase failed (operation: '%s').\n", cls? (const char*) cls : "unknown");
80
81 if (die_task)
82 GNUNET_SCHEDULER_cancel (die_task);
83
84 end (NULL);
85 status = 1;
86}
87
88static void
89end_error (void *cls)
90{
91 op_task = NULL;
92
93 fprintf (stderr, "Testcase failed (error: '%s').\n", cls? (const char*) cls : "unknown");
94 GNUNET_free(cls);
95
96 if (die_task)
97 GNUNET_SCHEDULER_cancel (die_task);
98
99 end (NULL);
100 status = 1;
101}
102
103/**
104 * Function called whenever a message is received or sent.
105 *
106 * @param cls Closure
107 * @param room Room
108 * @param message Message
109 * @param hash Hash of message
110 */
111static void
112on_message (void *cls, const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Message *message,
113 const struct GNUNET_HashCode *hash)
114{
115 // TODO
116}
117
118/**
119 * Function called when an identity is retrieved.
120 *
121 * @param cls Closure
122 * @param handle Handle of messenger service
123 */
124static void
125on_identity (void *cls, struct GNUNET_MESSENGER_Handle *handle)
126{
127 // TODO
128}
129
130static void
131on_peer (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
132 const struct GNUNET_TESTBED_PeerInformation *pinfo,
133 const char *emsg)
134{
135 if (emsg)
136 {
137 op_task = GNUNET_SCHEDULER_add_now (&end_error, GNUNET_strdup(emsg));
138 return;
139 }
140
141 if (pinfo->pit != GNUNET_TESTBED_PIT_CONFIGURATION)
142 {
143 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "config");
144 return;
145 }
146
147 struct GNUNET_MESSENGER_Handle *handle;
148 struct GNUNET_MESSENGER_Room *room;
149
150 fprintf (stderr, "MSG: connect\n");
151
152 handle = GNUNET_MESSENGER_connect(pinfo->result.cfg, "tester", &on_identity, NULL, &on_message, NULL);
153
154 struct GNUNET_HashCode hash;
155 GNUNET_CRYPTO_hash("test", 4, &hash);
156
157 fprintf (stderr, "MSG: open\n");
158
159 room = GNUNET_MESSENGER_open_room(handle, &hash);
160
161 fprintf (stderr, "MSG: close\n");
162
163 GNUNET_MESSENGER_close_room(room);
164
165 fprintf (stderr, "MSG: disconnect\n");
166
167 GNUNET_MESSENGER_disconnect(handle);
168
169 GNUNET_TESTBED_operation_done(op);
170
171}
172
173/**
174 * Main function for a peer of the testcase.
175 *
176 * @param cls Closure
177 * @param event Information about the event
178 */
179static void
180run (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
181{
182 if (GNUNET_TESTBED_ET_PEER_START != event->type)
183 {
184 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "start");
185 return;
186 }
187
188 GNUNET_TESTBED_peer_get_information(event->details.peer_start.peer,
189 GNUNET_TESTBED_PIT_CONFIGURATION,
190 on_peer, event->details.peer_start.peer);
191
192 fprintf (stderr, "MSG: barrier\n");
193
194 GNUNET_TESTBED_barrier_wait("exit", NULL, NULL);
195
196 fprintf (stderr, "MSG: exit\n");
197}
198
199static void
200exit_status (void *cls, const char *name,
201 struct GNUNET_TESTBED_Barrier *barrier,
202 enum GNUNET_TESTBED_BarrierStatus status,
203 const char *emsg)
204{
205 if (emsg)
206 {
207 op_task = GNUNET_SCHEDULER_add_now (&end_error, GNUNET_strdup(emsg));
208 return;
209 }
210
211 if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
212 {
213 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "exit");
214 return;
215 }
216 else if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED == status)
217 GNUNET_SCHEDULER_add_now(&end, NULL);
218}
219
220static void
221init (void *cls, struct GNUNET_TESTBED_RunHandle *h, unsigned int num_peers,
222 struct GNUNET_TESTBED_Peer **peers, unsigned int links_succeeded,
223 unsigned int links_failed)
224{
225 die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
226
227 struct GNUNET_TESTBED_Controller *controller;
228
229 controller = GNUNET_TESTBED_run_get_controller_handle(h);
230
231 GNUNET_TESTBED_barrier_init(controller, "exit", num_peers, exit_status, NULL);
232}
233
234/**
235 * The main function.
236 *
237 * @param argc number of arguments from the command line
238 * @param argv command line arguments
239 * @return 0 ok, 1 on error
240 */
241int
242main(int argc, char **argv)
243{
244 if (GNUNET_OK != GNUNET_TESTBED_test_run("test-messenger-comm0",
245 "test_messenger_api.conf",
246 2, 0,
247 &run, NULL,
248 &init, NULL))
249 return 1;
250
251 return status;
252}