gnunet-social.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2016 GNUnet e.V.
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. /**
  18. * CLI tool to interact with the social service.
  19. *
  20. * @author Gabor X Toth
  21. */
  22. #include <inttypes.h>
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_social_service.h"
  26. #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
  27. #define DATA2ARG(data) data, sizeof (data)
  28. /* operations corresponding to API calls */
  29. /** --status */
  30. static int op_status;
  31. /** --host-enter */
  32. static int op_host_enter;
  33. /** --host-reconnect */
  34. static int op_host_reconnect;
  35. /** --host-leave */
  36. static int op_host_leave;
  37. /** --host-announce */
  38. static int op_host_announce;
  39. /** --host-assign */
  40. static int op_host_assign;
  41. /** --guest-enter */
  42. static int op_guest_enter;
  43. /** --guest-reconnect */
  44. static int op_guest_reconnect;
  45. /** --guest-leave */
  46. static int op_guest_leave;
  47. /** --guest-talk */
  48. static int op_guest_talk;
  49. /** --replay */
  50. static int op_replay;
  51. /** --replay-latest */
  52. static int op_replay_latest;
  53. /** --look-at */
  54. static int op_look_at;
  55. /** --look-for */
  56. static int op_look_for;
  57. /* options */
  58. /** --app */
  59. static char *opt_app = "cli";
  60. /** --place */
  61. static char *opt_place;
  62. /** --ego */
  63. static char *opt_ego;
  64. /** --gns */
  65. static char *opt_gns;
  66. /** --peer */
  67. static char *opt_peer;
  68. /** --follow */
  69. static int opt_follow;
  70. /** --welcome */
  71. static int opt_welcome;
  72. /** --deny */
  73. static int opt_deny;
  74. /** --method */
  75. static char *opt_method;
  76. /** --data */
  77. // FIXME: should come from STDIN
  78. static char *opt_data;
  79. /** --name */
  80. static char *opt_name;
  81. /** --start */
  82. static unsigned long long opt_start;
  83. /** --until */
  84. static unsigned long long opt_until;
  85. /** --limit */
  86. static unsigned long long opt_limit;
  87. /* global vars */
  88. /** exit code */
  89. static int ret = 1;
  90. /** are we waiting for service to close our connection */
  91. static char is_disconnecting = 0;
  92. /** Task handle for timeout termination. */
  93. struct GNUNET_SCHEDULER_Task *timeout_task;
  94. const struct GNUNET_CONFIGURATION_Handle *cfg;
  95. struct GNUNET_PeerIdentity peer, this_peer;
  96. struct GNUNET_SOCIAL_App *app;
  97. /** public key of connected place */
  98. struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
  99. struct GNUNET_PSYC_Slicer *slicer;
  100. struct GNUNET_SOCIAL_Ego *ego;
  101. struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
  102. struct GNUNET_SOCIAL_Host *hst;
  103. struct GNUNET_SOCIAL_Guest *gst;
  104. struct GNUNET_SOCIAL_Place *plc;
  105. const char *method_received;
  106. /* DISCONNECT */
  107. /**
  108. * Callback called after the host or guest place disconnected.
  109. */
  110. static void
  111. disconnected (void *cls)
  112. {
  113. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnected()\n");
  114. GNUNET_SCHEDULER_shutdown ();
  115. }
  116. /**
  117. * Callback called after the application disconnected.
  118. */
  119. static void
  120. app_disconnected (void *cls)
  121. {
  122. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "app_disconnected()\n");
  123. if (hst || gst)
  124. {
  125. if (hst)
  126. {
  127. GNUNET_SOCIAL_host_disconnect (hst, disconnected, NULL);
  128. }
  129. if (gst)
  130. {
  131. GNUNET_SOCIAL_guest_disconnect (gst, disconnected, NULL);
  132. }
  133. }
  134. else
  135. {
  136. GNUNET_SCHEDULER_shutdown ();
  137. }
  138. }
  139. /**
  140. * Disconnect from connected GNUnet services.
  141. */
  142. static void
  143. disconnect ()
  144. {
  145. // handle that we get called several times from several places, but should we?
  146. if (!is_disconnecting++) {
  147. GNUNET_SOCIAL_app_disconnect (app, app_disconnected, NULL);
  148. }
  149. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnect() called for the #%d time\n", is_disconnecting);
  150. }
  151. static void
  152. scheduler_shutdown (void *cls)
  153. {
  154. disconnect ();
  155. }
  156. /**
  157. * Callback called when the program failed to finish the requested operation in time.
  158. */
  159. static void
  160. timeout (void *cls)
  161. {
  162. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "timeout()\n");
  163. disconnect ();
  164. }
  165. static void
  166. schedule_success (void *cls)
  167. {
  168. ret = 0;
  169. disconnect ();
  170. }
  171. static void
  172. schedule_fail (void *cls)
  173. {
  174. disconnect ();
  175. }
  176. /**
  177. * Schedule exit with success result.
  178. */
  179. static void
  180. exit_success ()
  181. {
  182. if (timeout_task != NULL)
  183. {
  184. GNUNET_SCHEDULER_cancel (timeout_task);
  185. timeout_task = NULL;
  186. }
  187. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_success, NULL);
  188. }
  189. /**
  190. * Schedule exit with failure result.
  191. */
  192. static void
  193. exit_fail ()
  194. {
  195. if (timeout_task != NULL)
  196. {
  197. GNUNET_SCHEDULER_cancel (timeout_task);
  198. timeout_task = NULL;
  199. }
  200. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_fail, NULL);
  201. }
  202. /* LEAVE */
  203. /**
  204. * Callback notifying about the host has left and stopped hosting the place.
  205. *
  206. * This also indicates the end of the connection to the service.
  207. */
  208. static void
  209. host_left ()
  210. {
  211. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  212. "The host has left the place.\n");
  213. exit_success ();
  214. }
  215. /**
  216. * Leave a place permanently and stop hosting a place.
  217. */
  218. static void
  219. host_leave ()
  220. {
  221. GNUNET_SOCIAL_host_leave (hst, NULL, host_left, NULL);
  222. hst = NULL;
  223. plc = NULL;
  224. }
  225. /**
  226. * Callback notifying about the guest has left the place.
  227. *
  228. * This also indicates the end of the connection to the service.
  229. */
  230. static void
  231. guest_left (void *cls)
  232. {
  233. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  234. "Guest has left the place.\n");
  235. }
  236. /**
  237. * Leave a place permanently as guest.
  238. */
  239. static void
  240. guest_leave ()
  241. {
  242. struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
  243. // FIXME: wrong use of vars
  244. GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
  245. "_message", DATA2ARG ("Leaving."));
  246. GNUNET_SOCIAL_guest_leave (gst, env, guest_left, NULL);
  247. GNUNET_PSYC_env_destroy (env);
  248. gst = NULL;
  249. plc = NULL;
  250. }
  251. /* ANNOUNCE / ASSIGN / TALK */
  252. struct TransmitClosure
  253. {
  254. const char *data;
  255. size_t size;
  256. } tmit;
  257. /**
  258. * Callback notifying about available buffer space to write message data
  259. * when transmitting messages using host_announce() or guest_talk()
  260. */
  261. static int
  262. notify_data (void *cls, uint16_t *data_size, void *data)
  263. {
  264. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  265. "Transmit notify data: %u bytes available\n",
  266. *data_size);
  267. struct TransmitClosure *tmit = cls;
  268. uint16_t size = tmit->size < *data_size ? tmit->size : *data_size;
  269. *data_size = size;
  270. GNUNET_memcpy (data, tmit->data, size);
  271. tmit->size -= size;
  272. tmit->data += size;
  273. if (0 == tmit->size)
  274. {
  275. if ((op_host_announce || op_host_assign || op_guest_talk) && !opt_follow)
  276. {
  277. exit_success ();
  278. }
  279. return GNUNET_YES;
  280. }
  281. else
  282. {
  283. return GNUNET_NO;
  284. }
  285. }
  286. /**
  287. * Host announcement - send a message to the place.
  288. */
  289. static void
  290. host_announce (const char *method, const char *data, size_t data_size)
  291. {
  292. struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
  293. GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
  294. "_foo", DATA2ARG ("bar baz"));
  295. tmit = (struct TransmitClosure) {};
  296. tmit.data = data;
  297. tmit.size = data_size;
  298. GNUNET_SOCIAL_host_announce (hst, method, env,
  299. notify_data, &tmit,
  300. GNUNET_SOCIAL_ANNOUNCE_NONE);
  301. GNUNET_PSYC_env_destroy (env);
  302. }
  303. /**
  304. * Assign a state var of @a name to the value of @a data.
  305. */
  306. static void
  307. host_assign (const char *name, const char *data, size_t data_size)
  308. {
  309. struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
  310. GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
  311. name, data, data_size);
  312. tmit = (struct TransmitClosure) {};
  313. GNUNET_SOCIAL_host_announce (hst, "_assign", env,
  314. notify_data, &tmit,
  315. GNUNET_SOCIAL_ANNOUNCE_NONE);
  316. GNUNET_PSYC_env_destroy (env);
  317. }
  318. /**
  319. * Guest talk request to host.
  320. */
  321. static void
  322. guest_talk (const char *method,
  323. const char *data, size_t data_size)
  324. {
  325. struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
  326. GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
  327. "_foo", DATA2ARG ("bar baz"));
  328. tmit = (struct TransmitClosure) {};
  329. tmit.data = data;
  330. tmit.size = data_size;
  331. GNUNET_SOCIAL_guest_talk (gst, method, env,
  332. notify_data, &tmit,
  333. GNUNET_SOCIAL_TALK_NONE);
  334. GNUNET_PSYC_env_destroy (env);
  335. }
  336. /* HISTORY REPLAY */
  337. /**
  338. * Callback notifying about the end of history replay results.
  339. */
  340. static void
  341. recv_history_replay_result (void *cls, int64_t result,
  342. const void *data, uint16_t data_size)
  343. {
  344. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  345. "Received history replay result: %" PRId64 "\n"
  346. "%.*s\n",
  347. result, data_size, (const char *) data);
  348. if (op_replay || op_replay_latest)
  349. {
  350. exit_success ();
  351. }
  352. }
  353. /**
  354. * Replay history between a given @a start and @a end message IDs,
  355. * optionally filtered by a method @a prefix.
  356. */
  357. static void
  358. history_replay (uint64_t start, uint64_t end, const char *prefix)
  359. {
  360. GNUNET_SOCIAL_place_history_replay (plc, start, end, prefix,
  361. GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
  362. slicer,
  363. recv_history_replay_result,
  364. NULL);
  365. }
  366. /**
  367. * Replay latest @a limit messages.
  368. */
  369. static void
  370. history_replay_latest (uint64_t limit, const char *prefix)
  371. {
  372. GNUNET_SOCIAL_place_history_replay_latest (plc, limit, prefix,
  373. GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
  374. slicer,
  375. recv_history_replay_result,
  376. NULL);
  377. }
  378. /* LOOK AT/FOR */
  379. /**
  380. * Callback notifying about the end of state var results.
  381. */
  382. static void
  383. look_result (void *cls, int64_t result_code,
  384. const void *data, uint16_t data_size)
  385. {
  386. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  387. "Received look result: %" PRId64 "\n", result_code);
  388. if (op_look_at || op_look_for)
  389. {
  390. exit_success ();
  391. }
  392. }
  393. /**
  394. * Callback notifying about a state var result.
  395. */
  396. static void
  397. look_var (void *cls,
  398. const struct GNUNET_MessageHeader *mod,
  399. const char *name,
  400. const void *value,
  401. uint32_t value_size,
  402. uint32_t full_value_size)
  403. {
  404. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  405. "Received var: %s\n%.*s\n",
  406. name, value_size, (const char *) value);
  407. }
  408. /**
  409. * Look for a state var using exact match of the name.
  410. */
  411. static void
  412. look_at (const char *full_name)
  413. {
  414. GNUNET_SOCIAL_place_look_at (plc, full_name, look_var, look_result, NULL);
  415. }
  416. /**
  417. * Look for state vars by name prefix.
  418. */
  419. static void
  420. look_for (const char *name_prefix)
  421. {
  422. GNUNET_SOCIAL_place_look_for (plc, name_prefix, look_var, look_result, NULL);
  423. }
  424. /* SLICER */
  425. /**
  426. * Callback notifying about the start of a new incoming message.
  427. */
  428. static void
  429. slicer_recv_method (void *cls,
  430. const struct GNUNET_PSYC_MessageHeader *msg,
  431. const struct GNUNET_PSYC_MessageMethod *meth,
  432. uint64_t message_id,
  433. const char *method_name)
  434. {
  435. method_received = method_name;
  436. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  437. "Received method for message ID %" PRIu64 ":\n"
  438. "%s (flags: %x)\n",
  439. message_id, method_name, ntohl (meth->flags));
  440. /* routing header is missing, so we just print double newline */
  441. printf("\n");
  442. /* we output . instead of | to indicate that this is not proper PSYC syntax */
  443. /* FIXME: use libpsyc here */
  444. }
  445. /**
  446. * Callback notifying about an incoming modifier.
  447. */
  448. static void
  449. slicer_recv_modifier (void *cls,
  450. const struct GNUNET_PSYC_MessageHeader *msg,
  451. const struct GNUNET_MessageHeader *pmsg,
  452. uint64_t message_id,
  453. enum GNUNET_PSYC_Operator oper,
  454. const char *name,
  455. const void *value,
  456. uint16_t value_size,
  457. uint16_t full_value_size)
  458. {
  459. #if 0
  460. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  461. "Received modifier for message ID %" PRIu64 ":\n"
  462. "%c%s: %.*s (size: %u)\n",
  463. message_id, oper, name, value_size, (const char *) value, value_size);
  464. #else
  465. /* obviously not binary safe */
  466. printf("%c%s\t%.*s\n",
  467. oper, name, value_size, (const char *) value);
  468. #endif
  469. }
  470. /**
  471. * Callback notifying about an incoming data fragment.
  472. */
  473. static void
  474. slicer_recv_data (void *cls,
  475. const struct GNUNET_PSYC_MessageHeader *msg,
  476. const struct GNUNET_MessageHeader *pmsg,
  477. uint64_t message_id,
  478. const void *data,
  479. uint16_t data_size)
  480. {
  481. #if 0
  482. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  483. "Received data for message ID %" PRIu64 ":\n"
  484. "%.*s\n",
  485. message_id, data_size, (const char *) data);
  486. #else
  487. /* obviously not binary safe */
  488. printf("%s\n%.*s\n",
  489. method_received, data_size, (const char *) data);
  490. #endif
  491. }
  492. /**
  493. * Callback notifying about the end of a message.
  494. */
  495. static void
  496. slicer_recv_eom (void *cls,
  497. const struct GNUNET_PSYC_MessageHeader *msg,
  498. const struct GNUNET_MessageHeader *pmsg,
  499. uint64_t message_id,
  500. uint8_t is_cancelled)
  501. {
  502. printf(".\n");
  503. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  504. "Received end of message ID %" PRIu64
  505. ", cancelled: %u\n",
  506. message_id, is_cancelled);
  507. }
  508. /**
  509. * Create a slicer for receiving message parts.
  510. */
  511. static struct GNUNET_PSYC_Slicer *
  512. slicer_create ()
  513. {
  514. slicer = GNUNET_PSYC_slicer_create ();
  515. /* register slicer to receive incoming messages with any method name */
  516. GNUNET_PSYC_slicer_method_add (slicer, "", NULL,
  517. slicer_recv_method, slicer_recv_modifier,
  518. slicer_recv_data, slicer_recv_eom, NULL);
  519. return slicer;
  520. }
  521. /* GUEST ENTER */
  522. /**
  523. * Callback called when the guest receives an entry decision from the host.
  524. *
  525. * It is called once after using guest_enter() or guest_enter_by_name(),
  526. * in case of a reconnection only the local enter callback is called.
  527. */
  528. static void
  529. guest_recv_entry_decision (void *cls,
  530. int is_admitted,
  531. const struct GNUNET_PSYC_Message *entry_msg)
  532. {
  533. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  534. "Guest received entry decision %d\n",
  535. is_admitted);
  536. if (NULL != entry_msg)
  537. {
  538. struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
  539. const char *method_name = NULL;
  540. const void *data = NULL;
  541. uint16_t data_size = 0;
  542. struct GNUNET_PSYC_MessageHeader *
  543. pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
  544. GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
  545. GNUNET_free (pmsg);
  546. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  547. "%s\n%.*s\n",
  548. method_name, data_size, (const char *) data);
  549. }
  550. if (op_guest_enter && !opt_follow)
  551. {
  552. exit_success ();
  553. }
  554. }
  555. /**
  556. * Callback called after a guest connection is established to the local service.
  557. */
  558. static void
  559. guest_recv_local_enter (void *cls, int result,
  560. const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
  561. uint64_t max_message_id)
  562. {
  563. char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
  564. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  565. "Guest entered local place: %s, max_message_id: %" PRIu64 "\n",
  566. pub_str, max_message_id);
  567. GNUNET_free (pub_str);
  568. GNUNET_assert (0 <= result);
  569. if (op_guest_enter && !opt_follow)
  570. {
  571. exit_success ();
  572. }
  573. }
  574. /**
  575. * Create entry request message.
  576. */
  577. static struct GNUNET_PSYC_Message *
  578. guest_enter_msg_create ()
  579. {
  580. const char *method_name = "_request_enter";
  581. struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
  582. GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
  583. "_foo", DATA2ARG ("bar"));
  584. void *data = "let me in";
  585. uint16_t data_size = strlen (data) + 1;
  586. return GNUNET_PSYC_message_create (method_name, env, data, data_size);
  587. }
  588. /**
  589. * Enter a place as guest, using its public key and peer ID.
  590. */
  591. static void
  592. guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
  593. const struct GNUNET_PeerIdentity *peer)
  594. {
  595. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  596. "Entering to place as guest.\n");
  597. if (NULL == ego)
  598. {
  599. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
  600. exit_fail ();
  601. return;
  602. }
  603. struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
  604. gst = GNUNET_SOCIAL_guest_enter (app, ego, pub_key,
  605. GNUNET_PSYC_SLAVE_JOIN_NONE,
  606. peer, 0, NULL, join_msg, slicer_create (),
  607. guest_recv_local_enter,
  608. guest_recv_entry_decision, NULL);
  609. GNUNET_free (join_msg);
  610. plc = GNUNET_SOCIAL_guest_get_place (gst);
  611. }
  612. /**
  613. * Enter a place as guest using its GNS address.
  614. */
  615. static void
  616. guest_enter_by_name (const char *gns_name)
  617. {
  618. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  619. "Entering to place by name as guest.\n");
  620. struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
  621. gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL,
  622. join_msg, slicer,
  623. guest_recv_local_enter,
  624. guest_recv_entry_decision, NULL);
  625. GNUNET_free (join_msg);
  626. plc = GNUNET_SOCIAL_guest_get_place (gst);
  627. }
  628. /* HOST ENTER */
  629. /**
  630. * Callback called when a @a nym wants to enter the place.
  631. *
  632. * The request needs to be replied with an entry decision.
  633. */
  634. static void
  635. host_answer_door (void *cls,
  636. struct GNUNET_SOCIAL_Nym *nym,
  637. const char *method_name,
  638. struct GNUNET_PSYC_Environment *env,
  639. const void *data,
  640. size_t data_size)
  641. {
  642. const struct GNUNET_CRYPTO_EcdsaPublicKey *
  643. nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
  644. char *
  645. nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
  646. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  647. "Entry request: %s\n", nym_str);
  648. GNUNET_free (nym_str);
  649. if (opt_welcome)
  650. {
  651. struct GNUNET_PSYC_Message *
  652. resp = GNUNET_PSYC_message_create ("_notice_place_admit", env,
  653. DATA2ARG ("Welcome, nym!"));
  654. GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, resp);
  655. GNUNET_free (resp);
  656. }
  657. else if (opt_deny)
  658. {
  659. struct GNUNET_PSYC_Message *
  660. resp = GNUNET_PSYC_message_create ("_notice_place_refuse", NULL,
  661. DATA2ARG ("Go away!"));
  662. GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, resp);
  663. GNUNET_free (resp);
  664. }
  665. }
  666. /**
  667. * Callback called when a @a nym has left the place.
  668. */
  669. static void
  670. host_farewell (void *cls,
  671. const struct GNUNET_SOCIAL_Nym *nym,
  672. struct GNUNET_PSYC_Environment *env)
  673. {
  674. const struct GNUNET_CRYPTO_EcdsaPublicKey *
  675. nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
  676. char *
  677. nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
  678. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  679. "Farewell: %s\n", nym_str);
  680. GNUNET_free (nym_str);
  681. }
  682. /**
  683. * Callback called after the host entered the place.
  684. */
  685. static void
  686. host_entered (void *cls, int result,
  687. const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
  688. uint64_t max_message_id)
  689. {
  690. place_pub_key = *pub_key;
  691. char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
  692. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  693. "Host entered: %s, max_message_id: %" PRIu64 "\n",
  694. pub_str, max_message_id);
  695. GNUNET_free (pub_str);
  696. if (op_host_enter && !opt_follow)
  697. {
  698. exit_success ();
  699. }
  700. }
  701. /**
  702. * Enter and start hosting a place.
  703. */
  704. static void
  705. host_enter ()
  706. {
  707. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n");
  708. if (NULL == ego)
  709. {
  710. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
  711. exit_fail ();
  712. return;
  713. }
  714. hst = GNUNET_SOCIAL_host_enter (app, ego,
  715. GNUNET_PSYC_CHANNEL_PRIVATE,
  716. slicer_create (), host_entered,
  717. host_answer_door, host_farewell, NULL);
  718. plc = GNUNET_SOCIAL_host_get_place (hst);
  719. }
  720. /* PLACE RECONNECT */
  721. /**
  722. * Perform operations common to both host & guest places.
  723. */
  724. static void
  725. place_reconnected ()
  726. {
  727. static int first_run = GNUNET_YES;
  728. if (GNUNET_NO == first_run)
  729. return;
  730. first_run = GNUNET_NO;
  731. if (op_replay) {
  732. history_replay (opt_start, opt_until, opt_method);
  733. }
  734. else if (op_replay_latest) {
  735. history_replay_latest (opt_limit, opt_method);
  736. }
  737. else if (op_look_at) {
  738. look_at (opt_name);
  739. }
  740. else if (op_look_for) {
  741. look_for (opt_name);
  742. }
  743. }
  744. /**
  745. * Callback called after reconnecting to a host place.
  746. */
  747. static void
  748. host_reconnected (void *cls, int result,
  749. const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
  750. uint64_t max_message_id)
  751. {
  752. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  753. "Host reconnected.\n");
  754. if (op_host_leave) {
  755. host_leave ();
  756. }
  757. else if (op_host_announce) {
  758. host_announce (opt_method, opt_data, strlen (opt_data));
  759. }
  760. else if (op_host_assign) {
  761. host_assign (opt_name, opt_data, strlen (opt_data) + 1);
  762. }
  763. else {
  764. place_reconnected ();
  765. }
  766. }
  767. /**
  768. * Callback called after reconnecting to a guest place.
  769. */
  770. static void
  771. guest_reconnected (void *cls, int result,
  772. const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
  773. uint64_t max_message_id)
  774. {
  775. char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key);
  776. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  777. "Guest reconnected to place %s.\n", place_pub_str);
  778. GNUNET_free (place_pub_str);
  779. if (op_guest_leave) {
  780. guest_leave ();
  781. }
  782. else if (op_guest_talk) {
  783. guest_talk (opt_method, opt_data, strlen (opt_data));
  784. }
  785. else {
  786. place_reconnected ();
  787. }
  788. }
  789. /* APP */
  790. /**
  791. * Callback called after the ego and place callbacks.
  792. */
  793. static void
  794. app_connected (void *cls)
  795. {
  796. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  797. "App connected: %p\n", cls);
  798. if (op_status)
  799. {
  800. exit_success ();
  801. }
  802. else if (op_host_enter)
  803. {
  804. host_enter ();
  805. }
  806. else if (op_guest_enter)
  807. {
  808. if (opt_gns)
  809. {
  810. guest_enter_by_name (opt_gns);
  811. }
  812. else
  813. {
  814. if (opt_peer)
  815. {
  816. if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_peer,
  817. strlen (opt_peer),
  818. &peer.public_key))
  819. {
  820. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  821. "--peer invalid");
  822. exit_fail ();
  823. return;
  824. }
  825. }
  826. else
  827. {
  828. peer = this_peer;
  829. }
  830. guest_enter (&place_pub_key, &peer);
  831. }
  832. }
  833. printf(".\n");
  834. }
  835. /**
  836. * Callback notifying about a host place available for reconnection.
  837. */
  838. static void
  839. app_recv_host (void *cls,
  840. struct GNUNET_SOCIAL_HostConnection *hconn,
  841. struct GNUNET_SOCIAL_Ego *ego,
  842. const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
  843. enum GNUNET_SOCIAL_AppPlaceState place_state)
  844. {
  845. char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key);
  846. printf ("Host\t%s\n", host_pub_str);
  847. GNUNET_free (host_pub_str);
  848. if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
  849. || op_replay || op_replay_latest
  850. || op_look_at || op_look_for)
  851. && 0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
  852. {
  853. hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected,
  854. host_answer_door, host_farewell, NULL);
  855. plc = GNUNET_SOCIAL_host_get_place (hst);
  856. }
  857. }
  858. /**
  859. * Callback notifying about a guest place available for reconnection.
  860. */
  861. static void
  862. app_recv_guest (void *cls,
  863. struct GNUNET_SOCIAL_GuestConnection *gconn,
  864. struct GNUNET_SOCIAL_Ego *ego,
  865. const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
  866. enum GNUNET_SOCIAL_AppPlaceState place_state)
  867. {
  868. char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key);
  869. printf ("Guest\t%s\n", guest_pub_str);
  870. GNUNET_free (guest_pub_str);
  871. if ((op_guest_reconnect || op_guest_leave || op_guest_talk
  872. || op_replay || op_replay_latest
  873. || op_look_at || op_look_for)
  874. && 0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
  875. {
  876. gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE,
  877. slicer_create (), guest_reconnected, NULL);
  878. plc = GNUNET_SOCIAL_guest_get_place (gst);
  879. }
  880. }
  881. /**
  882. * Callback notifying about an available ego.
  883. */
  884. static void
  885. app_recv_ego (void *cls,
  886. struct GNUNET_SOCIAL_Ego *e,
  887. const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
  888. const char *name)
  889. {
  890. char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key);
  891. printf ("Ego\t%s\t%s\n", s, name);
  892. GNUNET_free (s);
  893. if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key))
  894. || (NULL != opt_ego && 0 == strcmp (opt_ego, name)))
  895. {
  896. ego = e;
  897. }
  898. }
  899. /**
  900. * Establish application connection to receive available egos and places.
  901. */
  902. static void
  903. app_connect (void *cls)
  904. {
  905. app = GNUNET_SOCIAL_app_connect (cfg, opt_app,
  906. app_recv_ego,
  907. app_recv_host,
  908. app_recv_guest,
  909. app_connected,
  910. NULL);
  911. }
  912. /**
  913. * Main function run by the scheduler.
  914. *
  915. * @param cls closure
  916. * @param args remaining command-line arguments
  917. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  918. * @param c configuration
  919. */
  920. static void
  921. run (void *cls, char *const *args, const char *cfgfile,
  922. const struct GNUNET_CONFIGURATION_Handle *c)
  923. {
  924. cfg = c;
  925. GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
  926. if (!opt_method)
  927. opt_method = "message";
  928. if (!opt_data)
  929. opt_data = "";
  930. if (!opt_name)
  931. opt_name = "";
  932. if (! (op_status
  933. || op_host_enter || op_host_reconnect || op_host_leave
  934. || op_host_announce || op_host_assign
  935. || op_guest_enter || op_guest_reconnect
  936. || op_guest_leave || op_guest_talk
  937. || op_replay || op_replay_latest
  938. || op_look_at || op_look_for))
  939. {
  940. op_status = 1;
  941. fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr);
  942. }
  943. GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL);
  944. if (!opt_follow)
  945. {
  946. timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, timeout, NULL);
  947. }
  948. if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
  949. || op_guest_reconnect || (op_guest_enter && !opt_gns)
  950. || op_guest_leave || op_guest_talk
  951. || op_replay || op_replay_latest
  952. || op_look_at || op_look_for)
  953. && (!opt_place
  954. || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place,
  955. strlen (opt_place),
  956. &place_pub_key)))
  957. {
  958. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  959. _("--place missing or invalid.\n"));
  960. /* FIXME: why does it segfault here? */
  961. exit_fail ();
  962. return;
  963. }
  964. if (opt_ego)
  965. {
  966. if (GNUNET_OK !=
  967. GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego,
  968. strlen (opt_ego),
  969. &ego_pub_key))
  970. {
  971. FPRINTF (stderr,
  972. _("Public key `%s' malformed\n"),
  973. opt_ego);
  974. exit_fail ();
  975. return;
  976. }
  977. }
  978. GNUNET_SCHEDULER_add_now (app_connect, NULL);
  979. }
  980. /**
  981. * The main function to obtain peer information.
  982. *
  983. * @param argc number of arguments from the command line
  984. * @param argv command line arguments
  985. * @return 0 ok, 1 on error
  986. */
  987. int
  988. main (int argc, char *const *argv)
  989. {
  990. int res;
  991. struct GNUNET_GETOPT_CommandLineOption options[] = {
  992. /*
  993. * gnunet program options in addition to the ones below:
  994. *
  995. * -c, --config=FILENAME
  996. * -l, --logfile=LOGFILE
  997. * -L, --log=LOGLEVEL
  998. * -h, --help
  999. * -v, --version
  1000. */
  1001. /* operations */
  1002. GNUNET_GETOPT_option_flag ('A',
  1003. "host-assign",
  1004. gettext_noop ("assign --name in state to --data"),
  1005. &op_host_assign),
  1006. GNUNET_GETOPT_option_flag ('B',
  1007. "guest-leave",
  1008. gettext_noop ("say good-bye and leave somebody else's place"),
  1009. &op_guest_leave),
  1010. GNUNET_GETOPT_option_flag ('C',
  1011. "host-enter",
  1012. gettext_noop ("create a place"),
  1013. &op_host_enter),
  1014. GNUNET_GETOPT_option_flag ('D',
  1015. "host-leave",
  1016. gettext_noop ("destroy a place we were hosting"),
  1017. &op_host_leave),
  1018. GNUNET_GETOPT_option_flag ('E',
  1019. "guest-enter",
  1020. gettext_noop ("enter somebody else's place"),
  1021. &op_guest_enter),
  1022. GNUNET_GETOPT_option_flag ('F',
  1023. "look-for",
  1024. gettext_noop ("find state matching name prefix"),
  1025. &op_look_for),
  1026. GNUNET_GETOPT_option_flag ('H',
  1027. "replay-latest",
  1028. gettext_noop ("replay history of messages up to the given --limit"),
  1029. &op_replay_latest),
  1030. GNUNET_GETOPT_option_flag ('N',
  1031. "host-reconnect",
  1032. gettext_noop ("reconnect to a previously created place"),
  1033. &op_host_reconnect),
  1034. GNUNET_GETOPT_option_flag ('P',
  1035. "host-announce",
  1036. gettext_noop ("publish something to a place we are hosting"),
  1037. &op_host_announce),
  1038. GNUNET_GETOPT_option_flag ('R',
  1039. "guest-reconnect",
  1040. gettext_noop ("reconnect to a previously entered place"),
  1041. &op_guest_reconnect),
  1042. GNUNET_GETOPT_option_flag ('S',
  1043. "look-at",
  1044. gettext_noop ("search for state matching exact name"),
  1045. &op_look_at),
  1046. GNUNET_GETOPT_option_flag ('T',
  1047. "guest-talk",
  1048. gettext_noop ("submit something to somebody's place"),
  1049. &op_guest_talk),
  1050. GNUNET_GETOPT_option_flag ('U',
  1051. "status",
  1052. gettext_noop ("list of egos and subscribed places"),
  1053. &op_status),
  1054. GNUNET_GETOPT_option_flag ('X',
  1055. "replay",
  1056. gettext_noop ("extract and replay history between message IDs --start and --until"),
  1057. &op_replay),
  1058. /* options */
  1059. GNUNET_GETOPT_option_string ('a',
  1060. "app",
  1061. "APPLICATION_ID",
  1062. gettext_noop ("application ID to use when connecting"),
  1063. &opt_app),
  1064. GNUNET_GETOPT_option_string ('d',
  1065. "data",
  1066. "DATA",
  1067. gettext_noop ("message body or state value"),
  1068. &opt_data),
  1069. GNUNET_GETOPT_option_string ('e',
  1070. "ego",
  1071. "NAME|PUBKEY",
  1072. gettext_noop ("name or public key of ego"),
  1073. &opt_ego),
  1074. GNUNET_GETOPT_option_flag ('f',
  1075. "follow",
  1076. gettext_noop ("wait for incoming messages"),
  1077. &opt_follow),
  1078. GNUNET_GETOPT_option_string ('g',
  1079. "gns",
  1080. "GNS_NAME",
  1081. gettext_noop ("GNS name"),
  1082. &opt_gns),
  1083. GNUNET_GETOPT_option_string ('i',
  1084. "peer",
  1085. "PEER_ID",
  1086. gettext_noop ("peer ID for --guest-enter"),
  1087. &opt_peer),
  1088. GNUNET_GETOPT_option_string ('k',
  1089. "name",
  1090. "VAR_NAME",
  1091. gettext_noop ("name (key) to query from state"),
  1092. &opt_name),
  1093. GNUNET_GETOPT_option_string ('m',
  1094. "method",
  1095. "METHOD_NAME",
  1096. gettext_noop ("method name"),
  1097. &opt_method),
  1098. GNUNET_GETOPT_option_ulong ('n',
  1099. "limit",
  1100. NULL,
  1101. gettext_noop ("number of messages to replay from history"),
  1102. &opt_limit),
  1103. GNUNET_GETOPT_option_string ('p',
  1104. "place",
  1105. "PUBKEY",
  1106. gettext_noop ("key address of place"),
  1107. &opt_place),
  1108. GNUNET_GETOPT_option_ulong ('s',
  1109. "start",
  1110. NULL,
  1111. gettext_noop ("start message ID for history replay"),
  1112. &opt_start),
  1113. GNUNET_GETOPT_option_flag ('w',
  1114. "welcome",
  1115. gettext_noop ("respond to entry requests by admitting all guests"),
  1116. &opt_welcome),
  1117. GNUNET_GETOPT_option_ulong ('u',
  1118. "until",
  1119. NULL,
  1120. gettext_noop ("end message ID for history replay"),
  1121. &opt_until),
  1122. GNUNET_GETOPT_option_flag ('y',
  1123. "deny",
  1124. gettext_noop ("respond to entry requests by refusing all guests"),
  1125. &opt_deny),
  1126. GNUNET_GETOPT_OPTION_END
  1127. };
  1128. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  1129. return 2;
  1130. const char *help =
  1131. _ ("gnunet-social - Interact with the social service: enter/leave, send/receive messages, access history and state.\n");
  1132. const char *usage =
  1133. "gnunet-social [--status]\n"
  1134. "\n"
  1135. "gnunet-social --host-enter --ego <NAME or PUBKEY> [--follow] [--welcome | --deny]\n"
  1136. "gnunet-social --host-reconnect --place <PUBKEY> [--follow] [--welcome | --deny]\n"
  1137. "gnunet-social --host-leave --place <PUBKEY>\n"
  1138. "gnunet-social --host-assign --place <PUBKEY> --name <NAME> --data <VALUE>\n"
  1139. // FIXME: some state ops not implemented yet (no hurry)
  1140. // "gnunet-social --host-augment --place <PUBKEY> --name <NAME> --data <VALUE>\n"
  1141. // "gnunet-social --host-diminish --place <PUBKEY> --name <NAME> --data <VALUE>\n"
  1142. // "gnunet-social --host-set --place <PUBKEY> --name <NAME> --data <VALUE>\n"
  1143. "gnunet-social --host-announce --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
  1144. "\n"
  1145. "gnunet-social --guest-enter --place <PUBKEY> --peer <PEERID> --ego <NAME or PUBKEY> [--follow]\n"
  1146. "gnunet-social --guest-enter --gns <GNS_NAME> --ego <NAME or PUBKEY> [--follow]\n"
  1147. "gnunet-social --guest-reconnect --place <PUBKEY> [--follow]\n"
  1148. "gnunet-social --guest-leave --place <PUBKEY>\n"
  1149. "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
  1150. "\n"
  1151. "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n"
  1152. "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
  1153. "\n"
  1154. "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
  1155. "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n";
  1156. res = GNUNET_PROGRAM_run (argc, argv, help, usage, options, &run, NULL);
  1157. GNUNET_free ((void *) argv);
  1158. if (GNUNET_OK == res)
  1159. return ret;
  1160. else
  1161. return 1;
  1162. }