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
31 #include "gnunet_util_lib.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_core_service.h"
35 #include "gnunet_identity_service.h"
36 #include "gnunet_namestore_service.h"
37 #include "gnunet_gns_service.h"
38 #include "gnunet_statistics_service.h"
39 #include "gnunet_psyc_service.h"
40 #include "gnunet_psyc_util_lib.h"
41 #include "gnunet_social_service.h"
46 * Handle to our current configuration.
48 static const struct GNUNET_CONFIGURATION_Handle *cfg;
50 /* Handles to other services */
51 static struct GNUNET_CORE_Handle *core;
52 static struct GNUNET_IDENTITY_Handle *id;
53 static struct GNUNET_GNS_Handle *gns;
54 static struct GNUNET_NAMESTORE_Handle *namestore;
55 static struct GNUNET_STATISTICS_Handle *stats;
60 static struct GNUNET_PeerIdentity this_peer;
63 * Notification context, simplifies client broadcasts.
65 static struct GNUNET_SERVER_NotificationContext *nc;
68 * All connected hosts.
69 * H(place_pub_key) -> struct Host
71 static struct GNUNET_CONTAINER_MultiHashMap *hosts;
74 * All connected guests.
75 * H(place_pub_key) -> struct Guest
77 static struct GNUNET_CONTAINER_MultiHashMap *guests;
80 * Connected guests per place.
81 * H(place_pub_key) -> ego_pub_key -> struct Guest
83 static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
86 * Places entered as host or guest.
87 * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest
89 static struct GNUNET_CONTAINER_MultiHashMap *places;
92 * Places entered per application.
93 * H(app_id) -> H(place_pub_key) -> NULL
95 static struct GNUNET_CONTAINER_MultiHashMap *apps_places;
98 * Application subscriptions per place.
99 * H(place_pub_key) -> H(app_id)
101 static struct GNUNET_CONTAINER_MultiHashMap *places_apps;
104 * Connected applications.
105 * H(app_id) -> struct Application
107 static struct GNUNET_CONTAINER_MultiHashMap *apps;
111 * H(ego_pub_key) -> struct Ego
113 static struct GNUNET_CONTAINER_MultiHashMap *egos;
116 * Directory for storing social data.
117 * Default: $GNUNET_DATA_HOME/social
119 static char *dir_social;
122 * Directory for storing place data.
125 static char *dir_places;
128 * Directory for storing app data.
131 static char *dir_apps;
135 * Message fragment transmission queue.
137 struct FragmentTransmitQueue
139 struct FragmentTransmitQueue *prev;
140 struct FragmentTransmitQueue *next;
142 struct GNUNET_SERVER_Client *client;
145 * Pointer to the next message part inside the data after this struct.
147 struct GNUNET_MessageHeader *next_part;
155 * @see enum GNUNET_PSYC_MessageState
159 /* Followed by one or more message parts. */
164 * Message transmission queue.
166 struct MessageTransmitQueue
168 struct MessageTransmitQueue *prev;
169 struct MessageTransmitQueue *next;
171 struct FragmentTransmitQueue *frags_head;
172 struct FragmentTransmitQueue *frags_tail;
174 struct GNUNET_SERVER_Client *client;
178 * List of connected clients.
180 struct ClientListItem
182 struct ClientListItem *prev;
183 struct ClientListItem *next;
185 struct GNUNET_SERVER_Client *client;
190 * Common part of the client context for both a host and guest.
194 struct ClientListItem *clients_head;
195 struct ClientListItem *clients_tail;
197 struct MessageTransmitQueue *tmit_msgs_head;
198 struct MessageTransmitQueue *tmit_msgs_tail;
200 struct GNUNET_PSYC_Channel *channel;
203 * Private key of home in case of a host.
205 struct GNUNET_CRYPTO_EddsaPublicKey key;
208 * Public key of place.
210 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
213 * Hash of @a pub_key.
215 struct GNUNET_HashCode pub_key_hash;
218 * Private key of ego.
220 struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
225 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
228 * Hash of @a ego_pub_key.
230 struct GNUNET_HashCode ego_pub_hash;
232 uint64_t file_message_id;
233 uint64_t file_fragment_offset;
235 uint64_t file_offset;
238 * Last message ID received for the place.
239 * 0 if there is no such message.
241 uint64_t max_message_id;
244 * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
249 * Is this place ready to receive messages from client?
250 * #GNUNET_YES or #GNUNET_NO
255 * Is the client disconnected?
256 * #GNUNET_YES or #GNUNET_NO
258 uint8_t is_disconnected;
263 * Client context for a host.
268 * Place struct common for Host and Guest
273 * Handle for the multicast origin.
275 struct GNUNET_PSYC_Master *master;
278 * Transmit handle for multicast.
280 struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
283 * Incoming join requests.
284 * guest_key -> struct GNUNET_PSYC_JoinHandle *
286 struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
289 * @see enum GNUNET_PSYC_Policy
291 enum GNUNET_PSYC_Policy policy;
296 * Client context for a guest.
301 * Place struct common for Host and Guest.
306 * Handle for the PSYC slave.
308 struct GNUNET_PSYC_Slave *slave;
311 * Transmit handle for multicast.
313 struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
316 * Peer identity of the origin.
318 struct GNUNET_PeerIdentity origin;
321 * Number of items in @a relays.
323 uint32_t relay_count;
326 * Relays that multicast can use to connect.
328 struct GNUNET_PeerIdentity *relays;
331 * Join request to be transmitted to the master on join.
333 struct GNUNET_MessageHeader *join_req;
336 * Join decision received from PSYC.
338 struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
341 * Join flags for the PSYC service.
343 enum GNUNET_PSYC_SlaveJoinFlags join_flags;
348 * Context for a client.
353 * Place where the client entered.
358 * Message queue for the message currently being transmitted
361 struct MessageTransmitQueue *tmit_msg;
364 * ID for application clients.
372 struct ClientListItem *clients_head;
373 struct ClientListItem *clients_tail;
378 struct GNUNET_CRYPTO_EcdsaPrivateKey key;
383 struct OperationClosure
385 struct GNUNET_SERVER_Client *client;
393 psyc_transmit_message (struct Place *plc);
397 cleanup_place (struct Place *plc);
401 place_entry_cleanup (void *cls, const struct GNUNET_HashCode *key, void *value)
403 cleanup_place (value);
409 * Task run during shutdown.
415 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
417 GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL);
418 GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL);
422 GNUNET_SERVER_notification_context_destroy (nc);
427 GNUNET_CORE_disconnect (core);
432 GNUNET_IDENTITY_disconnect (id);
435 if (NULL != namestore)
437 GNUNET_NAMESTORE_disconnect (namestore);
442 GNUNET_GNS_disconnect (gns);
447 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
454 * Clean up host data structures after a client disconnected.
457 cleanup_host (struct Host *hst)
459 struct Place *plc = &hst->plc;
461 if (NULL != hst->master)
462 GNUNET_PSYC_master_stop (hst->master, GNUNET_NO, NULL, NULL); // FIXME
463 GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
464 GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
469 * Clean up guest data structures after a client disconnected.
472 cleanup_guest (struct Guest *gst)
474 struct Place *plc = &gst->plc;
475 struct GNUNET_CONTAINER_MultiHashMap *
476 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
478 GNUNET_assert (NULL != plc_gst); // FIXME
479 GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst);
481 if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
483 GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
485 GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
487 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
489 if (NULL != gst->join_req)
490 GNUNET_free (gst->join_req);
491 if (NULL != gst->relays)
492 GNUNET_free (gst->relays);
493 if (NULL != gst->slave)
494 GNUNET_PSYC_slave_part (gst->slave, GNUNET_NO, NULL, NULL); // FIXME
495 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
500 * Clean up place data structures after a client disconnected.
503 cleanup_place (struct Place *plc)
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
506 "%p Cleaning up place %s\n",
507 plc, GNUNET_h2s (&plc->pub_key_hash));
509 (GNUNET_YES == plc->is_host)
510 ? cleanup_host ((struct Host *) plc)
511 : cleanup_guest ((struct Guest *) plc);
517 schedule_cleanup_place (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
524 * Called whenever a client is disconnected.
525 * Frees our resources associated with that client.
527 * @param cls Closure.
528 * @param client Identification of the client.
531 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
537 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541 "%p User context is NULL in client_disconnect()\n", ctx);
545 struct Place *plc = ctx->plc;
547 if (NULL != ctx->app_id)
548 GNUNET_free (ctx->app_id);
553 return; // application client, nothing to do
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556 "%p Client (%s) disconnected from place %s\n",
557 plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
558 GNUNET_h2s (&plc->pub_key_hash));
560 struct ClientListItem *cli = plc->clients_head;
563 if (cli->client == client)
565 GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
575 * Send message to a client.
578 client_send_msg (struct GNUNET_SERVER_Client *client,
579 const struct GNUNET_MessageHeader *msg)
581 GNUNET_SERVER_notification_context_add (nc, client);
582 GNUNET_SERVER_notification_context_unicast (nc, client, msg, GNUNET_NO);
587 * Send message to all clients connected to a place.
590 place_send_msg (const struct Place *plc,
591 const struct GNUNET_MessageHeader *msg)
593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
594 "%p Sending message to clients of place.\n", plc);
596 struct ClientListItem *cli = plc->clients_head;
599 client_send_msg (cli->client, msg);
606 * Send a result code back to the client.
609 * Client that should receive the result code.
613 * Operation ID in network byte order.
615 * Data payload or NULL.
620 client_send_result (struct GNUNET_SERVER_Client *client, uint64_t op_id,
621 int64_t result_code, const void *data, uint16_t data_size)
623 struct GNUNET_OperationResultMessage *res;
625 res = GNUNET_malloc (sizeof (*res) + data_size);
626 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
627 res->header.size = htons (sizeof (*res) + data_size);
628 res->result_code = GNUNET_htonll (result_code);
631 memcpy (&res[1], data, data_size);
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "%p Sending result to client for operation #%" PRIu64 ": "
635 "%" PRId64 " (size: %u)\n",
636 client, GNUNET_ntohll (op_id), result_code, data_size);
638 client_send_msg (client, &res->header);
644 client_send_host_enter_ack (struct GNUNET_SERVER_Client *client,
645 struct Host *hst, uint32_t result)
647 struct Place *plc = &hst->plc;
649 struct HostEnterAck hack;
650 hack.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
651 hack.header.size = htons (sizeof (hack));
652 hack.result_code = htonl (result);
653 hack.max_message_id = GNUNET_htonll (plc->max_message_id);
654 hack.place_pub_key = plc->pub_key;
657 client_send_msg (client, &hack.header);
659 place_send_msg (plc, &hack.header);
664 * Called after a PSYC master is started.
667 psyc_master_started (void *cls, int result, uint64_t max_message_id)
669 struct Host *hst = cls;
670 struct Place *plc = &hst->plc;
671 plc->max_message_id = max_message_id;
672 plc->is_ready = GNUNET_YES;
674 client_send_host_enter_ack (NULL, hst, result);
679 * Called when a PSYC master receives a join request.
682 psyc_recv_join_request (void *cls,
683 const struct GNUNET_PSYC_JoinRequestMessage *req,
684 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
685 const struct GNUNET_PSYC_Message *join_msg,
686 struct GNUNET_PSYC_JoinHandle *jh)
688 struct Host *hst = cls;
689 struct GNUNET_HashCode slave_key_hash;
690 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
691 GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
692 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
693 place_send_msg (&hst->plc, &req->header);
698 * Called after a PSYC slave is connected.
701 psyc_slave_connected (void *cls, int result, uint64_t max_message_id)
703 struct Guest *gst = cls;
704 struct Place *plc = &gst->plc;
705 plc->max_message_id = max_message_id;
706 plc->is_ready = GNUNET_YES;
708 struct GNUNET_PSYC_CountersResultMessage res;
709 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
710 res.header.size = htons (sizeof (res));
711 res.result_code = htonl (result);
712 res.max_message_id = GNUNET_htonll (plc->max_message_id);
714 place_send_msg (plc, &res.header);
719 * Called when a PSYC slave receives a join decision.
722 psyc_recv_join_dcsn (void *cls,
723 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
725 const struct GNUNET_PSYC_Message *join_msg)
727 struct Guest *gst = cls;
728 place_send_msg (&gst->plc, &dcsn->header);
732 * Save _file data to disk.
735 psyc_recv_file (struct Place *plc, const struct GNUNET_PSYC_MessageHeader *msg,
736 uint32_t flags, uint64_t message_id, uint64_t fragment_offset,
737 const char *method_name, struct GNUNET_ENV_Environment *env,
738 const void *data, uint16_t data_size)
740 if (plc->file_message_id != message_id)
742 if (0 != fragment_offset)
744 /* unexpected message ID */
750 plc->file_offset = 0;
753 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
754 memcpy (&place_pub_hash_ascii.encoding,
755 GNUNET_h2s_full (&plc->pub_key_hash), sizeof (place_pub_hash_ascii));
757 char *filename = NULL;
758 GNUNET_asprintf (&filename, "%s%c%s%c%s%c%" PRIu64,
759 dir_social, DIR_SEPARATOR,
760 "files", DIR_SEPARATOR,
761 place_pub_hash_ascii.encoding, DIR_SEPARATOR,
763 GNUNET_DISK_directory_create_for_file (filename);
764 struct GNUNET_DISK_FileHandle *
765 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE,
766 GNUNET_DISK_PERM_USER_READ
767 | GNUNET_DISK_PERM_USER_WRITE);
768 GNUNET_free (filename);
770 GNUNET_DISK_file_seek (fh, plc->file_offset, GNUNET_DISK_SEEK_SET);
771 GNUNET_DISK_file_write (fh, data, data_size);
772 GNUNET_DISK_file_close (fh);
773 plc->file_offset += data_size;
778 * Called when a PSYC master or slave receives a message.
781 psyc_recv_message (void *cls,
784 const struct GNUNET_PSYC_MessageHeader *msg)
786 struct Place *plc = cls;
788 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_key);
789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
790 "%p Received PSYC message of size %u from %s.\n",
791 plc, ntohs (msg->header.size), str);
794 /* process message */
795 /* FIXME: use slicer */
796 const char *method_name = NULL;
797 struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
798 const void *data = NULL;
799 uint16_t data_size = 0;
801 if (GNUNET_SYSERR == GNUNET_PSYC_message_parse (msg, &method_name, env, &data, &data_size))
807 char *method_found = strstr (method_name, "_file");
808 if (method_name == method_found)
810 method_found += strlen ("_file");
811 if (('\0' == *method_found) || ('_' == *method_found))
813 psyc_recv_file (plc, msg, flags, message_id, GNUNET_ntohll (msg->fragment_offset),
814 method_name, env, data, data_size);
818 GNUNET_ENV_environment_destroy (env);
820 place_send_msg (plc, &msg->header);
825 * Initialize place data structure.
828 place_init (struct Place *plc)
834 * Add a place to the @e places hash map.
839 * @return #GNUNET_OK if the place was added
840 * #GNUNET_NO if the place already exists in the hash map
841 * #GNUNET_SYSERR on error
844 place_add (const struct PlaceEnterRequest *ereq)
846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847 "Adding place to hashmap:\n");
849 struct EgoPlacePublicKey ego_place_pub_key = {
850 .ego_pub_key = ereq->ego_pub_key,
851 .place_pub_key = ereq->place_pub_key,
853 struct GNUNET_HashCode ego_place_pub_hash;
854 GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
857 " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
859 struct GNUNET_MessageHeader *
860 place_msg = GNUNET_CONTAINER_multihashmap_get (places, &ego_place_pub_hash);
861 if (NULL != place_msg)
864 place_msg = GNUNET_copy_message (&ereq->header);
865 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, &ego_place_pub_hash, place_msg,
866 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
869 GNUNET_free (place_msg);
870 return GNUNET_SYSERR;
877 * Add a place to the @e app_places hash map.
884 * @return #GNUNET_OK if the place was added
885 * #GNUNET_NO if the place already exists in the hash map
886 * #GNUNET_SYSERR on error
889 app_place_add (const char *app_id,
890 const struct PlaceEnterRequest *ereq)
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "Adding app place to hashmap:\n");
894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
895 " app_id = %s\n", app_id);
897 struct GNUNET_HashCode app_id_hash;
898 GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
900 struct EgoPlacePublicKey ego_place_pub_key = {
901 .ego_pub_key = ereq->ego_pub_key,
902 .place_pub_key = ereq->place_pub_key,
904 struct GNUNET_HashCode ego_place_pub_hash;
905 GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
908 " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
910 struct GNUNET_CONTAINER_MultiHashMap *
911 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
912 if (NULL == app_places)
914 app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
915 GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places,
916 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
919 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, &ego_place_pub_hash))
922 if (GNUNET_SYSERR == place_add (ereq))
923 return GNUNET_SYSERR;
925 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, &ego_place_pub_hash, NULL,
926 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
929 return GNUNET_SYSERR;
932 struct GNUNET_HashCode place_pub_hash;
933 GNUNET_CRYPTO_hash (&ereq->place_pub_key, sizeof (ereq->place_pub_key), &place_pub_hash);
935 struct GNUNET_CONTAINER_MultiHashMap *
936 place_apps = GNUNET_CONTAINER_multihashmap_get (places_apps, &place_pub_hash);
937 if (NULL == place_apps)
939 place_apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
940 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places_apps, &place_pub_hash, place_apps,
941 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
948 size_t app_id_size = strlen (app_id);
949 void *app_id_value = GNUNET_malloc (app_id_size);
950 memcpy (app_id_value, app_id, app_id_size);
952 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (place_apps, &app_id_hash, app_id_value,
953 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
963 * Save place entry message to disk.
971 app_place_save (const char *app_id,
972 const struct PlaceEnterRequest *ereq)
974 app_place_add (app_id, ereq);
976 if (NULL == dir_places)
977 return GNUNET_SYSERR;
979 struct GNUNET_HashCode ego_pub_hash;
980 struct GNUNET_HashCode place_pub_hash;
981 GNUNET_CRYPTO_hash (&ereq->ego_pub_key, sizeof (ereq->ego_pub_key),
983 GNUNET_CRYPTO_hash (&ereq->place_pub_key, sizeof (ereq->place_pub_key),
986 struct GNUNET_CRYPTO_HashAsciiEncoded ego_pub_hash_ascii;
987 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
988 memcpy (&ego_pub_hash_ascii.encoding,
989 GNUNET_h2s_full (&ego_pub_hash), sizeof (ego_pub_hash_ascii));
990 memcpy (&place_pub_hash_ascii.encoding,
991 GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
993 char *filename = NULL;
994 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
995 dir_social, DIR_SEPARATOR,
996 "places", DIR_SEPARATOR,
997 ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
998 place_pub_hash_ascii.encoding);
999 int ret = GNUNET_DISK_directory_create_for_file (filename);
1000 if (GNUNET_OK != ret
1001 || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size),
1002 GNUNET_DISK_PERM_USER_READ
1003 | GNUNET_DISK_PERM_USER_WRITE))
1006 ret = GNUNET_SYSERR;
1008 GNUNET_free (filename);
1010 if (ret == GNUNET_OK)
1012 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s",
1013 dir_social, DIR_SEPARATOR,
1014 "apps", DIR_SEPARATOR,
1015 app_id, DIR_SEPARATOR,
1016 ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
1017 place_pub_hash_ascii.encoding);
1018 ret = GNUNET_DISK_directory_create_for_file (filename);
1019 if (GNUNET_OK != ret
1020 || 0 > GNUNET_DISK_fn_write (filename, "", 0,
1021 GNUNET_DISK_PERM_USER_READ
1022 | GNUNET_DISK_PERM_USER_WRITE))
1025 ret = GNUNET_SYSERR;
1027 GNUNET_free (filename);
1034 app_place_remove (const char *app_id,
1035 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key)
1037 struct GNUNET_HashCode place_pub_hash;
1038 GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash);
1040 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
1041 memcpy (&place_pub_hash_ascii.encoding,
1042 GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
1044 char *app_place_filename = NULL;
1045 GNUNET_asprintf (&app_place_filename,
1047 dir_social, DIR_SEPARATOR,
1048 "apps", DIR_SEPARATOR,
1049 app_id, DIR_SEPARATOR,
1050 place_pub_hash_ascii.encoding);
1052 struct GNUNET_HashCode app_id_hash;
1053 GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
1055 struct GNUNET_CONTAINER_MultiHashMap *
1056 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1058 if (NULL != app_places)
1059 GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL);
1061 struct GNUNET_CONTAINER_MultiHashMap *
1062 place_apps = GNUNET_CONTAINER_multihashmap_get (places_apps, &place_pub_hash);
1063 if (NULL != place_apps)
1065 void *app_id_value = GNUNET_CONTAINER_multihashmap_get (place_apps, &app_id_hash);
1066 if (NULL != app_id_value)
1068 GNUNET_free (app_id_value);
1069 GNUNET_CONTAINER_multihashmap_remove_all (place_apps, &app_id_hash);
1074 int ret = unlink (app_place_filename);
1075 GNUNET_free (app_place_filename);
1079 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1080 "Error removing app place: unlink returned %d\n", errno);
1081 return GNUNET_SYSERR;
1089 * Enter place as host.
1093 * @param[out] ret_hst
1094 * Returned Host struct.
1096 * @return #GNUNET_YES if the host entered the place just now,
1097 * #GNUNET_NO if the place is already entered,
1098 * #GNUNET_SYSERR if place_pub_key was set
1099 * but its private key was not found
1102 host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst)
1104 int ret = GNUNET_NO;
1105 struct GNUNET_HashCode place_pub_hash;
1106 GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key),
1108 struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash);
1112 hst = GNUNET_new (struct Host);
1113 hst->policy = hreq->policy;
1114 hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1116 struct Place *plc = &hst->plc;
1118 plc->is_host = GNUNET_YES;
1119 plc->pub_key = hreq->place_pub_key;
1120 plc->pub_key_hash = place_pub_hash;
1122 GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
1123 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1124 hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy,
1125 &psyc_master_started,
1126 &psyc_recv_join_request,
1127 &psyc_recv_message, NULL, hst);
1128 hst->plc.channel = GNUNET_PSYC_master_get_channel (hst->master);
1132 if (NULL != ret_hst)
1139 * Handle a connecting client entering a place as host.
1142 client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
1143 const struct GNUNET_MessageHeader *msg)
1145 struct HostEnterRequest *hreq
1146 = (struct HostEnterRequest *) GNUNET_copy_message (msg);
1148 uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq);
1149 const char *app_id = NULL;
1150 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1],
1151 app_id_size, 1, &app_id);
1152 if (0 == offset || offset != app_id_size || app_id == NULL)
1154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1155 "offset = %u, app_id_size = %u, app_id = %s\n",
1156 offset, app_id_size, app_id);
1158 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1162 struct Host *hst = NULL;
1163 struct Place *plc = NULL;
1164 int ret = GNUNET_OK;
1166 struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key;
1167 memset (&empty_pub_key, 0, sizeof (empty_pub_key));
1169 if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof (empty_pub_key)))
1170 { // no public key set: create new private key & save the place
1171 struct GNUNET_CRYPTO_EddsaPrivateKey *
1172 place_key = GNUNET_CRYPTO_eddsa_key_create ();
1173 hreq->place_key = *place_key;
1174 GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key);
1175 GNUNET_CRYPTO_eddsa_key_clear (place_key);
1176 GNUNET_free (place_key);
1178 app_place_save (app_id, (const struct PlaceEnterRequest *) hreq);
1181 switch (host_enter (hreq, &hst))
1190 client_send_host_enter_ack (client, hst, GNUNET_OK);
1194 ret = GNUNET_SYSERR;
1197 if (ret != GNUNET_SYSERR)
1200 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1201 "%p Client connected as host to place %s.\n",
1202 hst, GNUNET_h2s (&plc->pub_key_hash));
1204 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1205 cli->client = client;
1206 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1208 struct Client *ctx = GNUNET_new (struct Client);
1210 GNUNET_SERVER_client_set_user_context (client, ctx);
1213 GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key);
1215 GNUNET_SERVER_receive_done (client, ret);
1220 * Enter place as guest.
1224 * @param[out] ret_gst
1225 * Returned Guest struct.
1227 * @return #GNUNET_YES if the guest entered the place just now,
1228 * #GNUNET_NO if the place is already entered,
1229 * #GNUNET_SYSERR on error.
1232 guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst)
1234 int ret = GNUNET_NO;
1235 uint16_t greq_size = ntohs (greq->header.size);
1237 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key;
1238 struct GNUNET_HashCode ego_pub_hash;
1239 GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
1240 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
1243 return GNUNET_SYSERR;
1245 struct GNUNET_HashCode place_pub_hash;
1246 GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key),
1249 struct GNUNET_CONTAINER_MultiHashMap *
1250 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash);
1251 struct Guest *gst = NULL;
1253 if (NULL != plc_gst)
1254 gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash);
1256 if (NULL == gst || NULL == gst->slave)
1258 gst = GNUNET_new (struct Guest);
1259 gst->origin = greq->origin;
1260 gst->relay_count = ntohl (greq->relay_count);
1263 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1264 const char *app_id = (const char *) &greq[1];
1265 const char *p = app_id;
1267 len = strnlen (app_id, remaining);
1268 if (len == remaining)
1271 return GNUNET_SYSERR;
1274 remaining -= len + 1;
1276 const struct GNUNET_PeerIdentity *relays = NULL;
1277 uint16_t relay_size = gst->relay_count * sizeof (*relays);
1278 if (remaining < relay_size)
1281 return GNUNET_SYSERR;
1284 relays = (const struct GNUNET_PeerIdentity *) p;
1286 remaining -= relay_size;
1288 struct GNUNET_PSYC_Message *join_msg = NULL;
1289 uint16_t join_msg_size = 0;
1291 if (sizeof (struct GNUNET_MessageHeader) <= remaining)
1293 join_msg = (struct GNUNET_PSYC_Message *) p;
1294 join_msg_size = ntohs (join_msg->header.size);
1296 remaining -= join_msg_size;
1300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1301 "%u + %u + %u != %u\n",
1302 sizeof (*greq), relay_size, join_msg_size, greq_size);
1305 return GNUNET_SYSERR;
1309 gst->relays = GNUNET_malloc (relay_size);
1310 memcpy (gst->relays, relays, relay_size);
1313 gst->join_flags = ntohl (greq->flags);
1315 struct Place *plc = &gst->plc;
1317 plc->is_host = GNUNET_NO;
1318 plc->pub_key = greq->place_pub_key;
1319 plc->pub_key_hash = place_pub_hash;
1320 plc->ego_pub_key = ego_pub_key;
1321 plc->ego_pub_hash = ego_pub_hash;
1322 plc->ego_key = ego->key;
1324 if (NULL == plc_gst)
1326 plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1327 (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
1328 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1330 (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst,
1331 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1332 (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
1333 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1335 = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key,
1336 gst->join_flags, &gst->origin,
1337 gst->relay_count, gst->relays,
1338 &psyc_recv_message, NULL,
1339 &psyc_slave_connected,
1340 &psyc_recv_join_dcsn,
1342 gst->plc.channel = GNUNET_PSYC_slave_get_channel (gst->slave);
1346 if (NULL != ret_gst)
1353 * Handle a connecting client entering a place as guest.
1356 client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client,
1357 const struct GNUNET_MessageHeader *msg)
1359 const struct GuestEnterRequest *
1360 greq = (const struct GuestEnterRequest *) msg;
1362 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1363 const char *app_id = NULL;
1364 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1],
1365 remaining, 1, &app_id);
1369 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1373 struct Guest *gst = NULL;
1374 struct Place *plc = NULL;
1376 switch (guest_enter (greq, &gst))
1380 app_place_save (app_id, (const struct PlaceEnterRequest *) greq);
1387 struct GNUNET_PSYC_CountersResultMessage res;
1388 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
1389 res.header.size = htons (sizeof (res));
1390 res.result_code = htonl (GNUNET_OK);
1391 res.max_message_id = GNUNET_htonll (plc->max_message_id);
1393 client_send_msg (client, &res.header);
1394 if (NULL != gst->join_dcsn)
1395 client_send_msg (client, &gst->join_dcsn->header);
1401 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1406 "%p Client connected as guest to place %s.\n",
1407 gst, GNUNET_h2s (&plc->pub_key_hash));
1409 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1410 cli->client = client;
1411 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1413 struct Client *ctx = GNUNET_new (struct Client);
1415 GNUNET_SERVER_client_set_user_context (client, ctx);
1416 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1420 struct GuestEnterByNameClosure
1422 struct GNUNET_SERVER_Client *client;
1425 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
1426 struct GNUNET_MessageHeader *join_msg;
1431 * Result of a GNS name lookup for entering a place.
1433 * @see GNUNET_SOCIAL_guest_enter_by_name
1436 gns_result_guest_enter (void *cls, uint32_t rd_count,
1437 const struct GNUNET_GNSRECORD_Data *rd)
1439 struct GuestEnterByNameClosure *gcls = cls;
1440 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1441 "%p GNS result: %u records.\n", gcls->client, rd_count);
1443 const struct GNUNET_GNSRECORD_PlaceData *
1444 rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
1446 if (0 == rd_count || rd->data_size < sizeof (*rec))
1449 GNUNET_SERVER_receive_done (gcls->client, GNUNET_SYSERR);
1453 uint16_t relay_count = ntohl (rec->relay_count);
1454 struct GNUNET_PeerIdentity *relays = NULL;
1456 if (0 < relay_count)
1458 if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity))
1460 relays = (struct GNUNET_PeerIdentity *) &rec[1];
1465 GNUNET_break_op (0);
1469 uint16_t app_id_size = strlen (gcls->app_id) + 1;
1470 uint16_t relay_size = relay_count * sizeof (*relays);
1471 uint16_t join_msg_size = 0;
1472 if (NULL != gcls->join_msg)
1473 join_msg_size = ntohs (gcls->join_msg->size);
1474 uint16_t greq_size = sizeof (struct GuestEnterRequest)
1475 + app_id_size + relay_size + join_msg_size;
1476 struct GuestEnterRequest *greq = GNUNET_malloc (greq_size);
1477 greq->header.size = htons (greq_size);
1478 greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1479 greq->ego_pub_key = gcls->ego_pub_key;
1480 greq->place_pub_key = rec->place_pub_key;
1481 greq->origin = rec->origin;
1482 greq->relay_count = rec->relay_count;
1485 memcpy (p, gcls->app_id, app_id_size);
1487 memcpy (p, relays, relay_size);
1489 memcpy (p, gcls->join_msg, join_msg_size);
1491 client_recv_guest_enter (NULL, gcls->client, &greq->header);
1493 GNUNET_free (gcls->app_id);
1494 if (NULL != gcls->password)
1495 GNUNET_free (gcls->password);
1496 if (NULL != gcls->join_msg)
1497 GNUNET_free (gcls->join_msg);
1504 * Handle a connecting client entering a place as guest using a GNS address.
1506 * Look up GNS address and generate a GuestEnterRequest from that.
1509 client_recv_guest_enter_by_name (void *cls, struct GNUNET_SERVER_Client *client,
1510 const struct GNUNET_MessageHeader *msg)
1512 const struct GuestEnterByNameRequest *
1513 greq = (const struct GuestEnterByNameRequest *) msg;
1515 struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls));
1516 gcls->client = client;
1517 gcls->ego_pub_key = greq->ego_pub_key;
1519 const char *p = (const char *) &greq[1];
1520 const char *app_id = NULL, *password = NULL, *gns_name = NULL;
1521 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1522 uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3,
1527 remaining -= offset;
1529 if (0 != offset && sizeof (*gcls->join_msg) <= remaining)
1531 gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p);
1532 remaining -= ntohs (gcls->join_msg->size);
1535 if (0 == offset || 0 != remaining)
1537 if (NULL != gcls->join_msg)
1538 GNUNET_free (gcls->join_msg);
1540 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1544 uint16_t app_id_size = strlen (app_id) + 1;
1545 gcls->app_id = GNUNET_malloc (app_id_size);
1546 memcpy (gcls->app_id, app_id, app_id_size);
1548 uint16_t password_size = strlen (password);
1549 if (0 < password_size++)
1551 gcls->password = GNUNET_malloc (password_size);
1552 memcpy (gcls->password, password, password_size);
1555 GNUNET_GNS_lookup (gns, gns_name, &greq->ego_pub_key,
1556 GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
1557 NULL, gns_result_guest_enter, gcls);
1562 app_notify_place (struct GNUNET_MessageHeader *msg,
1563 struct GNUNET_SERVER_Client *client)
1565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1566 "%p Sending place notification of type %u to client.\n",
1567 client, ntohs (msg->type));
1569 uint16_t msg_size = ntohs (msg->size);
1570 struct AppPlaceMessage amsg;
1571 amsg.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE);
1572 amsg.header.size = htons (sizeof (amsg));
1573 // FIXME: also notify about not entered places
1574 amsg.place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED;
1576 switch (ntohs (msg->type))
1578 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
1579 if (msg_size < sizeof (struct HostEnterRequest))
1581 struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
1582 amsg.is_host = GNUNET_YES;
1583 amsg.ego_pub_key = hreq->ego_pub_key;
1584 amsg.place_pub_key = hreq->place_pub_key;
1587 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
1588 if (msg_size < sizeof (struct GuestEnterRequest))
1590 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
1591 amsg.is_host = GNUNET_NO;
1592 amsg.ego_pub_key = greq->ego_pub_key;
1593 amsg.place_pub_key = greq->place_pub_key;
1600 client_send_msg (client, &amsg.header);
1605 app_notify_ego (struct Ego *ego, struct GNUNET_SERVER_Client *client)
1607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608 "%p Sending ego notification to client: %s\n",
1611 size_t name_size = strlen (ego->name) + 1;
1612 struct AppEgoMessage *emsg = GNUNET_malloc (sizeof (*emsg) + name_size);
1613 emsg->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO);
1614 emsg->header.size = htons (sizeof (*emsg) + name_size);
1616 GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key);
1617 memcpy (&emsg[1], ego->name, name_size);
1619 client_send_msg (client, &emsg->header);
1625 app_place_entry_notify (void *cls, const struct GNUNET_HashCode *key, void *value)
1627 struct GNUNET_MessageHeader *
1628 msg = GNUNET_CONTAINER_multihashmap_get (places, key);
1630 app_notify_place (msg, cls);
1636 ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
1638 app_notify_ego (value, cls);
1644 * Handle application connection.
1647 client_recv_app_connect (void *cls, struct GNUNET_SERVER_Client *client,
1648 const struct GNUNET_MessageHeader *msg)
1650 const struct AppConnectRequest *creq
1651 = (const struct AppConnectRequest *) msg;
1653 uint8_t app_id_size = ntohs (creq->header.size) - sizeof (*creq);
1654 const char *app_id = NULL;
1655 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1],
1656 app_id_size, 1, &app_id);
1657 if (0 == offset || offset != app_id_size)
1660 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1664 struct GNUNET_HashCode app_id_hash;
1665 GNUNET_CRYPTO_hash (app_id, app_id_size, &app_id_hash);
1667 GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client);
1669 struct GNUNET_CONTAINER_MultiHashMap *
1670 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1671 if (NULL != app_places)
1672 GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry_notify, client);
1674 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1675 cli->client = client;
1676 struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps,
1679 app = GNUNET_malloc (sizeof (*app));
1680 (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app,
1681 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1683 GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli);
1685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1686 "%p Application %s connected.\n", app, app_id);
1688 struct Client *ctx = GNUNET_new (struct Client);
1689 ctx->app_id = GNUNET_malloc (app_id_size);
1690 memcpy (ctx->app_id, app_id, app_id_size);
1692 GNUNET_SERVER_client_set_user_context (client, ctx);
1693 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1698 * Handle application detach request.
1701 client_recv_app_detach (void *cls, struct GNUNET_SERVER_Client *client,
1702 const struct GNUNET_MessageHeader *msg)
1705 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1706 GNUNET_assert (NULL != ctx);
1708 const struct AppDetachRequest *req
1709 = (const struct AppDetachRequest *) msg;
1711 int ret = app_place_remove (ctx->app_id, &req->place_pub_key);
1712 client_send_result (client, req->op_id, ret, NULL, 0);
1714 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1719 app_places_entry_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
1721 app_place_remove (value, cls);
1727 * Handle application detach request.
1730 client_recv_place_leave (void *cls, struct GNUNET_SERVER_Client *client,
1731 const struct GNUNET_MessageHeader *msg)
1734 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1735 GNUNET_assert (NULL != ctx);
1736 struct Place *plc = ctx->plc;
1738 /* FIXME: remove all app subscriptions and leave this place */
1740 struct GNUNET_CONTAINER_MultiHashMap *
1741 place_apps = GNUNET_CONTAINER_multihashmap_get (places_apps, &plc->pub_key_hash);
1742 if (NULL != place_apps)
1744 GNUNET_CONTAINER_multihashmap_iterate (place_apps, app_places_entry_remove, &plc->pub_key);
1747 /* FIXME: disconnect from the network, but keep local connection for history access */
1749 /* Disconnect all clients connected to the place */
1750 struct ClientListItem *cli = plc->clients_head, *next;
1753 GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
1754 GNUNET_SERVER_client_disconnect (cli->client);
1760 if (GNUNET_YES != plc->is_disconnected)
1762 plc->is_disconnected = GNUNET_YES;
1763 if (NULL != plc->tmit_msgs_head)
1764 { /* Send pending messages to PSYC before cleanup. */
1765 psyc_transmit_message (plc);
1769 cleanup_place (plc);
1775 struct JoinDecisionClosure
1777 int32_t is_admitted;
1778 struct GNUNET_PSYC_Message *msg;
1783 * Iterator callback for responding to join requests.
1786 psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
1789 struct JoinDecisionClosure *jcls = cls;
1790 struct GNUNET_PSYC_JoinHandle *jh = value;
1791 // FIXME: add relays
1792 GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
1798 * Handle an entry decision from a host client.
1801 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
1802 const struct GNUNET_MessageHeader *msg)
1805 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1806 GNUNET_assert (NULL != ctx);
1807 struct Place *plc = ctx->plc;
1808 GNUNET_assert (GNUNET_YES == plc->is_host);
1809 struct Host *hst = (struct Host *) plc;
1811 struct GNUNET_PSYC_JoinDecisionMessage *
1812 dcsn = (struct GNUNET_PSYC_JoinDecisionMessage *) msg;
1813 struct JoinDecisionClosure jcls;
1814 jcls.is_admitted = ntohl (dcsn->is_admitted);
1816 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
1817 ? (struct GNUNET_PSYC_Message *) &dcsn[1]
1820 struct GNUNET_HashCode slave_key_hash;
1821 GNUNET_CRYPTO_hash (&dcsn->slave_key, sizeof (dcsn->slave_key),
1824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1825 "%p Got join decision (%d) from client for place %s..\n",
1826 hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
1827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1828 "%p ..and slave %s.\n",
1829 hst, GNUNET_h2s (&slave_key_hash));
1831 GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_key_hash,
1832 &psyc_send_join_decision, &jcls);
1833 GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_key_hash);
1834 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1839 * Send acknowledgement to a client.
1841 * Sent after a message fragment has been passed on to multicast.
1843 * @param plc The place struct for the client.
1846 send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client)
1848 struct GNUNET_MessageHeader res;
1849 res.size = htons (sizeof (res));
1850 res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
1851 client_send_msg (client, &res);
1856 * Proceed to the next message part in the transmission queue.
1859 * Place where the transmission is going on.
1861 * Currently transmitted message.
1863 * Currently transmitted message fragment.
1865 * @return @a tmit_frag, or NULL if reached the end of fragment.
1867 static struct FragmentTransmitQueue *
1868 psyc_transmit_queue_next_part (struct Place *plc,
1869 struct MessageTransmitQueue *tmit_msg,
1870 struct FragmentTransmitQueue *tmit_frag)
1872 uint16_t psize = ntohs (tmit_frag->next_part->size);
1873 if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
1876 tmit_frag->next_part
1877 = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
1879 else /* Reached end of current fragment. */
1881 if (NULL != tmit_frag->client)
1882 send_message_ack (plc, tmit_frag->client);
1883 GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1884 GNUNET_free (tmit_frag);
1892 * Proceed to next message in transmission queue.
1895 * Place where the transmission is going on.
1897 * Currently transmitted message.
1899 * @return The next message in queue, or NULL if queue is empty.
1901 static struct MessageTransmitQueue *
1902 psyc_transmit_queue_next_msg (struct Place *plc,
1903 struct MessageTransmitQueue *tmit_msg)
1905 GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1906 GNUNET_free (tmit_msg);
1907 return plc->tmit_msgs_head;
1912 * Callback for data transmission to PSYC.
1915 psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1917 struct Place *plc = cls;
1918 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1919 GNUNET_assert (NULL != tmit_msg);
1920 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1921 if (NULL == tmit_frag)
1922 { /* Rest of the message have not arrived yet, pause transmission */
1926 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1930 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
1935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1936 "%p psyc_transmit_notify_data()\n", plc);
1937 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1939 uint16_t ptype = ntohs (pmsg->type);
1940 uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
1945 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1946 if (*data_size < pdata_size)
1948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1949 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
1953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1954 "%p psyc_transmit_notify_data: sending %u bytes.\n",
1957 *data_size = pdata_size;
1958 memcpy (data, &pmsg[1], *data_size);
1962 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1967 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1969 ret = GNUNET_SYSERR;
1973 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1974 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
1976 ret = GNUNET_SYSERR;
1979 if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
1982 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1983 plc->is_disconnected = GNUNET_YES;
1984 GNUNET_SERVER_client_disconnect (tmit_frag->client);
1985 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1990 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1991 if (NULL != tmit_frag)
1993 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1994 ptype = ntohs (pmsg->type);
1997 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2000 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2001 ret = GNUNET_SYSERR;
2006 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2007 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2008 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2012 if (NULL == tmit_msg->frags_head
2013 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2014 { /* Reached end of current message. */
2015 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2019 if (ret != GNUNET_NO)
2021 if (NULL != tmit_msg)
2023 psyc_transmit_message (plc);
2025 else if (GNUNET_YES == plc->is_disconnected)
2027 /* FIXME: handle partial message (when still in_transmit) */
2028 cleanup_place (plc);
2036 * Callback for modifier transmission to PSYC.
2039 psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2040 uint8_t *oper, uint32_t *full_value_size)
2042 struct Place *plc = cls;
2043 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2044 GNUNET_assert (NULL != tmit_msg);
2045 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2046 if (NULL == tmit_frag)
2047 { /* Rest of the message have not arrived yet, pause transmission */
2051 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2055 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
2060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2061 "%p psyc_transmit_notify_mod()\n", plc);
2062 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
2064 uint16_t ptype = ntohs (pmsg->type);
2069 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
2073 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2074 "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
2075 ret = GNUNET_SYSERR;
2078 struct GNUNET_PSYC_MessageModifier *
2079 pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
2080 uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
2082 if (*data_size < mod_size)
2084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2085 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2090 *full_value_size = ntohl (pmod->value_size);
2092 *data_size = mod_size;
2093 memcpy (data, &pmod[1], mod_size);
2098 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
2102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2103 "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
2104 ret = GNUNET_SYSERR;
2107 uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
2108 if (*data_size < mod_size)
2110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2111 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2116 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
2118 *data_size = mod_size;
2119 memcpy (data, &pmsg[1], *data_size);
2124 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
2125 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2126 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2132 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2133 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
2135 ret = GNUNET_SYSERR;
2138 if (GNUNET_SYSERR == ret)
2141 ret = GNUNET_SYSERR;
2142 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2143 plc->is_disconnected = GNUNET_YES;
2144 GNUNET_SERVER_client_disconnect (tmit_frag->client);
2145 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
2149 if (GNUNET_YES != ret)
2150 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2152 if (NULL == tmit_msg->frags_head
2153 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2154 { /* Reached end of current message. */
2155 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2162 * Callback for data transmission from a host to PSYC.
2165 host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2167 int ret = psyc_transmit_notify_data (cls, data_size, data);
2169 if (GNUNET_NO != ret)
2171 struct Host *hst = cls;
2172 hst->tmit_handle = NULL;
2179 * Callback for the transmit functions of multicast.
2182 guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2184 int ret = psyc_transmit_notify_data (cls, data_size, data);
2186 if (GNUNET_NO != ret)
2188 struct Guest *gst = cls;
2189 gst->tmit_handle = NULL;
2196 * Callback for modifier transmission from a host to PSYC.
2199 host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2200 uint8_t *oper, uint32_t *full_value_size)
2202 int ret = psyc_transmit_notify_mod (cls, data_size, data,
2203 oper, full_value_size);
2204 if (GNUNET_SYSERR == ret)
2206 struct Host *hst = cls;
2207 hst->tmit_handle = NULL;
2214 * Callback for modifier transmission from a guest to PSYC.
2217 guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2218 uint8_t *oper, uint32_t *full_value_size)
2220 int ret = psyc_transmit_notify_mod (cls, data_size, data,
2221 oper, full_value_size);
2222 if (GNUNET_SYSERR == ret)
2224 struct Guest *gst = cls;
2225 gst->tmit_handle = NULL;
2232 * Get method part of next message from transmission queue.
2235 * Next item in message transmission queue.
2237 * The message method is returned here.
2239 * @return #GNUNET_OK on success
2240 * #GNUNET_NO if there are no more messages in queue.
2241 * #GNUNET_SYSERR if the next message is malformed.
2244 psyc_transmit_queue_next_method (struct Place *plc,
2245 struct GNUNET_PSYC_MessageMethod **pmeth)
2247 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2248 if (NULL == tmit_msg)
2251 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2252 if (NULL == tmit_frag)
2258 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2260 || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
2262 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2263 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
2264 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
2266 return GNUNET_SYSERR;
2269 uint16_t psize = ntohs (pmsg->size);
2270 *pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
2271 if (psize < sizeof (**pmeth) + 1 || '\0' != *((char *) *pmeth + psize - 1))
2273 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2274 "%p psyc_transmit_queue_next_method: invalid method name.\n",
2275 plc, ntohs (pmsg->type));
2276 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2277 "%u <= %u || NUL != %u\n",
2278 sizeof (**pmeth), psize, *((char *) *pmeth + psize - 1));
2280 return GNUNET_SYSERR;
2283 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2289 * Transmit the next message in queue from the host to the PSYC channel.
2292 psyc_master_transmit_message (struct Host *hst)
2295 if (NULL == hst->tmit_handle)
2297 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
2298 int ret = psyc_transmit_queue_next_method (&hst->plc, &pmeth);
2299 if (GNUNET_OK != ret)
2303 = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
2304 &host_transmit_notify_mod,
2305 &host_transmit_notify_data, hst,
2310 GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
2317 * Transmit the next message in queue from a guest to the PSYC channel.
2320 psyc_slave_transmit_message (struct Guest *gst)
2322 if (NULL == gst->tmit_handle)
2324 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
2325 int ret = psyc_transmit_queue_next_method (&gst->plc, &pmeth);
2326 if (GNUNET_OK != ret)
2330 = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
2331 &guest_transmit_notify_mod,
2332 &guest_transmit_notify_data, gst,
2337 GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
2344 * Transmit a message to PSYC.
2347 psyc_transmit_message (struct Place *plc)
2351 ? psyc_master_transmit_message ((struct Host *) plc)
2352 : psyc_slave_transmit_message ((struct Guest *) plc);
2357 * Queue message parts for sending to PSYC.
2359 * @param plc Place to send to.
2360 * @param client Client the message originates from.
2361 * @param data_size Size of @a data.
2362 * @param data Concatenated message parts.
2363 * @param first_ptype First message part type in @a data.
2364 * @param last_ptype Last message part type in @a data.
2366 static struct MessageTransmitQueue *
2367 psyc_transmit_queue_message (struct Place *plc,
2368 struct GNUNET_SERVER_Client *client,
2371 uint16_t first_ptype, uint16_t last_ptype,
2372 struct MessageTransmitQueue *tmit_msg)
2374 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
2376 tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
2377 GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2379 else if (NULL == tmit_msg)
2384 struct FragmentTransmitQueue *
2385 tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
2386 memcpy (&tmit_frag[1], data, data_size);
2387 tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
2388 tmit_frag->client = client;
2389 tmit_frag->size = data_size;
2391 GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2392 tmit_msg->client = client;
2398 * Cancel transmission of current message to PSYC.
2400 * @param plc Place to send to.
2401 * @param client Client the message originates from.
2404 psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVER_Client *client)
2406 uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
2408 struct GNUNET_MessageHeader msg;
2409 msg.size = htons (sizeof (msg));
2410 msg.type = htons (type);
2412 psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
2413 psyc_transmit_message (plc);
2415 /* FIXME: cleanup */
2420 * Handle an incoming message from a client, to be transmitted to the place.
2423 client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
2424 const struct GNUNET_MessageHeader *msg)
2427 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2428 GNUNET_assert (NULL != ctx);
2429 struct Place *plc = ctx->plc;
2430 int ret = GNUNET_SYSERR;
2432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2433 "%p Received message from client.\n", plc);
2434 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
2436 if (GNUNET_YES != plc->is_ready)
2438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2439 "%p Place is not ready yet, disconnecting client.\n", plc);
2441 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2445 uint16_t size = ntohs (msg->size);
2446 uint16_t psize = size - sizeof (*msg);
2447 if (psize < sizeof (struct GNUNET_MessageHeader)
2448 || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
2450 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2451 "%p Received message with invalid payload size (%u) from client.\n",
2454 psyc_transmit_cancel (plc, client);
2455 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2459 uint16_t first_ptype = 0, last_ptype = 0;
2461 == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
2462 &first_ptype, &last_ptype))
2464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2465 "%p Received invalid message part from client.\n", plc);
2467 psyc_transmit_cancel (plc, client);
2468 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2472 "%p Received message with first part type %u and last part type %u.\n",
2473 plc, first_ptype, last_ptype);
2476 = psyc_transmit_queue_message (plc, client, psize, &msg[1],
2477 first_ptype, last_ptype, ctx->tmit_msg);
2478 if (NULL != ctx->tmit_msg)
2480 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
2481 ctx->tmit_msg = NULL;
2482 ret = psyc_transmit_message (plc);
2485 if (GNUNET_OK != ret)
2487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2488 "%p Received invalid message part from client.\n", plc);
2490 psyc_transmit_cancel (plc, client);
2491 ret = GNUNET_SYSERR;
2493 GNUNET_SERVER_receive_done (client, ret);
2498 * A historic message arrived from PSYC.
2501 psyc_recv_history_message (void *cls, uint64_t message_id, uint32_t flags,
2502 const struct GNUNET_PSYC_MessageHeader *msg)
2504 struct OperationClosure *opcls = cls;
2505 struct Place *plc = opcls->plc;
2507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2508 "%p Received historic message #%" PRId64 " (flags: %x)\n",
2509 plc, message_id, flags);
2511 uint16_t size = ntohs (msg->header.size);
2513 struct GNUNET_OperationResultMessage *
2514 res = GNUNET_malloc (sizeof (*res) + size);
2515 res->header.size = htons (sizeof (*res) + size);
2516 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
2517 res->op_id = opcls->op_id;
2518 res->result_code = GNUNET_htonll (GNUNET_OK);
2520 memcpy (&res[1], msg, size);
2522 /** @todo FIXME: send only to requesting client */
2523 place_send_msg (plc, &res->header);
2528 * Result of message history replay from PSYC.
2531 psyc_recv_history_result (void *cls, int64_t result,
2532 const void *err_msg, uint16_t err_msg_size)
2534 struct OperationClosure *opcls = cls;
2535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2536 "%p History replay #%" PRIu64 ": "
2537 "PSYCstore returned %" PRId64 " (%.*s)\n",
2538 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
2540 // FIXME: place might have been destroyed
2541 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
2546 * Client requests channel history.
2549 client_recv_history_replay (void *cls, struct GNUNET_SERVER_Client *client,
2550 const struct GNUNET_MessageHeader *msg)
2553 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2554 GNUNET_assert (NULL != ctx);
2555 struct Place *plc = ctx->plc;
2557 const struct GNUNET_PSYC_HistoryRequestMessage *
2558 req = (const struct GNUNET_PSYC_HistoryRequestMessage *) msg;
2559 uint16_t size = ntohs (msg->size);
2560 const char *method_prefix = (const char *) &req[1];
2562 if (size < sizeof (*req) + 1
2563 || '\0' != method_prefix[size - sizeof (*req) - 1])
2565 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2566 "%p History replay #%" PRIu64 ": "
2567 "invalid method prefix. size: %u < %u?\n",
2568 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2570 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2574 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2575 opcls->client = client;
2577 opcls->op_id = req->op_id;
2578 opcls->flags = ntohl (req->flags);
2580 if (0 == req->message_limit)
2581 GNUNET_PSYC_channel_history_replay (plc->channel,
2582 GNUNET_ntohll (req->start_message_id),
2583 GNUNET_ntohll (req->end_message_id),
2584 method_prefix, opcls->flags,
2585 &psyc_recv_history_message, NULL,
2586 &psyc_recv_history_result, opcls);
2588 GNUNET_PSYC_channel_history_replay_latest (plc->channel,
2589 GNUNET_ntohll (req->message_limit),
2590 method_prefix, opcls->flags,
2591 &psyc_recv_history_message, NULL,
2592 &psyc_recv_history_result, opcls);
2594 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2599 * A state variable part arrived from PSYC.
2602 psyc_recv_state_var (void *cls,
2603 const struct GNUNET_MessageHeader *mod,
2606 uint32_t value_size,
2607 uint32_t full_value_size)
2609 struct OperationClosure *opcls = cls;
2610 struct Place *plc = opcls->plc;
2612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2613 "%p Received state variable %s from PSYC\n",
2616 uint16_t size = ntohs (mod->size);
2618 struct GNUNET_OperationResultMessage *
2619 res = GNUNET_malloc (sizeof (*res) + size);
2620 res->header.size = htons (sizeof (*res) + size);
2621 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
2622 res->op_id = opcls->op_id;
2623 res->result_code = GNUNET_htonll (GNUNET_OK);
2625 memcpy (&res[1], mod, size);
2627 /** @todo FIXME: send only to requesting client */
2628 place_send_msg (plc, &res->header);
2633 * Result of retrieving state variable from PSYC.
2636 psyc_recv_state_result (void *cls, int64_t result,
2637 const void *err_msg, uint16_t err_msg_size)
2639 struct OperationClosure *opcls = cls;
2640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2641 "%p State get #%" PRIu64 ": "
2642 "PSYCstore returned %" PRId64 " (%.*s)\n",
2643 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
2645 // FIXME: place might have been destroyed
2646 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
2651 * Client requests channel history.
2654 client_recv_state_get (void *cls, struct GNUNET_SERVER_Client *client,
2655 const struct GNUNET_MessageHeader *msg)
2658 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2659 GNUNET_assert (NULL != ctx);
2660 struct Place *plc = ctx->plc;
2662 const struct GNUNET_PSYC_StateRequestMessage *
2663 req = (const struct GNUNET_PSYC_StateRequestMessage *) msg;
2664 uint16_t size = ntohs (msg->size);
2665 const char *name = (const char *) &req[1];
2667 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2668 "%p State get #%" PRIu64 ": %s\n",
2669 plc, GNUNET_ntohll (req->op_id), name);
2671 if (size < sizeof (*req) + 1
2672 || '\0' != name[size - sizeof (*req) - 1])
2674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2675 "%p State get #%" PRIu64 ": "
2676 "invalid name. size: %u < %u?\n",
2677 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2679 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2683 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2684 opcls->client = client;
2686 opcls->op_id = req->op_id;
2688 switch (ntohs (msg->type))
2690 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
2691 GNUNET_PSYC_channel_state_get (plc->channel, name,
2692 psyc_recv_state_var,
2693 psyc_recv_state_result, opcls);
2696 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
2697 GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
2698 psyc_recv_state_var,
2699 psyc_recv_state_result, opcls);
2706 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2711 namestore_recv_records_store_result (void *cls, int32_t result,
2712 const char *err_msg)
2714 struct OperationClosure *ocls = cls;
2715 client_send_result (ocls->client, ocls->op_id, result, err_msg,
2716 (NULL != err_msg) ? strlen (err_msg) : 0);
2722 * Handle request to add PLACE record to GNS zone.
2725 client_recv_zone_add_place (void *cls, struct GNUNET_SERVER_Client *client,
2726 const struct GNUNET_MessageHeader *msg)
2728 const struct ZoneAddPlaceRequest *preq
2729 = (const struct ZoneAddPlaceRequest *) msg;
2731 uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq);
2732 const char *p = (const char *) &preq[1];
2733 const char *name = NULL, *password = NULL;
2734 uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2,
2736 remaining -= offset;
2738 const struct GNUNET_PeerIdentity *
2739 relays = (const struct GNUNET_PeerIdentity *) p;
2740 uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays);
2742 if (0 == offset || remaining != relay_size)
2745 client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
2746 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2750 struct GNUNET_GNSRECORD_Data rd = { };
2751 rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
2752 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
2753 rd.expiration_time = GNUNET_ntohll (preq->expiration_time);
2755 struct GNUNET_GNSRECORD_PlaceData *
2756 rec = GNUNET_malloc (sizeof (*rec) + relay_size);
2757 rec->place_pub_key = preq->place_pub_key;
2758 rec->origin = this_peer;
2759 rec->relay_count = preq->relay_count;
2760 memcpy (&rec[1], relays, relay_size);
2763 rd.data_size = sizeof (*rec) + relay_size;
2765 struct GNUNET_HashCode ego_pub_hash;
2766 GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash);
2767 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
2770 client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
2774 struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
2775 ocls->client = client;
2776 ocls->op_id = preq->op_id;
2777 GNUNET_NAMESTORE_records_store (namestore, &ego->key,
2779 namestore_recv_records_store_result, ocls);
2781 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2786 * Handle request to add PLACE record to GNS zone.
2789 client_recv_zone_add_nym (void *cls, struct GNUNET_SERVER_Client *client,
2790 const struct GNUNET_MessageHeader *msg)
2792 const struct ZoneAddNymRequest *nreq
2793 = (const struct ZoneAddNymRequest *) msg;
2795 uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq);
2796 const char *name = NULL;
2797 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1],
2798 name_size, 1, &name);
2799 if (0 == offset || offset != name_size)
2802 client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
2803 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2807 struct GNUNET_GNSRECORD_Data rd = { };
2808 rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
2809 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
2810 rd.expiration_time = GNUNET_ntohll (nreq->expiration_time);
2811 rd.data = &nreq->nym_pub_key;
2812 rd.data_size = sizeof (nreq->nym_pub_key);
2814 struct GNUNET_HashCode ego_pub_hash;
2815 GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash);
2816 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
2819 client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
2823 struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
2824 ocls->client = client;
2825 ocls->op_id = nreq->op_id;
2826 GNUNET_NAMESTORE_records_store (namestore, &ego->key,
2828 namestore_recv_records_store_result, ocls);
2830 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2834 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2835 { &client_recv_host_enter, NULL,
2836 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
2838 { &client_recv_guest_enter, NULL,
2839 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
2841 { &client_recv_guest_enter_by_name, NULL,
2842 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME, 0 },
2844 { &client_recv_join_decision, NULL,
2845 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
2847 { &client_recv_psyc_message, NULL,
2848 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 },
2850 { &client_recv_history_replay, NULL,
2851 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, 0 },
2853 { &client_recv_state_get, NULL,
2854 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, 0 },
2856 { &client_recv_state_get, NULL,
2857 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 },
2859 { &client_recv_zone_add_place, NULL,
2860 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE, 0 },
2862 { &client_recv_zone_add_nym, NULL,
2863 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM, 0 },
2865 { &client_recv_app_connect, NULL,
2866 GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT, 0 },
2868 { &client_recv_app_detach, NULL,
2869 GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH, 0 },
2871 { &client_recv_place_leave, NULL,
2872 GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE, 0 },
2874 { NULL, NULL, 0, 0 }
2879 path_basename (const char *path)
2881 const char *basename = strrchr (path, DIR_SEPARATOR);
2882 if (NULL != basename)
2885 if (NULL == basename || '\0' == basename)
2892 struct PlaceLoadClosure
2895 const char *ego_pub_hash_str;
2899 /** Load a place file */
2901 file_place_load (void *cls, const char *filename)
2904 uint64_t file_size = 0;
2906 GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES)
2907 || file_size < sizeof (struct HostEnterRequest))
2910 struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size);
2911 ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size);
2912 if (read_size < 0 || read_size < sizeof (*ereq))
2915 uint16_t ereq_size = ntohs (ereq->header.size);
2916 if (read_size != ereq_size)
2919 switch (ntohs (ereq->header.type))
2921 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
2922 if (ereq_size < sizeof (struct HostEnterRequest))
2924 struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq;
2925 host_enter (hreq, NULL);
2928 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
2929 if (ereq_size < sizeof (struct GuestEnterRequest))
2931 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq;
2932 guest_enter (greq, NULL);
2939 app_place_add (app_id, ereq);
2944 /** Load an ego place file */
2946 file_ego_place_load (void *cls, const char *place_filename)
2948 struct PlaceLoadClosure *plcls = cls;
2950 const char *place_pub_hash_str = path_basename (place_filename);
2951 if (NULL == place_pub_hash_str)
2957 char *filename = NULL;
2958 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
2959 dir_social, DIR_SEPARATOR,
2960 "places", DIR_SEPARATOR,
2961 plcls->ego_pub_hash_str, DIR_SEPARATOR,
2962 place_pub_hash_str);
2964 struct PlaceEnterRequest ereq[GNUNET_SERVER_MAX_MESSAGE_SIZE];
2966 int read_size = GNUNET_DISK_fn_read (filename, &ereq,
2967 GNUNET_SERVER_MAX_MESSAGE_SIZE);
2968 GNUNET_free (filename);
2970 if (read_size < (ssize_t) sizeof (ereq))
2973 app_place_add (plcls->app_id, ereq);
2979 * Read @e place_pub_hash_str entries in @a dir_ego
2982 * Data directory of an application ego.
2983 * $GNUNET_DATA_HOME/social/apps/$app_id/$ego_pub_hash_str/
2986 scan_app_ego_dir (void *cls, const char *dir_ego)
2988 struct PlaceLoadClosure *plcls = cls;
2989 plcls->ego_pub_hash_str = path_basename (dir_ego);
2991 if (NULL != plcls->ego_pub_hash_str)
2992 GNUNET_DISK_directory_scan (dir_ego, file_ego_place_load, plcls);
2998 * Read @e ego_pub_hash_str entries in @a dir_app
3001 * Data directory of an application.
3002 * $GNUNET_DATA_HOME/social/apps/$app_id/
3005 scan_app_dir (void *cls, const char *dir_app)
3007 if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES))
3010 struct PlaceLoadClosure plcls;
3011 plcls.app_id = path_basename (dir_app);
3013 if (NULL != plcls.app_id)
3014 GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls);
3021 identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego,
3022 void **ctx, const char *name)
3024 if (NULL == id_ego) // end of initial list of egos
3027 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
3028 GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key);
3030 struct GNUNET_HashCode ego_pub_hash;
3031 GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
3033 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3036 GNUNET_free (ego->name);
3037 if (NULL == name) // deleted
3039 GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego);
3046 ego = GNUNET_malloc (sizeof (*ego));
3050 ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego));
3051 size_t name_size = strlen (name) + 1;
3052 ego->name = GNUNET_malloc (name_size);
3053 memcpy (ego->name, name, name_size);
3055 GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego,
3056 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
3062 * Connected to core service.
3065 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
3067 this_peer = *my_identity;
3072 * Initialize the PSYC service.
3074 * @param cls Closure.
3075 * @param server The initialized server.
3076 * @param c Configuration to use.
3079 run (void *cls, struct GNUNET_SERVER_Handle *server,
3080 const struct GNUNET_CONFIGURATION_Handle *c)
3084 hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3085 guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3086 place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3088 egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3089 apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3090 places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3091 apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3092 places_apps = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3094 core = GNUNET_CORE_connect (cfg, NULL, core_connected, NULL, NULL,
3095 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
3096 id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL);
3097 gns = GNUNET_GNS_connect (cfg);
3098 namestore = GNUNET_NAMESTORE_connect (cfg);
3099 stats = GNUNET_STATISTICS_create ("social", cfg);
3102 GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "DATA_HOME",
3105 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3106 "social", "DATA_HOME");
3110 GNUNET_asprintf (&dir_places, "%s%c%s",
3111 dir_social, DIR_SEPARATOR, "places");
3112 GNUNET_asprintf (&dir_apps, "%s%c%s",
3113 dir_social, DIR_SEPARATOR, "apps");
3115 GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL);
3117 nc = GNUNET_SERVER_notification_context_create (server, 1);
3118 GNUNET_SERVER_add_handlers (server, handlers);
3119 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3120 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
3121 &shutdown_task, NULL);
3126 * The main function for the service.
3128 * @param argc number of arguments from the command line
3129 * @param argv command line arguments
3130 * @return 0 ok, 1 on error
3133 main (int argc, char *const *argv)
3135 return (GNUNET_OK ==
3136 GNUNET_SERVICE_run (argc, argv, "social",
3137 GNUNET_SERVICE_OPTION_NONE,
3138 &run, NULL)) ? 0 : 1;
3141 /* end of gnunet-service-social.c */