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