*/
#include "platform.h"
#include "gnunet_util_lib.h"
+#include "gnunet_signatures.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_core_service.h"
+#include "gnunet_multicast_service.h"
+#include "multicast.h"
+
+/**
+ * Handle to our current configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Server handle.
+ */
+static struct GNUNET_SERVER_Handle *server;
+
+/**
+ * Core handle.
+ * Only used during initialization.
+ */
+static struct GNUNET_CORE_Handle *core;
+
+/**
+ * Identity of this peer.
+ */
+static struct GNUNET_PeerIdentity this_peer;
+
+/**
+ * Handle to the statistics service.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+/**
+ * Notification context, simplifies client broadcasts.
+ */
+static struct GNUNET_SERVER_NotificationContext *nc;
+
+/**
+ * All connected origins.
+ * Group's pub_key_hash -> struct Origin
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *origins;
+
+/**
+ * All connected members.
+ * Group's pub_key_hash -> struct Member
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *members;
+
+/**
+ * Connected members per group.
+ * Group's pub_key_hash -> Member's pub_key -> struct Member
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *group_members;
+
+/**
+ * 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 an origin and member.
+ */
+struct Group
+{
+ struct ClientList *clients_head;
+ struct ClientList *clients_tail;
+
+ /**
+ * Public key of the group.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
+
+ /**
+ * Hash of @a pub_key.
+ */
+ struct GNUNET_HashCode pub_key_hash;
+
+ /**
+ * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)?
+ */
+ uint8_t is_origin;
+
+ /**
+ * Is the client disconnected? #GNUNET_YES or #GNUNET_NO
+ */
+ uint8_t disconnected;
+};
+
+
+/**
+ * Client context for a group's origin.
+ */
+struct Origin
+{
+ struct Group grp;
+
+ /**
+ * Private key of the group.
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
+
+ /**
+ * Last message fragment ID sent to the group.
+ */
+ uint64_t max_fragment_id;
+};
+
+
+/**
+ * Client context for a group member.
+ */
+struct Member
+{
+ struct Group grp;
+
+ /**
+ * Private key of the member.
+ */
+ struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
+
+ /**
+ * Public key of the member.
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
+
+ /**
+ * Hash of @a pub_key.
+ */
+ struct GNUNET_HashCode pub_key_hash;
+
+ /**
+ * Join request sent to the origin / members.
+ */
+ struct MulticastJoinRequestMessage *join_req;
+
+ /**
+ * Join decision sent in reply to our request.
+ *
+ * Only a positive decision is stored here, in case of a negative decision the
+ * client is disconnected.
+ */
+ struct MulticastJoinDecisionMessageHeader *join_dcsn;
+
+ /**
+ * Last request fragment ID sent to the origin.
+ */
+ uint64_t max_fragment_id;
+};
/**
* @param tc unused
*/
static void
-cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (NULL != core)
+ {
+ GNUNET_CORE_disconnect (core);
+ core = NULL;
+ }
+ if (NULL != stats)
+ {
+ GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
+ stats = NULL;
+ }
+ /* FIXME: do more clean up here */
+}
+
+/**
+ * Clean up origin data structures after a client disconnected.
+ */
+static void
+cleanup_origin (struct Origin *orig)
{
- /* FIXME: do clean up here */
+ struct Group *grp = &orig->grp;
+ GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig);
}
/**
- * Process multicast requests.
+ * Clean up member data structures after a client disconnected.
+ */
+static void
+cleanup_member (struct Member *mem)
+{
+ struct Group *grp = &mem->grp;
+ struct GNUNET_CONTAINER_MultiHashMap *
+ grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
+ &grp->pub_key_hash);
+ GNUNET_assert (NULL != grp_mem);
+ GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem);
+
+ if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem))
+ {
+ GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash,
+ grp_mem);
+ GNUNET_CONTAINER_multihashmap_destroy (grp_mem);
+ }
+ if (NULL != mem->join_dcsn)
+ {
+ GNUNET_free (mem->join_dcsn);
+ mem->join_dcsn = NULL;
+ }
+ GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem);
+}
+
+
+/**
+ * Clean up group data structures after a client disconnected.
+ */
+static void
+cleanup_group (struct Group *grp)
+{
+ (GNUNET_YES == grp->is_origin)
+ ? cleanup_origin ((struct Origin *) grp)
+ : cleanup_member ((struct Member *) grp);
+
+ GNUNET_free (grp);
+}
+
+
+/**
+ * Called whenever a client is disconnected.
*
- * @param cls closure
- * @param server the initialized server
- * @param cfg configuration to use
+ * Frees our resources associated with that client.
+ *
+ * @param cls Closure.
+ * @param client Client handle.
+ */
+static void
+client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ if (NULL == client)
+ return;
+
+ struct Group *grp
+ = GNUNET_SERVER_client_get_user_context (client, struct Group);
+
+ if (NULL == grp)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%p User context is NULL in client_disconnect()\n", grp);
+ GNUNET_assert (0);
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%p Client (%s) disconnected from group %s\n",
+ grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member",
+ GNUNET_h2s (&grp->pub_key_hash));
+
+ struct ClientList *cl = grp->clients_head;
+ while (NULL != cl)
+ {
+ if (cl->client == client)
+ {
+ GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl);
+ GNUNET_free (cl);
+ break;
+ }
+ cl = cl->next;
+ }
+
+ if (NULL == grp->clients_head)
+ { /* Last client disconnected. */
+#if FIXME
+ if (NULL != grp->tmit_head)
+ { /* Send pending messages via CADET before cleanup. */
+ transmit_message (grp);
+ }
+ else
+#endif
+ {
+ cleanup_group (grp);
+ }
+ }
+}
+
+
+/**
+ * Send message to all clients connected to the group.
+ */
+static void
+message_to_clients (const struct Group *grp,
+ const struct GNUNET_MessageHeader *msg)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "%p Sending message to clients.\n", grp);
+
+ struct ClientList *cl = grp->clients_head;
+ while (NULL != cl)
+ {
+ GNUNET_SERVER_notification_context_add (nc, cl->client);
+ GNUNET_SERVER_notification_context_unicast (nc, cl->client, msg, GNUNET_NO);
+ cl = cl->next;
+ }
+}
+
+
+/**
+ * Iterator callback for sending a message to origin clients.
+ */
+static int
+origin_message_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
+ void *origin)
+{
+ const struct GNUNET_MessageHeader *msg = cls;
+ struct Member *orig = origin;
+
+ message_to_clients (&orig->grp, msg);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Iterator callback for sending a message to member clients.
+ */
+static int
+member_message_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
+ void *member)
+{
+ const struct GNUNET_MessageHeader *msg = cls;
+ struct Member *mem = member;
+
+ if (NULL != mem->join_dcsn)
+ { /* Only send message to admitted members */
+ message_to_clients (&mem->grp, msg);
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Send message to all origin and member clients connected to the group.
+ *
+ * @param grp The group to send @a msg to.
+ * @param msg Message to send.
+ */
+static void
+message_to_group (struct Group *grp, const struct GNUNET_MessageHeader *msg)
+{
+ if (origins != NULL)
+ GNUNET_CONTAINER_multihashmap_get_multiple (origins, &grp->pub_key_hash,
+ origin_message_cb, (void *) msg);
+ if (members != NULL)
+ GNUNET_CONTAINER_multihashmap_get_multiple (members, &grp->pub_key_hash,
+ member_message_cb, (void *) msg);
+}
+
+
+/**
+ * Send message to all origin clients connected to the group.
+ *
+ * @param grp The group to send @a msg to.
+ * @param msg Message to send.
+ */
+static void
+message_to_origin (struct Group *grp, const struct GNUNET_MessageHeader *msg)
+{
+ if (origins != NULL)
+ GNUNET_CONTAINER_multihashmap_get_multiple (origins, &grp->pub_key_hash,
+ origin_message_cb, (void *) msg);
+}
+
+
+/**
+ * Handle a connecting client starting an origin.
*/
static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
+client_origin_start (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *m)
{
+ const struct MulticastOriginStartMessage *
+ msg = (const struct MulticastOriginStartMessage *) m;
+
+ struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
+ struct GNUNET_HashCode pub_key_hash;
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key);
+ GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
+
+ struct Origin *
+ orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash);
+ struct Group *grp;
+
+ if (NULL == orig)
+ {
+ orig = GNUNET_new (struct Origin);
+ orig->priv_key = msg->group_key;
+ orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id);
+ grp = &orig->grp;
+ grp->is_origin = GNUNET_YES;
+ grp->pub_key = pub_key;
+ grp->pub_key_hash = pub_key_hash;
+
+ GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ }
+ else
+ {
+ grp = &orig->grp;
+ }
+
+ struct ClientList *cl = GNUNET_new (struct ClientList);
+ cl->client = client;
+ GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%p Client connected as origin to group %s.\n",
+ orig, GNUNET_h2s (&grp->pub_key_hash));
+
+ GNUNET_SERVER_client_set_user_context (client, grp);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle a connecting client joining a group.
+ */
+static void
+client_member_join (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *m)
+{
+ const struct MulticastMemberJoinMessage *
+ msg = (const struct MulticastMemberJoinMessage *) m;
+ uint16_t msg_size = ntohs (msg->header.size);
+
+ struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key;
+ struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash;
+
+ GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key);
+ GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash);
+ GNUNET_CRYPTO_hash (&msg->group_key, sizeof (msg->group_key), &pub_key_hash);
+
+ struct GNUNET_CONTAINER_MultiHashMap *
+ grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash);
+ struct Member *mem = NULL;
+ struct Group *grp;
+
+ if (NULL != grp_mem)
+ {
+ mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash);
+ }
+ if (NULL == mem)
+ {
+ mem = GNUNET_new (struct Member);
+ mem->priv_key = msg->member_key;
+ mem->pub_key = mem_pub_key;
+ mem->pub_key_hash = mem_pub_key_hash;
+ mem->max_fragment_id = 0; // FIXME
+
+ grp = &mem->grp;
+ grp->is_origin = GNUNET_NO;
+ grp->pub_key = msg->group_key;
+ grp->pub_key_hash = pub_key_hash;
+
+ if (NULL == grp_mem)
+ {
+ grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
+ GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ }
+ GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ }
+ else
+ {
+ grp = &mem->grp;
+ }
+
+ struct ClientList *cl = GNUNET_new (struct ClientList);
+ cl->client = client;
+ GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%p Client connected to group %s..\n",
+ mem, GNUNET_h2s (&grp->pub_key_hash));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%p ..as member %s.\n",
+ mem, GNUNET_h2s (&mem_pub_key_hash));
+
+ GNUNET_SERVER_client_set_user_context (client, grp);
+
+ if (NULL != mem->join_dcsn)
+ { /* Already got a join decision, send it to client. */
+ GNUNET_SERVER_notification_context_add (nc, client);
+ GNUNET_SERVER_notification_context_unicast (nc, client,
+ (struct GNUNET_MessageHeader *)
+ mem->join_dcsn,
+ GNUNET_NO);
+ }
+ else if (grp->clients_head == grp->clients_tail)
+ { /* First client of the group, send join request. */
+ struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
+ uint32_t relay_count = ntohs (msg->relay_count);
+ uint16_t relay_size = relay_count * sizeof (*relays);
+ struct GNUNET_MessageHeader *join_msg = NULL;
+ uint16_t join_msg_size = 0;
+ if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
+ <= msg_size)
+ {
+ join_msg = (struct GNUNET_MessageHeader *)
+ (((char *) &msg[1]) + relay_size);
+ join_msg_size = ntohs (join_msg->size);
+ }
+ if (sizeof (*msg) + relay_size + join_msg_size != msg_size)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_client_disconnect (client);
+ return;
+ }
+
+ struct MulticastJoinRequestMessage *
+ req = GNUNET_malloc (sizeof (*req) + join_msg_size);
+ req->header.size = htons (sizeof (*req) + join_msg_size);
+ req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST);
+ req->group_key = grp->pub_key;
+ req->member_peer = this_peer;
+ GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_key);
+ if (0 < join_msg_size)
+ memcpy (&req[1], join_msg, join_msg_size);
+
+ req->purpose.size = htonl (sizeof (*req) + join_msg_size
+ - sizeof (req->header)
+ - sizeof (req->signature));
+ req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
+
+ if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
+ &req->signature))
+ {
+ /* FIXME: handle error */
+ GNUNET_assert (0);
+ }
+
+ if (NULL != mem->join_req)
+ GNUNET_free (mem->join_req);
+ mem->join_req = req;
+
+ if (GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (origins, &grp->pub_key_hash))
+ { /* Local origin */
+ message_to_origin (grp, (struct GNUNET_MessageHeader *) mem->join_req);
+ }
+ else
+ {
+ /* FIXME: send join request to remote peers */
+ }
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Join decision from client.
+ */
+static void
+client_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *m)
+{
+ struct Group *
+ grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
+ const struct MulticastJoinDecisionMessageHeader *
+ hdcsn = (const struct MulticastJoinDecisionMessageHeader *) m;
+ const struct MulticastJoinDecisionMessage *
+ dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%p Got join decision from client for group %s..\n",
+ grp, GNUNET_h2s (&grp->pub_key_hash));
+
+ if (GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (origins, &grp->pub_key_hash))
+ { /* Local origin */
+ struct GNUNET_CONTAINER_MultiHashMap *
+ grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
+ &grp->pub_key_hash);
+ if (NULL != grp_mem)
+ {
+ struct GNUNET_HashCode member_key_hash;
+ GNUNET_CRYPTO_hash (&hdcsn->member_key, sizeof (hdcsn->member_key),
+ &member_key_hash);
+ struct Member *
+ mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%p ..and member %s: %p\n",
+ grp, GNUNET_h2s (&member_key_hash), mem);
+ if (NULL != mem)
+ {
+ message_to_clients (&mem->grp, (struct GNUNET_MessageHeader *) hdcsn);
+ if (GNUNET_YES == ntohl (dcsn->is_admitted))
+ { /* Member admitted, store join_decision. */
+ uint16_t dcsn_size = ntohs (dcsn->header.size);
+ mem->join_dcsn = GNUNET_malloc (dcsn_size);
+ memcpy (mem->join_dcsn, dcsn, dcsn_size);
+ }
+ else
+ { /* Refused entry, disconnect clients. */
+ struct ClientList *cl = mem->grp.clients_head;
+ while (NULL != cl)
+ {
+ struct GNUNET_SERVER_Client *client = cl->client;
+ cl = cl->next;
+ GNUNET_SERVER_client_disconnect (client);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* FIXME: send join decision to hdcsn->peer */
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+/**
+ * Incoming message from a client.
+ */
+static void
+client_multicast_message (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *m)
+{
+ struct Group *
+ grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
+ GNUNET_assert (GNUNET_YES == grp->is_origin);
+ struct Origin *orig = (struct Origin *) grp;
+ struct GNUNET_MULTICAST_MessageHeader *
+ msg = (struct GNUNET_MULTICAST_MessageHeader *) m;
+
+ msg->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
+ msg->purpose.size = htonl (sizeof (*msg) + ntohs (m->size)
+ - sizeof (msg->header)
+ - sizeof (msg->hop_counter)
+ - sizeof (msg->signature));
+ msg->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
+
+ if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &msg->purpose,
+ &msg->signature))
+ {
+ /* FIXME: handle error */
+ GNUNET_assert (0);
+ }
+
+ /* FIXME: send to remote members */
+
+ message_to_group (grp, m);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Incoming request from a client.
+ */
+static void
+client_multicast_request (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *m)
+{
+ struct Group *
+ grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
+ GNUNET_assert (GNUNET_NO == grp->is_origin);
+ struct Member *mem = (struct Member *) grp;
+
+ struct GNUNET_MULTICAST_RequestHeader *
+ req = (struct GNUNET_MULTICAST_RequestHeader *) m;
+
+ req->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
+ req->purpose.size = htonl (sizeof (*req) + ntohs (m->size)
+ - sizeof (req->header)
+ - sizeof (req->member_key)
+ - sizeof (req->signature));
+ req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
+
+ if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
+ &req->signature))
+ {
+ /* FIXME: handle error */
+ GNUNET_assert (0);
+ }
+
+ if (GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (origins, &grp->pub_key_hash))
+ { /* Local origin */
+ message_to_origin (grp, m);
+ }
+ else
+ {
+ /* FIXME: send to remote origin */
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Connected to core service.
+ */
+static void
+core_connected_cb (void *cls, const struct GNUNET_PeerIdentity *my_identity)
+{
+ this_peer = *my_identity;
+
static const struct GNUNET_SERVER_MessageHandler handlers[] = {
- /* FIXME: add handlers here! */
+ { &client_origin_start, NULL,
+ GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START, 0 },
+
+ { &client_member_join, NULL,
+ GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN, 0 },
+
+ { &client_join_decision, NULL,
+ GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, 0 },
+
+ { &client_multicast_message, NULL,
+ GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, 0 },
+
+ { &client_multicast_request, NULL,
+ GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, 0 },
+
{NULL, NULL, 0, 0}
};
- /* FIXME: do setup here */
+
+ stats = GNUNET_STATISTICS_create ("multicast", cfg);
+ origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
+ members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
+ group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+ nc = GNUNET_SERVER_notification_context_create (server, 1);
+
GNUNET_SERVER_add_handlers (server, handlers);
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
+ GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
NULL);
}
+/**
+ * Service started.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *srv,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ cfg = c;
+ server = srv;
+ core = GNUNET_CORE_connect (cfg, NULL, core_connected_cb, NULL, NULL,
+ NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
+}
+
+
/**
* The main function for the multicast service.
*