summaryrefslogtreecommitdiff
path: root/src/social/gnunet-service-social.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/social/gnunet-service-social.c')
-rw-r--r--src/social/gnunet-service-social.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/src/social/gnunet-service-social.c b/src/social/gnunet-service-social.c
new file mode 100644
index 000000000..db704898b
--- /dev/null
+++ b/src/social/gnunet-service-social.c
@@ -0,0 +1,461 @@
+/*
+ * This file is part of GNUnet
+ * (C) 2013 Christian Grothoff (and other contributing authors)
+ *
+ * GNUnet is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 3, 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNUnet; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file psyc/gnunet-service-social.c
+ * @brief Social service
+ * @author Gabor X Toth
+ */
+
+#include <inttypes.h>
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_protocols.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_psyc_service.h"
+#include "gnunet_social_service.h"
+#include "social.h"
+
+
+/**
+ * Handle to our current configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to the statistics service.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Notification context, simplifies client broadcasts.
+ */
+static struct GNUNET_SERVER_NotificationContext *nc;
+
+/**
+ * All connected hosts.
+ * Place's pub_key_hash -> struct Host
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *hosts;
+
+/**
+ * All connected guests.
+ * Place's pub_key_hash -> struct Guest
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *guests;
+
+/**
+ * Connected guests per place.
+ * Place's pub_key_hash -> Guest's pub_key -> struct Guest
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
+
+
+/**
+ * Message in the transmission queue.
+ */
+struct TransmitMessage
+{
+ struct TransmitMessage *prev;
+ struct TransmitMessage *next;
+
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * ID assigned to the message.
+ */
+ uint64_t id;
+
+ /**
+ * Size of @a buf
+ */
+ uint16_t size;
+
+ /**
+ * @see enum MessageState
+ */
+ uint8_t state;
+
+ /* Followed by message */
+};
+
+
+/**
+ * List of connected clients.
+ */
+struct ClientList
+{
+ struct ClientList *prev;
+ struct ClientList *next;
+ struct GNUNET_SERVER_Client *client;
+};
+
+
+/**
+ * Common part of the client context for both a host and guest.
+ */
+struct Place
+{
+ struct ClientList *clients_head;
+ struct ClientList *clients_tail;
+
+ struct TransmitMessage *tmit_head;
+ struct TransmitMessage *tmit_tail;
+
+ /**
+ * Public key of the channel.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
+
+ /**
+ * Hash of @a pub_key.
+ */
+ struct GNUNET_HashCode pub_key_hash;
+
+ /**
+ * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
+ */
+ uint8_t is_host;
+};
+
+
+/**
+ * Client context for a host.
+ */
+struct Host
+{
+ /**
+ * Place struct common for Host and Guest
+ */
+ struct Place pl;
+
+ /**
+ * Private key of the channel.
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
+
+ /**
+ * Handle for the multicast origin.
+ */
+ struct GNUNET_PSYC_Master *master;
+
+ /**
+ * Transmit handle for multicast.
+ */
+ struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
+
+ /**
+ * Incoming join requests.
+ * guest_key -> struct GNUNET_PSYC_JoinHandle *
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
+
+ /**
+ * @see enum GNUNET_PSYC_Policy
+ */
+ enum GNUNET_PSYC_Policy policy;
+};
+
+
+/**
+ * Client context for a guest.
+ */
+struct Guest
+{
+ /**
+ * Place struct common for Host and Guest.
+ */
+ struct Place pl;
+
+ /**
+ * Private key of the slave.
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
+
+ /**
+ * Public key of the slave.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
+
+ /**
+ * Hash of @a pub_key.
+ */
+ struct GNUNET_HashCode pub_key_hash;
+
+ /**
+ * Handle for the PSYC slave.
+ */
+ struct GNUNET_PSYC_Slave *slave;
+
+ /**
+ * Transmit handle for multicast.
+ */
+ struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
+
+ /**
+ * Peer identity of the origin.
+ */
+ struct GNUNET_PeerIdentity origin;
+
+ /**
+ * Number of items in @a relays.
+ */
+ uint32_t relay_count;
+
+ /**
+ * Relays that multicast can use to connect.
+ */
+ struct GNUNET_PeerIdentity *relays;
+
+ /**
+ * Join request to be transmitted to the master on join.
+ */
+ struct GNUNET_MessageHeader *join_req;
+};
+
+
+static inline void
+transmit_message (struct Place *pl);
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (NULL != nc)
+ {
+ GNUNET_SERVER_notification_context_destroy (nc);
+ nc = NULL;
+ }
+ if (NULL != stats)
+ {
+ GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
+ stats = NULL;
+ }
+}
+
+
+/**
+ * Clean up host data structures after a client disconnected.
+ */
+static void
+cleanup_host (struct Host *hst)
+{
+ struct Place *pl = &hst->pl;
+
+ if (NULL != hst->master)
+ GNUNET_PSYC_master_stop (hst->master);
+ GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
+ GNUNET_CONTAINER_multihashmap_remove (hosts, &pl->pub_key_hash, pl);
+}
+
+
+/**
+ * Clean up guest data structures after a client disconnected.
+ */
+static void
+cleanup_guest (struct Guest *gst)
+{
+ struct Place *pl = &gst->pl;
+ struct GNUNET_CONTAINER_MultiHashMap *
+ pl_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
+ &pl->pub_key_hash);
+ GNUNET_assert (NULL != pl_gst);
+ GNUNET_CONTAINER_multihashmap_remove (pl_gst, &gst->pub_key_hash, gst);
+
+ if (0 == GNUNET_CONTAINER_multihashmap_size (pl_gst))
+ {
+ GNUNET_CONTAINER_multihashmap_remove (place_guests, &pl->pub_key_hash,
+ pl_gst);
+ GNUNET_CONTAINER_multihashmap_destroy (pl_gst);
+ }
+ GNUNET_CONTAINER_multihashmap_remove (guests, &pl->pub_key_hash, gst);
+
+ if (NULL != gst->join_req)
+ GNUNET_free (gst->join_req);
+ if (NULL != gst->relays)
+ GNUNET_free (gst->relays);
+ if (NULL != gst->slave)
+ GNUNET_PSYC_slave_part (gst->slave);
+ GNUNET_CONTAINER_multihashmap_remove (guests, &pl->pub_key_hash, pl);
+}
+
+
+/**
+ * Clean up place data structures after a client disconnected.
+ */
+static void
+cleanup_place (struct Place *pl)
+{
+ (GNUNET_YES == pl->is_host)
+ ? cleanup_host ((struct Host *) pl)
+ : cleanup_guest ((struct Guest *) pl);
+ GNUNET_free (pl);
+}
+
+
+/**
+ * Called whenever a client is disconnected.
+ * Frees our resources associated with that client.
+ *
+ * @param cls Closure.
+ * @param client Identification of the client.
+ */
+static void
+client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ if (NULL == client)
+ return;
+
+ struct Place *
+ pl = GNUNET_SERVER_client_get_user_context (client, struct Place);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%p Client (%s) disconnected from place %s\n",
+ pl, (GNUNET_YES == pl->is_host) ? "host" : "guest",
+ GNUNET_h2s (&pl->pub_key_hash));
+
+ if (NULL == pl)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%p User context is NULL in client_disconnect()\n", pl);
+ GNUNET_break (0);
+ return;
+ }
+
+ struct ClientList *cl = pl->clients_head;
+ while (NULL != cl)
+ {
+ if (cl->client == client)
+ {
+ GNUNET_CONTAINER_DLL_remove (pl->clients_head, pl->clients_tail, cl);
+ GNUNET_free (cl);
+ break;
+ }
+ cl = cl->next;
+ }
+
+ if (NULL == pl->clients_head)
+ { /* Last client disconnected. */
+ if (NULL != pl->tmit_head)
+ { /* Send pending messages to PSYC before cleanup. */
+ //FIXME: transmit_message (pl);
+ }
+ else
+ {
+ cleanup_place (pl);
+ }
+ }
+}
+
+
+static void
+client_home_enter (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *msg)
+{
+
+}
+
+
+static void
+client_place_enter (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *msg)
+{
+
+}
+
+
+static void
+client_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *msg)
+{
+
+}
+
+
+static void
+client_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *msg)
+{
+
+}
+
+
+/**
+ * Initialize the PSYC service.
+ *
+ * @param cls Closure.
+ * @param server The initialized server.
+ * @param c Configuration to use.
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+ { &client_home_enter, NULL,
+ GNUNET_MESSAGE_TYPE_SOCIAL_HOME_ENTER, 0 },
+
+ { &client_place_enter, NULL,
+ GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_ENTER, 0 },
+
+ { &client_join_decision, NULL,
+ GNUNET_MESSAGE_TYPE_SOCIAL_JOIN_DECISION, 0 },
+
+ { &client_psyc_message, NULL,
+ GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 }
+ };
+
+ cfg = c;
+ stats = GNUNET_STATISTICS_create ("social", cfg);
+ hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
+ guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
+ place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+ nc = GNUNET_SERVER_notification_context_create (server, 1);
+ GNUNET_SERVER_add_handlers (server, handlers);
+ GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_task, NULL);
+}
+
+
+/**
+ * The main function for the service.
+ *
+ * @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)
+{
+ return (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc, argv, "social",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-social.c */