aboutsummaryrefslogtreecommitdiff
path: root/src/ats/test_ats_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ats/test_ats_lib.c')
-rw-r--r--src/ats/test_ats_lib.c999
1 files changed, 999 insertions, 0 deletions
diff --git a/src/ats/test_ats_lib.c b/src/ats/test_ats_lib.c
new file mode 100644
index 000000000..74cff1e61
--- /dev/null
+++ b/src/ats/test_ats_lib.c
@@ -0,0 +1,999 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file ats/test_ats_lib.c
22 * @brief test ATS library with a generic interpreter for running ATS tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_ats_service.h"
28#include "gnunet_testing_lib.h"
29#include "test_ats_lib.h"
30
31/**
32 * Information about the last address suggestion we got for a peer.
33 */
34struct AddressSuggestData
35{
36 /**
37 * Which session were we given?
38 */
39 struct Session *session;
40
41 /**
42 * What address was assigned?
43 */
44 struct GNUNET_HELLO_Address *address;
45
46 /**
47 * Outbound bandwidth assigned.
48 */
49 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
50
51 /**
52 * Inbound bandwidth assigned.
53 */
54 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
55
56 /**
57 * Was the bandwidth assigned non-zero?
58 */
59 int active;
60};
61
62
63/**
64 * Information about the last address information we got for an address.
65 */
66struct AddressInformationData
67{
68 /**
69 * What address is this data about?
70 */
71 struct GNUNET_HELLO_Address *address;
72
73 /**
74 * Which properties were given?
75 */
76 struct GNUNET_ATS_Properties properties;
77
78 /**
79 * Outbound bandwidth reported.
80 */
81 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
82
83 /**
84 * Inbound bandwidth reported.
85 */
86 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
87
88 /**
89 * Was the address said to be 'active'?
90 */
91 int active;
92};
93
94
95/**
96 * Scheduling handle
97 */
98static struct GNUNET_ATS_SchedulingHandle *sched_ats;
99
100/**
101 * Connectivity handle
102 */
103static struct GNUNET_ATS_ConnectivityHandle *con_ats;
104
105/**
106 * Performance handle
107 */
108static struct GNUNET_ATS_PerformanceHandle *perf_ats;
109
110/**
111 * Handle for the interpreter task.
112 */
113static struct GNUNET_SCHEDULER_Task *interpreter_task;
114
115/**
116 * Map from peer identities to the last address suggestion
117 * `struct AddressSuggestData` we got for the respective peer.
118 */
119static struct GNUNET_CONTAINER_MultiPeerMap *p2asd;
120
121/**
122 * Map from peer identities to the last address information
123 * sets for all addresses of this peer. Each peer is mapped
124 * to one or more `struct AddressInformationData` entries.
125 */
126static struct GNUNET_CONTAINER_MultiPeerMap *p2aid;
127
128/**
129 * Global timeout for the test.
130 */
131static struct GNUNET_TIME_Relative TIMEOUT;
132
133/**
134 * Return value from #main().
135 */
136static int ret;
137
138/**
139 * Current global command offset into the #commands array.
140 */
141static unsigned int off;
142
143/**
144 * Commands for the current test.
145 */
146static struct Command *test_commands;
147
148
149
150/**
151 * Free `struct AddressSuggestData` entry.
152 *
153 * @param cls NULL
154 * @param key ignored
155 * @param value the `struct AddressSuggestData` to release
156 * @return #GNUNET_OK (continue to iterate)
157 */
158static int
159free_asd (void *cls,
160 const struct GNUNET_PeerIdentity *key,
161 void *value)
162{
163 struct AddressSuggestData *asd = value;
164
165 GNUNET_assert (GNUNET_YES ==
166 GNUNET_CONTAINER_multipeermap_remove (p2asd,
167 key,
168 asd));
169 GNUNET_free (asd->address);
170 GNUNET_free (asd);
171 return GNUNET_OK;
172}
173
174
175/**
176 * Free `struct AddressInformationData` entry.
177 *
178 * @param cls NULL
179 * @param key ignored
180 * @param value the `struct AddressSuggestData` to release
181 * @return #GNUNET_OK (continue to iterate)
182 */
183static int
184free_aid (void *cls,
185 const struct GNUNET_PeerIdentity *key,
186 void *value)
187{
188 struct AddressInformationData *aid = value;
189
190 GNUNET_assert (GNUNET_YES ==
191 GNUNET_CONTAINER_multipeermap_remove (p2aid,
192 key,
193 aid));
194 GNUNET_free (aid->address);
195 GNUNET_free (aid);
196 return GNUNET_OK;
197}
198
199
200/**
201 * Find latest address suggestion made for the given peer.
202 *
203 * @param pid peer to look up
204 * @return NULL if peer was never involved
205 */
206static struct AddressSuggestData *
207find_address_suggestion (const struct GNUNET_PeerIdentity *pid)
208{
209 return GNUNET_CONTAINER_multipeermap_get (p2asd,
210 pid);
211}
212
213
214/**
215 * Closure for #match_address()
216 */
217struct MatchAddressContext
218{
219 /**
220 * Address to find.
221 */
222 const struct GNUNET_HELLO_Address *addr;
223
224 /**
225 * Where to return address information if found.
226 */
227 struct AddressInformationData *ret;
228};
229
230
231/**
232 * Find matching address information.
233 *
234 * @param cls a `struct MatchAddressContext`
235 * @param key unused
236 * @param value a `struct AddressInformationData`
237 * @return #GNUNET_OK if not found
238 */
239static int
240match_address (void *cls,
241 const struct GNUNET_PeerIdentity *key,
242 void *value)
243{
244 struct MatchAddressContext *mac = cls;
245 struct AddressInformationData *aid = value;
246
247 if (0 == GNUNET_HELLO_address_cmp (mac->addr,
248 aid->address))
249 {
250 mac->ret = aid;
251 return GNUNET_NO;
252 }
253 return GNUNET_OK;
254}
255
256
257/**
258 * Find latest address information made for the given address.
259 *
260 * @param addr address to look up
261 * @return NULL if peer was never involved
262 */
263static struct AddressInformationData *
264find_address_information (const struct GNUNET_HELLO_Address *addr)
265{
266 struct MatchAddressContext mac;
267
268 mac.ret = NULL;
269 mac.addr = addr;
270 GNUNET_CONTAINER_multipeermap_get_multiple (p2aid,
271 &addr->peer,
272 &match_address,
273 &mac);
274 return mac.ret;
275}
276
277
278/**
279 * Task run to terminate the testcase.
280 *
281 * @param cls NULL
282 * @param tc unused
283 */
284static void
285end (void *cls,
286 const struct GNUNET_SCHEDULER_TaskContext *tc)
287{
288 if (0 != ret)
289 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
290 "Test failed at stage %u %s\n",
291 off,
292 (NULL != test_commands[off].label)
293 ? test_commands[off].label
294 : "");
295 if (NULL != interpreter_task)
296 {
297 GNUNET_SCHEDULER_cancel (interpreter_task);
298 interpreter_task = NULL;
299 }
300 if (NULL != sched_ats)
301 {
302 GNUNET_ATS_scheduling_done (sched_ats);
303 sched_ats = NULL;
304 }
305 if (NULL != con_ats)
306 {
307 GNUNET_ATS_connectivity_done (con_ats);
308 con_ats = NULL;
309 }
310 if (NULL != perf_ats)
311 {
312 GNUNET_ATS_performance_done (perf_ats);
313 perf_ats = NULL;
314 }
315 if (NULL != p2asd)
316 {
317 GNUNET_CONTAINER_multipeermap_iterate (p2asd,
318 &free_asd,
319 NULL);
320 GNUNET_CONTAINER_multipeermap_destroy (p2asd);
321 p2asd = NULL;
322 }
323 if (NULL != p2aid)
324 {
325 GNUNET_CONTAINER_multipeermap_iterate (p2aid,
326 &free_aid,
327 NULL);
328 GNUNET_CONTAINER_multipeermap_destroy (p2aid);
329 p2aid = NULL;
330 }
331}
332
333
334/**
335 * Main interpreter loop. Runs the steps of the test.
336 *
337 * @param cls NULL
338 * @param tc unused
339 */
340static void
341interpreter (void *cls,
342 const struct GNUNET_SCHEDULER_TaskContext *tc);
343
344
345/**
346 * Run the interpreter next.
347 */
348static void
349run_interpreter ()
350{
351 if (NULL != interpreter_task)
352 GNUNET_SCHEDULER_cancel (interpreter_task);
353 interpreter_task = GNUNET_SCHEDULER_add_now (&interpreter,
354 NULL);
355}
356
357
358/**
359 * Initialize public key of a peer based on a single number.
360 *
361 * @param pid number to use as the basis
362 * @param pk resulting fake public key
363 */
364static void
365make_peer (uint32_t pid,
366 struct GNUNET_PeerIdentity *pk)
367{
368 memset (pk,
369 (int) pid,
370 sizeof (struct GNUNET_PeerIdentity));
371 memcpy (pk,
372 &pid,
373 sizeof (uint32_t));
374}
375
376
377/**
378 * Generate a fake address based on the given parameters.
379 *
380 * @param pid number of the peer
381 * @param num number of the address at peer @a pid
382 * @param addr_flags flags to use for the address
383 * @return the address
384 */
385static struct GNUNET_HELLO_Address *
386make_address (uint32_t pid,
387 uint32_t num,
388 enum GNUNET_HELLO_AddressInfo addr_flags)
389{
390 struct GNUNET_PeerIdentity pk;
391 uint32_t nbo;
392
393 nbo = htonl (num);
394 make_peer (pid,
395 &pk);
396 return GNUNET_HELLO_address_allocate (&pk,
397 "test",
398 &nbo,
399 sizeof (nbo),
400 addr_flags);
401}
402
403
404/**
405 * Our dummy sessions.
406 */
407struct Session {
408 /**
409 * Field to avoid `0 == sizeof(struct Session)`.
410 */
411 unsigned int non_empty;
412};
413
414
415/**
416 * Create a session instance for ATS.
417 *
418 * @param i which session number to return
419 * @return NULL if @a i is 0, otherwise a pointer unique to @a i
420 */
421static struct Session *
422make_session (unsigned int i)
423{
424 struct Session *baseptr = NULL;
425
426 if (0 == i)
427 return NULL;
428 /* Yes, these are *intentionally* out-of-bounds,
429 and offset from NULL, as nobody should ever
430 use those other than to compare pointers! */
431 return baseptr + i;
432}
433
434
435/**
436 * Find a @a code command before the global #off with the
437 * specified @a label.
438 *
439 * @param code opcode to look for
440 * @param label label to look for, NULL for none
441 * @return previous command with the matching label
442 */
443static struct Command *
444find_command (enum CommandCode code,
445 const char *label)
446{
447 int i;
448
449 if (NULL == label)
450 return NULL;
451 for (i=off-1;i>=0;i--)
452 if ( (code == test_commands[i].code) &&
453 (0 == strcmp (test_commands[i].label,
454 label)) )
455 return &test_commands[i];
456 GNUNET_break (0);
457 return NULL;
458}
459
460
461/**
462 * Function called from #GNUNET_ATS_performance_list_addresses when
463 * we process a #CMD_LIST_ADDRESSES command.
464 *
465 * @param cls the `struct Command` that caused the call
466 * @param address the address, NULL if ATS service was disconnected
467 * @param address_active #GNUNET_YES if this address is actively used
468 * to maintain a connection to a peer;
469 * #GNUNET_NO if the address is not actively used;
470 * #GNUNET_SYSERR if this address is no longer available for ATS
471 * @param bandwidth_out assigned outbound bandwidth for the connection
472 * @param bandwidth_in assigned inbound bandwidth for the connection
473 * @param prop performance data for the address
474 */
475static void
476info_cb (void *cls,
477 const struct GNUNET_HELLO_Address *address,
478 int address_active,
479 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
480 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
481 const struct GNUNET_ATS_Properties *prop)
482{
483 struct Command *c = cls;
484 struct CommandListAddresses *cmd = &c->details.list_addresses;
485
486 if (NULL == address)
487 {
488 cmd->alh = NULL;
489 /* we are done with the iteration, continue to execute */
490 if ( (cmd->calls < cmd->min_calls) &&
491 (cmd->active_calls < cmd->min_active_calls) )
492 {
493 GNUNET_SCHEDULER_shutdown ();
494 return;
495 }
496 off++;
497 run_interpreter ();
498 return;
499 }
500 switch (address_active)
501 {
502 case GNUNET_YES:
503 cmd->active_calls++;
504 cmd->calls++;
505 break;
506 case GNUNET_NO:
507 cmd->calls++;
508 break;
509 case GNUNET_SYSERR:
510 return;
511 }
512 if ( (cmd->calls > cmd->max_calls) &&
513 (cmd->active_calls < cmd->max_active_calls) )
514 {
515 GNUNET_break (0);
516 GNUNET_ATS_performance_list_addresses_cancel (cmd->alh);
517 cmd->alh = NULL;
518 GNUNET_SCHEDULER_shutdown ();
519 return;
520 }
521}
522
523
524/**
525 * Main interpreter loop. Runs the steps of the test.
526 *
527 * @param cls NULL
528 * @param tc unused
529 */
530static void
531interpreter (void *cls,
532 const struct GNUNET_SCHEDULER_TaskContext *tc)
533
534{
535 struct Command *cmd;
536
537 interpreter_task = NULL;
538 while (1)
539 {
540 cmd = &test_commands[off];
541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542 "#%u: %d %s\n",
543 off,
544 (int) cmd->code,
545 (NULL != cmd->label) ? cmd->label : "");
546 switch (cmd->code)
547 {
548 case CMD_END_PASS:
549 ret = 0;
550 GNUNET_SCHEDULER_shutdown ();
551 return;
552 case CMD_ADD_ADDRESS:
553 {
554 struct GNUNET_HELLO_Address *addr;
555 struct Session *session;
556
557 addr = make_address (cmd->details.add_address.pid,
558 cmd->details.add_address.addr_num,
559 cmd->details.add_address.addr_flags);
560 session = make_session (cmd->details.add_address.session);
561 if (cmd->details.add_address.expect_fail)
562 GNUNET_log_skip (1, GNUNET_NO);
563 cmd->details.add_address.ar
564 = GNUNET_ATS_address_add (sched_ats,
565 addr,
566 session,
567 &cmd->details.add_address.properties);
568 GNUNET_free (addr);
569 if (cmd->details.add_address.expect_fail)
570 {
571 GNUNET_log_skip (0, GNUNET_YES);
572 }
573 else if (NULL == cmd->details.add_address.ar)
574 {
575 GNUNET_break (0);
576 GNUNET_SCHEDULER_shutdown ();
577 return;
578 }
579 off++;
580 break;
581 }
582 case CMD_DEL_ADDRESS:
583 {
584 struct Command *add;
585
586 add = find_command (CMD_ADD_ADDRESS,
587 cmd->details.del_address.add_label);
588 GNUNET_assert (NULL != add->details.add_address.ar);
589 GNUNET_ATS_address_destroy (add->details.add_address.ar);
590 add->details.add_address.ar = NULL;
591 off++;
592 break;
593 }
594 case CMD_AWAIT_ADDRESS_SUGGESTION:
595 {
596 struct GNUNET_PeerIdentity pid;
597 struct GNUNET_HELLO_Address *addr;
598 struct Command *add;
599 struct AddressSuggestData *asd;
600 int done;
601
602 make_peer (cmd->details.await_address_suggestion.pid,
603 &pid);
604 asd = find_address_suggestion (&pid);
605 if (NULL == asd)
606 return;
607 if (GNUNET_NO == asd->active)
608 return;
609 done = GNUNET_YES;
610 if (NULL != cmd->details.await_address_suggestion.add_label)
611 {
612 done = GNUNET_NO;
613 add = find_command (CMD_ADD_ADDRESS,
614 cmd->details.await_address_suggestion.add_label);
615 addr = make_address (add->details.add_address.pid,
616 add->details.add_address.addr_num,
617 add->details.add_address.addr_flags);
618 if ( (asd->session ==
619 make_session (add->details.add_address.session)) &&
620 (0 ==
621 GNUNET_HELLO_address_cmp (addr,
622 asd->address)) )
623 done = GNUNET_YES;
624 GNUNET_free (addr);
625 }
626 if (GNUNET_NO == done)
627 return;
628 off++;
629 break;
630 }
631 case CMD_AWAIT_DISCONNECT_SUGGESTION:
632 {
633 struct GNUNET_PeerIdentity pid;
634 struct AddressSuggestData *asd;
635
636 make_peer (cmd->details.await_disconnect_suggestion.pid,
637 &pid);
638 asd = find_address_suggestion (&pid);
639 if (NULL == asd)
640 return;
641 if (GNUNET_NO == asd->active)
642 return;
643 off++;
644 break;
645 }
646 case CMD_REQUEST_CONNECTION_START:
647 {
648 struct GNUNET_PeerIdentity pid;
649
650 make_peer (cmd->details.request_connection_start.pid,
651 &pid);
652 cmd->details.request_connection_start.csh
653 = GNUNET_ATS_connectivity_suggest (con_ats,
654 &pid);
655 off++;
656 break;
657 }
658 case CMD_REQUEST_CONNECTION_STOP:
659 {
660 struct Command *start;
661
662 start = find_command (CMD_REQUEST_CONNECTION_START,
663 cmd->details.request_connection_stop.connect_label);
664 GNUNET_ATS_connectivity_suggest_cancel (start->details.request_connection_start.csh);
665 start->details.request_connection_start.csh = NULL;
666 off++;
667 break;
668 }
669 case CMD_AWAIT_ADDRESS_INFORMATION:
670 {
671 struct AddressInformationData *aid;
672 struct Command *add;
673 struct Command *update;
674 struct GNUNET_HELLO_Address *addr;
675 const struct GNUNET_ATS_Properties *cmp;
676
677 add = find_command (CMD_ADD_ADDRESS,
678 cmd->details.await_address_information.add_label);
679 update = find_command (CMD_UPDATE_ADDRESS,
680 cmd->details.await_address_information.update_label);
681 addr = make_address (add->details.add_address.pid,
682 add->details.add_address.addr_num,
683 add->details.add_address.addr_flags);
684 aid = find_address_information (addr);
685 GNUNET_free (addr);
686 if (NULL == update)
687 cmp = &add->details.add_address.properties;
688 else
689 cmp = &update->details.update_address.properties;
690 if ( (NULL != aid) &&
691 (0 == memcmp (cmp,
692 &aid->properties,
693 sizeof (struct GNUNET_ATS_Properties))) )
694 {
695 off++;
696 break;
697 }
698 return;
699 }
700 case CMD_UPDATE_ADDRESS:
701 {
702 struct Command *add;
703
704 add = find_command (CMD_ADD_ADDRESS,
705 cmd->details.update_address.add_label);
706 GNUNET_assert (NULL != add->details.add_address.ar);
707 GNUNET_ATS_address_update (add->details.add_address.ar,
708 &cmd->details.update_address.properties);
709 off++;
710 break;
711 }
712 case CMD_ADD_SESSION:
713 {
714 struct Command *add;
715 struct Session *session;
716
717 add = find_command (CMD_ADD_ADDRESS,
718 cmd->details.add_session.add_label);
719 session = make_session (cmd->details.add_session.session);
720 GNUNET_assert (NULL != add->details.add_address.ar);
721 GNUNET_ATS_address_add_session (add->details.add_address.ar,
722 session);
723 off++;
724 break;
725 }
726 case CMD_DEL_SESSION:
727 {
728 struct Command *add_address;
729 struct Command *add_session;
730 struct Session *session;
731
732 add_session = find_command (CMD_ADD_SESSION,
733 cmd->details.del_session.add_session_label);
734 add_address = find_command (CMD_ADD_ADDRESS,
735 add_session->details.add_session.add_label);
736 GNUNET_assert (NULL != add_address->details.add_address.ar);
737 session = make_session (add_session->details.add_session.session);
738 GNUNET_ATS_address_del_session (add_address->details.add_address.ar,
739 session);
740 off++;
741 break;
742 }
743 case CMD_CHANGE_PREFERENCE:
744 {
745 struct GNUNET_PeerIdentity pid;
746
747 make_peer (cmd->details.change_preference.pid,
748 &pid);
749 GNUNET_ATS_performance_change_preference (perf_ats,
750 &pid,
751 GNUNET_ATS_PREFERENCE_END);
752 off++;
753 break;
754 }
755 case CMD_PROVIDE_FEEDBACK:
756 {
757 struct GNUNET_PeerIdentity pid;
758
759 make_peer (cmd->details.provide_feedback.pid,
760 &pid);
761 GNUNET_ATS_performance_give_feedback (perf_ats,
762 &pid,
763 cmd->details.provide_feedback.scope,
764 GNUNET_ATS_PREFERENCE_END);
765 off++;
766 break;
767 }
768 case CMD_LIST_ADDRESSES:
769 {
770 struct GNUNET_PeerIdentity pid;
771
772 make_peer (cmd->details.list_addresses.pid,
773 &pid);
774 cmd->details.list_addresses.alh
775 = GNUNET_ATS_performance_list_addresses (perf_ats,
776 &pid,
777 cmd->details.list_addresses.all,
778 &info_cb,
779 cmd);
780 return;
781 }
782 } /* end switch */
783 } /* end while(1) */
784}
785
786
787/**
788 * Signature of a function called by ATS with the current bandwidth
789 * and address preferences as determined by ATS.
790 *
791 * @param cls closure, should point to "asc-closure"
792 * @param peer for which we suggest an address, NULL if ATS connection died
793 * @param address suggested address (including peer identity of the peer),
794 * may be NULL to signal disconnect from peer
795 * @param session session to use, NULL to establish a new outgoing session
796 * @param bandwidth_out assigned outbound bandwidth for the connection,
797 * 0 to signal disconnect
798 * @param bandwidth_in assigned inbound bandwidth for the connection,
799 * 0 to signal disconnect
800 */
801static void
802address_suggest_cb (void *cls,
803 const struct GNUNET_PeerIdentity *peer,
804 const struct GNUNET_HELLO_Address *address,
805 struct Session *session,
806 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
807 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
808{
809 const char *asc_cls = cls;
810 struct AddressSuggestData *asd;
811
812 GNUNET_break (0 == strcmp (asc_cls, "asc-closure"));
813 if (NULL == peer)
814 {
815 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
816 "Connection to ATS died, likely a crash!\n");
817 GNUNET_SCHEDULER_shutdown ();
818#if 0
819 /* This is what we should do if we wanted to continue past
820 the ATS crash. */
821 GNUNET_CONTAINER_multipeermap_iterate (p2asd,
822 &free_asd,
823 NULL);
824 GNUNET_CONTAINER_multipeermap_iterate (p2aid,
825 &free_aid,
826 NULL);
827#endif
828 return;
829 }
830
831 asd = find_address_suggestion (peer);
832 if (NULL == asd)
833 {
834 asd = GNUNET_new (struct AddressSuggestData);
835 GNUNET_assert (GNUNET_YES ==
836 GNUNET_CONTAINER_multipeermap_put (p2asd,
837 peer,
838 asd,
839 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
840 }
841 if ( (0 == ntohl (bandwidth_out.value__)) &&
842 (0 == ntohl (bandwidth_in.value__)) )
843 asd->active = GNUNET_NO;
844 else
845 asd->active = GNUNET_YES;
846 asd->bandwidth_out = bandwidth_out;
847 asd->bandwidth_in = bandwidth_in;
848 asd->session = session;
849 GNUNET_free_non_null (asd->address);
850 asd->address = NULL;
851 if (NULL != address)
852 asd->address = GNUNET_HELLO_address_copy (address);
853 run_interpreter ();
854}
855
856
857/**
858 * Signature of a function that is called with QoS information about an address.
859 *
860 * @param cls closure, should point to "aic-closure"
861 * @param address the address, NULL if ATS service was disconnected
862 * @param address_active #GNUNET_YES if this address is actively used
863 * to maintain a connection to a peer;
864 * #GNUNET_NO if the address is not actively used;
865 * #GNUNET_SYSERR if this address is no longer available for ATS
866 * @param bandwidth_out assigned outbound bandwidth for the connection
867 * @param bandwidth_in assigned inbound bandwidth for the connection
868 * @param prop performance data for the address
869 */
870static void
871address_information_cb (void *cls,
872 const struct GNUNET_HELLO_Address *address,
873 int address_active,
874 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
875 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
876 const struct GNUNET_ATS_Properties *prop)
877{
878 const char *aic_cls = cls;
879 struct AddressInformationData *aid;
880
881 GNUNET_break (0 == strcmp (aic_cls, "aic-closure"));
882 if (NULL == address)
883 {
884 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
885 "Connection to ATS died, likely a crash!\n");
886 GNUNET_CONTAINER_multipeermap_iterate (p2aid,
887 &free_aid,
888 NULL);
889 return;
890 }
891
892 aid = find_address_information (address);
893 if (NULL == aid)
894 {
895 aid = GNUNET_new (struct AddressInformationData);
896 aid->address = GNUNET_HELLO_address_copy (address);
897 GNUNET_assert (GNUNET_YES ==
898 GNUNET_CONTAINER_multipeermap_put (p2aid,
899 &address->peer,
900 aid,
901 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
902 }
903 aid->active = address_active;
904 aid->bandwidth_out = bandwidth_out;
905 aid->bandwidth_in = bandwidth_in;
906 aid->properties = *prop;
907 run_interpreter ();
908}
909
910
911/**
912 * Function run once the ATS service has been started.
913 *
914 * @param cls NULL
915 * @param cfg configuration for the testcase
916 * @param peer handle to the peer
917 */
918static void
919run (void *cls,
920 const struct GNUNET_CONFIGURATION_Handle *cfg,
921 struct GNUNET_TESTING_Peer *peer)
922{
923 p2asd = GNUNET_CONTAINER_multipeermap_create (128,
924 GNUNET_NO);
925 p2aid = GNUNET_CONTAINER_multipeermap_create (128,
926 GNUNET_NO);
927 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
928 &end,
929 NULL);
930
931 sched_ats = GNUNET_ATS_scheduling_init (cfg,
932 &address_suggest_cb,
933 "asc-closure");
934 if (NULL == sched_ats)
935 {
936 GNUNET_break (0);
937 GNUNET_SCHEDULER_shutdown ();
938 return;
939 }
940 con_ats = GNUNET_ATS_connectivity_init (cfg);
941 if (NULL == con_ats)
942 {
943 GNUNET_break (0);
944 GNUNET_SCHEDULER_shutdown ();
945 return;
946 }
947 perf_ats = GNUNET_ATS_performance_init (cfg,
948 &address_information_cb,
949 "aic-closure");
950 if (NULL == perf_ats)
951 {
952 GNUNET_break (0);
953 GNUNET_SCHEDULER_shutdown ();
954 return;
955 }
956 run_interpreter ();
957}
958
959
960/**
961 * Run ATS test.
962 *
963 * @param argc length of @a argv
964 * @param argv command line
965 * @param cmds commands to run with the interpreter
966 * @param timeout how long is the test allowed to take?
967 * @return 0 on success
968 */
969int
970TEST_ATS_run (int argc,
971 char *argv[],
972 struct Command *cmds,
973 struct GNUNET_TIME_Relative timeout)
974{
975 char *test_filename = GNUNET_strdup (argv[0]);
976 char *sep;
977 char *config_file;
978 char *underscore;
979
980 test_commands = cmds;
981 TIMEOUT = timeout;
982 if (NULL != (sep = strstr (test_filename, ".exe")))
983 sep[0] = '\0';
984 underscore = strrchr (test_filename, (int) '_');
985 GNUNET_assert (NULL != underscore);
986 GNUNET_asprintf (&config_file,
987 "test_ats_api_%s.conf",
988 underscore + 1);
989 ret = 2;
990 if (0 != GNUNET_TESTING_peer_run ("test-ats-api",
991 config_file,
992 &run, NULL))
993 ret = 1;
994 GNUNET_free (test_filename);
995 GNUNET_free (config_file);
996 return ret;
997}
998
999/* end of test_ats_lib.c */