aboutsummaryrefslogtreecommitdiff
path: root/src/ats/gnunet-service-ats-new.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-12-06 17:03:35 +0100
committerChristian Grothoff <christian@grothoff.org>2018-12-06 17:03:35 +0100
commite298fa7e3eeafea48a8abf6c5b8bf449b279e7a7 (patch)
tree953ffb47d5be13b73c4f220c27de5232c72855f6 /src/ats/gnunet-service-ats-new.c
parent898c6edf16913beacd9422622fb4469b6169a13b (diff)
downloadgnunet-e298fa7e3eeafea48a8abf6c5b8bf449b279e7a7.tar.gz
gnunet-e298fa7e3eeafea48a8abf6c5b8bf449b279e7a7.zip
high-level new ATS service implementation
Diffstat (limited to 'src/ats/gnunet-service-ats-new.c')
-rw-r--r--src/ats/gnunet-service-ats-new.c653
1 files changed, 653 insertions, 0 deletions
diff --git a/src/ats/gnunet-service-ats-new.c b/src/ats/gnunet-service-ats-new.c
new file mode 100644
index 000000000..57398e641
--- /dev/null
+++ b/src/ats/gnunet-service-ats-new.c
@@ -0,0 +1,653 @@
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/**
19 * @file ats/gnunet-service-ats-new.c
20 * @brief ats service
21 * @author Matthias Wachs
22 * @author Christian Grothoff
23 *
24 * TODO:
25 * - implement messages ATS -> transport
26 * - implement loading / unloading of ATS plugins
27 * - expose plugin the API to send messages ATS -> transport
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet_ats_plugin_new.h"
33#include "ats2.h"
34
35
36/**
37 * What type of client is this client?
38 */
39enum ClientType {
40 /**
41 * We don't know yet.
42 */
43 CT_NONE = 0,
44
45 /**
46 * Transport service.
47 */
48 CT_TRANSPORT,
49
50 /**
51 * Application.
52 */
53 CT_APPLICATION
54};
55
56
57/**
58 * Information we track per client.
59 */
60struct Client;
61
62/**
63 * Preferences expressed by a client are kept in a DLL per client.
64 */
65struct ClientPreference
66{
67 /**
68 * DLL pointer.
69 */
70 struct ClientPreference *next;
71
72 /**
73 * DLL pointer.
74 */
75 struct ClientPreference *prev;
76
77 /**
78 * Which client expressed the preference?
79 */
80 struct Client *client;
81
82 /**
83 * Plugin's representation of the preference.
84 */
85 struct GNUNET_ATS_PreferenceHandle *ph;
86
87 /**
88 * Details about the preference.
89 */
90 struct GNUNET_ATS_Preference pref;
91};
92
93
94/**
95 * Information about ongoing sessions of the transport client.
96 */
97struct GNUNET_ATS_Session
98{
99
100 /**
101 * Session data exposed to the plugin.
102 */
103 struct GNUNET_ATS_SessionData data;
104
105 /**
106 * The transport client that provided the session.
107 */
108 struct Client *client;
109
110 /**
111 * Session state in the plugin.
112 */
113 struct GNUNET_ATS_SessionHandle *sh;
114
115 /**
116 * Unique ID for the session when talking with the client.
117 */
118 uint32_t session_id;
119
120};
121
122
123/**
124 * Information we track per client.
125 */
126struct Client
127{
128 /**
129 * Type of the client, initially #CT_NONE.
130 */
131 enum ClientType type;
132
133 /**
134 * Service handle of the client.
135 */
136 struct GNUNET_SERVICE_Client *client;
137
138 /**
139 * Message queue to talk to the client.
140 */
141 struct GNUNET_MQ_Handle *mq;
142
143 /**
144 * Details depending on @e type.
145 */
146 union {
147
148 struct {
149
150 /**
151 * Head of DLL of preferences expressed by this client.
152 */
153 struct ClientPreference *cp_head;
154
155 /**
156 * Tail of DLL of preferences expressed by this client.
157 */
158 struct ClientPreference *cp_tail;
159
160 } application;
161
162 struct {
163
164 /**
165 * Map from session IDs to `struct GNUNET_ATS_Session` objects.
166 */
167 struct GNUNET_CONTAINER_MultiHashMap32 *sessions;
168
169 } transport;
170
171 } details;
172
173};
174
175
176/**
177 * Handle for statistics.
178 */
179static struct GNUNET_STATISTICS_Handle *GSA_stats;
180
181/**
182 * Our solver.
183 */
184static struct GNUNET_ATS_SolverFunctions *plugin;
185
186/**
187 * The transport client (there can only be one at a time).
188 */
189static struct Client *transport_client;
190
191
192/**
193 * Convert @a properties to @a prop
194 *
195 * @param properties in NBO
196 * @param prop[out] in HBO
197 */
198static void
199prop_ntoh (const struct PropertiesNBO *properties,
200 struct GNUNET_ATS_Properties *prop)
201{
202 prop->delay = GNUNET_TIME_relative_ntoh (properties->delay);
203 prop->goodput_out = ntohl (properties->goodput_out);
204 prop->goodput_in = ntohl (properties->goodput_in);
205 prop->utilization_out = ntohl (properties->utilization_out);
206 prop->utilization_in = ntohl (properties->utilization_in);
207 prop->distance = ntohl (properties->distance);
208 prop->mtu = ntohl (properties->mtu);
209 prop->nt = (enum GNUNET_NetworkType) ntohl (properties->nt);
210 prop->cc = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (properties->cc);
211}
212
213
214/**
215 * We have received a `struct ExpressPreferenceMessage` from an application client.
216 *
217 * @param cls handle to the client
218 * @param msg the start message
219 */
220static void
221handle_suggest (void *cls,
222 const struct ExpressPreferenceMessage *msg)
223{
224 struct Client *c = cls;
225 struct ClientPreference *cp;
226
227 if (CT_NONE == c->type)
228 c->type = CT_APPLICATION;
229 if (CT_APPLICATION != c->type)
230 {
231 GNUNET_break (0);
232 GNUNET_SERVICE_client_drop (c->client);
233 return;
234 }
235 cp = GNUNET_new (struct ClientPreference);
236 cp->client = c;
237 cp->pref.peer = msg->peer;
238 cp->pref.bw = msg->bw;
239 cp->pref.pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
240 cp->ph = plugin->preference_add (plugin->cls,
241 &cp->pref);
242 GNUNET_CONTAINER_DLL_insert (c->details.application.cp_head,
243 c->details.application.cp_tail,
244 cp);
245 GNUNET_SERVICE_client_continue (c->client);
246}
247
248
249/**
250 * We have received a `struct ExpressPreferenceMessage` from an application client.
251 *
252 * @param cls handle to the client
253 * @param msg the start message
254 */
255static void
256handle_suggest_cancel (void *cls,
257 const struct ExpressPreferenceMessage *msg)
258{
259 struct Client *c = cls;
260 struct ClientPreference *cp;
261
262 if (CT_NONE == c->type)
263 c->type = CT_APPLICATION;
264 if (CT_APPLICATION != c->type)
265 {
266 GNUNET_break (0);
267 GNUNET_SERVICE_client_drop (c->client);
268 return;
269 }
270 for (cp = c->details.application.cp_head;
271 NULL != cp;
272 cp = cp->next)
273 if ( (cp->pref.pk == (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk)) &&
274 (cp->pref.bw.value__ == msg->bw.value__) &&
275 (0 == memcmp (&cp->pref.peer,
276 &msg->peer,
277 sizeof (struct GNUNET_PeerIdentity))) )
278 break;
279 if (NULL == cp)
280 {
281 GNUNET_break (0);
282 GNUNET_SERVICE_client_drop (c->client);
283 return;
284 }
285 plugin->preference_del (plugin->cls,
286 cp->ph,
287 &cp->pref);
288 GNUNET_CONTAINER_DLL_remove (c->details.application.cp_head,
289 c->details.application.cp_tail,
290 cp);
291 GNUNET_free (cp);
292 GNUNET_SERVICE_client_continue (c->client);
293}
294
295
296/**
297 * Handle 'start' messages from transport clients.
298 *
299 * @param cls client that sent the request
300 * @param message the request message
301 */
302static void
303handle_start (void *cls,
304 const struct GNUNET_MessageHeader *hdr)
305{
306 struct Client *c = cls;
307
308 if (CT_NONE != c->type)
309 {
310 GNUNET_break (0);
311 GNUNET_SERVICE_client_drop (c->client);
312 return;
313 }
314 c->type = CT_TRANSPORT;
315 c->details.transport.sessions
316 = GNUNET_CONTAINER_multihashmap32_create (128);
317 if (NULL != transport_client)
318 {
319 GNUNET_SERVICE_client_drop (transport_client->client);
320 transport_client = NULL;
321 }
322 transport_client = c;
323 GNUNET_SERVICE_client_continue (c->client);
324}
325
326
327/**
328 * Check 'session_add' message is well-formed and comes from a
329 * transport client.
330 *
331 * @param cls client that sent the request
332 * @param message the request message
333 * @return #GNUNET_OK if @a message is well-formed
334 */
335static int
336check_session_add (void *cls,
337 const struct SessionAddMessage *message)
338{
339 struct Client *c = cls;
340
341 GNUNET_MQ_check_zero_termination (message);
342 if (CT_TRANSPORT != c->type)
343 {
344 GNUNET_break (0);
345 return GNUNET_SYSERR;
346 }
347 return GNUNET_OK;
348}
349
350
351/**
352 * Handle 'session add' messages from transport clients.
353 *
354 * @param cls client that sent the request
355 * @param message the request message
356 */
357static void
358handle_session_add (void *cls,
359 const struct SessionAddMessage *message)
360{
361 struct Client *c = cls;
362 struct GNUNET_ATS_Session *session;
363 int inbound_only = (GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY ==
364 ntohs (message->header.type));
365
366 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
367 message->session_id);
368 if (NULL != session)
369 {
370 GNUNET_break (0);
371 GNUNET_SERVICE_client_drop (c->client);
372 return;
373 }
374 session = GNUNET_new (struct GNUNET_ATS_Session);
375 session->data.session = session;
376 session->client = c;
377 session->session_id = message->session_id;
378 session->data.peer = message->peer;
379 prop_ntoh (&message->properties,
380 &session->data.prop);
381 session->data.inbound_only = inbound_only;
382 GNUNET_assert (GNUNET_YES ==
383 GNUNET_CONTAINER_multihashmap32_put (c->details.transport.sessions,
384 message->session_id,
385 session,
386 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
387 session->sh = plugin->session_add (plugin->cls,
388 &session->data);
389 GNUNET_SERVICE_client_continue (c->client);
390}
391
392
393
394/**
395 * Handle 'session update' messages from transport clients.
396 *
397 * @param cls client that sent the request
398 * @param msg the request message
399 */
400static void
401handle_session_update (void *cls,
402 const struct SessionUpdateMessage *msg)
403{
404 struct Client *c = cls;
405 struct GNUNET_ATS_Session *session;
406
407 if (CT_TRANSPORT != c->type)
408 {
409 GNUNET_break (0);
410 GNUNET_SERVICE_client_drop (c->client);
411 return;
412 }
413 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
414 msg->session_id);
415 if (NULL == session)
416 {
417 GNUNET_break (0);
418 GNUNET_SERVICE_client_drop (c->client);
419 return;
420 }
421 prop_ntoh (&msg->properties,
422 &session->data.prop);
423 plugin->session_update (plugin->cls,
424 session->sh,
425 &session->data);
426 GNUNET_SERVICE_client_continue (c->client);
427}
428
429
430/**
431 * Handle 'session delete' messages from transport clients.
432 *
433 * @param cls client that sent the request
434 * @param message the request message
435 */
436static void
437handle_session_del (void *cls,
438 const struct SessionDelMessage *message)
439{
440 struct Client *c = cls;
441 struct GNUNET_ATS_Session *session;
442
443 if (CT_TRANSPORT != c->type)
444 {
445 GNUNET_break (0);
446 GNUNET_SERVICE_client_drop (c->client);
447 return;
448 }
449 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
450 message->session_id);
451 if (NULL == session)
452 {
453 GNUNET_break (0);
454 GNUNET_SERVICE_client_drop (c->client);
455 return;
456 }
457 plugin->session_del (plugin->cls,
458 session->sh,
459 &session->data);
460 GNUNET_assert (GNUNET_YES ==
461 GNUNET_CONTAINER_multihashmap32_remove (c->details.transport.sessions,
462 session->session_id,
463 session));
464 GNUNET_free (session);
465 GNUNET_SERVICE_client_continue (c->client);
466}
467
468
469/**
470 * A client connected to us. Setup the local client
471 * record.
472 *
473 * @param cls unused
474 * @param client handle of the client
475 * @param mq message queue to talk to @a client
476 * @return @a client
477 */
478static void *
479client_connect_cb (void *cls,
480 struct GNUNET_SERVICE_Client *client,
481 struct GNUNET_MQ_Handle *mq)
482{
483 struct Client *c = GNUNET_new (struct Client);
484
485 c->client = client;
486 c->mq = mq;
487 return c;
488}
489
490
491/**
492 * Function called on each session to release associated state
493 * on transport disconnect.
494 *
495 * @param cls the `struct Client`
496 * @param key unused (session_id)
497 * @param value a `struct GNUNET_ATS_Session`
498 */
499static int
500free_session (void *cls,
501 uint32_t key,
502 void *value)
503{
504 struct Client *c = cls;
505 struct GNUNET_ATS_Session *session = value;
506
507 (void) key;
508 GNUNET_assert (c == session->client);
509 plugin->session_del (plugin->cls,
510 session->sh,
511 &session->data);
512 GNUNET_free (session);
513 return GNUNET_OK;
514}
515
516
517/**
518 * A client disconnected from us. Tear down the local client
519 * record.
520 *
521 * @param cls unused
522 * @param client handle of the client
523 * @param app_ctx our `struct Client`
524 */
525static void
526client_disconnect_cb (void *cls,
527 struct GNUNET_SERVICE_Client *client,
528 void *app_ctx)
529{
530 struct Client *c = app_ctx;
531
532 (void) cls;
533 GNUNET_assert (c->client == client);
534 switch (c->type)
535 {
536 case CT_NONE:
537 break;
538 case CT_APPLICATION:
539 for (struct ClientPreference *cp = c->details.application.cp_head;
540 NULL != cp;
541 cp = c->details.application.cp_head)
542 {
543 plugin->preference_del (plugin->cls,
544 cp->ph,
545 &cp->pref);
546 GNUNET_CONTAINER_DLL_remove (c->details.application.cp_head,
547 c->details.application.cp_tail,
548 cp);
549 GNUNET_free (cp);
550 }
551 break;
552 case CT_TRANSPORT:
553 if (transport_client == c)
554 transport_client = NULL;
555 GNUNET_CONTAINER_multihashmap32_iterate (c->details.transport.sessions,
556 &free_session,
557 c);
558 GNUNET_CONTAINER_multihashmap32_destroy (c->details.transport.sessions);
559 break;
560 }
561 GNUNET_free (c);
562}
563
564
565/**
566 * Task run during shutdown.
567 *
568 * @param cls unused
569 */
570static void
571cleanup_task (void *cls)
572{
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "ATS shutdown initiated\n");
575 if (NULL != GSA_stats)
576 {
577 GNUNET_STATISTICS_destroy (GSA_stats,
578 GNUNET_NO);
579 GSA_stats = NULL;
580 }
581}
582
583
584/**
585 * Process template requests.
586 *
587 * @param cls closure
588 * @param cfg configuration to use
589 * @param service the initialized service
590 */
591static void
592run (void *cls,
593 const struct GNUNET_CONFIGURATION_Handle *cfg,
594 struct GNUNET_SERVICE_Handle *service)
595{
596 GSA_stats = GNUNET_STATISTICS_create ("ats",
597 cfg);
598 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
599 NULL);
600#if 0
601 if (GNUNET_OK !=
602 GAS_plugin_init (cfg))
603 {
604 GNUNET_break (0);
605 GNUNET_SCHEDULER_shutdown ();
606 return;
607 }
608#endif
609}
610
611
612/**
613 * Define "main" method using service macro.
614 */
615GNUNET_SERVICE_MAIN
616("ats",
617 GNUNET_SERVICE_OPTION_NONE,
618 &run,
619 &client_connect_cb,
620 &client_disconnect_cb,
621 NULL,
622 GNUNET_MQ_hd_fixed_size (suggest,
623 GNUNET_MESSAGE_TYPE_ATS_SUGGEST,
624 struct ExpressPreferenceMessage,
625 NULL),
626 GNUNET_MQ_hd_fixed_size (suggest_cancel,
627 GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL,
628 struct ExpressPreferenceMessage,
629 NULL),
630 GNUNET_MQ_hd_fixed_size (start,
631 GNUNET_MESSAGE_TYPE_ATS_START,
632 struct GNUNET_MessageHeader,
633 NULL),
634 GNUNET_MQ_hd_var_size (session_add,
635 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD,
636 struct SessionAddMessage,
637 NULL),
638 GNUNET_MQ_hd_var_size (session_add,
639 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY,
640 struct SessionAddMessage,
641 NULL),
642 GNUNET_MQ_hd_fixed_size (session_update,
643 GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE,
644 struct SessionUpdateMessage,
645 NULL),
646 GNUNET_MQ_hd_fixed_size (session_del,
647 GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL,
648 struct SessionDelMessage,
649 NULL),
650 GNUNET_MQ_handler_end ());
651
652
653/* end of gnunet-service-ats.c */