|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2016 GNUnet e.V.
-
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- SPDX-License-Identifier: AGPL3.0-or-later
- */
-
- /**
- * CLI tool to interact with the social service.
- *
- * @author Gabor X Toth
- */
-
- #include <inttypes.h>
-
- #include <gnunet/platform.h>
- #include <gnunet/gnunet_util_lib.h>
- #include "gnunet_social_service.h"
-
- #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
-
- #define DATA2ARG(data) data, sizeof (data)
-
- /* operations corresponding to API calls */
-
- /** --status */
- static int op_status;
-
- /** --host-enter */
- static int op_host_enter;
-
- /** --host-reconnect */
- static int op_host_reconnect;
-
- /** --host-leave */
- static int op_host_leave;
-
- /** --host-announce */
- static int op_host_announce;
-
- /** --host-assign */
- static int op_host_assign;
-
- /** --guest-enter */
- static int op_guest_enter;
-
- /** --guest-reconnect */
- static int op_guest_reconnect;
-
- /** --guest-leave */
- static int op_guest_leave;
-
- /** --guest-talk */
- static int op_guest_talk;
-
- /** --replay */
- static int op_replay;
-
- /** --replay-latest */
- static int op_replay_latest;
-
- /** --look-at */
- static int op_look_at;
-
- /** --look-for */
- static int op_look_for;
-
-
- /* options */
-
- /** --app */
- static char *opt_app = "cli";
-
- /** --place */
- static char *opt_place;
-
- /** --ego */
- static char *opt_ego;
-
- /** --gns */
- static char *opt_gns;
-
- /** --peer */
- static char *opt_peer;
-
- /** --follow */
- static int opt_follow;
-
- /** --welcome */
- static int opt_welcome;
-
- /** --deny */
- static int opt_deny;
-
- /** --method */
- static char *opt_method;
-
- /** --data */
- // FIXME: should come from STDIN
- static char *opt_data;
-
- /** --name */
- static char *opt_name;
-
- /** --start */
- static unsigned long long opt_start;
-
- /** --until */
- static unsigned long long opt_until;
-
- /** --limit */
- static unsigned long long opt_limit;
-
-
- /* global vars */
-
- /** exit code */
- static int ret = 1;
-
- /** are we waiting for service to close our connection */
- static char is_disconnecting = 0;
-
- /** Task handle for timeout termination. */
- struct GNUNET_SCHEDULER_Task *timeout_task;
-
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- struct GNUNET_PeerIdentity peer, this_peer;
-
- struct GNUNET_SOCIAL_App *app;
-
- /** public key of connected place */
- struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
-
- struct GNUNET_PSYC_Slicer *slicer;
-
- struct GNUNET_SOCIAL_Ego *ego;
- struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
-
- struct GNUNET_SOCIAL_Host *hst;
- struct GNUNET_SOCIAL_Guest *gst;
- struct GNUNET_SOCIAL_Place *plc;
-
- const char *method_received;
-
-
- /* DISCONNECT */
-
-
- /**
- * Callback called after the host or guest place disconnected.
- */
- static void
- disconnected (void *cls)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnected()\n");
- GNUNET_SCHEDULER_shutdown ();
- }
-
-
- /**
- * Callback called after the application disconnected.
- */
- static void
- app_disconnected (void *cls)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "app_disconnected()\n");
- if (hst || gst)
- {
- if (hst)
- {
- GNUNET_SOCIAL_host_disconnect (hst, disconnected, NULL);
- }
- if (gst)
- {
- GNUNET_SOCIAL_guest_disconnect (gst, disconnected, NULL);
- }
- }
- else
- {
- GNUNET_SCHEDULER_shutdown ();
- }
- }
-
-
- /**
- * Disconnect from connected GNUnet services.
- */
- static void
- disconnect ()
- {
- // handle that we get called several times from several places, but should we?
- if (!is_disconnecting++) {
- GNUNET_SOCIAL_app_disconnect (app, app_disconnected, NULL);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnect() called for the #%d time\n", is_disconnecting);
- }
-
-
- static void
- scheduler_shutdown (void *cls)
- {
- disconnect ();
- }
-
-
- /**
- * Callback called when the program failed to finish the requested operation in time.
- */
- static void
- timeout (void *cls)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "timeout()\n");
- disconnect ();
- }
-
- static void
- schedule_success (void *cls)
- {
- ret = 0;
- disconnect ();
- }
-
-
- static void
- schedule_fail (void *cls)
- {
- disconnect ();
- }
-
-
- /**
- * Schedule exit with success result.
- */
- static void
- exit_success ()
- {
- if (timeout_task != NULL)
- {
- GNUNET_SCHEDULER_cancel (timeout_task);
- timeout_task = NULL;
- }
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_success, NULL);
- }
-
-
- /**
- * Schedule exit with failure result.
- */
- static void
- exit_fail ()
- {
- if (timeout_task != NULL)
- {
- GNUNET_SCHEDULER_cancel (timeout_task);
- timeout_task = NULL;
- }
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_fail, NULL);
- }
-
-
- /* LEAVE */
-
-
- /**
- * Callback notifying about the host has left and stopped hosting the place.
- *
- * This also indicates the end of the connection to the service.
- */
- static void
- host_left (void *cls)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "The host has left the place.\n");
- exit_success ();
- }
-
-
- /**
- * Leave a place permanently and stop hosting a place.
- */
- static void
- host_leave ()
- {
- GNUNET_SOCIAL_host_leave (hst, NULL, host_left, NULL);
- hst = NULL;
- plc = NULL;
- }
-
-
- /**
- * Callback notifying about the guest has left the place.
- *
- * This also indicates the end of the connection to the service.
- */
- static void
- guest_left (void *cls)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Guest has left the place.\n");
- }
-
-
- /**
- * Leave a place permanently as guest.
- */
- static void
- guest_leave ()
- {
- struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
- // FIXME: wrong use of vars
- GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
- "_message", DATA2ARG ("Leaving."));
- GNUNET_SOCIAL_guest_leave (gst, env, guest_left, NULL);
- GNUNET_PSYC_env_destroy (env);
- gst = NULL;
- plc = NULL;
- }
-
-
- /* ANNOUNCE / ASSIGN / TALK */
-
-
- struct TransmitClosure
- {
- const char *data;
- size_t size;
- } tmit;
-
-
- /**
- * Callback notifying about available buffer space to write message data
- * when transmitting messages using host_announce() or guest_talk()
- */
- static int
- notify_data (void *cls, uint16_t *data_size, void *data)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transmit notify data: %u bytes available\n",
- *data_size);
-
- struct TransmitClosure *tmit = cls;
- uint16_t size = tmit->size < *data_size ? tmit->size : *data_size;
- *data_size = size;
- GNUNET_memcpy (data, tmit->data, size);
-
- tmit->size -= size;
- tmit->data += size;
-
- if (0 == tmit->size)
- {
- if ((op_host_announce || op_host_assign || op_guest_talk) && !opt_follow)
- {
- exit_success ();
- }
- return GNUNET_YES;
- }
- else
- {
- return GNUNET_NO;
- }
- }
-
-
- /**
- * Host announcement - send a message to the place.
- */
- static void
- host_announce (const char *method, const char *data, size_t data_size)
- {
- struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
- GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
- "_foo", DATA2ARG ("bar baz"));
-
- tmit = (struct TransmitClosure) {};
- tmit.data = data;
- tmit.size = data_size;
-
- GNUNET_SOCIAL_host_announce (hst, method, env,
- notify_data, &tmit,
- GNUNET_SOCIAL_ANNOUNCE_NONE);
- GNUNET_PSYC_env_destroy (env);
- }
-
-
- /**
- * Assign a state var of @a name to the value of @a data.
- */
- static void
- host_assign (const char *name, const char *data, size_t data_size)
- {
- struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
- GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
- name, data, data_size);
-
- tmit = (struct TransmitClosure) {};
- GNUNET_SOCIAL_host_announce (hst, "_assign", env,
- notify_data, &tmit,
- GNUNET_SOCIAL_ANNOUNCE_NONE);
- GNUNET_PSYC_env_destroy (env);
- }
-
-
- /**
- * Guest talk request to host.
- */
- static void
- guest_talk (const char *method,
- const char *data, size_t data_size)
- {
- struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
- GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
- "_foo", DATA2ARG ("bar baz"));
-
- tmit = (struct TransmitClosure) {};
- tmit.data = data;
- tmit.size = data_size;
-
- GNUNET_SOCIAL_guest_talk (gst, method, env,
- notify_data, &tmit,
- GNUNET_SOCIAL_TALK_NONE);
- GNUNET_PSYC_env_destroy (env);
- }
-
-
- /* HISTORY REPLAY */
-
-
- /**
- * Callback notifying about the end of history replay results.
- */
- static void
- recv_history_replay_result (void *cls, int64_t result,
- const void *data, uint16_t data_size)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received history replay result: %" PRId64 "\n"
- "%.*s\n",
- result, data_size, (const char *) data);
-
- if (op_replay || op_replay_latest)
- {
- exit_success ();
- }
- }
-
-
- /**
- * Replay history between a given @a start and @a end message IDs,
- * optionally filtered by a method @a prefix.
- */
- static void
- history_replay (uint64_t start, uint64_t end, const char *prefix)
- {
- GNUNET_SOCIAL_place_history_replay (plc, start, end, prefix,
- GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
- slicer,
- recv_history_replay_result,
- NULL);
- }
-
-
- /**
- * Replay latest @a limit messages.
- */
- static void
- history_replay_latest (uint64_t limit, const char *prefix)
- {
- GNUNET_SOCIAL_place_history_replay_latest (plc, limit, prefix,
- GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
- slicer,
- recv_history_replay_result,
- NULL);
- }
-
-
- /* LOOK AT/FOR */
-
-
- /**
- * Callback notifying about the end of state var results.
- */
- static void
- look_result (void *cls, int64_t result_code,
- const void *data, uint16_t data_size)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received look result: %" PRId64 "\n", result_code);
-
- if (op_look_at || op_look_for)
- {
- exit_success ();
- }
- }
-
-
- /**
- * Callback notifying about a state var result.
- */
- static void
- look_var (void *cls,
- const struct GNUNET_MessageHeader *mod,
- const char *name,
- const void *value,
- uint32_t value_size,
- uint32_t full_value_size)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Received var: %s\n%.*s\n",
- name, value_size, (const char *) value);
- }
-
-
- /**
- * Look for a state var using exact match of the name.
- */
- static void
- look_at (const char *full_name)
- {
- GNUNET_SOCIAL_place_look_at (plc, full_name, look_var, look_result, NULL);
- }
-
-
- /**
- * Look for state vars by name prefix.
- */
- static void
- look_for (const char *name_prefix)
- {
- GNUNET_SOCIAL_place_look_for (plc, name_prefix, look_var, look_result, NULL);
- }
-
-
- /* SLICER */
-
-
- /**
- * Callback notifying about the start of a new incoming message.
- */
- static void
- slicer_recv_method (void *cls,
- const struct GNUNET_PSYC_MessageHeader *msg,
- const struct GNUNET_PSYC_MessageMethod *meth,
- uint64_t message_id,
- const char *method_name)
- {
- method_received = method_name;
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Received method for message ID %" PRIu64 ":\n"
- "%s (flags: %x)\n",
- message_id, method_name, ntohl (meth->flags));
- /* routing header is missing, so we just print double newline */
- printf("\n");
- /* we output . instead of | to indicate that this is not proper PSYC syntax */
- /* FIXME: use libpsyc here */
- }
-
-
- /**
- * Callback notifying about an incoming modifier.
- */
- static void
- slicer_recv_modifier (void *cls,
- const struct GNUNET_PSYC_MessageHeader *msg,
- const struct GNUNET_MessageHeader *pmsg,
- uint64_t message_id,
- enum GNUNET_PSYC_Operator oper,
- const char *name,
- const void *value,
- uint16_t value_size,
- uint16_t full_value_size)
- {
- #if 0
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Received modifier for message ID %" PRIu64 ":\n"
- "%c%s: %.*s (size: %u)\n",
- message_id, oper, name, value_size, (const char *) value, value_size);
- #else
- /* obviously not binary safe */
- printf("%c%s\t%.*s\n",
- oper, name, value_size, (const char *) value);
- #endif
- }
-
-
- /**
- * Callback notifying about an incoming data fragment.
- */
- static void
- slicer_recv_data (void *cls,
- const struct GNUNET_PSYC_MessageHeader *msg,
- const struct GNUNET_MessageHeader *pmsg,
- uint64_t message_id,
- const void *data,
- uint16_t data_size)
- {
- #if 0
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Received data for message ID %" PRIu64 ":\n"
- "%.*s\n",
- message_id, data_size, (const char *) data);
- #else
- /* obviously not binary safe */
- printf("%s\n%.*s\n",
- method_received, data_size, (const char *) data);
- #endif
- }
-
-
- /**
- * Callback notifying about the end of a message.
- */
- static void
- slicer_recv_eom (void *cls,
- const struct GNUNET_PSYC_MessageHeader *msg,
- const struct GNUNET_MessageHeader *pmsg,
- uint64_t message_id,
- uint8_t is_cancelled)
- {
- printf(".\n");
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Received end of message ID %" PRIu64
- ", cancelled: %u\n",
- message_id, is_cancelled);
- }
-
-
- /**
- * Create a slicer for receiving message parts.
- */
- static struct GNUNET_PSYC_Slicer *
- slicer_create ()
- {
- slicer = GNUNET_PSYC_slicer_create ();
-
- /* register slicer to receive incoming messages with any method name */
- GNUNET_PSYC_slicer_method_add (slicer, "", NULL,
- slicer_recv_method, slicer_recv_modifier,
- slicer_recv_data, slicer_recv_eom, NULL);
- return slicer;
- }
-
-
- /* GUEST ENTER */
-
-
- /**
- * Callback called when the guest receives an entry decision from the host.
- *
- * It is called once after using guest_enter() or guest_enter_by_name(),
- * in case of a reconnection only the local enter callback is called.
- */
- static void
- guest_recv_entry_decision (void *cls,
- int is_admitted,
- const struct GNUNET_PSYC_Message *entry_msg)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Guest received entry decision %d\n",
- is_admitted);
-
- if (NULL != entry_msg)
- {
- struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
- const char *method_name = NULL;
- const void *data = NULL;
- uint16_t data_size = 0;
- struct GNUNET_PSYC_MessageHeader *
- pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
- GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
- GNUNET_free (pmsg);
-
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "%s\n%.*s\n",
- method_name, data_size, (const char *) data);
- }
-
- if (op_guest_enter && !opt_follow)
- {
- exit_success ();
- }
- }
-
-
- /**
- * Callback called after a guest connection is established to the local service.
- */
- static void
- guest_recv_local_enter (void *cls, int result,
- const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
- uint64_t max_message_id)
- {
- char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Guest entered local place: %s, max_message_id: %" PRIu64 "\n",
- pub_str, max_message_id);
- GNUNET_free (pub_str);
- GNUNET_assert (0 <= result);
-
- if (op_guest_enter && !opt_follow)
- {
- exit_success ();
- }
- }
-
-
- /**
- * Create entry request message.
- */
- static struct GNUNET_PSYC_Message *
- guest_enter_msg_create ()
- {
- const char *method_name = "_request_enter";
- struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
- GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
- "_foo", DATA2ARG ("bar"));
- void *data = "let me in";
- uint16_t data_size = strlen (data) + 1;
-
- return GNUNET_PSYC_message_create (method_name, env, data, data_size);
- }
-
-
- /**
- * Enter a place as guest, using its public key and peer ID.
- */
- static void
- guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
- const struct GNUNET_PeerIdentity *peer)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Entering to place as guest.\n");
-
- if (NULL == ego)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
- exit_fail ();
- return;
- }
-
- struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
- gst = GNUNET_SOCIAL_guest_enter (app, ego, pub_key,
- GNUNET_PSYC_SLAVE_JOIN_NONE,
- peer, 0, NULL, join_msg, slicer_create (),
- guest_recv_local_enter,
- guest_recv_entry_decision, NULL);
- GNUNET_free (join_msg);
- plc = GNUNET_SOCIAL_guest_get_place (gst);
- }
-
-
- /**
- * Enter a place as guest using its GNS address.
- */
- static void
- guest_enter_by_name (const char *gns_name)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Entering to place by name as guest.\n");
-
- struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
- gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL,
- join_msg, slicer,
- guest_recv_local_enter,
- guest_recv_entry_decision, NULL);
- GNUNET_free (join_msg);
- plc = GNUNET_SOCIAL_guest_get_place (gst);
- }
-
-
- /* HOST ENTER */
-
-
- /**
- * Callback called when a @a nym wants to enter the place.
- *
- * The request needs to be replied with an entry decision.
- */
- static void
- host_answer_door (void *cls,
- struct GNUNET_SOCIAL_Nym *nym,
- const char *method_name,
- struct GNUNET_PSYC_Environment *env,
- const void *data,
- size_t data_size)
- {
- const struct GNUNET_CRYPTO_EcdsaPublicKey *
- nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
- char *
- nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
-
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Entry request: %s\n", nym_str);
- GNUNET_free (nym_str);
-
- if (opt_welcome)
- {
- struct GNUNET_PSYC_Message *
- resp = GNUNET_PSYC_message_create ("_notice_place_admit", env,
- DATA2ARG ("Welcome, nym!"));
- GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, resp);
- GNUNET_free (resp);
- }
- else if (opt_deny)
- {
- struct GNUNET_PSYC_Message *
- resp = GNUNET_PSYC_message_create ("_notice_place_refuse", NULL,
- DATA2ARG ("Go away!"));
- GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, resp);
- GNUNET_free (resp);
- }
-
-
- }
-
-
- /**
- * Callback called when a @a nym has left the place.
- */
- static void
- host_farewell (void *cls,
- const struct GNUNET_SOCIAL_Nym *nym,
- struct GNUNET_PSYC_Environment *env)
- {
- const struct GNUNET_CRYPTO_EcdsaPublicKey *
- nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
- char *
- nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
-
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Farewell: %s\n", nym_str);
- GNUNET_free (nym_str);
- }
-
-
- /**
- * Callback called after the host entered the place.
- */
- static void
- host_entered (void *cls, int result,
- const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
- uint64_t max_message_id)
- {
- place_pub_key = *pub_key;
- char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Host entered: %s, max_message_id: %" PRIu64 "\n",
- pub_str, max_message_id);
- GNUNET_free (pub_str);
-
- if (op_host_enter && !opt_follow)
- {
- exit_success ();
- }
- }
-
-
- /**
- * Enter and start hosting a place.
- */
- static void
- host_enter ()
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n");
-
- if (NULL == ego)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
- exit_fail ();
- return;
- }
-
- hst = GNUNET_SOCIAL_host_enter (app, ego,
- GNUNET_PSYC_CHANNEL_PRIVATE,
- slicer_create (), host_entered,
- host_answer_door, host_farewell, NULL);
- plc = GNUNET_SOCIAL_host_get_place (hst);
- }
-
-
- /* PLACE RECONNECT */
-
-
- /**
- * Perform operations common to both host & guest places.
- */
- static void
- place_reconnected ()
- {
- static int first_run = GNUNET_YES;
- if (GNUNET_NO == first_run)
- return;
- first_run = GNUNET_NO;
-
- if (op_replay) {
- history_replay (opt_start, opt_until, opt_method);
- }
- else if (op_replay_latest) {
- history_replay_latest (opt_limit, opt_method);
- }
- else if (op_look_at) {
- look_at (opt_name);
- }
- else if (op_look_for) {
- look_for (opt_name);
- }
- }
-
-
- /**
- * Callback called after reconnecting to a host place.
- */
- static void
- host_reconnected (void *cls, int result,
- const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
- uint64_t max_message_id)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Host reconnected.\n");
-
- if (op_host_leave) {
- host_leave ();
- }
- else if (op_host_announce) {
- host_announce (opt_method, opt_data, strlen (opt_data));
- }
- else if (op_host_assign) {
- host_assign (opt_name, opt_data, strlen (opt_data) + 1);
- }
- else {
- place_reconnected ();
- }
- }
-
-
- /**
- * Callback called after reconnecting to a guest place.
- */
- static void
- guest_reconnected (void *cls, int result,
- const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
- uint64_t max_message_id)
- {
- char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Guest reconnected to place %s.\n", place_pub_str);
- GNUNET_free (place_pub_str);
-
- if (op_guest_leave) {
- guest_leave ();
- }
- else if (op_guest_talk) {
- guest_talk (opt_method, opt_data, strlen (opt_data));
- }
- else {
- place_reconnected ();
- }
- }
-
-
- /* APP */
-
-
- /**
- * Callback called after the ego and place callbacks.
- */
- static void
- app_connected (void *cls)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "App connected: %p\n", cls);
-
- if (op_status)
- {
- exit_success ();
- }
- else if (op_host_enter)
- {
- host_enter ();
- }
- else if (op_guest_enter)
- {
- if (opt_gns)
- {
- guest_enter_by_name (opt_gns);
- }
- else
- {
- if (opt_peer)
- {
- if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_peer,
- strlen (opt_peer),
- &peer.public_key))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "--peer invalid");
- exit_fail ();
- return;
- }
- }
- else
- {
- peer = this_peer;
- }
- guest_enter (&place_pub_key, &peer);
- }
- }
- printf(".\n");
- }
-
-
- /**
- * Callback notifying about a host place available for reconnection.
- */
- static void
- app_recv_host (void *cls,
- struct GNUNET_SOCIAL_HostConnection *hconn,
- struct GNUNET_SOCIAL_Ego *ego,
- const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
- enum GNUNET_SOCIAL_AppPlaceState place_state)
- {
- char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key);
- printf ("Host\t%s\n", host_pub_str);
- GNUNET_free (host_pub_str);
-
- if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
- || op_replay || op_replay_latest
- || op_look_at || op_look_for)
- && 0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
- {
- hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected,
- host_answer_door, host_farewell, NULL);
- plc = GNUNET_SOCIAL_host_get_place (hst);
- }
- }
-
-
- /**
- * Callback notifying about a guest place available for reconnection.
- */
- static void
- app_recv_guest (void *cls,
- struct GNUNET_SOCIAL_GuestConnection *gconn,
- struct GNUNET_SOCIAL_Ego *ego,
- const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
- enum GNUNET_SOCIAL_AppPlaceState place_state)
- {
- char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key);
- printf ("Guest\t%s\n", guest_pub_str);
- GNUNET_free (guest_pub_str);
-
- if ((op_guest_reconnect || op_guest_leave || op_guest_talk
- || op_replay || op_replay_latest
- || op_look_at || op_look_for)
- && 0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
- {
- gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE,
- slicer_create (), guest_reconnected, NULL);
- plc = GNUNET_SOCIAL_guest_get_place (gst);
- }
- }
-
-
- /**
- * Callback notifying about an available ego.
- */
- static void
- app_recv_ego (void *cls,
- struct GNUNET_SOCIAL_Ego *e,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
- const char *name)
- {
- char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key);
- printf ("Ego\t%s\t%s\n", s, name);
- GNUNET_free (s);
-
- if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key))
- || (NULL != opt_ego && 0 == strcmp (opt_ego, name)))
- {
- ego = e;
- }
-
- }
-
-
-
- /**
- * Establish application connection to receive available egos and places.
- */
- static void
- app_connect (void *cls)
- {
- app = GNUNET_SOCIAL_app_connect (cfg, opt_app,
- app_recv_ego,
- app_recv_host,
- app_recv_guest,
- app_connected,
- NULL);
- }
-
-
- /**
- * Main function run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
- */
- static void
- run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
- {
- cfg = c;
- GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
-
- if (!opt_method)
- opt_method = "message";
- if (!opt_data)
- opt_data = "";
- if (!opt_name)
- opt_name = "";
-
- if (! (op_status
- || op_host_enter || op_host_reconnect || op_host_leave
- || op_host_announce || op_host_assign
- || op_guest_enter || op_guest_reconnect
- || op_guest_leave || op_guest_talk
- || op_replay || op_replay_latest
- || op_look_at || op_look_for))
- {
- op_status = 1;
- fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr);
- }
-
- GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL);
- if (!opt_follow)
- {
- timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, timeout, NULL);
- }
-
- if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
- || op_guest_reconnect || (op_guest_enter && !opt_gns)
- || op_guest_leave || op_guest_talk
- || op_replay || op_replay_latest
- || op_look_at || op_look_for)
- && (!opt_place
- || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place,
- strlen (opt_place),
- &place_pub_key)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("--place missing or invalid.\n"));
- /* FIXME: why does it segfault here? */
- exit_fail ();
- return;
- }
-
- if (opt_ego)
- {
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego,
- strlen (opt_ego),
- &ego_pub_key))
- {
- fprintf (stderr,
- _("Public key `%s' malformed\n"),
- opt_ego);
- exit_fail ();
- return;
- }
- }
-
- GNUNET_SCHEDULER_add_now (app_connect, NULL);
- }
-
-
- /**
- * The main function to obtain peer information.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
- int
- main (int argc, char *const *argv)
- {
- int res;
- struct GNUNET_GETOPT_CommandLineOption options[] = {
- /*
- * gnunet program options in addition to the ones below:
- *
- * -c, --config=FILENAME
- * -l, --logfile=LOGFILE
- * -L, --log=LOGLEVEL
- * -h, --help
- * -v, --version
- */
-
- /* operations */
-
- GNUNET_GETOPT_option_flag ('A',
- "host-assign",
- gettext_noop ("assign --name in state to --data"),
- &op_host_assign),
-
- GNUNET_GETOPT_option_flag ('B',
- "guest-leave",
- gettext_noop ("say good-bye and leave somebody else's place"),
- &op_guest_leave),
-
- GNUNET_GETOPT_option_flag ('C',
- "host-enter",
- gettext_noop ("create a place"),
- &op_host_enter),
-
- GNUNET_GETOPT_option_flag ('D',
- "host-leave",
- gettext_noop ("destroy a place we were hosting"),
- &op_host_leave),
-
- GNUNET_GETOPT_option_flag ('E',
- "guest-enter",
- gettext_noop ("enter somebody else's place"),
- &op_guest_enter),
-
-
- GNUNET_GETOPT_option_flag ('F',
- "look-for",
- gettext_noop ("find state matching name prefix"),
- &op_look_for),
-
- GNUNET_GETOPT_option_flag ('H',
- "replay-latest",
- gettext_noop ("replay history of messages up to the given --limit"),
- &op_replay_latest),
-
- GNUNET_GETOPT_option_flag ('N',
- "host-reconnect",
- gettext_noop ("reconnect to a previously created place"),
- &op_host_reconnect),
-
- GNUNET_GETOPT_option_flag ('P',
- "host-announce",
- gettext_noop ("publish something to a place we are hosting"),
- &op_host_announce),
-
- GNUNET_GETOPT_option_flag ('R',
- "guest-reconnect",
- gettext_noop ("reconnect to a previously entered place"),
- &op_guest_reconnect),
-
- GNUNET_GETOPT_option_flag ('S',
- "look-at",
- gettext_noop ("search for state matching exact name"),
- &op_look_at),
-
- GNUNET_GETOPT_option_flag ('T',
- "guest-talk",
- gettext_noop ("submit something to somebody's place"),
- &op_guest_talk),
-
- GNUNET_GETOPT_option_flag ('U',
- "status",
- gettext_noop ("list of egos and subscribed places"),
- &op_status),
-
- GNUNET_GETOPT_option_flag ('X',
- "replay",
- gettext_noop ("extract and replay history between message IDs --start and --until"),
- &op_replay),
-
-
- /* options */
-
- GNUNET_GETOPT_option_string ('a',
- "app",
- "APPLICATION_ID",
- gettext_noop ("application ID to use when connecting"),
- &opt_app),
-
- GNUNET_GETOPT_option_string ('d',
- "data",
- "DATA",
- gettext_noop ("message body or state value"),
- &opt_data),
-
- GNUNET_GETOPT_option_string ('e',
- "ego",
- "NAME|PUBKEY",
- gettext_noop ("name or public key of ego"),
- &opt_ego),
-
- GNUNET_GETOPT_option_flag ('f',
- "follow",
- gettext_noop ("wait for incoming messages"),
- &opt_follow),
-
- GNUNET_GETOPT_option_string ('g',
- "gns",
- "GNS_NAME",
- gettext_noop ("GNS name"),
- &opt_gns),
-
- GNUNET_GETOPT_option_string ('i',
- "peer",
- "PEER_ID",
- gettext_noop ("peer ID for --guest-enter"),
- &opt_peer),
-
- GNUNET_GETOPT_option_string ('k',
- "name",
- "VAR_NAME",
- gettext_noop ("name (key) to query from state"),
- &opt_name),
-
- GNUNET_GETOPT_option_string ('m',
- "method",
- "METHOD_NAME",
- gettext_noop ("method name"),
- &opt_method),
-
- GNUNET_GETOPT_option_ulong ('n',
- "limit",
- NULL,
- gettext_noop ("number of messages to replay from history"),
- &opt_limit),
-
- GNUNET_GETOPT_option_string ('p',
- "place",
- "PUBKEY",
- gettext_noop ("key address of place"),
- &opt_place),
-
- GNUNET_GETOPT_option_ulong ('s',
- "start",
- NULL,
- gettext_noop ("start message ID for history replay"),
- &opt_start),
-
- GNUNET_GETOPT_option_flag ('w',
- "welcome",
- gettext_noop ("respond to entry requests by admitting all guests"),
- &opt_welcome),
-
- GNUNET_GETOPT_option_ulong ('u',
- "until",
- NULL,
- gettext_noop ("end message ID for history replay"),
- &opt_until),
-
- GNUNET_GETOPT_option_flag ('y',
- "deny",
- gettext_noop ("respond to entry requests by refusing all guests"),
- &opt_deny),
-
- GNUNET_GETOPT_OPTION_END
- };
-
- if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
- return 2;
-
- const char *help =
- _ ("gnunet-social - Interact with the social service: enter/leave, send/receive messages, access history and state.\n");
- const char *usage =
- "gnunet-social [--status]\n"
- "\n"
- "gnunet-social --host-enter --ego <NAME or PUBKEY> [--follow] [--welcome | --deny]\n"
- "gnunet-social --host-reconnect --place <PUBKEY> [--follow] [--welcome | --deny]\n"
- "gnunet-social --host-leave --place <PUBKEY>\n"
- "gnunet-social --host-assign --place <PUBKEY> --name <NAME> --data <VALUE>\n"
- // FIXME: some state ops not implemented yet (no hurry)
- // "gnunet-social --host-augment --place <PUBKEY> --name <NAME> --data <VALUE>\n"
- // "gnunet-social --host-diminish --place <PUBKEY> --name <NAME> --data <VALUE>\n"
- // "gnunet-social --host-set --place <PUBKEY> --name <NAME> --data <VALUE>\n"
- "gnunet-social --host-announce --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
- "\n"
- "gnunet-social --guest-enter --place <PUBKEY> --peer <PEERID> --ego <NAME or PUBKEY> [--follow]\n"
- "gnunet-social --guest-enter --gns <GNS_NAME> --ego <NAME or PUBKEY> [--follow]\n"
- "gnunet-social --guest-reconnect --place <PUBKEY> [--follow]\n"
- "gnunet-social --guest-leave --place <PUBKEY>\n"
- "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
- "\n"
- "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n"
- "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
- "\n"
- "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
- "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n";
-
- res = GNUNET_PROGRAM_run (argc, argv, help, usage, options, &run, NULL);
-
- GNUNET_free ((void *) argv);
-
- if (GNUNET_OK == res)
- return ret;
- else
- return 1;
- }
|