aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-12-10 23:29:52 +0100
committerChristian Grothoff <christian@grothoff.org>2018-12-10 23:29:52 +0100
commit70ae2bd54ee0ff610d95a63856f38395920b804d (patch)
treeb08b1726bd4957a9dd0e55ff0057198087f3796d /src
parent08e22453a438c8a3f6135632a6ce39239b47d9f5 (diff)
downloadgnunet-70ae2bd54ee0ff610d95a63856f38395920b804d.tar.gz
gnunet-70ae2bd54ee0ff610d95a63856f38395920b804d.zip
finish first draft of ats2 simple plugin (untested)
Diffstat (limited to 'src')
-rw-r--r--src/ats/Makefile.am3
-rw-r--r--src/ats/gnunet-service-ats-new.c69
-rw-r--r--src/ats/plugin_ats2_simple.c600
-rw-r--r--src/hello/hello-ng.c5
-rw-r--r--src/include/gnunet_hello_lib.h10
-rw-r--r--src/transport/gnunet-service-tng.c2
6 files changed, 612 insertions, 77 deletions
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am
index 97497c94e..147d371e6 100644
--- a/src/ats/Makefile.am
+++ b/src/ats/Makefile.am
@@ -81,6 +81,7 @@ libgnunet_plugin_ats_proportional_la_LDFLAGS = \
81libgnunet_plugin_ats2_simple_la_SOURCES = \ 81libgnunet_plugin_ats2_simple_la_SOURCES = \
82 plugin_ats2_simple.c 82 plugin_ats2_simple.c
83libgnunet_plugin_ats2_simple_la_LIBADD = \ 83libgnunet_plugin_ats2_simple_la_LIBADD = \
84 $(top_builddir)/src/hello/libgnunethello.la \
84 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 85 $(top_builddir)/src/statistics/libgnunetstatistics.la \
85 $(top_builddir)/src/util/libgnunetutil.la \ 86 $(top_builddir)/src/util/libgnunetutil.la \
86 $(LTLIBINTL) 87 $(LTLIBINTL)
@@ -130,7 +131,7 @@ gnunet_service_ats_LDADD = \
130 $(GN_LIBINTL) 131 $(GN_LIBINTL)
131 132
132gnunet_service_ats_new_SOURCES = \ 133gnunet_service_ats_new_SOURCES = \
133 gnunet-service-ats-new.c 134 gnunet-service-ats-new.c
134gnunet_service_ats_new_LDADD = \ 135gnunet_service_ats_new_LDADD = \
135 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 136 $(top_builddir)/src/statistics/libgnunetstatistics.la \
136 $(top_builddir)/src/util/libgnunetutil.la \ 137 $(top_builddir)/src/util/libgnunetutil.la \
diff --git a/src/ats/gnunet-service-ats-new.c b/src/ats/gnunet-service-ats-new.c
index d3b2f1ead..fa8c07a1a 100644
--- a/src/ats/gnunet-service-ats-new.c
+++ b/src/ats/gnunet-service-ats-new.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/ 17*/
@@ -78,7 +78,7 @@ struct ClientPreference
78 * Plugin's representation of the preference. 78 * Plugin's representation of the preference.
79 */ 79 */
80 struct GNUNET_ATS_PreferenceHandle *ph; 80 struct GNUNET_ATS_PreferenceHandle *ph;
81 81
82 /** 82 /**
83 * Details about the preference. 83 * Details about the preference.
84 */ 84 */
@@ -93,7 +93,7 @@ struct GNUNET_ATS_Session
93{ 93{
94 94
95 /** 95 /**
96 * Session data exposed to the plugin. 96 * Session data exposed to the plugin.
97 */ 97 */
98 struct GNUNET_ATS_SessionData data; 98 struct GNUNET_ATS_SessionData data;
99 99
@@ -106,12 +106,12 @@ struct GNUNET_ATS_Session
106 * Session state in the plugin. 106 * Session state in the plugin.
107 */ 107 */
108 struct GNUNET_ATS_SessionHandle *sh; 108 struct GNUNET_ATS_SessionHandle *sh;
109 109
110 /** 110 /**
111 * Unique ID for the session when talking with the client. 111 * Unique ID for the session when talking with the client.
112 */ 112 */
113 uint32_t session_id; 113 uint32_t session_id;
114 114
115}; 115};
116 116
117 117
@@ -146,12 +146,12 @@ struct Client
146 * Head of DLL of preferences expressed by this client. 146 * Head of DLL of preferences expressed by this client.
147 */ 147 */
148 struct ClientPreference *cp_head; 148 struct ClientPreference *cp_head;
149 149
150 /** 150 /**
151 * Tail of DLL of preferences expressed by this client. 151 * Tail of DLL of preferences expressed by this client.
152 */ 152 */
153 struct ClientPreference *cp_tail; 153 struct ClientPreference *cp_tail;
154 154
155 } application; 155 } application;
156 156
157 struct { 157 struct {
@@ -160,9 +160,9 @@ struct Client
160 * Map from session IDs to `struct GNUNET_ATS_Session` objects. 160 * Map from session IDs to `struct GNUNET_ATS_Session` objects.
161 */ 161 */
162 struct GNUNET_CONTAINER_MultiHashMap32 *sessions; 162 struct GNUNET_CONTAINER_MultiHashMap32 *sessions;
163 163
164 } transport; 164 } transport;
165 165
166 } details; 166 } details;
167 167
168}; 168};
@@ -196,7 +196,7 @@ static struct Client *transport_client;
196 * @param cls closure, NULL 196 * @param cls closure, NULL
197 * @param pid peer this is about 197 * @param pid peer this is about
198 * @param address address the transport should try 198 * @param address address the transport should try
199 */ 199 */
200static void 200static void
201suggest_cb (void *cls, 201suggest_cb (void *cls,
202 const struct GNUNET_PeerIdentity *pid, 202 const struct GNUNET_PeerIdentity *pid,
@@ -205,7 +205,7 @@ suggest_cb (void *cls,
205 struct GNUNET_MQ_Envelope *env; 205 struct GNUNET_MQ_Envelope *env;
206 size_t slen = strlen (address) + 1; 206 size_t slen = strlen (address) + 1;
207 struct AddressSuggestionMessage *as; 207 struct AddressSuggestionMessage *as;
208 208
209 if (NULL == transport_client) 209 if (NULL == transport_client)
210 { 210 {
211 // FIXME: stats! 211 // FIXME: stats!
@@ -285,7 +285,7 @@ prop_ntoh (const struct PropertiesNBO *properties,
285 285
286 286
287/** 287/**
288 * We have received a `struct ExpressPreferenceMessage` from an application client. 288 * We have received a `struct ExpressPreferenceMessage` from an application client.
289 * 289 *
290 * @param cls handle to the client 290 * @param cls handle to the client
291 * @param msg the start message 291 * @param msg the start message
@@ -320,7 +320,7 @@ handle_suggest (void *cls,
320 320
321 321
322/** 322/**
323 * We have received a `struct ExpressPreferenceMessage` from an application client. 323 * We have received a `struct ExpressPreferenceMessage` from an application client.
324 * 324 *
325 * @param cls handle to the client 325 * @param cls handle to the client
326 * @param msg the start message 326 * @param msg the start message
@@ -331,7 +331,7 @@ handle_suggest_cancel (void *cls,
331{ 331{
332 struct Client *c = cls; 332 struct Client *c = cls;
333 struct ClientPreference *cp; 333 struct ClientPreference *cp;
334 334
335 if (CT_NONE == c->type) 335 if (CT_NONE == c->type)
336 c->type = CT_APPLICATION; 336 c->type = CT_APPLICATION;
337 if (CT_APPLICATION != c->type) 337 if (CT_APPLICATION != c->type)
@@ -398,7 +398,7 @@ handle_start (void *cls,
398 398
399 399
400/** 400/**
401 * Check 'session_add' message is well-formed and comes from a 401 * Check 'session_add' message is well-formed and comes from a
402 * transport client. 402 * transport client.
403 * 403 *
404 * @param cls client that sent the request 404 * @param cls client that sent the request
@@ -433,7 +433,7 @@ handle_session_add (void *cls,
433{ 433{
434 struct Client *c = cls; 434 struct Client *c = cls;
435 const char *address = (const char *) &message[1]; 435 const char *address = (const char *) &message[1];
436 struct GNUNET_ATS_Session *session; 436 struct GNUNET_ATS_Session *session;
437 int inbound_only = (GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY == 437 int inbound_only = (GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY ==
438 ntohs (message->header.type)); 438 ntohs (message->header.type));
439 439
@@ -477,7 +477,7 @@ handle_session_update (void *cls,
477{ 477{
478 struct Client *c = cls; 478 struct Client *c = cls;
479 struct GNUNET_ATS_Session *session; 479 struct GNUNET_ATS_Session *session;
480 480
481 if (CT_TRANSPORT != c->type) 481 if (CT_TRANSPORT != c->type)
482 { 482 {
483 GNUNET_break (0); 483 GNUNET_break (0);
@@ -527,7 +527,7 @@ handle_session_del (void *cls,
527 GNUNET_break (0); 527 GNUNET_break (0);
528 GNUNET_SERVICE_client_drop (c->client); 528 GNUNET_SERVICE_client_drop (c->client);
529 return; 529 return;
530 } 530 }
531 plugin->session_del (plugin->cls, 531 plugin->session_del (plugin->cls,
532 session->sh, 532 session->sh,
533 &session->data); 533 &session->data);
@@ -637,15 +637,14 @@ client_disconnect_cb (void *cls,
637 637
638 638
639/** 639/**
640 * Task run during shutdown. 640 * Task run at the end during shutdown.
641 * 641 *
642 * @param cls unused 642 * @param cls unused
643 */ 643 */
644static void 644static void
645cleanup_task (void *cls) 645final_cleanup (void *cls)
646{ 646{
647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 647 (void) cls;
648 "ATS shutdown initiated\n");
649 if (NULL != stats) 648 if (NULL != stats)
650 { 649 {
651 GNUNET_STATISTICS_destroy (stats, 650 GNUNET_STATISTICS_destroy (stats,
@@ -667,6 +666,22 @@ cleanup_task (void *cls)
667 666
668 667
669/** 668/**
669 * Task run during shutdown.
670 *
671 * @param cls unused
672 */
673static void
674cleanup_task (void *cls)
675{
676 (void) cls;
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 "ATS shutdown initiated\n");
679 GNUNET_SCHEDULER_add_now (&final_cleanup,
680 NULL);
681}
682
683
684/**
670 * Process template requests. 685 * Process template requests.
671 * 686 *
672 * @param cls closure 687 * @param cls closure
@@ -680,7 +695,7 @@ run (void *cls,
680{ 695{
681 static struct GNUNET_ATS_PluginEnvironment env; 696 static struct GNUNET_ATS_PluginEnvironment env;
682 char *solver; 697 char *solver;
683 698
684 stats = GNUNET_STATISTICS_create ("ats", 699 stats = GNUNET_STATISTICS_create ("ats",
685 cfg); 700 cfg);
686 if (GNUNET_SYSERR == 701 if (GNUNET_SYSERR ==
@@ -711,7 +726,7 @@ run (void *cls,
711 _("Failed to initialize solver `%s'!\n"), 726 _("Failed to initialize solver `%s'!\n"),
712 plugin_name); 727 plugin_name);
713 GNUNET_SCHEDULER_shutdown (); 728 GNUNET_SCHEDULER_shutdown ();
714 return; 729 return;
715 } 730 }
716} 731}
717 732
@@ -746,11 +761,11 @@ GNUNET_SERVICE_MAIN
746 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY, 761 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY,
747 struct SessionAddMessage, 762 struct SessionAddMessage,
748 NULL), 763 NULL),
749 GNUNET_MQ_hd_fixed_size (session_update, 764 GNUNET_MQ_hd_fixed_size (session_update,
750 GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE, 765 GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE,
751 struct SessionUpdateMessage, 766 struct SessionUpdateMessage,
752 NULL), 767 NULL),
753 GNUNET_MQ_hd_fixed_size (session_del, 768 GNUNET_MQ_hd_fixed_size (session_del,
754 GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL, 769 GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL,
755 struct SessionDelMessage, 770 struct SessionDelMessage,
756 NULL), 771 NULL),
diff --git a/src/ats/plugin_ats2_simple.c b/src/ats/plugin_ats2_simple.c
index 55234f1bc..6faf8ad7c 100644
--- a/src/ats/plugin_ats2_simple.c
+++ b/src/ats/plugin_ats2_simple.c
@@ -22,26 +22,48 @@
22 * @author Christian Grothoff 22 * @author Christian Grothoff
23 * 23 *
24 * TODO: 24 * TODO:
25 * - subscribe to PEERSTORE when short on HELLOs (given application preferences!) 25 * - needs testing
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 */ 26 */
31#include "platform.h" 27#include "platform.h"
32#include "gnunet_ats_plugin_new.h" 28#include "gnunet_ats_plugin_new.h"
29#include "gnunet_hello_lib.h"
33#include "gnunet_peerstore_service.h" 30#include "gnunet_peerstore_service.h"
34 31
35#define LOG(kind,...) GNUNET_log_from (kind, "ats-simple",__VA_ARGS__) 32#define LOG(kind,...) GNUNET_log_from (kind, "ats-simple",__VA_ARGS__)
36 33
37 34
38/** 35/**
36 * Base frequency at which we suggest addresses to transport.
37 * Multiplied by the square of the number of active connections
38 * (and randomized) to calculate the actual frequency at which
39 * we will suggest addresses to the transport. Furthermore, each
40 * address is also bounded by an exponential back-off.
41 */
42#define SUGGEST_FREQ GNUNET_TIME_UNIT_SECONDS
43
44/**
45 * What is the minimum bandwidth we always try to allocate for
46 * any session that is up? (May still be scaled down lower if
47 * the number of sessions is so high that the total bandwidth
48 * is insufficient to allow for this value to be granted.)
49 */
50#define MIN_BANDWIDTH_PER_SESSION 1024
51
52
53/**
39 * A handle for the proportional solver 54 * A handle for the proportional solver
40 */ 55 */
41struct SimpleHandle; 56struct SimpleHandle;
42 57
43 58
44/** 59/**
60 * Information about preferences and sessions we track
61 * per peer.
62 */
63struct Peer;
64
65
66/**
45 * Entry in list of addresses we could try per peer. 67 * Entry in list of addresses we could try per peer.
46 */ 68 */
47struct Hello 69struct Hello
@@ -58,11 +80,27 @@ struct Hello
58 struct Hello *prev; 80 struct Hello *prev;
59 81
60 /** 82 /**
83 * Peer this hello belongs to.
84 */
85 struct Peer *peer;
86
87 /**
61 * The address we could try. 88 * The address we could try.
62 */ 89 */
63 const char *address; 90 const char *address;
64 91
65 /** 92 /**
93 * Is a session with this address already up?
94 * If not, set to NULL.
95 */
96 struct GNUNET_ATS_SessionHandle *sh;
97
98 /**
99 * When does the HELLO expire?
100 */
101 struct GNUNET_TIME_Absolute expiration;
102
103 /**
66 * When did we try it last? 104 * When did we try it last?
67 */ 105 */
68 struct GNUNET_TIME_Absolute last_attempt; 106 struct GNUNET_TIME_Absolute last_attempt;
@@ -73,22 +111,14 @@ struct Hello
73 struct GNUNET_TIME_Relative backoff; 111 struct GNUNET_TIME_Relative backoff;
74 112
75 /** 113 /**
76 * Is a session with this address already up? 114 * Type of the network for this HELLO.
77 * If not, set to NULL.
78 */ 115 */
79 struct GNUNET_ATS_SessionHandle *sh; 116 enum GNUNET_NetworkType nt;
80 117
81}; 118};
82 119
83 120
84/** 121/**
85 * Information about preferences and sessions we track
86 * per peer.
87 */
88struct Peer;
89
90
91/**
92 * Internal representation of a session by the plugin. 122 * Internal representation of a session by the plugin.
93 * (If desired, plugin may just use NULL.) 123 * (If desired, plugin may just use NULL.)
94 */ 124 */
@@ -131,6 +161,12 @@ struct GNUNET_ATS_SessionHandle
131 const char *address; 161 const char *address;
132 162
133 /** 163 /**
164 * When did we last update transport about the allocation?
165 * Used to dampen the frequency of updates.
166 */
167 struct GNUNET_TIME_Absolute last_allocation;
168
169 /**
134 * Last BW-in allocation given to the transport service. 170 * Last BW-in allocation given to the transport service.
135 */ 171 */
136 struct GNUNET_BANDWIDTH_Value32NBO bw_in; 172 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
@@ -140,6 +176,16 @@ struct GNUNET_ATS_SessionHandle
140 */ 176 */
141 struct GNUNET_BANDWIDTH_Value32NBO bw_out; 177 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
142 178
179 /**
180 * New BW-in allocation given to the transport service.
181 */
182 uint64_t target_in;
183
184 /**
185 * New BW-out allocation given to the transport service.
186 */
187 uint64_t target_out;
188
143}; 189};
144 190
145 191
@@ -176,26 +222,31 @@ struct Peer
176 struct SimpleHandle *h; 222 struct SimpleHandle *h;
177 223
178 /** 224 /**
179 * Which peer is this for? 225 * Watch context where we are currently looking for HELLOs for
226 * this peer.
180 */ 227 */
181 struct GNUNET_PeerIdentity pid; 228 struct GNUNET_PEERSTORE_WatchContext *wc;
182 229
183 /** 230 /**
184 * Array where we sum up the bandwidth requests received indexed 231 * Task used to try again to suggest an address for this peer.
185 * by preference kind (see `enum GNUNET_MQ_PreferenceKind`)
186 */ 232 */
187 uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT]; 233 struct GNUNET_SCHEDULER_Task *task;
188 234
189 /** 235 /**
190 * Watch context where we are currently looking for HELLOs for 236 * Which peer is this for?
191 * this peer.
192 */ 237 */
193 struct GNUNET_PEERSTORE_WatchContext *wc; 238 struct GNUNET_PeerIdentity pid;
194 239
195 /** 240 /**
196 * Task used to try again to suggest an address for this peer. 241 * When did we last suggest an address to connect to for this peer?
197 */ 242 */
198 struct GNUNET_SCHEDULER_Task *task; 243 struct GNUNET_TIME_Absolute last_suggestion;
244
245 /**
246 * Array where we sum up the bandwidth requests received indexed
247 * by preference kind (see `enum GNUNET_MQ_PreferenceKind`)
248 */
249 uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT];
199 250
200}; 251};
201 252
@@ -241,14 +292,21 @@ struct SimpleHandle
241 struct GNUNET_CONTAINER_MultiPeerMap *peers; 292 struct GNUNET_CONTAINER_MultiPeerMap *peers;
242 293
243 /** 294 /**
244 * Information we track per network type (quotas). 295 * Handle to the peerstore service.
245 */ 296 */
246 struct Network networks[GNUNET_NT_COUNT]; 297 struct GNUNET_PEERSTORE_Handle *ps;
247 298
248 /** 299 /**
249 * Handle to the peerstore service. 300 * Array where we sum up the bandwidth requests received indexed
301 * by preference kind (see `enum GNUNET_MQ_PreferenceKind`) (sums
302 * over all peers).
250 */ 303 */
251 struct GNUNET_PEERSTORE_Handle *ps; 304 uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT];
305
306 /**
307 * Information we track per network type (quotas).
308 */
309 struct Network networks[GNUNET_NT_COUNT];
252 310
253}; 311};
254 312
@@ -291,6 +349,129 @@ peer_test_dead (struct Peer *p)
291 349
292 350
293/** 351/**
352 * Contact the transport service and suggest to it to
353 * try connecting to the address of @a hello. Updates
354 * backoff and timestamp values in the @a hello.
355 *
356 * @param hello[in,out] address suggestion to make
357 */
358static void
359suggest_hello (struct Hello *hello)
360{
361 struct Peer *p = hello->peer;
362 struct SimpleHandle *h = p->h;
363
364 p->last_suggestion
365 = hello->last_attempt
366 = GNUNET_TIME_absolute_get ();
367 hello->backoff = GNUNET_TIME_randomized_backoff (hello->backoff,
368 GNUNET_TIME_absolute_get_remaining (hello->expiration));
369 h->env->suggest_cb (h->env->cls,
370 &p->pid,
371 hello->address);
372}
373
374
375/**
376 * Consider suggesting a HELLO (without a session) to transport.
377 * We look at how many active sessions we have for the peer, and
378 * if there are many, reduce the frequency of trying new addresses.
379 * Also, for each address we consider when we last tried it, and
380 * its exponential backoff if the attempt failed. Note that it
381 * is possible that this function is called when no suggestion
382 * is to be made.
383 *
384 * In this case, we only calculate the time until we make the next
385 * suggestion.
386 *
387 * @param cls a `struct Peer`
388 */
389static void
390suggest_start_cb (void *cls)
391{
392 struct Peer *p = cls;
393 struct GNUNET_TIME_Relative delay = GNUNET_TIME_UNIT_ZERO;
394 struct Hello *hello = NULL;
395 struct GNUNET_TIME_Absolute hpt = GNUNET_TIME_UNIT_FOREVER_ABS;
396 struct GNUNET_TIME_Relative xdelay;
397 struct GNUNET_TIME_Absolute xnext;
398 unsigned int num_sessions = 0;
399 uint32_t sq;
400
401 /* count number of active sessions */
402 for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head;
403 NULL != sh;
404 sh = sh->next)
405 num_sessions++;
406 /* calculate square of number of sessions */
407 num_sessions++; /* start with 1, even if we have zero sessions */
408 if (num_sessions < UINT16_MAX)
409 sq = num_sessions * (uint32_t) num_sessions;
410 else
411 sq = UINT32_MAX;
412 xdelay = GNUNET_TIME_randomized_backoff (GNUNET_TIME_relative_multiply (SUGGEST_FREQ,
413 sq),
414 GNUNET_TIME_UNIT_FOREVER_REL);
415 xnext = GNUNET_TIME_relative_to_absolute (xdelay);
416
417 p->task = NULL;
418 while (0 == delay.rel_value_us)
419 {
420 struct Hello *next;
421 struct GNUNET_TIME_Absolute xmax;
422
423 if (NULL != hello)
424 {
425 /* We went through the loop already once and found
426 a HELLO that is due *now*, so make a suggestion! */
427 GNUNET_break (NULL == hello->sh);
428 suggest_hello (hello);
429 hello = NULL;
430 hpt = GNUNET_TIME_UNIT_FOREVER_ABS;
431 }
432 for (struct Hello *pos = p->h_head; NULL != pos; pos = next)
433 {
434 struct GNUNET_TIME_Absolute pt;
435
436 next = pos->next;
437 if (NULL != pos->sh)
438 continue;
439 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).rel_value_us)
440 {
441 /* expired, remove! */
442 GNUNET_CONTAINER_DLL_remove (p->h_head,
443 p->h_tail,
444 pos);
445 GNUNET_free (pos);
446 continue;
447 }
448 pt = GNUNET_TIME_absolute_add (pos->last_attempt,
449 pos->backoff);
450 if ( (NULL == hello) ||
451 (pt.abs_value_us < hpt.abs_value_us) )
452 {
453 hello = pos;
454 hpt = pt;
455 }
456 }
457 if (NULL == hello)
458 return; /* no HELLOs that could still be tried */
459
460 /* hpt is now the *earliest* possible time for any HELLO
461 but we might not want to go for as early as possible for
462 this peer. So the actual time is the max of the earliest
463 HELLO and the 'xnext' */
464 xmax = GNUNET_TIME_absolute_max (hpt,
465 xnext);
466 delay = GNUNET_TIME_absolute_get_remaining (xmax);
467 }
468 p->task = GNUNET_SCHEDULER_add_delayed (delay,
469 &suggest_start_cb,
470 p);
471}
472
473
474/**
294 * Function called by PEERSTORE for each matching record. 475 * Function called by PEERSTORE for each matching record.
295 * 476 *
296 * @param cls closure with a `struct Peer` 477 * @param cls closure with a `struct Peer`
@@ -303,15 +484,85 @@ watch_cb (void *cls,
303 const char *emsg) 484 const char *emsg)
304{ 485{
305 struct Peer *p = cls; 486 struct Peer *p = cls;
487 char *addr;
488 size_t alen;
489 enum GNUNET_NetworkType nt;
490 struct GNUNET_TIME_Absolute expiration;
491 struct Hello *hello;
306 492
307 // FIXME: process hello! 493 if (0 != memcmp (&p->pid,
308 // check for expiration 494 &record->peer,
309 // (add to p's doubly-linked list) 495 sizeof (struct GNUNET_PeerIdentity)))
310
311 if (NULL == p->task)
312 { 496 {
313 // start suggestion task! 497 GNUNET_break (0);
498 return;
499 }
500 if (0 != strcmp (record->key,
501 GNUNET_HELLO_PEERSTORE_KEY))
502 {
503 GNUNET_break (0);
504 return;
505 }
506 addr = GNUNET_HELLO_extract_address (record->value,
507 record->value_size,
508 &p->pid,
509 &nt,
510 &expiration);
511 if (NULL == addr)
512 return; /* invalid hello, bad signature, other problem */
513 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
514 {
515 /* expired, ignore */
516 GNUNET_free (addr);
517 return;
518 }
519 /* check if addr is already known */
520 for (struct Hello *he = p->h_head;
521 NULL != he;
522 he = he->next)
523 {
524 if (0 != strcmp (he->address,
525 addr))
526 continue;
527 if (he->expiration.abs_value_us < expiration.abs_value_us)
528 {
529 he->expiration = expiration;
530 he->nt = nt;
531 }
532 GNUNET_free (addr);
533 return;
534 }
535 /* create new HELLO */
536 alen = strlen (addr) + 1;
537 hello = GNUNET_malloc (sizeof (struct Hello) + alen);
538 hello->address = (const char *) &hello[1];
539 hello->expiration = expiration;
540 hello->nt = nt;
541 hello->peer = p;
542 memcpy (&hello[1],
543 addr,
544 alen);
545 GNUNET_free (addr);
546 GNUNET_CONTAINER_DLL_insert (p->h_head,
547 p->h_tail,
548 hello);
549 /* check if sh for this HELLO already exists */
550 for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head;
551 NULL != sh;
552 sh = sh->next)
553 {
554 if ( (NULL == sh->address) ||
555 (0 != strcmp (sh->address,
556 addr)) )
557 continue;
558 GNUNET_assert (NULL == sh->hello);
559 sh->hello = hello;
560 hello->sh = sh;
561 break;
314 } 562 }
563 if (NULL == p->task)
564 p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb,
565 p);
315} 566}
316 567
317 568
@@ -337,7 +588,7 @@ peer_add (struct SimpleHandle *h,
337 p->wc = GNUNET_PEERSTORE_watch (h->ps, 588 p->wc = GNUNET_PEERSTORE_watch (h->ps,
338 "transport", 589 "transport",
339 &p->pid, 590 &p->pid,
340 "HELLO" /* key */, 591 GNUNET_HELLO_PEERSTORE_KEY,
341 &watch_cb, 592 &watch_cb,
342 p); 593 p);
343 GNUNET_assert (GNUNET_YES == 594 GNUNET_assert (GNUNET_YES ==
@@ -390,13 +641,259 @@ peer_free (struct Peer *p)
390 641
391 642
392/** 643/**
644 * Check if the new allocation for @a sh is significantly different
645 * from the last one, and if so, tell transport.
646 *
647 * @param sh session handle to consider updating transport for
648 */
649static void
650consider_notify_transport (struct GNUNET_ATS_SessionHandle *sh)
651{
652 struct Peer *peer = sh->peer;
653 struct SimpleHandle *h = peer->h;
654 enum GNUNET_NetworkType nt = sh->data->prop.nt;
655 struct GNUNET_TIME_Relative delay;
656 uint64_t sig_in;
657 uint64_t sig_out;
658 int64_t delta_in;
659 int64_t delta_out;
660
661 delay = GNUNET_TIME_absolute_get_duration (sh->last_allocation);
662 /* A significant change is more than 10% of the quota,
663 which is given in bytes/second */
664 sig_in
665 = h->networks[nt].total_quota_in * (delay.rel_value_us / 1000LL) / 1000LL / 10;
666 sig_out
667 = h->networks[nt].total_quota_out * (delay.rel_value_us / 1000LL) / 1000LL / 10;
668 delta_in = ( (int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in);
669 delta_out = ( (int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in);
670 /* we want the absolute values */
671 if (delta_in < 0)
672 delta_in = - delta_in;
673 if (INT64_MIN == delta_in)
674 delta_in = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */
675 if (delta_out < 0)
676 delta_out = - delta_out;
677 if (INT64_MIN == delta_out)
678 delta_out = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */
679 if ( (sig_in > delta_in) &&
680 (sig_out > delta_out) )
681 return; /* insignificant change */
682 /* change is significant, tell transport! */
683 if (sh->target_in > UINT32_MAX)
684 sh->target_in = UINT32_MAX;
685 sh->bw_in.value__ = htonl ((uint32_t) sh->target_in);
686 if (sh->target_out > UINT32_MAX)
687 sh->target_out = UINT32_MAX;
688 sh->bw_out.value__ = htonl ((uint32_t) sh->target_out);
689 sh->last_allocation = GNUNET_TIME_absolute_get ();
690 h->env->allocate_cb (h->env->cls,
691 sh->session,
692 &peer->pid,
693 sh->bw_in,
694 sh->bw_out);
695}
696
697
698/**
699 * Closure for #update_counters and #update_allocation.
700 */
701struct Counters
702{
703 /**
704 * Plugin's state.
705 */
706 struct SimpleHandle *h;
707
708 /**
709 * Bandwidth that applications would prefer to allocate in this
710 * network type. We initially add all requested allocations to the
711 * respective network type where the given preference is best
712 * satisfied. Later we may rebalance.
713 */
714 uint64_t bw_out_by_nt[GNUNET_NT_COUNT];
715
716 /**
717 * Current bandwidth utilization for this network type. We simply
718 * add the current goodput up (with some fairness considerations).
719 */
720 uint64_t bw_in_by_nt[GNUNET_NT_COUNT];
721
722 /**
723 * By how much do we have to scale (up or down) our expectations
724 * for outbound bandwidth?
725 */
726 double scale_out[GNUNET_NT_COUNT];
727
728 /**
729 * By how much do we have to scale (up or down) our expectations
730 * for inbound bandwidth?
731 */
732 double scale_in[GNUNET_NT_COUNT];
733
734};
735
736
737/**
738 * Function used to iterate over all peers and collect
739 * counter data.
740 *
741 * @param cls a `struct Counters *`
742 * @param pid identity of the peer we process, unused
743 * @param value a `struct Peer *`
744 * @return #GNUNET_YES (continue to iterate)
745 */
746static int
747update_counters (void *cls,
748 const struct GNUNET_PeerIdentity *pid,
749 void *value)
750{
751 struct Counters *c = cls;
752 struct Peer *peer = value;
753 struct GNUNET_ATS_SessionHandle *best[GNUNET_MQ_PREFERENCE_COUNT];
754
755 (void) pid;
756 memset (best,
757 0,
758 sizeof (best));
759 for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head;
760 NULL != sh;
761 sh = sh->next)
762 {
763 enum GNUNET_NetworkType nt = sh->data->prop.nt;
764
765 sh->target_out = MIN_BANDWIDTH_PER_SESSION;
766 c->bw_out_by_nt[nt] += MIN_BANDWIDTH_PER_SESSION;
767 c->bw_in_by_nt[nt] += GNUNET_MAX (MIN_BANDWIDTH_PER_SESSION,
768 sh->data->prop.goodput_in);
769 for (enum GNUNET_MQ_PreferenceKind pk = 0;
770 pk < GNUNET_MQ_PREFERENCE_COUNT;
771 pk++)
772 {
773 /* General rule: always prefer smaller distance if possible,
774 otherwise decide by pk: */
775 switch (pk) {
776 case GNUNET_MQ_PREFERENCE_NONE:
777 break;
778 case GNUNET_MQ_PREFERENCE_BANDWIDTH:
779 /* For bandwidth, we compare the sum of transmitted bytes and
780 confirmed transmitted bytes, so confirmed data counts twice */
781 if ( (NULL == best[pk]) ||
782 (sh->data->prop.distance < best[pk]->data->prop.distance) ||
783 (sh->data->prop.utilization_out + sh->data->prop.goodput_out >
784 best[pk]->data->prop.utilization_out + best[pk]->data->prop.goodput_out) )
785 best[pk] = sh;
786 /* If both are equal (i.e. usually this happens if there is a zero), use
787 latency as a yardstick */
788 if ( (sh->data->prop.utilization_out + sh->data->prop.goodput_out ==
789 best[pk]->data->prop.utilization_out + best[pk]->data->prop.goodput_out) &&
790 (sh->data->prop.distance == best[pk]->data->prop.distance) &&
791 (sh->data->prop.delay.rel_value_us <
792 best[pk]->data->prop.delay.rel_value_us) )
793 best[pk] = sh;
794 break;
795 case GNUNET_MQ_PREFERENCE_LATENCY:
796 if ( (NULL == best[pk]) ||
797 (sh->data->prop.distance < best[pk]->data->prop.distance) ||
798 ( (sh->data->prop.distance == best[pk]->data->prop.distance) &&
799 (sh->data->prop.delay.rel_value_us <
800 best[pk]->data->prop.delay.rel_value_us) ) )
801 best[pk] = sh;
802 break;
803 case GNUNET_MQ_PREFERENCE_RELIABILITY:
804 /* For reliability, we consider the ratio of goodput to utilization
805 (but use multiplicative formultations to avoid division by zero) */
806 if ( (NULL == best[pk]) ||
807 (1ULL * sh->data->prop.goodput_out * best[pk]->data->prop.utilization_out >
808 1ULL * sh->data->prop.utilization_out * best[pk]->data->prop.goodput_out) )
809 best[pk] = sh;
810 /* If both are equal (i.e. usually this happens if there is a zero), use
811 latency as a yardstick */
812 if ( (1ULL * sh->data->prop.goodput_out * best[pk]->data->prop.utilization_out ==
813 1ULL * sh->data->prop.utilization_out * best[pk]->data->prop.goodput_out) &&
814 (sh->data->prop.distance == best[pk]->data->prop.distance) &&
815 (sh->data->prop.delay.rel_value_us <
816 best[pk]->data->prop.delay.rel_value_us) )
817 best[pk] = sh;
818 break;
819 }
820 }
821 }
822 /* for first round, assign target bandwidth simply to sum of
823 requested bandwidth */
824 for (enum GNUNET_MQ_PreferenceKind pk = 0;
825 pk < GNUNET_MQ_PREFERENCE_COUNT;
826 pk++)
827 {
828 enum GNUNET_NetworkType nt = best[pk]->data->prop.nt;
829
830 best[pk]->target_out = GNUNET_MIN (peer->bw_by_pk[pk],
831 MIN_BANDWIDTH_PER_SESSION);
832 c->bw_out_by_nt[nt] += (uint64_t) (best[pk]->target_out - MIN_BANDWIDTH_PER_SESSION);
833 }
834 return GNUNET_YES;
835}
836
837
838/**
839 * Function used to iterate over all peers and collect
840 * counter data.
841 *
842 * @param cls a `struct Counters *`
843 * @param pid identity of the peer we process, unused
844 * @param value a `struct Peer *`
845 * @return #GNUNET_YES (continue to iterate)
846 */
847static int
848update_allocation (void *cls,
849 const struct GNUNET_PeerIdentity *pid,
850 void *value)
851{
852 struct Counters *c = cls;
853 struct Peer *peer = value;
854
855 (void) pid;
856 for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head;
857 NULL != sh;
858 sh = sh->next)
859 {
860 enum GNUNET_NetworkType nt = sh->data->prop.nt;
861
862 sh->target_out = (uint64_t) (c->scale_out[nt] * sh->target_out);
863 sh->target_in = (uint64_t) (c->scale_in[nt] * sh->target_in);
864 consider_notify_transport (sh);
865 }
866 return GNUNET_YES;
867}
868
869
870/**
393 * The world changed, recalculate our allocations. 871 * The world changed, recalculate our allocations.
394 */ 872 */
395static void 873static void
396update (struct SimpleHandle *h) 874update (struct SimpleHandle *h)
397{ 875{
398 // recalculate allocations 876 struct Counters cnt = {
399 // notify transport if it makes sense (delta significant) 877 .h = h
878 };
879
880 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
881 &update_counters,
882 &cnt);
883 /* calculate how badly the missmatch between requested
884 allocations and available bandwidth is per network type */
885 for (enum GNUNET_NetworkType nt = 0;
886 nt < GNUNET_NT_COUNT;
887 nt++)
888 {
889 cnt.scale_out[nt] = 1.0 * cnt.bw_out_by_nt[nt] / h->networks[nt].total_quota_out;
890 cnt.scale_in[nt] = 1.0 * cnt.bw_in_by_nt[nt] / h->networks[nt].total_quota_in;
891 }
892 /* recalculate allocations, considering scaling factor, and
893 update transport if the change is significant */
894 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
895 &update_allocation,
896 &cnt);
400} 897}
401 898
402 899
@@ -417,6 +914,7 @@ simple_preference_add (void *cls,
417 914
418 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT); 915 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT);
419 p->bw_by_pk[pref->pk] += ntohl (pref->bw.value__); 916 p->bw_by_pk[pref->pk] += ntohl (pref->bw.value__);
917 h->bw_by_pk[pref->pk] += ntohl (pref->bw.value__);
420 update (h); 918 update (h);
421 return NULL; 919 return NULL;
422} 920}
@@ -442,6 +940,7 @@ simple_preference_del (void *cls,
442 GNUNET_assert (NULL != p); 940 GNUNET_assert (NULL != p);
443 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT); 941 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT);
444 p->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__); 942 p->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__);
943 h->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__);
445 if ( (0 == p->bw_by_pk[pref->pk]) && 944 if ( (0 == p->bw_by_pk[pref->pk]) &&
446 (GNUNET_YES == peer_test_dead (p)) ) 945 (GNUNET_YES == peer_test_dead (p)) )
447 peer_free (p); 946 peer_free (p);
@@ -502,6 +1001,7 @@ simple_session_add (void *cls,
502 if (NULL != hello) 1001 if (NULL != hello)
503 { 1002 {
504 hello->sh = sh; 1003 hello->sh = sh;
1004 hello->backoff = GNUNET_TIME_UNIT_ZERO;
505 sh->hello = hello; 1005 sh->hello = hello;
506 } 1006 }
507 update (h); 1007 update (h);
@@ -543,11 +1043,24 @@ simple_session_del (void *cls,
543{ 1043{
544 struct SimpleHandle *h = cls; 1044 struct SimpleHandle *h = cls;
545 struct Peer *p = sh->peer; 1045 struct Peer *p = sh->peer;
1046 struct Hello *hello = sh->hello;
546 1047
547 // FIXME: tear down session 1048 /* clean up sh */
548 // del peer if otherwise dead 1049 GNUNET_CONTAINER_DLL_remove (p->sh_head,
549 1050 p->sh_tail,
550 1051 sh);
1052 if (NULL != hello)
1053 {
1054 GNUNET_assert (sh == hello->sh);
1055 hello->sh = NULL;
1056 /* session went down, if necessary restart suggesting
1057 addresses */
1058 if (NULL == p->task)
1059 p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb,
1060 p);
1061 }
1062 GNUNET_free (sh);
1063 /* del peer if otherwise dead */
551 if ( (NULL == p->sh_head) && 1064 if ( (NULL == p->sh_head) &&
552 (GNUNET_YES == peer_test_dead (p)) ) 1065 (GNUNET_YES == peer_test_dead (p)) )
553 peer_free (p); 1066 peer_free (p);
@@ -619,7 +1132,8 @@ libgnunet_plugin_ats2_simple_done (void *cls)
619 struct GNUNET_ATS_SolverFunctions *sf = cls; 1132 struct GNUNET_ATS_SolverFunctions *sf = cls;
620 struct SimpleHandle *s = sf->cls; 1133 struct SimpleHandle *s = sf->cls;
621 1134
622 // FIXME: iterate over peers and clean up! 1135 GNUNET_break (0 ==
1136 GNUNET_CONTAINER_multipeermap_size (s->peers));
623 GNUNET_CONTAINER_multipeermap_destroy (s->peers); 1137 GNUNET_CONTAINER_multipeermap_destroy (s->peers);
624 GNUNET_PEERSTORE_disconnect (s->ps, 1138 GNUNET_PEERSTORE_disconnect (s->ps,
625 GNUNET_NO); 1139 GNUNET_NO);
diff --git a/src/hello/hello-ng.c b/src/hello/hello-ng.c
index a16ceb944..723ec0eaa 100644
--- a/src/hello/hello-ng.c
+++ b/src/hello/hello-ng.c
@@ -101,7 +101,7 @@ GNUNET_HELLO_sign_address (const char *address,
101 * 101 *
102 * @param raw raw signed address 102 * @param raw raw signed address
103 * @param raw_size size of @a raw 103 * @param raw_size size of @a raw
104 * @param public_key public key to use for signature verification 104 * @param pid public key to use for signature verification
105 * @param nt[out] set to network type 105 * @param nt[out] set to network type
106 * @param expiration[out] how long is the address valid 106 * @param expiration[out] how long is the address valid
107 * @return NULL on error, otherwise the address 107 * @return NULL on error, otherwise the address
@@ -109,10 +109,11 @@ GNUNET_HELLO_sign_address (const char *address,
109char * 109char *
110GNUNET_HELLO_extract_address (const void *raw, 110GNUNET_HELLO_extract_address (const void *raw,
111 size_t raw_size, 111 size_t raw_size,
112 const struct GNUNET_CRYPTO_EddsaPublicKey *public_key, 112 const struct GNUNET_PeerIdentity *pid,
113 enum GNUNET_NetworkType *nt, 113 enum GNUNET_NetworkType *nt,
114 struct GNUNET_TIME_Absolute *expiration) 114 struct GNUNET_TIME_Absolute *expiration)
115{ 115{
116 const struct GNUNET_CRYPTO_EddsaPublicKey *public_key = &pid->public_key;
116 const char *raws = raw; 117 const char *raws = raw;
117 unsigned long long raw_us; 118 unsigned long long raw_us;
118 unsigned int raw_nt; 119 unsigned int raw_nt;
diff --git a/src/include/gnunet_hello_lib.h b/src/include/gnunet_hello_lib.h
index 8a405a25e..a47162f99 100644
--- a/src/include/gnunet_hello_lib.h
+++ b/src/include/gnunet_hello_lib.h
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/ 17*/
@@ -476,6 +476,10 @@ GNUNET_HELLO_parse_uri (const char *uri,
476/* NG API */ 476/* NG API */
477#include "gnunet_nt_lib.h" 477#include "gnunet_nt_lib.h"
478 478
479/**
480 * Key used for storing HELLOs in the peerstore
481 */
482#define GNUNET_HELLO_PEERSTORE_KEY "hello"
479 483
480/** 484/**
481 * Build address record by signing raw information with private key. 485 * Build address record by signing raw information with private key.
@@ -501,7 +505,7 @@ GNUNET_HELLO_sign_address (const char *address,
501 * 505 *
502 * @param raw raw signed address 506 * @param raw raw signed address
503 * @param raw_size size of @a raw 507 * @param raw_size size of @a raw
504 * @param public_key public key to use for signature verification 508 * @param pid public key to use for signature verification
505 * @param nt[out] set to network type 509 * @param nt[out] set to network type
506 * @param expiration[out] how long is the address valid 510 * @param expiration[out] how long is the address valid
507 * @return NULL on error, otherwise the address 511 * @return NULL on error, otherwise the address
@@ -509,7 +513,7 @@ GNUNET_HELLO_sign_address (const char *address,
509char * 513char *
510GNUNET_HELLO_extract_address (const void *raw, 514GNUNET_HELLO_extract_address (const void *raw,
511 size_t raw_size, 515 size_t raw_size,
512 const struct GNUNET_CRYPTO_EddsaPublicKey *public_key, 516 const struct GNUNET_PeerIdentity *pid,
513 enum GNUNET_NetworkType *nt, 517 enum GNUNET_NetworkType *nt,
514 struct GNUNET_TIME_Absolute *expiration); 518 struct GNUNET_TIME_Absolute *expiration);
515 519
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
index feaa0cfff..3630e6af0 100644
--- a/src/transport/gnunet-service-tng.c
+++ b/src/transport/gnunet-service-tng.c
@@ -1196,7 +1196,7 @@ store_pi (void *cls)
1196 ale->sc = GNUNET_PEERSTORE_store (peerstore, 1196 ale->sc = GNUNET_PEERSTORE_store (peerstore,
1197 "transport", 1197 "transport",
1198 &GST_my_identity, 1198 &GST_my_identity,
1199 "hello", 1199 GNUNET_HELLO_PEERSTORE_KEY,
1200 addr, 1200 addr,
1201 addr_len, 1201 addr_len,
1202 expiration, 1202 expiration,