summaryrefslogtreecommitdiff
path: root/src/ats/gnunet-service-ats-new.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ats/gnunet-service-ats-new.c')
-rw-r--r--src/ats/gnunet-service-ats-new.c804
1 files changed, 0 insertions, 804 deletions
diff --git a/src/ats/gnunet-service-ats-new.c b/src/ats/gnunet-service-ats-new.c
deleted file mode 100644
index f2ef92436..000000000
--- a/src/ats/gnunet-service-ats-new.c
+++ /dev/null
@@ -1,804 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2018 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 * @file ats/gnunet-service-ats-new.c
22 * @brief ats service
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_ats_plugin_new.h"
30#include "ats2.h"
31
32
33/**
34 * What type of client is this client?
35 */
36enum ClientType
37{
38 /**
39 * We don't know yet.
40 */
41 CT_NONE = 0,
42
43 /**
44 * Transport service.
45 */
46 CT_TRANSPORT,
47
48 /**
49 * Application.
50 */
51 CT_APPLICATION
52};
53
54
55/**
56 * Information we track per client.
57 */
58struct Client;
59
60/**
61 * Preferences expressed by a client are kept in a DLL per client.
62 */
63struct ClientPreference
64{
65 /**
66 * DLL pointer.
67 */
68 struct ClientPreference *next;
69
70 /**
71 * DLL pointer.
72 */
73 struct ClientPreference *prev;
74
75 /**
76 * Which client expressed the preference?
77 */
78 struct Client *client;
79
80 /**
81 * Plugin's representation of the preference.
82 */
83 struct GNUNET_ATS_PreferenceHandle *ph;
84
85 /**
86 * Details about the preference.
87 */
88 struct GNUNET_ATS_Preference pref;
89};
90
91
92/**
93 * Information about ongoing sessions of the transport client.
94 */
95struct GNUNET_ATS_Session
96{
97 /**
98 * Session data exposed to the plugin.
99 */
100 struct GNUNET_ATS_SessionData data;
101
102 /**
103 * The transport client that provided the session.
104 */
105 struct Client *client;
106
107 /**
108 * Session state in the plugin.
109 */
110 struct GNUNET_ATS_SessionHandle *sh;
111
112 /**
113 * Unique ID for the session when talking with the client.
114 */
115 uint32_t session_id;
116};
117
118
119/**
120 * Information we track per client.
121 */
122struct Client
123{
124 /**
125 * Type of the client, initially #CT_NONE.
126 */
127 enum ClientType type;
128
129 /**
130 * Service handle of the client.
131 */
132 struct GNUNET_SERVICE_Client *client;
133
134 /**
135 * Message queue to talk to the client.
136 */
137 struct GNUNET_MQ_Handle *mq;
138
139 /**
140 * Details depending on @e type.
141 */
142 union
143 {
144 struct
145 {
146 /**
147 * Head of DLL of preferences expressed by this client.
148 */
149 struct ClientPreference *cp_head;
150
151 /**
152 * Tail of DLL of preferences expressed by this client.
153 */
154 struct ClientPreference *cp_tail;
155 } application;
156
157 struct
158 {
159 /**
160 * Map from session IDs to `struct GNUNET_ATS_Session` objects.
161 */
162 struct GNUNET_CONTAINER_MultiHashMap32 *sessions;
163 } transport;
164 } details;
165};
166
167
168/**
169 * Handle for statistics.
170 */
171static struct GNUNET_STATISTICS_Handle *stats;
172
173/**
174 * Our solver.
175 */
176static struct GNUNET_ATS_SolverFunctions *plugin;
177
178/**
179 * Solver plugin name as string
180 */
181static char *plugin_name;
182
183/**
184 * The transport client (there can only be one at a time).
185 */
186static struct Client *transport_client;
187
188
189/**
190 * Function called by the solver to prompt the transport to
191 * try out a new address.
192 *
193 * @param cls closure, NULL
194 * @param pid peer this is about
195 * @param address address the transport should try
196 */
197static void
198suggest_cb (void *cls,
199 const struct GNUNET_PeerIdentity *pid,
200 const char *address)
201{
202 struct GNUNET_MQ_Envelope *env;
203 size_t slen = strlen (address) + 1;
204 struct AddressSuggestionMessage *as;
205
206 if (NULL == transport_client)
207 {
208 // FIXME: stats!
209 return;
210 }
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212 "Suggesting address `%s' of peer `%s'\n",
213 address,
214 GNUNET_i2s (pid));
215 env = GNUNET_MQ_msg_extra (as,
216 slen,
217 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION);
218 as->peer = *pid;
219 memcpy (&as[1],
220 address,
221 slen);
222 GNUNET_MQ_send (transport_client->mq,
223 env);
224}
225
226
227/**
228 * Function called by the solver to tell the transpor to
229 * allocate bandwidth for the specified session.
230 *
231 * @param cls closure, NULL
232 * @param session session this is about
233 * @param peer peer this is about
234 * @param bw_in suggested bandwidth for receiving
235 * @param bw_out suggested bandwidth for transmission
236 */
237static void
238allocate_cb (void *cls,
239 struct GNUNET_ATS_Session *session,
240 const struct GNUNET_PeerIdentity *peer,
241 struct GNUNET_BANDWIDTH_Value32NBO bw_in,
242 struct GNUNET_BANDWIDTH_Value32NBO bw_out)
243{
244 struct GNUNET_MQ_Envelope *env;
245 struct SessionAllocationMessage *sam;
246
247 (void) cls;
248 if ((NULL == transport_client) ||
249 (session->client != transport_client))
250 {
251 /* transport must have just died and solver is addressing the
252 losses of sessions (possibly of previous transport), ignore! */
253 return;
254 }
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256 "Allocating %u/%u bytes for %p of peer `%s'\n",
257 ntohl (bw_in.value__),
258 ntohl (bw_out.value__),
259 session,
260 GNUNET_i2s (peer));
261 env = GNUNET_MQ_msg (sam,
262 GNUNET_MESSAGE_TYPE_ATS_SESSION_ALLOCATION);
263 sam->session_id = session->session_id;
264 sam->peer = *peer;
265 sam->bandwidth_in = bw_in;
266 sam->bandwidth_out = bw_out;
267 GNUNET_MQ_send (transport_client->mq,
268 env);
269}
270
271
272/**
273 * Convert @a properties to @a prop
274 *
275 * @param properties in NBO
276 * @param prop[out] in HBO
277 */
278static void
279prop_ntoh (const struct PropertiesNBO *properties,
280 struct GNUNET_ATS_Properties *prop)
281{
282 prop->delay = GNUNET_TIME_relative_ntoh (properties->delay);
283 prop->goodput_out = ntohl (properties->goodput_out);
284 prop->goodput_in = ntohl (properties->goodput_in);
285 prop->utilization_out = ntohl (properties->utilization_out);
286 prop->utilization_in = ntohl (properties->utilization_in);
287 prop->distance = ntohl (properties->distance);
288 prop->mtu = ntohl (properties->mtu);
289 prop->nt = (enum GNUNET_NetworkType) ntohl (properties->nt);
290 prop->cc = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (
291 properties->cc);
292}
293
294
295/**
296 * We have received a `struct ExpressPreferenceMessage` from an application client.
297 *
298 * @param cls handle to the client
299 * @param msg the start message
300 */
301static void
302handle_suggest (void *cls,
303 const struct ExpressPreferenceMessage *msg)
304{
305 struct Client *c = cls;
306 struct ClientPreference *cp;
307
308 if (CT_NONE == c->type)
309 c->type = CT_APPLICATION;
310 if (CT_APPLICATION != c->type)
311 {
312 GNUNET_break (0);
313 GNUNET_SERVICE_client_drop (c->client);
314 return;
315 }
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "Client suggested we talk to %s with preference %d at rate %u\n",
318 GNUNET_i2s (&msg->peer),
319 (int) ntohl (msg->pk),
320 (int) ntohl (msg->bw.value__));
321 cp = GNUNET_new (struct ClientPreference);
322 cp->client = c;
323 cp->pref.peer = msg->peer;
324 cp->pref.bw = msg->bw;
325 cp->pref.pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
326 cp->ph = plugin->preference_add (plugin->cls,
327 &cp->pref);
328 GNUNET_CONTAINER_DLL_insert (c->details.application.cp_head,
329 c->details.application.cp_tail,
330 cp);
331 GNUNET_SERVICE_client_continue (c->client);
332}
333
334
335/**
336 * We have received a `struct ExpressPreferenceMessage` from an application client.
337 *
338 * @param cls handle to the client
339 * @param msg the start message
340 */
341static void
342handle_suggest_cancel (void *cls,
343 const struct ExpressPreferenceMessage *msg)
344{
345 struct Client *c = cls;
346 struct ClientPreference *cp;
347
348 if (CT_NONE == c->type)
349 c->type = CT_APPLICATION;
350 if (CT_APPLICATION != c->type)
351 {
352 GNUNET_break (0);
353 GNUNET_SERVICE_client_drop (c->client);
354 return;
355 }
356 for (cp = c->details.application.cp_head;
357 NULL != cp;
358 cp = cp->next)
359 if ((cp->pref.pk == (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk)) &&
360 (cp->pref.bw.value__ == msg->bw.value__) &&
361 (0 == GNUNET_memcmp (&cp->pref.peer,
362 &msg->peer)))
363 break;
364 if (NULL == cp)
365 {
366 GNUNET_break (0);
367 GNUNET_SERVICE_client_drop (c->client);
368 return;
369 }
370 plugin->preference_del (plugin->cls,
371 cp->ph,
372 &cp->pref);
373 GNUNET_CONTAINER_DLL_remove (c->details.application.cp_head,
374 c->details.application.cp_tail,
375 cp);
376 GNUNET_free (cp);
377 GNUNET_SERVICE_client_continue (c->client);
378}
379
380
381/**
382 * Handle 'start' messages from transport clients.
383 *
384 * @param cls client that sent the request
385 * @param message the request message
386 */
387static void
388handle_start (void *cls,
389 const struct GNUNET_MessageHeader *hdr)
390{
391 struct Client *c = cls;
392
393 if (CT_NONE != c->type)
394 {
395 GNUNET_break (0);
396 GNUNET_SERVICE_client_drop (c->client);
397 return;
398 }
399 c->type = CT_TRANSPORT;
400 c->details.transport.sessions
401 = GNUNET_CONTAINER_multihashmap32_create (128);
402 if (NULL != transport_client)
403 {
404 GNUNET_SERVICE_client_drop (transport_client->client);
405 transport_client = NULL;
406 }
407 transport_client = c;
408 GNUNET_SERVICE_client_continue (c->client);
409}
410
411
412/**
413 * Check 'session_add' message is well-formed and comes from a
414 * transport client.
415 *
416 * @param cls client that sent the request
417 * @param message the request message
418 * @return #GNUNET_OK if @a message is well-formed
419 */
420static int
421check_session_add (void *cls,
422 const struct SessionAddMessage *message)
423{
424 struct Client *c = cls;
425
426 GNUNET_MQ_check_zero_termination (message);
427 if (CT_TRANSPORT != c->type)
428 {
429 GNUNET_break (0);
430 return GNUNET_SYSERR;
431 }
432 return GNUNET_OK;
433}
434
435
436/**
437 * Handle 'session add' messages from transport clients.
438 *
439 * @param cls client that sent the request
440 * @param message the request message
441 */
442static void
443handle_session_add (void *cls,
444 const struct SessionAddMessage *message)
445{
446 struct Client *c = cls;
447 const char *address = (const char *) &message[1];
448 struct GNUNET_ATS_Session *session;
449 int inbound_only = (GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY ==
450 ntohs (message->header.type));
451
452 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
453 message->session_id);
454 if (NULL != session)
455 {
456 GNUNET_break (0);
457 GNUNET_SERVICE_client_drop (c->client);
458 return;
459 }
460 session = GNUNET_new (struct GNUNET_ATS_Session);
461 session->data.session = session;
462 session->client = c;
463 session->session_id = message->session_id;
464 session->data.peer = message->peer;
465 prop_ntoh (&message->properties,
466 &session->data.prop);
467 session->data.inbound_only = inbound_only;
468 GNUNET_assert (GNUNET_YES ==
469 GNUNET_CONTAINER_multihashmap32_put (
470 c->details.transport.sessions,
471 message->session_id,
472 session,
473 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
474 session->sh = plugin->session_add (plugin->cls,
475 &session->data,
476 address);
477 GNUNET_assert (NULL != session->sh);
478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
479 "Transport has new session %p to %s\n",
480 session,
481 GNUNET_i2s (&message->peer));
482 GNUNET_SERVICE_client_continue (c->client);
483}
484
485
486/**
487 * Handle 'session update' messages from transport clients.
488 *
489 * @param cls client that sent the request
490 * @param msg the request message
491 */
492static void
493handle_session_update (void *cls,
494 const struct SessionUpdateMessage *msg)
495{
496 struct Client *c = cls;
497 struct GNUNET_ATS_Session *session;
498
499 if (CT_TRANSPORT != c->type)
500 {
501 GNUNET_break (0);
502 GNUNET_SERVICE_client_drop (c->client);
503 return;
504 }
505 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
506 msg->session_id);
507 if (NULL == session)
508 {
509 GNUNET_break (0);
510 GNUNET_SERVICE_client_drop (c->client);
511 return;
512 }
513 prop_ntoh (&msg->properties,
514 &session->data.prop);
515 plugin->session_update (plugin->cls,
516 session->sh,
517 &session->data);
518 GNUNET_SERVICE_client_continue (c->client);
519}
520
521
522/**
523 * Handle 'session delete' messages from transport clients.
524 *
525 * @param cls client that sent the request
526 * @param message the request message
527 */
528static void
529handle_session_del (void *cls,
530 const struct SessionDelMessage *message)
531{
532 struct Client *c = cls;
533 struct GNUNET_ATS_Session *session;
534
535 if (CT_TRANSPORT != c->type)
536 {
537 GNUNET_break (0);
538 GNUNET_SERVICE_client_drop (c->client);
539 return;
540 }
541 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
542 message->session_id);
543 if (NULL == session)
544 {
545 GNUNET_break (0);
546 GNUNET_SERVICE_client_drop (c->client);
547 return;
548 }
549 GNUNET_assert (NULL != session->sh);
550 plugin->session_del (plugin->cls,
551 session->sh,
552 &session->data);
553 session->sh = NULL;
554 GNUNET_assert (GNUNET_YES ==
555 GNUNET_CONTAINER_multihashmap32_remove (
556 c->details.transport.sessions,
557 session->session_id,
558 session));
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "Transport lost session %p to %s\n",
561 session,
562 GNUNET_i2s (&session->data.peer));
563 GNUNET_free (session);
564 GNUNET_SERVICE_client_continue (c->client);
565}
566
567
568/**
569 * A client connected to us. Setup the local client
570 * record.
571 *
572 * @param cls unused
573 * @param client handle of the client
574 * @param mq message queue to talk to @a client
575 * @return @a client
576 */
577static void *
578client_connect_cb (void *cls,
579 struct GNUNET_SERVICE_Client *client,
580 struct GNUNET_MQ_Handle *mq)
581{
582 struct Client *c = GNUNET_new (struct Client);
583
584 c->client = client;
585 c->mq = mq;
586 return c;
587}
588
589
590/**
591 * Function called on each session to release associated state
592 * on transport disconnect.
593 *
594 * @param cls the `struct Client`
595 * @param key unused (session_id)
596 * @param value a `struct GNUNET_ATS_Session`
597 */
598static int
599free_session (void *cls,
600 uint32_t key,
601 void *value)
602{
603 struct Client *c = cls;
604 struct GNUNET_ATS_Session *session = value;
605
606 (void) key;
607 GNUNET_assert (c == session->client);
608 GNUNET_assert (NULL != session->sh);
609 plugin->session_del (plugin->cls,
610 session->sh,
611 &session->data);
612 session->sh = NULL;
613 GNUNET_free (session);
614 return GNUNET_OK;
615}
616
617
618/**
619 * A client disconnected from us. Tear down the local client
620 * record.
621 *
622 * @param cls unused
623 * @param client handle of the client
624 * @param app_ctx our `struct Client`
625 */
626static void
627client_disconnect_cb (void *cls,
628 struct GNUNET_SERVICE_Client *client,
629 void *app_ctx)
630{
631 struct Client *c = app_ctx;
632
633 (void) cls;
634 GNUNET_assert (c->client == client);
635 switch (c->type)
636 {
637 case CT_NONE:
638 break;
639
640 case CT_APPLICATION:
641 for (struct ClientPreference *cp = c->details.application.cp_head;
642 NULL != cp;
643 cp = c->details.application.cp_head)
644 {
645 plugin->preference_del (plugin->cls,
646 cp->ph,
647 &cp->pref);
648 GNUNET_CONTAINER_DLL_remove (c->details.application.cp_head,
649 c->details.application.cp_tail,
650 cp);
651 GNUNET_free (cp);
652 }
653 break;
654
655 case CT_TRANSPORT:
656 if (transport_client == c)
657 transport_client = NULL;
658 GNUNET_CONTAINER_multihashmap32_iterate (c->details.transport.sessions,
659 &free_session,
660 c);
661 GNUNET_CONTAINER_multihashmap32_destroy (c->details.transport.sessions);
662 break;
663 }
664 GNUNET_free (c);
665}
666
667
668/**
669 * Task run at the end during shutdown.
670 *
671 * @param cls unused
672 */
673static void
674final_cleanup (void *cls)
675{
676 (void) cls;
677 if (NULL != stats)
678 {
679 GNUNET_STATISTICS_destroy (stats,
680 GNUNET_NO);
681 stats = NULL;
682 }
683 if (NULL != plugin)
684 {
685 GNUNET_PLUGIN_unload (plugin_name,
686 plugin);
687 plugin = NULL;
688 }
689 if (NULL != plugin_name)
690 {
691 GNUNET_free (plugin_name);
692 plugin_name = NULL;
693 }
694}
695
696
697/**
698 * Task run during shutdown.
699 *
700 * @param cls unused
701 */
702static void
703cleanup_task (void *cls)
704{
705 (void) cls;
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707 "ATS shutdown initiated\n");
708 GNUNET_SCHEDULER_add_now (&final_cleanup,
709 NULL);
710}
711
712
713/**
714 * Process template requests.
715 *
716 * @param cls closure
717 * @param cfg configuration to use
718 * @param service the initialized service
719 */
720static void
721run (void *cls,
722 const struct GNUNET_CONFIGURATION_Handle *cfg,
723 struct GNUNET_SERVICE_Handle *service)
724{
725 static struct GNUNET_ATS_PluginEnvironment env;
726 char *solver;
727
728 stats = GNUNET_STATISTICS_create ("ats",
729 cfg);
730 if (GNUNET_SYSERR ==
731 GNUNET_CONFIGURATION_get_value_string (cfg,
732 "ats",
733 "SOLVER",
734 &solver))
735 {
736 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
737 "No ATS solver configured, using 'simple' approach\n");
738 solver = GNUNET_strdup ("simple");
739 }
740 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
741 NULL);
742 env.cls = NULL;
743 env.cfg = cfg;
744 env.stats = stats;
745 env.suggest_cb = &suggest_cb;
746 env.allocate_cb = &allocate_cb;
747 GNUNET_asprintf (&plugin_name,
748 "libgnunet_plugin_ats2_%s",
749 solver);
750 GNUNET_free (solver);
751 if (NULL == (plugin = GNUNET_PLUGIN_load (plugin_name,
752 &env)))
753 {
754 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
755 _ ("Failed to initialize solver `%s'!\n"),
756 plugin_name);
757 GNUNET_SCHEDULER_shutdown ();
758 return;
759 }
760}
761
762
763/**
764 * Define "main" method using service macro.
765 */
766GNUNET_SERVICE_MAIN
767 ("ats",
768 GNUNET_SERVICE_OPTION_NONE,
769 &run,
770 &client_connect_cb,
771 &client_disconnect_cb,
772 NULL,
773 GNUNET_MQ_hd_fixed_size (suggest,
774 GNUNET_MESSAGE_TYPE_ATS_SUGGEST,
775 struct ExpressPreferenceMessage,
776 NULL),
777 GNUNET_MQ_hd_fixed_size (suggest_cancel,
778 GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL,
779 struct ExpressPreferenceMessage,
780 NULL),
781 GNUNET_MQ_hd_fixed_size (start,
782 GNUNET_MESSAGE_TYPE_ATS_START,
783 struct GNUNET_MessageHeader,
784 NULL),
785 GNUNET_MQ_hd_var_size (session_add,
786 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD,
787 struct SessionAddMessage,
788 NULL),
789 GNUNET_MQ_hd_var_size (session_add,
790 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY,
791 struct SessionAddMessage,
792 NULL),
793 GNUNET_MQ_hd_fixed_size (session_update,
794 GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE,
795 struct SessionUpdateMessage,
796 NULL),
797 GNUNET_MQ_hd_fixed_size (session_del,
798 GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL,
799 struct SessionDelMessage,
800 NULL),
801 GNUNET_MQ_handler_end ());
802
803
804/* end of gnunet-service-ats.c */