diff options
Diffstat (limited to 'src/service/messenger/gnunet-service-messenger_service.c')
-rw-r--r-- | src/service/messenger/gnunet-service-messenger_service.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/src/service/messenger/gnunet-service-messenger_service.c b/src/service/messenger/gnunet-service-messenger_service.c new file mode 100644 index 000000000..b72bbd201 --- /dev/null +++ b/src/service/messenger/gnunet-service-messenger_service.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2020--2023 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_service.c | ||
23 | * @brief GNUnet MESSENGER service | ||
24 | */ | ||
25 | |||
26 | #include "platform.h" | ||
27 | #include "gnunet-service-messenger_service.h" | ||
28 | #include "gnunet-service-messenger.h" | ||
29 | #include "messenger_api_message_kind.h" | ||
30 | |||
31 | static void | ||
32 | callback_shutdown_service (void *cls) | ||
33 | { | ||
34 | struct GNUNET_MESSENGER_Service *service = cls; | ||
35 | |||
36 | if (service) | ||
37 | { | ||
38 | service->shutdown = NULL; | ||
39 | |||
40 | destroy_service (service); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | |||
45 | struct GNUNET_MESSENGER_Service* | ||
46 | create_service (const struct GNUNET_CONFIGURATION_Handle *config, | ||
47 | struct GNUNET_SERVICE_Handle *service_handle) | ||
48 | { | ||
49 | GNUNET_assert ((config) && (service_handle)); | ||
50 | |||
51 | struct GNUNET_MESSENGER_Service *service = GNUNET_new (struct | ||
52 | GNUNET_MESSENGER_Service); | ||
53 | |||
54 | service->config = config; | ||
55 | service->service = service_handle; | ||
56 | |||
57 | service->shutdown = GNUNET_SCHEDULER_add_shutdown (&callback_shutdown_service, | ||
58 | service); | ||
59 | |||
60 | service->peer = NULL; | ||
61 | service->dir = NULL; | ||
62 | |||
63 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (service->config, | ||
64 | GNUNET_MESSENGER_SERVICE_NAME, | ||
65 | "MESSENGER_DIR", | ||
66 | &(service->dir))) | ||
67 | { | ||
68 | if (service->dir) | ||
69 | GNUNET_free (service->dir); | ||
70 | |||
71 | service->dir = NULL; | ||
72 | } | ||
73 | else | ||
74 | { | ||
75 | if ((GNUNET_YES != GNUNET_DISK_directory_test (service->dir, GNUNET_YES)) && | ||
76 | (GNUNET_OK | ||
77 | != | ||
78 | GNUNET_DISK_directory_create (service->dir))) | ||
79 | { | ||
80 | GNUNET_free (service->dir); | ||
81 | |||
82 | service->dir = NULL; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | service->cadet = GNUNET_CADET_connect (service->config); | ||
87 | |||
88 | init_list_handles (&(service->handles)); | ||
89 | |||
90 | service->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO); | ||
91 | |||
92 | init_contact_store (get_service_contact_store (service)); | ||
93 | |||
94 | return service; | ||
95 | } | ||
96 | |||
97 | |||
98 | static int | ||
99 | iterate_destroy_rooms (void *cls, | ||
100 | const struct GNUNET_HashCode *key, | ||
101 | void *value) | ||
102 | { | ||
103 | struct GNUNET_MESSENGER_SrvRoom *room = value; | ||
104 | destroy_srv_room (room, GNUNET_NO); | ||
105 | return GNUNET_YES; | ||
106 | } | ||
107 | |||
108 | |||
109 | void | ||
110 | destroy_service (struct GNUNET_MESSENGER_Service *service) | ||
111 | { | ||
112 | GNUNET_assert (service); | ||
113 | |||
114 | if (service->shutdown) | ||
115 | { | ||
116 | GNUNET_SCHEDULER_cancel (service->shutdown); | ||
117 | |||
118 | service->shutdown = NULL; | ||
119 | } | ||
120 | |||
121 | clear_list_handles (&(service->handles)); | ||
122 | |||
123 | GNUNET_CONTAINER_multihashmap_iterate (service->rooms, iterate_destroy_rooms, | ||
124 | NULL); | ||
125 | GNUNET_CONTAINER_multihashmap_destroy (service->rooms); | ||
126 | |||
127 | clear_contact_store (get_service_contact_store (service)); | ||
128 | |||
129 | if (service->cadet) | ||
130 | { | ||
131 | GNUNET_CADET_disconnect (service->cadet); | ||
132 | |||
133 | service->cadet = NULL; | ||
134 | } | ||
135 | |||
136 | if (service->dir) | ||
137 | { | ||
138 | GNUNET_free (service->dir); | ||
139 | |||
140 | service->dir = NULL; | ||
141 | } | ||
142 | |||
143 | if (service->peer) | ||
144 | { | ||
145 | GNUNET_free (service->peer); | ||
146 | |||
147 | service->peer = NULL; | ||
148 | } | ||
149 | |||
150 | GNUNET_SERVICE_shutdown (service->service); | ||
151 | |||
152 | GNUNET_free (service); | ||
153 | } | ||
154 | |||
155 | |||
156 | struct GNUNET_MESSENGER_ContactStore* | ||
157 | get_service_contact_store (struct GNUNET_MESSENGER_Service *service) | ||
158 | { | ||
159 | GNUNET_assert (service); | ||
160 | |||
161 | return &(service->contact_store); | ||
162 | } | ||
163 | |||
164 | |||
165 | struct GNUNET_MESSENGER_SrvHandle* | ||
166 | add_service_handle (struct GNUNET_MESSENGER_Service *service, | ||
167 | struct GNUNET_MQ_Handle *mq) | ||
168 | { | ||
169 | GNUNET_assert ((service) && (mq)); | ||
170 | |||
171 | struct GNUNET_MESSENGER_SrvHandle *handle = create_srv_handle (service, mq); | ||
172 | |||
173 | if (handle) | ||
174 | { | ||
175 | add_list_handle (&(service->handles), handle); | ||
176 | } | ||
177 | |||
178 | return handle; | ||
179 | } | ||
180 | |||
181 | |||
182 | void | ||
183 | remove_service_handle (struct GNUNET_MESSENGER_Service *service, | ||
184 | struct GNUNET_MESSENGER_SrvHandle *handle) | ||
185 | { | ||
186 | GNUNET_assert ((service) && (handle)); | ||
187 | |||
188 | if (! handle) | ||
189 | return; | ||
190 | |||
191 | if (GNUNET_YES == remove_list_handle (&(service->handles), handle)) | ||
192 | destroy_srv_handle (handle); | ||
193 | } | ||
194 | |||
195 | |||
196 | int | ||
197 | get_service_peer_identity (struct GNUNET_MESSENGER_Service *service, | ||
198 | struct GNUNET_PeerIdentity *peer) | ||
199 | { | ||
200 | GNUNET_assert ((service) && (peer)); | ||
201 | |||
202 | if (service->peer) | ||
203 | { | ||
204 | GNUNET_memcpy (peer, service->peer, sizeof(struct GNUNET_PeerIdentity)); | ||
205 | return GNUNET_OK; | ||
206 | } | ||
207 | |||
208 | int result = GNUNET_CRYPTO_get_peer_identity (service->config, peer); | ||
209 | |||
210 | if (GNUNET_OK != result) | ||
211 | return result; | ||
212 | |||
213 | if (! service->peer) | ||
214 | service->peer = GNUNET_new (struct GNUNET_PeerIdentity); | ||
215 | |||
216 | GNUNET_memcpy (service->peer, peer, sizeof(struct GNUNET_PeerIdentity)); | ||
217 | return result; | ||
218 | } | ||
219 | |||
220 | |||
221 | struct GNUNET_MESSENGER_SrvRoom* | ||
222 | get_service_room (const struct GNUNET_MESSENGER_Service *service, | ||
223 | const struct GNUNET_HashCode *key) | ||
224 | { | ||
225 | GNUNET_assert ((service) && (key)); | ||
226 | |||
227 | return GNUNET_CONTAINER_multihashmap_get (service->rooms, key); | ||
228 | } | ||
229 | |||
230 | |||
231 | int | ||
232 | open_service_room (struct GNUNET_MESSENGER_Service *service, | ||
233 | struct GNUNET_MESSENGER_SrvHandle *handle, | ||
234 | const struct GNUNET_HashCode *key) | ||
235 | { | ||
236 | GNUNET_assert ((service) && (handle) && (key)); | ||
237 | |||
238 | struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key); | ||
239 | |||
240 | if (room) | ||
241 | return open_srv_room (room, handle); | ||
242 | |||
243 | room = create_srv_room (handle, key); | ||
244 | |||
245 | if ((GNUNET_YES == open_srv_room (room, handle)) && | ||
246 | (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->rooms, | ||
247 | key, room, | ||
248 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))) | ||
249 | return GNUNET_YES; | ||
250 | |||
251 | destroy_srv_room (room, GNUNET_YES); | ||
252 | return GNUNET_NO; | ||
253 | } | ||
254 | |||
255 | |||
256 | int | ||
257 | entry_service_room (struct GNUNET_MESSENGER_Service *service, | ||
258 | struct GNUNET_MESSENGER_SrvHandle *handle, | ||
259 | const struct GNUNET_PeerIdentity *door, | ||
260 | const struct GNUNET_HashCode *key) | ||
261 | { | ||
262 | GNUNET_assert ((service) && (handle) && (door) && (key)); | ||
263 | |||
264 | struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key); | ||
265 | |||
266 | if (room) | ||
267 | { | ||
268 | if (GNUNET_YES == enter_srv_room_at (room, handle, door)) | ||
269 | return GNUNET_YES; | ||
270 | else | ||
271 | return GNUNET_NO; | ||
272 | } | ||
273 | |||
274 | room = create_srv_room (handle, key); | ||
275 | |||
276 | if ((GNUNET_YES == enter_srv_room_at (room, handle, door)) && | ||
277 | (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->rooms, | ||
278 | key, room, | ||
279 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))) | ||
280 | { | ||
281 | return GNUNET_YES; | ||
282 | } | ||
283 | else | ||
284 | { | ||
285 | destroy_srv_room (room, GNUNET_YES); | ||
286 | return GNUNET_NO; | ||
287 | } | ||
288 | |||
289 | } | ||
290 | |||
291 | |||
292 | int | ||
293 | close_service_room (struct GNUNET_MESSENGER_Service *service, | ||
294 | struct GNUNET_MESSENGER_SrvHandle *handle, | ||
295 | const struct GNUNET_HashCode *key) | ||
296 | { | ||
297 | GNUNET_assert ((service) && (handle) && (key)); | ||
298 | |||
299 | struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key); | ||
300 | |||
301 | if (! room) | ||
302 | return GNUNET_NO; | ||
303 | |||
304 | const struct GNUNET_ShortHashCode *id = get_srv_handle_member_id (handle, | ||
305 | key); | ||
306 | |||
307 | GNUNET_assert (id); | ||
308 | |||
309 | if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (handle->member_ids, | ||
310 | key, id)) | ||
311 | return GNUNET_NO; | ||
312 | |||
313 | struct GNUNET_MESSENGER_SrvHandle *member_handle = (struct | ||
314 | GNUNET_MESSENGER_SrvHandle | ||
315 | *) | ||
316 | find_list_handle_by_member ( | ||
317 | &(service->handles), key); | ||
318 | |||
319 | if (! member_handle) | ||
320 | { | ||
321 | if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (service->rooms, key, | ||
322 | room)) | ||
323 | { | ||
324 | destroy_srv_room (room, GNUNET_YES); | ||
325 | return GNUNET_YES; | ||
326 | } | ||
327 | else | ||
328 | return GNUNET_NO; | ||
329 | } | ||
330 | |||
331 | if (room->host == handle) | ||
332 | room->host = member_handle; | ||
333 | |||
334 | return GNUNET_YES; | ||
335 | } | ||
336 | |||
337 | |||
338 | void | ||
339 | handle_service_message (struct GNUNET_MESSENGER_Service *service, | ||
340 | struct GNUNET_MESSENGER_SrvRoom *room, | ||
341 | const struct GNUNET_MESSENGER_SenderSession *session, | ||
342 | const struct GNUNET_MESSENGER_Message *message, | ||
343 | const struct GNUNET_HashCode *hash) | ||
344 | { | ||
345 | GNUNET_assert ((service) && (room) && (session) && (message) && (hash)); | ||
346 | |||
347 | struct GNUNET_MESSENGER_ListHandle *element = service->handles.head; | ||
348 | |||
349 | while (element) | ||
350 | { | ||
351 | notify_srv_handle_message (element->handle, room, session, message, hash); | ||
352 | element = element->next; | ||
353 | } | ||
354 | } | ||