You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2828 lines
79 KiB

  1. /*
  2. * This file is part of GNUnet
  3. * Copyright (C) 2013 GNUnet e.V.
  4. *
  5. * GNUnet is free software: you can redistribute it and/or modify it
  6. * under the terms of the GNU Affero General Public License as published
  7. * by the Free Software Foundation, either version 3 of the License,
  8. * or (at your option) any later version.
  9. *
  10. * GNUnet is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. SPDX-License-Identifier: AGPL3.0-or-later
  18. */
  19. /**
  20. * @author Gabor X Toth
  21. *
  22. * @file
  23. * Social service; implements social interactions using the PSYC service.
  24. */
  25. #include <inttypes.h>
  26. #include <string.h>
  27. #include <gnunet/platform.h>
  28. #include <gnunet/gnunet_util_lib.h>
  29. #include "gnunet_psyc_service.h"
  30. #include "gnunet_psyc_util_lib.h"
  31. #include "gnunet_social_service.h"
  32. #include "social.h"
  33. #define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__)
  34. /**
  35. * Handle for an ego.
  36. */
  37. struct GNUNET_SOCIAL_Ego
  38. {
  39. struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
  40. struct GNUNET_HashCode pub_key_hash;
  41. char *name;
  42. };
  43. /**
  44. * Handle for a pseudonym of another user in the network.
  45. */
  46. struct GNUNET_SOCIAL_Nym
  47. {
  48. struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
  49. struct GNUNET_HashCode pub_key_hash;
  50. };
  51. /**
  52. * Handle for an application.
  53. */
  54. struct GNUNET_SOCIAL_App
  55. {
  56. /**
  57. * Configuration to use.
  58. */
  59. const struct GNUNET_CONFIGURATION_Handle *cfg;
  60. /**
  61. * Client connection to the service.
  62. */
  63. struct GNUNET_MQ_Handle *mq;
  64. /**
  65. * Message to send on connect.
  66. */
  67. struct GNUNET_MQ_Envelope *connect_env;
  68. /**
  69. * Time to wait until we try to reconnect on failure.
  70. */
  71. struct GNUNET_TIME_Relative reconnect_delay;
  72. /**
  73. * Task for reconnecting when the listener fails.
  74. */
  75. struct GNUNET_SCHEDULER_Task *reconnect_task;
  76. /**
  77. * Async operations.
  78. */
  79. struct GNUNET_OP_Handle *op;
  80. /**
  81. * Function called after disconnected from the service.
  82. */
  83. GNUNET_ContinuationCallback disconnect_cb;
  84. /**
  85. * Closure for @a disconnect_cb.
  86. */
  87. void *disconnect_cls;
  88. /**
  89. * Application ID.
  90. */
  91. char *id;
  92. /**
  93. * Hash map of all egos.
  94. * pub_key_hash -> struct GNUNET_SOCIAL_Ego *
  95. */
  96. struct GNUNET_CONTAINER_MultiHashMap *egos;
  97. GNUNET_SOCIAL_AppEgoCallback ego_cb;
  98. GNUNET_SOCIAL_AppHostPlaceCallback host_cb;
  99. GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb;
  100. GNUNET_SOCIAL_AppConnectedCallback connected_cb;
  101. void *cb_cls;
  102. };
  103. struct GNUNET_SOCIAL_HostConnection
  104. {
  105. struct GNUNET_SOCIAL_App *app;
  106. struct AppPlaceMessage plc_msg;
  107. };
  108. struct GNUNET_SOCIAL_GuestConnection
  109. {
  110. struct GNUNET_SOCIAL_App *app;
  111. struct AppPlaceMessage plc_msg;
  112. };
  113. /**
  114. * Handle for a place where social interactions happen.
  115. */
  116. struct GNUNET_SOCIAL_Place
  117. {
  118. /**
  119. * Configuration to use.
  120. */
  121. const struct GNUNET_CONFIGURATION_Handle *cfg;
  122. /**
  123. * Client connection to the service.
  124. */
  125. struct GNUNET_MQ_Handle *mq;
  126. /**
  127. * Message to send on connect.
  128. */
  129. struct GNUNET_MQ_Envelope *connect_env;
  130. /**
  131. * Time to wait until we try to reconnect on failure.
  132. */
  133. struct GNUNET_TIME_Relative reconnect_delay;
  134. /**
  135. * Task for reconnecting when the listener fails.
  136. */
  137. struct GNUNET_SCHEDULER_Task *reconnect_task;
  138. /**
  139. * Async operations.
  140. */
  141. struct GNUNET_OP_Handle *op;
  142. /**
  143. * Transmission handle.
  144. */
  145. struct GNUNET_PSYC_TransmitHandle *tmit;
  146. /**
  147. * Slicer for processing incoming messages.
  148. */
  149. struct GNUNET_PSYC_Slicer *slicer;
  150. // FIXME: do we need is_disconnecing like on the psyc and multicast APIs?
  151. /**
  152. * Function called after disconnected from the service.
  153. */
  154. GNUNET_ContinuationCallback disconnect_cb;
  155. /**
  156. * Closure for @a disconnect_cb.
  157. */
  158. void *disconnect_cls;
  159. /**
  160. * Public key of the place.
  161. */
  162. struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
  163. /**
  164. * Public key of the ego.
  165. */
  166. struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
  167. /**
  168. * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)?
  169. */
  170. uint8_t is_host;
  171. };
  172. /**
  173. * Host handle for a place that we entered.
  174. */
  175. struct GNUNET_SOCIAL_Host
  176. {
  177. struct GNUNET_SOCIAL_Place plc;
  178. /**
  179. * Slicer for processing incoming messages from guests.
  180. */
  181. struct GNUNET_PSYC_Slicer *slicer;
  182. GNUNET_SOCIAL_HostEnterCallback enter_cb;
  183. GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb;
  184. GNUNET_SOCIAL_FarewellCallback farewell_cb;
  185. /**
  186. * Closure for callbacks.
  187. */
  188. void *cb_cls;
  189. struct GNUNET_SOCIAL_Nym *notice_place_leave_nym;
  190. struct GNUNET_PSYC_Environment *notice_place_leave_env;
  191. };
  192. /**
  193. * Guest handle for place that we entered.
  194. */
  195. struct GNUNET_SOCIAL_Guest
  196. {
  197. struct GNUNET_SOCIAL_Place plc;
  198. GNUNET_SOCIAL_GuestEnterCallback enter_cb;
  199. GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb;
  200. /**
  201. * Closure for callbacks.
  202. */
  203. void *cb_cls;
  204. };
  205. /**
  206. * Hash map of all nyms.
  207. * pub_key_hash -> struct GNUNET_SOCIAL_Nym *
  208. */
  209. struct GNUNET_CONTAINER_MultiHashMap *nyms;
  210. /**
  211. * Handle for an announcement request.
  212. */
  213. struct GNUNET_SOCIAL_Announcement
  214. {
  215. };
  216. /**
  217. * A talk request.
  218. */
  219. struct GNUNET_SOCIAL_TalkRequest
  220. {
  221. };
  222. /**
  223. * A history lesson.
  224. */
  225. struct GNUNET_SOCIAL_HistoryRequest
  226. {
  227. /**
  228. * Place.
  229. */
  230. struct GNUNET_SOCIAL_Place *plc;
  231. /**
  232. * Operation ID.
  233. */
  234. uint64_t op_id;
  235. /**
  236. * Slicer for processing incoming messages.
  237. */
  238. struct GNUNET_PSYC_Slicer *slicer;
  239. /**
  240. * Function to call when the operation finished.
  241. */
  242. GNUNET_ResultCallback result_cb;
  243. /**
  244. * Closure for @a result_cb.
  245. */
  246. void *cls;
  247. };
  248. struct GNUNET_SOCIAL_LookHandle
  249. {
  250. /**
  251. * Place.
  252. */
  253. struct GNUNET_SOCIAL_Place *plc;
  254. /**
  255. * Operation ID.
  256. */
  257. uint64_t op_id;
  258. /**
  259. * State variable result callback.
  260. */
  261. GNUNET_PSYC_StateVarCallback var_cb;
  262. /**
  263. * Function to call when the operation finished.
  264. */
  265. GNUNET_ResultCallback result_cb;
  266. /**
  267. * Name of current modifier being received.
  268. */
  269. char *mod_name;
  270. /**
  271. * Size of current modifier value being received.
  272. */
  273. size_t mod_value_size;
  274. /**
  275. * Remaining size of current modifier value still to be received.
  276. */
  277. size_t mod_value_remaining;
  278. /**
  279. * Closure for @a result_cb.
  280. */
  281. void *cls;
  282. };
  283. struct ZoneAddPlaceHandle
  284. {
  285. GNUNET_ResultCallback result_cb;
  286. void *result_cls;
  287. };
  288. struct ZoneAddNymHandle
  289. {
  290. GNUNET_ResultCallback result_cb;
  291. void *result_cls;
  292. };
  293. /*** CLEANUP / DISCONNECT ***/
  294. static void
  295. host_cleanup (struct GNUNET_SOCIAL_Host *hst)
  296. {
  297. if (NULL != hst->slicer)
  298. {
  299. GNUNET_PSYC_slicer_destroy (hst->slicer);
  300. hst->slicer = NULL;
  301. }
  302. GNUNET_free (hst);
  303. }
  304. static void
  305. guest_cleanup (struct GNUNET_SOCIAL_Guest *gst)
  306. {
  307. GNUNET_free (gst);
  308. }
  309. static void
  310. place_cleanup (struct GNUNET_SOCIAL_Place *plc)
  311. {
  312. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  313. "cleaning up place %p\n",
  314. plc);
  315. if (NULL != plc->tmit)
  316. {
  317. GNUNET_PSYC_transmit_destroy (plc->tmit);
  318. plc->tmit = NULL;
  319. }
  320. if (NULL != plc->connect_env)
  321. {
  322. GNUNET_MQ_discard (plc->connect_env);
  323. plc->connect_env = NULL;
  324. }
  325. if (NULL != plc->mq)
  326. {
  327. GNUNET_MQ_destroy (plc->mq);
  328. plc->mq = NULL;
  329. }
  330. if (NULL != plc->disconnect_cb)
  331. {
  332. plc->disconnect_cb (plc->disconnect_cls);
  333. plc->disconnect_cb = NULL;
  334. }
  335. (GNUNET_YES == plc->is_host)
  336. ? host_cleanup ((struct GNUNET_SOCIAL_Host *) plc)
  337. : guest_cleanup ((struct GNUNET_SOCIAL_Guest *) plc);
  338. }
  339. static void
  340. place_disconnect (struct GNUNET_SOCIAL_Place *plc)
  341. {
  342. place_cleanup (plc);
  343. }
  344. /*** NYM ***/
  345. static struct GNUNET_SOCIAL_Nym *
  346. nym_get_or_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key)
  347. {
  348. struct GNUNET_SOCIAL_Nym *nym = NULL;
  349. struct GNUNET_HashCode pub_key_hash;
  350. if (NULL == pub_key)
  351. return NULL;
  352. GNUNET_CRYPTO_hash (pub_key, sizeof (*pub_key), &pub_key_hash);
  353. if (NULL == nyms)
  354. nyms = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
  355. else
  356. nym = GNUNET_CONTAINER_multihashmap_get (nyms, &pub_key_hash);
  357. if (NULL == nym)
  358. {
  359. nym = GNUNET_new (struct GNUNET_SOCIAL_Nym);
  360. nym->pub_key = *pub_key;
  361. nym->pub_key_hash = pub_key_hash;
  362. GNUNET_CONTAINER_multihashmap_put (nyms, &nym->pub_key_hash, nym,
  363. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  364. }
  365. return nym;
  366. }
  367. static void
  368. nym_destroy (struct GNUNET_SOCIAL_Nym *nym)
  369. {
  370. GNUNET_CONTAINER_multihashmap_remove (nyms, &nym->pub_key_hash, nym);
  371. GNUNET_free (nym);
  372. }
  373. /*** MESSAGE HANDLERS ***/
  374. /** _notice_place_leave from guests */
  375. static void
  376. host_recv_notice_place_leave_method (void *cls,
  377. const struct GNUNET_PSYC_MessageHeader *msg,
  378. const struct GNUNET_PSYC_MessageMethod *meth,
  379. uint64_t message_id,
  380. const char *method_name)
  381. {
  382. struct GNUNET_SOCIAL_Host *hst = cls;
  383. if (0 == memcmp (&(struct GNUNET_CRYPTO_EcdsaPublicKey) {},
  384. &msg->slave_pub_key, sizeof (msg->slave_pub_key)))
  385. return;
  386. struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&msg->slave_pub_key);
  387. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  388. "Host received method for message ID %" PRIu64 " from nym %s: %s\n",
  389. message_id, GNUNET_h2s (&nym->pub_key_hash), method_name);
  390. hst->notice_place_leave_nym = (struct GNUNET_SOCIAL_Nym *) nym;
  391. hst->notice_place_leave_env = GNUNET_PSYC_env_create ();
  392. char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key);
  393. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  394. "_notice_place_leave: got method from nym %s (%s).\n",
  395. GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str);
  396. GNUNET_free (str);
  397. }
  398. static void
  399. host_recv_notice_place_leave_modifier (void *cls,
  400. const struct GNUNET_PSYC_MessageHeader *msg,
  401. const struct GNUNET_MessageHeader *pmsg,
  402. uint64_t message_id,
  403. enum GNUNET_PSYC_Operator oper,
  404. const char *name,
  405. const void *value,
  406. uint16_t value_size,
  407. uint16_t full_value_size)
  408. {
  409. struct GNUNET_SOCIAL_Host *hst = cls;
  410. if (NULL == hst->notice_place_leave_env)
  411. return;
  412. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  413. "Host received modifier for _notice_place_leave message with ID %" PRIu64 ":\n"
  414. "%c%s: %.*s\n",
  415. message_id, oper, name, value_size, (const char *) value);
  416. /* skip _nym, it's added later in eom() */
  417. if (0 == memcmp (name, "_nym", sizeof ("_nym"))
  418. || 0 == memcmp (name, "_nym_", sizeof ("_nym_") - 1))
  419. return;
  420. GNUNET_PSYC_env_add (hst->notice_place_leave_env,
  421. GNUNET_PSYC_OP_SET, name, value, value_size);
  422. }
  423. static void
  424. host_recv_notice_place_leave_eom (void *cls,
  425. const struct GNUNET_PSYC_MessageHeader *msg,
  426. const struct GNUNET_MessageHeader *pmsg,
  427. uint64_t message_id,
  428. uint8_t is_cancelled)
  429. {
  430. struct GNUNET_SOCIAL_Host *hst = cls;
  431. if (NULL == hst->notice_place_leave_env)
  432. return;
  433. char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key);
  434. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  435. "_notice_place_leave: got EOM from nym %s (%s).\n",
  436. GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str);
  437. GNUNET_free (str);
  438. if (GNUNET_YES != is_cancelled)
  439. {
  440. if (NULL != hst->farewell_cb)
  441. hst->farewell_cb (hst->cb_cls, hst->notice_place_leave_nym,
  442. hst->notice_place_leave_env);
  443. /* announce leaving guest to place */
  444. GNUNET_PSYC_env_add (hst->notice_place_leave_env, GNUNET_PSYC_OP_SET,
  445. "_nym", hst->notice_place_leave_nym,
  446. sizeof (*hst->notice_place_leave_nym));
  447. GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave",
  448. hst->notice_place_leave_env,
  449. NULL, NULL, GNUNET_SOCIAL_ANNOUNCE_NONE);
  450. nym_destroy (hst->notice_place_leave_nym);
  451. }
  452. GNUNET_PSYC_env_destroy (hst->notice_place_leave_env);
  453. hst->notice_place_leave_env = NULL;
  454. }
  455. /*** PLACE ***/
  456. static int
  457. check_place_result (void *cls,
  458. const struct GNUNET_OperationResultMessage *res)
  459. {
  460. uint16_t size = ntohs (res->header.size);
  461. if (size < sizeof (*res))
  462. { /* Error, message too small. */
  463. GNUNET_break (0);
  464. return GNUNET_SYSERR;
  465. }
  466. return GNUNET_OK;
  467. }
  468. static void
  469. handle_place_result (void *cls,
  470. const struct GNUNET_OperationResultMessage *res)
  471. {
  472. struct GNUNET_SOCIAL_Place *plc = cls;
  473. uint16_t size = ntohs (res->header.size);
  474. uint16_t data_size = size - sizeof (*res);
  475. const char *data = (0 < data_size) ? (const char *) &res[1] : NULL;
  476. GNUNET_OP_result (plc->op, GNUNET_ntohll (res->op_id),
  477. GNUNET_ntohll (res->result_code),
  478. data, data_size, NULL);
  479. }
  480. static int
  481. check_app_result (void *cls,
  482. const struct GNUNET_OperationResultMessage *res)
  483. {
  484. uint16_t size = ntohs (res->header.size);
  485. if (size < sizeof (*res))
  486. { /* Error, message too small. */
  487. GNUNET_break (0);
  488. return GNUNET_SYSERR;
  489. }
  490. return GNUNET_OK;
  491. }
  492. static void
  493. handle_app_result (void *cls,
  494. const struct GNUNET_OperationResultMessage *res)
  495. {
  496. struct GNUNET_SOCIAL_App *app = cls;
  497. uint16_t size = ntohs (res->header.size);
  498. uint16_t data_size = size - sizeof (*res);
  499. const char *data = (0 < data_size) ? (const char *) &res[1] : NULL;
  500. GNUNET_OP_result (app->op, GNUNET_ntohll (res->op_id),
  501. GNUNET_ntohll (res->result_code),
  502. data, data_size, NULL);
  503. }
  504. static void
  505. op_recv_history_result (void *cls, int64_t result,
  506. const void *err_msg, uint16_t err_msg_size)
  507. {
  508. LOG (GNUNET_ERROR_TYPE_DEBUG,
  509. "Received history replay result: %" PRId64 ".\n", result);
  510. struct GNUNET_SOCIAL_HistoryRequest *hist = cls;
  511. if (NULL != hist->result_cb)
  512. hist->result_cb (hist->cls, result, err_msg, err_msg_size);
  513. GNUNET_free (hist);
  514. }
  515. static void
  516. op_recv_state_result (void *cls, int64_t result,
  517. const void *err_msg, uint16_t err_msg_size)
  518. {
  519. LOG (GNUNET_ERROR_TYPE_DEBUG,
  520. "Received state request result: %" PRId64 ".\n", result);
  521. struct GNUNET_SOCIAL_LookHandle *look = cls;
  522. if (NULL != look->result_cb)
  523. look->result_cb (look->cls, result, err_msg, err_msg_size);
  524. GNUNET_free (look);
  525. }
  526. static int
  527. check_place_history_result (void *cls,
  528. const struct GNUNET_OperationResultMessage *res)
  529. {
  530. struct GNUNET_PSYC_MessageHeader *
  531. pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res);
  532. uint16_t size = ntohs (res->header.size);
  533. if (NULL == pmsg || size < sizeof (*res) + sizeof (*pmsg))
  534. { /* Error, message too small. */
  535. GNUNET_break (0);
  536. return GNUNET_SYSERR;
  537. }
  538. return GNUNET_OK;
  539. }
  540. static void
  541. handle_place_history_result (void *cls,
  542. const struct GNUNET_OperationResultMessage *res)
  543. {
  544. struct GNUNET_SOCIAL_Place *plc = cls;
  545. struct GNUNET_PSYC_MessageHeader *
  546. pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res);
  547. LOG (GNUNET_ERROR_TYPE_DEBUG,
  548. "%p Received historic fragment for message #%" PRIu64 ".\n",
  549. plc, GNUNET_ntohll (pmsg->message_id));
  550. GNUNET_ResultCallback result_cb = NULL;
  551. struct GNUNET_SOCIAL_HistoryRequest *hist = NULL;
  552. if (GNUNET_YES != GNUNET_OP_get (plc->op,
  553. GNUNET_ntohll (res->op_id),
  554. &result_cb, (void *) &hist, NULL))
  555. { /* Operation not found. */
  556. LOG (GNUNET_ERROR_TYPE_WARNING,
  557. "%p Replay operation not found for historic fragment of message #%"
  558. PRIu64 ".\n",
  559. plc, GNUNET_ntohll (pmsg->message_id));
  560. return;
  561. }
  562. GNUNET_PSYC_slicer_message (hist->slicer,
  563. (const struct GNUNET_PSYC_MessageHeader *) pmsg);
  564. }
  565. static int
  566. check_place_state_result (void *cls,
  567. const struct GNUNET_OperationResultMessage *res)
  568. {
  569. const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res);
  570. if (NULL == mod)
  571. {
  572. GNUNET_break_op (0);
  573. LOG (GNUNET_ERROR_TYPE_WARNING,
  574. "Invalid modifier in state result\n");
  575. return GNUNET_SYSERR;
  576. }
  577. uint16_t size = ntohs (res->header.size);
  578. uint16_t mod_size = ntohs (mod->size);
  579. if (size - sizeof (*res) != mod_size)
  580. {
  581. GNUNET_break_op (0);
  582. LOG (GNUNET_ERROR_TYPE_WARNING,
  583. "Invalid modifier size in state result: %u - %u != %u\n",
  584. ntohs (res->header.size), sizeof (*res), mod_size);
  585. return GNUNET_SYSERR;
  586. }
  587. return GNUNET_OK;
  588. }
  589. static void
  590. handle_place_state_result (void *cls,
  591. const struct GNUNET_OperationResultMessage *res)
  592. {
  593. struct GNUNET_SOCIAL_Place *plc = cls;
  594. GNUNET_ResultCallback result_cb = NULL;
  595. struct GNUNET_SOCIAL_LookHandle *look = NULL;
  596. if (GNUNET_YES != GNUNET_OP_get (plc->op,
  597. GNUNET_ntohll (res->op_id),
  598. &result_cb, (void *) &look, NULL))
  599. { /* Operation not found. */
  600. return;
  601. }
  602. const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res);
  603. uint16_t mod_size = ntohs (mod->size);
  604. switch (ntohs (mod->type))
  605. {
  606. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
  607. {
  608. const struct GNUNET_PSYC_MessageModifier *
  609. pmod = (const struct GNUNET_PSYC_MessageModifier *) mod;
  610. const char *name = (const char *) &pmod[1];
  611. uint16_t name_size = ntohs (pmod->name_size);
  612. if (0 == name_size
  613. || mod_size - sizeof (*pmod) < name_size
  614. || '\0' != name[name_size - 1])
  615. {
  616. GNUNET_break_op (0);
  617. LOG (GNUNET_ERROR_TYPE_WARNING,
  618. "Invalid modifier name in state result\n");
  619. return;
  620. }
  621. look->mod_value_size = ntohs (pmod->value_size);
  622. look->var_cb (look->cls, mod, name, name + name_size,
  623. mod_size - sizeof (*mod) - name_size,
  624. look->mod_value_size);
  625. if (look->mod_value_size > mod_size - sizeof (*mod) - name_size)
  626. {
  627. look->mod_value_remaining = look->mod_value_size;
  628. look->mod_name = GNUNET_malloc (name_size);
  629. GNUNET_memcpy (look->mod_name, name, name_size);
  630. }
  631. break;
  632. }
  633. case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
  634. look->var_cb (look->cls, mod, look->mod_name, (const char *) &mod[1],
  635. mod_size - sizeof (*mod), look->mod_value_size);
  636. look->mod_value_remaining -= mod_size - sizeof (*mod);
  637. if (0 == look->mod_value_remaining)
  638. {
  639. GNUNET_free (look->mod_name);
  640. }
  641. break;
  642. }
  643. }
  644. static void
  645. handle_place_message_ack (void *cls,
  646. const struct GNUNET_MessageHeader *msg)
  647. {
  648. struct GNUNET_SOCIAL_Place *plc = cls;
  649. GNUNET_PSYC_transmit_got_ack (plc->tmit);
  650. }
  651. static int
  652. check_place_message (void *cls,
  653. const struct GNUNET_PSYC_MessageHeader *pmsg)
  654. {
  655. return GNUNET_OK;
  656. }
  657. static void
  658. handle_place_message (void *cls,
  659. const struct GNUNET_PSYC_MessageHeader *pmsg)
  660. {
  661. struct GNUNET_SOCIAL_Place *plc = cls;
  662. GNUNET_PSYC_slicer_message (plc->slicer, pmsg);
  663. }
  664. static int
  665. check_host_message (void *cls,
  666. const struct GNUNET_PSYC_MessageHeader *pmsg)
  667. {
  668. return GNUNET_OK;
  669. }
  670. static void
  671. handle_host_message (void *cls,
  672. const struct GNUNET_PSYC_MessageHeader *pmsg)
  673. {
  674. struct GNUNET_SOCIAL_Host *hst = cls;
  675. GNUNET_PSYC_slicer_message (hst->slicer, pmsg);
  676. GNUNET_PSYC_slicer_message (hst->plc.slicer, pmsg);
  677. }
  678. static void
  679. handle_host_enter_ack (void *cls,
  680. const struct HostEnterAck *hack)
  681. {
  682. struct GNUNET_SOCIAL_Host *hst = cls;
  683. hst->plc.pub_key = hack->place_pub_key;
  684. int32_t result = ntohl (hack->result_code);
  685. if (NULL != hst->enter_cb)
  686. hst->enter_cb (hst->cb_cls, result, &hack->place_pub_key,
  687. GNUNET_ntohll (hack->max_message_id));
  688. }
  689. static int
  690. check_host_enter_request (void *cls,
  691. const struct GNUNET_PSYC_JoinRequestMessage *req)
  692. {
  693. return GNUNET_OK;
  694. }
  695. static void
  696. handle_host_enter_request (void *cls,
  697. const struct GNUNET_PSYC_JoinRequestMessage *req)
  698. {
  699. struct GNUNET_SOCIAL_Host *hst = cls;
  700. if (NULL == hst->answer_door_cb)
  701. return;
  702. const char *method_name = NULL;
  703. struct GNUNET_PSYC_Environment *env = NULL;
  704. struct GNUNET_PSYC_MessageHeader *entry_pmsg = NULL;
  705. const void *data = NULL;
  706. uint16_t data_size = 0;
  707. char *str;
  708. const struct GNUNET_PSYC_Message *join_msg = NULL;
  709. do
  710. {
  711. if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size))
  712. {
  713. join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req);
  714. LOG (GNUNET_ERROR_TYPE_DEBUG,
  715. "Received join_msg of type %u and size %u.\n",
  716. ntohs (join_msg->header.type), ntohs (join_msg->header.size));
  717. env = GNUNET_PSYC_env_create ();
  718. entry_pmsg = GNUNET_PSYC_message_header_create_from_psyc (join_msg);
  719. if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_pmsg, &method_name, env,
  720. &data, &data_size))
  721. {
  722. GNUNET_break_op (0);
  723. str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_pub_key);
  724. LOG (GNUNET_ERROR_TYPE_WARNING,
  725. "Ignoring invalid entry request from nym %s.\n",
  726. str);
  727. GNUNET_free (str);
  728. break;
  729. }
  730. }
  731. struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_pub_key);
  732. hst->answer_door_cb (hst->cb_cls, nym, method_name, env,
  733. data, data_size);
  734. } while (0);
  735. if (NULL != env)
  736. GNUNET_PSYC_env_destroy (env);
  737. if (NULL != entry_pmsg)
  738. GNUNET_free (entry_pmsg);
  739. }
  740. static void
  741. handle_guest_enter_ack (void *cls,
  742. const struct GNUNET_PSYC_CountersResultMessage *cres)
  743. {
  744. struct GNUNET_SOCIAL_Guest *gst = cls;
  745. int32_t result = ntohl (cres->result_code);
  746. if (NULL != gst->enter_cb)
  747. gst->enter_cb (gst->cb_cls, result, &gst->plc.pub_key,
  748. GNUNET_ntohll (cres->max_message_id));
  749. }
  750. static int
  751. check_guest_enter_decision (void *cls,
  752. const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
  753. {
  754. return GNUNET_OK;
  755. }
  756. static void
  757. handle_guest_enter_decision (void *cls,
  758. const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
  759. {
  760. struct GNUNET_SOCIAL_Guest *gst = cls;
  761. struct GNUNET_PSYC_Message *pmsg = NULL;
  762. if (ntohs (dcsn->header.size) > sizeof (*dcsn))
  763. pmsg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (dcsn);
  764. if (NULL != gst->entry_dcsn_cb)
  765. gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg);
  766. }
  767. static int
  768. check_app_ego (void *cls,
  769. const struct AppEgoMessage *emsg)
  770. {
  771. return GNUNET_OK;
  772. }
  773. static void
  774. handle_app_ego (void *cls,
  775. const struct AppEgoMessage *emsg)
  776. {
  777. struct GNUNET_SOCIAL_App *app = cls;
  778. uint16_t name_size = ntohs (emsg->header.size) - sizeof (*emsg);
  779. struct GNUNET_HashCode ego_pub_hash;
  780. GNUNET_CRYPTO_hash (&emsg->ego_pub_key, sizeof (emsg->ego_pub_key),
  781. &ego_pub_hash);
  782. struct GNUNET_SOCIAL_Ego *
  783. ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash);
  784. if (NULL == ego)
  785. {
  786. ego = GNUNET_malloc (sizeof (*ego));
  787. ego->pub_key = emsg->ego_pub_key;
  788. ego->name = GNUNET_malloc (name_size);
  789. GNUNET_memcpy (ego->name, &emsg[1], name_size);
  790. }
  791. else
  792. {
  793. ego->name = GNUNET_realloc (ego->name, name_size);
  794. GNUNET_memcpy (ego->name, &emsg[1], name_size);
  795. }
  796. GNUNET_CONTAINER_multihashmap_put (app->egos, &ego_pub_hash, ego,
  797. GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
  798. if (NULL != app->ego_cb)
  799. app->ego_cb (app->cb_cls, ego, &ego->pub_key, ego->name);
  800. }
  801. static void
  802. handle_app_ego_end (void *cls,
  803. const struct GNUNET_MessageHeader *msg)
  804. {
  805. //struct GNUNET_SOCIAL_App *app = cls;
  806. }
  807. static int
  808. check_app_place (void *cls,
  809. const struct AppPlaceMessage *pmsg)
  810. {
  811. return GNUNET_OK;
  812. }
  813. static void
  814. handle_app_place (void *cls,
  815. const struct AppPlaceMessage *pmsg)
  816. {
  817. struct GNUNET_SOCIAL_App *app = cls;
  818. if ((GNUNET_YES == pmsg->is_host && NULL == app->host_cb)
  819. || (GNUNET_NO == pmsg->is_host && NULL == app->guest_cb))
  820. return;
  821. struct GNUNET_HashCode ego_pub_hash;
  822. GNUNET_CRYPTO_hash (&pmsg->ego_pub_key, sizeof (pmsg->ego_pub_key),
  823. &ego_pub_hash);
  824. struct GNUNET_SOCIAL_Ego *
  825. ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash);
  826. if (NULL == ego)
  827. {
  828. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failure to obtain ego %s.\n",
  829. GNUNET_h2s (&ego_pub_hash));
  830. GNUNET_break (0);
  831. return;
  832. }
  833. if (GNUNET_YES == pmsg->is_host)
  834. {
  835. if (NULL != app->host_cb) {
  836. struct GNUNET_SOCIAL_HostConnection *hconn = GNUNET_malloc (sizeof (*hconn));
  837. hconn->app = app;
  838. hconn->plc_msg = *pmsg;
  839. app->host_cb (app->cb_cls, hconn, ego, &pmsg->place_pub_key, pmsg->place_state);
  840. GNUNET_free (hconn);
  841. }
  842. }
  843. else if (NULL != app->guest_cb)
  844. {
  845. struct GNUNET_SOCIAL_GuestConnection *gconn = GNUNET_malloc (sizeof (*gconn));
  846. gconn->app = app;
  847. gconn->plc_msg = *pmsg;
  848. app->guest_cb (app->cb_cls, gconn, ego, &pmsg->place_pub_key, pmsg->place_state);
  849. GNUNET_free (gconn);
  850. }
  851. }
  852. static void
  853. handle_app_place_end (void *cls,
  854. const struct GNUNET_MessageHeader *msg)
  855. {
  856. struct GNUNET_SOCIAL_App *app = cls;
  857. if (NULL != app->connected_cb)
  858. app->connected_cb (app->cb_cls);
  859. }
  860. /**
  861. * Handler for a #GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK message received
  862. * from the social service.
  863. *
  864. * @param cls the place of type `struct GNUNET_SOCIAL_Place`
  865. * @param msg the message received from the service
  866. */
  867. static void
  868. handle_place_leave_ack (void *cls,
  869. const struct GNUNET_MessageHeader *msg)
  870. {
  871. struct GNUNET_SOCIAL_Place *plc = cls;
  872. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  873. "%s left place %p\n",
  874. plc->is_host ? "host" : "guest",
  875. plc);
  876. place_disconnect (plc);
  877. }
  878. /*** HOST ***/
  879. static void
  880. host_connect (struct GNUNET_SOCIAL_Host *hst);
  881. static void
  882. host_reconnect (void *cls)
  883. {
  884. host_connect (cls);
  885. }
  886. /**
  887. * Host client disconnected from service.
  888. *
  889. * Reconnect after backoff period.
  890. */
  891. static void
  892. host_disconnected (void *cls, enum GNUNET_MQ_Error error)
  893. {
  894. struct GNUNET_SOCIAL_Host *hst = cls;
  895. struct GNUNET_SOCIAL_Place *plc = &hst->plc;
  896. LOG (GNUNET_ERROR_TYPE_DEBUG,
  897. "Host client disconnected (%d), re-connecting\n",
  898. (int) error);
  899. if (NULL != plc->tmit)
  900. {
  901. GNUNET_PSYC_transmit_destroy (plc->tmit);
  902. plc->tmit = NULL;
  903. }
  904. if (NULL != plc->mq)
  905. {
  906. GNUNET_MQ_destroy (plc->mq);
  907. plc->mq = NULL;
  908. }
  909. plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay,
  910. host_reconnect,
  911. hst);
  912. plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay);
  913. }
  914. static void
  915. host_connect (struct GNUNET_SOCIAL_Host *hst)
  916. {
  917. struct GNUNET_SOCIAL_Place *plc = &hst->plc;
  918. struct GNUNET_MQ_MessageHandler handlers[] = {
  919. GNUNET_MQ_hd_fixed_size (host_enter_ack,
  920. GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK,
  921. struct HostEnterAck,
  922. hst),
  923. GNUNET_MQ_hd_fixed_size (place_leave_ack,
  924. GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK,
  925. struct GNUNET_MessageHeader,
  926. plc),
  927. GNUNET_MQ_hd_var_size (host_enter_request,
  928. GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
  929. struct GNUNET_PSYC_JoinRequestMessage,
  930. hst),
  931. GNUNET_MQ_hd_var_size (host_message,
  932. GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
  933. struct GNUNET_PSYC_MessageHeader,
  934. hst),
  935. GNUNET_MQ_hd_fixed_size (place_message_ack,
  936. GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
  937. struct GNUNET_MessageHeader,
  938. plc),
  939. GNUNET_MQ_hd_var_size (place_history_result,
  940. GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
  941. struct GNUNET_OperationResultMessage,
  942. plc),
  943. GNUNET_MQ_hd_var_size (place_state_result,
  944. GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
  945. struct GNUNET_OperationResultMessage,
  946. plc),
  947. GNUNET_MQ_hd_var_size (place_result,
  948. GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
  949. struct GNUNET_OperationResultMessage,
  950. plc),
  951. GNUNET_MQ_handler_end ()
  952. };
  953. plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social",
  954. handlers, host_disconnected, hst);
  955. GNUNET_assert (NULL != plc->mq);
  956. plc->tmit = GNUNET_PSYC_transmit_create (plc->mq);
  957. GNUNET_MQ_send_copy (plc->mq, plc->connect_env);
  958. }
  959. /**
  960. * Enter a place as host.
  961. *
  962. * A place is created upon first entering, and it is active until permanently
  963. * left using GNUNET_SOCIAL_host_leave().
  964. *
  965. * @param app
  966. * Application handle.
  967. * @param ego
  968. * Identity of the host.
  969. * @param policy
  970. * Policy specifying entry and history restrictions for the place.
  971. * @param slicer
  972. * Slicer to handle incoming messages.
  973. * @param enter_cb
  974. * Function called when the place is entered and ready to use.
  975. * @param answer_door_cb
  976. * Function to handle new nyms that want to enter.
  977. * @param farewell_cb
  978. * Function to handle departing nyms.
  979. * @param cls
  980. * Closure for the callbacks.
  981. *
  982. * @return Handle for the host. This handle contains the pubkey.
  983. */
  984. struct GNUNET_SOCIAL_Host *
  985. GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app,
  986. const struct GNUNET_SOCIAL_Ego *ego,
  987. enum GNUNET_PSYC_Policy policy,
  988. struct GNUNET_PSYC_Slicer *slicer,
  989. GNUNET_SOCIAL_HostEnterCallback enter_cb,
  990. GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
  991. GNUNET_SOCIAL_FarewellCallback farewell_cb,
  992. void *cls)
  993. {
  994. struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
  995. struct GNUNET_SOCIAL_Place *plc = &hst->plc;
  996. plc->cfg = app->cfg;
  997. plc->is_host = GNUNET_YES;
  998. plc->slicer = slicer;
  999. hst->enter_cb = enter_cb;
  1000. hst->answer_door_cb = answer_door_cb;
  1001. hst->farewell_cb = farewell_cb;
  1002. hst->cb_cls = cls;
  1003. plc->op = GNUNET_OP_create ();
  1004. hst->slicer = GNUNET_PSYC_slicer_create ();
  1005. GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL,
  1006. host_recv_notice_place_leave_method,
  1007. host_recv_notice_place_leave_modifier,
  1008. NULL, host_recv_notice_place_leave_eom, hst);
  1009. uint16_t app_id_size = strlen (app->id) + 1;
  1010. struct HostEnterRequest *hreq;
  1011. plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size,
  1012. GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
  1013. hreq->policy = policy;
  1014. hreq->ego_pub_key = ego->pub_key;
  1015. GNUNET_memcpy (&hreq[1], app->id, app_id_size);
  1016. host_connect (hst);
  1017. return hst;
  1018. }
  1019. /**
  1020. * Reconnect to an already entered place as host.
  1021. *
  1022. * @param hconn
  1023. * Host connection handle.
  1024. * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback()
  1025. * @param slicer
  1026. * Slicer to handle incoming messages.
  1027. * @param enter_cb
  1028. * Function called when the place is entered and ready to use.
  1029. * @param answer_door_cb
  1030. * Function to handle new nyms that want to enter.
  1031. * @param farewell_cb
  1032. * Function to handle departing nyms.
  1033. * @param cls
  1034. * Closure for the callbacks.
  1035. *
  1036. * @return Handle for the host.
  1037. */
  1038. struct GNUNET_SOCIAL_Host *
  1039. GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn,
  1040. struct GNUNET_PSYC_Slicer *slicer,
  1041. GNUNET_SOCIAL_HostEnterCallback enter_cb,
  1042. GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
  1043. GNUNET_SOCIAL_FarewellCallback farewell_cb,
  1044. void *cls)
  1045. {
  1046. struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
  1047. struct GNUNET_SOCIAL_Place *plc = &hst->plc;
  1048. hst->enter_cb = enter_cb;
  1049. hst->answer_door_cb = answer_door_cb;
  1050. hst->farewell_cb = farewell_cb;
  1051. hst->cb_cls = cls;
  1052. plc->cfg = hconn->app->cfg;
  1053. plc->is_host = GNUNET_YES;
  1054. plc->slicer = slicer;
  1055. plc->pub_key = hconn->plc_msg.place_pub_key;
  1056. plc->ego_pub_key = hconn->plc_msg.ego_pub_key;
  1057. plc->op = GNUNET_OP_create ();
  1058. hst->slicer = GNUNET_PSYC_slicer_create ();
  1059. GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL,
  1060. host_recv_notice_place_leave_method,
  1061. host_recv_notice_place_leave_modifier,
  1062. NULL, host_recv_notice_place_leave_eom, hst);
  1063. size_t app_id_size = strlen (hconn->app->id) + 1;
  1064. struct HostEnterRequest *hreq;
  1065. plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size,
  1066. GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
  1067. hreq->place_pub_key = hconn->plc_msg.place_pub_key;
  1068. hreq->ego_pub_key = hconn->plc_msg.ego_pub_key;
  1069. GNUNET_memcpy (&hreq[1], hconn->app->id, app_id_size);
  1070. host_connect (hst);
  1071. return hst;
  1072. }
  1073. /**
  1074. * Decision whether to admit @a nym into the place or refuse entry.
  1075. *
  1076. * @param hst
  1077. * Host of the place.
  1078. * @param nym
  1079. * Handle for the entity that wanted to enter.
  1080. * @param is_admitted
  1081. * #GNUNET_YES if @a nym is admitted,
  1082. * #GNUNET_NO if @a nym is refused entry,
  1083. * #GNUNET_SYSERR if we cannot answer the request.
  1084. * @param method_name
  1085. * Method name for the rejection message.
  1086. * @param env
  1087. * Environment containing variables for the message, or NULL.
  1088. * @param data
  1089. * Data for the rejection message to send back.
  1090. * @param data_size
  1091. * Number of bytes in @a data for method.
  1092. * @return #GNUNET_OK on success,
  1093. * #GNUNET_SYSERR if the message is too large.
  1094. */
  1095. int
  1096. GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
  1097. struct GNUNET_SOCIAL_Nym *nym,
  1098. int is_admitted,
  1099. const struct GNUNET_PSYC_Message *entry_resp)
  1100. {
  1101. struct GNUNET_SOCIAL_Place *plc = &hst->plc;
  1102. struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
  1103. uint16_t entry_resp_size
  1104. = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0;
  1105. if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size)
  1106. return GNUNET_SYSERR;
  1107. struct GNUNET_MQ_Envelope *
  1108. env = GNUNET_MQ_msg_extra (dcsn, entry_resp_size,
  1109. GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
  1110. dcsn->is_admitted = htonl (is_admitted);
  1111. dcsn->slave_pub_key = nym->pub_key;
  1112. if (0 < entry_resp_size)
  1113. GNUNET_memcpy (&dcsn[1], entry_resp, entry_resp_size);
  1114. GNUNET_MQ_send (plc->mq, env);
  1115. return GNUNET_OK;
  1116. }
  1117. /**
  1118. * Throw @a nym out of the place.
  1119. *
  1120. * The @a nym reference will remain valid until the
  1121. * #GNUNET_SOCIAL_FarewellCallback is invoked,
  1122. * which should be very soon after this call.
  1123. *
  1124. * @param host
  1125. * Host of the place.
  1126. * @param nym
  1127. * Handle for the entity to be ejected.
  1128. * @param env
  1129. * Environment for the message or NULL.
  1130. */
  1131. void
  1132. GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst,
  1133. const struct GNUNET_SOCIAL_Nym *nym,
  1134. struct GNUNET_PSYC_Environment *e)
  1135. {
  1136. struct GNUNET_PSYC_Environment *env = e;
  1137. if (NULL == env)
  1138. env = GNUNET_PSYC_env_create ();
  1139. GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
  1140. "_nym", &nym->pub_key, sizeof (nym->pub_key));
  1141. GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL,
  1142. GNUNET_SOCIAL_ANNOUNCE_NONE);
  1143. if (NULL == e)
  1144. GNUNET_PSYC_env_destroy (env);
  1145. }
  1146. /**
  1147. * Get the public key of @a ego.
  1148. *
  1149. * @param ego
  1150. * Ego.
  1151. *
  1152. * @return Public key of ego.
  1153. */
  1154. const struct GNUNET_CRYPTO_EcdsaPublicKey *
  1155. GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego)
  1156. {
  1157. return &ego->pub_key;
  1158. }
  1159. /**
  1160. * Get the hash of the public key of @a ego.
  1161. *
  1162. * @param ego
  1163. * Ego.
  1164. *
  1165. * @return Hash of the public key of @a ego.
  1166. */
  1167. const struct GNUNET_HashCode *
  1168. GNUNET_SOCIAL_ego_get_pub_key_hash (const struct GNUNET_SOCIAL_Ego *ego)
  1169. {
  1170. return &ego->pub_key_hash;
  1171. }
  1172. /**
  1173. * Get the name of @a ego.
  1174. *
  1175. * @param ego
  1176. * Ego.
  1177. *
  1178. * @return Public key of @a ego.
  1179. */
  1180. const char *
  1181. GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego)
  1182. {
  1183. return ego->name;
  1184. }
  1185. /**
  1186. * Get the public key of @a nym.
  1187. *
  1188. * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym().
  1189. *
  1190. * @param nym
  1191. * Pseudonym.
  1192. *
  1193. * @return Public key of @a nym.
  1194. */
  1195. const struct GNUNET_CRYPTO_EcdsaPublicKey *
  1196. GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym)
  1197. {
  1198. return &nym->pub_key;
  1199. }
  1200. /**
  1201. * Get the hash of the public key of @a nym.
  1202. *
  1203. * @param nym
  1204. * Pseudonym.
  1205. *
  1206. * @return Hash of the public key of @a nym.
  1207. */
  1208. const struct GNUNET_HashCode *
  1209. GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym)
  1210. {
  1211. return &nym->pub_key_hash;
  1212. }
  1213. /**
  1214. * Send a message to all nyms that are present in the place.
  1215. *
  1216. * This function is restricted to the host. Nyms can only send requests
  1217. * to the host who can decide to relay it to everyone in the place.
  1218. *
  1219. * @param host Host of the place.
  1220. * @param method_name Method to use for the announcement.
  1221. * @param env Environment containing variables for the message and operations
  1222. * on objects of the place. Can be NULL.
  1223. * @param notify Function to call to get the payload of the announcement.
  1224. * @param notify_cls Closure for @a notify.
  1225. * @param flags Flags for this announcement.
  1226. *
  1227. * @return NULL on error (announcement already in progress?).
  1228. */
  1229. struct GNUNET_SOCIAL_Announcement *
  1230. GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst,
  1231. const char *method_name,
  1232. const struct GNUNET_PSYC_Environment *env,
  1233. GNUNET_PSYC_TransmitNotifyData notify_data,
  1234. void *notify_data_cls,
  1235. enum GNUNET_SOCIAL_AnnounceFlags flags)
  1236. {
  1237. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1238. "PSYC_transmit_message for host, method: %s\n",
  1239. method_name);
  1240. if (GNUNET_OK ==
  1241. GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env,
  1242. NULL, notify_data, notify_data_cls, flags))
  1243. return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit;
  1244. else
  1245. return NULL;
  1246. }
  1247. /**
  1248. * Resume transmitting announcement.
  1249. *
  1250. * @param a
  1251. * The announcement to resume.
  1252. */
  1253. void
  1254. GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a)
  1255. {
  1256. GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a);
  1257. }
  1258. /**
  1259. * Cancel announcement.
  1260. *
  1261. * @param a
  1262. * The announcement to cancel.
  1263. */
  1264. void
  1265. GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a)
  1266. {
  1267. GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a);
  1268. }
  1269. /**
  1270. * Obtain handle for a hosted place.
  1271. *
  1272. * The returned handle can be used to access the place API.
  1273. *
  1274. * @param host Handle for the host.
  1275. *
  1276. * @return Handle for the hosted place, valid as long as @a host is valid.
  1277. */
  1278. struct GNUNET_SOCIAL_Place *
  1279. GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst)
  1280. {
  1281. return &hst->plc;
  1282. }
  1283. /**
  1284. * Disconnect from a home.
  1285. *
  1286. * Invalidates host handle.
  1287. *
  1288. * @param hst
  1289. * The host to disconnect.
  1290. */
  1291. void
  1292. GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst,
  1293. GNUNET_ContinuationCallback disconnect_cb,
  1294. void *cls)
  1295. {
  1296. struct GNUNET_SOCIAL_Place *plc = &hst->plc;
  1297. plc->disconnect_cb = disconnect_cb;
  1298. plc->disconnect_cls = cls;
  1299. place_disconnect (plc);
  1300. }
  1301. /**
  1302. * Stop hosting the home.
  1303. *
  1304. * Sends a _notice_place_closing announcement to the home.
  1305. * Invalidates host handle.
  1306. *
  1307. * @param hst
  1308. * The host leaving.
  1309. * @param env
  1310. * Environment for the message or NULL.
  1311. * _nym is set to @e nym regardless whether an @e env is provided.
  1312. * @param disconnect_cb
  1313. * Function called after the host left the place
  1314. * and disconnected from the social service.
  1315. * @param cls
  1316. * Closure for @a disconnect_cb.
  1317. */
  1318. void
  1319. GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
  1320. const struct GNUNET_PSYC_Environment *env,
  1321. GNUNET_ContinuationCallback disconnect_cb,
  1322. void *cls)
  1323. {
  1324. struct GNUNET_MQ_Envelope *envelope;
  1325. GNUNET_SOCIAL_host_announce (hst, "_notice_place_closing", env, NULL, NULL,
  1326. GNUNET_SOCIAL_ANNOUNCE_NONE);
  1327. hst->plc.disconnect_cb = disconnect_cb;
  1328. hst->plc.disconnect_cls = cls;
  1329. envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE);
  1330. GNUNET_MQ_send (hst->plc.mq,
  1331. envelope);
  1332. }
  1333. /*** GUEST ***/
  1334. static void
  1335. guest_connect (struct GNUNET_SOCIAL_Guest *gst);
  1336. static void
  1337. guest_reconnect (void *cls)
  1338. {
  1339. guest_connect (cls);
  1340. }
  1341. /**
  1342. * Guest client disconnected from service.
  1343. *
  1344. * Reconnect after backoff period.
  1345. */
  1346. static void
  1347. guest_disconnected (void *cls, enum GNUNET_MQ_Error error)
  1348. {
  1349. struct GNUNET_SOCIAL_Guest *gst = cls;
  1350. struct GNUNET_SOCIAL_Place *plc = &gst->plc;
  1351. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1352. "Guest client disconnected (%d), re-connecting\n",
  1353. (int) error);
  1354. if (NULL != plc->tmit)
  1355. {
  1356. GNUNET_PSYC_transmit_destroy (plc->tmit);
  1357. plc->tmit = NULL;
  1358. }
  1359. if (NULL != plc->mq)
  1360. {
  1361. GNUNET_MQ_destroy (plc->mq);
  1362. plc->mq = NULL;
  1363. }
  1364. plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay,
  1365. guest_reconnect,
  1366. gst);
  1367. plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay);
  1368. }
  1369. static void
  1370. guest_connect (struct GNUNET_SOCIAL_Guest *gst)
  1371. {
  1372. struct GNUNET_SOCIAL_Place *plc = &gst->plc;
  1373. struct GNUNET_MQ_MessageHandler handlers[] = {
  1374. GNUNET_MQ_hd_fixed_size (guest_enter_ack,
  1375. GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK,
  1376. struct GNUNET_PSYC_CountersResultMessage,
  1377. gst),
  1378. GNUNET_MQ_hd_fixed_size (place_leave_ack,
  1379. GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK,
  1380. struct GNUNET_MessageHeader,
  1381. plc),
  1382. GNUNET_MQ_hd_var_size (guest_enter_decision,
  1383. GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
  1384. struct GNUNET_PSYC_JoinDecisionMessage,
  1385. gst),
  1386. GNUNET_MQ_hd_var_size (place_message,
  1387. GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
  1388. struct GNUNET_PSYC_MessageHeader,
  1389. plc),
  1390. GNUNET_MQ_hd_fixed_size (place_message_ack,
  1391. GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
  1392. struct GNUNET_MessageHeader,
  1393. plc),
  1394. GNUNET_MQ_hd_var_size (place_history_result,
  1395. GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
  1396. struct GNUNET_OperationResultMessage,
  1397. plc),
  1398. GNUNET_MQ_hd_var_size (place_state_result,
  1399. GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
  1400. struct GNUNET_OperationResultMessage,
  1401. plc),
  1402. GNUNET_MQ_hd_var_size (place_result,
  1403. GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
  1404. struct GNUNET_OperationResultMessage,
  1405. plc),
  1406. GNUNET_MQ_handler_end ()
  1407. };
  1408. plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social",
  1409. handlers, guest_disconnected, gst);
  1410. GNUNET_assert (NULL != plc->mq);
  1411. plc->tmit = GNUNET_PSYC_transmit_create (plc->mq);
  1412. GNUNET_MQ_send_copy (plc->mq, plc->connect_env);
  1413. }
  1414. static struct GNUNET_MQ_Envelope *
  1415. guest_enter_request_create (const char *app_id,
  1416. const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
  1417. const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
  1418. const struct GNUNET_PeerIdentity *origin,
  1419. size_t relay_count,
  1420. const struct GNUNET_PeerIdentity *relays,
  1421. const struct GNUNET_PSYC_Message *join_msg)
  1422. {
  1423. uint16_t app_id_size = strlen (app_id) + 1;
  1424. uint16_t join_msg_size = ntohs (join_msg->header.size);
  1425. uint16_t relay_size = relay_count * sizeof (*relays);
  1426. struct GuestEnterRequest *greq;
  1427. struct GNUNET_MQ_Envelope *
  1428. env = GNUNET_MQ_msg_extra (greq, app_id_size + relay_size + join_msg_size,
  1429. GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
  1430. greq->place_pub_key = *place_pub_key;
  1431. greq->ego_pub_key = *ego_pub_key;
  1432. greq->origin = *origin;
  1433. greq->relay_count = htonl (relay_count);
  1434. char *p = (char *) &greq[1];
  1435. GNUNET_memcpy (p, app_id, app_id_size);
  1436. p += app_id_size;
  1437. if (0 < relay_size)
  1438. {
  1439. GNUNET_memcpy (p, relays, relay_size);
  1440. p += relay_size;
  1441. }
  1442. GNUNET_memcpy (p, join_msg, join_msg_size);
  1443. return env;
  1444. }
  1445. /**
  1446. * Request entry to a place as a guest.
  1447. *
  1448. * @param app
  1449. * Application handle.
  1450. * @param ego
  1451. * Identity of the guest.
  1452. * @param place_pub_key
  1453. * Public key of the place to enter.
  1454. * @param flags
  1455. * Flags for the entry.
  1456. * @param origin
  1457. * Peer identity of the origin of the underlying multicast group.
  1458. * @param relay_count
  1459. * Number of elements in the @a relays array.
  1460. * @param relays
  1461. * Relays for the underlying multicast group.
  1462. * @param method_name
  1463. * Method name for the message.
  1464. * @param env
  1465. * Environment containing variables for the message, or NULL.
  1466. * @param data
  1467. * Payload for the message to give to the enter callback.
  1468. * @param data_size
  1469. * Number of bytes in @a data.
  1470. * @param slicer
  1471. * Slicer to use for processing incoming requests from guests.
  1472. *
  1473. * @return NULL on errors, otherwise handle for the guest.
  1474. */
  1475. struct GNUNET_SOCIAL_Guest *
  1476. GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app,
  1477. const struct GNUNET_SOCIAL_Ego *ego,
  1478. const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
  1479. enum GNUNET_PSYC_SlaveJoinFlags flags,
  1480. const struct GNUNET_PeerIdentity *origin,
  1481. uint32_t relay_count,
  1482. const struct GNUNET_PeerIdentity *relays,
  1483. const struct GNUNET_PSYC_Message *entry_msg,
  1484. struct GNUNET_PSYC_Slicer *slicer,
  1485. GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
  1486. GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
  1487. void *cls)
  1488. {
  1489. struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
  1490. struct GNUNET_SOCIAL_Place *plc = &gst->plc;
  1491. plc->ego_pub_key = ego->pub_key;
  1492. plc->pub_key = *place_pub_key;
  1493. plc->cfg = app->cfg;
  1494. plc->is_host = GNUNET_NO;
  1495. plc->slicer = slicer;
  1496. plc->op = GNUNET_OP_create ();
  1497. plc->connect_env
  1498. = guest_enter_request_create (app->id, &ego->pub_key, &plc->pub_key,
  1499. origin, relay_count, relays, entry_msg);
  1500. gst->enter_cb = local_enter_cb;
  1501. gst->entry_dcsn_cb = entry_dcsn_cb;
  1502. gst->cb_cls = cls;
  1503. guest_connect (gst);
  1504. return gst;
  1505. }
  1506. /**
  1507. * Request entry to a place by name as a guest.
  1508. *
  1509. * @param app
  1510. * Application handle.
  1511. * @param ego
  1512. * Identity of the guest.
  1513. * @param gns_name
  1514. * GNS name of the place to enter. Either in the form of
  1515. * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to
  1516. * the 'PLACE' record of the empty label ("+") in the GNS zone with the
  1517. * nym's public key 'NYMPUBKEY', and can be used to request entry to a
  1518. * pseudonym's place directly.
  1519. * @param password
  1520. * Password to decrypt the record, or NULL for cleartext records.
  1521. * @param join_msg
  1522. * Entry request message or NULL.
  1523. * @param slicer
  1524. * Slicer to use for processing incoming requests from guests.
  1525. * @param local_enter_cb
  1526. * Called upon connection established to the social service.
  1527. * @param entry_decision_cb
  1528. * Called upon receiving entry decision.
  1529. *
  1530. * @return NULL on errors, otherwise handle for the guest.
  1531. */
  1532. struct GNUNET_SOCIAL_Guest *
  1533. GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app,
  1534. const struct GNUNET_SOCIAL_Ego *ego,
  1535. const char *gns_name,
  1536. const char *password,
  1537. const struct GNUNET_PSYC_Message *join_msg,
  1538. struct GNUNET_PSYC_Slicer *slicer,
  1539. GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
  1540. GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
  1541. void *cls)
  1542. {
  1543. struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
  1544. struct GNUNET_SOCIAL_Place *plc = &gst->plc;
  1545. if (NULL == password)
  1546. password = "";
  1547. uint16_t app_id_size = strlen (app->id) + 1;
  1548. uint16_t gns_name_size = strlen (gns_name) + 1;
  1549. uint16_t password_size = strlen (password) + 1;
  1550. uint16_t join_msg_size = 0;
  1551. if (NULL != join_msg)
  1552. join_msg_size = ntohs (join_msg->header.size);
  1553. struct GuestEnterByNameRequest *greq;
  1554. plc->connect_env
  1555. = GNUNET_MQ_msg_extra (greq, app_id_size + gns_name_size
  1556. + password_size + join_msg_size,
  1557. GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME);
  1558. greq->ego_pub_key = ego->pub_key;
  1559. char *p = (char *) &greq[1];
  1560. GNUNET_memcpy (p, app->id, app_id_size);
  1561. p += app_id_size;
  1562. GNUNET_memcpy (p, gns_name, gns_name_size);
  1563. p += gns_name_size;
  1564. GNUNET_memcpy (p, password, password_size);
  1565. p += password_size;
  1566. if (NULL != join_msg)
  1567. GNUNET_memcpy (p, join_msg, join_msg_size);
  1568. plc->ego_pub_key = ego->pub_key;
  1569. plc->cfg = app->cfg;
  1570. plc->is_host = GNUNET_NO;
  1571. plc->slicer = slicer;
  1572. plc->op = GNUNET_OP_create ();
  1573. gst->enter_cb = local_enter_cb;
  1574. gst->entry_dcsn_cb = entry_decision_cb;
  1575. gst->cb_cls = cls;
  1576. guest_connect (gst);
  1577. return gst;
  1578. }
  1579. struct ReconnectContext
  1580. {
  1581. struct GNUNET_SOCIAL_Guest *guest;
  1582. int *result;
  1583. int64_t *max_message_id;
  1584. GNUNET_SOCIAL_GuestEnterCallback enter_cb;
  1585. void *enter_cls;
  1586. };
  1587. static void
  1588. guest_enter_reconnect_cb (void *cls,
  1589. int result,
  1590. const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
  1591. uint64_t max_message_id)
  1592. {
  1593. struct ReconnectContext *reconnect_ctx = cls;
  1594. GNUNET_assert (NULL != reconnect_ctx);
  1595. reconnect_ctx->result = GNUNET_new (int);
  1596. *(reconnect_ctx->result) = result;
  1597. reconnect_ctx->max_message_id = GNUNET_new (int64_t);
  1598. *(reconnect_ctx->max_message_id) = max_message_id;
  1599. }
  1600. static void
  1601. guest_entry_dcsn_reconnect_cb (void *cls,
  1602. int is_admitted,
  1603. const struct GNUNET_PSYC_Message *entry_resp)
  1604. {
  1605. struct ReconnectContext *reconnect_ctx = cls;
  1606. struct GNUNET_SOCIAL_Guest *gst = reconnect_ctx->guest;
  1607. GNUNET_assert (NULL != reconnect_ctx);
  1608. GNUNET_assert (NULL != reconnect_ctx->result);
  1609. GNUNET_assert (NULL != reconnect_ctx->max_message_id);
  1610. if (GNUNET_YES != is_admitted)
  1611. {
  1612. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1613. "Guest was rejected after calling "
  1614. "GNUNET_SOCIAL_guest_enter_reconnect ()\n");
  1615. }
  1616. else if (NULL != reconnect_ctx->enter_cb)
  1617. {
  1618. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1619. "guest reconnected!\n");
  1620. reconnect_ctx->enter_cb (reconnect_ctx->enter_cls,
  1621. *(reconnect_ctx->result),
  1622. &gst->plc.pub_key,
  1623. *(reconnect_ctx->max_message_id));
  1624. }
  1625. GNUNET_free (reconnect_ctx->result);
  1626. GNUNET_free (reconnect_ctx->max_message_id);
  1627. GNUNET_free (reconnect_ctx);
  1628. }
  1629. /**
  1630. * Reconnect to an already entered place as guest.
  1631. *
  1632. * @param gconn
  1633. * Guest connection handle.
  1634. * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback()
  1635. * @param flags
  1636. * Flags for the entry.
  1637. * @param slicer
  1638. * Slicer to use for processing incoming requests from guests.
  1639. * @param enter_cb
  1640. * Called upon re-entering is complete.
  1641. * @param entry_decision_cb
  1642. * Called upon receiving entry decision.
  1643. *
  1644. * @return NULL on errors, otherwise handle for the guest.
  1645. */
  1646. struct GNUNET_SOCIAL_Guest *
  1647. GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn,
  1648. enum GNUNET_PSYC_SlaveJoinFlags flags,
  1649. struct GNUNET_PSYC_Slicer *slicer,
  1650. GNUNET_SOCIAL_GuestEnterCallback enter_cb,
  1651. void *cls)
  1652. {
  1653. struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
  1654. struct GNUNET_SOCIAL_Place *plc = &gst->plc;
  1655. struct ReconnectContext *reconnect_ctx;
  1656. uint16_t app_id_size = strlen (gconn->app->id) + 1;
  1657. struct GuestEnterRequest *greq;
  1658. plc->connect_env
  1659. = GNUNET_MQ_msg_extra (greq, app_id_size,
  1660. GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
  1661. greq->ego_pub_key = gconn->plc_msg.ego_pub_key;
  1662. greq->place_pub_key = gconn->plc_msg.place_pub_key;
  1663. greq->flags = htonl (flags);
  1664. GNUNET_memcpy (&greq[1], gconn->app->id, app_id_size);
  1665. plc->cfg = gconn->app->cfg;
  1666. plc->is_host = GNUNET_NO;
  1667. plc->slicer = slicer;
  1668. plc->pub_key = gconn->plc_msg.place_pub_key;
  1669. plc->ego_pub_key = gconn->plc_msg.ego_pub_key;
  1670. reconnect_ctx = GNUNET_new (struct ReconnectContext);
  1671. reconnect_ctx->guest = gst;
  1672. reconnect_ctx->enter_cb = enter_cb;
  1673. reconnect_ctx->enter_cls = cls;
  1674. plc->op = GNUNET_OP_create ();
  1675. gst->enter_cb = &guest_enter_reconnect_cb;
  1676. gst->entry_dcsn_cb = &guest_entry_dcsn_reconnect_cb;
  1677. gst->cb_cls = reconnect_ctx;
  1678. guest_connect (gst);
  1679. return gst;
  1680. }
  1681. /**
  1682. * Talk to the host of the place.
  1683. *
  1684. * @param place
  1685. * Place where we want to talk to the host.
  1686. * @param method_name
  1687. * Method to invoke on the host.
  1688. * @param env
  1689. * Environment containing variables for the message, or NULL.
  1690. * @param notify_data
  1691. * Function to use to get the payload for the method.
  1692. * @param notify_data_cls
  1693. * Closure for @a notify_data.
  1694. * @param flags
  1695. * Flags for the message being sent.
  1696. *
  1697. * @return NULL if we are already trying to talk to the host,
  1698. * otherwise handle to cancel the request.
  1699. */
  1700. struct GNUNET_SOCIAL_TalkRequest *
  1701. GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *gst,
  1702. const char *method_name,
  1703. const struct GNUNET_PSYC_Environment *env,
  1704. GNUNET_PSYC_TransmitNotifyData notify_data,
  1705. void *notify_data_cls,
  1706. enum GNUNET_SOCIAL_TalkFlags flags)
  1707. {
  1708. struct GNUNET_SOCIAL_Place *plc = &gst->plc;
  1709. GNUNET_assert (NULL != plc->tmit);
  1710. if (GNUNET_OK ==
  1711. GNUNET_PSYC_transmit_message (plc->tmit, method_name, env,
  1712. NULL, notify_data, notify_data_cls, flags))
  1713. return (struct GNUNET_SOCIAL_TalkRequest *) plc->tmit;
  1714. else
  1715. return NULL;
  1716. }
  1717. /**
  1718. * Resume talking to the host of the place.
  1719. *
  1720. * @param tr
  1721. * Talk request to resume.
  1722. */
  1723. void
  1724. GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr)
  1725. {
  1726. GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr);
  1727. }
  1728. /**
  1729. * Cancel talking to the host of the place.
  1730. *
  1731. * @param tr
  1732. * Talk request to cancel.
  1733. */
  1734. void
  1735. GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr)
  1736. {
  1737. GNUNET_PSYC_transmit_cancel ( (struct GNUNET_PSYC_TransmitHandle *) tr);
  1738. }
  1739. /**
  1740. * Disconnect from a place.
  1741. *
  1742. * Invalidates guest handle.
  1743. *
  1744. * @param gst
  1745. * The guest to disconnect.
  1746. */
  1747. void
  1748. GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst,
  1749. GNUNET_ContinuationCallback disconnect_cb,
  1750. void *cls)
  1751. {
  1752. struct GNUNET_SOCIAL_Place *plc = &gst->plc;
  1753. plc->disconnect_cb = disconnect_cb;
  1754. plc->disconnect_cls = cls;
  1755. place_disconnect (plc);
  1756. }
  1757. /**
  1758. * Leave a place temporarily or permanently.
  1759. *
  1760. * Notifies the owner of the place about leaving, and destroys the place handle.
  1761. *
  1762. * @param place
  1763. * Place to leave.
  1764. * @param keep_active
  1765. * Keep place active after last application disconnected.
  1766. * #GNUNET_YES or #GNUNET_NO
  1767. * @param env
  1768. * Optional environment for the leave message if @a keep_active
  1769. * is #GNUNET_NO. NULL if not needed.
  1770. * @param leave_cb
  1771. * Called upon disconnecting from the social service.
  1772. */
  1773. void
  1774. GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
  1775. struct GNUNET_PSYC_Environment *env,
  1776. GNUNET_ContinuationCallback disconnect_cb,
  1777. void *cls)
  1778. {
  1779. struct GNUNET_MQ_Envelope *envelope;
  1780. GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL,
  1781. GNUNET_SOCIAL_TALK_NONE);
  1782. gst->plc.disconnect_cb = disconnect_cb;
  1783. gst->plc.disconnect_cls = cls;
  1784. envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE);
  1785. GNUNET_MQ_send (gst->plc.mq,
  1786. envelope);
  1787. }
  1788. /**
  1789. * Obtain handle for a place entered as guest.
  1790. *
  1791. * The returned handle can be used to access the place API.
  1792. *
  1793. * @param guest Handle for the guest.
  1794. *
  1795. * @return Handle for the place, valid as long as @a guest is valid.
  1796. */
  1797. struct GNUNET_SOCIAL_Place *
  1798. GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst)
  1799. {
  1800. return &gst->plc;
  1801. }
  1802. /**
  1803. * Obtain the public key of a place.
  1804. *
  1805. * @param plc
  1806. * Place.
  1807. *
  1808. * @return Public key of the place.
  1809. */
  1810. const struct GNUNET_CRYPTO_EddsaPublicKey *
  1811. GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc)
  1812. {
  1813. return &plc->pub_key;
  1814. }
  1815. /**
  1816. * Set message processing @a flags for a @a method_prefix.
  1817. *
  1818. * @param plc
  1819. * Place.
  1820. * @param method_prefix
  1821. * Method prefix @a flags apply to.
  1822. * @param flags
  1823. * The flags that apply to a matching @a method_prefix.
  1824. */
  1825. void
  1826. GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc,
  1827. const char *method_prefix,
  1828. enum GNUNET_SOCIAL_MsgProcFlags flags)
  1829. {
  1830. GNUNET_assert (NULL != method_prefix);
  1831. struct MsgProcRequest *mpreq;
  1832. uint16_t method_size = strnlen (method_prefix,
  1833. GNUNET_MAX_MESSAGE_SIZE
  1834. - sizeof (*mpreq)) + 1;
  1835. GNUNET_assert ('\0' == method_prefix[method_size - 1]);
  1836. struct GNUNET_MQ_Envelope *
  1837. env = GNUNET_MQ_msg_extra (mpreq, method_size,
  1838. GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET);
  1839. mpreq->flags = htonl (flags);
  1840. GNUNET_memcpy (&mpreq[1], method_prefix, method_size);
  1841. GNUNET_MQ_send (plc->mq, env);
  1842. }
  1843. /**
  1844. * Clear all message processing flags previously set for this place.
  1845. */
  1846. void
  1847. GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc)
  1848. {
  1849. struct GNUNET_MessageHeader *req;
  1850. struct GNUNET_MQ_Envelope *
  1851. env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR);
  1852. GNUNET_MQ_send (plc->mq, env);
  1853. }
  1854. static struct GNUNET_SOCIAL_HistoryRequest *
  1855. place_history_replay (struct GNUNET_SOCIAL_Place *plc,
  1856. uint64_t start_message_id,
  1857. uint64_t end_message_id,
  1858. uint64_t message_limit,
  1859. const char *method_prefix,
  1860. uint32_t flags,
  1861. struct GNUNET_PSYC_Slicer *slicer,
  1862. GNUNET_ResultCallback result_cb,
  1863. void *cls)
  1864. {
  1865. struct GNUNET_PSYC_HistoryRequestMessage *req;
  1866. struct GNUNET_SOCIAL_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist));
  1867. hist->plc = plc;
  1868. hist->slicer = slicer;
  1869. hist->result_cb = result_cb;
  1870. hist->cls = cls;
  1871. hist->op_id = GNUNET_OP_add (plc->op, op_recv_history_result, hist, NULL);
  1872. GNUNET_assert (NULL != method_prefix);
  1873. uint16_t method_size = strnlen (method_prefix,
  1874. GNUNET_MAX_MESSAGE_SIZE
  1875. - sizeof (*req)) + 1;
  1876. GNUNET_assert ('\0' == method_prefix[method_size - 1]);
  1877. struct GNUNET_MQ_Envelope *
  1878. env = GNUNET_MQ_msg_extra (req, method_size,
  1879. GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY);
  1880. req->start_message_id = GNUNET_htonll (start_message_id);
  1881. req->end_message_id = GNUNET_htonll (end_message_id);
  1882. req->message_limit = GNUNET_htonll (message_limit);
  1883. req->flags = htonl (flags);
  1884. req->op_id = GNUNET_htonll (hist->op_id);
  1885. GNUNET_memcpy (&req[1], method_prefix, method_size);
  1886. GNUNET_MQ_send (plc->mq, env);
  1887. return hist;
  1888. }
  1889. /**
  1890. * Learn about the history of a place.
  1891. *
  1892. * Messages are returned through the @a slicer function
  1893. * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
  1894. *
  1895. * @param place
  1896. * Place we want to learn more about.
  1897. * @param start_message_id
  1898. * First historic message we are interested in.
  1899. * @param end_message_id
  1900. * Last historic message we are interested in (inclusive).
  1901. * @param method_prefix
  1902. * Only retrieve messages with this method prefix.
  1903. * @param flags
  1904. * OR'ed GNUNET_PSYC_HistoryReplayFlags
  1905. * @param slicer
  1906. * Slicer to use for retrieved messages.
  1907. * Can be the same as the slicer of the place.
  1908. * @param result_cb
  1909. * Function called after all messages retrieved.
  1910. * NULL if not needed.
  1911. * @param cls Closure for @a result_cb.
  1912. */
  1913. struct GNUNET_SOCIAL_HistoryRequest *
  1914. GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc,
  1915. uint64_t start_message_id,
  1916. uint64_t end_message_id,
  1917. const char *method_prefix,
  1918. uint32_t flags,
  1919. struct GNUNET_PSYC_Slicer *slicer,
  1920. GNUNET_ResultCallback result_cb,
  1921. void *cls)
  1922. {
  1923. return place_history_replay (plc, start_message_id, end_message_id, 0,
  1924. method_prefix, flags, slicer, result_cb, cls);
  1925. }
  1926. /**
  1927. * Learn about the history of a place.
  1928. *
  1929. * Sends messages through the slicer function of the place where
  1930. * start_message_id <= message_id <= end_message_id.
  1931. * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
  1932. *
  1933. * To get the latest message, use 0 for both the start and end message ID.
  1934. *
  1935. * @param place
  1936. * Place we want to learn more about.
  1937. * @param message_limit
  1938. * Maximum number of historic messages we are interested in.
  1939. * @param method_prefix
  1940. * Only retrieve messages with this method prefix.
  1941. * @param flags
  1942. * OR'ed GNUNET_PSYC_HistoryReplayFlags
  1943. * @param result_cb
  1944. * Function called after all messages retrieved.
  1945. * NULL if not needed.
  1946. * @param cls Closure for @a result_cb.
  1947. */
  1948. struct GNUNET_SOCIAL_HistoryRequest *
  1949. GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc,
  1950. uint64_t message_limit,
  1951. const char *method_prefix,
  1952. uint32_t flags,
  1953. struct GNUNET_PSYC_Slicer *slicer,
  1954. GNUNET_ResultCallback result_cb,
  1955. void *cls)
  1956. {
  1957. return place_history_replay (plc, 0, 0, message_limit, method_prefix, flags,
  1958. slicer, result_cb, cls);
  1959. }
  1960. /**
  1961. * Cancel learning about the history of a place.
  1962. *
  1963. * @param hist
  1964. * History lesson to cancel.
  1965. */
  1966. void
  1967. GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist)
  1968. {
  1969. GNUNET_OP_remove (hist->plc->op, hist->op_id);
  1970. GNUNET_free (hist);
  1971. }
  1972. /**
  1973. * Request matching state variables.
  1974. */
  1975. static struct GNUNET_SOCIAL_LookHandle *
  1976. place_state_get (struct GNUNET_SOCIAL_Place *plc,
  1977. uint16_t type, const char *name,
  1978. GNUNET_PSYC_StateVarCallback var_cb,
  1979. GNUNET_ResultCallback result_cb, void *cls)
  1980. {
  1981. struct GNUNET_PSYC_StateRequestMessage *req;
  1982. struct GNUNET_SOCIAL_LookHandle *look = GNUNET_malloc (sizeof (*look));
  1983. look->plc = plc;
  1984. look->var_cb = var_cb;
  1985. look->result_cb = result_cb;
  1986. look->cls = cls;
  1987. look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL);
  1988. GNUNET_assert (NULL != name);
  1989. size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE
  1990. - sizeof (*req)) + 1;
  1991. struct GNUNET_MQ_Envelope *
  1992. env = GNUNET_MQ_msg_extra (req, name_size, type);
  1993. req->op_id = GNUNET_htonll (look->op_id);
  1994. GNUNET_memcpy (&req[1], name, name_size);
  1995. GNUNET_MQ_send (plc->mq, env);
  1996. return look;
  1997. }
  1998. /**
  1999. * Look at a particular object in the place.
  2000. *
  2001. * The best matching object is returned (its name might be less specific than
  2002. * what was requested).
  2003. *
  2004. * @param place
  2005. * The place where to look.
  2006. * @param full_name
  2007. * Full name of the object.
  2008. * @param value_size
  2009. * Set to the size of the returned value.
  2010. *
  2011. * @return NULL if there is no such object at this place.
  2012. */
  2013. struct GNUNET_SOCIAL_LookHandle *
  2014. GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc,
  2015. const char *full_name,
  2016. GNUNET_PSYC_StateVarCallback var_cb,
  2017. GNUNET_ResultCallback result_cb,
  2018. void *cls)
  2019. {
  2020. return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET,
  2021. full_name, var_cb, result_cb, cls);
  2022. }
  2023. /**
  2024. * Look for objects in the place with a matching name prefix.
  2025. *
  2026. * @param place
  2027. * The place where to look.
  2028. * @param name_prefix
  2029. * Look at objects with names beginning with this value.
  2030. * @param var_cb
  2031. * Function to call for each object found.
  2032. * @param cls
  2033. * Closure for callback function.
  2034. *
  2035. * @return Handle that can be used to stop looking at objects.
  2036. */
  2037. struct GNUNET_SOCIAL_LookHandle *
  2038. GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc,
  2039. const char *name_prefix,
  2040. GNUNET_PSYC_StateVarCallback var_cb,
  2041. GNUNET_ResultCallback result_cb,
  2042. void *cls)
  2043. {
  2044. return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX,
  2045. name_prefix, var_cb, result_cb, cls);
  2046. }
  2047. /**
  2048. * Cancel a state request operation.
  2049. *
  2050. * @param sr
  2051. * Handle for the operation to cancel.
  2052. */
  2053. void
  2054. GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look)
  2055. {
  2056. GNUNET_OP_remove (look->plc->op, look->op_id);
  2057. GNUNET_free (look);
  2058. }
  2059. static void
  2060. op_recv_zone_add_place_result (void *cls, int64_t result,
  2061. const void *err_msg, uint16_t err_msg_size)
  2062. {
  2063. LOG (GNUNET_ERROR_TYPE_DEBUG,
  2064. "Received zone add place result: %" PRId64 ".\n", result);
  2065. struct ZoneAddPlaceHandle *add_plc = cls;
  2066. if (NULL != add_plc->result_cb)
  2067. add_plc->result_cb (add_plc->result_cls, result, err_msg, err_msg_size);
  2068. GNUNET_free (add_plc);
  2069. }
  2070. /**
  2071. * Advertise @e place in the GNS zone of @e ego.
  2072. *
  2073. * @param app
  2074. * Application handle.
  2075. * @param ego
  2076. * Ego.
  2077. * @param place_pub_key
  2078. * Public key of place to add.
  2079. * @param name
  2080. * The name for the PLACE record to put in the zone.
  2081. * @param password
  2082. * Password used to encrypt the record or NULL to keep it cleartext.
  2083. * @param relay_count
  2084. * Number of elements in the @a relays array.
  2085. * @param relays
  2086. * List of relays to put in the PLACE record to advertise
  2087. * as entry points to the place in addition to the origin.
  2088. * @param expiration_time
  2089. * Expiration time of the record, use 0 to remove the record.
  2090. * @param result_cb
  2091. * Function called with the result of the operation.
  2092. * @param result_cls
  2093. * Closure for @a result_cb
  2094. *
  2095. * @return #GNUNET_OK if the request was sent,
  2096. * #GNUNET_SYSERR on error, e.g. the name/password is too long.
  2097. */
  2098. int
  2099. GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app,
  2100. const struct GNUNET_SOCIAL_Ego *ego,
  2101. const char *name,
  2102. const char *password,
  2103. const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
  2104. const struct GNUNET_PeerIdentity *origin,
  2105. uint32_t relay_count,
  2106. const struct GNUNET_PeerIdentity *relays,
  2107. struct GNUNET_TIME_Absolute expiration_time,
  2108. GNUNET_ResultCallback result_cb,
  2109. void *result_cls)
  2110. {
  2111. struct ZoneAddPlaceRequest *preq;
  2112. size_t name_size = strlen (name) + 1;
  2113. size_t password_size = strlen (password) + 1;
  2114. size_t relay_size = relay_count * sizeof (*relays);
  2115. size_t payload_size = name_size + password_size + relay_size;
  2116. if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size)
  2117. return GNUNET_SYSERR;
  2118. struct GNUNET_MQ_Envelope *
  2119. env = GNUNET_MQ_msg_extra (preq, payload_size,
  2120. GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE);
  2121. preq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us);
  2122. preq->ego_pub_key = ego->pub_key;
  2123. preq->place_pub_key = *place_pub_key;
  2124. preq->origin = *origin;
  2125. preq->relay_count = htonl (relay_count);
  2126. char *p = (char *) &preq[1];
  2127. GNUNET_memcpy (p, name, name_size);
  2128. p += name_size;
  2129. GNUNET_memcpy (p, password, password_size);
  2130. p += password_size;
  2131. GNUNET_memcpy (p, relays, relay_size);
  2132. struct ZoneAddPlaceHandle * add_plc = GNUNET_malloc (sizeof (*add_plc));
  2133. add_plc->result_cb = result_cb;
  2134. add_plc->result_cls = result_cls;
  2135. preq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op,
  2136. op_recv_zone_add_place_result,
  2137. add_plc, NULL));
  2138. GNUNET_MQ_send (app->mq, env);
  2139. return GNUNET_OK;
  2140. }
  2141. static void
  2142. op_recv_zone_add_nym_result (void *cls, int64_t result,
  2143. const void *err_msg, uint16_t err_msg_size)
  2144. {
  2145. LOG (GNUNET_ERROR_TYPE_DEBUG,
  2146. "Received zone add nym result: %" PRId64 ".\n", result);
  2147. struct ZoneAddNymHandle *add_nym = cls;
  2148. if (NULL != add_nym->result_cb)
  2149. add_nym->result_cb (add_nym->result_cls, result, err_msg, err_msg_size);
  2150. GNUNET_free (add_nym);
  2151. }
  2152. /**
  2153. * Add nym to the GNS zone of @e ego.
  2154. *
  2155. * @param cfg
  2156. * Configuration.
  2157. * @param ego
  2158. * Ego.
  2159. * @param name
  2160. * The name for the PKEY record to put in the zone.
  2161. * @param nym_pub_key
  2162. * Public key of nym to add.
  2163. * @param expiration_time
  2164. * Expiration time of the record, use 0 to remove the record.
  2165. * @param result_cb
  2166. * Function called with the result of the operation.
  2167. * @param result_cls
  2168. * Closure for @a result_cb
  2169. *
  2170. * @return #GNUNET_OK if the request was sent,
  2171. * #GNUNET_SYSERR on error, e.g. the name is too long.
  2172. */
  2173. int
  2174. GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app,
  2175. const struct GNUNET_SOCIAL_Ego *ego,
  2176. const char *name,
  2177. const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key,
  2178. struct GNUNET_TIME_Absolute expiration_time,
  2179. GNUNET_ResultCallback result_cb,
  2180. void *result_cls)
  2181. {
  2182. struct ZoneAddNymRequest *nreq;
  2183. size_t name_size = strlen (name) + 1;
  2184. if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size)
  2185. return GNUNET_SYSERR;
  2186. struct GNUNET_MQ_Envelope *
  2187. env = GNUNET_MQ_msg_extra (nreq, name_size,
  2188. GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM);
  2189. nreq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us);
  2190. nreq->ego_pub_key = ego->pub_key;
  2191. nreq->nym_pub_key = *nym_pub_key;
  2192. GNUNET_memcpy (&nreq[1], name, name_size);
  2193. struct ZoneAddNymHandle *add_nym = GNUNET_malloc (sizeof (*add_nym));
  2194. add_nym->result_cb = result_cb;
  2195. add_nym->result_cls = result_cls;
  2196. nreq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op,
  2197. op_recv_zone_add_nym_result,
  2198. add_nym, NULL));
  2199. GNUNET_MQ_send (app->mq, env);
  2200. return GNUNET_OK;
  2201. }
  2202. /*** APP ***/
  2203. static void
  2204. app_connect (struct GNUNET_SOCIAL_App *app);
  2205. static void
  2206. app_reconnect (void *cls)
  2207. {
  2208. app_connect (cls);
  2209. }
  2210. /**
  2211. * App client disconnected from service.
  2212. *
  2213. * Reconnect after backoff period.
  2214. */
  2215. static void
  2216. app_disconnected (void *cls, enum GNUNET_MQ_Error error)
  2217. {
  2218. struct GNUNET_SOCIAL_App *app = cls;
  2219. LOG (GNUNET_ERROR_TYPE_DEBUG,
  2220. "App client disconnected (%d), re-connecting\n",
  2221. (int) error);
  2222. if (NULL != app->mq)
  2223. {
  2224. GNUNET_MQ_destroy (app->mq);
  2225. app->mq = NULL;
  2226. }
  2227. app->reconnect_task = GNUNET_SCHEDULER_add_delayed (app->reconnect_delay,
  2228. app_reconnect,
  2229. app);
  2230. app->reconnect_delay = GNUNET_TIME_STD_BACKOFF (app->reconnect_delay);
  2231. }
  2232. static void
  2233. app_connect (struct GNUNET_SOCIAL_App *app)
  2234. {
  2235. struct GNUNET_MQ_MessageHandler handlers[] = {
  2236. GNUNET_MQ_hd_var_size (app_ego,
  2237. GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO,
  2238. struct AppEgoMessage,
  2239. app),
  2240. GNUNET_MQ_hd_fixed_size (app_ego_end,
  2241. GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END,
  2242. struct GNUNET_MessageHeader,
  2243. app),
  2244. GNUNET_MQ_hd_var_size (app_place,
  2245. GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE,
  2246. struct AppPlaceMessage,
  2247. app),
  2248. GNUNET_MQ_hd_fixed_size (app_place_end,
  2249. GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END,
  2250. struct GNUNET_MessageHeader,
  2251. app),
  2252. GNUNET_MQ_hd_var_size (app_result,
  2253. GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
  2254. struct GNUNET_OperationResultMessage,
  2255. app),
  2256. GNUNET_MQ_handler_end ()
  2257. };
  2258. app->mq = GNUNET_CLIENT_connect (app->cfg, "social",
  2259. handlers, app_disconnected, app);
  2260. GNUNET_assert (NULL != app->mq);
  2261. GNUNET_MQ_send_copy (app->mq, app->connect_env);
  2262. }
  2263. /**
  2264. * Connect application to the social service.
  2265. *
  2266. * The @host_place_cb and @guest_place_cb functions are
  2267. * initially called for each entered places,
  2268. * then later each time a new place is entered with the current application ID.
  2269. *
  2270. * @param cfg
  2271. * Configuration.
  2272. * @param id
  2273. * Application ID.
  2274. * @param ego_cb
  2275. * Function to notify about an available ego.
  2276. * @param host_cb
  2277. * Function to notify about a place entered as host.
  2278. * @param guest_cb
  2279. * Function to notify about a place entered as guest.
  2280. * @param cls
  2281. * Closure for the callbacks.
  2282. *
  2283. * @return Handle that can be used to stop listening.
  2284. */
  2285. struct GNUNET_SOCIAL_App *
  2286. GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
  2287. const char *id,
  2288. GNUNET_SOCIAL_AppEgoCallback ego_cb,
  2289. GNUNET_SOCIAL_AppHostPlaceCallback host_cb,
  2290. GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb,
  2291. GNUNET_SOCIAL_AppConnectedCallback connected_cb,
  2292. void *cls)
  2293. {
  2294. uint16_t app_id_size = strnlen (id, GNUNET_SOCIAL_APP_MAX_ID_SIZE);
  2295. if (GNUNET_SOCIAL_APP_MAX_ID_SIZE == app_id_size)
  2296. return NULL;
  2297. app_id_size++;
  2298. struct GNUNET_SOCIAL_App *app = GNUNET_malloc (sizeof *app);
  2299. app->cfg = cfg;
  2300. app->ego_cb = ego_cb;
  2301. app->host_cb = host_cb;
  2302. app->guest_cb = guest_cb;
  2303. app->connected_cb = connected_cb;
  2304. app->cb_cls = cls;
  2305. app->egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
  2306. app->op = GNUNET_OP_create ();
  2307. app->id = GNUNET_malloc (app_id_size);
  2308. GNUNET_memcpy (app->id, id, app_id_size);
  2309. struct AppConnectRequest *creq;
  2310. app->connect_env = GNUNET_MQ_msg_extra (creq, app_id_size,
  2311. GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT);
  2312. GNUNET_memcpy (&creq[1], app->id, app_id_size);
  2313. app_connect (app);
  2314. return app;
  2315. }
  2316. static void
  2317. app_cleanup (struct GNUNET_SOCIAL_App *app)
  2318. {
  2319. if (NULL != app->mq)
  2320. {
  2321. GNUNET_MQ_destroy (app->mq);
  2322. app->mq = NULL;
  2323. }
  2324. if (NULL != app->disconnect_cb)
  2325. {
  2326. app->disconnect_cb (app->disconnect_cls);
  2327. app->disconnect_cb = NULL;
  2328. }
  2329. GNUNET_free (app);
  2330. }
  2331. /**
  2332. * Disconnect application.
  2333. *
  2334. * @param app
  2335. * Application handle.
  2336. * @param disconnect_cb
  2337. * Disconnect callback.
  2338. * @param disconnect_cls
  2339. * Disconnect closure.
  2340. */
  2341. void
  2342. GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app,
  2343. GNUNET_ContinuationCallback disconnect_cb,
  2344. void *disconnect_cls)
  2345. {
  2346. if (NULL == app) return;
  2347. app->disconnect_cb = disconnect_cb;
  2348. app->disconnect_cls = disconnect_cls;
  2349. if (NULL != app->mq)
  2350. {
  2351. struct GNUNET_MQ_Envelope *env = GNUNET_MQ_get_last_envelope (app->mq);
  2352. if (NULL != env)
  2353. {
  2354. GNUNET_MQ_notify_sent (env, (GNUNET_SCHEDULER_TaskCallback) app_cleanup, app);
  2355. }
  2356. else
  2357. {
  2358. app_cleanup (app);
  2359. }
  2360. }
  2361. else
  2362. {
  2363. app_cleanup (app);
  2364. }
  2365. }
  2366. /**
  2367. * Detach application from a place.
  2368. *
  2369. * Removes the place from the entered places list for this application.
  2370. * Note: this does not disconnect from the place.
  2371. *
  2372. * @see GNUNET_SOCIAL_host_disconnect() and GNUNET_SOCIAL_guest_disconnect()
  2373. *
  2374. * @param app
  2375. * Application.
  2376. * @param plc
  2377. * Place.
  2378. */
  2379. void
  2380. GNUNET_SOCIAL_app_detach (struct GNUNET_SOCIAL_App *app,
  2381. struct GNUNET_SOCIAL_Place *plc)
  2382. {
  2383. struct AppDetachRequest *dreq;
  2384. struct GNUNET_MQ_Envelope *
  2385. env = GNUNET_MQ_msg (dreq, GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH);
  2386. dreq->place_pub_key = plc->pub_key;
  2387. dreq->ego_pub_key = plc->ego_pub_key;
  2388. GNUNET_MQ_send (app->mq, env);
  2389. }
  2390. /* end of social_api.c */