skeleton for 'simple' ATS2 plugin
[oweals/gnunet.git] / src / ats / plugin_ats2_simple.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-2015, 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/plugin_ats2_simple.c
20  * @brief ATS simple solver
21  * @author Matthias Wachs
22  * @author Christian Grothoff
23  *
24  * TODO:
25  * - subscribe to PEERSTORE when short on HELLOs (given application preferences!)
26  * - keep track of HELLOs and when we tried them last => re-suggest 
27  * - sum up preferences per peer, keep totals! => PeerMap pid -> [preferences + sessions + addrs!]
28  * - sum up preferences overall, keep global sum => starting point for "proportional"
29  * - store DLL of available sessions per peer
30  */
31 #include "platform.h"
32 #include "gnunet_ats_plugin_new.h"
33 #include "gnunet_peerstore_service.h"
34
35 #define LOG(kind,...) GNUNET_log_from (kind, "ats-simple",__VA_ARGS__)
36
37
38 /**
39  * Entry in list of addresses we could try per peer.
40  */
41 struct Hello
42 {
43
44   /**
45    * Kept in a DLL.
46    */
47   struct Hello *next;
48
49   /**
50    * Kept in a DLL.
51    */
52   struct Hello *prev;
53   
54   /**
55    * The address we could try.
56    */
57   const char *address;
58
59   /**
60    * When did we try it last?
61    */
62   struct GNUNET_TIME_Absolute last_attempt;
63
64   /**
65    * Current exponential backoff value.
66    */
67   struct GNUNET_TIME_Relative backoff;
68
69   /**
70    * Is a session with this address already up?
71    * If not, set to NULL.
72    */
73   struct GNUNET_ATS_SessionHandle *sh;
74
75 };
76
77
78 /**
79  * Internal representation of a session by the plugin.
80  * (If desired, plugin may just use NULL.)
81  */
82 struct GNUNET_ATS_SessionHandle
83 {
84
85   /**
86    * Kept in DLL per peer.
87    */
88   struct GNUNET_ATS_SessionHandle *next;
89
90   /**
91    * Kept in DLL per peer.
92    */
93   struct GNUNET_ATS_SessionHandle *prev;
94   
95   /**
96    * The session in the main ATS service.
97    */
98   struct GNUNET_ATS_Session *session;
99
100   /**
101    * Current performance data for this @e session
102    */
103   const struct GNUNET_ATS_SessionData *data;
104
105   /**
106    * Hello matching this session, or NULL for none.
107    */
108   struct Hello *hello;
109   
110   /**
111    * Address used by this session (largely for debugging).
112    */
113   const char *address;
114
115   /**
116    * Last BW-in allocation given to the transport service.
117    */
118   struct GNUNET_BANDWIDTH_Value32NBO bw_in;
119
120   /**
121    * Last BW-out allocation given to the transport service.
122    */
123   struct GNUNET_BANDWIDTH_Value32NBO bw_out;
124
125 };
126
127
128 /**
129  * Information about preferences and sessions we track
130  * per peer.
131  */
132 struct Peer
133 {
134
135   /**
136    * Kept in DLL per peer.
137    */
138   struct GNUNET_ATS_SessionHandle *sh_head;
139
140   /**
141    * Kept in DLL per peer.
142    */
143   struct GNUNET_ATS_SessionHandle *sh_tail;
144
145   /**
146    * Which peer is this for?
147    */
148   struct GNUNET_PeerIdentity pid;
149
150   /**
151    * Array where we sum up the bandwidth requests received indexed
152    * by preference kind (see `struct GNUNET_MQ_PreferenceKind`)
153    */
154   uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT];
155
156   /**
157    * Watch context where we are currently looking for HELLOs for
158    * this peer.
159    */
160   struct GNUNET_PEERSTORE_WatchContext *wc;
161
162   /**
163    * Task used to try again to suggest an address for this peer.
164    */
165   struct GNUNET_SCHEDULER_TaskHandle *task;  
166  
167 };
168
169
170 /**
171  * Representation of a network (to be expanded...)
172  */
173 struct Network
174 {
175
176   /**
177    * Total inbound quota
178    */
179   unsigned long long total_quota_in;
180
181   /**
182    * Total outbound quota
183    */
184   unsigned long long total_quota_out;
185
186   /**
187    * ATS network type
188    */
189   enum GNUNET_NetworkType type;
190
191 };
192
193
194 /**
195  * A handle for the proportional solver
196  */
197 struct SimpleHandle
198 {
199
200   /**
201    * Our execution environment.
202    */
203   struct GNUNET_ATS_PluginEnvironment *env;
204
205   /**
206    * Information we track for each peer.
207    */
208   struct GNUNET_CONTAINER_MultiPeerMap *peers;
209
210   /**
211    * Information we track per network type (quotas).
212    */
213   struct Network networks[GNUNET_NT_COUNT];
214
215   /**
216    * Handle to the peerstore service.
217    */
218   struct GNUNET_PEERSTORE_Handle *ps;
219   
220 };
221
222
223 /**
224  * The world changed, recalculate our allocations.
225  */
226 static void
227 update (struct SimpleHandle *h)
228 {
229   // recalculate allocations
230   // notify transport if it makes sense (delta significant)
231 }
232
233
234 /**
235  * The plugin should begin to respect a new preference.
236  *
237  * @param cls the closure
238  * @param pref the preference to add
239  * @return plugin's internal representation, or NULL
240  */
241 static struct GNUNET_ATS_PreferenceHandle *
242 simple_preference_add (void *cls,
243                        const struct GNUNET_ATS_Preference *pref)
244 {
245   struct SimpleHandle *h = cls;
246   // Setup peer if necessary (-> including HELLO triggers!)
247   // add pref to bw_by_pk
248   // trigger update
249   return NULL;
250 }
251
252
253 /**
254  * The plugin should end respecting a preference.
255  *
256  * @param cls the closure
257  * @param ph whatever @e preference_add returned 
258  * @param pref the preference to delete
259  * @return plugin's internal representation, or NULL
260  */
261 static void
262 simple_preference_del (void *cls,                   
263                        struct GNUNET_ATS_PreferenceHandle *ph,
264                        const struct GNUNET_ATS_Preference *pref)
265 {
266   struct SimpleHandle *h = cls;
267   // find peer
268   // subtract pref from bw_by_pk
269   // remove peer if otherwise dead
270   // trigger update
271 }
272
273
274 /**
275  * Transport established a new session with performance
276  * characteristics given in @a data.
277  *
278  * @param cls closure
279  * @param data performance characteristics of @a sh
280  * @param address address information (for debugging)
281  * @return handle by which the plugin will identify this session
282  */
283 static struct GNUNET_ATS_SessionHandle *
284 simple_session_add (void *cls,
285                     const struct GNUNET_ATS_SessionData *data,
286                     const char *address)
287 {
288   struct SimpleHandle *h = cls;
289
290   // find or add peer if necessary
291   // setup session
292   // match HELLO
293   // trigger update
294   return NULL;
295 }
296
297
298 /**
299  * @a data changed for a given @a sh, solver should consider
300  * the updated performance characteristics.
301  *
302  * @param cls closure
303  * @param sh session this is about
304  * @param data performance characteristics of @a sh
305  */
306 static void
307 simple_session_update (void *cls,
308                        struct GNUNET_ATS_SessionHandle *sh,
309                        const struct GNUNET_ATS_SessionData *data)
310 {
311   struct SimpleHandle *h = cls;
312   // trigger update
313 }
314
315
316 /**
317  * A session went away. Solver should update accordingly.
318  *
319  * @param cls closure
320  * @param sh session this is about
321  * @param data (last) performance characteristics of @a sh
322  */
323 static void
324 simple_session_del (void *cls,
325                     struct GNUNET_ATS_SessionHandle *sh,
326                     const struct GNUNET_ATS_SessionData *data)
327 {
328   struct SimpleHandle *h = cls;
329   // tear down session
330   // del peer if otherwise dead
331   // trigger update
332 }
333
334
335 #include "plugin_ats2_common.c"
336
337
338 /**
339  * Function invoked when the plugin is loaded.
340  *
341  * @param[in,out] cls the `struct GNUNET_ATS_PluginEnvironment *` to use;
342  *            modified to return the API functions (ugh).
343  * @return the `struct SimpleHandle` to pass as a closure
344  */
345 void *
346 libgnunet_plugin_ats2_simple_init (void *cls)
347 {
348   static struct GNUNET_ATS_SolverFunctions sf;
349   struct GNUNET_ATS_PluginEnvironment *env = cls;
350   struct SimpleHandle *s;
351
352   s = GNUNET_new (struct SimpleHandle);
353   s->env = env;
354   s->peers = GNUNET_CONTAINER_multipeermap_create (128,
355                                                    GNUNET_YES);
356   s->ps = GNUNET_PEERSTORE_connect (env->cfg);
357   sf.cls = s;
358   sf.preference_add = &simple_preference_add;
359   sf.preference_del = &simple_preference_del;
360   sf.session_add = &simple_session_add;
361   sf.session_update = &simple_session_update;
362   sf.session_del = &simple_session_del;
363   for (enum GNUNET_NetworkType nt = 0;
364        nt < GNUNET_NT_COUNT;
365        nt++)
366   {
367     const char *name = GNUNET_NT_to_string (nt);
368
369     if (NULL == name)
370     {
371       GNUNET_break (0);
372       break;
373     }
374     get_quota (env->cfg,
375                name,
376                "IN",
377                &s->networks[nt].total_quota_in);
378     get_quota (env->cfg,
379                name,
380                "OUT",
381                &s->networks[nt].total_quota_out);
382     s->networks[nt].type = nt;
383   }
384   return &sf;
385 }
386
387
388 /**
389  * Function used to unload the plugin.
390  *
391  * @param cls return value from #libgnunet_plugin_ats_proportional_init()
392  */
393 void *
394 libgnunet_plugin_ats2_simple_done (void *cls)
395 {
396   struct GNUNET_ATS_SolverFunctions *sf = cls;
397   struct SimpleHandle *s = sf->cls;
398
399   // FIXME: iterate over peers and clean up!
400   GNUNET_CONTAINER_multipeermap_destroy (s->peers);
401   GNUNET_PEERSTORE_disconnect (s->ps,
402                                GNUNET_NO);
403   GNUNET_free (s);
404   return NULL;
405 }
406
407
408 /* end of plugin_ats2_simple.c */