gnunet-service-nse.c 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 2010, 2011, 2012, 2013, 2016 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your 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. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file nse/gnunet-service-nse.c
  18. * @brief network size estimation service
  19. * @author Nathan Evans
  20. * @author Christian Grothoff
  21. *
  22. * The purpose of this service is to estimate the size of the network.
  23. * Given a specified interval, each peer hashes the most recent
  24. * timestamp which is evenly divisible by that interval. This hash is
  25. * compared in distance to the peer identity to choose an offset. The
  26. * closer the peer identity to the hashed timestamp, the earlier the
  27. * peer sends out a "nearest peer" message. The closest peer's
  28. * message should thus be received before any others, which stops
  29. * those peer from sending their messages at a later duration. So
  30. * every peer should receive the same nearest peer message, and from
  31. * this can calculate the expected number of peers in the network.
  32. */
  33. #include "platform.h"
  34. #include <math.h>
  35. #include "gnunet_util_lib.h"
  36. #include "gnunet_constants.h"
  37. #include "gnunet_protocols.h"
  38. #include "gnunet_signatures.h"
  39. #include "gnunet_statistics_service.h"
  40. #include "gnunet_core_service.h"
  41. #include "gnunet_nse_service.h"
  42. #if ENABLE_NSE_HISTOGRAM
  43. #include "gnunet_testbed_logger_service.h"
  44. #endif
  45. #include "nse.h"
  46. #include <gcrypt.h>
  47. /**
  48. * Should messages be delayed randomly? This option should be set to
  49. * #GNUNET_NO only for experiments, not in production.
  50. */
  51. #define USE_RANDOM_DELAYS GNUNET_YES
  52. /**
  53. * Generate extensive debug-level log messages?
  54. */
  55. #define DEBUG_NSE GNUNET_NO
  56. /**
  57. * Over how many values do we calculate the weighted average?
  58. */
  59. #define HISTORY_SIZE 64
  60. /**
  61. * Message priority to use. No real rush, reliability not
  62. * required. Corking OK.
  63. */
  64. #define NSE_PRIORITY \
  65. (GNUNET_MQ_PRIO_BACKGROUND | GNUNET_MQ_PREF_UNRELIABLE | \
  66. GNUNET_MQ_PREF_CORK_ALLOWED)
  67. #if FREEBSD
  68. #define log2(a) (log (a) / log (2))
  69. #endif
  70. /**
  71. * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
  72. */
  73. static unsigned long long nse_work_required;
  74. /**
  75. * Interval for sending network size estimation flood requests.
  76. */
  77. static struct GNUNET_TIME_Relative gnunet_nse_interval;
  78. /**
  79. * Interval between proof find runs.
  80. */
  81. static struct GNUNET_TIME_Relative proof_find_delay;
  82. #if ENABLE_NSE_HISTOGRAM
  83. /**
  84. * Handle to test if testbed logger service is running or not
  85. */
  86. struct GNUNET_CLIENT_TestHandle *logger_test;
  87. /**
  88. * Handle for writing when we received messages to disk.
  89. */
  90. static struct GNUNET_TESTBED_LOGGER_Handle *lh;
  91. /**
  92. * Handle for writing message received timestamp information to disk.
  93. */
  94. static struct GNUNET_BIO_WriteHandle *histogram;
  95. #endif
  96. /**
  97. * Per-peer information.
  98. */
  99. struct NSEPeerEntry
  100. {
  101. /**
  102. * Core handle for sending messages to this peer.
  103. */
  104. struct GNUNET_MQ_Handle *mq;
  105. /**
  106. * What is the identity of the peer?
  107. */
  108. const struct GNUNET_PeerIdentity *id;
  109. /**
  110. * Task scheduled to send message to this peer.
  111. */
  112. struct GNUNET_SCHEDULER_Task *transmit_task;
  113. /**
  114. * Did we receive or send a message about the previous round
  115. * to this peer yet? #GNUNET_YES if the previous round has
  116. * been taken care of.
  117. */
  118. int previous_round;
  119. #if ENABLE_NSE_HISTOGRAM
  120. /**
  121. * Amount of messages received from this peer on this round.
  122. */
  123. unsigned int received_messages;
  124. /**
  125. * Amount of messages transmitted to this peer on this round.
  126. */
  127. unsigned int transmitted_messages;
  128. /**
  129. * Which size did we tell the peer the network is?
  130. */
  131. unsigned int last_transmitted_size;
  132. #endif
  133. };
  134. GNUNET_NETWORK_STRUCT_BEGIN
  135. /**
  136. * Network size estimate reply; sent when "this"
  137. * peer's timer has run out before receiving a
  138. * valid reply from another peer.
  139. */
  140. struct GNUNET_NSE_FloodMessage
  141. {
  142. /**
  143. * Type: #GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD
  144. */
  145. struct GNUNET_MessageHeader header;
  146. /**
  147. * Number of hops this message has taken so far.
  148. */
  149. uint32_t hop_count GNUNET_PACKED;
  150. /**
  151. * Purpose.
  152. */
  153. struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
  154. /**
  155. * The current timestamp value (which all
  156. * peers should agree on).
  157. */
  158. struct GNUNET_TIME_AbsoluteNBO timestamp;
  159. /**
  160. * Number of matching bits between the hash
  161. * of timestamp and the initiator's public
  162. * key.
  163. */
  164. uint32_t matching_bits GNUNET_PACKED;
  165. /**
  166. * Public key of the originator.
  167. */
  168. struct GNUNET_PeerIdentity origin;
  169. /**
  170. * Proof of work, causing leading zeros when hashed with pkey.
  171. */
  172. uint64_t proof_of_work GNUNET_PACKED;
  173. /**
  174. * Signature (over range specified in purpose).
  175. */
  176. struct GNUNET_CRYPTO_EddsaSignature signature;
  177. };
  178. GNUNET_NETWORK_STRUCT_END
  179. /**
  180. * Handle to our current configuration.
  181. */
  182. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  183. /**
  184. * Handle to the statistics service.
  185. */
  186. static struct GNUNET_STATISTICS_Handle *stats;
  187. /**
  188. * Handle to the core service.
  189. */
  190. static struct GNUNET_CORE_Handle *core_api;
  191. /**
  192. * Map of all connected peers.
  193. */
  194. static struct GNUNET_CONTAINER_MultiPeerMap *peers;
  195. /**
  196. * The current network size estimate. Number of bits matching on
  197. * average thus far.
  198. */
  199. static double current_size_estimate;
  200. /**
  201. * The standard deviation of the last #HISTORY_SIZE network
  202. * size estimates.
  203. */
  204. static double current_std_dev = NAN;
  205. /**
  206. * Current hop counter estimate (estimate for network diameter).
  207. */
  208. static uint32_t hop_count_max;
  209. /**
  210. * Message for the next round, if we got any.
  211. */
  212. static struct GNUNET_NSE_FloodMessage next_message;
  213. /**
  214. * Array of recent size estimate messages.
  215. */
  216. static struct GNUNET_NSE_FloodMessage size_estimate_messages[HISTORY_SIZE];
  217. /**
  218. * Index of most recent estimate.
  219. */
  220. static unsigned int estimate_index;
  221. /**
  222. * Number of valid entries in the history.
  223. */
  224. static unsigned int estimate_count;
  225. /**
  226. * Task scheduled to update our flood message for the next round.
  227. */
  228. static struct GNUNET_SCHEDULER_Task *flood_task;
  229. /**
  230. * Task scheduled to compute our proof.
  231. */
  232. static struct GNUNET_SCHEDULER_Task *proof_task;
  233. /**
  234. * Notification context, simplifies client broadcasts.
  235. */
  236. static struct GNUNET_NotificationContext *nc;
  237. /**
  238. * The next major time.
  239. */
  240. static struct GNUNET_TIME_Absolute next_timestamp;
  241. /**
  242. * The current major time.
  243. */
  244. static struct GNUNET_TIME_Absolute current_timestamp;
  245. /**
  246. * The private key of this peer.
  247. */
  248. static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
  249. /**
  250. * The peer identity of this peer.
  251. */
  252. static struct GNUNET_PeerIdentity my_identity;
  253. /**
  254. * Proof of work for this peer.
  255. */
  256. static uint64_t my_proof;
  257. /**
  258. * Initialize a message to clients with the current network
  259. * size estimate.
  260. *
  261. * @param em message to fill in
  262. */
  263. static void
  264. setup_estimate_message (struct GNUNET_NSE_ClientMessage *em)
  265. {
  266. double mean;
  267. double sum;
  268. double std_dev;
  269. double variance;
  270. double val;
  271. double nsize;
  272. #define WEST 1
  273. /* Weighted incremental algorithm for stddev according to West (1979) */
  274. #if WEST
  275. double sumweight;
  276. double weight;
  277. double q;
  278. double r;
  279. double temp;
  280. mean = 0.0;
  281. sum = 0.0;
  282. sumweight = 0.0;
  283. variance = 0.0;
  284. for (unsigned int i = 0; i < estimate_count; i++)
  285. {
  286. unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
  287. val = htonl (size_estimate_messages[j].matching_bits);
  288. weight = estimate_count + 1 - i;
  289. temp = weight + sumweight;
  290. q = val - mean;
  291. r = q * weight / temp;
  292. mean += r;
  293. sum += sumweight * q * r;
  294. sumweight = temp;
  295. }
  296. if (estimate_count > 0)
  297. variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0);
  298. #else
  299. /* trivial version for debugging */
  300. double vsq;
  301. /* non-weighted trivial version */
  302. sum = 0.0;
  303. vsq = 0.0;
  304. variance = 0.0;
  305. mean = 0.0;
  306. for (unsigned int i = 0; i < estimate_count; i++)
  307. {
  308. unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
  309. val = htonl (size_estimate_messages[j].matching_bits);
  310. sum += val;
  311. vsq += val * val;
  312. }
  313. if (0 != estimate_count)
  314. {
  315. mean = sum / estimate_count;
  316. variance = (vsq - mean * sum) /
  317. (estimate_count - 1.0); // terrible for numerical stability...
  318. }
  319. #endif
  320. if (variance >= 0)
  321. std_dev = sqrt (variance);
  322. else
  323. std_dev = variance; /* must be infinity due to estimate_count == 0 */
  324. current_std_dev = std_dev;
  325. current_size_estimate = mean;
  326. em->header.size = htons (sizeof (struct GNUNET_NSE_ClientMessage));
  327. em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
  328. em->reserved = htonl (0);
  329. em->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
  330. {
  331. double se = mean - 0.332747;
  332. unsigned int j = GNUNET_CONTAINER_multipeermap_size (peers);
  333. if (0 == j)
  334. j = 1; /* Avoid log2(0); can only happen if CORE didn't report
  335. connection to self yet */
  336. nsize = log2 (j);
  337. em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize));
  338. em->std_deviation = GNUNET_hton_double (std_dev);
  339. GNUNET_STATISTICS_set (stats,
  340. "# nodes in the network (estimate)",
  341. (uint64_t) pow (2, GNUNET_MAX (se, nsize)),
  342. GNUNET_NO);
  343. }
  344. }
  345. /**
  346. * Handler for START message from client, triggers an
  347. * immediate current network estimate notification.
  348. * Also, we remember the client for updates upon future
  349. * estimate measurements.
  350. *
  351. * @param cls client who sent the message
  352. * @param message the message received
  353. */
  354. static void
  355. handle_start (void *cls, const struct GNUNET_MessageHeader *message)
  356. {
  357. struct GNUNET_SERVICE_Client *client = cls;
  358. struct GNUNET_MQ_Handle *mq;
  359. struct GNUNET_NSE_ClientMessage em;
  360. struct GNUNET_MQ_Envelope *env;
  361. (void) message;
  362. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n");
  363. mq = GNUNET_SERVICE_client_get_mq (client);
  364. GNUNET_notification_context_add (nc, mq);
  365. setup_estimate_message (&em);
  366. env = GNUNET_MQ_msg_copy (&em.header);
  367. GNUNET_MQ_send (mq, env);
  368. GNUNET_SERVICE_client_continue (client);
  369. }
  370. /**
  371. * How long should we delay a message to go the given number of
  372. * matching bits?
  373. *
  374. * @param matching_bits number of matching bits to consider
  375. */
  376. static double
  377. get_matching_bits_delay (uint32_t matching_bits)
  378. {
  379. /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */
  380. // S is next_timestamp (ignored in return value)
  381. // f is frequency (gnunet_nse_interval)
  382. // x is matching_bits
  383. // p' is current_size_estimate
  384. return ((double) gnunet_nse_interval.rel_value_us / (double) 2.0) -
  385. ((gnunet_nse_interval.rel_value_us / M_PI) *
  386. atan (matching_bits - current_size_estimate));
  387. }
  388. /**
  389. * What delay randomization should we apply for a given number of matching bits?
  390. *
  391. * @param matching_bits number of matching bits
  392. * @return random delay to apply
  393. */
  394. static struct GNUNET_TIME_Relative
  395. get_delay_randomization (uint32_t matching_bits)
  396. {
  397. #if USE_RANDOM_DELAYS
  398. struct GNUNET_TIME_Relative ret;
  399. uint32_t i;
  400. double d;
  401. d = get_matching_bits_delay (matching_bits);
  402. i = (uint32_t) (d / (double) (hop_count_max + 1));
  403. ret.rel_value_us = i;
  404. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  405. "Randomizing flood using latencies up to %s\n",
  406. GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
  407. ret.rel_value_us =
  408. GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1);
  409. return ret;
  410. #else
  411. return GNUNET_TIME_UNIT_ZERO;
  412. #endif
  413. }
  414. /**
  415. * Calculate the 'proof-of-work' hash (an expensive hash).
  416. *
  417. * @param buf data to hash
  418. * @param buf_len number of bytes in @a buf
  419. * @param result where to write the resulting hash
  420. */
  421. static void
  422. pow_hash (const void *buf, size_t buf_len, struct GNUNET_HashCode *result)
  423. {
  424. GNUNET_break (
  425. 0 == gcry_kdf_derive (buf,
  426. buf_len,
  427. GCRY_KDF_SCRYPT,
  428. 1 /* subalgo */,
  429. "gnunet-proof-of-work",
  430. strlen ("gnunet-proof-of-work"),
  431. 2 /* iterations; keep cost of individual op small */,
  432. sizeof (struct GNUNET_HashCode),
  433. result));
  434. }
  435. /**
  436. * Get the number of matching bits that the given timestamp has to the given peer ID.
  437. *
  438. * @param timestamp time to generate key
  439. * @param id peer identity to compare with
  440. * @return number of matching bits
  441. */
  442. static uint32_t
  443. get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
  444. const struct GNUNET_PeerIdentity *id)
  445. {
  446. struct GNUNET_HashCode timestamp_hash;
  447. struct GNUNET_HashCode pid_hash;
  448. GNUNET_CRYPTO_hash (&timestamp.abs_value_us,
  449. sizeof (timestamp.abs_value_us),
  450. &timestamp_hash);
  451. GNUNET_CRYPTO_hash (id, sizeof (struct GNUNET_PeerIdentity), &pid_hash);
  452. return GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash, &pid_hash);
  453. }
  454. /**
  455. * Get the transmission delay that should be applied for a
  456. * particular round.
  457. *
  458. * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
  459. * 0 for the current round (based on our proximity to time key)
  460. * @return delay that should be applied
  461. */
  462. static struct GNUNET_TIME_Relative
  463. get_transmit_delay (int round_offset)
  464. {
  465. struct GNUNET_TIME_Relative ret;
  466. struct GNUNET_TIME_Absolute tgt;
  467. double dist_delay;
  468. uint32_t matching_bits;
  469. switch (round_offset)
  470. {
  471. case -1:
  472. /* previous round is randomized between 0 and 50 ms */
  473. #if USE_RANDOM_DELAYS
  474. ret.rel_value_us =
  475. GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50);
  476. #else
  477. ret = GNUNET_TIME_UNIT_ZERO;
  478. #endif
  479. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  480. "Transmitting previous round behind schedule in %s\n",
  481. GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
  482. return ret;
  483. case 0:
  484. /* current round is based on best-known matching_bits */
  485. matching_bits =
  486. ntohl (size_estimate_messages[estimate_index].matching_bits);
  487. dist_delay = get_matching_bits_delay (matching_bits);
  488. dist_delay += get_delay_randomization (matching_bits).rel_value_us;
  489. ret.rel_value_us = (uint64_t) dist_delay;
  490. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  491. "For round %s, delay for %u matching bits is %s\n",
  492. GNUNET_STRINGS_absolute_time_to_string (current_timestamp),
  493. (unsigned int) matching_bits,
  494. GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
  495. /* now consider round start time and add delay to it */
  496. tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
  497. return GNUNET_TIME_absolute_get_remaining (tgt);
  498. }
  499. GNUNET_break (0);
  500. return GNUNET_TIME_UNIT_FOREVER_REL;
  501. }
  502. /**
  503. * Task that triggers a NSE P2P transmission.
  504. *
  505. * @param cls the `struct NSEPeerEntry *`
  506. */
  507. static void
  508. transmit_task_cb (void *cls)
  509. {
  510. struct NSEPeerEntry *peer_entry = cls;
  511. unsigned int idx;
  512. struct GNUNET_MQ_Envelope *env;
  513. peer_entry->transmit_task = NULL;
  514. idx = estimate_index;
  515. if (GNUNET_NO == peer_entry->previous_round)
  516. {
  517. idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
  518. peer_entry->previous_round = GNUNET_YES;
  519. peer_entry->transmit_task =
  520. GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0),
  521. &transmit_task_cb,
  522. peer_entry);
  523. }
  524. if ((0 == ntohl (size_estimate_messages[idx].hop_count)) &&
  525. (NULL != proof_task))
  526. {
  527. GNUNET_STATISTICS_update (stats,
  528. "# flood messages not generated (no proof yet)",
  529. 1,
  530. GNUNET_NO);
  531. return;
  532. }
  533. if (0 == ntohs (size_estimate_messages[idx].header.size))
  534. {
  535. GNUNET_STATISTICS_update (stats,
  536. "# flood messages not generated (lack of history)",
  537. 1,
  538. GNUNET_NO);
  539. return;
  540. }
  541. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  542. "In round %s, sending to `%s' estimate with %u bits\n",
  543. GNUNET_STRINGS_absolute_time_to_string (
  544. GNUNET_TIME_absolute_ntoh (
  545. size_estimate_messages[idx].timestamp)),
  546. GNUNET_i2s (peer_entry->id),
  547. (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
  548. if (0 == ntohl (size_estimate_messages[idx].hop_count))
  549. GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
  550. GNUNET_STATISTICS_update (stats,
  551. "# flood messages transmitted",
  552. 1,
  553. GNUNET_NO);
  554. #if ENABLE_NSE_HISTOGRAM
  555. peer_entry->transmitted_messages++;
  556. peer_entry->last_transmitted_size =
  557. ntohl (size_estimate_messages[idx].matching_bits);
  558. #endif
  559. env = GNUNET_MQ_msg_copy (&size_estimate_messages[idx].header);
  560. GNUNET_MQ_send (peer_entry->mq, env);
  561. }
  562. /**
  563. * We've sent on our flood message or one that we received which was
  564. * validated and closer than ours. Update the global list of recent
  565. * messages and the average. Also re-broadcast the message to any
  566. * clients.
  567. */
  568. static void
  569. update_network_size_estimate ()
  570. {
  571. struct GNUNET_NSE_ClientMessage em;
  572. setup_estimate_message (&em);
  573. GNUNET_notification_context_broadcast (nc, &em.header, GNUNET_YES);
  574. }
  575. /**
  576. * Setup a flood message in our history array at the given
  577. * slot offset for the given timestamp.
  578. *
  579. * @param slot index to use
  580. * @param ts timestamp to use
  581. */
  582. static void
  583. setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
  584. {
  585. struct GNUNET_NSE_FloodMessage *fm;
  586. uint32_t matching_bits;
  587. matching_bits = get_matching_bits (ts, &my_identity);
  588. fm = &size_estimate_messages[slot];
  589. fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage));
  590. fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
  591. fm->hop_count = htonl (0);
  592. fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
  593. fm->purpose.size =
  594. htonl (sizeof (struct GNUNET_NSE_FloodMessage) -
  595. sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) -
  596. sizeof (struct GNUNET_CRYPTO_EddsaSignature));
  597. fm->matching_bits = htonl (matching_bits);
  598. fm->timestamp = GNUNET_TIME_absolute_hton (ts);
  599. fm->origin = my_identity;
  600. fm->proof_of_work = my_proof;
  601. if (nse_work_required > 0)
  602. GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (my_private_key,
  603. &fm->purpose,
  604. &fm->signature));
  605. else
  606. memset (&fm->signature, 0, sizeof (fm->signature));
  607. }
  608. /**
  609. * Schedule transmission for the given peer for the current round based
  610. * on what we know about the desired delay.
  611. *
  612. * @param cls unused
  613. * @param key hash of peer identity
  614. * @param value the `struct NSEPeerEntry`
  615. * @return #GNUNET_OK (continue to iterate)
  616. */
  617. static int
  618. schedule_current_round (void *cls,
  619. const struct GNUNET_PeerIdentity *key,
  620. void *value)
  621. {
  622. struct NSEPeerEntry *peer_entry = value;
  623. struct GNUNET_TIME_Relative delay;
  624. (void) cls;
  625. (void) key;
  626. if (NULL != peer_entry->transmit_task)
  627. {
  628. GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
  629. peer_entry->previous_round = GNUNET_NO;
  630. }
  631. #if ENABLE_NSE_HISTOGRAM
  632. if (peer_entry->received_messages > 1)
  633. GNUNET_STATISTICS_update (stats,
  634. "# extra messages",
  635. peer_entry->received_messages - 1,
  636. GNUNET_NO);
  637. peer_entry->transmitted_messages = 0;
  638. peer_entry->last_transmitted_size = 0;
  639. peer_entry->received_messages = 0;
  640. #endif
  641. delay =
  642. get_transmit_delay ((GNUNET_NO == peer_entry->previous_round) ? -1 : 0);
  643. peer_entry->transmit_task =
  644. GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
  645. return GNUNET_OK;
  646. }
  647. /**
  648. * Update our flood message to be sent (and our timestamps).
  649. *
  650. * @param cls unused
  651. */
  652. static void
  653. update_flood_message (void *cls)
  654. {
  655. struct GNUNET_TIME_Relative offset;
  656. (void) cls;
  657. flood_task = NULL;
  658. offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
  659. if (0 != offset.rel_value_us)
  660. {
  661. /* somehow run early, delay more */
  662. flood_task =
  663. GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL);
  664. return;
  665. }
  666. estimate_index = (estimate_index + 1) % HISTORY_SIZE;
  667. if (estimate_count < HISTORY_SIZE)
  668. estimate_count++;
  669. current_timestamp = next_timestamp;
  670. next_timestamp =
  671. GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
  672. if ((current_timestamp.abs_value_us ==
  673. GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value_us) &&
  674. (get_matching_bits (current_timestamp, &my_identity) <
  675. ntohl (next_message.matching_bits)))
  676. {
  677. /* we received a message for this round way early, use it! */
  678. size_estimate_messages[estimate_index] = next_message;
  679. size_estimate_messages[estimate_index].hop_count =
  680. htonl (1 + ntohl (next_message.hop_count));
  681. }
  682. else
  683. setup_flood_message (estimate_index, current_timestamp);
  684. next_message.matching_bits = htonl (0); /* reset for 'next' round */
  685. hop_count_max = 0;
  686. for (unsigned int i = 0; i < HISTORY_SIZE; i++)
  687. hop_count_max =
  688. GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
  689. GNUNET_CONTAINER_multipeermap_iterate (peers, &schedule_current_round, NULL);
  690. flood_task =
  691. GNUNET_SCHEDULER_add_at (next_timestamp, &update_flood_message, NULL);
  692. }
  693. /**
  694. * Count the leading zeroes in hash.
  695. *
  696. * @param hash to count leading zeros in
  697. * @return the number of leading zero bits.
  698. */
  699. static unsigned int
  700. count_leading_zeroes (const struct GNUNET_HashCode *hash)
  701. {
  702. unsigned int hash_count;
  703. hash_count = 0;
  704. while (0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count))
  705. hash_count++;
  706. return hash_count;
  707. }
  708. /**
  709. * Check whether the given public key and integer are a valid proof of
  710. * work.
  711. *
  712. * @param pkey the public key
  713. * @param val the integer
  714. * @return #GNUNET_YES if valid, #GNUNET_NO if not
  715. */
  716. static int
  717. check_proof_of_work (const struct GNUNET_CRYPTO_EddsaPublicKey *pkey,
  718. uint64_t val)
  719. {
  720. char buf[sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
  721. sizeof (val)] GNUNET_ALIGN;
  722. struct GNUNET_HashCode result;
  723. GNUNET_memcpy (buf, &val, sizeof (val));
  724. GNUNET_memcpy (&buf[sizeof (val)],
  725. pkey,
  726. sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
  727. pow_hash (buf, sizeof (buf), &result);
  728. return (count_leading_zeroes (&result) >= nse_work_required) ? GNUNET_YES
  729. : GNUNET_NO;
  730. }
  731. /**
  732. * Write our current proof to disk.
  733. */
  734. static void
  735. write_proof ()
  736. {
  737. char *proof;
  738. if (GNUNET_OK !=
  739. GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
  740. return;
  741. if (sizeof (my_proof) != GNUNET_DISK_fn_write (proof,
  742. &my_proof,
  743. sizeof (my_proof),
  744. GNUNET_DISK_PERM_USER_READ |
  745. GNUNET_DISK_PERM_USER_WRITE))
  746. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof);
  747. GNUNET_free (proof);
  748. }
  749. /**
  750. * Find our proof of work.
  751. *
  752. * @param cls closure (unused)
  753. */
  754. static void
  755. find_proof (void *cls)
  756. {
  757. #define ROUND_SIZE 10
  758. uint64_t counter;
  759. char buf[sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
  760. sizeof (uint64_t)] GNUNET_ALIGN;
  761. struct GNUNET_HashCode result;
  762. unsigned int i;
  763. (void) cls;
  764. proof_task = NULL;
  765. GNUNET_memcpy (&buf[sizeof (uint64_t)],
  766. &my_identity,
  767. sizeof (struct GNUNET_PeerIdentity));
  768. i = 0;
  769. counter = my_proof;
  770. while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
  771. {
  772. GNUNET_memcpy (buf, &counter, sizeof (uint64_t));
  773. pow_hash (buf, sizeof (buf), &result);
  774. if (nse_work_required <= count_leading_zeroes (&result))
  775. {
  776. my_proof = counter;
  777. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  778. "Proof of work found: %llu!\n",
  779. (unsigned long long) GNUNET_ntohll (counter));
  780. write_proof ();
  781. setup_flood_message (estimate_index, current_timestamp);
  782. return;
  783. }
  784. counter++;
  785. i++;
  786. }
  787. if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
  788. {
  789. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  790. "Testing proofs currently at %llu\n",
  791. (unsigned long long) counter);
  792. /* remember progress every 100 rounds */
  793. my_proof = counter;
  794. write_proof ();
  795. }
  796. else
  797. {
  798. my_proof = counter;
  799. }
  800. proof_task =
  801. GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
  802. GNUNET_SCHEDULER_PRIORITY_IDLE,
  803. &find_proof,
  804. NULL);
  805. }
  806. /**
  807. * An incoming flood message has been received which claims
  808. * to have more bits matching than any we know in this time
  809. * period. Verify the signature and/or proof of work.
  810. *
  811. * @param incoming_flood the message to verify
  812. * @return #GNUNET_YES if the message is verified
  813. * #GNUNET_NO if the key/signature don't verify
  814. */
  815. static int
  816. verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
  817. {
  818. if (GNUNET_YES != check_proof_of_work (&incoming_flood->origin.public_key,
  819. incoming_flood->proof_of_work))
  820. {
  821. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  822. "Proof of work invalid: %llu!\n",
  823. (unsigned long long) GNUNET_ntohll (
  824. incoming_flood->proof_of_work));
  825. GNUNET_break_op (0);
  826. return GNUNET_NO;
  827. }
  828. if ((nse_work_required > 0) &&
  829. (GNUNET_OK !=
  830. GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
  831. &incoming_flood->purpose,
  832. &incoming_flood->signature,
  833. &incoming_flood->origin.public_key)))
  834. {
  835. GNUNET_break_op (0);
  836. return GNUNET_NO;
  837. }
  838. return GNUNET_YES;
  839. }
  840. /**
  841. * Update transmissions for the given peer for the current round based
  842. * on updated proximity information.
  843. *
  844. * @param cls peer entry to exclude from updates
  845. * @param key hash of peer identity
  846. * @param value the `struct NSEPeerEntry *` of a peer to transmit to
  847. * @return #GNUNET_OK (continue to iterate)
  848. */
  849. static int
  850. update_flood_times (void *cls,
  851. const struct GNUNET_PeerIdentity *key,
  852. void *value)
  853. {
  854. struct NSEPeerEntry *exclude = cls;
  855. struct NSEPeerEntry *peer_entry = value;
  856. struct GNUNET_TIME_Relative delay;
  857. (void) key;
  858. if (peer_entry == exclude)
  859. return GNUNET_OK; /* trigger of the update */
  860. if (GNUNET_NO == peer_entry->previous_round)
  861. {
  862. /* still stuck in previous round, no point to update, check that
  863. * we are active here though... */
  864. if (NULL == peer_entry->transmit_task)
  865. {
  866. GNUNET_break (0);
  867. }
  868. return GNUNET_OK;
  869. }
  870. if (NULL != peer_entry->transmit_task)
  871. {
  872. GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
  873. peer_entry->transmit_task = NULL;
  874. }
  875. delay = get_transmit_delay (0);
  876. peer_entry->transmit_task =
  877. GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
  878. return GNUNET_OK;
  879. }
  880. /**
  881. * Core handler for size estimate flooding messages.
  882. *
  883. * @param cls peer this message is from
  884. * @param incoming_flood received message
  885. */
  886. static void
  887. handle_p2p_estimate (void *cls,
  888. const struct GNUNET_NSE_FloodMessage *incoming_flood)
  889. {
  890. struct NSEPeerEntry *peer_entry = cls;
  891. struct GNUNET_TIME_Absolute ts;
  892. uint32_t matching_bits;
  893. unsigned int idx;
  894. #if ENABLE_NSE_HISTOGRAM
  895. {
  896. uint64_t t;
  897. t = GNUNET_TIME_absolute_get ().abs_value_us;
  898. if (NULL != lh)
  899. GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof (uint64_t));
  900. if (NULL != histogram)
  901. GNUNET_BIO_write_int64 (histogram, t);
  902. }
  903. #endif
  904. GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
  905. matching_bits = ntohl (incoming_flood->matching_bits);
  906. #if DEBUG_NSE
  907. {
  908. char origin[5];
  909. char pred[5];
  910. struct GNUNET_PeerIdentity os;
  911. GNUNET_snprintf (origin,
  912. sizeof (origin),
  913. "%s",
  914. GNUNET_i2s (&incoming_flood->origin));
  915. GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer_entry->id));
  916. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  917. "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
  918. GNUNET_STRINGS_absolute_time_to_string (
  919. GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
  920. origin,
  921. pred,
  922. GNUNET_i2s (&my_identity),
  923. (unsigned int) matching_bits);
  924. }
  925. #endif
  926. #if ENABLE_NSE_HISTOGRAM
  927. peer_entry->received_messages++;
  928. if (peer_entry->transmitted_messages > 0 &&
  929. peer_entry->last_transmitted_size >= matching_bits)
  930. GNUNET_STATISTICS_update (stats, "# cross messages", 1, GNUNET_NO);
  931. #endif
  932. ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
  933. if (ts.abs_value_us == current_timestamp.abs_value_us)
  934. idx = estimate_index;
  935. else if (ts.abs_value_us ==
  936. current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us)
  937. idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
  938. else if (ts.abs_value_us == next_timestamp.abs_value_us)
  939. {
  940. if (matching_bits <= ntohl (next_message.matching_bits))
  941. return; /* ignore, simply too early/late */
  942. if (GNUNET_YES != verify_message_crypto (incoming_flood))
  943. {
  944. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  945. "Peer %s is likely ill-configured!\n",
  946. GNUNET_i2s (peer_entry->id));
  947. GNUNET_break_op (0);
  948. return;
  949. }
  950. next_message = *incoming_flood;
  951. return;
  952. }
  953. else
  954. {
  955. GNUNET_STATISTICS_update (stats,
  956. "# flood messages discarded (clock skew too large)",
  957. 1,
  958. GNUNET_NO);
  959. return;
  960. }
  961. if (0 == (GNUNET_memcmp (peer_entry->id, &my_identity)))
  962. {
  963. /* send to self, update our own estimate IF this also comes from us! */
  964. if (0 == GNUNET_memcmp (&incoming_flood->origin, &my_identity))
  965. update_network_size_estimate ();
  966. return;
  967. }
  968. if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
  969. {
  970. /* Cancel transmission in the other direction, as this peer clearly has
  971. up-to-date information already. Even if we didn't talk to this peer in
  972. the previous round, we should no longer send it stale information as it
  973. told us about the current round! */
  974. peer_entry->previous_round = GNUNET_YES;
  975. if (idx != estimate_index)
  976. {
  977. /* do not transmit information for the previous round to this peer
  978. anymore (but allow current round) */
  979. return;
  980. }
  981. /* got up-to-date information for current round, cancel transmission to
  982. * this peer altogether */
  983. if (NULL != peer_entry->transmit_task)
  984. {
  985. GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
  986. peer_entry->transmit_task = NULL;
  987. }
  988. return;
  989. }
  990. if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
  991. {
  992. if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
  993. {
  994. peer_entry->previous_round = GNUNET_NO;
  995. }
  996. /* push back our result now, that peer is spreading bad information... */
  997. if (NULL != peer_entry->transmit_task)
  998. GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
  999. peer_entry->transmit_task =
  1000. GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
  1001. /* Not closer than our most recent message, no need to do work here */
  1002. GNUNET_STATISTICS_update (stats,
  1003. "# flood messages ignored (had closer already)",
  1004. 1,
  1005. GNUNET_NO);
  1006. return;
  1007. }
  1008. if (GNUNET_YES != verify_message_crypto (incoming_flood))
  1009. {
  1010. GNUNET_break_op (0);
  1011. return;
  1012. }
  1013. GNUNET_assert (matching_bits >
  1014. ntohl (size_estimate_messages[idx].matching_bits));
  1015. /* Cancel transmission in the other direction, as this peer clearly has
  1016. * up-to-date information already.
  1017. */
  1018. peer_entry->previous_round = GNUNET_YES;
  1019. if (idx == estimate_index)
  1020. {
  1021. /* cancel any activity for current round */
  1022. if (NULL != peer_entry->transmit_task)
  1023. {
  1024. GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
  1025. peer_entry->transmit_task = NULL;
  1026. }
  1027. }
  1028. size_estimate_messages[idx] = *incoming_flood;
  1029. size_estimate_messages[idx].hop_count =
  1030. htonl (ntohl (incoming_flood->hop_count) + 1);
  1031. hop_count_max =
  1032. GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
  1033. GNUNET_STATISTICS_set (stats,
  1034. "# estimated network diameter",
  1035. hop_count_max,
  1036. GNUNET_NO);
  1037. /* have a new, better size estimate, inform clients */
  1038. update_network_size_estimate ();
  1039. /* flood to rest */
  1040. GNUNET_CONTAINER_multipeermap_iterate (peers,
  1041. &update_flood_times,
  1042. peer_entry);
  1043. }
  1044. /**
  1045. * Method called whenever a peer connects. Sets up the PeerEntry and
  1046. * schedules the initial size info transmission to this peer.
  1047. *
  1048. * @param cls closure
  1049. * @param peer peer identity this notification is about
  1050. */
  1051. static void *
  1052. handle_core_connect (void *cls,
  1053. const struct GNUNET_PeerIdentity *peer,
  1054. struct GNUNET_MQ_Handle *mq)
  1055. {
  1056. struct NSEPeerEntry *peer_entry;
  1057. (void) cls;
  1058. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1059. "Peer `%s' connected to us\n",
  1060. GNUNET_i2s (peer));
  1061. /* set our default transmission options */
  1062. GNUNET_MQ_set_options (mq, NSE_PRIORITY);
  1063. /* create our peer entry for this peer */
  1064. peer_entry = GNUNET_new (struct NSEPeerEntry);
  1065. peer_entry->id = peer;
  1066. peer_entry->mq = mq;
  1067. GNUNET_assert (GNUNET_OK ==
  1068. GNUNET_CONTAINER_multipeermap_put (
  1069. peers,
  1070. peer_entry->id,
  1071. peer_entry,
  1072. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  1073. peer_entry->transmit_task =
  1074. GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1),
  1075. &transmit_task_cb,
  1076. peer_entry);
  1077. GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
  1078. return peer_entry;
  1079. }
  1080. /**
  1081. * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
  1082. * any pending transmission requests to that peer.
  1083. *
  1084. * @param cls closure
  1085. * @param peer peer identity this notification is about
  1086. * @parma internal_cls the `struct NSEPeerEntry` for the @a peer
  1087. */
  1088. static void
  1089. handle_core_disconnect (void *cls,
  1090. const struct GNUNET_PeerIdentity *peer,
  1091. void *internal_cls)
  1092. {
  1093. struct NSEPeerEntry *pos = internal_cls;
  1094. (void) cls;
  1095. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1096. "Peer `%s' disconnected from us\n",
  1097. GNUNET_i2s (peer));
  1098. GNUNET_assert (GNUNET_YES ==
  1099. GNUNET_CONTAINER_multipeermap_remove (peers, peer, pos));
  1100. if (NULL != pos->transmit_task)
  1101. {
  1102. GNUNET_SCHEDULER_cancel (pos->transmit_task);
  1103. pos->transmit_task = NULL;
  1104. }
  1105. GNUNET_free (pos);
  1106. GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
  1107. }
  1108. #if ENABLE_NSE_HISTOGRAM
  1109. /**
  1110. * Functions of this type are called to notify a successful transmission of the
  1111. * message to the logger service
  1112. *
  1113. * @param cls NULL
  1114. * @param size the amount of data sent (ignored)
  1115. */
  1116. static void
  1117. flush_comp_cb (void *cls, size_t size)
  1118. {
  1119. (void) cls;
  1120. (void) size;
  1121. GNUNET_TESTBED_LOGGER_disconnect (lh);
  1122. lh = NULL;
  1123. }
  1124. #endif
  1125. /**
  1126. * Task run during shutdown.
  1127. *
  1128. * @param cls unused
  1129. */
  1130. static void
  1131. shutdown_task (void *cls)
  1132. {
  1133. (void) cls;
  1134. if (NULL != flood_task)
  1135. {
  1136. GNUNET_SCHEDULER_cancel (flood_task);
  1137. flood_task = NULL;
  1138. }
  1139. if (NULL != proof_task)
  1140. {
  1141. GNUNET_SCHEDULER_cancel (proof_task);
  1142. proof_task = NULL;
  1143. write_proof (); /* remember progress */
  1144. }
  1145. if (NULL != nc)
  1146. {
  1147. GNUNET_notification_context_destroy (nc);
  1148. nc = NULL;
  1149. }
  1150. if (NULL != core_api)
  1151. {
  1152. GNUNET_CORE_disconnect (core_api);
  1153. core_api = NULL;
  1154. }
  1155. if (NULL != stats)
  1156. {
  1157. GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
  1158. stats = NULL;
  1159. }
  1160. if (NULL != peers)
  1161. {
  1162. GNUNET_CONTAINER_multipeermap_destroy (peers);
  1163. peers = NULL;
  1164. }
  1165. if (NULL != my_private_key)
  1166. {
  1167. GNUNET_free (my_private_key);
  1168. my_private_key = NULL;
  1169. }
  1170. #if ENABLE_NSE_HISTOGRAM
  1171. if (NULL != logger_test)
  1172. {
  1173. GNUNET_CLIENT_service_test_cancel (logger_test);
  1174. logger_test = NULL;
  1175. }
  1176. if (NULL != lh)
  1177. {
  1178. GNUNET_TESTBED_LOGGER_flush (lh, &flush_comp_cb, NULL);
  1179. }
  1180. if (NULL != histogram)
  1181. {
  1182. GNUNET_BIO_write_close (histogram);
  1183. histogram = NULL;
  1184. }
  1185. #endif
  1186. }
  1187. /**
  1188. * Called on core init/fail.
  1189. *
  1190. * @param cls service closure
  1191. * @param identity the public identity of this peer
  1192. */
  1193. static void
  1194. core_init (void *cls, const struct GNUNET_PeerIdentity *identity)
  1195. {
  1196. struct GNUNET_TIME_Absolute now;
  1197. struct GNUNET_TIME_Absolute prev_time;
  1198. (void) cls;
  1199. if (NULL == identity)
  1200. {
  1201. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
  1202. GNUNET_SCHEDULER_shutdown ();
  1203. return;
  1204. }
  1205. GNUNET_assert (0 == GNUNET_memcmp (&my_identity, identity));
  1206. now = GNUNET_TIME_absolute_get ();
  1207. current_timestamp.abs_value_us =
  1208. (now.abs_value_us / gnunet_nse_interval.rel_value_us) *
  1209. gnunet_nse_interval.rel_value_us;
  1210. next_timestamp =
  1211. GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
  1212. estimate_index = HISTORY_SIZE - 1;
  1213. estimate_count = 0;
  1214. if (GNUNET_YES == check_proof_of_work (&my_identity.public_key, my_proof))
  1215. {
  1216. int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
  1217. prev_time.abs_value_us =
  1218. current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us;
  1219. setup_flood_message (idx, prev_time);
  1220. setup_flood_message (estimate_index, current_timestamp);
  1221. estimate_count++;
  1222. }
  1223. flood_task =
  1224. GNUNET_SCHEDULER_add_at (next_timestamp, &update_flood_message, NULL);
  1225. }
  1226. #if ENABLE_NSE_HISTOGRAM
  1227. /**
  1228. * Function called with the status of the testbed logger service
  1229. *
  1230. * @param cls NULL
  1231. * @param status #GNUNET_YES if the service is running,
  1232. * #GNUNET_NO if the service is not running
  1233. * #GNUNET_SYSERR if the configuration is invalid
  1234. */
  1235. static void
  1236. status_cb (void *cls, int status)
  1237. {
  1238. (void) cls;
  1239. logger_test = NULL;
  1240. if (GNUNET_YES != status)
  1241. {
  1242. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed logger not running\n");
  1243. return;
  1244. }
  1245. if (NULL == (lh = GNUNET_TESTBED_LOGGER_connect (cfg)))
  1246. {
  1247. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1248. "Cannot connect to the testbed logger. Exiting.\n");
  1249. GNUNET_SCHEDULER_shutdown ();
  1250. }
  1251. }
  1252. #endif
  1253. /**
  1254. * Handle network size estimate clients.
  1255. *
  1256. * @param cls closure
  1257. * @param c configuration to use
  1258. * @param service the initialized service
  1259. */
  1260. static void
  1261. run (void *cls,
  1262. const struct GNUNET_CONFIGURATION_Handle *c,
  1263. struct GNUNET_SERVICE_Handle *service)
  1264. {
  1265. struct GNUNET_MQ_MessageHandler core_handlers[] =
  1266. {GNUNET_MQ_hd_fixed_size (p2p_estimate,
  1267. GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
  1268. struct GNUNET_NSE_FloodMessage,
  1269. NULL),
  1270. GNUNET_MQ_handler_end ()};
  1271. char *proof;
  1272. struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
  1273. (void) cls;
  1274. (void) service;
  1275. cfg = c;
  1276. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
  1277. "NSE",
  1278. "INTERVAL",
  1279. &gnunet_nse_interval))
  1280. {
  1281. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "INTERVAL");
  1282. GNUNET_SCHEDULER_shutdown ();
  1283. return;
  1284. }
  1285. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
  1286. "NSE",
  1287. "WORKDELAY",
  1288. &proof_find_delay))
  1289. {
  1290. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKDELAY");
  1291. GNUNET_SCHEDULER_shutdown ();
  1292. return;
  1293. }
  1294. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
  1295. "NSE",
  1296. "WORKBITS",
  1297. &nse_work_required))
  1298. {
  1299. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS");
  1300. GNUNET_SCHEDULER_shutdown ();
  1301. return;
  1302. }
  1303. if (nse_work_required >= sizeof (struct GNUNET_HashCode) * 8)
  1304. {
  1305. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  1306. "NSE",
  1307. "WORKBITS",
  1308. _ ("Value is too large.\n"));
  1309. GNUNET_SCHEDULER_shutdown ();
  1310. return;
  1311. }
  1312. #if ENABLE_NSE_HISTOGRAM
  1313. {
  1314. char *histogram_dir;
  1315. char *histogram_fn;
  1316. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
  1317. "NSE",
  1318. "HISTOGRAM_DIR",
  1319. &histogram_dir))
  1320. {
  1321. GNUNET_assert (
  1322. 0 < GNUNET_asprintf (&histogram_fn, "%s/timestamps", histogram_dir));
  1323. GNUNET_free (histogram_dir);
  1324. histogram = GNUNET_BIO_write_open (histogram_fn);
  1325. if (NULL == histogram)
  1326. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1327. "Unable to open histogram file `%s'\n",
  1328. histogram_fn);
  1329. GNUNET_free (histogram_fn);
  1330. }
  1331. logger_test = GNUNET_CLIENT_service_test ("testbed-logger",
  1332. cfg,
  1333. GNUNET_TIME_UNIT_SECONDS,
  1334. &status_cb,
  1335. NULL);
  1336. }
  1337. #endif
  1338. GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
  1339. pk = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
  1340. GNUNET_assert (NULL != pk);
  1341. my_private_key = pk;
  1342. GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
  1343. if (GNUNET_OK !=
  1344. GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
  1345. {
  1346. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE");
  1347. GNUNET_free (my_private_key);
  1348. my_private_key = NULL;
  1349. GNUNET_SCHEDULER_shutdown ();
  1350. return;
  1351. }
  1352. if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
  1353. (sizeof (my_proof) !=
  1354. GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
  1355. my_proof = 0;
  1356. GNUNET_free (proof);
  1357. proof_task =
  1358. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
  1359. &find_proof,
  1360. NULL);
  1361. peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
  1362. nc = GNUNET_notification_context_create (1);
  1363. /* Connect to core service and register core handlers */
  1364. core_api =
  1365. GNUNET_CORE_connect (cfg, /* Main configuration */
  1366. NULL, /* Closure passed to functions */
  1367. &core_init, /* Call core_init once connected */
  1368. &handle_core_connect, /* Handle connects */
  1369. &handle_core_disconnect, /* Handle disconnects */
  1370. core_handlers); /* Register these handlers */
  1371. if (NULL == core_api)
  1372. {
  1373. GNUNET_SCHEDULER_shutdown ();
  1374. return;
  1375. }
  1376. stats = GNUNET_STATISTICS_create ("nse", cfg);
  1377. }
  1378. /**
  1379. * Callback called when a client connects to the service.
  1380. *
  1381. * @param cls closure for the service
  1382. * @param c the new client that connected to the service
  1383. * @param mq the message queue used to send messages to the client
  1384. * @return @a c
  1385. */
  1386. static void *
  1387. client_connect_cb (void *cls,
  1388. struct GNUNET_SERVICE_Client *c,
  1389. struct GNUNET_MQ_Handle *mq)
  1390. {
  1391. (void) cls;
  1392. (void) mq;
  1393. return c;
  1394. }
  1395. /**
  1396. * Callback called when a client disconnected from the service
  1397. *
  1398. * @param cls closure for the service
  1399. * @param c the client that disconnected
  1400. * @param internal_cls should be equal to @a c
  1401. */
  1402. static void
  1403. client_disconnect_cb (void *cls,
  1404. struct GNUNET_SERVICE_Client *c,
  1405. void *internal_cls)
  1406. {
  1407. (void) cls;
  1408. GNUNET_assert (c == internal_cls);
  1409. }
  1410. /**
  1411. * Define "main" method using service macro.
  1412. */
  1413. GNUNET_SERVICE_MAIN ("nse",
  1414. GNUNET_SERVICE_OPTION_NONE,
  1415. &run,
  1416. &client_connect_cb,
  1417. &client_disconnect_cb,
  1418. NULL,
  1419. GNUNET_MQ_hd_fixed_size (start,
  1420. GNUNET_MESSAGE_TYPE_NSE_START,
  1421. struct GNUNET_MessageHeader,
  1422. NULL),
  1423. GNUNET_MQ_handler_end ());
  1424. #if defined(LINUX) && defined(__GLIBC__)
  1425. #include <malloc.h>
  1426. /**
  1427. * MINIMIZE heap size (way below 128k) since this process doesn't need much.
  1428. */
  1429. void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
  1430. {
  1431. mallopt (M_TRIM_THRESHOLD, 4 * 1024);
  1432. mallopt (M_TOP_PAD, 1 * 1024);
  1433. malloc_trim (0);
  1434. }
  1435. #endif
  1436. /* end of gnunet-service-nse.c */