aboutsummaryrefslogtreecommitdiff
path: root/src/messenger/gnunet-service-messenger_room.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/messenger/gnunet-service-messenger_room.c')
-rw-r--r--src/messenger/gnunet-service-messenger_room.c1273
1 files changed, 0 insertions, 1273 deletions
diff --git a/src/messenger/gnunet-service-messenger_room.c b/src/messenger/gnunet-service-messenger_room.c
deleted file mode 100644
index 7a20d2191..000000000
--- a/src/messenger/gnunet-service-messenger_room.c
+++ /dev/null
@@ -1,1273 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2021 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_member.h"
29#include "gnunet-service-messenger_member_session.h"
30
31#include "gnunet-service-messenger_message_kind.h"
32#include "gnunet-service-messenger_message_handle.h"
33#include "gnunet-service-messenger_message_send.h"
34
35#include "gnunet-service-messenger_operation.h"
36
37#include "gnunet-service-messenger.h"
38#include "gnunet-service-messenger_service.h"
39#include "gnunet-service-messenger_tunnel.h"
40#include "messenger_api_util.h"
41
42static void
43idle_request_room_messages (void *cls);
44
45struct GNUNET_MESSENGER_SrvRoom*
46create_room (struct GNUNET_MESSENGER_SrvHandle *handle,
47 const struct GNUNET_HashCode *key)
48{
49 GNUNET_assert((handle) && (key));
50
51 struct GNUNET_MESSENGER_SrvRoom *room = GNUNET_new(struct GNUNET_MESSENGER_SrvRoom);
52
53 room->service = handle->service;
54 room->host = handle;
55 room->port = NULL;
56
57 GNUNET_memcpy(&(room->key), key, sizeof(struct GNUNET_HashCode));
58
59 room->tunnels = GNUNET_CONTAINER_multipeermap_create (8, GNUNET_NO);
60
61 init_member_store(get_room_member_store(room), room);
62 init_message_store (get_room_message_store(room));
63 init_operation_store(get_room_operation_store(room), room);
64
65 init_list_tunnels (&(room->basement));
66 init_message_state(&(room->state));
67
68 room->peer_message = NULL;
69
70 init_list_messages (&(room->handling));
71 room->idle = NULL;
72
73 if (room->service->dir)
74 load_room (room);
75
76 room->idle = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, idle_request_room_messages, room);
77
78 return room;
79}
80
81static int
82iterate_destroy_tunnels (void *cls,
83 const struct GNUNET_PeerIdentity *key,
84 void *value)
85{
86 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
87 destroy_tunnel (tunnel);
88 return GNUNET_YES;
89}
90
91static void
92handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room);
93
94void
95destroy_room (struct GNUNET_MESSENGER_SrvRoom *room,
96 int deletion)
97{
98 GNUNET_assert(room);
99
100 if (room->idle)
101 {
102 GNUNET_SCHEDULER_cancel (room->idle);
103 room->idle = NULL;
104 }
105
106 if (room->port)
107 GNUNET_CADET_close_port (room->port);
108
109 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_destroy_tunnels, NULL);
110 handle_room_messages (room);
111
112 if (!(room->service->dir))
113 goto skip_saving;
114
115 if (GNUNET_YES == deletion)
116 remove_room (room);
117 else
118 save_room (room);
119
120skip_saving:
121 clear_member_store (get_room_member_store(room));
122 clear_message_store (get_room_message_store(room));
123 clear_operation_store(get_room_operation_store(room));
124
125 GNUNET_CONTAINER_multipeermap_destroy (room->tunnels);
126 clear_list_tunnels (&(room->basement));
127 clear_message_state(&(room->state));
128
129 if (room->peer_message)
130 GNUNET_free(room->peer_message);
131
132 GNUNET_free(room);
133}
134
135struct GNUNET_MESSENGER_MemberStore*
136get_room_member_store (struct GNUNET_MESSENGER_SrvRoom *room)
137{
138 GNUNET_assert(room);
139
140 return &(room->member_store);
141}
142
143struct GNUNET_MESSENGER_MessageStore*
144get_room_message_store (struct GNUNET_MESSENGER_SrvRoom *room)
145{
146 GNUNET_assert(room);
147
148 return &(room->message_store);
149}
150
151struct GNUNET_MESSENGER_OperationStore*
152get_room_operation_store (struct GNUNET_MESSENGER_SrvRoom *room)
153{
154 GNUNET_assert(room);
155
156 return &(room->operation_store);
157}
158
159static int
160send_room_info (struct GNUNET_MESSENGER_SrvRoom *room,
161 struct GNUNET_MESSENGER_SrvHandle *handle,
162 struct GNUNET_MESSENGER_SrvTunnel *tunnel)
163{
164 if ((!handle) || (!is_tunnel_connected (tunnel)))
165 return GNUNET_NO;
166
167 return send_tunnel_message (tunnel, handle, create_message_info (get_handle_ego (handle)));
168}
169
170static void*
171callback_room_connect (void *cls,
172 struct GNUNET_CADET_Channel *channel,
173 const struct GNUNET_PeerIdentity *source)
174{
175 struct GNUNET_MESSENGER_SrvRoom *room = cls;
176
177 struct GNUNET_MESSENGER_SrvTunnel *tunnel = create_tunnel (room, source);
178
179 if ((tunnel) &&
180 (GNUNET_OK != GNUNET_CONTAINER_multipeermap_put (room->tunnels, source, tunnel,
181 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)))
182 {
183 destroy_tunnel (tunnel);
184 tunnel = NULL;
185 }
186
187 if (!tunnel)
188 {
189 delayed_disconnect_channel (channel);
190 return NULL;
191 }
192
193 bind_tunnel(tunnel, channel);
194
195 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "New tunnel in room (%s) established to peer: %s\n",
196 GNUNET_h2s(get_room_key(room)), GNUNET_i2s (source));
197
198 if (GNUNET_YES == send_room_info (room, room->host, tunnel))
199 return tunnel;
200
201 disconnect_tunnel (tunnel);
202
203 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (room->tunnels, source, tunnel))
204 destroy_tunnel (tunnel);
205
206 return NULL;
207}
208
209static int
210join_room (struct GNUNET_MESSENGER_SrvRoom *room,
211 struct GNUNET_MESSENGER_SrvHandle *handle,
212 struct GNUNET_MESSENGER_Member *member)
213{
214 GNUNET_assert((room) && (handle) && (member));
215
216 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Joining room: %s (%s)\n", GNUNET_h2s (get_room_key (room)),
217 GNUNET_sh2s (get_member_id(member)));
218
219 const struct GNUNET_ShortHashCode *member_id = get_member_id(member);
220
221 if (GNUNET_OK != change_handle_member_id (handle, get_room_key(room), member_id))
222 return GNUNET_NO;
223
224 struct GNUNET_MESSENGER_Message *message = create_message_join (get_handle_ego (handle));
225
226 if (!message)
227 {
228 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Your join message could not be created!\n");
229
230 return GNUNET_NO;
231 }
232
233 GNUNET_memcpy(&(message->header.sender_id), member_id, sizeof(*member_id));
234 return send_room_message (room, handle, message);
235}
236
237struct GNUNET_MESSENGER_MemberNotify
238{
239 struct GNUNET_MESSENGER_SrvRoom *room;
240 struct GNUNET_MESSENGER_SrvHandle *handle;
241 struct GNUNET_MESSENGER_MemberSession *session;
242};
243
244static void
245notify_about_members (struct GNUNET_MESSENGER_MemberNotify *notify,
246 struct GNUNET_MESSENGER_MemberSession *session,
247 struct GNUNET_CONTAINER_MultiHashMap *map,
248 int check_permission)
249{
250 if (session->prev)
251 notify_about_members (notify, session->prev, map, GNUNET_YES);
252
253 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(notify->room);
254 struct GNUNET_MESSENGER_ListMessage *element;
255
256 for (element = session->messages.head; element; element = element->next)
257 {
258 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(map, &(element->hash)))
259 continue;
260
261 if ((GNUNET_YES == check_permission) &&
262 (GNUNET_YES != check_member_session_history(notify->session, &(element->hash), GNUNET_NO)))
263 continue;
264
265 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(map, &(element->hash), NULL,
266 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
267 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Notification of session message could be duplicated!\n");
268
269 const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, &(element->hash));
270
271 if (message)
272 notify_handle_message (notify->handle, notify->room, session, message, &(element->hash));
273 }
274}
275
276static int
277iterate_notify_about_members (void *cls,
278 const struct GNUNET_IDENTITY_PublicKey *public_key,
279 struct GNUNET_MESSENGER_MemberSession *session)
280{
281 struct GNUNET_MESSENGER_MemberNotify *notify = cls;
282
283 if ((notify->session == session) || (GNUNET_YES == is_member_session_completed(session)))
284 return GNUNET_YES;
285
286 struct GNUNET_CONTAINER_MultiHashMap *map = GNUNET_CONTAINER_multihashmap_create(4, GNUNET_NO);
287
288 notify_about_members (notify, session, map, GNUNET_NO);
289
290 GNUNET_CONTAINER_multihashmap_destroy(map);
291 return GNUNET_YES;
292}
293
294static int
295join_room_locally (struct GNUNET_MESSENGER_SrvRoom *room,
296 struct GNUNET_MESSENGER_SrvHandle *handle)
297{
298 const struct GNUNET_ShortHashCode *member_id = get_handle_member_id (handle, get_room_key(room));
299
300 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
301 struct GNUNET_MESSENGER_Member *member = add_store_member(member_store, member_id);
302
303 if (GNUNET_NO == join_room (room, handle, member))
304 return GNUNET_NO;
305
306 const struct GNUNET_MESSENGER_Ego *ego = get_handle_ego(handle);
307 struct GNUNET_MESSENGER_MemberSession *session = get_member_session (member, &(ego->pub));
308
309 if (!session)
310 {
311 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "A valid session is required to join a room!\n");
312 return GNUNET_NO;
313 }
314
315 struct GNUNET_MESSENGER_MemberNotify notify;
316
317 notify.room = room;
318 notify.handle = handle;
319 notify.session = session;
320
321 iterate_store_members(get_room_member_store(room), iterate_notify_about_members, &notify);
322
323 return GNUNET_YES;
324}
325
326extern int
327check_tunnel_message (void *cls,
328 const struct GNUNET_MessageHeader *header);
329
330extern void
331handle_tunnel_message (void *cls,
332 const struct GNUNET_MessageHeader *header);
333
334extern void
335callback_tunnel_disconnect (void *cls,
336 const struct GNUNET_CADET_Channel *channel);
337
338int
339open_room (struct GNUNET_MESSENGER_SrvRoom *room,
340 struct GNUNET_MESSENGER_SrvHandle *handle)
341{
342 GNUNET_assert((room) && (handle));
343
344 if (room->port)
345 return join_room_locally (room, handle);
346
347 struct GNUNET_CADET_Handle *cadet = get_room_cadet (room);
348 const struct GNUNET_HashCode *key = get_room_key (room);
349
350 struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size(tunnel_message, GNUNET_MESSAGE_TYPE_CADET_CLI,
351 struct GNUNET_MessageHeader, NULL),
352 GNUNET_MQ_handler_end() };
353
354 struct GNUNET_HashCode port;
355 convert_messenger_key_to_port(key, &port);
356 room->port = GNUNET_CADET_open_port (cadet, &port, callback_room_connect, room, NULL, callback_tunnel_disconnect,
357 handlers);
358
359 if (room->port)
360 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Port of room (%s) was opened!\n",
361 GNUNET_h2s(get_room_key(room)));
362 else
363 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Port of room (%s) could not be opened!\n",
364 GNUNET_h2s(get_room_key(room)));
365
366 const struct GNUNET_ShortHashCode *member_id = get_handle_member_id (handle, get_room_key(room));
367
368 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
369 struct GNUNET_MESSENGER_Member *member = add_store_member(member_store, member_id);
370
371 if ((GNUNET_NO == join_room (room, handle, member)) && (room->port))
372 {
373 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not join the room, therefore it keeps closed!\n");
374
375 GNUNET_CADET_close_port (room->port);
376 room->port = NULL;
377
378 return GNUNET_NO;
379 }
380
381 struct GNUNET_MESSENGER_Message *peer_msg = create_message_peer (room->service);
382 GNUNET_memcpy(&(peer_msg->header.sender_id), member_id, sizeof(*member_id));
383 return (room->port ? send_room_message (room, handle, peer_msg) : GNUNET_NO);
384}
385
386int
387enter_room_at (struct GNUNET_MESSENGER_SrvRoom *room,
388 struct GNUNET_MESSENGER_SrvHandle *handle,
389 const struct GNUNET_PeerIdentity *door)
390{
391 GNUNET_assert((room) && (handle) && (door));
392
393 struct GNUNET_PeerIdentity peer;
394
395 if ((GNUNET_OK == get_service_peer_identity (room->service, &peer)) &&
396 (0 == GNUNET_memcmp(&peer, door)))
397 return join_room_locally (room, handle);
398
399 struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, door);
400
401 if (!tunnel)
402 {
403 tunnel = create_tunnel (room, door);
404
405 if (GNUNET_OK != GNUNET_CONTAINER_multipeermap_put (room->tunnels, door, tunnel,
406 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
407 {
408 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not connect to that door!\n");
409 destroy_tunnel (tunnel);
410 return GNUNET_NO;
411 }
412 }
413
414 if (GNUNET_SYSERR == connect_tunnel (tunnel))
415 {
416 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Connection failure during entrance!\n");
417 GNUNET_CONTAINER_multipeermap_remove (room->tunnels, door, tunnel);
418 destroy_tunnel (tunnel);
419 return GNUNET_NO;
420 }
421
422 return join_room_locally (room, handle);
423}
424
425struct GNUNET_MQ_Envelope*
426pack_room_message (const struct GNUNET_MESSENGER_SrvRoom *room,
427 const struct GNUNET_MESSENGER_SrvHandle *handle,
428 struct GNUNET_MESSENGER_Message *message,
429 struct GNUNET_HashCode *hash,
430 int mode)
431{
432 GNUNET_assert((room) && (handle) && (message) && (hash));
433
434 message->header.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
435
436 const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, get_room_key(room));
437
438 GNUNET_assert(id);
439
440 GNUNET_memcpy(&(message->header.sender_id), id, sizeof(struct GNUNET_ShortHashCode));
441 get_message_state_chain_hash (&(room->state), &(message->header.previous));
442
443 return pack_message (message, hash, get_handle_ego (handle), mode);
444}
445
446struct GNUNET_MESSENGER_ClosureSendRoom
447{
448 struct GNUNET_MESSENGER_SrvRoom *room;
449 struct GNUNET_MESSENGER_SrvHandle *handle;
450 struct GNUNET_MESSENGER_SrvTunnel *exclude;
451 struct GNUNET_MESSENGER_Message *message;
452 struct GNUNET_HashCode *hash;
453 int packed;
454};
455
456static int
457iterate_send_room_message (void *cls,
458 const struct GNUNET_PeerIdentity *key,
459 void *value)
460{
461 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
462
463 if ((!is_tunnel_connected (tunnel)) ||
464 (get_tunnel_messenger_version(tunnel) < GNUNET_MESSENGER_VERSION))
465 return GNUNET_YES;
466
467 struct GNUNET_MESSENGER_ClosureSendRoom *closure = cls;
468
469 if (tunnel == closure->exclude)
470 return GNUNET_YES;
471
472 struct GNUNET_MQ_Envelope *env = NULL;
473
474 if (closure->packed == GNUNET_NO)
475 {
476 env = pack_room_message (closure->room, closure->handle, closure->message, closure->hash,
477 GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
478
479 if (env)
480 closure->packed = GNUNET_YES;
481 }
482 else
483 env = pack_message (closure->message, NULL, NULL, GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
484
485 if (env)
486 send_tunnel_envelope (tunnel, env, closure->hash);
487
488 return GNUNET_YES;
489}
490
491int
492update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
493 struct GNUNET_MESSENGER_Message *message,
494 const struct GNUNET_HashCode *hash);
495
496void
497callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room,
498 struct GNUNET_MESSENGER_SrvHandle *handle,
499 const struct GNUNET_MESSENGER_Message *message,
500 const struct GNUNET_HashCode *hash);
501
502int
503send_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
504 struct GNUNET_MESSENGER_SrvHandle *handle,
505 struct GNUNET_MESSENGER_Message *message)
506{
507 GNUNET_assert((room) && (handle));
508
509 if (!message)
510 return GNUNET_NO;
511
512 if (GNUNET_YES == is_message_session_bound(message))
513 merge_room_last_messages(room, handle);
514
515 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Sending message from handle with member id: %s\n",
516 GNUNET_sh2s(get_handle_member_id(handle, get_room_key(room))));
517
518 struct GNUNET_HashCode hash;
519 struct GNUNET_MESSENGER_ClosureSendRoom closure;
520
521 closure.room = room;
522 closure.handle = handle;
523 closure.exclude = NULL;
524 closure.message = message;
525 closure.hash = &hash;
526 closure.packed = GNUNET_NO;
527
528 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
529
530 if (GNUNET_NO == closure.packed)
531 pack_room_message (room, handle, message, &hash, GNUNET_MESSENGER_PACK_MODE_UNKNOWN);
532
533 const int new_message = update_room_message (room, message, &hash);
534
535 if (GNUNET_YES != new_message)
536 return GNUNET_SYSERR;
537
538 switch (message->header.kind)
539 {
540 case GNUNET_MESSENGER_KIND_JOIN:
541 send_message_join (room, handle, message, &hash);
542 break;
543 case GNUNET_MESSENGER_KIND_PEER:
544 send_message_peer (room, handle, message, &hash);
545 break;
546 case GNUNET_MESSENGER_KIND_ID:
547 send_message_id (room, handle, message, &hash);
548 break;
549 case GNUNET_MESSENGER_KIND_REQUEST:
550 send_message_request (room, handle, message, &hash);
551 break;
552 default:
553 break;
554 }
555
556 callback_room_handle_message (room, handle, message, &hash);
557 return GNUNET_YES;
558}
559
560void
561forward_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
562 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
563 struct GNUNET_MESSENGER_Message *message,
564 const struct GNUNET_HashCode *hash)
565{
566 GNUNET_assert((room) && (tunnel));
567
568 if (!message)
569 return;
570
571 struct GNUNET_MESSENGER_ClosureSendRoom closure;
572 struct GNUNET_HashCode message_hash;
573
574 GNUNET_memcpy(&message_hash, hash, sizeof(struct GNUNET_HashCode));
575
576 closure.room = room;
577 closure.handle = NULL;
578 closure.exclude = tunnel;
579 closure.message = message;
580 closure.hash = &message_hash;
581 closure.packed = GNUNET_YES;
582
583 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
584}
585
586void
587check_room_peer_status (struct GNUNET_MESSENGER_SrvRoom *room,
588 struct GNUNET_MESSENGER_SrvTunnel *tunnel)
589{
590 if (!room->peer_message)
591 return;
592
593 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
594
595 const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, room->peer_message);
596
597 if (!message)
598 {
599 GNUNET_free(room->peer_message);
600 room->peer_message = NULL;
601 return;
602 }
603
604 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
605 struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
606
607 if (!member)
608 goto resend_peer_message;
609
610 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, room->peer_message);
611
612 if (GNUNET_YES == is_member_session_closed(session))
613 goto resend_peer_message;
614
615 if (tunnel)
616 forward_tunnel_message(tunnel, message, room->peer_message);
617
618 return;
619
620resend_peer_message:
621 if (room->host)
622 send_room_message (room, room->host, create_message_peer (room->service));
623}
624
625void
626merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room,
627 struct GNUNET_MESSENGER_SrvHandle *handle)
628{
629 GNUNET_assert(room);
630
631 if (!handle)
632 return;
633
634 const struct GNUNET_HashCode *hash;
635
636merge_next:
637 hash = get_message_state_merge_hash (&(room->state));
638
639 if (!hash)
640 return;
641
642 send_room_message (room, handle, create_message_merge (hash));
643 goto merge_next;
644}
645
646void
647callback_room_deletion (struct GNUNET_MESSENGER_SrvRoom *room,
648 const struct GNUNET_HashCode *hash)
649{
650 if (GNUNET_OK != delete_store_message (get_room_message_store(room), hash))
651 {
652 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Deletion of message failed! (%s)\n", GNUNET_h2s(hash));
653 return;
654 }
655}
656
657void
658callback_room_merge (struct GNUNET_MESSENGER_SrvRoom *room,
659 const struct GNUNET_HashCode *hash)
660{
661 if (!room->host)
662 return;
663
664 send_room_message (room, room->host, create_message_merge (hash));
665}
666
667int
668delete_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
669 struct GNUNET_MESSENGER_MemberSession *session,
670 const struct GNUNET_HashCode *hash,
671 const struct GNUNET_TIME_Relative delay)
672{
673 GNUNET_assert((room) && (session) && (hash));
674
675 const struct GNUNET_TIME_Relative forever = GNUNET_TIME_relative_get_forever_ ();
676
677 if (0 == GNUNET_memcmp(&forever, &delay))
678 {
679 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Deletion is delayed forever: operation is impossible!\n");
680 return GNUNET_SYSERR;
681 }
682
683 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
684
685 const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, hash);
686
687 if (!message)
688 return GNUNET_YES;
689
690 if (GNUNET_YES != check_member_session_history(session, hash, GNUNET_YES))
691 {
692 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Unpermitted request for deletion by member (%s) of message (%s)!\n",
693 GNUNET_sh2s(get_member_session_id(session)), GNUNET_h2s(hash));
694
695 return GNUNET_NO;
696 }
697
698 struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
699
700 if (GNUNET_OK != use_store_operation(operation_store, hash, GNUNET_MESSENGER_OP_DELETE, delay))
701 {
702 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Deletion has failed: operation denied!\n");
703 return GNUNET_SYSERR;
704 }
705
706 return GNUNET_YES;
707}
708
709struct GNUNET_CADET_Handle*
710get_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room)
711{
712 GNUNET_assert(room);
713
714 return room->service->cadet;
715}
716
717const struct GNUNET_HashCode*
718get_room_key (const struct GNUNET_MESSENGER_SrvRoom *room)
719{
720 GNUNET_assert(room);
721
722 return &(room->key);
723}
724
725const struct GNUNET_MESSENGER_SrvTunnel*
726get_room_tunnel (const struct GNUNET_MESSENGER_SrvRoom *room,
727 const struct GNUNET_PeerIdentity *peer)
728{
729 GNUNET_assert((room) && (peer));
730
731 return GNUNET_CONTAINER_multipeermap_get (room->tunnels, peer);
732}
733
734static int
735request_room_message_step (struct GNUNET_MESSENGER_SrvRoom *room,
736 const struct GNUNET_HashCode *hash,
737 const struct GNUNET_MESSENGER_MemberSession *session,
738 GNUNET_MESSENGER_MessageRequestCallback callback,
739 void* cls)
740{
741 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
742
743 const struct GNUNET_MESSENGER_MessageLink *link = get_store_message_link(
744 message_store, hash, GNUNET_YES
745 );
746
747 if (!link)
748 goto forward;
749
750 int result = request_room_message_step(room, &(link->first), session, callback, cls);
751
752 if ((GNUNET_YES == link->multiple) &&
753 (GNUNET_YES == request_room_message_step(room, &(link->second), session, callback, cls)))
754 return GNUNET_YES;
755 else
756 return result;
757
758forward:
759 if (GNUNET_YES != check_member_session_history(session, hash, GNUNET_NO))
760 return GNUNET_YES;
761
762 const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, hash);
763
764 if (!message)
765 return GNUNET_NO;
766
767 if (callback)
768 callback (cls, room, message, hash);
769
770 return GNUNET_YES;
771}
772
773int
774request_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
775 const struct GNUNET_HashCode *hash,
776 const struct GNUNET_MESSENGER_MemberSession *session,
777 GNUNET_MESSENGER_MessageRequestCallback callback,
778 void* cls)
779{
780 GNUNET_assert((room) && (hash));
781
782 int result = request_room_message_step (room, hash, session, callback, cls);
783
784 if ((GNUNET_NO == result) && (callback))
785 callback (cls, room, NULL, hash);
786
787 return result;
788}
789
790void
791callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room,
792 void *cls)
793{
794 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
795
796 if (!room->host)
797 return;
798
799 struct GNUNET_PeerIdentity identity;
800 get_tunnel_peer_identity(tunnel, &identity);
801
802 if ((GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove (room->tunnels, &identity, tunnel)) ||
803 (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains(room->tunnels, &identity)))
804 return;
805
806 if (GNUNET_YES == contains_list_tunnels (&(room->basement), &identity))
807 send_room_message (room, room->host, create_message_miss (&identity));
808}
809
810int
811callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
812 void *cls,
813 struct GNUNET_MESSENGER_Message *message,
814 struct GNUNET_HashCode *hash)
815{
816 if (GNUNET_MESSENGER_KIND_UNKNOWN == message->header.kind)
817 {
818 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Message error: Kind is unknown! (%d)\n", message->header.kind);
819 return GNUNET_SYSERR;
820 }
821
822 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
823
824 const struct GNUNET_MESSENGER_Message *previous = get_store_message(message_store, &(message->header.previous));
825
826 if (!previous)
827 goto skip_time_comparison;
828
829 struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh(message->header.timestamp);
830 struct GNUNET_TIME_Absolute last = GNUNET_TIME_absolute_ntoh(previous->header.timestamp);
831
832 if (GNUNET_TIME_relative_get_zero_().rel_value_us != GNUNET_TIME_absolute_get_difference(timestamp, last).rel_value_us)
833 {
834 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Message error: Timestamp does not check out!\n");
835 return GNUNET_SYSERR;
836 }
837
838skip_time_comparison:
839 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Receiving message of kind: %s!\n",
840 GNUNET_MESSENGER_name_of_kind(message->header.kind));
841
842 return GNUNET_OK;
843}
844
845static void
846idle_request_room_messages (void *cls)
847{
848 struct GNUNET_MESSENGER_SrvRoom *room = cls;
849
850 room->idle = NULL;
851
852 struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
853 const struct GNUNET_HashCode *hash = get_message_state_merge_hash(&(room->state));
854
855 if ((hash) &&
856 (GNUNET_MESSENGER_OP_UNKNOWN == get_store_operation_type(operation_store, hash)))
857 use_store_operation(
858 operation_store,
859 hash,
860 GNUNET_MESSENGER_OP_MERGE,
861 GNUNET_MESSENGER_MERGE_DELAY
862 );
863
864 room->idle = GNUNET_SCHEDULER_add_delayed_with_priority (
865 GNUNET_MESSENGER_IDLE_DELAY,
866 GNUNET_SCHEDULER_PRIORITY_IDLE,
867 idle_request_room_messages,
868 cls
869 );
870}
871
872void
873solve_room_member_collisions (struct GNUNET_MESSENGER_SrvRoom *room,
874 const struct GNUNET_IDENTITY_PublicKey *public_key,
875 const struct GNUNET_ShortHashCode *member_id,
876 struct GNUNET_TIME_Absolute timestamp)
877{
878 GNUNET_assert ((room) && (public_key) && (member_id));
879
880 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
881 struct GNUNET_MESSENGER_Member *member = get_store_member(member_store, member_id);
882
883 if ((!member) || (1 >= GNUNET_CONTAINER_multihashmap_size(member->sessions)))
884 return;
885
886 struct GNUNET_MESSENGER_ListHandles *handles = &(room->service->handles);
887 struct GNUNET_MESSENGER_ListHandle* element;
888
889 for (element = handles->head; element; element = element->next)
890 {
891 if (0 != GNUNET_memcmp(member_id, get_handle_member_id(element->handle, get_room_key(room))))
892 continue;
893
894 if (0 == GNUNET_memcmp(public_key, &(get_handle_ego(element->handle)->pub)))
895 continue;
896
897 struct GNUNET_MESSENGER_MemberSession *session = get_member_session(member, &(get_handle_ego(element->handle)->pub));
898
899 if (!session)
900 continue;
901
902 struct GNUNET_TIME_Absolute start = get_member_session_start(session);
903
904 if (GNUNET_TIME_relative_get_zero_().rel_value_us != GNUNET_TIME_absolute_get_difference(start, timestamp).rel_value_us)
905 continue;
906
907 struct GNUNET_ShortHashCode random_id;
908 generate_free_member_id (&random_id, member_store->members);
909
910 send_room_message(room, element->handle, create_message_id(&random_id));
911 }
912}
913
914void
915rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room)
916{
917 GNUNET_assert(room);
918
919 struct GNUNET_PeerIdentity peer;
920 size_t src;
921
922 if ((GNUNET_OK != get_service_peer_identity (room->service, &peer)) ||
923 (!find_list_tunnels (&(room->basement), &peer, &src)))
924 return;
925
926 size_t count = count_of_tunnels (&(room->basement));
927
928 struct GNUNET_MESSENGER_ListTunnel *element = room->basement.head;
929 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
930
931 size_t dst = 0;
932
933 while (element)
934 {
935 GNUNET_PEER_resolve (element->peer, &peer);
936
937 tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, &peer);
938
939 if (!tunnel)
940 {
941 element = remove_from_list_tunnels (&(room->basement), element);
942 continue;
943 }
944
945 if (GNUNET_YES == required_connection_between (count, src, dst))
946 {
947 if (GNUNET_SYSERR == connect_tunnel (tunnel))
948 {
949 element = remove_from_list_tunnels (&(room->basement), element);
950 continue;
951 }
952 }
953 else
954 disconnect_tunnel (tunnel);
955
956 element = element->next;
957 dst++;
958 }
959}
960
961static void
962handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room)
963{
964 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
965 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
966
967 while (room->handling.head)
968 {
969 struct GNUNET_MESSENGER_ListMessage *element = room->handling.head;
970
971 const struct GNUNET_MESSENGER_Message *message = get_store_message (message_store, &(element->hash));
972
973 if (!message)
974 goto finish_handling;
975
976 struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
977
978 if (!member)
979 goto finish_handling;
980
981 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, &(element->hash));
982
983 if (session)
984 handle_service_message (room->service, room, session, message, &(element->hash));
985
986finish_handling:
987 GNUNET_CONTAINER_DLL_remove(room->handling.head, room->handling.tail, element);
988 GNUNET_free(element);
989 }
990}
991
992int
993update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
994 struct GNUNET_MESSENGER_Message *message,
995 const struct GNUNET_HashCode *hash)
996{
997 GNUNET_assert((room) && (message) && (hash));
998
999 struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
1000
1001 const int requested = (GNUNET_MESSENGER_OP_REQUEST == get_store_operation_type(operation_store, hash)?
1002 GNUNET_YES : GNUNET_NO
1003 );
1004
1005 if (GNUNET_YES == requested)
1006 cancel_store_operation(operation_store, hash);
1007
1008 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
1009
1010 const struct GNUNET_MESSENGER_Message *old_message = get_store_message (message_store, hash);
1011
1012 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Handle a message in room (%s).\n", GNUNET_h2s (get_room_key(room)));
1013
1014 if ((old_message) || (GNUNET_OK != put_store_message (message_store, hash, message)))
1015 {
1016 if (old_message != message)
1017 destroy_message(message);
1018
1019 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Duplicate message got dropped!\n");
1020 return GNUNET_NO;
1021 }
1022
1023 update_message_state(&(room->state), requested, message, hash);
1024
1025 if ((GNUNET_YES == requested) ||
1026 (GNUNET_MESSENGER_KIND_INFO == message->header.kind) ||
1027 (GNUNET_MESSENGER_KIND_REQUEST == message->header.kind))
1028 return GNUNET_YES;
1029
1030 if ((GNUNET_MESSENGER_KIND_MERGE == message->header.kind) &&
1031 (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type(operation_store, &(message->body.merge.previous))))
1032 cancel_store_operation(operation_store, &(message->body.merge.previous));
1033
1034 if (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type(operation_store, &(message->header.previous)))
1035 cancel_store_operation(operation_store, &(message->header.previous));
1036
1037 return GNUNET_YES;
1038}
1039
1040struct GNUNET_MESSENGER_MemberSessionCompletion
1041{
1042 struct GNUNET_MESSENGER_MemberSessionCompletion *prev;
1043 struct GNUNET_MESSENGER_MemberSessionCompletion *next;
1044
1045 struct GNUNET_MESSENGER_MemberSession *session;
1046};
1047
1048struct GNUNET_MESSENGER_MemberUpdate
1049{
1050 const struct GNUNET_MESSENGER_Message *message;
1051 const struct GNUNET_HashCode *hash;
1052
1053 struct GNUNET_MESSENGER_MemberSessionCompletion *head;
1054 struct GNUNET_MESSENGER_MemberSessionCompletion *tail;
1055};
1056
1057static int
1058iterate_update_member_sessions (void *cls,
1059 const struct GNUNET_IDENTITY_PublicKey *public_key,
1060 struct GNUNET_MESSENGER_MemberSession *session)
1061{
1062 struct GNUNET_MESSENGER_MemberUpdate *update = cls;
1063
1064 update_member_session_history(session, update->message, update->hash);
1065
1066 if (GNUNET_YES == is_member_session_completed(session))
1067 {
1068 struct GNUNET_MESSENGER_MemberSessionCompletion *element = GNUNET_new(
1069 struct GNUNET_MESSENGER_MemberSessionCompletion
1070 );
1071
1072 element->session = session;
1073
1074 GNUNET_CONTAINER_DLL_insert_tail(update->head, update->tail, element);
1075 }
1076
1077 return GNUNET_YES;
1078}
1079
1080static void
1081remove_room_member_session (struct GNUNET_MESSENGER_SrvRoom *room,
1082 struct GNUNET_MESSENGER_MemberSession *session);
1083
1084void
1085callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room,
1086 struct GNUNET_MESSENGER_SrvHandle *handle,
1087 const struct GNUNET_MESSENGER_Message *message,
1088 const struct GNUNET_HashCode *hash)
1089{
1090 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
1091 struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
1092
1093 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Callback for message (%s)\n", GNUNET_h2s (hash));
1094
1095 if (!member)
1096 {
1097 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Message handling dropped: Member is missing!\n");
1098 return;
1099 }
1100
1101 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, hash);
1102
1103 if (!session)
1104 {
1105 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Message handling dropped: Session is missing!\n");
1106 return;
1107 }
1108
1109 struct GNUNET_MESSENGER_MemberUpdate update;
1110 update.message = message;
1111 update.hash = hash;
1112
1113 update.head = NULL;
1114 update.tail = NULL;
1115
1116 iterate_store_members(member_store, iterate_update_member_sessions, &update);
1117
1118 while (update.head)
1119 {
1120 struct GNUNET_MESSENGER_MemberSessionCompletion *element = update.head;
1121
1122 remove_room_member_session (room, element->session);
1123
1124 GNUNET_CONTAINER_DLL_remove(update.head, update.tail, element);
1125 GNUNET_free (element);
1126 }
1127
1128 const int start_handle = room->handling.head ? GNUNET_NO : GNUNET_YES;
1129
1130 add_to_list_messages (&(room->handling), hash);
1131
1132 switch (message->header.kind)
1133 {
1134 case GNUNET_MESSENGER_KIND_JOIN:
1135 handle_message_join (room, session, message, hash);
1136 break;
1137 case GNUNET_MESSENGER_KIND_LEAVE:
1138 handle_message_leave (room, session, message, hash);
1139 break;
1140 case GNUNET_MESSENGER_KIND_NAME:
1141 handle_message_name (room, session, message, hash);
1142 break;
1143 case GNUNET_MESSENGER_KIND_KEY:
1144 handle_message_key (room, session, message, hash);
1145 break;
1146 case GNUNET_MESSENGER_KIND_PEER:
1147 handle_message_peer (room, session, message, hash);
1148 break;
1149 case GNUNET_MESSENGER_KIND_ID:
1150 handle_message_id (room, session, message, hash);
1151 break;
1152 case GNUNET_MESSENGER_KIND_MISS:
1153 handle_message_miss (room, session, message, hash);
1154 break;
1155 case GNUNET_MESSENGER_KIND_DELETE:
1156 handle_message_delete (room, session, message, hash);
1157 break;
1158 default:
1159 break;
1160 }
1161
1162 if (GNUNET_YES == start_handle)
1163 handle_room_messages (room);
1164}
1165
1166static void
1167get_room_data_subdir (struct GNUNET_MESSENGER_SrvRoom *room,
1168 char **dir)
1169{
1170 GNUNET_assert((room) && (dir));
1171
1172 GNUNET_asprintf (dir, "%s%s%c%s%c", room->service->dir, "rooms", DIR_SEPARATOR, GNUNET_h2s (get_room_key(room)), DIR_SEPARATOR);
1173}
1174
1175void
1176load_room (struct GNUNET_MESSENGER_SrvRoom *room)
1177{
1178 GNUNET_assert(room);
1179
1180 char *room_dir;
1181 get_room_data_subdir (room, &room_dir);
1182
1183 if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
1184 {
1185 load_member_store (get_room_member_store(room), room_dir);
1186 load_message_store (get_room_message_store(room), room_dir);
1187 load_operation_store(get_room_operation_store(room), room_dir);
1188
1189 char *basement_file;
1190 GNUNET_asprintf (&basement_file, "%s%s", room_dir, "basement.list");
1191
1192 load_list_tunnels(&(room->basement), basement_file);
1193 GNUNET_free(basement_file);
1194
1195 load_message_state(&(room->state), room_dir);
1196 }
1197
1198 GNUNET_free(room_dir);
1199}
1200
1201void
1202save_room (struct GNUNET_MESSENGER_SrvRoom *room)
1203{
1204 GNUNET_assert(room);
1205
1206 char *room_dir;
1207 get_room_data_subdir (room, &room_dir);
1208
1209 if ((GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_NO)) ||
1210 (GNUNET_OK == GNUNET_DISK_directory_create (room_dir)))
1211 {
1212 save_member_store(get_room_member_store(room), room_dir);
1213 save_message_store (get_room_message_store(room), room_dir);
1214 save_operation_store(get_room_operation_store(room), room_dir);
1215
1216 char *basement_file;
1217 GNUNET_asprintf (&basement_file, "%s%s", room_dir, "basement.list");
1218
1219 save_list_tunnels(&(room->basement), basement_file);
1220 GNUNET_free(basement_file);
1221
1222 save_message_state(&(room->state), room_dir);
1223 }
1224
1225 GNUNET_free(room_dir);
1226}
1227
1228void
1229remove_room (struct GNUNET_MESSENGER_SrvRoom *room)
1230{
1231 GNUNET_assert(room);
1232
1233 char *room_dir;
1234 get_room_data_subdir (room, &room_dir);
1235
1236 if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
1237 GNUNET_DISK_directory_remove(room_dir);
1238
1239 GNUNET_free(room_dir);
1240}
1241
1242static void
1243remove_room_member_session (struct GNUNET_MESSENGER_SrvRoom *room,
1244 struct GNUNET_MESSENGER_MemberSession *session)
1245{
1246 GNUNET_assert ((room) && (session));
1247
1248 remove_member_session (session->member, session);
1249
1250 const struct GNUNET_IDENTITY_PublicKey *public_key = get_member_session_public_key(session);
1251
1252 struct GNUNET_HashCode hash;
1253 GNUNET_CRYPTO_hash(public_key, sizeof(*public_key), &hash);
1254
1255 char *room_dir;
1256 get_room_data_subdir (room, &room_dir);
1257
1258 char* session_dir;
1259 GNUNET_asprintf (
1260 &session_dir, "%s%s%c%s%c%s%c%s%c", room_dir,
1261 "members", DIR_SEPARATOR,
1262 GNUNET_sh2s(get_member_session_id(session)), DIR_SEPARATOR,
1263 "sessions", DIR_SEPARATOR,
1264 GNUNET_h2s(&hash), DIR_SEPARATOR
1265 );
1266
1267 GNUNET_free (room_dir);
1268
1269 GNUNET_DISK_directory_remove(session_dir);
1270 GNUNET_free (session_dir);
1271
1272 destroy_member_session(session);
1273}