gnunet-service-messenger_service.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2020 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. * @author Tobias Frisch
  18. * @file src/messenger/gnunet-service-messenger_service.c
  19. * @brief GNUnet MESSENGER service
  20. */
  21. #include "gnunet-service-messenger_service.h"
  22. #include "gnunet-service-messenger_message_kind.h"
  23. #include "gnunet-service-messenger.h"
  24. #include "gnunet-service-messenger_util.h"
  25. static void
  26. callback_shutdown_service (void *cls)
  27. {
  28. struct GNUNET_MESSENGER_Service *service = cls;
  29. if (service)
  30. {
  31. service->shutdown = NULL;
  32. destroy_service (service);
  33. }
  34. }
  35. static void
  36. callback_update_ego (void *cls,
  37. struct GNUNET_IDENTITY_Ego *ego,
  38. void **ctx,
  39. const char *identifier)
  40. {
  41. if ((!ego) || (!identifier))
  42. return;
  43. struct GNUNET_MESSENGER_Service *service = cls;
  44. update_service_ego(service, identifier, GNUNET_IDENTITY_ego_get_private_key(ego));
  45. }
  46. struct GNUNET_MESSENGER_Service*
  47. create_service (const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service_handle)
  48. {
  49. struct GNUNET_MESSENGER_Service *service = GNUNET_new(struct GNUNET_MESSENGER_Service);
  50. service->config = config;
  51. service->service = service_handle;
  52. service->shutdown = GNUNET_SCHEDULER_add_shutdown (&callback_shutdown_service, service);
  53. service->dir = NULL;
  54. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (service->config,
  55. GNUNET_MESSENGER_SERVICE_NAME,
  56. "MESSENGER_DIR", &(service->dir)))
  57. {
  58. if (service->dir)
  59. GNUNET_free(service->dir);
  60. service->dir = NULL;
  61. }
  62. else
  63. {
  64. if ((GNUNET_YES != GNUNET_DISK_directory_test (service->dir, GNUNET_YES)) && (GNUNET_OK
  65. != GNUNET_DISK_directory_create (service->dir)))
  66. {
  67. GNUNET_free(service->dir);
  68. service->dir = NULL;
  69. }
  70. }
  71. service->cadet = GNUNET_CADET_connect (service->config);
  72. service->identity = GNUNET_IDENTITY_connect (service->config, &callback_update_ego, service);
  73. service->egos = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
  74. init_list_handles (&(service->handles));
  75. service->contacts = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
  76. service->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
  77. return service;
  78. }
  79. static int
  80. iterate_destroy_egos (void *cls, const struct GNUNET_HashCode *key, void *value)
  81. {
  82. struct GNUNET_MESSENGER_Ego *ego = value;
  83. GNUNET_free(ego);
  84. return GNUNET_YES;
  85. }
  86. static int
  87. iterate_destroy_rooms (void *cls, const struct GNUNET_HashCode *key, void *value)
  88. {
  89. struct GNUNET_MESSENGER_SrvRoom *room = value;
  90. destroy_room (room);
  91. return GNUNET_YES;
  92. }
  93. static int
  94. iterate_destroy_contacts (void *cls, const struct GNUNET_HashCode *key, void *value)
  95. {
  96. struct GNUNET_MESSENGER_SrvContact *contact = value;
  97. destroy_contact (contact);
  98. return GNUNET_YES;
  99. }
  100. void
  101. destroy_service (struct GNUNET_MESSENGER_Service *service)
  102. {
  103. if (service->shutdown)
  104. {
  105. GNUNET_SCHEDULER_cancel (service->shutdown);
  106. service->shutdown = NULL;
  107. }
  108. GNUNET_CONTAINER_multihashmap_iterate (service->egos, iterate_destroy_egos, NULL);
  109. clear_list_handles (&(service->handles));
  110. GNUNET_CONTAINER_multihashmap_iterate (service->rooms, iterate_destroy_rooms, NULL);
  111. GNUNET_CONTAINER_multihashmap_iterate (service->contacts, iterate_destroy_contacts, NULL);
  112. GNUNET_CONTAINER_multihashmap_destroy (service->egos);
  113. GNUNET_CONTAINER_multihashmap_destroy (service->rooms);
  114. GNUNET_CONTAINER_multihashmap_destroy (service->contacts);
  115. if (service->cadet)
  116. {
  117. GNUNET_CADET_disconnect (service->cadet);
  118. service->cadet = NULL;
  119. }
  120. if (service->identity)
  121. {
  122. GNUNET_IDENTITY_disconnect (service->identity);
  123. service->identity = NULL;
  124. }
  125. if (service->dir)
  126. {
  127. GNUNET_free(service->dir);
  128. service->dir = NULL;
  129. }
  130. GNUNET_SERVICE_shutdown (service->service);
  131. GNUNET_free(service);
  132. }
  133. struct GNUNET_MESSENGER_Ego*
  134. lookup_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier)
  135. {
  136. GNUNET_assert(identifier);
  137. struct GNUNET_HashCode hash;
  138. GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
  139. return GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
  140. }
  141. void
  142. update_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier,
  143. const struct GNUNET_IDENTITY_PrivateKey* key)
  144. {
  145. GNUNET_assert((identifier) && (key));
  146. struct GNUNET_HashCode hash;
  147. GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
  148. struct GNUNET_MESSENGER_Ego* ego = GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
  149. if (!ego)
  150. {
  151. ego = GNUNET_new(struct GNUNET_MESSENGER_Ego);
  152. GNUNET_CONTAINER_multihashmap_put(service->egos, &hash, ego, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  153. }
  154. GNUNET_memcpy(&(ego->priv), key, sizeof(*key));
  155. if (GNUNET_OK != GNUNET_IDENTITY_key_get_public(key, &(ego->pub)))
  156. GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Updating invalid ego key failed!\n");
  157. }
  158. struct GNUNET_MESSENGER_SrvHandle*
  159. add_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq)
  160. {
  161. struct GNUNET_MESSENGER_SrvHandle *handle = create_handle (service, mq);
  162. if (handle)
  163. {
  164. add_list_handle (&(service->handles), handle);
  165. }
  166. return handle;
  167. }
  168. void
  169. remove_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle)
  170. {
  171. if (!handle)
  172. return;
  173. if (GNUNET_YES == remove_list_handle (&(service->handles), handle))
  174. destroy_handle (handle);
  175. }
  176. int
  177. get_service_peer_identity (const struct GNUNET_MESSENGER_Service *service, struct GNUNET_PeerIdentity *peer)
  178. {
  179. return GNUNET_CRYPTO_get_peer_identity (service->config, peer);
  180. }
  181. struct GNUNET_MESSENGER_SrvContact*
  182. get_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_IDENTITY_PublicKey *pubkey)
  183. {
  184. struct GNUNET_HashCode hash;
  185. GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
  186. struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multihashmap_get (service->contacts, &hash);
  187. if (contact)
  188. return contact;
  189. contact = create_contact (pubkey);
  190. if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->contacts, &hash, contact,
  191. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
  192. return contact;
  193. destroy_contact (contact);
  194. return NULL;
  195. }
  196. void
  197. swap_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvContact *contact,
  198. const struct GNUNET_IDENTITY_PublicKey *pubkey)
  199. {
  200. const struct GNUNET_HashCode *hash = get_contact_id_from_key (contact);
  201. if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (service->contacts, hash, contact))
  202. {
  203. GNUNET_memcpy(&(contact->public_key), pubkey, sizeof(*pubkey));
  204. hash = get_contact_id_from_key (contact);
  205. GNUNET_CONTAINER_multihashmap_put (service->contacts, hash, contact,
  206. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  207. }
  208. }
  209. struct GNUNET_ShortHashCode*
  210. generate_service_new_member_id (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
  211. {
  212. struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
  213. if (room)
  214. {
  215. return generate_room_member_id (room);
  216. }
  217. else
  218. {
  219. struct GNUNET_ShortHashCode *random_id = GNUNET_new(struct GNUNET_ShortHashCode);
  220. generate_free_member_id (random_id, NULL);
  221. return random_id;
  222. }
  223. }
  224. struct GNUNET_MESSENGER_SrvRoom*
  225. get_service_room (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
  226. {
  227. return GNUNET_CONTAINER_multihashmap_get (service->rooms, key);
  228. }
  229. int
  230. open_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
  231. const struct GNUNET_HashCode *key)
  232. {
  233. struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
  234. if (room)
  235. return open_room (room, handle);
  236. room = create_room (handle, key);
  237. if ((GNUNET_YES == open_room (room, handle)) && (GNUNET_OK
  238. == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
  239. return GNUNET_YES;
  240. destroy_room (room);
  241. return GNUNET_NO;
  242. }
  243. int
  244. entry_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
  245. const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key)
  246. {
  247. struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
  248. if (room)
  249. {
  250. if (GNUNET_YES == entry_room_at (room, handle, door))
  251. return GNUNET_YES;
  252. else
  253. return GNUNET_NO;
  254. }
  255. room = create_room (handle, key);
  256. if ((GNUNET_YES == entry_room_at (room, handle, door)) && (GNUNET_OK
  257. == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
  258. {
  259. return GNUNET_YES;
  260. }
  261. else
  262. {
  263. destroy_room (room);
  264. return GNUNET_NO;
  265. }
  266. }
  267. int
  268. close_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
  269. const struct GNUNET_HashCode *key)
  270. {
  271. struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
  272. if (!room)
  273. return GNUNET_NO;
  274. struct GNUNET_MESSENGER_Message *message = create_message_leave ();
  275. if (message)
  276. {
  277. struct GNUNET_HashCode hash;
  278. send_room_message (room, handle, message, &hash);
  279. destroy_message (message);
  280. }
  281. const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, key);
  282. GNUNET_assert(id);
  283. if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (handle->member_ids, key, id))
  284. return GNUNET_NO;
  285. struct GNUNET_MESSENGER_SrvHandle *member_handle = (struct GNUNET_MESSENGER_SrvHandle*) find_list_handle_by_member (
  286. &(service->handles), key);
  287. if (!member_handle)
  288. {
  289. if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (service->rooms, key, room))
  290. {
  291. destroy_room (room);
  292. return GNUNET_YES;
  293. }
  294. else
  295. return GNUNET_NO;
  296. }
  297. if (room->host == handle)
  298. room->host = member_handle;
  299. return GNUNET_YES;
  300. }
  301. static void
  302. get_room_data_subdir (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room, char **dir)
  303. {
  304. GNUNET_asprintf (dir, "%s%s%c%s%c", service->dir, "rooms", DIR_SEPARATOR, GNUNET_h2s (&(room->key)), DIR_SEPARATOR);
  305. }
  306. void
  307. load_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
  308. {
  309. char *room_dir;
  310. get_room_data_subdir (service, room, &room_dir);
  311. if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
  312. {
  313. load_message_store (&room->store, room_dir);
  314. char *config_file;
  315. GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
  316. struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
  317. if ((GNUNET_YES == GNUNET_DISK_file_test (config_file)) && (GNUNET_OK
  318. == GNUNET_CONFIGURATION_parse (cfg, config_file)))
  319. {
  320. unsigned long long access;
  321. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "room", "access-rule", &access))
  322. room->strict_access = (int) (access);
  323. char *message_string;
  324. if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "room", "last-message", &message_string)) && (message_string))
  325. {
  326. struct GNUNET_HashCode hash;
  327. GNUNET_CRYPTO_hash_from_string(message_string, &hash);
  328. const struct GNUNET_MESSENGER_Message *message = get_room_message (room, room->host, &hash, GNUNET_NO);
  329. if (message)
  330. update_room_last_messages (room, message, &hash);
  331. GNUNET_free(message_string);
  332. }
  333. }
  334. GNUNET_CONFIGURATION_destroy (cfg);
  335. GNUNET_free(config_file);
  336. }
  337. GNUNET_free(room_dir);
  338. }
  339. void
  340. save_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
  341. {
  342. if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (service->rooms, &(room->key)))
  343. {
  344. return;
  345. }
  346. char *room_dir;
  347. get_room_data_subdir (service, room, &room_dir);
  348. if ((GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_NO)) || (GNUNET_OK
  349. == GNUNET_DISK_directory_create (room_dir)))
  350. {
  351. save_message_store (&room->store, room_dir);
  352. char *config_file;
  353. GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
  354. struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
  355. GNUNET_CONFIGURATION_set_value_number (cfg, "room", "access-rule", room->strict_access);
  356. if (room->last_messages.head)
  357. GNUNET_CONFIGURATION_set_value_string (cfg, "room", "last-message",
  358. GNUNET_h2s_full (&(room->last_messages.head->hash)));
  359. GNUNET_CONFIGURATION_write (cfg, config_file);
  360. GNUNET_CONFIGURATION_destroy (cfg);
  361. GNUNET_free(config_file);
  362. }
  363. GNUNET_free(room_dir);
  364. }
  365. void
  366. handle_service_message (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room,
  367. const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
  368. {
  369. struct GNUNET_MESSENGER_ListHandle *element = service->handles.head;
  370. const uint16_t length = get_message_size (message);
  371. while (element)
  372. {
  373. struct GNUNET_MESSENGER_SrvHandle *handle = (struct GNUNET_MESSENGER_SrvHandle*) element->handle;
  374. if ((handle->mq) && (get_handle_member_id (handle, &(room->key))))
  375. {
  376. struct GNUNET_MESSENGER_RecvMessage *msg;
  377. struct GNUNET_MQ_Envelope *env;
  378. env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE);
  379. GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
  380. GNUNET_memcpy(&(msg->hash), hash, sizeof(*hash));
  381. char *buffer = ((char*) msg) + sizeof(*msg);
  382. encode_message (message, length, buffer);
  383. GNUNET_MQ_send (handle->mq, env);
  384. }
  385. element = element->next;
  386. }
  387. }