2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
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;
233 * Slicer for processing incoming messages.
235 struct GNUNET_PSYC_Slicer *slicer;
238 * Last message ID received for the place.
239 * 0 if there is no such message.
241 uint64_t max_message_id;
244 * Offset where the file is currently being written.
246 uint64_t file_offset;
249 * Whether or not to save the file (#GNUNET_YES or #GNUNET_NO)
254 * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
259 * Is this place ready to receive messages from client?
260 * #GNUNET_YES or #GNUNET_NO
265 * Is the client disconnected?
266 * #GNUNET_YES or #GNUNET_NO
268 uint8_t is_disconnected;
273 * Client context for a host.
278 * Place struct common for Host and Guest
283 * Handle for the multicast origin.
285 struct GNUNET_PSYC_Master *master;
288 * Transmit handle for multicast.
290 struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
293 * Incoming join requests.
294 * guest_key -> struct GNUNET_PSYC_JoinHandle *
296 struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
299 * @see enum GNUNET_PSYC_Policy
301 enum GNUNET_PSYC_Policy policy;
306 * Client context for a guest.
311 * Place struct common for Host and Guest.
316 * Handle for the PSYC slave.
318 struct GNUNET_PSYC_Slave *slave;
321 * Transmit handle for multicast.
323 struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
326 * Peer identity of the origin.
328 struct GNUNET_PeerIdentity origin;
331 * Number of items in @a relays.
333 uint32_t relay_count;
336 * Relays that multicast can use to connect.
338 struct GNUNET_PeerIdentity *relays;
341 * Join request to be transmitted to the master on join.
343 struct GNUNET_MessageHeader *join_req;
346 * Join decision received from PSYC.
348 struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
351 * Join flags for the PSYC service.
353 enum GNUNET_PSYC_SlaveJoinFlags join_flags;
358 * Context for a client.
363 * Place where the client entered.
368 * Message queue for the message currently being transmitted
371 struct MessageTransmitQueue *tmit_msg;
374 * ID for application clients.
382 struct ClientListItem *clients_head;
383 struct ClientListItem *clients_tail;
388 struct GNUNET_CRYPTO_EcdsaPrivateKey key;
393 struct OperationClosure
395 struct GNUNET_SERVER_Client *client;
403 psyc_transmit_message (struct Place *plc);
407 cleanup_place (struct Place *plc);
411 place_entry_cleanup (void *cls, const struct GNUNET_HashCode *key, void *value)
413 cleanup_place (value);
419 * Task run during shutdown.
425 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
427 GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL);
428 GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL);
432 GNUNET_SERVER_notification_context_destroy (nc);
437 GNUNET_CORE_disconnect (core);
442 GNUNET_IDENTITY_disconnect (id);
445 if (NULL != namestore)
447 GNUNET_NAMESTORE_disconnect (namestore);
452 GNUNET_GNS_disconnect (gns);
457 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
464 * Clean up host data structures after a client disconnected.
467 cleanup_host (struct Host *hst)
469 struct Place *plc = &hst->plc;
471 if (NULL != hst->master)
472 GNUNET_PSYC_master_stop (hst->master, GNUNET_NO, NULL, NULL); // FIXME
473 GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
474 GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
479 * Clean up guest data structures after a client disconnected.
482 cleanup_guest (struct Guest *gst)
484 struct Place *plc = &gst->plc;
485 struct GNUNET_CONTAINER_MultiHashMap *
486 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
488 GNUNET_assert (NULL != plc_gst); // FIXME
489 GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst);
491 if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
493 GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
495 GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
497 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
499 if (NULL != gst->join_req)
500 GNUNET_free (gst->join_req);
501 if (NULL != gst->relays)
502 GNUNET_free (gst->relays);
503 if (NULL != gst->slave)
504 GNUNET_PSYC_slave_part (gst->slave, GNUNET_NO, NULL, NULL); // FIXME
505 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
510 * Clean up place data structures after a client disconnected.
513 cleanup_place (struct Place *plc)
515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
516 "%p Cleaning up place %s\n",
517 plc, GNUNET_h2s (&plc->pub_key_hash));
519 (GNUNET_YES == plc->is_host)
520 ? cleanup_host ((struct Host *) plc)
521 : cleanup_guest ((struct Guest *) plc);
523 GNUNET_PSYC_slicer_destroy (plc->slicer);
529 schedule_cleanup_place (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
536 * Called whenever a client is disconnected.
537 * Frees our resources associated with that client.
539 * @param cls Closure.
540 * @param client Identification of the client.
543 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
549 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
553 "%p User context is NULL in client_disconnect()\n", ctx);
557 struct Place *plc = ctx->plc;
559 if (NULL != ctx->app_id)
560 GNUNET_free (ctx->app_id);
565 return; // application client, nothing to do
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
568 "%p Client (%s) disconnected from place %s\n",
569 plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
570 GNUNET_h2s (&plc->pub_key_hash));
572 struct ClientListItem *cli = plc->clients_head;
575 if (cli->client == client)
577 GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
587 * Send message to a client.
590 client_send_msg (struct GNUNET_SERVER_Client *client,
591 const struct GNUNET_MessageHeader *msg)
593 GNUNET_SERVER_notification_context_add (nc, client);
594 GNUNET_SERVER_notification_context_unicast (nc, client, msg, GNUNET_NO);
599 * Send message to all clients connected to a place.
602 place_send_msg (const struct Place *plc,
603 const struct GNUNET_MessageHeader *msg)
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "%p Sending message to clients of place.\n", plc);
608 struct ClientListItem *cli = plc->clients_head;
611 client_send_msg (cli->client, msg);
618 * Send a result code back to the client.
621 * Client that should receive the result code.
625 * Operation ID in network byte order.
627 * Data payload or NULL.
632 client_send_result (struct GNUNET_SERVER_Client *client, uint64_t op_id,
633 int64_t result_code, const void *data, uint16_t data_size)
635 struct GNUNET_OperationResultMessage *res;
637 res = GNUNET_malloc (sizeof (*res) + data_size);
638 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
639 res->header.size = htons (sizeof (*res) + data_size);
640 res->result_code = GNUNET_htonll (result_code);
643 memcpy (&res[1], data, data_size);
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646 "%p Sending result to client for operation #%" PRIu64 ": "
647 "%" PRId64 " (size: %u)\n",
648 client, GNUNET_ntohll (op_id), result_code, data_size);
650 client_send_msg (client, &res->header);
656 client_send_host_enter_ack (struct GNUNET_SERVER_Client *client,
657 struct Host *hst, uint32_t result)
659 struct Place *plc = &hst->plc;
661 struct HostEnterAck hack;
662 hack.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
663 hack.header.size = htons (sizeof (hack));
664 hack.result_code = htonl (result);
665 hack.max_message_id = GNUNET_htonll (plc->max_message_id);
666 hack.place_pub_key = plc->pub_key;
669 client_send_msg (client, &hack.header);
671 place_send_msg (plc, &hack.header);
676 * Called after a PSYC master is started.
679 psyc_master_started (void *cls, int result, uint64_t max_message_id)
681 struct Host *hst = cls;
682 struct Place *plc = &hst->plc;
683 plc->max_message_id = max_message_id;
684 plc->is_ready = GNUNET_YES;
686 client_send_host_enter_ack (NULL, hst, result);
691 * Called when a PSYC master receives a join request.
694 psyc_recv_join_request (void *cls,
695 const struct GNUNET_PSYC_JoinRequestMessage *req,
696 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
697 const struct GNUNET_PSYC_Message *join_msg,
698 struct GNUNET_PSYC_JoinHandle *jh)
700 struct Host *hst = cls;
701 struct GNUNET_HashCode slave_key_hash;
702 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
703 GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
704 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
705 place_send_msg (&hst->plc, &req->header);
710 * Called after a PSYC slave is connected.
713 psyc_slave_connected (void *cls, int result, uint64_t max_message_id)
715 struct Guest *gst = cls;
716 struct Place *plc = &gst->plc;
717 plc->max_message_id = max_message_id;
718 plc->is_ready = GNUNET_YES;
720 struct GNUNET_PSYC_CountersResultMessage res;
721 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
722 res.header.size = htons (sizeof (res));
723 res.result_code = htonl (result);
724 res.max_message_id = GNUNET_htonll (plc->max_message_id);
726 place_send_msg (plc, &res.header);
731 * Called when a PSYC slave receives a join decision.
734 psyc_recv_join_dcsn (void *cls,
735 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
737 const struct GNUNET_PSYC_Message *join_msg)
739 struct Guest *gst = cls;
740 place_send_msg (&gst->plc, &dcsn->header);
745 * Called when a PSYC master or slave receives a message.
748 psyc_recv_message (void *cls,
751 const struct GNUNET_PSYC_MessageHeader *msg)
753 struct Place *plc = cls;
755 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key);
756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757 "%p Received PSYC message of size %u from %s.\n",
758 plc, ntohs (msg->header.size), str);
761 GNUNET_PSYC_slicer_message (plc->slicer, msg);
763 place_send_msg (plc, &msg->header);
768 place_recv_relay_method (void *cls,
769 const struct GNUNET_PSYC_MessageMethod *meth,
772 const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key,
773 const char *method_name)
775 struct Host *hst = cls;
776 struct Place *plc = &hst->plc;
778 // FIXME: relay message
783 place_recv_relay_modifier (void *cls,
784 const struct GNUNET_MessageHeader *msg,
786 enum GNUNET_PSYC_Operator oper,
790 uint16_t full_value_size)
797 place_recv_relay_eom (void *cls,
798 const struct GNUNET_MessageHeader *msg,
807 place_recv_relay_data (void *cls,
808 const struct GNUNET_MessageHeader *msg,
810 uint64_t data_offset,
819 place_recv_save_method (void *cls,
820 const struct GNUNET_PSYC_MessageMethod *meth,
823 const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key,
824 const char *method_name)
826 struct Place *plc = cls;
827 plc->file_offset = 0;
828 plc->file_save = GNUNET_NO;
830 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
831 memcpy (&place_pub_hash_ascii.encoding,
832 GNUNET_h2s_full (&plc->pub_key_hash), sizeof (place_pub_hash_ascii));
834 char *filename = NULL;
835 GNUNET_asprintf (&filename, "%s%c%s%c%s%c%.part" PRIu64,
836 dir_social, DIR_SEPARATOR,
837 "files", DIR_SEPARATOR,
838 place_pub_hash_ascii.encoding, DIR_SEPARATOR,
841 /* save if does not already exist */
842 if (GNUNET_NO == GNUNET_DISK_file_test (filename))
844 plc->file_save = GNUNET_YES;
847 GNUNET_free (filename);
852 place_recv_save_data (void *cls,
853 const struct GNUNET_MessageHeader *msg,
855 uint64_t data_offset,
859 struct Place *plc = cls;
860 if (GNUNET_YES != plc->file_save)
863 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
864 memcpy (&place_pub_hash_ascii.encoding,
865 GNUNET_h2s_full (&plc->pub_key_hash), sizeof (place_pub_hash_ascii));
867 char *filename = NULL;
868 GNUNET_asprintf (&filename, "%s%c%s%c%s%c%.part" PRIu64,
869 dir_social, DIR_SEPARATOR,
870 "files", DIR_SEPARATOR,
871 place_pub_hash_ascii.encoding, DIR_SEPARATOR,
873 GNUNET_DISK_directory_create_for_file (filename);
874 struct GNUNET_DISK_FileHandle *
875 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE,
876 GNUNET_DISK_PERM_USER_READ
877 | GNUNET_DISK_PERM_USER_WRITE);
878 GNUNET_free (filename);
880 GNUNET_DISK_file_seek (fh, plc->file_offset, GNUNET_DISK_SEEK_SET);
881 GNUNET_DISK_file_write (fh, data, data_size);
882 GNUNET_DISK_file_close (fh);
883 plc->file_offset += data_size;
888 place_recv_save_eom (void *cls,
889 const struct GNUNET_MessageHeader *msg,
893 struct Place *plc = cls;
894 if (GNUNET_YES != plc->file_save)
897 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
898 memcpy (&place_pub_hash_ascii.encoding,
899 GNUNET_h2s_full (&plc->pub_key_hash), sizeof (place_pub_hash_ascii));
901 char *fn_part = NULL;
902 GNUNET_asprintf (&fn_part, "%s%c%s%c%s%c%.part" PRIu64,
903 dir_social, DIR_SEPARATOR,
904 "files", DIR_SEPARATOR,
905 place_pub_hash_ascii.encoding, DIR_SEPARATOR,
909 GNUNET_asprintf (&fn, "%s%c%s%c%s%c%" PRIu64,
910 dir_social, DIR_SEPARATOR,
911 "files", DIR_SEPARATOR,
912 place_pub_hash_ascii.encoding, DIR_SEPARATOR,
915 rename (fn_part, fn);
918 GNUNET_free (fn_part);
923 * Initialize place data structure.
926 place_init (struct Place *plc)
932 * Add a place to the @e places hash map.
937 * @return #GNUNET_OK if the place was added
938 * #GNUNET_NO if the place already exists in the hash map
939 * #GNUNET_SYSERR on error
942 place_add (const struct PlaceEnterRequest *ereq)
944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
945 "Adding place to hashmap:\n");
947 struct EgoPlacePublicKey ego_place_pub_key = {
948 .ego_pub_key = ereq->ego_pub_key,
949 .place_pub_key = ereq->place_pub_key,
951 struct GNUNET_HashCode ego_place_pub_hash;
952 GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
955 " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
957 struct GNUNET_MessageHeader *
958 place_msg = GNUNET_CONTAINER_multihashmap_get (places, &ego_place_pub_hash);
959 if (NULL != place_msg)
962 place_msg = GNUNET_copy_message (&ereq->header);
963 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, &ego_place_pub_hash, place_msg,
964 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
967 GNUNET_free (place_msg);
968 return GNUNET_SYSERR;
975 * Add a place to the @e app_places hash map.
982 * @return #GNUNET_OK if the place was added
983 * #GNUNET_NO if the place already exists in the hash map
984 * #GNUNET_SYSERR on error
987 app_place_add (const char *app_id,
988 const struct PlaceEnterRequest *ereq)
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 "Adding app place to hashmap:\n");
992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
993 " app_id = %s\n", app_id);
995 struct GNUNET_HashCode app_id_hash;
996 GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
998 struct EgoPlacePublicKey ego_place_pub_key = {
999 .ego_pub_key = ereq->ego_pub_key,
1000 .place_pub_key = ereq->place_pub_key,
1002 struct GNUNET_HashCode ego_place_pub_hash;
1003 GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
1005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1006 " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
1008 struct GNUNET_CONTAINER_MultiHashMap *
1009 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1010 if (NULL == app_places)
1012 app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1013 GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places,
1014 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1017 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, &ego_place_pub_hash))
1020 if (GNUNET_SYSERR == place_add (ereq))
1021 return GNUNET_SYSERR;
1023 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, &ego_place_pub_hash, NULL,
1024 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
1027 return GNUNET_SYSERR;
1030 struct GNUNET_HashCode place_pub_hash;
1031 GNUNET_CRYPTO_hash (&ereq->place_pub_key, sizeof (ereq->place_pub_key), &place_pub_hash);
1033 struct GNUNET_CONTAINER_MultiHashMap *
1034 place_apps = GNUNET_CONTAINER_multihashmap_get (places_apps, &place_pub_hash);
1035 if (NULL == place_apps)
1037 place_apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1038 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places_apps, &place_pub_hash, place_apps,
1039 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
1046 size_t app_id_size = strlen (app_id);
1047 void *app_id_value = GNUNET_malloc (app_id_size);
1048 memcpy (app_id_value, app_id, app_id_size);
1050 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (place_apps, &app_id_hash, app_id_value,
1051 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1061 * Save place entry message to disk.
1069 app_place_save (const char *app_id,
1070 const struct PlaceEnterRequest *ereq)
1072 app_place_add (app_id, ereq);
1074 if (NULL == dir_places)
1075 return GNUNET_SYSERR;
1077 struct GNUNET_HashCode ego_pub_hash;
1078 struct GNUNET_HashCode place_pub_hash;
1079 GNUNET_CRYPTO_hash (&ereq->ego_pub_key, sizeof (ereq->ego_pub_key),
1081 GNUNET_CRYPTO_hash (&ereq->place_pub_key, sizeof (ereq->place_pub_key),
1084 struct GNUNET_CRYPTO_HashAsciiEncoded ego_pub_hash_ascii;
1085 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
1086 memcpy (&ego_pub_hash_ascii.encoding,
1087 GNUNET_h2s_full (&ego_pub_hash), sizeof (ego_pub_hash_ascii));
1088 memcpy (&place_pub_hash_ascii.encoding,
1089 GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
1091 char *filename = NULL;
1092 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
1093 dir_social, DIR_SEPARATOR,
1094 "places", DIR_SEPARATOR,
1095 ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
1096 place_pub_hash_ascii.encoding);
1097 int ret = GNUNET_DISK_directory_create_for_file (filename);
1098 if (GNUNET_OK != ret
1099 || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size),
1100 GNUNET_DISK_PERM_USER_READ
1101 | GNUNET_DISK_PERM_USER_WRITE))
1104 ret = GNUNET_SYSERR;
1106 GNUNET_free (filename);
1108 if (ret == GNUNET_OK)
1110 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s",
1111 dir_social, DIR_SEPARATOR,
1112 "apps", DIR_SEPARATOR,
1113 app_id, DIR_SEPARATOR,
1114 ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
1115 place_pub_hash_ascii.encoding);
1116 ret = GNUNET_DISK_directory_create_for_file (filename);
1117 if (GNUNET_OK != ret
1118 || 0 > GNUNET_DISK_fn_write (filename, "", 0,
1119 GNUNET_DISK_PERM_USER_READ
1120 | GNUNET_DISK_PERM_USER_WRITE))
1123 ret = GNUNET_SYSERR;
1125 GNUNET_free (filename);
1132 app_place_remove (const char *app_id,
1133 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key)
1135 struct GNUNET_HashCode place_pub_hash;
1136 GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash);
1138 struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
1139 memcpy (&place_pub_hash_ascii.encoding,
1140 GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
1142 char *app_place_filename = NULL;
1143 GNUNET_asprintf (&app_place_filename,
1145 dir_social, DIR_SEPARATOR,
1146 "apps", DIR_SEPARATOR,
1147 app_id, DIR_SEPARATOR,
1148 place_pub_hash_ascii.encoding);
1150 struct GNUNET_HashCode app_id_hash;
1151 GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
1153 struct GNUNET_CONTAINER_MultiHashMap *
1154 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1156 if (NULL != app_places)
1157 GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL);
1159 struct GNUNET_CONTAINER_MultiHashMap *
1160 place_apps = GNUNET_CONTAINER_multihashmap_get (places_apps, &place_pub_hash);
1161 if (NULL != place_apps)
1163 void *app_id_value = GNUNET_CONTAINER_multihashmap_get (place_apps, &app_id_hash);
1164 if (NULL != app_id_value)
1166 GNUNET_free (app_id_value);
1167 GNUNET_CONTAINER_multihashmap_remove_all (place_apps, &app_id_hash);
1172 int ret = unlink (app_place_filename);
1173 GNUNET_free (app_place_filename);
1177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1178 "Error removing app place: unlink returned %d\n", errno);
1179 return GNUNET_SYSERR;
1187 * Enter place as host.
1191 * @param[out] ret_hst
1192 * Returned Host struct.
1194 * @return #GNUNET_YES if the host entered the place just now,
1195 * #GNUNET_NO if the place is already entered,
1196 * #GNUNET_SYSERR if place_pub_key was set
1197 * but its private key was not found
1200 host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst)
1202 int ret = GNUNET_NO;
1203 struct GNUNET_HashCode place_pub_hash;
1204 GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key),
1206 struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash);
1210 hst = GNUNET_new (struct Host);
1211 hst->policy = hreq->policy;
1212 hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1214 struct Place *plc = &hst->plc;
1216 plc->is_host = GNUNET_YES;
1217 plc->pub_key = hreq->place_pub_key;
1218 plc->pub_key_hash = place_pub_hash;
1219 plc->slicer = GNUNET_PSYC_slicer_create ();
1221 GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
1222 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1223 hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy,
1224 &psyc_master_started,
1225 &psyc_recv_join_request,
1226 &psyc_recv_message, NULL, hst);
1227 plc->channel = GNUNET_PSYC_master_get_channel (hst->master);
1231 if (NULL != ret_hst)
1237 const struct MsgProcRequest *
1238 relay_req_parse (const struct GNUNET_MessageHeader *msg,
1240 const char **method_prefix,
1241 struct GNUNET_HashCode *method_hash)
1243 const struct MsgProcRequest *mpreq = (const struct MsgProcRequest *) msg;
1244 uint8_t method_size = ntohs (mpreq->header.size) - sizeof (*mpreq);
1245 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &mpreq[1],
1246 method_size, 1, method_prefix);
1248 if (0 == offset || offset != method_size || *method_prefix == NULL)
1250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1251 "offset = %u, method_size = %u, method_name = %s\n",
1252 offset, method_size, *method_prefix);
1256 GNUNET_CRYPTO_hash (*method_prefix, method_size, method_hash);
1257 *flags = ntohl (mpreq->flags);
1263 * Handle a client setting message proccesing flags for a method prefix.
1266 client_recv_msg_proc_set (void *cls, struct GNUNET_SERVER_Client *client,
1267 const struct GNUNET_MessageHeader *msg)
1270 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1271 GNUNET_assert (NULL != ctx);
1272 struct Place *plc = ctx->plc;
1274 const char *method_prefix = NULL;
1276 struct GNUNET_HashCode method_hash;
1277 const struct MsgProcRequest *
1278 mpreq = relay_req_parse (msg, &flags, &method_prefix, &method_hash);
1280 if (NULL == mpreq) {
1282 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1286 GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix,
1287 place_recv_relay_method,
1288 place_recv_relay_modifier,
1289 place_recv_relay_data,
1290 place_recv_relay_eom);
1291 GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix,
1292 place_recv_save_method,
1294 place_recv_save_data,
1295 place_recv_save_eom);
1297 if (flags & GNUNET_SOCIAL_MSG_PROC_RELAY)
1299 GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix,
1300 place_recv_relay_method,
1301 place_recv_relay_modifier,
1302 place_recv_relay_data,
1303 place_recv_relay_eom,
1306 if (flags & GNUNET_SOCIAL_MSG_PROC_SAVE)
1308 GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix,
1309 place_recv_save_method,
1311 place_recv_save_data,
1312 place_recv_save_eom,
1316 /** @todo Save flags to be able to resume relaying/saving after restart */
1318 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1323 * Handle a connecting client requesting to clear all relay rules.
1326 client_recv_msg_proc_clear (void *cls, struct GNUNET_SERVER_Client *client,
1327 const struct GNUNET_MessageHeader *msg)
1330 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1331 GNUNET_assert (NULL != ctx);
1332 struct Place *plc = ctx->plc;
1333 if (GNUNET_YES != plc->is_host) {
1335 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1338 struct Host *hst = (struct Host *) plc;
1340 GNUNET_PSYC_slicer_clear (plc->slicer);
1342 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1347 * Handle a connecting client entering a place as host.
1350 client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
1351 const struct GNUNET_MessageHeader *msg)
1353 struct HostEnterRequest *hreq
1354 = (struct HostEnterRequest *) GNUNET_copy_message (msg);
1356 uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq);
1357 const char *app_id = NULL;
1358 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1],
1359 app_id_size, 1, &app_id);
1360 if (0 == offset || offset != app_id_size || app_id == NULL)
1362 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1363 "offset = %u, app_id_size = %u, app_id = %s\n",
1364 offset, app_id_size, app_id);
1366 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1370 struct Host *hst = NULL;
1371 struct Place *plc = NULL;
1372 int ret = GNUNET_OK;
1374 struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key;
1375 memset (&empty_pub_key, 0, sizeof (empty_pub_key));
1377 if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof (empty_pub_key)))
1378 { // no public key set: create new private key & save the place
1379 struct GNUNET_CRYPTO_EddsaPrivateKey *
1380 place_key = GNUNET_CRYPTO_eddsa_key_create ();
1381 hreq->place_key = *place_key;
1382 GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key);
1383 GNUNET_CRYPTO_eddsa_key_clear (place_key);
1384 GNUNET_free (place_key);
1386 app_place_save (app_id, (const struct PlaceEnterRequest *) hreq);
1389 switch (host_enter (hreq, &hst))
1398 client_send_host_enter_ack (client, hst, GNUNET_OK);
1402 ret = GNUNET_SYSERR;
1405 if (ret != GNUNET_SYSERR)
1408 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1409 "%p Client connected as host to place %s.\n",
1410 hst, GNUNET_h2s (&plc->pub_key_hash));
1412 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1413 cli->client = client;
1414 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1416 struct Client *ctx = GNUNET_new (struct Client);
1418 GNUNET_SERVER_client_set_user_context (client, ctx);
1421 GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key);
1423 GNUNET_SERVER_receive_done (client, ret);
1428 * Enter place as guest.
1432 * @param[out] ret_gst
1433 * Returned Guest struct.
1435 * @return #GNUNET_YES if the guest entered the place just now,
1436 * #GNUNET_NO if the place is already entered,
1437 * #GNUNET_SYSERR on error.
1440 guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst)
1442 int ret = GNUNET_NO;
1443 uint16_t greq_size = ntohs (greq->header.size);
1445 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key;
1446 struct GNUNET_HashCode ego_pub_hash;
1447 GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
1448 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
1451 return GNUNET_SYSERR;
1453 struct GNUNET_HashCode place_pub_hash;
1454 GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key),
1457 struct GNUNET_CONTAINER_MultiHashMap *
1458 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash);
1459 struct Guest *gst = NULL;
1461 if (NULL != plc_gst)
1462 gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash);
1464 if (NULL == gst || NULL == gst->slave)
1466 gst = GNUNET_new (struct Guest);
1467 gst->origin = greq->origin;
1468 gst->relay_count = ntohl (greq->relay_count);
1471 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1472 const char *app_id = (const char *) &greq[1];
1473 const char *p = app_id;
1475 len = strnlen (app_id, remaining);
1476 if (len == remaining)
1479 return GNUNET_SYSERR;
1482 remaining -= len + 1;
1484 const struct GNUNET_PeerIdentity *relays = NULL;
1485 uint16_t relay_size = gst->relay_count * sizeof (*relays);
1486 if (remaining < relay_size)
1489 return GNUNET_SYSERR;
1492 relays = (const struct GNUNET_PeerIdentity *) p;
1494 remaining -= relay_size;
1496 struct GNUNET_PSYC_Message *join_msg = NULL;
1497 uint16_t join_msg_size = 0;
1499 if (sizeof (struct GNUNET_MessageHeader) <= remaining)
1501 join_msg = (struct GNUNET_PSYC_Message *) p;
1502 join_msg_size = ntohs (join_msg->header.size);
1504 remaining -= join_msg_size;
1508 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1509 "%u + %u + %u != %u\n",
1510 sizeof (*greq), relay_size, join_msg_size, greq_size);
1513 return GNUNET_SYSERR;
1517 gst->relays = GNUNET_malloc (relay_size);
1518 memcpy (gst->relays, relays, relay_size);
1521 gst->join_flags = ntohl (greq->flags);
1523 struct Place *plc = &gst->plc;
1525 plc->is_host = GNUNET_NO;
1526 plc->pub_key = greq->place_pub_key;
1527 plc->pub_key_hash = place_pub_hash;
1528 plc->ego_pub_key = ego_pub_key;
1529 plc->ego_pub_hash = ego_pub_hash;
1530 plc->ego_key = ego->key;
1531 plc->slicer = GNUNET_PSYC_slicer_create ();
1533 if (NULL == plc_gst)
1535 plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1536 (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
1537 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1539 (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst,
1540 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1541 (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
1542 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1544 = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key,
1545 gst->join_flags, &gst->origin,
1546 gst->relay_count, gst->relays,
1547 &psyc_recv_message, NULL,
1548 &psyc_slave_connected,
1549 &psyc_recv_join_dcsn,
1551 plc->channel = GNUNET_PSYC_slave_get_channel (gst->slave);
1555 if (NULL != ret_gst)
1562 * Handle a connecting client entering a place as guest.
1565 client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client,
1566 const struct GNUNET_MessageHeader *msg)
1568 const struct GuestEnterRequest *
1569 greq = (const struct GuestEnterRequest *) msg;
1571 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1572 const char *app_id = NULL;
1573 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1],
1574 remaining, 1, &app_id);
1578 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1582 struct Guest *gst = NULL;
1583 struct Place *plc = NULL;
1585 switch (guest_enter (greq, &gst))
1589 app_place_save (app_id, (const struct PlaceEnterRequest *) greq);
1596 struct GNUNET_PSYC_CountersResultMessage res;
1597 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
1598 res.header.size = htons (sizeof (res));
1599 res.result_code = htonl (GNUNET_OK);
1600 res.max_message_id = GNUNET_htonll (plc->max_message_id);
1602 client_send_msg (client, &res.header);
1603 if (NULL != gst->join_dcsn)
1604 client_send_msg (client, &gst->join_dcsn->header);
1610 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1615 "%p Client connected as guest to place %s.\n",
1616 gst, GNUNET_h2s (&plc->pub_key_hash));
1618 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1619 cli->client = client;
1620 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1622 struct Client *ctx = GNUNET_new (struct Client);
1624 GNUNET_SERVER_client_set_user_context (client, ctx);
1625 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1629 struct GuestEnterByNameClosure
1631 struct GNUNET_SERVER_Client *client;
1634 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
1635 struct GNUNET_MessageHeader *join_msg;
1640 * Result of a GNS name lookup for entering a place.
1642 * @see GNUNET_SOCIAL_guest_enter_by_name
1645 gns_result_guest_enter (void *cls, uint32_t rd_count,
1646 const struct GNUNET_GNSRECORD_Data *rd)
1648 struct GuestEnterByNameClosure *gcls = cls;
1649 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1650 "%p GNS result: %u records.\n", gcls->client, rd_count);
1652 const struct GNUNET_GNSRECORD_PlaceData *
1653 rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
1655 if (0 == rd_count || rd->data_size < sizeof (*rec))
1658 GNUNET_SERVER_receive_done (gcls->client, GNUNET_SYSERR);
1662 uint16_t relay_count = ntohl (rec->relay_count);
1663 struct GNUNET_PeerIdentity *relays = NULL;
1665 if (0 < relay_count)
1667 if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity))
1669 relays = (struct GNUNET_PeerIdentity *) &rec[1];
1674 GNUNET_break_op (0);
1678 uint16_t app_id_size = strlen (gcls->app_id) + 1;
1679 uint16_t relay_size = relay_count * sizeof (*relays);
1680 uint16_t join_msg_size = 0;
1681 if (NULL != gcls->join_msg)
1682 join_msg_size = ntohs (gcls->join_msg->size);
1683 uint16_t greq_size = sizeof (struct GuestEnterRequest)
1684 + app_id_size + relay_size + join_msg_size;
1685 struct GuestEnterRequest *greq = GNUNET_malloc (greq_size);
1686 greq->header.size = htons (greq_size);
1687 greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1688 greq->ego_pub_key = gcls->ego_pub_key;
1689 greq->place_pub_key = rec->place_pub_key;
1690 greq->origin = rec->origin;
1691 greq->relay_count = rec->relay_count;
1694 memcpy (p, gcls->app_id, app_id_size);
1696 memcpy (p, relays, relay_size);
1698 memcpy (p, gcls->join_msg, join_msg_size);
1700 client_recv_guest_enter (NULL, gcls->client, &greq->header);
1702 GNUNET_free (gcls->app_id);
1703 if (NULL != gcls->password)
1704 GNUNET_free (gcls->password);
1705 if (NULL != gcls->join_msg)
1706 GNUNET_free (gcls->join_msg);
1713 * Handle a connecting client entering a place as guest using a GNS address.
1715 * Look up GNS address and generate a GuestEnterRequest from that.
1718 client_recv_guest_enter_by_name (void *cls, struct GNUNET_SERVER_Client *client,
1719 const struct GNUNET_MessageHeader *msg)
1721 const struct GuestEnterByNameRequest *
1722 greq = (const struct GuestEnterByNameRequest *) msg;
1724 struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls));
1725 gcls->client = client;
1726 gcls->ego_pub_key = greq->ego_pub_key;
1728 const char *p = (const char *) &greq[1];
1729 const char *app_id = NULL, *password = NULL, *gns_name = NULL;
1730 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1731 uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3,
1736 remaining -= offset;
1738 if (0 != offset && sizeof (*gcls->join_msg) <= remaining)
1740 gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p);
1741 remaining -= ntohs (gcls->join_msg->size);
1744 if (0 == offset || 0 != remaining)
1746 if (NULL != gcls->join_msg)
1747 GNUNET_free (gcls->join_msg);
1749 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1753 uint16_t app_id_size = strlen (app_id) + 1;
1754 gcls->app_id = GNUNET_malloc (app_id_size);
1755 memcpy (gcls->app_id, app_id, app_id_size);
1757 uint16_t password_size = strlen (password);
1758 if (0 < password_size++)
1760 gcls->password = GNUNET_malloc (password_size);
1761 memcpy (gcls->password, password, password_size);
1764 GNUNET_GNS_lookup (gns, gns_name, &greq->ego_pub_key,
1765 GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
1766 NULL, gns_result_guest_enter, gcls);
1771 app_notify_place (struct GNUNET_MessageHeader *msg,
1772 struct GNUNET_SERVER_Client *client)
1774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1775 "%p Sending place notification of type %u to client.\n",
1776 client, ntohs (msg->type));
1778 uint16_t msg_size = ntohs (msg->size);
1779 struct AppPlaceMessage amsg;
1780 amsg.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE);
1781 amsg.header.size = htons (sizeof (amsg));
1782 // FIXME: also notify about not entered places
1783 amsg.place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED;
1785 switch (ntohs (msg->type))
1787 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
1788 if (msg_size < sizeof (struct HostEnterRequest))
1790 struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
1791 amsg.is_host = GNUNET_YES;
1792 amsg.ego_pub_key = hreq->ego_pub_key;
1793 amsg.place_pub_key = hreq->place_pub_key;
1796 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
1797 if (msg_size < sizeof (struct GuestEnterRequest))
1799 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
1800 amsg.is_host = GNUNET_NO;
1801 amsg.ego_pub_key = greq->ego_pub_key;
1802 amsg.place_pub_key = greq->place_pub_key;
1809 client_send_msg (client, &amsg.header);
1814 app_notify_ego (struct Ego *ego, struct GNUNET_SERVER_Client *client)
1816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1817 "%p Sending ego notification to client: %s\n",
1820 size_t name_size = strlen (ego->name) + 1;
1821 struct AppEgoMessage *emsg = GNUNET_malloc (sizeof (*emsg) + name_size);
1822 emsg->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO);
1823 emsg->header.size = htons (sizeof (*emsg) + name_size);
1825 GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key);
1826 memcpy (&emsg[1], ego->name, name_size);
1828 client_send_msg (client, &emsg->header);
1834 app_place_entry_notify (void *cls, const struct GNUNET_HashCode *key, void *value)
1836 struct GNUNET_MessageHeader *
1837 msg = GNUNET_CONTAINER_multihashmap_get (places, key);
1839 app_notify_place (msg, cls);
1845 ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
1847 app_notify_ego (value, cls);
1853 * Handle application connection.
1856 client_recv_app_connect (void *cls, struct GNUNET_SERVER_Client *client,
1857 const struct GNUNET_MessageHeader *msg)
1859 const struct AppConnectRequest *creq
1860 = (const struct AppConnectRequest *) msg;
1862 uint8_t app_id_size = ntohs (creq->header.size) - sizeof (*creq);
1863 const char *app_id = NULL;
1864 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1],
1865 app_id_size, 1, &app_id);
1866 if (0 == offset || offset != app_id_size)
1869 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1873 struct GNUNET_HashCode app_id_hash;
1874 GNUNET_CRYPTO_hash (app_id, app_id_size, &app_id_hash);
1876 GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client);
1878 struct GNUNET_CONTAINER_MultiHashMap *
1879 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1880 if (NULL != app_places)
1881 GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry_notify, client);
1883 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1884 cli->client = client;
1885 struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps,
1888 app = GNUNET_malloc (sizeof (*app));
1889 (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app,
1890 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1892 GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli);
1894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1895 "%p Application %s connected.\n", app, app_id);
1897 struct Client *ctx = GNUNET_new (struct Client);
1898 ctx->app_id = GNUNET_malloc (app_id_size);
1899 memcpy (ctx->app_id, app_id, app_id_size);
1901 GNUNET_SERVER_client_set_user_context (client, ctx);
1902 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1907 * Handle application detach request.
1910 client_recv_app_detach (void *cls, struct GNUNET_SERVER_Client *client,
1911 const struct GNUNET_MessageHeader *msg)
1914 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1915 GNUNET_assert (NULL != ctx);
1917 const struct AppDetachRequest *req
1918 = (const struct AppDetachRequest *) msg;
1920 int ret = app_place_remove (ctx->app_id, &req->place_pub_key);
1921 client_send_result (client, req->op_id, ret, NULL, 0);
1923 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1928 app_places_entry_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
1930 app_place_remove (value, cls);
1936 * Handle application detach request.
1939 client_recv_place_leave (void *cls, struct GNUNET_SERVER_Client *client,
1940 const struct GNUNET_MessageHeader *msg)
1943 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1944 GNUNET_assert (NULL != ctx);
1945 struct Place *plc = ctx->plc;
1947 /* FIXME: remove all app subscriptions and leave this place */
1949 struct GNUNET_CONTAINER_MultiHashMap *
1950 place_apps = GNUNET_CONTAINER_multihashmap_get (places_apps, &plc->pub_key_hash);
1951 if (NULL != place_apps)
1953 GNUNET_CONTAINER_multihashmap_iterate (place_apps, app_places_entry_remove, &plc->pub_key);
1956 /* FIXME: disconnect from the network, but keep local connection for history access */
1958 /* Disconnect all clients connected to the place */
1959 struct ClientListItem *cli = plc->clients_head, *next;
1962 GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
1963 GNUNET_SERVER_client_disconnect (cli->client);
1969 if (GNUNET_YES != plc->is_disconnected)
1971 plc->is_disconnected = GNUNET_YES;
1972 if (NULL != plc->tmit_msgs_head)
1973 { /* Send pending messages to PSYC before cleanup. */
1974 psyc_transmit_message (plc);
1978 cleanup_place (plc);
1984 struct JoinDecisionClosure
1986 int32_t is_admitted;
1987 struct GNUNET_PSYC_Message *msg;
1992 * Iterator callback for responding to join requests.
1995 psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
1998 struct JoinDecisionClosure *jcls = cls;
1999 struct GNUNET_PSYC_JoinHandle *jh = value;
2000 // FIXME: add relays
2001 GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
2007 * Handle an entry decision from a host client.
2010 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
2011 const struct GNUNET_MessageHeader *msg)
2014 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2015 GNUNET_assert (NULL != ctx);
2016 struct Place *plc = ctx->plc;
2017 if (GNUNET_YES != plc->is_host) {
2019 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2022 struct Host *hst = (struct Host *) plc;
2024 struct GNUNET_PSYC_JoinDecisionMessage *
2025 dcsn = (struct GNUNET_PSYC_JoinDecisionMessage *) msg;
2026 struct JoinDecisionClosure jcls;
2027 jcls.is_admitted = ntohl (dcsn->is_admitted);
2029 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
2030 ? (struct GNUNET_PSYC_Message *) &dcsn[1]
2033 struct GNUNET_HashCode slave_pub_hash;
2034 GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key),
2037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2038 "%p Got join decision (%d) from client for place %s..\n",
2039 hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
2040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2041 "%p ..and slave %s.\n",
2042 hst, GNUNET_h2s (&slave_pub_hash));
2044 GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_pub_hash,
2045 &psyc_send_join_decision, &jcls);
2046 GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_pub_hash);
2047 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2052 * Send acknowledgement to a client.
2054 * Sent after a message fragment has been passed on to multicast.
2056 * @param plc The place struct for the client.
2059 send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client)
2061 struct GNUNET_MessageHeader res;
2062 res.size = htons (sizeof (res));
2063 res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
2064 client_send_msg (client, &res);
2069 * Proceed to the next message part in the transmission queue.
2072 * Place where the transmission is going on.
2074 * Currently transmitted message.
2076 * Currently transmitted message fragment.
2078 * @return @a tmit_frag, or NULL if reached the end of fragment.
2080 static struct FragmentTransmitQueue *
2081 psyc_transmit_queue_next_part (struct Place *plc,
2082 struct MessageTransmitQueue *tmit_msg,
2083 struct FragmentTransmitQueue *tmit_frag)
2085 uint16_t psize = ntohs (tmit_frag->next_part->size);
2086 if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
2089 tmit_frag->next_part
2090 = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
2092 else /* Reached end of current fragment. */
2094 if (NULL != tmit_frag->client)
2095 send_message_ack (plc, tmit_frag->client);
2096 GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2097 GNUNET_free (tmit_frag);
2105 * Proceed to next message in transmission queue.
2108 * Place where the transmission is going on.
2110 * Currently transmitted message.
2112 * @return The next message in queue, or NULL if queue is empty.
2114 static struct MessageTransmitQueue *
2115 psyc_transmit_queue_next_msg (struct Place *plc,
2116 struct MessageTransmitQueue *tmit_msg)
2118 GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2119 GNUNET_free (tmit_msg);
2120 return plc->tmit_msgs_head;
2125 * Callback for data transmission to PSYC.
2128 psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2130 struct Place *plc = cls;
2131 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2132 GNUNET_assert (NULL != tmit_msg);
2133 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2134 if (NULL == tmit_frag)
2135 { /* Rest of the message have not arrived yet, pause transmission */
2139 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2143 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
2148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2149 "%p psyc_transmit_notify_data()\n", plc);
2150 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
2152 uint16_t ptype = ntohs (pmsg->type);
2153 uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
2158 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
2159 if (*data_size < pdata_size)
2161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2162 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
2166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2167 "%p psyc_transmit_notify_data: sending %u bytes.\n",
2170 *data_size = pdata_size;
2171 memcpy (data, &pmsg[1], *data_size);
2175 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2180 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2182 ret = GNUNET_SYSERR;
2186 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2187 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
2189 ret = GNUNET_SYSERR;
2192 if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
2195 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2196 plc->is_disconnected = GNUNET_YES;
2197 GNUNET_SERVER_client_disconnect (tmit_frag->client);
2198 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
2203 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2204 if (NULL != tmit_frag)
2206 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2207 ptype = ntohs (pmsg->type);
2210 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2213 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2214 ret = GNUNET_SYSERR;
2219 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2220 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2221 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2225 if (NULL == tmit_msg->frags_head
2226 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2227 { /* Reached end of current message. */
2228 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2232 if (ret != GNUNET_NO)
2234 if (NULL != tmit_msg)
2236 psyc_transmit_message (plc);
2238 else if (GNUNET_YES == plc->is_disconnected)
2240 /* FIXME: handle partial message (when still in_transmit) */
2241 cleanup_place (plc);
2249 * Callback for modifier transmission to PSYC.
2252 psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2253 uint8_t *oper, uint32_t *full_value_size)
2255 struct Place *plc = cls;
2256 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2257 GNUNET_assert (NULL != tmit_msg);
2258 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2259 if (NULL == tmit_frag)
2260 { /* Rest of the message have not arrived yet, pause transmission */
2264 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2268 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
2273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2274 "%p psyc_transmit_notify_mod()\n", plc);
2275 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
2277 uint16_t ptype = ntohs (pmsg->type);
2282 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
2286 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2287 "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
2288 ret = GNUNET_SYSERR;
2291 struct GNUNET_PSYC_MessageModifier *
2292 pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
2293 uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
2295 if (*data_size < mod_size)
2297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2298 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2303 *full_value_size = ntohl (pmod->value_size);
2305 *data_size = mod_size;
2306 memcpy (data, &pmod[1], mod_size);
2311 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
2315 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2316 "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
2317 ret = GNUNET_SYSERR;
2320 uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
2321 if (*data_size < mod_size)
2323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2324 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2329 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
2331 *data_size = mod_size;
2332 memcpy (data, &pmsg[1], *data_size);
2337 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
2338 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2339 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2345 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2346 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
2348 ret = GNUNET_SYSERR;
2351 if (GNUNET_SYSERR == ret)
2354 ret = GNUNET_SYSERR;
2355 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2356 plc->is_disconnected = GNUNET_YES;
2357 GNUNET_SERVER_client_disconnect (tmit_frag->client);
2358 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
2362 if (GNUNET_YES != ret)
2363 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2365 if (NULL == tmit_msg->frags_head
2366 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2367 { /* Reached end of current message. */
2368 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2375 * Callback for data transmission from a host to PSYC.
2378 host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2380 int ret = psyc_transmit_notify_data (cls, data_size, data);
2382 if (GNUNET_NO != ret)
2384 struct Host *hst = cls;
2385 hst->tmit_handle = NULL;
2392 * Callback for the transmit functions of multicast.
2395 guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2397 int ret = psyc_transmit_notify_data (cls, data_size, data);
2399 if (GNUNET_NO != ret)
2401 struct Guest *gst = cls;
2402 gst->tmit_handle = NULL;
2409 * Callback for modifier transmission from a host to PSYC.
2412 host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2413 uint8_t *oper, uint32_t *full_value_size)
2415 int ret = psyc_transmit_notify_mod (cls, data_size, data,
2416 oper, full_value_size);
2417 if (GNUNET_SYSERR == ret)
2419 struct Host *hst = cls;
2420 hst->tmit_handle = NULL;
2427 * Callback for modifier transmission from a guest to PSYC.
2430 guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2431 uint8_t *oper, uint32_t *full_value_size)
2433 int ret = psyc_transmit_notify_mod (cls, data_size, data,
2434 oper, full_value_size);
2435 if (GNUNET_SYSERR == ret)
2437 struct Guest *gst = cls;
2438 gst->tmit_handle = NULL;
2445 * Get method part of next message from transmission queue.
2448 * Next item in message transmission queue.
2450 * The message method is returned here.
2452 * @return #GNUNET_OK on success
2453 * #GNUNET_NO if there are no more messages in queue.
2454 * #GNUNET_SYSERR if the next message is malformed.
2457 psyc_transmit_queue_next_method (struct Place *plc,
2458 struct GNUNET_PSYC_MessageMethod **pmeth)
2460 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2461 if (NULL == tmit_msg)
2464 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2465 if (NULL == tmit_frag)
2471 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2473 || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
2475 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2476 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
2477 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
2479 return GNUNET_SYSERR;
2482 uint16_t psize = ntohs (pmsg->size);
2483 *pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
2484 if (psize < sizeof (**pmeth) + 1 || '\0' != *((char *) *pmeth + psize - 1))
2486 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2487 "%p psyc_transmit_queue_next_method: invalid method name.\n",
2488 plc, ntohs (pmsg->type));
2489 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2490 "%u <= %u || NUL != %u\n",
2491 sizeof (**pmeth), psize, *((char *) *pmeth + psize - 1));
2493 return GNUNET_SYSERR;
2496 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2502 * Transmit the next message in queue from the host to the PSYC channel.
2505 psyc_master_transmit_message (struct Host *hst)
2508 if (NULL == hst->tmit_handle)
2510 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
2511 int ret = psyc_transmit_queue_next_method (&hst->plc, &pmeth);
2512 if (GNUNET_OK != ret)
2516 = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
2517 &host_transmit_notify_mod,
2518 &host_transmit_notify_data, hst,
2523 GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
2530 * Transmit the next message in queue from a guest to the PSYC channel.
2533 psyc_slave_transmit_message (struct Guest *gst)
2535 if (NULL == gst->tmit_handle)
2537 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
2538 int ret = psyc_transmit_queue_next_method (&gst->plc, &pmeth);
2539 if (GNUNET_OK != ret)
2543 = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
2544 &guest_transmit_notify_mod,
2545 &guest_transmit_notify_data, gst,
2550 GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
2557 * Transmit a message to PSYC.
2560 psyc_transmit_message (struct Place *plc)
2564 ? psyc_master_transmit_message ((struct Host *) plc)
2565 : psyc_slave_transmit_message ((struct Guest *) plc);
2570 * Queue message parts for sending to PSYC.
2572 * @param plc Place to send to.
2573 * @param client Client the message originates from.
2574 * @param data_size Size of @a data.
2575 * @param data Concatenated message parts.
2576 * @param first_ptype First message part type in @a data.
2577 * @param last_ptype Last message part type in @a data.
2579 static struct MessageTransmitQueue *
2580 psyc_transmit_queue_message (struct Place *plc,
2581 struct GNUNET_SERVER_Client *client,
2584 uint16_t first_ptype, uint16_t last_ptype,
2585 struct MessageTransmitQueue *tmit_msg)
2587 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
2589 tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
2590 GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2592 else if (NULL == tmit_msg)
2597 struct FragmentTransmitQueue *
2598 tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
2599 memcpy (&tmit_frag[1], data, data_size);
2600 tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
2601 tmit_frag->client = client;
2602 tmit_frag->size = data_size;
2604 GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2605 tmit_msg->client = client;
2611 * Cancel transmission of current message to PSYC.
2613 * @param plc Place to send to.
2614 * @param client Client the message originates from.
2617 psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVER_Client *client)
2619 uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
2621 struct GNUNET_MessageHeader msg;
2622 msg.size = htons (sizeof (msg));
2623 msg.type = htons (type);
2625 psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
2626 psyc_transmit_message (plc);
2628 /* FIXME: cleanup */
2633 * Handle an incoming message from a client, to be transmitted to the place.
2636 client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
2637 const struct GNUNET_MessageHeader *msg)
2640 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2641 GNUNET_assert (NULL != ctx);
2642 struct Place *plc = ctx->plc;
2643 int ret = GNUNET_SYSERR;
2645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2646 "%p Received message from client.\n", plc);
2647 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
2649 if (GNUNET_YES != plc->is_ready)
2651 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2652 "%p Place is not ready yet, disconnecting client.\n", plc);
2654 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2658 uint16_t size = ntohs (msg->size);
2659 uint16_t psize = size - sizeof (*msg);
2660 if (psize < sizeof (struct GNUNET_MessageHeader)
2661 || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
2663 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2664 "%p Received message with invalid payload size (%u) from client.\n",
2667 psyc_transmit_cancel (plc, client);
2668 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2672 uint16_t first_ptype = 0, last_ptype = 0;
2674 == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
2675 &first_ptype, &last_ptype))
2677 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2678 "%p Received invalid message part from client.\n", plc);
2680 psyc_transmit_cancel (plc, client);
2681 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2685 "%p Received message with first part type %u and last part type %u.\n",
2686 plc, first_ptype, last_ptype);
2689 = psyc_transmit_queue_message (plc, client, psize, &msg[1],
2690 first_ptype, last_ptype, ctx->tmit_msg);
2691 if (NULL != ctx->tmit_msg)
2693 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
2694 ctx->tmit_msg = NULL;
2695 ret = psyc_transmit_message (plc);
2698 if (GNUNET_OK != ret)
2700 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2701 "%p Received invalid message part from client.\n", plc);
2703 psyc_transmit_cancel (plc, client);
2704 ret = GNUNET_SYSERR;
2706 GNUNET_SERVER_receive_done (client, ret);
2711 * A historic message arrived from PSYC.
2714 psyc_recv_history_message (void *cls, uint64_t message_id, uint32_t flags,
2715 const struct GNUNET_PSYC_MessageHeader *msg)
2717 struct OperationClosure *opcls = cls;
2718 struct Place *plc = opcls->plc;
2720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2721 "%p Received historic message #%" PRId64 " (flags: %x)\n",
2722 plc, message_id, flags);
2724 uint16_t size = ntohs (msg->header.size);
2726 struct GNUNET_OperationResultMessage *
2727 res = GNUNET_malloc (sizeof (*res) + size);
2728 res->header.size = htons (sizeof (*res) + size);
2729 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
2730 res->op_id = opcls->op_id;
2731 res->result_code = GNUNET_htonll (GNUNET_OK);
2733 memcpy (&res[1], msg, size);
2735 /** @todo FIXME: send only to requesting client */
2736 place_send_msg (plc, &res->header);
2741 * Result of message history replay from PSYC.
2744 psyc_recv_history_result (void *cls, int64_t result,
2745 const void *err_msg, uint16_t err_msg_size)
2747 struct OperationClosure *opcls = cls;
2748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2749 "%p History replay #%" PRIu64 ": "
2750 "PSYCstore returned %" PRId64 " (%.*s)\n",
2751 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
2753 // FIXME: place might have been destroyed
2754 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
2759 * Client requests channel history.
2762 client_recv_history_replay (void *cls, struct GNUNET_SERVER_Client *client,
2763 const struct GNUNET_MessageHeader *msg)
2766 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2767 GNUNET_assert (NULL != ctx);
2768 struct Place *plc = ctx->plc;
2770 const struct GNUNET_PSYC_HistoryRequestMessage *
2771 req = (const struct GNUNET_PSYC_HistoryRequestMessage *) msg;
2772 uint16_t size = ntohs (msg->size);
2773 const char *method_prefix = (const char *) &req[1];
2775 if (size < sizeof (*req) + 1
2776 || '\0' != method_prefix[size - sizeof (*req) - 1])
2778 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2779 "%p History replay #%" PRIu64 ": "
2780 "invalid method prefix. size: %u < %u?\n",
2781 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2783 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2787 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2788 opcls->client = client;
2790 opcls->op_id = req->op_id;
2791 opcls->flags = ntohl (req->flags);
2793 if (0 == req->message_limit)
2794 GNUNET_PSYC_channel_history_replay (plc->channel,
2795 GNUNET_ntohll (req->start_message_id),
2796 GNUNET_ntohll (req->end_message_id),
2797 method_prefix, opcls->flags,
2798 &psyc_recv_history_message, NULL,
2799 &psyc_recv_history_result, opcls);
2801 GNUNET_PSYC_channel_history_replay_latest (plc->channel,
2802 GNUNET_ntohll (req->message_limit),
2803 method_prefix, opcls->flags,
2804 &psyc_recv_history_message, NULL,
2805 &psyc_recv_history_result, opcls);
2807 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2812 * A state variable part arrived from PSYC.
2815 psyc_recv_state_var (void *cls,
2816 const struct GNUNET_MessageHeader *mod,
2819 uint32_t value_size,
2820 uint32_t full_value_size)
2822 struct OperationClosure *opcls = cls;
2823 struct Place *plc = opcls->plc;
2825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2826 "%p Received state variable %s from PSYC\n",
2829 uint16_t size = ntohs (mod->size);
2831 struct GNUNET_OperationResultMessage *
2832 res = GNUNET_malloc (sizeof (*res) + size);
2833 res->header.size = htons (sizeof (*res) + size);
2834 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
2835 res->op_id = opcls->op_id;
2836 res->result_code = GNUNET_htonll (GNUNET_OK);
2838 memcpy (&res[1], mod, size);
2840 /** @todo FIXME: send only to requesting client */
2841 place_send_msg (plc, &res->header);
2846 * Result of retrieving state variable from PSYC.
2849 psyc_recv_state_result (void *cls, int64_t result,
2850 const void *err_msg, uint16_t err_msg_size)
2852 struct OperationClosure *opcls = cls;
2853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2854 "%p State get #%" PRIu64 ": "
2855 "PSYCstore returned %" PRId64 " (%.*s)\n",
2856 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
2858 // FIXME: place might have been destroyed
2859 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
2864 * Client requests channel history.
2867 client_recv_state_get (void *cls, struct GNUNET_SERVER_Client *client,
2868 const struct GNUNET_MessageHeader *msg)
2871 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2872 GNUNET_assert (NULL != ctx);
2873 struct Place *plc = ctx->plc;
2875 const struct GNUNET_PSYC_StateRequestMessage *
2876 req = (const struct GNUNET_PSYC_StateRequestMessage *) msg;
2877 uint16_t size = ntohs (msg->size);
2878 const char *name = (const char *) &req[1];
2880 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2881 "%p State get #%" PRIu64 ": %s\n",
2882 plc, GNUNET_ntohll (req->op_id), name);
2884 if (size < sizeof (*req) + 1
2885 || '\0' != name[size - sizeof (*req) - 1])
2887 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2888 "%p State get #%" PRIu64 ": "
2889 "invalid name. size: %u < %u?\n",
2890 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2892 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2896 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2897 opcls->client = client;
2899 opcls->op_id = req->op_id;
2901 switch (ntohs (msg->type))
2903 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
2904 GNUNET_PSYC_channel_state_get (plc->channel, name,
2905 psyc_recv_state_var,
2906 psyc_recv_state_result, opcls);
2909 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
2910 GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
2911 psyc_recv_state_var,
2912 psyc_recv_state_result, opcls);
2919 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2924 namestore_recv_records_store_result (void *cls, int32_t result,
2925 const char *err_msg)
2927 struct OperationClosure *ocls = cls;
2928 client_send_result (ocls->client, ocls->op_id, result, err_msg,
2929 (NULL != err_msg) ? strlen (err_msg) : 0);
2935 * Handle request to add PLACE record to GNS zone.
2938 client_recv_zone_add_place (void *cls, struct GNUNET_SERVER_Client *client,
2939 const struct GNUNET_MessageHeader *msg)
2941 const struct ZoneAddPlaceRequest *preq
2942 = (const struct ZoneAddPlaceRequest *) msg;
2944 uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq);
2945 const char *p = (const char *) &preq[1];
2946 const char *name = NULL, *password = NULL;
2947 uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2,
2949 remaining -= offset;
2951 const struct GNUNET_PeerIdentity *
2952 relays = (const struct GNUNET_PeerIdentity *) p;
2953 uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays);
2955 if (0 == offset || remaining != relay_size)
2958 client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
2959 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2963 struct GNUNET_GNSRECORD_Data rd = { };
2964 rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
2965 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
2966 rd.expiration_time = GNUNET_ntohll (preq->expiration_time);
2968 struct GNUNET_GNSRECORD_PlaceData *
2969 rec = GNUNET_malloc (sizeof (*rec) + relay_size);
2970 rec->place_pub_key = preq->place_pub_key;
2971 rec->origin = this_peer;
2972 rec->relay_count = preq->relay_count;
2973 memcpy (&rec[1], relays, relay_size);
2976 rd.data_size = sizeof (*rec) + relay_size;
2978 struct GNUNET_HashCode ego_pub_hash;
2979 GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash);
2980 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
2983 client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
2987 struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
2988 ocls->client = client;
2989 ocls->op_id = preq->op_id;
2990 GNUNET_NAMESTORE_records_store (namestore, &ego->key,
2992 namestore_recv_records_store_result, ocls);
2994 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2999 * Handle request to add PLACE record to GNS zone.
3002 client_recv_zone_add_nym (void *cls, struct GNUNET_SERVER_Client *client,
3003 const struct GNUNET_MessageHeader *msg)
3005 const struct ZoneAddNymRequest *nreq
3006 = (const struct ZoneAddNymRequest *) msg;
3008 uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq);
3009 const char *name = NULL;
3010 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1],
3011 name_size, 1, &name);
3012 if (0 == offset || offset != name_size)
3015 client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
3016 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3020 struct GNUNET_GNSRECORD_Data rd = { };
3021 rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
3022 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
3023 rd.expiration_time = GNUNET_ntohll (nreq->expiration_time);
3024 rd.data = &nreq->nym_pub_key;
3025 rd.data_size = sizeof (nreq->nym_pub_key);
3027 struct GNUNET_HashCode ego_pub_hash;
3028 GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash);
3029 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3032 client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
3036 struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
3037 ocls->client = client;
3038 ocls->op_id = nreq->op_id;
3039 GNUNET_NAMESTORE_records_store (namestore, &ego->key,
3041 namestore_recv_records_store_result, ocls);
3043 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3047 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
3048 { client_recv_host_enter, NULL,
3049 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
3051 { client_recv_guest_enter, NULL,
3052 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
3054 { client_recv_guest_enter_by_name, NULL,
3055 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME, 0 },
3057 { client_recv_join_decision, NULL,
3058 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
3060 { client_recv_psyc_message, NULL,
3061 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 },
3063 { client_recv_history_replay, NULL,
3064 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, 0 },
3066 { client_recv_state_get, NULL,
3067 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, 0 },
3069 { client_recv_state_get, NULL,
3070 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 },
3072 { client_recv_zone_add_place, NULL,
3073 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE, 0 },
3075 { client_recv_zone_add_nym, NULL,
3076 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM, 0 },
3078 { client_recv_app_connect, NULL,
3079 GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT, 0 },
3081 { client_recv_app_detach, NULL,
3082 GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH, 0 },
3084 { client_recv_place_leave, NULL,
3085 GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE, 0 },
3087 { client_recv_msg_proc_set, NULL,
3088 GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET, 0 },
3090 { client_recv_msg_proc_clear, NULL,
3091 GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR, 0 },
3093 { NULL, NULL, 0, 0 }
3098 path_basename (const char *path)
3100 const char *basename = strrchr (path, DIR_SEPARATOR);
3101 if (NULL != basename)
3104 if (NULL == basename || '\0' == basename)
3111 struct PlaceLoadClosure
3114 const char *ego_pub_hash_str;
3118 /** Load a place file */
3120 file_place_load (void *cls, const char *filename)
3123 uint64_t file_size = 0;
3125 GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES)
3126 || file_size < sizeof (struct HostEnterRequest))
3129 struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size);
3130 ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size);
3131 if (read_size < 0 || read_size < sizeof (*ereq))
3134 uint16_t ereq_size = ntohs (ereq->header.size);
3135 if (read_size != ereq_size)
3138 switch (ntohs (ereq->header.type))
3140 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
3141 if (ereq_size < sizeof (struct HostEnterRequest))
3143 struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq;
3144 host_enter (hreq, NULL);
3147 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
3148 if (ereq_size < sizeof (struct GuestEnterRequest))
3150 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq;
3151 guest_enter (greq, NULL);
3158 app_place_add (app_id, ereq);
3163 /** Load an ego place file */
3165 file_ego_place_load (void *cls, const char *place_filename)
3167 struct PlaceLoadClosure *plcls = cls;
3169 const char *place_pub_hash_str = path_basename (place_filename);
3170 if (NULL == place_pub_hash_str)
3176 char *filename = NULL;
3177 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
3178 dir_social, DIR_SEPARATOR,
3179 "places", DIR_SEPARATOR,
3180 plcls->ego_pub_hash_str, DIR_SEPARATOR,
3181 place_pub_hash_str);
3183 struct PlaceEnterRequest ereq[GNUNET_SERVER_MAX_MESSAGE_SIZE];
3185 int read_size = GNUNET_DISK_fn_read (filename, &ereq,
3186 GNUNET_SERVER_MAX_MESSAGE_SIZE);
3187 GNUNET_free (filename);
3189 if (read_size < (ssize_t) sizeof (ereq))
3192 app_place_add (plcls->app_id, ereq);
3198 * Read @e place_pub_hash_str entries in @a dir_ego
3201 * Data directory of an application ego.
3202 * $GNUNET_DATA_HOME/social/apps/$app_id/$ego_pub_hash_str/
3205 scan_app_ego_dir (void *cls, const char *dir_ego)
3207 struct PlaceLoadClosure *plcls = cls;
3208 plcls->ego_pub_hash_str = path_basename (dir_ego);
3210 if (NULL != plcls->ego_pub_hash_str)
3211 GNUNET_DISK_directory_scan (dir_ego, file_ego_place_load, plcls);
3217 * Read @e ego_pub_hash_str entries in @a dir_app
3220 * Data directory of an application.
3221 * $GNUNET_DATA_HOME/social/apps/$app_id/
3224 scan_app_dir (void *cls, const char *dir_app)
3226 if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES))
3229 struct PlaceLoadClosure plcls;
3230 plcls.app_id = path_basename (dir_app);
3232 if (NULL != plcls.app_id)
3233 GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls);
3240 identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego,
3241 void **ctx, const char *name)
3243 if (NULL == id_ego) // end of initial list of egos
3246 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
3247 GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key);
3249 struct GNUNET_HashCode ego_pub_hash;
3250 GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
3252 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3255 GNUNET_free (ego->name);
3256 if (NULL == name) // deleted
3258 GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego);
3265 ego = GNUNET_malloc (sizeof (*ego));
3269 ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego));
3270 size_t name_size = strlen (name) + 1;
3271 ego->name = GNUNET_malloc (name_size);
3272 memcpy (ego->name, name, name_size);
3274 GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego,
3275 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
3281 * Connected to core service.
3284 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
3286 this_peer = *my_identity;
3291 * Initialize the PSYC service.
3293 * @param cls Closure.
3294 * @param server The initialized server.
3295 * @param c Configuration to use.
3298 run (void *cls, struct GNUNET_SERVER_Handle *server,
3299 const struct GNUNET_CONFIGURATION_Handle *c)
3303 hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3304 guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3305 place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3307 egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3308 apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3309 places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3310 apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3311 places_apps = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3313 core = GNUNET_CORE_connect (cfg, NULL, core_connected, NULL, NULL,
3314 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
3315 id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL);
3316 gns = GNUNET_GNS_connect (cfg);
3317 namestore = GNUNET_NAMESTORE_connect (cfg);
3318 stats = GNUNET_STATISTICS_create ("social", cfg);
3321 GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "DATA_HOME",
3324 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3325 "social", "DATA_HOME");
3329 GNUNET_asprintf (&dir_places, "%s%c%s",
3330 dir_social, DIR_SEPARATOR, "places");
3331 GNUNET_asprintf (&dir_apps, "%s%c%s",
3332 dir_social, DIR_SEPARATOR, "apps");
3334 GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL);
3336 nc = GNUNET_SERVER_notification_context_create (server, 1);
3337 GNUNET_SERVER_add_handlers (server, handlers);
3338 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3339 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
3340 &shutdown_task, NULL);
3345 * The main function for the service.
3347 * @param argc number of arguments from the command line
3348 * @param argv command line arguments
3349 * @return 0 ok, 1 on error
3352 main (int argc, char *const *argv)
3354 return (GNUNET_OK ==
3355 GNUNET_SERVICE_run (argc, argv, "social",
3356 GNUNET_SERVICE_OPTION_NONE,
3357 &run, NULL)) ? 0 : 1;
3360 /* end of gnunet-service-social.c */