gnunet-service-core.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 2010, 2011, 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 core/gnunet-service-core.c
  18. * @brief high-level P2P messaging
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include <gcrypt.h>
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet-service-core.h"
  25. #include "gnunet-service-core_kx.h"
  26. #include "gnunet-service-core_sessions.h"
  27. #include "gnunet-service-core_typemap.h"
  28. /**
  29. * How many messages do we queue up at most for any client? This can
  30. * cause messages to be dropped if clients do not process them fast
  31. * enough! Note that this is a soft limit; we try
  32. * to keep a few larger messages above the limit.
  33. */
  34. #define SOFT_MAX_QUEUE 128
  35. /**
  36. * How many messages do we queue up at most for any client? This can
  37. * cause messages to be dropped if clients do not process them fast
  38. * enough! Note that this is the hard limit.
  39. */
  40. #define HARD_MAX_QUEUE 256
  41. /**
  42. * Data structure for each client connected to the CORE service.
  43. */
  44. struct GSC_Client
  45. {
  46. /**
  47. * Clients are kept in a linked list.
  48. */
  49. struct GSC_Client *next;
  50. /**
  51. * Clients are kept in a linked list.
  52. */
  53. struct GSC_Client *prev;
  54. /**
  55. * Handle for the client with the server API.
  56. */
  57. struct GNUNET_SERVICE_Client *client;
  58. /**
  59. * Message queue to talk to @e client.
  60. */
  61. struct GNUNET_MQ_Handle *mq;
  62. /**
  63. * Array of the types of messages this peer cares
  64. * about (with @e tcnt entries). Allocated as part
  65. * of this client struct, do not free!
  66. */
  67. uint16_t *types;
  68. /**
  69. * Map of peer identities to active transmission requests of this
  70. * client to the peer (of type `struct GSC_ClientActiveRequest`).
  71. */
  72. struct GNUNET_CONTAINER_MultiPeerMap *requests;
  73. /**
  74. * Map containing all peers that this client knows we're connected to.
  75. */
  76. struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
  77. /**
  78. * Options for messages this client cares about,
  79. * see GNUNET_CORE_OPTION_ values.
  80. */
  81. uint32_t options;
  82. /**
  83. * Have we gotten the #GNUNET_MESSAGE_TYPE_CORE_INIT message
  84. * from this client already?
  85. */
  86. int got_init;
  87. /**
  88. * Number of types of incoming messages this client
  89. * specifically cares about. Size of the @e types array.
  90. */
  91. unsigned int tcnt;
  92. };
  93. /**
  94. * Our identity.
  95. */
  96. struct GNUNET_PeerIdentity GSC_my_identity;
  97. /**
  98. * Our configuration.
  99. */
  100. const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
  101. /**
  102. * For creating statistics.
  103. */
  104. struct GNUNET_STATISTICS_Handle *GSC_stats;
  105. /**
  106. * Big "or" of all client options.
  107. */
  108. static uint32_t all_client_options;
  109. /**
  110. * Head of linked list of our clients.
  111. */
  112. static struct GSC_Client *client_head;
  113. /**
  114. * Tail of linked list of our clients.
  115. */
  116. static struct GSC_Client *client_tail;
  117. /**
  118. * Test if the client is interested in messages of the given type.
  119. *
  120. * @param type message type
  121. * @param c client to test
  122. * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
  123. */
  124. static int
  125. type_match (uint16_t type, struct GSC_Client *c)
  126. {
  127. if ((0 == c->tcnt) && (0 != c->options))
  128. return GNUNET_YES; /* peer without handlers and inbound/outbond
  129. callbacks matches ALL */
  130. if (NULL == c->types)
  131. return GNUNET_NO;
  132. for (unsigned int i = 0; i < c->tcnt; i++)
  133. if (type == c->types[i])
  134. return GNUNET_YES;
  135. return GNUNET_NO;
  136. }
  137. /**
  138. * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
  139. *
  140. * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
  141. * @param im the `struct InitMessage`
  142. * @return #GNUNET_OK if @a im is well-formed
  143. */
  144. static int
  145. check_client_init (void *cls, const struct InitMessage *im)
  146. {
  147. return GNUNET_OK;
  148. }
  149. /**
  150. * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
  151. *
  152. * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
  153. * @param im the `struct InitMessage`
  154. */
  155. static void
  156. handle_client_init (void *cls, const struct InitMessage *im)
  157. {
  158. struct GSC_Client *c = cls;
  159. struct GNUNET_MQ_Envelope *env;
  160. struct InitReplyMessage *irm;
  161. uint16_t msize;
  162. const uint16_t *types;
  163. /* check that we don't have an entry already */
  164. msize = ntohs (im->header.size) - sizeof(struct InitMessage);
  165. types = (const uint16_t *) &im[1];
  166. c->tcnt = msize / sizeof(uint16_t);
  167. c->options = ntohl (im->options);
  168. c->got_init = GNUNET_YES;
  169. all_client_options |= c->options;
  170. c->types = GNUNET_malloc (msize);
  171. GNUNET_assert (GNUNET_YES ==
  172. GNUNET_CONTAINER_multipeermap_put (
  173. c->connectmap,
  174. &GSC_my_identity,
  175. NULL,
  176. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  177. for (unsigned int i = 0; i < c->tcnt; i++)
  178. c->types[i] = ntohs (types[i]);
  179. GSC_TYPEMAP_add (c->types, c->tcnt);
  180. GNUNET_log (
  181. GNUNET_ERROR_TYPE_DEBUG,
  182. "Client connecting to core service is interested in %u message types\n",
  183. (unsigned int) c->tcnt);
  184. /* send init reply message */
  185. env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
  186. irm->reserved = htonl (0);
  187. irm->my_identity = GSC_my_identity;
  188. GNUNET_MQ_send (c->mq, env);
  189. GSC_SESSIONS_notify_client_about_sessions (c);
  190. GNUNET_SERVICE_client_continue (c->client);
  191. }
  192. /**
  193. * We will never be ready to transmit the given message in (disconnect
  194. * or invalid request). Frees resources associated with @a car. We
  195. * don't explicitly tell the client, it'll learn with the disconnect
  196. * (or violated the protocol).
  197. *
  198. * @param car request that now permanently failed; the
  199. * responsibility for the handle is now returned
  200. * to CLIENTS (SESSIONS is done with it).
  201. * @param drop_client #GNUNET_YES if the client violated the protocol
  202. * and we should thus drop the connection
  203. */
  204. void
  205. GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
  206. int drop_client)
  207. {
  208. GNUNET_assert (
  209. GNUNET_YES ==
  210. GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
  211. &car->target,
  212. car));
  213. if (GNUNET_YES == drop_client)
  214. GNUNET_SERVICE_client_drop (car->client_handle->client);
  215. GNUNET_free (car);
  216. }
  217. /**
  218. * Tell a client that we are ready to receive the message.
  219. *
  220. * @param car request that is now ready; the responsibility
  221. * for the handle remains shared between CLIENTS
  222. * and SESSIONS after this call.
  223. */
  224. void
  225. GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
  226. {
  227. struct GSC_Client *c;
  228. struct GNUNET_MQ_Envelope *env;
  229. struct SendMessageReady *smr;
  230. struct GNUNET_TIME_Relative delay;
  231. struct GNUNET_TIME_Relative left;
  232. c = car->client_handle;
  233. if (GNUNET_YES !=
  234. GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &car->target))
  235. {
  236. /* connection has gone down since, drop request */
  237. GNUNET_assert (0 != memcmp (&car->target,
  238. &GSC_my_identity,
  239. sizeof(struct GNUNET_PeerIdentity)));
  240. GSC_SESSIONS_dequeue_request (car);
  241. GSC_CLIENTS_reject_request (car, GNUNET_NO);
  242. return;
  243. }
  244. delay = GNUNET_TIME_absolute_get_duration (car->received_time);
  245. left = GNUNET_TIME_absolute_get_duration (car->deadline);
  246. if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
  247. GNUNET_log (
  248. GNUNET_ERROR_TYPE_WARNING,
  249. "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
  250. GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
  251. GNUNET_i2s (&car->target),
  252. (0 == left.rel_value_us) ? " (past deadline)" : "",
  253. car->priority);
  254. env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
  255. smr->size = htons (car->msize);
  256. smr->smr_id = car->smr_id;
  257. smr->peer = car->target;
  258. GNUNET_MQ_send (c->mq, env);
  259. }
  260. /**
  261. * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
  262. *
  263. * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
  264. * @param req the `struct SendMessageRequest`
  265. */
  266. static void
  267. handle_client_send_request (void *cls, const struct SendMessageRequest *req)
  268. {
  269. struct GSC_Client *c = cls;
  270. struct GSC_ClientActiveRequest *car;
  271. int is_loopback;
  272. if (NULL == c->requests)
  273. c->requests = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
  274. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  275. "Client asked for transmission to `%s'\n",
  276. GNUNET_i2s (&req->peer));
  277. is_loopback = (0 == memcmp (&req->peer,
  278. &GSC_my_identity,
  279. sizeof(struct GNUNET_PeerIdentity)));
  280. if ((! is_loopback) &&
  281. (GNUNET_YES !=
  282. GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &req->peer)))
  283. {
  284. /* neighbour must have disconnected since request was issued,
  285. * ignore (client will realize it once it processes the
  286. * disconnect notification) */
  287. GNUNET_STATISTICS_update (GSC_stats,
  288. gettext_noop (
  289. "# send requests dropped (disconnected)"),
  290. 1,
  291. GNUNET_NO);
  292. GNUNET_SERVICE_client_continue (c->client);
  293. return;
  294. }
  295. car = GNUNET_CONTAINER_multipeermap_get (c->requests, &req->peer);
  296. if (NULL == car)
  297. {
  298. /* create new entry */
  299. car = GNUNET_new (struct GSC_ClientActiveRequest);
  300. GNUNET_assert (GNUNET_OK ==
  301. GNUNET_CONTAINER_multipeermap_put (
  302. c->requests,
  303. &req->peer,
  304. car,
  305. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
  306. car->client_handle = c;
  307. }
  308. else
  309. {
  310. /* dequeue and recycle memory from pending request, there can only
  311. be at most one per client and peer */
  312. GNUNET_STATISTICS_update (GSC_stats,
  313. gettext_noop (
  314. "# dequeuing CAR (duplicate request)"),
  315. 1,
  316. GNUNET_NO);
  317. GSC_SESSIONS_dequeue_request (car);
  318. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  319. "Transmission request to `%s' was a duplicate!\n",
  320. GNUNET_i2s (&req->peer));
  321. }
  322. car->target = req->peer;
  323. car->received_time = GNUNET_TIME_absolute_get ();
  324. car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
  325. car->priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (req->priority);
  326. car->msize = ntohs (req->size);
  327. car->smr_id = req->smr_id;
  328. car->was_solicited = GNUNET_NO;
  329. GNUNET_SERVICE_client_continue (c->client);
  330. if (is_loopback)
  331. {
  332. /* loopback, satisfy immediately */
  333. GSC_CLIENTS_solicit_request (car);
  334. return;
  335. }
  336. GSC_SESSIONS_queue_request (car);
  337. }
  338. /**
  339. * Closure for the #client_tokenizer_callback().
  340. */
  341. struct TokenizerContext
  342. {
  343. /**
  344. * Active request handle for the message.
  345. */
  346. struct GSC_ClientActiveRequest *car;
  347. /**
  348. * How important is this message.
  349. */
  350. enum GNUNET_MQ_PriorityPreferences priority;
  351. };
  352. /**
  353. * Functions with this signature are called whenever a complete
  354. * message is received by the tokenizer. Used by
  355. * #handle_client_send() for dispatching messages from clients to
  356. * either the SESSION subsystem or other CLIENT (for loopback).
  357. *
  358. * @param cls reservation request (`struct TokenizerContext`)
  359. * @param message the actual message
  360. * @return #GNUNET_OK on success,
  361. * #GNUNET_NO to stop further processing (no error)
  362. * #GNUNET_SYSERR to stop further processing with error
  363. */
  364. static int
  365. tokenized_cb (void *cls, const struct GNUNET_MessageHeader *message)
  366. {
  367. struct TokenizerContext *tc = cls;
  368. struct GSC_ClientActiveRequest *car = tc->car;
  369. char buf[92];
  370. GNUNET_snprintf (buf,
  371. sizeof(buf),
  372. gettext_noop ("# bytes of messages of type %u received"),
  373. (unsigned int) ntohs (message->type));
  374. GNUNET_STATISTICS_update (GSC_stats, buf, ntohs (message->size), GNUNET_NO);
  375. if (0 == memcmp (&car->target,
  376. &GSC_my_identity,
  377. sizeof(struct GNUNET_PeerIdentity)))
  378. {
  379. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  380. "Delivering message of type %u to myself\n",
  381. ntohs (message->type));
  382. GSC_CLIENTS_deliver_message (&GSC_my_identity,
  383. message,
  384. ntohs (message->size),
  385. GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
  386. GSC_CLIENTS_deliver_message (&GSC_my_identity,
  387. message,
  388. sizeof(struct GNUNET_MessageHeader),
  389. GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
  390. GSC_CLIENTS_deliver_message (&GSC_my_identity,
  391. message,
  392. ntohs (message->size),
  393. GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
  394. GSC_CLIENTS_deliver_message (&GSC_my_identity,
  395. message,
  396. sizeof(struct GNUNET_MessageHeader),
  397. GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
  398. }
  399. else
  400. {
  401. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  402. "Delivering message of type %u and size %u to %s\n",
  403. ntohs (message->type),
  404. ntohs (message->size),
  405. GNUNET_i2s (&car->target));
  406. GSC_CLIENTS_deliver_message (&car->target,
  407. message,
  408. ntohs (message->size),
  409. GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
  410. GSC_CLIENTS_deliver_message (&car->target,
  411. message,
  412. sizeof(struct GNUNET_MessageHeader),
  413. GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
  414. GSC_SESSIONS_transmit (car, message, tc->priority);
  415. }
  416. return GNUNET_OK;
  417. }
  418. /**
  419. * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
  420. *
  421. * @param cls the `struct GSC_Client`
  422. * @param sm the `struct SendMessage`
  423. * @return #GNUNET_OK if @a sm is well-formed
  424. */
  425. static int
  426. check_client_send (void *cls, const struct SendMessage *sm)
  427. {
  428. return GNUNET_OK;
  429. }
  430. /**
  431. * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
  432. *
  433. * @param cls the `struct GSC_Client`
  434. * @param sm the `struct SendMessage`
  435. */
  436. static void
  437. handle_client_send (void *cls, const struct SendMessage *sm)
  438. {
  439. struct GSC_Client *c = cls;
  440. struct TokenizerContext tc;
  441. uint16_t msize;
  442. struct GNUNET_TIME_Relative delay;
  443. struct GNUNET_MessageStreamTokenizer *mst;
  444. msize = ntohs (sm->header.size) - sizeof(struct SendMessage);
  445. tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
  446. if (NULL == tc.car)
  447. {
  448. /* Must have been that we first approved the request, then got disconnected
  449. * (which triggered removal of the 'car') and now the client gives us a message
  450. * just *before* the client learns about the disconnect. Theoretically, we
  451. * might also now be *again* connected. So this can happen (but should be
  452. * rare). If it does happen, the message is discarded. */GNUNET_STATISTICS_update (GSC_stats,
  453. gettext_noop (
  454. "# messages discarded (session disconnected)"),
  455. 1,
  456. GNUNET_NO);
  457. GNUNET_SERVICE_client_continue (c->client);
  458. return;
  459. }
  460. delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
  461. tc.priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (sm->priority);
  462. if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
  463. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  464. "Client waited %s for transmission of %u bytes to `%s'\n",
  465. GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
  466. msize,
  467. GNUNET_i2s (&sm->peer));
  468. else
  469. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  470. "Client waited %s for transmission of %u bytes to `%s'\n",
  471. GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
  472. msize,
  473. GNUNET_i2s (&sm->peer));
  474. GNUNET_assert (
  475. GNUNET_YES ==
  476. GNUNET_CONTAINER_multipeermap_remove (c->requests, &sm->peer, tc.car));
  477. mst = GNUNET_MST_create (&tokenized_cb, &tc);
  478. GNUNET_MST_from_buffer (mst,
  479. (const char *) &sm[1],
  480. msize,
  481. GNUNET_YES,
  482. GNUNET_NO);
  483. GNUNET_MST_destroy (mst);
  484. GSC_SESSIONS_dequeue_request (tc.car);
  485. GNUNET_free (tc.car);
  486. GNUNET_SERVICE_client_continue (c->client);
  487. }
  488. /**
  489. * Free client request records.
  490. *
  491. * @param cls NULL
  492. * @param key identity of peer for which this is an active request
  493. * @param value the `struct GSC_ClientActiveRequest` to free
  494. * @return #GNUNET_YES (continue iteration)
  495. */
  496. static int
  497. destroy_active_client_request (void *cls,
  498. const struct GNUNET_PeerIdentity *key,
  499. void *value)
  500. {
  501. struct GSC_ClientActiveRequest *car = value;
  502. GNUNET_assert (
  503. GNUNET_YES ==
  504. GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
  505. &car->target,
  506. car));
  507. GSC_SESSIONS_dequeue_request (car);
  508. GNUNET_free (car);
  509. return GNUNET_YES;
  510. }
  511. /**
  512. * A client connected, set up.
  513. *
  514. * @param cls closure
  515. * @param client identification of the client
  516. * @param mq message queue to talk to @a client
  517. * @return our client handle
  518. */
  519. static void *
  520. client_connect_cb (void *cls,
  521. struct GNUNET_SERVICE_Client *client,
  522. struct GNUNET_MQ_Handle *mq)
  523. {
  524. struct GSC_Client *c;
  525. c = GNUNET_new (struct GSC_Client);
  526. c->client = client;
  527. c->mq = mq;
  528. c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
  529. GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
  530. return c;
  531. }
  532. /**
  533. * A client disconnected, clean up.
  534. *
  535. * @param cls closure
  536. * @param client identification of the client
  537. * @param app_ctx our `struct GST_Client` for @a client
  538. */
  539. static void
  540. client_disconnect_cb (void *cls,
  541. struct GNUNET_SERVICE_Client *client,
  542. void *app_ctx)
  543. {
  544. struct GSC_Client *c = app_ctx;
  545. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  546. "Client %p has disconnected from core service.\n",
  547. client);
  548. GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
  549. if (NULL != c->requests)
  550. {
  551. GNUNET_CONTAINER_multipeermap_iterate (c->requests,
  552. &destroy_active_client_request,
  553. NULL);
  554. GNUNET_CONTAINER_multipeermap_destroy (c->requests);
  555. }
  556. GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
  557. c->connectmap = NULL;
  558. if (NULL != c->types)
  559. {
  560. GSC_TYPEMAP_remove (c->types, c->tcnt);
  561. GNUNET_free (c->types);
  562. }
  563. GNUNET_free (c);
  564. /* recalculate 'all_client_options' */
  565. all_client_options = 0;
  566. for (c = client_head; NULL != c; c = c->next)
  567. all_client_options |= c->options;
  568. }
  569. /**
  570. * Notify a particular client about a change to existing connection to
  571. * one of our neighbours (check if the client is interested). Called
  572. * from #GSC_SESSIONS_notify_client_about_sessions().
  573. *
  574. * @param client client to notify
  575. * @param neighbour identity of the neighbour that changed status
  576. * @param tmap_old previous type map for the neighbour, NULL for connect
  577. * @param tmap_new updated type map for the neighbour, NULL for disconnect
  578. */
  579. void
  580. GSC_CLIENTS_notify_client_about_neighbour (
  581. struct GSC_Client *client,
  582. const struct GNUNET_PeerIdentity *neighbour,
  583. const struct GSC_TypeMap *tmap_old,
  584. const struct GSC_TypeMap *tmap_new)
  585. {
  586. struct GNUNET_MQ_Envelope *env;
  587. int old_match;
  588. int new_match;
  589. if (GNUNET_YES != client->got_init)
  590. return;
  591. old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
  592. new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
  593. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  594. "Notifying client about neighbour %s (%d/%d)\n",
  595. GNUNET_i2s (neighbour),
  596. old_match,
  597. new_match);
  598. if (old_match == new_match)
  599. {
  600. GNUNET_assert (
  601. old_match ==
  602. GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
  603. return; /* no change */
  604. }
  605. if (GNUNET_NO == old_match)
  606. {
  607. struct ConnectNotifyMessage *cnm;
  608. /* send connect */
  609. GNUNET_assert (
  610. GNUNET_NO ==
  611. GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
  612. GNUNET_assert (GNUNET_YES ==
  613. GNUNET_CONTAINER_multipeermap_put (
  614. client->connectmap,
  615. neighbour,
  616. NULL,
  617. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  618. env = GNUNET_MQ_msg (cnm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
  619. cnm->reserved = htonl (0);
  620. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  621. "Sending NOTIFY_CONNECT message about peer %s to client.\n",
  622. GNUNET_i2s (neighbour));
  623. cnm->peer = *neighbour;
  624. GNUNET_MQ_send (client->mq, env);
  625. }
  626. else
  627. {
  628. struct DisconnectNotifyMessage *dcm;
  629. /* send disconnect */
  630. GNUNET_assert (
  631. GNUNET_YES ==
  632. GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
  633. GNUNET_assert (GNUNET_YES ==
  634. GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
  635. neighbour,
  636. NULL));
  637. env = GNUNET_MQ_msg (dcm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
  638. dcm->reserved = htonl (0);
  639. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  640. "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
  641. GNUNET_i2s (neighbour));
  642. dcm->peer = *neighbour;
  643. GNUNET_MQ_send (client->mq, env);
  644. }
  645. }
  646. /**
  647. * Notify all clients about a change to existing session.
  648. * Called from SESSIONS whenever there is a change in sessions
  649. * or types processed by the respective peer.
  650. *
  651. * @param neighbour identity of the neighbour that changed status
  652. * @param tmap_old previous type map for the neighbour, NULL for connect
  653. * @param tmap_new updated type map for the neighbour, NULL for disconnect
  654. */
  655. void
  656. GSC_CLIENTS_notify_clients_about_neighbour (
  657. const struct GNUNET_PeerIdentity *neighbour,
  658. const struct GSC_TypeMap *tmap_old,
  659. const struct GSC_TypeMap *tmap_new)
  660. {
  661. struct GSC_Client *c;
  662. for (c = client_head; NULL != c; c = c->next)
  663. GSC_CLIENTS_notify_client_about_neighbour (c,
  664. neighbour,
  665. tmap_old,
  666. tmap_new);
  667. }
  668. /**
  669. * Deliver P2P message to interested clients. Caller must have checked
  670. * that the sending peer actually lists the given message type as one
  671. * of its types.
  672. *
  673. * @param sender peer who sent us the message
  674. * @param msg the message
  675. * @param msize number of bytes to transmit
  676. * @param options options for checking which clients should
  677. * receive the message
  678. */
  679. void
  680. GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
  681. const struct GNUNET_MessageHeader *msg,
  682. uint16_t msize,
  683. uint32_t options)
  684. {
  685. size_t size = msize + sizeof(struct NotifyTrafficMessage);
  686. if (size >= GNUNET_MAX_MESSAGE_SIZE)
  687. {
  688. GNUNET_break (0);
  689. return;
  690. }
  691. if (! ((0 != (all_client_options & options)) ||
  692. (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))))
  693. return; /* no client cares about this message notification */
  694. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  695. "Core service passes message from `%s' of type %u to client.\n",
  696. GNUNET_i2s (sender),
  697. (unsigned int) ntohs (msg->type));
  698. GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
  699. for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
  700. {
  701. struct GNUNET_MQ_Envelope *env;
  702. struct NotifyTrafficMessage *ntm;
  703. uint16_t mtype;
  704. unsigned int qlen;
  705. int tm;
  706. tm = type_match (ntohs (msg->type), c);
  707. if (! ((0 != (c->options & options)) ||
  708. ((0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
  709. (GNUNET_YES == tm))))
  710. continue; /* neither options nor type match permit the message */
  711. if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
  712. ((0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
  713. (GNUNET_YES == tm)))
  714. continue;
  715. if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
  716. (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)))
  717. continue;
  718. /* Drop messages if:
  719. 1) We are above the hard limit, or
  720. 2) We are above the soft limit, and a coin toss limited
  721. to the message size (giving larger messages a
  722. proportionally higher chance of being queued) falls
  723. below the threshold. The threshold is based on where
  724. we are between the soft and the hard limit, scaled
  725. to match the range of message sizes we usually encounter
  726. (i.e. up to 32k); so a 64k message has a 50% chance of
  727. being kept if we are just barely below the hard max,
  728. and a 99% chance of being kept if we are at the soft max.
  729. The reason is to make it more likely to drop control traffic
  730. (ACK, queries) which may be cumulative or highly redundant,
  731. and cheap to drop than data traffic. */qlen = GNUNET_MQ_get_length (c->mq);
  732. if ((qlen >= HARD_MAX_QUEUE) ||
  733. ((qlen > SOFT_MAX_QUEUE) &&
  734. ((GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  735. ntohs (msg->size))) <
  736. (qlen - SOFT_MAX_QUEUE) * 0x8000
  737. / (HARD_MAX_QUEUE - SOFT_MAX_QUEUE))))
  738. {
  739. char buf[1024];
  740. GNUNET_log (
  741. GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
  742. "Dropping decrypted message of type %u as client is too busy (queue full)\n",
  743. (unsigned int) ntohs (msg->type));
  744. GNUNET_snprintf (buf,
  745. sizeof(buf),
  746. gettext_noop (
  747. "# messages of type %u discarded (client busy)"),
  748. (unsigned int) ntohs (msg->type));
  749. GNUNET_STATISTICS_update (GSC_stats, buf, 1, GNUNET_NO);
  750. continue;
  751. }
  752. GNUNET_log (
  753. GNUNET_ERROR_TYPE_DEBUG,
  754. "Sending %u message with %u bytes to client interested in messages of type %u.\n",
  755. options,
  756. ntohs (msg->size),
  757. (unsigned int) ntohs (msg->type));
  758. if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND
  759. | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
  760. mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
  761. else
  762. mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
  763. env = GNUNET_MQ_msg_extra (ntm, msize, mtype);
  764. ntm->peer = *sender;
  765. GNUNET_memcpy (&ntm[1], msg, msize);
  766. GNUNET_assert (
  767. (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
  768. (GNUNET_YES != tm) ||
  769. (GNUNET_YES ==
  770. GNUNET_CONTAINER_multipeermap_contains (c->connectmap, sender)));
  771. GNUNET_MQ_send (c->mq, env);
  772. }
  773. }
  774. /**
  775. * Last task run during shutdown. Disconnects us from
  776. * the transport.
  777. *
  778. * @param cls NULL, unused
  779. */
  780. static void
  781. shutdown_task (void *cls)
  782. {
  783. struct GSC_Client *c;
  784. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n");
  785. while (NULL != (c = client_head))
  786. GNUNET_SERVICE_client_drop (c->client);
  787. GSC_SESSIONS_done ();
  788. GSC_KX_done ();
  789. GSC_TYPEMAP_done ();
  790. if (NULL != GSC_stats)
  791. {
  792. GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO);
  793. GSC_stats = NULL;
  794. }
  795. GSC_cfg = NULL;
  796. }
  797. /**
  798. * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
  799. * request type, the client does not have to have transmitted an INIT
  800. * request. All current peers are returned, regardless of which
  801. * message types they accept.
  802. *
  803. * @param cls client sending the iteration request
  804. * @param message iteration request message
  805. */
  806. static void
  807. handle_client_monitor_peers (void *cls,
  808. const struct GNUNET_MessageHeader *message)
  809. {
  810. struct GSC_Client *c = cls;
  811. GNUNET_SERVICE_client_continue (c->client);
  812. GSC_KX_handle_client_monitor_peers (c->mq);
  813. }
  814. /**
  815. * Initiate core service.
  816. *
  817. * @param cls closure
  818. * @param c configuration to use
  819. * @param service the initialized service
  820. */
  821. static void
  822. run (void *cls,
  823. const struct GNUNET_CONFIGURATION_Handle *c,
  824. struct GNUNET_SERVICE_Handle *service)
  825. {
  826. struct GNUNET_CRYPTO_EddsaPrivateKey pk;
  827. char *keyfile;
  828. GSC_cfg = c;
  829. if (GNUNET_OK !=
  830. GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
  831. "PEER",
  832. "PRIVATE_KEY",
  833. &keyfile))
  834. {
  835. GNUNET_log (
  836. GNUNET_ERROR_TYPE_ERROR,
  837. _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
  838. GNUNET_SCHEDULER_shutdown ();
  839. return;
  840. }
  841. GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg);
  842. GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
  843. GNUNET_SERVICE_suspend (service);
  844. GSC_TYPEMAP_init ();
  845. if (GNUNET_SYSERR ==
  846. GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
  847. GNUNET_YES,
  848. &pk))
  849. {
  850. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  851. "Failed to setup peer's private key\n");
  852. GNUNET_SCHEDULER_shutdown ();
  853. GNUNET_free (keyfile);
  854. return;
  855. }
  856. GNUNET_free (keyfile);
  857. if (GNUNET_OK != GSC_KX_init (&pk))
  858. {
  859. GNUNET_SCHEDULER_shutdown ();
  860. return;
  861. }
  862. GSC_SESSIONS_init ();
  863. GNUNET_SERVICE_resume (service);
  864. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  865. _ ("Core service of `%s' ready.\n"),
  866. GNUNET_i2s (&GSC_my_identity));
  867. }
  868. /**
  869. * Define "main" method using service macro.
  870. */
  871. GNUNET_SERVICE_MAIN (
  872. "core",
  873. GNUNET_SERVICE_OPTION_NONE,
  874. &run,
  875. &client_connect_cb,
  876. &client_disconnect_cb,
  877. NULL,
  878. GNUNET_MQ_hd_var_size (client_init,
  879. GNUNET_MESSAGE_TYPE_CORE_INIT,
  880. struct InitMessage,
  881. NULL),
  882. GNUNET_MQ_hd_fixed_size (client_monitor_peers,
  883. GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
  884. struct GNUNET_MessageHeader,
  885. NULL),
  886. GNUNET_MQ_hd_fixed_size (client_send_request,
  887. GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
  888. struct SendMessageRequest,
  889. NULL),
  890. GNUNET_MQ_hd_var_size (client_send,
  891. GNUNET_MESSAGE_TYPE_CORE_SEND,
  892. struct SendMessage,
  893. NULL),
  894. GNUNET_MQ_handler_end ());
  895. /* end of gnunet-service-core.c */