gnunet-daemon-topology.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2007-2013 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file topology/gnunet-daemon-topology.c
  19. * @brief code for maintaining the cadet topology
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_friends_lib.h"
  25. #include "gnunet_constants.h"
  26. #include "gnunet_core_service.h"
  27. #include "gnunet_protocols.h"
  28. #include "gnunet_peerinfo_service.h"
  29. #include "gnunet_statistics_service.h"
  30. #include "gnunet_transport_service.h"
  31. /**
  32. * Minimum required delay between calls to GNUNET_TRANSPORT_try_connect.
  33. */
  34. #define MAX_CONNECT_FREQUENCY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
  35. /**
  36. * Maximum delay allowed delay between calls to GNUNET_TRANSPORT_try_connect.
  37. */
  38. #define MIN_CONNECT_FREQUENCY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 2500)
  39. /**
  40. * For how long do we blacklist a peer after a failed connection
  41. * attempt? This is the baseline factor which is then multiplied by
  42. * two to the power of the number of failed attempts.
  43. */
  44. #define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
  45. /**
  46. * For how long do we blacklist a friend after a failed connection
  47. * attempt? This is the baseline factor which is then multiplied by
  48. * two to the power of the number of failed attempts.
  49. */
  50. #define GREYLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
  51. /**
  52. * For how long do we blacklist anyone under any cirumstances at least after a failed connection
  53. * attempt? This is the absolute minimum, regardless of what the calculation based on
  54. * exponential backoff returns.
  55. */
  56. #define GREYLIST_AFTER_ATTEMPT_MIN GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
  57. /**
  58. * For how long do we blacklist anyone under any cirumstances at most after a failed connection
  59. * attempt? This is the absolute maximum, regardless of what the calculation based on
  60. * exponential back-off returns.
  61. */
  62. #define GREYLIST_AFTER_ATTEMPT_MAX GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
  63. /**
  64. * At what frequency do we sent HELLOs to a peer?
  65. */
  66. #define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
  67. /**
  68. * After what time period do we expire the HELLO Bloom filter?
  69. */
  70. #define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
  71. /**
  72. * Record for neighbours, friends and blacklisted peers.
  73. */
  74. struct Peer
  75. {
  76. /**
  77. * Which peer is this entry about?
  78. */
  79. struct GNUNET_PeerIdentity pid;
  80. /**
  81. * Our handle for the request to transmit HELLOs to this peer; NULL
  82. * if no such request is pending.
  83. */
  84. struct GNUNET_CORE_TransmitHandle *hello_req;
  85. /**
  86. * Pointer to the HELLO message of this peer; can be NULL.
  87. */
  88. struct GNUNET_HELLO_Message *hello;
  89. /**
  90. * Bloom filter used to mark which peers already got the HELLO
  91. * from this peer.
  92. */
  93. struct GNUNET_CONTAINER_BloomFilter *filter;
  94. /**
  95. * Until what time should we not try to connect again
  96. * to this peer?
  97. */
  98. struct GNUNET_TIME_Absolute greylisted_until;
  99. /**
  100. * Next time we are allowed to transmit a HELLO to this peer?
  101. */
  102. struct GNUNET_TIME_Absolute next_hello_allowed;
  103. /**
  104. * When should we reset the bloom filter of this entry?
  105. */
  106. struct GNUNET_TIME_Absolute filter_expiration;
  107. /**
  108. * When should try next connection attempt?
  109. */
  110. struct GNUNET_TIME_Absolute next_connect_attempt;
  111. /**
  112. * ID of task we use to wait for the time to send the next HELLO
  113. * to this peer.
  114. */
  115. GNUNET_SCHEDULER_TaskIdentifier hello_delay_task;
  116. /**
  117. * Task for issuing GNUNET_TRANSPORT_try_connect for this peer.
  118. */
  119. GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task;
  120. /**
  121. * ID of task we use to clear peers from the greylist.
  122. */
  123. GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task;
  124. /**
  125. * How often have we tried so far?
  126. */
  127. unsigned int connect_attempts;
  128. /**
  129. * Is this peer listed here because he is a friend?
  130. */
  131. int is_friend;
  132. /**
  133. * Are we connected to this peer right now?
  134. */
  135. int is_connected;
  136. };
  137. /**
  138. * Our peerinfo notification context. We use notification
  139. * to instantly learn about new peers as they are discovered.
  140. */
  141. static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
  142. /**
  143. * Our configuration.
  144. */
  145. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  146. /**
  147. * Handle to the core API.
  148. */
  149. static struct GNUNET_CORE_Handle *handle;
  150. /**
  151. * Handle to the transport API.
  152. */
  153. static struct GNUNET_TRANSPORT_Handle *transport;
  154. /**
  155. * Identity of this peer.
  156. */
  157. static struct GNUNET_PeerIdentity my_identity;
  158. /**
  159. * All of our friends, all of our current neighbours and all peers for
  160. * which we have HELLOs. So pretty much everyone. Maps peer identities
  161. * to 'struct Peer *' values.
  162. */
  163. static struct GNUNET_CONTAINER_MultiPeerMap *peers;
  164. /**
  165. * Handle for reporting statistics.
  166. */
  167. static struct GNUNET_STATISTICS_Handle *stats;
  168. /**
  169. * Blacklist (NULL if we have none).
  170. */
  171. static struct GNUNET_TRANSPORT_Blacklist *blacklist;
  172. /**
  173. * When can we next ask transport to create a connection?
  174. */
  175. static struct GNUNET_TIME_Absolute next_connect_attempt;
  176. /**
  177. * Task scheduled to try to add peers.
  178. */
  179. static GNUNET_SCHEDULER_TaskIdentifier add_task;
  180. /**
  181. * Flag to disallow non-friend connections (pure F2F mode).
  182. */
  183. static int friends_only;
  184. /**
  185. * Minimum number of friends to have in the
  186. * connection set before we allow non-friends.
  187. */
  188. static unsigned int minimum_friend_count;
  189. /**
  190. * Number of peers (friends and others) that we are currently connected to.
  191. */
  192. static unsigned int connection_count;
  193. /**
  194. * Target number of connections.
  195. */
  196. static unsigned int target_connection_count;
  197. /**
  198. * Number of friends that we are currently connected to.
  199. */
  200. static unsigned int friend_count;
  201. /**
  202. * Function that decides if a connection is acceptable or not.
  203. * If we have a blacklist, only friends are allowed, so the check
  204. * is rather simple.
  205. *
  206. * @param cls closure
  207. * @param pid peer to approve or disapprove
  208. * @return GNUNET_OK if the connection is allowed
  209. */
  210. static int
  211. blacklist_check (void *cls, const struct GNUNET_PeerIdentity *pid)
  212. {
  213. struct Peer *pos;
  214. pos = GNUNET_CONTAINER_multipeermap_get (peers, pid);
  215. if ((pos != NULL) && (pos->is_friend == GNUNET_YES))
  216. return GNUNET_OK;
  217. GNUNET_STATISTICS_update (stats, gettext_noop ("# peers blacklisted"), 1,
  218. GNUNET_NO);
  219. return GNUNET_SYSERR;
  220. }
  221. /**
  222. * Whitelist all peers that we blacklisted; we've passed
  223. * the minimum number of friends.
  224. */
  225. static void
  226. whitelist_peers ()
  227. {
  228. if (blacklist != NULL)
  229. {
  230. GNUNET_TRANSPORT_blacklist_cancel (blacklist);
  231. blacklist = NULL;
  232. }
  233. }
  234. /**
  235. * Check if an additional connection from the given peer is allowed.
  236. *
  237. * @param peer connection to check
  238. * @return GNUNET_OK if the connection is allowed
  239. */
  240. static int
  241. is_connection_allowed (struct Peer *peer)
  242. {
  243. if (0 ==
  244. memcmp (&my_identity, &peer->pid, sizeof (struct GNUNET_PeerIdentity)))
  245. return GNUNET_SYSERR; /* disallow connections to self */
  246. if (peer->is_friend)
  247. return GNUNET_OK;
  248. if (GNUNET_YES == friends_only)
  249. {
  250. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  251. "Determined that `%s' is not allowed to connect (not a friend)\n",
  252. GNUNET_i2s (&peer->pid));
  253. return GNUNET_SYSERR;
  254. }
  255. if (friend_count >= minimum_friend_count)
  256. return GNUNET_OK;
  257. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  258. "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
  259. GNUNET_i2s (&peer->pid));
  260. return GNUNET_SYSERR;
  261. }
  262. /**
  263. * Free all resources associated with the given peer.
  264. *
  265. * @param cls closure (not used)
  266. * @param pid identity of the peer
  267. * @param value peer to free
  268. * @return GNUNET_YES (always: continue to iterate)
  269. */
  270. static int
  271. free_peer (void *cls, const struct GNUNET_PeerIdentity * pid, void *value)
  272. {
  273. struct Peer *pos = value;
  274. GNUNET_break (GNUNET_NO == pos->is_connected);
  275. GNUNET_break (GNUNET_OK ==
  276. GNUNET_CONTAINER_multipeermap_remove (peers, pid, pos));
  277. if (pos->hello_req != NULL)
  278. GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
  279. if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
  280. GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
  281. if (pos->attempt_connect_task != GNUNET_SCHEDULER_NO_TASK)
  282. GNUNET_SCHEDULER_cancel (pos->attempt_connect_task);
  283. if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
  284. GNUNET_SCHEDULER_cancel (pos->greylist_clean_task);
  285. GNUNET_free_non_null (pos->hello);
  286. if (pos->filter != NULL)
  287. GNUNET_CONTAINER_bloomfilter_free (pos->filter);
  288. GNUNET_free (pos);
  289. return GNUNET_YES;
  290. }
  291. /**
  292. * Discard peer entries for greylisted peers
  293. * where the greylisting has expired.
  294. *
  295. * @param cls 'struct Peer' to greylist
  296. * @param tc scheduler context
  297. */
  298. static void
  299. remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  300. /**
  301. * Try to connect to the specified peer.
  302. *
  303. * @param pos peer to connect to
  304. */
  305. static void
  306. attempt_connect (struct Peer *pos)
  307. {
  308. struct GNUNET_TIME_Relative rem;
  309. if ((connection_count >= target_connection_count) &&
  310. (friend_count >= minimum_friend_count))
  311. return;
  312. if (GNUNET_YES == pos->is_connected)
  313. return;
  314. if (GNUNET_OK != is_connection_allowed (pos))
  315. return;
  316. if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value_us > 0)
  317. return;
  318. if (GNUNET_YES == pos->is_friend)
  319. rem = GREYLIST_AFTER_ATTEMPT_FRIEND;
  320. else
  321. rem = GREYLIST_AFTER_ATTEMPT;
  322. rem = GNUNET_TIME_relative_multiply (rem, connection_count);
  323. rem = GNUNET_TIME_relative_divide (rem, target_connection_count);
  324. if (pos->connect_attempts > 30)
  325. pos->connect_attempts = 30;
  326. else
  327. pos->connect_attempts ++;
  328. rem = GNUNET_TIME_relative_multiply (rem, 1 << pos->connect_attempts);
  329. rem = GNUNET_TIME_relative_max (rem, GREYLIST_AFTER_ATTEMPT_MIN);
  330. rem = GNUNET_TIME_relative_min (rem, GREYLIST_AFTER_ATTEMPT_MAX);
  331. pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem);
  332. pos->next_connect_attempt = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
  333. GNUNET_TIME_relative_multiply (MAX_CONNECT_FREQUENCY_DELAY, pos->connect_attempts));
  334. pos->next_connect_attempt = GNUNET_TIME_absolute_min (pos->next_connect_attempt,
  335. GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), MIN_CONNECT_FREQUENCY_DELAY));
  336. if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
  337. GNUNET_SCHEDULER_cancel (pos->greylist_clean_task);
  338. pos->greylist_clean_task =
  339. GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos);
  340. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to connect to `%s'\n",
  341. GNUNET_i2s (&pos->pid));
  342. GNUNET_STATISTICS_update (stats,
  343. gettext_noop
  344. ("# connect requests issued to transport"), 1,
  345. GNUNET_NO);
  346. GNUNET_TRANSPORT_try_connect (transport, &pos->pid, NULL, NULL);
  347. }
  348. /**
  349. * Try to connect to the specified peer.
  350. *
  351. * @param cls peer to connect to
  352. * @param tc scheduler context
  353. */
  354. static void
  355. do_attempt_connect (void *cls,
  356. const struct GNUNET_SCHEDULER_TaskContext *tc)
  357. {
  358. struct Peer *pos = cls;
  359. struct GNUNET_TIME_Relative delay;
  360. pos->attempt_connect_task = GNUNET_SCHEDULER_NO_TASK;
  361. if (GNUNET_YES == pos->is_connected)
  362. return;
  363. /* Try next connection attempt, when:
  364. * - topology allows the next transport connection attempt
  365. * and
  366. * - the next connection event for this peer is allowed
  367. */
  368. delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (next_connect_attempt),
  369. GNUNET_TIME_absolute_get_remaining (pos->next_connect_attempt));
  370. if (delay.rel_value_us > 0)
  371. {
  372. pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (delay,
  373. &do_attempt_connect,
  374. pos);
  375. return;
  376. }
  377. next_connect_attempt = GNUNET_TIME_relative_to_absolute (MAX_CONNECT_FREQUENCY_DELAY);
  378. attempt_connect (pos);
  379. }
  380. /**
  381. * Schedule a task to try to connect to the specified peer.
  382. *
  383. * @param pos peer to connect to
  384. */
  385. static void
  386. schedule_attempt_connect (struct Peer *pos)
  387. {
  388. if (GNUNET_SCHEDULER_NO_TASK != pos->attempt_connect_task)
  389. return;
  390. pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_connect_attempt),
  391. &do_attempt_connect,
  392. pos);
  393. }
  394. /**
  395. * Discard peer entries for greylisted peers
  396. * where the greylisting has expired.
  397. *
  398. * @param cls 'struct Peer' to greylist
  399. * @param tc scheduler context
  400. */
  401. static void
  402. remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  403. {
  404. struct Peer *pos = cls;
  405. struct GNUNET_TIME_Relative rem;
  406. pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK;
  407. rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until);
  408. if (0 == rem.rel_value_us)
  409. {
  410. schedule_attempt_connect (pos);
  411. }
  412. else
  413. {
  414. pos->greylist_clean_task =
  415. GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos);
  416. }
  417. if ((GNUNET_NO == pos->is_friend) && (GNUNET_NO == pos->is_connected) &&
  418. (NULL == pos->hello))
  419. {
  420. free_peer (NULL, &pos->pid, pos);
  421. return;
  422. }
  423. }
  424. /**
  425. * Create a new entry in the peer list.
  426. *
  427. * @param peer identity of the new entry
  428. * @param hello hello message, can be NULL
  429. * @param is_friend is the new entry for a friend?
  430. * @return the new entry
  431. */
  432. static struct Peer *
  433. make_peer (const struct GNUNET_PeerIdentity *peer,
  434. const struct GNUNET_HELLO_Message *hello, int is_friend)
  435. {
  436. struct Peer *ret;
  437. ret = GNUNET_new (struct Peer);
  438. ret->pid = *peer;
  439. ret->is_friend = is_friend;
  440. ret->next_connect_attempt = GNUNET_TIME_absolute_get();
  441. if (hello != NULL)
  442. {
  443. ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
  444. memcpy (ret->hello, hello, GNUNET_HELLO_size (hello));
  445. }
  446. GNUNET_break (GNUNET_OK ==
  447. GNUNET_CONTAINER_multipeermap_put (peers, peer,
  448. ret,
  449. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  450. return ret;
  451. }
  452. /**
  453. * Setup bloom filter for the given peer entry.
  454. *
  455. * @param peer entry to initialize
  456. */
  457. static void
  458. setup_filter (struct Peer *peer)
  459. {
  460. struct GNUNET_HashCode hc;
  461. /* 2^{-5} chance of not sending a HELLO to a peer is
  462. * acceptably small (if the filter is 50% full);
  463. * 64 bytes of memory are small compared to the rest
  464. * of the data structure and would only really become
  465. * "useless" once a HELLO has been passed on to ~100
  466. * other peers, which is likely more than enough in
  467. * any case; hence 64, 5 as bloomfilter parameters. */
  468. peer->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, 64, 5);
  469. peer->filter_expiration =
  470. GNUNET_TIME_relative_to_absolute
  471. (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
  472. /* never send a peer its own HELLO */
  473. GNUNET_CRYPTO_hash (&peer->pid, sizeof (struct GNUNET_PeerIdentity), &hc);
  474. GNUNET_CONTAINER_bloomfilter_add (peer->filter, &hc);
  475. }
  476. /**
  477. * Function to fill send buffer with HELLO.
  478. *
  479. * @param cls 'struct Peer' of the target peer
  480. * @param size number of bytes available in @a buf
  481. * @param buf where the callee should write the message
  482. * @return number of bytes written to @a buf
  483. */
  484. static size_t
  485. hello_advertising_ready (void *cls, size_t size, void *buf);
  486. /**
  487. * Closure for 'find_advertisable_hello'.
  488. */
  489. struct FindAdvHelloContext
  490. {
  491. /**
  492. * Peer we want to advertise to.
  493. */
  494. struct Peer *peer;
  495. /**
  496. * Where to store the result (peer selected for advertising).
  497. */
  498. struct Peer *result;
  499. /**
  500. * Maximum HELLO size we can use right now.
  501. */
  502. size_t max_size;
  503. struct GNUNET_TIME_Relative next_adv;
  504. };
  505. /**
  506. * Find a peer that would be reasonable for advertising.
  507. *
  508. * @param cls closure
  509. * @param pid identity of a peer
  510. * @param value 'struct Peer*' for the peer we are considering
  511. * @return GNUNET_YES (continue iteration)
  512. */
  513. static int
  514. find_advertisable_hello (void *cls, const struct GNUNET_PeerIdentity * pid, void *value)
  515. {
  516. struct FindAdvHelloContext *fah = cls;
  517. struct Peer *pos = value;
  518. struct GNUNET_TIME_Relative rst_time;
  519. struct GNUNET_HashCode hc;
  520. size_t hs;
  521. if (pos == fah->peer)
  522. return GNUNET_YES;
  523. if (pos->hello == NULL)
  524. return GNUNET_YES;
  525. rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
  526. if (0 == rst_time.rel_value_us)
  527. {
  528. /* time to discard... */
  529. GNUNET_CONTAINER_bloomfilter_free (pos->filter);
  530. setup_filter (pos);
  531. }
  532. fah->next_adv = GNUNET_TIME_relative_min (rst_time, fah->next_adv);
  533. hs = GNUNET_HELLO_size (pos->hello);
  534. if (hs > fah->max_size)
  535. return GNUNET_YES;
  536. GNUNET_CRYPTO_hash (&fah->peer->pid, sizeof (struct GNUNET_PeerIdentity), &hc);
  537. if (GNUNET_NO ==
  538. GNUNET_CONTAINER_bloomfilter_test (pos->filter,
  539. &hc))
  540. fah->result = pos;
  541. return GNUNET_YES;
  542. }
  543. /**
  544. * Calculate when we would like to send the next HELLO to this
  545. * peer and ask for it.
  546. *
  547. * @param cls for which peer to schedule the HELLO
  548. * @param tc task context
  549. */
  550. static void
  551. schedule_next_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  552. {
  553. struct Peer *pl = cls;
  554. struct FindAdvHelloContext fah;
  555. size_t next_want;
  556. struct GNUNET_TIME_Relative delay;
  557. pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
  558. GNUNET_assert (GNUNET_YES == pl->is_connected);
  559. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  560. return; /* we're out of here */
  561. if (pl->hello_req != NULL)
  562. return; /* did not finish sending the previous one */
  563. /* find applicable HELLOs */
  564. fah.peer = pl;
  565. fah.result = NULL;
  566. fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
  567. fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
  568. GNUNET_CONTAINER_multipeermap_iterate (peers, &find_advertisable_hello, &fah);
  569. pl->hello_delay_task =
  570. GNUNET_SCHEDULER_add_delayed (fah.next_adv, &schedule_next_hello, pl);
  571. if (fah.result == NULL)
  572. return;
  573. next_want = GNUNET_HELLO_size (fah.result->hello);
  574. delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
  575. if (0 == delay.rel_value_us)
  576. {
  577. /* now! */
  578. pl->hello_req =
  579. GNUNET_CORE_notify_transmit_ready (handle, GNUNET_YES,
  580. GNUNET_CORE_PRIO_BEST_EFFORT,
  581. GNUNET_CONSTANTS_SERVICE_TIMEOUT,
  582. &pl->pid, next_want,
  583. &hello_advertising_ready, pl);
  584. }
  585. }
  586. /**
  587. * Cancel existing requests for sending HELLOs to this peer
  588. * and recalculate when we should send HELLOs to it based
  589. * on our current state (something changed!).
  590. *
  591. * @param cls closure, 'struct Peer' to skip, or NULL
  592. * @param pid identity of a peer
  593. * @param value 'struct Peer*' for the peer
  594. * @return GNUNET_YES (always)
  595. */
  596. static int
  597. reschedule_hellos (void *cls, const struct GNUNET_PeerIdentity * pid, void *value)
  598. {
  599. struct Peer *peer = value;
  600. struct Peer *skip = cls;
  601. if (skip == peer)
  602. return GNUNET_YES;
  603. if (!peer->is_connected)
  604. return GNUNET_YES;
  605. if (peer->hello_req != NULL)
  606. {
  607. GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req);
  608. peer->hello_req = NULL;
  609. }
  610. if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
  611. {
  612. GNUNET_SCHEDULER_cancel (peer->hello_delay_task);
  613. peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
  614. }
  615. peer->hello_delay_task =
  616. GNUNET_SCHEDULER_add_now (&schedule_next_hello, peer);
  617. return GNUNET_YES;
  618. }
  619. /**
  620. * Method called whenever a peer connects.
  621. *
  622. * @param cls closure
  623. * @param peer peer identity this notification is about
  624. */
  625. static void
  626. connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer)
  627. {
  628. struct Peer *pos;
  629. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  630. "Core told us that we are connecting to `%s'\n",
  631. GNUNET_i2s (peer));
  632. if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
  633. return;
  634. connection_count++;
  635. GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"),
  636. connection_count, GNUNET_NO);
  637. pos = GNUNET_CONTAINER_multipeermap_get (peers, peer);
  638. if (NULL == pos)
  639. {
  640. pos = make_peer (peer, NULL, GNUNET_NO);
  641. GNUNET_break (GNUNET_OK == is_connection_allowed (pos));
  642. }
  643. else
  644. {
  645. GNUNET_assert (GNUNET_NO == pos->is_connected);
  646. pos->greylisted_until.abs_value_us = 0; /* remove greylisting */
  647. }
  648. pos->is_connected = GNUNET_YES;
  649. pos->connect_attempts = 0; /* re-set back-off factor */
  650. pos->next_connect_attempt = GNUNET_TIME_absolute_get(); /* re-set back-off factor */
  651. if (pos->is_friend)
  652. {
  653. if ((friend_count == minimum_friend_count - 1) &&
  654. (GNUNET_YES != friends_only))
  655. whitelist_peers ();
  656. friend_count++;
  657. GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"),
  658. friend_count, GNUNET_NO);
  659. }
  660. reschedule_hellos (NULL, peer, pos);
  661. }
  662. /**
  663. * Try to add more peers to our connection set.
  664. *
  665. * @param cls closure, not used
  666. * @param pid identity of a peer
  667. * @param value 'struct Peer*' for the peer
  668. * @return GNUNET_YES (continue to iterate)
  669. */
  670. static int
  671. try_add_peers (void *cls, const struct GNUNET_PeerIdentity * pid, void *value)
  672. {
  673. struct Peer *pos = value;
  674. schedule_attempt_connect (pos);
  675. return GNUNET_YES;
  676. }
  677. /**
  678. * Add peers and schedule connection attempt
  679. *
  680. * @param cls unused, NULL
  681. * @param tc scheduler context
  682. */
  683. static void
  684. add_peer_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  685. {
  686. add_task = GNUNET_SCHEDULER_NO_TASK;
  687. GNUNET_CONTAINER_multipeermap_iterate (peers, &try_add_peers, NULL);
  688. }
  689. /**
  690. * Method called whenever a peer disconnects.
  691. *
  692. * @param cls closure
  693. * @param peer peer identity this notification is about
  694. */
  695. static void
  696. disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer)
  697. {
  698. struct Peer *pos;
  699. if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
  700. return;
  701. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  702. "Core told us that we disconnected from `%s'\n",
  703. GNUNET_i2s (peer));
  704. pos = GNUNET_CONTAINER_multipeermap_get (peers, peer);
  705. if (NULL == pos)
  706. {
  707. GNUNET_break (0);
  708. return;
  709. }
  710. if (pos->is_connected != GNUNET_YES)
  711. {
  712. GNUNET_break (0);
  713. return;
  714. }
  715. pos->is_connected = GNUNET_NO;
  716. connection_count--;
  717. if (NULL != pos->hello_req)
  718. {
  719. GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
  720. pos->hello_req = NULL;
  721. }
  722. if (GNUNET_SCHEDULER_NO_TASK != pos->hello_delay_task)
  723. {
  724. GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
  725. pos->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
  726. }
  727. GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"),
  728. connection_count, GNUNET_NO);
  729. if (pos->is_friend)
  730. {
  731. friend_count--;
  732. GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"),
  733. friend_count, GNUNET_NO);
  734. }
  735. if (((connection_count < target_connection_count) ||
  736. (friend_count < minimum_friend_count)) &&
  737. (GNUNET_SCHEDULER_NO_TASK == add_task))
  738. add_task = GNUNET_SCHEDULER_add_now (&add_peer_task, NULL);
  739. if ((friend_count < minimum_friend_count) && (blacklist == NULL))
  740. blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL);
  741. }
  742. /**
  743. * Iterator called on each address.
  744. *
  745. * @param cls flag that we will set if we see any addresses
  746. * @param address the address of the peer
  747. * @param expiration when will the given address expire
  748. * @return GNUNET_SYSERR always, to terminate iteration
  749. */
  750. static int
  751. address_iterator (void *cls, const struct GNUNET_HELLO_Address *address,
  752. struct GNUNET_TIME_Absolute expiration)
  753. {
  754. int *flag = cls;
  755. *flag = GNUNET_YES;
  756. return GNUNET_SYSERR;
  757. }
  758. /**
  759. * We've gotten a HELLO from another peer. Consider it for
  760. * advertising.
  761. *
  762. * @param hello the HELLO we got
  763. */
  764. static void
  765. consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
  766. {
  767. int have_address;
  768. struct GNUNET_PeerIdentity pid;
  769. struct GNUNET_TIME_Absolute dt;
  770. struct GNUNET_HELLO_Message *nh;
  771. struct Peer *peer;
  772. uint16_t size;
  773. if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
  774. {
  775. GNUNET_break (0);
  776. return;
  777. }
  778. if (0 == memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
  779. return; /* that's me! */
  780. have_address = GNUNET_NO;
  781. GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &address_iterator,
  782. &have_address);
  783. if (GNUNET_NO == have_address)
  784. return; /* no point in advertising this one... */
  785. peer = GNUNET_CONTAINER_multipeermap_get (peers, &pid);
  786. if (NULL == peer)
  787. {
  788. peer = make_peer (&pid, hello, GNUNET_NO);
  789. }
  790. else if (peer->hello != NULL)
  791. {
  792. dt = GNUNET_HELLO_equals (peer->hello, hello, GNUNET_TIME_absolute_get ());
  793. if (dt.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
  794. return; /* nothing new here */
  795. }
  796. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  797. "Found `%s' from peer `%s' for advertising\n", "HELLO",
  798. GNUNET_i2s (&pid));
  799. if (peer->hello != NULL)
  800. {
  801. nh = GNUNET_HELLO_merge (peer->hello, hello);
  802. GNUNET_free (peer->hello);
  803. peer->hello = nh;
  804. }
  805. else
  806. {
  807. size = GNUNET_HELLO_size (hello);
  808. peer->hello = GNUNET_malloc (size);
  809. memcpy (peer->hello, hello, size);
  810. }
  811. if (peer->filter != NULL)
  812. GNUNET_CONTAINER_bloomfilter_free (peer->filter);
  813. setup_filter (peer);
  814. /* since we have a new HELLO to pick from, re-schedule all
  815. * HELLO requests that are not bound by the HELLO send rate! */
  816. GNUNET_CONTAINER_multipeermap_iterate (peers, &reschedule_hellos, peer);
  817. }
  818. /**
  819. * PEERINFO calls this function to let us know about a possible peer
  820. * that we might want to connect to.
  821. *
  822. * @param cls closure (not used)
  823. * @param peer potential peer to connect to
  824. * @param hello HELLO for this peer (or NULL)
  825. * @param err_msg NULL if successful, otherwise contains error message
  826. */
  827. static void
  828. process_peer (void *cls, const struct GNUNET_PeerIdentity *peer,
  829. const struct GNUNET_HELLO_Message *hello, const char *err_msg)
  830. {
  831. struct Peer *pos;
  832. if (err_msg != NULL)
  833. {
  834. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  835. _("Error in communication with PEERINFO service: %s\n"),
  836. err_msg);
  837. GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
  838. peerinfo_notify = GNUNET_PEERINFO_notify (cfg, GNUNET_NO, &process_peer, NULL);
  839. return;
  840. }
  841. GNUNET_assert (peer != NULL);
  842. if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
  843. return; /* that's me! */
  844. if (hello == NULL)
  845. {
  846. /* free existing HELLO, if any */
  847. pos = GNUNET_CONTAINER_multipeermap_get (peers, peer);
  848. if (NULL != pos)
  849. {
  850. GNUNET_free_non_null (pos->hello);
  851. pos->hello = NULL;
  852. if (pos->filter != NULL)
  853. {
  854. GNUNET_CONTAINER_bloomfilter_free (pos->filter);
  855. pos->filter = NULL;
  856. }
  857. if ((GNUNET_NO == pos->is_connected) && (GNUNET_NO == pos->is_friend) &&
  858. (0 ==
  859. GNUNET_TIME_absolute_get_remaining (pos->
  860. greylisted_until).rel_value_us))
  861. free_peer (NULL, &pos->pid, pos);
  862. }
  863. return;
  864. }
  865. consider_for_advertising (hello);
  866. pos = GNUNET_CONTAINER_multipeermap_get (peers, peer);
  867. if (pos == NULL)
  868. pos = make_peer (peer, hello, GNUNET_NO);
  869. GNUNET_assert (NULL != pos);
  870. if (GNUNET_YES == pos->is_connected)
  871. {
  872. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already connected to peer `%s'\n",
  873. GNUNET_i2s (peer));
  874. return;
  875. }
  876. if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value_us > 0)
  877. {
  878. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already tried peer `%s' recently\n",
  879. GNUNET_i2s (peer));
  880. return; /* peer still greylisted */
  881. }
  882. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting to peer `%s'\n",
  883. GNUNET_i2s (peer));
  884. schedule_attempt_connect (pos);
  885. }
  886. /**
  887. * Function called after #GNUNET_CORE_connect has succeeded
  888. * (or failed for good).
  889. *
  890. * @param cls closure
  891. * @param my_id ID of this peer, NULL if we failed
  892. */
  893. static void
  894. core_init (void *cls,
  895. const struct GNUNET_PeerIdentity *my_id)
  896. {
  897. if (NULL == my_id)
  898. {
  899. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  900. _
  901. ("Failed to connect to core service, can not manage topology!\n"));
  902. GNUNET_SCHEDULER_shutdown ();
  903. return;
  904. }
  905. my_identity = *my_id;
  906. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  907. "I am peer `%s'\n",
  908. GNUNET_i2s (my_id));
  909. peerinfo_notify = GNUNET_PEERINFO_notify (cfg, GNUNET_NO,
  910. &process_peer, NULL);
  911. }
  912. /**
  913. * Process friend found in FRIENDS file.
  914. *
  915. * @param cls pointer to an `unsigned int` to be incremented per friend found
  916. * @param pid identity of the friend
  917. */
  918. static void
  919. handle_friend (void *cls,
  920. const struct GNUNET_PeerIdentity *pid)
  921. {
  922. unsigned int *entries_found = cls;
  923. struct Peer *fl;
  924. if (0 == memcmp (pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
  925. {
  926. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  927. _("Found myself `%s' in friend list (useless, ignored)\n"),
  928. GNUNET_i2s (pid));
  929. return;
  930. }
  931. (*entries_found)++;
  932. fl = make_peer (pid, NULL, GNUNET_YES);
  933. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  934. _("Found friend `%s' in configuration\n"),
  935. GNUNET_i2s (&fl->pid));
  936. }
  937. /**
  938. * Read the friends file.
  939. */
  940. static void
  941. read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
  942. {
  943. unsigned int entries_found;
  944. entries_found = 0;
  945. if (GNUNET_OK !=
  946. GNUNET_FRIENDS_parse (cfg,
  947. &handle_friend,
  948. &entries_found))
  949. {
  950. if ((friends_only) || (minimum_friend_count > 0))
  951. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  952. _("Encountered errors parsing friends list!\n"));
  953. }
  954. GNUNET_STATISTICS_update (stats, gettext_noop ("# friends in configuration"),
  955. entries_found, GNUNET_NO);
  956. if ((minimum_friend_count > entries_found) && (friends_only == GNUNET_NO))
  957. {
  958. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  959. _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
  960. }
  961. if ((minimum_friend_count > target_connection_count) &&
  962. (friends_only == GNUNET_NO))
  963. {
  964. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  965. _("More friendly connections required than target total number of connections.\n"));
  966. }
  967. }
  968. /**
  969. * This function is called whenever an encrypted HELLO message is
  970. * received.
  971. *
  972. * @param cls closure
  973. * @param other the other peer involved (sender or receiver, NULL
  974. * for loopback messages where we are both sender and receiver)
  975. * @param message the actual HELLO message
  976. * @return GNUNET_OK to keep the connection open,
  977. * GNUNET_SYSERR to close it (signal serious error)
  978. */
  979. static int
  980. handle_encrypted_hello (void *cls, const struct GNUNET_PeerIdentity *other,
  981. const struct GNUNET_MessageHeader *message)
  982. {
  983. struct Peer *peer;
  984. struct GNUNET_PeerIdentity pid;
  985. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted `%s' from peer `%s'",
  986. "HELLO", GNUNET_i2s (other));
  987. if (GNUNET_OK !=
  988. GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &pid))
  989. {
  990. GNUNET_break_op (0);
  991. return GNUNET_SYSERR;
  992. }
  993. GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received"),
  994. 1, GNUNET_NO);
  995. peer = GNUNET_CONTAINER_multipeermap_get (peers, &pid);
  996. if (NULL == peer)
  997. {
  998. if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_count))
  999. return GNUNET_OK;
  1000. }
  1001. else
  1002. {
  1003. if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only))
  1004. return GNUNET_OK;
  1005. if ((GNUNET_YES != peer->is_friend) &&
  1006. (friend_count < minimum_friend_count))
  1007. return GNUNET_OK;
  1008. }
  1009. if (transport != NULL)
  1010. GNUNET_TRANSPORT_offer_hello (transport, message, NULL, NULL);
  1011. return GNUNET_OK;
  1012. }
  1013. /**
  1014. * Function to fill send buffer with HELLO.
  1015. *
  1016. * @param cls 'struct Peer' of the target peer
  1017. * @param size number of bytes available in buf
  1018. * @param buf where the callee should write the message
  1019. * @return number of bytes written to buf
  1020. */
  1021. static size_t
  1022. hello_advertising_ready (void *cls, size_t size, void *buf)
  1023. {
  1024. struct Peer *pl = cls;
  1025. struct FindAdvHelloContext fah;
  1026. size_t want;
  1027. struct GNUNET_HashCode hc;
  1028. pl->hello_req = NULL;
  1029. GNUNET_assert (GNUNET_YES == pl->is_connected);
  1030. /* find applicable HELLOs */
  1031. fah.peer = pl;
  1032. fah.result = NULL;
  1033. fah.max_size = size;
  1034. fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
  1035. GNUNET_CONTAINER_multipeermap_iterate (peers, &find_advertisable_hello, &fah);
  1036. want = 0;
  1037. if (fah.result != NULL)
  1038. {
  1039. want = GNUNET_HELLO_size (fah.result->hello);
  1040. GNUNET_assert (want <= size);
  1041. memcpy (buf, fah.result->hello, want);
  1042. GNUNET_CRYPTO_hash (&pl->pid, sizeof (struct GNUNET_PeerIdentity), &hc);
  1043. GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &hc);
  1044. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' with %u bytes", "HELLO",
  1045. (unsigned int) want);
  1046. GNUNET_STATISTICS_update (stats,
  1047. gettext_noop ("# HELLO messages gossipped"), 1,
  1048. GNUNET_NO);
  1049. }
  1050. if (pl->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
  1051. GNUNET_SCHEDULER_cancel (pl->hello_delay_task);
  1052. pl->next_hello_allowed =
  1053. GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
  1054. pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl);
  1055. return want;
  1056. }
  1057. /**
  1058. * Last task run during shutdown. Disconnects us from
  1059. * the transport and core.
  1060. *
  1061. * @param cls unused, NULL
  1062. * @param tc scheduler context
  1063. */
  1064. static void
  1065. cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  1066. {
  1067. if (NULL != peerinfo_notify)
  1068. {
  1069. GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
  1070. peerinfo_notify = NULL;
  1071. }
  1072. GNUNET_TRANSPORT_disconnect (transport);
  1073. transport = NULL;
  1074. if (handle != NULL)
  1075. {
  1076. GNUNET_CORE_disconnect (handle);
  1077. handle = NULL;
  1078. }
  1079. whitelist_peers ();
  1080. if (GNUNET_SCHEDULER_NO_TASK != add_task)
  1081. {
  1082. GNUNET_SCHEDULER_cancel (add_task);
  1083. add_task = GNUNET_SCHEDULER_NO_TASK;
  1084. }
  1085. GNUNET_CONTAINER_multipeermap_iterate (peers, &free_peer, NULL);
  1086. GNUNET_CONTAINER_multipeermap_destroy (peers);
  1087. peers = NULL;
  1088. if (stats != NULL)
  1089. {
  1090. GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
  1091. stats = NULL;
  1092. }
  1093. }
  1094. /**
  1095. * Main function that will be run.
  1096. *
  1097. * @param cls closure
  1098. * @param args remaining command-line arguments
  1099. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  1100. * @param c configuration
  1101. */
  1102. static void
  1103. run (void *cls,
  1104. char *const *args,
  1105. const char *cfgfile,
  1106. const struct GNUNET_CONFIGURATION_Handle *c)
  1107. {
  1108. static struct GNUNET_CORE_MessageHandler handlers[] = {
  1109. {&handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
  1110. {NULL, 0, 0}
  1111. };
  1112. unsigned long long opt;
  1113. cfg = c;
  1114. stats = GNUNET_STATISTICS_create ("topology", cfg);
  1115. friends_only =
  1116. GNUNET_CONFIGURATION_get_value_yesno (cfg, "TOPOLOGY", "FRIENDS-ONLY");
  1117. if (GNUNET_OK !=
  1118. GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY", "MINIMUM-FRIENDS",
  1119. &opt))
  1120. opt = 0;
  1121. minimum_friend_count = (unsigned int) opt;
  1122. if (GNUNET_OK !=
  1123. GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY",
  1124. "TARGET-CONNECTION-COUNT", &opt))
  1125. opt = 16;
  1126. target_connection_count = (unsigned int) opt;
  1127. peers = GNUNET_CONTAINER_multipeermap_create (target_connection_count * 2, GNUNET_NO);
  1128. if ((friends_only == GNUNET_YES) || (minimum_friend_count > 0))
  1129. read_friends_file (cfg);
  1130. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1131. "Topology would like %u connections with at least %u friends\n",
  1132. target_connection_count, minimum_friend_count);
  1133. if ((friend_count < minimum_friend_count) && (blacklist == NULL))
  1134. blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL);
  1135. transport = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL, NULL, NULL);
  1136. handle =
  1137. GNUNET_CORE_connect (cfg, NULL,
  1138. &core_init,
  1139. &connect_notify,
  1140. &disconnect_notify,
  1141. NULL, GNUNET_NO,
  1142. NULL, GNUNET_NO,
  1143. handlers);
  1144. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task,
  1145. NULL);
  1146. if (NULL == transport)
  1147. {
  1148. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1149. _("Failed to connect to `%s' service.\n"), "transport");
  1150. GNUNET_SCHEDULER_shutdown ();
  1151. return;
  1152. }
  1153. if (NULL == handle)
  1154. {
  1155. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1156. _("Failed to connect to `%s' service.\n"), "core");
  1157. GNUNET_SCHEDULER_shutdown ();
  1158. return;
  1159. }
  1160. }
  1161. /**
  1162. * The main function for the topology daemon.
  1163. *
  1164. * @param argc number of arguments from the command line
  1165. * @param argv command line arguments
  1166. * @return 0 ok, 1 on error
  1167. */
  1168. int
  1169. main (int argc, char *const *argv)
  1170. {
  1171. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  1172. GNUNET_GETOPT_OPTION_END
  1173. };
  1174. int ret;
  1175. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  1176. return 2;
  1177. ret =
  1178. (GNUNET_OK ==
  1179. GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-topology",
  1180. _
  1181. ("GNUnet topology control (maintaining P2P cadet and F2F constraints)"),
  1182. options, &run, NULL)) ? 0 : 1;
  1183. GNUNET_free ((void*) argv);
  1184. return ret;
  1185. }
  1186. #ifdef LINUX
  1187. #include <malloc.h>
  1188. /**
  1189. * MINIMIZE heap size (way below 128k) since this process doesn't need much.
  1190. */
  1191. void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
  1192. {
  1193. mallopt (M_TRIM_THRESHOLD, 4 * 1024);
  1194. mallopt (M_TOP_PAD, 1 * 1024);
  1195. malloc_trim (0);
  1196. }
  1197. #endif
  1198. /* end of gnunet-daemon-topology.c */