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