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.c1210
1 files changed, 0 insertions, 1210 deletions
diff --git a/src/messenger/gnunet-service-messenger_room.c b/src/messenger/gnunet-service-messenger_room.c
deleted file mode 100644
index 73e94908f..000000000
--- a/src/messenger/gnunet-service-messenger_room.c
+++ /dev/null
@@ -1,1210 +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 struct GNUNET_HashCode port;
333 convert_messenger_key_to_port(key, &port);
334 room->port = GNUNET_CADET_open_port (cadet, &port, callback_room_connect, room, NULL, callback_tunnel_disconnect,
335 handlers);
336
337 if (room->port)
338 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Port of room (%s) was opened!\n",
339 GNUNET_h2s(get_room_key(room)));
340 else
341 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Port of room (%s) could not be opened!\n",
342 GNUNET_h2s(get_room_key(room)));
343
344 const struct GNUNET_ShortHashCode *member_id = get_handle_member_id (handle, get_room_key(room));
345
346 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
347 struct GNUNET_MESSENGER_Member *member = get_store_member(member_store, member_id);
348
349 if (member)
350 goto exit_open_room;
351
352 member = add_store_member(member_store, member_id);
353
354 if ((GNUNET_NO == join_room (room, handle, member)) && (room->port))
355 {
356 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not join the room, therefore it keeps closed!\n");
357
358 GNUNET_CADET_close_port (room->port);
359 room->port = NULL;
360
361 return GNUNET_NO;
362 }
363
364exit_open_room:
365 return (room->port ? send_room_message (room, handle, create_message_peer (room->service)) : GNUNET_NO);
366}
367
368int
369enter_room_at (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
370 const struct GNUNET_PeerIdentity *door)
371{
372 GNUNET_assert((room) && (handle) && (door));
373
374 struct GNUNET_PeerIdentity peer;
375
376 if ((GNUNET_OK == get_service_peer_identity (room->service, &peer)) &&
377 (0 == GNUNET_memcmp(&peer, door)))
378 return join_room_locally (room, handle);
379
380 struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, door);
381
382 if (!tunnel)
383 {
384 tunnel = create_tunnel (room, door);
385
386 if (GNUNET_OK != GNUNET_CONTAINER_multipeermap_put (room->tunnels, door, tunnel,
387 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
388 {
389 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "You could not connect to that door!\n");
390 destroy_tunnel (tunnel);
391 return GNUNET_NO;
392 }
393 }
394
395 if (GNUNET_SYSERR == connect_tunnel (tunnel))
396 {
397 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Connection failure during entrance!\n");
398 GNUNET_CONTAINER_multipeermap_remove (room->tunnels, door, tunnel);
399 destroy_tunnel (tunnel);
400 return GNUNET_NO;
401 }
402
403 return join_room_locally (room, handle);
404}
405
406struct GNUNET_MQ_Envelope*
407pack_room_message (const struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_MESSENGER_SrvHandle *handle,
408 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash, int mode)
409{
410 GNUNET_assert((room) && (handle) && (message) && (hash));
411
412 message->header.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
413
414 const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, get_room_key(room));
415
416 GNUNET_assert(id);
417
418 GNUNET_memcpy(&(message->header.sender_id), id, sizeof(struct GNUNET_ShortHashCode));
419 get_message_state_chain_hash (&(room->state), &(message->header.previous));
420
421 return pack_message (message, hash, get_handle_ego (handle), mode);
422}
423
424struct GNUNET_MESSENGER_ClosureSendRoom
425{
426 struct GNUNET_MESSENGER_SrvRoom *room;
427 struct GNUNET_MESSENGER_SrvHandle *handle;
428 struct GNUNET_MESSENGER_SrvTunnel *exclude;
429 struct GNUNET_MESSENGER_Message *message;
430 struct GNUNET_HashCode *hash;
431 int packed;
432};
433
434static int
435iterate_send_room_message (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
436{
437 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
438
439 if ((!is_tunnel_connected (tunnel)) ||
440 (get_tunnel_messenger_version(tunnel) < GNUNET_MESSENGER_VERSION))
441 return GNUNET_YES;
442
443 struct GNUNET_MESSENGER_ClosureSendRoom *closure = cls;
444
445 if (tunnel == closure->exclude)
446 return GNUNET_YES;
447
448 struct GNUNET_MQ_Envelope *env = NULL;
449
450 if (closure->packed == GNUNET_NO)
451 {
452 env = pack_room_message (closure->room, closure->handle, closure->message, closure->hash,
453 GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
454
455 if (env)
456 closure->packed = GNUNET_YES;
457 }
458 else
459 env = pack_message (closure->message, NULL, NULL, GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
460
461 if (env)
462 send_tunnel_envelope (tunnel, env, closure->hash);
463
464 return GNUNET_YES;
465}
466
467int
468update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
469 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
470
471void
472callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
473 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
474
475int
476send_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
477 struct GNUNET_MESSENGER_Message *message)
478{
479 GNUNET_assert((room) && (handle));
480
481 if (!message)
482 return GNUNET_NO;
483
484 if (GNUNET_YES == is_message_session_bound(message))
485 merge_room_last_messages(room, handle);
486
487 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Sending message from handle with member id: %s\n",
488 GNUNET_sh2s(get_handle_member_id(handle, get_room_key(room))));
489
490 struct GNUNET_HashCode hash;
491 struct GNUNET_MESSENGER_ClosureSendRoom closure;
492
493 closure.room = room;
494 closure.handle = handle;
495 closure.exclude = NULL;
496 closure.message = message;
497 closure.hash = &hash;
498 closure.packed = GNUNET_NO;
499
500 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
501
502 if (GNUNET_NO == closure.packed)
503 pack_room_message (room, handle, message, &hash, GNUNET_MESSENGER_PACK_MODE_UNKNOWN);
504
505 const int new_message = update_room_message (room, message, &hash);
506
507 if (GNUNET_YES != new_message)
508 return GNUNET_SYSERR;
509
510 switch (message->header.kind)
511 {
512 case GNUNET_MESSENGER_KIND_JOIN:
513 send_message_join (room, handle, message, &hash);
514 break;
515 case GNUNET_MESSENGER_KIND_PEER:
516 send_message_peer (room, handle, message, &hash);
517 break;
518 case GNUNET_MESSENGER_KIND_ID:
519 send_message_id (room, handle, message, &hash);
520 break;
521 case GNUNET_MESSENGER_KIND_REQUEST:
522 send_message_request (room, handle, message, &hash);
523 break;
524 default:
525 break;
526 }
527
528 callback_room_handle_message (room, handle, message, &hash);
529 return GNUNET_YES;
530}
531
532void
533forward_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
534 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
535{
536 GNUNET_assert((room) && (tunnel));
537
538 if (!message)
539 return;
540
541 struct GNUNET_MESSENGER_ClosureSendRoom closure;
542 struct GNUNET_HashCode message_hash;
543
544 GNUNET_memcpy(&message_hash, hash, sizeof(struct GNUNET_HashCode));
545
546 closure.room = room;
547 closure.handle = NULL;
548 closure.exclude = tunnel;
549 closure.message = message;
550 closure.hash = &message_hash;
551 closure.packed = GNUNET_YES;
552
553 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_send_room_message, &closure);
554}
555
556void
557check_room_peer_status (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel)
558{
559 if (!room->peer_message)
560 return;
561
562 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
563
564 const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, room->peer_message);
565
566 if (!message)
567 {
568 GNUNET_free(room->peer_message);
569 room->peer_message = NULL;
570 return;
571 }
572
573 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
574 struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
575
576 if (!member)
577 goto resend_peer_message;
578
579 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, room->peer_message);
580
581 if (GNUNET_YES == is_member_session_closed(session))
582 goto resend_peer_message;
583
584 if (tunnel)
585 forward_tunnel_message(tunnel, message, room->peer_message);
586
587 return;
588
589resend_peer_message:
590 if (room->host)
591 send_room_message (room, room->host, create_message_peer (room->service));
592}
593
594void
595merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
596{
597 GNUNET_assert(room);
598
599 if (!handle)
600 return;
601
602 const struct GNUNET_HashCode *hash;
603
604merge_next:
605 hash = get_message_state_merge_hash (&(room->state));
606
607 if (!hash)
608 return;
609
610 send_room_message (room, handle, create_message_merge (hash));
611 goto merge_next;
612}
613
614void
615callback_room_deletion (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash)
616{
617 if (GNUNET_OK != delete_store_message (get_room_message_store(room), hash))
618 {
619 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Deletion of message failed! (%s)\n", GNUNET_h2s(hash));
620 return;
621 }
622}
623
624void
625callback_room_merge (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash)
626{
627 if (!room->host)
628 return;
629
630 send_room_message (room, room->host, create_message_merge (hash));
631}
632
633int
634delete_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_MemberSession *session,
635 const struct GNUNET_HashCode *hash, const struct GNUNET_TIME_Relative delay)
636{
637 GNUNET_assert((room) && (session) && (hash));
638
639 const struct GNUNET_TIME_Relative forever = GNUNET_TIME_relative_get_forever_ ();
640
641 if (0 == GNUNET_memcmp(&forever, &delay))
642 {
643 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Deletion is delayed forever: operation is impossible!\n");
644 return GNUNET_SYSERR;
645 }
646
647 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
648
649 const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, hash);
650
651 if (!message)
652 return GNUNET_YES;
653
654 if (GNUNET_YES != check_member_session_history(session, hash, GNUNET_YES))
655 {
656 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Unpermitted request for deletion by member (%s) of message (%s)!\n",
657 GNUNET_sh2s(get_member_session_id(session)), GNUNET_h2s(hash));
658
659 return GNUNET_NO;
660 }
661
662 struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
663
664 if (GNUNET_OK != use_store_operation(operation_store, hash, GNUNET_MESSENGER_OP_DELETE, delay))
665 {
666 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Deletion has failed: operation denied!\n");
667 return GNUNET_SYSERR;
668 }
669
670 return GNUNET_YES;
671}
672
673struct GNUNET_CADET_Handle*
674get_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room)
675{
676 GNUNET_assert(room);
677
678 return room->service->cadet;
679}
680
681const struct GNUNET_HashCode*
682get_room_key (const struct GNUNET_MESSENGER_SrvRoom *room)
683{
684 GNUNET_assert(room);
685
686 return &(room->key);
687}
688
689const struct GNUNET_MESSENGER_SrvTunnel*
690get_room_tunnel (const struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *peer)
691{
692 GNUNET_assert((room) && (peer));
693
694 return GNUNET_CONTAINER_multipeermap_get (room->tunnels, peer);
695}
696
697static int
698request_room_message_step (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash,
699 const struct GNUNET_MESSENGER_MemberSession *session,
700 GNUNET_MESSENGER_MessageRequestCallback callback, void* cls)
701{
702 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
703
704 const struct GNUNET_MESSENGER_MessageLink *link = get_store_message_link(
705 message_store, hash, GNUNET_YES
706 );
707
708 if (!link)
709 goto forward;
710
711 int result = request_room_message_step(room, &(link->first), session, callback, cls);
712
713 if ((GNUNET_YES == link->multiple) &&
714 (GNUNET_YES == request_room_message_step(room, &(link->second), session, callback, cls)))
715 return GNUNET_YES;
716 else
717 return result;
718
719forward:
720 if (GNUNET_YES != check_member_session_history(session, hash, GNUNET_NO))
721 return GNUNET_YES;
722
723 const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, hash);
724
725 if (!message)
726 return GNUNET_NO;
727
728 if (callback)
729 callback (cls, room, message, hash);
730
731 return GNUNET_YES;
732}
733
734int
735request_room_message (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash,
736 const struct GNUNET_MESSENGER_MemberSession *session,
737 GNUNET_MESSENGER_MessageRequestCallback callback, void* cls)
738{
739 GNUNET_assert((room) && (hash));
740
741 int result = request_room_message_step (room, hash, session, callback, cls);
742
743 if ((GNUNET_NO == result) && (callback))
744 callback (cls, room, NULL, hash);
745
746 return result;
747}
748
749void
750callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room, void *cls)
751{
752 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
753
754 if (!room->host)
755 return;
756
757 struct GNUNET_PeerIdentity identity;
758 get_tunnel_peer_identity(tunnel, &identity);
759
760 if ((GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove (room->tunnels, &identity, tunnel)) ||
761 (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains(room->tunnels, &identity)))
762 return;
763
764 if (GNUNET_YES == contains_list_tunnels (&(room->basement), &identity))
765 send_room_message (room, room->host, create_message_miss (&identity));
766}
767
768int
769callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room, void *cls,
770 struct GNUNET_MESSENGER_Message *message, struct GNUNET_HashCode *hash)
771{
772 if (GNUNET_MESSENGER_KIND_UNKNOWN == message->header.kind)
773 {
774 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Message error: Kind is unknown! (%d)\n", message->header.kind);
775 return GNUNET_SYSERR;
776 }
777
778 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
779
780 const struct GNUNET_MESSENGER_Message *previous = get_store_message(message_store, &(message->header.previous));
781
782 if (!previous)
783 goto skip_time_comparison;
784
785 struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh(message->header.timestamp);
786 struct GNUNET_TIME_Absolute last = GNUNET_TIME_absolute_ntoh(previous->header.timestamp);
787
788 if (GNUNET_TIME_relative_get_zero_().rel_value_us != GNUNET_TIME_absolute_get_difference(timestamp, last).rel_value_us)
789 {
790 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Message error: Timestamp does not check out!\n");
791 return GNUNET_SYSERR;
792 }
793
794skip_time_comparison:
795 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Receiving message of kind: %s!\n",
796 GNUNET_MESSENGER_name_of_kind(message->header.kind));
797
798 return GNUNET_OK;
799}
800
801static void
802idle_request_room_messages (void *cls)
803{
804 struct GNUNET_MESSENGER_SrvRoom *room = cls;
805
806 room->idle = NULL;
807
808 struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
809 const struct GNUNET_HashCode *hash = get_message_state_merge_hash(&(room->state));
810
811 if ((hash) &&
812 (GNUNET_MESSENGER_OP_UNKNOWN == get_store_operation_type(operation_store, hash)))
813 use_store_operation(
814 operation_store,
815 hash,
816 GNUNET_MESSENGER_OP_MERGE,
817 GNUNET_MESSENGER_MERGE_DELAY
818 );
819
820 room->idle = GNUNET_SCHEDULER_add_delayed_with_priority (
821 GNUNET_MESSENGER_IDLE_DELAY,
822 GNUNET_SCHEDULER_PRIORITY_IDLE,
823 idle_request_room_messages,
824 cls
825 );
826}
827
828void
829solve_room_member_collisions (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_IDENTITY_PublicKey *public_key,
830 const struct GNUNET_ShortHashCode *member_id, struct GNUNET_TIME_Absolute timestamp)
831{
832 GNUNET_assert ((room) && (public_key) && (member_id));
833
834 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
835 struct GNUNET_MESSENGER_Member *member = get_store_member(member_store, member_id);
836
837 if ((!member) || (1 >= GNUNET_CONTAINER_multihashmap_size(member->sessions)))
838 return;
839
840 struct GNUNET_MESSENGER_ListHandles *handles = &(room->service->handles);
841 struct GNUNET_MESSENGER_ListHandle* element;
842
843 for (element = handles->head; element; element = element->next)
844 {
845 if (0 != GNUNET_memcmp(member_id, get_handle_member_id(element->handle, get_room_key(room))))
846 continue;
847
848 if (0 == GNUNET_memcmp(public_key, &(get_handle_ego(element->handle)->pub)))
849 continue;
850
851 struct GNUNET_MESSENGER_MemberSession *session = get_member_session(member, &(get_handle_ego(element->handle)->pub));
852
853 if (!session)
854 continue;
855
856 struct GNUNET_TIME_Absolute start = get_member_session_start(session);
857
858 if (GNUNET_TIME_relative_get_zero_().rel_value_us != GNUNET_TIME_absolute_get_difference(start, timestamp).rel_value_us)
859 continue;
860
861 struct GNUNET_ShortHashCode random_id;
862 generate_free_member_id (&random_id, member_store->members);
863
864 send_room_message(room, element->handle, create_message_id(&random_id));
865 }
866}
867
868void
869rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room)
870{
871 GNUNET_assert(room);
872
873 struct GNUNET_PeerIdentity peer;
874 size_t src;
875
876 if ((GNUNET_OK != get_service_peer_identity (room->service, &peer)) ||
877 (!find_list_tunnels (&(room->basement), &peer, &src)))
878 return;
879
880 size_t count = count_of_tunnels (&(room->basement));
881
882 struct GNUNET_MESSENGER_ListTunnel *element = room->basement.head;
883 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
884
885 size_t dst = 0;
886
887 while (element)
888 {
889 GNUNET_PEER_resolve (element->peer, &peer);
890
891 tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, &peer);
892
893 if (!tunnel)
894 {
895 element = remove_from_list_tunnels (&(room->basement), element);
896 continue;
897 }
898
899 if (GNUNET_YES == required_connection_between (count, src, dst))
900 {
901 if (GNUNET_SYSERR == connect_tunnel (tunnel))
902 {
903 element = remove_from_list_tunnels (&(room->basement), element);
904 continue;
905 }
906 }
907 else
908 disconnect_tunnel (tunnel);
909
910 element = element->next;
911 dst++;
912 }
913}
914
915static void
916handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room)
917{
918 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
919 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
920
921 while (room->handling.head)
922 {
923 struct GNUNET_MESSENGER_ListMessage *element = room->handling.head;
924
925 const struct GNUNET_MESSENGER_Message *message = get_store_message (message_store, &(element->hash));
926
927 if (!message)
928 goto finish_handling;
929
930 struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
931
932 if (!member)
933 goto finish_handling;
934
935 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, &(element->hash));
936
937 if (session)
938 handle_service_message (room->service, room, session, message, &(element->hash));
939
940finish_handling:
941 GNUNET_CONTAINER_DLL_remove(room->handling.head, room->handling.tail, element);
942 GNUNET_free(element);
943 }
944}
945
946int
947update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
948 struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
949{
950 GNUNET_assert((room) && (message) && (hash));
951
952 struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
953
954 const int requested = (GNUNET_MESSENGER_OP_REQUEST == get_store_operation_type(operation_store, hash)?
955 GNUNET_YES : GNUNET_NO
956 );
957
958 if (GNUNET_YES == requested)
959 cancel_store_operation(operation_store, hash);
960
961 struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
962
963 const struct GNUNET_MESSENGER_Message *old_message = get_store_message (message_store, hash);
964
965 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Handle a message in room (%s).\n", GNUNET_h2s (get_room_key(room)));
966
967 if ((old_message) || (GNUNET_OK != put_store_message (message_store, hash, message)))
968 {
969 if (old_message != message)
970 destroy_message(message);
971
972 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Duplicate message got dropped!\n");
973 return GNUNET_NO;
974 }
975
976 update_message_state(&(room->state), requested, message, hash);
977
978 if ((GNUNET_YES == requested) ||
979 (GNUNET_MESSENGER_KIND_INFO == message->header.kind) ||
980 (GNUNET_MESSENGER_KIND_REQUEST == message->header.kind))
981 return GNUNET_YES;
982
983 if ((GNUNET_MESSENGER_KIND_MERGE == message->header.kind) &&
984 (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type(operation_store, &(message->body.merge.previous))))
985 cancel_store_operation(operation_store, &(message->body.merge.previous));
986
987 if (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type(operation_store, &(message->header.previous)))
988 cancel_store_operation(operation_store, &(message->header.previous));
989
990 return GNUNET_YES;
991}
992
993struct GNUNET_MESSENGER_MemberSessionCompletion
994{
995 struct GNUNET_MESSENGER_MemberSessionCompletion *prev;
996 struct GNUNET_MESSENGER_MemberSessionCompletion *next;
997
998 struct GNUNET_MESSENGER_MemberSession *session;
999};
1000
1001struct GNUNET_MESSENGER_MemberUpdate
1002{
1003 const struct GNUNET_MESSENGER_Message *message;
1004 const struct GNUNET_HashCode *hash;
1005
1006 struct GNUNET_MESSENGER_MemberSessionCompletion *head;
1007 struct GNUNET_MESSENGER_MemberSessionCompletion *tail;
1008};
1009
1010static int
1011iterate_update_member_sessions (void *cls, const struct GNUNET_IDENTITY_PublicKey *public_key,
1012 struct GNUNET_MESSENGER_MemberSession *session)
1013{
1014 struct GNUNET_MESSENGER_MemberUpdate *update = cls;
1015
1016 update_member_session_history(session, update->message, update->hash);
1017
1018 if (GNUNET_YES == is_member_session_completed(session))
1019 {
1020 struct GNUNET_MESSENGER_MemberSessionCompletion *element = GNUNET_new(
1021 struct GNUNET_MESSENGER_MemberSessionCompletion
1022 );
1023
1024 element->session = session;
1025
1026 GNUNET_CONTAINER_DLL_insert_tail(update->head, update->tail, element);
1027 }
1028
1029 return GNUNET_YES;
1030}
1031
1032static void
1033remove_room_member_session (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_MemberSession *session);
1034
1035void
1036callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
1037 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
1038{
1039 struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
1040 struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
1041
1042 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Callback for message (%s)\n", GNUNET_h2s (hash));
1043
1044 if (!member)
1045 {
1046 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Message handling dropped: Member is missing!\n");
1047 return;
1048 }
1049
1050 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, hash);
1051
1052 if (!session)
1053 {
1054 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Message handling dropped: Session is missing!\n");
1055 return;
1056 }
1057
1058 struct GNUNET_MESSENGER_MemberUpdate update;
1059 update.message = message;
1060 update.hash = hash;
1061
1062 update.head = NULL;
1063 update.tail = NULL;
1064
1065 iterate_store_members(member_store, iterate_update_member_sessions, &update);
1066
1067 while (update.head)
1068 {
1069 struct GNUNET_MESSENGER_MemberSessionCompletion *element = update.head;
1070
1071 remove_room_member_session (room, element->session);
1072
1073 GNUNET_CONTAINER_DLL_remove(update.head, update.tail, element);
1074 GNUNET_free (element);
1075 }
1076
1077 const int start_handle = room->handling.head ? GNUNET_NO : GNUNET_YES;
1078
1079 add_to_list_messages (&(room->handling), hash);
1080
1081 switch (message->header.kind)
1082 {
1083 case GNUNET_MESSENGER_KIND_JOIN:
1084 handle_message_join (room, session, message, hash);
1085 break;
1086 case GNUNET_MESSENGER_KIND_LEAVE:
1087 handle_message_leave (room, session, message, hash);
1088 break;
1089 case GNUNET_MESSENGER_KIND_NAME:
1090 handle_message_name (room, session, message, hash);
1091 break;
1092 case GNUNET_MESSENGER_KIND_KEY:
1093 handle_message_key (room, session, message, hash);
1094 break;
1095 case GNUNET_MESSENGER_KIND_PEER:
1096 handle_message_peer (room, session, message, hash);
1097 break;
1098 case GNUNET_MESSENGER_KIND_ID:
1099 handle_message_id (room, session, message, hash);
1100 break;
1101 case GNUNET_MESSENGER_KIND_MISS:
1102 handle_message_miss (room, session, message, hash);
1103 break;
1104 case GNUNET_MESSENGER_KIND_DELETE:
1105 handle_message_delete (room, session, message, hash);
1106 break;
1107 default:
1108 break;
1109 }
1110
1111 if (GNUNET_YES == start_handle)
1112 handle_room_messages (room);
1113}
1114
1115static void
1116get_room_data_subdir (struct GNUNET_MESSENGER_SrvRoom *room, char **dir)
1117{
1118 GNUNET_assert((room) && (dir));
1119
1120 GNUNET_asprintf (dir, "%s%s%c%s%c", room->service->dir, "rooms", DIR_SEPARATOR, GNUNET_h2s (get_room_key(room)), DIR_SEPARATOR);
1121}
1122
1123void
1124load_room (struct GNUNET_MESSENGER_SrvRoom *room)
1125{
1126 GNUNET_assert(room);
1127
1128 char *room_dir;
1129 get_room_data_subdir (room, &room_dir);
1130
1131 if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
1132 {
1133 load_member_store (get_room_member_store(room), room_dir);
1134 load_message_store (get_room_message_store(room), room_dir);
1135 load_operation_store(get_room_operation_store(room), room_dir);
1136
1137 char *basement_file;
1138 GNUNET_asprintf (&basement_file, "%s%s", room_dir, "basement.list");
1139
1140 load_list_tunnels(&(room->basement), basement_file);
1141 GNUNET_free(basement_file);
1142
1143 char *last_messages_file;
1144 GNUNET_asprintf (&last_messages_file, "%s%s", room_dir, "last_messages.list");
1145
1146 load_message_state(&(room->state), room_dir);
1147 GNUNET_free (last_messages_file);
1148 }
1149
1150 GNUNET_free(room_dir);
1151}
1152
1153void
1154save_room (struct GNUNET_MESSENGER_SrvRoom *room)
1155{
1156 GNUNET_assert(room);
1157
1158 char *room_dir;
1159 get_room_data_subdir (room, &room_dir);
1160
1161 if ((GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_NO)) ||
1162 (GNUNET_OK == GNUNET_DISK_directory_create (room_dir)))
1163 {
1164 save_member_store(get_room_member_store(room), room_dir);
1165 save_message_store (get_room_message_store(room), room_dir);
1166 save_operation_store(get_room_operation_store(room), room_dir);
1167
1168 char *basement_file;
1169 GNUNET_asprintf (&basement_file, "%s%s", room_dir, "basement.list");
1170
1171 save_list_tunnels(&(room->basement), basement_file);
1172 GNUNET_free(basement_file);
1173
1174 save_message_state(&(room->state), room_dir);
1175 }
1176
1177 GNUNET_free(room_dir);
1178}
1179
1180static void
1181remove_room_member_session (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_MemberSession *session)
1182{
1183 GNUNET_assert ((room) && (session));
1184
1185 remove_member_session (session->member, session);
1186
1187 const struct GNUNET_IDENTITY_PublicKey *public_key = get_member_session_public_key(session);
1188
1189 struct GNUNET_HashCode hash;
1190 GNUNET_CRYPTO_hash(public_key, sizeof(*public_key), &hash);
1191
1192 char *room_dir;
1193 get_room_data_subdir (room, &room_dir);
1194
1195 char* session_dir;
1196 GNUNET_asprintf (
1197 &session_dir, "%s%s%c%s%c%s%c%s%c", room_dir,
1198 "members", DIR_SEPARATOR,
1199 GNUNET_sh2s(get_member_session_id(session)), DIR_SEPARATOR,
1200 "sessions", DIR_SEPARATOR,
1201 GNUNET_h2s(&hash), DIR_SEPARATOR
1202 );
1203
1204 GNUNET_free (room_dir);
1205
1206 GNUNET_DISK_directory_remove(session_dir);
1207 GNUNET_free (session_dir);
1208
1209 destroy_member_session(session);
1210}