gnunet-service-peerinfo.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2001-2014 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 peerinfo/gnunet-service-peerinfo.c
  19. * @brief maintains list of known peers
  20. *
  21. * Code to maintain the list of currently known hosts (in memory
  22. * structure of data/hosts/).
  23. *
  24. * @author Christian Grothoff
  25. */
  26. #include "platform.h"
  27. #include "gnunet_util_lib.h"
  28. #include "gnunet_hello_lib.h"
  29. #include "gnunet_protocols.h"
  30. #include "gnunet_statistics_service.h"
  31. #include "peerinfo.h"
  32. /**
  33. * How often do we scan the HOST_DIR for new entries?
  34. */
  35. #define DATA_HOST_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
  36. /**
  37. * How often do we discard old entries in data/hosts/?
  38. */
  39. #define DATA_HOST_CLEAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 60)
  40. /**
  41. * In-memory cache of known hosts.
  42. */
  43. struct HostEntry
  44. {
  45. /**
  46. * Identity of the peer.
  47. */
  48. struct GNUNET_PeerIdentity identity;
  49. /**
  50. * Hello for the peer (can be NULL)
  51. */
  52. struct GNUNET_HELLO_Message *hello;
  53. /**
  54. * Friend only hello for the peer (can be NULL)
  55. */
  56. struct GNUNET_HELLO_Message *friend_only_hello;
  57. };
  58. /**
  59. * Transmit context for GET requests
  60. */
  61. struct TransmitContext
  62. {
  63. /**
  64. * Server transmit context
  65. */
  66. struct GNUNET_SERVER_TransmitContext *tc;
  67. /**
  68. * Include friend only HELLOs #GNUNET_YES or #GNUNET_NO
  69. */
  70. int friend_only;
  71. };
  72. /**
  73. * Result of reading a file
  74. */
  75. struct ReadHostFileContext
  76. {
  77. /**
  78. * Hello for the peer (can be NULL)
  79. */
  80. struct GNUNET_HELLO_Message *hello;
  81. /**
  82. * Friend only hello for the peer (can be NULL)
  83. */
  84. struct GNUNET_HELLO_Message *friend_only_hello;
  85. };
  86. /**
  87. * Client notification context
  88. */
  89. struct NotificationContext
  90. {
  91. /**
  92. * Next in DLL
  93. */
  94. struct NotificationContext *prev;
  95. /**
  96. * Previous in DLL
  97. */
  98. struct NotificationContext *next;
  99. /**
  100. * Server client
  101. */
  102. struct GNUNET_SERVER_Client *client;
  103. /**
  104. * Interested in friend only HELLO?
  105. */
  106. int include_friend_only;
  107. };
  108. /**
  109. * The in-memory list of known hosts, mapping of
  110. * host IDs to 'struct HostEntry*' values.
  111. */
  112. static struct GNUNET_CONTAINER_MultiPeerMap *hostmap;
  113. /**
  114. * Clients to immediately notify about all changes.
  115. */
  116. static struct GNUNET_SERVER_NotificationContext *notify_list;
  117. /**
  118. * Directory where the hellos are stored in (peerinfo/)
  119. */
  120. static char *networkIdDirectory;
  121. /**
  122. * Handle for reporting statistics.
  123. */
  124. static struct GNUNET_STATISTICS_Handle *stats;
  125. /**
  126. * DLL of notification contexts: head
  127. */
  128. static struct NotificationContext *nc_head;
  129. /**
  130. * DLL of notification contexts: tail
  131. */
  132. static struct NotificationContext *nc_tail;
  133. /**
  134. * Notify all clients in the notify list about the
  135. * given host entry changing.
  136. *
  137. * @param he entry of the host for which we generate a notification
  138. * @param include_friend_only create public of friend-only message
  139. * @return generated notification message
  140. */
  141. static struct InfoMessage *
  142. make_info_message (const struct HostEntry *he,
  143. int include_friend_only)
  144. {
  145. struct InfoMessage *im;
  146. struct GNUNET_HELLO_Message *src;
  147. size_t hs;
  148. if (GNUNET_YES == include_friend_only)
  149. src = he->friend_only_hello;
  150. else
  151. src = he->hello;
  152. hs = (NULL == src) ? 0 : GNUNET_HELLO_size (src);
  153. im = GNUNET_malloc (sizeof (struct InfoMessage) + hs);
  154. im->header.size = htons (hs + sizeof (struct InfoMessage));
  155. im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
  156. im->peer = he->identity;
  157. if (NULL != src)
  158. memcpy (&im[1], src, hs);
  159. return im;
  160. }
  161. /**
  162. * Address iterator that causes expired entries to be discarded.
  163. *
  164. * @param cls pointer to the current time
  165. * @param address the address
  166. * @param expiration expiration time for the address
  167. * @return #GNUNET_NO if expiration smaller than the current time
  168. */
  169. static int
  170. discard_expired (void *cls,
  171. const struct GNUNET_HELLO_Address *address,
  172. struct GNUNET_TIME_Absolute expiration)
  173. {
  174. const struct GNUNET_TIME_Absolute *now = cls;
  175. if (now->abs_value_us > expiration.abs_value_us)
  176. {
  177. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  178. _("Removing expired address of transport `%s'\n"),
  179. address->transport_name);
  180. return GNUNET_NO;
  181. }
  182. return GNUNET_OK;
  183. }
  184. /**
  185. * Address iterator that counts the remaining addresses.
  186. *
  187. * @param cls pointer to the counter
  188. * @param address the address
  189. * @param expiration expiration time for the address
  190. * @return #GNUNET_OK (always)
  191. */
  192. static int
  193. count_addresses (void *cls,
  194. const struct GNUNET_HELLO_Address *address,
  195. struct GNUNET_TIME_Absolute expiration)
  196. {
  197. unsigned int *cnt = cls;
  198. (*cnt)++;
  199. return GNUNET_OK;
  200. }
  201. /**
  202. * Get the filename under which we would store the GNUNET_HELLO_Message
  203. * for the given host and protocol.
  204. *
  205. * @param id peer for which we need the filename for the HELLO
  206. * @return filename of the form DIRECTORY/HOSTID
  207. */
  208. static char *
  209. get_host_filename (const struct GNUNET_PeerIdentity *id)
  210. {
  211. char *fn;
  212. if (NULL == networkIdDirectory)
  213. return NULL;
  214. GNUNET_asprintf (&fn, "%s%s%s", networkIdDirectory, DIR_SEPARATOR_STR,
  215. GNUNET_i2s_full (id));
  216. return fn;
  217. }
  218. /**
  219. * Broadcast information about the given entry to all
  220. * clients that care.
  221. *
  222. * @param entry entry to broadcast about
  223. */
  224. static void
  225. notify_all (struct HostEntry *entry)
  226. {
  227. struct InfoMessage *msg_pub;
  228. struct InfoMessage *msg_friend;
  229. struct NotificationContext *cur;
  230. msg_pub = make_info_message (entry, GNUNET_NO);
  231. msg_friend = make_info_message (entry, GNUNET_YES);
  232. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  233. "Notifying all clients about peer `%s'\n",
  234. GNUNET_i2s(&entry->identity));
  235. for (cur = nc_head; NULL != cur; cur = cur->next)
  236. {
  237. if (GNUNET_NO == cur->include_friend_only)
  238. {
  239. GNUNET_SERVER_notification_context_unicast (notify_list,
  240. cur->client,
  241. &msg_pub->header,
  242. GNUNET_NO);
  243. }
  244. if (GNUNET_YES == cur->include_friend_only)
  245. {
  246. GNUNET_SERVER_notification_context_unicast (notify_list,
  247. cur->client,
  248. &msg_friend->header,
  249. GNUNET_NO);
  250. }
  251. }
  252. GNUNET_free (msg_pub);
  253. GNUNET_free (msg_friend);
  254. }
  255. /**
  256. * Bind a host address (hello) to a hostId.
  257. *
  258. * @param peer the peer for which this is a hello
  259. * @param hello the verified (!) hello message
  260. */
  261. static void
  262. update_hello (const struct GNUNET_PeerIdentity *peer,
  263. const struct GNUNET_HELLO_Message *hello);
  264. /**
  265. * Try to read the HELLOs in the given filename and discard expired
  266. * addresses. Removes the file if one the HELLO is malformed. If all
  267. * addresses are expired, the HELLO is also removed (but the HELLO
  268. * with the public key is still returned if it was found and valid).
  269. * The file can contain multiple HELLO messages.
  270. *
  271. * @param fn name of the file
  272. * @param unlink_garbage if #GNUNET_YES, try to remove useless files
  273. * @param r ReadHostFileContext to store the resutl
  274. */
  275. static void
  276. read_host_file (const char *fn,
  277. int unlink_garbage,
  278. struct ReadHostFileContext *r)
  279. {
  280. char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  281. unsigned int size_total;
  282. struct GNUNET_TIME_Absolute now;
  283. unsigned int left;
  284. const struct GNUNET_HELLO_Message *hello;
  285. struct GNUNET_HELLO_Message *hello_clean;
  286. unsigned read_pos;
  287. int size_hello;
  288. r->friend_only_hello = NULL;
  289. r->hello = NULL;
  290. if (GNUNET_YES != GNUNET_DISK_file_test (fn))
  291. return;
  292. size_total = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
  293. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  294. "Read %u bytes from `%s'\n",
  295. size_total,
  296. fn);
  297. if (size_total < sizeof (struct GNUNET_MessageHeader))
  298. {
  299. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  300. _("Failed to parse HELLO in file `%s': %s\n"),
  301. fn, "Fail has invalid size");
  302. if ( (GNUNET_YES == unlink_garbage) &&
  303. (0 != UNLINK (fn)) &&
  304. (ENOENT != errno) )
  305. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  306. "unlink",
  307. fn);
  308. return;
  309. }
  310. read_pos = 0;
  311. while (read_pos < size_total)
  312. {
  313. hello = (const struct GNUNET_HELLO_Message *) &buffer[read_pos];
  314. size_hello = GNUNET_HELLO_size (hello);
  315. if (0 == size_hello)
  316. {
  317. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  318. _("Failed to parse HELLO in file `%s'\n"),
  319. fn);
  320. if ((GNUNET_YES == unlink_garbage) &&
  321. (0 != UNLINK (fn)) &&
  322. (ENOENT != errno) )
  323. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  324. "unlink",
  325. fn);
  326. return;
  327. }
  328. now = GNUNET_TIME_absolute_get ();
  329. hello_clean = GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES,
  330. &discard_expired, &now);
  331. if (NULL == hello_clean)
  332. {
  333. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  334. _("Failed to parse HELLO in file `%s'\n"),
  335. fn);
  336. if ((GNUNET_YES == unlink_garbage) &&
  337. (0 != UNLINK (fn)) &&
  338. (ENOENT != errno) )
  339. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  340. "unlink",
  341. fn);
  342. return;
  343. }
  344. left = 0;
  345. (void) GNUNET_HELLO_iterate_addresses (hello_clean, GNUNET_NO,
  346. &count_addresses, &left);
  347. if (0 == left)
  348. {
  349. GNUNET_free (hello_clean);
  350. break;
  351. }
  352. if (GNUNET_NO == GNUNET_HELLO_is_friend_only (hello_clean))
  353. {
  354. if (NULL == r->hello)
  355. r->hello = hello_clean;
  356. else
  357. {
  358. GNUNET_break (0);
  359. GNUNET_free (r->hello);
  360. r->hello = hello_clean;
  361. }
  362. }
  363. else
  364. {
  365. if (NULL == r->friend_only_hello)
  366. r->friend_only_hello = hello_clean;
  367. else
  368. {
  369. GNUNET_break (0);
  370. GNUNET_free (r->friend_only_hello);
  371. r->friend_only_hello = hello_clean;
  372. }
  373. }
  374. read_pos += size_hello;
  375. }
  376. if (0 == left)
  377. {
  378. /* no addresses left, remove from disk */
  379. if ( (GNUNET_YES == unlink_garbage) &&
  380. (0 != UNLINK (fn)) )
  381. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  382. "unlink",
  383. fn);
  384. }
  385. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  386. "Found `%s' and `%s' HELLO message in file\n",
  387. (NULL != r->hello) ? "public" : "NON-public",
  388. (NULL != r->friend_only_hello) ? "friend only" : "NO friend only");
  389. }
  390. /**
  391. * Add a host to the list and notify clients about this event
  392. *
  393. * @param identity the identity of the host
  394. * @return the HostEntry
  395. */
  396. static struct HostEntry *
  397. add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity)
  398. {
  399. struct HostEntry *entry;
  400. struct ReadHostFileContext r;
  401. char *fn;
  402. entry = GNUNET_CONTAINER_multipeermap_get (hostmap, identity);
  403. if (NULL == entry)
  404. {
  405. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  406. "Adding new peer `%s'\n",
  407. GNUNET_i2s (identity));
  408. GNUNET_STATISTICS_update (stats, gettext_noop ("# peers known"), 1,
  409. GNUNET_NO);
  410. entry = GNUNET_new (struct HostEntry);
  411. entry->identity = *identity;
  412. GNUNET_assert (GNUNET_OK ==
  413. GNUNET_CONTAINER_multipeermap_put (hostmap,
  414. &entry->identity,
  415. entry,
  416. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  417. notify_all (entry);
  418. fn = get_host_filename (identity);
  419. if (NULL != fn)
  420. {
  421. read_host_file (fn, GNUNET_YES, &r);
  422. if (NULL != r.hello)
  423. update_hello (identity, r.hello);
  424. if (NULL != r.friend_only_hello)
  425. update_hello (identity, r.friend_only_hello);
  426. GNUNET_free_non_null (r.hello);
  427. GNUNET_free_non_null (r.friend_only_hello);
  428. GNUNET_free (fn);
  429. }
  430. }
  431. return entry;
  432. }
  433. /**
  434. * Remove a file that should not be there. LOG
  435. * success or failure.
  436. *
  437. * @param fullname name of the file to remove
  438. */
  439. static void
  440. remove_garbage (const char *fullname)
  441. {
  442. if (0 == UNLINK (fullname))
  443. GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
  444. _("File `%s' in directory `%s' does not match naming convention. Removed.\n"),
  445. fullname,
  446. networkIdDirectory);
  447. else
  448. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  449. "unlink",
  450. fullname);
  451. }
  452. /**
  453. * Closure for #hosts_directory_scan_callback().
  454. */
  455. struct DirScanContext
  456. {
  457. /**
  458. * #GNUNET_YES if we should remove files that are broken,
  459. * #GNUNET_NO if the directory we are iterating over should
  460. * be treated as read-only by us.
  461. */
  462. int remove_files;
  463. /**
  464. * Counter for the number of (valid) entries found, incremented
  465. * by one for each match.
  466. */
  467. unsigned int matched;
  468. };
  469. /**
  470. * Function that is called on each HELLO file in a particular directory.
  471. * Try to parse the file and add the HELLO to our list.
  472. *
  473. * @param cls pointer to 'unsigned int' to increment for each file, or NULL
  474. * if the file is from a read-only, read-once resource directory
  475. * @param fullname name of the file to parse
  476. * @return #GNUNET_OK (continue iteration)
  477. */
  478. static int
  479. hosts_directory_scan_callback (void *cls,
  480. const char *fullname)
  481. {
  482. struct DirScanContext *dsc = cls;
  483. struct GNUNET_PeerIdentity identity;
  484. struct ReadHostFileContext r;
  485. const char *filename;
  486. struct GNUNET_PeerIdentity id_public;
  487. struct GNUNET_PeerIdentity id_friend;
  488. struct GNUNET_PeerIdentity id;
  489. if (GNUNET_YES != GNUNET_DISK_file_test (fullname))
  490. return GNUNET_OK; /* ignore non-files */
  491. filename = strrchr (fullname, DIR_SEPARATOR);
  492. if ((NULL == filename) || (1 > strlen (filename)))
  493. filename = fullname;
  494. else
  495. filename ++;
  496. read_host_file (fullname, dsc->remove_files, &r);
  497. if ( (NULL == r.hello) && (NULL == r.friend_only_hello))
  498. return GNUNET_OK;
  499. if (NULL != r.friend_only_hello)
  500. {
  501. if (GNUNET_OK != GNUNET_HELLO_get_id (r.friend_only_hello, &id_friend))
  502. if (GNUNET_YES == dsc->remove_files)
  503. {
  504. remove_garbage (fullname);
  505. return GNUNET_OK;
  506. }
  507. id = id_friend;
  508. }
  509. if (NULL != r.hello)
  510. {
  511. if (GNUNET_OK != GNUNET_HELLO_get_id (r.hello, &id_public))
  512. if (GNUNET_YES == dsc->remove_files)
  513. {
  514. remove_garbage (fullname);
  515. return GNUNET_OK;
  516. }
  517. id = id_public;
  518. }
  519. if ( (NULL != r.hello) && (NULL != r.friend_only_hello) &&
  520. (0 != memcmp (&id_friend, &id_public, sizeof (id_friend))) )
  521. {
  522. /* HELLOs are not for the same peer */
  523. GNUNET_break (0);
  524. if (GNUNET_YES == dsc->remove_files)
  525. remove_garbage (fullname);
  526. return GNUNET_OK;
  527. }
  528. if (GNUNET_OK ==
  529. GNUNET_CRYPTO_eddsa_public_key_from_string (filename,
  530. strlen (filename),
  531. &identity.public_key))
  532. {
  533. if (0 != memcmp (&id, &identity, sizeof (id_friend)))
  534. {
  535. /* HELLOs are not for the same peer */
  536. GNUNET_break (0);
  537. if (GNUNET_YES == dsc->remove_files)
  538. remove_garbage (fullname);
  539. return GNUNET_OK;
  540. }
  541. }
  542. /* ok, found something valid, remember HELLO */
  543. add_host_to_known_hosts (&id);
  544. if (NULL != r.hello)
  545. {
  546. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  547. "Updating peer `%s' public HELLO \n",
  548. GNUNET_i2s (&id));
  549. update_hello (&id, r.hello);
  550. GNUNET_free (r.hello);
  551. }
  552. if (NULL != r.friend_only_hello)
  553. {
  554. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  555. "Updating peer `%s' friend only HELLO \n",
  556. GNUNET_i2s (&id));
  557. update_hello (&id, r.friend_only_hello);
  558. GNUNET_free (r.friend_only_hello);
  559. }
  560. dsc->matched++;
  561. return GNUNET_OK;
  562. }
  563. /**
  564. * Call this method periodically to scan data/hosts for new hosts.
  565. *
  566. * @param cls unused
  567. * @param tc scheduler context, aborted if reason is shutdown
  568. */
  569. static void
  570. cron_scan_directory_data_hosts (void *cls,
  571. const struct GNUNET_SCHEDULER_TaskContext *tc)
  572. {
  573. static unsigned int retries;
  574. struct DirScanContext dsc;
  575. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  576. return;
  577. if (GNUNET_SYSERR == GNUNET_DISK_directory_create (networkIdDirectory))
  578. {
  579. GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ,
  580. GNUNET_SCHEDULER_PRIORITY_IDLE,
  581. &cron_scan_directory_data_hosts, NULL);
  582. return;
  583. }
  584. dsc.matched = 0;
  585. dsc.remove_files = GNUNET_YES;
  586. GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
  587. _("Scanning directory `%s'\n"),
  588. networkIdDirectory);
  589. GNUNET_DISK_directory_scan (networkIdDirectory,
  590. &hosts_directory_scan_callback, &dsc);
  591. if ((0 == dsc.matched) && (0 == (++retries & 31)))
  592. GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
  593. _("Still no peers found in `%s'!\n"),
  594. networkIdDirectory);
  595. GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ,
  596. GNUNET_SCHEDULER_PRIORITY_IDLE,
  597. &cron_scan_directory_data_hosts,
  598. NULL);
  599. }
  600. /**
  601. * Update the HELLO of a friend by merging the addresses.
  602. *
  603. * @param hello original hello
  604. * @param friend_hello hello with additional addresses
  605. * @return merged HELLO
  606. */
  607. static struct GNUNET_HELLO_Message *
  608. update_friend_hello (const struct GNUNET_HELLO_Message *hello,
  609. const struct GNUNET_HELLO_Message *friend_hello)
  610. {
  611. struct GNUNET_HELLO_Message * res;
  612. struct GNUNET_HELLO_Message * tmp;
  613. struct GNUNET_CRYPTO_EddsaPublicKey pk;
  614. if (NULL != friend_hello)
  615. {
  616. res = GNUNET_HELLO_merge (hello, friend_hello);
  617. GNUNET_assert (GNUNET_YES == GNUNET_HELLO_is_friend_only (res));
  618. return res;
  619. }
  620. if (GNUNET_OK !=
  621. GNUNET_HELLO_get_key (hello, &pk))
  622. {
  623. GNUNET_break (0);
  624. return NULL;
  625. }
  626. tmp = GNUNET_HELLO_create (&pk, NULL, NULL, GNUNET_YES);
  627. res = GNUNET_HELLO_merge (hello, tmp);
  628. GNUNET_free (tmp);
  629. GNUNET_assert (GNUNET_YES == GNUNET_HELLO_is_friend_only (res));
  630. return res;
  631. }
  632. /**
  633. * Bind a host address (hello) to a hostId.
  634. *
  635. * @param peer the peer for which this is a hello
  636. * @param hello the verified (!) hello message
  637. */
  638. static void
  639. update_hello (const struct GNUNET_PeerIdentity *peer,
  640. const struct GNUNET_HELLO_Message *hello)
  641. {
  642. char *fn;
  643. struct HostEntry *host;
  644. struct GNUNET_HELLO_Message *mrg;
  645. struct GNUNET_HELLO_Message **dest;
  646. struct GNUNET_TIME_Absolute delta;
  647. unsigned int cnt;
  648. unsigned int size;
  649. int friend_hello_type;
  650. int store_hello;
  651. int store_friend_hello;
  652. int pos;
  653. char *buffer;
  654. host = GNUNET_CONTAINER_multipeermap_get (hostmap, peer);
  655. GNUNET_assert (NULL != host);
  656. friend_hello_type = GNUNET_HELLO_is_friend_only (hello);
  657. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  658. "Updating %s HELLO for `%s'\n",
  659. (GNUNET_YES == friend_hello_type) ? "friend-only" : "public",
  660. GNUNET_i2s (peer));
  661. dest = NULL;
  662. if (GNUNET_YES == friend_hello_type)
  663. {
  664. dest = &host->friend_only_hello;
  665. }
  666. else
  667. {
  668. dest = &host->hello;
  669. }
  670. if (NULL == (*dest))
  671. {
  672. (*dest) = GNUNET_malloc (GNUNET_HELLO_size (hello));
  673. memcpy ((*dest), hello, GNUNET_HELLO_size (hello));
  674. }
  675. else
  676. {
  677. mrg = GNUNET_HELLO_merge ((*dest), hello);
  678. delta = GNUNET_HELLO_equals (mrg, (*dest), GNUNET_TIME_absolute_get ());
  679. if (delta.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
  680. {
  681. /* no differences, just ignore the update */
  682. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  683. "No change in %s HELLO for `%s'\n",
  684. (GNUNET_YES == friend_hello_type) ? "friend-only" : "public",
  685. GNUNET_i2s (peer));
  686. GNUNET_free (mrg);
  687. return;
  688. }
  689. GNUNET_free ((*dest));
  690. (*dest) = mrg;
  691. }
  692. if ( (NULL != (host->hello)) &&
  693. (GNUNET_NO == friend_hello_type) )
  694. {
  695. /* Update friend only hello */
  696. mrg = update_friend_hello (host->hello, host->friend_only_hello);
  697. if (NULL != host->friend_only_hello)
  698. GNUNET_free (host->friend_only_hello);
  699. host->friend_only_hello = mrg;
  700. }
  701. if (NULL != host->hello)
  702. GNUNET_assert ((GNUNET_NO ==
  703. GNUNET_HELLO_is_friend_only (host->hello)));
  704. if (NULL != host->friend_only_hello)
  705. GNUNET_assert ((GNUNET_YES ==
  706. GNUNET_HELLO_is_friend_only (host->friend_only_hello)));
  707. fn = get_host_filename (peer);
  708. if ( (NULL != fn) &&
  709. (GNUNET_OK ==
  710. GNUNET_DISK_directory_create_for_file (fn)) )
  711. {
  712. store_hello = GNUNET_NO;
  713. size = 0;
  714. cnt = 0;
  715. if (NULL != host->hello)
  716. (void) GNUNET_HELLO_iterate_addresses (host->hello,
  717. GNUNET_NO,
  718. &count_addresses,
  719. &cnt);
  720. if (cnt > 0)
  721. {
  722. store_hello = GNUNET_YES;
  723. size += GNUNET_HELLO_size (host->hello);
  724. }
  725. cnt = 0;
  726. if (NULL != host->friend_only_hello)
  727. (void) GNUNET_HELLO_iterate_addresses (host->friend_only_hello,
  728. GNUNET_NO,
  729. &count_addresses,
  730. &cnt);
  731. store_friend_hello = GNUNET_NO;
  732. if (0 < cnt)
  733. {
  734. store_friend_hello = GNUNET_YES;
  735. size += GNUNET_HELLO_size (host->friend_only_hello);
  736. }
  737. if ( (GNUNET_NO == store_hello) &&
  738. (GNUNET_NO == store_friend_hello) )
  739. {
  740. /* no valid addresses, don't put HELLO on disk; in fact,
  741. if one exists on disk, remove it */
  742. (void) UNLINK (fn);
  743. }
  744. else
  745. {
  746. buffer = GNUNET_malloc (size);
  747. pos = 0;
  748. if (GNUNET_YES == store_hello)
  749. {
  750. memcpy (buffer, host->hello,
  751. GNUNET_HELLO_size (host->hello));
  752. pos += GNUNET_HELLO_size (host->hello);
  753. }
  754. if (GNUNET_YES == store_friend_hello)
  755. {
  756. memcpy (&buffer[pos], host->friend_only_hello, GNUNET_HELLO_size (host->friend_only_hello));
  757. pos += GNUNET_HELLO_size (host->friend_only_hello);
  758. }
  759. GNUNET_assert (pos == size);
  760. if (GNUNET_SYSERR == GNUNET_DISK_fn_write (fn, buffer, size,
  761. GNUNET_DISK_PERM_USER_READ |
  762. GNUNET_DISK_PERM_USER_WRITE |
  763. GNUNET_DISK_PERM_GROUP_READ |
  764. GNUNET_DISK_PERM_OTHER_READ))
  765. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);
  766. else
  767. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  768. "Stored %s %s HELLO in %s with total size %u\n",
  769. (GNUNET_YES == store_friend_hello) ? "friend-only": "",
  770. (GNUNET_YES == store_hello) ? "public": "",
  771. fn, size);
  772. GNUNET_free (buffer);
  773. }
  774. }
  775. GNUNET_free_non_null (fn);
  776. notify_all (host);
  777. }
  778. /**
  779. * Do transmit info about peer to given host.
  780. *
  781. * @param cls NULL to hit all hosts, otherwise specifies a particular target
  782. * @param key hostID
  783. * @param value information to transmit
  784. * @return #GNUNET_YES (continue to iterate)
  785. */
  786. static int
  787. add_to_tc (void *cls,
  788. const struct GNUNET_PeerIdentity *key,
  789. void *value)
  790. {
  791. struct TransmitContext *tc = cls;
  792. struct HostEntry *pos = value;
  793. struct InfoMessage *im;
  794. uint16_t hs;
  795. char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  796. hs = 0;
  797. im = (struct InfoMessage *) buf;
  798. if ( (NULL != pos->hello) &&
  799. (GNUNET_NO == tc->friend_only) )
  800. {
  801. /* Copy public HELLO */
  802. hs = GNUNET_HELLO_size (pos->hello);
  803. GNUNET_assert (hs < GNUNET_SERVER_MAX_MESSAGE_SIZE -
  804. sizeof (struct InfoMessage));
  805. memcpy (&im[1], pos->hello, hs);
  806. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  807. "Sending public HELLO with size %u for peer `%4s'\n",
  808. hs, GNUNET_i2s (key));
  809. }
  810. else if ( (NULL != pos->friend_only_hello) &&
  811. (GNUNET_YES == tc->friend_only) )
  812. {
  813. /* Copy friend only HELLO */
  814. hs = GNUNET_HELLO_size (pos->friend_only_hello);
  815. GNUNET_assert (hs < GNUNET_SERVER_MAX_MESSAGE_SIZE -
  816. sizeof (struct InfoMessage));
  817. memcpy (&im[1], pos->friend_only_hello, hs);
  818. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  819. "Sending friend-only HELLO with size %u for peer `%4s'\n",
  820. hs,
  821. GNUNET_i2s (key));
  822. }
  823. else
  824. {
  825. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  826. "Adding no HELLO for peer `%s'\n",
  827. GNUNET_i2s (key));
  828. }
  829. im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
  830. im->header.size = htons (sizeof (struct InfoMessage) + hs);
  831. im->reserved = htonl (0);
  832. im->peer = pos->identity;
  833. GNUNET_SERVER_transmit_context_append_message (tc->tc, &im->header);
  834. return GNUNET_YES;
  835. }
  836. /**
  837. * @brief delete expired HELLO entries in directory
  838. *
  839. * @param cls pointer to current time (`struct GNUNET_TIME_Absolute *`)
  840. * @param fn filename to test to see if the HELLO expired
  841. * @return #GNUNET_OK (continue iteration)
  842. */
  843. static int
  844. discard_hosts_helper (void *cls,
  845. const char *fn)
  846. {
  847. struct GNUNET_TIME_Absolute *now = cls;
  848. char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  849. const struct GNUNET_HELLO_Message *hello;
  850. struct GNUNET_HELLO_Message *new_hello;
  851. int read_size;
  852. unsigned int cur_hello_size;
  853. unsigned int new_hello_size;
  854. int read_pos;
  855. int write_pos;
  856. unsigned int cnt;
  857. char *writebuffer;
  858. read_size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
  859. if (read_size < sizeof (struct GNUNET_MessageHeader))
  860. {
  861. if (0 != UNLINK (fn))
  862. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
  863. GNUNET_ERROR_TYPE_BULK, "unlink", fn);
  864. return GNUNET_OK;
  865. }
  866. writebuffer = GNUNET_malloc (read_size);
  867. read_pos = 0;
  868. write_pos = 0;
  869. while (read_pos < read_size)
  870. {
  871. /* Check each HELLO */
  872. hello = (const struct GNUNET_HELLO_Message *) &buffer[read_pos];
  873. cur_hello_size = GNUNET_HELLO_size (hello);
  874. if (0 == cur_hello_size)
  875. {
  876. /* Invalid data, discard */
  877. if (0 != UNLINK (fn))
  878. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
  879. GNUNET_ERROR_TYPE_BULK,
  880. "unlink", fn);
  881. return GNUNET_OK;
  882. }
  883. new_hello = GNUNET_HELLO_iterate_addresses (hello,
  884. GNUNET_YES,
  885. &discard_expired, now);
  886. cnt = 0;
  887. if (NULL != new_hello)
  888. (void) GNUNET_HELLO_iterate_addresses (hello,
  889. GNUNET_NO,
  890. &count_addresses, &cnt);
  891. if ( (NULL != new_hello) && (0 < cnt) )
  892. {
  893. /* Store new HELLO to write it when done */
  894. new_hello_size = GNUNET_HELLO_size (new_hello);
  895. memcpy (&writebuffer[write_pos], new_hello, new_hello_size);
  896. write_pos += new_hello_size;
  897. }
  898. read_pos += cur_hello_size;
  899. GNUNET_free_non_null (new_hello);
  900. }
  901. if (0 < write_pos)
  902. {
  903. GNUNET_DISK_fn_write (fn, writebuffer,write_pos,
  904. GNUNET_DISK_PERM_USER_READ |
  905. GNUNET_DISK_PERM_USER_WRITE |
  906. GNUNET_DISK_PERM_GROUP_READ |
  907. GNUNET_DISK_PERM_OTHER_READ);
  908. }
  909. else if (0 != UNLINK (fn))
  910. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
  911. GNUNET_ERROR_TYPE_BULK,
  912. "unlink", fn);
  913. GNUNET_free (writebuffer);
  914. return GNUNET_OK;
  915. }
  916. /**
  917. * Call this method periodically to scan peerinfo/ for ancient
  918. * HELLOs to expire.
  919. *
  920. * @param cls unused
  921. * @param tc scheduler context, aborted if reason is shutdown
  922. */
  923. static void
  924. cron_clean_data_hosts (void *cls,
  925. const struct GNUNET_SCHEDULER_TaskContext *tc)
  926. {
  927. struct GNUNET_TIME_Absolute now;
  928. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  929. return;
  930. now = GNUNET_TIME_absolute_get ();
  931. GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
  932. _("Cleaning up directory `%s'\n"),
  933. networkIdDirectory);
  934. GNUNET_DISK_directory_scan (networkIdDirectory,
  935. &discard_hosts_helper,
  936. &now);
  937. GNUNET_SCHEDULER_add_delayed (DATA_HOST_CLEAN_FREQ,
  938. &cron_clean_data_hosts,
  939. NULL);
  940. }
  941. /**
  942. * Handle HELLO-message.
  943. *
  944. * @param cls closure
  945. * @param client identification of the client
  946. * @param message the actual message
  947. */
  948. static void
  949. handle_hello (void *cls,
  950. struct GNUNET_SERVER_Client *client,
  951. const struct GNUNET_MessageHeader *message)
  952. {
  953. const struct GNUNET_HELLO_Message *hello;
  954. struct GNUNET_PeerIdentity pid;
  955. hello = (const struct GNUNET_HELLO_Message *) message;
  956. if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
  957. {
  958. GNUNET_break (0);
  959. GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
  960. return;
  961. }
  962. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  963. "`%s' message received for peer `%4s'\n",
  964. "HELLO",
  965. GNUNET_i2s (&pid));
  966. add_host_to_known_hosts (&pid);
  967. update_hello (&pid, hello);
  968. GNUNET_SERVER_receive_done (client, GNUNET_OK);
  969. }
  970. /**
  971. * Handle GET-message.
  972. *
  973. * @param cls closure
  974. * @param client identification of the client
  975. * @param message the actual message
  976. */
  977. static void
  978. handle_get (void *cls,
  979. struct GNUNET_SERVER_Client *client,
  980. const struct GNUNET_MessageHeader *message)
  981. {
  982. const struct ListPeerMessage *lpm;
  983. struct TransmitContext tcx;
  984. lpm = (const struct ListPeerMessage *) message;
  985. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  986. "`%s' message received for peer `%4s'\n",
  987. "GET",
  988. GNUNET_i2s (&lpm->peer));
  989. tcx.friend_only = ntohl (lpm->include_friend_only);
  990. tcx.tc = GNUNET_SERVER_transmit_context_create (client);
  991. GNUNET_CONTAINER_multipeermap_get_multiple (hostmap, &lpm->peer,
  992. &add_to_tc, &tcx);
  993. GNUNET_SERVER_transmit_context_append_data (tcx.tc, NULL, 0,
  994. GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
  995. GNUNET_SERVER_transmit_context_run (tcx.tc, GNUNET_TIME_UNIT_FOREVER_REL);
  996. }
  997. /**
  998. * Handle GET-ALL-message.
  999. *
  1000. * @param cls closure
  1001. * @param client identification of the client
  1002. * @param message the actual message
  1003. */
  1004. static void
  1005. handle_get_all (void *cls, struct GNUNET_SERVER_Client *client,
  1006. const struct GNUNET_MessageHeader *message)
  1007. {
  1008. const struct ListAllPeersMessage *lapm;
  1009. struct TransmitContext tcx;
  1010. lapm = (const struct ListAllPeersMessage *) message;
  1011. tcx.friend_only = ntohl (lapm->include_friend_only);
  1012. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1013. "`%s' message received\n",
  1014. "GET_ALL");
  1015. GNUNET_SERVER_disable_receive_done_warning (client);
  1016. tcx.tc = GNUNET_SERVER_transmit_context_create (client);
  1017. GNUNET_CONTAINER_multipeermap_iterate (hostmap,
  1018. &add_to_tc,
  1019. &tcx);
  1020. GNUNET_SERVER_transmit_context_append_data (tcx.tc, NULL, 0,
  1021. GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
  1022. GNUNET_SERVER_transmit_context_run (tcx.tc, GNUNET_TIME_UNIT_FOREVER_REL);
  1023. }
  1024. /**
  1025. * Pass the given client the information we have in the respective
  1026. * host entry; the client is already in the notification context.
  1027. *
  1028. * @param cls the `struct GNUNET_SERVER_Client` to notify
  1029. * @param key key for the value (unused)
  1030. * @param value the `struct HostEntry` to notify the client about
  1031. * @return #GNUNET_YES (always, continue to iterate)
  1032. */
  1033. static int
  1034. do_notify_entry (void *cls,
  1035. const struct GNUNET_PeerIdentity *key,
  1036. void *value)
  1037. {
  1038. struct NotificationContext *nc = cls;
  1039. struct HostEntry *he = value;
  1040. struct InfoMessage *msg;
  1041. if ( (NULL == he->hello) &&
  1042. (GNUNET_NO == nc->include_friend_only) )
  1043. {
  1044. /* We have no public hello */
  1045. return GNUNET_YES;
  1046. }
  1047. if ( (NULL == he->friend_only_hello) &&
  1048. (GNUNET_YES == nc->include_friend_only) )
  1049. {
  1050. /* We have no friend hello */
  1051. return GNUNET_YES;
  1052. }
  1053. msg = make_info_message (he, nc->include_friend_only);
  1054. GNUNET_SERVER_notification_context_unicast (notify_list,
  1055. nc->client,
  1056. &msg->header,
  1057. GNUNET_NO);
  1058. GNUNET_free (msg);
  1059. return GNUNET_YES;
  1060. }
  1061. /**
  1062. * Handle NOTIFY-message.
  1063. *
  1064. * @param cls closure
  1065. * @param client identification of the client
  1066. * @param message the actual message
  1067. */
  1068. static void
  1069. handle_notify (void *cls,
  1070. struct GNUNET_SERVER_Client *client,
  1071. const struct GNUNET_MessageHeader *message)
  1072. {
  1073. struct NotifyMessage *nm = (struct NotifyMessage *) message;
  1074. struct NotificationContext *nc;
  1075. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1076. "`%s' message received\n",
  1077. "NOTIFY");
  1078. nc = GNUNET_new (struct NotificationContext);
  1079. nc->client = client;
  1080. nc->include_friend_only = ntohl (nm->include_friend_only);
  1081. GNUNET_CONTAINER_DLL_insert (nc_head, nc_tail, nc);
  1082. GNUNET_SERVER_client_mark_monitor (client);
  1083. GNUNET_SERVER_notification_context_add (notify_list, client);
  1084. GNUNET_CONTAINER_multipeermap_iterate (hostmap, &do_notify_entry, nc);
  1085. GNUNET_SERVER_receive_done (client, GNUNET_OK);
  1086. }
  1087. /**
  1088. * Client disconnect callback
  1089. *
  1090. * @param cls unused
  1091. * @param client server client
  1092. */
  1093. static void
  1094. disconnect_cb (void *cls,
  1095. struct GNUNET_SERVER_Client *client)
  1096. {
  1097. struct NotificationContext *cur;
  1098. for (cur = nc_head; NULL != cur; cur = cur->next)
  1099. if (cur->client == client)
  1100. break;
  1101. if (NULL == cur)
  1102. return;
  1103. GNUNET_CONTAINER_DLL_remove (nc_head, nc_tail, cur);
  1104. GNUNET_free (cur);
  1105. }
  1106. /**
  1107. * Release memory taken by a host entry.
  1108. *
  1109. * @param cls NULL
  1110. * @param key key of the host entry
  1111. * @param value the `struct HostEntry` to free
  1112. * @return #GNUNET_YES (continue to iterate)
  1113. */
  1114. static int
  1115. free_host_entry (void *cls,
  1116. const struct GNUNET_PeerIdentity *key,
  1117. void *value)
  1118. {
  1119. struct HostEntry *he = value;
  1120. GNUNET_free_non_null (he->hello);
  1121. GNUNET_free_non_null (he->friend_only_hello);
  1122. GNUNET_free (he);
  1123. return GNUNET_YES;
  1124. }
  1125. /**
  1126. * Clean up our state. Called during shutdown.
  1127. *
  1128. * @param cls unused
  1129. * @param tc scheduler task context, unused
  1130. */
  1131. static void
  1132. shutdown_task (void *cls,
  1133. const struct GNUNET_SCHEDULER_TaskContext *tc)
  1134. {
  1135. struct NotificationContext *cur;
  1136. struct NotificationContext *next;
  1137. GNUNET_SERVER_notification_context_destroy (notify_list);
  1138. notify_list = NULL;
  1139. for (cur = nc_head; NULL != cur; cur = next)
  1140. {
  1141. next = cur->next;
  1142. GNUNET_CONTAINER_DLL_remove (nc_head, nc_tail, cur);
  1143. GNUNET_free (cur);
  1144. }
  1145. GNUNET_CONTAINER_multipeermap_iterate (hostmap,
  1146. &free_host_entry,
  1147. NULL);
  1148. GNUNET_CONTAINER_multipeermap_destroy (hostmap);
  1149. if (NULL != stats)
  1150. {
  1151. GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
  1152. stats = NULL;
  1153. }
  1154. }
  1155. /**
  1156. * Start up peerinfo service.
  1157. *
  1158. * @param cls closure
  1159. * @param server the initialized server
  1160. * @param cfg configuration to use
  1161. */
  1162. static void
  1163. run (void *cls,
  1164. struct GNUNET_SERVER_Handle *server,
  1165. const struct GNUNET_CONFIGURATION_Handle *cfg)
  1166. {
  1167. static const struct GNUNET_SERVER_MessageHandler handlers[] = {
  1168. {&handle_hello, NULL, GNUNET_MESSAGE_TYPE_HELLO, 0},
  1169. {&handle_get, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET,
  1170. sizeof (struct ListPeerMessage)},
  1171. {&handle_get_all, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL,
  1172. sizeof (struct ListAllPeersMessage)},
  1173. {&handle_notify, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY,
  1174. sizeof (struct NotifyMessage)},
  1175. {NULL, NULL, 0, 0}
  1176. };
  1177. char *peerdir;
  1178. char *ip;
  1179. struct DirScanContext dsc;
  1180. int noio;
  1181. int use_included;
  1182. hostmap = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
  1183. stats = GNUNET_STATISTICS_create ("peerinfo", cfg);
  1184. notify_list = GNUNET_SERVER_notification_context_create (server, 0);
  1185. noio = GNUNET_CONFIGURATION_get_value_yesno (cfg, "peerinfo", "NO_IO");
  1186. use_included = GNUNET_CONFIGURATION_get_value_yesno (cfg,
  1187. "peerinfo",
  1188. "USE_INCLUDED_HELLOS");
  1189. if (GNUNET_SYSERR == use_included)
  1190. use_included = GNUNET_NO;
  1191. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
  1192. &shutdown_task,
  1193. NULL);
  1194. if (GNUNET_YES != noio)
  1195. {
  1196. GNUNET_assert (GNUNET_OK ==
  1197. GNUNET_CONFIGURATION_get_value_filename (cfg, "peerinfo",
  1198. "HOSTS",
  1199. &networkIdDirectory));
  1200. if (GNUNET_OK !=
  1201. GNUNET_DISK_directory_create (networkIdDirectory))
  1202. {
  1203. GNUNET_SCHEDULER_shutdown ();
  1204. return;
  1205. }
  1206. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
  1207. &cron_scan_directory_data_hosts, NULL);
  1208. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
  1209. &cron_clean_data_hosts, NULL);
  1210. if (GNUNET_YES == use_included)
  1211. {
  1212. ip = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
  1213. GNUNET_asprintf (&peerdir,
  1214. "%shellos",
  1215. ip);
  1216. GNUNET_free(ip);
  1217. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  1218. _("Importing HELLOs from `%s'\n"),
  1219. peerdir);
  1220. dsc.matched = 0;
  1221. dsc.remove_files = GNUNET_NO;
  1222. GNUNET_DISK_directory_scan (peerdir,
  1223. &hosts_directory_scan_callback,
  1224. &dsc);
  1225. GNUNET_free (peerdir);
  1226. }
  1227. else
  1228. {
  1229. GNUNET_log(GNUNET_ERROR_TYPE_INFO,
  1230. _("Skipping import of included HELLOs\n"));
  1231. }
  1232. }
  1233. GNUNET_SERVER_add_handlers (server, handlers);
  1234. GNUNET_SERVER_disconnect_notify (server,
  1235. &disconnect_cb,
  1236. NULL);
  1237. }
  1238. /**
  1239. * The main function for the peerinfo service.
  1240. *
  1241. * @param argc number of arguments from the command line
  1242. * @param argv command line arguments
  1243. * @return 0 ok, 1 on error
  1244. */
  1245. int
  1246. main (int argc,
  1247. char *const *argv)
  1248. {
  1249. int ret;
  1250. ret =
  1251. (GNUNET_OK ==
  1252. GNUNET_SERVICE_run (argc, argv,
  1253. "peerinfo",
  1254. GNUNET_SERVICE_OPTION_NONE,
  1255. &run, NULL)) ? 0 : 1;
  1256. GNUNET_free_non_null (networkIdDirectory);
  1257. return ret;
  1258. }
  1259. /* end of gnunet-service-peerinfo.c */