2 * This file is part of GNUnet
3 * Copyright (C) 2013 Christian Grothoff (and other contributing authors)
5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your
8 * option) any later version.
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNUnet; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * @file social/gnunet-service-social.c
23 * @brief Social service
24 * @author Gabor X Toth
30 #include "gnunet_util_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_psyc_service.h"
35 #include "gnunet_psyc_util_lib.h"
36 #include "gnunet_social_service.h"
41 * Handle to our current configuration.
43 static const struct GNUNET_CONFIGURATION_Handle *cfg;
46 * Handle to the statistics service.
48 static struct GNUNET_STATISTICS_Handle *stats;
51 * Notification context, simplifies client broadcasts.
53 static struct GNUNET_SERVER_NotificationContext *nc;
56 * All connected hosts.
57 * H(place_pub_key) -> struct Host
59 static struct GNUNET_CONTAINER_MultiHashMap *hosts;
62 * All connected guests.
63 * H(place_pub_key) -> struct Guest
65 static struct GNUNET_CONTAINER_MultiHashMap *guests;
68 * Connected guests per place.
69 * H(place_pub_key) -> Guest's pub_key -> struct Guest
71 static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
74 * Places entered as host or guest.
75 * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest
77 static struct GNUNET_CONTAINER_MultiHashMap *places_entered;
80 * Place listener clients.
81 * H(ego_pub_key) -> struct PlaceListener
83 static struct GNUNET_CONTAINER_MultiHashMap *place_listeners;
86 * Directory for storing places.
88 static char *dir_places;
92 * Message fragment transmission queue.
94 struct FragmentTransmitQueue
96 struct FragmentTransmitQueue *prev;
97 struct FragmentTransmitQueue *next;
99 struct GNUNET_SERVER_Client *client;
102 * Pointer to the next message part inside the data after this struct.
104 struct GNUNET_MessageHeader *next_part;
112 * @see enum GNUNET_PSYC_MessageState
116 /* Followed by one or more message parts. */
121 * Message transmission queue.
123 struct MessageTransmitQueue
125 struct MessageTransmitQueue *prev;
126 struct MessageTransmitQueue *next;
128 struct FragmentTransmitQueue *frags_head;
129 struct FragmentTransmitQueue *frags_tail;
131 struct GNUNET_SERVER_Client *client;
135 * List of connected clients.
137 struct ClientListItem
139 struct ClientListItem *prev;
140 struct ClientListItem *next;
142 struct GNUNET_SERVER_Client *client;
147 * Common part of the client context for both a host and guest.
151 struct ClientListItem *clients_head;
152 struct ClientListItem *clients_tail;
154 struct MessageTransmitQueue *tmit_msgs_head;
155 struct MessageTransmitQueue *tmit_msgs_tail;
157 struct GNUNET_PSYC_Channel *channel;
160 * Public key of the channel.
162 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
165 * Hash of @a pub_key.
167 struct GNUNET_HashCode pub_key_hash;
170 * Last message ID received for the place.
171 * 0 if there is no such message.
173 uint64_t max_message_id;
176 * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
181 * Is this place ready to receive messages from client?
182 * #GNUNET_YES or #GNUNET_NO
187 * Is the client disconnected?
188 * #GNUNET_YES or #GNUNET_NO
190 uint8_t is_disconnected;
195 * Client context for a host.
200 * Place struct common for Host and Guest
205 * Private key of the channel.
207 struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
210 * Handle for the multicast origin.
212 struct GNUNET_PSYC_Master *master;
215 * Transmit handle for multicast.
217 struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
220 * Incoming join requests.
221 * guest_key -> struct GNUNET_PSYC_JoinHandle *
223 struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
226 * @see enum GNUNET_PSYC_Policy
228 enum GNUNET_PSYC_Policy policy;
233 * Client context for a guest.
238 * Place struct common for Host and Guest.
243 * Private key of the slave.
245 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
248 * Public key of the slave.
250 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
253 * Hash of @a pub_key.
255 struct GNUNET_HashCode pub_key_hash;
258 * Handle for the PSYC slave.
260 struct GNUNET_PSYC_Slave *slave;
263 * Transmit handle for multicast.
265 struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
268 * Peer identity of the origin.
270 struct GNUNET_PeerIdentity origin;
273 * Number of items in @a relays.
275 uint32_t relay_count;
278 * Relays that multicast can use to connect.
280 struct GNUNET_PeerIdentity *relays;
283 * Join request to be transmitted to the master on join.
285 struct GNUNET_MessageHeader *join_req;
288 * Join decision received from PSYC.
290 struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
296 * Context for host/guest client.
301 * Place where the client entered.
306 * Message queue for the message currently being transmitted
309 struct MessageTransmitQueue *tmit_msg;
312 * Ego key for listener clients;
314 struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
320 struct ClientListItem *clients_head;
321 struct ClientListItem *clients_tail;
325 struct OperationClosure
327 struct GNUNET_SERVER_Client *client;
335 psyc_transmit_message (struct Place *plc);
339 * Task run during shutdown.
345 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
349 GNUNET_SERVER_notification_context_destroy (nc);
354 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
361 * Clean up host data structures after a client disconnected.
364 cleanup_host (struct Host *hst)
366 struct Place *plc = &hst->plc;
368 if (NULL != hst->master)
369 GNUNET_PSYC_master_stop (hst->master, GNUNET_NO, NULL, NULL); // FIXME
370 GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
371 GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
376 * Clean up guest data structures after a client disconnected.
379 cleanup_guest (struct Guest *gst)
381 struct Place *plc = &gst->plc;
382 struct GNUNET_CONTAINER_MultiHashMap *
383 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
385 GNUNET_assert (NULL != plc_gst); // FIXME
386 GNUNET_CONTAINER_multihashmap_remove (plc_gst, &gst->pub_key_hash, gst);
388 if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
390 GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
392 GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
394 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
396 if (NULL != gst->join_req)
397 GNUNET_free (gst->join_req);
398 if (NULL != gst->relays)
399 GNUNET_free (gst->relays);
400 if (NULL != gst->slave)
401 GNUNET_PSYC_slave_part (gst->slave, GNUNET_NO, NULL, NULL); // FIXME
402 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
407 * Clean up place data structures after a client disconnected.
410 cleanup_place (struct Place *plc)
412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
413 "%p Cleaning up place %s\n",
414 plc, GNUNET_h2s (&plc->pub_key_hash));
416 (GNUNET_YES == plc->is_host)
417 ? cleanup_host ((struct Host *) plc)
418 : cleanup_guest ((struct Guest *) plc);
424 schedule_cleanup_place (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
431 * Called whenever a client is disconnected.
432 * Frees our resources associated with that client.
434 * @param cls Closure.
435 * @param client Identification of the client.
438 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
444 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
448 "%p User context is NULL in client_disconnect()\n", ctx);
453 struct Place *plc = ctx->plc;
455 return; // place listener client, nothing to do
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "%p Client (%s) disconnected from place %s\n",
459 plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
460 GNUNET_h2s (&plc->pub_key_hash));
462 struct ClientListItem *cli = plc->clients_head;
465 if (cli->client == client)
467 GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
474 if (NULL == plc->clients_head)
475 { /* Last client disconnected. */
476 if (GNUNET_YES != plc->is_disconnected)
478 plc->is_disconnected = GNUNET_YES;
479 if (NULL != plc->tmit_msgs_head)
480 { /* Send pending messages to PSYC before cleanup. */
481 psyc_transmit_message (plc);
493 * Send message to all clients connected to the channel.
496 client_send_msg (const struct Place *plc,
497 const struct GNUNET_MessageHeader *msg)
499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
500 "%p Sending message to clients.\n", plc);
502 struct ClientListItem *cli = plc->clients_head;
505 GNUNET_SERVER_notification_context_add (nc, cli->client);
506 GNUNET_SERVER_notification_context_unicast (nc, cli->client, msg, GNUNET_NO);
513 * Send a result code back to the client.
516 * Client that should receive the result code.
520 * Operation ID in network byte order.
522 * Data payload or NULL.
527 client_send_result (struct GNUNET_SERVER_Client *client, uint64_t op_id,
528 int64_t result_code, const void *data, uint16_t data_size)
530 struct GNUNET_OperationResultMessage *res;
532 res = GNUNET_malloc (sizeof (*res) + data_size);
533 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
534 res->header.size = htons (sizeof (*res) + data_size);
535 res->result_code = GNUNET_htonll (result_code);
538 memcpy (&res[1], data, data_size);
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541 "%p Sending result to client for operation #%" PRIu64 ": "
542 "%" PRId64 " (size: %u)\n",
543 client, GNUNET_ntohll (op_id), result_code, data_size);
545 GNUNET_SERVER_notification_context_add (nc, client);
546 GNUNET_SERVER_notification_context_unicast (nc, client, &res->header,
553 * Called after a PSYC master is started.
556 psyc_master_started (void *cls, int result, uint64_t max_message_id)
558 struct Host *hst = cls;
559 struct Place *plc = &hst->plc;
560 plc->max_message_id = max_message_id;
561 plc->is_ready = GNUNET_YES;
563 struct GNUNET_PSYC_CountersResultMessage res;
564 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
565 res.header.size = htons (sizeof (res));
566 res.result_code = htonl (result);
567 res.max_message_id = GNUNET_htonll (plc->max_message_id);
569 client_send_msg (plc, &res.header);
574 * Called when a PSYC master receives a join request.
577 psyc_recv_join_request (void *cls,
578 const struct GNUNET_PSYC_JoinRequestMessage *req,
579 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
580 const struct GNUNET_PSYC_Message *join_msg,
581 struct GNUNET_PSYC_JoinHandle *jh)
583 struct Host *hst = cls;
584 struct GNUNET_HashCode slave_key_hash;
585 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
586 GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
587 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
588 client_send_msg (&hst->plc, &req->header);
593 * Called after a PSYC slave is connected.
596 psyc_slave_connected (void *cls, int result, uint64_t max_message_id)
598 struct Guest *gst = cls;
599 struct Place *plc = &gst->plc;
600 plc->max_message_id = max_message_id;
601 plc->is_ready = GNUNET_YES;
603 struct GNUNET_PSYC_CountersResultMessage res;
604 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
605 res.header.size = htons (sizeof (res));
606 res.result_code = htonl (result);
607 res.max_message_id = GNUNET_htonll (plc->max_message_id);
609 client_send_msg (plc, &res.header);
614 * Called when a PSYC slave receives a join decision.
617 psyc_recv_join_dcsn (void *cls,
618 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
620 const struct GNUNET_PSYC_Message *join_msg)
622 struct Guest *gst = cls;
623 client_send_msg (&gst->plc, &dcsn->header);
628 * Called when a PSYC master or slave receives a message.
631 psyc_recv_message (void *cls,
634 const struct GNUNET_PSYC_MessageHeader *msg)
636 struct Place *plc = cls;
638 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_key);
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640 "%p Received PSYC message of size %u from %s.\n",
641 plc, ntohs (msg->header.size), str);
644 client_send_msg (plc, &msg->header);
646 /* FIXME: further processing */
651 * Initialize place data structure.
654 place_init (struct Place *plc)
661 * Add place to places_entered hash map.
663 * @param ego_pub_hash
665 * @param place_pub_hash
670 * @return Return value of GNUNET_CONTAINER_multihashmap_put ()
673 place_add (const struct GNUNET_HashCode *ego_pub_hash,
674 const struct GNUNET_HashCode *place_pub_hash,
675 const struct GNUNET_MessageHeader *msg)
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 "Adding place to hashmap:\n");
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 " ego_pub_hash = %s\n", GNUNET_h2s (ego_pub_hash));
681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682 " place_pub_hash = %s\n", GNUNET_h2s (place_pub_hash));
684 struct GNUNET_CONTAINER_MultiHashMap *
685 ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, ego_pub_hash);
686 if (NULL == ego_places)
688 ego_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
689 GNUNET_CONTAINER_multihashmap_put (places_entered, ego_pub_hash, ego_places,
690 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
693 struct GNUNET_MessageHeader *msg_old, *msg_new;
694 if (NULL != (msg_old = GNUNET_CONTAINER_multihashmap_get (ego_places, place_pub_hash)))
696 GNUNET_free (msg_old);
697 GNUNET_CONTAINER_multihashmap_remove_all (ego_places, place_pub_hash);
700 uint16_t msg_size = ntohs (msg->size);
701 msg_new = GNUNET_malloc (msg_size);
702 memcpy (msg_new, msg, msg_size);
703 int ret = GNUNET_CONTAINER_multihashmap_put (ego_places, place_pub_hash, msg_new,
704 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
705 if (GNUNET_OK != ret)
712 * Save place entry message to disk.
715 * Private key of ego.
716 * @param place_pub_hash
717 * Hash of public key of place.
722 place_save (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ego_key,
723 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub,
724 const struct GNUNET_MessageHeader *msg)
726 if (NULL == dir_places)
729 struct GNUNET_HashCode place_pub_hash;
730 GNUNET_CRYPTO_hash (place_pub, sizeof (place_pub), &place_pub_hash);
732 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
733 struct GNUNET_HashCode ego_pub_hash;
734 GNUNET_CRYPTO_ecdsa_key_get_public (ego_key, &ego_pub);
735 GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
737 place_add (&ego_pub_hash, &place_pub_hash, msg);
739 char *ego_pub_hash_str = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1);
740 char *place_pub_hash_str = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1);
741 memcpy (ego_pub_hash_str, GNUNET_h2s_full (&ego_pub_hash), sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
742 memcpy (place_pub_hash_str, GNUNET_h2s_full (&place_pub_hash), sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
744 char *filename = GNUNET_malloc (strlen (dir_places) + 1
745 + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1
746 + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1);
747 GNUNET_asprintf (&filename,
749 dir_places, DIR_SEPARATOR_STR,
750 ego_pub_hash_str, DIR_SEPARATOR_STR,
753 GNUNET_DISK_directory_create_for_file (filename);
754 if (GNUNET_DISK_fn_write (filename, msg, ntohs (msg->size),
755 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE) < 0)
760 GNUNET_free (ego_pub_hash_str);
761 GNUNET_free (place_pub_hash_str);
762 GNUNET_free (filename);
767 * Enter place as host.
771 * @param[out] ret_hst
772 * Returned Host struct.
774 * @return #GNUNET_YES if the host entered the place just now,
775 * #GNUNET_NO if the place is already entered.
778 host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst)
781 struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
782 struct GNUNET_HashCode place_pub_hash;
784 GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
785 GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash);
787 struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash);
790 hst = GNUNET_new (struct Host);
791 hst->policy = ntohl (hreq->policy);
792 hst->priv_key = hreq->place_key;
793 hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
795 struct Place *plc = &hst->plc;
796 plc->is_host = GNUNET_YES;
797 plc->pub_key = place_pub;
798 plc->pub_key_hash = place_pub_hash;
801 GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
802 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
803 hst->master = GNUNET_PSYC_master_start (cfg, &hst->priv_key, hst->policy,
804 &psyc_master_started,
805 &psyc_recv_join_request,
806 &psyc_recv_message, NULL, hst);
807 hst->plc.channel = GNUNET_PSYC_master_get_channel (hst->master);
818 * Handle a connecting client entering a place as host.
821 client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
822 const struct GNUNET_MessageHeader *msg)
824 const struct HostEnterRequest *hreq
825 = (const struct HostEnterRequest *) msg;
829 switch (host_enter (hreq, &hst))
839 struct GNUNET_PSYC_CountersResultMessage res;
840 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
841 res.header.size = htons (sizeof (res));
842 res.result_code = htonl (GNUNET_OK);
843 res.max_message_id = GNUNET_htonll (plc->max_message_id);
845 GNUNET_SERVER_notification_context_add (nc, client);
846 GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
851 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
855 struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
856 GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
858 place_save (&hreq->host_key, &place_pub, msg);
860 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
861 "%p Client connected as host to place %s.\n",
862 hst, GNUNET_h2s (&plc->pub_key_hash));
864 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
865 cli->client = client;
866 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
868 struct Client *ctx = GNUNET_new (struct Client);
870 GNUNET_SERVER_client_set_user_context (client, ctx);
871 GNUNET_SERVER_receive_done (client, GNUNET_OK);
876 * Enter place as guest.
880 * @param[out] ret_gst
881 * Returned Guest struct.
883 * @return #GNUNET_YES if the guest entered the place just now,
884 * #GNUNET_NO if the place is already entered.
887 guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst)
890 uint16_t greq_size = ntohs (greq->header.size);
892 struct GNUNET_CRYPTO_EcdsaPublicKey gst_pub_key;
893 struct GNUNET_HashCode place_pub_hash, gst_pub_key_hash;
894 GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &gst_pub_key);
895 GNUNET_CRYPTO_hash (&gst_pub_key, sizeof (gst_pub_key), &gst_pub_key_hash);
896 GNUNET_CRYPTO_hash (&greq->place_key, sizeof (greq->place_key), &place_pub_hash);
898 struct GNUNET_CONTAINER_MultiHashMap *
899 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash);
900 struct Guest *gst = NULL;
904 gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &gst_pub_key_hash);
906 if (NULL == gst || NULL == gst->slave)
908 gst = GNUNET_new (struct Guest);
909 gst->priv_key = greq->guest_key;
910 gst->pub_key = gst_pub_key;
911 gst->pub_key_hash = gst_pub_key_hash;
912 gst->origin = greq->origin;
913 gst->relay_count = ntohl (greq->relay_count);
915 const struct GNUNET_PeerIdentity *relays = NULL;
916 uint16_t relay_size = gst->relay_count * sizeof (*relays);
918 relays = (const struct GNUNET_PeerIdentity *) &greq[1];
919 struct GNUNET_PSYC_Message *join_msg = NULL;
920 uint16_t join_msg_size = 0;
922 if (sizeof (*greq) + relay_size + sizeof (struct GNUNET_MessageHeader)
925 join_msg = (struct GNUNET_PSYC_Message *)
926 (((char *) &greq[1]) + relay_size);
927 join_msg_size = ntohs (join_msg->header.size);
929 if (sizeof (*greq) + relay_size + join_msg_size != greq_size)
931 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
932 "%u + %u + %u != %u\n",
933 sizeof (*greq), relay_size, join_msg_size, greq_size);
936 return GNUNET_SYSERR;
938 if (0 < gst->relay_count)
940 gst->relays = GNUNET_malloc (relay_size);
941 memcpy (gst->relays, &greq[1], relay_size);
945 plc->is_host = GNUNET_NO;
946 plc->pub_key = greq->place_key;
947 plc->pub_key_hash = place_pub_hash;
952 plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
953 (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
954 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
956 (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &gst->pub_key_hash, gst,
957 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
958 (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
959 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
961 = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &gst->priv_key,
962 &gst->origin, gst->relay_count, gst->relays,
963 &psyc_recv_message, NULL, &psyc_slave_connected,
964 &psyc_recv_join_dcsn, gst, join_msg);
965 gst->plc.channel = GNUNET_PSYC_slave_get_channel (gst->slave);
976 * Handle a connecting client entering a place as guest.
979 client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client,
980 const struct GNUNET_MessageHeader *msg)
982 const struct GuestEnterRequest *
983 greq = (const struct GuestEnterRequest *) msg;
984 struct Guest *gst = NULL;
985 struct Place *plc = NULL;
987 switch (guest_enter (greq, &gst))
997 struct GNUNET_PSYC_CountersResultMessage res;
998 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
999 res.header.size = htons (sizeof (res));
1000 res.result_code = htonl (GNUNET_OK);
1001 res.max_message_id = GNUNET_htonll (plc->max_message_id);
1003 GNUNET_SERVER_notification_context_add (nc, client);
1004 GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
1006 if (NULL != gst->join_dcsn)
1008 GNUNET_SERVER_notification_context_add (nc, client);
1009 GNUNET_SERVER_notification_context_unicast (nc, client,
1010 &gst->join_dcsn->header,
1016 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1020 place_save (&greq->guest_key, &greq->place_key, msg);
1022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1023 "%p Client connected as guest to place %s.\n",
1024 gst, GNUNET_h2s (&gst->plc.pub_key_hash));
1026 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1027 cli->client = client;
1028 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1030 struct Client *ctx = GNUNET_new (struct Client);
1032 GNUNET_SERVER_client_set_user_context (client, ctx);
1033 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1038 place_notify (struct GNUNET_MessageHeader *msg,
1039 struct GNUNET_SERVER_Client *client)
1041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042 "%p Sending place notification of type %u to client.\n",
1043 client, ntohs (msg->type));
1045 uint16_t msg_size = ntohs (msg->size);
1046 struct GNUNET_CRYPTO_EcdsaPublicKey place_pub;
1048 switch (ntohs (msg->type))
1050 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
1051 if (msg_size < sizeof (struct HostEnterRequest))
1053 struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
1054 GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &place_pub);
1057 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
1058 if (msg_size < sizeof (struct GuestEnterRequest))
1060 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
1061 GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &place_pub);
1068 GNUNET_SERVER_notification_context_add (nc, client);
1069 GNUNET_SERVER_notification_context_unicast (nc, client, msg,
1075 map_entry_place (void *cls, const struct GNUNET_HashCode *key, void *value)
1077 place_notify (value, cls);
1083 * Handle a connecting client listening for entered places.
1086 client_recv_place_listen (void *cls, struct GNUNET_SERVER_Client *client,
1087 const struct GNUNET_MessageHeader *msg)
1089 const struct PlaceListenRequest *req
1090 = (const struct PlaceListenRequest *) msg;
1092 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
1093 struct GNUNET_HashCode ego_pub_hash;
1095 GNUNET_CRYPTO_ecdsa_key_get_public (&req->ego_key, &ego_pub);
1096 GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
1098 struct GNUNET_CONTAINER_MultiHashMap *
1099 ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, &ego_pub_hash);
1100 if (NULL != ego_places)
1101 GNUNET_CONTAINER_multihashmap_iterate (ego_places, map_entry_place, client);
1103 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1104 "%p Client connected to listen for entered places of ego %s.\n",
1105 NULL, GNUNET_h2s (&ego_pub_hash));
1107 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1108 cli->client = client;
1109 struct PlaceListener *pl = GNUNET_CONTAINER_multihashmap_get (place_listeners,
1112 pl = GNUNET_malloc (sizeof (*pl));
1113 (void) GNUNET_CONTAINER_multihashmap_put (place_listeners, &ego_pub_hash, pl,
1114 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1116 GNUNET_CONTAINER_DLL_insert (pl->clients_head, pl->clients_tail, cli);
1118 struct Client *ctx = GNUNET_new (struct Client);
1119 ctx->ego_key = req->ego_key;
1120 GNUNET_SERVER_client_set_user_context (client, ctx);
1121 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1125 struct JoinDecisionClosure
1127 int32_t is_admitted;
1128 struct GNUNET_PSYC_Message *msg;
1133 * Iterator callback for responding to join requests.
1136 psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
1139 struct JoinDecisionClosure *jcls = cls;
1140 struct GNUNET_PSYC_JoinHandle *jh = value;
1141 // FIXME: add relays
1142 GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
1148 * Handle an entry decision from a host client.
1151 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
1152 const struct GNUNET_MessageHeader *msg)
1155 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1156 GNUNET_assert (NULL != ctx);
1157 struct Place *plc = ctx->plc;
1158 GNUNET_assert (GNUNET_YES == plc->is_host);
1159 struct Host *hst = (struct Host *) plc;
1161 struct GNUNET_PSYC_JoinDecisionMessage *
1162 dcsn = (struct GNUNET_PSYC_JoinDecisionMessage *) msg;
1163 struct JoinDecisionClosure jcls;
1164 jcls.is_admitted = ntohl (dcsn->is_admitted);
1166 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
1167 ? (struct GNUNET_PSYC_Message *) &dcsn[1]
1170 struct GNUNET_HashCode slave_key_hash;
1171 GNUNET_CRYPTO_hash (&dcsn->slave_key, sizeof (dcsn->slave_key),
1174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1175 "%p Got join decision (%d) from client for place %s..\n",
1176 hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
1177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1178 "%p ..and slave %s.\n",
1179 hst, GNUNET_h2s (&slave_key_hash));
1181 GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_key_hash,
1182 &psyc_send_join_decision, &jcls);
1183 GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_key_hash);
1184 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1189 * Send acknowledgement to a client.
1191 * Sent after a message fragment has been passed on to multicast.
1193 * @param plc The place struct for the client.
1196 send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client)
1198 struct GNUNET_MessageHeader res;
1199 res.size = htons (sizeof (res));
1200 res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
1202 GNUNET_SERVER_notification_context_add (nc, client);
1203 GNUNET_SERVER_notification_context_unicast (nc, client, &res, GNUNET_NO);
1208 * Proceed to the next message part in the transmission queue.
1211 * Place where the transmission is going on.
1213 * Currently transmitted message.
1215 * Currently transmitted message fragment.
1217 * @return @a tmit_frag, or NULL if reached the end of fragment.
1219 static struct FragmentTransmitQueue *
1220 psyc_transmit_queue_next_part (struct Place *plc,
1221 struct MessageTransmitQueue *tmit_msg,
1222 struct FragmentTransmitQueue *tmit_frag)
1224 uint16_t psize = ntohs (tmit_frag->next_part->size);
1225 if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
1228 tmit_frag->next_part
1229 = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
1231 else /* Reached end of current fragment. */
1233 if (NULL != tmit_frag->client)
1234 send_message_ack (plc, tmit_frag->client);
1235 GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1236 GNUNET_free (tmit_frag);
1244 * Proceed to next message in transmission queue.
1247 * Place where the transmission is going on.
1249 * Currently transmitted message.
1251 * @return The next message in queue, or NULL if queue is empty.
1253 static struct MessageTransmitQueue *
1254 psyc_transmit_queue_next_msg (struct Place *plc,
1255 struct MessageTransmitQueue *tmit_msg)
1257 GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1258 GNUNET_free (tmit_msg);
1259 return plc->tmit_msgs_head;
1264 * Callback for data transmission to PSYC.
1267 psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1269 struct Place *plc = cls;
1270 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1271 GNUNET_assert (NULL != tmit_msg);
1272 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1273 if (NULL == tmit_frag)
1274 { /* Rest of the message have not arrived yet, pause transmission */
1278 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1282 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
1287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1288 "%p psyc_transmit_notify_data()\n", plc);
1289 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1291 uint16_t ptype = ntohs (pmsg->type);
1292 uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
1297 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1298 if (*data_size < pdata_size)
1300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1301 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306 "%p psyc_transmit_notify_data: sending %u bytes.\n",
1309 *data_size = pdata_size;
1310 memcpy (data, &pmsg[1], *data_size);
1314 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1319 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1321 ret = GNUNET_SYSERR;
1325 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1326 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
1328 ret = GNUNET_SYSERR;
1331 if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
1334 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1335 plc->is_disconnected = GNUNET_YES;
1336 GNUNET_SERVER_client_disconnect (tmit_frag->client);
1337 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1342 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1343 if (NULL != tmit_frag)
1345 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1346 ptype = ntohs (pmsg->type);
1349 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1352 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1353 ret = GNUNET_SYSERR;
1358 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1359 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1360 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1364 if (NULL == tmit_msg->frags_head
1365 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1366 { /* Reached end of current message. */
1367 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1371 if (ret != GNUNET_NO)
1373 if (NULL != tmit_msg)
1375 psyc_transmit_message (plc);
1377 else if (GNUNET_YES == plc->is_disconnected)
1379 /* FIXME: handle partial message (when still in_transmit) */
1380 cleanup_place (plc);
1388 * Callback for modifier transmission to PSYC.
1391 psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1392 uint8_t *oper, uint32_t *full_value_size)
1394 struct Place *plc = cls;
1395 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1396 GNUNET_assert (NULL != tmit_msg);
1397 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1398 if (NULL == tmit_frag)
1399 { /* Rest of the message have not arrived yet, pause transmission */
1403 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1407 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
1412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413 "%p psyc_transmit_notify_mod()\n", plc);
1414 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1416 uint16_t ptype = ntohs (pmsg->type);
1421 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1425 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1426 "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
1427 ret = GNUNET_SYSERR;
1430 struct GNUNET_PSYC_MessageModifier *
1431 pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
1432 uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
1434 if (*data_size < mod_size)
1436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1437 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1442 *full_value_size = ntohl (pmod->value_size);
1444 *data_size = mod_size;
1445 memcpy (data, &pmod[1], mod_size);
1450 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1455 "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
1456 ret = GNUNET_SYSERR;
1459 uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
1460 if (*data_size < mod_size)
1462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1463 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1468 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
1470 *data_size = mod_size;
1471 memcpy (data, &pmsg[1], *data_size);
1476 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1477 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1478 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1484 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1485 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
1487 ret = GNUNET_SYSERR;
1490 if (GNUNET_SYSERR == ret)
1493 ret = GNUNET_SYSERR;
1494 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1495 plc->is_disconnected = GNUNET_YES;
1496 GNUNET_SERVER_client_disconnect (tmit_frag->client);
1497 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1501 if (GNUNET_YES != ret)
1502 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1504 if (NULL == tmit_msg->frags_head
1505 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1506 { /* Reached end of current message. */
1507 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1514 * Callback for data transmission from a host to PSYC.
1517 host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1519 int ret = psyc_transmit_notify_data (cls, data_size, data);
1521 if (GNUNET_NO != ret)
1523 struct Host *hst = cls;
1524 hst->tmit_handle = NULL;
1531 * Callback for the transmit functions of multicast.
1534 guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1536 int ret = psyc_transmit_notify_data (cls, data_size, data);
1538 if (GNUNET_NO != ret)
1540 struct Guest *gst = cls;
1541 gst->tmit_handle = NULL;
1548 * Callback for modifier transmission from a host to PSYC.
1551 host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1552 uint8_t *oper, uint32_t *full_value_size)
1554 int ret = psyc_transmit_notify_mod (cls, data_size, data,
1555 oper, full_value_size);
1556 if (GNUNET_SYSERR == ret)
1558 struct Host *hst = cls;
1559 hst->tmit_handle = NULL;
1566 * Callback for modifier transmission from a guest to PSYC.
1569 guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1570 uint8_t *oper, uint32_t *full_value_size)
1572 int ret = psyc_transmit_notify_mod (cls, data_size, data,
1573 oper, full_value_size);
1574 if (GNUNET_SYSERR == ret)
1576 struct Guest *gst = cls;
1577 gst->tmit_handle = NULL;
1584 * Get method part of next message from transmission queue.
1587 * Next item in message transmission queue.
1589 * The message method is returned here.
1591 * @return #GNUNET_OK on success
1592 * #GNUNET_NO if there are no more messages in queue.
1593 * #GNUNET_SYSERR if the next message is malformed.
1596 psyc_transmit_queue_next_method (struct Place *plc,
1597 struct GNUNET_PSYC_MessageMethod **pmeth)
1599 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1600 if (NULL == tmit_msg)
1603 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1604 if (NULL == tmit_frag)
1610 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1612 || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
1614 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1615 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
1616 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
1618 return GNUNET_SYSERR;
1621 uint16_t psize = ntohs (pmsg->size);
1622 *pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
1623 if (psize < sizeof (**pmeth) + 1 || '\0' != *((char *) *pmeth + psize - 1))
1625 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1626 "%p psyc_transmit_queue_next_method: invalid method name.\n",
1627 plc, ntohs (pmsg->type));
1628 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1629 "%u <= %u || NUL != %u\n",
1630 sizeof (**pmeth), psize, *((char *) *pmeth + psize - 1));
1632 return GNUNET_SYSERR;
1635 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1641 * Transmit the next message in queue from the host to the PSYC channel.
1644 psyc_master_transmit_message (struct Host *hst)
1647 if (NULL == hst->tmit_handle)
1649 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1650 int ret = psyc_transmit_queue_next_method (&hst->plc, &pmeth);
1651 if (GNUNET_OK != ret)
1655 = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
1656 &host_transmit_notify_mod,
1657 &host_transmit_notify_data, hst,
1662 GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
1669 * Transmit the next message in queue from a guest to the PSYC channel.
1672 psyc_slave_transmit_message (struct Guest *gst)
1674 if (NULL == gst->tmit_handle)
1676 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1677 int ret = psyc_transmit_queue_next_method (&gst->plc, &pmeth);
1678 if (GNUNET_OK != ret)
1682 = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
1683 &guest_transmit_notify_mod,
1684 &guest_transmit_notify_data, gst,
1689 GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
1696 * Transmit a message to PSYC.
1699 psyc_transmit_message (struct Place *plc)
1703 ? psyc_master_transmit_message ((struct Host *) plc)
1704 : psyc_slave_transmit_message ((struct Guest *) plc);
1709 * Queue message parts for sending to PSYC.
1711 * @param plc Place to send to.
1712 * @param client Client the message originates from.
1713 * @param data_size Size of @a data.
1714 * @param data Concatenated message parts.
1715 * @param first_ptype First message part type in @a data.
1716 * @param last_ptype Last message part type in @a data.
1718 static struct MessageTransmitQueue *
1719 psyc_transmit_queue_message (struct Place *plc,
1720 struct GNUNET_SERVER_Client *client,
1723 uint16_t first_ptype, uint16_t last_ptype,
1724 struct MessageTransmitQueue *tmit_msg)
1726 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
1728 tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
1729 GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1731 else if (NULL == tmit_msg)
1736 struct FragmentTransmitQueue *
1737 tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
1738 memcpy (&tmit_frag[1], data, data_size);
1739 tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
1740 tmit_frag->client = client;
1741 tmit_frag->size = data_size;
1743 GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1744 tmit_msg->client = client;
1750 * Cancel transmission of current message to PSYC.
1752 * @param plc Place to send to.
1753 * @param client Client the message originates from.
1756 psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVER_Client *client)
1758 uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
1760 struct GNUNET_MessageHeader msg;
1761 msg.size = htons (sizeof (msg));
1762 msg.type = htons (type);
1764 psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
1765 psyc_transmit_message (plc);
1767 /* FIXME: cleanup */
1772 * Handle an incoming message from a client, to be transmitted to the place.
1775 client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
1776 const struct GNUNET_MessageHeader *msg)
1779 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1780 GNUNET_assert (NULL != ctx);
1781 struct Place *plc = ctx->plc;
1782 int ret = GNUNET_SYSERR;
1784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1785 "%p Received message from client.\n", plc);
1786 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
1788 if (GNUNET_YES != plc->is_ready)
1790 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1791 "%p Place is not ready yet, disconnecting client.\n", plc);
1793 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1797 uint16_t size = ntohs (msg->size);
1798 uint16_t psize = size - sizeof (*msg);
1799 if (psize < sizeof (struct GNUNET_MessageHeader)
1800 || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
1802 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1803 "%p Received message with invalid payload size (%u) from client.\n",
1806 psyc_transmit_cancel (plc, client);
1807 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1811 uint16_t first_ptype = 0, last_ptype = 0;
1813 == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
1814 &first_ptype, &last_ptype))
1816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1817 "%p Received invalid message part from client.\n", plc);
1819 psyc_transmit_cancel (plc, client);
1820 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1824 "%p Received message with first part type %u and last part type %u.\n",
1825 plc, first_ptype, last_ptype);
1828 = psyc_transmit_queue_message (plc, client, psize, &msg[1],
1829 first_ptype, last_ptype, ctx->tmit_msg);
1830 if (NULL != ctx->tmit_msg)
1832 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
1833 ctx->tmit_msg = NULL;
1834 ret = psyc_transmit_message (plc);
1837 if (GNUNET_OK != ret)
1839 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1840 "%p Received invalid message part from client.\n", plc);
1842 psyc_transmit_cancel (plc, client);
1843 ret = GNUNET_SYSERR;
1845 GNUNET_SERVER_receive_done (client, ret);
1850 * A historic message arrived from PSYC.
1853 psyc_recv_history_message (void *cls, uint64_t message_id, uint32_t flags,
1854 const struct GNUNET_PSYC_MessageHeader *msg)
1856 struct OperationClosure *opcls = cls;
1857 struct Place *plc = opcls->plc;
1859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860 "%p Received historic message #%" PRId64 " (flags: %x)\n",
1861 plc, message_id, flags);
1863 uint16_t size = ntohs (msg->header.size);
1865 struct GNUNET_OperationResultMessage *
1866 res = GNUNET_malloc (sizeof (*res) + size);
1867 res->header.size = htons (sizeof (*res) + size);
1868 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
1869 res->op_id = opcls->op_id;
1870 res->result_code = GNUNET_htonll (GNUNET_OK);
1872 memcpy (&res[1], msg, size);
1874 /** @todo FIXME: send only to requesting client */
1875 client_send_msg (plc, &res->header);
1880 * Result of message history replay from PSYC.
1883 psyc_recv_history_result (void *cls, int64_t result,
1884 const void *err_msg, uint16_t err_msg_size)
1886 struct OperationClosure *opcls = cls;
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1888 "%p History replay #%" PRIu64 ": "
1889 "PSYCstore returned %" PRId64 " (%.*s)\n",
1890 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
1892 // FIXME: place might have been destroyed
1893 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
1898 * Client requests channel history.
1901 client_recv_history_replay (void *cls, struct GNUNET_SERVER_Client *client,
1902 const struct GNUNET_MessageHeader *msg)
1905 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1906 GNUNET_assert (NULL != ctx);
1907 struct Place *plc = ctx->plc;
1909 const struct GNUNET_PSYC_HistoryRequestMessage *
1910 req = (const struct GNUNET_PSYC_HistoryRequestMessage *) msg;
1911 uint16_t size = ntohs (msg->size);
1912 const char *method_prefix = (const char *) &req[1];
1914 if (size < sizeof (*req) + 1
1915 || '\0' != method_prefix[size - sizeof (*req) - 1])
1917 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1918 "%p History replay #%" PRIu64 ": "
1919 "invalid method prefix. size: %u < %u?\n",
1920 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
1922 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1926 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
1927 opcls->client = client;
1929 opcls->op_id = req->op_id;
1930 opcls->flags = ntohl (req->flags);
1932 if (0 == req->message_limit)
1933 GNUNET_PSYC_channel_history_replay (plc->channel,
1934 GNUNET_ntohll (req->start_message_id),
1935 GNUNET_ntohll (req->end_message_id),
1936 method_prefix, opcls->flags,
1937 &psyc_recv_history_message, NULL,
1938 &psyc_recv_history_result, opcls);
1940 GNUNET_PSYC_channel_history_replay_latest (plc->channel,
1941 GNUNET_ntohll (req->message_limit),
1942 method_prefix, opcls->flags,
1943 &psyc_recv_history_message, NULL,
1944 &psyc_recv_history_result, opcls);
1946 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1951 * A state variable part arrived from PSYC.
1954 psyc_recv_state_var (void *cls,
1955 const struct GNUNET_MessageHeader *mod,
1958 uint32_t value_size,
1959 uint32_t full_value_size)
1961 struct OperationClosure *opcls = cls;
1962 struct Place *plc = opcls->plc;
1964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1965 "%p Received state variable %s from PSYC\n",
1968 uint16_t size = ntohs (mod->size);
1970 struct GNUNET_OperationResultMessage *
1971 res = GNUNET_malloc (sizeof (*res) + size);
1972 res->header.size = htons (sizeof (*res) + size);
1973 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
1974 res->op_id = opcls->op_id;
1975 res->result_code = GNUNET_htonll (GNUNET_OK);
1977 memcpy (&res[1], mod, size);
1979 /** @todo FIXME: send only to requesting client */
1980 client_send_msg (plc, &res->header);
1985 * Result of retrieving state variable from PSYC.
1988 psyc_recv_state_result (void *cls, int64_t result,
1989 const void *err_msg, uint16_t err_msg_size)
1991 struct OperationClosure *opcls = cls;
1992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1993 "%p State get #%" PRIu64 ": "
1994 "PSYCstore returned %" PRId64 " (%.*s)\n",
1995 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
1997 // FIXME: place might have been destroyed
1998 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
2003 * Client requests channel history.
2006 client_recv_state_get (void *cls, struct GNUNET_SERVER_Client *client,
2007 const struct GNUNET_MessageHeader *msg)
2010 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2011 GNUNET_assert (NULL != ctx);
2012 struct Place *plc = ctx->plc;
2014 const struct GNUNET_PSYC_StateRequestMessage *
2015 req = (const struct GNUNET_PSYC_StateRequestMessage *) msg;
2016 uint16_t size = ntohs (msg->size);
2017 const char *name = (const char *) &req[1];
2019 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2020 "%p State get #%" PRIu64 ": %s\n",
2021 plc, GNUNET_ntohll (req->op_id), name);
2023 if (size < sizeof (*req) + 1
2024 || '\0' != name[size - sizeof (*req) - 1])
2026 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2027 "%p State get #%" PRIu64 ": "
2028 "invalid name. size: %u < %u?\n",
2029 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2031 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2035 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2036 opcls->client = client;
2038 opcls->op_id = req->op_id;
2040 switch (ntohs (msg->type))
2042 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
2043 GNUNET_PSYC_channel_state_get (plc->channel, name,
2044 psyc_recv_state_var,
2045 psyc_recv_state_result, opcls);
2048 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
2049 GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
2050 psyc_recv_state_var,
2051 psyc_recv_state_result, opcls);
2058 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2062 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2063 { &client_recv_host_enter, NULL,
2064 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
2066 { &client_recv_guest_enter, NULL,
2067 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
2069 { &client_recv_join_decision, NULL,
2070 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
2072 { &client_recv_psyc_message, NULL,
2073 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 },
2075 { &client_recv_history_replay, NULL,
2076 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, 0 },
2078 { &client_recv_state_get, NULL,
2079 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, 0 },
2081 { &client_recv_state_get, NULL,
2082 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 },
2084 { &client_recv_place_listen, NULL,
2085 GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN, 0 },
2087 { NULL, NULL, 0, 0 }
2092 file_place_load (void *cls, const char *filename)
2096 GNUNET_DISK_file_size (filename, &fsize, GNUNET_YES, GNUNET_YES)
2097 || fsize < sizeof (struct HostEnterRequest))
2100 struct GNUNET_MessageHeader *msg = GNUNET_malloc (fsize);
2101 ssize_t rsize = GNUNET_DISK_fn_read (filename, msg, fsize);
2102 if (rsize < 0 || (size_t) rsize < sizeof (*msg))
2105 uint16_t msg_size = ntohs (msg->size);
2106 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
2107 struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
2109 switch (ntohs (msg->type))
2111 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
2112 if (msg_size < sizeof (struct HostEnterRequest))
2114 struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
2115 GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &ego_pub);
2116 GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
2118 host_enter (hreq, NULL);
2121 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
2122 if (msg_size < sizeof (struct GuestEnterRequest))
2124 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
2125 GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &ego_pub);
2126 place_pub = greq->place_key;
2128 guest_enter (greq, NULL);
2135 struct GNUNET_HashCode ego_pub_hash, place_pub_hash;
2136 GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
2137 GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash);
2139 place_add (&ego_pub_hash, &place_pub_hash, msg);
2145 load_places_of_ego (void *cls, const char *dir_ego)
2147 if (GNUNET_YES != GNUNET_DISK_directory_test (dir_ego, GNUNET_YES))
2150 GNUNET_DISK_directory_scan (dir_ego, file_place_load, NULL);
2159 GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "PLACES_DIR",
2162 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "social", "PLACES_DIR");
2167 places_entered = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
2168 GNUNET_DISK_directory_scan (dir_places, load_places_of_ego, NULL);
2173 * Initialize the PSYC service.
2175 * @param cls Closure.
2176 * @param server The initialized server.
2177 * @param c Configuration to use.
2180 run (void *cls, struct GNUNET_SERVER_Handle *server,
2181 const struct GNUNET_CONFIGURATION_Handle *c)
2184 stats = GNUNET_STATISTICS_create ("social", cfg);
2185 hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2186 guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2187 place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2188 place_listeners = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2191 nc = GNUNET_SERVER_notification_context_create (server, 1);
2192 GNUNET_SERVER_add_handlers (server, handlers);
2193 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
2194 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2195 &shutdown_task, NULL);
2200 * The main function for the service.
2202 * @param argc number of arguments from the command line
2203 * @param argv command line arguments
2204 * @return 0 ok, 1 on error
2207 main (int argc, char *const *argv)
2209 return (GNUNET_OK ==
2210 GNUNET_SERVICE_run (argc, argv, "social",
2211 GNUNET_SERVICE_OPTION_NONE,
2212 &run, NULL)) ? 0 : 1;
2215 /* end of gnunet-service-social.c */