diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-10-06 21:03:33 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-10-06 21:03:33 +0200 |
commit | 622fd12c7101c53c1fa0f9563a831f3196732dc5 (patch) | |
tree | d86047807232d9921341b8ed84558dea2b9df929 /src/ats | |
parent | 6c38429f96ff9128ebd983a85aa6a2024112ed25 (diff) | |
download | gnunet-622fd12c7101c53c1fa0f9563a831f3196732dc5.tar.gz gnunet-622fd12c7101c53c1fa0f9563a831f3196732dc5.zip |
remove dead, obsolete or never-to-become ATS logic (DCE)
Diffstat (limited to 'src/ats')
-rw-r--r-- | src/ats/Makefile.am | 127 | ||||
-rw-r--r-- | src/ats/ats2.h | 294 | ||||
-rw-r--r-- | src/ats/ats_api2_application.c | 366 | ||||
-rw-r--r-- | src/ats/ats_api2_transport.c | 689 | ||||
-rw-r--r-- | src/ats/gnunet-service-ats-new.c | 804 | ||||
-rw-r--r-- | src/ats/perf_ats_solver_mlp.conf | 0 | ||||
-rw-r--r-- | src/ats/perf_ats_solver_ril.conf | 0 | ||||
-rw-r--r-- | src/ats/plugin_ats2_common.c | 99 | ||||
-rw-r--r-- | src/ats/plugin_ats2_simple.c | 1087 | ||||
-rw-r--r-- | src/ats/plugin_ats_mlp.c | 2924 | ||||
-rw-r--r-- | src/ats/plugin_ats_ril.c | 2997 | ||||
-rw-r--r-- | src/ats/test_ats2_lib.c | 259 | ||||
-rw-r--r-- | src/ats/test_ats2_lib.conf | 13 | ||||
-rw-r--r-- | src/ats/test_ats2_lib.h | 523 | ||||
-rw-r--r-- | src/ats/test_ats_api_mlp.conf | 45 | ||||
-rw-r--r-- | src/ats/test_ats_api_ril.conf | 24 | ||||
-rw-r--r-- | src/ats/test_ats_solver_delayed_mlp.conf | 20 | ||||
-rw-r--r-- | src/ats/test_ats_solver_delayed_ril.conf | 31 |
18 files changed, 6 insertions, 10296 deletions
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am index d7e5b68c7..bd8962158 100644 --- a/src/ats/Makefile.am +++ b/src/ats/Makefile.am | |||
@@ -15,22 +15,10 @@ if USE_COVERAGE | |||
15 | endif | 15 | endif |
16 | 16 | ||
17 | lib_LTLIBRARIES = \ | 17 | lib_LTLIBRARIES = \ |
18 | libgnunetats.la \ | 18 | libgnunetats.la |
19 | libgnunetatsapplication.la \ | ||
20 | libgnunetatstransport.la | ||
21 | 19 | ||
22 | plugin_LTLIBRARIES = \ | 20 | plugin_LTLIBRARIES = \ |
23 | libgnunet_plugin_ats_proportional.la \ | 21 | libgnunet_plugin_ats_proportional.la |
24 | libgnunet_plugin_ats2_simple.la | ||
25 | |||
26 | if HAVE_EXPERIMENTAL | ||
27 | plugin_LTLIBRARIES += \ | ||
28 | libgnunet_plugin_ats_ril.la | ||
29 | if HAVE_LIBGLPK | ||
30 | plugin_LTLIBRARIES += \ | ||
31 | libgnunet_plugin_ats_mlp.la | ||
32 | endif | ||
33 | endif | ||
34 | 22 | ||
35 | libgnunetats_la_SOURCES = \ | 23 | libgnunetats_la_SOURCES = \ |
36 | ats_api_connectivity.c \ | 24 | ats_api_connectivity.c \ |
@@ -45,74 +33,20 @@ libgnunetats_la_LDFLAGS = \ | |||
45 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | 33 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ |
46 | -version-info 4:0:0 | 34 | -version-info 4:0:0 |
47 | 35 | ||
48 | |||
49 | libgnunetatsapplication_la_SOURCES = \ | ||
50 | ats_api2_application.c | ||
51 | libgnunetatsapplication_la_LIBADD = \ | ||
52 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
53 | $(LTLIBINTL) | ||
54 | libgnunetatsapplication_la_LDFLAGS = \ | ||
55 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
56 | -version-info 0:0:0 | ||
57 | |||
58 | libgnunetatstransport_la_SOURCES = \ | ||
59 | ats_api2_transport.c | ||
60 | libgnunetatstransport_la_LIBADD = \ | ||
61 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
62 | $(LTLIBINTL) | ||
63 | libgnunetatstransport_la_LDFLAGS = \ | ||
64 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
65 | -version-info 0:0:0 | ||
66 | |||
67 | libgnunet_plugin_ats_proportional_la_SOURCES = \ | 36 | libgnunet_plugin_ats_proportional_la_SOURCES = \ |
68 | plugin_ats_proportional.c | 37 | plugin_ats_proportional.c |
69 | libgnunet_plugin_ats_proportional_la_LIBADD = \ | 38 | libgnunet_plugin_ats_proportional_la_LIBADD = \ |
70 | libgnunetats.la \ | 39 | libgnunetats.la \ |
71 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | 40 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ |
72 | $(top_builddir)/src/util/libgnunetutil.la \ | 41 | $(top_builddir)/src/util/libgnunetutil.la \ |
73 | $(top_builddir)/src/nt/libgnunetnt.la \ | ||
74 | $(LTLIBINTL) | ||
75 | libgnunet_plugin_ats_proportional_la_LDFLAGS = \ | ||
76 | $(GN_PLUGIN_LDFLAGS) | ||
77 | |||
78 | libgnunet_plugin_ats2_simple_la_SOURCES = \ | ||
79 | plugin_ats2_simple.c | ||
80 | libgnunet_plugin_ats2_simple_la_LIBADD = \ | ||
81 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
82 | $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ | ||
83 | $(top_builddir)/src/nt/libgnunetnt.la \ | 42 | $(top_builddir)/src/nt/libgnunetnt.la \ |
84 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
85 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
86 | $(LTLIBINTL) | 43 | $(LTLIBINTL) |
87 | libgnunet_plugin_ats2_simple_la_LDFLAGS = \ | 44 | libgnunet_plugin_ats_proportional_la_LDFLAGS = \ |
88 | $(GN_PLUGIN_LDFLAGS) | 45 | $(GN_PLUGIN_LDFLAGS) |
89 | 46 | ||
90 | 47 | ||
91 | libgnunet_plugin_ats_mlp_la_SOURCES = \ | ||
92 | plugin_ats_mlp.c | ||
93 | libgnunet_plugin_ats_mlp_la_LIBADD = \ | ||
94 | libgnunetats.la \ | ||
95 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
96 | $(top_builddir)/src/nt/libgnunetnt.la \ | ||
97 | $(top_builddir)/src/util/libgnunetutil.la | ||
98 | libgnunet_plugin_ats_mlp_la_LDFLAGS = \ | ||
99 | $(GN_PLUGIN_LDFLAGS) \ | ||
100 | -lglpk | ||
101 | |||
102 | libgnunet_plugin_ats_ril_la_SOURCES = \ | ||
103 | plugin_ats_ril.c | ||
104 | libgnunet_plugin_ats_ril_la_LIBADD = \ | ||
105 | libgnunetats.la \ | ||
106 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
107 | $(top_builddir)/src/nt/libgnunetnt.la \ | ||
108 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
109 | $(LTLIBINTL) | ||
110 | libgnunet_plugin_ats_ril_la_LDFLAGS = \ | ||
111 | $(GN_PLUGIN_LDFLAGS) | ||
112 | |||
113 | libexec_PROGRAMS = \ | 48 | libexec_PROGRAMS = \ |
114 | gnunet-service-ats \ | 49 | gnunet-service-ats |
115 | gnunet-service-ats-new | ||
116 | 50 | ||
117 | gnunet_service_ats_SOURCES = \ | 51 | gnunet_service_ats_SOURCES = \ |
118 | gnunet-service-ats.c gnunet-service-ats.h \ | 52 | gnunet-service-ats.c gnunet-service-ats.h \ |
@@ -131,27 +65,10 @@ gnunet_service_ats_LDADD = \ | |||
131 | libgnunetats.la \ | 65 | libgnunetats.la \ |
132 | $(GN_LIBINTL) | 66 | $(GN_LIBINTL) |
133 | 67 | ||
134 | gnunet_service_ats_new_SOURCES = \ | ||
135 | gnunet-service-ats-new.c | ||
136 | gnunet_service_ats_new_LDADD = \ | ||
137 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
138 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
139 | $(GN_LIBINTL) | ||
140 | |||
141 | |||
142 | if HAVE_TESTING | 68 | if HAVE_TESTING |
143 | TESTING_TESTS = \ | 69 | TESTING_TESTS = \ |
144 | test_ats_api_proportional \ | 70 | test_ats_api_proportional \ |
145 | test_ats_reservation_api_proportional \ | 71 | test_ats_reservation_api_proportional |
146 | test_ats2_lib | ||
147 | if HAVE_EXPERIMENTAL | ||
148 | TESTING_TESTS += \ | ||
149 | test_ats_api_ril | ||
150 | if HAVE_LIBGLPK | ||
151 | TESTING_TESTS += \ | ||
152 | test_ats_api_mlp | ||
153 | endif | ||
154 | endif | ||
155 | endif | 72 | endif |
156 | 73 | ||
157 | check_PROGRAMS = \ | 74 | check_PROGRAMS = \ |
@@ -180,40 +97,8 @@ test_ats_reservation_api_proportional_LDADD = \ | |||
180 | $(top_builddir)/src/testing/libgnunettesting.la \ | 97 | $(top_builddir)/src/testing/libgnunettesting.la \ |
181 | libgnunetats.la | 98 | libgnunetats.la |
182 | 99 | ||
183 | test_ats_api_ril_SOURCES = \ | ||
184 | test_ats_api.c \ | ||
185 | test_ats_lib.c test_ats_lib.h | ||
186 | test_ats_api_ril_LDADD = \ | ||
187 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
188 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
189 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
190 | libgnunetats.la | ||
191 | |||
192 | test_ats_api_mlp_SOURCES = \ | ||
193 | test_ats_api.c \ | ||
194 | test_ats_lib.c test_ats_lib.h | ||
195 | test_ats_api_mlp_LDADD = \ | ||
196 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
197 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
198 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
199 | libgnunetats.la | ||
200 | |||
201 | test_ats2_lib_SOURCES = \ | ||
202 | test_ats2_lib.c test_ats2_lib.h | ||
203 | test_ats2_lib_LDADD = \ | ||
204 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
205 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
206 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
207 | libgnunetatsapplication.la \ | ||
208 | libgnunetatstransport.la | ||
209 | |||
210 | |||
211 | EXTRA_DIST = \ | 100 | EXTRA_DIST = \ |
212 | ats.h ats2.h \ | 101 | ats.h \ |
213 | plugin_ats2_common.c \ | ||
214 | test_delay \ | 102 | test_delay \ |
215 | test_ats2_lib.conf \ | ||
216 | test_ats_api.conf \ | 103 | test_ats_api.conf \ |
217 | test_ats_api_mlp.conf \ | ||
218 | test_ats_api_ril.conf \ | ||
219 | test_ats_api_proportional.conf | 104 | test_ats_api_proportional.conf |
diff --git a/src/ats/ats2.h b/src/ats/ats2.h deleted file mode 100644 index df402dba2..000000000 --- a/src/ats/ats2.h +++ /dev/null | |||
@@ -1,294 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010-2015 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/ats2.h | ||
22 | * @brief automatic transport selection messages | ||
23 | * @author Christian Grothoff | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | #ifndef ATS2_H | ||
27 | #define ATS2_H | ||
28 | |||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_ats_transport_service.h" | ||
31 | |||
32 | |||
33 | GNUNET_NETWORK_STRUCT_BEGIN | ||
34 | |||
35 | |||
36 | /** | ||
37 | * ATS performance characteristics for an address. | ||
38 | */ | ||
39 | struct PropertiesNBO | ||
40 | { | ||
41 | /** | ||
42 | * Delay. Time between when the time packet is sent and the packet | ||
43 | * arrives. FOREVER if we did not (successfully) measure yet. | ||
44 | */ | ||
45 | struct GNUNET_TIME_RelativeNBO delay; | ||
46 | |||
47 | /** | ||
48 | * Confirmed successful payload on this connection from this peer to | ||
49 | * the other peer. In NBO. | ||
50 | * | ||
51 | * Unit: [bytes/second] | ||
52 | */ | ||
53 | uint32_t goodput_out; | ||
54 | |||
55 | /** | ||
56 | * Confirmed useful payload on this connection to this peer from | ||
57 | * the other peer. In NBO. | ||
58 | * | ||
59 | * Unit: [bytes/second] | ||
60 | */ | ||
61 | uint32_t goodput_in; | ||
62 | |||
63 | /** | ||
64 | * Actual traffic on this connection from this peer to the other peer. | ||
65 | * Includes transport overhead. In NBO. | ||
66 | * | ||
67 | * Unit: [bytes/second] | ||
68 | */ | ||
69 | uint32_t utilization_out; | ||
70 | |||
71 | /** | ||
72 | * Actual traffic on this connection from the other peer to this peer. | ||
73 | * Includes transport overhead. In NBO. | ||
74 | * | ||
75 | * Unit: [bytes/second] | ||
76 | */ | ||
77 | uint32_t utilization_in; | ||
78 | |||
79 | /** | ||
80 | * Distance on network layer (required for distance-vector routing) | ||
81 | * in hops. Zero for direct connections (i.e. plain TCP/UDP). In NBO. | ||
82 | */ | ||
83 | uint32_t distance; | ||
84 | |||
85 | /** | ||
86 | * MTU of the network layer, UINT32_MAX for no MTU (stream). | ||
87 | * | ||
88 | * Unit: [bytes]. In NBO. | ||
89 | */ | ||
90 | uint32_t mtu; | ||
91 | |||
92 | /** | ||
93 | * Which network scope does the respective address belong to? | ||
94 | * A `enum GNUNET_NetworkType nt` in NBO. | ||
95 | */ | ||
96 | uint32_t nt; | ||
97 | |||
98 | /** | ||
99 | * What characteristics does this communicator have? | ||
100 | * A `enum GNUNET_TRANSPORT_CommunicatorCharacteristics` in NBO. | ||
101 | */ | ||
102 | uint32_t cc; | ||
103 | }; | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Application client to ATS service: we would like to have | ||
108 | * address suggestions for this peer. | ||
109 | */ | ||
110 | struct ExpressPreferenceMessage | ||
111 | { | ||
112 | /** | ||
113 | * Type is #GNUNET_MESSAGE_TYPE_ATS_SUGGEST or | ||
114 | * #GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL to stop | ||
115 | * suggestions. | ||
116 | */ | ||
117 | struct GNUNET_MessageHeader header; | ||
118 | |||
119 | /** | ||
120 | * What type of performance preference does the client have? | ||
121 | * A `enum GNUNET_MQ_PreferenceKind` in NBO. | ||
122 | */ | ||
123 | uint32_t pk GNUNET_PACKED; | ||
124 | |||
125 | /** | ||
126 | * Peer to get address suggestions for. | ||
127 | */ | ||
128 | struct GNUNET_PeerIdentity peer; | ||
129 | |||
130 | /** | ||
131 | * How much bandwidth in bytes/second does the application expect? | ||
132 | */ | ||
133 | struct GNUNET_BANDWIDTH_Value32NBO bw; | ||
134 | }; | ||
135 | |||
136 | |||
137 | /** | ||
138 | * Transport client to ATS service: here is another session you can use. | ||
139 | */ | ||
140 | struct SessionAddMessage | ||
141 | { | ||
142 | /** | ||
143 | * Type is #GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD or | ||
144 | * #GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY | ||
145 | */ | ||
146 | struct GNUNET_MessageHeader header; | ||
147 | |||
148 | /** | ||
149 | * Internal number this client will henceforth use to | ||
150 | * refer to this session. | ||
151 | */ | ||
152 | uint32_t session_id GNUNET_PACKED; | ||
153 | |||
154 | /** | ||
155 | * Identity of the peer that this session is for. | ||
156 | */ | ||
157 | struct GNUNET_PeerIdentity peer; | ||
158 | |||
159 | /** | ||
160 | * Performance properties of the session. | ||
161 | */ | ||
162 | struct PropertiesNBO properties; | ||
163 | |||
164 | /* followed by: | ||
165 | * - char * address (including '\0'-termination). | ||
166 | */ | ||
167 | }; | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Message used to notify ATS that the performance | ||
172 | * characteristics for an session have changed. | ||
173 | */ | ||
174 | struct SessionUpdateMessage | ||
175 | { | ||
176 | /** | ||
177 | * Message of type #GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE. | ||
178 | */ | ||
179 | struct GNUNET_MessageHeader header; | ||
180 | |||
181 | /** | ||
182 | * Internal number this client uses to refer to this session. | ||
183 | */ | ||
184 | uint32_t session_id GNUNET_PACKED; | ||
185 | |||
186 | /** | ||
187 | * Which peer is this about? (Technically redundant, as the | ||
188 | * @e session_id should be sufficient, but enables ATS service | ||
189 | * to find the session faster). | ||
190 | */ | ||
191 | struct GNUNET_PeerIdentity peer; | ||
192 | |||
193 | /** | ||
194 | * Performance properties of the session. | ||
195 | */ | ||
196 | struct PropertiesNBO properties; | ||
197 | }; | ||
198 | |||
199 | |||
200 | /** | ||
201 | * Message sent by ATS client to ATS service when an session | ||
202 | * was destroyed and must thus henceforth no longer be considered | ||
203 | * for scheduling. | ||
204 | */ | ||
205 | struct SessionDelMessage | ||
206 | { | ||
207 | /** | ||
208 | * Type is #GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL. | ||
209 | */ | ||
210 | struct GNUNET_MessageHeader header; | ||
211 | |||
212 | /** | ||
213 | * Internal number this client uses to refer to this session. | ||
214 | */ | ||
215 | uint32_t session_id GNUNET_PACKED; | ||
216 | |||
217 | /** | ||
218 | * Which peer is this about? (Technically redundant, as the | ||
219 | * @e session_id should be sufficient, but enables ATS service | ||
220 | * to find the session faster). | ||
221 | */ | ||
222 | struct GNUNET_PeerIdentity peer; | ||
223 | }; | ||
224 | |||
225 | |||
226 | /** | ||
227 | * ATS Service allocates resources to an session | ||
228 | * identified by the given @e session_id for the given @e peer with | ||
229 | * the given @e bandwidth_in and @e bandwidth_out limits from now on. | ||
230 | */ | ||
231 | struct SessionAllocationMessage | ||
232 | { | ||
233 | /** | ||
234 | * A message of type #GNUNET_MESSAGE_TYPE_ATS_SESSION_ALLOCATION. | ||
235 | */ | ||
236 | struct GNUNET_MessageHeader header; | ||
237 | |||
238 | /** | ||
239 | * Internal number this client uses to refer to the session this | ||
240 | * suggestion is about. | ||
241 | */ | ||
242 | uint32_t session_id GNUNET_PACKED; | ||
243 | |||
244 | /** | ||
245 | * Which peer is this about? (Technically redundant, as the | ||
246 | * @e session_id should be sufficient, but may enable client | ||
247 | * to find the session faster and/or check consistency). | ||
248 | */ | ||
249 | struct GNUNET_PeerIdentity peer; | ||
250 | |||
251 | /** | ||
252 | * How much bandwidth we are allowed for sending. | ||
253 | */ | ||
254 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; | ||
255 | |||
256 | /** | ||
257 | * How much bandwidth we are allowed for receiving. | ||
258 | */ | ||
259 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; | ||
260 | }; | ||
261 | |||
262 | |||
263 | /** | ||
264 | * ATS Service suggests to the transport service to try the address | ||
265 | * for the given @e peer. | ||
266 | */ | ||
267 | struct AddressSuggestionMessage | ||
268 | { | ||
269 | /** | ||
270 | * A message of type #GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION. | ||
271 | */ | ||
272 | struct GNUNET_MessageHeader header; | ||
273 | |||
274 | /** | ||
275 | * Zero. | ||
276 | */ | ||
277 | uint32_t reserved GNUNET_PACKED; | ||
278 | |||
279 | /** | ||
280 | * Which peer is this about? (Technically redundant, as the | ||
281 | * @e session_id should be sufficient, but may enable client | ||
282 | * to find the session faster and/or check consistency). | ||
283 | */ | ||
284 | struct GNUNET_PeerIdentity peer; | ||
285 | |||
286 | /* Followed by 0-terminated address */ | ||
287 | }; | ||
288 | |||
289 | |||
290 | GNUNET_NETWORK_STRUCT_END | ||
291 | |||
292 | |||
293 | |||
294 | #endif | ||
diff --git a/src/ats/ats_api2_application.c b/src/ats/ats_api2_application.c deleted file mode 100644 index 46e57c5bb..000000000 --- a/src/ats/ats_api2_application.c +++ /dev/null | |||
@@ -1,366 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010-2016 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/ats_api2_application.c | ||
22 | * @brief enable clients to ask ATS about establishing connections to peers | ||
23 | * @author Christian Grothoff | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_ats_application_service.h" | ||
28 | #include "ats2.h" | ||
29 | |||
30 | |||
31 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-application-api", \ | ||
32 | __VA_ARGS__) | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Handle for ATS address suggestion requests. | ||
37 | */ | ||
38 | struct GNUNET_ATS_ApplicationSuggestHandle | ||
39 | { | ||
40 | /** | ||
41 | * ID of the peer for which address suggestion was requested. | ||
42 | */ | ||
43 | struct GNUNET_PeerIdentity id; | ||
44 | |||
45 | /** | ||
46 | * Connecitivity handle this suggestion handle belongs to. | ||
47 | */ | ||
48 | struct GNUNET_ATS_ApplicationHandle *ch; | ||
49 | |||
50 | /** | ||
51 | * What preference is being expressed? | ||
52 | */ | ||
53 | enum GNUNET_MQ_PreferenceKind pk; | ||
54 | |||
55 | /** | ||
56 | * How much bandwidth does the client expect? | ||
57 | */ | ||
58 | struct GNUNET_BANDWIDTH_Value32NBO bw; | ||
59 | }; | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Handle to the ATS subsystem for application management. | ||
64 | */ | ||
65 | struct GNUNET_ATS_ApplicationHandle | ||
66 | { | ||
67 | /** | ||
68 | * Our configuration. | ||
69 | */ | ||
70 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
71 | |||
72 | /** | ||
73 | * Map with the identities of all the peers for which we would | ||
74 | * like to have address suggestions. The key is the PID, the | ||
75 | * value is currently the `struct GNUNET_ATS_ApplicationSuggestHandle` | ||
76 | */ | ||
77 | struct GNUNET_CONTAINER_MultiPeerMap *sug_requests; | ||
78 | |||
79 | /** | ||
80 | * Message queue for sending requests to the ATS service. | ||
81 | */ | ||
82 | struct GNUNET_MQ_Handle *mq; | ||
83 | |||
84 | /** | ||
85 | * Task to trigger reconnect. | ||
86 | */ | ||
87 | struct GNUNET_SCHEDULER_Task *task; | ||
88 | |||
89 | /** | ||
90 | * Reconnect backoff delay. | ||
91 | */ | ||
92 | struct GNUNET_TIME_Relative backoff; | ||
93 | }; | ||
94 | |||
95 | |||
96 | /** | ||
97 | * Re-establish the connection to the ATS service. | ||
98 | * | ||
99 | * @param ch handle to use to re-connect. | ||
100 | */ | ||
101 | static void | ||
102 | reconnect (struct GNUNET_ATS_ApplicationHandle *ch); | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Re-establish the connection to the ATS service. | ||
107 | * | ||
108 | * @param cls handle to use to re-connect. | ||
109 | */ | ||
110 | static void | ||
111 | reconnect_task (void *cls) | ||
112 | { | ||
113 | struct GNUNET_ATS_ApplicationHandle *ch = cls; | ||
114 | |||
115 | ch->task = NULL; | ||
116 | reconnect (ch); | ||
117 | } | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Disconnect from ATS and then reconnect. | ||
122 | * | ||
123 | * @param ch our handle | ||
124 | */ | ||
125 | static void | ||
126 | force_reconnect (struct GNUNET_ATS_ApplicationHandle *ch) | ||
127 | { | ||
128 | if (NULL != ch->mq) | ||
129 | { | ||
130 | GNUNET_MQ_destroy (ch->mq); | ||
131 | ch->mq = NULL; | ||
132 | } | ||
133 | ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff); | ||
134 | ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff, | ||
135 | &reconnect_task, | ||
136 | ch); | ||
137 | } | ||
138 | |||
139 | |||
140 | /** | ||
141 | * We encountered an error handling the MQ to the | ||
142 | * ATS service. Reconnect. | ||
143 | * | ||
144 | * @param cls the `struct GNUNET_ATS_ApplicationHandle` | ||
145 | * @param error details about the error | ||
146 | */ | ||
147 | static void | ||
148 | error_handler (void *cls, | ||
149 | enum GNUNET_MQ_Error error) | ||
150 | { | ||
151 | struct GNUNET_ATS_ApplicationHandle *ch = cls; | ||
152 | |||
153 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
154 | "ATS connection died (code %d), reconnecting\n", | ||
155 | (int) error); | ||
156 | force_reconnect (ch); | ||
157 | } | ||
158 | |||
159 | |||
160 | /** | ||
161 | * Transmit request for an address suggestion. | ||
162 | * | ||
163 | * @param cls the `struct GNUNET_ATS_ApplicationHandle` | ||
164 | * @param peer peer to ask for an address suggestion for | ||
165 | * @param value the `struct GNUNET_ATS_SuggestHandle` | ||
166 | * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on | ||
167 | * failure (message queue no longer exists) | ||
168 | */ | ||
169 | static int | ||
170 | transmit_suggestion (void *cls, | ||
171 | const struct GNUNET_PeerIdentity *peer, | ||
172 | void *value) | ||
173 | { | ||
174 | struct GNUNET_ATS_ApplicationHandle *ch = cls; | ||
175 | struct GNUNET_ATS_ApplicationSuggestHandle *sh = value; | ||
176 | struct GNUNET_MQ_Envelope *ev; | ||
177 | struct ExpressPreferenceMessage *m; | ||
178 | |||
179 | if (NULL == ch->mq) | ||
180 | return GNUNET_SYSERR; | ||
181 | ev = GNUNET_MQ_msg (m, | ||
182 | GNUNET_MESSAGE_TYPE_ATS_SUGGEST); | ||
183 | m->pk = htonl ((uint32_t) sh->pk); | ||
184 | m->bw = sh->bw; | ||
185 | m->peer = *peer; | ||
186 | GNUNET_MQ_send (ch->mq, ev); | ||
187 | return GNUNET_OK; | ||
188 | } | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Re-establish the connection to the ATS service. | ||
193 | * | ||
194 | * @param ch handle to use to re-connect. | ||
195 | */ | ||
196 | static void | ||
197 | reconnect (struct GNUNET_ATS_ApplicationHandle *ch) | ||
198 | { | ||
199 | static const struct GNUNET_MQ_MessageHandler handlers[] = { | ||
200 | { NULL, 0, 0 } | ||
201 | }; | ||
202 | |||
203 | GNUNET_assert (NULL == ch->mq); | ||
204 | ch->mq = GNUNET_CLIENT_connect (ch->cfg, | ||
205 | "ats", | ||
206 | handlers, | ||
207 | &error_handler, | ||
208 | ch); | ||
209 | if (NULL == ch->mq) | ||
210 | { | ||
211 | force_reconnect (ch); | ||
212 | return; | ||
213 | } | ||
214 | GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests, | ||
215 | &transmit_suggestion, | ||
216 | ch); | ||
217 | } | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Initialize the ATS application suggestion client handle. | ||
222 | * | ||
223 | * @param cfg configuration to use | ||
224 | * @return ats application handle, NULL on error | ||
225 | */ | ||
226 | struct GNUNET_ATS_ApplicationHandle * | ||
227 | GNUNET_ATS_application_init (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
228 | { | ||
229 | struct GNUNET_ATS_ApplicationHandle *ch; | ||
230 | |||
231 | ch = GNUNET_new (struct GNUNET_ATS_ApplicationHandle); | ||
232 | ch->cfg = cfg; | ||
233 | ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32, | ||
234 | GNUNET_YES); | ||
235 | reconnect (ch); | ||
236 | return ch; | ||
237 | } | ||
238 | |||
239 | |||
240 | /** | ||
241 | * Function called to free all `struct GNUNET_ATS_ApplicationSuggestHandle`s | ||
242 | * in the map. | ||
243 | * | ||
244 | * @param cls NULL | ||
245 | * @param key the key | ||
246 | * @param value the value to free | ||
247 | * @return #GNUNET_OK (continue to iterate) | ||
248 | */ | ||
249 | static int | ||
250 | free_sug_handle (void *cls, | ||
251 | const struct GNUNET_PeerIdentity *key, | ||
252 | void *value) | ||
253 | { | ||
254 | struct GNUNET_ATS_ApplicationSuggestHandle *cur = value; | ||
255 | |||
256 | GNUNET_free (cur); | ||
257 | return GNUNET_OK; | ||
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Client is done with ATS application management, release resources. | ||
263 | * | ||
264 | * @param ch handle to release | ||
265 | */ | ||
266 | void | ||
267 | GNUNET_ATS_application_done (struct GNUNET_ATS_ApplicationHandle *ch) | ||
268 | { | ||
269 | if (NULL != ch->mq) | ||
270 | { | ||
271 | GNUNET_MQ_destroy (ch->mq); | ||
272 | ch->mq = NULL; | ||
273 | } | ||
274 | if (NULL != ch->task) | ||
275 | { | ||
276 | GNUNET_SCHEDULER_cancel (ch->task); | ||
277 | ch->task = NULL; | ||
278 | } | ||
279 | GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests, | ||
280 | &free_sug_handle, | ||
281 | NULL); | ||
282 | GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests); | ||
283 | GNUNET_free (ch); | ||
284 | } | ||
285 | |||
286 | |||
287 | /** | ||
288 | * We would like to receive address suggestions for a peer. ATS will | ||
289 | * respond with a call to the continuation immediately containing an address or | ||
290 | * no address if none is available. ATS can suggest more addresses until we call | ||
291 | * #GNUNET_ATS_application_suggest_cancel(). | ||
292 | * | ||
293 | * @param ch handle | ||
294 | * @param peer identity of the peer we need an address for | ||
295 | * @param pk what kind of application will the application require (can be | ||
296 | * #GNUNET_MQ_PREFERENCE_NONE, we will still try to connect) | ||
297 | * @param bw desired bandwith, can be zero (we will still try to connect) | ||
298 | * @return suggest handle, NULL if a request is already pending | ||
299 | */ | ||
300 | struct GNUNET_ATS_ApplicationSuggestHandle * | ||
301 | GNUNET_ATS_application_suggest (struct GNUNET_ATS_ApplicationHandle *ch, | ||
302 | const struct GNUNET_PeerIdentity *peer, | ||
303 | enum GNUNET_MQ_PreferenceKind pk, | ||
304 | struct GNUNET_BANDWIDTH_Value32NBO bw) | ||
305 | { | ||
306 | struct GNUNET_ATS_ApplicationSuggestHandle *s; | ||
307 | |||
308 | s = GNUNET_new (struct GNUNET_ATS_ApplicationSuggestHandle); | ||
309 | s->ch = ch; | ||
310 | s->id = *peer; | ||
311 | s->pk = pk; | ||
312 | s->bw = bw; | ||
313 | (void) GNUNET_CONTAINER_multipeermap_put (ch->sug_requests, | ||
314 | &s->id, | ||
315 | s, | ||
316 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
317 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
318 | "Requesting ATS to suggest address for `%s'\n", | ||
319 | GNUNET_i2s (peer)); | ||
320 | if (NULL == ch->mq) | ||
321 | return s; | ||
322 | GNUNET_assert (GNUNET_OK == | ||
323 | transmit_suggestion (ch, | ||
324 | &s->id, | ||
325 | s)); | ||
326 | return s; | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * We no longer care about being connected to a peer. | ||
332 | * | ||
333 | * @param sh handle to stop | ||
334 | */ | ||
335 | void | ||
336 | GNUNET_ATS_application_suggest_cancel (struct | ||
337 | GNUNET_ATS_ApplicationSuggestHandle *sh) | ||
338 | { | ||
339 | struct GNUNET_ATS_ApplicationHandle *ch = sh->ch; | ||
340 | struct GNUNET_MQ_Envelope *ev; | ||
341 | struct ExpressPreferenceMessage *m; | ||
342 | |||
343 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
344 | "Telling ATS we no longer care for an address for `%s'\n", | ||
345 | GNUNET_i2s (&sh->id)); | ||
346 | GNUNET_assert (GNUNET_OK == | ||
347 | GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests, | ||
348 | &sh->id, | ||
349 | sh)); | ||
350 | if (NULL == ch->mq) | ||
351 | { | ||
352 | GNUNET_free (sh); | ||
353 | return; | ||
354 | } | ||
355 | ev = GNUNET_MQ_msg (m, | ||
356 | GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL); | ||
357 | m->pk = htonl ((uint32_t) sh->pk); | ||
358 | m->bw = sh->bw; | ||
359 | m->peer = sh->id; | ||
360 | GNUNET_MQ_send (ch->mq, | ||
361 | ev); | ||
362 | GNUNET_free (sh); | ||
363 | } | ||
364 | |||
365 | |||
366 | /* end of ats_api2_application.c */ | ||
diff --git a/src/ats/ats_api2_transport.c b/src/ats/ats_api2_transport.c deleted file mode 100644 index da02ca592..000000000 --- a/src/ats/ats_api2_transport.c +++ /dev/null | |||
@@ -1,689 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010-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 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file ats/ats_api2_transport.c | ||
22 | * @brief address suggestions and bandwidth allocation | ||
23 | * @author Christian Grothoff | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_ats_transport_service.h" | ||
28 | #include "ats2.h" | ||
29 | |||
30 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-transport-api", __VA_ARGS__) | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Information we track per session, incoming or outgoing. It also | ||
35 | * doesn't matter if we have a session, any session that ATS is | ||
36 | * allowed to suggest right now should be tracked. | ||
37 | */ | ||
38 | struct GNUNET_ATS_SessionRecord | ||
39 | { | ||
40 | /** | ||
41 | * Transport handle this session record belongs to. | ||
42 | */ | ||
43 | struct GNUNET_ATS_TransportHandle *ath; | ||
44 | |||
45 | /** | ||
46 | * Address data. | ||
47 | */ | ||
48 | const char *address; | ||
49 | |||
50 | /** | ||
51 | * Session handle, NULL if inbound-only (also implies we cannot | ||
52 | * actually control inbound traffic via transport!). So if | ||
53 | * @e session is NULL, the @e properties are informative for | ||
54 | * ATS (connection exists, utilization) but ATS cannot directly | ||
55 | * influence it (and should thus not call the | ||
56 | * #GNUNET_ATS_AllocationCallback for this @e session, which is | ||
57 | * obvious as NULL is not a meaningful session to allocation | ||
58 | * resources to). | ||
59 | */ | ||
60 | struct GNUNET_ATS_Session *session; | ||
61 | |||
62 | /** | ||
63 | * Identity of the peer reached at @e address. | ||
64 | */ | ||
65 | struct GNUNET_PeerIdentity pid; | ||
66 | |||
67 | /** | ||
68 | * Performance data about the @e session. | ||
69 | */ | ||
70 | struct GNUNET_ATS_Properties properties; | ||
71 | |||
72 | /** | ||
73 | * Unique ID to identify this session at this @a pid in IPC | ||
74 | * messages. | ||
75 | */ | ||
76 | uint32_t slot; | ||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Handle to the ATS subsystem for bandwidth/transport transport information. | ||
82 | */ | ||
83 | struct GNUNET_ATS_TransportHandle | ||
84 | { | ||
85 | /** | ||
86 | * Our configuration. | ||
87 | */ | ||
88 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
89 | |||
90 | /** | ||
91 | * Callback to invoke on suggestions. | ||
92 | */ | ||
93 | GNUNET_ATS_SuggestionCallback suggest_cb; | ||
94 | |||
95 | /** | ||
96 | * Closure for @e suggest_cb. | ||
97 | */ | ||
98 | void *suggest_cb_cls; | ||
99 | |||
100 | /** | ||
101 | * Callback to invoke on allocations. | ||
102 | */ | ||
103 | GNUNET_ATS_AllocationCallback alloc_cb; | ||
104 | |||
105 | /** | ||
106 | * Closure for @e alloc_cb. | ||
107 | */ | ||
108 | void *alloc_cb_cls; | ||
109 | |||
110 | /** | ||
111 | * Message queue for sending requests to the ATS service. | ||
112 | */ | ||
113 | struct GNUNET_MQ_Handle *mq; | ||
114 | |||
115 | /** | ||
116 | * Task to trigger reconnect. | ||
117 | */ | ||
118 | struct GNUNET_SCHEDULER_Task *task; | ||
119 | |||
120 | /** | ||
121 | * Hash map mapping PIDs to session records. | ||
122 | */ | ||
123 | struct GNUNET_CONTAINER_MultiPeerMap *records; | ||
124 | |||
125 | /** | ||
126 | * Reconnect backoff delay. | ||
127 | */ | ||
128 | struct GNUNET_TIME_Relative backoff; | ||
129 | }; | ||
130 | |||
131 | |||
132 | |||
133 | /** | ||
134 | * Convert ATS properties from host to network byte order. | ||
135 | * | ||
136 | * @param nbo[OUT] value written | ||
137 | * @param hbo value read | ||
138 | */ | ||
139 | static void | ||
140 | properties_hton (struct PropertiesNBO *nbo, | ||
141 | const struct GNUNET_ATS_Properties *hbo) | ||
142 | { | ||
143 | nbo->delay = GNUNET_TIME_relative_hton (hbo->delay); | ||
144 | nbo->goodput_out = htonl (hbo->goodput_out); | ||
145 | nbo->goodput_in = htonl (hbo->goodput_in); | ||
146 | nbo->utilization_out = htonl (hbo->utilization_out); | ||
147 | nbo->utilization_in = htonl (hbo->utilization_in); | ||
148 | nbo->distance = htonl (hbo->distance); | ||
149 | nbo->mtu = htonl (hbo->mtu); | ||
150 | nbo->nt = htonl ((uint32_t) hbo->nt); | ||
151 | nbo->cc = htonl ((uint32_t) hbo->cc); | ||
152 | } | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Re-establish the connection to the ATS service. | ||
157 | * | ||
158 | * @param sh handle to use to re-connect. | ||
159 | */ | ||
160 | static void | ||
161 | reconnect (struct GNUNET_ATS_TransportHandle *ath); | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Re-establish the connection to the ATS service. | ||
166 | * | ||
167 | * @param cls handle to use to re-connect. | ||
168 | */ | ||
169 | static void | ||
170 | reconnect_task (void *cls) | ||
171 | { | ||
172 | struct GNUNET_ATS_TransportHandle *ath = cls; | ||
173 | |||
174 | ath->task = NULL; | ||
175 | reconnect (ath); | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Disconnect from ATS and then reconnect. | ||
181 | * | ||
182 | * @param ath our handle | ||
183 | */ | ||
184 | static void | ||
185 | force_reconnect (struct GNUNET_ATS_TransportHandle *ath) | ||
186 | { | ||
187 | if (NULL != ath->mq) | ||
188 | { | ||
189 | GNUNET_MQ_destroy (ath->mq); | ||
190 | ath->mq = NULL; | ||
191 | } | ||
192 | /* FIXME: do we tell transport service about disconnect events? CON: | ||
193 | initially ATS will have a really screwed picture of the world and | ||
194 | the rapid change would be bad. PRO: if we don't, ATS and | ||
195 | transport may disagree about the allocation for a while... | ||
196 | For now: lazy: do nothing. */ | ||
197 | ath->backoff = GNUNET_TIME_STD_BACKOFF (ath->backoff); | ||
198 | ath->task = GNUNET_SCHEDULER_add_delayed (ath->backoff, | ||
199 | &reconnect_task, | ||
200 | ath); | ||
201 | } | ||
202 | |||
203 | |||
204 | /** | ||
205 | * Check format of address suggestion message from the service. | ||
206 | * | ||
207 | * @param cls the `struct GNUNET_ATS_TransportHandle` | ||
208 | * @param m message received | ||
209 | */ | ||
210 | static int | ||
211 | check_ats_address_suggestion (void *cls, | ||
212 | const struct AddressSuggestionMessage *m) | ||
213 | { | ||
214 | (void) cls; | ||
215 | GNUNET_MQ_check_zero_termination (m); | ||
216 | return GNUNET_SYSERR; | ||
217 | } | ||
218 | |||
219 | |||
220 | /** | ||
221 | * We received an address suggestion message from the service. | ||
222 | * | ||
223 | * @param cls the `struct GNUNET_ATS_TransportHandle` | ||
224 | * @param m message received | ||
225 | */ | ||
226 | static void | ||
227 | handle_ats_address_suggestion (void *cls, | ||
228 | const struct AddressSuggestionMessage *m) | ||
229 | { | ||
230 | struct GNUNET_ATS_TransportHandle *ath = cls; | ||
231 | const char *address = (const char *) &m[1]; | ||
232 | |||
233 | ath->suggest_cb (ath->suggest_cb_cls, | ||
234 | &m->peer, | ||
235 | address); | ||
236 | } | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Closure for #match_session_cb. | ||
241 | */ | ||
242 | struct FindContext | ||
243 | { | ||
244 | /** | ||
245 | * Key to look for. | ||
246 | */ | ||
247 | uint32_t session_id; | ||
248 | |||
249 | /** | ||
250 | * Where to store the result. | ||
251 | */ | ||
252 | struct GNUNET_ATS_SessionRecord *sr; | ||
253 | }; | ||
254 | |||
255 | |||
256 | /** | ||
257 | * Finds matching session record. | ||
258 | * | ||
259 | * @param cls a `struct FindContext` | ||
260 | * @param pid peer identity (unused) | ||
261 | * @param value a `struct GNUNET_ATS_SessionRecord` | ||
262 | * @return #GNUNET_NO if match found, #GNUNET_YES to continue searching | ||
263 | */ | ||
264 | static int | ||
265 | match_session_cb (void *cls, | ||
266 | const struct GNUNET_PeerIdentity *pid, | ||
267 | void *value) | ||
268 | { | ||
269 | struct FindContext *fc = cls; | ||
270 | struct GNUNET_ATS_SessionRecord *sr = value; | ||
271 | |||
272 | (void) pid; | ||
273 | if (fc->session_id == sr->slot) | ||
274 | { | ||
275 | fc->sr = sr; | ||
276 | return GNUNET_NO; | ||
277 | } | ||
278 | return GNUNET_YES; | ||
279 | } | ||
280 | |||
281 | |||
282 | |||
283 | /** | ||
284 | * Find session record for peer @a pid and session @a session_id | ||
285 | * | ||
286 | * @param ath transport handle to search | ||
287 | * @param session_id session ID to match | ||
288 | * @param pid peer to search under | ||
289 | * @return NULL if no such record exists | ||
290 | */ | ||
291 | static struct GNUNET_ATS_SessionRecord * | ||
292 | find_session (struct GNUNET_ATS_TransportHandle *ath, | ||
293 | uint32_t session_id, | ||
294 | const struct GNUNET_PeerIdentity *pid) | ||
295 | { | ||
296 | struct FindContext fc = { | ||
297 | .session_id = session_id, | ||
298 | .sr = NULL | ||
299 | }; | ||
300 | |||
301 | GNUNET_CONTAINER_multipeermap_get_multiple (ath->records, | ||
302 | pid, | ||
303 | &match_session_cb, | ||
304 | &fc); | ||
305 | return fc.sr; | ||
306 | } | ||
307 | |||
308 | |||
309 | /** | ||
310 | * We received a session allocation message from the service. | ||
311 | * | ||
312 | * @param cls the `struct GNUNET_ATS_TransportHandle` | ||
313 | * @param m message received | ||
314 | */ | ||
315 | static void | ||
316 | handle_ats_session_allocation (void *cls, | ||
317 | const struct SessionAllocationMessage *m) | ||
318 | { | ||
319 | struct GNUNET_ATS_TransportHandle *ath = cls; | ||
320 | struct GNUNET_ATS_SessionRecord *ar; | ||
321 | uint32_t session_id; | ||
322 | |||
323 | session_id = ntohl (m->session_id); | ||
324 | ar = find_session (ath, | ||
325 | session_id, | ||
326 | &m->peer); | ||
327 | if (NULL == ar) | ||
328 | { | ||
329 | /* this can (rarely) happen if ATS changes an sessiones allocation | ||
330 | just when the transport service deleted it */ | ||
331 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
332 | "Allocation ignored, session unknown\n"); | ||
333 | return; | ||
334 | } | ||
335 | ath->backoff = GNUNET_TIME_UNIT_ZERO; | ||
336 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
337 | "ATS allocates bandwidth for peer `%s' using address %s\n", | ||
338 | GNUNET_i2s (&ar->pid), | ||
339 | ar->address); | ||
340 | ath->alloc_cb (ath->alloc_cb_cls, | ||
341 | ar->session, | ||
342 | m->bandwidth_out, | ||
343 | m->bandwidth_in); | ||
344 | } | ||
345 | |||
346 | |||
347 | /** | ||
348 | * We encountered an error handling the MQ to the ATS service. | ||
349 | * Reconnect. | ||
350 | * | ||
351 | * @param cls the `struct GNUNET_ATS_TransportHandle` | ||
352 | * @param error details about the error | ||
353 | */ | ||
354 | static void | ||
355 | error_handler (void *cls, | ||
356 | enum GNUNET_MQ_Error error) | ||
357 | { | ||
358 | struct GNUNET_ATS_TransportHandle *ath = cls; | ||
359 | |||
360 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
361 | "ATS connection died (code %d), reconnecting\n", | ||
362 | (int) error); | ||
363 | force_reconnect (ath); | ||
364 | } | ||
365 | |||
366 | |||
367 | /** | ||
368 | * Generate and transmit the `struct SessionAddMessage` for the given | ||
369 | * session record. | ||
370 | * | ||
371 | * @param ar the session to inform the ATS service about | ||
372 | */ | ||
373 | static void | ||
374 | send_add_session_message (const struct GNUNET_ATS_SessionRecord *ar) | ||
375 | { | ||
376 | struct GNUNET_ATS_TransportHandle *ath = ar->ath; | ||
377 | struct GNUNET_MQ_Envelope *ev; | ||
378 | struct SessionAddMessage *m; | ||
379 | size_t alen; | ||
380 | |||
381 | if (NULL == ath->mq) | ||
382 | return; /* disconnected, skip for now */ | ||
383 | alen = strlen (ar->address) + 1; | ||
384 | ev = GNUNET_MQ_msg_extra (m, | ||
385 | alen, | ||
386 | (NULL == ar->session) | ||
387 | ? GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY | ||
388 | : GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD); | ||
389 | m->peer = ar->pid; | ||
390 | m->session_id = htonl (ar->slot); | ||
391 | properties_hton (&m->properties, | ||
392 | &ar->properties); | ||
393 | GNUNET_memcpy (&m[1], | ||
394 | ar->address, | ||
395 | alen); | ||
396 | |||
397 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
398 | "Adding address `%s' for peer `%s'\n", | ||
399 | ar->address, | ||
400 | GNUNET_i2s (&ar->pid)); | ||
401 | GNUNET_MQ_send (ath->mq, | ||
402 | ev); | ||
403 | } | ||
404 | |||
405 | |||
406 | /** | ||
407 | * Send ATS information about the session record. | ||
408 | * | ||
409 | * @param cls our `struct GNUNET_ATS_TransportHandle *`, unused | ||
410 | * @param pid unused | ||
411 | * @param value the `struct GNUNET_ATS_SessionRecord *` to add | ||
412 | * @return #GNUNET_OK | ||
413 | */ | ||
414 | static int | ||
415 | send_add_session_cb (void *cls, | ||
416 | const struct GNUNET_PeerIdentity *pid, | ||
417 | void *value) | ||
418 | { | ||
419 | struct GNUNET_ATS_SessionRecord *ar = value; | ||
420 | |||
421 | (void) cls; | ||
422 | (void) pid; | ||
423 | send_add_session_message (ar); | ||
424 | return GNUNET_OK; | ||
425 | } | ||
426 | |||
427 | |||
428 | /** | ||
429 | * Re-establish the connection to the ATS service. | ||
430 | * | ||
431 | * @param ath handle to use to re-connect. | ||
432 | */ | ||
433 | static void | ||
434 | reconnect (struct GNUNET_ATS_TransportHandle *ath) | ||
435 | { | ||
436 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
437 | GNUNET_MQ_hd_var_size (ats_address_suggestion, | ||
438 | GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION, | ||
439 | struct AddressSuggestionMessage, | ||
440 | ath), | ||
441 | GNUNET_MQ_hd_fixed_size (ats_session_allocation, | ||
442 | GNUNET_MESSAGE_TYPE_ATS_SESSION_ALLOCATION, | ||
443 | struct SessionAllocationMessage, | ||
444 | ath), | ||
445 | GNUNET_MQ_handler_end () | ||
446 | }; | ||
447 | struct GNUNET_MQ_Envelope *ev; | ||
448 | struct GNUNET_MessageHeader *init; | ||
449 | |||
450 | GNUNET_assert (NULL == ath->mq); | ||
451 | ath->mq = GNUNET_CLIENT_connect (ath->cfg, | ||
452 | "ats", | ||
453 | handlers, | ||
454 | &error_handler, | ||
455 | ath); | ||
456 | if (NULL == ath->mq) | ||
457 | { | ||
458 | GNUNET_break (0); | ||
459 | force_reconnect (ath); | ||
460 | return; | ||
461 | } | ||
462 | ev = GNUNET_MQ_msg (init, | ||
463 | GNUNET_MESSAGE_TYPE_ATS_START); | ||
464 | GNUNET_MQ_send (ath->mq, | ||
465 | ev); | ||
466 | if (NULL == ath->mq) | ||
467 | return; | ||
468 | GNUNET_CONTAINER_multipeermap_iterate (ath->records, | ||
469 | &send_add_session_cb, | ||
470 | ath); | ||
471 | } | ||
472 | |||
473 | |||
474 | /** | ||
475 | * Initialize the ATS subsystem. | ||
476 | * | ||
477 | * @param cfg configuration to use | ||
478 | * @param alloc_cb notification to call whenever the allocation changed | ||
479 | * @param alloc_cb_cls closure for @a alloc_cb | ||
480 | * @param suggest_cb notification to call whenever the suggestation is made | ||
481 | * @param suggest_cb_cls closure for @a suggest_cb | ||
482 | * @return ats context | ||
483 | */ | ||
484 | struct GNUNET_ATS_TransportHandle * | ||
485 | GNUNET_ATS_transport_init (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
486 | GNUNET_ATS_AllocationCallback alloc_cb, | ||
487 | void *alloc_cb_cls, | ||
488 | GNUNET_ATS_SuggestionCallback suggest_cb, | ||
489 | void *suggest_cb_cls) | ||
490 | { | ||
491 | struct GNUNET_ATS_TransportHandle *ath; | ||
492 | |||
493 | ath = GNUNET_new (struct GNUNET_ATS_TransportHandle); | ||
494 | ath->cfg = cfg; | ||
495 | ath->suggest_cb = suggest_cb; | ||
496 | ath->suggest_cb_cls = suggest_cb_cls; | ||
497 | ath->alloc_cb = alloc_cb; | ||
498 | ath->alloc_cb_cls = alloc_cb_cls; | ||
499 | ath->records = GNUNET_CONTAINER_multipeermap_create (128, | ||
500 | GNUNET_YES); | ||
501 | reconnect (ath); | ||
502 | return ath; | ||
503 | } | ||
504 | |||
505 | |||
506 | /** | ||
507 | * Release memory associated with the session record. | ||
508 | * | ||
509 | * @param cls NULL | ||
510 | * @param pid unused | ||
511 | * @param value a `struct GNUNET_ATS_SessionRecord` | ||
512 | * @return #GNUNET_OK | ||
513 | */ | ||
514 | static int | ||
515 | free_record (void *cls, | ||
516 | const struct GNUNET_PeerIdentity *pid, | ||
517 | void *value) | ||
518 | { | ||
519 | struct GNUNET_ATS_SessionRecord *ar = value; | ||
520 | |||
521 | (void) cls; | ||
522 | (void) pid; | ||
523 | GNUNET_free (ar); | ||
524 | return GNUNET_OK; | ||
525 | } | ||
526 | |||
527 | |||
528 | /** | ||
529 | * Client is done with ATS transport, release resources. | ||
530 | * | ||
531 | * @param ath handle to release | ||
532 | */ | ||
533 | void | ||
534 | GNUNET_ATS_transport_done (struct GNUNET_ATS_TransportHandle *ath) | ||
535 | { | ||
536 | if (NULL != ath->mq) | ||
537 | { | ||
538 | GNUNET_MQ_destroy (ath->mq); | ||
539 | ath->mq = NULL; | ||
540 | } | ||
541 | if (NULL != ath->task) | ||
542 | { | ||
543 | GNUNET_SCHEDULER_cancel (ath->task); | ||
544 | ath->task = NULL; | ||
545 | } | ||
546 | GNUNET_CONTAINER_multipeermap_iterate (ath->records, | ||
547 | &free_record, | ||
548 | NULL); | ||
549 | GNUNET_CONTAINER_multipeermap_destroy (ath->records); | ||
550 | GNUNET_free (ath); | ||
551 | } | ||
552 | |||
553 | |||
554 | /** | ||
555 | * We have a new session ATS should know. Sessiones have to be added | ||
556 | * with this function before they can be: updated, set in use and | ||
557 | * destroyed. | ||
558 | * | ||
559 | * @param ath handle | ||
560 | * @param pid peer we connected to | ||
561 | * @param address the address (human readable version) | ||
562 | * @param session transport-internal handle for the session/queue, NULL if | ||
563 | * the session is inbound-only | ||
564 | * @param prop performance data for the session | ||
565 | * @return handle to the session representation inside ATS, NULL | ||
566 | * on error (i.e. ATS knows this exact session already) | ||
567 | */ | ||
568 | struct GNUNET_ATS_SessionRecord * | ||
569 | GNUNET_ATS_session_add (struct GNUNET_ATS_TransportHandle *ath, | ||
570 | const struct GNUNET_PeerIdentity *pid, | ||
571 | const char *address, | ||
572 | struct GNUNET_ATS_Session *session, | ||
573 | const struct GNUNET_ATS_Properties *prop) | ||
574 | { | ||
575 | struct GNUNET_ATS_SessionRecord *ar; | ||
576 | uint32_t s; | ||
577 | size_t alen; | ||
578 | |||
579 | if (NULL == address) | ||
580 | { | ||
581 | /* we need a valid address */ | ||
582 | GNUNET_break (0); | ||
583 | return NULL; | ||
584 | } | ||
585 | alen = strlen (address) + 1; | ||
586 | if ((alen + sizeof(struct SessionAddMessage) >= GNUNET_MAX_MESSAGE_SIZE) || | ||
587 | (alen >= GNUNET_MAX_MESSAGE_SIZE)) | ||
588 | { | ||
589 | /* address too large for us, this should not happen */ | ||
590 | GNUNET_break (0); | ||
591 | return NULL; | ||
592 | } | ||
593 | |||
594 | /* Spin 's' until we find an unused session ID for this pid */ | ||
595 | for (s = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
596 | UINT32_MAX); | ||
597 | NULL != find_session (ath, | ||
598 | s, | ||
599 | pid); | ||
600 | s++) | ||
601 | ; | ||
602 | |||
603 | alen = strlen (address) + 1; | ||
604 | ar = GNUNET_malloc (sizeof(struct GNUNET_ATS_SessionRecord) + alen); | ||
605 | ar->ath = ath; | ||
606 | ar->slot = s; | ||
607 | ar->session = session; | ||
608 | ar->address = (const char *) &ar[1]; | ||
609 | ar->pid = *pid; | ||
610 | ar->properties = *prop; | ||
611 | memcpy (&ar[1], | ||
612 | address, | ||
613 | alen); | ||
614 | (void) GNUNET_CONTAINER_multipeermap_put (ath->records, | ||
615 | &ar->pid, | ||
616 | ar, | ||
617 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
618 | send_add_session_message (ar); | ||
619 | return ar; | ||
620 | } | ||
621 | |||
622 | |||
623 | /** | ||
624 | * We have updated performance statistics for a given session. Note | ||
625 | * that this function can be called for sessiones that are currently | ||
626 | * in use as well as sessiones that are valid but not actively in use. | ||
627 | * Furthermore, the peer may not even be connected to us right now (in | ||
628 | * which case the call may be ignored or the information may be stored | ||
629 | * for later use). Update bandwidth assignments. | ||
630 | * | ||
631 | * @param ar session record to update information for | ||
632 | * @param prop performance data for the session | ||
633 | */ | ||
634 | void | ||
635 | GNUNET_ATS_session_update (struct GNUNET_ATS_SessionRecord *ar, | ||
636 | const struct GNUNET_ATS_Properties *prop) | ||
637 | { | ||
638 | struct GNUNET_ATS_TransportHandle *ath = ar->ath; | ||
639 | struct GNUNET_MQ_Envelope *ev; | ||
640 | struct SessionUpdateMessage *m; | ||
641 | |||
642 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
643 | "Updating address `%s' for peer `%s'\n", | ||
644 | ar->address, | ||
645 | GNUNET_i2s (&ar->pid)); | ||
646 | ar->properties = *prop; | ||
647 | if (NULL == ath->mq) | ||
648 | return; /* disconnected, skip for now */ | ||
649 | ev = GNUNET_MQ_msg (m, | ||
650 | GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE); | ||
651 | m->session_id = htonl (ar->slot); | ||
652 | m->peer = ar->pid; | ||
653 | properties_hton (&m->properties, | ||
654 | &ar->properties); | ||
655 | GNUNET_MQ_send (ath->mq, | ||
656 | ev); | ||
657 | } | ||
658 | |||
659 | |||
660 | /** | ||
661 | * A session was destroyed, ATS should now schedule and | ||
662 | * allocate under the assumption that this @a ar is no | ||
663 | * longer in use. | ||
664 | * | ||
665 | * @param ar session record to drop | ||
666 | */ | ||
667 | void | ||
668 | GNUNET_ATS_session_del (struct GNUNET_ATS_SessionRecord *ar) | ||
669 | { | ||
670 | struct GNUNET_ATS_TransportHandle *ath = ar->ath; | ||
671 | struct GNUNET_MQ_Envelope *ev; | ||
672 | struct SessionDelMessage *m; | ||
673 | |||
674 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
675 | "Deleting address `%s' for peer `%s'\n", | ||
676 | ar->address, | ||
677 | GNUNET_i2s (&ar->pid)); | ||
678 | if (NULL == ath->mq) | ||
679 | return; | ||
680 | ev = GNUNET_MQ_msg (m, | ||
681 | GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL); | ||
682 | m->session_id = htonl (ar->slot); | ||
683 | m->peer = ar->pid; | ||
684 | GNUNET_MQ_send (ath->mq, | ||
685 | ev); | ||
686 | } | ||
687 | |||
688 | |||
689 | /* end of ats_api2_transport.c */ | ||
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 | */ | ||
36 | enum 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 | */ | ||
58 | struct Client; | ||
59 | |||
60 | /** | ||
61 | * Preferences expressed by a client are kept in a DLL per client. | ||
62 | */ | ||
63 | struct 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 | */ | ||
95 | struct 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 | */ | ||
122 | struct 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 | */ | ||
171 | static struct GNUNET_STATISTICS_Handle *stats; | ||
172 | |||
173 | /** | ||
174 | * Our solver. | ||
175 | */ | ||
176 | static struct GNUNET_ATS_SolverFunctions *plugin; | ||
177 | |||
178 | /** | ||
179 | * Solver plugin name as string | ||
180 | */ | ||
181 | static char *plugin_name; | ||
182 | |||
183 | /** | ||
184 | * The transport client (there can only be one at a time). | ||
185 | */ | ||
186 | static 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 | */ | ||
197 | static void | ||
198 | suggest_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 | */ | ||
237 | static void | ||
238 | allocate_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 | */ | ||
278 | static void | ||
279 | prop_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 | */ | ||
301 | static void | ||
302 | handle_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 | */ | ||
341 | static void | ||
342 | handle_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 | */ | ||
387 | static void | ||
388 | handle_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 | */ | ||
420 | static int | ||
421 | check_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 | */ | ||
442 | static void | ||
443 | handle_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 | */ | ||
492 | static void | ||
493 | handle_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 | */ | ||
528 | static void | ||
529 | handle_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 | */ | ||
577 | static void * | ||
578 | client_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 | */ | ||
598 | static int | ||
599 | free_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 | */ | ||
626 | static void | ||
627 | client_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 | */ | ||
673 | static void | ||
674 | final_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 | */ | ||
702 | static void | ||
703 | cleanup_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 | */ | ||
720 | static void | ||
721 | run (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 | */ | ||
766 | GNUNET_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 */ | ||
diff --git a/src/ats/perf_ats_solver_mlp.conf b/src/ats/perf_ats_solver_mlp.conf deleted file mode 100644 index e69de29bb..000000000 --- a/src/ats/perf_ats_solver_mlp.conf +++ /dev/null | |||
diff --git a/src/ats/perf_ats_solver_ril.conf b/src/ats/perf_ats_solver_ril.conf deleted file mode 100644 index e69de29bb..000000000 --- a/src/ats/perf_ats_solver_ril.conf +++ /dev/null | |||
diff --git a/src/ats/plugin_ats2_common.c b/src/ats/plugin_ats2_common.c deleted file mode 100644 index da20a342c..000000000 --- a/src/ats/plugin_ats2_common.c +++ /dev/null | |||
@@ -1,99 +0,0 @@ | |||
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 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file ats/plugin_ats2_common.c | ||
22 | * @brief ATS solver helper functions to be inlined | ||
23 | * @author Matthias Wachs | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | /** | ||
28 | * Default bandwidth assigned to a network: 64 KB/s | ||
29 | */ | ||
30 | #define DEFAULT_BANDWIDTH 65536 | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Parse @a cfg for @a quota as specified for @a direction of | ||
35 | * network type @a nts. | ||
36 | * | ||
37 | * @param cfg configuration to parse | ||
38 | * @param nts network type string to get quota for | ||
39 | * @param direction direction to get quota for ("IN" or "OUT") | ||
40 | * @param quota[out] set to quota, #DEFAULT_BANDWIDTH if @a cfg does not say anything useful | ||
41 | */ | ||
42 | static void | ||
43 | get_quota (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
44 | const char *nts, | ||
45 | const char *direction, | ||
46 | unsigned long long *quota) | ||
47 | { | ||
48 | char *quota_str; | ||
49 | char *quota_s; | ||
50 | int res; | ||
51 | |||
52 | GNUNET_asprintf ("a_s, | ||
53 | "%s_QUOTA_%s", | ||
54 | nts, | ||
55 | direction); | ||
56 | if (GNUNET_OK != | ||
57 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
58 | "ATS", | ||
59 | quota_s, | ||
60 | "a_str)) | ||
61 | { | ||
62 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, | ||
63 | "ATS", | ||
64 | quota_s); | ||
65 | GNUNET_free (quota_s); | ||
66 | return; | ||
67 | } | ||
68 | GNUNET_free (quota_s); | ||
69 | res = GNUNET_NO; | ||
70 | if (0 == strcmp (quota_str, | ||
71 | "unlimited")) | ||
72 | { | ||
73 | *quota = ULONG_MAX; | ||
74 | res = GNUNET_YES; | ||
75 | } | ||
76 | if ((GNUNET_NO == res) && | ||
77 | (GNUNET_OK == | ||
78 | GNUNET_STRINGS_fancy_size_to_bytes (quota_str, | ||
79 | quota))) | ||
80 | res = GNUNET_YES; | ||
81 | if ((GNUNET_NO == res) && | ||
82 | (1 == | ||
83 | sscanf (quota_str, | ||
84 | "%llu", | ||
85 | quota))) | ||
86 | res = GNUNET_YES; | ||
87 | if (GNUNET_NO == res) | ||
88 | { | ||
89 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
90 | _ ( | ||
91 | "Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"), | ||
92 | direction, | ||
93 | nts, | ||
94 | quota_str, | ||
95 | (unsigned long long) DEFAULT_BANDWIDTH); | ||
96 | *quota = DEFAULT_BANDWIDTH; | ||
97 | } | ||
98 | GNUNET_free (quota_str); | ||
99 | } | ||
diff --git a/src/ats/plugin_ats2_simple.c b/src/ats/plugin_ats2_simple.c deleted file mode 100644 index 3062b6019..000000000 --- a/src/ats/plugin_ats2_simple.c +++ /dev/null | |||
@@ -1,1087 +0,0 @@ | |||
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 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file ats/plugin_ats2_simple.c | ||
22 | * @brief ATS simple solver | ||
23 | * @author Matthias Wachs | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - needs testing | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "gnunet_ats_plugin_new.h" | ||
31 | #include "gnunet_hello_lib.h" | ||
32 | #include "gnunet_peerstore_service.h" | ||
33 | |||
34 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-simple", __VA_ARGS__) | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Base frequency at which we suggest addresses to transport. | ||
39 | * Multiplied by the square of the number of active connections | ||
40 | * (and randomized) to calculate the actual frequency at which | ||
41 | * we will suggest addresses to the transport. Furthermore, each | ||
42 | * address is also bounded by an exponential back-off. | ||
43 | */ | ||
44 | #define SUGGEST_FREQ GNUNET_TIME_UNIT_SECONDS | ||
45 | |||
46 | /** | ||
47 | * What is the minimum bandwidth we always try to allocate for | ||
48 | * any session that is up? (May still be scaled down lower if | ||
49 | * the number of sessions is so high that the total bandwidth | ||
50 | * is insufficient to allow for this value to be granted.) | ||
51 | */ | ||
52 | #define MIN_BANDWIDTH_PER_SESSION 1024 | ||
53 | |||
54 | |||
55 | /** | ||
56 | * A handle for the proportional solver | ||
57 | */ | ||
58 | struct SimpleHandle; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Information about preferences and sessions we track | ||
63 | * per peer. | ||
64 | */ | ||
65 | struct Peer; | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Entry in list of addresses we could try per peer. | ||
70 | */ | ||
71 | struct Hello | ||
72 | { | ||
73 | /** | ||
74 | * Kept in a DLL. | ||
75 | */ | ||
76 | struct Hello *next; | ||
77 | |||
78 | /** | ||
79 | * Kept in a DLL. | ||
80 | */ | ||
81 | struct Hello *prev; | ||
82 | |||
83 | /** | ||
84 | * Peer this hello belongs to. | ||
85 | */ | ||
86 | struct Peer *peer; | ||
87 | |||
88 | /** | ||
89 | * The address we could try. | ||
90 | */ | ||
91 | const char *address; | ||
92 | |||
93 | /** | ||
94 | * Is a session with this address already up? | ||
95 | * If not, set to NULL. | ||
96 | */ | ||
97 | struct GNUNET_ATS_SessionHandle *sh; | ||
98 | |||
99 | /** | ||
100 | * When does the HELLO expire? | ||
101 | */ | ||
102 | struct GNUNET_TIME_Absolute expiration; | ||
103 | |||
104 | /** | ||
105 | * When did we try it last? | ||
106 | */ | ||
107 | struct GNUNET_TIME_Absolute last_attempt; | ||
108 | |||
109 | /** | ||
110 | * Current exponential backoff value. | ||
111 | */ | ||
112 | struct GNUNET_TIME_Relative backoff; | ||
113 | |||
114 | /** | ||
115 | * Type of the network for this HELLO. | ||
116 | */ | ||
117 | enum GNUNET_NetworkType nt; | ||
118 | }; | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Internal representation of a session by the plugin. | ||
123 | * (If desired, plugin may just use NULL.) | ||
124 | */ | ||
125 | struct GNUNET_ATS_SessionHandle | ||
126 | { | ||
127 | /** | ||
128 | * Kept in DLL per peer. | ||
129 | */ | ||
130 | struct GNUNET_ATS_SessionHandle *next; | ||
131 | |||
132 | /** | ||
133 | * Kept in DLL per peer. | ||
134 | */ | ||
135 | struct GNUNET_ATS_SessionHandle *prev; | ||
136 | |||
137 | /** | ||
138 | * The session in the main ATS service. | ||
139 | */ | ||
140 | struct GNUNET_ATS_Session *session; | ||
141 | |||
142 | /** | ||
143 | * Current performance data for this @e session | ||
144 | */ | ||
145 | const struct GNUNET_ATS_SessionData *data; | ||
146 | |||
147 | /** | ||
148 | * Hello matching this session, or NULL for none. | ||
149 | */ | ||
150 | struct Hello *hello; | ||
151 | |||
152 | /** | ||
153 | * Peer this session is for. | ||
154 | */ | ||
155 | struct Peer *peer; | ||
156 | |||
157 | /** | ||
158 | * Address used by this session (largely for debugging). | ||
159 | */ | ||
160 | const char *address; | ||
161 | |||
162 | /** | ||
163 | * When did we last update transport about the allocation? | ||
164 | * Used to dampen the frequency of updates. | ||
165 | */ | ||
166 | struct GNUNET_TIME_Absolute last_allocation; | ||
167 | |||
168 | /** | ||
169 | * Last BW-in allocation given to the transport service. | ||
170 | */ | ||
171 | struct GNUNET_BANDWIDTH_Value32NBO bw_in; | ||
172 | |||
173 | /** | ||
174 | * Last BW-out allocation given to the transport service. | ||
175 | */ | ||
176 | struct GNUNET_BANDWIDTH_Value32NBO bw_out; | ||
177 | |||
178 | /** | ||
179 | * New BW-in allocation given to the transport service. | ||
180 | */ | ||
181 | uint64_t target_in; | ||
182 | |||
183 | /** | ||
184 | * New BW-out allocation given to the transport service. | ||
185 | */ | ||
186 | uint64_t target_out; | ||
187 | }; | ||
188 | |||
189 | |||
190 | /** | ||
191 | * Information about preferences and sessions we track | ||
192 | * per peer. | ||
193 | */ | ||
194 | struct Peer | ||
195 | { | ||
196 | /** | ||
197 | * Kept in DLL per peer. | ||
198 | */ | ||
199 | struct GNUNET_ATS_SessionHandle *sh_head; | ||
200 | |||
201 | /** | ||
202 | * Kept in DLL per peer. | ||
203 | */ | ||
204 | struct GNUNET_ATS_SessionHandle *sh_tail; | ||
205 | |||
206 | /** | ||
207 | * Kept in a DLL. | ||
208 | */ | ||
209 | struct Hello *h_head; | ||
210 | |||
211 | /** | ||
212 | * Kept in a DLL. | ||
213 | */ | ||
214 | struct Hello *h_tail; | ||
215 | |||
216 | /** | ||
217 | * The handle for the proportional solver | ||
218 | */ | ||
219 | struct SimpleHandle *h; | ||
220 | |||
221 | /** | ||
222 | * Watch context where we are currently looking for HELLOs for | ||
223 | * this peer. | ||
224 | */ | ||
225 | struct GNUNET_PEERSTORE_WatchContext *wc; | ||
226 | |||
227 | /** | ||
228 | * Task used to try again to suggest an address for this peer. | ||
229 | */ | ||
230 | struct GNUNET_SCHEDULER_Task *task; | ||
231 | |||
232 | /** | ||
233 | * Which peer is this for? | ||
234 | */ | ||
235 | struct GNUNET_PeerIdentity pid; | ||
236 | |||
237 | /** | ||
238 | * When did we last suggest an address to connect to for this peer? | ||
239 | */ | ||
240 | struct GNUNET_TIME_Absolute last_suggestion; | ||
241 | |||
242 | /** | ||
243 | * Array where we sum up the bandwidth requests received indexed | ||
244 | * by preference kind (see `enum GNUNET_MQ_PreferenceKind`) | ||
245 | */ | ||
246 | uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT]; | ||
247 | }; | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Representation of a network (to be expanded...) | ||
252 | */ | ||
253 | struct Network | ||
254 | { | ||
255 | /** | ||
256 | * Total inbound quota | ||
257 | */ | ||
258 | unsigned long long total_quota_in; | ||
259 | |||
260 | /** | ||
261 | * Total outbound quota | ||
262 | */ | ||
263 | unsigned long long total_quota_out; | ||
264 | |||
265 | /** | ||
266 | * ATS network type | ||
267 | */ | ||
268 | enum GNUNET_NetworkType type; | ||
269 | }; | ||
270 | |||
271 | |||
272 | /** | ||
273 | * A handle for the proportional solver | ||
274 | */ | ||
275 | struct SimpleHandle | ||
276 | { | ||
277 | /** | ||
278 | * Our execution environment. | ||
279 | */ | ||
280 | struct GNUNET_ATS_PluginEnvironment *env; | ||
281 | |||
282 | /** | ||
283 | * Information we track for each peer. | ||
284 | */ | ||
285 | struct GNUNET_CONTAINER_MultiPeerMap *peers; | ||
286 | |||
287 | /** | ||
288 | * Handle to the peerstore service. | ||
289 | */ | ||
290 | struct GNUNET_PEERSTORE_Handle *ps; | ||
291 | |||
292 | /** | ||
293 | * Array where we sum up the bandwidth requests received indexed | ||
294 | * by preference kind (see `enum GNUNET_MQ_PreferenceKind`) (sums | ||
295 | * over all peers). | ||
296 | */ | ||
297 | uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT]; | ||
298 | |||
299 | /** | ||
300 | * Information we track per network type (quotas). | ||
301 | */ | ||
302 | struct Network networks[GNUNET_NT_COUNT]; | ||
303 | }; | ||
304 | |||
305 | |||
306 | /** | ||
307 | * Lookup peer in the peers map. | ||
308 | * | ||
309 | * @param h handle to look up in | ||
310 | * @param pid peer identity to look up by | ||
311 | * @return NULL for not found | ||
312 | */ | ||
313 | struct Peer * | ||
314 | lookup_peer (struct SimpleHandle *h, const struct GNUNET_PeerIdentity *pid) | ||
315 | { | ||
316 | return GNUNET_CONTAINER_multipeermap_get (h->peers, pid); | ||
317 | } | ||
318 | |||
319 | |||
320 | /** | ||
321 | * Check if there is _any_ interesting information left we | ||
322 | * store about the peer in @a p. | ||
323 | * | ||
324 | * @param p peer to test if we can drop the data structure | ||
325 | * @return #GNUNET_YES if no information is left in @a p | ||
326 | */ | ||
327 | static int | ||
328 | peer_test_dead (struct Peer *p) | ||
329 | { | ||
330 | for (enum GNUNET_MQ_PreferenceKind pk = 0; pk < GNUNET_MQ_PREFERENCE_COUNT; | ||
331 | pk++) | ||
332 | if (0 != p->bw_by_pk[pk]) | ||
333 | return GNUNET_NO; | ||
334 | if (NULL != p->sh_head) | ||
335 | return GNUNET_NO; | ||
336 | return GNUNET_YES; | ||
337 | } | ||
338 | |||
339 | |||
340 | /** | ||
341 | * Contact the transport service and suggest to it to | ||
342 | * try connecting to the address of @a hello. Updates | ||
343 | * backoff and timestamp values in the @a hello. | ||
344 | * | ||
345 | * @param hello[in,out] address suggestion to make | ||
346 | */ | ||
347 | static void | ||
348 | suggest_hello (struct Hello *hello) | ||
349 | { | ||
350 | struct Peer *p = hello->peer; | ||
351 | struct SimpleHandle *h = p->h; | ||
352 | |||
353 | p->last_suggestion = hello->last_attempt = GNUNET_TIME_absolute_get (); | ||
354 | hello->backoff = | ||
355 | GNUNET_TIME_randomized_backoff (hello->backoff, | ||
356 | GNUNET_TIME_absolute_get_remaining ( | ||
357 | hello->expiration)); | ||
358 | h->env->suggest_cb (h->env->cls, &p->pid, hello->address); | ||
359 | } | ||
360 | |||
361 | |||
362 | /** | ||
363 | * Consider suggesting a HELLO (without a session) to transport. | ||
364 | * We look at how many active sessions we have for the peer, and | ||
365 | * if there are many, reduce the frequency of trying new addresses. | ||
366 | * Also, for each address we consider when we last tried it, and | ||
367 | * its exponential backoff if the attempt failed. Note that it | ||
368 | * is possible that this function is called when no suggestion | ||
369 | * is to be made. | ||
370 | * | ||
371 | * In this case, we only calculate the time until we make the next | ||
372 | * suggestion. | ||
373 | * | ||
374 | * @param cls a `struct Peer` | ||
375 | */ | ||
376 | static void | ||
377 | suggest_start_cb (void *cls) | ||
378 | { | ||
379 | struct Peer *p = cls; | ||
380 | struct GNUNET_TIME_Relative delay = GNUNET_TIME_UNIT_ZERO; | ||
381 | struct Hello *hello = NULL; | ||
382 | struct GNUNET_TIME_Absolute hpt = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
383 | struct GNUNET_TIME_Relative xdelay; | ||
384 | struct GNUNET_TIME_Absolute xnext; | ||
385 | unsigned int num_sessions = 0; | ||
386 | uint32_t sq; | ||
387 | |||
388 | /* count number of active sessions */ | ||
389 | for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head; NULL != sh; | ||
390 | sh = sh->next) | ||
391 | num_sessions++; | ||
392 | /* calculate square of number of sessions */ | ||
393 | num_sessions++; /* start with 1, even if we have zero sessions */ | ||
394 | if (num_sessions < UINT16_MAX) | ||
395 | sq = num_sessions * (uint32_t) num_sessions; | ||
396 | else | ||
397 | sq = UINT32_MAX; | ||
398 | xdelay = | ||
399 | GNUNET_TIME_randomized_backoff (GNUNET_TIME_relative_multiply (SUGGEST_FREQ, | ||
400 | sq), | ||
401 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
402 | xnext = GNUNET_TIME_relative_to_absolute (xdelay); | ||
403 | |||
404 | p->task = NULL; | ||
405 | while (0 == delay.rel_value_us) | ||
406 | { | ||
407 | struct Hello *next; | ||
408 | struct GNUNET_TIME_Absolute xmax; | ||
409 | |||
410 | if (NULL != hello) | ||
411 | { | ||
412 | /* We went through the loop already once and found | ||
413 | a HELLO that is due *now*, so make a suggestion! */ | ||
414 | GNUNET_break (NULL == hello->sh); | ||
415 | suggest_hello (hello); | ||
416 | hello = NULL; | ||
417 | hpt = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
418 | } | ||
419 | for (struct Hello *pos = p->h_head; NULL != pos; pos = next) | ||
420 | { | ||
421 | struct GNUNET_TIME_Absolute pt; | ||
422 | |||
423 | next = pos->next; | ||
424 | if (NULL != pos->sh) | ||
425 | continue; | ||
426 | if (0 == | ||
427 | GNUNET_TIME_absolute_get_remaining (pos->expiration).rel_value_us) | ||
428 | { | ||
429 | /* expired, remove! */ | ||
430 | GNUNET_CONTAINER_DLL_remove (p->h_head, p->h_tail, pos); | ||
431 | GNUNET_free (pos); | ||
432 | continue; | ||
433 | } | ||
434 | pt = GNUNET_TIME_absolute_add (pos->last_attempt, pos->backoff); | ||
435 | if ((NULL == hello) || (pt.abs_value_us < hpt.abs_value_us)) | ||
436 | { | ||
437 | hello = pos; | ||
438 | hpt = pt; | ||
439 | } | ||
440 | } | ||
441 | if (NULL == hello) | ||
442 | return; /* no HELLOs that could still be tried */ | ||
443 | |||
444 | /* hpt is now the *earliest* possible time for any HELLO | ||
445 | but we might not want to go for as early as possible for | ||
446 | this peer. So the actual time is the max of the earliest | ||
447 | HELLO and the 'xnext' */ | ||
448 | xmax = GNUNET_TIME_absolute_max (hpt, xnext); | ||
449 | delay = GNUNET_TIME_absolute_get_remaining (xmax); | ||
450 | } | ||
451 | p->task = GNUNET_SCHEDULER_add_delayed (delay, &suggest_start_cb, p); | ||
452 | } | ||
453 | |||
454 | |||
455 | /** | ||
456 | * Function called by PEERSTORE for each matching record. | ||
457 | * | ||
458 | * @param cls closure with a `struct Peer` | ||
459 | * @param record peerstore record information | ||
460 | * @param emsg error message, or NULL if no errors | ||
461 | */ | ||
462 | static void | ||
463 | watch_cb (void *cls, | ||
464 | const struct GNUNET_PEERSTORE_Record *record, | ||
465 | const char *emsg) | ||
466 | { | ||
467 | struct Peer *p = cls; | ||
468 | char *addr; | ||
469 | size_t alen; | ||
470 | enum GNUNET_NetworkType nt; | ||
471 | struct GNUNET_TIME_Absolute expiration; | ||
472 | struct Hello *hello; | ||
473 | |||
474 | if (0 != GNUNET_memcmp (&p->pid, &record->peer)) | ||
475 | { | ||
476 | GNUNET_break (0); | ||
477 | return; | ||
478 | } | ||
479 | if (0 != strcmp (record->key, GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY)) | ||
480 | { | ||
481 | GNUNET_break (0); | ||
482 | return; | ||
483 | } | ||
484 | addr = GNUNET_HELLO_extract_address (record->value, | ||
485 | record->value_size, | ||
486 | &p->pid, | ||
487 | &nt, | ||
488 | &expiration); | ||
489 | if (NULL == addr) | ||
490 | return; /* invalid hello, bad signature, other problem */ | ||
491 | if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) | ||
492 | { | ||
493 | /* expired, ignore */ | ||
494 | GNUNET_free (addr); | ||
495 | return; | ||
496 | } | ||
497 | /* check if addr is already known */ | ||
498 | for (struct Hello *he = p->h_head; NULL != he; he = he->next) | ||
499 | { | ||
500 | if (0 != strcmp (he->address, addr)) | ||
501 | continue; | ||
502 | if (he->expiration.abs_value_us < expiration.abs_value_us) | ||
503 | { | ||
504 | he->expiration = expiration; | ||
505 | he->nt = nt; | ||
506 | } | ||
507 | GNUNET_free (addr); | ||
508 | return; | ||
509 | } | ||
510 | /* create new HELLO */ | ||
511 | alen = strlen (addr) + 1; | ||
512 | hello = GNUNET_malloc (sizeof(struct Hello) + alen); | ||
513 | hello->address = (const char *) &hello[1]; | ||
514 | hello->expiration = expiration; | ||
515 | hello->nt = nt; | ||
516 | hello->peer = p; | ||
517 | memcpy (&hello[1], addr, alen); | ||
518 | GNUNET_CONTAINER_DLL_insert (p->h_head, p->h_tail, hello); | ||
519 | /* check if sh for this HELLO already exists */ | ||
520 | for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head; NULL != sh; | ||
521 | sh = sh->next) | ||
522 | { | ||
523 | if ((NULL == sh->address) || (0 != strcmp (sh->address, addr))) | ||
524 | continue; | ||
525 | GNUNET_assert (NULL == sh->hello); | ||
526 | sh->hello = hello; | ||
527 | hello->sh = sh; | ||
528 | break; | ||
529 | } | ||
530 | GNUNET_free (addr); | ||
531 | if (NULL == p->task) | ||
532 | p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb, p); | ||
533 | } | ||
534 | |||
535 | |||
536 | /** | ||
537 | * Find or add peer if necessary. | ||
538 | * | ||
539 | * @param h our plugin handle | ||
540 | * @param pid the peer identity to add/look for | ||
541 | * @return a peer handle | ||
542 | */ | ||
543 | static struct Peer * | ||
544 | peer_add (struct SimpleHandle *h, const struct GNUNET_PeerIdentity *pid) | ||
545 | { | ||
546 | struct Peer *p = lookup_peer (h, pid); | ||
547 | |||
548 | if (NULL != p) | ||
549 | return p; | ||
550 | p = GNUNET_new (struct Peer); | ||
551 | p->h = h; | ||
552 | p->pid = *pid; | ||
553 | p->wc = GNUNET_PEERSTORE_watch (h->ps, | ||
554 | "transport", | ||
555 | &p->pid, | ||
556 | GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY, | ||
557 | &watch_cb, | ||
558 | p); | ||
559 | GNUNET_assert (GNUNET_YES == | ||
560 | GNUNET_CONTAINER_multipeermap_put ( | ||
561 | h->peers, | ||
562 | &p->pid, | ||
563 | p, | ||
564 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
565 | |||
566 | return p; | ||
567 | } | ||
568 | |||
569 | |||
570 | /** | ||
571 | * Free the entry (and associated tasks) of peer @a p. | ||
572 | * Note that @a p must be dead already (see #peer_test_dead()). | ||
573 | * | ||
574 | * @param p the peer to free | ||
575 | */ | ||
576 | static void | ||
577 | peer_free (struct Peer *p) | ||
578 | { | ||
579 | struct SimpleHandle *h = p->h; | ||
580 | struct Hello *hello; | ||
581 | |||
582 | GNUNET_assert (NULL == p->sh_head); | ||
583 | while (NULL != (hello = p->h_head)) | ||
584 | { | ||
585 | GNUNET_CONTAINER_DLL_remove (p->h_head, p->h_tail, hello); | ||
586 | GNUNET_assert (NULL == hello->sh); | ||
587 | GNUNET_free (hello); | ||
588 | } | ||
589 | if (NULL != p->task) | ||
590 | { | ||
591 | GNUNET_SCHEDULER_cancel (p->task); | ||
592 | p->task = NULL; | ||
593 | } | ||
594 | if (NULL != p->wc) | ||
595 | { | ||
596 | GNUNET_PEERSTORE_watch_cancel (p->wc); | ||
597 | p->wc = NULL; | ||
598 | } | ||
599 | GNUNET_assert (GNUNET_YES == | ||
600 | GNUNET_CONTAINER_multipeermap_remove (h->peers, &p->pid, p)); | ||
601 | GNUNET_free (p); | ||
602 | } | ||
603 | |||
604 | |||
605 | /** | ||
606 | * Check if the new allocation for @a sh is significantly different | ||
607 | * from the last one, and if so, tell transport. | ||
608 | * | ||
609 | * @param sh session handle to consider updating transport for | ||
610 | */ | ||
611 | static void | ||
612 | consider_notify_transport (struct GNUNET_ATS_SessionHandle *sh) | ||
613 | { | ||
614 | struct Peer *peer = sh->peer; | ||
615 | struct SimpleHandle *h = peer->h; | ||
616 | enum GNUNET_NetworkType nt = sh->data->prop.nt; | ||
617 | struct GNUNET_TIME_Relative delay; | ||
618 | uint64_t sig_in; | ||
619 | uint64_t sig_out; | ||
620 | int64_t delta_in; | ||
621 | int64_t delta_out; | ||
622 | |||
623 | delay = GNUNET_TIME_absolute_get_duration (sh->last_allocation); | ||
624 | /* A significant change is more than 10% of the quota, | ||
625 | which is given in bytes/second */ | ||
626 | sig_in = h->networks[nt].total_quota_in * (delay.rel_value_us / 1000LL) | ||
627 | / 1000LL / 10; | ||
628 | sig_out = h->networks[nt].total_quota_out * (delay.rel_value_us / 1000LL) | ||
629 | / 1000LL / 10; | ||
630 | delta_in = ((int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in); | ||
631 | delta_out = ((int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in); | ||
632 | /* we want the absolute values */ | ||
633 | if (delta_in < 0) | ||
634 | delta_in = -delta_in; | ||
635 | if (INT64_MIN == delta_in) | ||
636 | delta_in = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */ | ||
637 | if (delta_out < 0) | ||
638 | delta_out = -delta_out; | ||
639 | if (INT64_MIN == delta_out) | ||
640 | delta_out = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */ | ||
641 | if ((sig_in > delta_in) && (sig_out > delta_out)) | ||
642 | return; /* insignificant change */ | ||
643 | /* change is significant, tell transport! */ | ||
644 | if (sh->target_in > UINT32_MAX) | ||
645 | sh->target_in = UINT32_MAX; | ||
646 | sh->bw_in.value__ = htonl ((uint32_t) sh->target_in); | ||
647 | if (sh->target_out > UINT32_MAX) | ||
648 | sh->target_out = UINT32_MAX; | ||
649 | sh->bw_out.value__ = htonl ((uint32_t) sh->target_out); | ||
650 | sh->last_allocation = GNUNET_TIME_absolute_get (); | ||
651 | h->env->allocate_cb (h->env->cls, | ||
652 | sh->session, | ||
653 | &peer->pid, | ||
654 | sh->bw_in, | ||
655 | sh->bw_out); | ||
656 | } | ||
657 | |||
658 | |||
659 | /** | ||
660 | * Closure for #update_counters and #update_allocation. | ||
661 | */ | ||
662 | struct Counters | ||
663 | { | ||
664 | /** | ||
665 | * Plugin's state. | ||
666 | */ | ||
667 | struct SimpleHandle *h; | ||
668 | |||
669 | /** | ||
670 | * Bandwidth that applications would prefer to allocate in this | ||
671 | * network type. We initially add all requested allocations to the | ||
672 | * respective network type where the given preference is best | ||
673 | * satisfied. Later we may rebalance. | ||
674 | */ | ||
675 | uint64_t bw_out_by_nt[GNUNET_NT_COUNT]; | ||
676 | |||
677 | /** | ||
678 | * Current bandwidth utilization for this network type. We simply | ||
679 | * add the current goodput up (with some fairness considerations). | ||
680 | */ | ||
681 | uint64_t bw_in_by_nt[GNUNET_NT_COUNT]; | ||
682 | |||
683 | /** | ||
684 | * By how much do we have to scale (up or down) our expectations | ||
685 | * for outbound bandwidth? | ||
686 | */ | ||
687 | double scale_out[GNUNET_NT_COUNT]; | ||
688 | |||
689 | /** | ||
690 | * By how much do we have to scale (up or down) our expectations | ||
691 | * for inbound bandwidth? | ||
692 | */ | ||
693 | double scale_in[GNUNET_NT_COUNT]; | ||
694 | }; | ||
695 | |||
696 | |||
697 | /** | ||
698 | * Function used to iterate over all peers and collect | ||
699 | * counter data. | ||
700 | * | ||
701 | * @param cls a `struct Counters *` | ||
702 | * @param pid identity of the peer we process, unused | ||
703 | * @param value a `struct Peer *` | ||
704 | * @return #GNUNET_YES (continue to iterate) | ||
705 | */ | ||
706 | static int | ||
707 | update_counters (void *cls, const struct GNUNET_PeerIdentity *pid, void *value) | ||
708 | { | ||
709 | struct Counters *c = cls; | ||
710 | struct Peer *peer = value; | ||
711 | struct GNUNET_ATS_SessionHandle *best[GNUNET_MQ_PREFERENCE_COUNT]; | ||
712 | |||
713 | (void) pid; | ||
714 | if (NULL == peer->sh_head) | ||
715 | return GNUNET_YES; /* no available session, cannot allocate bandwidth */ | ||
716 | memset (best, 0, sizeof(best)); | ||
717 | for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head; NULL != sh; | ||
718 | sh = sh->next) | ||
719 | { | ||
720 | enum GNUNET_NetworkType nt = sh->data->prop.nt; | ||
721 | |||
722 | sh->target_out = MIN_BANDWIDTH_PER_SESSION; | ||
723 | c->bw_out_by_nt[nt] += MIN_BANDWIDTH_PER_SESSION; | ||
724 | c->bw_in_by_nt[nt] += | ||
725 | GNUNET_MAX (MIN_BANDWIDTH_PER_SESSION, sh->data->prop.goodput_in); | ||
726 | for (enum GNUNET_MQ_PreferenceKind pk = 0; pk < GNUNET_MQ_PREFERENCE_COUNT; | ||
727 | pk++) | ||
728 | { | ||
729 | /* General rule: always prefer smaller distance if possible, | ||
730 | otherwise decide by pk: */ | ||
731 | switch (pk) | ||
732 | { | ||
733 | case GNUNET_MQ_PREFERENCE_NONE: | ||
734 | break; | ||
735 | |||
736 | case GNUNET_MQ_PREFERENCE_BANDWIDTH: | ||
737 | /* For bandwidth, we compare the sum of transmitted bytes and | ||
738 | confirmed transmitted bytes, so confirmed data counts twice */ | ||
739 | if ((NULL == best[pk]) || | ||
740 | (sh->data->prop.distance < best[pk]->data->prop.distance) || | ||
741 | (sh->data->prop.utilization_out + sh->data->prop.goodput_out > | ||
742 | best[pk]->data->prop.utilization_out | ||
743 | + best[pk]->data->prop.goodput_out)) | ||
744 | best[pk] = sh; | ||
745 | /* If both are equal (i.e. usually this happens if there is a zero), use | ||
746 | latency as a yardstick */ | ||
747 | if ((sh->data->prop.utilization_out + sh->data->prop.goodput_out == | ||
748 | best[pk]->data->prop.utilization_out | ||
749 | + best[pk]->data->prop.goodput_out) && | ||
750 | (sh->data->prop.distance == best[pk]->data->prop.distance) && | ||
751 | (sh->data->prop.delay.rel_value_us < | ||
752 | best[pk]->data->prop.delay.rel_value_us)) | ||
753 | best[pk] = sh; | ||
754 | break; | ||
755 | |||
756 | case GNUNET_MQ_PREFERENCE_LATENCY: | ||
757 | if ((NULL == best[pk]) || | ||
758 | (sh->data->prop.distance < best[pk]->data->prop.distance) || | ||
759 | ((sh->data->prop.distance == best[pk]->data->prop.distance) && | ||
760 | (sh->data->prop.delay.rel_value_us < | ||
761 | best[pk]->data->prop.delay.rel_value_us))) | ||
762 | best[pk] = sh; | ||
763 | break; | ||
764 | |||
765 | case GNUNET_MQ_PREFERENCE_RELIABILITY: | ||
766 | /* For reliability, we consider the ratio of goodput to utilization | ||
767 | (but use multiplicative formultations to avoid division by zero) */ | ||
768 | if ((NULL == best[pk]) || (1ULL * sh->data->prop.goodput_out | ||
769 | * best[pk]->data->prop.utilization_out > | ||
770 | 1ULL * sh->data->prop.utilization_out | ||
771 | * best[pk]->data->prop.goodput_out)) | ||
772 | best[pk] = sh; | ||
773 | /* If both are equal (i.e. usually this happens if there is a zero), use | ||
774 | latency as a yardstick */ | ||
775 | if ((1ULL * sh->data->prop.goodput_out | ||
776 | * best[pk]->data->prop.utilization_out == | ||
777 | 1ULL * sh->data->prop.utilization_out | ||
778 | * best[pk]->data->prop.goodput_out) && | ||
779 | (sh->data->prop.distance == best[pk]->data->prop.distance) && | ||
780 | (sh->data->prop.delay.rel_value_us < | ||
781 | best[pk]->data->prop.delay.rel_value_us)) | ||
782 | best[pk] = sh; | ||
783 | break; | ||
784 | } | ||
785 | } | ||
786 | } | ||
787 | /* for first round, assign target bandwidth simply to sum of | ||
788 | requested bandwidth */ | ||
789 | for (enum GNUNET_MQ_PreferenceKind pk = | ||
790 | 1 /* skip GNUNET_MQ_PREFERENCE_NONE */; | ||
791 | pk < GNUNET_MQ_PREFERENCE_COUNT; | ||
792 | pk++) | ||
793 | { | ||
794 | const struct GNUNET_ATS_SessionData *data = best[pk]->data; | ||
795 | enum GNUNET_NetworkType nt; | ||
796 | |||
797 | GNUNET_assert (NULL != data); | ||
798 | nt = data->prop.nt; | ||
799 | best[pk]->target_out = | ||
800 | GNUNET_MIN (peer->bw_by_pk[pk], MIN_BANDWIDTH_PER_SESSION); | ||
801 | c->bw_out_by_nt[nt] += | ||
802 | (uint64_t) (best[pk]->target_out - MIN_BANDWIDTH_PER_SESSION); | ||
803 | } | ||
804 | return GNUNET_YES; | ||
805 | } | ||
806 | |||
807 | |||
808 | /** | ||
809 | * Function used to iterate over all peers and collect | ||
810 | * counter data. | ||
811 | * | ||
812 | * @param cls a `struct Counters *` | ||
813 | * @param pid identity of the peer we process, unused | ||
814 | * @param value a `struct Peer *` | ||
815 | * @return #GNUNET_YES (continue to iterate) | ||
816 | */ | ||
817 | static int | ||
818 | update_allocation (void *cls, | ||
819 | const struct GNUNET_PeerIdentity *pid, | ||
820 | void *value) | ||
821 | { | ||
822 | struct Counters *c = cls; | ||
823 | struct Peer *peer = value; | ||
824 | |||
825 | (void) pid; | ||
826 | for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head; NULL != sh; | ||
827 | sh = sh->next) | ||
828 | { | ||
829 | enum GNUNET_NetworkType nt = sh->data->prop.nt; | ||
830 | |||
831 | sh->target_out = (uint64_t) (c->scale_out[nt] * sh->target_out); | ||
832 | sh->target_in = (uint64_t) (c->scale_in[nt] * sh->target_in); | ||
833 | consider_notify_transport (sh); | ||
834 | } | ||
835 | return GNUNET_YES; | ||
836 | } | ||
837 | |||
838 | |||
839 | /** | ||
840 | * The world changed, recalculate our allocations. | ||
841 | */ | ||
842 | static void | ||
843 | update (struct SimpleHandle *h) | ||
844 | { | ||
845 | struct Counters cnt = { .h = h }; | ||
846 | |||
847 | GNUNET_CONTAINER_multipeermap_iterate (h->peers, &update_counters, &cnt); | ||
848 | /* calculate how badly the missmatch between requested | ||
849 | allocations and available bandwidth is per network type */ | ||
850 | for (enum GNUNET_NetworkType nt = 0; nt < GNUNET_NT_COUNT; nt++) | ||
851 | { | ||
852 | cnt.scale_out[nt] = | ||
853 | 1.0 * cnt.bw_out_by_nt[nt] / h->networks[nt].total_quota_out; | ||
854 | cnt.scale_in[nt] = | ||
855 | 1.0 * cnt.bw_in_by_nt[nt] / h->networks[nt].total_quota_in; | ||
856 | } | ||
857 | /* recalculate allocations, considering scaling factor, and | ||
858 | update transport if the change is significant */ | ||
859 | GNUNET_CONTAINER_multipeermap_iterate (h->peers, &update_allocation, &cnt); | ||
860 | } | ||
861 | |||
862 | |||
863 | /** | ||
864 | * The plugin should begin to respect a new preference. | ||
865 | * | ||
866 | * @param cls the closure | ||
867 | * @param pref the preference to add | ||
868 | * @return plugin's internal representation, or NULL | ||
869 | */ | ||
870 | static struct GNUNET_ATS_PreferenceHandle * | ||
871 | simple_preference_add (void *cls, const struct GNUNET_ATS_Preference *pref) | ||
872 | { | ||
873 | struct SimpleHandle *h = cls; | ||
874 | struct Peer *p = peer_add (h, &pref->peer); | ||
875 | |||
876 | GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT); | ||
877 | p->bw_by_pk[pref->pk] += ntohl (pref->bw.value__); | ||
878 | h->bw_by_pk[pref->pk] += ntohl (pref->bw.value__); | ||
879 | update (h); | ||
880 | return NULL; | ||
881 | } | ||
882 | |||
883 | |||
884 | /** | ||
885 | * The plugin should end respecting a preference. | ||
886 | * | ||
887 | * @param cls the closure | ||
888 | * @param ph whatever @e preference_add returned | ||
889 | * @param pref the preference to delete | ||
890 | * @return plugin's internal representation, or NULL | ||
891 | */ | ||
892 | static void | ||
893 | simple_preference_del (void *cls, | ||
894 | struct GNUNET_ATS_PreferenceHandle *ph, | ||
895 | const struct GNUNET_ATS_Preference *pref) | ||
896 | { | ||
897 | struct SimpleHandle *h = cls; | ||
898 | struct Peer *p = lookup_peer (h, &pref->peer); | ||
899 | |||
900 | GNUNET_assert (NULL != p); | ||
901 | GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT); | ||
902 | p->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__); | ||
903 | h->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__); | ||
904 | if ((0 == p->bw_by_pk[pref->pk]) && (GNUNET_YES == peer_test_dead (p))) | ||
905 | peer_free (p); | ||
906 | update (h); | ||
907 | } | ||
908 | |||
909 | |||
910 | /** | ||
911 | * Transport established a new session with performance | ||
912 | * characteristics given in @a data. | ||
913 | * | ||
914 | * @param cls closure | ||
915 | * @param data performance characteristics of @a sh | ||
916 | * @param address address information (for debugging) | ||
917 | * @return handle by which the plugin will identify this session | ||
918 | */ | ||
919 | static struct GNUNET_ATS_SessionHandle * | ||
920 | simple_session_add (void *cls, | ||
921 | const struct GNUNET_ATS_SessionData *data, | ||
922 | const char *address) | ||
923 | { | ||
924 | struct SimpleHandle *h = cls; | ||
925 | struct Peer *p = peer_add (h, &data->peer); | ||
926 | struct Hello *hello; | ||
927 | size_t alen; | ||
928 | struct GNUNET_ATS_SessionHandle *sh; | ||
929 | |||
930 | /* setup session handle */ | ||
931 | GNUNET_assert (NULL != data); | ||
932 | if (NULL == address) | ||
933 | alen = 0; | ||
934 | else | ||
935 | alen = strlen (address) + 1; | ||
936 | sh = GNUNET_malloc (sizeof(struct GNUNET_ATS_SessionHandle) + alen); | ||
937 | sh->peer = p; | ||
938 | sh->session = data->session; | ||
939 | sh->data = data; | ||
940 | if (NULL == address) | ||
941 | { | ||
942 | sh->address = NULL; | ||
943 | } | ||
944 | else | ||
945 | { | ||
946 | memcpy (&sh[1], address, alen); | ||
947 | sh->address = (const char *) &sh[1]; | ||
948 | } | ||
949 | GNUNET_CONTAINER_DLL_insert (p->sh_head, p->sh_tail, sh); | ||
950 | if (NULL != address) | ||
951 | { | ||
952 | /* match HELLO */ | ||
953 | hello = p->h_head; | ||
954 | while ((NULL != hello) && (0 != strcmp (address, hello->address))) | ||
955 | hello = hello->next; | ||
956 | if (NULL != hello) | ||
957 | { | ||
958 | hello->sh = sh; | ||
959 | hello->backoff = GNUNET_TIME_UNIT_ZERO; | ||
960 | sh->hello = hello; | ||
961 | } | ||
962 | } | ||
963 | update (h); | ||
964 | return sh; | ||
965 | } | ||
966 | |||
967 | |||
968 | /** | ||
969 | * @a data changed for a given @a sh, solver should consider | ||
970 | * the updated performance characteristics. | ||
971 | * | ||
972 | * @param cls closure | ||
973 | * @param sh session this is about | ||
974 | * @param data performance characteristics of @a sh | ||
975 | */ | ||
976 | static void | ||
977 | simple_session_update (void *cls, | ||
978 | struct GNUNET_ATS_SessionHandle *sh, | ||
979 | const struct GNUNET_ATS_SessionData *data) | ||
980 | { | ||
981 | struct SimpleHandle *h = cls; | ||
982 | |||
983 | GNUNET_assert (NULL != data); | ||
984 | sh->data = data; /* this statement should not really do anything... */ | ||
985 | update (h); | ||
986 | } | ||
987 | |||
988 | |||
989 | /** | ||
990 | * A session went away. Solver should update accordingly. | ||
991 | * | ||
992 | * @param cls closure | ||
993 | * @param sh session this is about | ||
994 | * @param data (last) performance characteristics of @a sh | ||
995 | */ | ||
996 | static void | ||
997 | simple_session_del (void *cls, | ||
998 | struct GNUNET_ATS_SessionHandle *sh, | ||
999 | const struct GNUNET_ATS_SessionData *data) | ||
1000 | { | ||
1001 | struct SimpleHandle *h = cls; | ||
1002 | struct Peer *p = sh->peer; | ||
1003 | struct Hello *hello = sh->hello; | ||
1004 | |||
1005 | /* clean up sh */ | ||
1006 | GNUNET_CONTAINER_DLL_remove (p->sh_head, p->sh_tail, sh); | ||
1007 | if (NULL != hello) | ||
1008 | { | ||
1009 | GNUNET_assert (sh == hello->sh); | ||
1010 | hello->sh = NULL; | ||
1011 | /* session went down, if necessary restart suggesting | ||
1012 | addresses */ | ||
1013 | if (NULL == p->task) | ||
1014 | p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb, p); | ||
1015 | } | ||
1016 | GNUNET_free (sh); | ||
1017 | /* del peer if otherwise dead */ | ||
1018 | if ((NULL == p->sh_head) && (GNUNET_YES == peer_test_dead (p))) | ||
1019 | peer_free (p); | ||
1020 | update (h); | ||
1021 | } | ||
1022 | |||
1023 | |||
1024 | #include "plugin_ats2_common.c" | ||
1025 | |||
1026 | |||
1027 | /** | ||
1028 | * Function invoked when the plugin is loaded. | ||
1029 | * | ||
1030 | * @param[in,out] cls the `struct GNUNET_ATS_PluginEnvironment *` to use; | ||
1031 | * modified to return the API functions (ugh). | ||
1032 | * @return the `struct SimpleHandle` to pass as a closure | ||
1033 | */ | ||
1034 | void * | ||
1035 | libgnunet_plugin_ats2_simple_init (void *cls) | ||
1036 | { | ||
1037 | static struct GNUNET_ATS_SolverFunctions sf; | ||
1038 | struct GNUNET_ATS_PluginEnvironment *env = cls; | ||
1039 | struct SimpleHandle *s; | ||
1040 | |||
1041 | s = GNUNET_new (struct SimpleHandle); | ||
1042 | s->env = env; | ||
1043 | s->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); | ||
1044 | s->ps = GNUNET_PEERSTORE_connect (env->cfg); | ||
1045 | sf.cls = s; | ||
1046 | sf.preference_add = &simple_preference_add; | ||
1047 | sf.preference_del = &simple_preference_del; | ||
1048 | sf.session_add = &simple_session_add; | ||
1049 | sf.session_update = &simple_session_update; | ||
1050 | sf.session_del = &simple_session_del; | ||
1051 | for (enum GNUNET_NetworkType nt = 0; nt < GNUNET_NT_COUNT; nt++) | ||
1052 | { | ||
1053 | const char *name = GNUNET_NT_to_string (nt); | ||
1054 | |||
1055 | if (NULL == name) | ||
1056 | { | ||
1057 | GNUNET_break (0); | ||
1058 | break; | ||
1059 | } | ||
1060 | get_quota (env->cfg, name, "IN", &s->networks[nt].total_quota_in); | ||
1061 | get_quota (env->cfg, name, "OUT", &s->networks[nt].total_quota_out); | ||
1062 | s->networks[nt].type = nt; | ||
1063 | } | ||
1064 | return &sf; | ||
1065 | } | ||
1066 | |||
1067 | |||
1068 | /** | ||
1069 | * Function used to unload the plugin. | ||
1070 | * | ||
1071 | * @param cls return value from #libgnunet_plugin_ats_proportional_init() | ||
1072 | */ | ||
1073 | void * | ||
1074 | libgnunet_plugin_ats2_simple_done (void *cls) | ||
1075 | { | ||
1076 | struct GNUNET_ATS_SolverFunctions *sf = cls; | ||
1077 | struct SimpleHandle *s = sf->cls; | ||
1078 | |||
1079 | GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (s->peers)); | ||
1080 | GNUNET_CONTAINER_multipeermap_destroy (s->peers); | ||
1081 | GNUNET_PEERSTORE_disconnect (s->ps, GNUNET_NO); | ||
1082 | GNUNET_free (s); | ||
1083 | return NULL; | ||
1084 | } | ||
1085 | |||
1086 | |||
1087 | /* end of plugin_ats2_simple.c */ | ||
diff --git a/src/ats/plugin_ats_mlp.c b/src/ats/plugin_ats_mlp.c deleted file mode 100644 index 6ab823b1e..000000000 --- a/src/ats/plugin_ats_mlp.c +++ /dev/null | |||
@@ -1,2924 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014 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 | /** | ||
22 | * @file ats/plugin_ats_mlp.c | ||
23 | * @brief ats mlp problem solver | ||
24 | * @author Matthias Wachs | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_ats_service.h" | ||
30 | #include "gnunet_ats_plugin.h" | ||
31 | #include "gnunet-service-ats_addresses.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include <float.h> | ||
34 | #include <glpk.h> | ||
35 | |||
36 | |||
37 | #define BIG_M_VALUE (UINT32_MAX) / 10 | ||
38 | #define BIG_M_STRING "unlimited" | ||
39 | |||
40 | #define MLP_AVERAGING_QUEUE_LENGTH 3 | ||
41 | |||
42 | #define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply ( \ | ||
43 | GNUNET_TIME_UNIT_SECONDS, 10) | ||
44 | #define MLP_MAX_ITERATIONS 4096 | ||
45 | |||
46 | #define MLP_DEFAULT_D 1.0 | ||
47 | #define MLP_DEFAULT_R 1.0 | ||
48 | #define MLP_DEFAULT_U 1.0 | ||
49 | #define MLP_DEFAULT_QUALITY 1.0 | ||
50 | #define MLP_DEFAULT_MIN_CONNECTIONS 4 | ||
51 | #define MLP_DEFAULT_PEER_PREFERENCE 1.0 | ||
52 | |||
53 | #define MLP_NaN -1 | ||
54 | #define MLP_UNDEFINED 0 | ||
55 | #define GLP_YES 1.0 | ||
56 | #define GLP_NO 0.0 | ||
57 | |||
58 | enum MLP_Output_Format | ||
59 | { | ||
60 | MLP_MPS, | ||
61 | MLP_CPLEX, | ||
62 | MLP_GLPK | ||
63 | }; | ||
64 | |||
65 | |||
66 | enum QualityMetrics | ||
67 | { | ||
68 | RQ_QUALITY_METRIC_DELAY = 0, | ||
69 | RQ_QUALITY_METRIC_DISTANCE = 1, | ||
70 | RQ_QUALITY_METRIC_COUNT = 2 | ||
71 | }; | ||
72 | |||
73 | |||
74 | static const char * | ||
75 | print_quality_type (enum QualityMetrics qm) | ||
76 | { | ||
77 | switch (qm) | ||
78 | { | ||
79 | case RQ_QUALITY_METRIC_DELAY: | ||
80 | return "delay"; | ||
81 | |||
82 | case RQ_QUALITY_METRIC_DISTANCE: | ||
83 | return "distance"; | ||
84 | |||
85 | default: | ||
86 | GNUNET_break (0); | ||
87 | return NULL; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | |||
92 | struct MLP_Solution | ||
93 | { | ||
94 | int lp_res; | ||
95 | int lp_presolv; | ||
96 | int mip_res; | ||
97 | int mip_presolv; | ||
98 | |||
99 | double lp_objective_value; | ||
100 | double mlp_objective_value; | ||
101 | double mlp_gap; | ||
102 | double lp_mlp_gap; | ||
103 | |||
104 | int p_elements; | ||
105 | int p_cols; | ||
106 | int p_rows; | ||
107 | |||
108 | int n_peers; | ||
109 | int n_addresses; | ||
110 | }; | ||
111 | |||
112 | struct ATS_Peer | ||
113 | { | ||
114 | struct GNUNET_PeerIdentity id; | ||
115 | |||
116 | /* Was this peer already added to the current problem? */ | ||
117 | int processed; | ||
118 | |||
119 | /* constraint 2: 1 address per peer*/ | ||
120 | unsigned int r_c2; | ||
121 | |||
122 | /* constraint 9: relativity */ | ||
123 | unsigned int r_c9; | ||
124 | |||
125 | /* Legacy preference value */ | ||
126 | double f; | ||
127 | }; | ||
128 | |||
129 | struct MLP_Problem | ||
130 | { | ||
131 | /** | ||
132 | * GLPK (MLP) problem object | ||
133 | */ | ||
134 | glp_prob *prob; | ||
135 | |||
136 | /* Number of addresses in problem */ | ||
137 | unsigned int num_addresses; | ||
138 | /* Number of peers in problem */ | ||
139 | unsigned int num_peers; | ||
140 | /* Number of elements in problem matrix */ | ||
141 | unsigned int num_elements; | ||
142 | |||
143 | /* Row index constraint 2: */ | ||
144 | unsigned int r_c2; | ||
145 | /* Row index constraint 4: minimum connections */ | ||
146 | unsigned int r_c4; | ||
147 | /* Row index constraint 6: maximize diversity */ | ||
148 | unsigned int r_c6; | ||
149 | /* Row index constraint 8: utilization*/ | ||
150 | unsigned int r_c8; | ||
151 | /* Row index constraint 9: relativity*/ | ||
152 | unsigned int r_c9; | ||
153 | /* Row indices quality metrics */ | ||
154 | int r_q[RQ_QUALITY_METRIC_COUNT]; | ||
155 | /* Row indices ATS network quotas */ | ||
156 | int r_quota[GNUNET_NT_COUNT]; | ||
157 | |||
158 | /* Column index Diversity (D) column */ | ||
159 | int c_d; | ||
160 | /* Column index Utilization (U) column */ | ||
161 | int c_u; | ||
162 | /* Column index Proportionality (R) column */ | ||
163 | int c_r; | ||
164 | /* Column index quality metrics */ | ||
165 | int c_q[RQ_QUALITY_METRIC_COUNT]; | ||
166 | |||
167 | /* Problem matrix */ | ||
168 | /* Current index */ | ||
169 | unsigned int ci; | ||
170 | /* Row index array */ | ||
171 | int *ia; | ||
172 | /* Column index array */ | ||
173 | int *ja; | ||
174 | /* Column index value */ | ||
175 | double *ar; | ||
176 | }; | ||
177 | |||
178 | struct MLP_Variables | ||
179 | { | ||
180 | /* Big M value for bandwidth capping */ | ||
181 | double BIG_M; | ||
182 | |||
183 | /* MIP Gap */ | ||
184 | double mip_gap; | ||
185 | |||
186 | /* LP MIP Gap */ | ||
187 | double lp_mip_gap; | ||
188 | |||
189 | /* Number of quality metrics @deprecated, use RQ_QUALITY_METRIC_COUNT */ | ||
190 | int m_q; | ||
191 | |||
192 | /* Number of quality metrics */ | ||
193 | int m_rc; | ||
194 | |||
195 | /* Quality metric coefficients*/ | ||
196 | double co_Q[RQ_QUALITY_METRIC_COUNT]; | ||
197 | |||
198 | /* Ressource costs coefficients*/ | ||
199 | double co_RC[RQ_QUALITY_METRIC_COUNT]; | ||
200 | |||
201 | /* Diversity coefficient */ | ||
202 | double co_D; | ||
203 | |||
204 | /* Utility coefficient */ | ||
205 | double co_U; | ||
206 | |||
207 | /* Relativity coefficient */ | ||
208 | double co_R; | ||
209 | |||
210 | /* Minimum bandwidth assigned to an address */ | ||
211 | unsigned int b_min; | ||
212 | |||
213 | /* Minimum number of addresses with bandwidth assigned */ | ||
214 | unsigned int n_min; | ||
215 | |||
216 | /* Quotas */ | ||
217 | /* Array mapping array index to ATS network */ | ||
218 | int quota_index[GNUNET_NT_COUNT]; | ||
219 | /* Outbound quotas */ | ||
220 | unsigned long long quota_out[GNUNET_NT_COUNT]; | ||
221 | /* Inbound quotas */ | ||
222 | |||
223 | unsigned long long quota_in[GNUNET_NT_COUNT]; | ||
224 | |||
225 | /* ATS ressource costs | ||
226 | * array with GNUNET_ATS_QualityPropertiesCount elements | ||
227 | * contains mapping to GNUNET_ATS_Property | ||
228 | * */ | ||
229 | int rc[RQ_QUALITY_METRIC_COUNT]; | ||
230 | }; | ||
231 | |||
232 | /** | ||
233 | * MLP Handle | ||
234 | */ | ||
235 | struct GAS_MLP_Handle | ||
236 | { | ||
237 | struct GNUNET_ATS_PluginEnvironment *env; | ||
238 | |||
239 | /** | ||
240 | * Exclude peer from next result propagation | ||
241 | */ | ||
242 | const struct GNUNET_PeerIdentity *exclude_peer; | ||
243 | |||
244 | /** | ||
245 | * Encapsulation for the MLP problem | ||
246 | */ | ||
247 | struct MLP_Problem p; | ||
248 | |||
249 | /** | ||
250 | * Encapsulation for the MLP problem variables | ||
251 | */ | ||
252 | struct MLP_Variables pv; | ||
253 | |||
254 | /** | ||
255 | * Encapsulation for the MLP solution | ||
256 | */ | ||
257 | struct MLP_Solution ps; | ||
258 | |||
259 | /** | ||
260 | * Bulk lock | ||
261 | */ | ||
262 | int stat_bulk_lock; | ||
263 | |||
264 | /** | ||
265 | * Number of changes while solver was locked | ||
266 | */ | ||
267 | int stat_bulk_requests; | ||
268 | |||
269 | /** | ||
270 | * GLPK LP control parameter | ||
271 | */ | ||
272 | glp_smcp control_param_lp; | ||
273 | |||
274 | /** | ||
275 | * GLPK LP control parameter | ||
276 | */ | ||
277 | glp_iocp control_param_mlp; | ||
278 | |||
279 | /** | ||
280 | * Peers with pending address requests | ||
281 | */ | ||
282 | struct GNUNET_CONTAINER_MultiPeerMap *requested_peers; | ||
283 | |||
284 | /** | ||
285 | * Was the problem updated since last solution | ||
286 | */ | ||
287 | int stat_mlp_prob_updated; | ||
288 | |||
289 | /** | ||
290 | * Has the problem size changed since last solution | ||
291 | */ | ||
292 | int stat_mlp_prob_changed; | ||
293 | |||
294 | /** | ||
295 | * Solve the problem automatically when updates occur? | ||
296 | * Default: GNUNET_YES | ||
297 | * Can be disabled for test and measurements | ||
298 | */ | ||
299 | int opt_mlp_auto_solve; | ||
300 | |||
301 | /** | ||
302 | * Write all MILP problems to a MPS file | ||
303 | */ | ||
304 | int opt_dump_problem_all; | ||
305 | |||
306 | /** | ||
307 | * Write all MILP problem solutions to a file | ||
308 | */ | ||
309 | int opt_dump_solution_all; | ||
310 | |||
311 | /** | ||
312 | * Write MILP problems to a MPS file when solver fails | ||
313 | */ | ||
314 | int opt_dump_problem_on_fail; | ||
315 | |||
316 | /** | ||
317 | * Write MILP problem solutions to a file when solver fails | ||
318 | */ | ||
319 | int opt_dump_solution_on_fail; | ||
320 | |||
321 | /** | ||
322 | * solve feasibility only | ||
323 | */ | ||
324 | int opt_dbg_feasibility_only; | ||
325 | |||
326 | /** | ||
327 | * solve autoscale the problem | ||
328 | */ | ||
329 | int opt_dbg_autoscale_problem; | ||
330 | |||
331 | /** | ||
332 | * use the intopt presolver instead of simplex | ||
333 | */ | ||
334 | int opt_dbg_intopt_presolver; | ||
335 | |||
336 | /** | ||
337 | * Print GLPK output | ||
338 | */ | ||
339 | int opt_dbg_glpk_verbose; | ||
340 | |||
341 | /** | ||
342 | * solve autoscale the problem | ||
343 | */ | ||
344 | int opt_dbg_optimize_relativity; | ||
345 | |||
346 | /** | ||
347 | * solve autoscale the problem | ||
348 | */ | ||
349 | int opt_dbg_optimize_diversity; | ||
350 | |||
351 | /** | ||
352 | * solve autoscale the problem | ||
353 | */ | ||
354 | int opt_dbg_optimize_quality; | ||
355 | |||
356 | /** | ||
357 | * solve autoscale the problem | ||
358 | */ | ||
359 | int opt_dbg_optimize_utility; | ||
360 | |||
361 | |||
362 | /** | ||
363 | * Output format | ||
364 | */ | ||
365 | enum MLP_Output_Format opt_log_format; | ||
366 | }; | ||
367 | |||
368 | /** | ||
369 | * Address specific MLP information | ||
370 | */ | ||
371 | struct MLP_information | ||
372 | { | ||
373 | /** | ||
374 | * Bandwidth assigned outbound | ||
375 | */ | ||
376 | uint32_t b_out; | ||
377 | |||
378 | /** | ||
379 | * Bandwidth assigned inbound | ||
380 | */ | ||
381 | uint32_t b_in; | ||
382 | |||
383 | /** | ||
384 | * Address selected | ||
385 | */ | ||
386 | int n; | ||
387 | |||
388 | /** | ||
389 | * bandwidth column index | ||
390 | */ | ||
391 | signed int c_b; | ||
392 | |||
393 | /** | ||
394 | * address usage column | ||
395 | */ | ||
396 | signed int c_n; | ||
397 | |||
398 | /* row indexes */ | ||
399 | |||
400 | /** | ||
401 | * constraint 1: bandwidth capping | ||
402 | */ | ||
403 | unsigned int r_c1; | ||
404 | |||
405 | /** | ||
406 | * constraint 3: minimum bandwidth | ||
407 | */ | ||
408 | unsigned int r_c3; | ||
409 | }; | ||
410 | |||
411 | |||
412 | |||
413 | /** | ||
414 | * | ||
415 | * NOTE: Do not modify this documentation. This documentation is based on | ||
416 | * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex | ||
417 | * use build_txt.sh to generate plaintext output | ||
418 | * | ||
419 | * The MLP solver (mlp) tries to finds an optimal bandwidth assignmentby | ||
420 | * optimizing an mixed integer programming problem. The MLP solver uses a | ||
421 | * number of constraints to find the best adddress for a peer and an optimal | ||
422 | * bandwidth assignment. mlp uses the GNU Linear Programming Kit to solve the | ||
423 | * MLP problem. | ||
424 | * | ||
425 | * We defined a constraint system to find an optimal bandwidth assignment. | ||
426 | * This constraint system uses as an input data addresses, bandwidth quotas, | ||
427 | * preferences and quality values. This constraint system is stored in an | ||
428 | * matrix based equotation system. | ||
429 | * | ||
430 | * 5 Using GLPK | ||
431 | * | ||
432 | * A (M)LP problem consists of a target function to optimizes, constraints | ||
433 | * and rows and columns. FIXME GLP uses three arrays to index the matrix: two | ||
434 | * integer arrays storing the row and column indices in the matrix and an | ||
435 | * float array to store the coeeficient. | ||
436 | * | ||
437 | * To solve the problem we first find an initial solution for the LP problem | ||
438 | * using the LP solver and then find an MLP solution based on this solution | ||
439 | * using the MLP solver. | ||
440 | * | ||
441 | * Solving (M)LP problems has the property that finding an initial solution | ||
442 | * for the LP problem is computationally expensive and finding the MLP | ||
443 | * solution is cheaper. This is especially interesting an existing LP | ||
444 | * solution can be reused if only coefficients in the matrix have changed | ||
445 | * (addresses updated). Only when the problem size changes (addresses added | ||
446 | * or deleted) a new LP solution has to be found. | ||
447 | * | ||
448 | * Intended usage | ||
449 | * The mlp solver solves the bandwidth assignment problem only on demand when | ||
450 | * an address suggestion is requested. When an address is requested mlp the | ||
451 | * solves the mlp problem and if the active address or the bandwidth assigned | ||
452 | * changes it calls the callback to addresses. The mlp solver gets notified | ||
453 | * about new addresses (adding sessions), removed addresses (address | ||
454 | * deletions) and address updates. To benefit from the mlp properties | ||
455 | * mentioned in section 5 the solver rembers if since the last solution | ||
456 | * addresses were added or deleted (problem size changed, problem has to be | ||
457 | * rebuild and solved from sratch) or if addresses were updated and the | ||
458 | * existing solution can be reused. | ||
459 | * | ||
460 | * 5.1 Input data | ||
461 | * | ||
462 | * The quotas for each network segment are passed by addresses. MLP can be | ||
463 | * adapted using configuration settings and uses the following parameters: | ||
464 | * * MLP_MAX_DURATION: | ||
465 | * Maximum duration for a MLP solution procees (default: 3 sec.) | ||
466 | * * MLP_MAX_ITERATIONS: | ||
467 | * Maximum number of iterations for a MLP solution process (default: | ||
468 | * 1024) | ||
469 | * * MLP_MIN_CONNECTIONS: | ||
470 | * Minimum number of desired connections (default: 4) | ||
471 | * * MLP_MIN_BANDWIDTH: | ||
472 | * Minimum amount of bandwidth assigned to an address (default: 1024) | ||
473 | * * MLP_COEFFICIENT_D: | ||
474 | * Diversity coefficient (default: 1.0) | ||
475 | * * MLP_COEFFICIENT_R: | ||
476 | * Relativity coefficient (default: 1.0) | ||
477 | * * MLP_COEFFICIENT_U: | ||
478 | * Utilization coefficient (default: 1.0) | ||
479 | * * MLP_COEFFICIENT_D: | ||
480 | * Diversity coefficient (default: 1.0) | ||
481 | * * MLP_COEFFICIENT_QUALITY_DELAY: | ||
482 | * Quality delay coefficient (default: 1.0) | ||
483 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
484 | * Quality distance coefficient (default: 1.0) | ||
485 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
486 | * Quality distance coefficient (default: 1.0) | ||
487 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
488 | * Quality distance coefficient (default: 1.0) | ||
489 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
490 | * Quality distance coefficient (default: 1.0) | ||
491 | * | ||
492 | * 5.2 Data structures used | ||
493 | * | ||
494 | * mlp has for each known peer a struct ATS_Peer containing information about | ||
495 | * a specific peer. The address field solver_information contains information | ||
496 | * about the mlp properties of this address. | ||
497 | * | ||
498 | * 5.3 Initializing | ||
499 | * | ||
500 | * During initialization mlp initializes the GLPK libray used to solve the | ||
501 | * MLP problem: it initializes the glpk environment and creates an initial LP | ||
502 | * problem. Next it loads the configuration values from the configuration or | ||
503 | * uses the default values configured in -addresses_mlp.h. The quotas used | ||
504 | * are given by addresses but may have to be adjusted. mlp uses a upper limit | ||
505 | * for the bandwidth assigned called BIG M and a minimum amount of bandwidth | ||
506 | * an address gets assigned as well as a minium desired number of | ||
507 | * connections. If the configured quota is bigger than BIG M, it is reduced | ||
508 | * to BIG M. If the configured quota is smaller than MLP_MIN_CONNECTIONS | ||
509 | * *MLP_MIN_BANDWIDTH it is increased to this value. | ||
510 | * | ||
511 | * 5.4 Shutdown | ||
512 | |||
513 | */ | ||
514 | |||
515 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-mlp", __VA_ARGS__) | ||
516 | |||
517 | /** | ||
518 | * Print debug output for mlp problem creation | ||
519 | */ | ||
520 | #define DEBUG_MLP_PROBLEM_CREATION GNUNET_NO | ||
521 | |||
522 | |||
523 | /** | ||
524 | * Intercept GLPK terminal output | ||
525 | * @param info the mlp handle | ||
526 | * @param s the string to print | ||
527 | * @return 0: glpk prints output on terminal, 0 != surpress output | ||
528 | */ | ||
529 | static int | ||
530 | mlp_term_hook (void *info, const char *s) | ||
531 | { | ||
532 | struct GAS_MLP_Handle *mlp = info; | ||
533 | |||
534 | if (mlp->opt_dbg_glpk_verbose) | ||
535 | LOG (GNUNET_ERROR_TYPE_ERROR, "%s", s); | ||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | |||
540 | /** | ||
541 | * Reset peers for next problem creation | ||
542 | * | ||
543 | * @param cls not used | ||
544 | * @param key the key | ||
545 | * @param value ATS_Peer | ||
546 | * @return #GNUNET_OK | ||
547 | */ | ||
548 | static int | ||
549 | reset_peers (void *cls, | ||
550 | const struct GNUNET_PeerIdentity *key, | ||
551 | void *value) | ||
552 | { | ||
553 | struct ATS_Peer *peer = value; | ||
554 | |||
555 | peer->processed = GNUNET_NO; | ||
556 | return GNUNET_OK; | ||
557 | } | ||
558 | |||
559 | /** | ||
560 | * Delete the MLP problem and free the constrain matrix | ||
561 | * | ||
562 | * @param mlp the MLP handle | ||
563 | */ | ||
564 | static void | ||
565 | mlp_delete_problem (struct GAS_MLP_Handle *mlp) | ||
566 | { | ||
567 | int c; | ||
568 | |||
569 | if (mlp == NULL) | ||
570 | return; | ||
571 | if (mlp->p.prob != NULL) | ||
572 | { | ||
573 | glp_delete_prob (mlp->p.prob); | ||
574 | mlp->p.prob = NULL; | ||
575 | } | ||
576 | |||
577 | /* delete row index */ | ||
578 | if (mlp->p.ia != NULL) | ||
579 | { | ||
580 | GNUNET_free (mlp->p.ia); | ||
581 | mlp->p.ia = NULL; | ||
582 | } | ||
583 | |||
584 | /* delete column index */ | ||
585 | if (mlp->p.ja != NULL) | ||
586 | { | ||
587 | GNUNET_free (mlp->p.ja); | ||
588 | mlp->p.ja = NULL; | ||
589 | } | ||
590 | |||
591 | /* delete coefficients */ | ||
592 | if (mlp->p.ar != NULL) | ||
593 | { | ||
594 | GNUNET_free (mlp->p.ar); | ||
595 | mlp->p.ar = NULL; | ||
596 | } | ||
597 | mlp->p.ci = 0; | ||
598 | mlp->p.prob = NULL; | ||
599 | |||
600 | mlp->p.c_d = MLP_UNDEFINED; | ||
601 | mlp->p.c_r = MLP_UNDEFINED; | ||
602 | mlp->p.r_c2 = MLP_UNDEFINED; | ||
603 | mlp->p.r_c4 = MLP_UNDEFINED; | ||
604 | mlp->p.r_c6 = MLP_UNDEFINED; | ||
605 | mlp->p.r_c9 = MLP_UNDEFINED; | ||
606 | for (c = 0; c < RQ_QUALITY_METRIC_COUNT; c++) | ||
607 | mlp->p.r_q[c] = MLP_UNDEFINED; | ||
608 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
609 | mlp->p.r_quota[c] = MLP_UNDEFINED; | ||
610 | mlp->p.ci = MLP_UNDEFINED; | ||
611 | |||
612 | |||
613 | GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers, | ||
614 | &reset_peers, NULL); | ||
615 | } | ||
616 | |||
617 | |||
618 | /** | ||
619 | * Translate glpk status error codes to text | ||
620 | * @param retcode return code | ||
621 | * @return string with result | ||
622 | */ | ||
623 | static const char * | ||
624 | mlp_status_to_string (int retcode) | ||
625 | { | ||
626 | switch (retcode) | ||
627 | { | ||
628 | case GLP_UNDEF: | ||
629 | return "solution is undefined"; | ||
630 | |||
631 | case GLP_FEAS: | ||
632 | return "solution is feasible"; | ||
633 | |||
634 | case GLP_INFEAS: | ||
635 | return "solution is infeasible"; | ||
636 | |||
637 | case GLP_NOFEAS: | ||
638 | return "no feasible solution exists"; | ||
639 | |||
640 | case GLP_OPT: | ||
641 | return "solution is optimal"; | ||
642 | |||
643 | case GLP_UNBND: | ||
644 | return "solution is unbounded"; | ||
645 | |||
646 | default: | ||
647 | GNUNET_break (0); | ||
648 | return "unknown error"; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | |||
653 | /** | ||
654 | * Translate glpk solver error codes to text | ||
655 | * @param retcode return code | ||
656 | * @return string with result | ||
657 | */ | ||
658 | static const char * | ||
659 | mlp_solve_to_string (int retcode) | ||
660 | { | ||
661 | switch (retcode) | ||
662 | { | ||
663 | case 0: | ||
664 | return "ok"; | ||
665 | |||
666 | case GLP_EBADB: | ||
667 | return "invalid basis"; | ||
668 | |||
669 | case GLP_ESING: | ||
670 | return "singular matrix"; | ||
671 | |||
672 | case GLP_ECOND: | ||
673 | return "ill-conditioned matrix"; | ||
674 | |||
675 | case GLP_EBOUND: | ||
676 | return "invalid bounds"; | ||
677 | |||
678 | case GLP_EFAIL: | ||
679 | return "solver failed"; | ||
680 | |||
681 | case GLP_EOBJLL: | ||
682 | return "objective lower limit reached"; | ||
683 | |||
684 | case GLP_EOBJUL: | ||
685 | return "objective upper limit reached"; | ||
686 | |||
687 | case GLP_EITLIM: | ||
688 | return "iteration limit exceeded"; | ||
689 | |||
690 | case GLP_ETMLIM: | ||
691 | return "time limit exceeded"; | ||
692 | |||
693 | case GLP_ENOPFS: | ||
694 | return "no primal feasible solution"; | ||
695 | |||
696 | case GLP_ENODFS: | ||
697 | return "no dual feasible solution"; | ||
698 | |||
699 | case GLP_EROOT: | ||
700 | return "root LP optimum not provided"; | ||
701 | |||
702 | case GLP_ESTOP: | ||
703 | return "search terminated by application"; | ||
704 | |||
705 | case GLP_EMIPGAP: | ||
706 | return "relative mip gap tolerance reached"; | ||
707 | |||
708 | case GLP_ENOFEAS: | ||
709 | return "no dual feasible solution"; | ||
710 | |||
711 | case GLP_ENOCVG: | ||
712 | return "no convergence"; | ||
713 | |||
714 | case GLP_EINSTAB: | ||
715 | return "numerical instability"; | ||
716 | |||
717 | case GLP_EDATA: | ||
718 | return "invalid data"; | ||
719 | |||
720 | case GLP_ERANGE: | ||
721 | return "result out of range"; | ||
722 | |||
723 | default: | ||
724 | GNUNET_break (0); | ||
725 | return "unknown error"; | ||
726 | } | ||
727 | } | ||
728 | |||
729 | |||
730 | struct CountContext | ||
731 | { | ||
732 | const struct GNUNET_CONTAINER_MultiPeerMap *map; | ||
733 | int result; | ||
734 | }; | ||
735 | |||
736 | static int | ||
737 | mlp_create_problem_count_addresses_it (void *cls, | ||
738 | const struct GNUNET_PeerIdentity *key, | ||
739 | void *value) | ||
740 | { | ||
741 | struct CountContext *cctx = cls; | ||
742 | |||
743 | /* Check if we have to add this peer due to a pending request */ | ||
744 | if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key)) | ||
745 | cctx->result++; | ||
746 | return GNUNET_OK; | ||
747 | } | ||
748 | |||
749 | |||
750 | static int | ||
751 | mlp_create_problem_count_addresses (const struct | ||
752 | GNUNET_CONTAINER_MultiPeerMap * | ||
753 | requested_peers, | ||
754 | const struct | ||
755 | GNUNET_CONTAINER_MultiPeerMap *addresses) | ||
756 | { | ||
757 | struct CountContext cctx; | ||
758 | |||
759 | cctx.map = requested_peers; | ||
760 | cctx.result = 0; | ||
761 | GNUNET_CONTAINER_multipeermap_iterate (addresses, | ||
762 | &mlp_create_problem_count_addresses_it, | ||
763 | &cctx); | ||
764 | return cctx.result; | ||
765 | } | ||
766 | |||
767 | |||
768 | static int | ||
769 | mlp_create_problem_count_peers_it (void *cls, | ||
770 | const struct GNUNET_PeerIdentity *key, | ||
771 | void *value) | ||
772 | { | ||
773 | struct CountContext *cctx = cls; | ||
774 | |||
775 | /* Check if we have to addresses for the requested peer */ | ||
776 | if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key)) | ||
777 | cctx->result++; | ||
778 | return GNUNET_OK; | ||
779 | } | ||
780 | |||
781 | |||
782 | static int | ||
783 | mlp_create_problem_count_peers (const struct | ||
784 | GNUNET_CONTAINER_MultiPeerMap *requested_peers, | ||
785 | const struct | ||
786 | GNUNET_CONTAINER_MultiPeerMap *addresses) | ||
787 | { | ||
788 | struct CountContext cctx; | ||
789 | |||
790 | cctx.map = addresses; | ||
791 | cctx.result = 0; | ||
792 | GNUNET_CONTAINER_multipeermap_iterate (requested_peers, | ||
793 | &mlp_create_problem_count_peers_it, | ||
794 | &cctx); | ||
795 | return cctx.result; | ||
796 | } | ||
797 | |||
798 | |||
799 | /** | ||
800 | * Updates an existing value in the matrix | ||
801 | * | ||
802 | * Extract the row, updates the value and updates the row in the problem | ||
803 | * | ||
804 | * @param p the mlp problem | ||
805 | * @param row the row to create the value in | ||
806 | * @param col the column to create the value in | ||
807 | * @param val the value to set | ||
808 | * @param line calling line for debbuging | ||
809 | * @return GNUNET_YES value changed, GNUNET_NO value did not change, GNUNET_SYSERR | ||
810 | * on error | ||
811 | */ | ||
812 | static int | ||
813 | mlp_create_problem_update_value (struct MLP_Problem *p, | ||
814 | int row, int col, double val, | ||
815 | int line) | ||
816 | { | ||
817 | int c_cols; | ||
818 | int c_elems; | ||
819 | int c1; | ||
820 | int res; | ||
821 | int found; | ||
822 | double *val_array; | ||
823 | int *ind_array; | ||
824 | |||
825 | GNUNET_assert (NULL != p->prob); | ||
826 | |||
827 | /* Get number of columns and prepare data structure */ | ||
828 | c_cols = glp_get_num_cols (p->prob); | ||
829 | if (0 >= c_cols) | ||
830 | return GNUNET_SYSERR; | ||
831 | |||
832 | val_array = GNUNET_malloc ((c_cols + 1) * sizeof(double)); | ||
833 | GNUNET_assert (NULL != val_array); | ||
834 | ind_array = GNUNET_malloc ((c_cols + 1) * sizeof(int)); | ||
835 | GNUNET_assert (NULL != ind_array); | ||
836 | /* Extract the row */ | ||
837 | |||
838 | /* Update the value */ | ||
839 | c_elems = glp_get_mat_row (p->prob, row, ind_array, val_array); | ||
840 | found = GNUNET_NO; | ||
841 | for (c1 = 1; c1 < (c_elems + 1); c1++) | ||
842 | { | ||
843 | if (ind_array[c1] == col) | ||
844 | { | ||
845 | found = GNUNET_YES; | ||
846 | break; | ||
847 | } | ||
848 | } | ||
849 | if (GNUNET_NO == found) | ||
850 | { | ||
851 | ind_array[c_elems + 1] = col; | ||
852 | val_array[c_elems + 1] = val; | ||
853 | LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Setting value in [%s : %s] to `%.2f'\n", | ||
854 | glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col), | ||
855 | val); | ||
856 | glp_set_mat_row (p->prob, row, c_elems + 1, ind_array, val_array); | ||
857 | GNUNET_free (ind_array); | ||
858 | GNUNET_free (val_array); | ||
859 | return GNUNET_YES; | ||
860 | } | ||
861 | else | ||
862 | { | ||
863 | /* Update value */ | ||
864 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
865 | "[P] Updating value in [%s : %s] from `%.2f' to `%.2f'\n", | ||
866 | glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col), | ||
867 | val_array[c1], val); | ||
868 | if (val != val_array[c1]) | ||
869 | res = GNUNET_YES; | ||
870 | else | ||
871 | res = GNUNET_NO; | ||
872 | val_array[c1] = val; | ||
873 | /* Update the row in the matrix */ | ||
874 | glp_set_mat_row (p->prob, row, c_elems, ind_array, val_array); | ||
875 | } | ||
876 | |||
877 | GNUNET_free (ind_array); | ||
878 | GNUNET_free (val_array); | ||
879 | return res; | ||
880 | } | ||
881 | |||
882 | /** | ||
883 | * Creates a new value in the matrix | ||
884 | * | ||
885 | * Sets the row and column index in the problem array and increments the | ||
886 | * position field | ||
887 | * | ||
888 | * @param p the mlp problem | ||
889 | * @param row the row to create the value in | ||
890 | * @param col the column to create the value in | ||
891 | * @param val the value to set | ||
892 | * @param line calling line for debbuging | ||
893 | */ | ||
894 | static void | ||
895 | mlp_create_problem_set_value (struct MLP_Problem *p, | ||
896 | int row, int col, double val, | ||
897 | int line) | ||
898 | { | ||
899 | if ((p->ci) >= p->num_elements) | ||
900 | { | ||
901 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
902 | "[P]: line %u: Request for index %u bigger than array size of %u\n", | ||
903 | line, p->ci + 1, p->num_elements); | ||
904 | GNUNET_break (0); | ||
905 | return; | ||
906 | } | ||
907 | if ((0 == row) || (0 == col)) | ||
908 | { | ||
909 | GNUNET_break (0); | ||
910 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
911 | "[P]: Invalid call from line %u: row = %u, col = %u\n", | ||
912 | line, row, col); | ||
913 | } | ||
914 | p->ia[p->ci] = row; | ||
915 | p->ja[p->ci] = col; | ||
916 | p->ar[p->ci] = val; | ||
917 | #if DEBUG_MLP_PROBLEM_CREATION | ||
918 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
919 | "[P]: line %u: Set value [%u,%u] in index %u == %.2f\n", | ||
920 | line, p->ia[p->ci], p->ja[p->ci], p->ci, p->ar[p->ci]); | ||
921 | #endif | ||
922 | p->ci++; | ||
923 | } | ||
924 | |||
925 | static int | ||
926 | mlp_create_problem_create_column (struct MLP_Problem *p, char *name, | ||
927 | unsigned int type, unsigned int bound, double | ||
928 | lb, double ub, | ||
929 | double coef) | ||
930 | { | ||
931 | int col = glp_add_cols (p->prob, 1); | ||
932 | |||
933 | glp_set_col_name (p->prob, col, name); | ||
934 | glp_set_col_bnds (p->prob, col, bound, lb, ub); | ||
935 | glp_set_col_kind (p->prob, col, type); | ||
936 | glp_set_obj_coef (p->prob, col, coef); | ||
937 | #if DEBUG_MLP_PROBLEM_CREATION | ||
938 | LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added column [%u] `%s': %.2f\n", | ||
939 | col, name, coef); | ||
940 | #endif | ||
941 | return col; | ||
942 | } | ||
943 | |||
944 | static int | ||
945 | mlp_create_problem_create_constraint (struct MLP_Problem *p, char *name, | ||
946 | unsigned int bound, double lb, double ub) | ||
947 | { | ||
948 | char *op; | ||
949 | int row = glp_add_rows (p->prob, 1); | ||
950 | |||
951 | /* set row name */ | ||
952 | glp_set_row_name (p->prob, row, name); | ||
953 | /* set row bounds: <= 0 */ | ||
954 | glp_set_row_bnds (p->prob, row, bound, lb, ub); | ||
955 | switch (bound) | ||
956 | { | ||
957 | case GLP_UP: | ||
958 | GNUNET_asprintf (&op, "-inf <= x <= %.2f", ub); | ||
959 | break; | ||
960 | |||
961 | case GLP_DB: | ||
962 | GNUNET_asprintf (&op, "%.2f <= x <= %.2f", lb, ub); | ||
963 | break; | ||
964 | |||
965 | case GLP_FX: | ||
966 | GNUNET_asprintf (&op, "%.2f == x == %.2f", lb, ub); | ||
967 | break; | ||
968 | |||
969 | case GLP_LO: | ||
970 | GNUNET_asprintf (&op, "%.2f <= x <= inf", lb); | ||
971 | break; | ||
972 | |||
973 | default: | ||
974 | GNUNET_asprintf (&op, "ERROR"); | ||
975 | break; | ||
976 | } | ||
977 | #if DEBUG_MLP_PROBLEM_CREATION | ||
978 | LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added row [%u] `%s': %s\n", | ||
979 | row, name, op); | ||
980 | #endif | ||
981 | GNUNET_free (op); | ||
982 | return row; | ||
983 | } | ||
984 | |||
985 | /** | ||
986 | * Create the | ||
987 | * - address columns b and n | ||
988 | * - address dependent constraint rows c1, c3 | ||
989 | * - peer dependent rows c2 and c9 | ||
990 | * - Set address dependent entries in problem matrix as well | ||
991 | */ | ||
992 | static int | ||
993 | mlp_create_problem_add_address_information (void *cls, | ||
994 | const struct | ||
995 | GNUNET_PeerIdentity *key, | ||
996 | void *value) | ||
997 | { | ||
998 | struct GAS_MLP_Handle *mlp = cls; | ||
999 | struct MLP_Problem *p = &mlp->p; | ||
1000 | struct ATS_Address *address = value; | ||
1001 | struct ATS_Peer *peer; | ||
1002 | struct MLP_information *mlpi; | ||
1003 | char *name; | ||
1004 | double cur_bigm; | ||
1005 | uint32_t addr_net; | ||
1006 | uint32_t addr_net_index; | ||
1007 | unsigned long long max_quota; | ||
1008 | int c; | ||
1009 | |||
1010 | /* Check if we have to add this peer due to a pending request */ | ||
1011 | if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mlp->requested_peers, | ||
1012 | key)) | ||
1013 | return GNUNET_OK; | ||
1014 | |||
1015 | mlpi = address->solver_information; | ||
1016 | if (NULL == mlpi) | ||
1017 | { | ||
1018 | fprintf (stderr, "%s %p\n", GNUNET_i2s (&address->peer), address); | ||
1019 | GNUNET_break (0); | ||
1020 | return GNUNET_OK; | ||
1021 | } | ||
1022 | |||
1023 | addr_net = address->properties.scope; | ||
1024 | for (addr_net_index = 0; addr_net_index < GNUNET_NT_COUNT; addr_net_index++) | ||
1025 | { | ||
1026 | if (mlp->pv.quota_index[addr_net_index] == addr_net) | ||
1027 | break; | ||
1028 | } | ||
1029 | |||
1030 | if (addr_net_index >= GNUNET_NT_COUNT) | ||
1031 | { | ||
1032 | GNUNET_break (0); | ||
1033 | return GNUNET_OK; | ||
1034 | } | ||
1035 | |||
1036 | max_quota = 0; | ||
1037 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
1038 | { | ||
1039 | if (mlp->pv.quota_out[c] > max_quota) | ||
1040 | max_quota = mlp->pv.quota_out[c]; | ||
1041 | if (mlp->pv.quota_in[c] > max_quota) | ||
1042 | max_quota = mlp->pv.quota_in[c]; | ||
1043 | } | ||
1044 | if (max_quota > mlp->pv.BIG_M) | ||
1045 | cur_bigm = (double) mlp->pv.BIG_M; | ||
1046 | else | ||
1047 | cur_bigm = max_quota; | ||
1048 | |||
1049 | |||
1050 | /* Get peer */ | ||
1051 | peer = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, key); | ||
1052 | GNUNET_assert (NULL != peer); | ||
1053 | if (peer->processed == GNUNET_NO) | ||
1054 | { | ||
1055 | /* Add peer dependent constraints */ | ||
1056 | /* Add c2) One address active per peer */ | ||
1057 | GNUNET_asprintf (&name, "c2_%s", GNUNET_i2s (&address->peer)); | ||
1058 | peer->r_c2 = mlp_create_problem_create_constraint (p, name, GLP_FX, 1.0, | ||
1059 | 1.0); | ||
1060 | GNUNET_free (name); | ||
1061 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1062 | { | ||
1063 | if (GNUNET_YES == mlp->opt_dbg_optimize_relativity) | ||
1064 | { | ||
1065 | /* Add c9) Relativity */ | ||
1066 | GNUNET_asprintf (&name, "c9_%s", GNUNET_i2s (&address->peer)); | ||
1067 | peer->r_c9 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, | ||
1068 | 0.0); | ||
1069 | GNUNET_free (name); | ||
1070 | /* c9) set coefficient */ | ||
1071 | mlp_create_problem_set_value (p, peer->r_c9, p->c_r, -peer->f, | ||
1072 | __LINE__); | ||
1073 | } | ||
1074 | } | ||
1075 | peer->processed = GNUNET_YES; | ||
1076 | } | ||
1077 | |||
1078 | /* Reset addresses' solver information */ | ||
1079 | mlpi->c_b = 0; | ||
1080 | mlpi->c_n = 0; | ||
1081 | mlpi->n = 0; | ||
1082 | mlpi->r_c1 = 0; | ||
1083 | mlpi->r_c3 = 0; | ||
1084 | |||
1085 | /* Add bandwidth column */ | ||
1086 | GNUNET_asprintf (&name, "b_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1087 | address->plugin, address); | ||
1088 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1089 | { | ||
1090 | mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, | ||
1091 | 0.0, 0.0); | ||
1092 | } | ||
1093 | else | ||
1094 | { | ||
1095 | /* Maximize for bandwidth assignment in feasibility testing */ | ||
1096 | mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, | ||
1097 | 0.0, 1.0); | ||
1098 | } | ||
1099 | GNUNET_free (name); | ||
1100 | |||
1101 | /* Add address active column */ | ||
1102 | GNUNET_asprintf (&name, "n_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1103 | address->plugin, address); | ||
1104 | mlpi->c_n = mlp_create_problem_create_column (p, name, GLP_IV, GLP_DB, 0.0, | ||
1105 | 1.0, 0.0); | ||
1106 | GNUNET_free (name); | ||
1107 | |||
1108 | /* Add address dependent constraints */ | ||
1109 | /* Add c1) bandwidth capping: b_t + (-M) * n_t <= 0 */ | ||
1110 | GNUNET_asprintf (&name, "c1_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1111 | address->plugin, address); | ||
1112 | mlpi->r_c1 = mlp_create_problem_create_constraint (p, name, GLP_UP, 0.0, 0.0); | ||
1113 | GNUNET_free (name); | ||
1114 | /* c1) set b = 1 coefficient */ | ||
1115 | mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_b, 1, __LINE__); | ||
1116 | /* c1) set n = - min (M, quota) coefficient */ | ||
1117 | cur_bigm = (double) mlp->pv.quota_out[addr_net_index]; | ||
1118 | if (cur_bigm > mlp->pv.BIG_M) | ||
1119 | cur_bigm = (double) mlp->pv.BIG_M; | ||
1120 | mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_n, -cur_bigm, __LINE__); | ||
1121 | |||
1122 | /* Add constraint c 3) minimum bandwidth | ||
1123 | * b_t + (-n_t * b_min) >= 0 | ||
1124 | * */ | ||
1125 | GNUNET_asprintf (&name, "c3_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1126 | address->plugin, address); | ||
1127 | mlpi->r_c3 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 0.0); | ||
1128 | GNUNET_free (name); | ||
1129 | |||
1130 | /* c3) set b = 1 coefficient */ | ||
1131 | mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_b, 1, __LINE__); | ||
1132 | /* c3) set n = -b_min coefficient */ | ||
1133 | mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_n, | ||
1134 | -((double ) mlp->pv.b_min), __LINE__); | ||
1135 | |||
1136 | |||
1137 | /* Set coefficient entries in invariant rows */ | ||
1138 | |||
1139 | /* Feasbility */ | ||
1140 | |||
1141 | /* c 4) minimum connections */ | ||
1142 | mlp_create_problem_set_value (p, p->r_c4, mlpi->c_n, 1, __LINE__); | ||
1143 | /* c 2) 1 address peer peer */ | ||
1144 | mlp_create_problem_set_value (p, peer->r_c2, mlpi->c_n, 1, __LINE__); | ||
1145 | /* c 10) obey network specific quotas | ||
1146 | * (1)*b_1 + ... + (1)*b_m <= quota_n | ||
1147 | */ | ||
1148 | mlp_create_problem_set_value (p, p->r_quota[addr_net_index], mlpi->c_b, 1, | ||
1149 | __LINE__); | ||
1150 | |||
1151 | /* Optimality */ | ||
1152 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1153 | { | ||
1154 | /* c 6) maximize diversity */ | ||
1155 | mlp_create_problem_set_value (p, p->r_c6, mlpi->c_n, 1, __LINE__); | ||
1156 | /* c 9) relativity */ | ||
1157 | if (GNUNET_YES == mlp->opt_dbg_optimize_relativity) | ||
1158 | mlp_create_problem_set_value (p, peer->r_c9, mlpi->c_b, 1, __LINE__); | ||
1159 | /* c 8) utility */ | ||
1160 | if (GNUNET_YES == mlp->opt_dbg_optimize_utility) | ||
1161 | mlp_create_problem_set_value (p, p->r_c8, mlpi->c_b, 1, __LINE__); | ||
1162 | /* c 7) Optimize quality */ | ||
1163 | /* For all quality metrics, set quality of this address */ | ||
1164 | if (GNUNET_YES == mlp->opt_dbg_optimize_quality) | ||
1165 | { | ||
1166 | mlp_create_problem_set_value (p, | ||
1167 | p->r_q[RQ_QUALITY_METRIC_DELAY], | ||
1168 | mlpi->c_b, | ||
1169 | address->norm_delay.norm, | ||
1170 | __LINE__); | ||
1171 | mlp_create_problem_set_value (p, | ||
1172 | p->r_q[RQ_QUALITY_METRIC_DISTANCE], | ||
1173 | mlpi->c_b, | ||
1174 | address->norm_distance.norm, | ||
1175 | __LINE__); | ||
1176 | } | ||
1177 | } | ||
1178 | |||
1179 | return GNUNET_OK; | ||
1180 | } | ||
1181 | |||
1182 | |||
1183 | /** | ||
1184 | * Create the invariant columns c4, c6, c10, c8, c7 | ||
1185 | */ | ||
1186 | static void | ||
1187 | mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct | ||
1188 | MLP_Problem *p) | ||
1189 | { | ||
1190 | int c; | ||
1191 | |||
1192 | /* Feasibility */ | ||
1193 | |||
1194 | /* Row for c4) minimum connection */ | ||
1195 | /* Number of minimum connections is min(|Peers|, n_min) */ | ||
1196 | p->r_c4 = mlp_create_problem_create_constraint (p, "c4", GLP_LO, | ||
1197 | (mlp->pv.n_min > | ||
1198 | p->num_peers) ? | ||
1199 | p->num_peers : mlp->pv.n_min, | ||
1200 | 0.0); | ||
1201 | |||
1202 | /* Rows for c 10) Enforce network quotas */ | ||
1203 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
1204 | { | ||
1205 | char *text; | ||
1206 | GNUNET_asprintf (&text, "c10_quota_ats_%s", | ||
1207 | GNUNET_NT_to_string (mlp->pv.quota_index[c])); | ||
1208 | p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 0.0, | ||
1209 | mlp->pv.quota_out[c]); | ||
1210 | GNUNET_free (text); | ||
1211 | } | ||
1212 | |||
1213 | /* Optimality */ | ||
1214 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1215 | { | ||
1216 | char *name; | ||
1217 | /* Add row for c6) Maximize for diversity */ | ||
1218 | if (GNUNET_YES == mlp->opt_dbg_optimize_diversity) | ||
1219 | { | ||
1220 | p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0, | ||
1221 | 0.0); | ||
1222 | /* Set c6 ) Setting -D */ | ||
1223 | mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__); | ||
1224 | } | ||
1225 | |||
1226 | /* Adding rows for c 8) Maximize utility */ | ||
1227 | if (GNUNET_YES == mlp->opt_dbg_optimize_utility) | ||
1228 | { | ||
1229 | p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0, | ||
1230 | 0.0); | ||
1231 | /* -u */ | ||
1232 | mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__); | ||
1233 | } | ||
1234 | |||
1235 | /* For all quality metrics: | ||
1236 | * c 7) Maximize quality, austerity */ | ||
1237 | if (GNUNET_YES == mlp->opt_dbg_optimize_quality) | ||
1238 | { | ||
1239 | for (c = 0; c < mlp->pv.m_q; c++) | ||
1240 | { | ||
1241 | GNUNET_asprintf (&name, | ||
1242 | "c7_q%i_%s", c, | ||
1243 | print_quality_type (c)); | ||
1244 | p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0, | ||
1245 | 0.0); | ||
1246 | GNUNET_free (name); | ||
1247 | mlp_create_problem_set_value (p, | ||
1248 | p->r_q[c], | ||
1249 | p->c_q[c], -1, __LINE__); | ||
1250 | } | ||
1251 | } | ||
1252 | } | ||
1253 | } | ||
1254 | |||
1255 | |||
1256 | /** | ||
1257 | * Create the invariant columns d, u, r, q0 ... qm | ||
1258 | */ | ||
1259 | static void | ||
1260 | mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct | ||
1261 | MLP_Problem *p) | ||
1262 | { | ||
1263 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1264 | { | ||
1265 | char *name; | ||
1266 | int c; | ||
1267 | |||
1268 | /* Diversity d column */ | ||
1269 | if (GNUNET_YES == mlp->opt_dbg_optimize_diversity) | ||
1270 | p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0, | ||
1271 | 0.0, mlp->pv.co_D); | ||
1272 | |||
1273 | /* Utilization u column */ | ||
1274 | if (GNUNET_YES == mlp->opt_dbg_optimize_utility) | ||
1275 | p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, | ||
1276 | 0.0, mlp->pv.co_U); | ||
1277 | |||
1278 | /* Relativity r column */ | ||
1279 | if (GNUNET_YES == mlp->opt_dbg_optimize_relativity) | ||
1280 | p->c_r = mlp_create_problem_create_column (p, "r", GLP_CV, GLP_LO, 0.0, | ||
1281 | 0.0, mlp->pv.co_R); | ||
1282 | |||
1283 | /* Quality metric columns */ | ||
1284 | if (GNUNET_YES == mlp->opt_dbg_optimize_quality) | ||
1285 | { | ||
1286 | for (c = 0; c < mlp->pv.m_q; c++) | ||
1287 | { | ||
1288 | GNUNET_asprintf (&name, "q_%u", c); | ||
1289 | p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, | ||
1290 | 0.0, 0.0, | ||
1291 | mlp->pv.co_Q[c]); | ||
1292 | GNUNET_free (name); | ||
1293 | } | ||
1294 | } | ||
1295 | } | ||
1296 | } | ||
1297 | |||
1298 | |||
1299 | /** | ||
1300 | * Create the MLP problem | ||
1301 | * | ||
1302 | * @param mlp the MLP handle | ||
1303 | * @return #GNUNET_OK or #GNUNET_SYSERR | ||
1304 | */ | ||
1305 | static int | ||
1306 | mlp_create_problem (struct GAS_MLP_Handle *mlp) | ||
1307 | { | ||
1308 | struct MLP_Problem *p = &mlp->p; | ||
1309 | int res = GNUNET_OK; | ||
1310 | |||
1311 | GNUNET_assert (p->prob == NULL); | ||
1312 | GNUNET_assert (p->ia == NULL); | ||
1313 | GNUNET_assert (p->ja == NULL); | ||
1314 | GNUNET_assert (p->ar == NULL); | ||
1315 | /* Reset MLP problem struct */ | ||
1316 | |||
1317 | /* create the glpk problem */ | ||
1318 | p->prob = glp_create_prob (); | ||
1319 | GNUNET_assert (NULL != p->prob); | ||
1320 | p->num_peers = mlp_create_problem_count_peers (mlp->requested_peers, | ||
1321 | mlp->env->addresses); | ||
1322 | p->num_addresses = mlp_create_problem_count_addresses (mlp->requested_peers, | ||
1323 | mlp->env->addresses); | ||
1324 | |||
1325 | /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 2 + 1 */ | ||
1326 | p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses | ||
1327 | + mlp->pv.m_q + p->num_peers + 2 + 1); | ||
1328 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1329 | "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality metrics == %u elements\n", | ||
1330 | p->num_peers, | ||
1331 | p->num_addresses, | ||
1332 | mlp->pv.m_q, | ||
1333 | p->num_elements); | ||
1334 | |||
1335 | /* Set a problem name */ | ||
1336 | glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution"); | ||
1337 | /* Set optimization direction to maximize */ | ||
1338 | glp_set_obj_dir (p->prob, GLP_MAX); | ||
1339 | |||
1340 | /* Create problem matrix */ | ||
1341 | /* last +1 caused by glpk index starting with one: [1..elements]*/ | ||
1342 | p->ci = 1; | ||
1343 | /* row index */ | ||
1344 | p->ia = GNUNET_malloc (p->num_elements * sizeof(int)); | ||
1345 | /* column index */ | ||
1346 | p->ja = GNUNET_malloc (p->num_elements * sizeof(int)); | ||
1347 | /* coefficient */ | ||
1348 | p->ar = GNUNET_malloc (p->num_elements * sizeof(double)); | ||
1349 | |||
1350 | if ((NULL == p->ia) || (NULL == p->ja) || (NULL == p->ar)) | ||
1351 | { | ||
1352 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ( | ||
1353 | "Problem size too large, cannot allocate memory!\n")); | ||
1354 | return GNUNET_SYSERR; | ||
1355 | } | ||
1356 | |||
1357 | /* Adding invariant columns */ | ||
1358 | mlp_create_problem_add_invariant_columns (mlp, p); | ||
1359 | |||
1360 | /* Adding address independent constraint rows */ | ||
1361 | mlp_create_problem_add_invariant_rows (mlp, p); | ||
1362 | |||
1363 | /* Adding address dependent columns constraint rows */ | ||
1364 | GNUNET_CONTAINER_multipeermap_iterate (mlp->env->addresses, | ||
1365 | & | ||
1366 | mlp_create_problem_add_address_information, | ||
1367 | mlp); | ||
1368 | |||
1369 | /* Load the matrix */ | ||
1370 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n"); | ||
1371 | glp_load_matrix (p->prob, (p->ci) - 1, p->ia, p->ja, p->ar); | ||
1372 | if (GNUNET_YES == mlp->opt_dbg_autoscale_problem) | ||
1373 | { | ||
1374 | glp_scale_prob (p->prob, GLP_SF_AUTO); | ||
1375 | } | ||
1376 | |||
1377 | return res; | ||
1378 | } | ||
1379 | |||
1380 | |||
1381 | /** | ||
1382 | * Solves the LP problem | ||
1383 | * | ||
1384 | * @param mlp the MLP Handle | ||
1385 | * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure | ||
1386 | */ | ||
1387 | static int | ||
1388 | mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp) | ||
1389 | { | ||
1390 | int res = 0; | ||
1391 | int res_status = 0; | ||
1392 | |||
1393 | res = glp_simplex (mlp->p.prob, &mlp->control_param_lp); | ||
1394 | if (0 == res) | ||
1395 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: %s\n", | ||
1396 | mlp_solve_to_string (res)); | ||
1397 | else | ||
1398 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem failed: %s\n", | ||
1399 | mlp_solve_to_string (res)); | ||
1400 | |||
1401 | /* Analyze problem status */ | ||
1402 | res_status = glp_get_status (mlp->p.prob); | ||
1403 | switch (res_status) | ||
1404 | { | ||
1405 | case GLP_OPT: /* solution is optimal */ | ||
1406 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1407 | "Solving LP problem: %s, %s\n", | ||
1408 | mlp_solve_to_string (res), | ||
1409 | mlp_status_to_string (res_status)); | ||
1410 | return GNUNET_OK; | ||
1411 | |||
1412 | default: | ||
1413 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1414 | "Solving LP problem failed: %s %s\n", | ||
1415 | mlp_solve_to_string (res), | ||
1416 | mlp_status_to_string (res_status)); | ||
1417 | return GNUNET_SYSERR; | ||
1418 | } | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | /** | ||
1423 | * Propagates the results when MLP problem was solved | ||
1424 | * | ||
1425 | * @param cls the MLP handle | ||
1426 | * @param key the peer identity | ||
1427 | * @param value the address | ||
1428 | * @return #GNUNET_OK to continue | ||
1429 | */ | ||
1430 | static int | ||
1431 | mlp_propagate_results (void *cls, | ||
1432 | const struct GNUNET_PeerIdentity *key, | ||
1433 | void *value) | ||
1434 | { | ||
1435 | struct GAS_MLP_Handle *mlp = cls; | ||
1436 | struct ATS_Address *address; | ||
1437 | struct MLP_information *mlpi; | ||
1438 | double mlp_bw_in = MLP_NaN; | ||
1439 | double mlp_bw_out = MLP_NaN; | ||
1440 | double mlp_use = MLP_NaN; | ||
1441 | |||
1442 | /* Check if we have to add this peer due to a pending request */ | ||
1443 | if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mlp->requested_peers, | ||
1444 | key)) | ||
1445 | { | ||
1446 | return GNUNET_OK; | ||
1447 | } | ||
1448 | address = value; | ||
1449 | GNUNET_assert (address->solver_information != NULL); | ||
1450 | mlpi = address->solver_information; | ||
1451 | |||
1452 | mlp_bw_in = glp_mip_col_val (mlp->p.prob, mlpi->c_b);/* FIXME */ | ||
1453 | if (mlp_bw_in > (double) UINT32_MAX) | ||
1454 | { | ||
1455 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1456 | "Overflow in assigned bandwidth, reducing ...\n"); | ||
1457 | mlp_bw_in = (double) UINT32_MAX; | ||
1458 | } | ||
1459 | mlp_bw_out = glp_mip_col_val (mlp->p.prob, mlpi->c_b); | ||
1460 | if (mlp_bw_out > (double) UINT32_MAX) | ||
1461 | { | ||
1462 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1463 | "Overflow in assigned bandwidth, reducing ...\n"); | ||
1464 | mlp_bw_out = (double) UINT32_MAX; | ||
1465 | } | ||
1466 | mlp_use = glp_mip_col_val (mlp->p.prob, mlpi->c_n); | ||
1467 | |||
1468 | /* | ||
1469 | * Debug: solution | ||
1470 | * LOG (GNUNET_ERROR_TYPE_INFO, "MLP result address: `%s' `%s' length %u session %u, mlp use %.3f\n", | ||
1471 | * GNUNET_i2s(&address->peer), address->plugin, | ||
1472 | * address->addr_len, address->session_id); | ||
1473 | */ | ||
1474 | |||
1475 | if (GLP_YES == mlp_use) | ||
1476 | { | ||
1477 | /* This address was selected by the solver to be used */ | ||
1478 | mlpi->n = GNUNET_YES; | ||
1479 | if (GNUNET_NO == address->active) | ||
1480 | { | ||
1481 | /* Address was not used before, enabling address */ | ||
1482 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : enabling address\n", | ||
1483 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1484 | address->active = GNUNET_YES; | ||
1485 | address->assigned_bw_in = mlp_bw_in; | ||
1486 | mlpi->b_in = mlp_bw_in; | ||
1487 | address->assigned_bw_out = mlp_bw_out; | ||
1488 | mlpi->b_out = mlp_bw_out; | ||
1489 | if ((NULL == mlp->exclude_peer) || (0 != GNUNET_memcmp (&address->peer, | ||
1490 | mlp->exclude_peer))) | ||
1491 | mlp->env->bandwidth_changed_cb (mlp->env->cls, address); | ||
1492 | return GNUNET_OK; | ||
1493 | } | ||
1494 | else if (GNUNET_YES == address->active) | ||
1495 | { | ||
1496 | /* Address was used before, check for bandwidth change */ | ||
1497 | if ((mlp_bw_out != address->assigned_bw_out) || | ||
1498 | (mlp_bw_in != address->assigned_bw_in)) | ||
1499 | { | ||
1500 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : bandwidth changed\n", | ||
1501 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1502 | address->assigned_bw_in = mlp_bw_in; | ||
1503 | mlpi->b_in = mlp_bw_in; | ||
1504 | address->assigned_bw_out = mlp_bw_out; | ||
1505 | mlpi->b_out = mlp_bw_out; | ||
1506 | if ((NULL == mlp->exclude_peer) || (0 != GNUNET_memcmp (&address->peer, | ||
1507 | mlp-> | ||
1508 | exclude_peer))) | ||
1509 | mlp->env->bandwidth_changed_cb (mlp->env->cls, address); | ||
1510 | return GNUNET_OK; | ||
1511 | } | ||
1512 | } | ||
1513 | else | ||
1514 | GNUNET_break (0); | ||
1515 | } | ||
1516 | else if (GLP_NO == mlp_use) | ||
1517 | { | ||
1518 | /* This address was selected by the solver to be not used */ | ||
1519 | mlpi->n = GNUNET_NO; | ||
1520 | if (GNUNET_NO == address->active) | ||
1521 | { | ||
1522 | /* Address was not used before, nothing to do */ | ||
1523 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : no change\n", | ||
1524 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1525 | return GNUNET_OK; | ||
1526 | } | ||
1527 | else if (GNUNET_YES == address->active) | ||
1528 | { | ||
1529 | /* Address was used before, disabling address */ | ||
1530 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : disabling address\n", | ||
1531 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1532 | address->active = GNUNET_NO; | ||
1533 | /* Set bandwidth to 0 */ | ||
1534 | address->assigned_bw_in = 0; | ||
1535 | mlpi->b_in = 0; | ||
1536 | address->assigned_bw_out = 0; | ||
1537 | mlpi->b_out = 0; | ||
1538 | return GNUNET_OK; | ||
1539 | } | ||
1540 | else | ||
1541 | GNUNET_break (0); | ||
1542 | } | ||
1543 | else | ||
1544 | GNUNET_break (0); | ||
1545 | |||
1546 | return GNUNET_OK; | ||
1547 | } | ||
1548 | |||
1549 | |||
1550 | static void | ||
1551 | notify (struct GAS_MLP_Handle *mlp, | ||
1552 | enum GAS_Solver_Operation op, | ||
1553 | enum GAS_Solver_Status stat, | ||
1554 | enum GAS_Solver_Additional_Information add) | ||
1555 | { | ||
1556 | mlp->env->info_cb (mlp->env->cls, | ||
1557 | op, | ||
1558 | stat, | ||
1559 | add); | ||
1560 | } | ||
1561 | |||
1562 | |||
1563 | static void | ||
1564 | mlp_branch_and_cut_cb (glp_tree *tree, void *info) | ||
1565 | { | ||
1566 | struct GAS_MLP_Handle *mlp = info; | ||
1567 | double mlp_obj = 0; | ||
1568 | |||
1569 | switch (glp_ios_reason (tree)) | ||
1570 | { | ||
1571 | case GLP_ISELECT: | ||
1572 | /* Do nothing here */ | ||
1573 | break; | ||
1574 | |||
1575 | case GLP_IPREPRO: | ||
1576 | /* Do nothing here */ | ||
1577 | break; | ||
1578 | |||
1579 | case GLP_IROWGEN: | ||
1580 | /* Do nothing here */ | ||
1581 | break; | ||
1582 | |||
1583 | case GLP_IHEUR: | ||
1584 | /* Do nothing here */ | ||
1585 | break; | ||
1586 | |||
1587 | case GLP_ICUTGEN: | ||
1588 | /* Do nothing here */ | ||
1589 | break; | ||
1590 | |||
1591 | case GLP_IBRANCH: | ||
1592 | /* Do nothing here */ | ||
1593 | break; | ||
1594 | |||
1595 | case GLP_IBINGO: | ||
1596 | /* A better solution was found */ | ||
1597 | mlp->ps.mlp_gap = glp_ios_mip_gap (tree); | ||
1598 | mlp_obj = glp_mip_obj_val (mlp->p.prob); | ||
1599 | mlp->ps.lp_mlp_gap = (abs (mlp_obj - mlp->ps.lp_objective_value)) / (abs ( | ||
1600 | mlp_obj) | ||
1601 | + | ||
1602 | DBL_EPSILON); | ||
1603 | |||
1604 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1605 | "Found better integer solution, current gaps: %.3f <= %.3f, %.3f <= %.3f\n", | ||
1606 | mlp->ps.mlp_gap, mlp->pv.mip_gap, | ||
1607 | mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap); | ||
1608 | |||
1609 | if (mlp->ps.mlp_gap <= mlp->pv.mip_gap) | ||
1610 | { | ||
1611 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1612 | "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n", | ||
1613 | mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap); | ||
1614 | glp_ios_terminate (tree); | ||
1615 | } | ||
1616 | |||
1617 | if (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap) | ||
1618 | { | ||
1619 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1620 | "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n", | ||
1621 | mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap); | ||
1622 | glp_ios_terminate (tree); | ||
1623 | } | ||
1624 | |||
1625 | break; | ||
1626 | |||
1627 | default: | ||
1628 | break; | ||
1629 | } | ||
1630 | // GNUNET_break (0); | ||
1631 | } | ||
1632 | |||
1633 | |||
1634 | /** | ||
1635 | * Solves the MLP problem | ||
1636 | * | ||
1637 | * @param solver the MLP Handle | ||
1638 | * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure | ||
1639 | */ | ||
1640 | static int | ||
1641 | GAS_mlp_solve_problem (void *solver) | ||
1642 | { | ||
1643 | struct GAS_MLP_Handle *mlp = solver; | ||
1644 | char *filename; | ||
1645 | int res_lp = 0; | ||
1646 | int mip_res = 0; | ||
1647 | int mip_status = 0; | ||
1648 | |||
1649 | struct GNUNET_TIME_Absolute start_total; | ||
1650 | struct GNUNET_TIME_Absolute start_cur_op; | ||
1651 | struct GNUNET_TIME_Relative dur_total; | ||
1652 | struct GNUNET_TIME_Relative dur_setup; | ||
1653 | struct GNUNET_TIME_Relative dur_lp; | ||
1654 | struct GNUNET_TIME_Relative dur_mlp; | ||
1655 | |||
1656 | GNUNET_assert (NULL != solver); | ||
1657 | dur_lp = GNUNET_TIME_UNIT_ZERO; | ||
1658 | |||
1659 | if (GNUNET_YES == mlp->stat_bulk_lock) | ||
1660 | { | ||
1661 | mlp->stat_bulk_requests++; | ||
1662 | return GNUNET_NO; | ||
1663 | } | ||
1664 | notify (mlp, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS, | ||
1665 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1666 | GAS_INFO_UPDATED); | ||
1667 | start_total = GNUNET_TIME_absolute_get (); | ||
1668 | |||
1669 | if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->requested_peers)) | ||
1670 | { | ||
1671 | notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE); | ||
1672 | return GNUNET_OK; /* No pending requests */ | ||
1673 | } | ||
1674 | if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->env->addresses)) | ||
1675 | { | ||
1676 | notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE); | ||
1677 | return GNUNET_OK; /* No addresses available */ | ||
1678 | } | ||
1679 | |||
1680 | if ((GNUNET_NO == mlp->stat_mlp_prob_changed) | ||
1681 | && (GNUNET_NO == mlp->stat_mlp_prob_updated)) | ||
1682 | { | ||
1683 | LOG (GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n"); | ||
1684 | notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE); | ||
1685 | return GNUNET_OK; | ||
1686 | } | ||
1687 | if (GNUNET_YES == mlp->stat_mlp_prob_changed) | ||
1688 | { | ||
1689 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n"); | ||
1690 | notify (mlp, GAS_OP_SOLVE_SETUP_START, GAS_STAT_SUCCESS, GAS_INFO_FULL); | ||
1691 | mlp_delete_problem (mlp); | ||
1692 | if (GNUNET_SYSERR == mlp_create_problem (mlp)) | ||
1693 | { | ||
1694 | notify (mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_FAIL, GAS_INFO_FULL); | ||
1695 | return GNUNET_SYSERR; | ||
1696 | } | ||
1697 | notify (mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_SUCCESS, GAS_INFO_FULL); | ||
1698 | if (GNUNET_NO == mlp->opt_dbg_intopt_presolver) | ||
1699 | { | ||
1700 | mlp->control_param_lp.presolve = GLP_YES; /* LP presolver, we need lp solution */ | ||
1701 | mlp->control_param_mlp.presolve = GNUNET_NO; /* No presolver, we have LP solution */ | ||
1702 | } | ||
1703 | else | ||
1704 | { | ||
1705 | mlp->control_param_lp.presolve = GNUNET_NO; /* LP presolver, we need lp solution */ | ||
1706 | mlp->control_param_mlp.presolve = GLP_YES; /* No presolver, we have LP solution */ | ||
1707 | dur_lp = GNUNET_TIME_UNIT_ZERO; | ||
1708 | } | ||
1709 | } | ||
1710 | else | ||
1711 | { | ||
1712 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n"); | ||
1713 | } | ||
1714 | |||
1715 | /* Reset solution info */ | ||
1716 | mlp->ps.lp_objective_value = 0.0; | ||
1717 | mlp->ps.mlp_gap = 1.0; | ||
1718 | mlp->ps.mlp_objective_value = 0.0; | ||
1719 | mlp->ps.lp_mlp_gap = 0.0; | ||
1720 | |||
1721 | dur_setup = GNUNET_TIME_absolute_get_duration (start_total); | ||
1722 | |||
1723 | /* Run LP solver */ | ||
1724 | if (GNUNET_NO == mlp->opt_dbg_intopt_presolver) | ||
1725 | { | ||
1726 | notify (mlp, GAS_OP_SOLVE_MLP_LP_START, GAS_STAT_SUCCESS, | ||
1727 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1728 | GAS_INFO_UPDATED); | ||
1729 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1730 | "Running LP solver %s\n", | ||
1731 | (GLP_YES == mlp->control_param_lp.presolve) ? "with presolver" : | ||
1732 | "without presolver"); | ||
1733 | start_cur_op = GNUNET_TIME_absolute_get (); | ||
1734 | |||
1735 | /* Solve LP */ | ||
1736 | /* Only for debugging: | ||
1737 | * Always use LP presolver: | ||
1738 | * mlp->control_param_lp.presolve = GLP_YES; */ | ||
1739 | res_lp = mlp_solve_lp_problem (mlp); | ||
1740 | if (GNUNET_OK == res_lp) | ||
1741 | { | ||
1742 | mlp->ps.lp_objective_value = glp_get_obj_val (mlp->p.prob); | ||
1743 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1744 | "LP solution was: %.3f\n", | ||
1745 | mlp->ps.lp_objective_value); | ||
1746 | } | ||
1747 | |||
1748 | dur_lp = GNUNET_TIME_absolute_get_duration (start_cur_op); | ||
1749 | notify (mlp, GAS_OP_SOLVE_MLP_LP_STOP, | ||
1750 | (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL, | ||
1751 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1752 | GAS_INFO_UPDATED); | ||
1753 | } | ||
1754 | |||
1755 | if (GNUNET_YES == mlp->opt_dbg_intopt_presolver) | ||
1756 | res_lp = GNUNET_OK; | ||
1757 | |||
1758 | /* Run MLP solver */ | ||
1759 | if ((GNUNET_OK == res_lp) || (GNUNET_YES == mlp->opt_dbg_intopt_presolver)) | ||
1760 | { | ||
1761 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n"); | ||
1762 | notify (mlp, GAS_OP_SOLVE_MLP_MLP_START, GAS_STAT_SUCCESS, | ||
1763 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1764 | GAS_INFO_UPDATED); | ||
1765 | start_cur_op = GNUNET_TIME_absolute_get (); | ||
1766 | |||
1767 | /* Solve MIP */ | ||
1768 | |||
1769 | /* Only for debugging, always use LP presolver */ | ||
1770 | if (GNUNET_YES == mlp->opt_dbg_intopt_presolver) | ||
1771 | mlp->control_param_mlp.presolve = GNUNET_YES; | ||
1772 | |||
1773 | mip_res = glp_intopt (mlp->p.prob, &mlp->control_param_mlp); | ||
1774 | switch (mip_res) | ||
1775 | { | ||
1776 | case 0: | ||
1777 | /* Successful */ | ||
1778 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1779 | "Solving MLP problem: %s\n", | ||
1780 | mlp_solve_to_string (mip_res)); | ||
1781 | break; | ||
1782 | |||
1783 | case GLP_ETMLIM: /* Time limit reached */ | ||
1784 | case GLP_EMIPGAP: /* MIP gap tolerance limit reached */ | ||
1785 | case GLP_ESTOP: /* Solver was instructed to stop*/ | ||
1786 | /* Semi-successful */ | ||
1787 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1788 | "Solving MLP problem solution was interupted: %s\n", | ||
1789 | mlp_solve_to_string (mip_res)); | ||
1790 | break; | ||
1791 | |||
1792 | case GLP_EBOUND: | ||
1793 | case GLP_EROOT: | ||
1794 | case GLP_ENOPFS: | ||
1795 | case GLP_ENODFS: | ||
1796 | case GLP_EFAIL: | ||
1797 | default: | ||
1798 | /* Fail */ | ||
1799 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1800 | "Solving MLP problem failed: %s\n", | ||
1801 | mlp_solve_to_string (mip_res)); | ||
1802 | break; | ||
1803 | } | ||
1804 | |||
1805 | /* Analyze problem status */ | ||
1806 | mip_status = glp_mip_status (mlp->p.prob); | ||
1807 | switch (mip_status) | ||
1808 | { | ||
1809 | case GLP_OPT: /* solution is optimal */ | ||
1810 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1811 | "Solution of MLP problem is optimal: %s, %s\n", | ||
1812 | mlp_solve_to_string (mip_res), | ||
1813 | mlp_status_to_string (mip_status)); | ||
1814 | mip_res = GNUNET_OK; | ||
1815 | break; | ||
1816 | |||
1817 | case GLP_FEAS: /* solution is feasible but not proven optimal */ | ||
1818 | |||
1819 | if ((mlp->ps.mlp_gap <= mlp->pv.mip_gap) || | ||
1820 | (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap)) | ||
1821 | { | ||
1822 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1823 | "Solution of MLP problem is feasible and solution within gap constraints: %s, %s\n", | ||
1824 | mlp_solve_to_string (mip_res), | ||
1825 | mlp_status_to_string (mip_status)); | ||
1826 | mip_res = GNUNET_OK; | ||
1827 | } | ||
1828 | else | ||
1829 | { | ||
1830 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1831 | "Solution of MLP problem is feasible but solution not within gap constraints: %s, %s\n", | ||
1832 | mlp_solve_to_string (mip_res), | ||
1833 | mlp_status_to_string (mip_status)); | ||
1834 | mip_res = GNUNET_SYSERR; | ||
1835 | } | ||
1836 | break; | ||
1837 | |||
1838 | case GLP_UNDEF: /* Solution undefined */ | ||
1839 | case GLP_NOFEAS: /* No feasible solution */ | ||
1840 | default: | ||
1841 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1842 | "Solving MLP problem failed: %s %s\n", | ||
1843 | mlp_solve_to_string (mip_res), | ||
1844 | mlp_status_to_string (mip_status)); | ||
1845 | mip_res = GNUNET_SYSERR; | ||
1846 | break; | ||
1847 | } | ||
1848 | |||
1849 | dur_mlp = GNUNET_TIME_absolute_get_duration (start_cur_op); | ||
1850 | dur_total = GNUNET_TIME_absolute_get_duration (start_total); | ||
1851 | |||
1852 | notify (mlp, GAS_OP_SOLVE_MLP_MLP_STOP, | ||
1853 | (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL, | ||
1854 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1855 | GAS_INFO_UPDATED); | ||
1856 | } | ||
1857 | else | ||
1858 | { | ||
1859 | /* Do not execute mip solver since lp solution is invalid */ | ||
1860 | dur_mlp = GNUNET_TIME_UNIT_ZERO; | ||
1861 | dur_total = GNUNET_TIME_absolute_get_duration (start_total); | ||
1862 | |||
1863 | notify (mlp, GAS_OP_SOLVE_MLP_MLP_STOP, GAS_STAT_FAIL, | ||
1864 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1865 | GAS_INFO_UPDATED); | ||
1866 | mip_res = GNUNET_SYSERR; | ||
1867 | } | ||
1868 | |||
1869 | /* Notify about end */ | ||
1870 | notify (mlp, GAS_OP_SOLVE_STOP, | ||
1871 | ((GNUNET_OK == mip_res) && (GNUNET_OK == mip_res)) ? | ||
1872 | GAS_STAT_SUCCESS : GAS_STAT_FAIL, | ||
1873 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1874 | GAS_INFO_UPDATED); | ||
1875 | |||
1876 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1877 | "Execution time for %s solve: (total/setup/lp/mlp) : %llu %llu %llu %llu\n", | ||
1878 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? "full" : "updated", | ||
1879 | (unsigned long long) dur_total.rel_value_us, | ||
1880 | (unsigned long long) dur_setup.rel_value_us, | ||
1881 | (unsigned long long) dur_lp.rel_value_us, | ||
1882 | (unsigned long long) dur_mlp.rel_value_us); | ||
1883 | |||
1884 | /* Save stats */ | ||
1885 | mlp->ps.lp_res = res_lp; | ||
1886 | mlp->ps.mip_res = mip_res; | ||
1887 | mlp->ps.lp_presolv = mlp->control_param_lp.presolve; | ||
1888 | mlp->ps.mip_presolv = mlp->control_param_mlp.presolve; | ||
1889 | mlp->ps.p_cols = glp_get_num_cols (mlp->p.prob); | ||
1890 | mlp->ps.p_rows = glp_get_num_rows (mlp->p.prob); | ||
1891 | mlp->ps.p_elements = mlp->p.num_elements; | ||
1892 | |||
1893 | /* Propagate result*/ | ||
1894 | notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START, | ||
1895 | (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : | ||
1896 | GAS_STAT_FAIL, | ||
1897 | GAS_INFO_NONE); | ||
1898 | if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res)) | ||
1899 | { | ||
1900 | GNUNET_CONTAINER_multipeermap_iterate (mlp->env->addresses, | ||
1901 | &mlp_propagate_results, mlp); | ||
1902 | } | ||
1903 | notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP, | ||
1904 | (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : | ||
1905 | GAS_STAT_FAIL, | ||
1906 | GAS_INFO_NONE); | ||
1907 | |||
1908 | struct GNUNET_TIME_Absolute time = GNUNET_TIME_absolute_get (); | ||
1909 | if ((GNUNET_YES == mlp->opt_dump_problem_all) || | ||
1910 | (mlp->opt_dump_problem_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK != | ||
1911 | mip_res)))) | ||
1912 | { | ||
1913 | /* Write problem to disk */ | ||
1914 | switch (mlp->opt_log_format) | ||
1915 | { | ||
1916 | case MLP_CPLEX: | ||
1917 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.cplex", | ||
1918 | mlp->p.num_peers, | ||
1919 | mlp->p.num_addresses, time.abs_value_us); | ||
1920 | glp_write_lp (mlp->p.prob, NULL, filename); | ||
1921 | break; | ||
1922 | |||
1923 | case MLP_GLPK: | ||
1924 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.glpk", | ||
1925 | mlp->p.num_peers, | ||
1926 | mlp->p.num_addresses, time.abs_value_us); | ||
1927 | glp_write_prob (mlp->p.prob, 0, filename); | ||
1928 | break; | ||
1929 | |||
1930 | case MLP_MPS: | ||
1931 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.mps", mlp->p.num_peers, | ||
1932 | mlp->p.num_addresses, time.abs_value_us); | ||
1933 | glp_write_mps (mlp->p.prob, GLP_MPS_FILE, NULL, filename); | ||
1934 | break; | ||
1935 | |||
1936 | default: | ||
1937 | break; | ||
1938 | } | ||
1939 | LOG (GNUNET_ERROR_TYPE_ERROR, "Dumped problem to file: `%s' \n", filename); | ||
1940 | GNUNET_free (filename); | ||
1941 | } | ||
1942 | if ((mlp->opt_dump_solution_all) || | ||
1943 | (mlp->opt_dump_solution_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK != | ||
1944 | mip_res)))) | ||
1945 | { | ||
1946 | /* Write solution to disk */ | ||
1947 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.sol", mlp->p.num_peers, | ||
1948 | mlp->p.num_addresses, time.abs_value_us); | ||
1949 | glp_print_mip (mlp->p.prob, filename); | ||
1950 | LOG (GNUNET_ERROR_TYPE_ERROR, "Dumped solution to file: `%s' \n", filename); | ||
1951 | GNUNET_free (filename); | ||
1952 | } | ||
1953 | |||
1954 | /* Reset change and update marker */ | ||
1955 | mlp->control_param_lp.presolve = GLP_NO; | ||
1956 | mlp->stat_mlp_prob_updated = GNUNET_NO; | ||
1957 | mlp->stat_mlp_prob_changed = GNUNET_NO; | ||
1958 | |||
1959 | if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res)) | ||
1960 | return GNUNET_OK; | ||
1961 | else | ||
1962 | return GNUNET_SYSERR; | ||
1963 | } | ||
1964 | |||
1965 | /** | ||
1966 | * Add a single address to the solve | ||
1967 | * | ||
1968 | * @param solver the solver Handle | ||
1969 | * @param address the address to add | ||
1970 | * @param network network type of this address | ||
1971 | */ | ||
1972 | static void | ||
1973 | GAS_mlp_address_add (void *solver, | ||
1974 | struct ATS_Address *address, | ||
1975 | uint32_t network) | ||
1976 | { | ||
1977 | struct GAS_MLP_Handle *mlp = solver; | ||
1978 | |||
1979 | if (GNUNET_NT_COUNT <= network) | ||
1980 | { | ||
1981 | GNUNET_break (0); | ||
1982 | return; | ||
1983 | } | ||
1984 | |||
1985 | if (NULL == address->solver_information) | ||
1986 | { | ||
1987 | address->solver_information = GNUNET_new (struct MLP_information); | ||
1988 | } | ||
1989 | else | ||
1990 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1991 | _ ("Adding address for peer `%s' multiple times\n"), | ||
1992 | GNUNET_i2s (&address->peer)); | ||
1993 | |||
1994 | /* Is this peer included in the problem? */ | ||
1995 | if (NULL == | ||
1996 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
1997 | &address->peer)) | ||
1998 | { | ||
1999 | /* FIXME: should this be an error? */ | ||
2000 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2001 | "Adding address for peer `%s' without address request\n", | ||
2002 | GNUNET_i2s (&address->peer)); | ||
2003 | return; | ||
2004 | } | ||
2005 | |||
2006 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2007 | "Adding address for peer `%s' with address request \n", | ||
2008 | GNUNET_i2s (&address->peer)); | ||
2009 | /* Problem size changed: new address for peer with pending request */ | ||
2010 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2011 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2012 | GAS_mlp_solve_problem (solver); | ||
2013 | } | ||
2014 | |||
2015 | |||
2016 | /** | ||
2017 | * Transport properties for this address have changed | ||
2018 | * | ||
2019 | * @param solver solver handle | ||
2020 | * @param address the address | ||
2021 | */ | ||
2022 | static void | ||
2023 | GAS_mlp_address_property_changed (void *solver, | ||
2024 | struct ATS_Address *address) | ||
2025 | { | ||
2026 | struct MLP_information *mlpi = address->solver_information; | ||
2027 | struct GAS_MLP_Handle *mlp = solver; | ||
2028 | |||
2029 | if (NULL == mlp->p.prob) | ||
2030 | return; /* There is no MLP problem to update yet */ | ||
2031 | |||
2032 | if (NULL == mlpi) | ||
2033 | { | ||
2034 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2035 | _ ("Updating address property for peer `%s' %p not added before\n"), | ||
2036 | GNUNET_i2s (&address->peer), | ||
2037 | address); | ||
2038 | GNUNET_break (0); | ||
2039 | return; | ||
2040 | } | ||
2041 | if (NULL == | ||
2042 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2043 | &address->peer)) | ||
2044 | { | ||
2045 | /* Peer is not requested, so no need to update problem */ | ||
2046 | return; | ||
2047 | } | ||
2048 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2049 | "Updating properties for peer `%s'\n", | ||
2050 | GNUNET_i2s (&address->peer)); | ||
2051 | |||
2052 | if (GNUNET_YES == mlp->opt_dbg_feasibility_only) | ||
2053 | return; | ||
2054 | |||
2055 | /* Update c7) [r_q[index]][c_b] = f_q * q_averaged[type_index] */ | ||
2056 | if ((GNUNET_YES == | ||
2057 | mlp_create_problem_update_value (&mlp->p, | ||
2058 | mlp->p.r_q[RQ_QUALITY_METRIC_DELAY], | ||
2059 | mlpi->c_b, | ||
2060 | address->norm_delay.norm, | ||
2061 | __LINE__)) || | ||
2062 | (GNUNET_YES == | ||
2063 | mlp_create_problem_update_value (&mlp->p, | ||
2064 | mlp->p.r_q[RQ_QUALITY_METRIC_DISTANCE], | ||
2065 | mlpi->c_b, | ||
2066 | address->norm_distance.norm, | ||
2067 | __LINE__))) | ||
2068 | { | ||
2069 | mlp->stat_mlp_prob_updated = GNUNET_YES; | ||
2070 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2071 | GAS_mlp_solve_problem (solver); | ||
2072 | } | ||
2073 | } | ||
2074 | |||
2075 | |||
2076 | /** | ||
2077 | * Find the active address in the set of addresses of a peer | ||
2078 | * @param cls destination | ||
2079 | * @param key peer id | ||
2080 | * @param value address | ||
2081 | * @return #GNUNET_OK | ||
2082 | */ | ||
2083 | static int | ||
2084 | mlp_get_preferred_address_it (void *cls, | ||
2085 | const struct GNUNET_PeerIdentity *key, | ||
2086 | void *value) | ||
2087 | { | ||
2088 | static int counter = 0; | ||
2089 | struct ATS_Address **aa = cls; | ||
2090 | struct ATS_Address *addr = value; | ||
2091 | struct MLP_information *mlpi = addr->solver_information; | ||
2092 | |||
2093 | if (mlpi == NULL) | ||
2094 | return GNUNET_YES; | ||
2095 | |||
2096 | /* | ||
2097 | * Debug output | ||
2098 | * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2099 | * "MLP [%u] Peer `%s' %s length %u session %u active %s mlp active %s\n", | ||
2100 | * counter, GNUNET_i2s (&addr->peer), addr->plugin, addr->addr_len, addr->session_id, | ||
2101 | * (GNUNET_YES == addr->active) ? "active" : "inactive", | ||
2102 | * (GNUNET_YES == mlpi->n) ? "active" : "inactive"); | ||
2103 | */ | ||
2104 | |||
2105 | if (GNUNET_YES == mlpi->n) | ||
2106 | { | ||
2107 | (*aa) = addr; | ||
2108 | (*aa)->assigned_bw_in = mlpi->b_in; | ||
2109 | (*aa)->assigned_bw_out = mlpi->b_out; | ||
2110 | return GNUNET_NO; | ||
2111 | } | ||
2112 | counter++; | ||
2113 | return GNUNET_YES; | ||
2114 | } | ||
2115 | |||
2116 | |||
2117 | static double | ||
2118 | get_peer_pref_value (struct GAS_MLP_Handle *mlp, | ||
2119 | const struct GNUNET_PeerIdentity *peer) | ||
2120 | { | ||
2121 | double res; | ||
2122 | const double *preferences; | ||
2123 | int c; | ||
2124 | |||
2125 | preferences = mlp->env->get_preferences (mlp->env->cls, peer); | ||
2126 | res = 0.0; | ||
2127 | for (c = 0; c < GNUNET_ATS_PREFERENCE_END; c++) | ||
2128 | { | ||
2129 | /* fprintf (stderr, "VALUE[%u] %s %.3f \n", | ||
2130 | * c, GNUNET_i2s (&cur->addr->peer), t[c]); */ | ||
2131 | res += preferences[c]; | ||
2132 | } | ||
2133 | |||
2134 | res /= GNUNET_ATS_PREFERENCE_END; | ||
2135 | res += 1.0; | ||
2136 | |||
2137 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2138 | "Peer preference for peer `%s' == %.2f\n", | ||
2139 | GNUNET_i2s (peer), res); | ||
2140 | |||
2141 | return res; | ||
2142 | } | ||
2143 | |||
2144 | |||
2145 | /** | ||
2146 | * Get the preferred address for a specific peer | ||
2147 | * | ||
2148 | * @param solver the MLP Handle | ||
2149 | * @param peer the peer | ||
2150 | */ | ||
2151 | static void | ||
2152 | GAS_mlp_get_preferred_address (void *solver, | ||
2153 | const struct GNUNET_PeerIdentity *peer) | ||
2154 | { | ||
2155 | struct GAS_MLP_Handle *mlp = solver; | ||
2156 | struct ATS_Peer *p; | ||
2157 | struct ATS_Address *res; | ||
2158 | |||
2159 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2160 | "Getting preferred address for `%s'\n", | ||
2161 | GNUNET_i2s (peer)); | ||
2162 | |||
2163 | /* Is this peer included in the problem? */ | ||
2164 | if (NULL == | ||
2165 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2166 | peer)) | ||
2167 | { | ||
2168 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2169 | "Adding peer `%s' to list of requested_peers with requests\n", | ||
2170 | GNUNET_i2s (peer)); | ||
2171 | |||
2172 | p = GNUNET_new (struct ATS_Peer); | ||
2173 | p->id = (*peer); | ||
2174 | p->f = get_peer_pref_value (mlp, peer); | ||
2175 | GNUNET_CONTAINER_multipeermap_put (mlp->requested_peers, | ||
2176 | peer, p, | ||
2177 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
2178 | |||
2179 | /* Added new peer, we have to rebuild problem before solving */ | ||
2180 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2181 | |||
2182 | if ((GNUNET_YES == mlp->opt_mlp_auto_solve) && | ||
2183 | (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains ( | ||
2184 | mlp->env->addresses, | ||
2185 | peer))) | ||
2186 | { | ||
2187 | mlp->exclude_peer = peer; | ||
2188 | GAS_mlp_solve_problem (mlp); | ||
2189 | mlp->exclude_peer = NULL; | ||
2190 | } | ||
2191 | } | ||
2192 | /* Get prefered address */ | ||
2193 | res = NULL; | ||
2194 | GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses, peer, | ||
2195 | &mlp_get_preferred_address_it, | ||
2196 | &res); | ||
2197 | if (NULL != res) | ||
2198 | mlp->env->bandwidth_changed_cb (mlp->env->cls, | ||
2199 | res); | ||
2200 | } | ||
2201 | |||
2202 | |||
2203 | /** | ||
2204 | * Deletes a single address in the MLP problem | ||
2205 | * | ||
2206 | * The MLP problem has to be recreated and the problem has to be resolved | ||
2207 | * | ||
2208 | * @param solver the MLP Handle | ||
2209 | * @param address the address to delete | ||
2210 | */ | ||
2211 | static void | ||
2212 | GAS_mlp_address_delete (void *solver, | ||
2213 | struct ATS_Address *address) | ||
2214 | { | ||
2215 | struct GAS_MLP_Handle *mlp = solver; | ||
2216 | struct MLP_information *mlpi; | ||
2217 | struct ATS_Address *res; | ||
2218 | int was_active; | ||
2219 | |||
2220 | mlpi = address->solver_information; | ||
2221 | if (NULL != mlpi) | ||
2222 | { | ||
2223 | /* Remove full address */ | ||
2224 | GNUNET_free (mlpi); | ||
2225 | address->solver_information = NULL; | ||
2226 | } | ||
2227 | was_active = address->active; | ||
2228 | address->active = GNUNET_NO; | ||
2229 | address->assigned_bw_in = 0; | ||
2230 | address->assigned_bw_out = 0; | ||
2231 | |||
2232 | /* Is this peer included in the problem? */ | ||
2233 | if (NULL == | ||
2234 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2235 | &address->peer)) | ||
2236 | { | ||
2237 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2238 | "Deleting address for peer `%s' without address request \n", | ||
2239 | GNUNET_i2s (&address->peer)); | ||
2240 | return; | ||
2241 | } | ||
2242 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2243 | "Deleting address for peer `%s' with address request \n", | ||
2244 | GNUNET_i2s (&address->peer)); | ||
2245 | |||
2246 | /* Problem size changed: new address for peer with pending request */ | ||
2247 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2248 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2249 | { | ||
2250 | GAS_mlp_solve_problem (solver); | ||
2251 | } | ||
2252 | if (GNUNET_YES == was_active) | ||
2253 | { | ||
2254 | GAS_mlp_get_preferred_address (solver, &address->peer); | ||
2255 | res = NULL; | ||
2256 | GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses, | ||
2257 | &address->peer, | ||
2258 | &mlp_get_preferred_address_it, | ||
2259 | &res); | ||
2260 | if (NULL == res) | ||
2261 | { | ||
2262 | /* No alternative address, disconnecting peer */ | ||
2263 | mlp->env->bandwidth_changed_cb (mlp->env->cls, address); | ||
2264 | } | ||
2265 | } | ||
2266 | } | ||
2267 | |||
2268 | |||
2269 | /** | ||
2270 | * Start a bulk operation | ||
2271 | * | ||
2272 | * @param solver the solver | ||
2273 | */ | ||
2274 | static void | ||
2275 | GAS_mlp_bulk_start (void *solver) | ||
2276 | { | ||
2277 | struct GAS_MLP_Handle *s = solver; | ||
2278 | |||
2279 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2280 | "Locking solver for bulk operation ...\n"); | ||
2281 | GNUNET_assert (NULL != solver); | ||
2282 | s->stat_bulk_lock++; | ||
2283 | } | ||
2284 | |||
2285 | |||
2286 | static void | ||
2287 | GAS_mlp_bulk_stop (void *solver) | ||
2288 | { | ||
2289 | struct GAS_MLP_Handle *s = solver; | ||
2290 | |||
2291 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2292 | "Unlocking solver from bulk operation ...\n"); | ||
2293 | GNUNET_assert (NULL != solver); | ||
2294 | |||
2295 | if (s->stat_bulk_lock < 1) | ||
2296 | { | ||
2297 | GNUNET_break (0); | ||
2298 | return; | ||
2299 | } | ||
2300 | s->stat_bulk_lock--; | ||
2301 | |||
2302 | if (0 < s->stat_bulk_requests) | ||
2303 | { | ||
2304 | GAS_mlp_solve_problem (solver); | ||
2305 | s->stat_bulk_requests = 0; | ||
2306 | } | ||
2307 | } | ||
2308 | |||
2309 | |||
2310 | |||
2311 | /** | ||
2312 | * Stop notifying about address and bandwidth changes for this peer | ||
2313 | * | ||
2314 | * @param solver the MLP handle | ||
2315 | * @param peer the peer | ||
2316 | */ | ||
2317 | static void | ||
2318 | GAS_mlp_stop_get_preferred_address (void *solver, | ||
2319 | const struct GNUNET_PeerIdentity *peer) | ||
2320 | { | ||
2321 | struct GAS_MLP_Handle *mlp = solver; | ||
2322 | struct ATS_Peer *p = NULL; | ||
2323 | |||
2324 | GNUNET_assert (NULL != solver); | ||
2325 | GNUNET_assert (NULL != peer); | ||
2326 | if (NULL != (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2327 | peer))) | ||
2328 | { | ||
2329 | GNUNET_assert (GNUNET_YES == | ||
2330 | GNUNET_CONTAINER_multipeermap_remove (mlp->requested_peers, | ||
2331 | peer, p)); | ||
2332 | GNUNET_free (p); | ||
2333 | |||
2334 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2335 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2336 | { | ||
2337 | GAS_mlp_solve_problem (solver); | ||
2338 | } | ||
2339 | } | ||
2340 | } | ||
2341 | |||
2342 | |||
2343 | /** | ||
2344 | * Changes the preferences for a peer in the MLP problem | ||
2345 | * | ||
2346 | * @param solver the MLP Handle | ||
2347 | * @param peer the peer | ||
2348 | * @param kind the kind to change the preference | ||
2349 | * @param pref_rel the relative score | ||
2350 | */ | ||
2351 | static void | ||
2352 | GAS_mlp_address_change_preference (void *solver, | ||
2353 | const struct GNUNET_PeerIdentity *peer, | ||
2354 | enum GNUNET_ATS_PreferenceKind kind, | ||
2355 | double pref_rel) | ||
2356 | { | ||
2357 | struct GAS_MLP_Handle *mlp = solver; | ||
2358 | struct ATS_Peer *p; | ||
2359 | |||
2360 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2361 | "Changing preference for address for peer `%s' to %.2f\n", | ||
2362 | GNUNET_i2s (peer), | ||
2363 | pref_rel); | ||
2364 | |||
2365 | GNUNET_STATISTICS_update (mlp->env->stats, | ||
2366 | "# LP address preference changes", 1, GNUNET_NO); | ||
2367 | /* Update the constraints with changed preferences */ | ||
2368 | |||
2369 | |||
2370 | |||
2371 | /* Update relativity constraint c9 */ | ||
2372 | if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2373 | peer))) | ||
2374 | { | ||
2375 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2376 | "Updating preference for unknown peer `%s'\n", | ||
2377 | GNUNET_i2s (peer)); | ||
2378 | return; | ||
2379 | } | ||
2380 | |||
2381 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
2382 | { | ||
2383 | p->f = get_peer_pref_value (mlp, peer); | ||
2384 | mlp_create_problem_update_value (&mlp->p, | ||
2385 | p->r_c9, | ||
2386 | mlp->p.c_r, | ||
2387 | -p->f, | ||
2388 | __LINE__); | ||
2389 | |||
2390 | /* Problem size changed: new address for peer with pending request */ | ||
2391 | mlp->stat_mlp_prob_updated = GNUNET_YES; | ||
2392 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2393 | GAS_mlp_solve_problem (solver); | ||
2394 | } | ||
2395 | } | ||
2396 | |||
2397 | |||
2398 | /** | ||
2399 | * Get application feedback for a peer | ||
2400 | * | ||
2401 | * @param solver the solver handle | ||
2402 | * @param application the application | ||
2403 | * @param peer the peer to change the preference for | ||
2404 | * @param scope the time interval for this feedback: [now - scope .. now] | ||
2405 | * @param kind the kind to change the preference | ||
2406 | * @param score the score | ||
2407 | */ | ||
2408 | static void | ||
2409 | GAS_mlp_address_preference_feedback (void *solver, | ||
2410 | struct GNUNET_SERVICE_Client *application, | ||
2411 | const struct GNUNET_PeerIdentity *peer, | ||
2412 | const struct GNUNET_TIME_Relative scope, | ||
2413 | enum GNUNET_ATS_PreferenceKind kind, | ||
2414 | double score) | ||
2415 | { | ||
2416 | struct GAS_PROPORTIONAL_Handle *s = solver; | ||
2417 | |||
2418 | GNUNET_assert (NULL != solver); | ||
2419 | GNUNET_assert (NULL != peer); | ||
2420 | GNUNET_assert (NULL != s); | ||
2421 | } | ||
2422 | |||
2423 | |||
2424 | static int | ||
2425 | mlp_free_peers (void *cls, | ||
2426 | const struct GNUNET_PeerIdentity *key, void *value) | ||
2427 | { | ||
2428 | struct GNUNET_CONTAINER_MultiPeerMap *map = cls; | ||
2429 | struct ATS_Peer *p = value; | ||
2430 | |||
2431 | GNUNET_assert (GNUNET_YES == | ||
2432 | GNUNET_CONTAINER_multipeermap_remove (map, key, value)); | ||
2433 | GNUNET_free (p); | ||
2434 | |||
2435 | return GNUNET_OK; | ||
2436 | } | ||
2437 | |||
2438 | |||
2439 | /** | ||
2440 | * Shutdown the MLP problem solving component | ||
2441 | * | ||
2442 | * @param cls the solver handle | ||
2443 | * @return NULL | ||
2444 | */ | ||
2445 | void * | ||
2446 | libgnunet_plugin_ats_mlp_done (void *cls) | ||
2447 | { | ||
2448 | struct GNUNET_ATS_SolverFunctions *sf = cls; | ||
2449 | struct GAS_MLP_Handle *mlp = sf->cls; | ||
2450 | |||
2451 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2452 | "Shutting down mlp solver\n"); | ||
2453 | mlp_delete_problem (mlp); | ||
2454 | GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers, | ||
2455 | &mlp_free_peers, | ||
2456 | mlp->requested_peers); | ||
2457 | GNUNET_CONTAINER_multipeermap_destroy (mlp->requested_peers); | ||
2458 | mlp->requested_peers = NULL; | ||
2459 | |||
2460 | /* Clean up GLPK environment */ | ||
2461 | glp_free_env (); | ||
2462 | GNUNET_free (mlp); | ||
2463 | |||
2464 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2465 | "Shutdown down of mlp solver complete\n"); | ||
2466 | return NULL; | ||
2467 | } | ||
2468 | |||
2469 | |||
2470 | void * | ||
2471 | libgnunet_plugin_ats_mlp_init (void *cls) | ||
2472 | { | ||
2473 | static struct GNUNET_ATS_SolverFunctions sf; | ||
2474 | struct GNUNET_ATS_PluginEnvironment *env = cls; | ||
2475 | struct GAS_MLP_Handle *mlp = GNUNET_new (struct GAS_MLP_Handle); | ||
2476 | float f_tmp; | ||
2477 | unsigned long long tmp; | ||
2478 | unsigned int b_min; | ||
2479 | unsigned int n_min; | ||
2480 | int c; | ||
2481 | char *outputformat; | ||
2482 | |||
2483 | struct GNUNET_TIME_Relative max_duration; | ||
2484 | long long unsigned int max_iterations; | ||
2485 | |||
2486 | /* Init GLPK environment */ | ||
2487 | int res = glp_init_env (); | ||
2488 | |||
2489 | switch (res) | ||
2490 | { | ||
2491 | case 0: | ||
2492 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n", | ||
2493 | "initialization successful"); | ||
2494 | break; | ||
2495 | |||
2496 | case 1: | ||
2497 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n", | ||
2498 | "environment is already initialized"); | ||
2499 | break; | ||
2500 | |||
2501 | case 2: | ||
2502 | LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n", | ||
2503 | "initialization failed (insufficient memory)"); | ||
2504 | GNUNET_free (mlp); | ||
2505 | return NULL; | ||
2506 | break; | ||
2507 | |||
2508 | case 3: | ||
2509 | LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n", | ||
2510 | "initialization failed (unsupported programming model)"); | ||
2511 | GNUNET_free (mlp); | ||
2512 | return NULL; | ||
2513 | break; | ||
2514 | |||
2515 | default: | ||
2516 | break; | ||
2517 | } | ||
2518 | |||
2519 | mlp->opt_dump_problem_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2520 | "ats", | ||
2521 | "MLP_DUMP_PROBLEM_ALL"); | ||
2522 | if (GNUNET_SYSERR == mlp->opt_dump_problem_all) | ||
2523 | mlp->opt_dump_problem_all = GNUNET_NO; | ||
2524 | |||
2525 | mlp->opt_dump_solution_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2526 | "ats", | ||
2527 | "MLP_DUMP_SOLUTION_ALL"); | ||
2528 | if (GNUNET_SYSERR == mlp->opt_dump_solution_all) | ||
2529 | mlp->opt_dump_solution_all = GNUNET_NO; | ||
2530 | |||
2531 | mlp->opt_dump_problem_on_fail = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2532 | env->cfg, | ||
2533 | "ats", | ||
2534 | "MLP_DUMP_PROBLEM_ON_FAIL"); | ||
2535 | if (GNUNET_SYSERR == mlp->opt_dump_problem_on_fail) | ||
2536 | mlp->opt_dump_problem_on_fail = GNUNET_NO; | ||
2537 | |||
2538 | mlp->opt_dump_solution_on_fail = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2539 | env->cfg, | ||
2540 | "ats", | ||
2541 | "MLP_DUMP_SOLUTION_ON_FAIL"); | ||
2542 | if (GNUNET_SYSERR == mlp->opt_dump_solution_on_fail) | ||
2543 | mlp->opt_dump_solution_on_fail = GNUNET_NO; | ||
2544 | |||
2545 | mlp->opt_dbg_glpk_verbose = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2546 | "ats", | ||
2547 | "MLP_DBG_GLPK_VERBOSE"); | ||
2548 | if (GNUNET_SYSERR == mlp->opt_dbg_glpk_verbose) | ||
2549 | mlp->opt_dbg_glpk_verbose = GNUNET_NO; | ||
2550 | |||
2551 | mlp->opt_dbg_feasibility_only = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2552 | env->cfg, | ||
2553 | "ats", | ||
2554 | "MLP_DBG_FEASIBILITY_ONLY"); | ||
2555 | if (GNUNET_SYSERR == mlp->opt_dbg_feasibility_only) | ||
2556 | mlp->opt_dbg_feasibility_only = GNUNET_NO; | ||
2557 | if (GNUNET_YES == mlp->opt_dbg_feasibility_only) | ||
2558 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2559 | "MLP solver is configured to check feasibility only!\n"); | ||
2560 | |||
2561 | mlp->opt_dbg_autoscale_problem = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2562 | env->cfg, | ||
2563 | "ats", | ||
2564 | "MLP_DBG_AUTOSCALE_PROBLEM"); | ||
2565 | if (GNUNET_SYSERR == mlp->opt_dbg_autoscale_problem) | ||
2566 | mlp->opt_dbg_autoscale_problem = GNUNET_NO; | ||
2567 | if (GNUNET_YES == mlp->opt_dbg_autoscale_problem) | ||
2568 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2569 | "MLP solver is configured automatically scale the problem!\n"); | ||
2570 | |||
2571 | mlp->opt_dbg_intopt_presolver = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2572 | env->cfg, | ||
2573 | "ats", | ||
2574 | "MLP_DBG_INTOPT_PRESOLVE"); | ||
2575 | if (GNUNET_SYSERR == mlp->opt_dbg_intopt_presolver) | ||
2576 | mlp->opt_dbg_intopt_presolver = GNUNET_NO; | ||
2577 | if (GNUNET_YES == mlp->opt_dbg_intopt_presolver) | ||
2578 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2579 | "MLP solver is configured use the mlp presolver\n"); | ||
2580 | |||
2581 | mlp->opt_dbg_optimize_diversity = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2582 | env->cfg, | ||
2583 | "ats", | ||
2584 | "MLP_DBG_OPTIMIZE_DIVERSITY"); | ||
2585 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_diversity) | ||
2586 | mlp->opt_dbg_optimize_diversity = GNUNET_YES; | ||
2587 | if (GNUNET_NO == mlp->opt_dbg_optimize_diversity) | ||
2588 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2589 | "MLP solver is not optimizing for diversity\n"); | ||
2590 | |||
2591 | mlp->opt_dbg_optimize_relativity = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2592 | env->cfg, | ||
2593 | "ats", | ||
2594 | "MLP_DBG_OPTIMIZE_RELATIVITY"); | ||
2595 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_relativity) | ||
2596 | mlp->opt_dbg_optimize_relativity = GNUNET_YES; | ||
2597 | if (GNUNET_NO == mlp->opt_dbg_optimize_relativity) | ||
2598 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2599 | "MLP solver is not optimizing for relativity\n"); | ||
2600 | |||
2601 | mlp->opt_dbg_optimize_quality = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2602 | env->cfg, | ||
2603 | "ats", | ||
2604 | "MLP_DBG_OPTIMIZE_QUALITY"); | ||
2605 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_quality) | ||
2606 | mlp->opt_dbg_optimize_quality = GNUNET_YES; | ||
2607 | if (GNUNET_NO == mlp->opt_dbg_optimize_quality) | ||
2608 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2609 | "MLP solver is not optimizing for quality\n"); | ||
2610 | |||
2611 | mlp->opt_dbg_optimize_utility = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2612 | env->cfg, | ||
2613 | "ats", | ||
2614 | "MLP_DBG_OPTIMIZE_UTILITY"); | ||
2615 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_utility) | ||
2616 | mlp->opt_dbg_optimize_utility = GNUNET_YES; | ||
2617 | if (GNUNET_NO == mlp->opt_dbg_optimize_utility) | ||
2618 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2619 | "MLP solver is not optimizing for utility\n"); | ||
2620 | |||
2621 | if ((GNUNET_NO == mlp->opt_dbg_optimize_utility) && | ||
2622 | (GNUNET_NO == mlp->opt_dbg_optimize_quality) && | ||
2623 | (GNUNET_NO == mlp->opt_dbg_optimize_relativity) && | ||
2624 | (GNUNET_NO == mlp->opt_dbg_optimize_utility) && | ||
2625 | (GNUNET_NO == mlp->opt_dbg_feasibility_only)) | ||
2626 | { | ||
2627 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2628 | _ ( | ||
2629 | "MLP solver is not optimizing for anything, changing to feasibility check\n")); | ||
2630 | mlp->opt_dbg_feasibility_only = GNUNET_YES; | ||
2631 | } | ||
2632 | |||
2633 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (env->cfg, | ||
2634 | "ats", | ||
2635 | "MLP_LOG_FORMAT", | ||
2636 | &outputformat)) | ||
2637 | mlp->opt_log_format = MLP_CPLEX; | ||
2638 | else | ||
2639 | { | ||
2640 | GNUNET_STRINGS_utf8_toupper (outputformat, outputformat); | ||
2641 | if (0 == strcmp (outputformat, "MPS")) | ||
2642 | { | ||
2643 | mlp->opt_log_format = MLP_MPS; | ||
2644 | } | ||
2645 | else if (0 == strcmp (outputformat, "CPLEX")) | ||
2646 | { | ||
2647 | mlp->opt_log_format = MLP_CPLEX; | ||
2648 | } | ||
2649 | else if (0 == strcmp (outputformat, "GLPK")) | ||
2650 | { | ||
2651 | mlp->opt_log_format = MLP_GLPK; | ||
2652 | } | ||
2653 | else | ||
2654 | { | ||
2655 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2656 | "Invalid log format `%s' in configuration, using CPLEX!\n", | ||
2657 | outputformat); | ||
2658 | mlp->opt_log_format = MLP_CPLEX; | ||
2659 | } | ||
2660 | GNUNET_free (outputformat); | ||
2661 | } | ||
2662 | |||
2663 | mlp->pv.BIG_M = (double) BIG_M_VALUE; | ||
2664 | |||
2665 | mlp->pv.mip_gap = (double) 0.0; | ||
2666 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2667 | "MLP_MAX_MIP_GAP", | ||
2668 | &f_tmp)) | ||
2669 | { | ||
2670 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2671 | { | ||
2672 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2673 | "MIP gap", f_tmp); | ||
2674 | } | ||
2675 | else | ||
2676 | { | ||
2677 | mlp->pv.mip_gap = f_tmp; | ||
2678 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2679 | "MIP gap", f_tmp); | ||
2680 | } | ||
2681 | } | ||
2682 | |||
2683 | mlp->pv.lp_mip_gap = (double) 0.0; | ||
2684 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2685 | "MLP_MAX_LP_MIP_GAP", | ||
2686 | &f_tmp)) | ||
2687 | { | ||
2688 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2689 | { | ||
2690 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2691 | "LP/MIP", f_tmp); | ||
2692 | } | ||
2693 | else | ||
2694 | { | ||
2695 | mlp->pv.lp_mip_gap = f_tmp; | ||
2696 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2697 | "LP/MIP", f_tmp); | ||
2698 | } | ||
2699 | } | ||
2700 | |||
2701 | /* Get timeout for iterations */ | ||
2702 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", | ||
2703 | "MLP_MAX_DURATION", | ||
2704 | &max_duration)) | ||
2705 | { | ||
2706 | max_duration = MLP_MAX_EXEC_DURATION; | ||
2707 | } | ||
2708 | |||
2709 | /* Get maximum number of iterations */ | ||
2710 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2711 | "MLP_MAX_ITERATIONS", | ||
2712 | &max_iterations)) | ||
2713 | { | ||
2714 | max_iterations = MLP_MAX_ITERATIONS; | ||
2715 | } | ||
2716 | |||
2717 | /* Get diversity coefficient from configuration */ | ||
2718 | mlp->pv.co_D = MLP_DEFAULT_D; | ||
2719 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2720 | "MLP_COEFFICIENT_D", | ||
2721 | &f_tmp)) | ||
2722 | { | ||
2723 | if ((f_tmp < 0.0)) | ||
2724 | { | ||
2725 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2726 | "MLP_COEFFICIENT_D", f_tmp); | ||
2727 | } | ||
2728 | else | ||
2729 | { | ||
2730 | mlp->pv.co_D = f_tmp; | ||
2731 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2732 | "MLP_COEFFICIENT_D", f_tmp); | ||
2733 | } | ||
2734 | } | ||
2735 | |||
2736 | /* Get relativity coefficient from configuration */ | ||
2737 | mlp->pv.co_R = MLP_DEFAULT_R; | ||
2738 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2739 | "MLP_COEFFICIENT_R", | ||
2740 | &f_tmp)) | ||
2741 | { | ||
2742 | if ((f_tmp < 0.0)) | ||
2743 | { | ||
2744 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2745 | "MLP_COEFFICIENT_R", f_tmp); | ||
2746 | } | ||
2747 | else | ||
2748 | { | ||
2749 | mlp->pv.co_R = f_tmp; | ||
2750 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2751 | "MLP_COEFFICIENT_R", f_tmp); | ||
2752 | } | ||
2753 | } | ||
2754 | |||
2755 | |||
2756 | /* Get utilization coefficient from configuration */ | ||
2757 | mlp->pv.co_U = MLP_DEFAULT_U; | ||
2758 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2759 | "MLP_COEFFICIENT_U", | ||
2760 | &f_tmp)) | ||
2761 | { | ||
2762 | if ((f_tmp < 0.0)) | ||
2763 | { | ||
2764 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2765 | "MLP_COEFFICIENT_U", f_tmp); | ||
2766 | } | ||
2767 | else | ||
2768 | { | ||
2769 | mlp->pv.co_U = f_tmp; | ||
2770 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2771 | "MLP_COEFFICIENT_U", f_tmp); | ||
2772 | } | ||
2773 | } | ||
2774 | |||
2775 | /* Get quality metric coefficients from configuration */ | ||
2776 | for (c = 0; c < RQ_QUALITY_METRIC_COUNT; c++) | ||
2777 | { | ||
2778 | /* initialize quality coefficients with default value 1.0 */ | ||
2779 | mlp->pv.co_Q[c] = MLP_DEFAULT_QUALITY; | ||
2780 | } | ||
2781 | |||
2782 | |||
2783 | if (GNUNET_OK == | ||
2784 | GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2785 | "MLP_COEFFICIENT_QUALITY_DELAY", | ||
2786 | &tmp)) | ||
2787 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = (double) tmp / 100; | ||
2788 | else | ||
2789 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = MLP_DEFAULT_QUALITY; | ||
2790 | |||
2791 | if (GNUNET_OK == | ||
2792 | GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2793 | "MLP_COEFFICIENT_QUALITY_DISTANCE", | ||
2794 | &tmp)) | ||
2795 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = (double) tmp / 100; | ||
2796 | else | ||
2797 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = MLP_DEFAULT_QUALITY; | ||
2798 | |||
2799 | /* Get minimum bandwidth per used address from configuration */ | ||
2800 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2801 | "MLP_MIN_BANDWIDTH", | ||
2802 | &tmp)) | ||
2803 | b_min = tmp; | ||
2804 | else | ||
2805 | { | ||
2806 | b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__); | ||
2807 | } | ||
2808 | |||
2809 | /* Get minimum number of connections from configuration */ | ||
2810 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2811 | "MLP_MIN_CONNECTIONS", | ||
2812 | &tmp)) | ||
2813 | n_min = tmp; | ||
2814 | else | ||
2815 | n_min = MLP_DEFAULT_MIN_CONNECTIONS; | ||
2816 | |||
2817 | /* Init network quotas */ | ||
2818 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
2819 | { | ||
2820 | mlp->pv.quota_index[c] = c; | ||
2821 | mlp->pv.quota_out[c] = env->out_quota[c]; | ||
2822 | mlp->pv.quota_in[c] = env->in_quota[c]; | ||
2823 | |||
2824 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2825 | "Quota for network `%s' (in/out) %llu/%llu\n", | ||
2826 | GNUNET_NT_to_string (c), | ||
2827 | mlp->pv.quota_out[c], | ||
2828 | mlp->pv.quota_in[c]); | ||
2829 | /* Check if defined quota could make problem unsolvable */ | ||
2830 | if ((n_min * b_min) > mlp->pv.quota_out[c]) | ||
2831 | { | ||
2832 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2833 | _ ( | ||
2834 | "Adjusting inconsistent outbound quota configuration for network `%s', is %llu must be at least %llu\n"), | ||
2835 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2836 | mlp->pv.quota_out[c], | ||
2837 | (n_min * b_min)); | ||
2838 | mlp->pv.quota_out[c] = (n_min * b_min); | ||
2839 | } | ||
2840 | if ((n_min * b_min) > mlp->pv.quota_in[c]) | ||
2841 | { | ||
2842 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2843 | _ ( | ||
2844 | "Adjusting inconsistent inbound quota configuration for network `%s', is %llu must be at least %llu\n"), | ||
2845 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2846 | mlp->pv.quota_in[c], | ||
2847 | (n_min * b_min)); | ||
2848 | mlp->pv.quota_in[c] = (n_min * b_min); | ||
2849 | } | ||
2850 | /* Check if bandwidth is too big to make problem solvable */ | ||
2851 | if (mlp->pv.BIG_M < mlp->pv.quota_out[c]) | ||
2852 | { | ||
2853 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2854 | _ ( | ||
2855 | "Adjusting outbound quota configuration for network `%s'from %llu to %.0f\n"), | ||
2856 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2857 | mlp->pv.quota_out[c], | ||
2858 | mlp->pv.BIG_M); | ||
2859 | mlp->pv.quota_out[c] = mlp->pv.BIG_M; | ||
2860 | } | ||
2861 | if (mlp->pv.BIG_M < mlp->pv.quota_in[c]) | ||
2862 | { | ||
2863 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2864 | _ ( | ||
2865 | "Adjusting inbound quota configuration for network `%s' from %llu to %.0f\n"), | ||
2866 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2867 | mlp->pv.quota_in[c], | ||
2868 | mlp->pv.BIG_M); | ||
2869 | mlp->pv.quota_in[c] = mlp->pv.BIG_M; | ||
2870 | } | ||
2871 | } | ||
2872 | mlp->env = env; | ||
2873 | sf.cls = mlp; | ||
2874 | sf.s_add = &GAS_mlp_address_add; | ||
2875 | sf.s_address_update_property = &GAS_mlp_address_property_changed; | ||
2876 | sf.s_get = &GAS_mlp_get_preferred_address; | ||
2877 | sf.s_get_stop = &GAS_mlp_stop_get_preferred_address; | ||
2878 | sf.s_pref = &GAS_mlp_address_change_preference; | ||
2879 | sf.s_feedback = &GAS_mlp_address_preference_feedback; | ||
2880 | sf.s_del = &GAS_mlp_address_delete; | ||
2881 | sf.s_bulk_start = &GAS_mlp_bulk_start; | ||
2882 | sf.s_bulk_stop = &GAS_mlp_bulk_stop; | ||
2883 | |||
2884 | /* Setting MLP Input variables */ | ||
2885 | mlp->pv.b_min = b_min; | ||
2886 | mlp->pv.n_min = n_min; | ||
2887 | mlp->pv.m_q = RQ_QUALITY_METRIC_COUNT; | ||
2888 | mlp->stat_mlp_prob_changed = GNUNET_NO; | ||
2889 | mlp->stat_mlp_prob_updated = GNUNET_NO; | ||
2890 | mlp->opt_mlp_auto_solve = GNUNET_YES; | ||
2891 | mlp->requested_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO); | ||
2892 | mlp->stat_bulk_requests = 0; | ||
2893 | mlp->stat_bulk_lock = 0; | ||
2894 | |||
2895 | /* Setup GLPK */ | ||
2896 | /* Redirect GLPK output to GNUnet logging */ | ||
2897 | glp_term_hook (&mlp_term_hook, (void *) mlp); | ||
2898 | |||
2899 | /* Init LP solving parameters */ | ||
2900 | glp_init_smcp (&mlp->control_param_lp); | ||
2901 | mlp->control_param_lp.msg_lev = GLP_MSG_OFF; | ||
2902 | if (GNUNET_YES == mlp->opt_dbg_glpk_verbose) | ||
2903 | mlp->control_param_lp.msg_lev = GLP_MSG_ALL; | ||
2904 | |||
2905 | mlp->control_param_lp.it_lim = max_iterations; | ||
2906 | mlp->control_param_lp.tm_lim = max_duration.rel_value_us / 1000LL; | ||
2907 | |||
2908 | /* Init MLP solving parameters */ | ||
2909 | glp_init_iocp (&mlp->control_param_mlp); | ||
2910 | /* Setting callback function */ | ||
2911 | mlp->control_param_mlp.cb_func = &mlp_branch_and_cut_cb; | ||
2912 | mlp->control_param_mlp.cb_info = mlp; | ||
2913 | mlp->control_param_mlp.msg_lev = GLP_MSG_OFF; | ||
2914 | mlp->control_param_mlp.mip_gap = mlp->pv.mip_gap; | ||
2915 | if (GNUNET_YES == mlp->opt_dbg_glpk_verbose) | ||
2916 | mlp->control_param_mlp.msg_lev = GLP_MSG_ALL; | ||
2917 | mlp->control_param_mlp.tm_lim = max_duration.rel_value_us / 1000LL; | ||
2918 | |||
2919 | LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n"); | ||
2920 | |||
2921 | return &sf; | ||
2922 | } | ||
2923 | |||
2924 | /* end of plugin_ats_mlp.c */ | ||
diff --git a/src/ats/plugin_ats_ril.c b/src/ats/plugin_ats_ril.c deleted file mode 100644 index 7be3cb0a1..000000000 --- a/src/ats/plugin_ats_ril.c +++ /dev/null | |||
@@ -1,2997 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014 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 | /** | ||
22 | * @file ats/plugin_ats_ril.c | ||
23 | * @brief ATS reinforcement learning solver | ||
24 | * @author Fabian Oehlmann | ||
25 | * @author Matthias Wachs | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include <float.h> | ||
29 | #include <math.h> | ||
30 | #include "gnunet_ats_plugin.h" | ||
31 | #include "gnunet-service-ats_addresses.h" | ||
32 | |||
33 | |||
34 | |||
35 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-ril", __VA_ARGS__) | ||
36 | |||
37 | #define RIL_MIN_BW (5 * ntohl ( \ | ||
38 | GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT. \ | ||
39 | value__)) | ||
40 | #define RIL_MAX_BW GNUNET_ATS_MaxBandwidth | ||
41 | |||
42 | #define RIL_ACTION_INVALID -1 | ||
43 | #define RIL_INTERVAL_EXPONENT 10 | ||
44 | #define RIL_UTILITY_DELAY_MAX 1000 | ||
45 | |||
46 | #define RIL_DEFAULT_STEP_TIME_MIN GNUNET_TIME_relative_multiply ( \ | ||
47 | GNUNET_TIME_UNIT_MILLISECONDS, 200) | ||
48 | #define RIL_DEFAULT_STEP_TIME_MAX GNUNET_TIME_relative_multiply ( \ | ||
49 | GNUNET_TIME_UNIT_MILLISECONDS, 2000) | ||
50 | #define RIL_DEFAULT_ALGORITHM RIL_ALGO_SARSA | ||
51 | #define RIL_DEFAULT_SELECT RIL_SELECT_SOFTMAX | ||
52 | #define RIL_DEFAULT_WELFARE RIL_WELFARE_NASH | ||
53 | #define RIL_DEFAULT_DISCOUNT_BETA 0.6 | ||
54 | #define RIL_DEFAULT_DISCOUNT_GAMMA 0.5 | ||
55 | #define RIL_DEFAULT_GRADIENT_STEP_SIZE 0.01 | ||
56 | #define RIL_DEFAULT_TRACE_DECAY 0.5 | ||
57 | #define RIL_DEFAULT_EXPLORE_RATIO 1 | ||
58 | #define RIL_DEFAULT_EXPLORE_DECAY 0.95 | ||
59 | #define RIL_DEFAULT_RBF_DIVISOR 50 | ||
60 | #define RIL_DEFAULT_TEMPERATURE 0.1 | ||
61 | #define RIL_DEFAULT_TEMPERATURE_DECAY 1 | ||
62 | |||
63 | #define RIL_INC_DEC_STEP_SIZE 1 | ||
64 | #define RIL_NOP_DECAY 0.5 | ||
65 | |||
66 | /** | ||
67 | * ATS reinforcement learning solver | ||
68 | * | ||
69 | * General description | ||
70 | */ | ||
71 | |||
72 | /** | ||
73 | * The actions, how an agent can manipulate the current assignment. I.e. how the bandwidth can be | ||
74 | * changed for the currently chosen address. Not depicted in the enum are the actions of switching | ||
75 | * to a particular address. The action of switching to address with index i is depicted by the | ||
76 | * number (RIL_ACTION_TYPE_NUM + i). | ||
77 | */ | ||
78 | enum RIL_Action_Type | ||
79 | { | ||
80 | RIL_ACTION_NOTHING = 0, | ||
81 | RIL_ACTION_BW_IN_DBL = -2, // TODO? Potentially add more actions | ||
82 | RIL_ACTION_BW_IN_HLV = -3, | ||
83 | RIL_ACTION_BW_IN_INC = 1, | ||
84 | RIL_ACTION_BW_IN_DEC = 2, | ||
85 | RIL_ACTION_BW_OUT_DBL = -4, | ||
86 | RIL_ACTION_BW_OUT_HLV = -5, | ||
87 | RIL_ACTION_BW_OUT_INC = 3, | ||
88 | RIL_ACTION_BW_OUT_DEC = 4, | ||
89 | RIL_ACTION_TYPE_NUM = 5 | ||
90 | }; | ||
91 | |||
92 | enum RIL_Algorithm | ||
93 | { | ||
94 | RIL_ALGO_SARSA = 0, | ||
95 | RIL_ALGO_Q = 1 | ||
96 | }; | ||
97 | |||
98 | enum RIL_Select | ||
99 | { | ||
100 | RIL_SELECT_SOFTMAX = 0, | ||
101 | RIL_SELECT_EGREEDY = 1 | ||
102 | }; | ||
103 | |||
104 | enum RIL_Welfare | ||
105 | { | ||
106 | RIL_WELFARE_NASH, | ||
107 | RIL_WELFARE_EGALITARIAN | ||
108 | }; | ||
109 | |||
110 | enum RIL_E_Modification | ||
111 | { | ||
112 | RIL_E_DECAY, | ||
113 | RIL_E_ZERO, | ||
114 | RIL_E_ACCUMULATE, | ||
115 | RIL_E_REPLACE | ||
116 | }; | ||
117 | |||
118 | /** | ||
119 | * Global learning parameters | ||
120 | */ | ||
121 | struct RIL_Learning_Parameters | ||
122 | { | ||
123 | /** | ||
124 | * The TD-algorithm to use | ||
125 | */ | ||
126 | enum RIL_Algorithm algorithm; | ||
127 | |||
128 | /** | ||
129 | * Gradient-descent step-size | ||
130 | */ | ||
131 | double alpha; | ||
132 | |||
133 | /** | ||
134 | * Learning discount variable in the TD-update for semi-MDPs | ||
135 | */ | ||
136 | double beta; | ||
137 | |||
138 | /** | ||
139 | * Learning discount factor in the TD-update for MDPs | ||
140 | */ | ||
141 | double gamma; | ||
142 | |||
143 | /** | ||
144 | * Trace-decay factor for eligibility traces | ||
145 | */ | ||
146 | double lambda; | ||
147 | |||
148 | /** | ||
149 | * Whether to accumulate or replace eligibility traces | ||
150 | */ | ||
151 | enum RIL_E_Modification eligibility_trace_mode; | ||
152 | |||
153 | /** | ||
154 | * Initial softmax action-selection temperature | ||
155 | */ | ||
156 | double temperature_init; | ||
157 | |||
158 | /** | ||
159 | * Softmax action-selection temperature | ||
160 | */ | ||
161 | double temperature; | ||
162 | |||
163 | /** | ||
164 | * Decay factor of the temperature value | ||
165 | */ | ||
166 | double temperature_decay; | ||
167 | |||
168 | /** | ||
169 | * Which measure of social welfare should be used | ||
170 | */ | ||
171 | enum RIL_Welfare social_welfare; | ||
172 | |||
173 | /** | ||
174 | * State space divisor | ||
175 | */ | ||
176 | unsigned long long rbf_divisor; | ||
177 | |||
178 | /** | ||
179 | * Action selection strategy; | ||
180 | */ | ||
181 | enum RIL_Select select; | ||
182 | |||
183 | /** | ||
184 | * Initial exploration ratio value | ||
185 | */ | ||
186 | double epsilon_init; | ||
187 | |||
188 | /** | ||
189 | * Ratio, with what probability an agent should explore in the e-greed policy | ||
190 | */ | ||
191 | double epsilon; | ||
192 | |||
193 | /** | ||
194 | * Decay factor of the explore ratio | ||
195 | */ | ||
196 | double epsilon_decay; | ||
197 | |||
198 | /** | ||
199 | * Minimal interval time between steps in milliseconds | ||
200 | */ | ||
201 | struct GNUNET_TIME_Relative step_time_min; | ||
202 | |||
203 | /** | ||
204 | * Maximum interval time between steps in milliseconds | ||
205 | */ | ||
206 | struct GNUNET_TIME_Relative step_time_max; | ||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * Wrapper for addresses to store them in agent's linked list | ||
211 | */ | ||
212 | struct RIL_Address_Wrapped | ||
213 | { | ||
214 | /** | ||
215 | * Next in DLL | ||
216 | */ | ||
217 | struct RIL_Address_Wrapped *next; | ||
218 | |||
219 | /** | ||
220 | * Previous in DLL | ||
221 | */ | ||
222 | struct RIL_Address_Wrapped *prev; | ||
223 | |||
224 | /** | ||
225 | * The address | ||
226 | */ | ||
227 | struct ATS_Address *address_naked; | ||
228 | }; | ||
229 | |||
230 | |||
231 | struct RIL_Peer_Agent | ||
232 | { | ||
233 | /** | ||
234 | * Next agent in solver's linked list | ||
235 | */ | ||
236 | struct RIL_Peer_Agent *next; | ||
237 | |||
238 | /** | ||
239 | * Previous agent in solver's linked list | ||
240 | */ | ||
241 | struct RIL_Peer_Agent *prev; | ||
242 | |||
243 | /** | ||
244 | * Environment handle | ||
245 | */ | ||
246 | struct GAS_RIL_Handle *envi; | ||
247 | |||
248 | /** | ||
249 | * Peer ID | ||
250 | */ | ||
251 | struct GNUNET_PeerIdentity peer; | ||
252 | |||
253 | /** | ||
254 | * Whether the agent is active or not | ||
255 | */ | ||
256 | int is_active; | ||
257 | |||
258 | /** | ||
259 | * Number of performed time-steps | ||
260 | */ | ||
261 | unsigned long long step_count; | ||
262 | |||
263 | /** | ||
264 | * Experience matrix W | ||
265 | */ | ||
266 | double **W; | ||
267 | |||
268 | /** | ||
269 | * Number of rows of W / Number of state-vector features | ||
270 | */ | ||
271 | unsigned int m; | ||
272 | |||
273 | /** | ||
274 | * Number of columns of W / Number of actions | ||
275 | */ | ||
276 | unsigned int n; | ||
277 | |||
278 | /** | ||
279 | * Last perceived state feature vector | ||
280 | */ | ||
281 | double *s_old; | ||
282 | |||
283 | /** | ||
284 | * Last chosen action | ||
285 | */ | ||
286 | int a_old; | ||
287 | |||
288 | /** | ||
289 | * Eligibility traces | ||
290 | */ | ||
291 | double **E; | ||
292 | |||
293 | /** | ||
294 | * Whether to reset the eligibility traces to 0 after a Q-exploration step | ||
295 | */ | ||
296 | int eligibility_reset; | ||
297 | |||
298 | /** | ||
299 | * Address in use | ||
300 | */ | ||
301 | struct ATS_Address *address_inuse; | ||
302 | |||
303 | /** | ||
304 | * Head of addresses DLL | ||
305 | */ | ||
306 | struct RIL_Address_Wrapped *addresses_head; | ||
307 | |||
308 | /** | ||
309 | * Tail of addresses DLL | ||
310 | */ | ||
311 | struct RIL_Address_Wrapped *addresses_tail; | ||
312 | |||
313 | /** | ||
314 | * Inbound bandwidth assigned by the agent | ||
315 | */ | ||
316 | uint32_t bw_in; | ||
317 | |||
318 | /** | ||
319 | * Outbound bandwidth assigned by the agent | ||
320 | */ | ||
321 | uint32_t bw_out; | ||
322 | |||
323 | /** | ||
324 | * Flag whether a suggestion has to be issued | ||
325 | */ | ||
326 | int suggestion_issue; | ||
327 | |||
328 | /** | ||
329 | * The address which has to be issued | ||
330 | */ | ||
331 | struct ATS_Address *suggestion_address; | ||
332 | |||
333 | /** | ||
334 | * The agent's last objective value | ||
335 | */ | ||
336 | double objective_old; | ||
337 | |||
338 | /** | ||
339 | * NOP bonus | ||
340 | */ | ||
341 | double nop_bonus; | ||
342 | }; | ||
343 | |||
344 | struct RIL_Scope | ||
345 | { | ||
346 | /** | ||
347 | * ATS network type | ||
348 | */ | ||
349 | enum GNUNET_NetworkType type; | ||
350 | |||
351 | /** | ||
352 | * Total available inbound bandwidth | ||
353 | */ | ||
354 | uint32_t bw_in_available; | ||
355 | |||
356 | /** | ||
357 | * Bandwidth inbound assigned in network after last step | ||
358 | */ | ||
359 | uint32_t bw_in_assigned; | ||
360 | |||
361 | /** | ||
362 | * Bandwidth inbound actually utilized in the network | ||
363 | */ | ||
364 | uint32_t bw_in_utilized; | ||
365 | |||
366 | /** | ||
367 | * Total available outbound bandwidth | ||
368 | */ | ||
369 | uint32_t bw_out_available; | ||
370 | |||
371 | /** | ||
372 | * Bandwidth outbound assigned in network after last step | ||
373 | */ | ||
374 | unsigned long long bw_out_assigned; | ||
375 | |||
376 | /** | ||
377 | * Bandwidth outbound actually utilized in the network | ||
378 | */ | ||
379 | unsigned long long bw_out_utilized; | ||
380 | |||
381 | /** | ||
382 | * Number of active agents in scope | ||
383 | */ | ||
384 | unsigned int active_agent_count; | ||
385 | |||
386 | /** | ||
387 | * The social welfare achieved in the scope | ||
388 | */ | ||
389 | double social_welfare; | ||
390 | }; | ||
391 | |||
392 | /** | ||
393 | * A handle for the reinforcement learning solver | ||
394 | */ | ||
395 | struct GAS_RIL_Handle | ||
396 | { | ||
397 | /** | ||
398 | * The solver-plugin environment of the solver-plugin API | ||
399 | */ | ||
400 | struct GNUNET_ATS_PluginEnvironment *env; | ||
401 | |||
402 | /** | ||
403 | * Number of performed steps | ||
404 | */ | ||
405 | unsigned long long step_count; | ||
406 | |||
407 | /** | ||
408 | * Timestamp for the last time-step | ||
409 | */ | ||
410 | struct GNUNET_TIME_Absolute step_time_last; | ||
411 | |||
412 | /** | ||
413 | * Task identifier of the next time-step to be executed | ||
414 | */ | ||
415 | struct GNUNET_SCHEDULER_Task *step_next_task_id; | ||
416 | |||
417 | /** | ||
418 | * Variable discount factor, dependent on time between steps | ||
419 | */ | ||
420 | double global_discount_variable; | ||
421 | |||
422 | /** | ||
423 | * Integrated variable discount factor, dependent on time between steps | ||
424 | */ | ||
425 | double global_discount_integrated; | ||
426 | |||
427 | /** | ||
428 | * Lock for bulk operations | ||
429 | */ | ||
430 | int bulk_lock; | ||
431 | |||
432 | /** | ||
433 | * Number of changes during a lock | ||
434 | */ | ||
435 | int bulk_changes; | ||
436 | |||
437 | /** | ||
438 | * Learning parameters | ||
439 | */ | ||
440 | struct RIL_Learning_Parameters parameters; | ||
441 | |||
442 | /** | ||
443 | * Array of networks with global assignment state | ||
444 | */ | ||
445 | struct RIL_Scope *network_entries; | ||
446 | |||
447 | /** | ||
448 | * Networks count | ||
449 | */ | ||
450 | unsigned int networks_count; | ||
451 | |||
452 | /** | ||
453 | * List of active peer-agents | ||
454 | */ | ||
455 | struct RIL_Peer_Agent *agents_head; | ||
456 | struct RIL_Peer_Agent *agents_tail; | ||
457 | |||
458 | /** | ||
459 | * Shutdown | ||
460 | */ | ||
461 | int done; | ||
462 | |||
463 | /** | ||
464 | * Simulate steps, i.e. schedule steps immediately | ||
465 | */ | ||
466 | unsigned long long simulate; | ||
467 | }; | ||
468 | |||
469 | /* | ||
470 | * "Private" functions | ||
471 | * --------------------------- | ||
472 | */ | ||
473 | |||
474 | /** | ||
475 | * Estimate the current action-value for state s and action a | ||
476 | * | ||
477 | * @param agent agent performing the estimation | ||
478 | * @param state s | ||
479 | * @param action a | ||
480 | * @return estimation value | ||
481 | */ | ||
482 | static double | ||
483 | agent_q (struct RIL_Peer_Agent *agent, | ||
484 | const double *state, | ||
485 | int action) | ||
486 | { | ||
487 | unsigned int i; | ||
488 | double result = 0.0; | ||
489 | |||
490 | for (i = 0; i < agent->m; i++) | ||
491 | result += state[i] * agent->W[action][i]; | ||
492 | |||
493 | /* prevent crashes if learning diverges */ | ||
494 | if (isnan (result)) | ||
495 | return isnan (result) * UINT32_MAX; | ||
496 | if (isinf (result)) | ||
497 | return isinf (result) * UINT32_MAX; | ||
498 | return result; | ||
499 | } | ||
500 | |||
501 | |||
502 | /** | ||
503 | * Get the index of the address in the agent's list. | ||
504 | * | ||
505 | * @param agent agent handle | ||
506 | * @param address address handle | ||
507 | * @return the index, starting with zero | ||
508 | */ | ||
509 | static int | ||
510 | agent_address_get_index (struct RIL_Peer_Agent *agent, struct | ||
511 | ATS_Address *address) | ||
512 | { | ||
513 | int i; | ||
514 | struct RIL_Address_Wrapped *cur; | ||
515 | |||
516 | i = -1; | ||
517 | for (cur = agent->addresses_head; NULL != cur; cur = cur->next) | ||
518 | { | ||
519 | i++; | ||
520 | if (cur->address_naked == address) | ||
521 | return i; | ||
522 | } | ||
523 | return i; | ||
524 | } | ||
525 | |||
526 | |||
527 | /** | ||
528 | * Gets the wrapped address from the agent's list | ||
529 | * | ||
530 | * @param agent agent handle | ||
531 | * @param address address handle | ||
532 | * @return wrapped address | ||
533 | */ | ||
534 | static struct RIL_Address_Wrapped * | ||
535 | agent_address_get_wrapped (struct RIL_Peer_Agent *agent, struct | ||
536 | ATS_Address *address) | ||
537 | { | ||
538 | struct RIL_Address_Wrapped *cur; | ||
539 | |||
540 | for (cur = agent->addresses_head; NULL != cur; cur = cur->next) | ||
541 | if (cur->address_naked == address) | ||
542 | return cur; | ||
543 | return NULL; | ||
544 | } | ||
545 | |||
546 | |||
547 | static int | ||
548 | agent_action_is_possible (struct RIL_Peer_Agent *agent, int action) | ||
549 | { | ||
550 | int address_index; | ||
551 | |||
552 | switch (action) | ||
553 | { | ||
554 | case RIL_ACTION_NOTHING: | ||
555 | return GNUNET_YES; | ||
556 | break; | ||
557 | |||
558 | case RIL_ACTION_BW_IN_INC: | ||
559 | case RIL_ACTION_BW_IN_DBL: | ||
560 | if (agent->bw_in >= RIL_MAX_BW) | ||
561 | return GNUNET_NO; | ||
562 | else | ||
563 | return GNUNET_YES; | ||
564 | break; | ||
565 | |||
566 | case RIL_ACTION_BW_IN_DEC: | ||
567 | case RIL_ACTION_BW_IN_HLV: | ||
568 | if (agent->bw_in <= 0) | ||
569 | return GNUNET_NO; | ||
570 | else | ||
571 | return GNUNET_YES; | ||
572 | break; | ||
573 | |||
574 | case RIL_ACTION_BW_OUT_INC: | ||
575 | case RIL_ACTION_BW_OUT_DBL: | ||
576 | if (agent->bw_out >= RIL_MAX_BW) | ||
577 | return GNUNET_NO; | ||
578 | else | ||
579 | return GNUNET_YES; | ||
580 | break; | ||
581 | |||
582 | case RIL_ACTION_BW_OUT_DEC: | ||
583 | case RIL_ACTION_BW_OUT_HLV: | ||
584 | if (agent->bw_out <= 0) | ||
585 | return GNUNET_NO; | ||
586 | else | ||
587 | return GNUNET_YES; | ||
588 | break; | ||
589 | |||
590 | default: | ||
591 | if ((action >= RIL_ACTION_TYPE_NUM) && (action < agent->n)) // switch address action | ||
592 | { | ||
593 | address_index = action - RIL_ACTION_TYPE_NUM; | ||
594 | |||
595 | GNUNET_assert (address_index >= 0); | ||
596 | GNUNET_assert ( | ||
597 | address_index <= agent_address_get_index (agent, | ||
598 | agent->addresses_tail-> | ||
599 | address_naked)); | ||
600 | |||
601 | if ((agent_address_get_index (agent, agent->address_inuse) == | ||
602 | address_index) || | ||
603 | agent->address_inuse->active) | ||
604 | return GNUNET_NO; | ||
605 | else | ||
606 | return GNUNET_YES; | ||
607 | break; | ||
608 | } | ||
609 | // error - action does not exist | ||
610 | GNUNET_assert (GNUNET_NO); | ||
611 | } | ||
612 | } | ||
613 | |||
614 | |||
615 | /** | ||
616 | * Gets the action, with the maximal estimated Q-value (i.e. the one currently estimated to bring the | ||
617 | * most reward in the future) | ||
618 | * | ||
619 | * @param agent agent performing the calculation | ||
620 | * @param state the state from which to take the action | ||
621 | * @return the action promising most future reward | ||
622 | */ | ||
623 | static int | ||
624 | agent_get_action_max (struct RIL_Peer_Agent *agent, double *state) | ||
625 | { | ||
626 | int i; | ||
627 | int max_i = RIL_ACTION_INVALID; | ||
628 | double cur_q; | ||
629 | double max_q = -DBL_MAX; | ||
630 | |||
631 | for (i = 0; i < agent->n; i++) | ||
632 | { | ||
633 | if (agent_action_is_possible (agent, i)) | ||
634 | { | ||
635 | cur_q = agent_q (agent, state, i); | ||
636 | if (cur_q > max_q) | ||
637 | { | ||
638 | max_q = cur_q; | ||
639 | max_i = i; | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | |||
644 | GNUNET_assert (RIL_ACTION_INVALID != max_i); | ||
645 | |||
646 | return max_i; | ||
647 | } | ||
648 | |||
649 | /** | ||
650 | * Chooses a random action from the set of possible ones | ||
651 | * | ||
652 | * @param agent the agent performing the action | ||
653 | * @return the action index | ||
654 | */ | ||
655 | static int | ||
656 | agent_get_action_random (struct RIL_Peer_Agent *agent) | ||
657 | { | ||
658 | int i; | ||
659 | int is_possible[agent->n]; | ||
660 | int sum = 0; | ||
661 | int r; | ||
662 | |||
663 | for (i = 0; i < agent->n; i++) | ||
664 | { | ||
665 | if (agent_action_is_possible (agent, i)) | ||
666 | { | ||
667 | is_possible[i] = GNUNET_YES; | ||
668 | sum++; | ||
669 | } | ||
670 | else | ||
671 | { | ||
672 | is_possible[i] = GNUNET_NO; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, sum); | ||
677 | |||
678 | sum = -1; | ||
679 | for (i = 0; i < agent->n; i++) | ||
680 | { | ||
681 | if (is_possible[i]) | ||
682 | { | ||
683 | sum++; | ||
684 | if (sum == r) | ||
685 | return i; | ||
686 | } | ||
687 | } | ||
688 | |||
689 | GNUNET_assert (GNUNET_NO); | ||
690 | return RIL_ACTION_INVALID; | ||
691 | } | ||
692 | |||
693 | |||
694 | /** | ||
695 | * Updates the weights (i.e. coefficients) of the weight vector in matrix W for action a | ||
696 | * | ||
697 | * @param agent the agent performing the update | ||
698 | * @param reward the reward received for the last action | ||
699 | * @param s_next the new state, the last step got the agent into | ||
700 | * @param a_prime the new | ||
701 | */ | ||
702 | static void | ||
703 | agent_update (struct RIL_Peer_Agent *agent, double reward, double *s_next, int | ||
704 | a_prime) | ||
705 | { | ||
706 | int i; | ||
707 | int k; | ||
708 | double delta; | ||
709 | double **theta = agent->W; | ||
710 | |||
711 | delta = agent->envi->global_discount_integrated * reward; // reward | ||
712 | delta += agent->envi->global_discount_variable * agent_q (agent, s_next, | ||
713 | a_prime); // discounted future value | ||
714 | delta -= agent_q (agent, agent->s_old, agent->a_old); // one step | ||
715 | |||
716 | // LOG(GNUNET_ERROR_TYPE_INFO, "update() Step# %llu Q(s,a): %f a: %f r: %f y: %f Q(s+1,a+1) = %f delta: %f\n", | ||
717 | // agent->step_count, | ||
718 | // agent_q (agent, agent->s_old, agent->a_old), | ||
719 | // agent->envi->parameters.alpha, | ||
720 | // reward, | ||
721 | // agent->envi->global_discount_variable, | ||
722 | // agent_q (agent, s_next, a_prime), | ||
723 | // delta); | ||
724 | |||
725 | for (k = 0; k < agent->n; k++) | ||
726 | { | ||
727 | for (i = 0; i < agent->m; i++) | ||
728 | { | ||
729 | // LOG(GNUNET_ERROR_TYPE_INFO, "alpha = %f delta = %f e[%d] = %f\n", | ||
730 | // agent->envi->parameters.alpha, | ||
731 | // delta, | ||
732 | // i, | ||
733 | // agent->e[i]); | ||
734 | theta[k][i] += agent->envi->parameters.alpha * delta * agent->E[k][i]; | ||
735 | } | ||
736 | } | ||
737 | } | ||
738 | |||
739 | |||
740 | /** | ||
741 | * Changes the eligibility trace vector e in various manners: | ||
742 | * #RIL_E_ACCUMULATE - adds @a feature to each component as in accumulating eligibility traces | ||
743 | * #RIL_E_REPLACE - resets each component to @a feature as in replacing traces | ||
744 | * #RIL_E_DECAY - multiplies e with discount factor and lambda as in the update rule | ||
745 | * #RIL_E_ZERO - sets e to 0 as in Watkin's Q-learning algorithm when exploring and when initializing | ||
746 | * | ||
747 | * @param agent the agent handle | ||
748 | * @param mod the kind of modification | ||
749 | * @param feature the feature vector | ||
750 | * @param action the action to take | ||
751 | */ | ||
752 | static void | ||
753 | agent_modify_eligibility (struct RIL_Peer_Agent *agent, | ||
754 | enum RIL_E_Modification mod, | ||
755 | double *feature, | ||
756 | int action) | ||
757 | { | ||
758 | int i; | ||
759 | int k; | ||
760 | |||
761 | for (i = 0; i < agent->m; i++) | ||
762 | { | ||
763 | switch (mod) | ||
764 | { | ||
765 | case RIL_E_ACCUMULATE: | ||
766 | agent->E[action][i] += feature[i]; | ||
767 | break; | ||
768 | |||
769 | case RIL_E_REPLACE: | ||
770 | agent->E[action][i] = agent->E[action][i] > feature[i] ? | ||
771 | agent->E[action][i] : feature[i]; | ||
772 | break; | ||
773 | |||
774 | case RIL_E_DECAY: | ||
775 | for (k = 0; k < agent->n; k++) | ||
776 | { | ||
777 | agent->E[k][i] *= agent->envi->global_discount_variable | ||
778 | * agent->envi->parameters.lambda; | ||
779 | } | ||
780 | break; | ||
781 | |||
782 | case RIL_E_ZERO: | ||
783 | for (k = 0; k < agent->n; k++) | ||
784 | { | ||
785 | agent->E[k][i] = 0; | ||
786 | } | ||
787 | break; | ||
788 | } | ||
789 | } | ||
790 | } | ||
791 | |||
792 | /** | ||
793 | * Informs the environment about the status of the solver | ||
794 | * | ||
795 | * @param solver | ||
796 | * @param op | ||
797 | * @param stat | ||
798 | */ | ||
799 | static void | ||
800 | ril_inform (struct GAS_RIL_Handle *solver, | ||
801 | enum GAS_Solver_Operation op, | ||
802 | enum GAS_Solver_Status stat) | ||
803 | { | ||
804 | solver->env->info_cb (solver->env->cls, | ||
805 | op, | ||
806 | stat, | ||
807 | GAS_INFO_NONE); | ||
808 | } | ||
809 | |||
810 | /** | ||
811 | * Calculates the maximum bandwidth an agent can assign in a network scope | ||
812 | * | ||
813 | * @param net | ||
814 | */ | ||
815 | static unsigned long long | ||
816 | ril_get_max_bw (struct RIL_Scope *net) | ||
817 | { | ||
818 | return GNUNET_MIN (2 * GNUNET_MAX (net->bw_in_available, | ||
819 | net->bw_out_available), | ||
820 | GNUNET_ATS_MaxBandwidth); | ||
821 | } | ||
822 | |||
823 | /** | ||
824 | * Changes the active assignment suggestion of the handler and invokes the bw_changed callback to | ||
825 | * notify ATS of its new decision | ||
826 | * | ||
827 | * @param solver solver handle | ||
828 | * @param agent agent handle | ||
829 | * @param new_address the address which is to be used | ||
830 | * @param new_bw_in the new amount of inbound bandwidth set for this address | ||
831 | * @param new_bw_out the new amount of outbound bandwidth set for this address | ||
832 | * @param silent disables invocation of the bw_changed callback, if #GNUNET_YES | ||
833 | */ | ||
834 | static void | ||
835 | envi_set_active_suggestion (struct GAS_RIL_Handle *solver, | ||
836 | struct RIL_Peer_Agent *agent, | ||
837 | struct ATS_Address *new_address, | ||
838 | unsigned long long new_bw_in, | ||
839 | unsigned long long new_bw_out, | ||
840 | int silent) | ||
841 | { | ||
842 | int notify = GNUNET_NO; | ||
843 | |||
844 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
845 | " set_active_suggestion() for peer '%s'\n", | ||
846 | GNUNET_i2s (&agent->peer)); | ||
847 | |||
848 | // address change | ||
849 | if (agent->address_inuse != new_address) | ||
850 | { | ||
851 | if (NULL != agent->address_inuse) | ||
852 | { | ||
853 | agent->address_inuse->active = GNUNET_NO; | ||
854 | agent->address_inuse->assigned_bw_in = 0; | ||
855 | agent->address_inuse->assigned_bw_out = 0; | ||
856 | } | ||
857 | if (NULL != new_address) | ||
858 | { | ||
859 | LOG (GNUNET_ERROR_TYPE_DEBUG, " set address active: %s\n", | ||
860 | agent->is_active ? "yes" : "no"); | ||
861 | new_address->active = agent->is_active; | ||
862 | new_address->assigned_bw_in = agent->bw_in; | ||
863 | new_address->assigned_bw_out = agent->bw_out; | ||
864 | } | ||
865 | notify |= GNUNET_YES; | ||
866 | } | ||
867 | |||
868 | if (new_address) | ||
869 | { | ||
870 | // activity change | ||
871 | if (new_address->active != agent->is_active) | ||
872 | { | ||
873 | new_address->active = agent->is_active; | ||
874 | notify |= GNUNET_YES; | ||
875 | } | ||
876 | |||
877 | // bw change | ||
878 | if (agent->bw_in != new_bw_in) | ||
879 | { | ||
880 | agent->bw_in = new_bw_in; | ||
881 | new_address->assigned_bw_in = new_bw_in; | ||
882 | notify |= GNUNET_YES; | ||
883 | } | ||
884 | if (agent->bw_out != new_bw_out) | ||
885 | { | ||
886 | agent->bw_out = new_bw_out; | ||
887 | new_address->assigned_bw_out = new_bw_out; | ||
888 | notify |= GNUNET_YES; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | if (notify && agent->is_active && (GNUNET_NO == silent)) | ||
893 | { | ||
894 | if (new_address) | ||
895 | { | ||
896 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
897 | " envi_set_active_suggestion() notify\n"); | ||
898 | agent->suggestion_issue = GNUNET_YES; | ||
899 | agent->suggestion_address = new_address; | ||
900 | } | ||
901 | else if (agent->address_inuse) | ||
902 | { | ||
903 | /* disconnect case, no new address */ | ||
904 | GNUNET_assert (0 == agent->address_inuse->assigned_bw_in); | ||
905 | GNUNET_assert (0 == agent->address_inuse->assigned_bw_out); | ||
906 | agent->bw_in = 0; | ||
907 | agent->bw_out = 0; | ||
908 | |||
909 | agent->suggestion_issue = GNUNET_YES; | ||
910 | agent->suggestion_address = agent->address_inuse; | ||
911 | } | ||
912 | } | ||
913 | agent->address_inuse = new_address; | ||
914 | } | ||
915 | |||
916 | |||
917 | /** | ||
918 | * Allocates a state vector and fills it with the features present | ||
919 | * @param solver the solver handle | ||
920 | * @param agent the agent handle | ||
921 | * @return pointer to the state vector | ||
922 | */ | ||
923 | static double * | ||
924 | envi_get_state (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent) | ||
925 | { | ||
926 | double *state; | ||
927 | double y[2]; | ||
928 | double x[2]; | ||
929 | double d[2]; | ||
930 | double sigma; | ||
931 | double f; | ||
932 | int m; | ||
933 | int i; | ||
934 | int k; | ||
935 | unsigned long long max_bw; | ||
936 | |||
937 | state = GNUNET_malloc (sizeof(double) * agent->m); | ||
938 | |||
939 | max_bw = ril_get_max_bw ((struct | ||
940 | RIL_Scope *) agent->address_inuse-> | ||
941 | solver_information); | ||
942 | |||
943 | y[0] = (double) agent->bw_out; | ||
944 | y[1] = (double) agent->bw_in; | ||
945 | |||
946 | m = agent_address_get_index (agent, agent->address_inuse) | ||
947 | * (solver->parameters.rbf_divisor + 1) * (solver->parameters.rbf_divisor | ||
948 | + 1); | ||
949 | for (i = 0; i <= solver->parameters.rbf_divisor; i++) | ||
950 | { | ||
951 | for (k = 0; k <= solver->parameters.rbf_divisor; k++) | ||
952 | { | ||
953 | x[0] = (double) i * (double) max_bw | ||
954 | / (double) solver->parameters.rbf_divisor; | ||
955 | x[1] = (double) k * (double) max_bw | ||
956 | / (double) solver->parameters.rbf_divisor; | ||
957 | d[0] = x[0] - y[0]; | ||
958 | d[1] = x[1] - y[1]; | ||
959 | sigma = (((double) max_bw / ((double) solver->parameters.rbf_divisor | ||
960 | + 1)) * 0.5); | ||
961 | f = exp (-((d[0] * d[0] + d[1] * d[1]) / (2 * sigma * sigma))); | ||
962 | state[m++] = f; | ||
963 | } | ||
964 | } | ||
965 | |||
966 | return state; | ||
967 | } | ||
968 | |||
969 | |||
970 | /** | ||
971 | * Returns the utility value of the connection an agent manages | ||
972 | * | ||
973 | * @param agent the agent in question | ||
974 | * @return the utility value | ||
975 | */ | ||
976 | static double | ||
977 | agent_get_utility (struct RIL_Peer_Agent *agent) | ||
978 | { | ||
979 | const double *preferences; | ||
980 | double delay_atsi; | ||
981 | double delay_norm; | ||
982 | double pref_match; | ||
983 | |||
984 | preferences = agent->envi->env->get_preferences (agent->envi->env->cls, | ||
985 | &agent->peer); | ||
986 | |||
987 | delay_atsi = agent->address_inuse->norm_delay.norm; | ||
988 | delay_norm = RIL_UTILITY_DELAY_MAX * exp (-delay_atsi * 0.00001); | ||
989 | |||
990 | pref_match = preferences[GNUNET_ATS_PREFERENCE_LATENCY] * delay_norm; | ||
991 | pref_match += preferences[GNUNET_ATS_PREFERENCE_BANDWIDTH] | ||
992 | * sqrt ((double) (agent->bw_in / RIL_MIN_BW) | ||
993 | * (double) (agent->bw_out / RIL_MIN_BW)); | ||
994 | return pref_match; | ||
995 | } | ||
996 | |||
997 | /** | ||
998 | * Calculates the social welfare within a network scope according to what social | ||
999 | * welfare measure is set in the configuration. | ||
1000 | * | ||
1001 | * @param solver the solver handle | ||
1002 | * @param scope the network scope in question | ||
1003 | * @return the social welfare value | ||
1004 | */ | ||
1005 | static double | ||
1006 | ril_network_get_social_welfare (struct GAS_RIL_Handle *solver, struct | ||
1007 | RIL_Scope *scope) | ||
1008 | { | ||
1009 | struct RIL_Peer_Agent *cur; | ||
1010 | double result; | ||
1011 | |||
1012 | switch (solver->parameters.social_welfare) | ||
1013 | { | ||
1014 | case RIL_WELFARE_EGALITARIAN: | ||
1015 | result = DBL_MAX; | ||
1016 | for (cur = solver->agents_head; NULL != cur; cur = cur->next) | ||
1017 | { | ||
1018 | if (cur->is_active && cur->address_inuse && | ||
1019 | (cur->address_inuse->solver_information == scope)) | ||
1020 | { | ||
1021 | result = GNUNET_MIN (result, agent_get_utility (cur)); | ||
1022 | } | ||
1023 | } | ||
1024 | return result; | ||
1025 | |||
1026 | case RIL_WELFARE_NASH: | ||
1027 | result = 0; | ||
1028 | for (cur = solver->agents_head; NULL != cur; cur = cur->next) | ||
1029 | { | ||
1030 | if (cur->is_active && cur->address_inuse && | ||
1031 | (cur->address_inuse->solver_information == scope)) | ||
1032 | { | ||
1033 | result *= pow (agent_get_utility (cur), 1.0 | ||
1034 | / (double) scope->active_agent_count); | ||
1035 | } | ||
1036 | } | ||
1037 | return result; | ||
1038 | } | ||
1039 | GNUNET_assert (GNUNET_NO); | ||
1040 | return 1; | ||
1041 | } | ||
1042 | |||
1043 | static double | ||
1044 | envi_get_penalty (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent) | ||
1045 | { | ||
1046 | struct RIL_Scope *net; | ||
1047 | unsigned long long over_max; | ||
1048 | unsigned long long over_in = 0; | ||
1049 | unsigned long long over_out = 0; | ||
1050 | |||
1051 | net = agent->address_inuse->solver_information; | ||
1052 | |||
1053 | if (net->bw_in_utilized > net->bw_in_available) | ||
1054 | { | ||
1055 | over_in = net->bw_in_utilized - net->bw_in_available; | ||
1056 | if (RIL_ACTION_BW_IN_INC == agent->a_old) | ||
1057 | { | ||
1058 | /* increase quadratically */ | ||
1059 | over_in *= over_in; | ||
1060 | } | ||
1061 | } | ||
1062 | if (net->bw_out_utilized > net->bw_out_available) | ||
1063 | { | ||
1064 | over_out = net->bw_out_utilized - net->bw_out_available; | ||
1065 | if (RIL_ACTION_BW_OUT_INC == agent->a_old) | ||
1066 | { | ||
1067 | /* increase quadratically */ | ||
1068 | over_out *= over_out; | ||
1069 | } | ||
1070 | } | ||
1071 | over_max = (over_in + over_out) / (RIL_MIN_BW * RIL_MIN_BW); | ||
1072 | |||
1073 | return -1.0 * (double) over_max; | ||
1074 | } | ||
1075 | |||
1076 | /** | ||
1077 | * Gets the reward for the last performed step, which is calculated in equal | ||
1078 | * parts from the local (the peer specific) and the global (for all peers | ||
1079 | * identical) reward. | ||
1080 | * | ||
1081 | * @param solver the solver handle | ||
1082 | * @param agent the agent handle | ||
1083 | * @return the reward | ||
1084 | */ | ||
1085 | static double | ||
1086 | envi_get_reward (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent) | ||
1087 | { | ||
1088 | struct RIL_Scope *net; | ||
1089 | double objective; | ||
1090 | double delta; | ||
1091 | double steady; | ||
1092 | double penalty; | ||
1093 | double reward; | ||
1094 | |||
1095 | net = agent->address_inuse->solver_information; | ||
1096 | |||
1097 | penalty = envi_get_penalty (solver, agent); | ||
1098 | objective = (agent_get_utility (agent) + net->social_welfare) / 2; | ||
1099 | delta = objective - agent->objective_old; | ||
1100 | agent->objective_old = objective; | ||
1101 | |||
1102 | if ((delta != 0)&&(penalty == 0)) | ||
1103 | { | ||
1104 | agent->nop_bonus = delta * RIL_NOP_DECAY; | ||
1105 | } | ||
1106 | else | ||
1107 | { | ||
1108 | agent->nop_bonus *= RIL_NOP_DECAY; | ||
1109 | } | ||
1110 | |||
1111 | steady = (RIL_ACTION_NOTHING == agent->a_old) ? agent->nop_bonus : 0; | ||
1112 | |||
1113 | reward = delta + steady; | ||
1114 | return reward + penalty; | ||
1115 | } | ||
1116 | |||
1117 | /** | ||
1118 | * Doubles the bandwidth for the active address | ||
1119 | * | ||
1120 | * @param solver solver handle | ||
1121 | * @param agent agent handle | ||
1122 | * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise the outbound bandwidth | ||
1123 | */ | ||
1124 | static void | ||
1125 | envi_action_bw_double (struct GAS_RIL_Handle *solver, | ||
1126 | struct RIL_Peer_Agent *agent, | ||
1127 | int direction_in) | ||
1128 | { | ||
1129 | unsigned long long new_bw; | ||
1130 | unsigned long long max_bw; | ||
1131 | |||
1132 | max_bw = ril_get_max_bw ((struct | ||
1133 | RIL_Scope *) agent->address_inuse-> | ||
1134 | solver_information); | ||
1135 | |||
1136 | if (direction_in) | ||
1137 | { | ||
1138 | new_bw = agent->bw_in * 2; | ||
1139 | if ((new_bw < agent->bw_in) ||(new_bw > max_bw) ) | ||
1140 | new_bw = max_bw; | ||
1141 | envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, | ||
1142 | agent->bw_out, GNUNET_NO); | ||
1143 | } | ||
1144 | else | ||
1145 | { | ||
1146 | new_bw = agent->bw_out * 2; | ||
1147 | if ((new_bw < agent->bw_out) ||(new_bw > max_bw) ) | ||
1148 | new_bw = max_bw; | ||
1149 | envi_set_active_suggestion (solver, agent, agent->address_inuse, | ||
1150 | agent->bw_in, | ||
1151 | new_bw, GNUNET_NO); | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | /** | ||
1156 | * Cuts the bandwidth for the active address in half. The least amount of bandwidth suggested, is | ||
1157 | * the minimum bandwidth for a peer, in order to not invoke a disconnect. | ||
1158 | * | ||
1159 | * @param solver solver handle | ||
1160 | * @param agent agent handle | ||
1161 | * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise change the outbound | ||
1162 | * bandwidth | ||
1163 | */ | ||
1164 | static void | ||
1165 | envi_action_bw_halven (struct GAS_RIL_Handle *solver, | ||
1166 | struct RIL_Peer_Agent *agent, | ||
1167 | int direction_in) | ||
1168 | { | ||
1169 | unsigned long long new_bw; | ||
1170 | |||
1171 | if (direction_in) | ||
1172 | { | ||
1173 | new_bw = agent->bw_in / 2; | ||
1174 | if ((new_bw <= 0) ||(new_bw > agent->bw_in) ) | ||
1175 | new_bw = 0; | ||
1176 | envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, | ||
1177 | agent->bw_out, | ||
1178 | GNUNET_NO); | ||
1179 | } | ||
1180 | else | ||
1181 | { | ||
1182 | new_bw = agent->bw_out / 2; | ||
1183 | if ((new_bw <= 0) ||(new_bw > agent->bw_out) ) | ||
1184 | new_bw = 0; | ||
1185 | envi_set_active_suggestion (solver, agent, agent->address_inuse, | ||
1186 | agent->bw_in, new_bw, | ||
1187 | GNUNET_NO); | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | /** | ||
1192 | * Increases the bandwidth by 5 times the minimum bandwidth for the active address. | ||
1193 | * | ||
1194 | * @param solver solver handle | ||
1195 | * @param agent agent handle | ||
1196 | * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise change the outbound | ||
1197 | * bandwidth | ||
1198 | */ | ||
1199 | static void | ||
1200 | envi_action_bw_inc (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent, | ||
1201 | int direction_in) | ||
1202 | { | ||
1203 | unsigned long long new_bw; | ||
1204 | unsigned long long max_bw; | ||
1205 | |||
1206 | max_bw = ril_get_max_bw ((struct | ||
1207 | RIL_Scope *) agent->address_inuse-> | ||
1208 | solver_information); | ||
1209 | |||
1210 | if (direction_in) | ||
1211 | { | ||
1212 | new_bw = agent->bw_in + (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW); | ||
1213 | if ((new_bw < agent->bw_in) ||(new_bw > max_bw) ) | ||
1214 | new_bw = max_bw; | ||
1215 | envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, | ||
1216 | agent->bw_out, GNUNET_NO); | ||
1217 | } | ||
1218 | else | ||
1219 | { | ||
1220 | new_bw = agent->bw_out + (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW); | ||
1221 | if ((new_bw < agent->bw_out) ||(new_bw > max_bw) ) | ||
1222 | new_bw = max_bw; | ||
1223 | envi_set_active_suggestion (solver, agent, agent->address_inuse, | ||
1224 | agent->bw_in, | ||
1225 | new_bw, GNUNET_NO); | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | /** | ||
1230 | * Decreases the bandwidth by 5 times the minimum bandwidth for the active address. The least amount | ||
1231 | * of bandwidth suggested, is the minimum bandwidth for a peer, in order to not invoke a disconnect. | ||
1232 | * | ||
1233 | * @param solver solver handle | ||
1234 | * @param agent agent handle | ||
1235 | * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise change the outbound | ||
1236 | * bandwidth | ||
1237 | */ | ||
1238 | static void | ||
1239 | envi_action_bw_dec (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent, | ||
1240 | int direction_in) | ||
1241 | { | ||
1242 | unsigned long long new_bw; | ||
1243 | |||
1244 | if (direction_in) | ||
1245 | { | ||
1246 | new_bw = agent->bw_in - (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW); | ||
1247 | if ((new_bw <= 0) ||(new_bw > agent->bw_in) ) | ||
1248 | new_bw = 0; | ||
1249 | envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, | ||
1250 | agent->bw_out, | ||
1251 | GNUNET_NO); | ||
1252 | } | ||
1253 | else | ||
1254 | { | ||
1255 | new_bw = agent->bw_out - (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW); | ||
1256 | if ((new_bw <= 0) ||(new_bw > agent->bw_out) ) | ||
1257 | new_bw = 0; | ||
1258 | envi_set_active_suggestion (solver, agent, agent->address_inuse, | ||
1259 | agent->bw_in, new_bw, | ||
1260 | GNUNET_NO); | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | /** | ||
1265 | * Switches to the address given by its index | ||
1266 | * | ||
1267 | * @param solver solver handle | ||
1268 | * @param agent agent handle | ||
1269 | * @param address_index index of the address as it is saved in the agent's list, starting with zero | ||
1270 | */ | ||
1271 | static void | ||
1272 | envi_action_address_switch (struct GAS_RIL_Handle *solver, | ||
1273 | struct RIL_Peer_Agent *agent, | ||
1274 | unsigned int address_index) | ||
1275 | { | ||
1276 | struct RIL_Address_Wrapped *cur; | ||
1277 | int i = 0; | ||
1278 | |||
1279 | // cur = agent_address_get_wrapped(agent, agent->address_inuse); | ||
1280 | |||
1281 | for (cur = agent->addresses_head; NULL != cur; cur = cur->next) | ||
1282 | { | ||
1283 | if (i == address_index) | ||
1284 | { | ||
1285 | envi_set_active_suggestion (solver, agent, cur->address_naked, | ||
1286 | agent->bw_in, agent->bw_out, | ||
1287 | GNUNET_NO); | ||
1288 | return; | ||
1289 | } | ||
1290 | |||
1291 | i++; | ||
1292 | } | ||
1293 | |||
1294 | // no address with address_index exists, in this case this action should not be callable | ||
1295 | GNUNET_assert (GNUNET_NO); | ||
1296 | } | ||
1297 | |||
1298 | /** | ||
1299 | * Puts the action into effect by calling the according function | ||
1300 | * | ||
1301 | * @param solver the solver handle | ||
1302 | * @param agent the action handle | ||
1303 | * @param action the action to perform by the solver | ||
1304 | */ | ||
1305 | static void | ||
1306 | envi_do_action (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent, int | ||
1307 | action) | ||
1308 | { | ||
1309 | int address_index; | ||
1310 | |||
1311 | switch (action) | ||
1312 | { | ||
1313 | case RIL_ACTION_NOTHING: | ||
1314 | break; | ||
1315 | |||
1316 | case RIL_ACTION_BW_IN_DBL: | ||
1317 | envi_action_bw_double (solver, agent, GNUNET_YES); | ||
1318 | break; | ||
1319 | |||
1320 | case RIL_ACTION_BW_IN_HLV: | ||
1321 | envi_action_bw_halven (solver, agent, GNUNET_YES); | ||
1322 | break; | ||
1323 | |||
1324 | case RIL_ACTION_BW_IN_INC: | ||
1325 | envi_action_bw_inc (solver, agent, GNUNET_YES); | ||
1326 | break; | ||
1327 | |||
1328 | case RIL_ACTION_BW_IN_DEC: | ||
1329 | envi_action_bw_dec (solver, agent, GNUNET_YES); | ||
1330 | break; | ||
1331 | |||
1332 | case RIL_ACTION_BW_OUT_DBL: | ||
1333 | envi_action_bw_double (solver, agent, GNUNET_NO); | ||
1334 | break; | ||
1335 | |||
1336 | case RIL_ACTION_BW_OUT_HLV: | ||
1337 | envi_action_bw_halven (solver, agent, GNUNET_NO); | ||
1338 | break; | ||
1339 | |||
1340 | case RIL_ACTION_BW_OUT_INC: | ||
1341 | envi_action_bw_inc (solver, agent, GNUNET_NO); | ||
1342 | break; | ||
1343 | |||
1344 | case RIL_ACTION_BW_OUT_DEC: | ||
1345 | envi_action_bw_dec (solver, agent, GNUNET_NO); | ||
1346 | break; | ||
1347 | |||
1348 | default: | ||
1349 | if ((action >= RIL_ACTION_TYPE_NUM) && (action < agent->n)) // switch address action | ||
1350 | { | ||
1351 | address_index = action - RIL_ACTION_TYPE_NUM; | ||
1352 | |||
1353 | GNUNET_assert (address_index >= 0); | ||
1354 | GNUNET_assert ( | ||
1355 | address_index <= agent_address_get_index (agent, | ||
1356 | agent->addresses_tail-> | ||
1357 | address_naked)); | ||
1358 | |||
1359 | envi_action_address_switch (solver, agent, address_index); | ||
1360 | break; | ||
1361 | } | ||
1362 | // error - action does not exist | ||
1363 | GNUNET_assert (GNUNET_NO); | ||
1364 | } | ||
1365 | } | ||
1366 | |||
1367 | /** | ||
1368 | * Selects the next action using the e-greedy strategy. I.e. with a probability | ||
1369 | * of (1-e) the action with the maximum expected return will be chosen | ||
1370 | * (=> exploitation) and with probability (e) a random action will be chosen. | ||
1371 | * In case the Q-learning rule is set, the function also resets the eligibility | ||
1372 | * traces in the exploration case (after Watkin's Q-learning). | ||
1373 | * | ||
1374 | * @param agent the agent selecting an action | ||
1375 | * @param state the current state-feature vector | ||
1376 | * @return the action index | ||
1377 | */ | ||
1378 | static int | ||
1379 | agent_select_egreedy (struct RIL_Peer_Agent *agent, double *state) | ||
1380 | { | ||
1381 | int action; | ||
1382 | double r = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1383 | UINT32_MAX) | ||
1384 | / (double) UINT32_MAX; | ||
1385 | |||
1386 | if (r < agent->envi->parameters.epsilon) // explore | ||
1387 | { | ||
1388 | action = agent_get_action_random (agent); | ||
1389 | if (RIL_ALGO_Q == agent->envi->parameters.algorithm) | ||
1390 | { | ||
1391 | agent->eligibility_reset = GNUNET_YES; | ||
1392 | } | ||
1393 | agent->envi->parameters.epsilon *= agent->envi->parameters.epsilon_decay; | ||
1394 | return action; | ||
1395 | } | ||
1396 | else // exploit | ||
1397 | { | ||
1398 | action = agent_get_action_max (agent, state); | ||
1399 | return action; | ||
1400 | } | ||
1401 | } | ||
1402 | |||
1403 | /** | ||
1404 | * Selects the next action with a probability corresponding to its value. The | ||
1405 | * probability is calculated using a Boltzmann distribution with a temperature | ||
1406 | * value. The higher the temperature, the more are the action selection | ||
1407 | * probabilities the same. With a temperature of 0, the selection is greedy, | ||
1408 | * i.e. always the action with the highest value is chosen. | ||
1409 | * @param agent | ||
1410 | * @param state | ||
1411 | * @return | ||
1412 | */ | ||
1413 | static int | ||
1414 | agent_select_softmax (struct RIL_Peer_Agent *agent, double *state) | ||
1415 | { | ||
1416 | int i; | ||
1417 | int a_max; | ||
1418 | double eqt[agent->n]; | ||
1419 | double p[agent->n]; | ||
1420 | double sum = 0; | ||
1421 | double r; | ||
1422 | |||
1423 | a_max = agent_get_action_max (agent, state); | ||
1424 | |||
1425 | for (i = 0; i < agent->n; i++) | ||
1426 | { | ||
1427 | if (agent_action_is_possible (agent, i)) | ||
1428 | { | ||
1429 | eqt[i] = exp (agent_q (agent, state, i) | ||
1430 | / agent->envi->parameters.temperature); | ||
1431 | if (isinf (eqt[i])) | ||
1432 | eqt[i] = isinf (eqt[i]) * UINT32_MAX; | ||
1433 | sum += eqt[i]; | ||
1434 | } | ||
1435 | } | ||
1436 | for (i = 0; i < agent->n; i++) | ||
1437 | { | ||
1438 | if (agent_action_is_possible (agent, i)) | ||
1439 | { | ||
1440 | p[i] = eqt[i] / sum; | ||
1441 | } | ||
1442 | else | ||
1443 | { | ||
1444 | p[i] = 0; | ||
1445 | } | ||
1446 | } | ||
1447 | r = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1448 | UINT32_MAX) / (double) UINT32_MAX; | ||
1449 | sum = 0; | ||
1450 | for (i = 0; i < agent->n; i++) | ||
1451 | { | ||
1452 | if (sum + p[i] > r) | ||
1453 | { | ||
1454 | if (i != a_max) | ||
1455 | { | ||
1456 | if (RIL_ALGO_Q == agent->envi->parameters.algorithm) | ||
1457 | agent->eligibility_reset = GNUNET_YES; | ||
1458 | agent->envi->parameters.temperature *= | ||
1459 | agent->envi->parameters.temperature_decay; | ||
1460 | } | ||
1461 | return i; | ||
1462 | } | ||
1463 | sum += p[i]; | ||
1464 | } | ||
1465 | GNUNET_assert (GNUNET_NO); | ||
1466 | return RIL_ACTION_INVALID; | ||
1467 | } | ||
1468 | |||
1469 | /** | ||
1470 | * Select the next action of an agent either according to the e-greedy strategy | ||
1471 | * or the softmax strategy. | ||
1472 | * | ||
1473 | * @param agent the agent in question | ||
1474 | * @param state the current state-feature vector | ||
1475 | * @return the action index | ||
1476 | */ | ||
1477 | static int | ||
1478 | agent_select_action (struct RIL_Peer_Agent *agent, double *state) | ||
1479 | { | ||
1480 | if (agent->envi->parameters.select == RIL_SELECT_EGREEDY) | ||
1481 | { | ||
1482 | return agent_select_egreedy (agent, state); | ||
1483 | } | ||
1484 | else | ||
1485 | { | ||
1486 | return agent_select_softmax (agent, state); | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | /** | ||
1491 | * Performs one step of the Markov Decision Process. Other than in the literature the step starts | ||
1492 | * after having done the last action a_old. It observes the new state s_next and the reward | ||
1493 | * received. Then the coefficient update is done according to the SARSA or Q-learning method. The | ||
1494 | * next action is put into effect. | ||
1495 | * | ||
1496 | * @param agent the agent performing the step | ||
1497 | */ | ||
1498 | static void | ||
1499 | agent_step (struct RIL_Peer_Agent *agent) | ||
1500 | { | ||
1501 | int a_next = RIL_ACTION_INVALID; | ||
1502 | int a_max; | ||
1503 | double *s_next; | ||
1504 | double reward; | ||
1505 | |||
1506 | LOG (GNUNET_ERROR_TYPE_DEBUG, " agent_step() Peer '%s', algorithm %s\n", | ||
1507 | GNUNET_i2s (&agent->peer), | ||
1508 | agent->envi->parameters.algorithm ? "Q" : "SARSA"); | ||
1509 | |||
1510 | s_next = envi_get_state (agent->envi, agent); | ||
1511 | reward = envi_get_reward (agent->envi, agent); | ||
1512 | |||
1513 | if (agent->eligibility_reset) | ||
1514 | { | ||
1515 | agent_modify_eligibility (agent, RIL_E_ZERO, NULL, -1); | ||
1516 | agent->eligibility_reset = GNUNET_NO; | ||
1517 | } | ||
1518 | else | ||
1519 | { | ||
1520 | agent_modify_eligibility (agent, RIL_E_DECAY, NULL, -1); | ||
1521 | } | ||
1522 | if (RIL_ACTION_INVALID != agent->a_old) | ||
1523 | { | ||
1524 | agent_modify_eligibility (agent, | ||
1525 | agent->envi->parameters.eligibility_trace_mode, | ||
1526 | agent->s_old, agent->a_old); | ||
1527 | } | ||
1528 | |||
1529 | switch (agent->envi->parameters.algorithm) | ||
1530 | { | ||
1531 | case RIL_ALGO_SARSA: | ||
1532 | a_next = agent_select_action (agent, s_next); | ||
1533 | if (RIL_ACTION_INVALID != agent->a_old) | ||
1534 | { | ||
1535 | // updates weights with selected action (on-policy), if not first step | ||
1536 | agent_update (agent, reward, s_next, a_next); | ||
1537 | } | ||
1538 | break; | ||
1539 | |||
1540 | case RIL_ALGO_Q: | ||
1541 | a_max = agent_get_action_max (agent, s_next); | ||
1542 | if (RIL_ACTION_INVALID != agent->a_old) | ||
1543 | { | ||
1544 | // updates weights with best action, disregarding actually selected action (off-policy), if not first step | ||
1545 | agent_update (agent, reward, s_next, a_max); | ||
1546 | } | ||
1547 | a_next = agent_select_action (agent, s_next); | ||
1548 | break; | ||
1549 | } | ||
1550 | |||
1551 | GNUNET_assert (RIL_ACTION_INVALID != a_next); | ||
1552 | |||
1553 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1554 | "step() Step# %llu R: %f IN %llu OUT %llu A: %d\n", | ||
1555 | agent->step_count, | ||
1556 | reward, | ||
1557 | agent->bw_in / 1024, | ||
1558 | agent->bw_out / 1024, | ||
1559 | a_next); | ||
1560 | |||
1561 | envi_do_action (agent->envi, agent, a_next); | ||
1562 | |||
1563 | GNUNET_free (agent->s_old); | ||
1564 | agent->s_old = s_next; | ||
1565 | agent->a_old = a_next; | ||
1566 | |||
1567 | agent->step_count += 1; | ||
1568 | } | ||
1569 | |||
1570 | /** | ||
1571 | * Prototype of the ril_step() procedure | ||
1572 | * | ||
1573 | * @param solver the solver handle | ||
1574 | */ | ||
1575 | static void | ||
1576 | ril_step (struct GAS_RIL_Handle *solver); | ||
1577 | |||
1578 | |||
1579 | /** | ||
1580 | * Task for the scheduler, which performs one step and lets the solver know that | ||
1581 | * no further step is scheduled. | ||
1582 | * | ||
1583 | * @param cls the solver handle | ||
1584 | */ | ||
1585 | static void | ||
1586 | ril_step_scheduler_task (void *cls) | ||
1587 | { | ||
1588 | struct GAS_RIL_Handle *solver = cls; | ||
1589 | |||
1590 | solver->step_next_task_id = NULL; | ||
1591 | ril_step (solver); | ||
1592 | } | ||
1593 | |||
1594 | /** | ||
1595 | * Determines how much of the available bandwidth is assigned. If more is | ||
1596 | * assigned than available it returns 1. The function is used to determine the | ||
1597 | * step size of the adaptive stepping. | ||
1598 | * | ||
1599 | * @param solver the solver handle | ||
1600 | * @return the ratio | ||
1601 | */ | ||
1602 | static double | ||
1603 | ril_get_used_resource_ratio (struct GAS_RIL_Handle *solver) | ||
1604 | { | ||
1605 | int i; | ||
1606 | struct RIL_Scope net; | ||
1607 | unsigned long long sum_assigned = 0; | ||
1608 | unsigned long long sum_available = 0; | ||
1609 | double ratio; | ||
1610 | |||
1611 | for (i = 0; i < solver->networks_count; i++) | ||
1612 | { | ||
1613 | net = solver->network_entries[i]; | ||
1614 | if (net.bw_in_assigned > 0) // only consider scopes where an address is actually active | ||
1615 | { | ||
1616 | sum_assigned += net.bw_in_utilized; | ||
1617 | sum_assigned += net.bw_out_utilized; | ||
1618 | sum_available += net.bw_in_available; | ||
1619 | sum_available += net.bw_out_available; | ||
1620 | } | ||
1621 | } | ||
1622 | if (sum_available > 0) | ||
1623 | { | ||
1624 | ratio = ((double) sum_assigned) / ((double) sum_available); | ||
1625 | } | ||
1626 | else | ||
1627 | { | ||
1628 | ratio = 0; | ||
1629 | } | ||
1630 | |||
1631 | return ratio > 1 ? 1 : ratio; // overutilization is possible, cap at 1 | ||
1632 | } | ||
1633 | |||
1634 | /** | ||
1635 | * Lookup network struct by type | ||
1636 | * | ||
1637 | * @param s the solver handle | ||
1638 | * @param type the network type | ||
1639 | * @return the network struct | ||
1640 | */ | ||
1641 | static struct RIL_Scope * | ||
1642 | ril_get_network (struct GAS_RIL_Handle *s, uint32_t type) | ||
1643 | { | ||
1644 | int i; | ||
1645 | |||
1646 | for (i = 0; i < s->networks_count; i++) | ||
1647 | { | ||
1648 | if (s->network_entries[i].type == type) | ||
1649 | { | ||
1650 | return &s->network_entries[i]; | ||
1651 | } | ||
1652 | } | ||
1653 | return NULL; | ||
1654 | } | ||
1655 | |||
1656 | /** | ||
1657 | * Determines whether more connections are allocated in a network scope, than | ||
1658 | * they would theoretically fit. This is used as a heuristic to determine, | ||
1659 | * whether a new connection can be allocated or not. | ||
1660 | * | ||
1661 | * @param solver the solver handle | ||
1662 | * @param network the network scope in question | ||
1663 | * @return GNUNET_YES if there are theoretically enough resources left | ||
1664 | */ | ||
1665 | static int | ||
1666 | ril_network_is_not_full (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType | ||
1667 | network) | ||
1668 | { | ||
1669 | struct RIL_Scope *net; | ||
1670 | struct RIL_Peer_Agent *agent; | ||
1671 | unsigned long long address_count = 0; | ||
1672 | |||
1673 | for (agent = solver->agents_head; NULL != agent; agent = agent->next) | ||
1674 | { | ||
1675 | if (agent->address_inuse && agent->is_active) | ||
1676 | { | ||
1677 | net = agent->address_inuse->solver_information; | ||
1678 | if (net->type == network) | ||
1679 | { | ||
1680 | address_count++; | ||
1681 | } | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | net = ril_get_network (solver, network); | ||
1686 | return (net->bw_in_available > RIL_MIN_BW * address_count) && | ||
1687 | (net->bw_out_available > RIL_MIN_BW * address_count); | ||
1688 | } | ||
1689 | |||
1690 | /** | ||
1691 | * Unblocks an agent for which a connection request is there, that could not | ||
1692 | * be satisfied. Iterates over the addresses of the agent, if one of its | ||
1693 | * addresses can now be allocated in its scope the agent is unblocked, | ||
1694 | * otherwise it remains unchanged. | ||
1695 | * | ||
1696 | * @param solver the solver handle | ||
1697 | * @param agent the agent in question | ||
1698 | * @param silent | ||
1699 | */ | ||
1700 | static void | ||
1701 | ril_try_unblock_agent (struct GAS_RIL_Handle *solver, struct | ||
1702 | RIL_Peer_Agent *agent, int silent) | ||
1703 | { | ||
1704 | struct RIL_Address_Wrapped *addr_wrap; | ||
1705 | struct RIL_Scope *net; | ||
1706 | unsigned long long start_in; | ||
1707 | unsigned long long start_out; | ||
1708 | |||
1709 | for (addr_wrap = agent->addresses_head; NULL != addr_wrap; addr_wrap = | ||
1710 | addr_wrap->next) | ||
1711 | { | ||
1712 | net = addr_wrap->address_naked->solver_information; | ||
1713 | if (ril_network_is_not_full (solver, net->type)) | ||
1714 | { | ||
1715 | if (NULL == agent->address_inuse) | ||
1716 | { | ||
1717 | start_in = net->bw_in_available < net->bw_in_utilized ? | ||
1718 | (net->bw_in_available - net->bw_in_utilized) / 2 : | ||
1719 | RIL_MIN_BW; | ||
1720 | start_out = net->bw_out_available < net->bw_out_utilized ? | ||
1721 | (net->bw_out_available - net->bw_out_utilized) / 2 : | ||
1722 | RIL_MIN_BW; | ||
1723 | envi_set_active_suggestion (solver, agent, addr_wrap->address_naked, | ||
1724 | start_in, start_out, silent); | ||
1725 | } | ||
1726 | return; | ||
1727 | } | ||
1728 | } | ||
1729 | agent->address_inuse = NULL; | ||
1730 | } | ||
1731 | |||
1732 | /** | ||
1733 | * Determines how much the reward needs to be discounted depending on the amount | ||
1734 | * of time, which has passed since the last time-step. | ||
1735 | * | ||
1736 | * @param solver the solver handle | ||
1737 | */ | ||
1738 | static void | ||
1739 | ril_calculate_discount (struct GAS_RIL_Handle *solver) | ||
1740 | { | ||
1741 | struct GNUNET_TIME_Absolute time_now; | ||
1742 | struct GNUNET_TIME_Relative time_delta; | ||
1743 | double tau; | ||
1744 | |||
1745 | // MDP case only for debugging purposes | ||
1746 | if (solver->simulate) | ||
1747 | { | ||
1748 | solver->global_discount_variable = solver->parameters.gamma; | ||
1749 | solver->global_discount_integrated = 1; | ||
1750 | return; | ||
1751 | } | ||
1752 | |||
1753 | // semi-MDP case | ||
1754 | |||
1755 | // calculate tau, i.e. how many real valued time units have passed, one time unit is one minimum time step | ||
1756 | time_now = GNUNET_TIME_absolute_get (); | ||
1757 | time_delta = GNUNET_TIME_absolute_get_difference (solver->step_time_last, | ||
1758 | time_now); | ||
1759 | solver->step_time_last = time_now; | ||
1760 | tau = (double) time_delta.rel_value_us | ||
1761 | / (double) solver->parameters.step_time_min.rel_value_us; | ||
1762 | |||
1763 | // calculate reward discounts (once per step for all agents) | ||
1764 | solver->global_discount_variable = pow (M_E, ((-1.0) | ||
1765 | * ((double) solver->parameters. | ||
1766 | beta) * tau)); | ||
1767 | solver->global_discount_integrated = (1.0 - solver->global_discount_variable) | ||
1768 | / (double) solver->parameters.beta; | ||
1769 | } | ||
1770 | |||
1771 | /** | ||
1772 | * Count the number of active agents/connections in a network scope | ||
1773 | * | ||
1774 | * @param solver the solver handle | ||
1775 | * @param scope the network scope in question | ||
1776 | * @return the number of allocated connections | ||
1777 | */ | ||
1778 | static int | ||
1779 | ril_network_count_active_agents (struct GAS_RIL_Handle *solver, struct | ||
1780 | RIL_Scope *scope) | ||
1781 | { | ||
1782 | int c = 0; | ||
1783 | struct RIL_Peer_Agent *cur_agent; | ||
1784 | |||
1785 | for (cur_agent = solver->agents_head; NULL != cur_agent; cur_agent = | ||
1786 | cur_agent->next) | ||
1787 | { | ||
1788 | if (cur_agent->is_active && cur_agent->address_inuse && | ||
1789 | (cur_agent->address_inuse->solver_information == scope)) | ||
1790 | { | ||
1791 | c++; | ||
1792 | } | ||
1793 | } | ||
1794 | return c; | ||
1795 | } | ||
1796 | |||
1797 | /** | ||
1798 | * Calculates how much bandwidth is assigned in sum in a network scope, either | ||
1799 | * in the inbound or in the outbound direction. | ||
1800 | * | ||
1801 | * @param solver the solver handle | ||
1802 | * @param type the type of the network scope in question | ||
1803 | * @param direction_in GNUNET_YES if the inbound direction should be summed up, | ||
1804 | * otherwise the outbound direction will be summed up | ||
1805 | * @return the sum of the assigned bandwidths | ||
1806 | */ | ||
1807 | static unsigned long long | ||
1808 | ril_network_get_assigned (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType | ||
1809 | type, int direction_in) | ||
1810 | { | ||
1811 | struct RIL_Peer_Agent *cur; | ||
1812 | struct RIL_Scope *net; | ||
1813 | unsigned long long sum = 0; | ||
1814 | |||
1815 | for (cur = solver->agents_head; NULL != cur; cur = cur->next) | ||
1816 | { | ||
1817 | if (cur->is_active && cur->address_inuse) | ||
1818 | { | ||
1819 | net = cur->address_inuse->solver_information; | ||
1820 | if (net->type == type) | ||
1821 | { | ||
1822 | if (direction_in) | ||
1823 | sum += cur->bw_in; | ||
1824 | else | ||
1825 | sum += cur->bw_out; | ||
1826 | } | ||
1827 | } | ||
1828 | } | ||
1829 | |||
1830 | return sum; | ||
1831 | } | ||
1832 | |||
1833 | /** | ||
1834 | * Calculates how much bandwidth is actually utilized in sum in a network scope, | ||
1835 | * either in the inbound or in the outbound direction. | ||
1836 | * | ||
1837 | * @param solver the solver handle | ||
1838 | * @param type the type of the network scope in question | ||
1839 | * @param direction_in GNUNET_YES if the inbound direction should be summed up, | ||
1840 | * otherwise the outbound direction will be summed up | ||
1841 | * @return the sum of the utilized bandwidths (in bytes/second) | ||
1842 | */ | ||
1843 | static unsigned long long | ||
1844 | ril_network_get_utilized (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType | ||
1845 | type, int direction_in) | ||
1846 | { | ||
1847 | struct RIL_Peer_Agent *cur; | ||
1848 | struct RIL_Scope *net; | ||
1849 | unsigned long long sum = 0; | ||
1850 | |||
1851 | for (cur = solver->agents_head; NULL != cur; cur = cur->next) | ||
1852 | { | ||
1853 | if (cur->is_active && cur->address_inuse) | ||
1854 | { | ||
1855 | net = cur->address_inuse->solver_information; | ||
1856 | if (net->type == type) | ||
1857 | { | ||
1858 | if (direction_in) | ||
1859 | sum += cur->address_inuse->norm_utilization_in.norm; | ||
1860 | else | ||
1861 | sum += cur->address_inuse->norm_utilization_out.norm; | ||
1862 | } | ||
1863 | } | ||
1864 | } | ||
1865 | |||
1866 | return sum; | ||
1867 | } | ||
1868 | |||
1869 | /** | ||
1870 | * Retrieves the state of the network scope, so that its attributes are up-to- | ||
1871 | * date. | ||
1872 | * | ||
1873 | * @param solver the solver handle | ||
1874 | */ | ||
1875 | static void | ||
1876 | ril_networks_update_state (struct GAS_RIL_Handle *solver) | ||
1877 | { | ||
1878 | int c; | ||
1879 | struct RIL_Scope *net; | ||
1880 | |||
1881 | for (c = 0; c < solver->networks_count; c++) | ||
1882 | { | ||
1883 | net = &solver->network_entries[c]; | ||
1884 | net->bw_in_assigned = ril_network_get_assigned (solver, net->type, | ||
1885 | GNUNET_YES); | ||
1886 | net->bw_in_utilized = ril_network_get_utilized (solver, net->type, | ||
1887 | GNUNET_YES); | ||
1888 | net->bw_out_assigned = ril_network_get_assigned (solver, net->type, | ||
1889 | GNUNET_NO); | ||
1890 | net->bw_out_utilized = ril_network_get_utilized (solver, net->type, | ||
1891 | GNUNET_NO); | ||
1892 | net->active_agent_count = ril_network_count_active_agents (solver, net); | ||
1893 | net->social_welfare = ril_network_get_social_welfare (solver, net); | ||
1894 | } | ||
1895 | } | ||
1896 | |||
1897 | /** | ||
1898 | * Schedules the next global step in an adaptive way. The more resources are | ||
1899 | * left, the earlier the next step is scheduled. This serves the reactivity of | ||
1900 | * the solver to changed inputs. | ||
1901 | * | ||
1902 | * @param solver the solver handle | ||
1903 | */ | ||
1904 | static void | ||
1905 | ril_step_schedule_next (struct GAS_RIL_Handle *solver) | ||
1906 | { | ||
1907 | double used_ratio; | ||
1908 | double factor; | ||
1909 | double y; | ||
1910 | double offset; | ||
1911 | struct GNUNET_TIME_Relative time_next; | ||
1912 | |||
1913 | used_ratio = ril_get_used_resource_ratio (solver); | ||
1914 | |||
1915 | GNUNET_assert ( | ||
1916 | solver->parameters.step_time_min.rel_value_us | ||
1917 | <= solver->parameters.step_time_max.rel_value_us); | ||
1918 | |||
1919 | factor = (double) GNUNET_TIME_relative_subtract ( | ||
1920 | solver->parameters.step_time_max, | ||
1921 | solver->parameters. | ||
1922 | step_time_min).rel_value_us; | ||
1923 | offset = (double) solver->parameters.step_time_min.rel_value_us; | ||
1924 | y = factor * pow (used_ratio, RIL_INTERVAL_EXPONENT) + offset; | ||
1925 | |||
1926 | GNUNET_assert (y <= (double) solver->parameters.step_time_max.rel_value_us); | ||
1927 | GNUNET_assert (y >= (double) solver->parameters.step_time_min.rel_value_us); | ||
1928 | |||
1929 | time_next = GNUNET_TIME_relative_saturating_multiply ( | ||
1930 | GNUNET_TIME_UNIT_MICROSECONDS, (unsigned long long) y); | ||
1931 | |||
1932 | // LOG (GNUNET_ERROR_TYPE_INFO, "ratio: %f, factor: %f, offset: %f, y: %f\n", | ||
1933 | // used_ratio, | ||
1934 | // factor, | ||
1935 | // offset, | ||
1936 | // y); | ||
1937 | |||
1938 | if (solver->simulate) | ||
1939 | { | ||
1940 | time_next = GNUNET_TIME_UNIT_ZERO; | ||
1941 | } | ||
1942 | |||
1943 | if ((NULL == solver->step_next_task_id) && (GNUNET_NO == solver->done)) | ||
1944 | { | ||
1945 | solver->step_next_task_id = GNUNET_SCHEDULER_add_delayed (time_next, | ||
1946 | & | ||
1947 | ril_step_scheduler_task, | ||
1948 | solver); | ||
1949 | } | ||
1950 | } | ||
1951 | |||
1952 | /** | ||
1953 | * Triggers one step per agent | ||
1954 | * | ||
1955 | * @param solver | ||
1956 | */ | ||
1957 | static void | ||
1958 | ril_step (struct GAS_RIL_Handle *solver) | ||
1959 | { | ||
1960 | struct RIL_Peer_Agent *cur; | ||
1961 | |||
1962 | if (GNUNET_YES == solver->bulk_lock) | ||
1963 | { | ||
1964 | solver->bulk_changes++; | ||
1965 | return; | ||
1966 | } | ||
1967 | |||
1968 | ril_inform (solver, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS); | ||
1969 | |||
1970 | LOG (GNUNET_ERROR_TYPE_DEBUG, " RIL step number %d\n", solver->step_count); | ||
1971 | |||
1972 | if (0 == solver->step_count) | ||
1973 | { | ||
1974 | solver->step_time_last = GNUNET_TIME_absolute_get (); | ||
1975 | } | ||
1976 | |||
1977 | ril_calculate_discount (solver); | ||
1978 | ril_networks_update_state (solver); | ||
1979 | |||
1980 | // trigger one step per active, unblocked agent | ||
1981 | for (cur = solver->agents_head; NULL != cur; cur = cur->next) | ||
1982 | { | ||
1983 | if (cur->is_active) | ||
1984 | { | ||
1985 | if (NULL == cur->address_inuse) | ||
1986 | { | ||
1987 | ril_try_unblock_agent (solver, cur, GNUNET_NO); | ||
1988 | } | ||
1989 | if (cur->address_inuse) | ||
1990 | { | ||
1991 | agent_step (cur); | ||
1992 | } | ||
1993 | } | ||
1994 | } | ||
1995 | |||
1996 | ril_networks_update_state (solver); | ||
1997 | |||
1998 | solver->step_count++; | ||
1999 | ril_step_schedule_next (solver); | ||
2000 | |||
2001 | ril_inform (solver, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS); | ||
2002 | |||
2003 | ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START, GAS_STAT_SUCCESS); | ||
2004 | for (cur = solver->agents_head; NULL != cur; cur = cur->next) | ||
2005 | { | ||
2006 | if (cur->suggestion_issue) | ||
2007 | { | ||
2008 | solver->env->bandwidth_changed_cb (solver->env->cls, | ||
2009 | cur->suggestion_address); | ||
2010 | cur->suggestion_issue = GNUNET_NO; | ||
2011 | } | ||
2012 | } | ||
2013 | ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP, GAS_STAT_SUCCESS); | ||
2014 | } | ||
2015 | |||
2016 | /** | ||
2017 | * Initializes the matrix W of parameter vectors theta with small random numbers. | ||
2018 | * | ||
2019 | * @param agent The respective agent | ||
2020 | */ | ||
2021 | static void | ||
2022 | agent_w_init (struct RIL_Peer_Agent *agent) | ||
2023 | { | ||
2024 | int i; | ||
2025 | int k; | ||
2026 | |||
2027 | for (i = 0; i < agent->n; i++) | ||
2028 | { | ||
2029 | for (k = 0; k < agent->m; k++) | ||
2030 | { | ||
2031 | agent->W[i][k] = agent->envi->parameters.alpha * (1.0 - 2.0 | ||
2032 | * ((double) | ||
2033 | GNUNET_CRYPTO_random_u32 ( | ||
2034 | GNUNET_CRYPTO_QUALITY_WEAK, | ||
2035 | UINT32_MAX) | ||
2036 | / (double) UINT32_MAX)); | ||
2037 | } | ||
2038 | } | ||
2039 | } | ||
2040 | |||
2041 | /** | ||
2042 | * Initialize an agent without addresses and its knowledge base | ||
2043 | * | ||
2044 | * @param s ril solver | ||
2045 | * @param peer the one in question | ||
2046 | * @return handle to the new agent | ||
2047 | */ | ||
2048 | static struct RIL_Peer_Agent * | ||
2049 | agent_init (void *s, const struct GNUNET_PeerIdentity *peer) | ||
2050 | { | ||
2051 | int i; | ||
2052 | struct GAS_RIL_Handle *solver = s; | ||
2053 | struct RIL_Peer_Agent *agent = GNUNET_new (struct RIL_Peer_Agent); | ||
2054 | |||
2055 | agent->envi = solver; | ||
2056 | agent->peer = *peer; | ||
2057 | agent->step_count = 0; | ||
2058 | agent->is_active = GNUNET_NO; | ||
2059 | agent->bw_in = RIL_MIN_BW; | ||
2060 | agent->bw_out = RIL_MIN_BW; | ||
2061 | agent->suggestion_issue = GNUNET_NO; | ||
2062 | agent->n = RIL_ACTION_TYPE_NUM; | ||
2063 | agent->m = 0; | ||
2064 | agent->W = (double **) GNUNET_malloc (sizeof(double *) * agent->n); | ||
2065 | agent->E = (double **) GNUNET_malloc (sizeof(double *) * agent->n); | ||
2066 | for (i = 0; i < agent->n; i++) | ||
2067 | { | ||
2068 | agent->W[i] = (double *) GNUNET_malloc (sizeof(double) * agent->m); | ||
2069 | agent->E[i] = (double *) GNUNET_malloc (sizeof(double) * agent->m); | ||
2070 | } | ||
2071 | agent_w_init (agent); | ||
2072 | agent->eligibility_reset = GNUNET_NO; | ||
2073 | agent->a_old = RIL_ACTION_INVALID; | ||
2074 | agent->s_old = GNUNET_malloc (sizeof(double) * agent->m); | ||
2075 | agent->address_inuse = NULL; | ||
2076 | agent->objective_old = 0; | ||
2077 | agent->nop_bonus = 0; | ||
2078 | |||
2079 | return agent; | ||
2080 | } | ||
2081 | |||
2082 | /** | ||
2083 | * Deallocate agent | ||
2084 | * | ||
2085 | * @param solver the solver handle | ||
2086 | * @param agent the agent to retire | ||
2087 | */ | ||
2088 | static void | ||
2089 | agent_die (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent) | ||
2090 | { | ||
2091 | int i; | ||
2092 | |||
2093 | for (i = 0; i < agent->n; i++) | ||
2094 | { | ||
2095 | GNUNET_free_non_null (agent->W[i]); | ||
2096 | GNUNET_free_non_null (agent->E[i]); | ||
2097 | } | ||
2098 | GNUNET_free_non_null (agent->W); | ||
2099 | GNUNET_free_non_null (agent->E); | ||
2100 | GNUNET_free_non_null (agent->s_old); | ||
2101 | GNUNET_free (agent); | ||
2102 | } | ||
2103 | |||
2104 | /** | ||
2105 | * Returns the agent for a peer | ||
2106 | * | ||
2107 | * @param solver the solver handle | ||
2108 | * @param peer the identity of the peer | ||
2109 | * @param create whether or not to create an agent, if none is allocated yet | ||
2110 | * @return the agent | ||
2111 | */ | ||
2112 | static struct RIL_Peer_Agent * | ||
2113 | ril_get_agent (struct GAS_RIL_Handle *solver, const struct | ||
2114 | GNUNET_PeerIdentity *peer, int create) | ||
2115 | { | ||
2116 | struct RIL_Peer_Agent *cur; | ||
2117 | |||
2118 | for (cur = solver->agents_head; NULL != cur; cur = cur->next) | ||
2119 | { | ||
2120 | if (0 == GNUNET_memcmp (peer, &cur->peer)) | ||
2121 | { | ||
2122 | return cur; | ||
2123 | } | ||
2124 | } | ||
2125 | |||
2126 | if (create) | ||
2127 | { | ||
2128 | cur = agent_init (solver, peer); | ||
2129 | GNUNET_CONTAINER_DLL_insert_tail (solver->agents_head, solver->agents_tail, | ||
2130 | cur); | ||
2131 | return cur; | ||
2132 | } | ||
2133 | return NULL; | ||
2134 | } | ||
2135 | |||
2136 | /** | ||
2137 | * Determine whether at least the minimum bandwidth is set for the network. Otherwise the network is | ||
2138 | * considered inactive and not used. Addresses in an inactive network are ignored. | ||
2139 | * | ||
2140 | * @param solver solver handle | ||
2141 | * @param network the network type | ||
2142 | * @return whether or not the network is considered active | ||
2143 | */ | ||
2144 | static int | ||
2145 | ril_network_is_active (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType | ||
2146 | network) | ||
2147 | { | ||
2148 | struct RIL_Scope *net; | ||
2149 | |||
2150 | net = ril_get_network (solver, network); | ||
2151 | return net->bw_out_available >= RIL_MIN_BW; | ||
2152 | } | ||
2153 | |||
2154 | /** | ||
2155 | * Cuts a slice out of a vector of elements. This is used to decrease the size of the matrix storing | ||
2156 | * the reward function approximation. It copies the memory, which is not cut, to the new vector, | ||
2157 | * frees the memory of the old vector, and redirects the pointer to the new one. | ||
2158 | * | ||
2159 | * @param old pointer to the pointer to the first element of the vector | ||
2160 | * @param element_size byte size of the vector elements | ||
2161 | * @param hole_start the first element to cut out | ||
2162 | * @param hole_length the number of elements to cut out | ||
2163 | * @param old_length the length of the old vector | ||
2164 | */ | ||
2165 | static void | ||
2166 | ril_cut_from_vector (void **old, | ||
2167 | size_t element_size, | ||
2168 | unsigned int hole_start, | ||
2169 | unsigned int hole_length, | ||
2170 | unsigned int old_length) | ||
2171 | { | ||
2172 | char *tmpptr; | ||
2173 | char *oldptr = (char *) *old; | ||
2174 | size_t size; | ||
2175 | unsigned int bytes_before; | ||
2176 | unsigned int bytes_hole; | ||
2177 | unsigned int bytes_after; | ||
2178 | |||
2179 | GNUNET_assert (old_length >= hole_length); | ||
2180 | GNUNET_assert (old_length >= (hole_start + hole_length)); | ||
2181 | |||
2182 | size = element_size * (old_length - hole_length); | ||
2183 | |||
2184 | bytes_before = element_size * hole_start; | ||
2185 | bytes_hole = element_size * hole_length; | ||
2186 | bytes_after = element_size * (old_length - hole_start - hole_length); | ||
2187 | |||
2188 | if (0 == size) | ||
2189 | { | ||
2190 | tmpptr = NULL; | ||
2191 | } | ||
2192 | else | ||
2193 | { | ||
2194 | tmpptr = GNUNET_malloc (size); | ||
2195 | GNUNET_memcpy (tmpptr, oldptr, bytes_before); | ||
2196 | GNUNET_memcpy (tmpptr + bytes_before, oldptr + (bytes_before + bytes_hole), | ||
2197 | bytes_after); | ||
2198 | } | ||
2199 | if (NULL != *old) | ||
2200 | { | ||
2201 | GNUNET_free (*old); | ||
2202 | } | ||
2203 | *old = (void *) tmpptr; | ||
2204 | } | ||
2205 | |||
2206 | /* | ||
2207 | * Solver API functions | ||
2208 | * --------------------------- | ||
2209 | */ | ||
2210 | |||
2211 | /** | ||
2212 | * Change relative preference for quality in solver | ||
2213 | * | ||
2214 | * @param solver the solver handle | ||
2215 | * @param peer the peer to change the preference for | ||
2216 | * @param kind the kind to change the preference | ||
2217 | * @param pref_rel the normalized preference value for this kind over all clients | ||
2218 | */ | ||
2219 | static void | ||
2220 | GAS_ril_address_change_preference (void *solver, | ||
2221 | const struct GNUNET_PeerIdentity *peer, | ||
2222 | enum GNUNET_ATS_PreferenceKind kind, | ||
2223 | double pref_rel) | ||
2224 | { | ||
2225 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2226 | "API_address_change_preference() Preference '%s' for peer '%s' changed to %.2f \n", | ||
2227 | GNUNET_ATS_print_preference_type (kind), GNUNET_i2s (peer), pref_rel); | ||
2228 | |||
2229 | struct GAS_RIL_Handle *s = solver; | ||
2230 | |||
2231 | s->parameters.temperature = s->parameters.temperature_init; | ||
2232 | s->parameters.epsilon = s->parameters.epsilon_init; | ||
2233 | ril_step (s); | ||
2234 | } | ||
2235 | |||
2236 | |||
2237 | /** | ||
2238 | * Add a new address for a peer to the solver | ||
2239 | * | ||
2240 | * The address is already contained in the addresses hashmap! | ||
2241 | * | ||
2242 | * @param solver the solver Handle | ||
2243 | * @param address the address to add | ||
2244 | * @param network network type of this address | ||
2245 | */ | ||
2246 | static void | ||
2247 | GAS_ril_address_add (void *solver, | ||
2248 | struct ATS_Address *address, | ||
2249 | uint32_t network) | ||
2250 | { | ||
2251 | struct GAS_RIL_Handle *s = solver; | ||
2252 | struct RIL_Peer_Agent *agent; | ||
2253 | struct RIL_Address_Wrapped *address_wrapped; | ||
2254 | struct RIL_Scope *net; | ||
2255 | unsigned int m_new; | ||
2256 | unsigned int m_old; | ||
2257 | unsigned int n_new; | ||
2258 | unsigned int n_old; | ||
2259 | int i; | ||
2260 | unsigned int zero; | ||
2261 | |||
2262 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2263 | "API_address_add()\n"); | ||
2264 | |||
2265 | net = ril_get_network (s, network); | ||
2266 | address->solver_information = net; | ||
2267 | |||
2268 | if (! ril_network_is_active (s, network)) | ||
2269 | { | ||
2270 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2271 | "API_address_add() Did not add %s address %s for peer '%s', network does not have enough bandwidth\n", | ||
2272 | address->plugin, address->addr, GNUNET_i2s (&address->peer)); | ||
2273 | return; | ||
2274 | } | ||
2275 | |||
2276 | s->parameters.temperature = s->parameters.temperature_init; | ||
2277 | s->parameters.epsilon = s->parameters.epsilon_init; | ||
2278 | |||
2279 | agent = ril_get_agent (s, &address->peer, GNUNET_YES); | ||
2280 | |||
2281 | // add address | ||
2282 | address_wrapped = GNUNET_new (struct RIL_Address_Wrapped); | ||
2283 | address_wrapped->address_naked = address; | ||
2284 | GNUNET_CONTAINER_DLL_insert_tail (agent->addresses_head, | ||
2285 | agent->addresses_tail, address_wrapped); | ||
2286 | |||
2287 | // increase size of W | ||
2288 | m_new = agent->m + ((s->parameters.rbf_divisor + 1) | ||
2289 | * (s->parameters.rbf_divisor + 1)); | ||
2290 | m_old = agent->m; | ||
2291 | n_new = agent->n + 1; | ||
2292 | n_old = agent->n; | ||
2293 | |||
2294 | GNUNET_array_grow (agent->W, agent->n, n_new); | ||
2295 | agent->n = n_old; | ||
2296 | GNUNET_array_grow (agent->E, agent->n, n_new); | ||
2297 | for (i = 0; i < n_new; i++) | ||
2298 | { | ||
2299 | if (i < n_old) | ||
2300 | { | ||
2301 | agent->m = m_old; | ||
2302 | GNUNET_array_grow (agent->W[i], agent->m, m_new); | ||
2303 | agent->m = m_old; | ||
2304 | GNUNET_array_grow (agent->E[i], agent->m, m_new); | ||
2305 | } | ||
2306 | else | ||
2307 | { | ||
2308 | zero = 0; | ||
2309 | GNUNET_array_grow (agent->W[i], zero, m_new); | ||
2310 | zero = 0; | ||
2311 | GNUNET_array_grow (agent->E[i], zero, m_new); | ||
2312 | } | ||
2313 | } | ||
2314 | |||
2315 | // increase size of old state vector | ||
2316 | agent->m = m_old; | ||
2317 | GNUNET_array_grow (agent->s_old, agent->m, m_new); | ||
2318 | |||
2319 | ril_try_unblock_agent (s, agent, GNUNET_NO); | ||
2320 | |||
2321 | ril_step (s); | ||
2322 | |||
2323 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2324 | "API_address_add() Added %s %s address %s for peer '%s'\n", | ||
2325 | address->active ? "active" : "inactive", address->plugin, address->addr, | ||
2326 | GNUNET_i2s (&address->peer)); | ||
2327 | } | ||
2328 | |||
2329 | /** | ||
2330 | * Delete an address in the solver | ||
2331 | * | ||
2332 | * The address is not contained in the address hashmap anymore! | ||
2333 | * | ||
2334 | * @param solver the solver handle | ||
2335 | * @param address the address to remove | ||
2336 | */ | ||
2337 | static void | ||
2338 | GAS_ril_address_delete (void *solver, | ||
2339 | struct ATS_Address *address) | ||
2340 | { | ||
2341 | struct GAS_RIL_Handle *s = solver; | ||
2342 | struct RIL_Peer_Agent *agent; | ||
2343 | struct RIL_Address_Wrapped *address_wrapped; | ||
2344 | int address_index; | ||
2345 | unsigned int m_new; | ||
2346 | unsigned int n_new; | ||
2347 | int i; | ||
2348 | struct RIL_Scope *net; | ||
2349 | |||
2350 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2351 | "API_address_delete() Delete %s %s address %s for peer '%s'\n", | ||
2352 | address->active ? "active" : "inactive", | ||
2353 | address->plugin, | ||
2354 | address->addr, | ||
2355 | GNUNET_i2s (&address->peer)); | ||
2356 | |||
2357 | agent = ril_get_agent (s, &address->peer, GNUNET_NO); | ||
2358 | if (NULL == agent) | ||
2359 | { | ||
2360 | net = address->solver_information; | ||
2361 | GNUNET_assert (! ril_network_is_active (s, net->type)); | ||
2362 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2363 | "No agent allocated for peer yet, since address was in inactive network\n"); | ||
2364 | return; | ||
2365 | } | ||
2366 | |||
2367 | s->parameters.temperature = s->parameters.temperature_init; | ||
2368 | s->parameters.epsilon = s->parameters.epsilon_init; | ||
2369 | |||
2370 | address_index = agent_address_get_index (agent, address); | ||
2371 | address_wrapped = agent_address_get_wrapped (agent, address); | ||
2372 | |||
2373 | if (NULL == address_wrapped) | ||
2374 | { | ||
2375 | net = address->solver_information; | ||
2376 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2377 | "Address not considered by agent, address was in inactive network\n"); | ||
2378 | return; | ||
2379 | } | ||
2380 | GNUNET_CONTAINER_DLL_remove (agent->addresses_head, | ||
2381 | agent->addresses_tail, | ||
2382 | address_wrapped); | ||
2383 | GNUNET_free (address_wrapped); | ||
2384 | |||
2385 | // decrease W | ||
2386 | m_new = agent->m - ((s->parameters.rbf_divisor + 1) | ||
2387 | * (s->parameters.rbf_divisor + 1)); | ||
2388 | n_new = agent->n - 1; | ||
2389 | |||
2390 | for (i = 0; i < agent->n; i++) | ||
2391 | { | ||
2392 | ril_cut_from_vector ((void **) &agent->W[i], sizeof(double), | ||
2393 | address_index * ((s->parameters.rbf_divisor + 1) | ||
2394 | * (s->parameters.rbf_divisor + 1)), | ||
2395 | ((s->parameters.rbf_divisor + 1) | ||
2396 | * (s->parameters.rbf_divisor + 1)), agent->m); | ||
2397 | ril_cut_from_vector ((void **) &agent->E[i], sizeof(double), | ||
2398 | address_index * ((s->parameters.rbf_divisor + 1) | ||
2399 | * (s->parameters.rbf_divisor + 1)), | ||
2400 | ((s->parameters.rbf_divisor + 1) | ||
2401 | * (s->parameters.rbf_divisor + 1)), agent->m); | ||
2402 | } | ||
2403 | GNUNET_free_non_null (agent->W[RIL_ACTION_TYPE_NUM + address_index]); | ||
2404 | GNUNET_free_non_null (agent->E[RIL_ACTION_TYPE_NUM + address_index]); | ||
2405 | ril_cut_from_vector ((void **) &agent->W, sizeof(double *), | ||
2406 | RIL_ACTION_TYPE_NUM + address_index, | ||
2407 | 1, agent->n); | ||
2408 | ril_cut_from_vector ((void **) &agent->E, sizeof(double *), | ||
2409 | RIL_ACTION_TYPE_NUM + address_index, | ||
2410 | 1, agent->n); | ||
2411 | // correct last action | ||
2412 | if (agent->a_old > (RIL_ACTION_TYPE_NUM + address_index)) | ||
2413 | { | ||
2414 | agent->a_old -= 1; | ||
2415 | } | ||
2416 | else if (agent->a_old == (RIL_ACTION_TYPE_NUM + address_index)) | ||
2417 | { | ||
2418 | agent->a_old = RIL_ACTION_INVALID; | ||
2419 | } | ||
2420 | // decrease old state vector | ||
2421 | ril_cut_from_vector ((void **) &agent->s_old, sizeof(double), | ||
2422 | address_index * ((s->parameters.rbf_divisor + 1) | ||
2423 | * (s->parameters.rbf_divisor + 1)), | ||
2424 | ((s->parameters.rbf_divisor + 1) | ||
2425 | * (s->parameters.rbf_divisor + 1)), agent->m); | ||
2426 | agent->m = m_new; | ||
2427 | agent->n = n_new; | ||
2428 | |||
2429 | if (agent->address_inuse == address) | ||
2430 | { | ||
2431 | if (NULL != agent->addresses_head) // if peer has an address left, use it | ||
2432 | { | ||
2433 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2434 | "Active address died, suggesting alternative!\n"); | ||
2435 | envi_set_active_suggestion (s, | ||
2436 | agent, | ||
2437 | agent->addresses_head->address_naked, | ||
2438 | agent->bw_in, | ||
2439 | agent->bw_out, | ||
2440 | GNUNET_YES); | ||
2441 | } | ||
2442 | else | ||
2443 | { | ||
2444 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2445 | "Active address died, suggesting disconnect!\n"); | ||
2446 | envi_set_active_suggestion (s, agent, NULL, 0, 0, GNUNET_NO); | ||
2447 | } | ||
2448 | } | ||
2449 | ril_step (solver); | ||
2450 | if (agent->suggestion_address == address) | ||
2451 | { | ||
2452 | agent->suggestion_issue = GNUNET_NO; | ||
2453 | agent->suggestion_address = NULL; | ||
2454 | } | ||
2455 | GNUNET_assert (agent->address_inuse != address); | ||
2456 | } | ||
2457 | |||
2458 | |||
2459 | /** | ||
2460 | * Update the properties of an address in the solver | ||
2461 | * | ||
2462 | * @param solver solver handle | ||
2463 | * @param address the address | ||
2464 | */ | ||
2465 | static void | ||
2466 | GAS_ril_address_property_changed (void *solver, | ||
2467 | struct ATS_Address *address) | ||
2468 | { | ||
2469 | struct GAS_RIL_Handle *s = solver; | ||
2470 | |||
2471 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2472 | "Properties for peer '%s' address changed\n", | ||
2473 | GNUNET_i2s (&address->peer)); | ||
2474 | s->parameters.temperature = s->parameters.temperature_init; | ||
2475 | s->parameters.epsilon = s->parameters.epsilon_init; | ||
2476 | ril_step (s); | ||
2477 | } | ||
2478 | |||
2479 | |||
2480 | /** | ||
2481 | * Give feedback about the current assignment | ||
2482 | * | ||
2483 | * @param solver the solver handle | ||
2484 | * @param application the application | ||
2485 | * @param peer the peer to change the preference for | ||
2486 | * @param scope the time interval for this feedback: [now - scope .. now] | ||
2487 | * @param kind the kind to change the preference | ||
2488 | * @param score the score | ||
2489 | */ | ||
2490 | static void | ||
2491 | GAS_ril_address_preference_feedback (void *solver, | ||
2492 | struct GNUNET_SERVICE_Client *application, | ||
2493 | const struct GNUNET_PeerIdentity *peer, | ||
2494 | const struct GNUNET_TIME_Relative scope, | ||
2495 | enum GNUNET_ATS_PreferenceKind kind, | ||
2496 | double score) | ||
2497 | { | ||
2498 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2499 | "API_address_preference_feedback() Peer '%s' got a feedback of %+.3f from application %s for " | ||
2500 | "preference %s for %d seconds\n", | ||
2501 | GNUNET_i2s (peer), | ||
2502 | "UNKNOWN", | ||
2503 | GNUNET_ATS_print_preference_type (kind), | ||
2504 | scope.rel_value_us / 1000000); | ||
2505 | } | ||
2506 | |||
2507 | |||
2508 | /** | ||
2509 | * Start a bulk operation | ||
2510 | * | ||
2511 | * @param solver the solver | ||
2512 | */ | ||
2513 | static void | ||
2514 | GAS_ril_bulk_start (void *solver) | ||
2515 | { | ||
2516 | struct GAS_RIL_Handle *s = solver; | ||
2517 | |||
2518 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2519 | "API_bulk_start() lock: %d\n", s->bulk_lock + 1); | ||
2520 | |||
2521 | s->bulk_lock++; | ||
2522 | } | ||
2523 | |||
2524 | |||
2525 | /** | ||
2526 | * Bulk operation done | ||
2527 | * | ||
2528 | * @param solver the solver handle | ||
2529 | */ | ||
2530 | static void | ||
2531 | GAS_ril_bulk_stop (void *solver) | ||
2532 | { | ||
2533 | struct GAS_RIL_Handle *s = solver; | ||
2534 | |||
2535 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2536 | "API_bulk_stop() lock: %d\n", | ||
2537 | s->bulk_lock - 1); | ||
2538 | |||
2539 | if (s->bulk_lock < 1) | ||
2540 | { | ||
2541 | GNUNET_break (0); | ||
2542 | return; | ||
2543 | } | ||
2544 | s->bulk_lock--; | ||
2545 | |||
2546 | if (0 < s->bulk_changes) | ||
2547 | { | ||
2548 | ril_step (solver); | ||
2549 | s->bulk_changes = 0; | ||
2550 | } | ||
2551 | } | ||
2552 | |||
2553 | |||
2554 | /** | ||
2555 | * Tell solver to notify ATS if the address to use changes for a specific | ||
2556 | * peer using the bandwidth changed callback | ||
2557 | * | ||
2558 | * The solver must only notify about changes for peers with pending address | ||
2559 | * requests! | ||
2560 | * | ||
2561 | * @param solver the solver handle | ||
2562 | * @param peer the identity of the peer | ||
2563 | */ | ||
2564 | static void | ||
2565 | GAS_ril_get_preferred_address (void *solver, | ||
2566 | const struct GNUNET_PeerIdentity *peer) | ||
2567 | { | ||
2568 | struct GAS_RIL_Handle *s = solver; | ||
2569 | struct RIL_Peer_Agent *agent; | ||
2570 | |||
2571 | LOG (GNUNET_ERROR_TYPE_DEBUG, "API_get_preferred_address()\n"); | ||
2572 | |||
2573 | agent = ril_get_agent (s, peer, GNUNET_YES); | ||
2574 | |||
2575 | agent->is_active = GNUNET_YES; | ||
2576 | envi_set_active_suggestion (solver, agent, agent->address_inuse, agent->bw_in, | ||
2577 | agent->bw_out, GNUNET_YES); | ||
2578 | |||
2579 | ril_try_unblock_agent (solver, agent, GNUNET_YES); | ||
2580 | |||
2581 | if (agent->address_inuse) | ||
2582 | { | ||
2583 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2584 | "API_get_preferred_address() Activated agent for peer '%s' with %s address %s\n", | ||
2585 | GNUNET_i2s (peer), agent->address_inuse->plugin, | ||
2586 | agent->address_inuse->addr); | ||
2587 | } | ||
2588 | else | ||
2589 | { | ||
2590 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2591 | "API_get_preferred_address() Activated agent for peer '%s', but no address available\n", | ||
2592 | GNUNET_i2s (peer)); | ||
2593 | s->parameters.temperature = s->parameters.temperature_init; | ||
2594 | s->parameters.epsilon = s->parameters.epsilon_init; | ||
2595 | } | ||
2596 | if (NULL != agent->address_inuse) | ||
2597 | s->env->bandwidth_changed_cb (s->env->cls, | ||
2598 | agent->address_inuse); | ||
2599 | } | ||
2600 | |||
2601 | |||
2602 | /** | ||
2603 | * Tell solver stop notifying ATS about changes for this peers | ||
2604 | * | ||
2605 | * The solver must only notify about changes for peers with pending address | ||
2606 | * requests! | ||
2607 | * | ||
2608 | * @param solver the solver handle | ||
2609 | * @param peer the peer | ||
2610 | */ | ||
2611 | static void | ||
2612 | GAS_ril_stop_get_preferred_address (void *solver, | ||
2613 | const struct GNUNET_PeerIdentity *peer) | ||
2614 | { | ||
2615 | struct GAS_RIL_Handle *s = solver; | ||
2616 | struct RIL_Peer_Agent *agent; | ||
2617 | |||
2618 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2619 | "API_stop_get_preferred_address()"); | ||
2620 | |||
2621 | agent = ril_get_agent (s, peer, GNUNET_NO); | ||
2622 | |||
2623 | if (NULL == agent) | ||
2624 | { | ||
2625 | GNUNET_break (0); | ||
2626 | return; | ||
2627 | } | ||
2628 | if (GNUNET_NO == agent->is_active) | ||
2629 | { | ||
2630 | GNUNET_break (0); | ||
2631 | return; | ||
2632 | } | ||
2633 | |||
2634 | s->parameters.temperature = s->parameters.temperature_init; | ||
2635 | s->parameters.epsilon = s->parameters.epsilon_init; | ||
2636 | |||
2637 | agent->is_active = GNUNET_NO; | ||
2638 | |||
2639 | envi_set_active_suggestion (s, agent, agent->address_inuse, agent->bw_in, | ||
2640 | agent->bw_out, | ||
2641 | GNUNET_YES); | ||
2642 | |||
2643 | ril_step (s); | ||
2644 | |||
2645 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2646 | "API_stop_get_preferred_address() Paused agent for peer '%s'\n", | ||
2647 | GNUNET_i2s (peer)); | ||
2648 | } | ||
2649 | |||
2650 | |||
2651 | /** | ||
2652 | * Entry point for the plugin | ||
2653 | * | ||
2654 | * @param cls pointer to the 'struct GNUNET_ATS_PluginEnvironment' | ||
2655 | */ | ||
2656 | void * | ||
2657 | libgnunet_plugin_ats_ril_init (void *cls) | ||
2658 | { | ||
2659 | static struct GNUNET_ATS_SolverFunctions sf; | ||
2660 | struct GNUNET_ATS_PluginEnvironment *env = cls; | ||
2661 | struct GAS_RIL_Handle *solver = GNUNET_new (struct GAS_RIL_Handle); | ||
2662 | struct RIL_Scope *cur; | ||
2663 | int c; | ||
2664 | char *string; | ||
2665 | float f_tmp; | ||
2666 | |||
2667 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2668 | "API_init() Initializing RIL solver\n"); | ||
2669 | |||
2670 | GNUNET_assert (NULL != env); | ||
2671 | GNUNET_assert (NULL != env->cfg); | ||
2672 | GNUNET_assert (NULL != env->stats); | ||
2673 | GNUNET_assert (NULL != env->bandwidth_changed_cb); | ||
2674 | GNUNET_assert (NULL != env->get_preferences); | ||
2675 | |||
2676 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "ats", | ||
2677 | "RIL_RBF_DIVISOR", | ||
2678 | &solver->parameters. | ||
2679 | rbf_divisor)) | ||
2680 | { | ||
2681 | solver->parameters.rbf_divisor = RIL_DEFAULT_RBF_DIVISOR; | ||
2682 | } | ||
2683 | |||
2684 | if (GNUNET_OK | ||
2685 | != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", | ||
2686 | "RIL_STEP_TIME_MIN", | ||
2687 | &solver->parameters.step_time_min)) | ||
2688 | { | ||
2689 | solver->parameters.step_time_min = RIL_DEFAULT_STEP_TIME_MIN; | ||
2690 | } | ||
2691 | |||
2692 | if (GNUNET_OK | ||
2693 | != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", | ||
2694 | "RIL_STEP_TIME_MAX", | ||
2695 | &solver->parameters.step_time_max)) | ||
2696 | { | ||
2697 | solver->parameters.step_time_max = RIL_DEFAULT_STEP_TIME_MAX; | ||
2698 | } | ||
2699 | |||
2700 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", | ||
2701 | "RIL_ALGORITHM", | ||
2702 | &string)) | ||
2703 | { | ||
2704 | GNUNET_STRINGS_utf8_toupper (string, string); | ||
2705 | if (0 == strcmp (string, "SARSA")) | ||
2706 | { | ||
2707 | solver->parameters.algorithm = RIL_ALGO_SARSA; | ||
2708 | } | ||
2709 | if (0 == strcmp (string, "Q-LEARNING")) | ||
2710 | { | ||
2711 | solver->parameters.algorithm = RIL_ALGO_Q; | ||
2712 | } | ||
2713 | |||
2714 | GNUNET_free (string); | ||
2715 | } | ||
2716 | else | ||
2717 | { | ||
2718 | solver->parameters.algorithm = RIL_DEFAULT_ALGORITHM; | ||
2719 | } | ||
2720 | |||
2721 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", | ||
2722 | "RIL_SELECT", | ||
2723 | &string)) | ||
2724 | { | ||
2725 | solver->parameters.select = ! strcmp (string, "EGREEDY") ? | ||
2726 | RIL_SELECT_EGREEDY : RIL_SELECT_SOFTMAX; | ||
2727 | GNUNET_free (string); | ||
2728 | } | ||
2729 | else | ||
2730 | { | ||
2731 | solver->parameters.select = RIL_DEFAULT_SELECT; | ||
2732 | } | ||
2733 | |||
2734 | |||
2735 | solver->parameters.beta = RIL_DEFAULT_DISCOUNT_BETA; | ||
2736 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2737 | "RIL_DISCOUNT_BETA", | ||
2738 | &f_tmp)) | ||
2739 | { | ||
2740 | if (f_tmp < 0.0) | ||
2741 | { | ||
2742 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2743 | "RIL_DISCOUNT_BETA", f_tmp); | ||
2744 | } | ||
2745 | else | ||
2746 | { | ||
2747 | solver->parameters.beta = f_tmp; | ||
2748 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2749 | "RIL_DISCOUNT_BETA", f_tmp); | ||
2750 | } | ||
2751 | } | ||
2752 | |||
2753 | solver->parameters.gamma = RIL_DEFAULT_DISCOUNT_GAMMA; | ||
2754 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2755 | "RIL_DISCOUNT_GAMMA", | ||
2756 | &f_tmp)) | ||
2757 | { | ||
2758 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2759 | { | ||
2760 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2761 | "RIL_DISCOUNT_GAMMA", f_tmp); | ||
2762 | } | ||
2763 | else | ||
2764 | { | ||
2765 | solver->parameters.gamma = f_tmp; | ||
2766 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2767 | "RIL_DISCOUNT_GAMMA", f_tmp); | ||
2768 | } | ||
2769 | } | ||
2770 | |||
2771 | solver->parameters.alpha = RIL_DEFAULT_GRADIENT_STEP_SIZE; | ||
2772 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2773 | "RIL_GRADIENT_STEP_SIZE", | ||
2774 | &f_tmp)) | ||
2775 | { | ||
2776 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2777 | { | ||
2778 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2779 | "RIL_GRADIENT_STEP_SIZE", f_tmp); | ||
2780 | } | ||
2781 | else | ||
2782 | { | ||
2783 | solver->parameters.alpha = f_tmp; | ||
2784 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2785 | "RIL_GRADIENT_STEP_SIZE", f_tmp); | ||
2786 | } | ||
2787 | } | ||
2788 | |||
2789 | solver->parameters.lambda = RIL_DEFAULT_TRACE_DECAY; | ||
2790 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2791 | "RIL_TRACE_DECAY", | ||
2792 | &f_tmp)) | ||
2793 | { | ||
2794 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2795 | { | ||
2796 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2797 | "RIL_TRACE_DECAY", f_tmp); | ||
2798 | } | ||
2799 | else | ||
2800 | { | ||
2801 | solver->parameters.lambda = f_tmp; | ||
2802 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2803 | "RIL_TRACE_DECAY", f_tmp); | ||
2804 | } | ||
2805 | } | ||
2806 | |||
2807 | solver->parameters.epsilon_init = RIL_DEFAULT_EXPLORE_RATIO; | ||
2808 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2809 | "RIL_EXPLORE_RATIO", | ||
2810 | &f_tmp)) | ||
2811 | { | ||
2812 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2813 | { | ||
2814 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2815 | "RIL_EXPLORE_RATIO", f_tmp); | ||
2816 | } | ||
2817 | else | ||
2818 | { | ||
2819 | solver->parameters.epsilon_init = f_tmp; | ||
2820 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2821 | "RIL_EXPLORE_RATIO", f_tmp); | ||
2822 | } | ||
2823 | } | ||
2824 | |||
2825 | solver->parameters.epsilon_decay = RIL_DEFAULT_EXPLORE_DECAY; | ||
2826 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2827 | "RIL_EXPLORE_DECAY", | ||
2828 | &f_tmp)) | ||
2829 | { | ||
2830 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2831 | { | ||
2832 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2833 | "RIL_EXPLORE_DECAY", f_tmp); | ||
2834 | } | ||
2835 | else | ||
2836 | { | ||
2837 | solver->parameters.epsilon_decay = f_tmp; | ||
2838 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2839 | "RIL_EXPLORE_DECAY", f_tmp); | ||
2840 | } | ||
2841 | } | ||
2842 | |||
2843 | solver->parameters.temperature_init = RIL_DEFAULT_TEMPERATURE; | ||
2844 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2845 | "RIL_TEMPERATURE", | ||
2846 | &f_tmp)) | ||
2847 | { | ||
2848 | if (f_tmp <= 0.0) | ||
2849 | { | ||
2850 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2851 | "RIL_TEMPERATURE", f_tmp); | ||
2852 | } | ||
2853 | else | ||
2854 | { | ||
2855 | solver->parameters.temperature_init = f_tmp; | ||
2856 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2857 | "RIL_TEMPERATURE", f_tmp); | ||
2858 | } | ||
2859 | } | ||
2860 | |||
2861 | solver->parameters.temperature_decay = RIL_DEFAULT_TEMPERATURE_DECAY; | ||
2862 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2863 | "RIL_TEMPERATURE_DECAY", | ||
2864 | &f_tmp)) | ||
2865 | { | ||
2866 | if ((f_tmp <= 0.0) ||(solver->parameters.temperature_decay > 1) ) | ||
2867 | { | ||
2868 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2869 | "RIL_TEMPERATURE_DECAY", f_tmp); | ||
2870 | } | ||
2871 | else | ||
2872 | { | ||
2873 | solver->parameters.temperature_decay = f_tmp; | ||
2874 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2875 | "RIL_TEMPERATURE_DECAY", f_tmp); | ||
2876 | } | ||
2877 | } | ||
2878 | |||
2879 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "ats", | ||
2880 | "RIL_SIMULATE", | ||
2881 | &solver->simulate)) | ||
2882 | { | ||
2883 | solver->simulate = GNUNET_NO; | ||
2884 | } | ||
2885 | |||
2886 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "ats", | ||
2887 | "RIL_REPLACE_TRACES")) | ||
2888 | { | ||
2889 | solver->parameters.eligibility_trace_mode = RIL_E_REPLACE; | ||
2890 | } | ||
2891 | else | ||
2892 | { | ||
2893 | solver->parameters.eligibility_trace_mode = RIL_E_ACCUMULATE; | ||
2894 | } | ||
2895 | |||
2896 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", | ||
2897 | "RIL_SOCIAL_WELFARE", | ||
2898 | &string)) | ||
2899 | { | ||
2900 | solver->parameters.social_welfare = ! strcmp (string, "NASH") ? | ||
2901 | RIL_WELFARE_NASH : | ||
2902 | RIL_WELFARE_EGALITARIAN; | ||
2903 | GNUNET_free (string); | ||
2904 | } | ||
2905 | else | ||
2906 | { | ||
2907 | solver->parameters.social_welfare = RIL_DEFAULT_WELFARE; | ||
2908 | } | ||
2909 | |||
2910 | solver->env = env; | ||
2911 | sf.cls = solver; | ||
2912 | sf.s_add = &GAS_ril_address_add; | ||
2913 | sf.s_address_update_property = &GAS_ril_address_property_changed; | ||
2914 | sf.s_get = &GAS_ril_get_preferred_address; | ||
2915 | sf.s_get_stop = &GAS_ril_stop_get_preferred_address; | ||
2916 | sf.s_pref = &GAS_ril_address_change_preference; | ||
2917 | sf.s_feedback = &GAS_ril_address_preference_feedback; | ||
2918 | sf.s_del = &GAS_ril_address_delete; | ||
2919 | sf.s_bulk_start = &GAS_ril_bulk_start; | ||
2920 | sf.s_bulk_stop = &GAS_ril_bulk_stop; | ||
2921 | |||
2922 | solver->networks_count = env->network_count; | ||
2923 | solver->network_entries = GNUNET_malloc (env->network_count * sizeof(struct | ||
2924 | RIL_Scope)); | ||
2925 | solver->step_count = 0; | ||
2926 | solver->done = GNUNET_NO; | ||
2927 | |||
2928 | for (c = 0; c < env->network_count; c++) | ||
2929 | { | ||
2930 | cur = &solver->network_entries[c]; | ||
2931 | cur->type = c; | ||
2932 | cur->bw_in_available = env->in_quota[c]; | ||
2933 | cur->bw_out_available = env->out_quota[c]; | ||
2934 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2935 | "init() Quotas for %s network: IN %llu - OUT %llu\n", | ||
2936 | GNUNET_NT_to_string (cur->type), | ||
2937 | cur->bw_in_available / 1024, | ||
2938 | cur->bw_out_available / 1024); | ||
2939 | } | ||
2940 | |||
2941 | LOG (GNUNET_ERROR_TYPE_DEBUG, "init() Parameters:\n"); | ||
2942 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2943 | "init() Algorithm = %s, alpha = %f, beta = %f, lambda = %f\n", | ||
2944 | solver->parameters.algorithm ? "Q" : "SARSA", | ||
2945 | solver->parameters.alpha, | ||
2946 | solver->parameters.beta, | ||
2947 | solver->parameters.lambda); | ||
2948 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2949 | "init() exploration_ratio = %f, temperature = %f, ActionSelection = %s\n", | ||
2950 | solver->parameters.epsilon, | ||
2951 | solver->parameters.temperature, | ||
2952 | solver->parameters.select ? "EGREEDY" : "SOFTMAX"); | ||
2953 | LOG (GNUNET_ERROR_TYPE_DEBUG, "init() RBF_DIVISOR = %llu\n", | ||
2954 | solver->parameters.rbf_divisor); | ||
2955 | |||
2956 | return &sf; | ||
2957 | } | ||
2958 | |||
2959 | |||
2960 | /** | ||
2961 | * Exit point for the plugin | ||
2962 | * | ||
2963 | * @param cls the solver handle | ||
2964 | */ | ||
2965 | void * | ||
2966 | libgnunet_plugin_ats_ril_done (void *cls) | ||
2967 | { | ||
2968 | struct GNUNET_ATS_SolverFunctions *sf = cls; | ||
2969 | struct GAS_RIL_Handle *s = sf->cls; | ||
2970 | struct RIL_Peer_Agent *cur_agent; | ||
2971 | struct RIL_Peer_Agent *next_agent; | ||
2972 | |||
2973 | LOG (GNUNET_ERROR_TYPE_DEBUG, "API_done() Shutting down RIL solver\n"); | ||
2974 | |||
2975 | s->done = GNUNET_YES; | ||
2976 | |||
2977 | cur_agent = s->agents_head; | ||
2978 | while (NULL != cur_agent) | ||
2979 | { | ||
2980 | next_agent = cur_agent->next; | ||
2981 | GNUNET_CONTAINER_DLL_remove (s->agents_head, s->agents_tail, cur_agent); | ||
2982 | agent_die (s, cur_agent); | ||
2983 | cur_agent = next_agent; | ||
2984 | } | ||
2985 | |||
2986 | if (NULL != s->step_next_task_id) | ||
2987 | { | ||
2988 | GNUNET_SCHEDULER_cancel (s->step_next_task_id); | ||
2989 | } | ||
2990 | GNUNET_free (s->network_entries); | ||
2991 | GNUNET_free (s); | ||
2992 | |||
2993 | return NULL; | ||
2994 | } | ||
2995 | |||
2996 | |||
2997 | /* end of plugin_ats_ril.c */ | ||
diff --git a/src/ats/test_ats2_lib.c b/src/ats/test_ats2_lib.c deleted file mode 100644 index f2a8eb1ea..000000000 --- a/src/ats/test_ats2_lib.c +++ /dev/null | |||
@@ -1,259 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010-2015 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/test_ats2_lib.c | ||
20 | * @brief test ATS library with a generic interpreter for running ATS tests | ||
21 | * @author Julius Bünger | ||
22 | */ | ||
23 | #include "platform.h" | ||
24 | #include "gnunet_util_lib.h" | ||
25 | #include "gnunet_ats_application_service.h" | ||
26 | #include "gnunet_ats_transport_service.h" | ||
27 | #include "gnunet_testing_lib.h" | ||
28 | |||
29 | /** | ||
30 | * @brief Indicates the success of the whole test | ||
31 | */ | ||
32 | static int ret; | ||
33 | |||
34 | /** | ||
35 | * @brief The time available until the test shuts down | ||
36 | */ | ||
37 | static struct GNUNET_TIME_Relative timeout; | ||
38 | |||
39 | /** | ||
40 | * @brief ATS Application Handle | ||
41 | * | ||
42 | * Handle to the application-side of ATS. | ||
43 | */ | ||
44 | static struct GNUNET_ATS_ApplicationHandle *ah; | ||
45 | |||
46 | /** | ||
47 | * @brief ATS Transport Handle | ||
48 | * | ||
49 | * Handle to the transport-side of ATS. | ||
50 | */ | ||
51 | static struct GNUNET_ATS_TransportHandle *th; | ||
52 | |||
53 | /** | ||
54 | * @brief Another (dummy) peer. | ||
55 | * | ||
56 | * Used as the peer ATS shall allocate bandwidth to. | ||
57 | */ | ||
58 | static struct GNUNET_PeerIdentity other_peer; | ||
59 | |||
60 | /** | ||
61 | * @brief Handle to the session record | ||
62 | */ | ||
63 | static struct GNUNET_ATS_SessionRecord *sr; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * @brief Called whenever allocation changed | ||
68 | * | ||
69 | * Implements #GNUNET_ATS_AllocationCallback | ||
70 | * | ||
71 | * @param cls | ||
72 | * @param session | ||
73 | * @param bandwidth_out | ||
74 | * @param bandwidth_in | ||
75 | * | ||
76 | * @return | ||
77 | */ | ||
78 | static void | ||
79 | allocation_cb (void *cls, | ||
80 | struct GNUNET_ATS_Session *session, | ||
81 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, | ||
82 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in) | ||
83 | { | ||
84 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
85 | "allocation_cb() called\n"); | ||
86 | } | ||
87 | |||
88 | |||
89 | /** | ||
90 | * @brief Called whenever suggestion is made | ||
91 | * | ||
92 | * Implements #GNUNET_ATS_SuggestionCallback | ||
93 | * | ||
94 | * @param cls | ||
95 | * @param pid | ||
96 | * @param address | ||
97 | */ | ||
98 | static void | ||
99 | suggestion_cb (void *cls, | ||
100 | const struct GNUNET_PeerIdentity *pid, | ||
101 | const char *address) | ||
102 | { | ||
103 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
104 | "suggestion_cb() called\n"); | ||
105 | ret = 0; | ||
106 | } | ||
107 | |||
108 | |||
109 | /** | ||
110 | * @brief Initialise both 'sides' of ATS | ||
111 | * | ||
112 | * Initialises the application and transportation side of ATS. | ||
113 | */ | ||
114 | static void | ||
115 | init_both (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
116 | { | ||
117 | ah = GNUNET_ATS_application_init (cfg); | ||
118 | GNUNET_assert (NULL != ah); | ||
119 | th = GNUNET_ATS_transport_init (cfg, | ||
120 | &allocation_cb, | ||
121 | NULL, | ||
122 | &suggestion_cb, | ||
123 | NULL); | ||
124 | GNUNET_assert (NULL != ah); | ||
125 | } | ||
126 | |||
127 | |||
128 | /** | ||
129 | * @brief Disconnect both 'sides' of ATS | ||
130 | */ | ||
131 | static void | ||
132 | finish_both (void) | ||
133 | { | ||
134 | GNUNET_ATS_application_done (ah); | ||
135 | ah = NULL; | ||
136 | GNUNET_ATS_transport_done (th); | ||
137 | th = NULL; | ||
138 | } | ||
139 | |||
140 | |||
141 | /** | ||
142 | * @brief Provide information about the start of an imaginary connection | ||
143 | */ | ||
144 | static void | ||
145 | provide_info_start (void) | ||
146 | { | ||
147 | struct GNUNET_ATS_Properties prop = { | ||
148 | .delay = GNUNET_TIME_UNIT_FOREVER_REL, | ||
149 | .goodput_out = 1048576, | ||
150 | .goodput_in = 1048576, | ||
151 | .utilization_out = 0, | ||
152 | .utilization_in = 0, | ||
153 | .distance = 0, | ||
154 | .mtu = UINT32_MAX, | ||
155 | .nt = GNUNET_NT_UNSPECIFIED, | ||
156 | .cc = GNUNET_TRANSPORT_CC_UNKNOWN, | ||
157 | }; | ||
158 | |||
159 | sr = GNUNET_ATS_session_add (th, | ||
160 | &other_peer, | ||
161 | "test-address", | ||
162 | NULL, | ||
163 | &prop); | ||
164 | GNUNET_assert (NULL != sr); | ||
165 | } | ||
166 | |||
167 | |||
168 | /** | ||
169 | * @brief Provide information about the end of an imaginary connection | ||
170 | */ | ||
171 | static void | ||
172 | provide_info_end (void) | ||
173 | { | ||
174 | GNUNET_ATS_session_del (sr); | ||
175 | } | ||
176 | |||
177 | |||
178 | /** | ||
179 | * @brief Inform ATS about the need of a connection towards a peer | ||
180 | */ | ||
181 | static void | ||
182 | get_suggestion (void) | ||
183 | { | ||
184 | struct GNUNET_ATS_ApplicationSuggestHandle *ash; | ||
185 | |||
186 | ash = GNUNET_ATS_application_suggest (ah, | ||
187 | &other_peer, | ||
188 | GNUNET_MQ_PREFERENCE_NONE, | ||
189 | GNUNET_BANDWIDTH_VALUE_MAX); | ||
190 | GNUNET_assert (NULL != ash); | ||
191 | } | ||
192 | |||
193 | |||
194 | static void | ||
195 | on_shutdown (void *cls) | ||
196 | { | ||
197 | provide_info_end (); | ||
198 | finish_both (); | ||
199 | GNUNET_SCHEDULER_shutdown (); | ||
200 | } | ||
201 | |||
202 | |||
203 | /** | ||
204 | * Function run once the ATS service has been started. | ||
205 | * | ||
206 | * @param cls NULL | ||
207 | * @param cfg configuration for the testcase | ||
208 | * @param peer handle to the peer | ||
209 | */ | ||
210 | static void | ||
211 | run (void *cls, | ||
212 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
213 | struct GNUNET_TESTING_Peer *peer) | ||
214 | { | ||
215 | init_both (cfg); | ||
216 | provide_info_start (); | ||
217 | get_suggestion (); | ||
218 | (void) GNUNET_SCHEDULER_add_delayed (timeout, | ||
219 | &on_shutdown, | ||
220 | NULL); | ||
221 | } | ||
222 | |||
223 | |||
224 | /** | ||
225 | * @brief Starts the gnunet-testing peer | ||
226 | * | ||
227 | * @param argc | ||
228 | * @param argv[] | ||
229 | * | ||
230 | * @return | ||
231 | */ | ||
232 | int | ||
233 | main (int argc, | ||
234 | char *argv[]) | ||
235 | { | ||
236 | ret = 1; | ||
237 | memset (&other_peer, 0, sizeof(struct GNUNET_PeerIdentity)); | ||
238 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
239 | 2); | ||
240 | if (0 != GNUNET_TESTING_peer_run ("test-ats2-lib", | ||
241 | "test_ats2_lib.conf", | ||
242 | &run, NULL)) | ||
243 | { | ||
244 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
245 | "Running the testing peer failed.\n"); | ||
246 | return 1; | ||
247 | } | ||
248 | if (0 != ret) | ||
249 | { | ||
250 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
251 | "Global status indicates unsuccessful testrun - probably allocation_cb was not called.\n"); | ||
252 | ret = 77; // SKIP test, test not yet right! | ||
253 | } | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | |||
258 | |||
259 | /* end of test_ats2_lib.c */ | ||
diff --git a/src/ats/test_ats2_lib.conf b/src/ats/test_ats2_lib.conf deleted file mode 100644 index e24f5ea68..000000000 --- a/src/ats/test_ats2_lib.conf +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | @INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf | ||
3 | |||
4 | [ats] | ||
5 | BINARY = gnunet-service-ats-new | ||
6 | |||
7 | [core] | ||
8 | START_ON_DEMAND = NO | ||
9 | IMMEDIATE_START = NO | ||
10 | |||
11 | [transport] | ||
12 | START_ON_DEMAND = NO | ||
13 | IMMEDIATE_START = NO | ||
diff --git a/src/ats/test_ats2_lib.h b/src/ats/test_ats2_lib.h deleted file mode 100644 index 090abc20d..000000000 --- a/src/ats/test_ats2_lib.h +++ /dev/null | |||
@@ -1,523 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010-2015 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/test_ats_lib.h | ||
20 | * @brief test ATS library with a generic interpreter for running ATS tests | ||
21 | * @author Christian Grothoff | ||
22 | */ | ||
23 | #ifndef TEST_ATS_LIB_H | ||
24 | #define TEST_ATS_LIB_H | ||
25 | |||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_ats_application_service.h" | ||
28 | #include "gnunet_ats_transport_service.h" | ||
29 | #include "gnunet_testing_lib.h" | ||
30 | |||
31 | |||
32 | ///** | ||
33 | // * Commands for the interpreter. | ||
34 | // */ | ||
35 | // enum CommandCode | ||
36 | // { | ||
37 | // /** | ||
38 | // * End the test (passing). | ||
39 | // */ | ||
40 | // CMD_END_PASS = 0, | ||
41 | // | ||
42 | // /** | ||
43 | // * Call #GNUNET_ATS_address_add(). | ||
44 | // */ | ||
45 | // CMD_ADD_ADDRESS, | ||
46 | // | ||
47 | // /** | ||
48 | // * Call #GNUNET_ATS_address_del(). | ||
49 | // */ | ||
50 | // CMD_DEL_ADDRESS, | ||
51 | // | ||
52 | // /** | ||
53 | // * Wait for ATS to suggest address. | ||
54 | // */ | ||
55 | // CMD_AWAIT_ADDRESS_SUGGESTION, | ||
56 | // | ||
57 | // /** | ||
58 | // * Wait for ATS to suggest disconnect. | ||
59 | // */ | ||
60 | // CMD_AWAIT_DISCONNECT_SUGGESTION, | ||
61 | // | ||
62 | // /** | ||
63 | // * Ask ATS to connect to a peer, using | ||
64 | // * #GNUNET_ATS_connectivity_suggest(). | ||
65 | // */ | ||
66 | // CMD_REQUEST_CONNECTION_START, | ||
67 | // | ||
68 | // /** | ||
69 | // * Tell ATS we no longer need a connection to a peer, using | ||
70 | // * #GNUNET_ATS_connectivity_suggest_cancel(). | ||
71 | // */ | ||
72 | // CMD_REQUEST_CONNECTION_STOP, | ||
73 | // | ||
74 | // /** | ||
75 | // * Wait for certain address information to be provided. | ||
76 | // */ | ||
77 | // CMD_AWAIT_ADDRESS_INFORMATION, | ||
78 | // | ||
79 | // /** | ||
80 | // * Update properties of an address, using | ||
81 | // * #GNUNET_ATS_address_update(). | ||
82 | // */ | ||
83 | // CMD_UPDATE_ADDRESS, | ||
84 | // | ||
85 | // /** | ||
86 | // * Add session to an address, using | ||
87 | // * #GNUNET_ATS_address_add_session(). | ||
88 | // */ | ||
89 | // CMD_ADD_SESSION, | ||
90 | // | ||
91 | // /** | ||
92 | // * Remove session from an address, using | ||
93 | // * #GNUNET_ATS_address_del_session(). | ||
94 | // */ | ||
95 | // CMD_DEL_SESSION, | ||
96 | // | ||
97 | // /** | ||
98 | // * Change performance preferences for a peer, testing | ||
99 | // * #GNUNET_ATS_performance_change_preference(). | ||
100 | // */ | ||
101 | // CMD_CHANGE_PREFERENCE, | ||
102 | // | ||
103 | // /** | ||
104 | // * Provide allocation quality feedback, testing | ||
105 | // * #GNUNET_ATS_performance_give_feedback(). | ||
106 | // */ | ||
107 | // CMD_PROVIDE_FEEDBACK, | ||
108 | // | ||
109 | // /** | ||
110 | // * Obtain list of all addresses, testing | ||
111 | // * #GNUNET_ATS_performance_list_addresses(). | ||
112 | // */ | ||
113 | // CMD_LIST_ADDRESSES, | ||
114 | // | ||
115 | // /** | ||
116 | // * Reserve bandwidth, testing | ||
117 | // * #GNUNET_ATS_reserve_bandwidth(). | ||
118 | // */ | ||
119 | // CMD_RESERVE_BANDWIDTH, | ||
120 | // | ||
121 | // /** | ||
122 | // * Wait for a bit. | ||
123 | // */ | ||
124 | // CMD_SLEEP | ||
125 | // | ||
126 | // }; | ||
127 | // | ||
128 | // | ||
129 | ///** | ||
130 | // * Details for the #CMD_ADD_ADDRESS command. | ||
131 | // */ | ||
132 | // struct CommandAddAddress | ||
133 | // { | ||
134 | // /** | ||
135 | // * Number of the peer (used to generate PID). | ||
136 | // */ | ||
137 | // unsigned int pid; | ||
138 | // | ||
139 | // /** | ||
140 | // * Number of the address (used to generate binary address). | ||
141 | // */ | ||
142 | // unsigned int addr_num; | ||
143 | // | ||
144 | // /** | ||
145 | // * Session to supply, 0 for NULL. | ||
146 | // */ | ||
147 | // unsigned int session; | ||
148 | // | ||
149 | // /** | ||
150 | // * Flags to set for the address. | ||
151 | // */ | ||
152 | // enum GNUNET_HELLO_AddressInfo addr_flags; | ||
153 | // | ||
154 | // /** | ||
155 | // * Performance properties to supply. | ||
156 | // */ | ||
157 | // struct GNUNET_ATS_Properties properties; | ||
158 | // | ||
159 | // /** | ||
160 | // * Expect the operation to fail (duplicate). | ||
161 | // */ | ||
162 | // int expect_fail; | ||
163 | // | ||
164 | // /** | ||
165 | // * Here the result of the add address operation will be stored. | ||
166 | // */ | ||
167 | // struct GNUNET_ATS_AddressRecord *ar; | ||
168 | // }; | ||
169 | // | ||
170 | // | ||
171 | ///** | ||
172 | // * Details for the #CMD_DEL_ADDRESS command. | ||
173 | // */ | ||
174 | // struct CommandDelAddress | ||
175 | // { | ||
176 | // /** | ||
177 | // * Label of the corresponding #CMD_ADD_ADDRESS that | ||
178 | // * we are now to remove. | ||
179 | // */ | ||
180 | // const char *add_label; | ||
181 | // }; | ||
182 | // | ||
183 | // | ||
184 | ///** | ||
185 | // * Details for the #CMD_AWAIT_ADDRESS_SUGGESTION command. | ||
186 | // */ | ||
187 | // struct CommandAwaitAddressSuggestion | ||
188 | // { | ||
189 | // /** | ||
190 | // * For which peer do we expect a suggestion? | ||
191 | // */ | ||
192 | // unsigned int pid; | ||
193 | // | ||
194 | // /** | ||
195 | // * If we expect the address suggested to match a particular | ||
196 | // * addition, specify the label of the add operation here. Otherwise | ||
197 | // * use NULL for "any" available address. | ||
198 | // */ | ||
199 | // const char *add_label; | ||
200 | // | ||
201 | // }; | ||
202 | // | ||
203 | // | ||
204 | ///** | ||
205 | // * Details for the #CMD_AWAIT_DISCONNECT_SUGGESTION command. | ||
206 | // */ | ||
207 | // struct CommandAwaitDisconnectSuggestion | ||
208 | // { | ||
209 | // /** | ||
210 | // * For which peer do we expect the disconnect? | ||
211 | // */ | ||
212 | // unsigned int pid; | ||
213 | // | ||
214 | // }; | ||
215 | // | ||
216 | // | ||
217 | ///** | ||
218 | // * Details for the #CMD_REQUEST_CONNECTION_START command. | ||
219 | // */ | ||
220 | // struct CommandRequestConnectionStart | ||
221 | // { | ||
222 | // /** | ||
223 | // * Identity of the peer we would like to connect to. | ||
224 | // */ | ||
225 | // unsigned int pid; | ||
226 | // | ||
227 | // /** | ||
228 | // * Location where we store the handle returned from | ||
229 | // * #GNUNET_ATS_connectivity_suggest(). | ||
230 | // */ | ||
231 | // struct GNUNET_ATS_ConnectivitySuggestHandle *csh; | ||
232 | // }; | ||
233 | // | ||
234 | // | ||
235 | ///** | ||
236 | // * Details for the #CMD_REQUEST_CONNECTION_STOP command. | ||
237 | // */ | ||
238 | // struct CommandRequestConnectionStop | ||
239 | // { | ||
240 | // /** | ||
241 | // * Label of the corresponding #CMD_REQUEST_CONNECTION_START that | ||
242 | // * we are now stopping. | ||
243 | // */ | ||
244 | // const char *connect_label; | ||
245 | // }; | ||
246 | // | ||
247 | // | ||
248 | ///** | ||
249 | // * Details for the #CMD_AWAIT_ADDRESS_INFORMATION command. | ||
250 | // */ | ||
251 | // struct CommandAwaitAddressInformation | ||
252 | // { | ||
253 | // /** | ||
254 | // * For which address do we expect information? | ||
255 | // * The address is identified by the respective | ||
256 | // * label of the corresponding add operation. | ||
257 | // */ | ||
258 | // const char *add_label; | ||
259 | // | ||
260 | // /** | ||
261 | // * Label of a possible update operation that may | ||
262 | // * have modified the properties. NULL to use | ||
263 | // * the properties from the @e add_label. | ||
264 | // */ | ||
265 | // const char *update_label; | ||
266 | // | ||
267 | // }; | ||
268 | // | ||
269 | // | ||
270 | ///** | ||
271 | // * Details for the #CMD_UPDATE_ADDRESS command. | ||
272 | // */ | ||
273 | // struct CommandUpdateAddress | ||
274 | // { | ||
275 | // /** | ||
276 | // * Label of the addresses's add operation. | ||
277 | // */ | ||
278 | // const char *add_label; | ||
279 | // | ||
280 | // /** | ||
281 | // * Performance properties to supply. | ||
282 | // */ | ||
283 | // struct GNUNET_ATS_Properties properties; | ||
284 | // | ||
285 | // }; | ||
286 | // | ||
287 | // | ||
288 | ///** | ||
289 | // * Details for the #CMD_ADD_SESSION command. | ||
290 | // */ | ||
291 | // struct CommandAddSession | ||
292 | // { | ||
293 | // /** | ||
294 | // * Label of the addresses's add operation. | ||
295 | // */ | ||
296 | // const char *add_label; | ||
297 | // | ||
298 | // /** | ||
299 | // * Session to supply. | ||
300 | // */ | ||
301 | // unsigned int session; | ||
302 | // | ||
303 | // }; | ||
304 | // | ||
305 | // | ||
306 | ///** | ||
307 | // * Details for the #CMD_DEL_SESSION command. | ||
308 | // */ | ||
309 | // struct CommandDelSession | ||
310 | // { | ||
311 | // /** | ||
312 | // * Label of the addresses's add operation. | ||
313 | // */ | ||
314 | // const char *add_session_label; | ||
315 | // | ||
316 | // }; | ||
317 | // | ||
318 | // | ||
319 | ///** | ||
320 | // * Details for the #CMD_CHANGE_PREFERENCE command. | ||
321 | // */ | ||
322 | // struct CommandChangePreference | ||
323 | // { | ||
324 | // /** | ||
325 | // * Identity of the peer we have a preference change towards. | ||
326 | // */ | ||
327 | // unsigned int pid; | ||
328 | // | ||
329 | // /* FIXME: preference details! */ | ||
330 | // | ||
331 | // }; | ||
332 | // | ||
333 | // | ||
334 | ///** | ||
335 | // * Details for the #CMD_PROVIDE_FEEDBACK command. | ||
336 | // */ | ||
337 | // struct CommandProvideFeedback | ||
338 | // { | ||
339 | // /** | ||
340 | // * Identity of the peer we have a feedback for. | ||
341 | // */ | ||
342 | // unsigned int pid; | ||
343 | // | ||
344 | // /** | ||
345 | // * Over which timeframe does the feedback apply? | ||
346 | // */ | ||
347 | // struct GNUNET_TIME_Relative scope; | ||
348 | // | ||
349 | // /* FIXME: feedback details! */ | ||
350 | // }; | ||
351 | // | ||
352 | // | ||
353 | ///** | ||
354 | // * Details for the #CMD_LIST_ADDRESSES command. | ||
355 | // */ | ||
356 | // struct CommandListAddresses | ||
357 | // { | ||
358 | // /** | ||
359 | // * Identity of the peer we want a list for. | ||
360 | // */ | ||
361 | // unsigned int pid; | ||
362 | // | ||
363 | // /** | ||
364 | // * All addresses or just active? | ||
365 | // */ | ||
366 | // int all; | ||
367 | // | ||
368 | // /** | ||
369 | // * Minimum number of addresses the callback may report. | ||
370 | // */ | ||
371 | // unsigned int min_calls; | ||
372 | // | ||
373 | // /** | ||
374 | // * Maximum number of addresses the callback may report. | ||
375 | // */ | ||
376 | // unsigned int max_calls; | ||
377 | // | ||
378 | // /** | ||
379 | // * Minimum number of active addresses the callback may report. | ||
380 | // */ | ||
381 | // unsigned int min_active_calls; | ||
382 | // | ||
383 | // /** | ||
384 | // * Maximum number of active addresses the callback may report. | ||
385 | // */ | ||
386 | // unsigned int max_active_calls; | ||
387 | // | ||
388 | // /** | ||
389 | // * Number of calls the command invoked the callback with | ||
390 | // * an address marked as active. (Set by command). | ||
391 | // */ | ||
392 | // unsigned int active_calls; | ||
393 | // | ||
394 | // /** | ||
395 | // * Number of calls the command invoked the callback with | ||
396 | // * any address marked as available to ATS. (Set by command). | ||
397 | // */ | ||
398 | // unsigned int calls; | ||
399 | // | ||
400 | // /** | ||
401 | // * Location where we store the return value from | ||
402 | // * #GNUNET_ATS_performance_list_addresses(). | ||
403 | // */ | ||
404 | // struct GNUNET_ATS_AddressListHandle *alh; | ||
405 | // | ||
406 | // }; | ||
407 | // | ||
408 | // | ||
409 | ///** | ||
410 | // * Details for the #CMD_RESERVE_BANDWIDTH command. | ||
411 | // */ | ||
412 | // struct CommandReserveBandwidth | ||
413 | // { | ||
414 | // /** | ||
415 | // * For which peer do we reserve bandwidth? | ||
416 | // */ | ||
417 | // unsigned int pid; | ||
418 | // | ||
419 | // /** | ||
420 | // * How much should we try to reserve? | ||
421 | // */ | ||
422 | // int32_t amount; | ||
423 | // | ||
424 | // /** | ||
425 | // * Should we expect this to work or fail? | ||
426 | // * #GNUNET_YES: must work | ||
427 | // * #GNUNET_NO: may work or fail | ||
428 | // * #GNUNET_SYSERR: must fail | ||
429 | // */ | ||
430 | // int expected_result; | ||
431 | // | ||
432 | // /** | ||
433 | // * Location where we store the return value from | ||
434 | // * #GNUNET_ATS_reserve_bandwidth(). | ||
435 | // */ | ||
436 | // struct GNUNET_ATS_ReservationContext *rc; | ||
437 | // | ||
438 | // }; | ||
439 | // | ||
440 | // | ||
441 | ///** | ||
442 | // * Details for the #CMD_SLEEP command. | ||
443 | // */ | ||
444 | // struct CommandSleep | ||
445 | // { | ||
446 | // /** | ||
447 | // * How long should we wait before running the next command? | ||
448 | // */ | ||
449 | // struct GNUNET_TIME_Relative delay; | ||
450 | // }; | ||
451 | // | ||
452 | // | ||
453 | ///** | ||
454 | // * A command for the test case interpreter. | ||
455 | // */ | ||
456 | // struct Command | ||
457 | // { | ||
458 | // /** | ||
459 | // * Command code to run. | ||
460 | // */ | ||
461 | // enum CommandCode code; | ||
462 | // | ||
463 | // /** | ||
464 | // * Commands can be given a label so we can reference them later. | ||
465 | // */ | ||
466 | // const char *label; | ||
467 | // | ||
468 | // /** | ||
469 | // * Additional arguments to commands, if any. | ||
470 | // */ | ||
471 | // union { | ||
472 | // | ||
473 | // struct CommandAddAddress add_address; | ||
474 | // | ||
475 | // struct CommandDelAddress del_address; | ||
476 | // | ||
477 | // struct CommandAwaitAddressSuggestion await_address_suggestion; | ||
478 | // | ||
479 | // struct CommandAwaitDisconnectSuggestion await_disconnect_suggestion; | ||
480 | // | ||
481 | // struct CommandRequestConnectionStart request_connection_start; | ||
482 | // | ||
483 | // struct CommandRequestConnectionStop request_connection_stop; | ||
484 | // | ||
485 | // struct CommandAwaitAddressInformation await_address_information; | ||
486 | // | ||
487 | // struct CommandUpdateAddress update_address; | ||
488 | // | ||
489 | // struct CommandAddSession add_session; | ||
490 | // | ||
491 | // struct CommandDelSession del_session; | ||
492 | // | ||
493 | // struct CommandChangePreference change_preference; | ||
494 | // | ||
495 | // struct CommandProvideFeedback provide_feedback; | ||
496 | // | ||
497 | // struct CommandListAddresses list_addresses; | ||
498 | // | ||
499 | // struct CommandReserveBandwidth reserve_bandwidth; | ||
500 | // | ||
501 | // struct CommandSleep sleep; | ||
502 | // | ||
503 | // } details; | ||
504 | // | ||
505 | // }; | ||
506 | |||
507 | |||
508 | /** | ||
509 | * Run ATS test. | ||
510 | * | ||
511 | * @param argc length of @a argv | ||
512 | * @param argv command line | ||
513 | * @param cmds commands to run with the interpreter | ||
514 | * @param timeout how long is the test allowed to take? | ||
515 | * @return 0 on success | ||
516 | */ | ||
517 | int | ||
518 | TEST_ATS_run (int argc, | ||
519 | char *argv[], | ||
520 | struct Command *cmds, | ||
521 | struct GNUNET_TIME_Relative timeout); | ||
522 | |||
523 | #endif | ||
diff --git a/src/ats/test_ats_api_mlp.conf b/src/ats/test_ats_api_mlp.conf deleted file mode 100644 index d5f05a3c4..000000000 --- a/src/ats/test_ats_api_mlp.conf +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | |||
3 | [PATHS] | ||
4 | GNUNET_TEST_HOME = $GNUNET_TMP/test-ats-mlp/ | ||
5 | |||
6 | [ats] | ||
7 | # Enable MLP mode (default: NO) | ||
8 | MODE = mlp | ||
9 | # Network specific inbound/outbound quotas | ||
10 | # UNSPECIFIED | ||
11 | UNSPECIFIED_QUOTA_IN = unlimited | ||
12 | UNSPECIFIED_QUOTA_OUT = unlimited | ||
13 | # LOOPBACK | ||
14 | LOOPBACK_QUOTA_IN = unlimited | ||
15 | LOOPBACK_QUOTA_OUT = unlimited | ||
16 | # LAN | ||
17 | LAN_QUOTA_IN = unlimited | ||
18 | LAN_QUOTA_OUT = unlimited | ||
19 | # WAN | ||
20 | WAN_QUOTA_IN = 64 KiB | ||
21 | WAN_QUOTA_OUT = 64 KiB | ||
22 | # WLAN | ||
23 | WLAN_QUOTA_IN = 4096 | ||
24 | WLAN_QUOTA_OUT = 4096 | ||
25 | |||
26 | # MLP specific settings | ||
27 | ATS_MIN_INTERVAL = 15000 | ||
28 | ATS_EXEC_INTERVAL = 30000 | ||
29 | |||
30 | # MLP defaults | ||
31 | # MLP_MAX_DURATION = 3 s | ||
32 | # MLP_MAX_ITERATIONS = 1024 | ||
33 | # MLP_COEFFICIENT_D = 1.0 | ||
34 | # MLP_COEFFICIENT_U = 1.0 | ||
35 | # MLP_COEFFICIENT_R = 1.0 | ||
36 | # MLP_MIN_BANDWIDTH = 1024 | ||
37 | # MLP_MIN_CONNECTIONS = 4 | ||
38 | |||
39 | # MLP Debugging settings | ||
40 | DUMP_MLP = NO | ||
41 | DUMP_SOLUTION = NO | ||
42 | DUMP_OVERWRITE = NO | ||
43 | DUMP_MIN_PEERS = 0 | ||
44 | DUMP_MIN_ADDRS = 0 | ||
45 | DUMP_OVERWRITE = NO | ||
diff --git a/src/ats/test_ats_api_ril.conf b/src/ats/test_ats_api_ril.conf deleted file mode 100644 index 5f5fb006b..000000000 --- a/src/ats/test_ats_api_ril.conf +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | |||
3 | [PATHS] | ||
4 | GNUNET_TEST_HOME = $GNUNET_TMP/test-ats-ril/ | ||
5 | |||
6 | [ats] | ||
7 | # Enable RIL mode (default: NO) | ||
8 | MODE = ril | ||
9 | # Network specific inbound/outbound quotas | ||
10 | # UNSPECIFIED | ||
11 | UNSPECIFIED_QUOTA_IN = unlimited | ||
12 | UNSPECIFIED_QUOTA_OUT = unlimited | ||
13 | # LOOPBACK | ||
14 | LOOPBACK_QUOTA_IN = unlimited | ||
15 | LOOPBACK_QUOTA_OUT = unlimited | ||
16 | # LAN | ||
17 | LAN_QUOTA_IN = unlimited | ||
18 | LAN_QUOTA_OUT = unlimited | ||
19 | # WAN | ||
20 | WAN_QUOTA_IN = 64 KiB | ||
21 | WAN_QUOTA_OUT = 64 KiB | ||
22 | # WLAN | ||
23 | WLAN_QUOTA_IN = 4096 | ||
24 | WLAN_QUOTA_OUT = 4096 | ||
diff --git a/src/ats/test_ats_solver_delayed_mlp.conf b/src/ats/test_ats_solver_delayed_mlp.conf deleted file mode 100644 index 632755570..000000000 --- a/src/ats/test_ats_solver_delayed_mlp.conf +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | @INLINE@ test_ats_solver_default.conf | ||
2 | |||
3 | [ats] | ||
4 | PREFIX = ./test_delay -t 10 -- | ||
5 | MODE = mlp | ||
6 | # UNSPECIFIED | ||
7 | UNSPECIFIED_QUOTA_IN = 64 KiB | ||
8 | UNSPECIFIED_QUOTA_OUT = 64 KiB | ||
9 | # LOOPBACK | ||
10 | LOOPBACK_QUOTA_IN = unlimited | ||
11 | LOOPBACK_QUOTA_OUT = unlimited | ||
12 | # LAN | ||
13 | LAN_QUOTA_IN = unlimited | ||
14 | LAN_QUOTA_OUT = unlimited | ||
15 | # WAN | ||
16 | WAN_QUOTA_IN = 64 KiB | ||
17 | WAN_QUOTA_OUT = 64 KiB | ||
18 | # WLAN | ||
19 | WLAN_QUOTA_IN = 512 | ||
20 | WLAN_QUOTA_OUT = 512 | ||
diff --git a/src/ats/test_ats_solver_delayed_ril.conf b/src/ats/test_ats_solver_delayed_ril.conf deleted file mode 100644 index a43fffa4c..000000000 --- a/src/ats/test_ats_solver_delayed_ril.conf +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | @INLINE@ test_ats_solver_default.conf | ||
2 | |||
3 | [ats] | ||
4 | PREFIX = ./test_delay -t 10 -- | ||
5 | MODE = ril | ||
6 | # UNSPECIFIED | ||
7 | UNSPECIFIED_QUOTA_IN = 64 KiB | ||
8 | UNSPECIFIED_QUOTA_OUT = 64 KiB | ||
9 | # LOOPBACK | ||
10 | LOOPBACK_QUOTA_IN = unlimited | ||
11 | LOOPBACK_QUOTA_OUT = unlimited | ||
12 | # LAN | ||
13 | LAN_QUOTA_IN = unlimited | ||
14 | LAN_QUOTA_OUT = unlimited | ||
15 | # WAN | ||
16 | WAN_QUOTA_IN = 64 KiB | ||
17 | WAN_QUOTA_OUT = 64 KiB | ||
18 | # WLAN | ||
19 | WLAN_QUOTA_IN = 512 | ||
20 | WLAN_QUOTA_OUT = 512 | ||
21 | |||
22 | # Reinforcement Learning Parameters | ||
23 | RIL_STEP_TIME_MIN = 500 ms | ||
24 | RIL_STEP_TIME_MAX = 1000 ms | ||
25 | |||
26 | RIL_ALGORITHM = Q | ||
27 | RIL_DISCOUNT_BETA = 0.7 | ||
28 | RIL_GRADIENT_STEP_SIZE = 0.3 | ||
29 | RIL_TRACE_DECAY = 0.2 | ||
30 | RIL_EXPLORE_RATIO = 0.1 | ||
31 | RIL_GLOBAL_REWARD_SHARE = 1 | ||