aboutsummaryrefslogtreecommitdiff
path: root/src/messenger/gnunet-service-messenger_handle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/messenger/gnunet-service-messenger_handle.c')
-rw-r--r--src/messenger/gnunet-service-messenger_handle.c503
1 files changed, 503 insertions, 0 deletions
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}