gnunet_chat_discourse.c (4828B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2024 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 gnunet_chat_discourse.c 23 */ 24 25 #include "gnunet_chat_discourse.h" 26 27 #include <gnunet/gnunet_common.h> 28 #include <gnunet/gnunet_scheduler_lib.h> 29 #include <gnunet/gnunet_time_lib.h> 30 31 #include <unistd.h> 32 33 #include "gnunet_chat_discourse_intern.c" 34 35 struct GNUNET_CHAT_Discourse* 36 discourse_create (struct GNUNET_CHAT_Context *context, 37 const struct GNUNET_CHAT_DiscourseId *id) 38 { 39 GNUNET_assert((context) && (id)); 40 41 struct GNUNET_CHAT_Discourse *discourse = GNUNET_new(struct GNUNET_CHAT_Discourse); 42 43 discourse->context = context; 44 45 GNUNET_memcpy(&(discourse->id), id, sizeof(struct GNUNET_CHAT_DiscourseId)); 46 47 if (0 != pipe(discourse->pipe)) 48 { 49 discourse->pipe[0] = -1; 50 discourse->pipe[1] = -1; 51 } 52 53 discourse->head = NULL; 54 discourse->tail = NULL; 55 56 discourse->pipe_task = GNUNET_SCHEDULER_add_now( 57 cb_reinit_discourse_pipe, discourse 58 ); 59 60 discourse->user_pointer = NULL; 61 62 return discourse; 63 } 64 65 static void 66 discourse_remove_subscription (void *cls) 67 { 68 struct GNUNET_CHAT_DiscourseSubscription *sub = cls; 69 struct GNUNET_CHAT_Discourse *discourse = sub->discourse; 70 71 GNUNET_CONTAINER_DLL_remove( 72 discourse->head, 73 discourse->tail, 74 sub 75 ); 76 77 GNUNET_free(sub); 78 } 79 80 void 81 discourse_destroy (struct GNUNET_CHAT_Discourse *discourse) 82 { 83 GNUNET_assert(discourse); 84 85 while (discourse->head) 86 { 87 struct GNUNET_CHAT_DiscourseSubscription *sub = discourse->head; 88 89 if (sub->task) 90 GNUNET_SCHEDULER_cancel(sub->task); 91 92 discourse_remove_subscription(sub); 93 } 94 95 if (discourse->pipe_task) 96 GNUNET_SCHEDULER_cancel(discourse->pipe_task); 97 98 if (-1 != discourse->pipe[0]) 99 close(discourse->pipe[0]); 100 if (-1 != discourse->pipe[1]) 101 close(discourse->pipe[1]); 102 103 GNUNET_free(discourse); 104 } 105 106 enum GNUNET_GenericReturnValue 107 discourse_subscribe (struct GNUNET_CHAT_Discourse *discourse, 108 struct GNUNET_CHAT_Contact *contact, 109 const struct GNUNET_TIME_Absolute timestamp, 110 const struct GNUNET_TIME_Relative time) 111 { 112 GNUNET_assert((discourse) && (contact)); 113 114 const struct GNUNET_TIME_Absolute end = GNUNET_TIME_absolute_add( 115 timestamp, 116 time 117 ); 118 119 if (GNUNET_TIME_absolute_cmp(end, <, GNUNET_TIME_absolute_get())) 120 return GNUNET_SYSERR; 121 122 struct GNUNET_CHAT_DiscourseSubscription *sub; 123 for (sub = discourse->head; sub; sub = sub->next) 124 if (sub->contact == contact) 125 break; 126 127 const enum GNUNET_GenericReturnValue update = ( 128 sub? GNUNET_YES : GNUNET_NO 129 ); 130 131 if (!sub) 132 { 133 sub = GNUNET_new(struct GNUNET_CHAT_DiscourseSubscription); 134 135 sub->prev = NULL; 136 sub->next = NULL; 137 138 sub->discourse = discourse; 139 sub->contact = contact; 140 141 GNUNET_CONTAINER_DLL_insert( 142 discourse->head, 143 discourse->tail, 144 sub 145 ); 146 } 147 else if (sub->task) 148 GNUNET_SCHEDULER_cancel(sub->task); 149 150 sub->start = timestamp; 151 sub->end = end; 152 153 sub->task = GNUNET_SCHEDULER_add_at( 154 end, 155 discourse_remove_subscription, 156 sub 157 ); 158 159 return update; 160 } 161 162 void 163 discourse_unsubscribe (struct GNUNET_CHAT_Discourse *discourse, 164 struct GNUNET_CHAT_Contact *contact, 165 const struct GNUNET_TIME_Absolute timestamp, 166 const struct GNUNET_TIME_Relative delay) 167 { 168 GNUNET_assert((discourse) && (contact)); 169 170 struct GNUNET_CHAT_DiscourseSubscription *sub; 171 for (sub = discourse->head; sub; sub = sub->next) 172 if (sub->contact == contact) 173 break; 174 175 if ((!sub) || (GNUNET_TIME_absolute_cmp(sub->start, >, timestamp))) 176 return; 177 178 const struct GNUNET_TIME_Absolute exit = GNUNET_TIME_absolute_add( 179 timestamp, delay 180 ); 181 182 if (GNUNET_TIME_absolute_cmp(exit, <, sub->end)) 183 sub->end = exit; 184 185 if (sub->task) 186 GNUNET_SCHEDULER_cancel(sub->task); 187 188 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 189 discourse_remove_subscription(sub); 190 else 191 sub->task = GNUNET_SCHEDULER_add_at( 192 sub->end, 193 discourse_remove_subscription, 194 sub 195 ); 196 }